|
|
|
@ -8,7 +8,7 @@ |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_ops.c,v 1.95 2007/02/27 23:48:08 tgl Exp $ |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_ops.c,v 1.96 2007/03/05 23:29:14 momjian Exp $ |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
@ -5063,128 +5063,126 @@ poly_circle(PG_FUNCTION_ARGS) |
|
|
|
|
***********************************************************************/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test to see if the point is inside the polygon. |
|
|
|
|
* Code adapted from integer-based routines in WN: A Server for the HTTP |
|
|
|
|
* Test to see if the point is inside the polygon, returns 1/0, or 2 if |
|
|
|
|
* the point is on the polygon. |
|
|
|
|
* Code adapted but not copied from integer-based routines in WN: A |
|
|
|
|
* Server for the HTTP |
|
|
|
|
* version 1.15.1, file wn/image.c |
|
|
|
|
* GPL Copyright (C) 1995 by John Franks |
|
|
|
|
* http://hopf.math.northwestern.edu/index.html
|
|
|
|
|
* Description of algorithm: http://www.linuxjournal.com/article/2197
|
|
|
|
|
* http://www.linuxjournal.com/article/2029
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define HIT_IT INT_MAX |
|
|
|
|
#define POINT_ON_POLYGON INT_MAX |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
point_inside(Point *p, int npts, Point *plist) |
|
|
|
|
{ |
|
|
|
|
double x0, |
|
|
|
|
y0; |
|
|
|
|
double px, |
|
|
|
|
py; |
|
|
|
|
int i; |
|
|
|
|
double prev_x, |
|
|
|
|
prev_y; |
|
|
|
|
int i = 0; |
|
|
|
|
double x, |
|
|
|
|
y; |
|
|
|
|
int cross, |
|
|
|
|
crossnum; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We calculate crossnum, which is twice the crossing number of a |
|
|
|
|
* ray from the origin parallel to the positive X axis. |
|
|
|
|
* A coordinate change is made to move the test point to the origin. |
|
|
|
|
* Then the function lseg_crossing() is called to calculate the crossnum of |
|
|
|
|
* one segment of the translated polygon with the ray which is the |
|
|
|
|
* positive X-axis. |
|
|
|
|
*/ |
|
|
|
|
int cross, total_cross = 0; |
|
|
|
|
|
|
|
|
|
crossnum = 0; |
|
|
|
|
i = 0; |
|
|
|
|
if (npts <= 0) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* compute first polygon point relative to single point */ |
|
|
|
|
x0 = plist[0].x - p->x; |
|
|
|
|
y0 = plist[0].y - p->y; |
|
|
|
|
|
|
|
|
|
px = x0; |
|
|
|
|
py = y0; |
|
|
|
|
prev_x = x0; |
|
|
|
|
prev_y = y0; |
|
|
|
|
/* loop over polygon points and aggregate total_cross */ |
|
|
|
|
for (i = 1; i < npts; i++) |
|
|
|
|
{ |
|
|
|
|
/* compute next polygon point relative to single point */ |
|
|
|
|
x = plist[i].x - p->x; |
|
|
|
|
y = plist[i].y - p->y; |
|
|
|
|
|
|
|
|
|
if ((cross = lseg_crossing(x, y, px, py)) == HIT_IT) |
|
|
|
|
/* compute previous to current point crossing */ |
|
|
|
|
if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON) |
|
|
|
|
return 2; |
|
|
|
|
crossnum += cross; |
|
|
|
|
|
|
|
|
|
px = x; |
|
|
|
|
py = y; |
|
|
|
|
total_cross += cross; |
|
|
|
|
|
|
|
|
|
prev_x = x; |
|
|
|
|
prev_y = y; |
|
|
|
|
} |
|
|
|
|
if ((cross = lseg_crossing(x0, y0, px, py)) == HIT_IT) |
|
|
|
|
|
|
|
|
|
/* now do the first point */ |
|
|
|
|
if ((cross = lseg_crossing(x0, y0, prev_x, prev_y)) == POINT_ON_POLYGON) |
|
|
|
|
return 2; |
|
|
|
|
crossnum += cross; |
|
|
|
|
if (crossnum != 0) |
|
|
|
|
total_cross += cross; |
|
|
|
|
|
|
|
|
|
if (total_cross != 0) |
|
|
|
|
return 1; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* lseg_crossing()
|
|
|
|
|
* The function lseg_crossing() returns +2, or -2 if the segment from (x,y) |
|
|
|
|
* to previous (x,y) crosses the positive X-axis positively or negatively. |
|
|
|
|
* It returns +1 or -1 if one endpoint is on this ray, or 0 if both are. |
|
|
|
|
* It returns 0 if the ray and the segment don't intersect. |
|
|
|
|
* It returns HIT_IT if the segment contains (0,0) |
|
|
|
|
* Returns +/-2 if line segment crosses the positive X-axis in a +/- direction. |
|
|
|
|
* Returns +/-1 if one point is on the positive X-axis. |
|
|
|
|
* Returns 0 if both points are on the positive X-axis, or there is no crossing. |
|
|
|
|
* Returns POINT_ON_POLYGON if the segment contains (0,0). |
|
|
|
|
* Wow, that is one confusing API, but it is used above, and when summed, |
|
|
|
|
* can tell is if a point is in a polygon. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
lseg_crossing(double x, double y, double px, double py) |
|
|
|
|
lseg_crossing(double x, double y, double prev_x, double prev_y) |
|
|
|
|
{ |
|
|
|
|
double z; |
|
|
|
|
int sgn; |
|
|
|
|
|
|
|
|
|
/* If (px,py) = (0,0) and not first call we have already sent HIT_IT */ |
|
|
|
|
int y_sign; |
|
|
|
|
|
|
|
|
|
if (FPzero(y)) |
|
|
|
|
{ |
|
|
|
|
if (FPzero(x)) |
|
|
|
|
{ |
|
|
|
|
return HIT_IT; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
{ /* y == 0, on X axis */ |
|
|
|
|
if (FPzero(x)) /* (x,y) is (0,0)? */ |
|
|
|
|
return POINT_ON_POLYGON; |
|
|
|
|
else if (FPgt(x, 0)) |
|
|
|
|
{ |
|
|
|
|
if (FPzero(py)) |
|
|
|
|
return FPgt(px, 0) ? 0 : HIT_IT; |
|
|
|
|
return FPlt(py, 0) ? 1 : -1; |
|
|
|
|
|
|
|
|
|
{ /* x > 0 */ |
|
|
|
|
if (FPzero(prev_y)) /* y and prev_y are zero */ |
|
|
|
|
/* prev_x > 0? */ |
|
|
|
|
return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON; |
|
|
|
|
return FPlt(prev_y, 0) ? 1 : -1; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ /* x < 0 */ |
|
|
|
|
if (FPzero(py)) |
|
|
|
|
return FPlt(px, 0) ? 0 : HIT_IT; |
|
|
|
|
{ /* x < 0, x not on positive X axis */ |
|
|
|
|
if (FPzero(prev_y)) |
|
|
|
|
/* prev_x < 0? */ |
|
|
|
|
return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Now we know y != 0; set sgn to sign of y */ |
|
|
|
|
sgn = (FPgt(y, 0) ? 1 : -1); |
|
|
|
|
if (FPzero(py)) |
|
|
|
|
return FPlt(px, 0) ? 0 : sgn; |
|
|
|
|
|
|
|
|
|
if (FPgt((sgn * py), 0)) |
|
|
|
|
{ /* y and py have same sign */ |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ /* y and py have opposite signs */ |
|
|
|
|
if (FPge(x, 0) && FPgt(px, 0)) |
|
|
|
|
return 2 * sgn; |
|
|
|
|
if (FPlt(x, 0) && FPle(px, 0)) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
z = (x - px) * y - (y - py) * x; |
|
|
|
|
if (FPzero(z)) |
|
|
|
|
return HIT_IT; |
|
|
|
|
return FPgt((sgn * z), 0) ? 0 : 2 * sgn; |
|
|
|
|
{ /* y != 0 */ |
|
|
|
|
/* compute y crossing direction from previous point */ |
|
|
|
|
y_sign = FPgt(y, 0) ? 1 : -1; |
|
|
|
|
|
|
|
|
|
if (FPzero(prev_y)) |
|
|
|
|
/* previous point was on X axis, so new point is either off or on */ |
|
|
|
|
return FPlt(prev_x, 0) ? 0 : y_sign; |
|
|
|
|
else if (FPgt(y_sign * prev_y, 0)) |
|
|
|
|
/* both above or below X axis */ |
|
|
|
|
return 0; /* same sign */ |
|
|
|
|
else |
|
|
|
|
{ /* y and prev_y cross X-axis */ |
|
|
|
|
if (FPge(x, 0) && FPgt(prev_x, 0)) |
|
|
|
|
/* both non-negative so cross positive X-axis */ |
|
|
|
|
return 2 * y_sign; |
|
|
|
|
if (FPlt(x, 0) && FPle(prev_x, 0)) |
|
|
|
|
/* both non-positive so do not cross positive X-axis */ |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* x and y cross axises, see URL above point_inside() */ |
|
|
|
|
z = (x - prev_x) * y - (y - prev_y) * x; |
|
|
|
|
if (FPzero(z)) |
|
|
|
|
return POINT_ON_POLYGON; |
|
|
|
|
return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|