From d5303716840e8a0bca65b6f8c8445d2a4328b6bd Mon Sep 17 00:00:00 2001 From: Emre Hasegeli Date: Mon, 20 Jun 2016 10:24:32 +0200 Subject: [PATCH 2/2] geo-ops-fpcomp-v02 --- src/backend/access/gist/gistproc.c | 102 +- src/backend/access/spgist/spgkdtreeproc.c | 25 +- src/backend/utils/adt/geo_ops.c | 1497 ++++++++++++++++------------ src/backend/utils/adt/geo_spgist.c | 26 +- src/include/utils/geo_decls.h | 35 +- src/test/regress/expected/line.out | 30 +- src/test/regress/expected/point.out | 8 +- src/test/regress/expected/select_views.out | 335 +------ src/test/regress/regress.c | 11 +- 9 files changed, 944 insertions(+), 1125 deletions(-) diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index c7ac033..7cd55c0 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -859,24 +859,20 @@ gist_box_picksplit(PG_FUNCTION_ARGS) v->spl_ldatum = PointerGetDatum(leftBox); v->spl_rdatum = PointerGetDatum(rightBox); PG_RETURN_POINTER(v); } /* * Equality method * * This is used for boxes, points, circles, and polygons, all of which store * boxes as GiST index entries. - * - * Returns true only when boxes are exactly the same. We can't use fuzzy - * comparisons here without breaking index consistency; therefore, this isn't - * equivalent to box_same(). */ Datum gist_box_same(PG_FUNCTION_ARGS) { BOX *b1 = PG_GETARG_BOX_P(0); BOX *b2 = PG_GETARG_BOX_P(1); bool *result = (bool *) PG_GETARG_POINTER(2); if (b1 && b2) *result = (FLOAT_EQ(b1->low.x, b2->low.x) && @@ -1128,24 +1124,24 @@ gist_circle_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; if (entry->leafkey) { CIRCLE *in = DatumGetCircleP(entry->key); BOX *r; r = (BOX *) palloc(sizeof(BOX)); - r->high.x = in->center.x + in->radius; - r->low.x = in->center.x - in->radius; - r->high.y = in->center.y + in->radius; - r->low.y = in->center.y - in->radius; + FLOAT_PL(r->high.x, in->center.x, in->radius); + FLOAT_MI(r->low.x, in->center.x, in->radius); + FLOAT_PL(r->high.y, in->center.y, in->radius); + FLOAT_MI(r->low.y, in->center.y, in->radius); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE); } else retval = entry; PG_RETURN_POINTER(retval); } @@ -1169,24 +1165,24 @@ gist_circle_consistent(PG_FUNCTION_ARGS) *recheck = true; if (DatumGetBoxP(entry->key) == NULL || query == NULL) PG_RETURN_BOOL(FALSE); /* * Since the operators require recheck anyway, we can just use * rtree_internal_consistent even at leaf nodes. (This works in part * because the index entries are bounding boxes not circles.) */ - bbox.high.x = query->center.x + query->radius; - bbox.low.x = query->center.x - query->radius; - bbox.high.y = query->center.y + query->radius; - bbox.low.y = query->center.y - query->radius; + FLOAT_PL(bbox.high.x, query->center.x, query->radius); + FLOAT_MI(bbox.low.x, query->center.x, query->radius); + FLOAT_PL(bbox.high.y, query->center.y, query->radius); + FLOAT_MI(bbox.low.y, query->center.y, query->radius); result = rtree_internal_consistent(DatumGetBoxP(entry->key), &bbox, strategy); PG_RETURN_BOOL(result); } /************************************************** * Point ops **************************************************/ @@ -1247,109 +1243,113 @@ gist_point_fetch(PG_FUNCTION_ARGS) static double computeDistance(bool isLeaf, BOX *box, Point *point) { double result = 0.0; if (isLeaf) { /* simple point to point distance */ result = point_point_distance(point, &box->low); } - else if (point->x <= box->high.x && point->x >= box->low.x && - point->y <= box->high.y && point->y >= box->low.y) + else if (FLOAT_LE(point->x, box->high.x) && + FLOAT_GE(point->x, box->low.x) && + FLOAT_LE(point->y, box->high.y) && + FLOAT_GE(point->y, box->low.y)) { /* point inside the box */ result = 0.0; } - else if (point->x <= box->high.x && point->x >= box->low.x) + else if (FLOAT_LE(point->x, box->high.x) && + FLOAT_GE(point->x, box->low.x)) { /* point is over or below box */ - Assert(box->low.y <= box->high.y); - if (point->y > box->high.y) - result = point->y - box->high.y; - else if (point->y < box->low.y) - result = box->low.y - point->y; + Assert(FLOAT_LE(box->low.y, box->high.y)); + if (FLOAT_GT(point->y, box->high.y)) + FLOAT_MI(result, point->y, box->high.y); + else if (FLOAT_LT(point->y, box->low.y)) + FLOAT_MI(result, box->low.y, point->y); else elog(ERROR, "inconsistent point values"); } - else if (point->y <= box->high.y && point->y >= box->low.y) + else if (FLOAT_LE(point->y, box->high.y) && + FLOAT_GE(point->y, box->low.y)) { /* point is to left or right of box */ - Assert(box->low.x <= box->high.x); - if (point->x > box->high.x) - result = point->x - box->high.x; - else if (point->x < box->low.x) - result = box->low.x - point->x; + Assert(FLOAT_LE(box->low.x, box->high.x)); + if (FLOAT_GT(point->x, box->high.x)) + FLOAT_MI(result, point->x, box->high.x); + else if (FLOAT_LT(point->x, box->low.x)) + FLOAT_MI(result, box->low.x, point->x); else elog(ERROR, "inconsistent point values"); } else { /* closest point will be a vertex */ Point p; double subresult; result = point_point_distance(point, &box->low); subresult = point_point_distance(point, &box->high); - if (result > subresult) + if (FLOAT_GT(result, subresult)) result = subresult; p.x = box->low.x; p.y = box->high.y; subresult = point_point_distance(point, &p); - if (result > subresult) + if (FLOAT_GT(result, subresult)) result = subresult; p.x = box->high.x; p.y = box->low.y; subresult = point_point_distance(point, &p); - if (result > subresult) + if (FLOAT_GT(result, subresult)) result = subresult; } return result; } 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 = FLOAT_LT(key->low.x, query->x); break; case RTRightStrategyNumber: - result = FPgt(key->high.x, query->x); + result = FLOAT_GT(key->high.x, query->x); break; case RTAboveStrategyNumber: - result = FPgt(key->high.y, query->y); + result = FLOAT_GT(key->high.y, query->y); break; case RTBelowStrategyNumber: - result = FPlt(key->low.y, query->y); + result = FLOAT_LT(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 = (FLOAT_EQ(key->low.x, query->x) && + FLOAT_EQ(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 = (FLOAT_LE(query->x, key->high.x) && + FLOAT_GE(query->x, key->low.x) && + FLOAT_LE(query->y, key->high.y) && + FLOAT_GE(query->y, key->low.y)); } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); result = false; /* keep compiler quiet */ break; } return result; } @@ -1376,39 +1376,31 @@ gist_point_consistent(PG_FUNCTION_ARGS) GIST_LEAF(entry), DatumGetBoxP(entry->key), PG_GETARG_POINT_P(1)); *recheck = false; break; case BoxStrategyNumberGroup: { /* * The only operator in this group is point <@ box (on_pb), so * we needn't examine strategy again. - * - * For historical reasons, on_pb uses exact rather than fuzzy - * comparisons. We could use box_overlap when at an internal - * page, but that would lead to possibly visiting child pages - * uselessly, because box_overlap uses fuzzy comparisons. - * Instead we write a non-fuzzy overlap test. The same code - * will also serve for leaf-page tests, since leaf keys have - * high == low. */ BOX *query, *key; query = PG_GETARG_BOX_P(1); key = DatumGetBoxP(entry->key); - result = (key->high.x >= query->low.x && - key->low.x <= query->high.x && - key->high.y >= query->low.y && - key->low.y <= query->high.y); + result = (FLOAT_GE(key->high.x, query->low.x) && + FLOAT_LE(key->low.x, query->high.x) && + FLOAT_GE(key->high.y, query->low.y) && + FLOAT_LE(key->low.y, query->high.y)); *recheck = false; } break; case PolygonStrategyNumberGroup: { POLYGON *query = PG_GETARG_POLYGON_P(1); result = DatumGetBool(DirectFunctionCall5( gist_poly_consistent, PointerGetDatum(entry), @@ -1417,22 +1409,22 @@ gist_point_consistent(PG_FUNCTION_ARGS) 0, PointerGetDatum(recheck))); if (GIST_LEAF(entry) && result) { /* * We are on leaf page and quick check shows overlapping * of polygon's bounding box and point */ BOX *box = DatumGetBoxP(entry->key); - Assert(box->high.x == box->low.x - && box->high.y == box->low.y); + Assert(FLOAT_EQ(box->high.x, box->low.x) && + FLOAT_EQ(box->high.y, box->low.y)); result = DatumGetBool(DirectFunctionCall2( poly_contain_pt, PolygonPGetDatum(query), PointPGetDatum(&box->high))); *recheck = false; } } break; case CircleStrategyNumberGroup: { @@ -1446,22 +1438,22 @@ gist_point_consistent(PG_FUNCTION_ARGS) 0, PointerGetDatum(recheck))); if (GIST_LEAF(entry) && result) { /* * We are on leaf page and quick check shows overlapping * of polygon's bounding box and point */ BOX *box = DatumGetBoxP(entry->key); - Assert(box->high.x == box->low.x - && box->high.y == box->low.y); + Assert(FLOAT_EQ(box->high.x, box->low.x) && + FLOAT_EQ(box->high.y, box->low.y)); result = DatumGetBool(DirectFunctionCall2( circle_contain_pt, CirclePGetDatum(query), PointPGetDatum(&box->high))); *recheck = false; } } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); diff --git a/src/backend/access/spgist/spgkdtreeproc.c b/src/backend/access/spgist/spgkdtreeproc.c index 1ab9335..10a08ed 100644 --- a/src/backend/access/spgist/spgkdtreeproc.c +++ b/src/backend/access/spgist/spgkdtreeproc.c @@ -12,20 +12,21 @@ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/spgist.h" #include "access/stratnum.h" #include "catalog/pg_type.h" #include "utils/builtins.h" +#include "utils/float.h" #include "utils/geo_decls.h" Datum spg_kd_config(PG_FUNCTION_ARGS) { /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */ spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1); cfg->prefixType = FLOAT8OID; @@ -175,72 +176,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 && FLOAT_LT(query->x, coord)) which &= (1 << 1); break; case RTRightStrategyNumber: - if ((in->level % 2) != 0 && FPgt(query->x, coord)) + if ((in->level % 2) != 0 && FLOAT_GT(query->x, coord)) which &= (1 << 2); break; case RTSameStrategyNumber: if ((in->level % 2) != 0) { - if (FPlt(query->x, coord)) + if (FLOAT_LT(query->x, coord)) which &= (1 << 1); - else if (FPgt(query->x, coord)) + else if (FLOAT_GT(query->x, coord)) which &= (1 << 2); } else { - if (FPlt(query->y, coord)) + if (FLOAT_LT(query->y, coord)) which &= (1 << 1); - else if (FPgt(query->y, coord)) + else if (FLOAT_GT(query->y, coord)) which &= (1 << 2); } break; case RTBelowStrategyNumber: - if ((in->level % 2) == 0 && FPlt(query->y, coord)) + if ((in->level % 2) == 0 && FLOAT_LT(query->y, coord)) which &= (1 << 1); break; case RTAboveStrategyNumber: - if ((in->level % 2) == 0 && FPgt(query->y, coord)) + if ((in->level % 2) == 0 && FLOAT_GT(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 (FLOAT_LT(boxQuery->high.x, coord)) which &= (1 << 1); - else if (FPgt(boxQuery->low.x, coord)) + else if (FLOAT_GT(boxQuery->low.x, coord)) which &= (1 << 2); } else { - if (FPlt(boxQuery->high.y, coord)) + if (FLOAT_LT(boxQuery->high.y, coord)) which &= (1 << 1); - else if (FPgt(boxQuery->low.y, coord)) + else if (FLOAT_GT(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 efc81ab..3855c8e 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -36,50 +36,56 @@ enum path_delim static int point_inside(Point *p, int npts, Point *plist); static int lseg_crossing(double x, double y, double px, double py); static BOX *box_construct(double x1, double x2, double y1, double y2); static BOX *box_copy(BOX *box); static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2); static bool box_ov(BOX *box1, BOX *box2); static double box_ht(BOX *box); static double box_wd(BOX *box); static double circle_ar(CIRCLE *circle); -static CIRCLE *circle_copy(CIRCLE *circle); +static CIRCLE *circle_construct(double x, double y, double radius); static LINE *line_construct_pm(Point *pt, double m); -static void line_construct_pts(LINE *line, Point *pt1, Point *pt2); +static LINE *line_construct_pts(Point *pt1, Point *pt2); static bool lseg_intersect_internal(LSEG *l1, LSEG *l2); static double lseg_dt(LSEG *l1, LSEG *l2); static bool on_ps_internal(Point *pt, LSEG *lseg); +static double point_on_line_value(Point *pt, LINE *line); +static int point_lseg_cmp(Point *pt, LSEG *lseg); static void make_bound_box(POLYGON *poly); static bool plist_same(int npts, Point *p1, Point *p2); static Point *point_construct(double x, double y); static Point *point_copy(Point *pt); +static double point_dt(Point *pt1, Point *pt2); +static double slope(double x1, double x2, double y1, double y2); static double single_decode(char *num, char **endptr_p, const char *type_name, const char *orig_string); static void single_encode(float8 x, StringInfo str); static void pair_decode(char *str, double *x, double *y, char **endptr_p, const char *type_name, const char *orig_string); static void pair_encode(float8 x, float8 y, StringInfo str); static int pair_count(char *s, char delim); static void path_decode(char *str, bool opentype, int npts, Point *p, bool *isopen, char **endptr_p, const char *type_name, const char *orig_string); static char *path_encode(enum path_delim path_delim, int npts, Point *pt); static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2); static double box_ar(BOX *box); static void box_cn(Point *center, BOX *box); static Point *interpt_sl(LSEG *lseg, LINE *line); static bool has_interpt_sl(LSEG *lseg, LINE *line); +static Point *close_pl_internal(Point *pt, LINE *line); static double dist_pl_internal(Point *pt, LINE *line); static double dist_ps_internal(Point *pt, LSEG *lseg); static Point *line_interpt_internal(LINE *l1, LINE *l2); static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start); +static Point *lseg_center_internal(LSEG *lseg); static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2); static double dist_ppoly_internal(Point *pt, POLYGON *poly); /* * Delimiters for input and output strings. * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively. * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints. */ @@ -349,27 +355,27 @@ box_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); BOX *box = (BOX *) palloc(sizeof(BOX)); bool isopen; double x, y; path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str); /* reorder corners if necessary... */ - if (box->high.x < box->low.x) + if (FLOAT_LT(box->high.x, box->low.x)) { x = box->high.x; box->high.x = box->low.x; box->low.x = x; } - if (box->high.y < box->low.y) + if (FLOAT_LT(box->high.y, box->low.y)) { y = box->high.y; box->high.y = box->low.y; box->low.y = y; } PG_RETURN_BOX_P(box); } /* box_out - convert a box to external form. @@ -394,27 +400,27 @@ box_recv(PG_FUNCTION_ARGS) y; box = (BOX *) palloc(sizeof(BOX)); box->high.x = pq_getmsgfloat8(buf); box->high.y = pq_getmsgfloat8(buf); box->low.x = pq_getmsgfloat8(buf); box->low.y = pq_getmsgfloat8(buf); /* reorder corners if necessary... */ - if (box->high.x < box->low.x) + if (FLOAT_LT(box->high.x, box->low.x)) { x = box->high.x; box->high.x = box->low.x; box->low.x = x; } - if (box->high.y < box->low.y) + if (FLOAT_LT(box->high.y, box->low.y)) { y = box->high.y; box->high.y = box->low.y; box->low.y = y; } PG_RETURN_BOX_P(box); } /* @@ -444,31 +450,31 @@ box_construct(double x1, double x2, double y1, double y2) return box_fill(result, x1, x2, y1, y2); } /* box_fill - fill in a given box struct */ static BOX * box_fill(BOX *result, double x1, double x2, double y1, double y2) { - if (x1 > x2) + if (FLOAT_GT(x1, x2)) { result->high.x = x1; result->low.x = x2; } else { result->high.x = x2; result->low.x = x1; } - if (y1 > y2) + if (FLOAT_GT(y1, y2)) { result->high.y = y1; result->low.y = y2; } else { result->high.y = y2; result->low.y = y1; } @@ -495,246 +501,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(FLOAT_EQ(box1->high.x, box2->high.x) && + FLOAT_EQ(box1->low.x, box2->low.x) && + FLOAT_EQ(box1->high.y, box2->high.y) && + FLOAT_EQ(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 (FLOAT_LE(box1->low.x, box2->high.x) && + FLOAT_LE(box2->low.x, box1->high.x) && + FLOAT_LE(box1->low.y, box2->high.y) && + FLOAT_LE(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(FLOAT_LT(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(FLOAT_LE(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(FLOAT_GT(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(FLOAT_GE(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(FLOAT_LT(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(FLOAT_LE(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(FLOAT_GT(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(FLOAT_GE(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(FLOAT_LE(box1->high.x, box2->high.x) && + FLOAT_GE(box1->low.x, box2->low.x) && + FLOAT_LE(box1->high.y, box2->high.y) && + FLOAT_GE(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(FLOAT_GE(box1->high.x, box2->high.x) && + FLOAT_LE(box1->low.x, box2->low.x) && + FLOAT_GE(box1->high.y, box2->high.y) && + FLOAT_LE(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(FLOAT_LE(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(FLOAT_GE(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(FLOAT_LT(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(FLOAT_GT(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(FLOAT_EQ(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(FLOAT_LE(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(FLOAT_GE(box_ar(box1), box_ar(box2))); } /*---------------------------------------------------------- * "Arithmetic" operators on boxes. *---------------------------------------------------------*/ /* box_area - returns the area of the box. */ Datum @@ -777,21 +783,21 @@ Datum box_distance(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); Point a, b; box_cn(&a, box1); box_cn(&b, box2); - PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y)); + PG_RETURN_FLOAT8(point_dt(&a, &b)); } /* box_center - returns the center point of the box. */ Datum box_center(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *result = (Point *) palloc(sizeof(Point)); @@ -809,22 +815,28 @@ box_ar(BOX *box) { return box_wd(box) * box_ht(box); } /* box_cn - stores the centerpoint of the box into *center. */ static void box_cn(Point *center, BOX *box) { - center->x = (box->high.x + box->low.x) / 2.0; - center->y = (box->high.y + box->low.y) / 2.0; + double sumx; + double sumy; + + FLOAT_PL(sumx, box->high.x, box->low.x); + FLOAT_DIV(center->x, sumx, 2.0); + + FLOAT_PL(sumy, box->high.y, box->low.y); + FLOAT_DIV(center->y, sumy, 2.0); } /* box_wd - returns the width (length) of the box * (horizontal magnitude). */ static double box_wd(BOX *box) { return box->high.x - box->low.x; @@ -854,24 +866,24 @@ box_intersect(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); BOX *result; if (!box_ov(box1, box2)) PG_RETURN_NULL(); result = (BOX *) palloc(sizeof(BOX)); - result->high.x = Min(box1->high.x, box2->high.x); - result->low.x = Max(box1->low.x, box2->low.x); - result->high.y = Min(box1->high.y, box2->high.y); - result->low.y = Max(box1->low.y, box2->low.y); + result->high.x = FLOAT_MIN(box1->high.x, box2->high.x); + result->low.x = FLOAT_MAX(box1->low.x, box2->low.x); + result->high.y = FLOAT_MIN(box1->high.y, box2->high.y); + result->low.y = FLOAT_MAX(box1->low.y, box2->low.y); PG_RETURN_BOX_P(result); } /* box_diagonal - * returns a line segment which happens to be the * positive-slope diagonal of "box". */ Datum @@ -908,48 +920,51 @@ line_decode(char *s, const char *str, LINE *line) s++; if (*s != '\0') return false; return true; } Datum line_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); - LINE *line = (LINE *) palloc(sizeof(LINE)); + LINE *line; LSEG lseg; bool isopen; char *s; s = str; while (isspace((unsigned char) *s)) s++; if (*s == '{') { + line = (LINE *) palloc(sizeof(LINE)); + 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 (FLOAT_EQ(line->A, 0.0) && FLOAT_EQ(line->B, 0.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 (FLOAT_EQ(lseg.p[0].x, lseg.p[1].x) && + FLOAT_EQ(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]); + line = line_construct_pts(&lseg.p[0], &lseg.p[1]); } PG_RETURN_LINE_P(line); } Datum line_out(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); @@ -968,20 +983,25 @@ line_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); LINE *line; line = (LINE *) palloc(sizeof(LINE)); line->A = pq_getmsgfloat8(buf); line->B = pq_getmsgfloat8(buf); line->C = pq_getmsgfloat8(buf); + if (FLOAT_EQ(line->A, 0.0) && FLOAT_EQ(line->B, 0.0)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid line specification: A and B cannot both be zero"))); + PG_RETURN_LINE_P(line); } /* * line_send - converts line to binary format */ Datum line_send(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); @@ -1000,93 +1020,101 @@ line_send(PG_FUNCTION_ARGS) * Internal form: Ax+By+C=0 *---------------------------------------------------------*/ /* line_construct_pm() * point-slope */ static LINE * line_construct_pm(Point *pt, double m) { LINE *result = (LINE *) palloc(sizeof(LINE)); + double val; - if (m == DBL_MAX) + if (FLOAT_EQ(m, DBL_MAX)) { /* vertical - use "x = C" */ - result->A = -1; - result->B = 0; + result->A = -1.0; + result->B = 0.0; result->C = pt->x; } else { - /* use "mx - y + yinter = 0" */ result->A = m; result->B = -1.0; - result->C = pt->y - m * pt->x; + FLOAT_MUL(val, m, pt->x); + FLOAT_MI(result->C, pt->y, val); } return result; } /* * Fill already-allocated LINE struct from two points on the line */ -static void -line_construct_pts(LINE *line, Point *pt1, Point *pt2) +static LINE * +line_construct_pts(Point *pt1, Point *pt2) { - if (FPeq(pt1->x, pt2->x)) + LINE *result = (LINE *) palloc(sizeof(LINE)); + + if (FLOAT_EQ(pt1->x, pt2->x)) { /* vertical */ /* use "x = C" */ - line->A = -1; - line->B = 0; - line->C = pt1->x; + result->A = -1.0; + result->B = 0.0; + result->C = pt1->x; #ifdef GEODEBUG printf("line_construct_pts- line is vertical\n"); #endif } - else if (FPeq(pt1->y, pt2->y)) + else if (FLOAT_EQ(pt1->y, pt2->y)) { /* horizontal */ /* use "y = C" */ - line->A = 0; - line->B = -1; - line->C = pt1->y; + result->A = 0.0; + result->B = -1.0; + result->C = pt1->y; #ifdef GEODEBUG printf("line_construct_pts- line is horizontal\n"); #endif } else { - /* use "mx - y + yinter = 0" */ - line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x); - line->B = -1.0; - line->C = pt1->y - line->A * pt1->x; - /* on some platforms, the preceding expression tends to produce -0 */ - if (line->C == 0.0) - line->C = 0.0; + double mul_x; + double mul_y; + + /* The equation is optimized to avoid losing precision by division. */ + FLOAT_MI(result->A, pt2->y, pt1->y); + FLOAT_MI(result->B, pt1->x, pt2->x); + FLOAT_MUL(mul_x, pt1->x, result->A); + FLOAT_MUL(mul_y, pt1->y, result->B); + FLOAT_PL(result->C, mul_x, mul_y); + if (FLOAT_NE(result->C, 0.0)) /* We don't want to get -0. */ + result->C = -result->C; + #ifdef GEODEBUG printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n", DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y)); #endif } + + return result; } /* line_construct_pp() * two points */ Datum line_construct_pp(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - LINE *result = (LINE *) palloc(sizeof(LINE)); - line_construct_pts(result, pt1, pt2); - PG_RETURN_LINE_P(result); + PG_RETURN_LINE_P(line_construct_pts(pt1, pt2)); } /*---------------------------------------------------------- * Relative position routines. *---------------------------------------------------------*/ Datum line_intersect(PG_FUNCTION_ARGS) { @@ -1096,102 +1124,139 @@ line_intersect(PG_FUNCTION_ARGS) PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))); } Datum line_parallel(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); + double mul12; + double mul21; - if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->B)); + if (FLOAT_EQ(l1->A, 0.0)) /* horizontal? */ + PG_RETURN_BOOL(FLOAT_EQ(l2->A, 0.0)); + if (FLOAT_EQ(l1->B, 0.0)) /* vertical? */ + PG_RETURN_BOOL(FLOAT_EQ(l2->B, 0.0)); - PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B))); + if (FLOAT_EQ(l2->A, 0.0) || FLOAT_EQ(l2->B, 0.0)) + PG_RETURN_BOOL(false); + + FLOAT_MUL(mul12, l1->A, l2->B); + FLOAT_MUL(mul21, l2->A, l1->B); + + PG_RETURN_BOOL(FLOAT_EQ(mul12, mul21)); } Datum line_perp(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); + double val1; + double val2; - if (FPzero(l1->A)) - PG_RETURN_BOOL(FPzero(l2->B)); - else if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->A)); + if (FLOAT_EQ(l1->A, 0.0)) /* horizontal? */ + PG_RETURN_BOOL(FLOAT_EQ(l2->B, 0.0)); + if (FLOAT_EQ(l1->B, 0.0)) /* vertical? */ + PG_RETURN_BOOL(FLOAT_EQ(l2->A, 0.0)); - PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0)); + if (FLOAT_EQ(l2->A, 0.0) || FLOAT_EQ(l2->B, 0.0)) + PG_RETURN_BOOL(false); + + FLOAT_MUL(val1, l1->A, l2->B); + FLOAT_MUL(val2, l2->A, l1->B); + + PG_RETURN_BOOL(FLOAT_EQ(val1, -val2)); } Datum line_vertical(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->B)); + PG_RETURN_BOOL(FLOAT_EQ(line->B, 0.0)); } Datum line_horizontal(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->A)); + PG_RETURN_BOOL(FLOAT_EQ(line->A, 0.0)); } Datum line_eq(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - double k; + double mul12; + double mul21; - 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; + FLOAT_MUL(mul12, l1->A, l2->B); + FLOAT_MUL(mul21, l2->A, l1->B); + if (FLOAT_NE(mul12, mul21)) + PG_RETURN_BOOL(false); - PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) && - FPeq(l1->B, k * l2->B) && - FPeq(l1->C, k * l2->C)); + if (FLOAT_NE(l1->A, 0.0)) + { + if (FLOAT_EQ(l2->A, 0.0)) + PG_RETURN_BOOL(false); + + FLOAT_MUL(mul12, l1->A, l2->C); + FLOAT_MUL(mul21, l2->A, l1->C); + } + else /* (l1->A == 0.0 => l1->B != 0.0 => l2->A == 0.0) */ + { + if (FLOAT_EQ(l2->B, 0.0)) + PG_RETURN_BOOL(false); + + FLOAT_MUL(mul12, l1->B, l2->C); + FLOAT_MUL(mul21, l2->B, l1->C); + } + + PG_RETURN_BOOL(FLOAT_EQ(mul12, mul21)); } /*---------------------------------------------------------- * Line arithmetic routines. *---------------------------------------------------------*/ /* line_distance() * Distance between two lines. */ Datum line_distance(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - float8 result; - Point *tmp; + double result; + double y; if (!DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))) PG_RETURN_FLOAT8(0.0); - if (FPzero(l1->B)) /* vertical? */ - PG_RETURN_FLOAT8(fabs(l1->C - l2->C)); - tmp = point_construct(0.0, l1->C); - result = dist_pl_internal(tmp, l2); + + if (FLOAT_EQ(l1->A, 0.0) || FLOAT_EQ(l1->B, 0.0)) /* horizontal or vertical? */ + { + FLOAT_MI(result, l1->C, l2->C); + } + else + { + FLOAT_DIV(y, -l1->C, l1->B); + result = dist_pl_internal(point_construct(0.0, y), l2); + } + PG_RETURN_FLOAT8(result); } /* line_interpt() * Point where two lines l1, l2 intersect (if any) */ Datum line_interpt(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); @@ -1207,48 +1272,69 @@ line_interpt(PG_FUNCTION_ARGS) /* * Internal version of line_interpt * * returns a NULL pointer if no intersection point */ static Point * line_interpt_internal(LINE *l1, LINE *l2) { Point *result; + double val1; + double val2; double x, y; /* * 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 (FLOAT_EQ(l1->B, 0.0)) /* l1 vertical? */ { - x = l1->C; - y = (l2->A * x + l2->C); - } - else if (FPzero(l2->B)) /* l2 vertical? */ - { - x = l2->C; - y = (l1->A * x + l1->C); + FLOAT_DIV(x, -l1->C, l1->A); + FLOAT_MUL(val1, l2->A, x); + FLOAT_PL(val2, val1, l2->C); + FLOAT_DIV(y, -val2, l2->B); } else { - x = (l1->C - l2->C) / (l2->A - l1->A); - y = (l1->A * x + l1->C); + if (FLOAT_EQ(l2->B, 0.0)) /* l2 vertical? */ + { + FLOAT_DIV(x, -l2->C, l2->A); + } + else + { + double mul12; + double mul21; + + FLOAT_MUL(mul12, l1->B, l2->C); + FLOAT_MUL(mul21, l2->B, l1->C); + FLOAT_MI(val1, mul12, mul21); + + FLOAT_MUL(mul12, l1->A, l2->B); + FLOAT_MUL(mul21, l2->A, l1->B); + FLOAT_MI(val2, mul12, mul21); + + FLOAT_DIV(x, val1, val2); + } + + FLOAT_MUL(val1, l1->A, x); + FLOAT_PL(val2, val1, l1->C); + FLOAT_DIV(y, -val2, l1->B); } + result = point_construct(x, y); #ifdef GEODEBUG printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n", DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C); printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y); #endif return result; } @@ -1274,35 +1360,40 @@ line_interpt_internal(LINE *l1, LINE *l2) * "[xcoord, ycoord,... ]" * Also support older format: * "(closed, npts, xcoord, ycoord,... )" *---------------------------------------------------------*/ Datum path_area(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P(0); double area = 0.0; + double mulxy; + double mulyx; + double new_area; int i, j; if (!path->closed) PG_RETURN_NULL(); for (i = 0; i < path->npts; i++) { j = (i + 1) % path->npts; - area += path->p[i].x * path->p[j].y; - area -= path->p[i].y * path->p[j].x; + FLOAT_MUL(mulxy, path->p[i].x, path->p[j].y); + FLOAT_MUL(mulyx, path->p[i].y, path->p[j].x); + FLOAT_PL(new_area, area, mulxy); + FLOAT_MI(area, new_area, mulyx); } - area *= 0.5; - PG_RETURN_FLOAT8(area < 0.0 ? -area : area); + FLOAT_MUL(new_area, area, 0.5); + PG_RETURN_FLOAT8(fabs(new_area)); } Datum path_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); PATH *path; bool isopen; char *s; @@ -1322,21 +1413,21 @@ path_in(PG_FUNCTION_ARGS) s++; /* skip single leading paren */ if ((*s == LDELIM) && (strrchr(s, LDELIM) == s)) { s++; depth++; } base_size = sizeof(path->p[0]) * npts; - size = offsetof(PATH, p) +base_size; + size = offsetof(PATH, p) + base_size; /* Check for integer overflow */ if (base_size / npts != sizeof(path->p[0]) || size <= base_size) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many points requested"))); path = (PATH *) palloc(size); SET_VARSIZE(path, size); @@ -1392,21 +1483,21 @@ path_recv(PG_FUNCTION_ARGS) int32 i; int size; closed = pq_getmsgbyte(buf); npts = pq_getmsgint(buf, sizeof(int32)); if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p)) / sizeof(Point))) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid number of points in external \"path\" value"))); - size = offsetof(PATH, p) +sizeof(path->p[0]) * npts; + size = offsetof(PATH, p) + sizeof(path->p[0]) * npts; path = (PATH *) palloc(size); SET_VARSIZE(path, size); path->npts = npts; path->closed = (closed ? 1 : 0); /* prevent instability in unused pad bytes */ path->dummy = 0; for (i = 0; i < npts; i++) { @@ -1519,31 +1610,31 @@ path_npoints(PG_FUNCTION_ARGS) PG_RETURN_INT32(path->npts); } Datum path_close(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); - path->closed = TRUE; + path->closed = true; PG_RETURN_PATH_P(path); } Datum path_open(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); - path->closed = FALSE; + path->closed = false; PG_RETURN_PATH_P(path); } /* path_inter - * Does p1 intersect p2 at any point? * Use bounding boxes for a quick (O(n)) check, then do a * O(n^2) iterative edge check. */ @@ -1559,33 +1650,33 @@ path_inter(PG_FUNCTION_ARGS) LSEG seg1, seg2; if (p1->npts <= 0 || p2->npts <= 0) PG_RETURN_BOOL(false); b1.high.x = b1.low.x = p1->p[0].x; b1.high.y = b1.low.y = p1->p[0].y; for (i = 1; i < p1->npts; i++) { - b1.high.x = Max(p1->p[i].x, b1.high.x); - b1.high.y = Max(p1->p[i].y, b1.high.y); - b1.low.x = Min(p1->p[i].x, b1.low.x); - b1.low.y = Min(p1->p[i].y, b1.low.y); + b1.high.x = FLOAT_MAX(p1->p[i].x, b1.high.x); + b1.high.y = FLOAT_MAX(p1->p[i].y, b1.high.y); + b1.low.x = FLOAT_MIN(p1->p[i].x, b1.low.x); + b1.low.y = FLOAT_MIN(p1->p[i].y, b1.low.y); } b2.high.x = b2.low.x = p2->p[0].x; b2.high.y = b2.low.y = p2->p[0].y; for (i = 1; i < p2->npts; i++) { - b2.high.x = Max(p2->p[i].x, b2.high.x); - b2.high.y = Max(p2->p[i].y, b2.high.y); - b2.low.x = Min(p2->p[i].x, b2.low.x); - b2.low.y = Min(p2->p[i].y, b2.low.y); + b2.high.x = FLOAT_MAX(p2->p[i].x, b2.high.x); + b2.high.y = FLOAT_MAX(p2->p[i].y, b2.high.y); + b2.low.x = FLOAT_MIN(p2->p[i].x, b2.low.x); + b2.low.y = FLOAT_MIN(p2->p[i].y, b2.low.y); } if (!box_ov(&b1, &b2)) PG_RETURN_BOOL(false); /* pairwise check lseg intersections */ for (i = 0; i < p1->npts; i++) { int iprev; if (i > 0) @@ -1663,21 +1754,21 @@ path_distance(PG_FUNCTION_ARGS) continue; jprev = p2->npts - 1; /* include the closure segment */ } statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]); statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]); tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance, LsegPGetDatum(&seg1), LsegPGetDatum(&seg2))); - if (!have_min || tmp < min) + if (!have_min || FLOAT_LT(tmp, min)) { min = tmp; have_min = true; } } } if (!have_min) PG_RETURN_NULL(); @@ -1686,38 +1777,43 @@ path_distance(PG_FUNCTION_ARGS) /*---------------------------------------------------------- * "Arithmetic" operations. *---------------------------------------------------------*/ Datum path_length(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P(0); + bool has_inf = false; + float8 distance; float8 result = 0.0; int i; for (i = 0; i < path->npts; i++) { int iprev; if (i > 0) iprev = i - 1; else { if (!path->closed) continue; iprev = path->npts - 1; /* include the closure segment */ } - result += point_dt(&path->p[iprev], &path->p[i]); + distance = point_dt(&path->p[iprev], &path->p[i]); + has_inf |= isinf(distance); + result += distance; } + CHECKFLOATVAL(result, has_inf, true); PG_RETURN_FLOAT8(result); } /*********************************************************************** ** ** Routines for 2D points. ** ***********************************************************************/ @@ -1746,26 +1842,23 @@ point_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(path_encode(PATH_NONE, 1, pt)); } /* * point_recv - converts external binary format to point */ Datum point_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - Point *point; - point = (Point *) palloc(sizeof(Point)); - point->x = pq_getmsgfloat8(buf); - point->y = pq_getmsgfloat8(buf); - PG_RETURN_POINT_P(point); + PG_RETURN_POINT_P(point_construct(pq_getmsgfloat8(buf), + pq_getmsgfloat8(buf))); } /* * point_send - converts point to binary format */ Datum point_send(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); StringInfoData buf; @@ -1784,153 +1877,162 @@ point_construct(double x, double y) result->x = x; result->y = y; return result; } static Point * point_copy(Point *pt) { - Point *result; - - if (!PointerIsValid(pt)) - return NULL; - - result = (Point *) palloc(sizeof(Point)); - - result->x = pt->x; - result->y = pt->y; - return result; + return point_construct(pt->x, pt->y); } /*---------------------------------------------------------- * Relational operators for Points. * Since we do have a sense of coordinates being * "equal" to a given accuracy (point_vert, point_horiz), * the other ops must preserve that sense. This means * 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(FLOAT_LT(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(FLOAT_GT(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(FLOAT_GT(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(FLOAT_LT(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(FLOAT_EQ(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(FLOAT_EQ(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(FLOAT_EQ(pt1->x, pt2->x) && FLOAT_EQ(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(FLOAT_NE(pt1->x, pt2->x) || FLOAT_NE(pt1->y, pt2->y)); } /*---------------------------------------------------------- * "Arithmetic" operators on points. *---------------------------------------------------------*/ Datum point_distance(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y)); + PG_RETURN_FLOAT8(point_dt(pt1, pt2)); } -double +static double point_dt(Point *pt1, Point *pt2) { + double xdiff, + ydiff, + result; + + FLOAT_MI(xdiff, pt1->x, pt2->x); + FLOAT_MI(ydiff, pt1->y, pt2->y); + FLOAT_HYPOT(result, xdiff, ydiff); + #ifdef GEODEBUG printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n", - pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y)); + pt1->x, pt1->y, pt2->x, pt2->y, result); #endif - return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y); + + return result; } Datum 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)); + PG_RETURN_FLOAT8(slope(pt1->x, pt2->x, pt1->y, pt2->y)); } double -point_sl(Point *pt1, Point *pt2) +slope(double x1, double x2, double y1, double y2) { - return (FPeq(pt1->x, pt2->x) - ? (double) DBL_MAX - : (pt1->y - pt2->y) / (pt1->x - pt2->x)); + double xdiff; + double ydiff; + double result; + + if (FLOAT_EQ(x1, x2)) + return DBL_MAX; + + FLOAT_MI(xdiff, x1, x2); + FLOAT_MI(ydiff, y1, y2); + FLOAT_DIV(result, ydiff, xdiff); + + return result; } /*********************************************************************** ** ** Routines for 2D line segments. ** ***********************************************************************/ /*---------------------------------------------------------- @@ -2002,24 +2104,21 @@ lseg_send(PG_FUNCTION_ARGS) /* lseg_construct - * form a LSEG from two Points. */ Datum lseg_construct(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); LSEG *result = (LSEG *) palloc(sizeof(LSEG)); - result->p[0].x = pt1->x; - result->p[0].y = pt1->y; - result->p[1].x = pt2->x; - result->p[1].y = pt2->y; + statlseg_construct(result, pt1, pt2); PG_RETURN_LSEG_P(result); } /* like lseg_construct, but assume space already allocated */ static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2) { lseg->p[0].x = pt1->x; lseg->p[0].y = pt1->y; @@ -2048,154 +2147,146 @@ lseg_intersect(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); PG_RETURN_BOOL(lseg_intersect_internal(l1, l2)); } static bool lseg_intersect_internal(LSEG *l1, LSEG *l2) { - LINE ln; Point *interpt; - bool retval; - line_construct_pts(&ln, &l2->p[0], &l2->p[1]); - interpt = interpt_sl(l1, &ln); + interpt = line_interpt_internal(line_construct_pts(&l1->p[0], &l1->p[1]), + line_construct_pts(&l2->p[0], &l2->p[1])); - if (interpt != NULL && on_ps_internal(interpt, l2)) - retval = true; /* interpt on l1 and l2 */ - else - retval = false; - return retval; + return (interpt != NULL && + point_lseg_cmp(interpt, l1) == 0 && + point_lseg_cmp(interpt, l2) == 0); } Datum lseg_parallel(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]), - point_sl(&l2->p[0], &l2->p[1]))); + PG_RETURN_BOOL(FLOAT_EQ(slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y), + slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y))); } /* 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 - * returned by point_sl() and the results seem better. + * returned by slope() and the results seem better. * - thomas 1998-01-31 */ Datum lseg_perp(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); 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])); + m1 = slope(l1->p[0].x, l1->p[1].x, l1->p[0].y, l1->p[1].y); + m2 = slope(l2->p[0].x, l2->p[1].x, l2->p[0].y, l2->p[1].y); #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)); - PG_RETURN_BOOL(FPeq(m1 / m2, -1.0)); + PG_RETURN_BOOL(FLOAT_EQ(m1, -m2)); } 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(FLOAT_EQ(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(FLOAT_EQ(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(FLOAT_EQ(l1->p[0].x, l2->p[0].x) && + FLOAT_EQ(l1->p[0].y, l2->p[0].y) && + FLOAT_EQ(l1->p[1].x, l2->p[1].x) && + FLOAT_EQ(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(FLOAT_NE(l1->p[0].x, l2->p[0].x) || + FLOAT_NE(l1->p[0].y, l2->p[0].y) || + FLOAT_NE(l1->p[1].x, l2->p[1].x) || + FLOAT_NE(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(FLOAT_LT(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(FLOAT_LE(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(FLOAT_GT(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(FLOAT_GE(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 @@ -2217,92 +2308,78 @@ lseg_distance(PG_FUNCTION_ARGS) */ static double lseg_dt(LSEG *l1, LSEG *l2) { double result, d; if (lseg_intersect_internal(l1, l2)) return 0.0; - d = dist_ps_internal(&l1->p[0], l2); - result = d; + result = dist_ps_internal(&l1->p[0], l2); d = dist_ps_internal(&l1->p[1], l2); - result = Min(result, d); + if (FLOAT_LT(d, result)) + result = d; d = dist_ps_internal(&l2->p[0], l1); - result = Min(result, d); + if (FLOAT_LT(d, result)) + result = d; d = dist_ps_internal(&l2->p[1], l1); - result = Min(result, d); + if (FLOAT_LT(d, result)) + result = d; return result; } Datum lseg_center(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); - Point *result; - result = (Point *) palloc(sizeof(Point)); + PG_RETURN_POINT_P(lseg_center_internal(lseg)); +} - result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0; - result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0; +static Point * +lseg_center_internal(LSEG *lseg) +{ + double xsum; + double ysum; + double x; + double y; - PG_RETURN_POINT_P(result); + FLOAT_PL(xsum, lseg->p[0].x, lseg->p[1].x); + FLOAT_PL(ysum, lseg->p[0].y, lseg->p[1].y); + FLOAT_DIV(x, xsum, 2.0); + FLOAT_DIV(y, ysum, 2.0); + + return point_construct(x, y); } static Point * lseg_interpt_internal(LSEG *l1, LSEG *l2) { Point *result; - LINE tmp1, - tmp2; - /* - * Find the intersection of the appropriate lines, if any. - */ - line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]); - line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]); - result = line_interpt_internal(&tmp1, &tmp2); + /* Find the intersection of the appropriate lines, if any */ + result = line_interpt_internal(line_construct_pts(&l1->p[0], &l1->p[1]), + line_construct_pts(&l2->p[0], &l2->p[1])); if (!PointerIsValid(result)) return NULL; - /* - * If the line intersection point isn't within l1 (or equivalently l2), - * there is no valid segment intersection point at all. - */ - if (!on_ps_internal(result, l1) || - !on_ps_internal(result, l2)) + /* Test if the point extend the segments of the lines */ + if (point_lseg_cmp(result, l1) != 0 || + point_lseg_cmp(result, l2) != 0) { 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 - */ - 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))) - { - result->x = l1->p[1].x; - result->y = l1->p[1].y; - } - return result; } /* lseg_interpt - * Find the intersection point of two segments (if any). */ Datum lseg_interpt(PG_FUNCTION_ARGS) { LSEG *l1 = PG_GETARG_LSEG_P(0); @@ -2336,22 +2413,29 @@ dist_pl(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); PG_RETURN_FLOAT8(dist_pl_internal(pt, line)); } static double dist_pl_internal(Point *pt, LINE *line) { - return fabs((line->A * pt->x + line->B * pt->y + line->C) / - HYPOT(line->A, line->B)); + double val; + double hyp; + double result; + + val = point_on_line_value(pt, line); + FLOAT_HYPOT(hyp, line->A, line->B); + FLOAT_DIV(result, val, hyp); + + return fabs(result); } /* * Distance from a point to a lseg */ Datum dist_ps(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); @@ -2365,69 +2449,65 @@ dist_ps_internal(Point *pt, LSEG *lseg) double m; /* slope of perp. */ LINE *ln; double result, tmpdist; Point *ip; /* * Construct a line perpendicular to the input segment and through the * input point */ - if (lseg->p[1].x == lseg->p[0].x) - m = 0; - else if (lseg->p[1].y == lseg->p[0].y) - m = (double) DBL_MAX; /* slope is infinite */ - else - m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y); + m = slope(lseg->p[1].y, lseg->p[0].y, lseg->p[0].x, lseg->p[1].x); ln = line_construct_pm(pt, m); #ifdef GEODEBUG printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n", ln->A, ln->B, ln->C, pt->x, pt->y, m); #endif /* * Calculate distance to the line segment or to the nearest endpoint of * the segment. */ /* intersection is on the line segment? */ - if ((ip = interpt_sl(lseg, ln)) != NULL) + ip = interpt_sl(lseg, ln); + if (ip != NULL) { /* yes, so use distance to the intersection point */ result = point_dt(pt, ip); #ifdef GEODEBUG printf("dist_ps- distance is %f to intersection point is (%f,%f)\n", result, ip->x, ip->y); #endif } else { /* no, so use distance to the nearer endpoint */ result = point_dt(pt, &lseg->p[0]); tmpdist = point_dt(pt, &lseg->p[1]); - if (tmpdist < result) + if (FLOAT_LT(tmpdist, result)) result = tmpdist; } return result; } /* * Distance from a point to a path */ Datum dist_ppath(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); PATH *path = PG_GETARG_PATH_P(1); - float8 result = 0.0; /* keep compiler quiet */ + float8 result; bool have_min = false; float8 tmp; int i; LSEG lseg; switch (path->npts) { case 0: /* no points in path? then result is undefined... */ PG_RETURN_NULL(); @@ -2436,36 +2516,37 @@ dist_ppath(PG_FUNCTION_ARGS) result = point_dt(pt, &path->p[0]); break; default: /* make sure the path makes sense... */ Assert(path->npts > 1); /* * the distance from a point to a path is the smallest distance * from the point to any of its constituent segments. */ + result = 0.0; for (i = 0; i < path->npts; i++) { int iprev; if (i > 0) iprev = i - 1; else { if (!path->closed) continue; iprev = path->npts - 1; /* include the closure segment */ } statlseg_construct(&lseg, &path->p[iprev], &path->p[i]); tmp = dist_ps_internal(pt, &lseg); - if (!have_min || tmp < result) + if (!have_min || FLOAT_LT(tmp, result)) { result = tmp; have_min = true; } } break; } PG_RETURN_FLOAT8(result); } @@ -2498,22 +2579,21 @@ dist_sl(PG_FUNCTION_ARGS) LINE *line = PG_GETARG_LINE_P(1); float8 result, d2; if (has_interpt_sl(lseg, line)) result = 0.0; else { result = dist_pl_internal(&lseg->p[0], line); d2 = dist_pl_internal(&lseg->p[1], line); - /* XXX shouldn't we take the min not max? */ - if (d2 > result) + if (FLOAT_LT(d2, result)) result = d2; } PG_RETURN_FLOAT8(result); } /* * Distance from a lseg to a box */ Datum @@ -2554,28 +2634,28 @@ dist_lb(PG_FUNCTION_ARGS) } /* * Distance from a circle to a polygon */ Datum dist_cpoly(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); POLYGON *poly = PG_GETARG_POLYGON_P(1); + float8 dist; float8 result; /* calculate distance to center, and subtract radius */ - result = dist_ppoly_internal(&circle->center, poly); - - result -= circle->radius; - if (result < 0) - result = 0; + dist = dist_ppoly_internal(&circle->center, poly); + FLOAT_MI(result, dist, circle->radius); + if (FLOAT_LT(result, 0.0)) + result = 0.0; PG_RETURN_FLOAT8(result); } /* * Distance from a point to a polygon */ Datum dist_ppoly(PG_FUNCTION_ARGS) { @@ -2630,56 +2710,54 @@ dist_ppoly_internal(Point *pt, POLYGON *poly) for (i = 0; (i < poly->npts - 1); i++) { seg.p[0].x = poly->p[i].x; seg.p[0].y = poly->p[i].y; seg.p[1].x = poly->p[i + 1].x; seg.p[1].y = poly->p[i + 1].y; d = dist_ps_internal(pt, &seg); #ifdef GEODEBUG printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d); #endif - if (d < result) + if (FLOAT_LT(d, result)) result = d; } return result; } /*--------------------------------------------------------------------- * interpt_ * Intersection point of objects. * We choose to ignore the "point" of intersection between * lines and boxes, since there are typically two. *-------------------------------------------------------------------*/ /* Get intersection point of lseg and line; returns NULL if no intersection */ static Point * interpt_sl(LSEG *lseg, LINE *line) { - LINE tmp; Point *p; - line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]); - p = line_interpt_internal(&tmp, line); + line_construct_pts(&lseg->p[0], &lseg->p[1]); + p = line_interpt_internal(line_construct_pts(&lseg->p[0], &lseg->p[1]), + line); #ifdef GEODEBUG printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n", DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y); - printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n", - DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C); #endif if (PointerIsValid(p)) { #ifdef GEODEBUG printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y); #endif - if (on_ps_internal(p, lseg)) + if (point_lseg_cmp(p, lseg) == 0) { #ifdef GEODEBUG printf("interpt_sl- intersection point is on segment\n"); #endif } else p = NULL; } return p; @@ -2704,174 +2782,81 @@ has_interpt_sl(LSEG *lseg, LINE *line) /* close_pl - * The intersection point of a perpendicular of the line * through the point. */ Datum close_pl(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); + + PG_RETURN_POINT_P(close_pl_internal(pt, line)); +} + +static Point * +close_pl_internal(Point *pt, LINE *line) +{ Point *result; - LINE *tmp; - double invm; + double val; - result = (Point *) palloc(sizeof(Point)); - - if (FPzero(line->B)) /* vertical? */ + if (FLOAT_EQ(line->B, 0.0)) /* vertical? */ { - result->x = line->C; - result->y = pt->y; - PG_RETURN_POINT_P(result); + FLOAT_DIV(val, -line->C, line->A); + result = point_construct(val, pt->y); } - if (FPzero(line->A)) /* horizontal? */ + else if (FLOAT_EQ(line->A, 0.0)) /* horizontal? */ { - result->x = pt->x; - result->y = line->C; - PG_RETURN_POINT_P(result); + FLOAT_DIV(val, -line->C, line->B); + result = point_construct(val, pt->y); + } + else + { + /* + * Drop a perpendicular and find the intersection point + * + * We need to invert and flip the sign on the slope to get + * the perpendicular. line_interpt_internal() returns NULL, + * when the lines are parallel. We might lose some precision + * on the division, but it cannot be as much to turn the line. + */ + FLOAT_DIV(val, line->B, line->A); + result = line_interpt_internal(line_construct_pm(pt, val), line); + Assert(result != NULL); } - /* 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); - result = line_interpt_internal(tmp, line); - Assert(result != NULL); - PG_RETURN_POINT_P(result); + return result; } -/* close_ps() - * Closest point on line segment to specified point. - * Take the closest endpoint if the point is left, right, - * above, or below the segment, otherwise find the intersection - * point of the segment and its perpendicular through the point. +/* + * Closest point on line segment to specified point * - * Some tricky code here, relying on boolean expressions - * evaluating to only zero or one to use as an array index. - * bug fixes by gthaker@atl.lmco.com; May 1, 1998 + * We find the closest point to the line, and then test if the point is + * on the line segment. If it is not, we return the closest endpoint + * of the line segment. */ Datum 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; + Point *result; + int order; -#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", - pt->x, pt->y, lseg->p[0].x, lseg->p[0].y, - lseg->p[1].x, lseg->p[1].y); -#endif + result = close_pl_internal(pt, line_construct_pts(&lseg->p[0], &lseg->p[1])); + order = point_lseg_cmp(result, lseg); - /* 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? */ - { -#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? */ - { -#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) - PG_RETURN_POINT_P(result); - - /* point lines along (at top or below) the horiz. lseg. */ - result = (Point *) palloc(sizeof(Point)); - result->x = pt->x; - result->y = lseg->p[0].y; - PG_RETURN_POINT_P(result); - } - - /* - * vert. and horiz. cases are down, now check if the closest point is one - * of the end points or someplace on the lseg. - */ - - invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1])); - tmp = line_construct_pm(&lseg->p[!yh], invm); /* lower edge of the - * "band" */ - if (pt->y < (tmp->A * pt->x + tmp->C)) - { /* we are below the lower edge */ - result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower - * end pt */ -#ifdef GEODEBUG - printf("close_ps below: tmp A %f B %f C %f\n", - tmp->A, tmp->B, tmp->C); -#endif - PG_RETURN_POINT_P(result); - } - tmp = line_construct_pm(&lseg->p[yh], invm); /* upper edge of the - * "band" */ - if (pt->y > (tmp->A * pt->x + tmp->C)) - { /* we are below the lower edge */ - result = point_copy(&lseg->p[yh]); /* above the lseg, take higher - * end pt */ -#ifdef GEODEBUG - printf("close_ps above: tmp A %f B %f C %f\n", - tmp->A, tmp->B, tmp->C); -#endif - PG_RETURN_POINT_P(result); - } - - /* - * at this point the "normal" from point will hit lseg. The closest point - * will be somewhere on the lseg - */ - tmp = line_construct_pm(pt, invm); -#ifdef GEODEBUG - printf("close_ps- tmp A %f B %f C %f\n", - tmp->A, tmp->B, tmp->C); -#endif - result = interpt_sl(lseg, tmp); - - /* - * ordinarily we should always find an intersection point, but that could - * fail in the presence of NaN coordinates, and perhaps even from simple - * roundoff issues. Return a SQL NULL if so. - */ - if (result == NULL) - PG_RETURN_NULL(); - -#ifdef GEODEBUG - printf("close_ps- result.x %f result.y %f\n", result->x, result->y); -#endif + if (order < 0) + PG_RETURN_POINT_P(point_copy(&lseg->p[0])); + if (order > 0) + PG_RETURN_POINT_P(point_copy(&lseg->p[1])); PG_RETURN_POINT_P(result); } /* close_lseg() * Closest point to l1 on l2. */ Datum close_lseg(PG_FUNCTION_ARGS) { @@ -2879,38 +2864,39 @@ close_lseg(PG_FUNCTION_ARGS) LSEG *l2 = PG_GETARG_LSEG_P(1); Point *result = NULL; Point point; double dist; double d; d = dist_ps_internal(&l1->p[0], l2); dist = d; memcpy(&point, &l1->p[0], sizeof(Point)); - if ((d = dist_ps_internal(&l1->p[1], l2)) < dist) + d = dist_ps_internal(&l1->p[1], l2); + if (FLOAT_LT(d, dist)) { dist = d; memcpy(&point, &l1->p[1], sizeof(Point)); } - if (dist_ps_internal(&l2->p[0], l1) < dist) + if (FLOAT_LT(dist_ps_internal(&l2->p[0], l1), dist)) { result = DatumGetPointP(DirectFunctionCall2(close_ps, PointPGetDatum(&l2->p[0]), LsegPGetDatum(l1))); memcpy(&point, result, sizeof(Point)); result = DatumGetPointP(DirectFunctionCall2(close_ps, PointPGetDatum(&point), LsegPGetDatum(l2))); } - if (dist_ps_internal(&l2->p[1], l1) < dist) + if (FLOAT_LT(dist_ps_internal(&l2->p[1], l1), dist)) { result = DatumGetPointP(DirectFunctionCall2(close_ps, PointPGetDatum(&l2->p[1]), LsegPGetDatum(l1))); memcpy(&point, result, sizeof(Point)); result = DatumGetPointP(DirectFunctionCall2(close_ps, PointPGetDatum(&point), LsegPGetDatum(l2))); } @@ -2939,37 +2925,40 @@ close_pb(PG_FUNCTION_ARGS) BoxPGetDatum(box)))) PG_RETURN_POINT_P(pt); /* pairwise check lseg distances */ point.x = box->low.x; point.y = box->high.y; statlseg_construct(&lseg, &box->low, &point); dist = dist_ps_internal(pt, &lseg); statlseg_construct(&seg, &box->high, &point); - if ((d = dist_ps_internal(pt, &seg)) < dist) + d = dist_ps_internal(pt, &seg); + if (FLOAT_LT(d, dist)) { dist = d; memcpy(&lseg, &seg, sizeof(lseg)); } point.x = box->high.x; point.y = box->low.y; statlseg_construct(&seg, &box->low, &point); - if ((d = dist_ps_internal(pt, &seg)) < dist) + d = dist_ps_internal(pt, &seg); + if (FLOAT_LT(d, dist)) { dist = d; memcpy(&lseg, &seg, sizeof(lseg)); } statlseg_construct(&seg, &box->high, &point); - if ((d = dist_ps_internal(pt, &seg)) < dist) + d = dist_ps_internal(pt, &seg); + if (FLOAT_LT(d, dist)) { dist = d; memcpy(&lseg, &seg, sizeof(lseg)); } PG_RETURN_DATUM(DirectFunctionCall2(close_ps, PointPGetDatum(pt), LsegPGetDatum(&lseg))); } @@ -2991,21 +2980,21 @@ close_sl(PG_FUNCTION_ARGS) Point *result; float8 d1, d2; result = interpt_sl(lseg, line); if (result) PG_RETURN_POINT_P(result); d1 = dist_pl_internal(&lseg->p[0], line); d2 = dist_pl_internal(&lseg->p[1], line); - if (d1 < d2) + if (FLOAT_LT(d1, d2)) result = point_copy(&lseg->p[0]); else result = point_copy(&lseg->p[1]); PG_RETURN_POINT_P(result); #endif ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function \"close_sl\" not implemented"))); @@ -3024,21 +3013,21 @@ close_ls(PG_FUNCTION_ARGS) Point *result; float8 d1, d2; result = interpt_sl(lseg, line); if (result) PG_RETURN_POINT_P(result); d1 = dist_pl_internal(&lseg->p[0], line); d2 = dist_pl_internal(&lseg->p[1], line); - if (d1 < d2) + if (FLOAT_LT(d1, d2)) result = point_copy(&lseg->p[0]); else result = point_copy(&lseg->p[1]); PG_RETURN_POINT_P(result); } /* close_sb() * Closest point on or in box to line segment. */ @@ -3064,37 +3053,40 @@ close_sb(PG_FUNCTION_ARGS) LsegPGetDatum(lseg))); } /* pairwise check lseg distances */ point.x = box->low.x; point.y = box->high.y; statlseg_construct(&bseg, &box->low, &point); dist = lseg_dt(lseg, &bseg); statlseg_construct(&seg, &box->high, &point); - if ((d = lseg_dt(lseg, &seg)) < dist) + d = lseg_dt(lseg, &seg); + if (FLOAT_LT(d, dist)) { dist = d; memcpy(&bseg, &seg, sizeof(bseg)); } point.x = box->high.x; point.y = box->low.y; statlseg_construct(&seg, &box->low, &point); - if ((d = lseg_dt(lseg, &seg)) < dist) + d = lseg_dt(lseg, &seg); + if (FLOAT_LE(d, dist)) { dist = d; memcpy(&bseg, &seg, sizeof(bseg)); } statlseg_construct(&seg, &box->high, &point); - if ((d = lseg_dt(lseg, &seg)) < dist) + d = lseg_dt(lseg, &seg); + if (FLOAT_LE(d, dist)) { dist = d; memcpy(&bseg, &seg, sizeof(bseg)); } /* OK, we now have the closest line segment on the box boundary */ PG_RETURN_DATUM(DirectFunctionCall2(close_lseg, LsegPGetDatum(lseg), LsegPGetDatum(&bseg))); } @@ -3113,71 +3105,152 @@ close_lb(PG_FUNCTION_ARGS) errmsg("function \"close_lb\" not implemented"))); PG_RETURN_NULL(); } /*--------------------------------------------------------------------- * on_ * Whether one object lies completely within another. *-------------------------------------------------------------------*/ -/* on_pl - - * Does the point satisfy the equation? +/* + * Test if the point satisfies the line 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(point_on_line_value(pt, line) == 0); } - -/* on_ps - - * Determine colinearity 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)); } +/* + * Test if the point is on the line segment + * + * We are first comparing the point with the line segment, even though + * this comparison makes no sense when the point is not on the line. + * The reason of it is that this check is cheaper than constructing + * the line and validating the line equation. + */ static bool on_ps_internal(Point *pt, LSEG *lseg) { - return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]), - point_dt(&lseg->p[0], &lseg->p[1])); + return (point_lseg_cmp(pt, lseg) == 0 && + FLOAT_EQ(point_on_line_value(pt, + line_construct_pts(&lseg->p[0], &lseg->p[1])), + 0.0)); +} + +/* + * Calculate the line equation for a point + * + * This returns the result of the line equation Ax + By + C. The result + * needs to be 0 for the point to be on the line. + */ +static double +point_on_line_value(Point *pt, LINE *line) +{ + double mulx; + double muly; + double sumxy; + double result; + + FLOAT_MUL(mulx, line->A, pt->x); + FLOAT_MUL(muly, line->B, pt->y); + FLOAT_PL(sumxy, mulx, muly); + FLOAT_PL(result, sumxy, line->C); + + return result; +} + +/* + * Compare a point with a line segment + * + * This function is useful when the point and line segment are on + * the same line. It returns + * + * * -1, if the point extends the first edge of the segment + * * 0, if the point is on the segment + * * 1, if the point extends the last edge of the segment. + * + * This check is not as trivial as checking if a point is inside a box, + * because the edges of the line segments are not normalised. We are + * doing the same checks for both x and y coordinates, to be correct + * when one of the coordinates of the point is on one edge of the segment. + */ +static int +point_lseg_cmp(Point *pt, LSEG *lseg) +{ + if (FLOAT_LT(lseg->p[0].x, lseg->p[1].x)) + { + if (FLOAT_LT(pt->x, lseg->p[0].x)) + return -1; + if (FLOAT_GT(pt->x, lseg->p[1].x)) + return 1; + } + else if (FLOAT_GT(lseg->p[0].x, lseg->p[1].x)) + { + if (FLOAT_GT(pt->x, lseg->p[0].x)) + return -1; + if (FLOAT_LT(pt->x, lseg->p[1].x)) + return 1; + } + else if (FLOAT_LE(lseg->p[0].y, lseg->p[1].y)) + { + if (FLOAT_LT(pt->y, lseg->p[0].y)) + return -1; + if (FLOAT_GT(pt->y, lseg->p[1].y)) + return 1; + } + else + { + if (FLOAT_GT(pt->y, lseg->p[0].y)) + return -1; + if (FLOAT_LT(pt->y, lseg->p[1].y)) + return 1; + } + + return 0; } Datum on_pb(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); BOX *box = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x && - pt->y <= box->high.y && pt->y >= box->low.y); + PG_RETURN_BOOL(FLOAT_LE(pt->x, box->high.x) && + FLOAT_GE(pt->x, box->low.x) && + FLOAT_LE(pt->y, box->high.y) && + FLOAT_GE(pt->y, box->low.y)); } Datum box_contain_pt(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *pt = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x && - pt->y <= box->high.y && pt->y >= box->low.y); + PG_RETURN_BOOL(FLOAT_LE(pt->x, box->high.x) && + FLOAT_GE(pt->x, box->low.x) && + FLOAT_LE(pt->y, box->high.y) && + FLOAT_GE(pt->y, box->low.y)); } /* on_ppath - * Whether a point lies within (on) a polyline. * If open, we have to (groan) check each segment. * (uses same algorithm as for point intersecting segment - tgl 1997-07-09) * If closed, we use the old O(n) ray method for point-in-polygon. * The ray is horizontal, from pt out to the right. * Each segment that crosses the ray counts as an * intersection; note that an endpoint or edge may touch @@ -3195,22 +3268,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 (FLOAT_EQ(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); } @@ -3268,24 +3340,24 @@ inter_sl(PG_FUNCTION_ARGS) */ Datum inter_sb(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); BOX *box = PG_GETARG_BOX_P(1); BOX lbox; LSEG bseg; Point point; - lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x); - lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y); - lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x); - lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y); + lbox.low.x = FLOAT_MIN(lseg->p[0].x, lseg->p[1].x); + lbox.low.y = FLOAT_MIN(lseg->p[0].y, lseg->p[1].y); + lbox.high.x = FLOAT_MAX(lseg->p[0].x, lseg->p[1].x); + lbox.high.y = FLOAT_MAX(lseg->p[0].y, lseg->p[1].y); /* nothing close to overlap? then not going to intersect */ if (!box_ov(&lbox, box)) PG_RETURN_BOOL(false); /* an endpoint of segment is inside box? then clearly intersects */ if (DatumGetBool(DirectFunctionCall2(on_pb, PointPGetDatum(&lseg->p[0]), BoxPGetDatum(box))) || DatumGetBool(DirectFunctionCall2(on_pb, @@ -3377,27 +3449,27 @@ make_bound_box(POLYGON *poly) y1, x2, y2; if (poly->npts > 0) { x2 = x1 = poly->p[0].x; y2 = y1 = poly->p[0].y; for (i = 1; i < poly->npts; i++) { - if (poly->p[i].x < x1) + if (FLOAT_LT(poly->p[i].x, x1)) x1 = poly->p[i].x; - if (poly->p[i].x > x2) + if (FLOAT_GT(poly->p[i].x, x2)) x2 = poly->p[i].x; - if (poly->p[i].y < y1) + if (FLOAT_LT(poly->p[i].y, y1)) y1 = poly->p[i].y; - if (poly->p[i].y > y2) + if (FLOAT_GT(poly->p[i].y, y2)) y2 = poly->p[i].y; } box_fill(&(poly->boundbox), x1, x2, y1, y2); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot create bounding box for empty polygon"))); } @@ -3420,21 +3492,21 @@ poly_in(PG_FUNCTION_ARGS) int base_size; bool isopen; if ((npts = pair_count(str, ',')) <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "polygon", str))); base_size = sizeof(poly->p[0]) * npts; - size = offsetof(POLYGON, p) +base_size; + size = offsetof(POLYGON, p) + base_size; /* Check for integer overflow */ if (base_size / npts != sizeof(poly->p[0]) || size <= base_size) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many points requested"))); poly = (POLYGON *) palloc0(size); /* zero any holes */ SET_VARSIZE(poly, size); @@ -3475,21 +3547,21 @@ poly_recv(PG_FUNCTION_ARGS) int32 npts; int32 i; int size; npts = pq_getmsgint(buf, sizeof(int32)); if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(POLYGON, p)) / sizeof(Point))) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid number of points in external \"polygon\" value"))); - size = offsetof(POLYGON, p) +sizeof(poly->p[0]) * npts; + size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * npts; poly = (POLYGON *) palloc0(size); /* zero any holes */ SET_VARSIZE(poly, size); poly->npts = npts; for (i = 0; i < npts; i++) { poly->p[i].x = pq_getmsgfloat8(buf); poly->p[i].y = pq_getmsgfloat8(buf); } @@ -3525,21 +3597,21 @@ poly_send(PG_FUNCTION_ARGS) * the right most point of A left of the left most point * of B? *-------------------------------------------------------*/ Datum poly_left(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.high.x < polyb->boundbox.low.x; + result = FLOAT_LT(polya->boundbox.high.x, polyb->boundbox.low.x); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3548,21 +3620,21 @@ poly_left(PG_FUNCTION_ARGS) * the right most point of A at or left of the right most point * of B? *-------------------------------------------------------*/ Datum poly_overleft(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.high.x <= polyb->boundbox.high.x; + result = FLOAT_LE(polya->boundbox.high.x, polyb->boundbox.high.x); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3571,21 +3643,21 @@ poly_overleft(PG_FUNCTION_ARGS) * the left most point of A right of the right most point * of B? *-------------------------------------------------------*/ Datum poly_right(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.low.x > polyb->boundbox.high.x; + result = FLOAT_GT(polya->boundbox.low.x, polyb->boundbox.high.x); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3594,21 +3666,21 @@ poly_right(PG_FUNCTION_ARGS) * the left most point of A at or right of the left most point * of B? *-------------------------------------------------------*/ Datum poly_overright(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.low.x >= polyb->boundbox.low.x; + result = FLOAT_GE(polya->boundbox.low.x, polyb->boundbox.low.x); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3617,21 +3689,21 @@ poly_overright(PG_FUNCTION_ARGS) * the upper most point of A below the lower most point * of B? *-------------------------------------------------------*/ Datum poly_below(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.high.y < polyb->boundbox.low.y; + result = FLOAT_LT(polya->boundbox.high.y, polyb->boundbox.low.y); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3640,21 +3712,21 @@ poly_below(PG_FUNCTION_ARGS) * the upper most point of A at or below the upper most point * of B? *-------------------------------------------------------*/ Datum poly_overbelow(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.high.y <= polyb->boundbox.high.y; + result = FLOAT_LE(polya->boundbox.high.y, polyb->boundbox.high.y); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3663,21 +3735,21 @@ poly_overbelow(PG_FUNCTION_ARGS) * the lower most point of A above the upper most point * of B? *-------------------------------------------------------*/ Datum poly_above(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.low.y > polyb->boundbox.high.y; + result = FLOAT_GT(polya->boundbox.low.y, polyb->boundbox.high.y); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3686,21 +3758,21 @@ poly_above(PG_FUNCTION_ARGS) * the lower most point of A at or above the lower most point * of B? *-------------------------------------------------------*/ Datum poly_overabove(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; - result = polya->boundbox.low.y >= polyb->boundbox.low.y; + result = FLOAT_GE(polya->boundbox.low.y, polyb->boundbox.low.y); /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); PG_RETURN_BOOL(result); } @@ -3738,21 +3810,21 @@ poly_same(PG_FUNCTION_ARGS) *-----------------------------------------------------------------*/ Datum poly_overlap(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; /* Quick check by bounding box */ result = (polya->npts > 0 && polyb->npts > 0 && - box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false; + box_ov(&polya->boundbox, &polyb->boundbox)); /* * Brute-force algorithm - try to find intersected edges, if so then * polygons are overlapped else check is one polygon inside other or not * by testing single point of them. */ if (result) { int ia, ib; @@ -3779,22 +3851,21 @@ poly_overlap(PG_FUNCTION_ARGS) } /* * move current endpoint to the first point of next edge */ sa.p[0] = sa.p[1]; } if (result == false) { - result = (point_inside(polya->p, polyb->npts, polyb->p) - || + result = (point_inside(polya->p, polyb->npts, polyb->p) || point_inside(polyb->p, polya->npts, polya->p)); } } /* * Avoid leaking memory for toasted inputs ... needed for rtree indexes */ PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); @@ -3814,21 +3885,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) (FLOAT_EQ((pt1)->x, (pt2)->x) && FLOAT_EQ((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); } @@ -3894,30 +3965,25 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) if (res) res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1); pfree(interpt); } s.p[0] = s.p[1]; } if (res && !intersection) { - Point p; - /* * if X-intersection wasn't found then check central point of tested * segment. In opposite case we already check all subsegments */ - p.x = (t.p[0].x + t.p[1].x) / 2.0; - p.y = (t.p[0].y + t.p[1].y) / 2.0; - - res = point_inside(&p, poly->npts, poly->p); + res = point_inside(lseg_center_internal(&t), poly->npts, poly->p); } return res; } /*----------------------------------------------------------------- * Determine if polygon A contains polygon B. *-----------------------------------------------------------------*/ Datum poly_contain(PG_FUNCTION_ARGS) @@ -4013,92 +4079,102 @@ poly_distance(PG_FUNCTION_ARGS) /*********************************************************************** ** ** Routines for 2D points. ** ***********************************************************************/ Datum construct_point(PG_FUNCTION_ARGS) { - float8 x = PG_GETARG_FLOAT8(0); - float8 y = PG_GETARG_FLOAT8(1); + double x = PG_GETARG_FLOAT8(0); + double y = PG_GETARG_FLOAT8(1); PG_RETURN_POINT_P(point_construct(x, y)); } Datum point_add(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; + double x; + double y; - result = (Point *) palloc(sizeof(Point)); + FLOAT_PL(x, p1->x, p2->x); + FLOAT_PL(y, p1->y, p2->y); - result->x = (p1->x + p2->x); - result->y = (p1->y + p2->y); - - PG_RETURN_POINT_P(result); + PG_RETURN_POINT_P(point_construct(x, y)); } Datum point_sub(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; + double x; + double y; - result = (Point *) palloc(sizeof(Point)); + FLOAT_MI(x, p1->x, p2->x); + FLOAT_MI(y, p1->y, p2->y); - result->x = (p1->x - p2->x); - result->y = (p1->y - p2->y); - - PG_RETURN_POINT_P(result); + PG_RETURN_POINT_P(point_construct(x, y)); } Datum point_mul(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; + double val1; + double val2; + double x; + double y; - result = (Point *) palloc(sizeof(Point)); + FLOAT_MUL(val1, p1->x, p2->x); + FLOAT_MUL(val2, p1->y, p2->y); + FLOAT_MI(x, val1, val2); - result->x = (p1->x * p2->x) - (p1->y * p2->y); - result->y = (p1->x * p2->y) + (p1->y * p2->x); + FLOAT_MUL(val1, p1->x, p2->y); + FLOAT_MUL(val2, p1->y, p2->x); + FLOAT_PL(y, val1, val2); - PG_RETURN_POINT_P(result); + PG_RETURN_POINT_P(point_construct(x, y)); } Datum point_div(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; + double mul1; + double mul2; double div; + double val; + double x; + double y; - result = (Point *) palloc(sizeof(Point)); + FLOAT_MUL(mul1, p2->x, p2->x); + FLOAT_MUL(mul2, p2->y, p2->y); + FLOAT_PL(div, mul1, mul2); - div = (p2->x * p2->x) + (p2->y * p2->y); + FLOAT_MUL(mul1, p1->x, p2->x); + FLOAT_MUL(mul2, p1->y, p2->y); + FLOAT_PL(val, mul1, mul2); + FLOAT_DIV(x, val, div); - if (div == 0.0) - ereport(ERROR, - (errcode(ERRCODE_DIVISION_BY_ZERO), - errmsg("division by zero"))); + FLOAT_MUL(mul1, p1->y, p2->x); + FLOAT_MUL(mul2, p1->x, p2->y); + FLOAT_MI(val, mul1, mul2); + FLOAT_DIV(y, val, div); - result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div; - result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div; - - PG_RETURN_POINT_P(result); + PG_RETURN_POINT_P(point_construct(x, y)); } /*********************************************************************** ** ** Routines for 2D boxes. ** ***********************************************************************/ Datum @@ -4108,37 +4184,49 @@ points_box(PG_FUNCTION_ARGS) Point *p2 = PG_GETARG_POINT_P(1); PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y)); } Datum box_add(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *p = PG_GETARG_POINT_P(1); + double highx; + double lowx; + double highy; + double lowy; - PG_RETURN_BOX_P(box_construct((box->high.x + p->x), - (box->low.x + p->x), - (box->high.y + p->y), - (box->low.y + p->y))); + FLOAT_PL(highx, box->high.x, p->x); + FLOAT_PL(lowx, box->low.x, p->x); + FLOAT_PL(highy, box->high.y, p->y); + FLOAT_PL(lowy, box->low.y, p->y); + + PG_RETURN_BOX_P(box_construct(highx, lowx, highy, lowy)); } Datum box_sub(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *p = PG_GETARG_POINT_P(1); + double highx; + double lowx; + double highy; + double lowy; - PG_RETURN_BOX_P(box_construct((box->high.x - p->x), - (box->low.x - p->x), - (box->high.y - p->y), - (box->low.y - p->y))); + FLOAT_MI(highx, box->high.x, p->x); + FLOAT_MI(lowx, box->low.x, p->x); + FLOAT_MI(highy, box->high.y, p->y); + FLOAT_MI(lowy, box->low.y, p->y); + + PG_RETURN_BOX_P(box_construct(highx, lowx, highy, lowy)); } Datum box_mul(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *p = PG_GETARG_POINT_P(1); BOX *result; Point *high, *low; @@ -4200,24 +4288,24 @@ point_box(PG_FUNCTION_ARGS) */ Datum boxes_bound_box(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0), *box2 = PG_GETARG_BOX_P(1), *container; container = (BOX *) palloc(sizeof(BOX)); - container->high.x = Max(box1->high.x, box2->high.x); - container->low.x = Min(box1->low.x, box2->low.x); - container->high.y = Max(box1->high.y, box2->high.y); - container->low.y = Min(box1->low.y, box2->low.y); + container->high.x = FLOAT_MAX(box1->high.x, box2->high.x); + container->low.x = FLOAT_MIN(box1->low.x, box2->low.x); + container->high.y = FLOAT_MAX(box1->high.y, box2->high.y); + container->low.y = FLOAT_MIN(box1->low.y, box2->low.y); PG_RETURN_BOX_P(container); } /*********************************************************************** ** ** Routines for 2D paths. ** ***********************************************************************/ @@ -4272,41 +4360,49 @@ path_add(PG_FUNCTION_ARGS) /* path_add_pt() * Translation operators. */ Datum path_add_pt(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); Point *point = PG_GETARG_POINT_P(1); int i; + double val; for (i = 0; i < path->npts; i++) { - path->p[i].x += point->x; - path->p[i].y += point->y; + FLOAT_PL(val, path->p[i].x, point->x); + path->p[i].x = val; + + FLOAT_PL(val, path->p[i].y, point->y); + path->p[i].y = val; } PG_RETURN_PATH_P(path); } Datum path_sub_pt(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); Point *point = PG_GETARG_POINT_P(1); int i; + double val; for (i = 0; i < path->npts; i++) { - path->p[i].x -= point->x; - path->p[i].y -= point->y; + FLOAT_MI(val, path->p[i].x, point->x); + path->p[i].x = val; + + FLOAT_MI(val, path->p[i].y, point->y); + path->p[i].y = val; } PG_RETURN_PATH_P(path); } /* path_mul_pt() * Rotation and scaling operators. */ Datum path_mul_pt(PG_FUNCTION_ARGS) @@ -4374,21 +4470,21 @@ path_poly(PG_FUNCTION_ARGS) /* This is not very consistent --- other similar cases return NULL ... */ if (!path->closed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("open path cannot be converted to polygon"))); /* * Never overflows: the old size fit in MaxAllocSize, and the new size is * just a small constant larger. */ - size = offsetof(POLYGON, p) +sizeof(poly->p[0]) * path->npts; + size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * path->npts; poly = (POLYGON *) palloc(size); SET_VARSIZE(poly, size); poly->npts = path->npts; for (i = 0; i < path->npts; i++) { poly->p[i].x = path->p[i].x; poly->p[i].y = path->p[i].y; } @@ -4483,26 +4579,26 @@ poly_path(PG_FUNCTION_ARGS) { POLYGON *poly = PG_GETARG_POLYGON_P(0); PATH *path; int size; int i; /* * Never overflows: the old size fit in MaxAllocSize, and the new size is * smaller by a small constant. */ - size = offsetof(PATH, p) +sizeof(path->p[0]) * poly->npts; + size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts; path = (PATH *) palloc(size); SET_VARSIZE(path, size); path->npts = poly->npts; - path->closed = TRUE; + path->closed = true; /* prevent instability in unused pad bytes */ path->dummy = 0; for (i = 0; i < poly->npts; i++) { path->p[i].x = poly->p[i].x; path->p[i].y = poly->p[i].y; } PG_RETURN_PATH_P(path); @@ -4546,30 +4642,29 @@ circle_in(PG_FUNCTION_ARGS) if (*cp == LDELIM) s = cp; } pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str); if (*s == DELIM) s++; circle->radius = single_decode(s, &s, "circle", str); - if (circle->radius < 0) + if (FLOAT_LT(circle->radius, 0.0)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "circle", str))); while (depth > 0) { - if ((*s == RDELIM) - || ((*s == RDELIM_C) && (depth == 1))) + if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1))) { depth--; s++; while (isspace((unsigned char) *s)) s++; } else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", @@ -4614,21 +4709,21 @@ circle_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); CIRCLE *circle; circle = (CIRCLE *) palloc(sizeof(CIRCLE)); circle->center.x = pq_getmsgfloat8(buf); circle->center.y = pq_getmsgfloat8(buf); circle->radius = pq_getmsgfloat8(buf); - if (circle->radius < 0) + if (FLOAT_LT(circle->radius, 0.0)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid radius in external \"circle\" value"))); PG_RETURN_CIRCLE_P(circle); } /* * circle_send - converts circle to binary format */ @@ -4652,334 +4747,371 @@ 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(FLOAT_EQ(circle1->radius, circle2->radius) && + FLOAT_EQ(circle1->center.x, circle2->center.x) && + FLOAT_EQ(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); + double sum_radius; - PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center), - circle1->radius + circle2->radius)); + FLOAT_PL(sum_radius, circle1->radius, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LE(point_dt(&circle1->center, &circle2->center), + sum_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); + double x1; + double x2; - PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius), - (circle2->center.x + circle2->radius))); + FLOAT_PL(x1, circle1->center.x, circle1->radius); + FLOAT_PL(x2, circle2->center.x, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LE(x1, x2)); } /* 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); + double x1; + double x2; - PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius), - (circle2->center.x - circle2->radius))); + FLOAT_PL(x1, circle1->center.x, circle1->radius); + FLOAT_MI(x2, circle2->center.x, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LT(x1, x2)); } /* 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); + double x1; + double x2; - PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius), - (circle2->center.x + circle2->radius))); + FLOAT_MI(x1, circle1->center.x, circle1->radius); + FLOAT_PL(x2, circle2->center.x, circle2->radius); + + PG_RETURN_BOOL(FLOAT_GT(x1, x2)); } /* 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); + double x1; + double x2; - PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius), - (circle2->center.x - circle2->radius))); + FLOAT_MI(x1, circle1->center.x, circle1->radius); + FLOAT_MI(x2, circle2->center.x, circle2->radius); + + PG_RETURN_BOOL(FLOAT_GE(x1, x2)); } /* 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); + double radius_diff; - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius)); + FLOAT_MI(radius_diff, circle2->radius, circle1->radius); + + PG_RETURN_BOOL(FLOAT_LE(point_dt(&circle1->center, &circle2->center), + radius_diff)); } /* 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); + double radius_diff; - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius)); + FLOAT_MI(radius_diff, circle1->radius, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LE(point_dt(&circle1->center, &circle2->center), + radius_diff)); } /* 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); + double y1; + double y2; - PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius), - (circle2->center.y - circle2->radius))); + FLOAT_PL(y1, circle1->center.y, circle1->radius); + FLOAT_MI(y2, circle2->center.y, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LT(y1, y2)); } /* 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); + double y1; + double y2; - PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius), - (circle2->center.y + circle2->radius))); + FLOAT_MI(y1, circle1->center.y, circle1->radius); + FLOAT_PL(y2, circle2->center.y, circle2->radius); + + PG_RETURN_BOOL(FLOAT_GT(y1, y2)); } /* 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); + double y1; + double y2; - PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius), - (circle2->center.y + circle2->radius))); + FLOAT_PL(y1, circle1->center.y, circle1->radius); + FLOAT_PL(y2, circle2->center.y, circle2->radius); + + PG_RETURN_BOOL(FLOAT_LE(y1, y2)); } /* 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); + double y1; + double y2; - PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius), - (circle2->center.y - circle2->radius))); + FLOAT_MI(y1, circle1->center.y, circle1->radius); + FLOAT_MI(y2, circle2->center.y, circle2->radius); + + PG_RETURN_BOOL(FLOAT_GE(y1, y2)); } /* 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(FLOAT_EQ(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(FLOAT_NE(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(FLOAT_LT(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(FLOAT_GT(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(FLOAT_LE(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(FLOAT_GE(circle_ar(circle1), circle_ar(circle2))); } /*---------------------------------------------------------- * "Arithmetic" operators on circles. *---------------------------------------------------------*/ static CIRCLE * -circle_copy(CIRCLE *circle) +circle_construct(double x, double y, double radius) { CIRCLE *result; - if (!PointerIsValid(circle)) - return NULL; - result = (CIRCLE *) palloc(sizeof(CIRCLE)); - memcpy((char *) result, (char *) circle, sizeof(CIRCLE)); + result->center.x = x; + result->center.y = y; + result->radius = radius; + return result; } /* circle_add_pt() * Translation operator. */ Datum circle_add_pt(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); - CIRCLE *result; - result = circle_copy(circle); - - result->center.x += point->x; - result->center.y += point->y; - - PG_RETURN_CIRCLE_P(result); + PG_RETURN_CIRCLE_P(circle_construct(point->x, point->y, circle->radius)); } Datum circle_sub_pt(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); - CIRCLE *result; + double x; + double y; - result = circle_copy(circle); + FLOAT_MI(x, circle->center.x, point->x); + FLOAT_MI(y, circle->center.y, point->y); - result->center.x -= point->x; - result->center.y -= point->y; - - PG_RETURN_CIRCLE_P(result); + PG_RETURN_CIRCLE_P(circle_construct(x, y, circle->radius)); } /* circle_mul_pt() * Rotation and scaling operators. */ Datum circle_mul_pt(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); - CIRCLE *result; Point *p; - - result = circle_copy(circle); + double hyp; + double radius; p = DatumGetPointP(DirectFunctionCall2(point_mul, PointPGetDatum(&circle->center), PointPGetDatum(point))); - result->center.x = p->x; - result->center.y = p->y; - result->radius *= HYPOT(point->x, point->y); - PG_RETURN_CIRCLE_P(result); + FLOAT_HYPOT(hyp, point->x, point->y); + FLOAT_MUL(radius, circle->radius, hyp); + + PG_RETURN_CIRCLE_P(circle_construct(p->x, p->y, radius)); } Datum circle_div_pt(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); - CIRCLE *result; Point *p; - - result = circle_copy(circle); + double hyp; + double radius; p = DatumGetPointP(DirectFunctionCall2(point_div, PointPGetDatum(&circle->center), PointPGetDatum(point))); - result->center.x = p->x; - result->center.y = p->y; - result->radius /= HYPOT(point->x, point->y); - PG_RETURN_CIRCLE_P(result); + FLOAT_HYPOT(hyp, point->x, point->y); + FLOAT_DIV(radius, circle->radius, hyp); + + PG_RETURN_CIRCLE_P(circle_construct(p->x, p->y, radius)); } /* circle_area - returns the area of the circle. */ Datum circle_area(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); PG_RETURN_FLOAT8(circle_ar(circle)); } /* circle_diameter - returns the diameter of the circle. */ Datum circle_diameter(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); + double result; - PG_RETURN_FLOAT8(2 * circle->radius); + FLOAT_MUL(result, circle->radius, 2.0); + + PG_RETURN_FLOAT8(result); } /* circle_radius - returns the radius of the circle. */ Datum circle_radius(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); @@ -4988,253 +5120,284 @@ circle_radius(PG_FUNCTION_ARGS) /* circle_distance - returns the distance between * two circles. */ Datum circle_distance(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - float8 result; + double d; + double sum_radius; + double result; + + d = point_dt(&circle1->center, &circle2->center); + FLOAT_PL(sum_radius, circle1->radius, circle2->radius); + FLOAT_MI(result, d, sum_radius); + if (FLOAT_LT(result, 0.0)) + result = 0.0; - result = point_dt(&circle1->center, &circle2->center) - - (circle1->radius + circle2->radius); - if (result < 0) - result = 0; PG_RETURN_FLOAT8(result); } Datum circle_contain_pt(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); double d; d = point_dt(&circle->center, point); - PG_RETURN_BOOL(d <= circle->radius); + PG_RETURN_BOOL(FLOAT_LE(d, circle->radius)); } Datum pt_contained_circle(PG_FUNCTION_ARGS) { Point *point = PG_GETARG_POINT_P(0); CIRCLE *circle = PG_GETARG_CIRCLE_P(1); double d; d = point_dt(&circle->center, point); - PG_RETURN_BOOL(d <= circle->radius); + PG_RETURN_BOOL(FLOAT_LE(d, circle->radius)); } /* dist_pc - returns the distance between * a point and a circle. */ Datum dist_pc(PG_FUNCTION_ARGS) { Point *point = PG_GETARG_POINT_P(0); CIRCLE *circle = PG_GETARG_CIRCLE_P(1); - float8 result; + double d; + double result; + + d = point_dt(point, &circle->center); + FLOAT_MI(result, d, circle->radius); + if (FLOAT_LT(result, 0.0)) + result = 0.0; - result = point_dt(point, &circle->center) - circle->radius; - if (result < 0) - result = 0; PG_RETURN_FLOAT8(result); } /* * Distance from a circle to a point */ Datum dist_cpoint(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); Point *point = PG_GETARG_POINT_P(1); - float8 result; + double d; + double result; + + d = point_dt(point, &circle->center); + FLOAT_MI(result, d, circle->radius); + if (FLOAT_LT(result, 0.0)) + result = 0.0; - result = point_dt(point, &circle->center) - circle->radius; - if (result < 0) - result = 0; PG_RETURN_FLOAT8(result); } /* circle_center - returns the center point of the circle. */ Datum circle_center(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); - Point *result; - result = (Point *) palloc(sizeof(Point)); - result->x = circle->center.x; - result->y = circle->center.y; - - PG_RETURN_POINT_P(result); + PG_RETURN_POINT_P(point_copy(&circle->center)); } /* circle_ar - returns the area of the circle. */ static double circle_ar(CIRCLE *circle) { - return M_PI * (circle->radius * circle->radius); + double radius2; + double result; + + FLOAT_MUL(radius2, circle->radius, circle->radius); + FLOAT_MUL(result, radius2, M_PI); + + return result; } /*---------------------------------------------------------- * Conversion operators. *---------------------------------------------------------*/ Datum cr_circle(PG_FUNCTION_ARGS) { Point *center = PG_GETARG_POINT_P(0); - float8 radius = PG_GETARG_FLOAT8(1); - CIRCLE *result; + double radius = PG_GETARG_FLOAT8(1); - result = (CIRCLE *) palloc(sizeof(CIRCLE)); - - result->center.x = center->x; - result->center.y = center->y; - result->radius = radius; - - PG_RETURN_CIRCLE_P(result); + PG_RETURN_CIRCLE_P(circle_construct(center->x, center->y, radius)); } Datum circle_box(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); BOX *box; double delta; box = (BOX *) palloc(sizeof(BOX)); - delta = circle->radius / sqrt(2.0); + FLOAT_DIV(delta, circle->radius, sqrt(2.0)); - box->high.x = circle->center.x + delta; - box->low.x = circle->center.x - delta; - box->high.y = circle->center.y + delta; - box->low.y = circle->center.y - delta; + FLOAT_PL(box->high.x, circle->center.x, delta); + FLOAT_MI(box->low.x, circle->center.x, delta); + FLOAT_PL(box->high.y, circle->center.y, delta); + FLOAT_MI(box->low.y, circle->center.y, delta); PG_RETURN_BOX_P(box); } /* box_circle() * Convert a box to a circle. */ Datum box_circle(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); CIRCLE *circle; + double sum; circle = (CIRCLE *) palloc(sizeof(CIRCLE)); - circle->center.x = (box->high.x + box->low.x) / 2; - circle->center.y = (box->high.y + box->low.y) / 2; + FLOAT_PL(sum, box->high.x, box->low.x); + FLOAT_DIV(circle->center.x, sum, 2.0); + + FLOAT_PL(sum, box->high.y, box->low.y); + FLOAT_DIV(circle->center.y, sum, 2.0); circle->radius = point_dt(&circle->center, &box->high); PG_RETURN_CIRCLE_P(circle); } Datum 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; + double mul; - if (FPzero(circle->radius)) + if (circle->radius == 0.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; - size = offsetof(POLYGON, p) +base_size; + size = offsetof(POLYGON, p) + base_size; /* Check for integer overflow */ if (base_size / npts != sizeof(poly->p[0]) || size <= base_size) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many points requested"))); poly = (POLYGON *) palloc0(size); /* zero any holes */ SET_VARSIZE(poly, size); poly->npts = npts; - anglestep = (2.0 * M_PI) / npts; + FLOAT_DIV(anglestep, 2.0 * M_PI, npts); for (i = 0; i < npts; i++) { - angle = i * anglestep; - poly->p[i].x = circle->center.x - (circle->radius * cos(angle)); - poly->p[i].y = circle->center.y + (circle->radius * sin(angle)); + FLOAT_MUL(angle, anglestep, i); + + FLOAT_MUL(mul, circle->radius, cos(angle)); + FLOAT_MI(poly->p[i].x, circle->center.x, mul); + + FLOAT_MUL(mul, circle->radius, sin(angle)); + FLOAT_PL(poly->p[i].y, circle->center.y, mul); } make_bound_box(poly); PG_RETURN_POLYGON_P(poly); } /* poly_circle - convert polygon to circle * * XXX This algorithm should use weighted means of line segments * rather than straight average values of points - tgl 97/01/21. */ Datum poly_circle(PG_FUNCTION_ARGS) { POLYGON *poly = PG_GETARG_POLYGON_P(0); CIRCLE *circle; + bool has_inf; int i; + double sum; + double dist; if (poly->npts < 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot convert empty polygon to circle"))); circle = (CIRCLE *) palloc(sizeof(CIRCLE)); - circle->center.x = 0; - circle->center.y = 0; - circle->radius = 0; - + has_inf = false; + sum = 0.0; for (i = 0; i < poly->npts; i++) { - circle->center.x += poly->p[i].x; - circle->center.y += poly->p[i].y; + has_inf |= isinf(poly->p[i].x); + sum += poly->p[i].x; } - circle->center.x /= poly->npts; - circle->center.y /= poly->npts; + CHECKFLOATVAL(sum, has_inf, true); + FLOAT_DIV(circle->center.x, sum, poly->npts); + has_inf = false; + sum = 0.0; for (i = 0; i < poly->npts; i++) - circle->radius += point_dt(&poly->p[i], &circle->center); - circle->radius /= poly->npts; + { + has_inf |= isinf(poly->p[i].y); + sum += poly->p[i].y; + } + CHECKFLOATVAL(sum, has_inf, true); + FLOAT_DIV(circle->center.y, sum, poly->npts); + + has_inf = false; + sum = 0.0; + for (i = 0; i < poly->npts; i++) + { + dist = point_dt(&poly->p[i], &circle->center); + has_inf |= isinf(dist); + sum += dist; + } + CHECKFLOATVAL(sum, has_inf, true); + FLOAT_DIV(circle->radius, sum, poly->npts); PG_RETURN_CIRCLE_P(circle); } /*********************************************************************** ** ** Private routines for multiple types. ** ***********************************************************************/ @@ -5262,31 +5425,31 @@ point_inside(Point *p, int npts, Point *plist) int i = 0; double x, y; int cross, total_cross = 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; + FLOAT_MI(x0, plist[0].x, p->x); + FLOAT_MI(y0, plist[0].y, p->y); 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; + FLOAT_MI(x, plist[i].x, p->x); + FLOAT_MI(y, plist[i].y, p->y); /* compute previous to current point crossing */ if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON) return 2; total_cross += cross; prev_x = x; prev_y = y; } @@ -5306,129 +5469,139 @@ point_inside(Point *p, int npts, Point *plist) * 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 prev_x, double prev_y) { - double z; int y_sign; + double xdiff; + double ydiff; + double mulxy; + double mulyx; - if (FPzero(y)) + if (FLOAT_EQ(y, 0.0)) { /* y == 0, on X axis */ - if (FPzero(x)) /* (x,y) is (0,0)? */ + if (FLOAT_EQ(x, 0.0)) /* (x,y) is (0,0)? */ return POINT_ON_POLYGON; - else if (FPgt(x, 0)) + else if (FLOAT_GT(x, 0.0)) { /* x > 0 */ - if (FPzero(prev_y)) /* y and prev_y are zero */ + if (FLOAT_EQ(prev_y, 0.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 FLOAT_GT(prev_x, 0.0) ? 0 : POINT_ON_POLYGON; + return FLOAT_LT(prev_y, 0.0) ? 1 : -1; } else { /* x < 0, x not on positive X axis */ - if (FPzero(prev_y)) + if (FLOAT_EQ(prev_y, 0.0)) /* prev_x < 0? */ - return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON; + return FLOAT_LT(prev_x, 0.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 = FLOAT_GT(y, 0.0) ? 1 : -1; - if (FPzero(prev_y)) + if (FLOAT_EQ(prev_y, 0.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 ? 0 : y_sign; + else if ((y_sign < 0 && FLOAT_LT(prev_y, 0.0)) || + (y_sign > 0 && FLOAT_GT(prev_y, 0.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 (FLOAT_GE(x, 0.0) && FLOAT_GT(prev_x, 0.0)) /* both non-negative so cross positive X-axis */ return 2 * y_sign; - if (FPlt(x, 0) && FPle(prev_x, 0)) + if (FLOAT_LT(x, 0.0) && FLOAT_LE(prev_x, 0.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)) + FLOAT_MI(xdiff, x, prev_x); + FLOAT_MI(ydiff, y, prev_y); + FLOAT_MUL(mulxy, xdiff, y); + FLOAT_MUL(mulyx, ydiff, x); + if (FLOAT_EQ(mulxy, mulyx)) return POINT_ON_POLYGON; - return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign; + if ((y_sign < 0 && FLOAT_LT(mulxy, mulyx)) || + (y_sign > 0 && FLOAT_GT(mulxy, mulyx))) + return 0; + + return 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 (FLOAT_EQ(p2[i].x, p1[0].x) && FLOAT_EQ(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 (FLOAT_NE(p2[j].x, p1[ii].x) || + FLOAT_NE(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; + 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 (FLOAT_NE(p2[j].x, p1[ii].x) || + FLOAT_NE(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 if (ii == npts) - return TRUE; + return true; } } - return FALSE; + return false; } /*------------------------------------------------------------------------- * Determine the hypotenuse. * * If required, x and y are swapped to make x the larger number. The * traditional formula of x^2+y^2 is rearranged to factor x outside the * sqrt. This allows computation of the hypotenuse for significantly * larger values, and with a higher precision than when using the naive diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c index 565a034..537414c 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -76,21 +76,21 @@ #include "access/spgist.h" #include "access/stratnum.h" #include "catalog/pg_type.h" #include "utils/float.h" #include "utils/geo_decls.h" /* * Comparator for qsort * * We don't need to use the floating point macros in here, because this - * is going only going to be used in a place to effect the performance + * is only going to be used in a place to effect the performance * of the index, not the correctness. */ static int compareDoubles(const void *a, const void *b) { double x = *(double *) a; double y = *(double *) b; if (x == y) return 0; @@ -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 fe9bc60..7a6f34b 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -1,63 +1,42 @@ /*------------------------------------------------------------------------- * * geo_decls.h - Declarations for various 2D constructs. * * * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/geo_decls.h * - * NOTE - * These routines do *not* use the float types from adt/. - * - * XXX These routines were not written by a numerical analyst. - * * XXX I have made some attempt to flesh out the operators * and data types. There are still some more to do. - tgl 97/04/19 * *------------------------------------------------------------------------- */ #ifndef GEO_DECLS_H #define GEO_DECLS_H #include #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) +#define FLOAT_HYPOT(result, val1, val2) \ +do { \ + result = pg_hypot(val1, val2); \ + CHECKFLOATVAL(result, isinf(val1) || isinf(val2), \ + (val1) == 0.0 && (val2) == 0.0); \ +} while(0) /*--------------------------------------------------------------------- * Point - (x,y) *-------------------------------------------------------------------*/ typedef struct { double x, y; } Point; @@ -193,22 +172,20 @@ extern Datum point_horiz(PG_FUNCTION_ARGS); extern Datum point_eq(PG_FUNCTION_ARGS); extern Datum point_ne(PG_FUNCTION_ARGS); extern Datum point_distance(PG_FUNCTION_ARGS); extern Datum point_slope(PG_FUNCTION_ARGS); extern Datum point_add(PG_FUNCTION_ARGS); extern Datum point_sub(PG_FUNCTION_ARGS); extern Datum point_mul(PG_FUNCTION_ARGS); extern Datum point_div(PG_FUNCTION_ARGS); /* private routines */ -extern double point_dt(Point *pt1, Point *pt2); -extern double point_sl(Point *pt1, Point *pt2); extern double pg_hypot(double x, double y); /* public lseg routines */ extern Datum lseg_in(PG_FUNCTION_ARGS); extern Datum lseg_out(PG_FUNCTION_ARGS); extern Datum lseg_recv(PG_FUNCTION_ARGS); extern Datum lseg_send(PG_FUNCTION_ARGS); extern Datum lseg_intersect(PG_FUNCTION_ARGS); extern Datum lseg_parallel(PG_FUNCTION_ARGS); extern Datum lseg_perp(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out index f20abdc..16ff522 100644 --- a/src/test/regress/expected/line.out +++ b/src/test/regress/expected/line.out @@ -32,56 +32,56 @@ LINE 1: INSERT INTO LINE_TBL VALUES ('[1,2,3, 4'); ^ INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]'); ERROR: invalid input syntax for type line: "[(,2),(3,4)]" LINE 1: INSERT INTO LINE_TBL VALUES ('[(,2),(3,4)]'); ^ INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)'); ERROR: invalid input syntax for type line: "[(1,2),(3,4)" LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(3,4)'); ^ select * from LINE_TBL; - s ---------------------------------------------- + s +-------------------------- {1,-1,1} - {1,-1,0} - {-0.4,-1,-6} - {-0.000184615384615385,-1,15.3846153846154} - {1,-1,11} + {6,-6,0} + {6,15,90} + {-240,-1300000,20000000} + {22,-22,242} {0,-1,3} {-1,0,3} (7 rows) -- functions and operators SELECT * FROM LINE_TBL WHERE (s <-> line '[(1,2),(3,4)]') < 10; - s ---------------------------------------------- + s +-------------------------- {1,-1,1} - {1,-1,0} - {-0.4,-1,-6} - {-0.000184615384615385,-1,15.3846153846154} - {1,-1,11} + {6,-6,0} + {6,15,90} + {-240,-1300000,20000000} + {22,-22,242} {0,-1,3} {-1,0,3} (7 rows) SELECT * FROM LINE_TBL WHERE (point '(0.1,0.1)' <-> s) < 1; s ---------- {1,-1,1} - {1,-1,0} + {6,-6,0} (2 rows) SELECT * FROM LINE_TBL WHERE (lseg '[(0.1,0.1),(0.2,0.2)]' <-> s) < 1; s ---------- {1,-1,1} - {1,-1,0} + {6,-6,0} (2 rows) SELECT line '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]'; ?column? ---------- 2 (1 row) SELECT lseg '[(1,1),(2,1)]' <-> line '[(-1,-1),(-2,-1)]'; ?column? @@ -247,21 +247,21 @@ SELECT ?| line '[(0,0),(0,1)]'; -- true SELECT ?| line '[(0,0),(1,1)]'; -- false ?column? ---------- f (1 row) SELECT line(point '(1,2)', point '(3,4)'); line ---------- - {1,-1,1} + {2,-2,2} (1 row) SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,5)]'; -- true ?column? ---------- t (1 row) SELECT line '[(1,2),(3,4)]' = line '[(3,4),(4,4)]'; -- false ?column? 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; diff --git a/src/test/regress/expected/select_views.out b/src/test/regress/expected/select_views.out index 8780353..851d03c 100644 --- a/src/test/regress/expected/select_views.out +++ b/src/test/regress/expected/select_views.out @@ -2,21 +2,20 @@ -- SELECT_VIEWS -- test the views defined in CREATE_VIEWS -- SELECT * FROM street; name | thepath | cname ------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------- Access Rd 25 | [(-121.9283,37.894),(-121.9283,37.9)] | Oakland Ada St | [(-122.2487,37.398),(-122.2496,37.401)] | Lafayette Agua Fria Creek | [(-121.9254,37.922),(-121.9281,37.889)] | Oakland Allen Ct | [(-122.0131,37.602),(-122.0117,37.597)] | Berkeley - Alvarado Niles Road | [(-122.0325,37.903),(-122.0316,37.9)] | Berkeley Andrea Cir | [(-121.733218,37.88641),(-121.733286,37.90617)] | Oakland Apricot Lane | [(-121.9471,37.401),(-121.9456,37.392)] | Oakland Apricot Lane | [(-121.9471,37.401),(-121.9456,37.392)] | Oakland Arden Road | [(-122.0978,37.177),(-122.1,37.177)] | Oakland Arizona St | [(-122.0381,37.901),(-122.0367,37.898)] | Berkeley Arlington Dr | [(-121.8802,37.408),(-121.8807,37.394)] | Oakland Arlington Dr | [(-121.8802,37.408),(-121.8807,37.394)] | Oakland Arlington Road | [(-121.7957,37.898),(-121.7956,37.906)] | Oakland Arroyo Las Positas | [(-121.7973,37.997),(-121.7957,37.005)] | Oakland Arroyo Las Positas | [(-121.7973,37.997),(-121.7957,37.005)] | Oakland @@ -41,21 +40,20 @@ SELECT * FROM street; Butterfield Dr | [(-122.0838,37.002),(-122.0834,37.987)] | Oakland Butterfield Dr | [(-122.0838,37.002),(-122.0834,37.987)] | Berkeley C St | [(-122.1768,37.46),(-122.1749,37.435)] | Oakland Calaveras Creek | [(-121.8203,37.035),(-121.8207,37.931)] | Oakland Calaveras Creek | [(-121.8203,37.035),(-121.8207,37.931)] | Oakland California St | [(-122.2032,37.005),(-122.2016,37.996)] | Berkeley California St | [(-122.2032,37.005),(-122.2016,37.996)] | Lafayette Cameron Ave | [(-122.1316,37.502),(-122.1327,37.481)] | Oakland Campus Dr | [(-122.1704,37.905),(-122.1678,37.868),(-122.1671,37.865)] | Berkeley Capricorn Ave | [(-122.2176,37.404),(-122.2164,37.384)] | Lafayette - Carson St | [(-122.1846,37.9),(-122.1843,37.901)] | Berkeley Cedar Blvd | [(-122.0282,37.446),(-122.0265,37.43)] | Oakland Cedar St | [(-122.3011,37.737),(-122.2999,37.739)] | Berkeley Celia St | [(-122.0611,37.3),(-122.0616,37.299)] | Oakland Central Ave | [(-122.2343,37.602),(-122.2331,37.595)] | Berkeley Chambers Dr | [(-122.2004,37.352),(-122.1972,37.368)] | Lafayette Chambers Lane | [(-122.2001,37.359),(-122.1975,37.371)] | Lafayette Champion St | [(-122.214,37.991),(-122.2147,37.002)] | Berkeley Champion St | [(-122.214,37.991),(-122.2147,37.002)] | Lafayette Chapman Dr | [(-122.0421,37.504),(-122.0414,37.498)] | Oakland Charles St | [(-122.0255,37.505),(-122.0252,37.499)] | Oakland @@ -66,21 +64,20 @@ SELECT * FROM street; Coliseum Way | [(-122.2001,37.47),(-122.1978,37.516)] | Oakland Coliseum Way | [(-122.2113,37.626),(-122.2085,37.592),(-122.2063,37.568)] | Berkeley Coolidge Ave | [(-122.2007,37.058),(-122.1992,37.06)] | Lafayette Cornell Ave | [(-122.2956,37.925),(-122.2949,37.906),(-122.2939,37.875)] | Berkeley Corriea Way | [(-121.9501,37.402),(-121.9505,37.398)] | Oakland Corriea Way | [(-121.9501,37.402),(-121.9505,37.398)] | Oakland Cowing Road | [(-122.0002,37.934),(-121.9772,37.782)] | Oakland Creston Road | [(-122.2639,37.002),(-122.2613,37.986),(-122.2602,37.978),(-122.2598,37.973)] | Berkeley Creston Road | [(-122.2639,37.002),(-122.2613,37.986),(-122.2602,37.978),(-122.2598,37.973)] | Lafayette Crow Canyon Creek | [(-122.043,37.905),(-122.0368,37.71)] | Berkeley - Crystaline Dr | [(-121.925856,37),(-121.925869,37.00527)] | Oakland Cull Canyon Road | [(-122.0536,37.435),(-122.0499,37.315)] | Oakland Cull Creek | [(-122.0624,37.875),(-122.0582,37.527)] | Berkeley D St | [(-122.1811,37.505),(-122.1805,37.497)] | Oakland Decoto Road | [(-122.0159,37.006),(-122.016,37.002),(-122.0164,37.993)] | Oakland Decoto Road | [(-122.0159,37.006),(-122.016,37.002),(-122.0164,37.993)] | Oakland Decoto Road | [(-122.0159,37.006),(-122.016,37.002),(-122.0164,37.993)] | Berkeley Deering St | [(-122.2146,37.904),(-122.2126,37.897)] | Berkeley Dimond Ave | [(-122.2167,37.994),(-122.2162,37.006)] | Berkeley Dimond Ave | [(-122.2167,37.994),(-122.2162,37.006)] | Lafayette Donna Way | [(-122.1333,37.606),(-122.1316,37.599)] | Berkeley @@ -182,21 +179,20 @@ SELECT * FROM street; I- 880 Ramp | [(-122.0618,37.011),(-122.0631,37.982),(-122.0585,37.967)] | Oakland I- 880 Ramp | [(-122.0618,37.011),(-122.0631,37.982),(-122.0585,37.967)] | Berkeley I- 880 Ramp | [(-122.085,37.34),(-122.0801,37.316),(-122.081,37.285)] | Oakland I- 880 Ramp | [(-122.085,37.34),(-122.0801,37.316),(-122.081,37.285)] | Oakland I- 880 Ramp | [(-122.085,37.34),(-122.0866,37.316),(-122.0819,37.296)] | Oakland I- 880 Ramp | [(-122.085,37.34),(-122.0866,37.316),(-122.0819,37.296)] | Oakland I- 880 Ramp | [(-122.1029,37.61),(-122.1013,37.587),(-122.0999,37.569)] | Berkeley I- 880 Ramp | [(-122.1379,37.891),(-122.1383,37.897),(-122.1377,37.902)] | Berkeley I- 880 Ramp | [(-122.1379,37.931),(-122.137597,37.92736),(-122.1374,37.925),(-122.1373,37.924),(-122.1369,37.914),(-122.1358,37.905),(-122.1365,37.908),(-122.1358,37.898)] | Berkeley I- 880 Ramp | [(-122.2536,37.898),(-122.254,37.902)] | Berkeley - I- 880 Ramp | [(-122.2771,37.002),(-122.278,37)] | Lafayette Indian Way | [(-122.2066,37.398),(-122.2045,37.411)] | Lafayette Jackson St | [(-122.0845,37.6),(-122.0842,37.606)] | Berkeley Johnson Dr | [(-121.9145,37.901),(-121.915,37.877)] | Oakland Joyce St | [(-122.0792,37.604),(-122.0774,37.581)] | Berkeley Juniper St | [(-121.7823,37.897),(-121.7815,37.9)] | Oakland Kaiser Dr | [(-122.067163,37.47821),(-122.060402,37.51961)] | Oakland Keeler Ave | [(-122.2578,37.906),(-122.2579,37.899)] | Berkeley Kildare Road | [(-122.0968,37.016),(-122.0959,37)] | Oakland La Playa Dr | [(-122.1039,37.545),(-122.101,37.493)] | Oakland Laguna Ave | [(-122.2099,37.989),(-122.2089,37)] | Berkeley @@ -234,21 +230,20 @@ SELECT * FROM street; Mission Blvd | [(-122.0006,37.896),(-121.9989,37.88)] | Berkeley Moores Ave | [(-122.0087,37.301),(-122.0094,37.292)] | Oakland National Ave | [(-122.1192,37.5),(-122.1281,37.489)] | Oakland Navajo Ct | [(-121.8779,37.901),(-121.8783,37.9)] | Oakland Newark Blvd | [(-122.0352,37.438),(-122.0341,37.423)] | Oakland Oakland Inner Harbor | [(-122.2625,37.913),(-122.260016,37.89484)] | Berkeley Oakridge Road | [(-121.8316,37.049),(-121.828382,37)] | Oakland Oneil Ave | [(-122.076754,37.62476),(-122.0745,37.595)] | Berkeley Parkridge Dr | [(-122.1438,37.884),(-122.1428,37.9)] | Berkeley Parkside Dr | [(-122.0475,37.603),(-122.0443,37.596)] | Berkeley - Paseo Padre Pkwy | [(-121.9143,37.005),(-121.913522,37)] | Oakland Paseo Padre Pkwy | [(-122.0021,37.639),(-121.996,37.628)] | Oakland Paseo Padre Pkwy | [(-122.0021,37.639),(-121.996,37.628)] | Berkeley Pearl St | [(-122.2383,37.594),(-122.2366,37.615)] | Berkeley Periwinkle Road | [(-122.0451,37.301),(-122.044758,37.29844)] | Oakland Pimlico Dr | [(-121.8616,37.998),(-121.8618,37.008)] | Oakland Pimlico Dr | [(-121.8616,37.998),(-121.8618,37.008)] | Oakland Portsmouth Ave | [(-122.1064,37.315),(-122.1064,37.308)] | Oakland Proctor Ave | [(-122.2267,37.406),(-122.2251,37.386)] | Lafayette Railroad Ave | [(-122.0245,37.013),(-122.0234,37.003),(-122.0223,37.993)] | Oakland Railroad Ave | [(-122.0245,37.013),(-122.0234,37.003),(-122.0223,37.993)] | Oakland @@ -263,39 +258,36 @@ SELECT * FROM street; Rosedale Ct | [(-121.9232,37.9),(-121.924,37.897)] | Oakland Sacramento St | [(-122.2799,37.606),(-122.2797,37.597)] | Berkeley Saddle Brook Dr | [(-122.1478,37.909),(-122.1454,37.904),(-122.1451,37.888)] | Berkeley Saginaw Ct | [(-121.8803,37.898),(-121.8806,37.901)] | Oakland San Andreas Dr | [(-122.0609,37.9),(-122.0614,37.895)] | Berkeley Santa Maria Ave | [(-122.0773,37),(-122.0773,37.98)] | Oakland Santa Maria Ave | [(-122.0773,37),(-122.0773,37.98)] | Oakland Santa Maria Ave | [(-122.0773,37),(-122.0773,37.98)] | Berkeley Shattuck Ave | [(-122.2686,37.904),(-122.2686,37.897)] | Berkeley Sheridan Road | [(-122.2279,37.425),(-122.2253,37.411),(-122.2223,37.377)] | Lafayette - Shoreline Dr | [(-122.2657,37.603),(-122.2648,37.6)] | Berkeley Skyline Blvd | [(-122.1738,37.01),(-122.1714,37.996)] | Oakland Skyline Blvd | [(-122.1738,37.01),(-122.1714,37.996)] | Berkeley - Skyline Dr | [(-122.0277,37.5),(-122.0284,37.498)] | Oakland Skywest Dr | [(-122.1161,37.62),(-122.1123,37.586)] | Berkeley Southern Pacific Railroad | [(-122.3002,37.674),(-122.2999,37.661)] | Berkeley Sp Railroad | [(-121.893564,37.99009),(-121.897,37.016)] | Oakland Sp Railroad | [(-121.893564,37.99009),(-121.897,37.016)] | Oakland Sp Railroad | [(-121.9565,37.898),(-121.9562,37.9)] | Oakland Sp Railroad | [(-122.0734,37.001),(-122.0734,37.997)] | Oakland Sp Railroad | [(-122.0734,37.001),(-122.0734,37.997)] | Oakland Sp Railroad | [(-122.0734,37.001),(-122.0734,37.997)] | Berkeley Sp Railroad | [(-122.0914,37.601),(-122.087,37.56),(-122.086408,37.5551)] | Berkeley Sp Railroad | [(-122.137792,37.003),(-122.1365,37.992),(-122.131257,37.94612)] | Oakland Sp Railroad | [(-122.137792,37.003),(-122.1365,37.992),(-122.131257,37.94612)] | Berkeley Sp Railroad | [(-122.1947,37.497),(-122.193328,37.4848)] | Oakland Stanton Ave | [(-122.100392,37.0697),(-122.099513,37.06052)] | Oakland State Hwy 123 | [(-122.3004,37.986),(-122.2998,37.969),(-122.2995,37.962),(-122.2992,37.952),(-122.299,37.942),(-122.2987,37.935),(-122.2984,37.924),(-122.2982,37.92),(-122.2976,37.904),(-122.297,37.88),(-122.2966,37.869),(-122.2959,37.848),(-122.2961,37.843)] | Berkeley - State Hwy 13 | [(-122.1797,37.943),(-122.179871,37.91849),(-122.18,37.9),(-122.179023,37.86615),(-122.1787,37.862),(-122.1781,37.851),(-122.1777,37.845),(-122.1773,37.839),(-122.177,37.833)] | Berkeley State Hwy 13 | [(-122.2049,37.2),(-122.20328,37.17975),(-122.1989,37.125),(-122.198078,37.11641),(-122.1975,37.11)] | Lafayette State Hwy 13 Ramp | [(-122.2244,37.427),(-122.223,37.414),(-122.2214,37.396),(-122.2213,37.388)] | Lafayette State Hwy 238 | ((-122.098,37.908),(-122.0983,37.907),(-122.099,37.905),(-122.101,37.898),(-122.101535,37.89711),(-122.103173,37.89438),(-122.1046,37.892),(-122.106,37.89)) | Berkeley State Hwy 238 Ramp | [(-122.1288,37.9),(-122.1293,37.895),(-122.1296,37.906)] | Berkeley State Hwy 24 | [(-122.2674,37.246),(-122.2673,37.248),(-122.267,37.261),(-122.2668,37.271),(-122.2663,37.298),(-122.2659,37.315),(-122.2655,37.336),(-122.265007,37.35882),(-122.264443,37.37286),(-122.2641,37.381),(-122.2638,37.388),(-122.2631,37.396),(-122.2617,37.405),(-122.2615,37.407),(-122.2605,37.412)] | Lafayette State Hwy 84 | [(-121.9565,37.898),(-121.956589,37.89911),(-121.9569,37.903),(-121.956,37.91),(-121.9553,37.919)] | Oakland State Hwy 84 | [(-122.0671,37.426),(-122.07,37.402),(-122.074,37.37),(-122.0773,37.338)] | Oakland State Hwy 92 | [(-122.1085,37.326),(-122.1095,37.322),(-122.1111,37.316),(-122.1119,37.313),(-122.1125,37.311),(-122.1131,37.308),(-122.1167,37.292),(-122.1187,37.285),(-122.12,37.28)] | Oakland State Hwy 92 Ramp | [(-122.1086,37.321),(-122.1089,37.315),(-122.1111,37.316)] | Oakland Stuart St | [(-122.2518,37.6),(-122.2507,37.601),(-122.2491,37.606)] | Berkeley @@ -331,148 +323,104 @@ SELECT * FROM street; 19th Ave | [(-122.2366,37.897),(-122.2359,37.905)] | Berkeley 1st St | [(-121.75508,37.89294),(-121.753581,37.90031)] | Oakland 5th St | [(-122.278,37),(-122.2792,37.005),(-122.2803,37.009)] | Lafayette 5th St | [(-122.296,37.615),(-122.2953,37.598)] | Berkeley 82nd Ave | [(-122.1695,37.596),(-122.1681,37.603)] | Berkeley 85th Ave | [(-122.1877,37.466),(-122.186,37.476)] | Oakland 89th Ave | [(-122.1822,37.459),(-122.1803,37.471)] | Oakland 98th Ave | [(-122.1568,37.498),(-122.1558,37.502)] | Oakland 98th Ave | [(-122.1693,37.438),(-122.1682,37.444)] | Oakland 98th Ave | [(-122.2001,37.258),(-122.1974,37.27)] | Lafayette -(333 rows) +(325 rows) SELECT name, #thepath FROM iexit ORDER BY 1, 2; name | ?column? ------------------------------------+---------- I- 580 | 2 I- 580 | 2 I- 580 | 2 I- 580 | 2 I- 580 | 2 I- 580 | 2 - I- 580 | 2 - I- 580 | 2 - I- 580 | 2 - I- 580 | 2 - I- 580 | 2 - I- 580 | 3 - I- 580 | 3 - I- 580 | 3 - I- 580 | 3 - I- 580 | 3 - I- 580 | 3 - I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 3 I- 580 | 4 I- 580 | 4 - I- 580 | 4 - I- 580 | 4 I- 580 | 5 I- 580 | 5 I- 580 | 5 I- 580 | 5 - I- 580 | 5 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 - I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 6 I- 580 | 7 I- 580 | 7 I- 580 | 7 I- 580 | 7 - I- 580 | 7 - I- 580 | 7 - I- 580 | 7 - I- 580 | 8 - I- 580 | 8 - I- 580 | 8 I- 580 | 8 I- 580 | 8 I- 580 | 8 I- 580 | 8 I- 580 | 8 I- 580 | 8 I- 580 | 9 I- 580 | 9 - I- 580 | 9 - I- 580 | 9 - I- 580 | 9 I- 580 | 12 I- 580 | 12 I- 580 | 12 I- 580 | 12 I- 580 | 12 I- 580 | 12 I- 580 | 12 - I- 580 | 12 - I- 580 | 12 - I- 580 | 12 - I- 580 | 13 I- 580 | 13 I- 580 | 13 I- 580 | 13 I- 580 | 13 I- 580 | 13 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 14 I- 580 | 18 I- 580 | 18 I- 580 | 18 I- 580 | 18 I- 580 | 18 - I- 580 | 18 I- 580 | 21 I- 580 | 21 I- 580 | 21 I- 580 | 21 I- 580 | 21 I- 580 | 21 - I- 580 | 21 - I- 580 | 21 - I- 580 | 21 - I- 580 | 21 - I- 580 | 22 I- 580 | 22 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 @@ -502,50 +450,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 - I- 580 Ramp | 2 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 @@ -587,90 +505,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 3 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 - I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 I- 580 Ramp | 4 @@ -698,336 +546,231 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 I- 580 Ramp | 5 - I- 580 Ramp | 5 - I- 580 Ramp | 5 - I- 580 Ramp | 6 - I- 580 Ramp | 6 I- 580 Ramp | 6 I- 580 Ramp | 7 I- 580 Ramp | 8 I- 580 Ramp | 8 I- 580 Ramp | 8 I- 580 Ramp | 8 I- 580 Ramp | 8 I- 580 Ramp | 8 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 2 I- 580/I-680 Ramp | 4 I- 580/I-680 Ramp | 4 I- 580/I-680 Ramp | 4 - I- 580/I-680 Ramp | 4 I- 580/I-680 Ramp | 5 I- 580/I-680 Ramp | 6 I- 580/I-680 Ramp | 6 - I- 580/I-680 Ramp | 6 - I- 680 | 2 - I- 680 | 2 - I- 680 | 2 - I- 680 | 2 - I- 680 | 2 - I- 680 | 2 I- 680 | 2 I- 680 | 3 - I- 680 | 3 - I- 680 | 3 - I- 680 | 4 - I- 680 | 4 I- 680 | 4 I- 680 | 5 I- 680 | 5 - I- 680 | 5 - I- 680 | 7 I- 680 | 7 I- 680 | 7 I- 680 | 7 I- 680 | 8 I- 680 | 8 I- 680 | 8 - I- 680 | 8 - I- 680 | 10 - I- 680 | 10 I- 680 | 10 I- 680 | 10 I- 680 | 10 I- 680 | 10 I- 680 | 10 I- 680 | 16 I- 680 | 16 I- 680 | 16 I- 680 | 16 I- 680 | 16 - I- 680 | 16 - I- 680 | 16 - I- 680 | 16 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 I- 680 Ramp | 2 - I- 680 Ramp | 2 - I- 680 Ramp | 2 - I- 680 Ramp | 2 - I- 680 Ramp | 2 - I- 680 Ramp | 2 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 - I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 3 I- 680 Ramp | 4 I- 680 Ramp | 4 - I- 680 Ramp | 4 I- 680 Ramp | 5 I- 680 Ramp | 5 I- 680 Ramp | 5 I- 680 Ramp | 5 I- 680 Ramp | 5 I- 680 Ramp | 5 I- 680 Ramp | 6 I- 680 Ramp | 6 - I- 680 Ramp | 6 - I- 680 Ramp | 6 - I- 680 Ramp | 7 I- 680 Ramp | 7 I- 680 Ramp | 7 I- 680 Ramp | 7 I- 680 Ramp | 8 I- 680 Ramp | 8 I- 680 Ramp | 8 - I- 680 Ramp | 8 I- 80 | 2 I- 80 | 2 I- 80 | 2 I- 80 | 2 I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 2 - I- 80 | 3 - I- 80 | 3 I- 80 | 3 I- 80 | 4 I- 80 | 4 I- 80 | 4 I- 80 | 4 I- 80 | 4 I- 80 | 5 I- 80 | 5 I- 80 | 5 I- 80 | 5 I- 80 | 5 I- 80 | 5 I- 80 | 5 I- 80 | 5 - I- 80 | 5 - I- 80 | 11 - I- 80 | 11 I- 80 | 11 I- 80 | 11 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 2 - I- 80 Ramp | 3 - I- 80 Ramp | 3 - I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 3 I- 80 Ramp | 4 I- 80 Ramp | 4 I- 80 Ramp | 4 I- 80 Ramp | 4 I- 80 Ramp | 5 I- 80 Ramp | 5 I- 80 Ramp | 5 I- 80 Ramp | 5 I- 80 Ramp | 5 - I- 80 Ramp | 5 - I- 80 Ramp | 5 I- 80 Ramp | 7 I- 80 Ramp | 7 I- 80 Ramp | 7 I- 80 Ramp | 7 I- 880 | 2 I- 880 | 2 - I- 880 | 2 - I- 880 | 2 - I- 880 | 2 - I- 880 | 5 - I- 880 | 5 - I- 880 | 5 I- 880 | 5 I- 880 | 5 I- 880 | 5 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 I- 880 | 6 - I- 880 | 6 - I- 880 | 6 - I- 880 | 6 - I- 880 | 7 - I- 880 | 7 I- 880 | 7 I- 880 | 7 I- 880 | 7 I- 880 | 7 I- 880 | 7 I- 880 | 9 I- 880 | 9 I- 880 | 9 - I- 880 | 9 - I- 880 | 9 - I- 880 | 9 - I- 880 | 9 - I- 880 | 10 - I- 880 | 10 - I- 880 | 10 - I- 880 | 10 - I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 10 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 I- 880 | 12 - I- 880 | 12 - I- 880 | 13 - I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 13 I- 880 | 14 I- 880 | 14 I- 880 | 14 I- 880 | 14 - I- 880 | 14 - I- 880 | 14 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 - I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 17 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 I- 880 | 19 - I- 880 | 19 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 @@ -1039,58 +782,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 2 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 - I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 I- 880 Ramp | 3 @@ -1138,31 +843,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 - I- 880 Ramp | 4 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 @@ -1172,81 +866,56 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 5 - I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 6 I- 880 Ramp | 8 I- 880 Ramp | 8 - I- 880 Ramp | 8 I- 980 | 2 I- 980 | 2 I- 980 | 2 - I- 980 | 2 - I- 980 | 2 - I- 980 | 2 - I- 980 | 2 - I- 980 | 2 - I- 980 | 3 - I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 3 I- 980 | 4 I- 980 | 4 I- 980 | 5 I- 980 | 5 I- 980 | 7 I- 980 | 7 - I- 980 | 7 - I- 980 | 7 I- 980 | 12 I- 980 Ramp | 3 - I- 980 Ramp | 3 - I- 980 Ramp | 3 - I- 980 Ramp | 7 -(896 rows) +(573 rows) SELECT * FROM toyemp WHERE name = 'sharon'; name | age | location | annualsal --------+-----+----------+----------- sharon | 25 | (15,12) | 12000 (1 row) -- -- Test for Leaky view scenario -- diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index e7826a4..3cd8427 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -66,21 +66,23 @@ regress_dist_ptpath(PG_FUNCTION_ARGS) float8 result = 0.0; /* keep compiler quiet */ float8 tmp; int i; LSEG lseg; switch (path->npts) { case 0: PG_RETURN_NULL(); case 1: - result = point_dt(pt, &path->p[0]); + result = DatumGetFloat8(DirectFunctionCall2(point_distance, + PointPGetDatum(pt), + PointPGetDatum(&path->p[0]))); break; default: /* * the distance from a point to a path is the smallest distance * from the point to any of its constituent segments. */ Assert(path->npts > 1); for (i = 0; i < path->npts - 1; ++i) { @@ -280,22 +282,27 @@ widget_out(WIDGET *widget) widget->center.x, widget->center.y, widget->radius); } PG_FUNCTION_INFO_V1(pt_in_widget); Datum pt_in_widget(PG_FUNCTION_ARGS) { Point *point = PG_GETARG_POINT_P(0); WIDGET *widget = (WIDGET *) PG_GETARG_POINTER(1); + float8 distance; - PG_RETURN_BOOL(point_dt(point, &widget->center) < widget->radius); + distance = DatumGetFloat8(DirectFunctionCall2(point_distance, + PointPGetDatum(point), + PointPGetDatum(&widget->center))); + + PG_RETURN_BOOL(distance < widget->radius); } PG_FUNCTION_INFO_V1(boxarea); Datum boxarea(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); double width, height; -- 2.7.4 (Apple Git-66)