]> granicus.if.org Git - postgis/commitdiff
Coordinate transformation function, transform() added in this file.
authorDavid Blasby <dblasby@gmail.com>
Fri, 21 Dec 2001 23:01:35 +0000 (23:01 +0000)
committerDavid Blasby <dblasby@gmail.com>
Fri, 21 Dec 2001 23:01:35 +0000 (23:01 +0000)
Adds requirement for linking the proj4 library if non-null version of
function is requested.

git-svn-id: http://svn.osgeo.org/postgis/trunk@114 b70326c6-7e19-0410-871a-916f4a2858ee

Makefile
postgis.h
postgis.sql.in
postgis_proj.c
postgis_transform.c

index 40181e363bc108c69bbaf70f52818b2c1f7397b4..2fa033416d5291bbc6e370929328422fef7db04f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,17 +21,18 @@ NAME=postgis
 SO_MAJOR_VERSION=0
 SO_MINOR_VERSION=6
 
+
 #override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
 # Altered for Cynwin
-override CPPFLAGS := -g  -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
+override CPPFLAGS := -g  -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"' -DWANT_PROJECTION 
 override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS)
 
-OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o
+OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o
 
 # Add libraries that libpq depends (or might depend) on into the
 # shared library link.  (The order in which you list them here doesn't
 # matter.)
-SHLIB_LINK = $(filter -L%, $(LDFLAGS))
+SHLIB_LINK = $(filter -L%, $(LDFLAGS)) -lproj
 
 all: all-lib $(NAME).sql $(NAME)_undef.sql loaderdumper
 
index 4bfd2d4497c8965d4a3310472a95ff9d2aa2e242..56083c1d5c0c629ab830de935ba657f3f4ceb4fa 100644 (file)
--- a/postgis.h
+++ b/postgis.h
@@ -347,6 +347,9 @@ void deparse_hex(unsigned char str, unsigned char *result);
 
 char *geometry_to_text(GEOMETRY  *geometry);
 
+
+
+
 //exposed to psql
 
 Datum box3d_in(PG_FUNCTION_ARGS);
@@ -456,6 +459,10 @@ Datum height_chip(PG_FUNCTION_ARGS);
 Datum datatype_chip(PG_FUNCTION_ARGS);
 Datum compression_chip(PG_FUNCTION_ARGS);
 
+
+Datum transform_geom(PG_FUNCTION_ARGS);
+
+
 //for GIST index
 typedef char* (*BINARY_UNION)(char*, char*, int*);
 typedef float (*SIZE_BOX)(char*);
index 1bb84751dc8df94d5e17e9ef5b11536f3e805890..438120ae4a4669de4b78a44927e10f7e62838e90 100644 (file)
@@ -24,7 +24,8 @@ create table spatial_ref_sys (
         srid integer not null primary key,
         auth_name varchar(256), 
         auth_srid integer, 
-        srtext varchar(2048) 
+        srtext varchar(2048),
+        proj4text varchar(2048) 
                                        );
 
 -- create the metadata table.  spec, section 3.2.2.1
@@ -52,6 +53,35 @@ CREATE FUNCTION find_SRID(varchar,varchar,varchar) returns int4 as
 -- select find_srid('','geometry_test','mygeom');
 
 
+-- given an SRID, find the proj4 definition string
+CREATE FUNCTION get_proj4_from_srid(integer) returns text as
+'SELECT proj4text::text FROM spatial_ref_sys WHERE srid= $1' 
+LANGUAGE 'sql' with (iscachable,isstrict);
+
+-- select get_proj4_from_srid(1);
+
+
+
+--- drop function transform(geometry,integer);
+-- given a geometry and a SRID, convert the geometry to the new SRID
+--     transform(geometry,new_srid)
+CREATE FUNCTION transform(geometry,integer) returns geometry as
+'BEGIN
+  RETURN transform_geometry( $1 , get_proj4_from_srid(SRID( $1 ) ), get_proj4_from_srid( $2 ), $2  );
+ END;
+'
+LANGUAGE 'plpgsql' with (iscachable,isstrict);
+
+-- test:
+--- trans=# select * from spatial_ref_sys ;
+--- srid |   auth_name   | auth_srid | srtext |                                proj4text                                 
+--- ------+---------------+-----------+--------+--------------------------------------------------------------------------
+---    1 | latlong WGS84 |         1 |        | +proj=longlat +datum=WGS84
+---    2 | BC albers     |         2 |        | proj=aea ellps=GRS80 lon_0=-126 lat_0=45 lat_1=50 lat_2=58.5 x_0=1000000
+
+-- select transform( 'SRID=1;POINT(-120.8 50.3)', 2);
+---   -> 'SRID=2;POINT(1370033.37046971 600755.810968684)'
+
 
 --- DropGeometryColumn(<db name>,<table name>,<column name>)
 --- There is no ALTER TABLE DROP COLUMN command in postgresql
@@ -240,6 +270,12 @@ create function WKB_in(opaque)
    AS '@MODULE_FILENAME@','WKB_in'
    LANGUAGE 'c' with (isstrict);
 
+create function transform_geometry(geometry,text,text,int)
+       RETURNS geometry
+   AS '@MODULE_FILENAME@','transform_geom'
+   LANGUAGE 'c' with (isstrict,iscachable);
+
+
 create function WKB_out(opaque)
        RETURNS opaque
    AS '@MODULE_FILENAME@','WKB_out'
index d05441fdecbab43e60a0291b50c6458b63ba5969..a93b9e8d8428c4bcdc557a1c632efc0cfa102c0d 100644 (file)
@@ -162,6 +162,8 @@ double      distance_ellipse(double lat1, double long1,
        double u2,A,B;
        double dsigma;
 
+       int iterations;  
+
        L1 = atan((1.0 - sphere->f ) * tan( lat1) );
        L2 = atan((1.0 - sphere->f ) * tan( lat2) );
        sinU1 = sin(L1);
@@ -173,6 +175,7 @@ double      distance_ellipse(double lat1, double long1,
        dl1 = dl;
        cosdl1 = cos(dl);
        sindl1 = sin(dl);
+       iterations = 0;
        do {
                cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosdl1;
                sigma = acos(cosSigma);
@@ -183,7 +186,8 @@ double      distance_ellipse(double lat1, double long1,
                dl1 = dl + dl2;
                cosdl1 = cos(dl1);
                sindl1 = sin(dl1);
-       } while (fabs(dl3) > 1.0e-032);
+               iterations++;
+       } while ( (iterations<999) && (fabs(dl3) > 1.0e-032));
 
           // compute expansions A and B 
        u2 = mu2(azimuthEQ,sphere);
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7abf1782c36da950beda7f0aa19a61e32fb28f82 100644 (file)
@@ -0,0 +1,265 @@
+#include "postgres.h"
+
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+
+
+#include "fmgr.h"
+
+
+#include "postgis.h"
+#include "utils/elog.h"
+
+#include "projects.h"
+
+
+#define SHOW_DIGS_DOUBLE 15
+#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
+
+
+// if WANT_PROJECTION undefined, we get a do-nothing transform() function
+#ifdef WANT_PROJECTION
+
+PJ *make_project(char *str1);
+void to_rad(POINT3D *pts, int num_points);
+void to_dec(POINT3D *pts, int num_points);
+
+
+// convert decimal degress to radians
+void to_rad(POINT3D *pts, int num_points)
+{
+       int t;
+       for(t=0;t<num_points;t++)
+       {
+               pts[t].x *= PI/180.0;
+               pts[t].y *= PI/180.0;
+       }
+}
+
+// convert radians to decimal degress
+void to_dec(POINT3D *pts, int num_points)
+{
+       int t;
+       for(t=0;t<num_points;t++)
+       {
+               pts[t].x *= 180.0/PI;
+               pts[t].y *= 180.0/PI;
+       }
+
+}
+
+       //given a string, make a PJ object
+PJ *make_project(char *str1)
+{
+       int t;
+       char    *params[1024];  //one for each parameter
+       char  *loc;
+       char    *str;
+       PJ *result;
+       
+
+       if (str1 == NULL)
+               return NULL;
+
+       if (strlen(str1) ==0)
+               return NULL;
+
+       str = palloc(1+strlen(str1) );
+       strcpy(str,str1);
+
+       //first we split the string into a bunch of smaller strings, based on the " " separator
+       
+       params[0] = str; //1st param, we'll null terminate at the " " soon
+
+       loc = str;
+       t =1;
+       while  ((loc != NULL) && (*loc != 0) )
+       {
+               loc = strchr( loc,' ');
+               if (loc != NULL)
+               {
+                       *loc = 0; // null terminate
+                       params[t] = loc +1;
+                       loc++; // next char
+                       t++; //next param 
+               }
+       }
+       
+       if (!(result= pj_init ( t , params)))
+       {
+               pfree(str);     
+               return NULL;
+       }
+       pfree(str);     
+       return result;
+}
+
+
+       //tranform_geom( GEOMETRY, TEXT (input proj4), TEXT (input proj4), INT (output srid)
+PG_FUNCTION_INFO_V1(transform_geom);
+Datum transform_geom(PG_FUNCTION_ARGS)
+{
+       GEOMETRY                   *geom = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       GEOMETRY                   *result;
+       PJ                         *input_pj,*output_pj;
+
+       char                            *o1;
+       int32                           *offsets1;
+       int                             j,type1,i,poly_points;
+
+       POLYGON3D                       *poly;
+       LINE3D                  *line;
+       POINT3D                 *pt,*poly_pts;
+
+       char                            *input_proj4, *output_proj4;
+
+       
+       text       *input_proj4_text  = (PG_GETARG_TEXT_P(1));
+       text       *output_proj4_text = (PG_GETARG_TEXT_P(2));
+       int32      result_srid   = PG_GETARG_INT32(3);
+
+       input_proj4 = (char *) palloc(input_proj4_text->vl_len +1-4);
+      memcpy(input_proj4,input_proj4_text->vl_dat, input_proj4_text->vl_len-4);
+       input_proj4[input_proj4_text->vl_len-4] = 0; //null terminate
+
+       output_proj4 = (char *) palloc(output_proj4_text->vl_len +1-4);
+      memcpy(output_proj4,output_proj4_text->vl_dat, output_proj4_text->vl_len-4);
+       output_proj4[output_proj4_text->vl_len-4] = 0; //null terminate
+
+       if (geom->SRID == -1)
+       {
+               pfree(input_proj4); pfree(output_proj4);
+               elog(ERROR,"tranform: source SRID = -1");
+               PG_RETURN_NULL();                       // no srid, cannot convert
+       }
+       
+       if (result_srid   == -1)
+       {
+               pfree(input_proj4); pfree(output_proj4);
+               elog(ERROR,"tranform: destination SRID = -1");  
+               PG_RETURN_NULL();                       // no srid, cannot convert
+       }
+
+       //make input and output projection objects
+       input_pj = make_project(input_proj4);
+       if ( (input_pj == NULL) || pj_errno) 
+       {
+               pfree(input_proj4); pfree(output_proj4);
+               elog(ERROR,"tranform: couldnt parse proj4 input string");
+               PG_RETURN_NULL();
+       }
+
+       output_pj = make_project(output_proj4);
+       if ((output_pj == NULL)|| pj_errno)
+       {
+               pfree(input_proj4); pfree(output_proj4);
+               pj_free(input_pj);
+               elog(ERROR,"tranform: couldnt parse proj4 output string");
+               
+               PG_RETURN_NULL();
+       }
+       //great, now we have a geometry, and input/output PJ* structs.  Excellent.
+
+               //copy the geometry structure - we're only going to change the points, not the structures
+       result = (GEOMETRY *) palloc (geom->size);
+       memcpy(result,geom, geom->size);
+
+               //handle each sub-geometry
+               offsets1 = (int32 *) ( ((char *) &(result->objType[0] ))+ sizeof(int32) * result->nobjs ) ;
+               for (j=0; j< result->nobjs; j++)                //for each object in geom1
+               {
+                       o1 = (char *) result +offsets1[j] ;  
+                       type1=  result->objType[j];
+
+                       if (type1 == POINTTYPE) //point
+                       {
+                               pt = (POINT3D *) o1;
+                               if (input_pj->is_latlong)
+                                       to_rad(pt,1);
+                               pj_transform(input_pj,output_pj, 1,3, &pt->x,&pt->y, &pt->z);
+                               if (pj_errno )
+                               {
+                                       pfree(input_proj4); pfree(output_proj4);
+                                       pj_free(input_pj); pj_free(output_pj);
+                                       elog(ERROR,"tranform: couldnt project point");
+                                       PG_RETURN_NULL();       
+                               }
+                               if (output_pj->is_latlong)
+                                       to_dec(pt,1);
+                       }
+                       if (type1 == LINETYPE)  //line
+                       {
+                               line = (LINE3D *) o1;
+                               if (input_pj->is_latlong)
+                                       to_rad(&line->points[0],line->npoints);
+                               pj_transform(input_pj,output_pj, line->npoints ,3, 
+                                                       &line->points[0].x,&line->points[0].y, &line->points[0].z);
+                               if (pj_errno )
+                               {
+                                       pfree(input_proj4); pfree(output_proj4);
+                                       pj_free(input_pj); pj_free(output_pj);
+                                       elog(ERROR,"tranform: couldnt project line");
+                                       PG_RETURN_NULL();       
+                               }
+                               if (output_pj->is_latlong)
+                                       to_dec(&line->points[0],line->npoints);
+                       }
+                       if (type1 == POLYGONTYPE)       //POLYGON
+                       {
+                               poly = (POLYGON3D *) o1;
+                               poly_points = 0;
+
+                               for (i=0; i<poly->nrings;i++)
+                               {
+                                       poly_points  += poly->npoints[i];
+                               }
+                               poly_pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] )  );
+                               if (input_pj->is_latlong)
+                                       to_rad(poly_pts , poly_points);
+
+                               pj_transform(input_pj,output_pj, poly_points,3, 
+                                                       &poly_pts[0].x,&poly_pts[0].y, &poly_pts[0].z);
+                               if (pj_errno)
+                               {
+                                       pfree(input_proj4); pfree(output_proj4);
+                                       pj_free(input_pj); pj_free(output_pj);
+                                       elog(ERROR,"tranform: couldnt project polygon");
+                                       PG_RETURN_NULL();       
+                               }
+                               if (output_pj->is_latlong)
+                                       to_dec(poly_pts , poly_points);
+                       }
+               }
+
+       // clean up
+       pj_free(input_pj);
+       pj_free(output_pj);
+       pfree(input_proj4); pfree(output_proj4);
+
+       result->SRID = result_srid   ;
+       PG_RETURN_POINTER(result); // new geometry
+}
+
+
+#else   
+
+       // return the original geometry
+PG_FUNCTION_INFO_V1(transform_geom);
+Datum transform_geom(PG_FUNCTION_ARGS)
+{
+       GEOMETRY                   *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       GEOMETRY                   *result;
+
+       result = (GEOMETRY *) palloc (geom1->size);
+       memcpy(result,geom1, geom1->size);
+       PG_RETURN_POINTER(result);
+}
+#endif
\ No newline at end of file