]> granicus.if.org Git - postgis/commitdiff
#897 (part of #2840 ) Support for X3D Geocoordinate (just WGS 84 for now), also...
authorRegina Obe <lr@pcorp.us>
Sat, 9 May 2015 22:57:15 +0000 (22:57 +0000)
committerRegina Obe <lr@pcorp.us>
Sat, 9 May 2015 22:57:15 +0000 (22:57 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13485 b70326c6-7e19-0410-871a-916f4a2858ee

doc/reference_output.xml
liblwgeom/cunit/cu_out_x3d.c
liblwgeom/liblwgeom.h.in
liblwgeom/lwout_x3d.c
postgis/lwgeom_export.c

index 9b5286decc538b9545789d740205ea15e08cb963..59c7f7543c26d91d14906cfaeff0fc4dae2b6ef0 100644 (file)
@@ -781,11 +781,28 @@ SELECT ST_AsGML(3, ST_GeomFromEWKT('POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0
 
                <para>Returns a geometry as an X3D xml formatted node element  <ulink url="http://www.web3d.org/standards/number/19776-1">http://www.web3d.org/standards/number/19776-1</ulink>.  If <varname>maxdecimaldigits</varname> (precision) is not specified then defaults to 15. </para>
                <note>
-                   <para>There are various options for translating PostGIS geometries to X3D since X3D geometry types don't map directly to PostGIS geometry types and some newer X3D types that might be better mappings we ahve avoided since most rendering tools don't currently support them.  
+                   <para>There are various options for translating PostGIS geometries to X3D since X3D geometry types don't map directly to PostGIS geometry types and some newer X3D types that might be better mappings we have avoided since most rendering tools don't currently support them.  
                        These are the mappings we have settled on.  Feel free to post a bug ticket if you have thoughts on the idea or ways we can allow people to denote their preferred mappings.</para>
                    <para>Below is how we currently map PostGIS 2D/3D types to X3D types</para>
                </note>
                
+               <para>The 'options' argument is a bitfield. For PostGIS 2.2+, this is used to denote whether to represent coordinates with X3D GeoCoordinates Geospatial node and also whether to flip the x/y axis.  By default, <code>ST_AsX3D</code> outputs in database form (long,lat or X,Y), but X3D default of lat/lon, y/x may be preferred.</para>
+          <itemizedlist>
+                <listitem>
+                  <para>0: X/Y in database order (e.g. long/lat = X,Y is standard database order), default value, and non-spatial coordinates (just regular old Coordinate tag).</para>
+                </listitem>
+
+                <listitem>
+                  <para>1: Flip X and Y.  If used in conjunction with the GeoCoordinate option switch, then output will be default "latitude_first" and coordinates will be flipped as well.</para>
+                </listitem>
+
+                <listitem>
+                  <para>2: Output coordinates in GeoSpatial GeoCoordinates.  This option will throw an error if geometries are not in WGS 84 long lat (srid: 4326). This is currenlty the only GeoCoordinate type supported.  <ulink url="http://www.web3d.org/documents/specifications/19775-1/V3.2/Part01/components/geodata.html#Specifyingaspatialreference">Refer to X3D specs specifying a spatial reference system.</ulink>. Default output will be <code>GeoCoordinate geoSystem='"GD" "WE" "longitude_first"'</code>.  If
+                  you prefer the X3D default of  <code>GeoCoordinate geoSystem='"GD" "WE" "latitude_first"'</code> use <code>(2 + 1)</code> = <code>3</code> </para>
+                </listitem>
+          </itemizedlist>
+        </para>
+               
                <informaltable>
                                <tgroup cols="3">
                                        <thead>
@@ -833,7 +850,8 @@ SELECT ST_AsGML(3, ST_GeomFromEWKT('POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0
                <para>Lots of advancements happening in 3D space particularly with <ulink url="http://www.web3d.org/x3d/wiki/index.php/X3D_and_HTML5#Goals:_X3D_and_HTML5">X3D Integration with HTML5</ulink></para>
                <para>There is also a nice open source X3D viewer you can use to view rendered geometries. Free Wrl <ulink url="http://freewrl.sourceforge.net/">http://freewrl.sourceforge.net/</ulink> binaries available for Mac, Linux, and Windows. Use the FreeWRL_Launcher packaged to view the geometries.</para>
                <para>Also check out <ulink url="https://github.com/robe2/postgis_x3d_viewer">PostGIS minimalist X3D viewer</ulink>  that utilizes this function and <ulink url="http://www.x3dom.org/">x3dDom html/js open source toolkit</ulink>.</para>
-               <para>Availability: 2.0.0: ISO-IEC-19776-1.2-X3DEncodings-XML</para>    
+               <para>Availability: 2.0.0: ISO-IEC-19776-1.2-X3DEncodings-XML</para>
+               <para>Enhanced: 2.2.0: Support for GeoCoordinates and axis (x/y, long/lat) flipping.  Look at options for details.</para>       
                <!-- Optionally mention 3d support -->
                <para>&Z_support;</para>
         <!-- Optionally mention supports Polyhedral Surface  -->
index 52a33e270b98ef22d81a498162e78175d4caf2e7..2830fd157a374f3de92a7e2ef786d4c6d7cfd268 100644 (file)
 #include "liblwgeom_internal.h"
 #include "cu_tester.h"
 
-static void do_x3d3_test(char * in, char * out, char * srs, int precision)
+static void do_x3d3_test(char * in, char * out, char * srs, int precision, int option)
 {
        LWGEOM *g;
        char * h;
 
        g = lwgeom_from_wkt(in, LW_PARSER_CHECK_NONE);
-       h = lwgeom_to_x3d3(g, srs, precision, 0, "");
+       h = lwgeom_to_x3d3(g, srs, precision, option, "");
 
        if (strcmp(h, out))
                fprintf(stderr, "\nIn:   %s\nOut:  %s\nTheo: %s\n", in, h, out);
@@ -62,40 +62,41 @@ static void out_x3d3_test_precision(void)
        do_x3d3_test(
            "POINT(1.1111111111111 1.1111111111111 2.11111111111111)",
            "1 1 2",
-           NULL, 0);
+           NULL, 0, 0);
 
        /* 3 digits precision */
        do_x3d3_test(
            "POINT(1.1111111111111 1.1111111111111 2.11111111111111)",
            "1.111 1.111 2.111",
-           NULL, 3);
+           NULL, 3, 0);
 
        /* 9 digits precision */
        do_x3d3_test(
            "POINT(1.2345678901234 1.2345678901234 4.123456789001)",
            "1.23456789 1.23456789 4.123456789",
-           NULL, 9);
+           NULL, 9, 0);
 
        /* huge data */
        do_x3d3_test(
            "POINT(1E300 -105E-153 4E300)'",
            "1e+300 -0 4e+300",
-           NULL, 0);
+           NULL, 0, 0);
 }
 
+
 static void out_x3d3_test_geoms(void)
 {
        /* Linestring */
        do_x3d3_test(
            "LINESTRING(0 1 5,2 3 6,4 5 7)",
            "<LineSet  vertexCount='3'><Coordinate point='0 1 5 2 3 6 4 5 7' /></LineSet>",
-           NULL, 0);
+           NULL, 0, 0);
 
        /* Polygon **/
        do_x3d3_test(
            "POLYGON((15 10 3,13.536 6.464 3,10 5 3,6.464 6.464 3,5 10 3,6.464 13.536 3,10 15 3,13.536 13.536 3,15 10 3))",
            "<IndexedFaceSet  coordIndex='0 1 2 3 4 5 6 7'><Coordinate point='15 10 3 13.536 6.464 3 10 5 3 6.464 6.464 3 5 10 3 6.464 13.536 3 10 15 3 13.536 13.536 3 ' /></IndexedFaceSet>",
-           NULL, 3);
+           NULL, 3, 0);
 
        /* TODO: Polygon - with internal ring - the answer is clearly wrong */
        /** do_x3d3_test(
@@ -107,30 +108,30 @@ static void out_x3d3_test_geoms(void)
        do_x3d3_test(
            "MULTIPOINT(0 1,2 3,4 5)",
            "<Polypoint2D  point='0 1 2 3 4 5 ' />",
-           NULL, 0);
+           NULL, 0, 0);
        
        /* 3D MultiPoint */
        do_x3d3_test(
            "MULTIPOINT Z(0 1 1,2 3 4,4 5 5)",
            "<PointSet ><Coordinate point='0 1 1 2 3 4 4 5 5 ' /></PointSet>",
-           NULL, 0);
+           NULL, 0, 0);
        /* 3D Multiline */
        do_x3d3_test(
            "MULTILINESTRING Z((0 1 1,2 3 4,4 5 5),(6 7 5,8 9 8,10 11 5))",
            "<IndexedLineSet  coordIndex='0 1 2 -1 3 4 5'><Coordinate point='0 1 1 2 3 4 4 5 5 6 7 5 8 9 8 10 11 5 ' /></IndexedLineSet>",
-           NULL, 0);
+           NULL, 0, 0);
 
        /* MultiPolygon */
        do_x3d3_test(
            "MULTIPOLYGON(((0 1 1,2 3 1,4 5 1,0 1 1)),((6 7 1,8 9 1,10 11 1,6 7 1)))",
            "<IndexedFaceSet  coordIndex='0 1 2 -1 3 4 5'><Coordinate point='0 1 1 2 3 1 4 5 1 6 7 1 8 9 1 10 11 1 ' /></IndexedFaceSet>",
-           NULL, 0);
+           NULL, 0, 0);
        
        /* PolyhedralSurface */
        do_x3d3_test(
            "POLYHEDRALSURFACE( ((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), ((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)), ((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)), ((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )",
            "<IndexedFaceSet  coordIndex='0 1 2 3 -1 4 5 6 7 -1 8 9 10 11 -1 12 13 14 15 -1 16 17 18 19 -1 20 21 22 23'><Coordinate point='0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 1 0 0 1 0 1 0 0 1 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 1 0 1 1' /></IndexedFaceSet>",
-           NULL, 0);
+           NULL, 0, 0);
 
        /* TODO: returns garbage at moment correctly implement GeometryCollection -- */
        /** do_x3d3_test(
@@ -156,6 +157,30 @@ static void out_x3d3_test_geoms(void)
 
 }
 
+static void out_x3d3_test_option(void)
+{
+       /* 0 precision, flip coordinates*/
+       do_x3d3_test(
+           "POINT(3.1111111111111 1.1111111111111 2.11111111111111)",
+           "1 3 2",
+           NULL, 0, 1);
+               
+       /* geocoordinate long,lat*/
+       do_x3d3_test(
+           "SRID=4326;POLYGON((15 10 3,13.536 6.464 3,10 5 3,6.464 6.464 3,5 10 3,6.464 13.536 3,10 15 3,13.536 13.536 3,15 10 3))",
+           "<IndexedFaceSet  coordIndex='0 1 2 3 4 5 6 7'><GeoCoordinate geoSystem='\"GD\" \"WE\" \"longitude_first\"' point='15 10 3 13.536 6.464 3 10 5 3 6.464 6.464 3 5 10 3 6.464 13.536 3 10 15 3 13.536 13.536 3 ' /></IndexedFaceSet>",
+           NULL, 3, 2);
+               
+       /* geocoordinate lat long*/
+       do_x3d3_test(
+           "SRID=4326;POLYGON((15 10 3,13.536 6.464 3,10 5 3,6.464 6.464 3,5 10 3,6.464 13.536 3,10 15 3,13.536 13.536 3,15 10 3))",
+           "<IndexedFaceSet  coordIndex='0 1 2 3 4 5 6 7'><GeoCoordinate geoSystem='\"GD\" \"WE\" \"latitude_first\"' point='10 15 3 6.464 13.536 3 5 10 3 6.464 6.464 3 10 5 3 13.536 6.464 3 15 10 3 13.536 13.536 3 ' /></IndexedFaceSet>",
+           NULL, 3, 3);
+
+
+}
+
+
 /*
 ** Used by test harness to register the tests in this file.
 */
