I wrote an algorithm inspired by some answers on StackOverflow : it detects points that are quite far from an infinite line. This algorithm is shown below.
However, I don't work with infinite lines in my project, but with segments. And the problem, according to me, is that if a point has the same ordinate than a segment's extremity, it will not be considered as "far from the segment".
How could I modify this algorithm to make it working with a segment, and not an infinite line please ?
List<Cupple> returned = new ArrayList<>(points_to_test);
for(Cupple c : points_to_test) {
/*if(c == segment_first_point || c == segment_last_point) {
continue;
}*/
if(Math.abs(Math.abs(
(segment_last_point.getNumber(0) - segment_first_point.getNumber(0))
*
(segment_first_point.getNumber(1) - c.getNumber(1))
-
(segment_first_point.getNumber(0) - c.getNumber(0))
*
(segment_last_point.getNumber(1) - segment_first_point.getNumber(1))
)
/
Math.sqrt(
Math.pow((segment_last_point.getNumber(0) - segment_first_point.getNumber(0)), 2)
+
Math.pow((segment_last_point.getNumber(1) - segment_first_point.getNumber(1)), 2)
)
) > maximal_allowed_distance) {
returned.remove(c);
}
}
return returned;
To be sure you understand :
returned
is the list with points that are on the segment, or near the segment (and the "imprecision" / maximal distance that determine if a point is out of the segment is the variable :maximal_allowed_distance
)points_to_test
are ALL the points that are present in my graph : the both of my segment + the points that are really on the segment + the points that are almost on the segment (<=maximal_allowed_distance
) + the points that are far from the segment (>maximal_allowed_distance
). The idea of my little algorithm is that I remove all the latter.segment_[first|last]_point
are the two segment's extremitiesc
is the current point ofpoints_to_test
and I want to know if it is far from the segment or in (according to themaximal_allowed_distance
)getNumber(0)
returns the X coordinate of the point,getNumber(1)
returns the Y one.
Important edit : implementation of the muzzlor's solution
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))"
/
(0.00001+ // "((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))"
/
(0.00001+ // "((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 x-a : " + 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 x-p : " + 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 x-b : " + point_to_test);
}
}
return returned;
}
Screenshot illustrating the execution
As you can see, for the Segment : (1 ; 2 ; 0 ) - (1 ; 0 ; 0 ), the point (1 ; 1 ; 0) is considered as too far from it. However, it must be considered as part of this segment.