Exemple #1
0
/**Creates a new projection object. See the intro for details.

   call-seq: new(String) -> Proj4::Projection
             new(Array) -> Proj4::Projection
             new(Hash) -> Proj4::Projection

 */
static VALUE proj_initialize(VALUE self, VALUE params){
  _wrap_pj* wpj;
  VALUE proj_params = rb_funcall(cProjection, idParseInitParameters, 1, params);
  int size = RARRAY_LEN(proj_params);
  char** c_params = (char **) malloc(size*sizeof(char *));
  int i;

  for (i=0; i < size; i++)
  {
    VALUE item = rb_ary_entry(proj_params, i);
    c_params[i]= StringValuePtr(item); 
  }

  Data_Get_Struct(self,_wrap_pj,wpj);
  wpj->pj = pj_init(size,c_params);
  free(c_params);
  if(wpj->pj == 0) {
    int pj_errno_ref = *pj_get_errno_ref();
    if (pj_errno_ref > 0) {
        rb_raise(rb_eSystemCallError, "Unknown system call error");
    } else {
        raise_error(pj_errno_ref);
    }
  }
  return self;
}
Exemple #2
0
void project_inv(int *n, double *x, double *y, double *xlon, double *ylat, char **projarg){

  /* call the _inverse_ projection specified by the string projarg,
  * returning longitude and lat in xlon and ylat vectors, given the
  * numbers in x and y vectors (all vectors of length n) */

  int i;

  projUV p;
  projPJ pj;
  
  if (!(pj = pj_init_plus(*projarg)))
    error(pj_strerrno(*pj_get_errno_ref()));
/*  Rprintf("%s\n", pj_get_def(pj, 0));*/

  for(i=0;i<*n;i++){
    if(ISNAN(x[i]) || ISNAN(y[i])){
      xlon[i]=x[i];
      ylat[i]=y[i];
    } else {
      p.u=x[i];
      p.v=y[i];
      p = pj_inv(p, pj);
      if (p.u == HUGE_VAL || ISNAN(p.u)) {
	    Rprintf("inverse projected point not finite\n");
      }
      xlon[i]=p.u * RAD_TO_DEG;
      ylat[i]=p.v * RAD_TO_DEG;
    }
  }

  pj_free(pj);
}
Exemple #3
0
SEXP checkCRSArgs(SEXP args) {
	SEXP res;
	projPJ pj;
	PROTECT(res = NEW_LIST(2));
	SET_VECTOR_ELT(res, 0, NEW_LOGICAL(1));
	SET_VECTOR_ELT(res, 1, NEW_CHARACTER(1));
	LOGICAL_POINTER(VECTOR_ELT(res, 0))[0] = FALSE;
	
	if (!(pj = pj_init_plus(CHAR(STRING_ELT(args, 0))))) {

		SET_STRING_ELT(VECTOR_ELT(res, 1), 0, 
			COPY_TO_USER_STRING(pj_strerrno(*pj_get_errno_ref())));
		
		UNPROTECT(1);
		return(res);
	}

	SET_STRING_ELT(VECTOR_ELT(res, 1), 0, 
		COPY_TO_USER_STRING(pj_get_def(pj, 0)));
	
	LOGICAL_POINTER(VECTOR_ELT(res, 0))[0] = TRUE;
	
	UNPROTECT(1);
	return(res);
}
Exemple #4
0
static GhtErr
l2g_coordinate_reproject(const Las2GhtState *state, GhtCoordinate *coord)
{

    int *pj_errno_ref;
    GhtCoordinate origcoord;

    /* Make a copy of the input point so we can report the original should an error occur */
    origcoord = *coord;

    if (pj_is_latlong(state->pj_input)) l2g_coordinate_to_rad(coord);

    /* Perform the transform */
    pj_transform(state->pj_input, state->pj_output, 1, 0, &(coord->x), &(coord->y), NULL);

    /* For NAD grid-shift errors, display an error message with an additional hint */
    pj_errno_ref = pj_get_errno_ref();

    if (*pj_errno_ref != 0)
    {
        if (*pj_errno_ref == -38)
        {
            ght_warn("No no grid shift files were found, or point out of range.");
        }
        ght_error("%s: could not project point (%g %g): %s (%d)", 
                  __func__, 
                  origcoord.x, origcoord.y,
                  pj_strerrno(*pj_errno_ref), *pj_errno_ref
                  );
        return GHT_ERROR;
    }

    if (pj_is_latlong(state->pj_output)) l2g_coordinate_to_dec(coord);
    return GHT_OK;
}
Exemple #5
0
/**
  * Initialise a proj-based projector as specified in the given file (as
  *serialised by a proj-based projector.
  *
  * @param input_file The file which a proj-based projector has been serialised
  *to.
  * @return A pointer to an initialised projector.
  */
projector *get_proj_projector_from_file(FILE *input_file) {
   unsigned int projection_string_length;
   fread(&projection_string_length, sizeof(unsigned int), 1, input_file);

   // Check projection string length
   if (projection_string_length == 0) {
      fprintf(stderr, "Read a projection string length of 0\n");
      exit(EXIT_FAILURE);
   }

   // Read the projection string
   char *projection_string = calloc(projection_string_length, sizeof(char));
   if (projection_string == NULL) {
      fprintf(stderr,
              "Failed to allocate space (%d chars) for projection string\n",
              projection_string_length);
      exit(EXIT_FAILURE);
   }
   fread(projection_string, sizeof(char), projection_string_length, input_file);

   // Paranoid checks on projection string
   if (projection_string[projection_string_length-1] != '\0') {
      fprintf( stderr,
         "Corrupted string read from file (null terminator doesn't exist in "\
         "expected position (%d), found %d)\n",
         projection_string_length,
         projection_string[projection_string_length - 1]);
      // Don't attempt to print out the projection string as we know it's
      // corrupt - very bad things may happen!
      exit(EXIT_FAILURE);
   }
   if (strlen(projection_string) != projection_string_length -1) {
      fprintf(stderr,
              "Corrupted string read from file (string length is wrong)\n");
      // Don't attempt to print out the projection string as we know it's
      // corrupt - very bad things may happen!
      exit(EXIT_FAILURE);
   }

   // Initialize the projection
   projPJ *projection = pj_init_plus(projection_string);
   if (projection == NULL) {
      fprintf(
         stderr,
         "Couldn't initialise projection '%s' (Proj error message: '%s')\n",
         projection_string, pj_strerrno(*pj_get_errno_ref()));
      exit(EXIT_FAILURE);
   }

   projector *p = malloc(sizeof(projector));
   p->internals = (void *)projection;
   p->project = &_proj_project;
   p->inverse_project = &_proj_inverse_project;
   p->serialize_to_file = &_proj_serialize_to_file;
   p->free = &_proj_free;

   return p;
}
Exemple #6
0
JNIEXPORT int JNICALL Java_org_gvsig_crs_proj_JNIBaseCrs_isLatlong
(JNIEnv * env, jobject parent, jlong crs)
{
	projPJ proj_pj = crs;

	int *err = pj_get_errno_ref();
	if(*err>=0)
	return proj_pj->is_latlong;
	else
	return *err;
}
Exemple #7
0
/**
  * Initialise a proj-based projector from a proj string.
  *
  * @param projection_string The proj compatible projection string.
  * @return A pointer to an initialised projector.
  */
