[postgis-users] X3D and Postgis
Paul Ramsey
pramsey at refractions.net
Wed Apr 4 14:39:16 PDT 2007
Olivier,
AsX3D sounds fine to me, we'll see what we can do to get it
integrated. I'm less enthusiastic about a new type, however,
particularly one not defined by any of the spatial database standards.
P
On 3-Apr-07, at 9:17 AM, Olivier Courtin wrote:
> Hi Folks,
>
> I've recently started playing with X3D output and Postgis...
>
> First problem i met, was 3D storage in order to be able to
> output 3D triangle (aka: mesh).
>
> Usually output from 3D software (Blender for example) is
> expressed like a MULTIPOINT, and then by a nodes sequence
> to construct each mesh:
>
> -0.3068164315138165 0.3362340357492064 0.08543229250743267
> -0.1394644092204649 0.02167141020453666 0.2313872251951948
> -0.07491186826947319 -0.04377333172017087 0.3016102088630295
> 0.1627740875471142 -0.2559157826527169 -0.1765609543552259
> -0.4599623796157188 0.4122854856888629 0.2821508331989411
> 3 3 0 4
> 3 0 2 4
> 3 2 0 3
> 3 1 3 4
> 3 2 1 4
> 3 1 2 3
>
> For the moment i choose to store points as a MULTIPOINT in
> EWKT, and nodes index sequence as an array int (PostgreSQL native)
>
> So a feature is related to both a geometry (Multipoint) and a
> int[] faces index
>
> I've not yet found something usefull in the specs (SFS or SQL/MM)
> related to 3D storage to provide mesh rendering.
>
> Would you accept a patch with such a new geometry type in Postgis ?
>
> A right way to handle that, should be something like:
> MESH(MULTIPOINT(x y z, x1 y1 z1,...), NODES(3 0 4, 0 2 4, 2 0 3, ...))
>
>
> Right now, as i need to go on 3D rendering, i wrote with David
> Desbuisson
> a first asX3D function below
>
>
> Any reaction, comments and/or help are welcome ! :)
>
>
> Patch against today SVN postgis version:
>
> diff -Nu lwgeom/lwgeom_x3d.c ../postgis-svn/lwgeom/lwgeom_x3d.c
> --- lwgeom/lwgeom_x3d.c 2007-04-03 17:44:22.000000000 +0200
> +++ ../postgis-svn/lwgeom/lwgeom_x3d.c 1970-01-01
> 01:00:00.000000000 +0100
> @@ -1,368 +0,0 @@
> -/
> **********************************************************************
> - * $Id$
> - *
> - * PostGIS - Spatial Types for PostgreSQL
> - * http://postgis.refractions.net
> - * Copyright 2001-2003 Refractions Research Inc.
> - *
> - * This is free software; you can redistribute and/or modify it under
> - * the terms of hte GNU General Public Licence. See the COPYING file.
> - *
> -
> **********************************************************************
> - *
> - * X3D output routines.
> - *
> - * This file is, widely inspired from lwgeom_kml.c, written by:
> - * David Desbuisson <david.desbuisson at tplm-3d.fr>
> - * Olivier Courtin <olivier.courtin at camptocamp.com>
> - *
> -
> **********************************************************************
> /
> -
> -
> -#include "postgres.h"
> -#include "utils/array.h"
> -
> -#include "stringBuffer.h"
> -
> -#include "lwgeom_pg.h"
> -#include "liblwgeom.h"
> -
> -Datum LWGEOM_asX3D(PG_FUNCTION_ARGS);
> -
> -char *geometry_to_x3d(uchar *srl);
> -static size_t asx3d_point_size(LWPOINT *point);
> -static char *asx3d_point(LWPOINT *point);
> -static char *array_to_faces(ArrayType *array);
> -static size_t asx3d_inspected_size(LWGEOM_INSPECTED *geom);
> -static char *asx3d_inspected(LWGEOM_INSPECTED *geom);
> -static size_t pointArray_X3Dsize(POINTARRAY *pa);
> -static size_t pointArray_toX3D(POINTARRAY *pa, char *buf);
> -
> -#define DEF_PRECISION 15
> -/* Add dot, sign, exponent sign, 'e', exponent digits */
> -#define SHOW_DIGS (precision + 8)
> -
> -/* Globals */
> -int precision;
> -
> -
> -/**
> - * Encode feature in X3D
> - */
> -PG_FUNCTION_INFO_V1(LWGEOM_asX3D);
> -Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
> -{
> - PG_LWGEOM *geom;
> - int len;
> - Datum datum;
> - STRBUFF *buf;
> - text *result;
> - char *x3d;
> - ArrayType *faces = NULL;
> -
> - precision = DEF_PRECISION;
> -
> - if ( PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL();
> -
> - /* geom related to MULTIPOINT */
> - geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
> -
> - /* faces */
> - datum = PG_GETARG_DATUM(1);
> - if ( (Pointer *) datum == NULL) {
> - elog(ERROR, "asX3D: 'faces' parameter is Null !");
> - PG_RETURN_NULL();
> - }
> - faces = (ArrayType *) PG_DETOAST_DATUM_COPY(datum);
> - /* FIXME: what about a check related to too
> - small faces datas (i.e below 3) ? */
> -
> - /* Get precision (if provided) */
> - if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
> - precision = PG_GETARG_INT32(2);
> -
> - if ( precision < 1 || precision > 15 )
> - {
> - elog(ERROR, "Precision out of range 1..15");
> - PG_RETURN_NULL();
> - }
> -
> -
> - buf = new_strBUFF(1024);
> -
> - add_str_simple(buf, array_to_faces(faces));
> - add_str_simple(buf, geometry_to_x3d(SERIALIZED_FORM(geom)));
> - add_str_simple(buf, "\n</IndexedFaceSet>\n");
> -
> - x3d = to_CString(buf);
> - delete_StrBUFF(buf);
> -
> - PG_FREE_IF_COPY(geom, 0);
> -
> - len = strlen(x3d) + VARHDRSZ;
> -
> - result = palloc(len);
> - VARATT_SIZEP(result) = len;
> -
> - memcpy(VARDATA(result), x3d, len - VARHDRSZ);
> - pfree(x3d);
> -
> -
> - PG_RETURN_POINTER(result);
> -}
> -
> -/*
> - * Handle transform from postgres int array to IndexedFaceSet
> - */
> - static char *
> -array_to_faces(ArrayType *array)
> -{
> - int i,j;
> - int nelems;
> - int offset;
> - int value;
> - STRBUFF *buf_face;
> - char *result;
> - char buf[64];
> -
> - buf_face = new_strBUFF(1024);
> - nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));postgis-
> users at postgis.refractions.net>
> -
> - add_str_simple(buf_face, "<IndexedFaceSet coordIndex='");
> -
> - for (i=0, j=0, offset=0; i<nelems ; i++, offset += sizeof(int)) {
> -
> - /* Add a -1 as a face separator (X3D syntax) */
> - if (!(j % ARR_DIMS(array)[1]) && j!=0)
> - {
> - sprintf(buf, "-1,");
> - add_str_simple(buf_face, buf);
> - }
> -
> - /* retrieve current array value */
> - value = *( (int *) (ARR_DATA_PTR(array) + offset) );
> -
> - /* -1 value are ignored (could be a way to code postgis-
> users at postgis.refractions.net>
> - various faces dimension in Postgres array) */
> - if (value != -1)
> - {
> - j++;
> - sprintf(buf,"%i,",value);
> - add_str_simple(buf_face, buf);
> - }
> - }
> -
> - /* remove last comma and close IndexedFaceSet tag*/
> - buf_face->length--;
> - add_str_simple(buf_face, "'>\n");
> -
> - /* retrieve string to return */
> - result = to_CString(buf_face);
> - delete_StrBUFF(buf_face);
> -
> - return result;
> -}
> -
> -/*
> - * takes a GEOMETRY and returns a X3D representation (point related)
> - */
> - char *
> -geometry_to_x3d(uchar *geom)
> -{
> - int type;
> - LWPOINT *point;
> - LWGEOM_INSPECTED *inspected;
> -
> - type = lwgeom_getType(geom[0]);
> -
> - switch (type)
> - {
> -
> - case POINTTYPE:
> - point = lwpoint_deserialize(geom);
> - return asx3d_point(point);
> -
> - case MULTIPOINTTYPE:
> - inspected = lwgeom_inspect(geom);
> - return asx3d_inspected(inspected);
> -
> - default:
> - lwerror("geometry_to_x3d: '%s' are not supported",
> - lwgeom_typename(type));
> - return NULL;
> - }
> -}
> -
> - static size_t
> -asx3d_point_size(LWPOINT *point)
> -{
> - int size;
> - size = pointArray_X3Dsize(point->point);
> - size += sizeof(",");
> - return size;
> -}
> -
> - static size_t
> -asx3d_point_buf(LWPOINT *point, char *output)
> -{
> - char *ptr = output;
> -
> - ptr += pointArray_toX3D(point->point, ptr);
> - ptr += sprintf(ptr, ",");
> -
> - return (ptr-output);
> -}
> -
> - static char *
> -asx3d_point(LWPOINT *point)
> -{
> - char *output;
> - int size;
> -
> - size = asx3d_point_size(point);
> - output = palloc(size);
> - asx3d_point_buf(point, output);
> - return output;
> -}
> -
> -/*
> - * Compute max size required for X3D version of this
> - * inspected geometry. Will recurse when needed.
> - * Don't call this with single-geoms inspected.
> - */
> - static size_t
> -asx3d_inspected_size(LWGEOM_INSPECTED *insp)
> -{
> - int i;
> - size_t size;
> -
> - /* the longest possible multi version */
> - size = sizeof("<Coordinate point=''/>");
> -
> - for (i=0; i<insp->ngeometries; i++)
> - {
> - LWPOINT *point;
> - LWGEOM_INSPECTED *subinsp;
> - uchar *subgeom;
> -
> - if ((point=lwgeom_getpoint_inspected(insp, i)))
> - {
> - size += asx3d_point_size(point);
> - pfree_point(point);
> - }
> - else
> - {
> - subgeom = lwgeom_getsubgeometry_inspected(insp, i);
> - subinsp = lwgeom_inspect(subgeom);
> - size += asx3d_inspected_size(subinsp);
> - pfree_inspected(subinsp);
> - }
> - }
> -
> - return size;
> -}
> -
> -/*
> - * Don't call this with single-geoms inspected!
> - */
> - static size_t
> -asx3d_inspected_buf(LWGEOM_INSPECTED *insp, char *output)
> -{
> - char *ptr;
> - int i;
> -
> - ptr = output;
> -
> - ptr += sprintf(ptr, "<Coordinate point='");
> -
> - for (i=0; i<insp->ngeometries; i++)
> - {
> - LWPOINT *point;
> - LWGEOM_INSPECTED *subinsp;
> - uchar *subgeom;
> -
> - if ((point=lwgeom_getpoint_inspected(insp, i)))
> - {
> - ptr += asx3d_point_buf(point, ptr);
> - pfree_point(point);
> - }
> - else
> - {
> - subgeom = lwgeom_getsubgeometry_inspected(insp, i);
> - subinsp = lwgeom_inspect(subgeom);
> - ptr += asx3d_inspected_buf(subinsp, ptr);
> - pfree_inspected(subinsp);
> - }
> - }
> -
> - /* Remove last comma and close outmost tag */
> - ptr += sprintf(--ptr, "'/>");
> -
> - return (ptr-output);
> -}
> -
> -/*
> - * Don't call this with single-geoms inspected!
> - */
> - static char *
> -asx3d_inspected(LWGEOM_INSPECTED *insp)
> -{
> - char *x3d;
> - size_t size;
> -
> - size = asx3d_inspected_size(insp);
> - x3d = palloc(size);
> - asx3d_inspected_buf(insp, x3d);
> - return x3d;
> -}postgis-users at postgis.refractions.net>
> -
> -/*
> - * Returns maximum size of rendered pointarray in bytes.
> - */
> - static size_t
> -pointArray_X3Dsize(POINTARRAY *pa)
> -{
> - return TYPE_NDIMS(pa->dims) * pa->npoints *
> - (SHOW_DIGS + (TYPE_NDIMS(pa->dims) - 1));
> -}
> -
> - static size_t
> -pointArray_toX3D(POINTARRAY *pa, char *output)
> -{
> - int i;
> - char *ptr;
> -
> - ptr = output;
> -
> - if ( ! TYPE_HASZ(pa->dims) )
> - {
> - for (i=0; i<pa->npoints; i++)
> - {
> - POINT2D pt;
> - getPoint2d_p(pa, i, &pt);
> - if ( i ) ptr += sprintf(ptr, " ");
> - ptr += sprintf(ptr, "%.*g %.*g 0",
> - precision, pt.x,
> - precision, pt.y);
> - }
> - }
> - else
> - {
> - for (i=0; i<pa->npoints; i++)
> - {
> - POINT4D pt;
> - getPoint4d_p(pa, i, &pt);
> - if ( i ) ptr += sprintf(ptr, " ");
> - ptr += sprintf(ptr, "%.*g %.*g %.*g",
> - precision, pt.x,
> - precision, pt.y,
> - precision, pt.z);
> - }
> - }
> -
> - return ptr-output;
> -}
> -
> -/
> **********************************************************************
> - * $Log$
> -
> **********************************************************************
> /
> diff -Nu lwgeom/lwpostgis.sql.in ../postgis-svn/lwgeom/
> lwpostgis.sql.in
> --- lwgeom/lwpostgis.sql.in 2007-04-03 17:14:37.000000000 +0200
> +++ ../postgis-svn/lwgeom/lwpostgis.sql.in 2006-12-15
> 11:48:56.000000000 +0100
> @@ -3096,23 +3096,6 @@
> AS 'SELECT AsUKML(transform($1,4326))'
> LANGUAGE 'SQL' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
>
> -
> ----------------------------------------------------------------------
> --
> --- X3D OUTPUT
> ----------------------------------------------------------------------
> --
> --- AsX3D(geom, faces, precision)
> -CREATE OR REPLACE FUNCTION AsX3D(geometry, integer[], int4)
> - RETURNS TEXT
> - AS '@MODULE_FILENAME@','LWGEOM_asX3D'
> - LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
> -
> --- AsX3D(geom, faces) / precision=15
> -CREATE OR REPLACE FUNCTION AsX3D(geometry, integer[])
> - RETURNS TEXT
> - AS '@MODULE_FILENAME@','LWGEOM_asX3D'
> - LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
> -
> -
>
> ----------------------------------------------------------------------
> --
> -- OGC defined
>
> ----------------------------------------------------------------------
> --
> @@ -3742,3 +3725,4 @@
> ---------------------------------------------------------------
>
> COMMIT;
> +
> diff -Nu lwgeom/Makefile ../postgis-svn/lwgeom/Makefile
> --- lwgeom/Makefile 2007-04-03 17:12:32.000000000 +0200
> +++ ../postgis-svn/lwgeom/Makefile 2006-12-15 11:48:56.000000000 +0100
> @@ -84,7 +84,7 @@
>
> SA_OBJS=measures.o box2d.o ptarray.o lwgeom_api.o lwgeom.o
> lwpoint.o lwline.o lwpoly.o lwmpoint.o lwmline.o lwmpoly.o
> lwcollection.o $(GEOS_WRAPPER) $(JTS_WRAPPER) wktunparse.o
> lwgparse.o wktparse.tab.o lex.yy.o vsprintf.o
>
> -OBJS=$(SA_OBJS) liblwgeom.o lwgeom_pg.o lwgeom_debug.o
> lwgeom_spheroid.o lwgeom_ogc.o lwgeom_functions_analytic.o $
> (JTS_OBJ) lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o
> lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o
> lwgeom_box.o lwgeom_box3d.o lwgeom_box2dfloat4.o lwgeom_chip.o
> lwgeom_svg.o lwgeom_gml.o lwgeom_kml.o lwgeom_x3d.o
> lwgeom_triggers.o lwgeom_dump.o lwgeom_functions_lrs.o long_xact.o
> lwcurve.o lwcompound.o lwcurvepoly.o lwmcurve.o lwmsurface.o
> lwgeom_sqlmm.o
> +OBJS=$(SA_OBJS) liblwgeom.o lwgeom_pg.o lwgeom_debug.o
> lwgeom_spheroid.o lwgeom_ogc.o lwgeom_functions_analytic.o $
> (JTS_OBJ) lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o
> lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o
> lwgeom_box.o lwgeom_box3d.o lwgeom_box2dfloat4.o lwgeom_chip.o
> lwgeom_svg.o lwgeom_gml.o lwgeom_kml.o lwgeom_triggers.o
> lwgeom_dump.o lwgeom_functions_lrs.o long_xact.o lwcurve.o
> lwcompound.o lwcurvepoly.o lwmcurve.o lwmsurface.o lwgeom_sqlmm.o
>
> #OTHERS=y.output lex.yy.c wktparse.tab.c wktparse.tab.h lwpostgis.sql
> OTHERS=y.output postgis_geos_version.h
>
>
>
> --
> Olivier Courtin
> Camptocamp France SAS
> _______________________________________________
> postgis-users mailing list
> postgis-users at postgis.refractions.net
> http://postgis.refractions.net/mailman/listinfo/postgis-users
More information about the postgis-users
mailing list