int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout) { if ( ( ! g1 ) && ( ! g2 ) ) return LW_FALSE; if ( ! g1 ) { memcpy(gout, g2, sizeof(GBOX)); return LW_TRUE; } if ( ! g2 ) { memcpy(gout, g1, sizeof(GBOX)); return LW_TRUE; } gout->flags = g1->flags; gout->xmin = FP_MIN(g1->xmin, g2->xmin); gout->xmax = FP_MAX(g1->xmax, g2->xmax); gout->ymin = FP_MIN(g1->ymin, g2->ymin); gout->ymax = FP_MAX(g1->ymax, g2->ymax); gout->zmin = FP_MIN(g1->zmin, g2->zmin); gout->zmax = FP_MAX(g1->zmax, g2->zmax); return LW_TRUE; }
static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox) { int rv; LWDEBUG(2, "lw_arc_calculate_gbox_cartesian called."); rv = lw_arc_calculate_gbox_cartesian_2d((POINT2D*)p1, (POINT2D*)p2, (POINT2D*)p3, gbox); gbox->zmin = FP_MIN(p1->z, p3->z); gbox->mmin = FP_MIN(p1->m, p3->m); gbox->zmax = FP_MAX(p1->z, p3->z); gbox->mmax = FP_MAX(p1->m, p3->m); return rv; }
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox ) { int i; POINT4D p; int has_z, has_m; if ( ! pa ) return LW_FAILURE; if ( ! gbox ) return LW_FAILURE; if ( pa->npoints < 1 ) return LW_FAILURE; has_z = FLAGS_GET_Z(pa->flags); has_m = FLAGS_GET_M(pa->flags); gbox->flags = gflags(has_z, has_m, 0); LWDEBUGF(4, "ptarray_calculate_gbox Z: %d M: %d", has_z, has_m); getPoint4d_p(pa, 0, &p); gbox->xmin = gbox->xmax = p.x; gbox->ymin = gbox->ymax = p.y; if ( has_z ) gbox->zmin = gbox->zmax = p.z; if ( has_m ) gbox->mmin = gbox->mmax = p.m; for ( i = 1 ; i < pa->npoints; i++ ) { getPoint4d_p(pa, i, &p); gbox->xmin = FP_MIN(gbox->xmin, p.x); gbox->xmax = FP_MAX(gbox->xmax, p.x); gbox->ymin = FP_MIN(gbox->ymin, p.y); gbox->ymax = FP_MAX(gbox->ymax, p.y); if ( has_z ) { gbox->zmin = FP_MIN(gbox->zmin, p.z); gbox->zmax = FP_MAX(gbox->zmax, p.z); } if ( has_m ) { gbox->mmin = FP_MIN(gbox->mmin, p.m); gbox->mmax = FP_MAX(gbox->mmax, p.m); } } return LW_SUCCESS; }
int lw_segment_envelope_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2) { double minq=FP_MIN(q1->x,q2->x); double maxq=FP_MAX(q1->x,q2->x); double minp=FP_MIN(p1->x,p2->x); double maxp=FP_MAX(p1->x,p2->x); if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) return LW_FALSE; minq=FP_MIN(q1->y,q2->y); maxq=FP_MAX(q1->y,q2->y); minp=FP_MIN(p1->y,p2->y); maxp=FP_MAX(p1->y,p2->y); if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) return LW_FALSE; return LW_TRUE; }
/** * This function doesn't work for edges crossing the dateline or in the southern * hemisphere. Points are pre-conditioned in ptarray_area_spheroid. */ static double spheroid_striparea(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, double latitude_min, const SPHEROID *spheroid) { GEOGRAPHIC_POINT A, B, mL, nR; double deltaLng, baseArea, topArea; double bE, tE, ratio, sign; A = *a; B = *b; mL.lat = latitude_min; mL.lon = FP_MIN(A.lon, B.lon); nR.lat = FP_MIN(A.lat, B.lat); nR.lon = FP_MAX(A.lon, B.lon); LWDEBUGF(4, "mL (%.12g %.12g)", mL.lat, mL.lon); LWDEBUGF(4, "nR (%.12g %.12g)", nR.lat, nR.lon); baseArea = spheroid_boundingbox_area(&mL, &nR, spheroid); LWDEBUGF(4, "baseArea %.12g", baseArea); mL.lat = FP_MIN(A.lat, B.lat); mL.lon = FP_MIN(A.lon, B.lon); nR.lat = FP_MAX(A.lat, B.lat); nR.lon = FP_MAX(A.lon, B.lon); LWDEBUGF(4, "mL (%.12g %.12g)", mL.lat, mL.lon); LWDEBUGF(4, "nR (%.12g %.12g)", nR.lat, nR.lon); topArea = spheroid_boundingbox_area(&mL, &nR, spheroid); LWDEBUGF(4, "topArea %.12g", topArea); deltaLng = B.lon - A.lon; LWDEBUGF(4, "deltaLng %.12g", deltaLng); bE = spheroid_parallel_arc_length(A.lat, deltaLng, spheroid); tE = spheroid_parallel_arc_length(B.lat, deltaLng, spheroid); LWDEBUGF(4, "bE %.12g", bE); LWDEBUGF(4, "tE %.12g", tE); ratio = (bE + tE)/tE; sign = signum(B.lon - A.lon); return (baseArea + topArea / ratio) * sign; }
int ptarray_calculate_gbox(const POINTARRAY *pa, GBOX *gbox ) { int i; POINT4D p; int has_z = FLAGS_GET_Z(gbox->flags); int has_m = FLAGS_GET_M(gbox->flags); if ( ! pa ) return G_FAILURE; if ( pa->npoints < 1 ) return G_FAILURE; getPoint4d_p(pa, 0, &p); gbox->xmin = gbox->xmax = p.x; gbox->ymin = gbox->ymax = p.y; if ( has_z ) gbox->zmin = gbox->zmax = p.z; if ( has_m ) gbox->mmin = gbox->mmax = p.m; for ( i = 1 ; i < pa->npoints; i++ ) { getPoint4d_p(pa, i, &p); gbox->xmin = FP_MIN(gbox->xmin, p.x); gbox->xmax = FP_MAX(gbox->xmax, p.x); gbox->ymin = FP_MIN(gbox->ymin, p.y); gbox->ymax = FP_MAX(gbox->ymax, p.y); if ( has_z ) { gbox->zmin = FP_MIN(gbox->zmin, p.z); gbox->zmax = FP_MAX(gbox->zmax, p.z); } if ( has_m ) { gbox->mmin = FP_MIN(gbox->mmin, p.m); gbox->mmax = FP_MAX(gbox->mmax, p.m); } } return G_SUCCESS; }
static int segment_locate_along(const POINT4D *p1, const POINT4D *p2, double m, double offset, POINT4D *pn) { double m1 = p1->m; double m2 = p2->m; double mprop; /* M is out of range, no new point generated. */ if ( (m < FP_MIN(m1,m2)) || (m > FP_MAX(m1,m2)) ) { return LW_FALSE; } /* We'll just can out on this degenerate case for now. Correct behavior is probably an mprop of 0.5? Still would have to deal with case of true p1==p2. */ if( m1 == m2 ) { lwerror("Zero measure-length line encountered!"); } /* M is in range, new point to be generated. */ mprop = (m - m1) / (m2 - m1); pn->x = p1->x + (p2->x - p1->x) * mprop; pn->y = p1->y + (p2->y - p1->y) * mprop; pn->z = p1->z + (p2->z - p1->z) * mprop; pn->m = m; /* Offset to the left or right, if necessary. */ if ( offset != 0.0 ) { double theta = atan2(p2->y - p1->y, p2->x - p1->x); pn->x -= sin(theta) * offset; pn->y += cos(theta) * offset; } return LW_TRUE; }
/** * Given two points, a dimensionality, an ordinate, and an interpolation value * generate a new point that is proportionally between the input points, * using the values in the provided dimension as the scaling factors. */ int point_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz, int hasm, char ordinate, double interpolation_value) { static char* dims = "XYZM"; double p1_value = lwpoint_get_ordinate(p1, ordinate); double p2_value = lwpoint_get_ordinate(p2, ordinate); double proportion; int i = 0; if ( ! ( ordinate == 'X' || ordinate == 'Y' || ordinate == 'Z' || ordinate == 'M' ) ) { lwerror("Cannot set %c ordinate.", ordinate); return 0; } if ( FP_MIN(p1_value, p2_value) > interpolation_value || FP_MAX(p1_value, p2_value) < interpolation_value ) { lwerror("Cannot interpolate to a value (%g) not between the input points (%g, %g).", interpolation_value, p1_value, p2_value); return 0; } proportion = fabs((interpolation_value - p1_value) / (p2_value - p1_value)); for ( i = 0; i < 4; i++ ) { double newordinate = 0.0; if ( dims[i] == 'Z' && ! hasz ) continue; if ( dims[i] == 'M' && ! hasm ) continue; p1_value = lwpoint_get_ordinate(p1, dims[i]); p2_value = lwpoint_get_ordinate(p2, dims[i]); newordinate = p1_value + proportion * (p2_value - p1_value); lwpoint_set_ordinate(p, dims[i], newordinate); LWDEBUGF(4, " clip ordinate(%c) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) ", dims[i], p1_value, p2_value, proportion, newordinate ); } return 1; }
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox) { POINT2D xmin, ymin, xmax, ymax; POINT2D C; int A2_side; double radius_A; LWDEBUG(2, "lw_arc_calculate_gbox_cartesian_2d called."); radius_A = lw_arc_center(A1, A2, A3, &C); /* Negative radius signals straight line, p1/p2/p3 are colinear */ if (radius_A < 0.0) { gbox->xmin = FP_MIN(A1->x, A3->x); gbox->ymin = FP_MIN(A1->y, A3->y); gbox->xmax = FP_MAX(A1->x, A3->x); gbox->ymax = FP_MAX(A1->y, A3->y); return LW_SUCCESS; } /* Matched start/end points imply circle */ if ( A1->x == A3->x && A1->y == A3->y ) { gbox->xmin = C.x - radius_A; gbox->ymin = C.y - radius_A; gbox->xmax = C.x + radius_A; gbox->ymax = C.y + radius_A; return LW_SUCCESS; } /* First approximation, bounds of start/end points */ gbox->xmin = FP_MIN(A1->x, A3->x); gbox->ymin = FP_MIN(A1->y, A3->y); gbox->xmax = FP_MAX(A1->x, A3->x); gbox->ymax = FP_MAX(A1->y, A3->y); /* Create points for the possible extrema */ xmin.x = C.x - radius_A; xmin.y = C.y; ymin.x = C.x; ymin.y = C.y - radius_A; xmax.x = C.x + radius_A; xmax.y = C.y; ymax.x = C.x; ymax.y = C.y + radius_A; /* Divide the circle into two parts, one on each side of a line joining p1 and p3. The circle extrema on the same side of that line as p2 is on, are also the extrema of the bbox. */ A2_side = lw_segment_side(A1, A3, A2); if ( A2_side == lw_segment_side(A1, A3, &xmin) ) gbox->xmin = xmin.x; if ( A2_side == lw_segment_side(A1, A3, &ymin) ) gbox->ymin = ymin.y; if ( A2_side == lw_segment_side(A1, A3, &xmax) ) gbox->xmax = xmax.x; if ( A2_side == lw_segment_side(A1, A3, &ymax) ) gbox->ymax = ymax.y; return LW_SUCCESS; }
/* static int lwcircle_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox) */ BOX3D * lwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3) { POINT2D xmin, ymin, xmax, ymax; POINT4D *center = NULL; int p2_side = 0; double radius = 0.0; LWDEBUG(2, "lwcircle_compute_box3d called."); radius = lwcircle_center(p1, p2, p3, ¢er); BOX3D *box = lwalloc(sizeof(BOX3D)); /* Negative radius signals straight line, p1/p2/p3 are colinear */ if (radius < 0.0) { if ( center ) lwfree(center); box->xmin = FP_MIN(p1->x, p3->x); box->ymin = FP_MIN(p1->y, p3->y); box->zmin = FP_MIN(p1->z, p3->z); box->xmax = FP_MAX(p1->x, p3->x); box->ymax = FP_MAX(p1->y, p3->y); box->zmax = FP_MAX(p1->z, p3->z); return box; } /* Matched start/end points imply circle */ if ( p1->x == p3->x && p1->y == p3->y ) { box->xmin = center->x - radius; box->ymin = center->y - radius; box->zmin = FP_MIN(p1->z,p2->z); box->xmax = center->x + radius; box->ymax = center->y + radius; box->zmax = FP_MAX(p1->z,p2->z); lwfree(center); return box; } /* First approximation, bounds of start/end points */ box->xmin = FP_MIN(p1->x, p3->x); box->ymin = FP_MIN(p1->y, p3->y); box->zmin = FP_MIN(p1->z, p3->z); box->xmax = FP_MAX(p1->x, p3->x); box->ymax = FP_MAX(p1->y, p3->y); box->zmax = FP_MAX(p1->z, p3->z); /* Create points for the possible extrema */ xmin.x = center->x - radius; xmin.y = center->y; ymin.x = center->x; ymin.y = center->y - radius; xmax.x = center->x + radius; xmax.y = center->y; ymax.x = center->x; ymax.y = center->y + radius; /* Divide the circle into two parts, one on each side of a line joining p1 and p3. The circle extrema on the same side of that line as p2 is on, are also the extrema of the bbox. */ p2_side = signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, (POINT2D*)p2)); if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmin)) ) box->xmin = xmin.x; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymin)) ) box->ymin = ymin.y; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmax)) ) box->xmax = xmax.x; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymax)) ) box->ymax = ymax.y; lwfree(center); return box; }
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number) { int wn = 0; int i, side; const POINT2D *seg1; const POINT2D *seg2; const POINT2D *seg3; GBOX gbox; /* Check for not an arc ring (always have odd # of points) */ if ( (pa->npoints % 2) == 0 ) { lwerror("ptarrayarc_contains_point called with even number of points"); return LW_OUTSIDE; } /* Check for not an arc ring (always have >= 3 points) */ if ( pa->npoints < 3 ) { lwerror("ptarrayarc_contains_point called too-short pointarray"); return LW_OUTSIDE; } /* Check for unclosed case */ seg1 = getPoint2d_cp(pa, 0); seg3 = getPoint2d_cp(pa, pa->npoints-1); if ( check_closed && ! p2d_same(seg1, seg3) ) { lwerror("ptarrayarc_contains_point called on unclosed ring"); return LW_OUTSIDE; } /* OK, it's closed. Is it just one circle? */ else if ( p2d_same(seg1, seg3) && pa->npoints == 3 ) { double radius, d; POINT2D c; seg2 = getPoint2d_cp(pa, 1); /* Wait, it's just a point, so it can't contain anything */ if ( lw_arc_is_pt(seg1, seg2, seg3) ) return LW_OUTSIDE; /* See if the point is within the circle radius */ radius = lw_arc_center(seg1, seg2, seg3, &c); d = distance2d_pt_pt(pt, &c); if ( FP_EQUALS(d, radius) ) return LW_BOUNDARY; /* Boundary of circle */ else if ( d < radius ) return LW_INSIDE; /* Inside circle */ else return LW_OUTSIDE; /* Outside circle */ } else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) ) { return LW_BOUNDARY; /* Boundary case */ } /* Start on the ring */ seg1 = getPoint2d_cp(pa, 0); for ( i=1; i < pa->npoints; i += 2 ) { seg2 = getPoint2d_cp(pa, i); seg3 = getPoint2d_cp(pa, i+1); /* Catch an easy boundary case */ if( p2d_same(seg3, pt) ) return LW_BOUNDARY; /* Skip arcs that have no size */ if ( lw_arc_is_pt(seg1, seg2, seg3) ) { seg1 = seg3; continue; } /* Only test segments in our vertical range */ lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox); if ( pt->y > gbox.ymax || pt->y < gbox.ymin ) { seg1 = seg3; continue; } /* Outside of horizontal range, and not between end points we also skip */ if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) && (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) ) { seg1 = seg3; continue; } side = lw_arc_side(seg1, seg2, seg3, pt); /* On the boundary */ if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) ) { return LW_BOUNDARY; } /* Going "up"! Point to left of arc. */ if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) ) { wn++; } /* Going "down"! */ if ( side > 0 && (seg2->y <= pt->y) && (pt->y < seg1->y) ) { wn--; } /* Inside the arc! */ if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin ) { POINT2D C; double radius = lw_arc_center(seg1, seg2, seg3, &C); double d = distance2d_pt_pt(pt, &C); /* On the boundary! */ if ( d == radius ) return LW_BOUNDARY; /* Within the arc! */ if ( d < radius ) { /* Left side, increment winding number */ if ( side < 0 ) wn++; /* Right side, decrement winding number */ if ( side > 0 ) wn--; } } seg1 = seg3; } /* Sent out the winding number for calls that are building on this as a primitive */ if ( winding_number ) *winding_number = wn; /* Outside */ if (wn == 0) { return LW_OUTSIDE; } /* Inside */ return LW_INSIDE; }
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number) { int wn = 0; int i; double side; const POINT2D *seg1; const POINT2D *seg2; double ymin, ymax; seg1 = getPoint2d_cp(pa, 0); seg2 = getPoint2d_cp(pa, pa->npoints-1); if ( check_closed && ! p2d_same(seg1, seg2) ) lwerror("ptarray_contains_point called on unclosed ring"); for ( i=1; i < pa->npoints; i++ ) { seg2 = getPoint2d_cp(pa, i); /* Zero length segments are ignored. */ if ( seg1->x == seg2->x && seg1->y == seg2->y ) { seg1 = seg2; continue; } ymin = FP_MIN(seg1->y, seg2->y); ymax = FP_MAX(seg1->y, seg2->y); /* Only test segments in our vertical range */ if ( pt->y > ymax || pt->y < ymin ) { seg1 = seg2; continue; } side = lw_segment_side(seg1, seg2, pt); /* * A point on the boundary of a ring is not contained. * WAS: if (fabs(side) < 1e-12), see #852 */ if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) ) { return LW_BOUNDARY; } /* * If the point is to the left of the line, and it's rising, * then the line is to the right of the point and * circling counter-clockwise, so incremement. */ if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) ) { wn++; } /* * If the point is to the right of the line, and it's falling, * then the line is to the right of the point and circling * clockwise, so decrement. */ else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) ) { wn--; } seg1 = seg2; } /* Sent out the winding number for calls that are building on this as a primitive */ if ( winding_number ) *winding_number = wn; /* Outside */ if (wn == 0) { return LW_OUTSIDE; } /* Inside */ return LW_INSIDE; }
static int lwcircle_calculate_gbox(POINT4D p1, POINT4D p2, POINT4D p3, GBOX *gbox) { double x1, x2, y1, y2, z1, z2, m1, m2; double angle, radius, sweep; /* angles from center */ double a1, a2, a3; /* angles from center once a1 is rotated to zero */ double r2, r3; double xe = 0.0, ye = 0.0; POINT4D *center; int i; LWDEBUG(2, "lwcircle_calculate_gbox called."); radius = lwcircle_center(&p1, &p2, &p3, ¢er); if (radius < 0.0) return G_FAILURE; x1 = MAXFLOAT; x2 = -1 * MAXFLOAT; y1 = MAXFLOAT; y2 = -1 * MAXFLOAT; a1 = atan2(p1.y - center->y, p1.x - center->x); a2 = atan2(p2.y - center->y, p2.x - center->x); a3 = atan2(p3.y - center->y, p3.x - center->x); /* Rotate a2 and a3 such that a1 = 0 */ r2 = a2 - a1; r3 = a3 - a1; /* * There are six cases here I'm interested in * Clockwise: * 1. a1-a2 < 180 == r2 < 0 && (r3 > 0 || r3 < r2) * 2. a1-a2 > 180 == r2 > 0 && (r3 > 0 && r3 < r2) * 3. a1-a2 > 180 == r2 > 0 && (r3 > r2 || r3 < 0) * Counter-clockwise: * 4. a1-a2 < 180 == r2 > 0 && (r3 < 0 || r3 > r2) * 5. a1-a2 > 180 == r2 < 0 && (r3 < 0 && r3 > r2) * 6. a1-a2 > 180 == r2 < 0 && (r3 < r2 || r3 > 0) * 3 and 6 are invalid cases where a3 is the midpoint. * BBOX is fundamental, so these cannot error out and will instead * calculate the sweep using a3 as the middle point. */ /* clockwise 1 */ if (FP_LT(r2, 0) && (FP_GT(r3, 0) || FP_LT(r3, r2))) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* clockwise 2 */ else if (FP_GT(r2, 0) && FP_GT(r3, 0) && FP_LT(r3, r2)) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* counter-clockwise 4 */ else if (FP_GT(r2, 0) && (FP_LT(r3, 0) || FP_GT(r3, r2))) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* counter-clockwise 5 */ else if (FP_LT(r2, 0) && FP_LT(r3, 0) && FP_GT(r3, r2)) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* clockwise invalid 3 */ else if (FP_GT(r2, 0) && (FP_GT(r3, r2) || FP_LT(r3, 0))) { sweep = (FP_GT(r2, 0)) ? (r2 - 2 * M_PI) : r2; } /* clockwise invalid 6 */ else { sweep = (FP_LT(r2, 0)) ? (r2 + 2 * M_PI) : r2; } LWDEBUGF(3, "a1 %.16f, a2 %.16f, a3 %.16f, sweep %.16f", a1, a2, a3, sweep); angle = 0.0; for (i=0; i < 6; i++) { switch (i) { /* right extent */ case 0: angle = 0.0; xe = center->x + radius; ye = center->y; break; /* top extent */ case 1: angle = M_PI_2; xe = center->x; ye = center->y + radius; break; /* left extent */ case 2: angle = M_PI; xe = center->x - radius; ye = center->y; break; /* bottom extent */ case 3: angle = -1 * M_PI_2; xe = center->x; ye = center->y - radius; break; /* first point */ case 4: angle = a1; xe = p1.x; ye = p1.y; break; /* last point */ case 5: angle = a3; xe = p3.x; ye = p3.y; break; } /* determine if the extents are outside the arc */ if (i < 4) { if (FP_GT(sweep, 0.0)) { if (FP_LT(a3, a1)) { if (FP_GT(angle, (a3 + 2 * M_PI)) || FP_LT(angle, a1)) continue; } else { if (FP_GT(angle, a3) || FP_LT(angle, a1)) continue; } } else { if (FP_GT(a3, a1)) { if (FP_LT(angle, (a3 - 2 * M_PI)) || FP_GT(angle, a1)) continue; } else { if (FP_LT(angle, a3) || FP_GT(angle, a1)) continue; } } } LWDEBUGF(3, "lwcircle_calculate_gbox: potential extreame %d (%.16f, %.16f)", i, xe, ye); x1 = (FP_LT(x1, xe)) ? x1 : xe; y1 = (FP_LT(y1, ye)) ? y1 : ye; x2 = (FP_GT(x2, xe)) ? x2 : xe; y2 = (FP_GT(y2, ye)) ? y2 : ye; } LWDEBUGF(3, "lwcircle_calculate_gbox: extreames found (%.16f %.16f, %.16f %.16f)", x1, y1, x2, y2); z1 = FP_MIN(p1.z, p2.z); z1 = FP_MIN(z1, p3.z); z2 = FP_MAX(p1.z, p2.z); z2 = FP_MAX(z2, p3.z); m1 = FP_MIN(p1.m, p2.m); m1 = FP_MIN(m1, p3.m); m2 = FP_MAX(p1.m, p2.m); m2 = FP_MAX(m2, p3.m); gbox->xmin = x1; gbox->xmax = x2; gbox->ymin = y1; gbox->ymax = y2; if ( FLAGS_GET_Z(gbox->flags) ) { gbox->zmin = z1; gbox->zmax = z2; } if ( FLAGS_GET_M(gbox->flags) ) { gbox->mmin = m1; gbox->mmax = m2; } return G_SUCCESS; }
/* * Populate a bounding box *without* allocating an LWGEOM. Useful * for some performance purposes. */ static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox) { uint32_t type = gserialized_get_type(g); /* Peeking doesn't help if you already have a box or are geodetic */ if ( FLAGS_GET_GEODETIC(g->flags) || FLAGS_GET_BBOX(g->flags) ) { return LW_FAILURE; } /* Boxes of points are easy peasy */ if ( type == POINTTYPE ) { int i = 1; /* Start past <pointtype><padding> */ double *dptr = (double*)(g->data); /* Read the empty flag */ int *iptr = (int*)(g->data); int isempty = (iptr[1] == 0); /* EMPTY point has no box */ if ( isempty ) return LW_FAILURE; gbox->xmin = gbox->xmax = dptr[i++]; gbox->ymin = gbox->ymax = dptr[i++]; if ( FLAGS_GET_Z(g->flags) ) { gbox->zmin = gbox->zmax = dptr[i++]; } if ( FLAGS_GET_M(g->flags) ) { gbox->mmin = gbox->mmax = dptr[i++]; } gbox_float_round(gbox); return LW_SUCCESS; } /* We can calculate the box of a two-point cartesian line trivially */ else if ( type == LINETYPE ) { int ndims = FLAGS_NDIMS(g->flags); int i = 0; /* Start at <linetype><npoints> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int npoints = iptr[1]; /* Read the npoints */ /* This only works with 2-point lines */ if ( npoints != 2 ) return LW_FAILURE; /* Advance to X */ /* Past <linetype><npoints> */ i++; gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]); /* Advance to Y */ i++; gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]); if ( FLAGS_GET_Z(g->flags) ) { /* Advance to Z */ i++; gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]); } if ( FLAGS_GET_M(g->flags) ) { /* Advance to M */ i++; gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]); } gbox_float_round(gbox); return LW_SUCCESS; } /* We can also do single-entry multi-points */ else if ( type == MULTIPOINTTYPE ) { int i = 0; /* Start at <multipointtype><ngeoms> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int ngeoms = iptr[1]; /* Read the ngeoms */ /* This only works with single-entry multipoints */ if ( ngeoms != 1 ) return LW_FAILURE; /* Move forward two doubles (four ints) */ /* Past <multipointtype><ngeoms> */ /* Past <pointtype><emtpyflat> */ i += 2; /* Read the doubles from the one point */ gbox->xmin = gbox->xmax = dptr[i++]; gbox->ymin = gbox->ymax = dptr[i++]; if ( FLAGS_GET_Z(g->flags) ) { gbox->zmin = gbox->zmax = dptr[i++]; } if ( FLAGS_GET_M(g->flags) ) { gbox->mmin = gbox->mmax = dptr[i++]; } gbox_float_round(gbox); return LW_SUCCESS; } /* And we can do single-entry multi-lines with two vertices (!!!) */ else if ( type == MULTILINETYPE ) { int ndims = FLAGS_NDIMS(g->flags); int i = 0; /* Start at <multilinetype><ngeoms> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int ngeoms = iptr[1]; /* Read the ngeoms */ int npoints; /* This only works with 1-line multilines */ if ( ngeoms != 1 ) return LW_FAILURE; /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */ npoints = iptr[3]; if ( npoints != 2 ) return LW_FAILURE; /* Advance to X */ /* Move forward two doubles (four ints) */ /* Past <multilinetype><ngeoms> */ /* Past <linetype><npoints> */ i += 2; gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]); /* Advance to Y */ i++; gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]); if ( FLAGS_GET_Z(g->flags) ) { /* Advance to Z */ i++; gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]); } if ( FLAGS_GET_M(g->flags) ) { /* Advance to M */ i++; gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]); } gbox_float_round(gbox); return LW_SUCCESS; } return LW_FAILURE; }
static int lwcircle_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox) { POINT2D xmin, ymin, xmax, ymax; POINT4D center; int p2_side; double radius; LWDEBUG(2, "lwcircle_calculate_gbox called."); radius = lwcircle_center(p1, p2, p3, ¢er); /* Negative radius signals straight line, p1/p2/p3 are colinear */ if (radius < 0.0) { gbox->xmin = FP_MIN(p1->x, p3->x); gbox->ymin = FP_MIN(p1->y, p3->y); gbox->zmin = FP_MIN(p1->z, p3->z); gbox->xmax = FP_MAX(p1->x, p3->x); gbox->ymax = FP_MAX(p1->y, p3->y); gbox->zmax = FP_MAX(p1->z, p3->z); return LW_SUCCESS; } /* Matched start/end points imply circle */ if ( p1->x == p3->x && p1->y == p3->y ) { gbox->xmin = center.x - radius; gbox->ymin = center.y - radius; gbox->zmin = FP_MIN(p1->z,p2->z); gbox->mmin = FP_MIN(p1->m,p2->m); gbox->xmax = center.x + radius; gbox->ymax = center.y + radius; gbox->zmax = FP_MAX(p1->z,p2->z); gbox->mmax = FP_MAX(p1->m,p2->m); return LW_SUCCESS; } /* First approximation, bounds of start/end points */ gbox->xmin = FP_MIN(p1->x, p3->x); gbox->ymin = FP_MIN(p1->y, p3->y); gbox->zmin = FP_MIN(p1->z, p3->z); gbox->mmin = FP_MIN(p1->m, p3->m); gbox->xmax = FP_MAX(p1->x, p3->x); gbox->ymax = FP_MAX(p1->y, p3->y); gbox->zmax = FP_MAX(p1->z, p3->z); gbox->mmax = FP_MAX(p1->m, p3->m); /* Create points for the possible extrema */ xmin.x = center.x - radius; xmin.y = center.y; ymin.x = center.x; ymin.y = center.y - radius; xmax.x = center.x + radius; xmax.y = center.y; ymax.x = center.x; ymax.y = center.y + radius; /* Divide the circle into two parts, one on each side of a line joining p1 and p3. The circle extrema on the same side of that line as p2 is on, are also the extrema of the bbox. */ p2_side = signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, (POINT2D*)p2)); if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmin)) ) gbox->xmin = xmin.x; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymin)) ) gbox->ymin = ymin.y; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmax)) ) gbox->xmax = xmax.x; if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymax)) ) gbox->ymax = ymax.y; return LW_SUCCESS; }
static double circ_tree_distance_tree_internal(const CIRC_NODE* n1, const CIRC_NODE* n2, double threshold, double* min_dist, double* max_dist, GEOGRAPHIC_POINT* closest1, GEOGRAPHIC_POINT* closest2) { double max; double d, d_min; int i; LWDEBUGF(4, "entered, min_dist %.8g max_dist %.8g", *min_dist, *max_dist); // circ_tree_print(n1, 0); // circ_tree_print(n2, 0); /* Short circuit if we've already hit the minimum */ if( FP_LT(*min_dist, threshold) ) return *min_dist; /* If your minimum is greater than anyone's maximum, you can't hold the winner */ if( circ_node_min_distance(n1, n2) > *max_dist ) { LWDEBUGF(4, "pruning pair %p, %p", n1, n2); return MAXFLOAT; } /* If your maximum is a new low, we'll use that as our new global tolerance */ max = circ_node_max_distance(n1, n2); LWDEBUGF(5, "max %.8g", max); if( max < *max_dist ) *max_dist = max; /* Both leaf nodes, do a real distance calculation */ if( circ_node_is_leaf(n1) ) { if( circ_node_is_leaf(n2) ) { double d; GEOGRAPHIC_POINT close1, close2; LWDEBUGF(4, "testing leaf pair [%d], [%d]", n1->edge_num, n2->edge_num); /* One of the nodes is a point */ if ( n1->p1 == n1->p2 || n2->p1 == n2->p2 ) { GEOGRAPHIC_EDGE e; GEOGRAPHIC_POINT gp1, gp2; /* Both nodes are points! */ if ( n1->p1 == n1->p2 && n2->p1 == n2->p2 ) { geographic_point_init(n1->p1->x, n1->p1->y, &gp1); geographic_point_init(n2->p1->x, n2->p1->y, &gp2); close1 = gp1; close2 = gp2; d = sphere_distance(&gp1, &gp2); } /* Node 1 is a point */ else if ( n1->p1 == n1->p2 ) { geographic_point_init(n1->p1->x, n1->p1->y, &gp1); geographic_point_init(n2->p1->x, n2->p1->y, &(e.start)); geographic_point_init(n2->p2->x, n2->p2->y, &(e.end)); close1 = gp1; d = edge_distance_to_point(&e, &gp1, &close2); } /* Node 2 is a point */ else { geographic_point_init(n2->p1->x, n2->p1->y, &gp1); geographic_point_init(n1->p1->x, n1->p1->y, &(e.start)); geographic_point_init(n1->p2->x, n1->p2->y, &(e.end)); close1 = gp1; d = edge_distance_to_point(&e, &gp1, &close2); } LWDEBUGF(4, " got distance %g", d); } /* Both nodes are edges */ else { GEOGRAPHIC_EDGE e1, e2; GEOGRAPHIC_POINT g; POINT3D A1, A2, B1, B2; geographic_point_init(n1->p1->x, n1->p1->y, &(e1.start)); geographic_point_init(n1->p2->x, n1->p2->y, &(e1.end)); geographic_point_init(n2->p1->x, n2->p1->y, &(e2.start)); geographic_point_init(n2->p2->x, n2->p2->y, &(e2.end)); geog2cart(&(e1.start), &A1); geog2cart(&(e1.end), &A2); geog2cart(&(e2.start), &B1); geog2cart(&(e2.end), &B2); if ( edge_intersects(&A1, &A2, &B1, &B2) ) { d = 0.0; edge_intersection(&e1, &e2, &g); close1 = close2 = g; } else { d = edge_distance_to_edge(&e1, &e2, &close1, &close2); } LWDEBUGF(4, "edge_distance_to_edge returned %g", d); } if ( d < *min_dist ) { *min_dist = d; *closest1 = close1; *closest2 = close2; } return d; } else { d_min = MAXFLOAT; for ( i = 0; i < n2->num_nodes; i++ ) { d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2); d_min = FP_MIN(d_min, d); } return d_min; } } else { d_min = MAXFLOAT; for ( i = 0; i < n1->num_nodes; i++ ) { d = circ_tree_distance_tree_internal(n2, n1->nodes[i], threshold, min_dist, max_dist, closest1, closest2); d_min = FP_MIN(d_min, d); } return d_min; } }