projector *get_proj_projector_from_string(char *projection_string) {
   projPJ *projection = pj_init_plus(projection_string);
   if (projection == NULL) {
      fprintf(
         stderr,
         "Couldn't initialise projection '%s' (Proj error message: '%s')\n",
         projection_string, pj_strerrno(*pj_get_errno_ref()));
      return NULL;
   }

   projector *p = malloc(sizeof(projector));
   p->internals = (void *)projection;
   p->project = &_proj_project;
   p->inverse_project = &_proj_inverse_project;
   p->serialize_to_file = &_proj_serialize_to_file;
   p->free = &_proj_free;

   return p;
}
int
point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj)
{
	int* pj_errno_ref;
	POINT4D orig_pt;

	/* Make a copy of the input point so we can report the original should an error occur */
	orig_pt.x = pt->x;
	orig_pt.y = pt->y;
	orig_pt.z = pt->z;

	if (pj_is_latlong(srcpj)) to_rad(pt) ;

	LWDEBUGF(4, "transforming POINT(%f %f) from '%s' to '%s'", orig_pt.x, orig_pt.y, pj_get_def(srcpj,0), pj_get_def(dstpj,0));

	/* Perform the transform */
	pj_transform(srcpj, dstpj, 1, 0, &(pt->x), &(pt->y), &(pt->z));

	/* For NAD grid-shift errors, display an error message with an additional hint */
	pj_errno_ref = pj_get_errno_ref();

	if (*pj_errno_ref != 0)
	{
		if (*pj_errno_ref == -38)
		{
			lwnotice("PostGIS was unable to transform the point because either no grid shift files were found, or the point does not lie within the range for which the grid shift is defined. Refer to the ST_Transform() section of the PostGIS manual for details on how to configure PostGIS to alter this behaviour.");
			lwerror("transform: couldn't project point (%g %g %g): %s (%d)",
			        orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref);
			return 0;
		}
		else
		{
			lwerror("transform: couldn't project point (%g %g %g): %s (%d)",
			        orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref);
			return 0;
		}
	}

	if (pj_is_latlong(dstpj)) to_dec(pt);
	return 1;
}
Exemple #9
0
/**Transforms a point in WGS84 LonLat in radians to projected coordinates.
   This version of the method changes the point in-place.

   call-seq: forward!(point) -> point

 */
static VALUE proj_forward(VALUE self,VALUE point){
  _wrap_pj* wpj;
  int pj_errno_ref;
  projLP pj_point;
  projXY pj_result;
  Data_Get_Struct(self,_wrap_pj,wpj);

  pj_point.u = NUM2DBL( rb_funcall(point, idGetX, 0) );
  pj_point.v = NUM2DBL( rb_funcall(point, idGetY, 0) );
  pj_result = pj_fwd(pj_point, wpj->pj);

  pj_errno_ref = *pj_get_errno_ref();
  if (pj_errno_ref == 0) {
    rb_funcall(point, idSetX, 1, rb_float_new(pj_result.u) );
    rb_funcall(point, idSetY, 1, rb_float_new(pj_result.v) );
    return point;
  } else if (pj_errno_ref > 0) {
    rb_raise(rb_eSystemCallError, "Unknown system call error");
  } else {
    raise_error(pj_errno_ref);
  }
  return self; /* Makes gcc happy */
}
Handle<Value> Projection::New(const Arguments& args)
{
    Projection      *proj;
    HandleScope     scope;
    
    if (args.Length() == 1 && args[0]->IsString()) {
        String::Utf8Value init(args[0]->ToString());
        proj = new Projection(*init);
        
        if (!proj->IsValid()) {
            int     *errno          = pj_get_errno_ref();
            char    *description    = pj_strerrno(*errno);
            
            return ThrowException(String::New(description));
        }
    }
    else {
        return ThrowException(String::New("No valid arguments passed for projection initialization string."));
    }
    
    proj->Wrap(args.This());
    return args.This();        
}
Exemple #11
0
void project(int *n, double *xlon, double *ylat, double *x, double *y, char **projarg){

  /* call the _forward_ projection specified by the string projarg,
  * using longitude and lat from xlon and ylat vectors, return
  * answers in x and y vectors (all vectors of length n) */

  int i;

  projUV p;
  projPJ pj;
  
  if (!(pj = pj_init_plus(*projarg))) 
    error(pj_strerrno(*pj_get_errno_ref()));
/*  Rprintf("%s\n", pj_get_def(pj, 0));*/

  for (i=0; i<*n; i++) {
    /* preserve NAs and NaNs. Allow Infs, since maybe proj can handle them. */
    if(ISNAN(xlon[i]) || ISNAN(ylat[i])){
      x[i]=xlon[i];
      y[i]=ylat[i];
    } else {
      p.u=xlon[i];
      p.v=ylat[i];
      p.u *= DEG_TO_RAD;
      p.v *= DEG_TO_RAD;
      p = pj_fwd(p, pj);
      if (p.u == HUGE_VAL || ISNAN(p.u)) {
	      Rprintf("projected point not finite\n");
      }
      x[i]=p.u;
      y[i]=p.v;
    }
  }

  pj_free(pj);
}
Exemple #12
0
 CRS(const std::string& crs) :
     m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
     if (!m_crs) {
         throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
     }
 }
