web-dev-qa-db-fra.com

Calcul des intersections entre les segments de ligne

Il y a beaucoup de questions sur les intersections entre les segments de ligne ici à stackowerflow et en voici une de plus! Désolé, mais j'ai besoin d'aide pour comprendre comment calculer les intersections. J'ai lu plusieurs des questions ici et regardé plusieurs exemples sur d'autres sites Web, mais je suis toujours confus et je ne comprends pas! Je n'aime pas copier et coller du code sans que les choses fonctionnent.

Jusqu'à présent, je sais que je vais comparer les points de chaque segment de ligne comme Ax, Ay, Bx, By, Cx, Cy, Dx, Dy. Quelqu'un pourrait-il m'expliquer ce que je vais calculer, quel serait le résultat du calcul s'il y a une intersection?

C'est l'un des exemples de code que j'ai vu. Je suppose que je n'ai pas besoin du point d'intersection, juste pour savoir si les lignes se croisent ou non.

   public static Point lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  if (denom == 0.0) { // Lines are parallel.
     return null;
  }
  double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3))/denom;
  double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3))/denom;
    if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) {
        // Get the intersection point.
        return new Point((int) (x1 + ua*(x2 - x1)), (int) (y1 + ua*(y2 - y1)));
    }

  return null;
  }

Dois-je également calculer une valeur médiane comme dans cet exemple de code?

For lines through points (x0,y0) and (x1,y1), let xm = (x0+x1)/2, ym = (y0+y1)/2 (median of line segment). 
Then a = (y1-y0) and b = (x0-x1). 
If you evaluate c = a(x-xm)+b(y-ym), c=0 for (x,y) on the line, and the sign(c) tells you which side a point is on
18
3D-kreativ

Le premier morceau de code que vous montrez est basé sur un produit vectoriel croisé, qui a été expliqué ici Comment détectez-vous l'intersection de deux segments de ligne? dans les moindres détails.

OMI, un moyen plus facile de le comprendre est de résoudre un système d'équations. Regardez d'abord les lignes en général, puis coupez-en des segments. Ci-dessous, j'utilise des notations pour des segments donnés ((x1, x2), (y1, y2)) Et ((x3, x4), (y3, y4)).

  1. Vérifiez si l'une des lignes est verticale (x1 == x2 Ou x3 == x4).

    une. Si les deux sont verticaux et x1 != x3, Alors aucune intersection.

    b. Si les deux sont verticaux et x1 == x3, Vérifiez si (y1, y2) Et (y3, y4) Se chevauchent.

    c. Si une seule est verticale (disons la première), alors construisez l'équation de la deuxième ligne (comme indiqué ci-dessous), trouvez le point où deux lignes se croisent (en remplaçant x1 Dans l'équation de la deuxième ligne) et vérifiez si ce point est dans les deux segments (similaire à l'étape 5).

    ré. Sinon, continuez.

  2. Utilisez les coordonnées des points pour construire des équations de lignes sous la forme y = a*x + b (Comme ici ).

    a1 = (y2-y1)/(x2-x1)
    b1 = y1 - a1*x1 
    a2 = (y4-y3)/(x4-x3)
    b2 = y3 - a2*x3
    
  3. Vérifiez si les lignes sont parallèles (même pente a). Si oui, vérifiez s'ils ont la même interception b. Si oui, vérifiez si les segments 1D (x1, x2) Et (x3, x4) Se chevauchent. Si oui, vos segments se chevauchent. Le cas où les lignes sont parallèles peut être ambigu. S'ils se chevauchent, vous pouvez le considérer comme une intersection (il peut même s'agir d'un point si leurs extrémités se touchent), ou non. Remarque: si vous travaillez avec des flotteurs, ce serait un peu plus délicat, je pense que vous voudriez ignorer cela. Dans le cas où vous n'avez que des entiers vérifiant si a1 = a2 Est équivalent à:

    if((y2-y1)*(x4-x3) == (x2-x1)*(y4-y3))
    
  4. Si les lignes ne sont pas parallèles. Le point d'intersection équivaut à une solution d'un système d'équations représentant les deux droites. En réalité, y = a1*x + b1 Et y = a2*x + b2 Qui se croisent signifient essentiellement que ces deux équations sont valables. Résolvez ce système en égalisant les deux côtés droits et cela vous donnera le point d'intersection. En fait, vous n'avez besoin que de la coordonnée x de l'intersection (dessinez-la et vous comprendrez pourquoi):

    x0 = -(b1-b2)/(a1-a2)
    
  5. La dernière étape consiste à vérifier si le point d'intersection x0 Se trouve dans les deux segments. Autrement dit, min(x1, x2) < x0 < max(x1, x2) et min(x3, x4) < x0 < max(x3, x4). Si oui, vos lignes se croisent!

27
sashkello

Je réponds vraiment à @ sashkello et la trouve plus intuitive et plus facile à expliquer que l'implémentation vectorielle. En particulier lors de l'ajout de ce type de code à une base de code.

Je mettrai cela en garde en disant que vous pouvez utiliser la méthode d'assistance Line2D de Java.

Line2D.linesIntersect(double x1, double y1,
                      double x2, double y2,
                      double x3, double y3,
                      double x4, double y4)

Le seul inconvénient est qu'il vous oblige à considérer que les segments se croisent même lorsqu'ils se touchent (sur les deux extrémités et la ligne elle-même).

Par exemple, les lignes ci-dessous sont considérées comme intersectées car elles partagent le point (1,1).

L1 = [(0,0),(1,1)]
L2 = [(1,1),(2,3)]

Si c'est un problème, vous pouvez ajouter 4 vérifications pour voir si les points sont égaux.

Si vous avez des inquiétudes concernant un point tombant sur un point de la ligne, cela demande un peu plus de travail et vous feriez peut-être mieux de l'implémenter vous-même afin de pouvoir effectuer les vérifications dans l'algorithme lui-même.

Si aucun de ces cas Edge ne vous affecte, alors Line2D.linesIntersectest pour toi. :)

4
Kenny Cason
public void fixData()
{
    slope = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
    yInt = p1.getY() - slope * p1.getX();
    xInt = (-yInt) / slope;
}
1
user7127290