Perpendicular on a line from a given point

Viewed 58125

How can I draw a perpendicular on a line segment from a given point? My line segment is defined as (x1, y1), (x2, y2), If I draw a perpendicular from a point (x3,y3) and it meets to line on point (x4,y4). I want to find out this (x4,y4).

14 Answers

This is a C# implementation of the accepted answer. It's also using ArcGis to return a MapPoint as that's what we're using for this project.

        private MapPoint GenerateLinePoint(double startPointX, double startPointY, double endPointX, double endPointY, double pointX, double pointY)
        {
            double k = ((endPointY - startPointY) * (pointX - startPointX) - (endPointX - startPointX) * (pointY - startPointY)) / (Math.Pow(endPointY - startPointY, 2) 
                + Math.Pow(endPointX - startPointX, 2));
            double resultX = pointX - k * (endPointY - startPointY);
            double resultY = pointY + k * (endPointX - startPointX);

            return new MapPoint(resultX, resultY, 0, SpatialReferences.Wgs84);
        }

Thanks to Ray as this worked perfectly for me.

Just for the sake of completeness, here is a solution using homogeneous coordinates.

  1. The homogeneous points are:

    p1 = (x1,y1,1), p2 = (x2,y2,1), p3 = (x3,y3,1)

  2. a line through two points is their cross-product

    l_12 := p1 x p2 = (y1-y2, x2-x1, x1*y2 - x2*y1)

  3. The (signed) distance of a point to a line is their dot product.

    d := l_12 * p3 = x3*(y1-y2) + y3*(x2-x1) + x1*y2 - x2*y1

  4. The vector from p4 to p3 is d times the normal vector of l_12 divided by the squared length of the normal vector.

    n2 := (y1-y2)^2 + (x2-x1)^2

    p4 := p3 + d/n2*(y1-y2, x2-x1, 0)

Note: if you divide l_12 by the length of the normal vector

l_12 := l_12 / sqrt((y1-y2)^2 + (x2-x1)^2)

the distance d will be the euclidean distance.

First, calculate the linear function determined by the points (x1,y2),(x2,y2).

We get:

y1 = mx+b1 where m and b1 are constants.

This step is easy to calculate by the formula of linear function between two points.


Then, calculate the linear function y that goes through (x3,y3).

The function slope is -m, where m is the slope of y1.


Then calculate the const b2 by the coordinates of the point (x3,y3).

We get y2 = -mx+b2 where m and b2 are constants.


The last thing to do is to find the intersection of y1, y2. You can find x by solving the equation: -mx+b2 = mx+b1, then place x in one of the equations to find y.

This is a vectorized Matlab function for finding pairwise projections of m points onto n line segments. Here xp and yp are m by 1 vectors holding coordinates of m different points, and x1, y1, x2 and y2 are n by 1 vectors holding coordinates of start and end points of n different line segments. It returns m by n matrices, x and y, where x(i, j) and y(i, j) are coordinates of projection of i-th point onto j-th line.

The actual work is done in first few lines and the rest of the function runs a self-test demo, just in case where it is called with no parameters. It's relatively fast, I managed to find projections of 2k points onto 2k line segments in less than 0.05s.

function [x, y] = projectPointLine(xp, yp, x1, y1, x2, y2)
if nargin > 0
        xd = (x2-x1)';
    yd = (y2-y1)';
    dAB = xd.*xd + yd.*yd;
    u = bsxfun(@rdivide, bsxfun(@times, bsxfun(@minus, xp, x1'), xd) + ...
        bsxfun(@times, bsxfun(@minus, yp, y1'), yd), dAB);
    x = bsxfun(@plus, x1', bsxfun(@times, u, xd));
    y = bsxfun(@plus, y1', bsxfun(@times, u, yd));
else
    nLine = 3;
    nPoint = 2;
    xp = rand(nPoint, 1) * 2 -1;
    yp = rand(nPoint, 1) * 2 -1;
    x1 = rand(nLine, 1) * 2 -1;
    y1 = rand(nLine, 1) * 2 -1;
    x2 = rand(nLine, 1) * 2 -1;
    y2 = rand(nLine, 1) * 2 -1;
    tic;
    [x, y] = projectPointLine(xp, yp, x1, y1, x2, y2);
    toc
    close all;
    plot([x1'; x2'], [y1'; y2'], '.-', 'linewidth', 2, 'markersize', 20);
    axis equal;
    hold on
    C = lines(nPoint + nLine);
    for i=1:nPoint
        scatter(x(i, :), y(i, :), 100, C(i+nLine, :), 'x', 'linewidth', 2);
        scatter(xp(i), yp(i), 100, C(i+nLine, :), 'x', 'linewidth', 2);
    end
    for i=1:nLine
        scatter(x(:, i)', y(:, i)', 100, C(i, :), 'o', 'linewidth', 2);
    end
end
end
Related