Distance from line segment

So I need to find te distance from a touch to a line segment.

function Dist(x1, y1, x2, y2)
    m = CurrentTouch.x
    n = CurrentTouch.y
    A = -1*(y2 - y1)
    B = x2-x1
    m = (-1*A)/B
    C = -1*(y1-(m*x1))
    d = math.abs(A*m + B*n + C)/math.sqrt(A^2 + B^2)
    return d
end

I used the formula at http://www.intmath.com/plane-analytic-geometry/perpendicular-distance-point-line.php
Its not working, Why?

@CNCode - it could have something to do with the fact that after setting m=the x value of the touch, you then set m to something else.

So you are using m for two different things. Try changing the name for one of them.

@Ignatz WHAT! I have been staring at this for an hour! Well, after I fixed the code, the results were better, but still off. I used this code to test it

-- Intersect test

-- Use this function to perform your initial setup
function setup()
    parameter.integer("x1", 0, WIDTH, 400)
    parameter.integer("y1", 0, HEIGHT, 100)
    parameter.integer("x2", 0, WIDTH, 400)
    parameter.integer("y2", 0, HEIGHT, 200)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)
    line(x1, y1, x2, y2)
    -- Do your drawing here
    text(tostring(Dist(x1, y1, x2, y2)), 100, 100)
end

function Dist(x1, y1, x2, y2)
    m = CurrentTouch.x
    n = CurrentTouch.y
    A = -1*(y2 - y1)
    B = x2-x1
    slope = (-1*A)/B
    C = -1*(y1-(slope*x1))
    d = math.abs(A*m + B*n + C)/math.sqrt(A^2 + B^2)
    return d
end

@CNCode Try this. Tap the screen for a point from the line.


function setup()
    x1=100
    y1=100
    x2=500
    y2=500
    M=0
    n=0
end

function draw()
    background(0)
    fill(255)
    stroke(255)
    strokeWidth(2)
    line(x1,y1,x2,y2)
    ellipse(M,n,5)
    if M>0 and n>0 then
        text(Dist(x1,y1,x2,y2),WIDTH/2,HEIGHT-100)  
    end  
end


function Dist(x1, y1, x2, y2)
    M = CurrentTouch.x
    n = CurrentTouch.y
    A = y2-y1
    B = x2-x1
    m = A/B
    C=(y1*-1)-(m*x1*-1)
    d = math.abs(-m*M+n+C)/math.sqrt(m*m+1)
    return(d)
end 

function touched(t)
    if t.state==BEGAN then
        M=t.x
        n=t.y
    end
end

The original post says “line segment” but the formula posted, ugly as it is, is for the distance from a point to an infinite line. These are different things. Which do you want?

@CNCode Just in case you can’t make up your mind, this one does both. Drag the white ball around the screen. The colored distance matches the colored line.


displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    x1=400
    y1=200
    x2=800
    y2=400
    M=200
    n=300
end

function draw()
    background(0)
    noStroke()
    fill(255)
    text("Drag the white circle around the screen",WIDTH/2,HEIGHT-25)
    ellipse(M,n,20)
    strokeWidth(2)
    stroke(255,0,0)
    line(x1,y1,x2,y2)
    distXX(x1,y1,x2,y2,M,n)
    if a<=0 or a>=1 then
        fill(0,0,255)   
        text(d1,WIDTH/2,HEIGHT-75) 
    end
    fill(0,255,0)
    text(d2,WIDTH/2,HEIGHT-125) 
    stroke(0,0,255)
    line(M,n,x6,y6) 
    stroke(0,255,0)
    line(M,n,x7,y7) 
end

function distXX(x1,y1, x2,y2, x3,y3)
    dx=x2-x1
    dy=y2-y1
    temp=dx*dx+dy*dy
    a=((x3-x1)*dx+(y3-y1)*dy)/temp
    b=a
    bdx=dx
    bdy=dy
    if a>1 then
        a=1
    elseif a<0 then
        a=0
    end
    x6=x1+a*dx
    y6=y1+a*dy
    dx=M-x6
    dy=n-y6
    d1=math.sqrt(dx*dx+dy*dy)
    
    x7=x1+b*bdx
    y7=y1+b*bdy
    dx=M-x7
    dy=n-y7
    d2=math.sqrt(dx*dx+dy*dy)
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        M=t.x
        n=t.y
    end
end

@LoopSpace I need a formula for a line segment. And thank you @dave1707

Untested, but should work.