Exemple #13
0
/**
 * Add an entry to the local PROJ4 SRS cache. If we need to wrap around then
 * we must make sure the entry we choose to delete does not contain other_srid
 * which is the definition for the other half of the transformation.
 */
static void
AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid)
{
	MemoryContext PJMemoryContext;
	projPJ projection = NULL;
	char *proj_str;
	int* pj_errno_ref;

	/*
	** Turn the SRID number into a proj4 string, by reading from spatial_ref_sys
	** or instantiating a magical value from a negative srid.
	*/
	proj_str = GetProj4String(srid);
	if ( ! proj_str )
	{
		elog(ERROR, "GetProj4String returned NULL for SRID (%d)", srid);
	}

	projection = lwproj_from_string(proj_str);

	pj_errno_ref = pj_get_errno_ref();
	if ( (projection == NULL) || (*pj_errno_ref))
	{
		/* we need this for error reporting */
		/*pfree(projection); */
		elog(ERROR, "AddToPROJ4SRSCache: couldn't parse proj4 string: '%s': %s", proj_str, pj_strerrno(*pj_errno_ref));
	}

	/*
	 * If the cache is already full then find the first entry
	 * that doesn't contain other_srid and use this as the
	 * subsequent value of PROJ4SRSCacheCount
	 */
	if (PROJ4Cache->PROJ4SRSCacheCount == PROJ4_CACHE_ITEMS)
	{
		bool found = false;
		int i;

		for (i = 0; i < PROJ4_CACHE_ITEMS; i++)
		{
			if (PROJ4Cache->PROJ4SRSCache[i].srid != other_srid && found == false)
			{
				POSTGIS_DEBUGF(3, "choosing to remove item from query cache with SRID %d and index %d", PROJ4Cache->PROJ4SRSCache[i].srid, i);

				DeleteFromPROJ4SRSCache(PROJ4Cache, PROJ4Cache->PROJ4SRSCache[i].srid);
				PROJ4Cache->PROJ4SRSCacheCount = i;

				found = true;
			}
		}
	}

	/*
	 * Now create a memory context for this projection and
	 * store it in the backend hash
	 */
	POSTGIS_DEBUGF(3, "adding SRID %d with proj4text \"%s\" to query cache at index %d", srid, proj_str, PROJ4Cache->PROJ4SRSCacheCount);

	PJMemoryContext = MemoryContextCreate(T_AllocSetContext, 8192,
	                                      &PROJ4SRSCacheContextMethods,
	                                      PROJ4Cache->PROJ4SRSCacheContext,
	                                      "PostGIS PROJ4 PJ Memory Context");

	/* Create the backend hash if it doesn't already exist */
	if (!PJHash)
		PJHash = CreatePJHash();

	/*
	 * Add the MemoryContext to the backend hash so we can
	 * clean up upon portal shutdown
	 */
	POSTGIS_DEBUGF(3, "adding projection object (%p) to hash table with MemoryContext key (%p)", projection, PJMemoryContext);

	AddPJHashEntry(PJMemoryContext, projection);

	PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].srid = srid;
	PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection = projection;
	PROJ4Cache->PROJ4SRSCache[PROJ4Cache->PROJ4SRSCacheCount].projection_mcxt = PJMemoryContext;
	PROJ4Cache->PROJ4SRSCacheCount++;

	/* Free the projection string */
	pfree(proj_str);

}
Exemple #14
0
SEXP transform(SEXP fromargs, SEXP toargs, SEXP npts, SEXP x, SEXP y) {

	/* interface to pj_transform() to be able to use longlat proj
	 * and datum transformation in an SEXP format */

	int i, n;
	double *xx, *yy, *zz;
	projPJ fromPJ, toPJ;
	SEXP res;
	
	if (!(fromPJ = pj_init_plus(CHAR(STRING_ELT(fromargs, 0))))) 
		error(pj_strerrno(*pj_get_errno_ref()));
	
	if (!(toPJ = pj_init_plus(CHAR(STRING_ELT(toargs, 0))))) 
		error(pj_strerrno(*pj_get_errno_ref()));
	
	n = INTEGER_POINTER(npts)[0];
	xx = (double *) R_alloc((long) n, sizeof(double));
	yy = (double *) R_alloc((long) n, sizeof(double));
	zz = (double *) R_alloc((long) n, sizeof(double));

	for (i=0; i < n; i++) {
		xx[i] = NUMERIC_POINTER(x)[i];
		yy[i] = NUMERIC_POINTER(y)[i];
		zz[i] = (double) 0;
	}
	if ( pj_is_latlong(fromPJ) ) {
		for (i=0; i < n; i++) {
       			 xx[i] *= DEG_TO_RAD;
       			 yy[i] *= DEG_TO_RAD;
		}
	}

	PROTECT(res = NEW_LIST(4));
	SET_VECTOR_ELT(res, 0, NEW_NUMERIC(n));
	SET_VECTOR_ELT(res, 1, NEW_NUMERIC(n));
	SET_VECTOR_ELT(res, 2, NEW_CHARACTER(1));
	SET_STRING_ELT(VECTOR_ELT(res, 2), 0, 
		COPY_TO_USER_STRING(pj_get_def(fromPJ, 0)));
	SET_VECTOR_ELT(res, 3, NEW_CHARACTER(1));
	SET_STRING_ELT(VECTOR_ELT(res, 3), 0, 
		COPY_TO_USER_STRING(pj_get_def(toPJ, 0)));

	if( pj_transform( fromPJ, toPJ, (long) n, 0, xx, yy, zz ) != 0 ) {
		pj_free(fromPJ); pj_free(toPJ);
		Rprintf("error in pj_transform\n");
		error(pj_strerrno(*pj_get_errno_ref()));
	}

        pj_free(fromPJ); pj_free(toPJ);
	if ( pj_is_latlong(toPJ) ) {
		for (i=0; i < n; i++) {
               		xx[i] *= RAD_TO_DEG;
               		yy[i] *= RAD_TO_DEG;
            	}
	}
	for (i=0; i < n; i++) {
		if (xx[i] == HUGE_VAL || yy[i] == HUGE_VAL 
		    || ISNAN(xx[i]) || ISNAN(yy[i])) {
		    Rprintf("transformed point not finite\n");
		}
		NUMERIC_POINTER(VECTOR_ELT(res, 0))[i] = xx[i];
		NUMERIC_POINTER(VECTOR_ELT(res, 1))[i] = yy[i];
	}

	UNPROTECT(1);
	return(res);
}
Exemple #15
0
/* file processing function --- verbosely */
static void vprocess(FILE *fid) {
    char line[MAX_LINE+3], *s, pline[40];
    PJ_LP dat_ll;
    PJ_XY dat_xy;
    int linvers;
    PJ_COORD coord;


    if (!oform)
        oform = "%.3f";

    if (bin_in || bin_out)
        emess(1,"binary I/O not available in -V option");

    for (;;) {
        proj_errno_reset(Proj);
        ++emess_dat.File_line;

        if (!(s = fgets(line, MAX_LINE, fid)))
            break;

        if (!strchr(s, '\n')) { /* overlong line */
            int c;
            (void)strcat(s, "\n");
            /* gobble up to newline */
            while ((c = fgetc(fid)) != EOF && c != '\n') ;
        }

        if (*s == tag) { /* pass on data */
            (void)fputs(s, stdout);
            continue;
        }

        /* check to override default input mode */
        if (*s == 'I' || *s == 'i') {
            linvers = 1;
            ++s;
        } else
            linvers = inverse;

        if (linvers) {
            if (!PJ_INVERS(Proj)) {
                emess(-1,"inverse for this projection not avail.\n");
                continue;
            }
            dat_xy.x = strtod(s, &s);
            dat_xy.y = strtod(s, &s);
            if (dat_xy.x == HUGE_VAL || dat_xy.y == HUGE_VAL) {
                emess(-1,"lon-lat input conversion failure\n");
                continue;
            }
            if (prescale) { dat_xy.x *= fscale; dat_xy.y *= fscale; }
            if (reversein) {
                PJ_XY temp = dat_xy;
                dat_xy.x = temp.y;
                dat_xy.y = temp.x;
            }
            dat_ll = pj_inv(dat_xy, Proj);
        } else {
            dat_ll.lam = proj_dmstor(s, &s);
            dat_ll.phi = proj_dmstor(s, &s);
            if (dat_ll.lam == HUGE_VAL || dat_ll.phi == HUGE_VAL) {
                emess(-1,"lon-lat input conversion failure\n");
                continue;
            }
            if (reversein) {
                PJ_LP temp = dat_ll;
                dat_ll.lam = temp.phi;
                dat_ll.phi = temp.lam;
            }
            dat_xy = pj_fwd(dat_ll, Proj);
            if (postscale) { dat_xy.x *= fscale; dat_xy.y *= fscale; }
        }

        /* For some reason pj_errno does not work as expected in some   */
        /* versions of Visual Studio, so using pj_get_errno_ref instead */
        if (*pj_get_errno_ref()) {
            emess(-1, pj_strerrno(*pj_get_errno_ref()));
            continue;
        }

        if (!*s && (s > line)) --s; /* assumed we gobbled \n */
        coord.lp = dat_ll;
        facs = proj_factors(Proj, coord);
        if (proj_errno(Proj)) {
            emess(-1,"failed to compute factors\n\n");
            continue;
        }

        if (*s != '\n')
            (void)fputs(s, stdout);

        (void)fputs("Longitude: ", stdout);
        (void)fputs(proj_rtodms(pline, dat_ll.lam, 'E', 'W'), stdout);
        (void)printf(" [ %.11g ]\n", dat_ll.lam * RAD_TO_DEG);
        (void)fputs("Latitude:  ", stdout);
        (void)fputs(proj_rtodms(pline, dat_ll.phi, 'N', 'S'), stdout);
        (void)printf(" [ %.11g ]\n", dat_ll.phi * RAD_TO_DEG);
        (void)fputs("Easting (x):   ", stdout);
        (void)printf(oform, dat_xy.x); putchar('\n');
        (void)fputs("Northing (y):  ", stdout);
        (void)printf(oform, dat_xy.y); putchar('\n');
        (void)printf("Meridian scale (h) : %.8f  ( %.4g %% error )\n", facs.meridional_scale, (facs.meridional_scale-1.)*100.);
        (void)printf("Parallel scale (k) : %.8f  ( %.4g %% error )\n", facs.parallel_scale, (facs.parallel_scale-1.)*100.);
        (void)printf("Areal scale (s):     %.8f  ( %.4g %% error )\n", facs.areal_scale, (facs.areal_scale-1.)*100.);
        (void)printf("Angular distortion (w): %.3f\n", facs.angular_distortion * RAD_TO_DEG);
        (void)printf("Meridian/Parallel angle: %.5f\n", facs.meridian_parallel_angle * RAD_TO_DEG);
        (void)printf("Convergence : ");
        (void)fputs(proj_rtodms(pline, facs.meridian_convergence, 0, 0), stdout);
        (void)printf(" [ %.8f ]\n", facs.meridian_convergence * RAD_TO_DEG);
        (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", facs.tissot_semimajor, facs.tissot_semiminor);
    }
}
Exemple #16
0
JNIEXPORT int JNICALL Java_org_gvsig_crs_proj_JNIBaseCrs_getErrno
(JNIEnv * env, jobject parent)
{
	int *err = pj_get_errno_ref();
	return *err;
}
Datum transform_geom(PG_FUNCTION_ARGS)
{
	GSERIALIZED *geom;
	GSERIALIZED *result=NULL;
	LWGEOM *lwgeom;
	projPJ input_pj, output_pj;
	char *input_proj4, *output_proj4;
	text *input_proj4_text;
	text *output_proj4_text;
	int32 result_srid ;
	char *pj_errstr;



	result_srid = PG_GETARG_INT32(3);
	if (result_srid == SRID_UNKNOWN)
	{
		elog(ERROR,"tranform: destination SRID = %d",SRID_UNKNOWN);
		PG_RETURN_NULL();
	}

	geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
	if (gserialized_get_srid(geom) == SRID_UNKNOWN)
	{
		pfree(geom);
		elog(ERROR,"transform_geom: source SRID = %d",SRID_UNKNOWN);
		PG_RETURN_NULL();
	}

	/* Set the search path if we haven't already */
	SetPROJ4LibPath();

	/* Read the arguments */
	input_proj4_text  = (PG_GETARG_TEXT_P(1));
	output_proj4_text = (PG_GETARG_TEXT_P(2));

	/* Convert from text to cstring for libproj */
	input_proj4 = text2cstring(input_proj4_text);
	output_proj4 = text2cstring(output_proj4_text);

	/* make input and output projection objects */
	input_pj = lwproj_from_string(input_proj4);
	if ( input_pj == NULL )
	{
		pj_errstr = pj_strerrno(*pj_get_errno_ref());
		if ( ! pj_errstr ) pj_errstr = "";

		/* we need this for error reporting */
		/* pfree(input_proj4); */
		pfree(output_proj4);
		pfree(geom);
		
		elog(ERROR,
		    "transform_geom: could not parse proj4 string '%s' %s",
		    input_proj4, pj_errstr);
		PG_RETURN_NULL();
	}
	pfree(input_proj4);

	output_pj = lwproj_from_string(output_proj4);

	if ( output_pj == NULL )
	{
		pj_errstr = pj_strerrno(*pj_get_errno_ref());
		if ( ! pj_errstr ) pj_errstr = "";

		/* we need this for error reporting */
		/* pfree(output_proj4); */
		pj_free(input_pj);
		pfree(geom);

		elog(ERROR,
			"transform_geom: couldn't parse proj4 output string: '%s': %s",
			output_proj4, pj_errstr);
		PG_RETURN_NULL();
	}
	pfree(output_proj4);

	/* now we have a geometry, and input/output PJ structs. */
	lwgeom = lwgeom_from_gserialized(geom);
	lwgeom_transform(lwgeom, input_pj, output_pj);
	lwgeom->srid = result_srid;

	/* clean up */
	pj_free(input_pj);
	pj_free(output_pj);

	/* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */
	if ( lwgeom->bbox )
	{
		lwgeom_drop_bbox(lwgeom);
		lwgeom_add_bbox(lwgeom);
	}

	result = geometry_serialize(lwgeom);

	lwgeom_free(lwgeom);
	PG_FREE_IF_COPY(geom, 0);

	PG_RETURN_POINTER(result); /* new geometry */
}