예제 #1
0
파일: point.c 프로젝트: akorotkov/pgsphere
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);
}
예제 #2
0
파일: euler.c 프로젝트: akorotkov/pgsphere
/*
 * 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;
}
예제 #3
0
파일: circle.c 프로젝트: china-vo/pgSphere
  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 );
  }
예제 #4
0
파일: point.c 프로젝트: mnullmei/pgsphere
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 );
}
예제 #5
0
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);
}
예제 #6
0
파일: polygon.c 프로젝트: mnullmei/pgsphere
  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;
  }
예제 #7
0
파일: polygon.c 프로젝트: mnullmei/pgsphere
  /*!
    \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 );

  }