@@ -165,4 +190,5 @@ void out_x3d_suite_setup(void)
        CU_pSuite suite = CU_add_suite("x3d_output", NULL, NULL);
        PG_ADD_TEST(suite, out_x3d3_test_precision);
        PG_ADD_TEST(suite, out_x3d3_test_geoms);
+       PG_ADD_TEST(suite, out_x3d3_test_option);
 }
index 8b5b6d78d73df573dd5acd75830b17d8ce1b22ba..1dcd3fbd6e0ca3baf86219d9e4c8e25d72574acf 100644 (file)
@@ -1470,6 +1470,17 @@ LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, d
 #define IS_DEGREE(x) ((x) & LW_GML_IS_DEGREE)
 /** @} */
 
+/**
+ * Macros for specifying X3D options. 
+ * @{
+ */
+/** For flip X/Y coordinates to Y/X */
+#define LW_X3D_FLIP_XY     (1<<0)
+#define LW_X3D_USE_GEOCOORDS     (1<<1)
+#define X3D_USE_GEOCOORDS(x) ((x) & LW_X3D_USE_GEOCOORDS)
+
+
+
 extern char* lwgeom_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix);
 extern char* lwgeom_extent_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix);
 /**
index e80ca97dd035b25cc88c2cda1068124c413a276b..efe514a2f3f74416031ed0db0b4c87dbef508a32 100644 (file)
@@ -2,9 +2,9 @@
  * $Id$
  *
  * PostGIS - Spatial Types for PostgreSQL
- * http://www.postgis.org
+ * http://postgis.net
  * adapted from lwout_asgml.c
- * Copyright 2011 Arrival 3D
+ * Copyright 2011-2015 Arrival 3D
  *                             Regina Obe with input from Dave Arendash
  *
  * This is free software; you can redistribute and/or modify it under
@@ -28,7 +28,7 @@ static char *asx3d3_line(const LWLINE *line, char *srs, int precision, int opts,
 static size_t asx3d3_poly_size(const LWPOLY *poly, char *srs, int precision, int opts, const char *defid);
 static size_t asx3d3_triangle_size(const LWTRIANGLE *triangle, char *srs, int precision, int opts, const char *defid);
 static char *asx3d3_triangle(const LWTRIANGLE *triangle, char *srs, int precision, int opts, const char *defid);
-static size_t asx3d3_multi_size(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid);
+static size_t asx3d3_multi_size(const LWCOLLECTION *col, char *srs, int precisioSn, int opts, const char *defid);
 static char *asx3d3_multi(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid);
 static char *asx3d3_psurface(const LWPSURFACE *psur, char *srs, int precision, int opts, const char *defid);
 static char *asx3d3_tin(const LWTIN *tin, char *srs, int precision, int opts, const char *defid);
@@ -145,10 +145,17 @@ asx3d3_line_size(const LWLINE *line, char *srs, int precision, int opts, const c
        size_t defidlen = strlen(defid);
 
        size = pointArray_X3Dsize(line->points, precision)*2;
-
-       size += (
-                   sizeof("<LineSet vertexCount=''><Coordinate point='' /></LineSet>")  + defidlen
+       
+       if ( X3D_USE_GEOCOORDS(opts) ) {
+                       size += (
+                   sizeof("<LineSet vertexCount=''><GeoCoordinate geoSystem='\"GD\" \"WE\" \"longitude_first\"' point='' /></LineSet>")  + defidlen
                ) * 2;
+       }
+       else {
+               size += (
+                           sizeof("<LineSet vertexCount=''><Coordinate point='' /></LineSet>")  + defidlen
+                       ) * 2;
+       }
 
        /* if (srs)     size += strlen(srs) + sizeof(" srsName=.."); */
        return size;
