web-dev-qa-db-fra.com

Perpendiculaire sur une ligne à partir d'un point donné

Comment dessiner une perpendiculaire sur un segment de ligne à partir d'un point donné? Mon segment de ligne est défini comme (x1, y1), (x2, y2), si je dessine une perpendiculaire à partir d'un point (x3, y3) et qu'il se réunit pour se aligner sur le point (x4, y4). Je veux le savoir (x4, y4).

36
Zinx

J'ai résolu les équations pour vous:

k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) / ((y2-y1)^2 + (x2-x1)^2)
x4 = x3 - k * (y2-y1)
y4 = y3 + k * (x2-x1)

Où ^ 2 signifie au carré

65
Ray Hidayat

De wiki :

En algèbre, pour toute équation linéaire y = mx + b, les perpendiculaires auront toutes une pente de (-1/m), l'inverse de la pente d'origine. Il est utile de mémoriser le slogan "pour trouver la pente de la ligne perpendiculaire, inverser la fraction et changer le signe". Rappelez-vous que tout nombre entier a est lui-même supérieur à un, et peut être écrit comme (a/1)

Pour trouver la perpendiculaire d'une ligne donnée qui passe également par un point particulier (x, y), résolvez l'équation y = (-1/m) x + b, en remplaçant par les valeurs connues de m, x et y à résoudre pour b.

La pente de la ligne, m, à travers (x1, y1) et (x2, y2) est m = (y1 - y2)/(x1 - x2)

17
Mitch Wheat

Je suis d'accord avec peter.murray.Rust, les vecteurs rendent la solution plus claire:

// first convert line to normalized unit vector
double dx = x2 - x1;
double dy = y2 - y1;
double mag = sqrt(dx*dx + dy*dy);
dx /= mag;
dy /= mag;

// translate the point and get the dot product
double lambda = (dx * (x3 - x1)) + (dy * (y3 - y1));
x4 = (dx * lambda) + x1;
y4 = (dy * lambda) + y1;
11
Abraxas

Vous constaterez souvent que l'utilisation de vecteurs rend la solution plus claire ...

Voici une routine de ma propre bibliothèque:

public class Line2  {

Real2 from;
Real2 to;
Vector2 vector;
Vector2 unitVector = null;


    public Real2 getNearestPointOnLine(Real2 point) {
        unitVector = to.subtract(from).getUnitVector();
        Vector2 lp = new Vector2(point.subtract(this.from));
        double lambda = unitVector.dotProduct(lp);
        Real2 vv = unitVector.multiplyBy(lambda);
        return from.plus(vv);
    }

}

Vous devrez implémenter Real2 (un point) et Vector2 et dotProduct () mais ceux-ci devraient être simples:

Le code ressemble alors à quelque chose comme:

Point2 p1 = new Point2(x1, y1);
Point2 p2 = new Point2(x2, y2);
Point2 p3 = new Point2(x3, y3);
Line2 line = new Line2(p1, p2);
Point2 p4 = getNearestPointOnLine(p3);

La bibliothèque (org.xmlcml.euclid) est à: http://sourceforge.net/projects/cml/

et il y a des tests unitaires qui exerceront cette méthode et vous montreront comment l'utiliser.

@Test
public final void testGetNearestPointOnLine() {
    Real2 p = l1112.getNearestPointOnLine(new Real2(0., 0.));
    Real2Test.assertEquals("point", new Real2(0.4, -0.2), p, 0.0000001);
}
8
peter.murray.rust

Vous connaissez à la fois le point et la pente, donc l'équation pour la nouvelle ligne est:

y-y3=m*(x-x3)

Puisque la ligne est perpendiculaire, la pente est l'inverse réciproque. Vous avez maintenant deux équations et pouvez résoudre leur intersection.

y-y3=-(1/m)*(x-x3)
y-y1=m*(x-x1)
7
Dan Lorenc

Calculez la pente des points de jonction de ligne (x1, y1) et (x2, y2) comme m=(y2-y1)/(x2-x1)

L'équation de la ligne joignant (x1, y1) et (x2, y2) en utilisant la forme point-pente de l'équation de ligne, serait y-y2 = m(x-x2)

La pente de la ligne joignant (x3, y3) et (x4, y4) serait -(1/m)

Encore une fois, l'équation de la ligne joignant (x3, y3) et (x4, y4) en utilisant la forme point-pente de l'équation de ligne, serait y-y3 = -(1/m)(x-x3)

Résolvez ces deux équations linéaires en résolvant une équation linéaire en deux variables et les valeurs de x et y que vous obtenez seraient vos (x4, y4)

J'espère que ça aide.

à votre santé

3
Arnkrishn

Code de fonction Matlab pour le problème suivant

function Pr=getSpPoint(Line,Point)
% getSpPoint(): find Perpendicular on a line segment from a given point
x1=Line(1,1);
y1=Line(1,2);
x2=Line(2,1);
y2=Line(2,1);
x3=Point(1,1);
y3=Point(1,2);

px = x2-x1;
py = y2-y1;
dAB = px*px + py*py;

u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
x = x1 + u * px;
y = y1 + u * py;

Pr=[x,y];

end
2
Rajnikant Sharma

Trouvez les pentes des deux droites, disons que les pentes sont m1 et m2, alors m1 * m2 = -1 est la condition de perpendicularité.

2
Prasoon Saurav

Mathematica a introduit la fonction RegionNearest[] dans la version 10, 2014. Cette fonction pourrait être utilisée pour retourner une réponse à cette question:

{x4,y4} = RegionNearest[Line[{{x1,y1},{x2,y2}}],{x3,y3}]
1
BeanSith

Il s'agit principalement d'un doublon de la réponse d'Arnkrishn. Je voulais juste compléter sa section avec un extrait de code Mathematica complet:

m = (y2 - y1)/(x2 - x1)
eqn1 = y - y3 == -(1/m)*(x - x3)
eqn2 = y - y1 == m*(x - x1)
Solve[eqn1 && eqn2, {x, y}]
1
BeanSith

Par souci d'exhaustivité, voici une solution utilisant des coordonnées homogènes.

  1. Les points homogènes sont:

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

  2. une ligne passant par deux points est leur produit croisé

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

  3. La distance (signée) d'un point à une ligne est leur produit scalaire.

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

  4. Le vecteur de p4 à p3 est d fois le vecteur normal de l_12 divisé par la longueur au carré du vecteur normal.

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

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

Remarque: si vous divisez l_12 par la longueur du vecteur normal

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

la distance d sera la distance euclidienne.

0
Tobias

Il s'agit d'une fonction Matlab vectorisée pour trouver des projections par paire de m points sur n segments de ligne. Ici xp et yp sont m by 1 Vecteurs contenant les coordonnées de m points différents, et x1, y1, x2 Et y2 Sont des vecteurs n by 1 Contenant les coordonnées des points de début et de fin de n segments de ligne différents. Il retourne les matrices m by n, x et y, où x(i, j) et y(i, j) sont les coordonnées de projection de i-ème point sur j- ème ligne.

Le travail réel se fait sur les premières lignes et le reste de la fonction exécute une démo d'auto-test, juste au cas où elle est appelée sans paramètres. C'est relativement rapide, j'ai réussi à trouver des projections de 2k points sur des segments de ligne 2k en moins de 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
0
saastn

Il s'agit d'une implémentation C # de la réponse acceptée. Il utilise également ArcGis pour renvoyer un MapPoint car c'est ce que nous utilisons pour ce projet.

        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);
        }

Merci à Ray car cela a parfaitement fonctionné pour moi. c #arcgis

0
wakeboardfit