问题
To find if the point is on a specified line containing two points i do the following checks:
-(Boolean)isOnLine:(Line*) line point:(CGPoint) point{
//If between two dots:
if (((line.first.x <= point.x && point.x <= line.last.x)||(line.first.x >= point.x && point.x >= line.last.x))&&((line.first.y<=point.y && point.y<= line.last.y)||(line.first.y>=point.y && point.y>=line.last.y)) ) {
//Calculate distance:
double dist = (((double)point.y - line.first.y)) / (0.00001+((double)(point.x - line.first.x)))- ((double)(line.last.y - line.first.y)) / (0.00001+((double)(line.last.x - line.first.x)));
NSLog(@"Dist to line: %f", fabs(dist));
return fabs(dist) <0.5;
}else
return NO;
}
}
Somehow, however, the function is not working with vertical lines. My guess is the if clause is invalid in some sense.
回答1:
I haven't read your code carefully so I'm not entirely sure what you're doing, but fyi the easiest way to do this operation is find the distance of one end of the line to the point, find the distance of the other end of the line to the point, and then add those distances and compare to the length of the line.
Something like:
Boolean isOnLine(line, point) {
var dist1 = dist(line.first, point)
var dist2 = dist(line.last, point)
return abs(line.length - (dist1 + dist2)) < .5
}
For the dist() function I'm guessing CoreGraphics provides that, but if not it's just basic trigonometry.
回答2:
Here's my implementation of jhockings' solution
return abs([line length] -
(sqrt((line.first.x - point.x)*(line.first.x - point.x)
+ (line.first.y - point.y)*(line.first.y - point.y))
+ sqrt((line.last.x - point.x)*(line.last.x - point.x)
+ (line.last.y - point.y)*(line.last.y - point.y)))) < .5;
回答3:
Another(my) implementation of @jhocking solution:
- (BOOL)isPoint:(CGPoint)origin nearToLineSegmentPointA:(CGPoint)pointA pointB:(CGPoint)pointB withMarginOfError:(CGFloat)marginOfError {
CGFloat distanceAP = [self distanceBetweenPointA:origin pointB:pointA];
CGFloat distanceBP = [self distanceBetweenPointA:origin pointB:pointB];
CGFloat distanceAB = [self distanceBetweenPointA:pointA pointB:pointB];
if (fabsf(distanceAB - distanceAP - distanceBP) < marginOfError) {
return YES;
} else {
return NO;
}
}
- (CGFloat)distanceBetweenPointA:(CGPoint)pointA pointB:(CGPoint)pointB {
return sqrtf(powf((pointA.x - pointB.x), 2.f) + powf((pointA.y - pointB.y), 2.f));
}
回答4:
The explanation of why it is not working is you are comparing the tangent of the angles of two triangles - you are not calculating distance at all despite the comments and variable name.
Now as the angle approaches 90 deg the magnitude of the tangent increases rapidly until it reaches infinity at 90 degrees itself. At 90 degrees the difference of the x coordinates is zero and you would end up with a divide-by-zero error where it not for adding in the 0.00001
constant to avoid it. While the relative difference between two tangents near 90 might be small the absolute difference can be huge even for very close angles, so your < 0.5
test fails.
So you need another approach. One is to calculate the distances from the point to the two end points, and the length of the line itself, and compare - if the sum of the two distances from the point is larger than the length of the line the three points form a triangle, if it isn't they are co-linear. (And if the sum is less you've slipped into an alternate dimension...).
You can calculate the length of the lines using Pythagorus: sqrt((x1 - x2)^2 + (y1 - y2)^2).
来源:https://stackoverflow.com/questions/12922789/finding-point-is-close-to-line-and-between-the-endpoints-of-the-line