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 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; }