From 1f30dff669e7b332cfa1fde5852cd43bd0418890 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-v03 --- src/backend/access/gist/gistproc.c | 102 +- src/backend/access/spgist/spgkdtreeproc.c | 25 +- src/backend/utils/adt/geo_ops.c | 1588 ++++++++++++++-------------- src/backend/utils/adt/geo_spgist.c | 40 +- src/include/utils/geo_decls.h | 49 +- src/test/regress/expected/point.out | 8 +- src/test/regress/expected/select_views.out | 29 +- src/test/regress/sql/select_views.sql | 2 +- 8 files changed, 890 insertions(+), 953 deletions(-) diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index 24b262d..37383a8 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -858,24 +858,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 = (float8_eq(b1->low.x, b2->low.x) && @@ -1127,24 +1123,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; + r->high.x = float8_pl(in->center.x, in->radius); + r->low.x = float8_mi(in->center.x, in->radius); + r->high.y = float8_pl(in->center.y, in->radius); + r->low.y = float8_mi(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); } @@ -1168,24 +1164,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; + bbox.high.x = float8_pl(query->center.x, query->radius); + bbox.low.x = float8_mi(query->center.x, query->radius); + bbox.high.y = float8_pl(query->center.y, query->radius); + bbox.low.y = float8_mi(query->center.y, query->radius); result = rtree_internal_consistent(DatumGetBoxP(entry->key), &bbox, strategy); PG_RETURN_BOOL(result); } /************************************************** * Point ops **************************************************/ @@ -1246,109 +1242,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 (float8_le(point->x, box->high.x) && + float8_ge(point->x, box->low.x) && + float8_le(point->y, box->high.y) && + float8_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 (float8_le(point->x, box->high.x) && + float8_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(float8_le(box->low.y, box->high.y)); + if (float8_gt(point->y, box->high.y)) + result = float8_mi(point->y, box->high.y); + else if (float8_lt(point->y, box->low.y)) + result = float8_mi(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 (float8_le(point->y, box->high.y) && + float8_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(float8_le(box->low.x, box->high.x)); + if (float8_gt(point->x, box->high.x)) + result = float8_mi(point->x, box->high.x); + else if (float8_lt(point->x, box->low.x)) + result = float8_mi(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 (float8_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 (float8_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 (float8_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 = float8_lt(key->low.x, query->x); break; case RTRightStrategyNumber: - result = FPgt(key->high.x, query->x); + result = float8_gt(key->high.x, query->x); break; case RTAboveStrategyNumber: - result = FPgt(key->high.y, query->y); + result = float8_gt(key->high.y, query->y); break; case RTBelowStrategyNumber: - result = FPlt(key->low.y, query->y); + result = float8_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 = (float8_eq(key->low.x, query->x) && + float8_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 = (float8_le(query->x, key->high.x) && + float8_ge(query->x, key->low.x) && + float8_le(query->y, key->high.y) && + float8_ge(query->y, key->low.y)); } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); result = false; /* keep compiler quiet */ break; } return result; } @@ -1375,39 +1375,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 = (float8_ge(key->high.x, query->low.x) && + float8_le(key->low.x, query->high.x) && + float8_ge(key->high.y, query->low.y) && + float8_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), @@ -1416,22 +1408,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(float8_eq(box->high.x, box->low.x) && + float8_eq(box->high.y, box->low.y)); result = DatumGetBool(DirectFunctionCall2( poly_contain_pt, PolygonPGetDatum(query), PointPGetDatum(&box->high))); *recheck = false; } } break; case CircleStrategyNumberGroup: { @@ -1445,22 +1437,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(float8_eq(box->high.x, box->low.x) && + float8_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..c030d7b 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 && float8_lt(query->x, coord)) which &= (1 << 1); break; case RTRightStrategyNumber: - if ((in->level % 2) != 0 && FPgt(query->x, coord)) + if ((in->level % 2) != 0 && float8_gt(query->x, coord)) which &= (1 << 2); break; case RTSameStrategyNumber: if ((in->level % 2) != 0) { - if (FPlt(query->x, coord)) + if (float8_lt(query->x, coord)) which &= (1 << 1); - else if (FPgt(query->x, coord)) + else if (float8_gt(query->x, coord)) which &= (1 << 2); } else { - if (FPlt(query->y, coord)) + if (float8_lt(query->y, coord)) which &= (1 << 1); - else if (FPgt(query->y, coord)) + else if (float8_gt(query->y, coord)) which &= (1 << 2); } break; case RTBelowStrategyNumber: - if ((in->level % 2) == 0 && FPlt(query->y, coord)) + if ((in->level % 2) == 0 && float8_lt(query->y, coord)) which &= (1 << 1); break; case RTAboveStrategyNumber: - if ((in->level % 2) == 0 && FPgt(query->y, coord)) + if ((in->level % 2) == 0 && float8_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 (float8_lt(boxQuery->high.x, coord)) which &= (1 << 1); - else if (FPgt(boxQuery->low.x, coord)) + else if (float8_gt(boxQuery->low.x, coord)) which &= (1 << 2); } else { - if (FPlt(boxQuery->high.y, coord)) + if (float8_lt(boxQuery->high.y, coord)) which &= (1 << 1); - else if (FPgt(boxQuery->low.y, coord)) + else if (float8_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 9e01ce9..e1f3698 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -37,52 +37,57 @@ 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 LINE *line_construct_pm(Point *pt, double m); static void line_construct_pts(LINE *line, Point *pt1, Point *pt2); -static bool lseg_intersect_internal(LSEG *l1, LSEG *l2); +static bool lseg_intersect_internal(Point *result, LSEG *l1, LSEG *l2); static double lseg_dt(LSEG *l1, LSEG *l2); static bool on_ps_internal(Point *pt, LSEG *lseg); +static float8 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 bool point_eq_internal(Point *pt1, Point *pt2); 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 bool lseg_intersect_line_internal(Point *result, LSEG *lseg, 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 line_intersect_internal(Point *result, LINE *l1, LINE *l2); static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start); -static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2); static double dist_ppoly_internal(Point *pt, POLYGON *poly); +static void point_add_internal(Point *result, Point *pt1, Point *pt2); +static void point_sub_internal(Point *result, Point *pt1, Point *pt2); +static void point_mul_internal(Point *result, Point *pt1, Point *pt2); +static void point_div_internal(Point *result, Point *pt1, Point *pt2); +static void point_mul_float8_internal(Point *result, Point *pt, float8 num); +static float8 point_cross_product_internal(Point *pt1, Point *pt2); /* * 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. */ #define LDELIM '(' #define RDELIM ')' @@ -350,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 (float8_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 (float8_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. @@ -395,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 (float8_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 (float8_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); } /* @@ -445,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 (float8_gt(x1, x2)) { result->high.x = x1; result->low.x = x2; } else { result->high.x = x2; result->low.x = x1; } - if (y1 > y2) + if (float8_gt(y1, y2)) { result->high.y = y1; result->low.y = y2; } else { result->high.y = y2; result->low.y = y1; } @@ -496,246 +501,244 @@ 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(point_eq_internal(&box1->high, &box2->high) && + point_eq_internal(&box1->low, &box2->low)); } /* 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 (float8_le(box1->low.x, box2->high.x) && + float8_le(box2->low.x, box1->high.x) && + float8_le(box1->low.y, box2->high.y) && + float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_le(box1->high.x, box2->high.x) && + float8_ge(box1->low.x, box2->low.x) && + float8_le(box1->high.y, box2->high.y) && + float8_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(float8_ge(box1->high.x, box2->high.x) && + float8_le(box1->low.x, box2->low.x) && + float8_ge(box1->high.y, box2->high.y) && + float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(float8_ge(box_ar(box1), box_ar(box2))); } /*---------------------------------------------------------- * "Arithmetic" operators on boxes. *---------------------------------------------------------*/ /* box_area - returns the area of the box. */ Datum @@ -778,21 +781,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)); @@ -810,22 +813,22 @@ 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; + center->x = float8_div(float8_pl(box->high.x, box->low.x), 2.0); + center->y = float8_div(float8_pl(box->high.y, box->low.y), 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; @@ -855,24 +858,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 = float8_min(box1->high.x, box2->high.x); + result->low.x = float8_max(box1->low.x, box2->low.x); + result->high.y = float8_min(box1->high.y, box2->high.y); + result->low.y = float8_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 @@ -924,29 +927,29 @@ line_in(PG_FUNCTION_ARGS) s = str; while (isspace((unsigned char) *s)) s++; if (*s == '{') { if (!line_decode(s + 1, str, line)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type %s: \"%s\"", "line", str))); - if (FPzero(line->A) && FPzero(line->B)) + if (float8_eq(line->A, 0.0) && float8_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 (point_eq_internal(&lseg.p[0], &lseg.p[1])) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: must be two distinct points"))); line_construct_pts(line, &lseg.p[0], &lseg.p[1]); } PG_RETURN_LINE_P(line); } @@ -969,20 +972,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 (float8_eq(line->A, 0.0) && float8_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); @@ -1002,72 +1010,73 @@ line_send(PG_FUNCTION_ARGS) *---------------------------------------------------------*/ /* line_construct_pm() * point-slope */ static LINE * line_construct_pm(Point *pt, double m) { LINE *result = (LINE *) palloc(sizeof(LINE)); - if (m == DBL_MAX) + if (float8_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; + result->C = float8_mi(pt->y, float8_mul(m, pt->x)); } return result; } /* * Fill already-allocated LINE struct from two points on the line */ static void line_construct_pts(LINE *line, Point *pt1, Point *pt2) { - if (FPeq(pt1->x, pt2->x)) + if (float8_eq(pt1->x, pt2->x)) { /* vertical */ /* use "x = C" */ - line->A = -1; - line->B = 0; + line->A = -1.0; + line->B = 0.0; line->C = pt1->x; #ifdef GEODEBUG printf("line_construct_pts- line is vertical\n"); #endif } - else if (FPeq(pt1->y, pt2->y)) + else if (float8_eq(pt1->y, pt2->y)) { /* horizontal */ /* use "y = C" */ - line->A = 0; - line->B = -1; + line->A = 0.0; + line->B = -1.0; line->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->A = float8_div(float8_mi(pt2->y, pt1->y), + float8_mi(pt2->x, pt1->x)); line->B = -1.0; - line->C = pt1->y - line->A * pt1->x; + line->C = float8_mi(pt1->y, float8_mul(line->A, pt1->x)); /* on some platforms, the preceding expression tends to produce -0 */ - if (line->C == 0.0) + if (float8_eq(line->C, 0.0)) line->C = 0.0; #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 } } /* line_construct_pp() * two points @@ -1087,178 +1096,201 @@ line_construct_pp(PG_FUNCTION_ARGS) /*---------------------------------------------------------- * Relative position routines. *---------------------------------------------------------*/ Datum line_intersect(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel, - LinePGetDatum(l1), - LinePGetDatum(l2)))); + PG_RETURN_BOOL(line_intersect_internal(NULL, l1, l2)); } Datum line_parallel(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->B)); - - PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B))); + PG_RETURN_BOOL(!line_intersect_internal(NULL, l1, l2)); } Datum line_perp(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - if (FPzero(l1->A)) - PG_RETURN_BOOL(FPzero(l2->B)); - else if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->A)); + if (float8_eq(l1->A, 0.0)) /* horizontal? */ + PG_RETURN_BOOL(float8_eq(l2->B, 0.0)); + if (float8_eq(l1->B, 0.0)) /* vertical? */ + PG_RETURN_BOOL(float8_eq(l2->A, 0.0)); - PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0)); + if (float8_eq(l2->A, 0.0) || float8_eq(l2->B, 0.0)) + PG_RETURN_BOOL(false); + + PG_RETURN_BOOL(float8_eq(float8_mul(l1->A, l2->B), + -float8_mul(l2->A, l1->B))); } Datum line_vertical(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->B)); + PG_RETURN_BOOL(float8_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(float8_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; - if (!FPzero(l2->A)) - k = l1->A / l2->A; - else if (!FPzero(l2->B)) - k = l1->B / l2->B; - else if (!FPzero(l2->C)) - k = l1->C / l2->C; - else - k = 1.0; + if (float8_ne(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B))) + 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 (float8_ne(l1->A, 0.0)) + { + if (float8_eq(l2->A, 0.0)) + PG_RETURN_BOOL(false); + + PG_RETURN_BOOL(float8_eq(float8_mul(l1->A, l2->C), + float8_mul(l2->A, l1->C))); + } + + /* l1->A == 0.0 => l1->B != 0.0 => l2->A == 0.0 */ + if (float8_eq(l2->B, 0.0)) + PG_RETURN_BOOL(false); + + PG_RETURN_BOOL(float8_eq(float8_mul(l1->B, l2->C), + float8_mul(l2->B, l1->C))); } /*---------------------------------------------------------- * 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; + Point tmp; - if (!DatumGetBool(DirectFunctionCall2(line_parallel, - LinePGetDatum(l1), - LinePGetDatum(l2)))) + if (line_intersect_internal(NULL, l1, 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); + + /* horizontal or vertical? */ + if (float8_eq(l1->A, 0.0) || float8_eq(l1->B, 0.0)) + PG_RETURN_FLOAT8(float8_mi(l1->C, l2->C)); + + tmp.x = 0.0; + tmp.y = float8_div(-l1->C, l1->B); + result = dist_pl_internal(&tmp, 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); LINE *l2 = PG_GETARG_LINE_P(1); Point *result; - result = line_interpt_internal(l1, l2); + result = (Point *) palloc(sizeof(Point)); - if (result == NULL) - PG_RETURN_NULL(); - PG_RETURN_POINT_P(result); + if (line_intersect_internal(result, l1, l2)) + PG_RETURN_POINT_P(result); + PG_RETURN_NULL(); } /* - * Internal version of line_interpt + * Check if two lines intersect (they do, if they are not parallel) * - * returns a NULL pointer if no intersection point + * It sets the intersection point to *result, if it is not NULL. + * + * 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. */ -static Point * -line_interpt_internal(LINE *l1, LINE *l2) +static bool +line_intersect_internal(Point *result, LINE *l1, LINE *l2) { - Point *result; - 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 (float8_eq(l1->A, 0.0)) /* l1 horizontal? */ { - x = l1->C; - y = (l2->A * x + l2->C); + if (float8_eq(l2->A, 0.0)) + return false; + + if (result != NULL) + { + result->y = float8_div(-l1->C, l1->B); + result->x = float8_div(-float8_pl(float8_mul(l2->B, result->y), + l2->C), l2->A); + } } - else if (FPzero(l2->B)) /* l2 vertical? */ + else if (float8_eq(l1->B, 0.0)) /* l1 vertical? */ { - x = l2->C; - y = (l1->A * x + l1->C); + if (float8_eq(l2->B, 0.0)) + return false; + + if (result != NULL) + { + result->x = float8_div(-l1->C, l1->A); + result->y = float8_div(-float8_pl(float8_mul(l2->A, result->x), + l2->C), l2->B); + } } else { - x = (l1->C - l2->C) / (l2->A - l1->A); - y = (l1->A * x + l1->C); + if (float8_eq(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B))) + return false; + + if (result != NULL) + { + if (float8_eq(l2->B, 0.0)) /* l2 vertical? */ + result->x = float8_div(-l2->C, l2->A); + else + result->x = float8_div(float8_mi(float8_mul(l1->B, l2->C), + float8_mul(l2->B, l1->C)), + float8_mi(float8_mul(l1->A, l2->B), + float8_mul(l2->A, l1->B))); + result->y = float8_div(-float8_pl(float8_mul(l1->A, result->x), + l1->C), 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", + printf("line_intersect- 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); + if (result != NULL) + printf("line_intersect- lines intersect at (%.*g,%.*g)\n", DBL_DIG, result->x, DBL_DIG, result->y); #endif - return result; + return true; } /*********************************************************************** ** ** Routines for 2D paths (sequences of line segments, also ** called `polylines'). ** ** This is not a general package for geometric paths, ** which of course include polygons; the emphasis here @@ -1284,26 +1316,26 @@ path_area(PG_FUNCTION_ARGS) double area = 0.0; 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; + area = float8_pl(area, + float8_mi(float8_mul(path->p[i].x, path->p[j].y), + float8_mul(path->p[i].y, path->p[j].x))); } - area *= 0.5; - PG_RETURN_FLOAT8(area < 0.0 ? -area : area); + PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0)); } Datum path_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); PATH *path; bool isopen; char *s; @@ -1520,31 +1552,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. */ @@ -1560,33 +1592,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 = float8_max(p1->p[i].x, b1.high.x); + b1.high.y = float8_max(p1->p[i].y, b1.high.y); + b1.low.x = float8_min(p1->p[i].x, b1.low.x); + b1.low.y = float8_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 = float8_max(p2->p[i].x, b2.high.x); + b2.high.y = float8_max(p2->p[i].y, b2.high.y); + b2.low.x = float8_min(p2->p[i].x, b2.low.x); + b2.low.y = float8_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) @@ -1606,21 +1638,21 @@ path_inter(PG_FUNCTION_ARGS) jprev = j - 1; else { if (!p2->closed) 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]); - if (lseg_intersect_internal(&seg1, &seg2)) + if (lseg_intersect_internal(NULL, &seg1, &seg2)) PG_RETURN_BOOL(true); } } /* if we dropped through, no two segs intersected */ PG_RETURN_BOOL(false); } /* path_distance() * This essentially does a cartesian product of the lsegs in the @@ -1660,25 +1692,22 @@ path_distance(PG_FUNCTION_ARGS) jprev = j - 1; else { if (!p2->closed) 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) + tmp = lseg_dt(&seg1, &seg2); + if (!have_min || float8_lt(tmp, min)) { min = tmp; have_min = true; } } } if (!have_min) PG_RETURN_NULL(); @@ -1703,21 +1732,21 @@ path_length(PG_FUNCTION_ARGS) 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]); + result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i])); } PG_RETURN_FLOAT8(result); } /*********************************************************************** ** ** Routines for 2D points. ** ***********************************************************************/ @@ -1772,31 +1801,20 @@ point_send(PG_FUNCTION_ARGS) StringInfoData buf; pq_begintypsend(&buf); pq_sendfloat8(&buf, pt->x); pq_sendfloat8(&buf, pt->y); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } static Point * -point_construct(double x, double y) -{ - Point *result = (Point *) palloc(sizeof(Point)); - - 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; @@ -1813,125 +1831,138 @@ point_copy(Point *pt) * that results may, strictly speaking, be a lie (unless * EPSILON = 0.0). *---------------------------------------------------------*/ Datum point_left(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(FPlt(pt1->x, pt2->x)); + PG_RETURN_BOOL(float8_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(float8_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(float8_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(float8_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(float8_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(float8_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(point_eq_internal(pt1, pt2)); +} + +static bool +point_eq_internal(Point *pt1, Point *pt2) +{ + return float8_eq(pt1->x, pt2->x) && float8_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(float8_ne(pt1->x, pt2->x) || float8_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 point_dt(Point *pt1, Point *pt2) { + float8 result; + + result = float8_hypot(float8_mi(pt1->x, pt2->x), float8_mi(pt1->y, pt2->y)); + #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)); } double point_sl(Point *pt1, Point *pt2) { - return (FPeq(pt1->x, pt2->x) - ? (double) DBL_MAX - : (pt1->y - pt2->y) / (pt1->x - pt2->x)); + if (float8_eq(pt1->x, pt2->x)) + return (double) DBL_MAX; + if (float8_eq(pt1->y, pt2->y)) + return 0.0; + return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x)); } /*********************************************************************** ** ** Routines for 2D line segments. ** ***********************************************************************/ /*---------------------------------------------------------- @@ -2033,58 +2064,111 @@ lseg_length(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1])); } /*---------------------------------------------------------- * Relative position routines. *---------------------------------------------------------*/ -/* - ** find intersection of the two lines, and see if it falls on - ** both segments. - */ Datum 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)); + PG_RETURN_BOOL(lseg_intersect_internal(NULL, l1, l2)); } +/* + * Check if two line segments intersect using the vector cross product + * approach [1] + * + * It sets the intersection point to *result, if it is not NULL. + * + * NOTE: If the segments are collinear 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 this would need to be changed one day, is trivial to detect collinear + * lines with this algorithm. + * + * [1] http://stackoverflow.com/a/565282/786339 + */ static bool -lseg_intersect_internal(LSEG *l1, LSEG *l2) +lseg_intersect_internal(Point *result, LSEG *l1, LSEG *l2) { - LINE ln; - Point *interpt; - bool retval; + float8 denominator, + ratio1, + ratio2; + Point p1, + p2, + p3; - line_construct_pts(&ln, &l2->p[0], &l2->p[1]); - interpt = interpt_sl(l1, &ln); + if (point_eq_internal(&l1->p[0], &l1->p[1])) + { + if (!on_ps_internal(&l1->p[0], l2)) + return false; - if (interpt != NULL && on_ps_internal(interpt, l2)) - retval = true; /* interpt on l1 and l2 */ - else - retval = false; - return retval; + if (result != NULL) + { + result->x = l1->p[0].x; + result->y = l1->p[0].y; + } + return true; + } + if (point_eq_internal(&l2->p[0], &l2->p[1])) + { + if (!on_ps_internal(&l2->p[0], l1)) + return false; + + if (result != NULL) + { + result->x = l2->p[0].x; + result->y = l2->p[0].y; + } + return true; + } + + point_sub_internal(&p1, &l1->p[1], &l1->p[0]); + point_sub_internal(&p2, &l2->p[1], &l2->p[0]); + denominator = point_cross_product_internal(&p1, &p2); + + /* Are they parallel? */ + if (float8_eq(denominator, 0.0)) + return false; + + point_sub_internal(&p3, &l2->p[0], &l1->p[0]); + ratio1 = float8_div(point_cross_product_internal(&p3, &p1), denominator); + ratio2 = float8_div(point_cross_product_internal(&p3, &p2), denominator); + + if (float8_lt(ratio1, 0.0) || float8_gt(ratio1, 1.0) || + float8_lt(ratio2, 0.0) || float8_gt(ratio2, 1.0)) + return false; + + if (result != NULL) + { + point_mul_float8_internal(result, &p1, ratio2); + point_add_internal(result, &l1->p[0], result); + } + + return true; } 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(float8_eq(point_sl(&l1->p[0], &l1->p[1]), + point_sl(&l2->p[0], &l2->p[1]))); } /* lseg_perp() * Determine if two line segments are perpendicular. * * This code did not get the correct answer for * '((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg * So, modified it to check explicitly for slope of vertical line * returned by point_sl() and the results seem better. * - thomas 1998-01-31 @@ -2096,107 +2180,105 @@ lseg_perp(PG_FUNCTION_ARGS) LSEG *l2 = PG_GETARG_LSEG_P(1); double m1, m2; m1 = point_sl(&(l1->p[0]), &(l1->p[1])); m2 = point_sl(&(l2->p[0]), &(l2->p[1])); #ifdef GEODEBUG printf("lseg_perp- slopes are %g and %g\n", m1, m2); #endif - if (FPzero(m1)) - PG_RETURN_BOOL(FPeq(m2, DBL_MAX)); - else if (FPzero(m2)) - PG_RETURN_BOOL(FPeq(m1, DBL_MAX)); - PG_RETURN_BOOL(FPeq(m1 / m2, -1.0)); + if (float8_eq(m1, 0.0)) + PG_RETURN_BOOL(float8_eq(m2, DBL_MAX)); + if (float8_eq(m2, 0.0)) + PG_RETURN_BOOL(float8_eq(m1, DBL_MAX)); + PG_RETURN_BOOL(float8_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(float8_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(float8_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(point_eq_internal(&l1->p[0], &l2->p[0]) && + point_eq_internal(&l1->p[1], &l2->p[1])); } 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(float8_ne(l1->p[0].x, l2->p[0].x) || + float8_ne(l1->p[0].y, l2->p[0].y) || + float8_ne(l1->p[1].x, l2->p[1].x) || + float8_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(float8_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(float8_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(float8_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(float8_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 @@ -2212,116 +2294,63 @@ lseg_distance(PG_FUNCTION_ARGS) } /* lseg_dt() * Distance between two line segments. * Must check both sets of endpoints to ensure minimum distance is found. * - thomas 1998-02-01 */ static double lseg_dt(LSEG *l1, LSEG *l2) { - double result, - d; + double result; - if (lseg_intersect_internal(l1, l2)) + if (lseg_intersect_internal(NULL, l1, l2)) return 0.0; - d = dist_ps_internal(&l1->p[0], l2); - result = d; - d = dist_ps_internal(&l1->p[1], l2); - result = Min(result, d); - d = dist_ps_internal(&l2->p[0], l1); - result = Min(result, d); - d = dist_ps_internal(&l2->p[1], l1); - result = Min(result, d); + result = dist_ps_internal(&l1->p[0], l2); + result = float8_min(result, dist_ps_internal(&l1->p[1], l2)); + result = float8_min(result, dist_ps_internal(&l2->p[0], l1)); + result = float8_min(result, dist_ps_internal(&l2->p[1], l1)); return result; } Datum lseg_center(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); Point *result; result = (Point *) palloc(sizeof(Point)); - result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0; - result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0; + result->x = float8_div(float8_pl(lseg->p[0].x, lseg->p[1].x), 2.0); + result->y = float8_div(float8_pl(lseg->p[0].y, lseg->p[1].y), 2.0); PG_RETURN_POINT_P(result); } -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); - 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)) - { - 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); LSEG *l2 = PG_GETARG_LSEG_P(1); Point *result; - result = lseg_interpt_internal(l1, l2); - if (!PointerIsValid(result)) - PG_RETURN_NULL(); + result = (Point *) palloc(sizeof(Point)); - PG_RETURN_POINT_P(result); + if (lseg_intersect_internal(result, l1, l2)) + PG_RETURN_POINT_P(result); + PG_RETURN_NULL(); } /*********************************************************************** ** ** Routines for position comparisons of differently-typed ** 2D objects. ** ***********************************************************************/ /*--------------------------------------------------------------------- @@ -2337,84 +2366,81 @@ 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)); + return float8_div(fabs(point_on_line_value(pt, line)), + float8_hypot(line->A, line->B)); } /* * 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); PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg)); } static double dist_ps_internal(Point *pt, LSEG *lseg) { double m; /* slope of perp. */ LINE *ln; - double result, - tmpdist; - Point *ip; + double result; + Point tmp; /* * 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) + if (float8_eq(lseg->p[0].x, lseg->p[1].x)) + m = 0.0; + else if (float8_eq(lseg->p[0].y, lseg->p[1].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 = float8_div(-1.0, point_sl(&lseg->p[0], &lseg->p[1])); 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) + if (lseg_intersect_line_internal(&tmp, lseg, ln)) { /* yes, so use distance to the intersection point */ - result = point_dt(pt, ip); + result = point_dt(pt, &tmp); #ifdef GEODEBUG printf("dist_ps- distance is %f to intersection point is (%f,%f)\n", - result, ip->x, ip->y); + result, tmp.x, tmp.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) - result = tmpdist; + result = float8_min(point_dt(pt, &lseg->p[0]), + point_dt(pt, &lseg->p[1])); } return result; } /* * Distance from a point to a path */ Datum dist_ppath(PG_FUNCTION_ARGS) @@ -2452,21 +2478,21 @@ dist_ppath(PG_FUNCTION_ARGS) 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 || float8_lt(tmp, result)) { result = tmp; have_min = true; } } break; } PG_RETURN_FLOAT8(result); } @@ -2490,33 +2516,27 @@ dist_pb(PG_FUNCTION_ARGS) } /* * Distance from a lseg to a line */ Datum dist_sl(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); LINE *line = PG_GETARG_LINE_P(1); - float8 result, - d2; + float8 result; - if (has_interpt_sl(lseg, line)) + if (lseg_intersect_line_internal(NULL, 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) - result = d2; - } + result = float8_min(dist_pl_internal(&lseg->p[0], line), + dist_pl_internal(&lseg->p[1], line)); PG_RETURN_FLOAT8(result); } /* * Distance from a lseg to a box */ Datum dist_sb(PG_FUNCTION_ARGS) { @@ -2560,23 +2580,23 @@ dist_lb(PG_FUNCTION_ARGS) Datum dist_cpoly(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); POLYGON *poly = PG_GETARG_POLYGON_P(1); float8 result; /* calculate distance to center, and subtract radius */ result = dist_ppoly_internal(&circle->center, poly); - result -= circle->radius; - if (result < 0) - result = 0; + result = float8_mi(result, circle->radius); + if (float8_lt(result, 0.0)) + result = 0.0; PG_RETURN_FLOAT8(result); } /* * Distance from a point to a polygon */ Datum dist_ppoly(PG_FUNCTION_ARGS) { @@ -2631,248 +2651,143 @@ 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 (float8_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) +/* + * Check if the line segment intersects with the line + * + * It sets the intersection point to *result, if it is not NULL. + */ +static bool +lseg_intersect_line_internal(Point *result, LSEG *lseg, LINE *line) { + Point interpt; LINE tmp; - Point *p; line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]); - p = line_interpt_internal(&tmp, line); + #ifdef GEODEBUG - printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n", + printf("lseg_intersect_line- 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", + printf("lseg_intersect_line- 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)) - { -#ifdef GEODEBUG - printf("interpt_sl- intersection point is on segment\n"); -#endif - } - else - p = NULL; - } - return p; + if (!line_intersect_internal(&interpt, &tmp, line)) + return false; + +#ifdef GEODEBUG + printf("lseg_intersect_line- intersection point is (%.*g %.*g)\n", DBL_DIG, interpt.x, DBL_DIG, interpt.y); +#endif + + if (point_lseg_cmp(&interpt, lseg) != 0) + return false; + +#ifdef GEODEBUG + printf("lseg_intersect_line- intersection point is on segment\n"); +#endif + + if (result != NULL) + *result = interpt; + + return true; } -/* variant: just indicate if intersection point exists */ -static bool -has_interpt_sl(LSEG *lseg, LINE *line) -{ - Point *tmp; - - tmp = interpt_sl(lseg, line); - if (tmp) - return true; - return false; -} /*--------------------------------------------------------------------- * close_ * Point of closest proximity between objects. *-------------------------------------------------------------------*/ /* 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); Point *result; - LINE *tmp; - double invm; result = (Point *) palloc(sizeof(Point)); - if (FPzero(line->B)) /* vertical? */ + if (float8_eq(line->B, 0.0)) /* vertical? */ { - result->x = line->C; + result->x = float8_div(-line->C, line->A); result->y = pt->y; - PG_RETURN_POINT_P(result); } - if (FPzero(line->A)) /* horizontal? */ + else if (float8_eq(line->A, 0.0)) /* horizontal? */ { - result->x = pt->x; - result->y = line->C; - PG_RETURN_POINT_P(result); + result->x = float8_div(-line->C, line->B); + result->y = pt->y; + } + else + { + double slope; + + /* + * Drop a perpendicular and find the intersection point + * + * We need to invert and flip the sign on the slope to get the + * perpendicular. We might lose some precision on the division, but + * it cannot be as much to turn the line. + */ + slope = float8_div(line->B, line->A); + line_intersect_internal(result, line_construct_pm(pt, slope), line); } - /* 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); } -/* 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; + LINE tmp; -#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 + line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]); + result = DatumGetPointP(DirectFunctionCall2(close_pl, + PointPGetDatum(pt), + LsegPGetDatum(&tmp))); + 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 (order < 0) + *result = lseg->p[0]; + else if (order > 0) + *result = lseg->p[1]; - 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 PG_RETURN_POINT_P(result); } /* close_lseg() * Closest point to l1 on l2. */ Datum close_lseg(PG_FUNCTION_ARGS) { @@ -2880,38 +2795,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 (float8_lt(d, dist)) { dist = d; memcpy(&point, &l1->p[1], sizeof(Point)); } - if (dist_ps_internal(&l2->p[0], l1) < dist) + if (float8_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 (float8_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))); } @@ -2940,37 +2856,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 (float8_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 (float8_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 (float8_lt(d, dist)) { dist = d; memcpy(&lseg, &seg, sizeof(lseg)); } PG_RETURN_DATUM(DirectFunctionCall2(close_ps, PointPGetDatum(pt), LsegPGetDatum(&lseg))); } @@ -2986,30 +2905,31 @@ close_pb(PG_FUNCTION_ARGS) Datum close_sl(PG_FUNCTION_ARGS) { #ifdef NOT_USED LSEG *lseg = PG_GETARG_LSEG_P(0); LINE *line = PG_GETARG_LINE_P(1); Point *result; float8 d1, d2; - result = interpt_sl(lseg, line); - if (result) + result = (Point *) palloc(sizeof(Point)); + + if (lseg_intersect_line_internal(result, lseg, line)) PG_RETURN_POINT_P(result); d1 = dist_pl_internal(&lseg->p[0], line); d2 = dist_pl_internal(&lseg->p[1], line); - if (d1 < d2) - result = point_copy(&lseg->p[0]); + if (float8_lt(d1, d2)) + *result = lseg->p[0]; else - result = point_copy(&lseg->p[1]); + *result = lseg->p[1]; PG_RETURN_POINT_P(result); #endif ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function \"close_sl\" not implemented"))); PG_RETURN_NULL(); } @@ -3019,30 +2939,31 @@ close_sl(PG_FUNCTION_ARGS) */ Datum close_ls(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); Point *result; float8 d1, d2; - result = interpt_sl(lseg, line); - if (result) + result = (Point *) palloc(sizeof(Point)); + + if (lseg_intersect_line_internal(result, lseg, line)) PG_RETURN_POINT_P(result); d1 = dist_pl_internal(&lseg->p[0], line); d2 = dist_pl_internal(&lseg->p[1], line); - if (d1 < d2) - result = point_copy(&lseg->p[0]); + if (float8_lt(d1, d2)) + *result = lseg->p[0]; else - result = point_copy(&lseg->p[1]); + *result = lseg->p[1]; PG_RETURN_POINT_P(result); } /* close_sb() * Closest point on or in box to line segment. */ Datum close_sb(PG_FUNCTION_ARGS) { @@ -3065,37 +2986,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 (float8_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 (float8_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 (float8_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))); } @@ -3123,62 +3047,141 @@ close_lb(PG_FUNCTION_ARGS) /* on_pl - * Does the point satisfy the equation? */ Datum on_pl(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C)); + PG_RETURN_BOOL(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 + * Does the point on line segment? */ Datum on_ps(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); PG_RETURN_BOOL(on_ps_internal(pt, lseg)); } static bool on_ps_internal(Point *pt, LSEG *lseg) { - return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]), - point_dt(&lseg->p[0], &lseg->p[1])); + LINE tmp; + + /* + * 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. + */ + if (point_lseg_cmp(pt, lseg) != 0) + return false; + + line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]); + if (float8_ne(point_on_line_value(pt, &tmp), 0.0)) + return false; + + return true; +} + +/* + * 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) +{ + return float8_pl(float8_pl(float8_mul(line->A, pt->x), + float8_mul(line->B, pt->y)), line->C); +} + +/* + * Compare a point with a line segment + * + * This function is useful when the point and line segment are collinear. + * 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 (float8_lt(lseg->p[0].x, lseg->p[1].x)) + { + if (float8_lt(pt->x, lseg->p[0].x)) + return -1; + if (float8_gt(pt->x, lseg->p[1].x)) + return 1; + } + else if (float8_gt(lseg->p[0].x, lseg->p[1].x)) + { + if (float8_gt(pt->x, lseg->p[0].x)) + return -1; + if (float8_lt(pt->x, lseg->p[1].x)) + return 1; + } + else if (float8_le(lseg->p[0].y, lseg->p[1].y)) + { + if (float8_lt(pt->y, lseg->p[0].y)) + return -1; + if (float8_gt(pt->y, lseg->p[1].y)) + return 1; + } + else + { + if (float8_gt(pt->y, lseg->p[0].y)) + return -1; + if (float8_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(float8_le(pt->x, box->high.x) && + float8_ge(pt->x, box->low.x) && + float8_le(pt->y, box->high.y) && + float8_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(float8_le(pt->x, box->high.x) && + float8_ge(pt->x, box->low.x) && + float8_le(pt->y, box->high.y) && + float8_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 @@ -3196,22 +3199,22 @@ 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 (float8_eq(float8_pl(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); } @@ -3247,21 +3250,21 @@ on_sb(PG_FUNCTION_ARGS) * inter_ * Whether one object intersects another. *-------------------------------------------------------------------*/ Datum inter_sl(PG_FUNCTION_ARGS) { LSEG *lseg = PG_GETARG_LSEG_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(has_interpt_sl(lseg, line)); + PG_RETURN_BOOL(lseg_intersect_line_internal(NULL, lseg, line)); } /* inter_sb() * Do line segment and box intersect? * * Segment completely inside box counts as intersection. * If you want only segments crossing box boundaries, * try converting box to path first. * * Optimize for non-intersection by checking for box intersection first. @@ -3269,97 +3272,91 @@ 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 = float8_min(lseg->p[0].x, lseg->p[1].x); + lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y); + lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x); + lbox.high.y = float8_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, PointPGetDatum(&lseg->p[1]), BoxPGetDatum(box)))) PG_RETURN_BOOL(true); /* pairwise check lseg intersections */ point.x = box->low.x; point.y = box->high.y; statlseg_construct(&bseg, &box->low, &point); - if (lseg_intersect_internal(&bseg, lseg)) + if (lseg_intersect_internal(NULL, &bseg, lseg)) PG_RETURN_BOOL(true); statlseg_construct(&bseg, &box->high, &point); - if (lseg_intersect_internal(&bseg, lseg)) + if (lseg_intersect_internal(NULL, &bseg, lseg)) PG_RETURN_BOOL(true); point.x = box->high.x; point.y = box->low.y; statlseg_construct(&bseg, &box->low, &point); - if (lseg_intersect_internal(&bseg, lseg)) + if (lseg_intersect_internal(NULL, &bseg, lseg)) PG_RETURN_BOOL(true); statlseg_construct(&bseg, &box->high, &point); - if (lseg_intersect_internal(&bseg, lseg)) + if (lseg_intersect_internal(NULL, &bseg, lseg)) PG_RETURN_BOOL(true); /* if we dropped through, no two segs intersected */ PG_RETURN_BOOL(false); } /* inter_lb() * Do line and box intersect? */ Datum inter_lb(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); BOX *box = PG_GETARG_BOX_P(1); LSEG bseg; - Point p1, - p2; /* pairwise check lseg intersections */ - p1.x = box->low.x; - p1.y = box->low.y; - p2.x = box->low.x; - p2.y = box->high.y; - statlseg_construct(&bseg, &p1, &p2); - if (has_interpt_sl(&bseg, line)) + bseg.p[0].x = box->low.x; + bseg.p[0].y = box->low.y; + bseg.p[1].x = box->low.x; + bseg.p[1].y = box->high.y; + if (lseg_intersect_line_internal(NULL, &bseg, line)) PG_RETURN_BOOL(true); - p1.x = box->high.x; - p1.y = box->high.y; - statlseg_construct(&bseg, &p1, &p2); - if (has_interpt_sl(&bseg, line)) + bseg.p[0].x = box->high.x; + bseg.p[0].y = box->high.y; + if (lseg_intersect_line_internal(NULL, &bseg, line)) PG_RETURN_BOOL(true); - p2.x = box->high.x; - p2.y = box->low.y; - statlseg_construct(&bseg, &p1, &p2); - if (has_interpt_sl(&bseg, line)) + bseg.p[1].x = box->high.x; + bseg.p[1].y = box->low.y; + if (lseg_intersect_line_internal(NULL, &bseg, line)) PG_RETURN_BOOL(true); - p1.x = box->low.x; - p1.y = box->low.y; - statlseg_construct(&bseg, &p1, &p2); - if (has_interpt_sl(&bseg, line)) + bseg.p[0].x = box->low.x; + bseg.p[0].y = box->low.y; + if (lseg_intersect_line_internal(NULL, &bseg, line)) PG_RETURN_BOOL(true); /* if we dropped through, no intersection */ PG_RETURN_BOOL(false); } /*------------------------------------------------------------------ * The following routines define a data type and operator class for * POLYGONS .... Part of which (the polygon's bounding box) is built on * top of the BOX data type. @@ -3378,27 +3375,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 (float8_lt(poly->p[i].x, x1)) x1 = poly->p[i].x; - if (poly->p[i].x > x2) + if (float8_gt(poly->p[i].x, x2)) x2 = poly->p[i].x; - if (poly->p[i].y < y1) + if (float8_lt(poly->p[i].y, y1)) y1 = poly->p[i].y; - if (poly->p[i].y > y2) + if (float8_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"))); } @@ -3526,21 +3523,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 = float8_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); } @@ -3549,21 +3546,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 = float8_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); } @@ -3572,21 +3569,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 = float8_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); } @@ -3595,21 +3592,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 = float8_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); } @@ -3618,21 +3615,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 = float8_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); } @@ -3641,21 +3638,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 = float8_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); } @@ -3664,21 +3661,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 = float8_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); } @@ -3687,21 +3684,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 = float8_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); } @@ -3739,21 +3736,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; @@ -3768,34 +3765,33 @@ poly_overlap(PG_FUNCTION_ARGS) { /* Second point of polya's edge is a current one */ sa.p[1] = polya->p[ia]; /* Init first of polyb's edge with last point */ sb.p[0] = polyb->p[polyb->npts - 1]; for (ib = 0; ib < polyb->npts && result == false; ib++) { sb.p[1] = polyb->p[ib]; - result = lseg_intersect_internal(&sa, &sb); + result = lseg_intersect_internal(NULL, &sa, &sb); sb.p[0] = sb.p[1]; } /* * 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); @@ -3815,27 +3811,26 @@ 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)) - if (POINTEQ(a, s->p)) + if (point_eq_internal(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)) + else if (point_eq_internal(a, s->p + 1)) { if (on_ps_internal(s->p, &t)) return lseg_inside_poly(b, s->p, poly, start); } else if (on_ps_internal(s->p, &t)) { return lseg_inside_poly(b, s->p, poly, start); } else if (on_ps_internal(s->p + 1, &t)) { @@ -3858,65 +3853,64 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) int i; bool res = true, intersection = false; t.p[0] = *a; t.p[1] = *b; s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)]; for (i = start; i < poly->npts && res; i++) { - Point *interpt; + Point interpt; CHECK_FOR_INTERRUPTS(); s.p[1] = poly->p[i]; if (on_ps_internal(t.p, &s)) { if (on_ps_internal(t.p + 1, &s)) return true; /* t is contained by s */ /* Y-cross */ res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1); } else if (on_ps_internal(t.p + 1, &s)) { /* Y-cross */ res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1); } - else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL) + else if (lseg_intersect_internal(&interpt, &t, &s)) { /* * segments are X-crossing, go to check each subsegment */ intersection = true; - res = lseg_inside_poly(t.p, interpt, poly, i + 1); + res = lseg_inside_poly(t.p, &interpt, poly, i + 1); if (res) - res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1); - pfree(interpt); + res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1); } 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; + p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0); + p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0); res = point_inside(&p, poly->npts, poly->p); } return res; } /*----------------------------------------------------------------- * Determine if polygon A contains polygon B. *-----------------------------------------------------------------*/ @@ -4016,92 +4010,121 @@ 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); + Point *result; - PG_RETURN_POINT_P(point_construct(x, y)); + result = (Point *) palloc(sizeof(Point)); + + result->x = x; + result->y = y; + PG_RETURN_POINT_P(result); } Datum point_add(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; - - result = (Point *) palloc(sizeof(Point)); - - result->x = (p1->x + p2->x); - result->y = (p1->y + p2->y); + Point *result = (Point *) palloc(sizeof(Point)); + point_add_internal(result, p1, p2); PG_RETURN_POINT_P(result); } +static void +point_add_internal(Point *result, Point *pt1, Point *pt2) +{ + result->x = float8_pl(pt1->x, pt2->x); + result->y = float8_pl(pt1->y, pt2->y); +} + Datum point_sub(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; - - result = (Point *) palloc(sizeof(Point)); - - result->x = (p1->x - p2->x); - result->y = (p1->y - p2->y); + Point *result = (Point *) palloc(sizeof(Point)); + point_sub_internal(result, p1, p2); PG_RETURN_POINT_P(result); } +static void +point_sub_internal(Point *result, Point *pt1, Point *pt2) +{ + result->x = float8_mi(pt1->x, pt2->x); + result->y = float8_mi(pt1->y, pt2->y); +} + Datum point_mul(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; - - result = (Point *) palloc(sizeof(Point)); - - result->x = (p1->x * p2->x) - (p1->y * p2->y); - result->y = (p1->x * p2->y) + (p1->y * p2->x); + Point *result = (Point *) palloc(sizeof(Point)); + point_mul_internal(result, p1, p2); PG_RETURN_POINT_P(result); } +static void +point_mul_internal(Point *result, Point *pt1, Point *pt2) +{ + result->x = float8_mi(float8_mul(pt1->x, pt2->x), + float8_mul(pt1->y, pt2->y)); + result->y = float8_pl(float8_mul(pt1->x, pt2->y), + float8_mul(pt1->y, pt2->x)); +} + Datum point_div(PG_FUNCTION_ARGS) { Point *p1 = PG_GETARG_POINT_P(0); Point *p2 = PG_GETARG_POINT_P(1); - Point *result; - double div; - - result = (Point *) palloc(sizeof(Point)); - - div = (p2->x * p2->x) + (p2->y * p2->y); - - if (div == 0.0) - ereport(ERROR, - (errcode(ERRCODE_DIVISION_BY_ZERO), - errmsg("division by zero"))); - - result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div; - result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div; + Point *result = (Point *) palloc(sizeof(Point)); + point_div_internal(result, p1, p2); PG_RETURN_POINT_P(result); } +static void +point_div_internal(Point *result, Point *pt1, Point *pt2) +{ + float8 div; + + div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y)); + result->x = float8_div(float8_pl(float8_mul(pt1->x, pt2->x), + float8_mul(pt1->y, pt2->y)), div); + result->y = float8_div(float8_mi(float8_mul(pt1->y, pt2->x), + float8_mul(pt1->x, pt2->y)), div); +} + +static void +point_mul_float8_internal(Point *result, Point *pt, float8 num) +{ + result->x = float8_mul(pt->x, num); + result->y = float8_mul(pt->y, num); +} + +static float8 +point_cross_product_internal(Point *pt1, Point *pt2) +{ + return float8_mi(float8_mul(pt1->x, pt2->y), float8_mul(pt1->y, pt2->x)); +} + /*********************************************************************** ** ** Routines for 2D boxes. ** ***********************************************************************/ Datum points_box(PG_FUNCTION_ARGS) { @@ -4110,115 +4133,99 @@ points_box(PG_FUNCTION_ARGS) 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); - 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))); + PG_RETURN_BOX_P(box_construct(float8_pl(box->high.x, p->x), + float8_pl(box->low.x, p->x), + float8_pl(box->high.y, p->y), + float8_pl(box->low.y, p->y))); } Datum box_sub(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *p = PG_GETARG_POINT_P(1); - 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))); + PG_RETURN_BOX_P(box_construct(float8_mi(box->high.x, p->x), + float8_mi(box->low.x, p->x), + float8_mi(box->high.y, p->y), + float8_mi(box->low.y, p->y))); } 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; + Point high, + low; - high = DatumGetPointP(DirectFunctionCall2(point_mul, - PointPGetDatum(&box->high), - PointPGetDatum(p))); - low = DatumGetPointP(DirectFunctionCall2(point_mul, - PointPGetDatum(&box->low), - PointPGetDatum(p))); + point_mul_internal(&high, &box->high, p); + point_mul_internal(&low, &box->low, p); - result = box_construct(high->x, low->x, high->y, low->y); + result = box_construct(high.x, low.x, high.y, low.y); PG_RETURN_BOX_P(result); } Datum box_div(PG_FUNCTION_ARGS) { BOX *box = PG_GETARG_BOX_P(0); Point *p = PG_GETARG_POINT_P(1); BOX *result; - Point *high, - *low; + Point high, + low; - high = DatumGetPointP(DirectFunctionCall2(point_div, - PointPGetDatum(&box->high), - PointPGetDatum(p))); - low = DatumGetPointP(DirectFunctionCall2(point_div, - PointPGetDatum(&box->low), - PointPGetDatum(p))); + point_div_internal(&high, &box->high, p); + point_div_internal(&low, &box->low, p); - result = box_construct(high->x, low->x, high->y, low->y); + result = box_construct(high.x, low.x, high.y, low.y); PG_RETURN_BOX_P(result); } /* * Convert point to empty box */ Datum point_box(PG_FUNCTION_ARGS) { Point *pt = PG_GETARG_POINT_P(0); - BOX *box; - box = (BOX *) palloc(sizeof(BOX)); - - box->high.x = pt->x; - box->low.x = pt->x; - box->high.y = pt->y; - box->low.y = pt->y; - - PG_RETURN_BOX_P(box); + PG_RETURN_BOX_P(box_construct(pt->x, pt->x, pt->y, pt->y)); } /* * Smallest bounding box that includes both of the given boxes */ 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 = float8_max(box1->high.x, box2->high.x); + container->low.x = float8_min(box1->low.x, box2->low.x); + container->high.y = float8_max(box1->high.y, box2->high.y); + container->low.y = float8_min(box1->low.y, box2->low.y); PG_RETURN_BOX_P(container); } /*********************************************************************** ** ** Routines for 2D paths. ** ***********************************************************************/ @@ -4275,82 +4282,72 @@ path_add(PG_FUNCTION_ARGS) * 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; for (i = 0; i < path->npts; i++) - { - path->p[i].x += point->x; - path->p[i].y += point->y; - } + point_add_internal(&path->p[i], &path->p[i], point); 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; for (i = 0; i < path->npts; i++) - { - path->p[i].x -= point->x; - path->p[i].y -= point->y; - } + point_sub_internal(&path->p[i], &path->p[i], point); PG_RETURN_PATH_P(path); } /* path_mul_pt() * Rotation and scaling operators. */ Datum path_mul_pt(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); Point *point = PG_GETARG_POINT_P(1); - Point *p; int i; + Point tmp; for (i = 0; i < path->npts; i++) { - p = DatumGetPointP(DirectFunctionCall2(point_mul, - PointPGetDatum(&path->p[i]), - PointPGetDatum(point))); - path->p[i].x = p->x; - path->p[i].y = p->y; + point_mul_internal(&tmp, &path->p[i], point); + path->p[i].x = tmp.x; + path->p[i].y = tmp.y; } PG_RETURN_PATH_P(path); } Datum path_div_pt(PG_FUNCTION_ARGS) { PATH *path = PG_GETARG_PATH_P_COPY(0); Point *point = PG_GETARG_POINT_P(1); - Point *p; int i; + Point tmp; for (i = 0; i < path->npts; i++) { - p = DatumGetPointP(DirectFunctionCall2(point_div, - PointPGetDatum(&path->p[i]), - PointPGetDatum(point))); - path->p[i].x = p->x; - path->p[i].y = p->y; + point_div_internal(&path->p[i], &path->p[i], point); + path->p[i].x = tmp.x; + path->p[i].y = tmp.y; } PG_RETURN_PATH_P(path); } Datum path_center(PG_FUNCTION_ARGS) { #ifdef NOT_USED @@ -4489,21 +4486,21 @@ poly_path(PG_FUNCTION_ARGS) /* * 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; 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); @@ -4547,30 +4544,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 (float8_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\"", @@ -4615,21 +4611,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 (float8_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 */ @@ -4653,310 +4649,290 @@ 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(float8_eq(circle1->radius, circle2->radius) && + float8_eq(circle1->center.x, circle2->center.x) && + float8_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); - PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center), - circle1->radius + circle2->radius)); + PG_RETURN_BOOL(float8_le(point_dt(&circle1->center, &circle2->center), + float8_pl(circle1->radius, circle2->radius))); } /* circle_overleft - is the right edge of circle1 at or left of * the right edge of circle2? */ Datum circle_overleft(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius), - (circle2->center.x + circle2->radius))); + PG_RETURN_BOOL(float8_le(float8_pl(circle1->center.x, circle1->radius), + float8_pl(circle2->center.x, circle2->radius))); } /* circle_left - is circle1 strictly left of circle2? */ Datum circle_left(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius), - (circle2->center.x - circle2->radius))); + PG_RETURN_BOOL(float8_lt(float8_pl(circle1->center.x, circle1->radius), + float8_mi(circle2->center.x, circle2->radius))); } /* circle_right - is circle1 strictly right of circle2? */ Datum circle_right(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius), - (circle2->center.x + circle2->radius))); + PG_RETURN_BOOL(float8_gt(float8_mi(circle1->center.x, circle1->radius), + float8_pl(circle2->center.x, circle2->radius))); } /* circle_overright - is the left edge of circle1 at or right of * the left edge of circle2? */ Datum circle_overright(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius), - (circle2->center.x - circle2->radius))); + PG_RETURN_BOOL(float8_ge(float8_mi(circle1->center.x, circle1->radius), + float8_mi(circle2->center.x, circle2->radius))); } /* circle_contained - is circle1 contained by circle2? */ Datum circle_contained(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius)); + PG_RETURN_BOOL(float8_le(point_dt(&circle1->center, &circle2->center), + float8_mi(circle2->radius, circle1->radius))); } /* circle_contain - does circle1 contain circle2? */ Datum circle_contain(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius)); + PG_RETURN_BOOL(float8_le(point_dt(&circle1->center, &circle2->center), + float8_mi(circle1->radius, circle2->radius))); } /* circle_below - is circle1 strictly below circle2? */ Datum circle_below(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius), - (circle2->center.y - circle2->radius))); + PG_RETURN_BOOL(float8_lt(float8_pl(circle1->center.y, circle1->radius), + float8_mi(circle2->center.y, circle2->radius))); } /* circle_above - is circle1 strictly above circle2? */ Datum circle_above(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius), - (circle2->center.y + circle2->radius))); + PG_RETURN_BOOL(float8_gt(float8_mi(circle1->center.y, circle1->radius), + float8_pl(circle2->center.y, circle2->radius))); } /* circle_overbelow - is the upper edge of circle1 at or below * the upper edge of circle2? */ Datum circle_overbelow(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius), - (circle2->center.y + circle2->radius))); + PG_RETURN_BOOL(float8_le(float8_pl(circle1->center.y, circle1->radius), + float8_pl(circle2->center.y, circle2->radius))); } /* circle_overabove - is the lower edge of circle1 at or above * the lower edge of circle2? */ Datum circle_overabove(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius), - (circle2->center.y - circle2->radius))); + PG_RETURN_BOOL(float8_ge(float8_mi(circle1->center.y, circle1->radius), + float8_mi(circle2->center.y, circle2->radius))); } /* circle_relop - is area(circle1) relop area(circle2), within * our accuracy constraint? */ Datum circle_eq(PG_FUNCTION_ARGS) { CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPeq(circle_ar(circle1), circle_ar(circle2))); + PG_RETURN_BOOL(float8_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(float8_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(float8_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(float8_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(float8_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(float8_ge(circle_ar(circle1), circle_ar(circle2))); } /*---------------------------------------------------------- * "Arithmetic" operators on circles. *---------------------------------------------------------*/ -static CIRCLE * -circle_copy(CIRCLE *circle) -{ - CIRCLE *result; - - if (!PointerIsValid(circle)) - return NULL; - - result = (CIRCLE *) palloc(sizeof(CIRCLE)); - memcpy((char *) result, (char *) circle, sizeof(CIRCLE)); - 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 = (CIRCLE *) palloc(sizeof(CIRCLE)); - result->center.x += point->x; - result->center.y += point->y; + point_add_internal(&result->center, &circle->center, point); + result->radius = circle->radius; PG_RETURN_CIRCLE_P(result); } Datum circle_sub_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 = (CIRCLE *) palloc(sizeof(CIRCLE)); - result->center.x -= point->x; - result->center.y -= point->y; + point_sub_internal(&result->center, &circle->center, point); + result->radius = circle->radius; PG_RETURN_CIRCLE_P(result); } /* 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); + result = (CIRCLE *) palloc(sizeof(CIRCLE)); - 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); + point_mul_internal(&result->center, &circle->center, point); + result->radius = float8_mul(circle->radius, + float8_hypot(point->x, point->y)); PG_RETURN_CIRCLE_P(result); } 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); + result = (CIRCLE *) palloc(sizeof(CIRCLE)); - 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); + point_div_internal(&result->center, &circle->center, point); + result->radius = float8_div(circle->radius, + float8_hypot(point->x, point->y)); PG_RETURN_CIRCLE_P(result); } /* circle_area - returns the area of the circle. */ Datum circle_area(PG_FUNCTION_ARGS) { @@ -4966,21 +4942,21 @@ circle_area(PG_FUNCTION_ARGS) } /* circle_diameter - returns the diameter of the circle. */ Datum circle_diameter(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); - PG_RETURN_FLOAT8(2 * circle->radius); + PG_RETURN_FLOAT8(float8_mul(circle->radius, 2.0)); } /* circle_radius - returns the radius of the circle. */ Datum circle_radius(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); @@ -4991,106 +4967,104 @@ 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; - result = point_dt(&circle1->center, &circle2->center) - - (circle1->radius + circle2->radius); - if (result < 0) - result = 0; + result = float8_mi(point_dt(&circle1->center, &circle2->center), + float8_pl(circle1->radius, circle2->radius)); + if (float8_lt(result, 0.0)) + result = 0.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(float8_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(float8_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; - result = point_dt(point, &circle->center) - circle->radius; - if (result < 0) - result = 0; + result = float8_mi(point_dt(point, &circle->center), circle->radius); + if (float8_lt(result, 0.0)) + result = 0.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 result; + + result = float8_mi(point_dt(point, &circle->center), circle->radius); + if (float8_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); + return float8_mul(float8_mul(circle->radius, circle->radius), M_PI); } /*---------------------------------------------------------- * Conversion operators. *---------------------------------------------------------*/ Datum cr_circle(PG_FUNCTION_ARGS) { @@ -5108,64 +5082,63 @@ cr_circle(PG_FUNCTION_ARGS) } Datum circle_box(PG_FUNCTION_ARGS) { CIRCLE *circle = PG_GETARG_CIRCLE_P(0); BOX *box; double delta; box = (BOX *) palloc(sizeof(BOX)); + delta = float8_div(circle->radius, sqrt(2.0)); - 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; + box->high.x = float8_pl(circle->center.x, delta); + box->low.x = float8_mi(circle->center.x, delta); + box->high.y = float8_pl(circle->center.y, delta); + box->low.y = float8_mi(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; 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; + circle->center.x = float8_div(float8_pl(box->high.x, box->low.x), 2.0); + circle->center.y = float8_div(float8_pl(box->high.y, box->low.y), 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; - if (FPzero(circle->radius)) + if (float8_eq(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; @@ -5174,27 +5147,30 @@ circle_poly(PG_FUNCTION_ARGS) /* 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; + anglestep = float8_div(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)); + angle = float8_mul(anglestep, i); + + poly->p[i].x = float8_mi(circle->center.x, + float8_mul(circle->radius, cos(angle))); + poly->p[i].y = float8_pl(circle->center.y, + float8_mul(circle->radius, sin(angle))); } 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 @@ -5213,29 +5189,30 @@ poly_circle(PG_FUNCTION_ARGS) errmsg("cannot convert empty polygon to circle"))); circle = (CIRCLE *) palloc(sizeof(CIRCLE)); circle->center.x = 0; circle->center.y = 0; circle->radius = 0; for (i = 0; i < poly->npts; i++) { - circle->center.x += poly->p[i].x; - circle->center.y += poly->p[i].y; + circle->center.x = float8_pl(circle->center.x, poly->p[i].x); + circle->center.y = float8_pl(circle->center.y, poly->p[i].y); } - circle->center.x /= poly->npts; - circle->center.y /= poly->npts; + circle->center.x = float8_div(circle->center.x, poly->npts); + circle->center.y = float8_div(circle->center.y, poly->npts); for (i = 0; i < poly->npts; i++) - circle->radius += point_dt(&poly->p[i], &circle->center); - circle->radius /= poly->npts; + circle->radius = float8_pl(circle->radius, + point_dt(&poly->p[i], &circle->center)); + circle->radius = float8_div(circle->radius, poly->npts); PG_RETURN_CIRCLE_P(circle); } /*********************************************************************** ** ** Private routines for multiple types. ** ***********************************************************************/ @@ -5263,31 +5240,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; + x0 = float8_mi(plist[0].x, p->x); + y0 = float8_mi(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; + x = float8_mi(plist[i].x, p->x); + y = float8_mi(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; } @@ -5310,126 +5287,127 @@ point_inside(Point *p, int npts, Point *plist) * Wow, that is one confusing API, but it is used above, and when summed, * can tell is if a point is in a polygon. */ static int lseg_crossing(double x, double y, double prev_x, double prev_y) { double z; int y_sign; - if (FPzero(y)) + if (float8_eq(y, 0.0)) { /* y == 0, on X axis */ - if (FPzero(x)) /* (x,y) is (0,0)? */ + if (float8_eq(x, 0.0)) /* (x,y) is (0,0)? */ return POINT_ON_POLYGON; - else if (FPgt(x, 0)) + else if (float8_gt(x, 0.0)) { /* x > 0 */ - if (FPzero(prev_y)) /* y and prev_y are zero */ + if (float8_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 float8_gt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON; + return float8_lt(prev_y, 0.0) ? 1 : -1; } else { /* x < 0, x not on positive X axis */ - if (FPzero(prev_y)) + if (float8_eq(prev_y, 0.0)) /* prev_x < 0? */ - return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON; + return float8_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 = float8_gt(y, 0.0) ? 1 : -1; - if (FPzero(prev_y)) + if (float8_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 && float8_lt(prev_y, 0.0)) || + (y_sign > 0 && float8_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 (float8_ge(x, 0.0) && float8_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 (float8_lt(x, 0.0) && float8_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)) + z = float8_mi(float8_mul(float8_mi(x, prev_x), y), + float8_mul(float8_mi(y, prev_y), x)); + if (float8_eq(z, 0.0)) return POINT_ON_POLYGON; - return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign; + return float8_gt((y_sign * z), 0) ? 0 : 2 * y_sign; } } } static bool plist_same(int npts, Point *p1, Point *p2) { int i, ii, j; /* find match for first point */ for (i = 0; i < npts; i++) { - if ((FPeq(p2[i].x, p1[0].x)) - && (FPeq(p2[i].y, p1[0].y))) + if (float8_eq(p2[i].x, p1[0].x) && float8_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 (float8_ne(p2[j].x, p1[ii].x) || + float8_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 (float8_ne(p2[j].x, p1[ii].x) || + float8_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 54f4f0e..b18e1d9 100644 --- a/src/backend/utils/adt/geo_spgist.c +++ b/src/backend/utils/adt/geo_spgist.c @@ -75,21 +75,21 @@ #include "access/spgist.h" #include "access/stratnum.h" #include "catalog/pg_type.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; @@ -120,30 +120,30 @@ typedef struct * The quadrant is 8 bit unsigned integer with 4 least bits in use. * This function accepts BOXes as input. They are not casted to * RangeBoxes, yet. All 4 bits are set by comparing a corner of the box. * This makes 16 quadrants in total. */ static uint8 getQuadrant(BOX *centroid, BOX *inBox) { uint8 quadrant = 0; - if (inBox->low.x > centroid->low.x) + if (float8_gt(inBox->low.x, centroid->low.x)) quadrant |= 0x8; - if (inBox->high.x > centroid->high.x) + if (float8_gt(inBox->high.x, centroid->high.x)) quadrant |= 0x4; - if (inBox->low.y > centroid->low.y) + if (float8_gt(inBox->low.y, centroid->low.y)) quadrant |= 0x2; - if (inBox->high.y > centroid->high.y) + if (float8_gt(inBox->high.y, centroid->high.y)) quadrant |= 0x1; return quadrant; } /* * Get RangeBox using BOX * * We are turning the BOX to our structures to emphasize their function * of representing points in 4D space. It also is more convenient to @@ -224,80 +224,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 float8_ge(range_box->right.high, query->low) && + float8_lt(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); + 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 float8_ge(range_box->right.high, query->high) && + float8_le(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); + 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 float8_le(range_box->left.low, query->high) && + float8_ge(range_box->left.high, query->low) && + float8_le(range_box->right.low, query->high) && + float8_ge(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); + 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 float8_lt(range_box->left.low, query->low) && + float8_lt(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 float8_gt(range_box->left.high, query->high) && + float8_gt(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 3a9287f..9977854 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -1,65 +1,33 @@ /*------------------------------------------------------------------------- * * 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" #include "utils/float.h" -/*-------------------------------------------------------------------- - * Useful floating point utilities and constants. - *-------------------------------------------------------------------*/ - - -#define EPSILON 1.0E-06 - -#ifdef EPSILON -#define FPzero(A) (fabs(A) <= EPSILON) -#define FPeq(A,B) (fabs((A) - (B)) <= EPSILON) -#define FPne(A,B) (fabs((A) - (B)) > EPSILON) -#define FPlt(A,B) ((B) - (A) > EPSILON) -#define FPle(A,B) ((A) - (B) <= EPSILON) -#define FPgt(A,B) ((A) - (B) > EPSILON) -#define FPge(A,B) ((B) - (A) <= EPSILON) -#else -#define FPzero(A) ((A) == 0) -#define FPeq(A,B) ((A) == (B)) -#define FPne(A,B) ((A) != (B)) -#define FPlt(A,B) ((A) < (B)) -#define FPle(A,B) ((A) <= (B)) -#define FPgt(A,B) ((A) > (B)) -#define FPge(A,B) ((A) >= (B)) -#endif - -#define HYPOT(A, B) pg_hypot(A, B) - /*--------------------------------------------------------------------- * Point - (x,y) *-------------------------------------------------------------------*/ typedef struct { double x, y; } Point; @@ -435,11 +403,28 @@ Datum spg_box_quad_inner_consistent(PG_FUNCTION_ARGS); Datum spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS); /* geo_selfuncs.c */ extern Datum areasel(PG_FUNCTION_ARGS); extern Datum areajoinsel(PG_FUNCTION_ARGS); extern Datum positionsel(PG_FUNCTION_ARGS); extern Datum positionjoinsel(PG_FUNCTION_ARGS); extern Datum contsel(PG_FUNCTION_ARGS); extern Datum contjoinsel(PG_FUNCTION_ARGS); + +/* + * Hypotenuse route with underflow and overflow checking + */ +static inline float8 +float8_hypot(float8 val1, float8 val2) +{ + float8 result; + + result = pg_hypot(val1, val2); + check_float8_val(result, isinf(val1) || isinf(val2), + val1 == 0.0 && val2 == 0.0); + Assert(isinf(result) || result >= 0.0); + + return result; +} + #endif /* GEO_DECLS_H */ 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..5d9fc44 100644 --- a/src/test/regress/expected/select_views.out +++ b/src/test/regress/expected/select_views.out @@ -217,21 +217,20 @@ SELECT * FROM street; Logan Ct | [(-122.0053,37.492),(-122.0061,37.484)] | Oakland Magnolia St | [(-122.0971,37.5),(-122.0962,37.484)] | Oakland Mandalay Road | [(-122.2322,37.397),(-122.2321,37.403)] | Lafayette Marin Ave | [(-122.2741,37.894),(-122.272,37.901)] | Berkeley Martin Luther King Jr Way | [(-122.2712,37.608),(-122.2711,37.599)] | Berkeley Mattos Dr | [(-122.0005,37.502),(-122.000898,37.49683)] | Oakland Maubert Ave | [(-122.1114,37.009),(-122.1096,37.995)] | Oakland Maubert Ave | [(-122.1114,37.009),(-122.1096,37.995)] | Berkeley McClure Ave | [(-122.1431,37.001),(-122.1436,37.998)] | Oakland McClure Ave | [(-122.1431,37.001),(-122.1436,37.998)] | Berkeley - Medlar Dr | [(-122.0627,37.378),(-122.0625,37.375)] | Oakland Mildred Ct | [(-122.0002,37.388),(-121.9998,37.386)] | Oakland Miller Road | [(-122.0902,37.645),(-122.0865,37.545)] | Berkeley Miramar Ave | [(-122.1009,37.025),(-122.099089,37.03209)] | Oakland Mission Blvd | [(-121.918886,37),(-121.9194,37.976),(-121.9198,37.975)] | Oakland Mission Blvd | [(-121.918886,37),(-121.9194,37.976),(-121.9198,37.975)] | Oakland Mission Blvd | [(-122.0006,37.896),(-121.9989,37.88)] | Oakland 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 @@ -331,38 +330,35 @@ 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) +(332 rows) -SELECT name, #thepath FROM iexit ORDER BY 1, 2; +SELECT name, #thepath FROM iexit ORDER BY name COLLATE "C", 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 @@ -527,25 +523,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 | 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 @@ -685,21 +676,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; 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 | 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 @@ -802,22 +792,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 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 | 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 @@ -838,21 +826,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 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 @@ -898,22 +885,20 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; 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 @@ -1051,22 +1036,22 @@ 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 | 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 @@ -1148,24 +1133,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 | 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 @@ -1232,21 +1213,21 @@ SELECT name, #thepath FROM iexit ORDER BY 1, 2; 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) +(878 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/sql/select_views.sql b/src/test/regress/sql/select_views.sql index 3b74ab9..e742f13 100644 --- a/src/test/regress/sql/select_views.sql +++ b/src/test/regress/sql/select_views.sql @@ -1,18 +1,18 @@ -- -- SELECT_VIEWS -- test the views defined in CREATE_VIEWS -- SELECT * FROM street; -SELECT name, #thepath FROM iexit ORDER BY 1, 2; +SELECT name, #thepath FROM iexit ORDER BY name COLLATE "C", 2; SELECT * FROM toyemp WHERE name = 'sharon'; -- -- Test for Leaky view scenario -- CREATE ROLE regress_alice; CREATE FUNCTION f_leak (text) RETURNS bool LANGUAGE 'plpgsql' COST 0.0000001 -- 2.7.4 (Apple Git-66)