-- Returns the distance from the point p to the line segment from a to b
-- p,a,b are all vec2s
function lineDist(p,a,b)
    -- Vector along the direction of the line from a to b
    local v = b - a
    -- Project p onto the vector v and compare with the projections of a and b
    if v:dot(p) < v:dot(a) then
    -- The projection of p is lower than a, so return the distance from p to a
        return p:dist(a)
    elseif v:dot(p) > v:dot(b) then
    -- The projection of p is beyond b, so return the distance from p to b
        return p:dist(b)
    end
    -- The projection of p is between a and b, so we need to take the dot product with the orthogonal vector to v, so we rotate v and normalise it.
    v = v:rotate90():normalize()
    -- This is the distance from v to the line segment.
    return math.abs(v:dot(p)-v:dot(a))
end

@loopSpace Thanks! Do you know if there is any way to put this in a mathematical formula? (I needed this for something else, but the question came up in class. A formula will also help for translating in to other languages). Do you think this is possible? I did test this code out, and it definitely works.

@Dave1707 nice code.

@dave1707 Your code works great.

i like math courseware

My function is a mathematical formula.

Edited In light of further discussion, I realised that a better formula for this function is:

||p - Max(Min(p.(b - a)/(b-a).(b-a),1),0)(b-a)||

@dave1707 As to the v:rotate90():normalize() in my code, that’s because if u and v are vectors in the place which are unit vectors and are at 90 degrees to each other, then for any vector p we have:

p = (p.u) u + (p.v) v

Moreover, (p.v) v is the orthogonal projection of p onto the line in the direction v so is the closest point of p to that line. Thus the distance from p to that line is the length of the vector p - (p.v) v. From the above, this is the length of the vector (p.u) u and, as u is of unit length, this is just the absolute value of p.u.

In our case, v points along the line so we need a unit vector at 90 degrees to the line. This is what v:rotate90():normalize() returns.

@CNCode I changed my code above to show just the distance to a line segment. If you want a formula, then use the code in the function distToLineSeg where x1,y1 and x2,y2 are the end points of the line segment and px,py is the values of the point. d1 is the distance from the point to the line segment at tx,ty.


displayMode(FULLSCREEN)

function setup()
    x1=300  -- first x,y point of line segment
    y1=200
    x2=600  -- second x,y point of line segment
    y2=500
    px=300  -- x,y values of a point 
    py=300
end

function draw()
    background(0)
    noStroke()
    fill(255)
    text("Drag the white circle around the screen",WIDTH/2,HEIGHT-25)
    ellipse(px,py,20)
    strokeWidth(2)
    stroke(255,0,0)
    line(x1,y1,x2,y2)   
     
    distToLineSeg(x1,y1,x2,y2,px,py)
    
    fill(0,255,0)
    text(d1,WIDTH/2,HEIGHT-125) -- display distance from point to line segment
    stroke(0,0,255)
    line(px,py,tx,ty) -- draw line from point to line segment
end

-- calculate closest point and distance to a line segment
function distToLineSeg(x1,y1,x2,y2,px,py)
    local dx=x2-x1
    local dy=y2-y1
    local temp=dx*dx+dy*dy
    local a=((px-x1)*dx+(py-y1)*dy)/temp
    if a>1 then
        a=1
    elseif a<0 then
        a=0
    end
    tx=x1+a*dx  -- x value on line segment
    ty=y1+a*dy  -- y value on line segment
    dx=px-tx
    dy=py-ty
    d1=math.sqrt(dx*dx+dy*dy)   -- distance of point to line segment
end

-- get x,y values of new point
function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        px=t.x
        py=t.y
    end
end

@dave1707 wouldn’t it be better to return d1 rather than as global variable?

Did you compare your distances with loopspace’s? For me they disagree. Your distances agree with a routine i have been using previously.

@piinthesky Since this is just an example, and it’s used in one spot, it probably doesn’t matter that much. If this was in a larger program and called from a lot of different places, then returning the values would probably be better. I haven’t tried comparing the values, I figured they were correct since it’s not a very complicated routine.

@piinthesky I added @LoopSpace routine in my code and the distance values were exact if the point was beyond either end of the line, but the value from his code was way off when the point was between the end points. I was getting values of 0 when the point was still 70 pixels from the line.

@LoopSpace @dave1707 if u could make a app for studying high school math and college math?add formula and theorem demos?its best to solve math problems automatically?like Codea makes games?it will be nice

there are many websites that do this already, aren’t there?