J'ai tracé une ligne entre deux points A (x, y) --- B (x, y) Maintenant, j'ai un troisième point C (x, y). Je veux savoir que si C se situe sur la ligne tracée entre A et B. .__ Je veux le faire en langage Java. J'ai trouvé quelques réponses similaires à ceci. Mais tous ont des problèmes et personne n'est parfait.
if (distance(A, C) + distance(B, C) == distance(A, B))
return true; // C is on the line.
return false; // C is not on the line.
ou juste:
return distance(A, C) + distance(B, C) == distance(A, B);
La façon dont cela fonctionne est plutôt simple. Si C se trouve sur la ligne AB
, vous obtiendrez le scénario suivant:
A-C------B
et, peu importe où il se trouve sur cette ligne, dist(AC) + dist(CB) == dist(AB)
. Pour tout autre cas, vous avez un triangle de description quelconque et 'dist (AC) + dist (CB)> dist (AB)':
A-----B
\ /
\ /
C
En fait, cela fonctionne même si C se trouve sur la ligne extrapolée:
C---A-------B
à condition que les distances ne soient pas signées. La distance dist(AB)
peut être calculée comme suit:
___________________________
/ 2 2
V (A.x - B.x) + (A.y - B.y)
N'oubliez pas les limites inhérentes (précision limitée) des opérations en virgule flottante. Il est possible que vous deviez opter pour un test "assez proche" (disons, moins d'une partie par million d'erreurs) pour garantir le fonctionnement correct de l'égalité.
ATTENTION! Math seulement!
Vous pouvez essayer cette formule. Mettez vos coordonnées A(x1, y1)
et B(x2, y2)
dans la formule, puis vous obtiendrez quelque chose comme
y = k*x + b; // k and b - numbers
Ensuite, tout point qui satisfera cette équation se trouvera sur votre droite. Pour vérifier que C(x, y)
est compris entre A(x1, y1)
et B(x2, y2)
, vérifiez ceci: (x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2)
.
Exemple
A(2,3) B(6,5)
L'équation de ligne:
(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;
Vérifions si C(4,4)
se trouve sur cette ligne.
2<4<6 & 3<4<5 // C between A and B
Maintenant, mettez les coordonnées C dans l'équation:
4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB
PS: Comme @paxdiablo l'a écrit, vous devez vérifier si la ligne est horizontale ou verticale avant de calculer. Vérifiez simplement
y1 == y2 || x1 == x2
Je crois que le plus simple est
// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
// if AC is horizontal
if (A.x == C.x) return B.x == C.x;
// if AC is vertical.
if (A.y == C.y) return B.y == C.y;
// match the gradients
return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}
Vous pouvez calculer le gradient en prenant la différence entre les valeurs x divisée par la différence entre les valeurs y.
Remarque: il existe un test différent pour voir si C apparaît sur la ligne entre A et B si vous le dessinez sur un écran. Les mathématiques supposent que A, B, C sont des points infiniment petits. En fait très petite à l'erreur de représentation.
Les réponses ci-dessus sont inutilement compliquées. Le plus simple est comme suit.
si (x-x1)/(x2-x1) = (y-y1)/(y2-y1) = alpha (une constante), alors le point C (x, y) sera situé entre les points 1 et 2 .
Si alpha <0.0, alors C est extérieur au point 1.
J'espère que cette réponse aide.
Un moyen facile de le faire serait de vérifier l’angle formé par les 3 points. Si l'angle ACB est égal à 180 degrés (ou proche de celui-ci, selon le degré de précision souhaité), le point C se situe entre A et B.
Je pense que toutes les méthodes ici présentent un piège, en ce sens qu'elles ne traitent pas les erreurs d'arrondi aussi rigoureusement qu'elles le pourraient. Fondamentalement, les méthodes décrites vous indiqueront si votre point est assez proche de la ligne en utilisant un algorithme simple et qu’il sera plus ou moins précis.
Pourquoi la précision est importante? Parce que c’est le problème même présenté par op. Pour un programme informatique, il n’existe pas de point sur une ligne, il n’ya qu’un point dans un epsilon d’une ligne et ce qu’il est nécessaire de documenter.
Illustrons le problème. En utilisant l'algorithme de comparaison de distance:
Supposons qu'un segment passe de (0, 0) à (0, 2000), nous utilisons des flottants dans notre application (qui ont environ 7 décimales de précision) et nous testons si un point sur (1E-6, 1000) est sur la ligne ou pas.
La distance entre chaque extrémité du segment et le point est 1000,0000000005 ou 1000 + 5E-10, et la différence avec l’ajout de la distance au point est donc d’environ 1E-9. Mais aucune de ces valeurs ne peut être stockée sur un float avec suffisamment de précision et la méthode retournera true
.
Si nous utilisons une méthode plus précise, telle que le calcul de la distance jusqu'au point le plus proche de la ligne, elle renvoie une valeur qu'un float a une précision suffisante pour stocker et nous pouvons renvoyer false en fonction de la valeur epsilon acceptable.
J'ai utilisé des flottants dans l'exemple mais la même chose s'applique à tout type de virgule flottante tel que double.
Une solution consiste à utiliser BigDecimal et la méthode de votre choix si les performances et la mémoire ne sont pas un problème.
Une méthode plus précise que la comparaison des distances pour les points flottants et, plus important encore, la précision systématiquement, bien qu'à un coût de calcul plus élevé, consiste à calculer la distance jusqu'au point le plus proche de la ligne.
Distance la plus courte entre un point et un segment de ligne
On dirait que je coupe les cheveux en quatre mais je devais régler ce problème auparavant. C'est un problème lors de l'enchaînement d'opérations géométriques. Si vous ne contrôlez pas le type de perte de précission que vous traitez, vous rencontrerez éventuellement des bogues difficiles qui vous obligeront à raisonner de manière rigoureuse sur le code afin de les corriger.