@@ -167,8 +174,9 @@ asx3d3_line_buf(const LWLINE *line, char *srs, char *output, int precision, int
        pa = line->points;
        ptr += sprintf(ptr, "<LineSet %s vertexCount='%d'>", defid, pa->npoints);
 
-
-       ptr += sprintf(ptr, "<Coordinate point='");
+       if ( X3D_USE_GEOCOORDS(opts) ) ptr += sprintf(ptr, "<GeoCoordinate geoSystem='\"GD\" \"WE\" \"%s\"' point='", ( (opts & LW_X3D_FLIP_XY) ? "latitude_first" : "longitude_first") );
+       else
+               ptr += sprintf(ptr, "<Coordinate point='");
        ptr += pointArray_toX3D3(line->points, ptr, precision, opts, lwline_is_closed((LWLINE *) line));
 
        ptr += sprintf(ptr, "' />");
@@ -371,7 +379,11 @@ asx3d3_multi_size(const LWCOLLECTION *col, char *srs, int precision, int opts, c
        LWGEOM *subgeom;
 
        /* the longest possible multi version needs to hold DEF=defid and coordinate breakout */
-       size = sizeof("<PointSet><Coordinate point='' /></PointSet>") + defidlen;
+       if ( X3D_USE_GEOCOORDS(opts) )
+               size = sizeof("<PointSet><GeoCoordinate geoSystem='\"GD\" \"WE\" \"longitude_first\"' point='' /></PointSet>");
+       else
+               size = sizeof("<PointSet><Coordinate point='' /></PointSet>") + defidlen;
+       
 
        /* if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); */
 
@@ -443,7 +455,10 @@ asx3d3_multi_buf(const LWCOLLECTION *col, char *srs, char *output, int precision
             return 0;
     }
     if (dimension == 3){
-        ptr += sprintf(ptr, "<Coordinate point='");
+               if ( X3D_USE_GEOCOORDS(opts) ) 
+                       ptr += sprintf(ptr, "<GeoCoordinate geoSystem='\"GD\" \"WE\" \"%s\"' point='", ((opts & LW_X3D_FLIP_XY) ? "latitude_first" : "longitude_first") );
+               else
+               ptr += sprintf(ptr, "<Coordinate point='");
     }
 
        for (i=0; i<col->ngeoms; i++)
@@ -497,7 +512,9 @@ asx3d3_psurface_size(const LWPSURFACE *psur, char *srs, int precision, int opts,
        size_t size;
        size_t defidlen = strlen(defid);
 
-       size = sizeof("<IndexedFaceSet coordIndex=''><Coordinate point='' />") + defidlen;
+       if ( X3D_USE_GEOCOORDS(opts) ) size = sizeof("<IndexedFaceSet coordIndex=''><GeoCoordinate geoSystem='\"GD\" \"WE\" \"longitude_first\"' point='' />") + defidlen;
+       else size = sizeof("<IndexedFaceSet coordIndex=''><Coordinate point='' />") + defidlen;
+       
 
        for (i=0; i<psur->ngeoms; i++)
        {
@@ -546,7 +563,9 @@ asx3d3_psurface_buf(const LWPSURFACE *psur, char *srs, char *output, int precisi
                j += k;
        }
 
-       ptr += sprintf(ptr, "'><Coordinate point='");
+       if ( X3D_USE_GEOCOORDS(opts) ) 
+               ptr += sprintf(ptr, "'><GeoCoordinate geoSystem='\"GD\" \"WE\" \"%s\"' point='", ( (opts & LW_X3D_FLIP_XY) ? "latitude_first" : "longitude_first") );
+       else ptr += sprintf(ptr, "'><Coordinate point='");
 
        for (i=0; i<psur->ngeoms; i++)
        {
@@ -626,7 +645,9 @@ asx3d3_tin_buf(const LWTIN *tin, char *srs, char *output, int precision, int opt
                k += 3;
        }
 
-       ptr += sprintf(ptr, "'><Coordinate point='");
+       if ( X3D_USE_GEOCOORDS(opts) ) ptr += sprintf(ptr, "'><GeoCoordinate geoSystem='\"GD\" \"WE\" \"%s\"' point='", ( (opts & LW_X3D_FLIP_XY) ? "latitude_first" : "longitude_first") );
+       else ptr += sprintf(ptr, "'><Coordinate point='");
+       
        for (i=0; i<tin->ngeoms; i++)
        {
                ptr += asx3d3_triangle_buf(tin->geoms[i], 0, ptr, precision,
@@ -830,7 +851,11 @@ pointArray_toX3D3(POINTARRAY *pa, char *output, int precision, int opts, int is_
 
                                if ( i )
                                        ptr += sprintf(ptr, " ");
-                               ptr += sprintf(ptr, "%s %s", x, y);
+                                       
+                               if ( ( opts & LW_X3D_FLIP_XY) )
+                                       ptr += sprintf(ptr, "%s %s", y, x);
+                               else
+                                       ptr += sprintf(ptr, "%s %s", x, y);
                        }
                }
        }
@@ -865,7 +890,10 @@ pointArray_toX3D3(POINTARRAY *pa, char *output, int precision, int opts, int is_
                                if ( i )
                                        ptr += sprintf(ptr, " ");
 
-                               ptr += sprintf(ptr, "%s %s %s", x, y, z);
+                               if ( ( opts & LW_X3D_FLIP_XY) )
+                                       ptr += sprintf(ptr, "%s %s %s", y, x, z);
+                               else
+                                       ptr += sprintf(ptr, "%s %s %s", x, y, z);
                        }
                }
        }
index 9232b93925e2b7e75381c4f0f05f47a65a74a18f..f1940e08cf3615af4c356b8d0f55961fec53dc92 100644 (file)
@@ -521,6 +521,8 @@ Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
        /* retrieve option */
        if (PG_NARGS() >3 && !PG_ARGISNULL(3))
                option = PG_GETARG_INT32(3);
+               
+       
 
        /* retrieve defid */
        if (PG_NARGS() >4 && !PG_ARGISNULL(4))
@@ -543,12 +545,22 @@ Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
                }
        }
 
+       lwgeom = lwgeom_from_gserialized(geom);
        srid = gserialized_get_srid(geom);
        if (srid == SRID_UNKNOWN)      srs = NULL;
        else if (option & 1) srs = getSRSbySRID(srid, false);
        else                 srs = getSRSbySRID(srid, true);
-
-       lwgeom = lwgeom_from_gserialized(geom);
+       
+       if (option & LW_X3D_USE_GEOCOORDS) {
+               if (srid != 4326) {
+                       PG_FREE_IF_COPY(geom, 0);
+                       /** TODO: we need to support UTM and other coordinate systems supported by X3D eventually 
+                       http://www.web3d.org/documents/specifications/19775-1/V3.2/Part01/components/geodata.html#t-earthgeoids **/
+                       elog(ERROR, "Only SRID 4326 is supported for geocoordinates.");
+                       PG_RETURN_NULL();
+               }
+       }
+       
 
        x3d = lwgeom_to_x3d3(lwgeom, srs, precision,option, defid);