web-dev-qa-db-fra.com

Comment vérifier si un point se trouve sur une ligne entre 2 autres points

Comment pourrais-je écrire cette fonction? Des exemples appréciés

function isPointBetweenPoints(currPoint, point1, point2):Boolean {

    var currX = currPoint.x;
    var currY = currPoint.y;

    var p1X = point1.x;
    var p1y = point1.y;

    var p2X = point2.x;
    var p2y = point2.y;

    //here I'm stuck
}
14
nuway

En supposant que point1 et point2 soient différents, commencez par vérifier si le point se trouve sur la ligne. Pour cela, vous avez simplement besoin d'un "produit croisé" de vecteurs point1 -> currPoint et point1 -> point2.

dxc = currPoint.x - point1.x;
dyc = currPoint.y - point1.y;

dxl = point2.x - point1.x;
dyl = point2.y - point1.y;

cross = dxc * dyl - dyc * dxl;

Votre point se trouve sur la ligne si et seulement si cross est égal à zéro.

if (cross != 0)
  return false;

Maintenant que vous savez que le point se trouve sur la ligne, il est temps de vérifier s'il se trouve entre les points d'origine. Cela peut être facilement fait en comparant les coordonnées x, si la ligne est "plus horizontale que verticale", ou les coordonnées y sinon

if (abs(dxl) >= abs(dyl))
  return dxl > 0 ? 
    point1.x <= currPoint.x && currPoint.x <= point2.x :
    point2.x <= currPoint.x && currPoint.x <= point1.x;
else
  return dyl > 0 ? 
    point1.y <= currPoint.y && currPoint.y <= point2.y :
    point2.y <= currPoint.y && currPoint.y <= point1.y;

Notez que l'algorithme ci-dessus est entièrement intégré si les données d'entrée sont intégrales, c'est-à-dire qu'il ne nécessite aucun calcul en virgule flottante pour l'entrée entière. Faites attention au risque de débordement lors du calcul de cross cependant.

P.S. Cet algorithme est absolument précis, ce qui signifie qu'il rejettera les points situés très près de la ligne mais pas précisément sur la ligne. Parfois, ce n'est pas ce qui est nécessaire. Mais c'est une autre histoire.

40
AnT
Distance(point1,currPoint)+Distance(currPoint,point2)==Distance(point1,point2)

Mais faites attention si vous avez des valeurs en virgule flottante, les choses sont différentes pour elles ...

20
maxim1000

Vous voulez vérifier si la pente de point1 à currPoint est la même que la pente de currPoint à point2, donc:

m1 = (currY - p1Y) / (currX - p1X);
m2 = (p2Y - currY) / (p2X - currX);

Vous voulez également vérifier si currPoint est à l'intérieur de la boîte créée par les deux autres, alors:

return (m1 == m2) && (p1Y <= currY && currY <= p2Y) && (p1X <= currX && currX <= p2X);

Edit: Ce n'est pas une très bonne méthode; Regardez la solution de maxim1000 pour une manière beaucoup plus correcte.

4
Christian Mann

Ceci est indépendant de Javascript. Essayez l’algorithme suivant, avec les points p1 = point1 et p2 = point2, et votre troisième point étant p3 = currPoint:

v1 = p2 - p1
v2 = p3 - p1
v3 = p3 - p2
if (dot(v2,v1)>0 and dot(v3,v1)<0) return between
else return not between

Si vous voulez être sûr que c'est sur le segment de ligne entre p1 et p2 également:

v1 = normalize(p2 - p1)
v2 = normalize(p3 - p1)
v3 = p3 - p2
if (fabs(dot(v2,v1)-1.0)<EPS and dot(v3,v1)<0) return between
else return not between
3
imallett

Illustration graphique

Si vous voulez savoir si le point se situe entre deux autres points ou non, vous devez rechercher des vecteurs vers ces points et calculer le produit scalaire de ces vecteurs.

Supposons que vous avez deux points A et B. Et le point P que vous souhaitez tester. D'abord, vous calculez les vecteurs PA, PB

  • PA = A - P
  • PB = B - P

Ensuite, vous calculez le produit scalaire de ces vecteurs DotProduct (PA, PB). Pour simplifier, supposons que les calculs soient faits en 2D.

test_dot_product = DotProduct(PA, PB) = PA.x * PB.x + PA.y * PB.y

Ainsi, lorsque le produit scalaire est calculé, nous devons vérifier si sa valeur est inférieure ou égale à 0. Si tel est le cas, les vecteurs PA et PB orientés dans des directions différentes et le point P se situent quelque part entre A et B. Sinon, les vecteurs orientés dans la même direction et le point P est quelque part en dehors de la plage AB.

if(test_dot_product <= 0.0f){
    Point P IS between A and B
}
else{
    Point P IS NOT between A and B
}

Voici un exemple de code. C'est le code du système de diffusion de rayons physique en 2D de mon moteur. Lorsque je trouve le point d'inflexion du rayon et de l'Edge, je dois vérifier s'il se situe entre les points minimum et maximum de Edge ...

    ....
    v2 HitPP1 = Edge->Min - HitData->HitPoint;
    v2 HitPP2 = Edge->Max - HitData->HitPoint;

    //NOTE(dima): If hit point is between Edge min and max points
    if (Dot(HitPP1, HitPP2) <= 0.0f) {
        HitData->HitHappened = 1;
        AtLeastOneHitHappened = 1;
    }
    .....

Désolé pour mon anglais

0
Gorevoy Dima

Je vais utiliser l'approche de triangle:  Triangle approach

Premièrement, je vérifierai la zone. Si la zone est proche de 0, le point se trouve sur la ligne.

Mais pensons au cas où la longueur de AC est si grande, alors que la Zone augmente loin de 0, mais visuellement, nous voyons encore que B est sur AC: que lorsque nous devons vérifier la hauteur du triangle.

Pour ce faire, nous devons nous rappeler la formule apprise en première année: Area = Base * Height / 2

Voici le code:

    bool Is3PointOn1Line(IList<Vector2> arrVert, int idx1, int idx2, int idx3)
    {
        //check if the area of the ABC triangle is 0:
        float fArea = arrVert[idx1].x * (arrVert[idx2].y - arrVert[idx3].y) +
            arrVert[idx2].x * (arrVert[idx3].y - arrVert[idx1].y) +
            arrVert[idx3].x * (arrVert[idx1].y - arrVert[idx2].y);
        fArea = Mathf.Abs(fArea);
        if (fArea < SS.EPSILON)
        {
            //Area is zero then it's the line
            return true;
        }
        else
        {
            //Check the height, in case the triangle has long base
            float fBase = Vector2.Distance(arrVert[idx1], arrVert[idx3]);
            float height = 2.0f * fArea / fBase;
            return height < SS.EPSILON;
        }
    }

Usage:

Vector2[] arrVert = new Vector2[3];

arrVert[0] = //...
arrVert[1] = //...
arrVert[2] = //...

if(Is3PointOn1Line(arrVert, 0, 1, 2))
{
    //Ta-da, they're on same line
}

PS: SS.EPSILON = 0.01f et j'utilise une fonction de Unity (par exemple: Vector2.Distance), mais vous avez eu l’idée.

0
123iamking