At Tue, 01 Dec 2020 10:03:42 -0500, Tom Lane <t...@sss.pgh.pa.us> wrote in > I think it should be "needs review" now.
Conflicted with some commit(s) uncertain to me. Rebased. regards. -- Kyotaro Horiguchi NTT Open Source Software Center
>From 26d9edeccf3f3111a7e0ff049aa6e3ba3746dce9 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horikyoga....@gmail.com> Date: Fri, 13 Nov 2020 13:31:20 +0900 Subject: [PATCH v8] fix geometric nan handling --- doc/src/sgml/func.sgml | 17 ++ src/backend/utils/adt/geo_ops.c | 337 ++++++++++++++++++--- src/include/utils/float.h | 22 ++ src/test/regress/expected/create_index.out | 2 +- src/test/regress/expected/geometry.out | 331 +++++++++----------- 5 files changed, 485 insertions(+), 224 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index d5cd705eeb..2f7f3c633c 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -10855,6 +10855,23 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple </para> </note> + <caution> + <para> + NaN and Infinity make geometric functions and operators behave + inconsistently. Geometric operators or functions that return a boolean + return false for operands that contain NaNs. Number-returning functions + and operators return NaN in most cases but sometimes return a valid + value if no NaNs are met while actual calculation. Object-returning ones + yield an object that contain NaNs depending to the operation. Likewise + the objects containing Infinity can make geometric operators and + functions behave inconsistently. For example (point + '(Infinity,Infinity)' <-> line '{-1,0,5}') is Infinity but (point + '(Infinity,Infinity)' <-> line '{0,-1,5}') is NaN. It can never + be a value other than these, but you should consider it uncertain how + geometric operators behave for objects containing Infinity. + </para> + </caution> + <table id="functions-geometry-func-table"> <title>Geometric Functions</title> <tgroup cols="1"> diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index c1dc511a1a..e74bf3031e 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -904,9 +904,9 @@ box_intersect(PG_FUNCTION_ARGS) result = (BOX *) palloc(sizeof(BOX)); - result->high.x = float8_min(box1->high.x, box2->high.x); + result->high.x = float8_min_nan(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->high.y = float8_min_nan(box1->high.y, box2->high.y); result->low.y = float8_max(box1->low.y, box2->low.y); PG_RETURN_BOX_P(result); @@ -1061,15 +1061,23 @@ line_construct(LINE *result, Point *pt, float8 m) result->A = -1.0; result->B = 0.0; result->C = pt->x; + + /* Avoid creating a valid line from an invalid point */ + if (likely(!isnan(pt->x) && !isnan(pt->y))) + return; } - else if (m == 0) + else if (m == 0.0) { /* horizontal - use "y = C" */ result->A = 0.0; result->B = -1.0; result->C = pt->y; + + /* Avoid creating a valid line from an invalid point */ + if (likely(!isnan(pt->x) && !isnan(pt->y))) + return; } - else + else if (!isnan(m)) { /* use "mx - y + yinter = 0" */ result->A = m; @@ -1078,7 +1086,12 @@ line_construct(LINE *result, Point *pt, float8 m) /* on some platforms, the preceding expression tends to produce -0 */ if (result->C == 0.0) result->C = 0.0; + + if (likely(!isnan(result->C))) + return; } + + result->A = result->B = result->C = get_float8_nan(); } /* line_construct_pp() @@ -1091,6 +1104,7 @@ line_construct_pp(PG_FUNCTION_ARGS) Point *pt2 = PG_GETARG_POINT_P(1); LINE *result = (LINE *) palloc(sizeof(LINE)); + /* NaNs are considered to be equal by point_eq_point */ if (point_eq_point(pt1, pt2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1111,8 +1125,12 @@ line_intersect(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); + Point xp; - PG_RETURN_BOOL(line_interpt_line(NULL, l1, l2)); + if (line_interpt_line(&xp, l1, l2) && !isnan(xp.x) && !isnan(xp.y)) + PG_RETURN_BOOL(true); + else + PG_RETURN_BOOL(false); } Datum @@ -1130,14 +1148,17 @@ 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 (FPzero(l1->A)) - PG_RETURN_BOOL(FPzero(l2->B)); + PG_RETURN_BOOL(FPzero(l2->B) && !isnan(l1->B) && !isnan(l2->A)); if (FPzero(l2->A)) - PG_RETURN_BOOL(FPzero(l1->B)); + PG_RETURN_BOOL(FPzero(l1->B) && !isnan(l2->B) && !isnan(l1->A)); if (FPzero(l1->B)) - PG_RETURN_BOOL(FPzero(l2->A)); + PG_RETURN_BOOL(FPzero(l2->A) && !isnan(l1->A) && !isnan(l2->B)); if (FPzero(l2->B)) - PG_RETURN_BOOL(FPzero(l1->A)); + PG_RETURN_BOOL(FPzero(l1->A) && !isnan(l2->A) && !isnan(l1->B)); PG_RETURN_BOOL(FPeq(float8_div(float8_mul(l1->A, l2->A), float8_mul(l1->B, l2->B)), -1.0)); @@ -1148,7 +1169,7 @@ line_vertical(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->B)); + PG_RETURN_BOOL(FPzero(line->B) && !isnan(line->A) && !isnan(line->C)); } Datum @@ -1156,7 +1177,7 @@ line_horizontal(PG_FUNCTION_ARGS) { LINE *line = PG_GETARG_LINE_P(0); - PG_RETURN_BOOL(FPzero(line->A)); + PG_RETURN_BOOL(FPzero(line->A) && !isnan(line->B) && !isnan(line->C)); } @@ -1206,9 +1227,20 @@ static inline float8 line_sl(LINE *line) { if (FPzero(line->A)) + { + /* C is likely to be NaN than B */ + if (unlikely(isnan(line->C) || isnan(line->B))) + return get_float8_nan(); return 0.0; + } if (FPzero(line->B)) + { + /* C is likely to be NaN than A */ + if (unlikely(isnan(line->C) || isnan(line->A))) + return get_float8_nan(); return get_float8_infinity(); + } + return float8_div(line->A, -line->B); } @@ -1220,9 +1252,20 @@ static inline float8 line_invsl(LINE *line) { if (FPzero(line->A)) + { + /* C is likely to be NaN than B */ + if (unlikely(isnan(line->C) || isnan(line->B))) + return get_float8_nan(); return get_float8_infinity(); + } + if (FPzero(line->B)) + { + /* C is likely to be NaN than A */ + if (unlikely(isnan(line->C) || isnan(line->A))) + return get_float8_nan(); return 0.0; + } return float8_div(line->B, line->A); } @@ -1235,14 +1278,23 @@ line_distance(PG_FUNCTION_ARGS) { LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); + Point xp; float8 ratio; - if (line_interpt_line(NULL, l1, l2)) /* intersecting? */ + if (line_interpt_line(&xp, l1, l2)) /* intersecting? */ + { + /* return NaN if NaN is involved */ + if (isnan(xp.x) || isnan(xp.y)) + PG_RETURN_FLOAT8(get_float8_nan()); + PG_RETURN_FLOAT8(0.0); + } - if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A)) + if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l2->A) || isnan(l2->B))) + ratio = get_float8_nan(); + else if (!FPzero(l1->A) && !FPzero(l2->A)) ratio = float8_div(l1->A, l2->A); - else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B)) + else if (!FPzero(l1->B) && !FPzero(l2->B)) ratio = float8_div(l1->B, l2->B); else ratio = 1.0; @@ -1264,8 +1316,13 @@ line_interpt(PG_FUNCTION_ARGS) result = (Point *) palloc(sizeof(Point)); - if (!line_interpt_line(result, l1, l2)) + if (!line_interpt_line(result, l1, l2) || + isnan(result->x) || isnan(result->y)) + { + pfree(result); PG_RETURN_NULL(); + } + PG_RETURN_POINT_P(result); } @@ -1291,6 +1348,7 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2) if (!FPzero(l1->B)) { + /* l1 is not virtucal */ if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B)))) return false; @@ -1298,18 +1356,34 @@ line_interpt_line(Point *result, LINE *l1, LINE *l2) float8_mul(l2->B, l1->C)), float8_mi(float8_mul(l1->A, l2->B), float8_mul(l2->A, l1->B))); - y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B); - } - else if (!FPzero(l2->B)) - { - if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B)))) - return false; - - x = float8_div(float8_mi(float8_mul(l2->B, l1->C), - float8_mul(l1->B, l2->C)), + /* + * You might want to simplify this expression by using x, but that can + * introduce unnecessary indeterminants (inf-inf) into the calculation, + * which leads to a wrong result. + * (For example, (-1, -1, Inf) and (1, -1, 0)) + */ + y = float8_div(float8_mi(float8_mul(l1->A, l2->C), + float8_mul(l2->A, l1->C)), float8_mi(float8_mul(l2->A, l1->B), float8_mul(l1->A, l2->B))); - y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B); + } + else if (!FPzero(l2->B)) + { + /* l2 is not virtical */ + /* + * We know that l1 is vertical here. The lines cannot be parallel and + * the x-coord of the cross point is -C/A of l1. + */ + x = -float8_div(l1->C, l1->A); + + /* + * When l2->A is zero, y is determined independently from x even if it + * is Inf. + */ + if (FPzero(l2->A)) + y = -float8_div(l2->C, l2->B); + else + y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B); } else return false; @@ -1639,8 +1713,8 @@ path_inter(PG_FUNCTION_ARGS) { 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); + 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; @@ -1648,8 +1722,8 @@ path_inter(PG_FUNCTION_ARGS) { 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); + 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); @@ -1739,6 +1813,11 @@ path_distance(PG_FUNCTION_ARGS) statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]); tmp = lseg_closept_lseg(NULL, &seg1, &seg2); + + /* return NULL immediately if NaN is involved */ + if (isnan(tmp)) + PG_RETURN_NULL(); + if (!have_min || float8_lt(tmp, min)) { min = tmp; @@ -1992,9 +2071,19 @@ static inline float8 point_sl(Point *pt1, Point *pt2) { if (FPeq(pt1->x, pt2->x)) + { + if (unlikely(isnan(pt1->y) || isnan(pt2->y))) + return get_float8_nan(); return get_float8_infinity(); + } + if (FPeq(pt1->y, pt2->y)) + { + if (unlikely(isnan(pt1->x) || isnan(pt2->x))) + return get_float8_nan(); return 0.0; + } + return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x)); } @@ -2008,9 +2097,19 @@ static inline float8 point_invsl(Point *pt1, Point *pt2) { if (FPeq(pt1->x, pt2->x)) + { + if (unlikely(isnan(pt1->y) || isnan(pt2->y))) + return get_float8_nan(); return 0.0; + } + if (FPeq(pt1->y, pt2->y)) + { + if (unlikely(isnan(pt1->x) || isnan(pt2->x))) + return get_float8_nan(); return get_float8_infinity(); + } + return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y)); } @@ -2426,6 +2525,11 @@ dist_ppath_internal(Point *pt, PATH *path) statlseg_construct(&lseg, &path->p[iprev], &path->p[i]); tmp = lseg_closept_point(NULL, &lseg, pt); + + /* return NaN if NaN is involved */ + if (unlikely(isnan(tmp))) + return tmp; + if (!have_min || float8_lt(tmp, result)) { result = tmp; @@ -2657,6 +2761,8 @@ dist_ppoly_internal(Point *pt, POLYGON *poly) d = lseg_closept_point(NULL, &seg, pt); if (float8_lt(d, result)) result = d; + else if (unlikely(isnan(d))) + return get_float8_nan(); } return result; @@ -2686,7 +2792,8 @@ 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)) + if (!line_interpt_line(&interpt, &tmp, line) || + unlikely(isnan(interpt.x) || isnan(interpt.y))) return false; /* @@ -2728,6 +2835,78 @@ line_closept_point(Point *result, LINE *line, Point *point) { Point closept; LINE tmp; + float8 val; + + /* + * Treat specially the cases where A = 0 and B = 0, which we regard the + * line is perfectly horizontal and vertical correspondingly, not applying + * the normal formula involving the behavior of inf*0 =NaN defined by + * IEEE754. + */ + if (FPzero(line->A)) + { + float8 y; + + /* the line is horizontal */ + Assert(!FPzero(line->B)); + + y = -line->C / line->B; + + /* Avoid -0 */ + if (y == 0.0) + y = 0.0; + + if (result != NULL) + { + result->x = point->x; + result->y = y; + } + + if (unlikely(isnan(point->x))) + return get_float8_nan(); + + return fabs(point->y - y); + } + else if (FPzero(line->B)) + { + float x; + + /* the line is virtical */ + Assert(!FPzero(line->A)); + + x = -line->C / line->A; + + /* Avoid -0 */ + if (x == 0) + x = 0; + + if (result != NULL) + { + result->x = x; + result->y = point->y; + } + + if (unlikely(isnan(point->y))) + return get_float8_nan(); + + return fabs(point->x - x); + } + + /* + * If it is unclear whether the point is on the line or not, then the + * results are ill-defined. This eliminates cases where any of the given + * coordinates are NaN, as well as cases where infinite coordinates give + * rise to Inf - Inf, 0 * Inf, etc. + */ + val = float8_pl(float8_pl(float8_mul(line->A, point->x), + float8_mul(line->B, point->y)), + line->C); + if (unlikely(isnan(val))) + { + if (result != NULL) + result->x = result->y = get_float8_nan(); + return get_float8_nan(); + } /* * We drop a perpendicular to find the intersection point. Ordinarily we @@ -2738,7 +2917,7 @@ line_closept_point(Point *result, LINE *line, Point *point) if (!line_interpt_line(&closept, &tmp, line)) { if (result != NULL) - *result = *point; + result->x = result->y = get_float8_nan(); return get_float8_nan(); } @@ -2746,7 +2925,17 @@ line_closept_point(Point *result, LINE *line, Point *point) if (result != NULL) *result = closept; - return point_dt(&closept, point); + /* + * If the closest point contains Inf's, the closest point may lose + * arithmetic relationship with the point which lets point_dt wrongly give + * NaN. To avoid that kind of failure, we calculate the distance using the + * following formula instead of using the closest point. + * + * | A*x + B*y + C | / sqrt(A^2 + B^2) + * + * The dividend have been already calculated so just divide it. + */ + return float8_div(fabs(val), HYPOT(line->A, line->B)); } Datum @@ -2758,7 +2947,9 @@ close_pl(PG_FUNCTION_ARGS) result = (Point *) palloc(sizeof(Point)); - if (isnan(line_closept_point(result, line, pt))) + (void) line_closept_point(result, line, pt); + + if (unlikely(isnan(result->x) || isnan(result->y))) PG_RETURN_NULL(); PG_RETURN_POINT_P(result); @@ -2815,6 +3006,7 @@ lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg) Point point; float8 dist, d; + bool anynan = false; /* First, we handle the case when the line segments are intersecting. */ if (lseg_interpt_lseg(result, on_lseg, to_lseg)) @@ -2826,6 +3018,7 @@ lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg) */ dist = lseg_closept_point(result, on_lseg, &to_lseg->p[0]); d = lseg_closept_point(&point, on_lseg, &to_lseg->p[1]); + anynan |= (isnan(dist) || isnan(d)); if (float8_lt(d, dist)) { dist = d; @@ -2835,6 +3028,7 @@ lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg) /* The closest point can still be one of the endpoints, so we test them. */ d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[0]); + anynan |= isnan(d); if (float8_lt(d, dist)) { dist = d; @@ -2842,6 +3036,7 @@ lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg) *result = on_lseg->p[0]; } d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[1]); + anynan |= isnan(d); if (float8_lt(d, dist)) { dist = d; @@ -2849,6 +3044,12 @@ lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg) *result = on_lseg->p[1]; } + if (unlikely(anynan)) + { + if (result != NULL) + result->x = result->y = get_float8_nan(); + return get_float8_nan(); + } return dist; } @@ -2885,6 +3086,7 @@ box_closept_point(Point *result, BOX *box, Point *pt) Point point, closept; LSEG lseg; + bool anynan = false; if (box_contain_point(box, pt)) { @@ -2899,9 +3101,10 @@ box_closept_point(Point *result, BOX *box, Point *pt) point.y = box->high.y; statlseg_construct(&lseg, &box->low, &point); dist = lseg_closept_point(result, &lseg, pt); - + anynan |= isnan(dist); statlseg_construct(&lseg, &box->high, &point); d = lseg_closept_point(&closept, &lseg, pt); + anynan |= isnan(d); if (float8_lt(d, dist)) { dist = d; @@ -2913,6 +3116,7 @@ box_closept_point(Point *result, BOX *box, Point *pt) point.y = box->low.y; statlseg_construct(&lseg, &box->low, &point); d = lseg_closept_point(&closept, &lseg, pt); + anynan |= isnan(d); if (float8_lt(d, dist)) { dist = d; @@ -2922,6 +3126,7 @@ box_closept_point(Point *result, BOX *box, Point *pt) statlseg_construct(&lseg, &box->high, &point); d = lseg_closept_point(&closept, &lseg, pt); + anynan |= isnan(d); if (float8_lt(d, dist)) { dist = d; @@ -2929,6 +3134,13 @@ box_closept_point(Point *result, BOX *box, Point *pt) *result = closept; } + if (unlikely(anynan)) + { + if (result != NULL) + result->x = result->y = get_float8_nan(); + return get_float8_nan(); + } + return dist; } @@ -3000,6 +3212,7 @@ close_sl(PG_FUNCTION_ARGS) * even because of simple roundoff issues, there may not be a single closest * point. We are likely to set the result to the second endpoint in these * cases. + * Returns Nan and stores {NaN,NaN} to result if NaN is involved, */ static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line) @@ -3022,6 +3235,14 @@ lseg_closept_line(Point *result, LSEG *lseg, LINE *line) } else { + /* return NaN if any of the two is NaN */ + if (unlikely(isnan(dist1) || isnan(dist2))) + { + if (result != NULL) + result->x = result->y = get_float8_nan(); + return get_float8_nan(); + } + if (result != NULL) *result = lseg->p[1]; @@ -3147,9 +3368,32 @@ close_lb(PG_FUNCTION_ARGS) static bool line_contain_point(LINE *line, Point *point) { - return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x), - float8_mul(line->B, point->y)), - line->C)); + /* + * Treat specially way the cases where A = 0 and B = 0, which we regard the + * line is perfectly horizontal and vertical correspondingly to avoid the + * normal formula based on the IEEE754's definitions yields unwanted NaNs. + */ + if (line->A == 0.0) + { + /* the line is horizontal */ + Assert(line->B != 0.0); + + /* inf == inf here */ + return FPeq(point->y, -line->C / line->B); + } + else if (line->B == 0.0) + { + /* the line is vertical */ + Assert(line->A != 0.0); + + /* inf == inf here */ + return FPeq(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)); } Datum @@ -3448,6 +3692,12 @@ make_bound_box(POLYGON *poly) y2 = y1 = poly->p[0].y; for (i = 1; i < poly->npts; i++) { + /* if NaN found, make an invalid boundbox */ + if (unlikely(isnan(poly->p[i].x) || isnan(poly->p[i].y))) + { + x1 = x2 = y1 = y2 = get_float8_nan(); + break; + } if (float8_lt(poly->p[i].x, x1)) x1 = poly->p[i].x; if (float8_gt(poly->p[i].x, x2)) @@ -3923,6 +4173,11 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start) 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)) + return false; + for (i = start; i < poly->npts && res; i++) { Point interpt; @@ -5362,6 +5617,10 @@ point_inside(Point *p, int npts, Point *plist) x0 = float8_mi(plist[0].x, p->x); y0 = float8_mi(plist[0].y, p->y); + /* NaN makes the point cannot be inside the polygon */ + if (unlikely(isnan(x0) || isnan(y0) || isnan(p->x) || isnan(p->y))) + return 0; + prev_x = x0; prev_y = y0; /* loop over polygon points and aggregate total_cross */ @@ -5371,6 +5630,10 @@ point_inside(Point *p, int npts, Point *plist) x = float8_mi(plist[i].x, p->x); y = float8_mi(plist[i].y, p->y); + /* NaN makes the point cannot be inside the polygon */ + if (unlikely(isnan(x) || isnan(y))) + return 0; + /* compute previous to current point crossing */ if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON) return 2; diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 79bf8daca8..52bcf853f2 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -353,4 +353,26 @@ float8_max(const float8 val1, const float8 val2) return float8_gt(val1, val2) ? val1 : val2; } +/* + * 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 + * convenient in some places. (Note that float4_max and float8_max act this + * way anyway, so no similar variant is needed for them.) + */ +static inline float4 +float4_min_nan(const float4 val1, const float4 val2) +{ + return (isnan(val1) ? val1 : + (isnan(val2) ? val2 : + (val1 < val2 ? val1 : val2))); +} + +static inline float8 +float8_min_nan(const float8 val1, const float8 val2) +{ + return (isnan(val1) ? val1 : + (isnan(val2) ? val2 : + (val1 < val2 ? val1 : val2))); +} + #endif /* FLOAT_H */ diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index fc6afab58a..3605186c44 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -139,7 +139,7 @@ SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; count ------- - 5 + 4 (1 row) SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out index 84f7eabb66..1ae14c4d4b 100644 --- a/src/test/regress/expected/geometry.out +++ b/src/test/regress/expected/geometry.out @@ -517,7 +517,7 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_pl, l.s <-> p.f1 AS dist_lp FROM POINT_TB (-3,4) | {0,3,0} | 4 | 4 (-3,4) | {1,-1,0} | 4.94974746831 | 4.94974746831 (-3,4) | {-0.4,-1,-6} | 8.17059487979 | 8.17059487979 - (-3,4) | {-0.000184615384615,-1,15.3846153846} | 11.3851690368 | 11.3851690368 + (-3,4) | {-0.000184615384615,-1,15.3846153846} | 11.3851690367 | 11.3851690367 (-3,4) | {3,NaN,5} | NaN | NaN (-3,4) | {NaN,NaN,NaN} | NaN | NaN (-3,4) | {0,-1,3} | 1 | 1 @@ -537,7 +537,7 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_pl, l.s <-> p.f1 AS dist_lp FROM POINT_TB (-5,-12) | {0,3,0} | 12 | 12 (-5,-12) | {1,-1,0} | 4.94974746831 | 4.94974746831 (-5,-12) | {-0.4,-1,-6} | 7.42781352708 | 7.42781352708 - (-5,-12) | {-0.000184615384615,-1,15.3846153846} | 27.3855379948 | 27.3855379948 + (-5,-12) | {-0.000184615384615,-1,15.3846153846} | 27.3855379949 | 27.3855379949 (-5,-12) | {3,NaN,5} | NaN | NaN (-5,-12) | {NaN,NaN,NaN} | NaN | NaN (-5,-12) | {0,-1,3} | 15 | 15 @@ -553,7 +553,7 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_pl, l.s <-> p.f1 AS dist_lp FROM POINT_TB (1e-300,-1e-300) | {0,-1,3} | 3 | 3 (1e-300,-1e-300) | {-1,0,3} | 3 | 3 (1e+300,Infinity) | {0,-1,5} | Infinity | Infinity - (1e+300,Infinity) | {1,0,5} | NaN | NaN + (1e+300,Infinity) | {1,0,5} | 1e+300 | 1e+300 (1e+300,Infinity) | {0,3,0} | Infinity | Infinity (1e+300,Infinity) | {1,-1,0} | Infinity | Infinity (1e+300,Infinity) | {-0.4,-1,-6} | Infinity | Infinity @@ -561,16 +561,16 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_pl, l.s <-> p.f1 AS dist_lp FROM POINT_TB (1e+300,Infinity) | {3,NaN,5} | NaN | NaN (1e+300,Infinity) | {NaN,NaN,NaN} | NaN | NaN (1e+300,Infinity) | {0,-1,3} | Infinity | Infinity - (1e+300,Infinity) | {-1,0,3} | NaN | NaN - (Infinity,1e+300) | {0,-1,5} | NaN | NaN + (1e+300,Infinity) | {-1,0,3} | 1e+300 | 1e+300 + (Infinity,1e+300) | {0,-1,5} | 1e+300 | 1e+300 (Infinity,1e+300) | {1,0,5} | Infinity | Infinity - (Infinity,1e+300) | {0,3,0} | NaN | NaN - (Infinity,1e+300) | {1,-1,0} | NaN | NaN - (Infinity,1e+300) | {-0.4,-1,-6} | NaN | NaN - (Infinity,1e+300) | {-0.000184615384615,-1,15.3846153846} | NaN | NaN + (Infinity,1e+300) | {0,3,0} | 1e+300 | 1e+300 + (Infinity,1e+300) | {1,-1,0} | Infinity | Infinity + (Infinity,1e+300) | {-0.4,-1,-6} | Infinity | Infinity + (Infinity,1e+300) | {-0.000184615384615,-1,15.3846153846} | Infinity | Infinity (Infinity,1e+300) | {3,NaN,5} | NaN | NaN (Infinity,1e+300) | {NaN,NaN,NaN} | NaN | NaN - (Infinity,1e+300) | {0,-1,3} | NaN | NaN + (Infinity,1e+300) | {0,-1,3} | 1e+300 | 1e+300 (Infinity,1e+300) | {-1,0,3} | Infinity | Infinity (NaN,NaN) | {0,-1,5} | NaN | NaN (NaN,NaN) | {1,0,5} | NaN | NaN @@ -587,7 +587,7 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_pl, l.s <-> p.f1 AS dist_lp FROM POINT_TB (10,10) | {0,3,0} | 10 | 10 (10,10) | {1,-1,0} | 0 | 0 (10,10) | {-0.4,-1,-6} | 18.5695338177 | 18.5695338177 - (10,10) | {-0.000184615384615,-1,15.3846153846} | 5.38276913903 | 5.38276913903 + (10,10) | {-0.000184615384615,-1,15.3846153846} | 5.38276913904 | 5.38276913904 (10,10) | {3,NaN,5} | NaN | NaN (10,10) | {NaN,NaN,NaN} | NaN | NaN (10,10) | {0,-1,3} | 7 | 7 @@ -653,7 +653,7 @@ SELECT p.f1, l.s, p.f1 <-> l.s AS dist_ps, l.s <-> p.f1 AS dist_sp FROM POINT_TB (1e+300,Infinity) | [(11,22),(33,44)] | Infinity | Infinity (1e+300,Infinity) | [(-10,2),(-10,3)] | Infinity | Infinity (1e+300,Infinity) | [(0,-20),(30,-20)] | Infinity | Infinity - (1e+300,Infinity) | [(NaN,1),(NaN,90)] | Infinity | Infinity + (1e+300,Infinity) | [(NaN,1),(NaN,90)] | NaN | NaN (Infinity,1e+300) | [(1,2),(3,4)] | Infinity | Infinity (Infinity,1e+300) | [(0,0),(6,6)] | Infinity | Infinity (Infinity,1e+300) | [(10,-10),(-3,-4)] | Infinity | Infinity @@ -892,13 +892,13 @@ SELECT p.f1, p1.f1, p.f1 <-> p1.f1 AS dist_ppoly, p1.f1 <-> p.f1 AS dist_polyp F (Infinity,1e+300) | ((1,2),(7,8),(5,6),(3,-4)) | Infinity | Infinity (Infinity,1e+300) | ((0,0)) | Infinity | Infinity (Infinity,1e+300) | ((0,1),(0,1)) | Infinity | Infinity - (NaN,NaN) | ((2,0),(2,4),(0,0)) | 0 | 0 - (NaN,NaN) | ((3,1),(3,3),(1,0)) | 0 | 0 - (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | 0 | 0 - (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | 0 | 0 - (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | 0 | 0 - (NaN,NaN) | ((0,0)) | 0 | 0 - (NaN,NaN) | ((0,1),(0,1)) | 0 | 0 + (NaN,NaN) | ((2,0),(2,4),(0,0)) | NaN | NaN + (NaN,NaN) | ((3,1),(3,3),(1,0)) | NaN | NaN + (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | NaN | NaN + (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | NaN | NaN + (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | NaN | NaN + (NaN,NaN) | ((0,0)) | NaN | NaN + (NaN,NaN) | ((0,1),(0,1)) | NaN | NaN (10,10) | ((2,0),(2,4),(0,0)) | 10 | 10 (10,10) | ((3,1),(3,3),(1,0)) | 9.89949493661 | 9.89949493661 (10,10) | ((1,2),(3,4),(5,6),(7,8)) | 3.60555127546 | 3.60555127546 @@ -919,7 +919,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (0,0) | (-5,-12) | {2.4,-1,0} (0,0) | (1e+300,Infinity) | {-1,0,0} (0,0) | (Infinity,1e+300) | {0,-1,0} - (0,0) | (NaN,NaN) | {NaN,-1,NaN} + (0,0) | (NaN,NaN) | {NaN,NaN,NaN} (0,0) | (10,10) | {1,-1,0} (-10,0) | (0,0) | {0,-1,0} (-10,0) | (-3,4) | {0.571428571429,-1,5.71428571429} @@ -928,7 +928,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (-10,0) | (1e-300,-1e-300) | {0,-1,0} (-10,0) | (1e+300,Infinity) | {-1,0,-10} (-10,0) | (Infinity,1e+300) | {0,-1,0} - (-10,0) | (NaN,NaN) | {NaN,-1,NaN} + (-10,0) | (NaN,NaN) | {NaN,NaN,NaN} (-10,0) | (10,10) | {0.5,-1,5} (-3,4) | (0,0) | {-1.33333333333,-1,0} (-3,4) | (-10,0) | {0.571428571429,-1,5.71428571429} @@ -937,7 +937,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (-3,4) | (1e-300,-1e-300) | {-1.33333333333,-1,0} (-3,4) | (1e+300,Infinity) | {-1,0,-3} (-3,4) | (Infinity,1e+300) | {0,-1,4} - (-3,4) | (NaN,NaN) | {NaN,-1,NaN} + (-3,4) | (NaN,NaN) | {NaN,NaN,NaN} (-3,4) | (10,10) | {0.461538461538,-1,5.38461538462} (5.1,34.5) | (0,0) | {6.76470588235,-1,0} (5.1,34.5) | (-10,0) | {2.28476821192,-1,22.8476821192} @@ -946,7 +946,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (5.1,34.5) | (1e-300,-1e-300) | {6.76470588235,-1,0} (5.1,34.5) | (1e+300,Infinity) | {-1,0,5.1} (5.1,34.5) | (Infinity,1e+300) | {0,-1,34.5} - (5.1,34.5) | (NaN,NaN) | {NaN,-1,NaN} + (5.1,34.5) | (NaN,NaN) | {NaN,NaN,NaN} (5.1,34.5) | (10,10) | {-5,-1,60} (-5,-12) | (0,0) | {2.4,-1,0} (-5,-12) | (-10,0) | {-2.4,-1,-24} @@ -955,7 +955,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (-5,-12) | (1e-300,-1e-300) | {2.4,-1,0} (-5,-12) | (1e+300,Infinity) | {-1,0,-5} (-5,-12) | (Infinity,1e+300) | {0,-1,-12} - (-5,-12) | (NaN,NaN) | {NaN,-1,NaN} + (-5,-12) | (NaN,NaN) | {NaN,NaN,NaN} (-5,-12) | (10,10) | {1.46666666667,-1,-4.66666666667} (1e-300,-1e-300) | (-10,0) | {0,-1,-1e-300} (1e-300,-1e-300) | (-3,4) | {-1.33333333333,-1,3.33333333333e-301} @@ -963,7 +963,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (1e-300,-1e-300) | (-5,-12) | {2.4,-1,-3.4e-300} (1e-300,-1e-300) | (1e+300,Infinity) | {-1,0,1e-300} (1e-300,-1e-300) | (Infinity,1e+300) | {0,-1,-1e-300} - (1e-300,-1e-300) | (NaN,NaN) | {NaN,-1,NaN} + (1e-300,-1e-300) | (NaN,NaN) | {NaN,NaN,NaN} (1e-300,-1e-300) | (10,10) | {1,-1,-2e-300} (1e+300,Infinity) | (0,0) | {-1,0,1e+300} (1e+300,Infinity) | (-10,0) | {-1,0,1e+300} @@ -971,8 +971,8 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (1e+300,Infinity) | (5.1,34.5) | {-1,0,1e+300} (1e+300,Infinity) | (-5,-12) | {-1,0,1e+300} (1e+300,Infinity) | (1e-300,-1e-300) | {-1,0,1e+300} - (1e+300,Infinity) | (Infinity,1e+300) | {NaN,-1,NaN} - (1e+300,Infinity) | (NaN,NaN) | {NaN,-1,NaN} + (1e+300,Infinity) | (Infinity,1e+300) | {NaN,NaN,NaN} + (1e+300,Infinity) | (NaN,NaN) | {NaN,NaN,NaN} (1e+300,Infinity) | (10,10) | {-1,0,1e+300} (Infinity,1e+300) | (0,0) | {0,-1,1e+300} (Infinity,1e+300) | (-10,0) | {0,-1,1e+300} @@ -980,18 +980,18 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (Infinity,1e+300) | (5.1,34.5) | {0,-1,1e+300} (Infinity,1e+300) | (-5,-12) | {0,-1,1e+300} (Infinity,1e+300) | (1e-300,-1e-300) | {0,-1,1e+300} - (Infinity,1e+300) | (1e+300,Infinity) | {NaN,-1,NaN} - (Infinity,1e+300) | (NaN,NaN) | {NaN,-1,NaN} + (Infinity,1e+300) | (1e+300,Infinity) | {NaN,NaN,NaN} + (Infinity,1e+300) | (NaN,NaN) | {NaN,NaN,NaN} (Infinity,1e+300) | (10,10) | {0,-1,1e+300} - (NaN,NaN) | (0,0) | {NaN,-1,NaN} - (NaN,NaN) | (-10,0) | {NaN,-1,NaN} - (NaN,NaN) | (-3,4) | {NaN,-1,NaN} - (NaN,NaN) | (5.1,34.5) | {NaN,-1,NaN} - (NaN,NaN) | (-5,-12) | {NaN,-1,NaN} - (NaN,NaN) | (1e-300,-1e-300) | {NaN,-1,NaN} - (NaN,NaN) | (1e+300,Infinity) | {NaN,-1,NaN} - (NaN,NaN) | (Infinity,1e+300) | {NaN,-1,NaN} - (NaN,NaN) | (10,10) | {NaN,-1,NaN} + (NaN,NaN) | (0,0) | {NaN,NaN,NaN} + (NaN,NaN) | (-10,0) | {NaN,NaN,NaN} + (NaN,NaN) | (-3,4) | {NaN,NaN,NaN} + (NaN,NaN) | (5.1,34.5) | {NaN,NaN,NaN} + (NaN,NaN) | (-5,-12) | {NaN,NaN,NaN} + (NaN,NaN) | (1e-300,-1e-300) | {NaN,NaN,NaN} + (NaN,NaN) | (1e+300,Infinity) | {NaN,NaN,NaN} + (NaN,NaN) | (Infinity,1e+300) | {NaN,NaN,NaN} + (NaN,NaN) | (10,10) | {NaN,NaN,NaN} (10,10) | (0,0) | {1,-1,0} (10,10) | (-10,0) | {0.5,-1,5} (10,10) | (-3,4) | {0.461538461538,-1,5.38461538462} @@ -1000,7 +1000,7 @@ SELECT p1.f1, p2.f1, line(p1.f1, p2.f1) (10,10) | (1e-300,-1e-300) | {1,-1,0} (10,10) | (1e+300,Infinity) | {-1,0,10} (10,10) | (Infinity,1e+300) | {0,-1,10} - (10,10) | (NaN,NaN) | {NaN,-1,NaN} + (10,10) | (NaN,NaN) | {NaN,NaN,NaN} (88 rows) -- Closest point to line @@ -1068,24 +1068,24 @@ SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l; (1e-300,-1e-300) | {0,-1,3} | (1e-300,3) (1e-300,-1e-300) | {-1,0,3} | (3,-1e-300) (1e+300,Infinity) | {0,-1,5} | (1e+300,5) - (1e+300,Infinity) | {1,0,5} | + (1e+300,Infinity) | {1,0,5} | (-5,Infinity) (1e+300,Infinity) | {0,3,0} | (1e+300,0) - (1e+300,Infinity) | {1,-1,0} | (Infinity,NaN) - (1e+300,Infinity) | {-0.4,-1,-6} | (-Infinity,NaN) - (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,NaN) + (1e+300,Infinity) | {1,-1,0} | (Infinity,Infinity) + (1e+300,Infinity) | {-0.4,-1,-6} | (-Infinity,Infinity) + (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | (-Infinity,Infinity) (1e+300,Infinity) | {3,NaN,5} | (1e+300,Infinity) | {NaN,NaN,NaN} | (1e+300,Infinity) | {0,-1,3} | (1e+300,3) - (1e+300,Infinity) | {-1,0,3} | - (Infinity,1e+300) | {0,-1,5} | + (1e+300,Infinity) | {-1,0,3} | (3,Infinity) + (Infinity,1e+300) | {0,-1,5} | (Infinity,5) (Infinity,1e+300) | {1,0,5} | (-5,1e+300) - (Infinity,1e+300) | {0,3,0} | - (Infinity,1e+300) | {1,-1,0} | - (Infinity,1e+300) | {-0.4,-1,-6} | - (Infinity,1e+300) | {-0.000184615384615,-1,15.3846153846} | + (Infinity,1e+300) | {0,3,0} | (Infinity,0) + (Infinity,1e+300) | {1,-1,0} | (Infinity,Infinity) + (Infinity,1e+300) | {-0.4,-1,-6} | (Infinity,-Infinity) + (Infinity,1e+300) | {-0.000184615384615,-1,15.3846153846} | (Infinity,-Infinity) (Infinity,1e+300) | {3,NaN,5} | (Infinity,1e+300) | {NaN,NaN,NaN} | - (Infinity,1e+300) | {0,-1,3} | + (Infinity,1e+300) | {0,-1,3} | (Infinity,3) (Infinity,1e+300) | {-1,0,3} | (3,1e+300) (NaN,NaN) | {0,-1,5} | (NaN,NaN) | {1,0,5} | @@ -1168,7 +1168,7 @@ SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LSEG_TBL l; (1e+300,Infinity) | [(11,22),(33,44)] | (33,44) (1e+300,Infinity) | [(-10,2),(-10,3)] | (-10,3) (1e+300,Infinity) | [(0,-20),(30,-20)] | (30,-20) - (1e+300,Infinity) | [(NaN,1),(NaN,90)] | (NaN,90) + (1e+300,Infinity) | [(NaN,1),(NaN,90)] | (Infinity,1e+300) | [(1,2),(3,4)] | (3,4) (Infinity,1e+300) | [(0,0),(6,6)] | (6,6) (Infinity,1e+300) | [(10,-10),(-3,-4)] | (-3,-4) @@ -1278,12 +1278,7 @@ SELECT p.f1, p1.f1 FROM POINT_TBL p, PATH_TBL p1 WHERE p.f1 <@ p1.f1; ------------------+--------------------------- (0,0) | [(0,0),(3,0),(4,5),(1,6)] (1e-300,-1e-300) | [(0,0),(3,0),(4,5),(1,6)] - (NaN,NaN) | ((1,2),(3,4)) - (NaN,NaN) | ((1,2),(3,4)) - (NaN,NaN) | ((1,2),(3,4)) - (NaN,NaN) | ((10,20)) - (NaN,NaN) | ((11,12),(13,14)) -(7 rows) +(2 rows) -- -- Lines @@ -1371,8 +1366,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {0,-1,5} | {1,-1,0} | 0 {0,-1,5} | {-0.4,-1,-6} | 0 {0,-1,5} | {-0.000184615384615,-1,15.3846153846} | 0 - {0,-1,5} | {3,NaN,5} | 0 - {0,-1,5} | {NaN,NaN,NaN} | 0 + {0,-1,5} | {3,NaN,5} | NaN + {0,-1,5} | {NaN,NaN,NaN} | NaN {0,-1,5} | {0,-1,3} | 2 {0,-1,5} | {-1,0,3} | 0 {1,0,5} | {0,-1,5} | 0 @@ -1381,8 +1376,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {1,0,5} | {1,-1,0} | 0 {1,0,5} | {-0.4,-1,-6} | 0 {1,0,5} | {-0.000184615384615,-1,15.3846153846} | 0 - {1,0,5} | {3,NaN,5} | 0 - {1,0,5} | {NaN,NaN,NaN} | 0 + {1,0,5} | {3,NaN,5} | NaN + {1,0,5} | {NaN,NaN,NaN} | NaN {1,0,5} | {0,-1,3} | 0 {1,0,5} | {-1,0,3} | 8 {0,3,0} | {0,-1,5} | 5 @@ -1391,8 +1386,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {0,3,0} | {1,-1,0} | 0 {0,3,0} | {-0.4,-1,-6} | 0 {0,3,0} | {-0.000184615384615,-1,15.3846153846} | 0 - {0,3,0} | {3,NaN,5} | 0 - {0,3,0} | {NaN,NaN,NaN} | 0 + {0,3,0} | {3,NaN,5} | NaN + {0,3,0} | {NaN,NaN,NaN} | NaN {0,3,0} | {0,-1,3} | 3 {0,3,0} | {-1,0,3} | 0 {1,-1,0} | {0,-1,5} | 0 @@ -1401,8 +1396,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {1,-1,0} | {1,-1,0} | 0 {1,-1,0} | {-0.4,-1,-6} | 0 {1,-1,0} | {-0.000184615384615,-1,15.3846153846} | 0 - {1,-1,0} | {3,NaN,5} | 0 - {1,-1,0} | {NaN,NaN,NaN} | 0 + {1,-1,0} | {3,NaN,5} | NaN + {1,-1,0} | {NaN,NaN,NaN} | NaN {1,-1,0} | {0,-1,3} | 0 {1,-1,0} | {-1,0,3} | 0 {-0.4,-1,-6} | {0,-1,5} | 0 @@ -1411,8 +1406,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {-0.4,-1,-6} | {1,-1,0} | 0 {-0.4,-1,-6} | {-0.4,-1,-6} | 0 {-0.4,-1,-6} | {-0.000184615384615,-1,15.3846153846} | 0 - {-0.4,-1,-6} | {3,NaN,5} | 0 - {-0.4,-1,-6} | {NaN,NaN,NaN} | 0 + {-0.4,-1,-6} | {3,NaN,5} | NaN + {-0.4,-1,-6} | {NaN,NaN,NaN} | NaN {-0.4,-1,-6} | {0,-1,3} | 0 {-0.4,-1,-6} | {-1,0,3} | 0 {-0.000184615384615,-1,15.3846153846} | {0,-1,5} | 0 @@ -1421,38 +1416,38 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {-0.000184615384615,-1,15.3846153846} | {1,-1,0} | 0 {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6} | 0 {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | 0 - {-0.000184615384615,-1,15.3846153846} | {3,NaN,5} | 0 - {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN} | 0 + {-0.000184615384615,-1,15.3846153846} | {3,NaN,5} | NaN + {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN} | NaN {-0.000184615384615,-1,15.3846153846} | {0,-1,3} | 0 {-0.000184615384615,-1,15.3846153846} | {-1,0,3} | 0 - {3,NaN,5} | {0,-1,5} | 0 - {3,NaN,5} | {1,0,5} | 0 - {3,NaN,5} | {0,3,0} | 0 - {3,NaN,5} | {1,-1,0} | 0 - {3,NaN,5} | {-0.4,-1,-6} | 0 - {3,NaN,5} | {-0.000184615384615,-1,15.3846153846} | 0 - {3,NaN,5} | {3,NaN,5} | 0 - {3,NaN,5} | {NaN,NaN,NaN} | 0 - {3,NaN,5} | {0,-1,3} | 0 - {3,NaN,5} | {-1,0,3} | 0 - {NaN,NaN,NaN} | {0,-1,5} | 0 - {NaN,NaN,NaN} | {1,0,5} | 0 - {NaN,NaN,NaN} | {0,3,0} | 0 - {NaN,NaN,NaN} | {1,-1,0} | 0 - {NaN,NaN,NaN} | {-0.4,-1,-6} | 0 - {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} | 0 - {NaN,NaN,NaN} | {3,NaN,5} | 0 - {NaN,NaN,NaN} | {NaN,NaN,NaN} | 0 - {NaN,NaN,NaN} | {0,-1,3} | 0 - {NaN,NaN,NaN} | {-1,0,3} | 0 + {3,NaN,5} | {0,-1,5} | NaN + {3,NaN,5} | {1,0,5} | NaN + {3,NaN,5} | {0,3,0} | NaN + {3,NaN,5} | {1,-1,0} | NaN + {3,NaN,5} | {-0.4,-1,-6} | NaN + {3,NaN,5} | {-0.000184615384615,-1,15.3846153846} | NaN + {3,NaN,5} | {3,NaN,5} | NaN + {3,NaN,5} | {NaN,NaN,NaN} | NaN + {3,NaN,5} | {0,-1,3} | NaN + {3,NaN,5} | {-1,0,3} | NaN + {NaN,NaN,NaN} | {0,-1,5} | NaN + {NaN,NaN,NaN} | {1,0,5} | NaN + {NaN,NaN,NaN} | {0,3,0} | NaN + {NaN,NaN,NaN} | {1,-1,0} | NaN + {NaN,NaN,NaN} | {-0.4,-1,-6} | NaN + {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} | NaN + {NaN,NaN,NaN} | {3,NaN,5} | NaN + {NaN,NaN,NaN} | {NaN,NaN,NaN} | NaN + {NaN,NaN,NaN} | {0,-1,3} | NaN + {NaN,NaN,NaN} | {-1,0,3} | NaN {0,-1,3} | {0,-1,5} | 2 {0,-1,3} | {1,0,5} | 0 {0,-1,3} | {0,3,0} | 3 {0,-1,3} | {1,-1,0} | 0 {0,-1,3} | {-0.4,-1,-6} | 0 {0,-1,3} | {-0.000184615384615,-1,15.3846153846} | 0 - {0,-1,3} | {3,NaN,5} | 0 - {0,-1,3} | {NaN,NaN,NaN} | 0 + {0,-1,3} | {3,NaN,5} | NaN + {0,-1,3} | {NaN,NaN,NaN} | NaN {0,-1,3} | {0,-1,3} | 0 {0,-1,3} | {-1,0,3} | 0 {-1,0,3} | {0,-1,5} | 0 @@ -1461,8 +1456,8 @@ SELECT l1.s, l2.s, l1.s <-> l2.s FROM LINE_TBL l1, LINE_TBL l2; {-1,0,3} | {1,-1,0} | 0 {-1,0,3} | {-0.4,-1,-6} | 0 {-1,0,3} | {-0.000184615384615,-1,15.3846153846} | 0 - {-1,0,3} | {3,NaN,5} | 0 - {-1,0,3} | {NaN,NaN,NaN} | 0 + {-1,0,3} | {3,NaN,5} | NaN + {-1,0,3} | {NaN,NaN,NaN} | NaN {-1,0,3} | {0,-1,3} | 0 {-1,0,3} | {-1,0,3} | 0 (100 rows) @@ -1480,31 +1475,23 @@ SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s; {0,-1,5} | {1,-1,0} {0,-1,5} | {-0.4,-1,-6} {0,-1,5} | {-0.000184615384615,-1,15.3846153846} - {0,-1,5} | {3,NaN,5} - {0,-1,5} | {NaN,NaN,NaN} {0,-1,5} | {-1,0,3} {1,0,5} | {0,-1,5} {1,0,5} | {0,3,0} {1,0,5} | {1,-1,0} {1,0,5} | {-0.4,-1,-6} {1,0,5} | {-0.000184615384615,-1,15.3846153846} - {1,0,5} | {3,NaN,5} - {1,0,5} | {NaN,NaN,NaN} {1,0,5} | {0,-1,3} {0,3,0} | {1,0,5} {0,3,0} | {1,-1,0} {0,3,0} | {-0.4,-1,-6} {0,3,0} | {-0.000184615384615,-1,15.3846153846} - {0,3,0} | {3,NaN,5} - {0,3,0} | {NaN,NaN,NaN} {0,3,0} | {-1,0,3} {1,-1,0} | {0,-1,5} {1,-1,0} | {1,0,5} {1,-1,0} | {0,3,0} {1,-1,0} | {-0.4,-1,-6} {1,-1,0} | {-0.000184615384615,-1,15.3846153846} - {1,-1,0} | {3,NaN,5} - {1,-1,0} | {NaN,NaN,NaN} {1,-1,0} | {0,-1,3} {1,-1,0} | {-1,0,3} {-0.4,-1,-6} | {0,-1,5} @@ -1512,8 +1499,6 @@ SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s; {-0.4,-1,-6} | {0,3,0} {-0.4,-1,-6} | {1,-1,0} {-0.4,-1,-6} | {-0.000184615384615,-1,15.3846153846} - {-0.4,-1,-6} | {3,NaN,5} - {-0.4,-1,-6} | {NaN,NaN,NaN} {-0.4,-1,-6} | {0,-1,3} {-0.4,-1,-6} | {-1,0,3} {-0.000184615384615,-1,15.3846153846} | {0,-1,5} @@ -1521,46 +1506,20 @@ SELECT l1.s, l2.s FROM LINE_TBL l1, LINE_TBL l2 WHERE l1.s ?# l2.s; {-0.000184615384615,-1,15.3846153846} | {0,3,0} {-0.000184615384615,-1,15.3846153846} | {1,-1,0} {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6} - {-0.000184615384615,-1,15.3846153846} | {3,NaN,5} - {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN} {-0.000184615384615,-1,15.3846153846} | {0,-1,3} {-0.000184615384615,-1,15.3846153846} | {-1,0,3} - {3,NaN,5} | {0,-1,5} - {3,NaN,5} | {1,0,5} - {3,NaN,5} | {0,3,0} - {3,NaN,5} | {1,-1,0} - {3,NaN,5} | {-0.4,-1,-6} - {3,NaN,5} | {-0.000184615384615,-1,15.3846153846} - {3,NaN,5} | {3,NaN,5} - {3,NaN,5} | {NaN,NaN,NaN} - {3,NaN,5} | {0,-1,3} - {3,NaN,5} | {-1,0,3} - {NaN,NaN,NaN} | {0,-1,5} - {NaN,NaN,NaN} | {1,0,5} - {NaN,NaN,NaN} | {0,3,0} - {NaN,NaN,NaN} | {1,-1,0} - {NaN,NaN,NaN} | {-0.4,-1,-6} - {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} - {NaN,NaN,NaN} | {3,NaN,5} - {NaN,NaN,NaN} | {NaN,NaN,NaN} - {NaN,NaN,NaN} | {0,-1,3} - {NaN,NaN,NaN} | {-1,0,3} {0,-1,3} | {1,0,5} {0,-1,3} | {1,-1,0} {0,-1,3} | {-0.4,-1,-6} {0,-1,3} | {-0.000184615384615,-1,15.3846153846} - {0,-1,3} | {3,NaN,5} - {0,-1,3} | {NaN,NaN,NaN} {0,-1,3} | {-1,0,3} {-1,0,3} | {0,-1,5} {-1,0,3} | {0,3,0} {-1,0,3} | {1,-1,0} {-1,0,3} | {-0.4,-1,-6} {-1,0,3} | {-0.000184615384615,-1,15.3846153846} - {-1,0,3} | {3,NaN,5} - {-1,0,3} | {NaN,NaN,NaN} {-1,0,3} | {0,-1,3} -(84 rows) +(48 rows) -- Intersect with box SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1; @@ -1583,16 +1542,16 @@ SELECT l.s, b.f1 FROM LINE_TBL l, BOX_TBL b WHERE l.s ?# b.f1; -- Intersection point with line SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; - s | s | ?column? ----------------------------------------+---------------------------------------+----------------------------------- + s | s | ?column? +---------------------------------------+---------------------------------------+--------------------------------- {0,-1,5} | {0,-1,5} | {0,-1,5} | {1,0,5} | (-5,5) {0,-1,5} | {0,3,0} | {0,-1,5} | {1,-1,0} | (5,5) {0,-1,5} | {-0.4,-1,-6} | (-27.5,5) {0,-1,5} | {-0.000184615384615,-1,15.3846153846} | (56250,5) - {0,-1,5} | {3,NaN,5} | (NaN,NaN) - {0,-1,5} | {NaN,NaN,NaN} | (NaN,NaN) + {0,-1,5} | {3,NaN,5} | + {0,-1,5} | {NaN,NaN,NaN} | {0,-1,5} | {0,-1,3} | {0,-1,5} | {-1,0,3} | (3,5) {1,0,5} | {0,-1,5} | (-5,5) @@ -1601,8 +1560,8 @@ SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; {1,0,5} | {1,-1,0} | (-5,-5) {1,0,5} | {-0.4,-1,-6} | (-5,-4) {1,0,5} | {-0.000184615384615,-1,15.3846153846} | (-5,15.3855384615) - {1,0,5} | {3,NaN,5} | (NaN,NaN) - {1,0,5} | {NaN,NaN,NaN} | (NaN,NaN) + {1,0,5} | {3,NaN,5} | + {1,0,5} | {NaN,NaN,NaN} | {1,0,5} | {0,-1,3} | (-5,3) {1,0,5} | {-1,0,3} | {0,3,0} | {0,-1,5} | @@ -1611,8 +1570,8 @@ SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; {0,3,0} | {1,-1,0} | (0,0) {0,3,0} | {-0.4,-1,-6} | (-15,0) {0,3,0} | {-0.000184615384615,-1,15.3846153846} | (83333.3333333,0) - {0,3,0} | {3,NaN,5} | (NaN,NaN) - {0,3,0} | {NaN,NaN,NaN} | (NaN,NaN) + {0,3,0} | {3,NaN,5} | + {0,3,0} | {NaN,NaN,NaN} | {0,3,0} | {0,-1,3} | {0,3,0} | {-1,0,3} | (3,0) {1,-1,0} | {0,-1,5} | (5,5) @@ -1621,8 +1580,8 @@ SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; {1,-1,0} | {1,-1,0} | {1,-1,0} | {-0.4,-1,-6} | (-4.28571428571,-4.28571428571) {1,-1,0} | {-0.000184615384615,-1,15.3846153846} | (15.3817756722,15.3817756722) - {1,-1,0} | {3,NaN,5} | (NaN,NaN) - {1,-1,0} | {NaN,NaN,NaN} | (NaN,NaN) + {1,-1,0} | {3,NaN,5} | + {1,-1,0} | {NaN,NaN,NaN} | {1,-1,0} | {0,-1,3} | (3,3) {1,-1,0} | {-1,0,3} | (3,3) {-0.4,-1,-6} | {0,-1,5} | (-27.5,5) @@ -1631,48 +1590,48 @@ SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; {-0.4,-1,-6} | {1,-1,0} | (-4.28571428571,-4.28571428571) {-0.4,-1,-6} | {-0.4,-1,-6} | {-0.4,-1,-6} | {-0.000184615384615,-1,15.3846153846} | (-53.4862244113,15.3944897645) - {-0.4,-1,-6} | {3,NaN,5} | (NaN,NaN) - {-0.4,-1,-6} | {NaN,NaN,NaN} | (NaN,NaN) + {-0.4,-1,-6} | {3,NaN,5} | + {-0.4,-1,-6} | {NaN,NaN,NaN} | {-0.4,-1,-6} | {0,-1,3} | (-22.5,3) {-0.4,-1,-6} | {-1,0,3} | (3,-7.2) {-0.000184615384615,-1,15.3846153846} | {0,-1,5} | (56250,5) {-0.000184615384615,-1,15.3846153846} | {1,0,5} | (-5,15.3855384615) - {-0.000184615384615,-1,15.3846153846} | {0,3,0} | (83333.3333333,-1.7763568394e-15) + {-0.000184615384615,-1,15.3846153846} | {0,3,0} | (83333.3333333,0) {-0.000184615384615,-1,15.3846153846} | {1,-1,0} | (15.3817756722,15.3817756722) {-0.000184615384615,-1,15.3846153846} | {-0.4,-1,-6} | (-53.4862244113,15.3944897645) {-0.000184615384615,-1,15.3846153846} | {-0.000184615384615,-1,15.3846153846} | - {-0.000184615384615,-1,15.3846153846} | {3,NaN,5} | (NaN,NaN) - {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN} | (NaN,NaN) + {-0.000184615384615,-1,15.3846153846} | {3,NaN,5} | + {-0.000184615384615,-1,15.3846153846} | {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} | {0,-1,3} | (67083.3333333,3) {-0.000184615384615,-1,15.3846153846} | {-1,0,3} | (3,15.3840615385) - {3,NaN,5} | {0,-1,5} | (NaN,NaN) - {3,NaN,5} | {1,0,5} | (NaN,NaN) - {3,NaN,5} | {0,3,0} | (NaN,NaN) - {3,NaN,5} | {1,-1,0} | (NaN,NaN) - {3,NaN,5} | {-0.4,-1,-6} | (NaN,NaN) - {3,NaN,5} | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN) - {3,NaN,5} | {3,NaN,5} | (NaN,NaN) - {3,NaN,5} | {NaN,NaN,NaN} | (NaN,NaN) - {3,NaN,5} | {0,-1,3} | (NaN,NaN) - {3,NaN,5} | {-1,0,3} | (NaN,NaN) - {NaN,NaN,NaN} | {0,-1,5} | (NaN,NaN) - {NaN,NaN,NaN} | {1,0,5} | (NaN,NaN) - {NaN,NaN,NaN} | {0,3,0} | (NaN,NaN) - {NaN,NaN,NaN} | {1,-1,0} | (NaN,NaN) - {NaN,NaN,NaN} | {-0.4,-1,-6} | (NaN,NaN) - {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} | (NaN,NaN) - {NaN,NaN,NaN} | {3,NaN,5} | (NaN,NaN) - {NaN,NaN,NaN} | {NaN,NaN,NaN} | (NaN,NaN) - {NaN,NaN,NaN} | {0,-1,3} | (NaN,NaN) - {NaN,NaN,NaN} | {-1,0,3} | (NaN,NaN) + {3,NaN,5} | {0,-1,5} | + {3,NaN,5} | {1,0,5} | + {3,NaN,5} | {0,3,0} | + {3,NaN,5} | {1,-1,0} | + {3,NaN,5} | {-0.4,-1,-6} | + {3,NaN,5} | {-0.000184615384615,-1,15.3846153846} | + {3,NaN,5} | {3,NaN,5} | + {3,NaN,5} | {NaN,NaN,NaN} | + {3,NaN,5} | {0,-1,3} | + {3,NaN,5} | {-1,0,3} | + {NaN,NaN,NaN} | {0,-1,5} | + {NaN,NaN,NaN} | {1,0,5} | + {NaN,NaN,NaN} | {0,3,0} | + {NaN,NaN,NaN} | {1,-1,0} | + {NaN,NaN,NaN} | {-0.4,-1,-6} | + {NaN,NaN,NaN} | {-0.000184615384615,-1,15.3846153846} | + {NaN,NaN,NaN} | {3,NaN,5} | + {NaN,NaN,NaN} | {NaN,NaN,NaN} | + {NaN,NaN,NaN} | {0,-1,3} | + {NaN,NaN,NaN} | {-1,0,3} | {0,-1,3} | {0,-1,5} | {0,-1,3} | {1,0,5} | (-5,3) {0,-1,3} | {0,3,0} | {0,-1,3} | {1,-1,0} | (3,3) {0,-1,3} | {-0.4,-1,-6} | (-22.5,3) {0,-1,3} | {-0.000184615384615,-1,15.3846153846} | (67083.3333333,3) - {0,-1,3} | {3,NaN,5} | (NaN,NaN) - {0,-1,3} | {NaN,NaN,NaN} | (NaN,NaN) + {0,-1,3} | {3,NaN,5} | + {0,-1,3} | {NaN,NaN,NaN} | {0,-1,3} | {0,-1,3} | {0,-1,3} | {-1,0,3} | (3,3) {-1,0,3} | {0,-1,5} | (3,5) @@ -1681,16 +1640,16 @@ SELECT l1.s, l2.s, l1.s # l2.s FROM LINE_TBL l1, LINE_TBL l2; {-1,0,3} | {1,-1,0} | (3,3) {-1,0,3} | {-0.4,-1,-6} | (3,-7.2) {-1,0,3} | {-0.000184615384615,-1,15.3846153846} | (3,15.3840615385) - {-1,0,3} | {3,NaN,5} | (NaN,NaN) - {-1,0,3} | {NaN,NaN,NaN} | (NaN,NaN) + {-1,0,3} | {3,NaN,5} | + {-1,0,3} | {NaN,NaN,NaN} | {-1,0,3} | {0,-1,3} | (3,3) {-1,0,3} | {-1,0,3} | (100 rows) -- Closest point to line segment SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1; - s | s | ?column? ----------------------------------------+-------------------------------+----------------------------------- + s | s | ?column? +---------------------------------------+-------------------------------+-------------------------------- {0,-1,5} | [(1,2),(3,4)] | (3,4) {0,-1,5} | [(0,0),(6,6)] | (5,5) {0,-1,5} | [(10,-10),(-3,-4)] | (-3,-4) @@ -1710,7 +1669,7 @@ SELECT l.s, l1.s, l.s ## l1.s FROM LINE_TBL l, LSEG_TBL l1; {0,3,0} | [(1,2),(3,4)] | (1,2) {0,3,0} | [(0,0),(6,6)] | (0,0) {0,3,0} | [(10,-10),(-3,-4)] | (-3,-4) - {0,3,0} | [(-1000000,200),(300000,-40)] | (83333.3333333,-1.7763568394e-15) + {0,3,0} | [(-1000000,200),(300000,-40)] | (83333.3333333,0) {0,3,0} | [(11,22),(33,44)] | (11,22) {0,3,0} | [(-10,2),(-10,3)] | (-10,2) {0,3,0} | [(0,-20),(30,-20)] | @@ -3735,13 +3694,13 @@ SELECT p.f1, poly.f1, poly.f1 @> p.f1 AS contains (Infinity,1e+300) | ((1,2),(7,8),(5,6),(3,-4)) | f (Infinity,1e+300) | ((0,0)) | f (Infinity,1e+300) | ((0,1),(0,1)) | f - (NaN,NaN) | ((2,0),(2,4),(0,0)) | t - (NaN,NaN) | ((3,1),(3,3),(1,0)) | t - (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | t - (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | t - (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | t - (NaN,NaN) | ((0,0)) | t - (NaN,NaN) | ((0,1),(0,1)) | t + (NaN,NaN) | ((2,0),(2,4),(0,0)) | f + (NaN,NaN) | ((3,1),(3,3),(1,0)) | f + (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | f + (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | f + (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | f + (NaN,NaN) | ((0,0)) | f + (NaN,NaN) | ((0,1),(0,1)) | f (10,10) | ((2,0),(2,4),(0,0)) | f (10,10) | ((3,1),(3,3),(1,0)) | f (10,10) | ((1,2),(3,4),(5,6),(7,8)) | f @@ -3811,13 +3770,13 @@ SELECT p.f1, poly.f1, p.f1 <@ poly.f1 AS contained (Infinity,1e+300) | ((1,2),(7,8),(5,6),(3,-4)) | f (Infinity,1e+300) | ((0,0)) | f (Infinity,1e+300) | ((0,1),(0,1)) | f - (NaN,NaN) | ((2,0),(2,4),(0,0)) | t - (NaN,NaN) | ((3,1),(3,3),(1,0)) | t - (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | t - (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | t - (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | t - (NaN,NaN) | ((0,0)) | t - (NaN,NaN) | ((0,1),(0,1)) | t + (NaN,NaN) | ((2,0),(2,4),(0,0)) | f + (NaN,NaN) | ((3,1),(3,3),(1,0)) | f + (NaN,NaN) | ((1,2),(3,4),(5,6),(7,8)) | f + (NaN,NaN) | ((7,8),(5,6),(3,4),(1,2)) | f + (NaN,NaN) | ((1,2),(7,8),(5,6),(3,-4)) | f + (NaN,NaN) | ((0,0)) | f + (NaN,NaN) | ((0,1),(0,1)) | f (10,10) | ((2,0),(2,4),(0,0)) | f (10,10) | ((3,1),(3,3),(1,0)) | f (10,10) | ((1,2),(3,4),(5,6),(7,8)) | f -- 2.27.0