There are those macros defined for the built-in geometric types: > #define EPSILON 1.0E-06
> #define FPzero(A) (fabs(A) <= EPSILON) > #define FPeq(A,B) (fabs((A) - (B)) <= EPSILON) > #define FPne(A,B) (fabs((A) - (B)) > EPSILON) > #define FPlt(A,B) ((B) - (A) > EPSILON) > #define FPle(A,B) ((A) - (B) <= EPSILON) > #define FPgt(A,B) ((A) - (B) > EPSILON) > #define FPge(A,B) ((B) - (A) <= EPSILON) with this warning: > * XXX These routines were not written by a numerical analyst. Most of the geometric operators use those macros for comparison, but those do not: * polygon << polygon * polygon &< polygon * polygon &> polygon * polygon >> polygon * polygon <<| polygon * polygon &<| polygon * polygon |&> polygon * polygon |>> polygon * box @> point * point <@ box * lseg <@ box * circle @> point * point <@ circle This is really a bug that needs to be fixed one way or another. I think that it is better to fix it by removing the macros all together. I am not sure how useful they are in practice. I haven't seen anyone complaining about the above operators not using the macros. Though, people often complain about the ones using the macros and the problems caused by them. The hackers evidently don't like the macros, either. That should be why they are not used on the new operators. What annoys me most about this situation is the inconsistency blocks demonstrating our indexes. Because of this, we had to rip out point type support from BRIN inclusion operator class which could be useful to PostGIS. Fixing it has been discussed many times before [1][2][3][4] with no result. Here is my plan to fix the situation covering the problems around it: 1) Reimplement some operators to avoid divisions The attached patch does it on some of the line operators. 2) Use exact comparison on everywhere except the operators fuzzy comparison is certainly required The attach patch changes all operators except some "lseg" operators. "lseg" stores two points on a line. Most of the operations done on it are lossy. I don't see a problem treating them differently, those operators are very unlikely to be index supported. 3) Check numbers for underflow and overflow I am thinking to use CHECKFLOATVAL on utils/adt/float.c, but it is not exposed outside at the moment. Would it be okay to create a new header file utils/float.h to increase code sharing between float and geometric types? 4) Implement relative fuzzy comparison for the remaining operators It is better to completely get rid of those macros while we are on it. I think we can get away by implementing just a single function for fuzzy equality, not for other comparisons. I am inclined to put it to utils/adt/float.c. Is this a good idea? Tom Lane commented on the function posted to the list [1] on 2002: > Not like that. Perhaps use a fraction of the absolute value of the > one with larger absolute value. As-is it's hard to tell how FLT_EPSILON > is measured. I cannot image how the function would look like. I would appreciate any guidance. 5) Implement default hash operator class for all geometric types This would solve most complained problem of those types allowing them to used with DISTINCT and GROUP BY. 6) Implement default btree operator class at least for the point type This would let the point type to be used with ORDER BY. It is relatively straight forward to implement it for the point type. Is it a good idea to somehow implement it for other types? 7) Add GiST index support for missing cross type operators Currently only contained by operators are supported by an out-of-range strategy number. I think we can make the operator classes much nicer by allowing really cross type operator families. Comments? [1] https://www.postgresql.org/message-id/flat/d90a5a6c612a39408103e6ecdd77b8290fd...@voyager.corporate.connx.com [2] https://www.postgresql.org/message-id/flat/4a7c2c4b.5020...@netspace.net.au [3] https://www.postgresql.org/message-id/flat/12549.1346111...@sss.pgh.pa.us [4] https://www.postgresql.org/message-id/flat/20150512181307.gj2...@alvh.no-ip.org
From aa79e331595860489cdbbdce2d5f35a7d1f33783 Mon Sep 17 00:00:00 2001 From: Emre Hasegeli <e...@hasegeli.com> Date: Wed, 25 May 2016 17:53:19 +0200 Subject: [PATCH] Stop using FP macros on geo_ops.c --- src/backend/access/gist/gistproc.c | 17 +- src/backend/access/spgist/spgkdtreeproc.c | 24 +-- src/backend/utils/adt/geo_ops.c | 312 +++++++++++++++--------------- src/backend/utils/adt/geo_spgist.c | 24 +-- src/include/utils/geo_decls.h | 16 -- src/test/regress/expected/point.out | 8 +- 6 files changed, 193 insertions(+), 208 deletions(-) diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index e8213e2..7fb4437 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -1295,44 +1295,41 @@ computeDistance(bool isLeaf, BOX *box, Point *point) static bool gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query) { bool result = false; switch (strategy) { case RTLeftStrategyNumber: - result = FPlt(key->low.x, query->x); + result = key->low.x < query->x; break; case RTRightStrategyNumber: - result = FPgt(key->high.x, query->x); + result = key->high.x > query->x; break; case RTAboveStrategyNumber: - result = FPgt(key->high.y, query->y); + result = key->high.y > query->y; break; case RTBelowStrategyNumber: - result = FPlt(key->low.y, query->y); + result = key->low.y < query->y; break; case RTSameStrategyNumber: if (isLeaf) { /* key.high must equal key.low, so we can disregard it */ - result = (FPeq(key->low.x, query->x) && - FPeq(key->low.y, query->y)); + result = key->low.x == query->x && key->low.y == query->y; } else { - result = (FPle(query->x, key->high.x) && - FPge(query->x, key->low.x) && - FPle(query->y, key->high.y) && - FPge(query->y, key->low.y)); + result = query->x <= key->high.x && query->x >= key->low.x && + query->y <= key->high.y && query->y >= key->low.y; } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); result = false; /* keep compiler quiet */ break; } return result; } diff --git a/src/backend/access/spgist/spgkdtreeproc.c b/src/backend/access/spgist/spgkdtreeproc.c index 1ab9335..4b3be5d 100644 --- a/src/backend/access/spgist/spgkdtreeproc.c +++ b/src/backend/access/spgist/spgkdtreeproc.c @@ -175,72 +175,72 @@ spg_kd_inner_consistent(PG_FUNCTION_ARGS) which = (1 << 1) | (1 << 2); for (i = 0; i < in->nkeys; i++) { Point *query = DatumGetPointP(in->scankeys[i].sk_argument); BOX *boxQuery; switch (in->scankeys[i].sk_strategy) { case RTLeftStrategyNumber: - if ((in->level % 2) != 0 && FPlt(query->x, coord)) + if ((in->level % 2) != 0 && query->x < coord) which &= (1 << 1); break; case RTRightStrategyNumber: - if ((in->level % 2) != 0 && FPgt(query->x, coord)) + if ((in->level % 2) != 0 && query->x > coord) which &= (1 << 2); break; case RTSameStrategyNumber: if ((in->level % 2) != 0) { - if (FPlt(query->x, coord)) + if (query->x < coord) which &= (1 << 1); - else if (FPgt(query->x, coord)) + else if (query->x > coord) which &= (1 << 2); } else { - if (FPlt(query->y, coord)) + if (query->y < coord) which &= (1 << 1); - else if (FPgt(query->y, coord)) + else if (query->y > coord) which &= (1 << 2); } break; case RTBelowStrategyNumber: - if ((in->level % 2) == 0 && FPlt(query->y, coord)) + if ((in->level % 2) == 0 && query->y < coord) which &= (1 << 1); break; case RTAboveStrategyNumber: - if ((in->level % 2) == 0 && FPgt(query->y, coord)) + if ((in->level % 2) == 0 && query->y > coord) which &= (1 << 2); break; case RTContainedByStrategyNumber: /* * For this operator, the query is a box not a point. We * cheat to the extent of assuming that DatumGetPointP won't * do anything that would be bad for a pointer-to-box. */ boxQuery = DatumGetBoxP(in->scankeys[i].sk_argument); if ((in->level % 2) != 0) { - if (FPlt(boxQuery->high.x, coord)) + if (boxQuery->high.x < coord) which &= (1 << 1); - else if (FPgt(boxQuery->low.x, coord)) + else if (boxQuery->low.x > coord) which &= (1 << 2); } else { - if (FPlt(boxQuery->high.y, coord)) + if (boxQuery->high.y < coord) which &= (1 << 1); - else if (FPgt(boxQuery->low.y, coord)) + else if (boxQuery->low.y > coord) which &= (1 << 2); } break; default: elog(ERROR, "unrecognized strategy number: %d", in->scankeys[i].sk_strategy); break; } if (which == 0) diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index 657bcee..7e553e6 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -499,246 +499,246 @@ box_copy(BOX *box) *---------------------------------------------------------*/ /* box_same - are two boxes identical? */ Datum box_same(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) && - FPeq(box1->low.x, box2->low.x) && - FPeq(box1->high.y, box2->high.y) && - FPeq(box1->low.y, box2->low.y)); + PG_RETURN_BOOL(box1->high.x == box2->high.x && + box1->low.x == box2->low.x && + box1->high.y == box2->high.y && + box1->low.y == box2->low.y); } /* box_overlap - does box1 overlap box2? */ Datum box_overlap(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(box_ov(box1, box2)); } static bool box_ov(BOX *box1, BOX *box2) { - return (FPle(box1->low.x, box2->high.x) && - FPle(box2->low.x, box1->high.x) && - FPle(box1->low.y, box2->high.y) && - FPle(box2->low.y, box1->high.y)); + return (box1->low.x <= box2->high.x && + box2->low.x <= box1->high.x && + box1->low.y <= box2->high.y && + box2->low.y <= box1->high.y); } /* box_left - is box1 strictly left of box2? */ Datum box_left(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x)); + PG_RETURN_BOOL(box1->high.x < box2->low.x); } /* box_overleft - is the right edge of box1 at or left of * the right edge of box2? * * This is "less than or equal" for the end of a time range, * when time ranges are stored as rectangles. */ Datum box_overleft(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x)); + PG_RETURN_BOOL(box1->high.x <= box2->high.x); } /* box_right - is box1 strictly right of box2? */ Datum box_right(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPgt(box1->low.x, box2->high.x)); + PG_RETURN_BOOL(box1->low.x > box2->high.x); } /* box_overright - is the left edge of box1 at or right of * the left edge of box2? * * This is "greater than or equal" for time ranges, when time ranges * are stored as rectangles. */ Datum box_overright(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPge(box1->low.x, box2->low.x)); + PG_RETURN_BOOL(box1->low.x >= box2->low.x); } /* box_below - is box1 strictly below box2? */ Datum box_below(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPlt(box1->high.y, box2->low.y)); + PG_RETURN_BOOL(box1->high.y < box2->low.y); } /* box_overbelow - is the upper edge of box1 at or below * the upper edge of box2? */ Datum box_overbelow(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPle(box1->high.y, box2->high.y)); + PG_RETURN_BOOL(box1->high.y <= box2->high.y); } /* box_above - is box1 strictly above box2? */ Datum box_above(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPgt(box1->low.y, box2->high.y)); + PG_RETURN_BOOL(box1->low.y > box2->high.y); } /* box_overabove - is the lower edge of box1 at or above * the lower edge of box2? */ Datum box_overabove(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPge(box1->low.y, box2->low.y)); + PG_RETURN_BOOL(box1->low.y >= box2->low.y); } /* box_contained - is box1 contained by box2? */ Datum box_contained(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) && - FPge(box1->low.x, box2->low.x) && - FPle(box1->high.y, box2->high.y) && - FPge(box1->low.y, box2->low.y)); + PG_RETURN_BOOL(box1->high.x <= box2->high.x && + box1->low.x >= box2->low.x && + box1->high.y <= box2->high.y && + box1->low.y >= box2->low.y); } /* box_contain - does box1 contain box2? */ Datum box_contain(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) && - FPle(box1->low.x, box2->low.x) && - FPge(box1->high.y, box2->high.y) && - FPle(box1->low.y, box2->low.y)); + PG_RETURN_BOOL(box1->high.x >= box2->high.x && + box1->low.x <= box2->low.x && + box1->high.y >= box2->high.y && + box1->low.y <= box2->low.y); } /* box_positionop - * is box1 entirely {above,below} box2? * * box_below_eq and box_above_eq are obsolete versions that (probably * erroneously) accept the equal-boundaries case. Since these are not * in sync with the box_left and box_right code, they are deprecated and * not supported in the PG 8.1 rtree operator class extension. */ Datum box_below_eq(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPle(box1->high.y, box2->low.y)); + PG_RETURN_BOOL(box1->high.y <= box2->low.y); } Datum box_above_eq(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPge(box1->low.y, box2->high.y)); + PG_RETURN_BOOL(box1->low.y >= box2->high.y); } /* box_relop - is area(box1) relop area(box2), within * our accuracy constraint? */ Datum box_lt(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPlt(box_ar(box1), box_ar(box2))); + PG_RETURN_BOOL(box_ar(box1) < box_ar(box2)); } Datum box_gt(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPgt(box_ar(box1), box_ar(box2))); + PG_RETURN_BOOL(box_ar(box1) > box_ar(box2)); } Datum box_eq(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPeq(box_ar(box1), box_ar(box2))); + PG_RETURN_BOOL(box_ar(box1) == box_ar(box2)); } Datum box_le(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPle(box_ar(box1), box_ar(box2))); + PG_RETURN_BOOL(box_ar(box1) <= box_ar(box2)); } Datum box_ge(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(FPge(box_ar(box1), box_ar(box2))); + PG_RETURN_BOOL(box_ar(box1) >= box_ar(box2)); } /*---------------------------------------------------------- * "Arithmetic" operators on boxes. *---------------------------------------------------------*/ /* box_area - returns the area of the box. */ Datum @@ -927,29 +927,29 @@ line_in(PG_FUNCTION_ARGS) s = str; while (isspace((unsigned char) *s)) s++; if (*s == '{') { if (!line_decode(s + 1, str, line)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "line", str))); - if (FPzero(line->A) && FPzero(line->B)) + if (line->A == 0 && line->B == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: A and B cannot both be zero"))); } else { path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str); - if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y)) + if (lseg.p[0].x == lseg.p[1].x && lseg.p[0].y == lseg.p[1].y) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: must be two distinct points"))); line_construct_pts(line, &lseg.p[0], &lseg.p[1]); } PG_RETURN_LINE_P(line); } @@ -1029,31 +1029,31 @@ line_construct_pm(Point *pt, double m) return result; } /* * Fill already-allocated LINE struct from two points on the line */ static void line_construct_pts(LINE *line, Point *pt1, Point *pt2) { - if (FPeq(pt1->x, pt2->x)) + if (pt1->x == pt2->x) { /* vertical */ /* use "x = C" */ line->A = -1; line->B = 0; line->C = pt1->x; #ifdef GEODEBUG printf("line_construct_pts- line is vertical\n"); #endif } - else if (FPeq(pt1->y, pt2->y)) + else if (pt1->y == pt2->y) { /* horizontal */ /* use "y = C" */ line->A = 0; line->B = -1; line->C = pt1->y; #ifdef GEODEBUG printf("line_construct_pts- line is horizontal\n"); #endif } else @@ -1101,75 +1101,77 @@ line_intersect(PG_FUNCTION_ARGS) LinePGetDatum(l1), LinePGetDatum(l2)))); } Datum line_parallel(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->B)); + if (l1->B == 0) + PG_RETURN_BOOL(l2->B == 0); - PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B))); + PG_RETURN_BOOL(l2->A * l1->B == l1->A * l2->B); } Datum line_perp(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - if (FPzero(l1->A)) - PG_RETURN_BOOL(FPzero(l2->B)); - else if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->A)); + if (l1->A == 0) + PG_RETURN_BOOL(l2->B == 0); + else if (l1->B == 0) + PG_RETURN_BOOL(l2->A == 0); - PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0)); + PG_RETURN_BOOL(l1->A * l2->B == l1->B * l2->A * -1.0); } Datum line_vertical(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->B)); + PG_RETURN_BOOL(line->B == 0); } Datum line_horizontal(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->A)); + PG_RETURN_BOOL(line->A == 0); } Datum line_eq(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); double k; - if (!FPzero(l2->A)) - k = l1->A / l2->A; - else if (!FPzero(l2->B)) - k = l1->B / l2->B; - else if (!FPzero(l2->C)) - k = l1->C / l2->C; - else - k = 1.0; + if (l1->A == l2->A) + PG_RETURN_BOOL(l1->B == l2->B && l1->C == l2->C); - PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) && - FPeq(l1->B, k * l2->B) && - FPeq(l1->C, k * l2->C)); + if (l1->A != 0) + PG_RETURN_BOOL(l1->A * l2->B == l2->A * l1->B && + l1->A * l2->C == l2->A * l1->C); + if (l2->B != 0) + PG_RETURN_BOOL(l1->B * l2->A == l2->B * l1->A && + l1->B * l2->C == l2->B * l1->C); + if (l2->C != 0) + PG_RETURN_BOOL(l1->C * l2->A == l2->C * l1->A && + l1->C * l2->B == l2->C * l1->B); + + PG_RETURN_BOOL(false); } /*---------------------------------------------------------- * Line arithmetic routines. *---------------------------------------------------------*/ /* line_distance() * Distance between two lines. */ @@ -1178,21 +1180,21 @@ line_distance(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); float8 result; Point *tmp; if (!DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))) PG_RETURN_FLOAT8(0.0); - if (FPzero(l1->B)) /* vertical? */ + if (l1->B == 0) /* vertical? */ PG_RETURN_FLOAT8(fabs(l1->C - l2->C)); tmp = point_construct(0.0, l1->C); result = dist_pl_internal(tmp, l2); PG_RETURN_FLOAT8(result); } /* line_interpt() * Point where two lines l1, l2 intersect (if any) */ Datum @@ -1224,26 +1226,26 @@ line_interpt_internal(LINE *l1, LINE *l2) /* * NOTE: if the lines are identical then we will find they are parallel * and report "no intersection". This is a little weird, but since * there's no *unique* intersection, maybe it's appropriate behavior. */ if (DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))) return NULL; - if (FPzero(l1->B)) /* l1 vertical? */ + if (l1->B == 0) /* l1 vertical? */ { x = l1->C; y = (l2->A * x + l2->C); } - else if (FPzero(l2->B)) /* l2 vertical? */ + else if (l2->B == 0) /* l2 vertical? */ { x = l2->C; y = (l1->A * x + l1->C); } else { x = (l1->C - l2->C) / (l2->A - l1->A); y = (l1->A * x + l1->C); } result = point_construct(x, y); @@ -1816,84 +1818,84 @@ point_copy(Point *pt) * that results may, strictly speaking, be a lie (unless * EPSILON = 0.0). *---------------------------------------------------------*/ Datum point_left(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPlt(pt1->x, pt2->x)); + PG_RETURN_BOOL(pt1->x < pt2->x); } Datum point_right(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPgt(pt1->x, pt2->x)); + PG_RETURN_BOOL(pt1->x > pt2->x); } Datum point_above(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPgt(pt1->y, pt2->y)); + PG_RETURN_BOOL(pt1->y > pt2->y); } Datum point_below(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPlt(pt1->y, pt2->y)); + PG_RETURN_BOOL(pt1->y < pt2->y); } Datum point_vert(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPeq(pt1->x, pt2->x)); + PG_RETURN_BOOL(pt1->x == pt2->x); } Datum point_horiz(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPeq(pt1->y, pt2->y)); + PG_RETURN_BOOL(pt1->y == pt2->y); } Datum point_eq(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)); + PG_RETURN_BOOL(pt1->x == pt2->x && pt1->y == pt2->y); } Datum point_ne(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y)); + PG_RETURN_BOOL(pt1->x != pt2->x || pt1->y != pt2->y); } /*---------------------------------------------------------- * "Arithmetic" operators on points. *---------------------------------------------------------*/ Datum point_distance(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); @@ -1918,21 +1920,21 @@ point_slope(PG_FUNCTION_ARGS) Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); PG_RETURN_FLOAT8(point_sl(pt1, pt2)); } double point_sl(Point *pt1, Point *pt2) { - return (FPeq(pt1->x, pt2->x) + return (pt1->x == pt2->x ? (double) DBL_MAX : (pt1->y - pt2->y) / (pt1->x - pt2->x)); } /*********************************************************************** ** ** Routines for 2D line segments. ** ***********************************************************************/ @@ -2072,20 +2074,21 @@ lseg_intersect_internal(LSEG *l1, LSEG *l2) retval = false; return retval; } Datum lseg_parallel(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); + /* The slopes are lossy. We cannot exact match them. */ PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]), point_sl(&l2->p[0], &l2->p[1]))); } /* lseg_perp() * Determine if two line segments are perpendicular. * * This code did not get the correct answer for * '((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg * So, modified it to check explicitly for slope of vertical line @@ -2099,107 +2102,108 @@ lseg_perp(PG_FUNCTION_ARGS) LSEG *l2 = PG_GETARG_LSEG_P(1); double m1, m2; m1 = point_sl(&(l1->p[0]), &(l1->p[1])); m2 = point_sl(&(l2->p[0]), &(l2->p[1])); #ifdef GEODEBUG printf("lseg_perp- slopes are %g and %g\n", m1, m2); #endif - if (FPzero(m1)) - PG_RETURN_BOOL(FPeq(m2, DBL_MAX)); - else if (FPzero(m2)) - PG_RETURN_BOOL(FPeq(m1, DBL_MAX)); + if (m1 == 0) + PG_RETURN_BOOL(m2 == DBL_MAX); + else if (m2 == 0) + PG_RETURN_BOOL(m1 == DBL_MAX); - PG_RETURN_BOOL(FPeq(m1 / m2, -1.0)); + /* The slopes are lossy. We cannot exact match them. */ + PG_RETURN_BOOL(FPeq(m1, m2 * -1.0)); } Datum lseg_vertical(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); - PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x)); + PG_RETURN_BOOL(lseg->p[0].x == lseg->p[1].x); } Datum lseg_horizontal(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); - PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y)); + PG_RETURN_BOOL(lseg->p[0].y == lseg->p[1].y); } Datum lseg_eq(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) && - FPeq(l1->p[0].y, l2->p[0].y) && - FPeq(l1->p[1].x, l2->p[1].x) && - FPeq(l1->p[1].y, l2->p[1].y)); + PG_RETURN_BOOL(l1->p[0].x == l2->p[0].x && + l1->p[0].y == l2->p[0].y && + l1->p[1].x == l2->p[1].x && + l1->p[1].y == l2->p[1].y); } Datum lseg_ne(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) || - !FPeq(l1->p[0].y, l2->p[0].y) || - !FPeq(l1->p[1].x, l2->p[1].x) || - !FPeq(l1->p[1].y, l2->p[1].y)); + PG_RETURN_BOOL(l1->p[0].x != l2->p[0].x || + l1->p[0].y != l2->p[0].y || + l1->p[1].x != l2->p[1].x || + l1->p[1].y != l2->p[1].y); } Datum lseg_lt(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]), - point_dt(&l2->p[0], &l2->p[1]))); + PG_RETURN_BOOL(point_dt(&l1->p[0], &l1->p[1]) < + point_dt(&l2->p[0], &l2->p[1])); } Datum lseg_le(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1]), - point_dt(&l2->p[0], &l2->p[1]))); + PG_RETURN_BOOL(point_dt(&l1->p[0], &l1->p[1]) <= + point_dt(&l2->p[0], &l2->p[1])); } Datum lseg_gt(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1]), - point_dt(&l2->p[0], &l2->p[1]))); + PG_RETURN_BOOL(point_dt(&l1->p[0], &l1->p[1]) > + point_dt(&l2->p[0], &l2->p[1])); } Datum lseg_ge(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1]), - point_dt(&l2->p[0], &l2->p[1]))); + PG_RETURN_BOOL(point_dt(&l1->p[0], &l1->p[1]) >= + point_dt(&l2->p[0], &l2->p[1])); } /*---------------------------------------------------------- * Line arithmetic routines. *---------------------------------------------------------*/ /* lseg_distance - * If two segments don't intersect, then the closest * point will be from one of the endpoints to the other @@ -2278,21 +2282,22 @@ lseg_interpt_internal(LSEG *l1, LSEG *l2) if (!on_ps_internal(result, l1) || !on_ps_internal(result, l2)) { pfree(result); return NULL; } /* * If there is an intersection, then check explicitly for matching * endpoints since there may be rounding effects with annoying lsb - * residue. - tgl 1997-07-09 + * residue. We are fuzzy matching them to be compatible with + * on_ps_internal(). */ if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) || (FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y))) { result->x = l1->p[0].x; result->y = l1->p[0].y; } else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) || (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y))) { @@ -2714,27 +2719,27 @@ Datum close_pl(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); Point *result; LINE *tmp; double invm; result = (Point *) palloc(sizeof(Point)); - if (FPzero(line->B)) /* vertical? */ + if (line->B == 0) /* vertical? */ { result->x = line->C; result->y = pt->y; PG_RETURN_POINT_P(result); } - if (FPzero(line->A)) /* horizontal? */ + if (line->A == 0) /* horizontal? */ { result->x = pt->x; result->y = line->C; PG_RETURN_POINT_P(result); } /* drop a perpendicular and find the intersection point */ /* invert and flip the sign on the slope to get a perpendicular */ invm = line->B / line->A; tmp = line_construct_pm(pt, invm); @@ -2759,51 +2764,51 @@ close_ps(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); Point *result = NULL; LINE *tmp; double invm; int xh, yh; #ifdef GEODEBUG - printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f lseg(1).x %f lseg(1).y %f\n", + printf("close_ps:spt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f lseg(1).x %f lseg(1).y %f\n", pt->x, pt->y, lseg->p[0].x, lseg->p[0].y, lseg->p[1].x, lseg->p[1].y); #endif /* xh (or yh) is the index of upper x( or y) end point of lseg */ /* !xh (or !yh) is the index of lower x( or y) end point of lseg */ xh = lseg->p[0].x < lseg->p[1].x; yh = lseg->p[0].y < lseg->p[1].y; - if (FPeq(lseg->p[0].x, lseg->p[1].x)) /* vertical? */ + if (lseg->p[0].x == lseg->p[1].x) /* vertical? */ { #ifdef GEODEBUG printf("close_ps- segment is vertical\n"); #endif /* first check if point is below or above the entire lseg. */ if (pt->y < lseg->p[!yh].y) result = point_copy(&lseg->p[!yh]); /* below the lseg */ else if (pt->y > lseg->p[yh].y) result = point_copy(&lseg->p[yh]); /* above the lseg */ if (result != NULL) PG_RETURN_POINT_P(result); /* point lines along (to left or right) of the vertical lseg. */ result = (Point *) palloc(sizeof(Point)); result->x = lseg->p[0].x; result->y = pt->y; PG_RETURN_POINT_P(result); } - else if (FPeq(lseg->p[0].y, lseg->p[1].y)) /* horizontal? */ + else if (lseg->p[0].y == lseg->p[1].y) /* horizontal? */ { #ifdef GEODEBUG printf("close_ps- segment is horizontal\n"); #endif /* first check if point is left or right of the entire lseg. */ if (pt->x < lseg->p[!xh].x) result = point_copy(&lseg->p[!xh]); /* left of the lseg */ else if (pt->x > lseg->p[xh].x) result = point_copy(&lseg->p[xh]); /* right of the lseg */ if (result != NULL) @@ -3118,40 +3123,41 @@ close_lb(PG_FUNCTION_ARGS) /* on_pl - * Does the point satisfy the equation? */ Datum on_pl(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C)); + PG_RETURN_BOOL(line->A * pt->x + line->B * pt->y + line->C == 0); } /* on_ps - - * Determine colinearity by detecting a triangle inequality. + * Determine collinearity by detecting a triangle inequality. * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09 */ Datum on_ps(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); PG_RETURN_BOOL(on_ps_internal(pt, lseg)); } static bool on_ps_internal(Point *pt, LSEG *lseg) { + /* The distances are lossy. We cannot exact match them. */ return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]), point_dt(&lseg->p[0], &lseg->p[1])); } Datum on_pb(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); BOX *box = PG_GETARG_BOX_P(1); @@ -3191,22 +3197,21 @@ on_ppath(PG_FUNCTION_ARGS) b; /*-- OPEN --*/ if (!path->closed) { n = path->npts - 1; a = point_dt(pt, &path->p[0]); for (i = 0; i < n; i++) { b = point_dt(pt, &path->p[i + 1]); - if (FPeq(a + b, - point_dt(&path->p[i], &path->p[i + 1]))) + if (a + b == point_dt(&path->p[i], &path->p[i + 1])) PG_RETURN_BOOL(true); a = b; } PG_RETURN_BOOL(false); } /*-- CLOSED --*/ PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0); } @@ -3810,21 +3815,21 @@ poly_overlap(PG_FUNCTION_ARGS) static bool touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start) { /* point a is on s, b is not */ LSEG t; t.p[0] = *a; t.p[1] = *b; -#define POINTEQ(pt1, pt2) (FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y)) +#define POINTEQ(pt1, pt2) ((pt1)->x == (pt2)->x && (pt1)->y == (pt2)->y) if (POINTEQ(a, s->p)) { if (on_ps_internal(s->p + 1, &t)) return lseg_inside_poly(b, s->p + 1, poly, start); } else if (POINTEQ(a, s->p + 1)) { if (on_ps_internal(s->p, &t)) return lseg_inside_poly(b, s->p, poly, start); } @@ -4648,216 +4653,218 @@ circle_send(PG_FUNCTION_ARGS) *---------------------------------------------------------*/ /* circles identical? */ Datum circle_same(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) && - FPeq(circle1->center.x, circle2->center.x) && - FPeq(circle1->center.y, circle2->center.y)); + PG_RETURN_BOOL(circle1->radius == circle2->radius && + circle1->center.x == circle2->center.x && + circle1->center.y == circle2->center.y); } /* circle_overlap - does circle1 overlap circle2? */ Datum circle_overlap(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center), - circle1->radius + circle2->radius)); + PG_RETURN_BOOL(point_dt(&circle1->center, &circle2->center) <= + circle1->radius + circle2->radius); } /* circle_overleft - is the right edge of circle1 at or left of * the right edge of circle2? */ Datum circle_overleft(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius), - (circle2->center.x + circle2->radius))); + PG_RETURN_BOOL(circle1->center.x + circle1->radius <= + circle2->center.x + circle2->radius); } /* circle_left - is circle1 strictly left of circle2? */ Datum circle_left(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius), - (circle2->center.x - circle2->radius))); + PG_RETURN_BOOL(circle1->center.x + circle1->radius < + circle2->center.x - circle2->radius); } /* circle_right - is circle1 strictly right of circle2? */ Datum circle_right(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius), - (circle2->center.x + circle2->radius))); + PG_RETURN_BOOL(circle1->center.x - circle1->radius > + circle2->center.x + circle2->radius); } /* circle_overright - is the left edge of circle1 at or right of * the left edge of circle2? */ Datum circle_overright(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius), - (circle2->center.x - circle2->radius))); + PG_RETURN_BOOL(circle1->center.x - circle1->radius >= + circle2->center.x - circle2->radius); } /* circle_contained - is circle1 contained by circle2? */ Datum circle_contained(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius)); + PG_RETURN_BOOL(point_dt(&circle1->center, &circle2->center) + + circle1->radius <= circle2->radius); } /* circle_contain - does circle1 contain circle2? */ Datum circle_contain(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius)); + PG_RETURN_BOOL(point_dt(&circle1->center, &circle2->center) + + circle2->radius <= circle1->radius); } /* circle_below - is circle1 strictly below circle2? */ Datum circle_below(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius), - (circle2->center.y - circle2->radius))); + PG_RETURN_BOOL(circle1->center.y + circle1->radius < + circle2->center.y - circle2->radius); } /* circle_above - is circle1 strictly above circle2? */ Datum circle_above(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius), - (circle2->center.y + circle2->radius))); + PG_RETURN_BOOL(circle1->center.y - circle1->radius > + circle2->center.y + circle2->radius); } /* circle_overbelow - is the upper edge of circle1 at or below * the upper edge of circle2? */ Datum circle_overbelow(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius), - (circle2->center.y + circle2->radius))); + PG_RETURN_BOOL(circle1->center.y + circle1->radius <= + circle2->center.y + circle2->radius); } /* circle_overabove - is the lower edge of circle1 at or above * the lower edge of circle2? */ Datum circle_overabove(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius), - (circle2->center.y - circle2->radius))); + PG_RETURN_BOOL(circle1->center.y - circle1->radius >= + circle2->center.y - circle2->radius); } /* circle_relop - is area(circle1) relop area(circle2), within * our accuracy constraint? */ Datum circle_eq(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPeq(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) == circle_ar(circle2)); } Datum circle_ne(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPne(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) != circle_ar(circle2)); } Datum circle_lt(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) < circle_ar(circle2)); } Datum circle_gt(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) > circle_ar(circle2)); } Datum circle_le(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) <= circle_ar(circle2)); } Datum circle_ge(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(circle_ar(circle1) >= circle_ar(circle2)); } /*---------------------------------------------------------- * "Arithmetic" operators on circles. *---------------------------------------------------------*/ static CIRCLE * circle_copy(CIRCLE *circle) { @@ -5146,21 +5153,21 @@ circle_poly(PG_FUNCTION_ARGS) { int32 npts = PG_GETARG_INT32(0); CIRCLE *circle = PG_GETARG_CIRCLE_P(1); POLYGON *poly; int base_size, size; int i; double angle; double anglestep; - if (FPzero(circle->radius)) + if (circle->radius == 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert circle with radius zero to polygon"))); if (npts < 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("must request at least 2 points"))); base_size = sizeof(poly->p[0]) * npts; @@ -5305,110 +5312,107 @@ point_inside(Point *p, int npts, Point *plist) * 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 prev_x, double prev_y) { double z; int y_sign; - if (FPzero(y)) + if (y == 0) { /* y == 0, on X axis */ - if (FPzero(x)) /* (x,y) is (0,0)? */ + if (x == 0) /* (x,y) is (0,0)? */ return POINT_ON_POLYGON; - else if (FPgt(x, 0)) + else if (x > 0) { /* x > 0 */ - if (FPzero(prev_y)) /* y and prev_y are zero */ + if (prev_y == 0) /* 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; + return prev_x > 0 ? 0 : POINT_ON_POLYGON; + return prev_y < 0 ? 1 : -1; } else { /* x < 0, x not on positive X axis */ - if (FPzero(prev_y)) + if (prev_y == 0) /* prev_x < 0? */ - return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON; + return prev_x < 0 ? 0 : POINT_ON_POLYGON; return 0; } } else { /* y != 0 */ /* compute y crossing direction from previous point */ - y_sign = FPgt(y, 0) ? 1 : -1; + y_sign = y > 0 ? 1 : -1; - if (FPzero(prev_y)) + if (prev_y == 0) /* 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)) + return prev_x < 0 ? 0 : y_sign; + else if (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)) + if (x >= 0 && prev_x > 0) /* both non-negative so cross positive X-axis */ return 2 * y_sign; - if (FPlt(x, 0) && FPle(prev_x, 0)) + if (x < 0 && 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)) + if (z == 0) return POINT_ON_POLYGON; - return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign; + return y_sign * z > 0 ? 0 : 2 * y_sign; } } } static bool plist_same(int npts, Point *p1, Point *p2) { int i, ii, j; /* find match for first point */ for (i = 0; i < npts; i++) { - if ((FPeq(p2[i].x, p1[0].x)) - && (FPeq(p2[i].y, p1[0].y))) + if (p2[i].x == p1[0].x && p2[i].y == p1[0].y) { /* match found? then look forward through remaining points */ for (ii = 1, j = i + 1; ii < npts; ii++, j++) { if (j >= npts) j = 0; - if ((!FPeq(p2[j].x, p1[ii].x)) - || (!FPeq(p2[j].y, p1[ii].y))) + if (p2[j].x != p1[ii].x || p2[j].y != p1[ii].y) { #ifdef GEODEBUG printf("plist_same- %d failed forward match with %d\n", j, ii); #endif break; } } #ifdef GEODEBUG printf("plist_same- ii = %d/%d after forward match\n", ii, npts); #endif if (ii == npts) return TRUE; /* match not found forwards? then look backwards */ for (ii = 1, j = i - 1; ii < npts; ii++, j--) { if (j < 0) j = (npts - 1); - if ((!FPeq(p2[j].x, p1[ii].x)) - || (!FPeq(p2[j].y, p1[ii].y))) + if (p2[j].x != p1[ii].x || p2[j].y != p1[ii].y) { #ifdef GEODEBUG printf("plist_same- %d failed reverse match with %d\n", j, ii); #endif break; } } #ifdef GEODEBUG printf("plist_same- ii = %d/%d after reverse match\n", ii, npts); #endif diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c index 83d509e..4b82f89 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -225,80 +225,80 @@ nextRectBox(RectBox *rect_box, RangeBox *centroid, uint8 quadrant) else next_rect_box->range_box_y.right.high = centroid->right.high; return next_rect_box; } /* Can any range from range_box overlap with this argument? */ static bool overlap2D(RangeBox *range_box, Range *query) { - return FPge(range_box->right.high, query->low) && - FPle(range_box->left.low, query->high); + return range_box->right.high >= query->low && + range_box->left.low <= query->high; } /* Can any rectangle from rect_box overlap with this argument? */ static bool overlap4D(RectBox *rect_box, RangeBox *query) { return overlap2D(&rect_box->range_box_x, &query->left) && overlap2D(&rect_box->range_box_y, &query->right); } /* Can any range from range_box contain this argument? */ static bool contain2D(RangeBox *range_box, Range *query) { - return FPge(range_box->right.high, query->high) && - FPle(range_box->left.low, query->low); + return range_box->right.high >= query->high && + range_box->left.low <= query->low; } /* Can any rectangle from rect_box contain this argument? */ static bool contain4D(RectBox *rect_box, RangeBox * query) { return contain2D(&rect_box->range_box_x, &query->left) && contain2D(&rect_box->range_box_y, &query->right); } /* Can any range from range_box be contained by this argument? */ static bool contained2D(RangeBox *range_box, Range *query) { - return FPle(range_box->left.low, query->high) && - FPge(range_box->left.high, query->low) && - FPle(range_box->right.low, query->high) && - FPge(range_box->right.high, query->low); + return range_box->left.low <= query->high && + range_box->left.high >= query->low && + range_box->right.low <= query->high && + range_box->right.high >= query->low; } /* Can any rectangle from rect_box be contained by this argument? */ static bool contained4D(RectBox *rect_box, RangeBox *query) { return contained2D(&rect_box->range_box_x, &query->left) && contained2D(&rect_box->range_box_y, &query->right); } /* Can any range from range_box to be lower than this argument? */ static bool lower2D(RangeBox *range_box, Range *query) { - return FPlt(range_box->left.low, query->low) && - FPlt(range_box->right.low, query->low); + return range_box->left.low < query->low && + range_box->right.low < query->low; } /* Can any range from range_box to be higher than this argument? */ static bool higher2D(RangeBox *range_box, Range *query) { - return FPgt(range_box->left.high, query->high) && - FPgt(range_box->right.high, query->high); + return range_box->left.high > query->high && + range_box->right.high > query->high; } /* Can any rectangle from rect_box be left of this argument? */ static bool left4D(RectBox *rect_box, RangeBox *query) { return lower2D(&rect_box->range_box_x, &query->left); } /* Can any rectangle from rect_box does not extend the right of this argument? */ diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index acf3202..163bc57 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -25,37 +25,21 @@ #include "fmgr.h" /*-------------------------------------------------------------------- * Useful floating point utilities and constants. *-------------------------------------------------------------------*/ #define EPSILON 1.0E-06 -#ifdef EPSILON -#define FPzero(A) (fabs(A) <= EPSILON) #define FPeq(A,B) (fabs((A) - (B)) <= EPSILON) -#define FPne(A,B) (fabs((A) - (B)) > EPSILON) -#define FPlt(A,B) ((B) - (A) > EPSILON) -#define FPle(A,B) ((A) - (B) <= EPSILON) -#define FPgt(A,B) ((A) - (B) > EPSILON) -#define FPge(A,B) ((B) - (A) <= EPSILON) -#else -#define FPzero(A) ((A) == 0) -#define FPeq(A,B) ((A) == (B)) -#define FPne(A,B) ((A) != (B)) -#define FPlt(A,B) ((A) < (B)) -#define FPle(A,B) ((A) <= (B)) -#define FPgt(A,B) ((A) > (B)) -#define FPge(A,B) ((A) >= (B)) -#endif #define HYPOT(A, B) pg_hypot(A, B) /*--------------------------------------------------------------------- * Point - (x,y) *-------------------------------------------------------------------*/ typedef struct { double x, y; diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out index bfc0962..6319652 100644 --- a/src/test/regress/expected/point.out +++ b/src/test/regress/expected/point.out @@ -249,49 +249,49 @@ SELECT '' AS three, p1.f1 AS point1, p2.f1 AS point2, (p1.f1 <-> p2.f1) AS dista CREATE TEMP TABLE point_gist_tbl(f1 point); INSERT INTO point_gist_tbl SELECT '(0,0)' FROM generate_series(0,1000); CREATE INDEX point_gist_tbl_index ON point_gist_tbl USING gist (f1); INSERT INTO point_gist_tbl VALUES ('(0.0000009,0.0000009)'); SET enable_seqscan TO true; SET enable_indexscan TO false; SET enable_bitmapscan TO false; SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point; count ------- - 1002 + 1 (1 row) SELECT COUNT(*) FROM point_gist_tbl WHERE f1 <@ '(0.0000009,0.0000009),(0.0000009,0.0000009)'::box; count ------- 1 (1 row) SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000018,0.0000018)'::point; count ------- - 1 + 0 (1 row) SET enable_seqscan TO false; SET enable_indexscan TO true; SET enable_bitmapscan TO true; SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000009,0.0000009)'::point; count ------- - 1002 + 1 (1 row) SELECT COUNT(*) FROM point_gist_tbl WHERE f1 <@ '(0.0000009,0.0000009),(0.0000009,0.0000009)'::box; count ------- 1 (1 row) SELECT COUNT(*) FROM point_gist_tbl WHERE f1 ~= '(0.0000018,0.0000018)'::point; count ------- - 1 + 0 (1 row) RESET enable_seqscan; RESET enable_indexscan; RESET enable_bitmapscan; -- 2.7.4 (Apple Git-66)
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers