Datum spherepoint_in(PG_FUNCTION_ARGS) { SPoint *sp = (SPoint *) palloc(sizeof(SPoint)); char *c = PG_GETARG_CSTRING(0); double lng, lat; void sphere_yyparse(void); init_buffer(c); sphere_yyparse(); if (get_point(&lng, &lat)) { sp->lng = lng; sp->lat = lat; spoint_check(sp); } else { reset_buffer(); pfree(sp); sp = NULL; elog(ERROR, "spherepoint_in: parse error"); } reset_buffer(); PG_RETURN_POINTER(sp); }
/* * Checks and modifies the Euler transformation. */ static void spheretrans_check(SEuler *e) { SPoint sp[3]; sp[0].lat = sp[1].lat = sp[2].lat = 0.0; sp[0].lng = e->phi; sp[1].lng = e->theta; sp[2].lng = e->psi; spoint_check(&sp[0]); spoint_check(&sp[1]); spoint_check(&sp[2]); e->phi = sp[0].lng; e->theta = sp[1].lng; e->psi = sp[2].lng; }
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 ); }
Datum spherepoint_from_long_lat(PG_FUNCTION_ARGS) { SPoint * p = ( SPoint * ) MALLOC ( sizeof ( SPoint ) ) ; p->lng = PG_GETARG_FLOAT8( 0 ); p->lat = PG_GETARG_FLOAT8( 1 ); spoint_check ( p ) ; PG_RETURN_POINTER( p ); }
Datum spheretrans_out(PG_FUNCTION_ARGS) { SEuler *se = (SEuler *) PG_GETARG_POINTER(0); char *buffer = (char *) palloc(255); char buf[100]; char etype[4]; SPoint val[3]; unsigned char i, t = 0; unsigned int rdeg, rmin; double rsec; val[0].lat = val[1].lat = val[2].lat = 0.0; val[0].lng = se->phi; val[1].lng = se->theta; val[2].lng = se->psi; spoint_check(&val[0]); spoint_check(&val[1]); spoint_check(&val[2]); buffer[0] = '\0'; for (i = 0; i < 3; i++) { rdeg = rmin = 0; rsec = 0.0; switch (sphere_output) { case OUTPUT_DEG: sprintf(&buf[0], "%.*gd", sphere_output_precision, RADIANS * val[i].lng); break; case OUTPUT_HMS: case OUTPUT_DMS: rad_to_dms(val[i].lng, &rdeg, &rmin, &rsec); sprintf(&buf[0], "%2ud %2um %.*gs", rdeg, rmin, sphere_output_precision, rsec); break; default: sprintf(&buf[0], "%.*g", sphere_output_precision, val[i].lng); break; } strcat(&buf[0], ", "); strcat(buffer, &buf[0]); } for (i = 0; i < 3; i++) { switch (i) { case 0: t = se->phi_a; break; case 1: t = se->theta_a; break; case 2: t = se->psi_a; break; } switch (t) { case EULER_AXIS_X: etype[i] = 'X'; break; case EULER_AXIS_Y: etype[i] = 'Y'; break; case EULER_AXIS_Z: etype[i] = 'Z'; break; } } etype[3] = '\0'; strcat(buffer, etype); PG_RETURN_CSTRING(buffer); }
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; }
/*! \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 ); }