[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