Edit important : la solution est donnée en fin de message
Bonjour à tous,
Je travaille sur un projet qui fait usage de formes géométriques et je suis amené à devoir être capable de dire si oui ou non un point donné appartient à un segment.
Appartenance d’un point à un segment
Je considère qu’un point appartient à un segment :
- Si ses coordonnées appartiennent effectivement à ce dernier ;
- Si ses coordonnées sont légèrement¹ distantes de ce segment (il y a donc une notion d’imprécision).
¹ : si un point est à une distance inférieure à 10 pixels du segment, je considère qu’il appartient au segment - sinon, non. Le "10 pixels" désigne une valeur pratique, mais évidemment il faut faire abstraction et considérer une constante maximal_allowed_distance = 10
.
En résumé : vous aurez compris qu’il ne s’agit pas de dire si précisément un point appartient au segment, mais bien s’il appartient "plus ou moins" à celui-ci !
Quelques exemples
(NB : J’affirme, et nous en ferons l’hypothèse donc, qu’aucun point ne peut se superposer.) Si un point est situé sur le segment (ordonnée ET abscisse également à l’un des points de ce segment), il y appartient.
Si un point a la même ordonnée qu’un point du segment, mais une absisse très différente, il n’y appartient pas (+ ou - une distance > maximal_allowed_distance
)
Si un point prolonge ce segment par l’une des extrémités de celui-ci, et qu’il n’est pas trop éloigné de l’extrémité adéquate (toujours en fonciton de maximal_allowed_distance
), il y appartient.
etc.
Solution (qui ne marche pas)
NB important : le segment n’est pas forcément à l’horizontale, à la verticale. Effectivement, il peut très bien être penché.
L’idée est de détecter si un point est !!! LOIN !!! du segment.
Il s’agit de projeter le point-vecteur test
que l’on veut tester (ie. : dont on veut savoir s’il appartient plus ou moins ou non au segment) sur le segment. Puis, partant du constat que tout point du segment est de la forme a + k(b-a)
avec a
: vecteur-point-extrémité et b
: l’autre vecteur-point-extrémité, je travaille sur le coefficient linéaire k
.
Donc si k < 0
, je comparerais à maximal_allowed_distance
la distance : test - a
.
Si k > 1
, ce sera test - b
.
Et si k
est compris entre [0;1]
, ce sera test - p
.
Avec p
: le point projeté sur le segment. p
, comme toute projection de point, est défini par : p = ((x - a).(b - a))/((b - a).(b - a)) (b - a) + a
.
J’ai cependant un gros souci avec cela : c’est que la plupart des points ne semblent pas être considérés comme étant éloignés du segment…
Screenshot illustrant une exécution
Comme vous pouvez le voir, mon code actuel considère qu’un point appartenant à un segment est éloigné de celui-ci… c’est évidemment un très gros problème… :
Pour le segment (1 ; 2 ; 0 ) - (1 ; 0 ; 0 ), le point (1 ; 1 ; 0) est considéré comme éloigné, alors qu’il y appartient…
Sources (ne marchent pas)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | public static List<Point> getOnlyOnSegmentPoints(Point segment_first_point, Point segment_last_point, List<Point> points_to_test, double maximal_allowed_distance) { System.out.println("=== Segment : " + segment_first_point + " - " + segment_last_point); double segment_first_point_x = segment_first_point.getNumber(0); double segment_first_point_y = segment_first_point.getNumber(1); double segment_last_point_x = segment_last_point.getNumber(0); double segment_last_point_y = segment_last_point.getNumber(1); double test_x, test_y; double k_numerator, k_denominator; Point p; List<String> coords_p = new ArrayList<>(); List<Point> returned = new ArrayList<>(points_to_test); for(Point point_to_test : points_to_test) { if(point_to_test == segment_first_point || point_to_test == segment_last_point) { continue; } test_x = point_to_test.getNumber(0); test_y = point_to_test.getNumber(1); // k = ((x - a).(b - a))/((b - a).(b - a)) k_numerator = (test_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x) + (test_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y); k_denominator = (segment_last_point_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x) + (segment_last_point_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y); // p = ((x - a).(b - a))/((b - a).(b - a)) (b - a) + a coords_p.add( "" + ( ((test_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x)) // "((x - a).(b - a))" / (// "((b - a).(b - a))" (segment_last_point_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x) ) * (segment_last_point_x - segment_first_point_x) // "* (b - a)" + segment_first_point_x) // " + a" ); coords_p.add( "" + ( ((test_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y)) // "((x - a).(b - a))" / (// "((b - a).(b - a))" (segment_last_point_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y) ) * (segment_last_point_y - segment_first_point_y) // "* (b - a)" + segment_first_point_y) // " + a" ); p = new Point(coords_p); if(k_numerator/k_denominator < 0 && EuclidianFilters.distanceBetweenTwoPoints(point_to_test, segment_first_point) > maximal_allowed_distance) { returned.remove(point_to_test); System.out.println("------> Point removed : " + point_to_test); } else if(k_numerator/k_denominator >= 0 && k_numerator/k_denominator <= 1 && EuclidianFilters.distanceBetweenTwoPoints(point_to_test, p) > maximal_allowed_distance) { returned.remove(point_to_test); System.out.println("------> Point removed : " + point_to_test); } else if(k_numerator/k_denominator > 1 && EuclidianFilters.distanceBetweenTwoPoints(point_to_test, segment_last_point) > maximal_allowed_distance) { returned.remove(point_to_test); System.out.println("------> Point removed : " + point_to_test); } } return returned; } |
Question
Je ne comprends pas ce qui ne va pas dans mon code, la logique semble pourtant assez correcte… Si vous pouviez m’aider un peu ce serait sympa du coup !
Solution (code qui compile et fait bien ce qu’on lui demande de faire)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | public static List<Point> getOnlyOnSegmentPoints(Point segment_first_extremity, Point segment_last_extremity, List<Point> points_to_test, double maximal_allowed_distance) { double segment_first_point_x = segment_first_extremity.getNumber(0); double segment_first_point_y = segment_first_extremity.getNumber(1); double segment_first_point_z = segment_first_extremity.getNumber(2); double segment_last_point_x = segment_last_extremity.getNumber(0); double segment_last_point_y = segment_last_extremity.getNumber(1); double segment_last_point_z = segment_last_extremity.getNumber(2); double test_x, test_y, test_z; double k_numerator, k_denominator, k; Point p; List<String> coords_p = new ArrayList<>(); List<Point> returned = new ArrayList<>(points_to_test); for(Point point_to_test : points_to_test) { coords_p.clear(); test_x = point_to_test.getNumber(0); test_y = point_to_test.getNumber(1); test_z = point_to_test.getNumber(2); // k = ((x - a).(b - a))/((b - a).(b - a)) k_numerator = (test_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x) + (test_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y) + (test_z - segment_first_point_z) * (segment_last_point_z - segment_first_point_z); k_denominator = (segment_last_point_x - segment_first_point_x) * (segment_last_point_x - segment_first_point_x) + (segment_last_point_y - segment_first_point_y) * (segment_last_point_y - segment_first_point_y) + (segment_last_point_z - segment_first_point_z) * (segment_last_point_z - segment_first_point_z); k = k_numerator/k_denominator; // p = ((x - a).(b - a))/((b - a).(b - a)) (b - a) + a coords_p.add("" + (k * (segment_last_point_x - segment_first_point_x) + (segment_first_point_x))); coords_p.add("" + (k * (segment_last_point_y - segment_first_point_y) + (segment_first_point_y))); coords_p.add("" + (k * (segment_last_point_z - segment_first_point_z) + (segment_first_point_z))); p = new Point(coords_p); if(k < 0.0 && EuclidianFilters.distance3DBetweenTwoPoints(point_to_test, segment_first_extremity) > maximal_allowed_distance) { returned.remove(point_to_test); } if(k >= 0.0 && k <= 1.0 && EuclidianFilters.distance3DBetweenTwoPoints(point_to_test, p) > maximal_allowed_distance) { returned.remove(point_to_test); } if(k > 1.0 && EuclidianFilters.distance3DBetweenTwoPoints(point_to_test, segment_last_extremity) > maximal_allowed_distance) { returned.remove(point_to_test); } } return returned; } |