Skip to content

Instantly share code, notes, and snippets.

@instcode
Created October 14, 2011 10:43
Show Gist options
  • Save instcode/1286793 to your computer and use it in GitHub Desktop.
Save instcode/1286793 to your computer and use it in GitHub Desktop.
Test if a point is "near" a segment specified by 2 points
// See: www.exaflop.org/docs/cgafaq/cga1.html
// Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
// Let P be the point of perpendicular projection of C on AB. The parameter
// r, which indicates P's position along AB, is computed by the dot product
// of AC and AB divided by the square of the length of AB:
// AC dot AB
// r = ---------
// ||AB||^2
//
// r has the following meaning:
//
// r=0 P = A
// r=1 P = B
// r<0 P is on the backward extension of AB
// r>1 P is on the forward extension of AB
// 0<r<1 P is interior to AB
//
// L = sqrt((Bx-Ax)^2 + (By-Ay)^2)
//
// (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
// => r = --------------------------------
// L^2
//
// (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
// Let s = -----------------------------
// L^2
// => d = |s * L|
public class RoadSegment {
private double Ax, Ay;
private double Bx, By;
private double ABx, ABy;
private double sqAB;
private double length;
private double width;
public RoadSegment(double lon1, double lat1, double lon2, double lat2, double roadWidth) {
Ax = lat1; Ay = lon1;
Bx = lat2; By = lon2;
ABx = Bx - Ax;
ABy = By - Ay;
sqAB = ABx * ABx + ABy * ABy;
length = Math.sqrt(sqAB);
width = roadWidth;
}
public boolean isNear(double lon, double lat) {
double Cx = lat, Cy = lon;
double ACx = Cx - Ax, ACy = Cy - Ay;
double r = (ACx * ABx + ACy * ABy) / sqAB;
if (r < 0 || r > 1) {
return false;
}
double d = Math.abs((-ACy * ABx + ACx * ABy) / length);
return (d < width);
}
public double getLength() {
return length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment