diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index a2e798ff95..b9ff60f56b 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -79,7 +79,7 @@ static inline void point_add_point(Point *result, Point *pt1, Point *pt2); static inline void point_sub_point(Point *result, Point *pt1, Point *pt2); static inline void point_mul_point(Point *result, Point *pt1, Point *pt2); static inline void point_div_point(Point *result, Point *pt1, Point *pt2); -static inline bool point_eq_point(Point *pt1, Point *pt2); +static inline tsbool point_eq_point(Point *pt1, Point *pt2); static inline float8 point_dt(Point *pt1, Point *pt2); static inline float8 point_sl(Point *pt1, Point *pt2); static int point_inside(Point *p, int npts, Point *plist); @@ -88,18 +88,18 @@ static int point_inside(Point *p, int npts, Point *plist); static inline void line_construct(LINE *result, Point *pt, float8 m); static inline float8 line_sl(LINE *line); static inline float8 line_invsl(LINE *line); -static bool line_interpt_line(Point *result, LINE *l1, LINE *l2); -static bool line_contain_point(LINE *line, Point *point); +static tsbool line_interpt_line(Point *result, LINE *l1, LINE *l2); +static tsbool line_contain_point(LINE *line, Point *point); static float8 line_closept_point(Point *result, LINE *line, Point *pt); /* Routines for line segments */ static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2); static inline float8 lseg_sl(LSEG *lseg); static inline float8 lseg_invsl(LSEG *lseg); -static bool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line); -static bool lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2); +static tsbool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line); +static tsbool lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2); static int lseg_crossing(float8 x, float8 y, float8 px, float8 py); -static bool lseg_contain_point(LSEG *lseg, Point *point); +static tsbool lseg_contain_point(LSEG *lseg, Point *point); static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt); static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line); static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg); @@ -107,14 +107,14 @@ static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg); /* Routines for boxes */ static inline void box_construct(BOX *result, Point *pt1, Point *pt2); static void box_cn(Point *center, BOX *box); -static bool box_ov(BOX *box1, BOX *box2); +static tsbool box_ov(BOX *box1, BOX *box2); static float8 box_ar(BOX *box); static float8 box_ht(BOX *box); static float8 box_wd(BOX *box); -static bool box_contain_point(BOX *box, Point *point); -static bool box_contain_box(BOX *contains_box, BOX *contained_box); -static bool box_contain_lseg(BOX *box, LSEG *lseg); -static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg); +static tsbool box_contain_point(BOX *box, Point *point); +static tsbool box_contain_box(BOX *contains_box, BOX *contained_box); +static tsbool box_contain_lseg(BOX *box, LSEG *lseg); +static tsbool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg); static float8 box_closept_point(Point *result, BOX *box, Point *point); static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg); @@ -124,9 +124,9 @@ static float8 circle_ar(CIRCLE *circle); /* Routines for polygons */ static void make_bound_box(POLYGON *poly); static void poly_to_circle(CIRCLE *result, POLYGON *poly); -static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start); -static bool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly); -static bool plist_same(int npts, Point *p1, Point *p2); +static tsbool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start); +static tsbool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly); +static tsbool plist_same(int npts, Point *p1, Point *p2); static float8 dist_ppoly_internal(Point *pt, POLYGON *poly); /* Routines for encoding and decoding */ @@ -540,9 +540,13 @@ box_same(PG_FUNCTION_ARGS) { BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); + tsbool res1 = point_eq_point(&box1->high, &box2->high); + tsbool res2 = point_eq_point(&box1->low, &box2->low); - PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) && - point_eq_point(&box1->low, &box2->low)); + if (res1 == TS_NULL || res2 == TS_NULL) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(res1 && res2); } /* box_overlap - does box1 overlap box2? @@ -553,16 +557,16 @@ 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)); + PG_RETURN_TSBOOL(box_ov(box1, box2)); } -static bool +static tsbool 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 (TS_AND4(FPTle(box1->low.x, box2->high.x), + FPTle(box2->low.x, box1->high.x), + FPTle(box1->low.y, box2->high.y), + FPTle(box2->low.y, box1->high.y))); } /* box_left - is box1 strictly left of box2? @@ -573,7 +577,7 @@ 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_TSBOOL(FPTlt(box1->high.x, box2->low.x)); } /* box_overleft - is the right edge of box1 at or left of @@ -588,7 +592,7 @@ 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_TSBOOL(FPTle(box1->high.x, box2->high.x)); } /* box_right - is box1 strictly right of box2? @@ -599,7 +603,7 @@ 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_TSBOOL(FPTgt(box1->low.x, box2->high.x)); } /* box_overright - is the left edge of box1 at or right of @@ -614,7 +618,7 @@ 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_TSBOOL(FPTge(box1->low.x, box2->low.x)); } /* box_below - is box1 strictly below box2? @@ -625,7 +629,7 @@ 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_TSBOOL(FPTlt(box1->high.y, box2->low.y)); } /* box_overbelow - is the upper edge of box1 at or below @@ -637,7 +641,7 @@ 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_TSBOOL(FPTle(box1->high.y, box2->high.y)); } /* box_above - is box1 strictly above box2? @@ -648,7 +652,7 @@ 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_TSBOOL(FPTgt(box1->low.y, box2->high.y)); } /* box_overabove - is the lower edge of box1 at or above @@ -660,7 +664,7 @@ 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_TSBOOL(FPTge(box1->low.y, box2->low.y)); } /* box_contained - is box1 contained by box2? @@ -671,7 +675,7 @@ box_contained(PG_FUNCTION_ARGS) BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(box_contain_box(box2, box1)); + PG_RETURN_TSBOOL(box_contain_box(box2, box1)); } /* box_contain - does box1 contain box2? @@ -682,19 +686,19 @@ box_contain(PG_FUNCTION_ARGS) BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(box_contain_box(box1, box2)); + PG_RETURN_TSBOOL(box_contain_box(box1, box2)); } /* * Check whether the second box is in the first box or on its border */ -static bool +static tsbool box_contain_box(BOX *contains_box, BOX *contained_box) { - return FPge(contains_box->high.x, contained_box->high.x) && - FPle(contains_box->low.x, contained_box->low.x) && - FPge(contains_box->high.y, contained_box->high.y) && - FPle(contains_box->low.y, contained_box->low.y); + return TS_AND4(FPTge(contains_box->high.x, contained_box->high.x), + FPTle(contains_box->low.x, contained_box->low.x), + FPTge(contains_box->high.y, contained_box->high.y), + FPTle(contains_box->low.y, contained_box->low.y)); } @@ -712,7 +716,7 @@ 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_TSBOOL(FPTle(box1->high.y, box2->low.y)); } Datum @@ -721,7 +725,7 @@ 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_TSBOOL(FPTge(box1->low.y, box2->high.y)); } @@ -734,7 +738,7 @@ 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_TSBOOL(FPTlt(box_ar(box1), box_ar(box2))); } Datum @@ -743,7 +747,7 @@ 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_TSBOOL(FPTgt(box_ar(box1), box_ar(box2))); } Datum @@ -752,7 +756,7 @@ 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_TSBOOL(FPTeq(box_ar(box1), box_ar(box2))); } Datum @@ -761,7 +765,7 @@ 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_TSBOOL(FPTle(box_ar(box1), box_ar(box2))); } Datum @@ -770,7 +774,7 @@ 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_TSBOOL(FPTge(box_ar(box1), box_ar(box2))); } @@ -981,7 +985,7 @@ line_in(PG_FUNCTION_ARGS) else { path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str); - if (point_eq_point(&lseg.p[0], &lseg.p[1])) + if (point_eq_point(&lseg.p[0], &lseg.p[1]) == TS_TRUE) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid line specification: must be two distinct points"))); @@ -1105,7 +1109,7 @@ line_construct_pp(PG_FUNCTION_ARGS) LINE *result = (LINE *) palloc(sizeof(LINE)); /* NaNs are considered to be equal by point_eq_point */ - if (point_eq_point(pt1, pt2)) + if (point_eq_point(pt1, pt2) == TS_TRUE) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid line specification: must be two distinct points"))); @@ -1126,11 +1130,16 @@ line_intersect(PG_FUNCTION_ARGS) LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); Point xp; + tsbool r; - if (line_interpt_line(&xp, l1, l2) && !isnan(xp.x) && !isnan(xp.y)) - PG_RETURN_BOOL(true); + if ((r = line_interpt_line(&xp, l1, l2)) == TS_TRUE) + { + if (!isnan(xp.x) && !isnan(xp.y)) + PG_RETURN_BOOL(true); + PG_RETURN_NULL(); + } else - PG_RETURN_BOOL(false); + PG_RETURN_TSBOOL(r); } Datum @@ -1139,7 +1148,7 @@ line_parallel(PG_FUNCTION_ARGS) LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(!line_interpt_line(NULL, l1, l2)); + PG_RETURN_TSBOOL(TS_NOT(line_interpt_line(NULL, l1, l2))); } Datum @@ -1148,17 +1157,18 @@ line_perp(PG_FUNCTION_ARGS) LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); - if (unlikely(isnan(l1->C) || isnan(l2->C))) - return false; + if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l1->C) || + isnan(l2->A) || isnan(l2->B) || isnan(l2->C))) + PG_RETURN_NULL(); if (FPzero(l1->A)) - PG_RETURN_BOOL(FPzero(l2->B) && !isnan(l1->B) && !isnan(l2->A)); + PG_RETURN_BOOL(FPzero(l2->B)); if (FPzero(l2->A)) - PG_RETURN_BOOL(FPzero(l1->B) && !isnan(l2->B) && !isnan(l1->A)); + PG_RETURN_BOOL(FPzero(l1->B)); if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->A) && !isnan(l1->A) && !isnan(l2->B)); + PG_RETURN_BOOL(FPzero(l2->A)); if (FPzero(l2->B)) - PG_RETURN_BOOL(FPzero(l1->A) && !isnan(l2->A) && !isnan(l1->B)); + PG_RETURN_BOOL(FPzero(l1->A)); PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A), float8_mul(l1->B, l2->B)), -1.0)); @@ -1177,7 +1187,10 @@ line_horizontal(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->A) && !isnan(line->B) && !isnan(line->C)); + if (!isnan(line->B) && !isnan(line->C)) + PG_RETURN_TSBOOL(FPzero(line->A)); + + PG_RETURN_NULL(); } @@ -1191,14 +1204,10 @@ line_eq(PG_FUNCTION_ARGS) LINE *l2 = PG_GETARG_LINE_P(1); float8 ratio; - /* If any NaNs are involved, insist on exact equality */ + /* If any NaNs are involved, the two cannot be equal */ if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l1->C) || isnan(l2->A) || isnan(l2->B) || isnan(l2->C))) - { - PG_RETURN_BOOL(float8_eq(l1->A, l2->A) && - float8_eq(l1->B, l2->B) && - float8_eq(l1->C, l2->C)); - } + PG_RETURN_NULL(); /* Otherwise, lines whose parameters are proportional are the same */ if (!FPzero(l2->A)) @@ -1281,7 +1290,7 @@ line_distance(PG_FUNCTION_ARGS) Point xp; float8 ratio; - if (line_interpt_line(&xp, l1, l2)) /* intersecting? */ + if (line_interpt_line(&xp, l1, l2) == TS_TRUE) /* intersecting? */ { /* return NaN if NaN is involved */ if (isnan(xp.x) || isnan(xp.y)) @@ -1316,7 +1325,7 @@ line_interpt(PG_FUNCTION_ARGS) result = (Point *) palloc(sizeof(Point)); - if (!line_interpt_line(result, l1, l2) || + if (line_interpt_line(result, l1, l2) != TS_TRUE || isnan(result->x) || isnan(result->y)) { pfree(result); @@ -1340,17 +1349,24 @@ line_interpt(PG_FUNCTION_ARGS) * point would have NaN coordinates. We shouldn't return false in this case * because that would mean the lines are parallel. */ -static bool +static tsbool line_interpt_line(Point *result, LINE *l1, LINE *l2) { float8 x, y; + tsbool r; - if (!FPzero(l1->B)) + if ((r = FPTzero(l1->B)) == TS_FALSE) { /* l1 is not virtucal */ - if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B)))) - return false; + if ((r = FPTeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B)))) + != TS_FALSE) + { + if (r == TS_TRUE) + return TS_FALSE; + else + return TS_NULL; + } x = float8_div(float8_mi(float8_mul(l1->B, l2->C), float8_mul(l2->B, l1->C)), @@ -1367,7 +1383,7 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2) float8_mi(float8_mul(l2->A, l1->B), float8_mul(l1->A, l2->B))); } - else if (!FPzero(l2->B)) + else if ((r = FPzero(l2->B)) == TS_FALSE) { /* l2 is not virtical */ /* @@ -1380,13 +1396,17 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2) * When l2->A is zero, y is determined independently from x even if it * is Inf. */ - if (FPzero(l2->A)) + if ((r = FPzero(l2->A)) == TS_TRUE) y = -float8_div(l2->C, l2->B); - else + else if (r == TS_FALSE) y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B); + else + return TS_NULL; } + else if (r != TS_NULL) + return TS_FALSE; else - return false; + return TS_NULL; /* On some platforms, the preceding expressions tend to produce -0. */ if (x == 0.0) @@ -1397,7 +1417,7 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2) if (result != NULL) point_construct(result, x, y); - return true; + return TS_TRUE; } @@ -1704,6 +1724,7 @@ path_inter(PG_FUNCTION_ARGS) j; LSEG seg1, seg2; + tsbool r; Assert(p1->npts > 0 && p2->npts > 0); @@ -1716,6 +1737,7 @@ path_inter(PG_FUNCTION_ARGS) b1.low.x = float8_min_nan(p1->p[i].x, b1.low.x); b1.low.y = float8_min_nan(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++) @@ -1725,8 +1747,8 @@ path_inter(PG_FUNCTION_ARGS) b2.low.x = float8_min_nan(p2->p[i].x, b2.low.x); b2.low.y = float8_min_nan(p2->p[i].y, b2.low.y); } - if (!box_ov(&b1, &b2)) - PG_RETURN_BOOL(false); + if ((r = box_ov(&b1, &b2)) != TS_TRUE) + PG_RETURN_TSBOOL(r); /* pairwise check lseg intersections */ for (i = 0; i < p1->npts; i++) @@ -2004,8 +2026,12 @@ point_eq(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); + tsbool res = point_eq_point(pt1, pt2); - PG_RETURN_BOOL(point_eq_point(pt1, pt2)); + if (res == TS_NULL) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(res); } Datum @@ -2013,23 +2039,22 @@ point_ne(PG_FUNCTION_ARGS) { Point *pt1 = PG_GETARG_POINT_P(0); Point *pt2 = PG_GETARG_POINT_P(1); + tsbool res = point_eq_point(pt1, pt2); - PG_RETURN_BOOL(!point_eq_point(pt1, pt2)); + if (res == TS_NULL) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(!res); } /* * Check whether the two points are the same */ -static inline bool +static inline tsbool point_eq_point(Point *pt1, Point *pt2) { - /* If any NaNs are involved, insist on exact equality */ - if (unlikely(isnan(pt1->x) || isnan(pt1->y) || - isnan(pt2->x) || isnan(pt2->y))) - return (float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)); - - return (FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)); + return TS_AND2(FPTeq(pt1->x, pt2->x), FPTeq(pt1->y, pt2->y)); } @@ -2070,6 +2095,7 @@ point_slope(PG_FUNCTION_ARGS) static inline float8 point_sl(Point *pt1, Point *pt2) { + /* NaN doesn't equal to NaN, so don't bother using a tri-state value */ if (FPeq(pt1->x, pt2->x)) { if (unlikely(isnan(pt1->y) || isnan(pt2->y))) @@ -2096,6 +2122,7 @@ point_sl(Point *pt1, Point *pt2) static inline float8 point_invsl(Point *pt1, Point *pt2) { + /* NaN doesn't equal to NaN, so don't bother using a tri-state value */ if (FPeq(pt1->x, pt2->x)) { if (unlikely(isnan(pt1->y) || isnan(pt2->y))) @@ -2254,7 +2281,7 @@ lseg_intersect(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(lseg_interpt_lseg(NULL, l1, l2)); + PG_RETURN_TSBOOL(lseg_interpt_lseg(NULL, l1, l2)); } @@ -2264,7 +2291,7 @@ lseg_parallel(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_sl(l2))); + PG_RETURN_TSBOOL(FPTeq(lseg_sl(l1), lseg_sl(l2))); } /* @@ -2276,7 +2303,7 @@ lseg_perp(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(FPeq(lseg_sl(l1), lseg_invsl(l2))); + PG_RETURN_TSBOOL(FPTeq(lseg_sl(l1), lseg_invsl(l2))); } Datum @@ -2284,7 +2311,7 @@ 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_TSBOOL(FPeq(lseg->p[0].x, lseg->p[1].x)); } Datum @@ -2292,7 +2319,7 @@ 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_TSBOOL(FPTeq(lseg->p[0].y, lseg->p[1].y)); } @@ -2302,8 +2329,8 @@ lseg_eq(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) && - point_eq_point(&l1->p[1], &l2->p[1])); + PG_RETURN_TSBOOL(TS_AND2(point_eq_point(&l1->p[0], &l2->p[0]), + point_eq_point(&l1->p[1], &l2->p[1]))); } Datum @@ -2312,8 +2339,9 @@ lseg_ne(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) || - !point_eq_point(&l1->p[1], &l2->p[1])); + PG_RETURN_TSBOOL(TS_OR2( + TS_NOT(point_eq_point(&l1->p[0], &l2->p[0])), + TS_NOT(point_eq_point(&l1->p[1], &l2->p[1])))); } Datum @@ -2322,8 +2350,8 @@ 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_TSBOOL(FPTlt(point_dt(&l1->p[0], &l1->p[1]), + point_dt(&l2->p[0], &l2->p[1]))); } Datum @@ -2332,8 +2360,8 @@ 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_TSBOOL(FPTle(point_dt(&l1->p[0], &l1->p[1]), + point_dt(&l2->p[0], &l2->p[1]))); } Datum @@ -2342,8 +2370,8 @@ 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_TSBOOL(FPTgt(point_dt(&l1->p[0], &l1->p[1]), + point_dt(&l2->p[0], &l2->p[1]))); } Datum @@ -2352,8 +2380,8 @@ 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_TSBOOL(FPTge(point_dt(&l1->p[0], &l1->p[1]), + point_dt(&l2->p[0], &l2->p[1]))); } @@ -2398,27 +2426,28 @@ lseg_center(PG_FUNCTION_ARGS) * This function is almost perfectly symmetric, even though it doesn't look * like it. See lseg_interpt_line() for the other half of it. */ -static bool +static tsbool lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2) { Point interpt; LINE tmp; + tsbool r; line_construct(&tmp, &l2->p[0], lseg_sl(l2)); - if (!lseg_interpt_line(&interpt, l1, &tmp)) - return false; + if ((r = lseg_interpt_line(&interpt, l1, &tmp)) != TS_TRUE) + return r; /* * If the line intersection point isn't within l2, there is no valid * segment intersection point at all. */ - if (!lseg_contain_point(l2, &interpt)) - return false; + if ((r = lseg_contain_point(l2, &interpt)) != TS_TRUE) + return r; if (result != NULL) *result = interpt; - return true; + return TS_TRUE; } Datum @@ -2427,10 +2456,11 @@ lseg_interpt(PG_FUNCTION_ARGS) LSEG *l1 = PG_GETARG_LSEG_P(0); LSEG *l2 = PG_GETARG_LSEG_P(1); Point *result; + tsbool r; result = (Point *) palloc(sizeof(Point)); - if (!lseg_interpt_lseg(result, l1, l2)) + if ((r = lseg_interpt_lseg(result, l1, l2)) != TS_TRUE) PG_RETURN_NULL(); PG_RETURN_POINT_P(result); } @@ -2740,8 +2770,13 @@ dist_ppoly_internal(Point *pt, POLYGON *poly) float8 d; int i; LSEG seg; + int inside; - if (point_inside(pt, poly->npts, poly->p) != 0) + inside = point_inside(pt, poly->npts, poly->p); + if (inside == -1) + return get_float8_nan(); + + if (inside != 0) return 0.0; /* initialize distance with segment between first and last points */ @@ -2780,11 +2815,12 @@ dist_ppoly_internal(Point *pt, POLYGON *poly) * Return whether the line segment intersect with the line. If *result is not * NULL, it is set to the intersection point. */ -static bool +static tsbool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line) { Point interpt; LINE tmp; + tsbool r; /* * First, we promote the line segment to a line, because we know how to @@ -2792,32 +2828,40 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line) * intersection point, we are done. */ line_construct(&tmp, &lseg->p[0], lseg_sl(lseg)); - if (!line_interpt_line(&interpt, &tmp, line) || - unlikely(isnan(interpt.x) || isnan(interpt.y))) - return false; + if ((r = line_interpt_line(&interpt, &tmp, line)) != TS_TRUE) + return r; + + if (unlikely(isnan(interpt.x) || isnan(interpt.y))) + return TS_FALSE; /* * Then, we check whether the intersection point is actually on the line * segment. */ - if (!lseg_contain_point(lseg, &interpt)) - return false; + if ((r = lseg_contain_point(lseg, &interpt)) != TS_TRUE) + return r; + if (result != NULL) { + tsbool r; + /* * If there is an intersection, then check explicitly for matching * endpoints since there may be rounding effects with annoying LSB * residue. */ - if (point_eq_point(&lseg->p[0], &interpt)) + if ((r = point_eq_point(&lseg->p[0], &interpt)) == TS_TRUE) *result = lseg->p[0]; - else if (point_eq_point(&lseg->p[1], &interpt)) + else if (r == TS_FALSE && + (r = point_eq_point(&lseg->p[1], &interpt)) == TS_TRUE) *result = lseg->p[1]; - else + else if (r == TS_FALSE) *result = interpt; + else + return r; } - return true; + return TS_TRUE; } /*--------------------------------------------------------------------- @@ -3178,11 +3222,14 @@ close_sl(PG_FUNCTION_ARGS) Point *result; float8 d1, d2; + tsbool r; result = (Point *) palloc(sizeof(Point)); - if (lseg_interpt_line(result, lseg, line)) + if ((r = lseg_interpt_line(result, lseg, line)) == TS_TRUE) PG_RETURN_POINT_P(result); + else if (r == TS_NULL) + PG_RETURN_NULL; d1 = line_closept_point(NULL, line, &lseg->p[0]); d2 = line_closept_point(NULL, line, &lseg->p[1]); @@ -3219,9 +3266,12 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line) { float8 dist1, dist2; + tsbool r; - if (lseg_interpt_line(result, lseg, line)) + if ((r = lseg_interpt_line(result, lseg, line)) == TS_TRUE) return 0.0; + else if (r == TS_NULL) + return get_float8_nan(); dist1 = line_closept_point(NULL, line, &lseg->p[0]); dist2 = line_closept_point(NULL, line, &lseg->p[1]); @@ -3365,7 +3415,7 @@ close_lb(PG_FUNCTION_ARGS) /* * Does the point satisfy the equation? */ -static bool +static tsbool line_contain_point(LINE *line, Point *point) { /* @@ -3379,7 +3429,7 @@ line_contain_point(LINE *line, Point *point) Assert(line->B != 0.0); /* inf == inf here */ - return FPeq(point->y, -line->C / line->B); + return FPTeq(point->y, -line->C / line->B); } else if (line->B == 0.0) { @@ -3387,13 +3437,13 @@ line_contain_point(LINE *line, Point *point) Assert(line->A != 0.0); /* inf == inf here */ - return FPeq(point->x, -line->C / line->A); + return FPTeq(point->x, -line->C / line->A); } - return FPzero(float8_pl( - float8_pl(float8_mul(line->A, point->x), - float8_mul(line->B, point->y)), - line->C)); + return FPTzero(float8_pl( + float8_pl(float8_mul(line->A, point->x), + float8_mul(line->B, point->y)), + line->C)); } Datum @@ -3402,7 +3452,7 @@ on_pl(PG_FUNCTION_ARGS) Point *pt = PG_GETARG_POINT_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(line_contain_point(line, pt)); + PG_RETURN_TSBOOL(line_contain_point(line, pt)); } @@ -3410,12 +3460,12 @@ on_pl(PG_FUNCTION_ARGS) * Determine colinearity by detecting a triangle inequality. * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09 */ -static bool +static tsbool lseg_contain_point(LSEG *lseg, Point *pt) { - return FPeq(point_dt(pt, &lseg->p[0]) + - point_dt(pt, &lseg->p[1]), - point_dt(&lseg->p[0], &lseg->p[1])); + return FPTeq(point_dt(pt, &lseg->p[0]) + + point_dt(pt, &lseg->p[1]), + point_dt(&lseg->p[0], &lseg->p[1])); } Datum @@ -3424,18 +3474,25 @@ on_ps(PG_FUNCTION_ARGS) Point *pt = PG_GETARG_POINT_P(0); LSEG *lseg = PG_GETARG_LSEG_P(1); - PG_RETURN_BOOL(lseg_contain_point(lseg, pt)); + PG_RETURN_TSBOOL(lseg_contain_point(lseg, pt)); } /* * Check whether the point is in the box or on its border */ -static bool +static tsbool box_contain_point(BOX *box, Point *point) { - return box->high.x >= point->x && box->low.x <= point->x && - box->high.y >= point->y && box->low.y <= point->y; + if (box->high.x >= point->x && box->low.x <= point->x && + box->high.y >= point->y && box->low.y <= point->y) + return TS_TRUE; + else if (!isnan(box->high.x) && !isnan(box->high.y) && + !isnan(box->low.x) && !isnan(box->low.y) && + !isnan(point->x) && !isnan(point->y)) + return TS_FALSE; + + return TS_NULL; } Datum @@ -3444,7 +3501,7 @@ on_pb(PG_FUNCTION_ARGS) Point *pt = PG_GETARG_POINT_P(0); BOX *box = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(box_contain_point(box, pt)); + PG_RETURN_TSBOOL(box_contain_point(box, pt)); } Datum @@ -3453,7 +3510,7 @@ box_contain_pt(PG_FUNCTION_ARGS) BOX *box = PG_GETARG_BOX_P(0); Point *pt = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(box_contain_point(box, pt)); + PG_RETURN_TSBOOL(box_contain_point(box, pt)); } /* on_ppath - @@ -3476,24 +3533,38 @@ on_ppath(PG_FUNCTION_ARGS) n; float8 a, b; + int inside; /*-- OPEN --*/ if (!path->closed) { + tsbool r; + 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(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1]))) - PG_RETURN_BOOL(true); + r = FPTeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1])); + if (r != TS_FALSE) + PG_RETURN_TSBOOL(r); a = b; } + /* See the PG_RETURN_BOOL at the end of this function */ PG_RETURN_BOOL(false); } /*-- CLOSED --*/ - PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0); + inside = point_inside(pt, path->npts, path->p); + + if (inside < 0) + PG_RETURN_NULL(); + + /* + * PG_RETURN_BOOL is compatible and faster than PG_RETURN_TSBOOL when the + * value is guaranteed to be in bool. + */ + PG_RETURN_BOOL(inside != 0); } @@ -3508,8 +3579,8 @@ on_sl(PG_FUNCTION_ARGS) LSEG *lseg = PG_GETARG_LSEG_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) && - line_contain_point(line, &lseg->p[1])); + PG_RETURN_TSBOOL(TS_AND2(line_contain_point(line, &lseg->p[0]), + line_contain_point(line, &lseg->p[1]))); } @@ -3518,11 +3589,11 @@ on_sl(PG_FUNCTION_ARGS) * * It is, if both of its points are in the box or on its border. */ -static bool +static tsbool box_contain_lseg(BOX *box, LSEG *lseg) { - return box_contain_point(box, &lseg->p[0]) && - box_contain_point(box, &lseg->p[1]); + return TS_AND2(box_contain_point(box, &lseg->p[0]), + box_contain_point(box, &lseg->p[1])); } Datum @@ -3531,7 +3602,7 @@ on_sb(PG_FUNCTION_ARGS) LSEG *lseg = PG_GETARG_LSEG_P(0); BOX *box = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(box_contain_lseg(box, lseg)); + PG_RETURN_TSBOOL(box_contain_lseg(box, lseg)); } /*--------------------------------------------------------------------- @@ -3545,7 +3616,7 @@ inter_sl(PG_FUNCTION_ARGS) LSEG *lseg = PG_GETARG_LSEG_P(0); LINE *line = PG_GETARG_LINE_P(1); - PG_RETURN_BOOL(lseg_interpt_line(NULL, lseg, line)); + PG_RETURN_TSBOOL(lseg_interpt_line(NULL, lseg, line)); } @@ -3564,12 +3635,13 @@ inter_sl(PG_FUNCTION_ARGS) * Optimize for non-intersection by checking for box intersection first. * - thomas 1998-01-30 */ -static bool +static tsbool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg) { BOX lbox; LSEG bseg; Point point; + tsbool r; 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); @@ -3577,8 +3649,8 @@ box_interpt_lseg(Point *result, BOX *box, LSEG *lseg) 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)) - return false; + if ((r = box_ov(&lbox, box)) != TS_TRUE) + return r; if (result != NULL) { @@ -3587,30 +3659,30 @@ box_interpt_lseg(Point *result, BOX *box, LSEG *lseg) } /* an endpoint of segment is inside box? then clearly intersects */ - if (box_contain_point(box, &lseg->p[0]) || - box_contain_point(box, &lseg->p[1])) - return true; + if ((r = TS_OR2(box_contain_point(box, &lseg->p[0]), + box_contain_point(box, &lseg->p[1]))) != TS_FALSE) + return r; /* pairwise check lseg intersections */ point.x = box->low.x; point.y = box->high.y; statlseg_construct(&bseg, &box->low, &point); - if (lseg_interpt_lseg(NULL, &bseg, lseg)) - return true; + if ((r = lseg_interpt_lseg(NULL, &bseg, lseg)) != TS_FALSE) + return r; statlseg_construct(&bseg, &box->high, &point); - if (lseg_interpt_lseg(NULL, &bseg, lseg)) - return true; + if ((r = lseg_interpt_lseg(NULL, &bseg, lseg)) != TS_FALSE) + return r; point.x = box->high.x; point.y = box->low.y; statlseg_construct(&bseg, &box->low, &point); - if (lseg_interpt_lseg(NULL, &bseg, lseg)) - return true; + if ((r = lseg_interpt_lseg(NULL, &bseg, lseg)) != TS_FALSE) + return r; statlseg_construct(&bseg, &box->high, &point); - if (lseg_interpt_lseg(NULL, &bseg, lseg)) - return true; + if ((r = lseg_interpt_lseg(NULL, &bseg, lseg)) != TS_FALSE) + return r; /* if we dropped through, no two segs intersected */ return false; @@ -3622,7 +3694,7 @@ inter_sb(PG_FUNCTION_ARGS) LSEG *lseg = PG_GETARG_LSEG_P(0); BOX *box = PG_GETARG_BOX_P(1); - PG_RETURN_BOOL(box_interpt_lseg(NULL, box, lseg)); + PG_RETURN_TSBOOL(box_interpt_lseg(NULL, box, lseg)); } @@ -3637,6 +3709,7 @@ inter_lb(PG_FUNCTION_ARGS) LSEG bseg; Point p1, p2; + tsbool r; /* pairwise check lseg intersections */ p1.x = box->low.x; @@ -3644,25 +3717,28 @@ inter_lb(PG_FUNCTION_ARGS) p2.x = box->low.x; p2.y = box->high.y; statlseg_construct(&bseg, &p1, &p2); - if (lseg_interpt_line(NULL, &bseg, line)) - PG_RETURN_BOOL(true); + if ((r = lseg_interpt_line(NULL, &bseg, line)) != TS_FALSE) + PG_RETURN_TSBOOL(r); p1.x = box->high.x; p1.y = box->high.y; statlseg_construct(&bseg, &p1, &p2); - if (lseg_interpt_line(NULL, &bseg, line)) - PG_RETURN_BOOL(true); + if ((r = lseg_interpt_line(NULL, &bseg, line)) != TS_FALSE) + PG_RETURN_TSBOOL(r); p2.x = box->high.x; p2.y = box->low.y; statlseg_construct(&bseg, &p1, &p2); - if (lseg_interpt_line(NULL, &bseg, line)) - PG_RETURN_BOOL(true); + if ((r = lseg_interpt_line(NULL, &bseg, line)) != TS_FALSE) + PG_RETURN_TSBOOL(r); p1.x = box->low.x; p1.y = box->low.y; statlseg_construct(&bseg, &p1, &p2); - if (lseg_interpt_line(NULL, &bseg, line)) - PG_RETURN_BOOL(true); + if ((r = lseg_interpt_line(NULL, &bseg, line)) != TS_FALSE) + PG_RETURN_TSBOOL(r); - /* if we dropped through, no intersection */ + /* + * if we dropped through, no intersection "false" doesn't need + * PG_RETURN_TSBOOL() + */ PG_RETURN_BOOL(false); } @@ -3844,6 +3920,9 @@ poly_left(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.high.x < polyb->boundbox.low.x; /* @@ -3867,6 +3946,9 @@ poly_overleft(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.high.x <= polyb->boundbox.high.x; /* @@ -3890,6 +3972,9 @@ poly_right(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.low.x > polyb->boundbox.high.x; /* @@ -3913,6 +3998,9 @@ poly_overright(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.low.x >= polyb->boundbox.low.x; /* @@ -3936,6 +4024,9 @@ poly_below(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.high.y < polyb->boundbox.low.y; /* @@ -3959,6 +4050,9 @@ poly_overbelow(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.high.y <= polyb->boundbox.high.y; /* @@ -3982,6 +4076,9 @@ poly_above(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.low.y > polyb->boundbox.high.y; /* @@ -4005,6 +4102,9 @@ poly_overabove(PG_FUNCTION_ARGS) POLYGON *polyb = PG_GETARG_POLYGON_P(1); bool result; + if (isnan(polya->boundbox.high.x) || isnan(polyb->boundbox.high.x)) + PG_RETURN_NULL(); + result = polya->boundbox.low.y >= polyb->boundbox.low.y; /* @@ -4023,16 +4123,20 @@ poly_overabove(PG_FUNCTION_ARGS) * Check all points for matches in both forward and reverse * direction since polygons are non-directional and are * closed shapes. + * + * XXX: returns TS_FALSE when the two polygons consists of + * different number of points even if any of the points were + * NaN. It might be thewrong defintion. *-------------------------------------------------------*/ Datum poly_same(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); - bool result; + tsbool result; if (polya->npts != polyb->npts) - result = false; + result = TS_FALSE; else result = plist_same(polya->npts, polya->p, polyb->p); @@ -4053,13 +4157,16 @@ poly_overlap(PG_FUNCTION_ARGS) { POLYGON *polya = PG_GETARG_POLYGON_P(0); POLYGON *polyb = PG_GETARG_POLYGON_P(1); - bool result; + tsbool result; Assert(polya->npts > 0 && polyb->npts > 0); /* Quick check by bounding box */ result = box_ov(&polya->boundbox, &polyb->boundbox); + if (result == TS_NULL) + PG_RETURN_NULL(); + /* * Brute-force algorithm - try to find intersected edges, if so then * polygons are overlapped else check is one polygon inside other or not @@ -4074,9 +4181,9 @@ poly_overlap(PG_FUNCTION_ARGS) /* Init first of polya's edge with last point */ sa.p[0] = polya->p[polya->npts - 1]; - result = false; + result = TS_FALSE; - for (ia = 0; ia < polya->npts && !result; ia++) + for (ia = 0; ia < polya->npts && result != TS_TRUE; ia++) { /* Second point of polya's edge is a current one */ sa.p[1] = polya->p[ia]; @@ -4097,8 +4204,12 @@ poly_overlap(PG_FUNCTION_ARGS) sa.p[0] = sa.p[1]; } - if (!result) + if (result == TS_NULL) + PG_RETURN_NULL(); + + if (result == TS_FALSE) { + /* in the case of NaN is handled ealier */ result = (point_inside(polya->p, polyb->npts, polyb->p) || point_inside(polyb->p, polya->npts, polya->p)); } @@ -4133,6 +4244,12 @@ touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start) t.p[0] = *a; t.p[1] = *b; + /* + * assume no parameters have NaN, so the tsbool functions shouldn't return + * TS_NULL. + */ + Assert(!isnan(a->x) && !isnan(a->y) && !isnan(b->x) && !isnan(b->y) && + !isnan(poly->boundbox.high.x)); if (point_eq_point(a, s->p)) { if (lseg_contain_point(&t, s->p + 1)) @@ -4160,7 +4277,7 @@ touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start) * start is used for optimization - function checks * polygon's edges starting from start */ -static bool +static tsbool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) { LSEG s, @@ -4168,14 +4285,21 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) int i; bool res = true, intersection = false; + tsbool res1; + tsbool res2; t.p[0] = *a; t.p[1] = *b; s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)]; /* Fast path. Check against boundbox. Also checks NaNs. */ - if (!box_contain_point(&poly->boundbox, a) || - !box_contain_point(&poly->boundbox, b)) + res1 = box_contain_point(&poly->boundbox, a); + res2 = box_contain_point(&poly->boundbox, b); + + if (res1 == TS_NULL || res2 == TS_NULL) + return TS_NULL; + + if (!res1 || !res2) return false; for (i = start; i < poly->npts && res; i++) @@ -4206,6 +4330,8 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) */ intersection = true; + + /* the calls below won't return TS_NULL */ res = lseg_inside_poly(t.p, &interpt, poly, i + 1); if (res) res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1); @@ -4234,11 +4360,12 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) /* * Check whether the first polygon contains the second */ -static bool +static tsbool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly) { int i; LSEG s; + tsbool r; Assert(contains_poly->npts > 0 && contained_poly->npts > 0); @@ -4246,20 +4373,22 @@ poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly) * Quick check to see if contained's bounding box is contained in * contains' bb. */ - if (!box_contain_box(&contains_poly->boundbox, &contained_poly->boundbox)) - return false; + r = box_contain_box(&contains_poly->boundbox, &contained_poly->boundbox); + if (r != TS_TRUE) + return r; s.p[0] = contained_poly->p[contained_poly->npts - 1]; for (i = 0; i < contained_poly->npts; i++) { s.p[1] = contained_poly->p[i]; - if (!lseg_inside_poly(s.p, s.p + 1, contains_poly, 0)) - return false; + r = lseg_inside_poly(s.p, s.p + 1, contains_poly, 0); + if (r != TS_TRUE) + return r; s.p[0] = s.p[1]; } - return true; + return TS_TRUE; } Datum @@ -4277,7 +4406,7 @@ poly_contain(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); - PG_RETURN_BOOL(result); + PG_RETURN_TSBOOL(result); } @@ -4300,7 +4429,7 @@ poly_contained(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(polya, 0); PG_FREE_IF_COPY(polyb, 1); - PG_RETURN_BOOL(result); + PG_RETURN_TSBOOL(result); } @@ -4310,7 +4439,7 @@ poly_contain_pt(PG_FUNCTION_ARGS) POLYGON *poly = PG_GETARG_POLYGON_P(0); Point *p = PG_GETARG_POINT_P(1); - PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0); + PG_RETURN_TSBOOL(point_inside(p, poly->npts, poly->p) != 0); } Datum @@ -4319,7 +4448,7 @@ pt_contained_poly(PG_FUNCTION_ARGS) Point *p = PG_GETARG_POINT_P(0); POLYGON *poly = PG_GETARG_POLYGON_P(1); - PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0); + PG_RETURN_TSBOOL(point_inside(p, poly->npts, poly->p) != 0); } @@ -5015,9 +5144,9 @@ circle_same(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle1->radius)) || - FPeq(circle1->radius, circle2->radius)) && - point_eq_point(&circle1->center, &circle2->center)); + PG_RETURN_TSBOOL( + TS_AND2(FPTeq(circle1->radius, circle2->radius), + point_eq_point(&circle1->center, &circle2->center))); } /* circle_overlap - does circle1 overlap circle2? @@ -5028,8 +5157,8 @@ 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), - float8_pl(circle1->radius, circle2->radius))); + PG_RETURN_TSBOOL(FPTle(point_dt(&circle1->center, &circle2->center), + float8_pl(circle1->radius, circle2->radius))); } /* circle_overleft - is the right edge of circle1 at or left of @@ -5041,8 +5170,8 @@ circle_overleft(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius), - float8_pl(circle2->center.x, circle2->radius))); + PG_RETURN_TSBOOL(FPTle(float8_pl(circle1->center.x, circle1->radius), + float8_pl(circle2->center.x, circle2->radius))); } /* circle_left - is circle1 strictly left of circle2? @@ -5053,8 +5182,8 @@ circle_left(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius), - float8_mi(circle2->center.x, circle2->radius))); + PG_RETURN_TSBOOL(FPTlt(float8_pl(circle1->center.x, circle1->radius), + float8_mi(circle2->center.x, circle2->radius))); } /* circle_right - is circle1 strictly right of circle2? @@ -5065,8 +5194,8 @@ circle_right(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius), - float8_pl(circle2->center.x, circle2->radius))); + PG_RETURN_TSBOOL(FPTgt(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 @@ -5078,8 +5207,8 @@ circle_overright(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius), - float8_mi(circle2->center.x, circle2->radius))); + PG_RETURN_TSBOOL(FPTge(float8_mi(circle1->center.x, circle1->radius), + float8_mi(circle2->center.x, circle2->radius))); } /* circle_contained - is circle1 contained by circle2? @@ -5102,8 +5231,8 @@ 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), - float8_mi(circle1->radius, circle2->radius))); + PG_RETURN_TSBOOL(FPTle(point_dt(&circle1->center, &circle2->center), + float8_mi(circle1->radius, circle2->radius))); } @@ -5115,8 +5244,8 @@ circle_below(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius), - float8_mi(circle2->center.y, circle2->radius))); + PG_RETURN_TSBOOL(FPTlt(float8_pl(circle1->center.y, circle1->radius), + float8_mi(circle2->center.y, circle2->radius))); } /* circle_above - is circle1 strictly above circle2? @@ -5127,8 +5256,8 @@ circle_above(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius), - float8_pl(circle2->center.y, circle2->radius))); + PG_RETURN_TSBOOL(FPTgt(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 @@ -5140,8 +5269,8 @@ circle_overbelow(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius), - float8_pl(circle2->center.y, circle2->radius))); + PG_RETURN_TSBOOL(FPTle(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 @@ -5153,13 +5282,15 @@ circle_overabove(PG_FUNCTION_ARGS) CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0); CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1); - PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius), - float8_mi(circle2->center.y, circle2->radius))); + PG_RETURN_TSBOOL(FPTge(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? + * + * XXX; area comparison doen't consider the NaN-ness of the center location. */ Datum circle_eq(PG_FUNCTION_ARGS) @@ -5167,7 +5298,7 @@ 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_TSBOOL(FPTeq(circle_ar(circle1), circle_ar(circle2))); } Datum @@ -5176,7 +5307,7 @@ 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_TSBOOL(FPTne(circle_ar(circle1), circle_ar(circle2))); } Datum @@ -5185,7 +5316,7 @@ 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_TSBOOL(FPTlt(circle_ar(circle1), circle_ar(circle2))); } Datum @@ -5194,7 +5325,7 @@ 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_TSBOOL(FPTgt(circle_ar(circle1), circle_ar(circle2))); } Datum @@ -5203,7 +5334,7 @@ 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_TSBOOL(FPTle(circle_ar(circle1), circle_ar(circle2))); } Datum @@ -5212,7 +5343,7 @@ 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_TSBOOL(FPTge(circle_ar(circle1), circle_ar(circle2))); } @@ -5348,6 +5479,11 @@ circle_contain_pt(PG_FUNCTION_ARGS) float8 d; d = point_dt(&circle->center, point); + + if (isnan(d) || isnan(circle->radius)) + PG_RETURN_NULL(); + + /* XXX: why don't we use FP(T)le? */ PG_RETURN_BOOL(d <= circle->radius); } @@ -5360,6 +5496,10 @@ pt_contained_circle(PG_FUNCTION_ARGS) float8 d; d = point_dt(&circle->center, point); + if (isnan(d) || isnan(circle->radius)) + PG_RETURN_NULL(); + + /* XXX: why don't we use FP(T)le? */ PG_RETURN_BOOL(d <= circle->radius); } @@ -5586,8 +5726,9 @@ poly_circle(PG_FUNCTION_ARGS) ***********************************************************************/ /* - * Test to see if the point is inside the polygon, returns 1/0, or 2 if - * the point is on the polygon. + * Test to see if the point is inside the polygon, returns 1/0, or 2 if the + * point is on the polygon. -1 means undetermined, in case any operand is an + * invalid object. (-1, 0 and 1 are compatible with tsbool type) * Code adapted but not copied from integer-based routines in WN: A * Server for the HTTP * version 1.15.1, file wn/image.c @@ -5619,7 +5760,7 @@ point_inside(Point *p, int npts, Point *plist) /* NaN makes the point cannot be inside the polygon */ if (unlikely(isnan(x0) || isnan(y0) || isnan(p->x) || isnan(p->y))) - return 0; + return -1; prev_x = x0; prev_y = y0; @@ -5632,7 +5773,7 @@ point_inside(Point *p, int npts, Point *plist) /* NaN makes the point cannot be inside the polygon */ if (unlikely(isnan(x) || isnan(y))) - return 0; + return -1; /* compute previous to current point crossing */ if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON) @@ -5659,6 +5800,8 @@ point_inside(Point *p, int npts, Point *plist) * Returns +/-1 if one point is on the positive X-axis. * Returns 0 if both points are on the positive X-axis, or there is no crossing. * Returns POINT_ON_POLYGON if the segment contains (0,0). + * This function doesn't check if the parameters contain NaNs, it's the + * responsibility of the callers. * Wow, that is one confusing API, but it is used above, and when summed, * can tell is if a point is in a polygon. */ @@ -5723,17 +5866,18 @@ lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y) } -static bool +static tsbool plist_same(int npts, Point *p1, Point *p2) { int i, ii, j; + tsbool r; /* find match for first point */ for (i = 0; i < npts; i++) { - if (point_eq_point(&p2[i], &p1[0])) + if ((r = point_eq_point(&p2[i], &p1[0])) == TS_TRUE) { /* match found? then look forward through remaining points */ @@ -5741,26 +5885,29 @@ plist_same(int npts, Point *p1, Point *p2) { if (j >= npts) j = 0; - if (!point_eq_point(&p2[j], &p1[ii])) + if ((r = point_eq_point(&p2[j], &p1[ii])) != TS_TRUE) break; } if (ii == npts) - return true; + return TS_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 (!point_eq_point(&p2[j], &p1[ii])) + if ((r = point_eq_point(&p2[j], &p1[ii])) != TS_TRUE) break; } if (ii == npts) - return true; + return TS_TRUE; } + + if (r == TS_NULL) + return TS_NULL; } - return false; + return TS_FALSE; } diff --git a/src/include/c.h b/src/include/c.h index c8ede08273..03e541936e 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -402,6 +402,13 @@ typedef unsigned char bool; #endif /* not PG_USE_STDBOOL */ #endif /* not C++ */ +/* tri-state boolean, false/true are compatible with bool */ +typedef enum tsbool +{ + TS_NULL = -1, + TS_FALSE = false, + TS_TRUE = true +} tsbool; /* ---------------------------------------------------------------- * Section 3: standard system types diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 4ab3f9d8ef..a983d6d8d0 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -353,6 +353,115 @@ float8_max(const float8 val1, const float8 val2) return float8_gt(val1, val2) ? val1 : val2; } +/* tri-state equivalents */ +static inline tsbool +float4_teq(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 == val2; + + return TS_NULL; +} + +static inline tsbool +float8_teq(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 == val2; + + return TS_NULL; +} + +static inline tsbool +float4_tne(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 != val2; + + return TS_NULL; +} + +static inline tsbool +float8_tne(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 != val2; + + return TS_NULL; +} + +static inline tsbool +float4_tlt(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 < val2; + + return TS_NULL; +} + +static inline tsbool +float8_tlt(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 < val2; + + return TS_NULL; +} + +static inline tsbool +float4_tle(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 <= val2; + + return TS_NULL; +} + +static inline tsbool +float8_tle(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 <= val2; + + return TS_NULL; +} + +static inline tsbool +float4_tgt(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 > val2; + + return TS_NULL; +} + +static inline tsbool +float8_tgt(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 > val2; + + return TS_NULL; +} + +static inline tsbool +float4_tge(const float4 val1, const float4 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 >= val2; + + return TS_NULL; +} + +static inline tsbool +float8_tge(const float8 val1, const float8 val2) +{ + if (!isnan(val1) && !isnan(val2)) + return val1 >= val2; + + return TS_NULL; +} + /* * These two functions return NaN if either input is NaN, else the smaller * of the two inputs. This does NOT follow our usual sort rule, but it is diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index 0b87437d83..7b8a0dbdf7 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -40,6 +40,19 @@ #define EPSILON 1.0E-06 +/* helper function for tri-state checking */ +static inline tsbool +FP_TRICHECK(double A, double B, bool cond) +{ + if (cond) + return TS_TRUE; + if (!isnan(A) && !isnan(B)) + return TS_FALSE; + + return TS_NULL; +} + + #ifdef EPSILON #define FPzero(A) (fabs(A) <= EPSILON) @@ -78,6 +91,53 @@ FPge(double A, double B) { return A + EPSILON >= B; } + +/* tri-state comparisons, don't use define to avoid duplicate evaluation */ +static inline tsbool +FPTzero(double A) +{ + if (fabs(A) <= EPSILON) + return TS_TRUE; + if (isnan(A)) + return TS_NULL; + return TS_FALSE; +} + +static inline tsbool +FPTeq(double A, double B) +{ + return FP_TRICHECK(A, B, A == B || fabs(A - B) <= EPSILON); +} + +static inline tsbool +FPTne(double A, double B) +{ + return FP_TRICHECK(A, B, A != B && fabs(A - B) > EPSILON); +} + +static inline tsbool +FPTlt(double A, double B) +{ + return FP_TRICHECK(A, B, A + EPSILON < B); +} + +static inline tsbool +FPTle(double A, double B) +{ + return FP_TRICHECK(A, B, A <= B + EPSILON); +} + +static inline tsbool +FPTgt(double A, double B) +{ + return FP_TRICHECK(A, B, A > B + EPSILON); +} + +static inline tsbool +FPTge(double A, double B) +{ + return FP_TRICHECK(A, B, A + EPSILON >= B); +} #else #define FPzero(A) ((A) == 0) #define FPeq(A,B) ((A) == (B)) @@ -86,10 +146,109 @@ FPge(double A, double B) #define FPle(A,B) ((A) <= (B)) #define FPgt(A,B) ((A) > (B)) #define FPge(A,B) ((A) >= (B)) + +/* define as inline functions to avoid duplicate evaluation */ +static inline tsbool +FPTzero(double A) +{ + if (fabs(A) <= EPSILON) + return TS_TRUE; + if (isnan(A)) + return TS_NULL; + return TS_FALSE; +} + +static inline tsbool +FPTeq(double A, double B) +{ + return FP_TRICHECK(A, B, A == B); +} + +static inline tsbool +FPTne(double A, double B) +{ + return FP_TRICHECK(A, B, A != B); +} + +static inline tsbool +FPTlt(double A, double B) +{ + return FP_TRICHECK(A, B, A < B); +} + +static inline tsbool +FPTle(double A, double B) +{ + return FP_TRICHECK(A, B, A <= B); +} + +static inline tsbool +FPTgt(double A, double B) +{ + return FP_TRICHECK(A, B, A > B); +} + +static inline tsbool +FPge(double A, double B) +{ + return FP_TRICHECK(A, B, A >= B); +} #endif #define HYPOT(A, B) pg_hypot(A, B) +static inline tsbool +TS_NOT(tsbool a) +{ + if (a != TS_NULL) + return !a; + + return TS_NULL; +} + +static inline tsbool +TS_OR2(tsbool p1, tsbool p2) +{ + if (p1 == TS_TRUE || p2 == TS_TRUE) + return TS_TRUE; + if (p1 == TS_NULL || p2 == TS_NULL) + return TS_NULL; + else + return TS_FALSE; +} + +static inline tsbool +TS_AND2(tsbool p1, tsbool p2) +{ + if (p1 == TS_TRUE && p2 == TS_TRUE) + return TS_TRUE; + if (p1 == TS_NULL || p2 == TS_NULL) + return TS_NULL; + else + return TS_FALSE; +} + +static inline tsbool +TS_AND4(tsbool p1, tsbool p2, tsbool p3, tsbool p4) +{ + if (p1 == TS_TRUE && p2 == TS_TRUE && p3 == TS_TRUE && p4 == TS_TRUE) + return TS_TRUE; + if (p1 == TS_NULL || p2 == TS_NULL || p3 == TS_NULL || p4 ==TS_NULL) + return TS_NULL; + else + return TS_FALSE; +} + +#define PG_RETURN_TSBOOL(e) \ + do \ + { \ + tsbool _tmpsb = (e); \ + if (_tmpsb != TS_NULL) \ + PG_RETURN_BOOL(_tmpsb); \ + else \ + PG_RETURN_NULL(); \ + } while (0) + /*--------------------------------------------------------------------- * Point - (x,y) *-------------------------------------------------------------------*/