Datum BOX2D_same(PG_FUNCTION_ARGS) { GBOX *box1 = (GBOX *) PG_GETARG_POINTER(0); GBOX *box2 = (GBOX *) PG_GETARG_POINTER(1); PG_RETURN_BOOL(FPeq(box1->xmax, box2->xmax) && FPeq(box1->xmin, box2->xmin) && FPeq(box1->ymax, box2->ymax) && FPeq(box1->ymin, box2->ymin)); }
Datum lwgeom_lt(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); GBOX box1; GBOX box2; POSTGIS_DEBUG(2, "lwgeom_lt called"); if (gserialized_get_srid(geom1) != gserialized_get_srid(geom2)) { elog(BTREE_SRID_MISMATCH_SEVERITY, "Operation on two GEOMETRIES with different SRIDs\n"); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_NULL(); } POSTGIS_DEBUG(3, "lwgeom_lt passed getSRID test"); gserialized_get_gbox_p(geom1, &box1); gserialized_get_gbox_p(geom2, &box2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); POSTGIS_DEBUG(3, "lwgeom_lt getbox2d_p passed"); if ( ! FPeq(box1.xmin , box2.xmin) ) { if (box1.xmin < box2.xmin) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.ymin , box2.ymin) ) { if (box1.ymin < box2.ymin) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.xmax , box2.xmax) ) { if (box1.xmax < box2.xmax) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.ymax , box2.ymax) ) { if (box1.ymax < box2.ymax) PG_RETURN_BOOL(TRUE); } PG_RETURN_BOOL(FALSE); }
Datum spherepoly_add_points_finalize(PG_FUNCTION_ARGS) { SPOLY * poly = ( SPOLY * ) PG_GETARG_POINTER ( 0 ) ; if ( poly == NULL ){ PG_RETURN_NULL ( ); } poly = PG_GETARG_SPOLY( 0 ); if ( poly->npts < 3 ){ elog ( NOTICE , "spoly(spoint): At least 3 points required" ); FREE ( poly ); PG_RETURN_NULL ( ); } // Skip if distance is equal 180deg if ( FPeq ( spoint_dist ( &poly->p[0], &poly->p[ poly->npts - 1 ]) , PI ) ) { elog ( NOTICE , "spoly(spoint): Cannot close polygon. Distance between first and last point is 180deg" ); FREE ( poly ); PG_RETURN_NULL ( ); } if ( !spherepoly_check ( poly ) ){ elog ( NOTICE , "spoly(spoint): a line segment overlaps or polygon too large" ); FREE ( poly ) ; PG_RETURN_NULL(); } PG_RETURN_POINTER ( poly ); }
long line_eq(LINE *l1, LINE *l2) { double k; if (! FPzero(l2->A)) k = l1->A / l2->A; else if (! FPzero(l2->B)) k = l1->B / l2->B; else if (! FPzero(l2->C)) k = l1->C / l2->C; else k = 1.0; return( FPeq(l1->A, k * l2->A) && FPeq(l1->B, k * l2->B) && FPeq(l1->C, k * l2->C) ); }
Datum spherecircle_in(PG_FUNCTION_ARGS) { SCIRCLE * c = ( SCIRCLE * ) MALLOC ( sizeof ( SCIRCLE ) ) ; char * s = PG_GETARG_CSTRING(0); double lng, lat, radius ; void sphere_yyparse( void ); init_buffer ( s ); sphere_yyparse(); if ( get_circle( &lng, &lat, &radius ) ){ c->center.lng = lng; c->center.lat = lat; c->radius = radius; reset_buffer(); /* It's important to allow circles with radius 90deg!! */ if ( FPgt(c->radius,PIH) ){ FREE( c ); c = NULL; elog ( ERROR , "spherecircle_in: radius must be not greater than 90 degrees" ); } else if ( FPeq(c->radius,PIH) ){ // set "exact" 90 degrees c->radius = PIH; } spoint_check ( &c->center ); } else { reset_buffer(); FREE( c ); c = NULL; elog ( ERROR , "spherecircle_in: parse error" ); } PG_RETURN_POINTER( c ); }
bool scircle_eq ( const SCIRCLE * c1 , const SCIRCLE * c2 ) { return ( spoint_eq ( &c1->center , &c2->center ) && FPeq ( c1->radius , c2->radius ) ) ; }
static bool gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query) { bool result = false; switch (strategy) { case RTLeftStrategyNumber: result = FPlt(key->low.x, query->x); break; case RTRightStrategyNumber: result = FPgt(key->high.x, query->x); break; case RTAboveStrategyNumber: result = FPgt(key->high.y, query->y); break; case RTBelowStrategyNumber: result = FPlt(key->low.y, query->y); break; case RTSameStrategyNumber: if (isLeaf) { /* key.high must equal key.low, so we can disregard it */ result = (FPeq(key->low.x, query->x) && FPeq(key->low.y, query->y)); } else { result = (FPle(query->x, key->high.x) && FPge(query->x, key->low.x) && FPle(query->y, key->high.y) && FPge(query->y, key->low.y)); } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); result = false; /* keep compiler quiet */ break; } return result; }
void spoint_check(SPoint *spoint) { bool lat_is_neg = (spoint->lat < 0) ? true : false; if (spoint->lng < 0 || spoint->lng > PID) spoint->lng = spoint->lng - floor(spoint->lng / (PID)) * PID; if (spoint->lat < -PIH || spoint->lat > PIH) spoint->lat = spoint->lat - floor(spoint->lat / (PID)) * PID; if (spoint->lng < 0.0) { spoint->lng += (PID); } if (spoint->lat > PI) { spoint->lat -= (2 * PI); } if (spoint->lat > PIH) { spoint->lat = (PI - spoint->lat); spoint->lng += ((spoint->lng < PI) ? (PI) : (-PI)); } if (spoint->lat < -PIH) { spoint->lat = (-PI - spoint->lat); spoint->lng += ((spoint->lng < PI) ? (PI) : (-PI)); } if (FPeq(spoint->lat, PIH) && lat_is_neg) spoint->lat = -PIH; if (FPeq(spoint->lng, PID)) { spoint->lng = 0.0; } if (FPzero(spoint->lng)) { spoint->lng = 0.0; } if (FPzero(spoint->lat)) { spoint->lat = 0.0; } }
static bool gist_point_consistent_internal(strat_nr_t strategy, bool isLeaf, BOX * key, Point * query) { bool result = false; switch (strategy) { case RTLeftStrategyNumber: result = FPlt(key->low.x, query->x); break; case RTRightStrategyNumber: result = FPgt(key->high.x, query->x); break; case RTAboveStrategyNumber: result = FPgt(key->high.y, query->y); break; case RTBelowStrategyNumber: result = FPlt(key->low.y, query->y); break; case RTSameStrategyNumber: if (isLeaf) { result = FPeq(key->low.x, query->x) && FPeq(key->low.y, query->y); } else { result = (query->x <= key->high.x && query->x >= key->low.x && query->y <= key->high.y && query->y >= key->low.y); } break; default: elog(ERROR, "unknown strategy number: %d", strategy); } return result; }
SPoint * spoint_check (SPoint * spoint) { static bool lat_is_neg; lat_is_neg = ( spoint->lat < 0 )?( TRUE ):( FALSE ); if(spoint->lng < 0 || spoint->lng > PID) spoint->lng = spoint->lng - floor(spoint->lng / ( PID ) ) * PID; if(spoint->lat < -PIH || spoint->lat > PIH) spoint->lat = spoint->lat - floor(spoint->lat / ( PID ) ) * PID; if( spoint->lng < 0.0 ) { spoint->lng += ( PID ); } if( spoint->lat > PI ) { spoint->lat -= ( 2*PI ); } if( spoint->lat > PIH ) { spoint->lat = ( PI - spoint->lat ); spoint->lng += ( ( spoint->lng<PI )?( PI ):( -PI ) ) ; } if( spoint->lat < -PIH ) { spoint->lat = ( -PI - spoint->lat ); spoint->lng += ( ( spoint->lng<PI )?( PI ):( -PI ) ) ; } if ( FPeq(spoint->lat,PIH) && lat_is_neg ) spoint->lat = -PIH ; if ( FPeq(spoint->lng,PID) ) { spoint->lng = 0.0 ; } if ( FPzero(spoint->lng) ) { spoint->lng = 0.0 ; } if ( FPzero(spoint->lat) ) { spoint->lat = 0.0 ; } return spoint; }
Datum spherepoly_add_point(PG_FUNCTION_ARGS) { SPOLY * poly = ( SPOLY * ) PG_GETARG_POINTER ( 0 ) ; SPoint * p = ( SPoint * ) PG_GETARG_POINTER ( 1 ) ; int32 size = 0 ; SPOLY * poly_new = NULL; if ( p == NULL ){ PG_RETURN_POINTER ( poly ); } if ( poly == NULL ){ size = offsetof(SPOLY, p[0]) + sizeof(SPoint) ; poly = ( SPOLY * ) MALLOC ( size ); memcpy( (void*) &poly->p[0] , (void*) p, sizeof(SPoint) ); #if PG_VERSION_NUM < 80300 poly->size = size; #else SET_VARSIZE(poly, size); #endif poly->npts = 1; PG_RETURN_POINTER ( poly ); } poly = PG_GETARG_SPOLY( 0 ); // skip if equal if ( spoint_eq (p, &poly->p[ poly->npts - 1 ]) ){ PG_RETURN_POINTER ( poly ); } // Skip if distance is equal 180deg if ( FPeq ( spoint_dist ( p, &poly->p[ poly->npts - 1 ]) , PI ) ) { elog ( NOTICE , "spoly(spoint): Skip point, distance of previous point is 180deg" ); } size = offsetof(SPOLY, p[0]) + sizeof(SPoint) * ( poly->npts + 1 ); poly_new = palloc( size ); memcpy( (void*) poly , (void*) poly_new, VARSIZE(poly) ); poly_new->npts++; #if PG_VERSION_NUM < 80300 poly_new->size = size ; #else SET_VARSIZE( poly_new, size ); #endif memcpy( (void*) &poly_new->p[poly->npts] , (void*) p, sizeof(SPoint) ); PG_RETURN_POINTER ( poly_new ); }
Datum lwgeom_eq(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); GBOX box1; GBOX box2; bool result; POSTGIS_DEBUG(2, "lwgeom_eq called"); if (gserialized_get_srid(geom1) != gserialized_get_srid(geom2)) { elog(BTREE_SRID_MISMATCH_SEVERITY, "Operation on two GEOMETRIES with different SRIDs\n"); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_NULL(); } gserialized_get_gbox_p(geom1, &box1); gserialized_get_gbox_p(geom2, &box2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); if ( ! (FPeq(box1.xmin, box2.xmin) && FPeq(box1.ymin, box2.ymin) && FPeq(box1.xmax, box2.xmax) && FPeq(box1.ymax, box2.ymax)) ) { result = FALSE; } else { result = TRUE; } PG_RETURN_BOOL(result); }
float8 spoint_dist ( const SPoint * p1, const SPoint * p2 ) { float8 dl = p1->lng - p2->lng; float8 f = ( ( sin( p1->lat )*sin( p2->lat ) + cos( p1->lat )*cos( p2->lat )*cos( dl ) ) ); if( FPeq( f, 1.0 ) ){ /* for small distances */ Vector3D v1, v2, v3; spoint_vector3d(&v1, p1); spoint_vector3d(&v2, p2); vector3d_cross( &v3, &v1, &v2 ); f = vector3d_length(&v3); } else { f = acos(f); } if ( FPzero(f) ){ return 0.0; } else { return f; } }
LINE * /* two points */ line_construct_pp(Point *pt1, Point *pt2) { LINE *result; result = PALLOCTYPE(LINE); if (FPeq(pt1->x, pt2->x)) { /* vertical */ /* use "x = C" */ result->m = 0.0; result->A = -1.0; result->B = 0.0; result->C = pt1->x; } else { /* use "mx - y + yinter = 0" */ result->m = (pt1->y - pt2->y) / (pt1->x - pt2->x); result->A = result->m; result->B = -1.0; result->C = pt1->y - result->m * pt1->x; } return(result); }
long line_vertical(LINE *line) { return( FPeq(line->A, -1.0) && FPzero(line->B) ); }
long line_parallel(LINE *l1, LINE *l2) { return( FPeq(l1->m, l2->m) ); }
long box_eq(BOX *box1, BOX *box2) { return( FPeq(box_ar(box1), box_ar(box2)) ); }
long lseg_horizontal(LSEG *lseg) { return( FPeq(lseg->p[0].y, lseg->p[1].y) ); }
Datum geography_gist_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector*) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC*) PG_GETARG_POINTER(1); OffsetNumber i; /* One union box for each half of the space. */ GIDX **box_union; /* One offset number list for each half of the space. */ OffsetNumber **list; /* One position index for each half of the space. */ int *pos; GIDX *box_pageunion; GIDX *box_current; int direction = -1; bool all_entries_equal = true; OffsetNumber max_offset; int nbytes, ndims_pageunion, d; int posmax = -1; POSTGIS_DEBUG(4, "[GIST] 'picksplit' function called"); /* ** First calculate the bounding box and maximum number of dimensions in this page. */ max_offset = entryvec->n - 1; box_current = (GIDX*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key); box_pageunion = gidx_copy(box_current); /* Calculate the containing box (box_pageunion) for the whole page we are going to split. */ for ( i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); if ( all_entries_equal == true && ! gidx_equals (box_pageunion, box_current) ) all_entries_equal = false; gidx_merge( &box_pageunion, box_current ); } POSTGIS_DEBUGF(3, "[GIST] box_pageunion: %s", gidx_to_string(box_pageunion)); /* Every box in the page is the same! So, we split and just put half the boxes in each child. */ if ( all_entries_equal ) { POSTGIS_DEBUG(4, "[GIST] picksplit finds all entries equal!"); geography_gist_picksplit_fallback(entryvec, v); PG_RETURN_POINTER(v); } /* Initialize memory structures. */ nbytes = (max_offset + 2) * sizeof(OffsetNumber); ndims_pageunion = GIDX_NDIMS(box_pageunion); POSTGIS_DEBUGF(4, "[GIST] ndims_pageunion == %d", ndims_pageunion); pos = palloc(2*ndims_pageunion * sizeof(int)); list = palloc(2*ndims_pageunion * sizeof(OffsetNumber*)); box_union = palloc(2*ndims_pageunion * sizeof(GIDX*)); for ( d = 0; d < ndims_pageunion; d++ ) { list[BELOW(d)] = (OffsetNumber*) palloc(nbytes); list[ABOVE(d)] = (OffsetNumber*) palloc(nbytes); box_union[BELOW(d)] = gidx_new(ndims_pageunion); box_union[ABOVE(d)] = gidx_new(ndims_pageunion); pos[BELOW(d)] = 0; pos[ABOVE(d)] = 0; } /* ** Assign each entry in the node to the volume partitions it belongs to, ** such as "above the x/y plane, left of the y/z plane, below the x/z plane". ** Each entry thereby ends up in three of the six partitions. */ POSTGIS_DEBUG(4, "[GIST] 'picksplit' calculating best split axis"); for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { if ( GIDX_GET_MIN(box_current,d)-GIDX_GET_MIN(box_pageunion,d) < GIDX_GET_MAX(box_pageunion,d)-GIDX_GET_MAX(box_current,d) ) { geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); } else { geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); } } } /* ** "Bad disposition", too many entries fell into one octant of the space, so no matter which ** plane we choose to split on, we're going to end up with a mostly full node. Where the ** data is pretty homogeneous (lots of duplicates) entries that are equidistant from the ** sides of the page union box can occasionally all end up in one place, leading ** to this condition. */ if ( geography_gist_picksplit_badratios(pos,ndims_pageunion) == TRUE ) { /* ** Instead we split on center points and see if we do better. ** First calculate the average center point for each axis. */ double *avgCenter = palloc(ndims_pageunion * sizeof(double)); for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] = 0.0; } POSTGIS_DEBUG(4, "[GIST] picksplit can't find good split axis, trying center point method"); for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] += (GIDX_GET_MAX(box_current,d) + GIDX_GET_MIN(box_current,d)) / 2.0; } } for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] /= max_offset; pos[BELOW(d)] = pos[ABOVE(d)] = 0; /* Re-initialize our counters. */ POSTGIS_DEBUGF(4, "[GIST] picksplit average center point[%d] = %.12g", d, avgCenter[d]); } /* For each of our entries... */ for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { double center; box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { center = (GIDX_GET_MIN(box_current,d)+GIDX_GET_MAX(box_current,d))/2.0; if ( center < avgCenter[d] ) geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); else if ( FPeq(center, avgCenter[d]) ) if ( pos[BELOW(d)] > pos[ABOVE(d)] ) geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); else geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); else geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); } } /* Do we have a good disposition now? If not, screw it, just cut the node in half. */ if ( geography_gist_picksplit_badratios(pos,ndims_pageunion) == TRUE ) { POSTGIS_DEBUG(4, "[GIST] picksplit still cannot find a good split! just cutting the node in half"); geography_gist_picksplit_fallback(entryvec, v); PG_RETURN_POINTER(v); } } /* ** Now, what splitting plane gives us the most even ratio of ** entries in our child pages? Since each split region has been apportioned entries ** against the same number of total entries, the axis that has the smallest maximum ** number of entries in its regions is the most evenly distributed. ** TODO: what if the distributions are equal in two or more axes? */ for ( d = 0; d < ndims_pageunion; d++ ) { int posd = Max(pos[ABOVE(d)],pos[BELOW(d)]); if ( posd > posmax ) { direction = d; posmax = posd; } } if ( direction == -1 || posmax == -1 ) { /* ERROR OUT HERE */ elog(ERROR, "Error in building split, unable to determine split direction."); } POSTGIS_DEBUGF(3, "[GIST] 'picksplit' splitting on axis %d", direction); geography_gist_picksplit_constructsplit(v, list[BELOW(direction)], pos[BELOW(direction)], &(box_union[BELOW(direction)]), list[ABOVE(direction)], pos[ABOVE(direction)], &(box_union[ABOVE(direction)]) ); POSTGIS_DEBUGF(4, "[GIST] spl_ldatum: %s", gidx_to_string((GIDX*)v->spl_ldatum)); POSTGIS_DEBUGF(4, "[GIST] spl_rdatum: %s", gidx_to_string((GIDX*)v->spl_rdatum)); POSTGIS_DEBUGF(4, "[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)", direction, GIDX_GET_MIN(box_pageunion, direction), GIDX_GET_MAX(box_pageunion, direction), GIDX_GET_MIN((GIDX*)v->spl_ldatum, direction), GIDX_GET_MAX((GIDX*)v->spl_ldatum, direction), GIDX_GET_MIN((GIDX*)v->spl_rdatum, direction), GIDX_GET_MAX((GIDX*)v->spl_rdatum, direction) ); PG_RETURN_POINTER(v); }
long lseg_parallel(LSEG *l1, LSEG *l2) { return( FPeq(l1->m, l2->m) ); }
/*! \brief Converts an array of spherical points to SPOLY \param arr pointer to array of spherical points \param nelem count of elements \return pointer to created spherical polygon */ static SPOLY * spherepoly_from_array ( SPoint * arr, int32 nelem ) { SPOLY * poly = NULL; if ( nelem < 3 ){ elog ( ERROR , "spherepoly_from_array: more than two points needed" ); return NULL; } else { static int32 i; static float8 scheck ; int32 size; for ( i=0; i<nelem ; i++ ){ spoint_check ( &arr[i] ); } // check duplicate points i = 0; while ( i<(nelem-1) ){ if ( nelem < 3 ) break; if ( spoint_eq (&arr[i],&arr[i+1]) ){ if ( i<(nelem-2) ){ memmove ((void*) &arr[i+1], (void*) &arr[i+2], (nelem-i-2) * sizeof( SPoint ) ); } nelem--; continue; } i++; } if ( spoint_eq (&arr[0],&arr[nelem-1]) ){ nelem--; } if ( nelem < 3 ){ elog ( ERROR , "spherepoly_from_array: more than two points needed" ); return NULL; } size = offsetof(SPOLY, p[0]) + sizeof(SPoint) * nelem; poly = (SPOLY *) MALLOC ( size ) ; SET_VARSIZE(poly, size); poly->npts = nelem; for ( i=0; i<nelem ; i++ ){ if ( i==0 ){ scheck = spoint_dist ( &arr[nelem-1], &arr[0] ); } else { scheck = spoint_dist ( &arr[i-1] , &arr[i] ); } if (FPeq(scheck,PI)){ elog ( ERROR , "spherepoly_from_array: a polygon segment length must be not equal 180 degrees." ); return NULL; } memcpy( (void*) &poly->p[i], (void*) &arr[i], sizeof( SPoint ) ); } } if ( ! spherepoly_check ( poly ) ){ elog ( ERROR , "spherepoly_from_array: a line segment overlaps or polygon too large" ); FREE ( poly ) ; return NULL; } return ( poly ); }
long point_vert(Point *pt1, Point *pt2) { return( FPeq( pt1->x, pt2->x ) ); }
long lseg_vertical(LSEG *lseg) { return( FPeq(lseg->p[0].x, lseg->p[1].x) ); }
long point_horiz(Point *pt1, Point *pt2) { return( FPeq( pt1->y, pt2->y ) ); }
bool spoly_contains_point ( const SPOLY * pg , const SPoint * sp ) { static int32 i; static SLine sl; bool res = FALSE ; static float8 scp; static Vector3D vc, vp; // First check, if point is outside polygon (behind) spherepoly_center ( &vc , pg ); spoint_vector3d ( &vp , sp ); scp = vector3d_scalar ( &vp , &vc ); if ( FPle ( scp, 0.0 ) ){ return false; } // Check whether point is edge for ( i=0; i<pg->npts; i++ ){ if ( spoint_eq ( &pg->p[i] , sp ) ){ return TRUE; } } // Check whether point is on a line segment for ( i=0; i<pg->npts; i++ ){ spoly_segment ( &sl , pg , i ); if ( spoint_at_sline( sp, &sl ) ){ return TRUE; } } do { SEuler se, te; SPoint p , lp[2]; bool a1, a2, eqa ; int32 cntr = 0; SPOLY * tmp = ( SPOLY * ) MALLOC ( VARSIZE(pg) ); /* Make a transformation, so point is (0,0) */ se.phi_a = EULER_AXIS_Z ; se.theta_a = EULER_AXIS_X ; se.psi_a = EULER_AXIS_Z ; se.phi = PIH - sp->lng ; se.theta = - sp->lat ; se.psi = -PIH ; euler_spoly_trans ( tmp , pg , &se ); p.lng = 0.0; p.lat = 0.0; // Check, whether an edge is on equator. // If yes, rotate randomized around 0,0 cntr = 0; do { eqa = FALSE; for ( i=0; i<pg->npts; i++ ){ if ( FPzero(tmp->p[i].lat) ){ if ( FPeq( cos(tmp->p[i].lng) , -1.0 ) ){ return false; } else { eqa = TRUE; break; } } } if ( eqa ){ SPOLY * ttt = ( SPOLY * ) MALLOC ( VARSIZE(pg) ); srand( cntr ); se.phi_a = se.theta_a = se.psi_a = EULER_AXIS_X ; se.phi = ( (double) rand() / RAND_MAX ) * PID ; se.theta = 0.0 ; se.psi = 0.0 ; euler_spoly_trans ( ttt , tmp , &se ); memcpy ( (void*) tmp, (void*) ttt, VARSIZE(pg) ); FREE(ttt); } if ( cntr>10000 ){ elog(WARNING ,"Bug found in spoly_contains_point"); elog(ERROR ,"Please report it to pg_sphere team!"); return false; } cntr++; } while ( eqa ); // Count line segment crossing "equator" cntr = 0; for ( i=0; i<pg->npts; i++ ){ // create a single line from segment spoly_segment ( &sl , tmp , i ); sline_begin ( &lp[0], &sl ); sline_end ( &lp[1], &sl ); a1 = ( FPgt(lp[0].lat,0.0) && FPlt(lp[1].lat,0.0) ); a2 = ( FPlt(lp[0].lat,0.0) && FPgt(lp[1].lat,0.0) ); if ( a1 || a2 ){ // if crossing sphereline_to_euler_inv ( &te, &sl ); if ( a2 ){ // crossing ascending p.lng = PID - te.phi; } else { p.lng = PI - te.phi; } spoint_check ( &p ); if ( p.lng < PI ){ // crossing between 0 and 180 deg cntr++; } } } FREE ( tmp ); if ( cntr % 2 ){ res = TRUE; } } while (0); return res; }