/* * Transforms a spherical vector from 'spb' to 'spe' into an inverse Euler * transformation. Returns true if the transformation was successful. */ static bool spherevector_to_euler_inv(SEuler *se, const SPoint *spb, const SPoint *spe) { if (spoint_eq(spb, spe)) { return false; } else { Vector3D vbeg, vend, vtmp; SPoint spt[2]; SEuler set; spoint_vector3d(&vbeg, spb); spoint_vector3d(&vend, spe); vector3d_cross(&vtmp, &vbeg, &vend); vector3d_spoint(&spt[0], &vtmp); set.phi = -spt[0].lng - PIH; set.theta = spt[0].lat - PIH; set.psi = 0.0; seuler_set_zxz(&set); euler_spoint_trans(&spt[1], spb, &set); set.psi = -spt[1].lng; memcpy((void *) se, (void *) &set, sizeof(SEuler)); } return true; }
bool spoint_eq ( const SPoint * p1 , const SPoint * p2 ) { Vector3D a,b ; spoint_vector3d ( &a , p1 ); spoint_vector3d ( &b , p2 ); return ( vector3d_eq ( &a, &b ) ); }
Datum spherepoint_z(PG_FUNCTION_ARGS) { SPoint * p = ( SPoint * ) PG_GETARG_POINTER ( 0 ) ; static Vector3D v ; spoint_vector3d ( &v , p ); PG_RETURN_FLOAT8 ( v.z ); }
/*! \brief "Center" of a polygon \param v pointer to center of polygon \param poly pointer to polygon \return true if crossing */ static Vector3D * spherepoly_center ( Vector3D * v , const SPOLY * poly ) { int32 i ; Vector3D v1, v2; v1.x = 2.0; v1.y = 2.0; v1.z = 2.0; v2.x = -2.0; v2.y = -2.0; v2.z = -2.0; for ( i=0; i<poly->npts; i++ ){ spoint_vector3d ( v , &poly->p[i] ); v1.x = min(v->x,v1.x); v1.y = min(v->y,v1.y); v1.z = min(v->z,v1.z); v2.x = max(v->x,v2.x); v2.y = max(v->y,v2.y); v2.z = max(v->z,v2.z); } v->x = ( v1.x + v2.x ) / 2.0 ; v->y = ( v1.y + v2.y ) / 2.0 ; v->z = ( v1.z + v2.z ) / 2.0 ; return v ; }
SPoint * euler_spoint_trans ( SPoint * out , const SPoint * in , const SEuler * se ) { Vector3D v,o ; spoint_vector3d ( &v , in ); euler_vector_trans ( &o , &v , se ); vector3d_spoint ( out , &o ); return out; }
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; } }
Datum spherepoint_xyz(PG_FUNCTION_ARGS) { SPoint * p = ( SPoint * ) PG_GETARG_POINTER ( 0 ) ; Datum dret[3]; ArrayType *result; static Vector3D v ; spoint_vector3d ( &v , p ); dret[0] = Float8GetDatumFast(v.x); dret[1] = Float8GetDatumFast(v.y); dret[2] = Float8GetDatumFast(v.z); result = construct_array ( dret , 3, FLOAT8OID, sizeof(float8), false /* float8 byval */ , 'd' ); PG_RETURN_ARRAYTYPE_P(result); }
Datum spherepoint_xyz(PG_FUNCTION_ARGS) { SPoint *p = (SPoint *) PG_GETARG_POINTER(0); Datum dret[3]; ArrayType *result; Vector3D v; spoint_vector3d(&v, p); dret[0] = Float8GetDatumFast(v.x); dret[1] = Float8GetDatumFast(v.y); dret[2] = Float8GetDatumFast(v.z); #ifdef USE_FLOAT8_BYVAL result = construct_array(dret, 3, FLOAT8OID, sizeof(float8), true, 'd'); #else result = construct_array(dret, 3, FLOAT8OID, sizeof(float8), false, 'd'); #endif PG_RETURN_ARRAYTYPE_P(result); }
int32 * spherepoint_gen_key ( int32 * k , const SPoint * sp ) { Vector3D v ; static const int32 ks = MAXCVALUE ; spoint_vector3d ( &v, sp ); if ( v.x < -1.0 ) v.x = -1.0; if ( v.y < -1.0 ) v.y = -1.0; if ( v.z < -1.0 ) v.z = -1.0; if ( v.x > 1.0 ) v.x = 1.0; if ( v.y > 1.0 ) v.y = 1.0; if ( v.z > 1.0 ) v.z = 1.0; k[0] = v.x * ks; k[1] = v.y * ks; k[2] = v.z * ks; k[3] = v.x * ks; k[4] = v.y * ks; k[5] = v.z * ks; return ( k ); }
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; }
int32 * sphereline_gen_key ( int32 * k , const SLine * sl ) { static const int32 ks = MAXCVALUE ; static SPoint p[3] ; sline_begin ( &p[0], sl ); sline_end ( &p[1], sl ); if ( FPzero(sl->length) ){ static Vector3D vbeg , vend ; spoint_vector3d ( &vbeg , &p[0] ); spoint_vector3d ( &vend , &p[1] ); k[0] = min(vbeg.x,vend.x) * ks; k[1] = min(vbeg.y,vend.y) * ks; k[2] = min(vbeg.z,vend.z) * ks; k[3] = max(vbeg.x,vend.x) * ks; k[4] = max(vbeg.y,vend.y) * ks; k[5] = max(vbeg.z,vend.z) * ks; } else { static Vector3D v[4], vt, vr[2] ; static SEuler se ; static float8 l, ls, lc ; static int8 i; sphereline_to_euler ( &se, sl ); l = sl->length / 2.0 ; ls = sin(l); lc = cos(l); se.phi += l; v[0].x = lc ; v[0].y = ((lc<0)?(-1.0):(-ls)) ; v[1].x = 1.0; v[1].y = ((lc<0)?(-1.0):(-ls)) ; v[2].x = lc ; v[2].y = ((lc<0)?(+1.0):(+ls)) ; v[3].x = 1.0; v[3].y = ((lc<0)?(+1.0):(+ls)) ; v[0].z = v[1].z = v[2].z = v[3].z = 0.0; vr[0].x = vr[0].y = vr[0].z = 1.0; vr[1].x = vr[1].y = vr[1].z = -1.0; for ( i=0; i<4; i++ ){ euler_vector_trans(&vt,&v[i],&se); if ( vt.x < -1.0 ) vt.x = -1.0; if ( vt.y < -1.0 ) vt.y = -1.0; if ( vt.z < -1.0 ) vt.z = -1.0; if ( vt.x > 1.0 ) vt.x = 1.0; if ( vt.y > 1.0 ) vt.y = 1.0; if ( vt.z > 1.0 ) vt.z = 1.0; vr[0].x = min ( vr[0].x , vt.x ); vr[1].x = max ( vr[1].x , vt.x ); vr[0].y = min ( vr[0].y , vt.y ); vr[1].y = max ( vr[1].y , vt.y ); vr[0].z = min ( vr[0].z , vt.z ); vr[1].z = max ( vr[1].z , vt.z ); } k[0] = vr[0].x * ks; k[1] = vr[0].y * ks; k[2] = vr[0].z * ks; k[3] = vr[1].x * ks; k[4] = vr[1].y * ks; k[5] = vr[1].z * ks; } return k; }