mirror of
https://git.osgeo.org/gitea/postgis/postgis
synced 2024-10-24 00:52:40 +00:00
Revert dos lineending commit that blew away those files...
git-svn-id: http://svn.osgeo.org/postgis/trunk@9262 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
parent
b69faad591
commit
c936b1eab7
|
@ -0,0 +1,868 @@
|
|||
/**********************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://www.postgis.org
|
||||
* adapted from lwout_asgml.c
|
||||
* Copyright 2011 Arrival 3D
|
||||
* Regina Obe with input from Dave Arendash
|
||||
*
|
||||
* This is free software; you can redistribute and/or modify it under
|
||||
* the terms of the GNU General Public Licence. See the COPYING file.
|
||||
*
|
||||
**********************************************************************/
|
||||
/**
|
||||
* @file X3D output routines.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "liblwgeom_internal.h"
|
||||
|
||||
/** defid is the id of the coordinate can be used to hold other elements DEF='abc' transform='' etc. **/
|
||||
static size_t asx3d3_point_size(const LWPOINT *point, char *srs, int precision, int opts, const char *defid);
|
||||
static char *asx3d3_point(const LWPOINT *point, char *srs, int precision, int opts, const char *defid);
|
||||
static size_t asx3d3_line_size(const LWLINE *line, char *srs, int precision, int opts, const char *defid);
|
||||
static char *asx3d3_line(const LWLINE *line, char *srs, int precision, int opts, const char *defid);
|
||||
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 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);
|
||||
static size_t asx3d3_collection_size(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid);
|
||||
static char *asx3d3_collection(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid);
|
||||
static size_t pointArray_toX3D3(POINTARRAY *pa, char *buf, int precision, int opts, int is_closed);
|
||||
|
||||
static size_t pointArray_X3Dsize(POINTARRAY *pa, int precision);
|
||||
|
||||
|
||||
/*
|
||||
* VERSION X3D 3.0.2 http://www.web3d.org/specifications/x3d-3.0.dtd
|
||||
*/
|
||||
|
||||
|
||||
/* takes a GEOMETRY and returns an X3D representation */
|
||||
extern char *
|
||||
lwgeom_to_x3d3(const LWGEOM *geom, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int type = geom->type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case POINTTYPE:
|
||||
return asx3d3_point((LWPOINT*)geom, srs, precision, opts, defid);
|
||||
|
||||
case LINETYPE:
|
||||
return asx3d3_line((LWLINE*)geom, srs, precision, opts, defid);
|
||||
|
||||
case POLYGONTYPE:
|
||||
{
|
||||
/** We might change this later, but putting a polygon in an indexed face set
|
||||
* seems like the simplest way to go so treat just like a mulitpolygon
|
||||
*/
|
||||
LWCOLLECTION *tmp = (LWCOLLECTION*)lwgeom_as_multi(geom);
|
||||
char *ret = asx3d3_multi(tmp, srs, precision, opts, defid);
|
||||
lwcollection_free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case TRIANGLETYPE:
|
||||
return asx3d3_triangle((LWTRIANGLE*)geom, srs, precision, opts, defid);
|
||||
|
||||
case MULTIPOINTTYPE:
|
||||
case MULTILINETYPE:
|
||||
case MULTIPOLYGONTYPE:
|
||||
return asx3d3_multi((LWCOLLECTION*)geom, srs, precision, opts, defid);
|
||||
|
||||
case POLYHEDRALSURFACETYPE:
|
||||
return asx3d3_psurface((LWPSURFACE*)geom, srs, precision, opts, defid);
|
||||
|
||||
case TINTYPE:
|
||||
return asx3d3_tin((LWTIN*)geom, srs, precision, opts, defid);
|
||||
|
||||
case COLLECTIONTYPE:
|
||||
return asx3d3_collection((LWCOLLECTION*)geom, srs, precision, opts, defid);
|
||||
|
||||
default:
|
||||
lwerror("lwgeom_to_x3d3: '%s' geometry type not supported", lwtype_name(type));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_point_size(const LWPOINT *point, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int size;
|
||||
//size_t defidlen = strlen(defid);
|
||||
|
||||
size = pointArray_X3Dsize(point->point, precision);
|
||||
//size += ( sizeof("<point><pos>/") + (defidlen*2) ) * 2;
|
||||
//if (srs) size += strlen(srs) + sizeof(" srsName=..");
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_point_buf(const LWPOINT *point, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr = output;
|
||||
//int dimension=2;
|
||||
|
||||
//if (FLAGS_GET_Z(point->flags)) dimension = 3;
|
||||
/* if ( srs )
|
||||
{
|
||||
ptr += sprintf(ptr, "<%sPoint srsName=\"%s\">", defid, srs);
|
||||
}
|
||||
else*/
|
||||
//ptr += sprintf(ptr, "%s", defid);
|
||||
|
||||
//ptr += sprintf(ptr, "<%spos>", defid);
|
||||
ptr += pointArray_toX3D3(point->point, ptr, precision, opts, 0);
|
||||
//ptr += sprintf(ptr, "</%spos></%sPoint>", defid, defid);
|
||||
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
static char *
|
||||
asx3d3_point(const LWPOINT *point, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *output;
|
||||
int size;
|
||||
|
||||
size = asx3d3_point_size(point, srs, precision, opts, defid);
|
||||
output = lwalloc(size);
|
||||
asx3d3_point_buf(point, srs, output, precision, opts, defid);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
asx3d3_line_size(const LWLINE *line, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int size;
|
||||
size_t defidlen = strlen(defid);
|
||||
|
||||
size = pointArray_X3Dsize(line->points, precision)*2;
|
||||
|
||||
size += (
|
||||
sizeof("<LineSet vertexCount=''><Coordinate point='' /></LineSet>") + defidlen
|
||||
) * 2;
|
||||
|
||||
//if (srs) size += strlen(srs) + sizeof(" srsName=..");
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_line_buf(const LWLINE *line, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr=output;
|
||||
//int dimension=2;
|
||||
POINTARRAY *pa;
|
||||
|
||||
|
||||
//if (FLAGS_GET_Z(line->flags)) dimension = 3;
|
||||
|
||||
pa = line->points;
|
||||
ptr += sprintf(ptr, "<LineSet %s vertexCount='%d'>", defid, pa->npoints);
|
||||
|
||||
|
||||
ptr += sprintf(ptr, "<Coordinate point='");
|
||||
ptr += pointArray_toX3D3(line->points, ptr, precision, opts, lwline_is_closed((LWLINE *) line));
|
||||
|
||||
ptr += sprintf(ptr, "' />");
|
||||
|
||||
ptr += sprintf(ptr, "</LineSet>");
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_line_coords(const LWLINE *line, char *output, int precision, int opts)
|
||||
{
|
||||
char *ptr=output;
|
||||
//ptr += sprintf(ptr, "");
|
||||
ptr += pointArray_toX3D3(line->points, ptr, precision, opts, lwline_is_closed(line));
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/* Calculate the coordIndex property of the IndexedLineSet for the multilinestring */
|
||||
static size_t
|
||||
asx3d3_mline_coordindex(const LWMLINE *mgeom, char *output)
|
||||
{
|
||||
char *ptr=output;
|
||||
LWLINE *geom;
|
||||
int i, j, k, si;
|
||||
POINTARRAY *pa;
|
||||
int np;
|
||||
|
||||
j = 0;
|
||||
for (i=0; i < mgeom->ngeoms; i++)
|
||||
{
|
||||
geom = (LWLINE *) mgeom->geoms[i];
|
||||
pa = geom->points;
|
||||
np = pa->npoints;
|
||||
si = j; //start index of first point of linestring
|
||||
for (k=0; k < np ; k++)
|
||||
{
|
||||
if (k)
|
||||
{
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
/** if the linestring is closed, we put the start point index
|
||||
* for the last vertex to denote use first point
|
||||
* and don't increment the index **/
|
||||
if (!lwline_is_closed(geom) || k < (np -1) )
|
||||
{
|
||||
ptr += sprintf(ptr, "%d", j);
|
||||
j += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr += sprintf(ptr,"%d", si);
|
||||
}
|
||||
}
|
||||
if (i < (mgeom->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " -1 "); //separator for each linestring
|
||||
}
|
||||
}
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/* Calculate the coordIndex property of the IndexedLineSet for a multipolygon
|
||||
This is not ideal -- would be really nice to just share this function with psurf,
|
||||
but I'm not smart enough to do that yet*/
|
||||
static size_t
|
||||
asx3d3_mpoly_coordindex(const LWMPOLY *psur, char *output)
|
||||
{
|
||||
char *ptr=output;
|
||||
LWPOLY *patch;
|
||||
int i, j, k, l;
|
||||
int np;
|
||||
j = 0;
|
||||
for (i=0; i<psur->ngeoms; i++)
|
||||
{
|
||||
patch = (LWPOLY *) psur->geoms[i];
|
||||
for (l=0; l < patch->nrings; l++)
|
||||
{
|
||||
np = patch->rings[l]->npoints - 1;
|
||||
for (k=0; k < np ; k++)
|
||||
{
|
||||
if (k)
|
||||
{
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
ptr += sprintf(ptr, "%d", (j + k));
|
||||
}
|
||||
j += k;
|
||||
if (l < (patch->nrings - 1) )
|
||||
{
|
||||
/** @todo TODO: Decide the best way to render holes
|
||||
* Evidentally according to my X3D expert the X3D consortium doesn't really
|
||||
* support holes and it's an issue of argument among many that feel it should. He thinks CAD x3d extensions to spec might.
|
||||
* What he has done and others developing X3D exports to simulate a hole is to cut around it.
|
||||
* So if you have a donut, you would cut it into half and have 2 solid polygons. Not really sure the best way to handle this.
|
||||
* For now will leave it as polygons stacked on top of each other -- which is what we are doing here and perhaps an option
|
||||
* to color differently. It's not ideal but the alternative sounds complicated.
|
||||
**/
|
||||
ptr += sprintf(ptr, " -1 "); //separator for each inner ring. Ideally we should probably triangulate and cut around as others do
|
||||
}
|
||||
}
|
||||
if (i < (psur->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " -1 "); //separator for each subgeom
|
||||
}
|
||||
}
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/** Return the linestring as an X3D LineSet */
|
||||
static char *
|
||||
asx3d3_line(const LWLINE *line, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *output;
|
||||
int size;
|
||||
|
||||
size = sizeof("<LineSet><CoordIndex ='' /></LineSet>") + asx3d3_line_size(line, srs, precision, opts, defid);
|
||||
output = lwalloc(size);
|
||||
asx3d3_line_buf(line, srs, output, precision, opts, defid);
|
||||
return output;
|
||||
}
|
||||
|
||||
/** Compute the string space needed for the IndexedFaceSet representation of the polygon **/
|
||||
static size_t
|
||||
asx3d3_poly_size(const LWPOLY *poly, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
int i;
|
||||
|
||||
size = ( sizeof("<IndexedFaceSet></IndexedFaceSet>") + (defidlen*3) ) * 2 + 6 * (poly->nrings - 1);
|
||||
|
||||
for (i=0; i<poly->nrings; i++)
|
||||
size += pointArray_X3Dsize(poly->rings[i], precision);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/** Compute the X3D coordinates of the polygon **/
|
||||
static size_t
|
||||
asx3d3_poly_buf(const LWPOLY *poly, char *srs, char *output, int precision, int opts, int is_patch, const char *defid)
|
||||
{
|
||||
int i;
|
||||
char *ptr=output;
|
||||
int dimension=2;
|
||||
|
||||
if (FLAGS_GET_Z(poly->flags))
|
||||
dimension = 3;
|
||||
ptr += pointArray_toX3D3(poly->rings[0], ptr, precision, opts, 1);
|
||||
for (i=1; i<poly->nrings; i++)
|
||||
{
|
||||
ptr += sprintf(ptr, " "); //inner ring points start
|
||||
ptr += pointArray_toX3D3(poly->rings[i], ptr, precision, opts,1);
|
||||
}
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_triangle_size(const LWTRIANGLE *triangle, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
|
||||
/** 6 for the 3 sides and space to separate each side **/
|
||||
size = sizeof("<IndexedTriangleSet index=''></IndexedTriangleSet>") + defidlen + 6;
|
||||
size += pointArray_X3Dsize(triangle->points, precision);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_triangle_buf(const LWTRIANGLE *triangle, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr=output;
|
||||
ptr += pointArray_toX3D3(triangle->points, ptr, precision, opts, 1);
|
||||
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
static char *
|
||||
asx3d3_triangle(const LWTRIANGLE *triangle, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *output;
|
||||
int size;
|
||||
|
||||
size = asx3d3_triangle_size(triangle, srs, precision, opts, defid);
|
||||
output = lwalloc(size);
|
||||
asx3d3_triangle_buf(triangle, srs, output, precision, opts, defid);
|
||||
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
|
||||
asx3d3_multi_size(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
LWGEOM *subgeom;
|
||||
|
||||
/* the longest possible multi version needs to hold DEF=defid and coordinate breakout */
|
||||
size = sizeof("<PointSet><Coordinate point='' /></PointSet>") + defidlen;
|
||||
|
||||
//if ( srs ) size += strlen(srs) + sizeof(" srsName=..");
|
||||
|
||||
for (i=0; i<col->ngeoms; i++)
|
||||
{
|
||||
subgeom = col->geoms[i];
|
||||
if (subgeom->type == POINTTYPE)
|
||||
{
|
||||
//size += ( sizeof("point=''") + defidlen ) * 2;
|
||||
size += asx3d3_point_size((LWPOINT*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else if (subgeom->type == LINETYPE)
|
||||
{
|
||||
//size += ( sizeof("<curveMember>/") + defidlen ) * 2;
|
||||
size += asx3d3_line_size((LWLINE*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else if (subgeom->type == POLYGONTYPE)
|
||||
{
|
||||
//size += ( sizeof("<surfaceMember>/") + defidlen ) * 2;
|
||||
size += asx3d3_poly_size((LWPOLY*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static size_t
|
||||
asx3d3_multi_buf(const LWCOLLECTION *col, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr, *x3dtype;
|
||||
int i;
|
||||
int dimension=2;
|
||||
|
||||
if (FLAGS_GET_Z(col->flags)) dimension = 3;
|
||||
LWGEOM *subgeom;
|
||||
ptr = output;
|
||||
x3dtype="";
|
||||
|
||||
|
||||
switch (col->type)
|
||||
{
|
||||
case MULTIPOINTTYPE:
|
||||
x3dtype = "PointSet";
|
||||
if ( dimension == 2 ){ /** Use Polypoint2D instead **/
|
||||
x3dtype = "Polypoint2D";
|
||||
ptr += sprintf(ptr, "<%s %s point='", x3dtype, defid);
|
||||
}
|
||||
else {
|
||||
ptr += sprintf(ptr, "<%s %s>", x3dtype, defid);
|
||||
}
|
||||
break;
|
||||
case MULTILINETYPE:
|
||||
x3dtype = "IndexedLineSet";
|
||||
ptr += sprintf(ptr, "<%s %s coordIndex='", x3dtype, defid);
|
||||
ptr += asx3d3_mline_coordindex((const LWMLINE *)col, ptr);
|
||||
ptr += sprintf(ptr, "'>");
|
||||
break;
|
||||
case MULTIPOLYGONTYPE:
|
||||
x3dtype = "IndexedFaceSet";
|
||||
ptr += sprintf(ptr, "<%s %s coordIndex='", x3dtype, defid);
|
||||
ptr += asx3d3_mpoly_coordindex((const LWMPOLY *)col, ptr);
|
||||
ptr += sprintf(ptr, "'>");
|
||||
break;
|
||||
default:
|
||||
lwerror("asx3d3_multi_buf: '%s' geometry type not supported", lwtype_name(col->type));
|
||||
return 0;
|
||||
}
|
||||
if (dimension == 3){
|
||||
ptr += sprintf(ptr, "<Coordinate point='");
|
||||
}
|
||||
|
||||
for (i=0; i<col->ngeoms; i++)
|
||||
{
|
||||
subgeom = col->geoms[i];
|
||||
if (subgeom->type == POINTTYPE)
|
||||
{
|
||||
ptr += asx3d3_point_buf((LWPOINT*)subgeom, 0, ptr, precision, opts, defid);
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
else if (subgeom->type == LINETYPE)
|
||||
{
|
||||
ptr += asx3d3_line_coords((LWLINE*)subgeom, ptr, precision, opts);
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
else if (subgeom->type == POLYGONTYPE)
|
||||
{
|
||||
ptr += asx3d3_poly_buf((LWPOLY*)subgeom, 0, ptr, precision, opts, 0, defid);
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
}
|
||||
|
||||
/* Close outmost tag */
|
||||
if (dimension == 3){
|
||||
ptr += sprintf(ptr, "' /></%s>", x3dtype);
|
||||
}
|
||||
else { ptr += sprintf(ptr, "' />"); }
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static char *
|
||||
asx3d3_multi(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *x3d;
|
||||
size_t size;
|
||||
|
||||
size = asx3d3_multi_size(col, srs, precision, opts, defid);
|
||||
x3d = lwalloc(size);
|
||||
asx3d3_multi_buf(col, srs, x3d, precision, opts, defid);
|
||||
return x3d;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
asx3d3_psurface_size(const LWPSURFACE *psur, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
|
||||
size = sizeof("<IndexedFaceSet coordIndex=''><Coordinate point='' />") + defidlen;
|
||||
|
||||
for (i=0; i<psur->ngeoms; i++)
|
||||
{
|
||||
size += asx3d3_poly_size(psur->geoms[i], 0, precision, opts, defid)*5; /** need to make space for coordIndex values too including -1 separating each poly**/
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static size_t
|
||||
asx3d3_psurface_buf(const LWPSURFACE *psur, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
int np;
|
||||
LWPOLY *patch;
|
||||
|
||||
ptr = output;
|
||||
|
||||
/* Open outmost tag */
|
||||
ptr += sprintf(ptr, "<IndexedFaceSet %s coordIndex='",defid);
|
||||
|
||||
j = 0;
|
||||
for (i=0; i<psur->ngeoms; i++)
|
||||
{
|
||||
patch = (LWPOLY *) psur->geoms[i];
|
||||
np = patch->rings[0]->npoints - 1;
|
||||
for (k=0; k < np ; k++)
|
||||
{
|
||||
if (k)
|
||||
{
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
ptr += sprintf(ptr, "%d", (j + k));
|
||||
}
|
||||
if (i < (psur->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " -1 "); //separator for each subgeom
|
||||
}
|
||||
j += k;
|
||||
}
|
||||
|
||||
ptr += sprintf(ptr, "'><Coordinate point='");
|
||||
|
||||
for (i=0; i<psur->ngeoms; i++)
|
||||
{
|
||||
ptr += asx3d3_poly_buf(psur->geoms[i], 0, ptr, precision, opts, 1, defid);
|
||||
if (i < (psur->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " "); //only add a trailing space if its not the last polygon in the set
|
||||
}
|
||||
}
|
||||
|
||||
/* Close outmost tag */
|
||||
ptr += sprintf(ptr, "' /></IndexedFaceSet>");
|
||||
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static char *
|
||||
asx3d3_psurface(const LWPSURFACE *psur, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *x3d;
|
||||
size_t size;
|
||||
|
||||
size = asx3d3_psurface_size(psur, srs, precision, opts, defid);
|
||||
x3d = lwalloc(size);
|
||||
asx3d3_psurface_buf(psur, srs, x3d, precision, opts, defid);
|
||||
return x3d;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
asx3d3_tin_size(const LWTIN *tin, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
//int dimension=2;
|
||||
|
||||
/** Need to make space for size of additional attributes,
|
||||
** the coordIndex has a value for each edge for each triangle plus a space to separate so we need at least that much extra room ***/
|
||||
size = sizeof("<IndexedTriangleSet coordIndex=''></IndexedTriangleSet>") + defidlen + tin->ngeoms*12;
|
||||
|
||||
for (i=0; i<tin->ngeoms; i++)
|
||||
{
|
||||
size += (asx3d3_triangle_size(tin->geoms[i], 0, precision, opts, defid) * 20); /** 3 is to make space for coordIndex **/
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static size_t
|
||||
asx3d3_tin_buf(const LWTIN *tin, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
int k;
|
||||
//int dimension=2;
|
||||
|
||||
ptr = output;
|
||||
|
||||
ptr += sprintf(ptr, "<IndexedTriangleSet %s index='",defid);
|
||||
k = 0;
|
||||
/** Fill in triangle index **/
|
||||
for (i=0; i<tin->ngeoms; i++)
|
||||
{
|
||||
ptr += sprintf(ptr, "%d %d %d", k, (k+1), (k+2));
|
||||
if (i < (tin->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
k += 3;
|
||||
}
|
||||
|
||||
ptr += sprintf(ptr, "'><Coordinate point='");
|
||||
for (i=0; i<tin->ngeoms; i++)
|
||||
{
|
||||
ptr += asx3d3_triangle_buf(tin->geoms[i], 0, ptr, precision,
|
||||
opts, defid);
|
||||
if (i < (tin->ngeoms - 1) )
|
||||
{
|
||||
ptr += sprintf(ptr, " ");
|
||||
}
|
||||
}
|
||||
|
||||
/* Close outmost tag */
|
||||
|
||||
ptr += sprintf(ptr, "'/></IndexedTriangleSet>");
|
||||
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static char *
|
||||
asx3d3_tin(const LWTIN *tin, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *x3d;
|
||||
size_t size;
|
||||
|
||||
size = asx3d3_tin_size(tin, srs, precision, opts, defid);
|
||||
x3d = lwalloc(size);
|
||||
asx3d3_tin_buf(tin, srs, x3d, precision, opts, defid);
|
||||
return x3d;
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_collection_size(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
size_t defidlen = strlen(defid);
|
||||
LWGEOM *subgeom;
|
||||
|
||||
size = sizeof("<MultiGeometry></MultiGeometry>") + defidlen*2;
|
||||
|
||||
if ( srs )
|
||||
size += strlen(srs) + sizeof(" srsName=..");
|
||||
|
||||
for (i=0; i<col->ngeoms; i++)
|
||||
{
|
||||
subgeom = col->geoms[i];
|
||||
size += ( sizeof("<geometryMember>/") + defidlen ) * 2;
|
||||
if ( subgeom->type == POINTTYPE )
|
||||
{
|
||||
size += asx3d3_point_size((LWPOINT*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else if ( subgeom->type == LINETYPE )
|
||||
{
|
||||
size += asx3d3_line_size((LWLINE*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else if ( subgeom->type == POLYGONTYPE )
|
||||
{
|
||||
size += asx3d3_poly_size((LWPOLY*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else if ( lwgeom_is_collection(subgeom) )
|
||||
{
|
||||
size += asx3d3_multi_size((LWCOLLECTION*)subgeom, 0, precision, opts, defid);
|
||||
}
|
||||
else
|
||||
lwerror("asx3d3_collection_size: unknown geometry type");
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
asx3d3_collection_buf(const LWCOLLECTION *col, char *srs, char *output, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
LWGEOM *subgeom;
|
||||
|
||||
ptr = output;
|
||||
|
||||
/* Open outmost tag */
|
||||
if ( srs )
|
||||
{
|
||||
ptr += sprintf(ptr, "<%sMultiGeometry srsName=\"%s\">", defid, srs);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr += sprintf(ptr, "<%sMultiGeometry>", defid);
|
||||
}
|
||||
|
||||
for (i=0; i<col->ngeoms; i++)
|
||||
{
|
||||
subgeom = col->geoms[i];
|
||||
ptr += sprintf(ptr, "<%sgeometryMember>", defid);
|
||||
if ( subgeom->type == POINTTYPE )
|
||||
{
|
||||
ptr += asx3d3_point_buf((LWPOINT*)subgeom, 0, ptr, precision, opts, defid);
|
||||
}
|
||||
else if ( subgeom->type == LINETYPE )
|
||||
{
|
||||
ptr += asx3d3_line_buf((LWLINE*)subgeom, 0, ptr, precision, opts, defid);
|
||||
}
|
||||
else if ( subgeom->type == POLYGONTYPE )
|
||||
{
|
||||
ptr += asx3d3_poly_buf((LWPOLY*)subgeom, 0, ptr, precision, opts, 0, defid);
|
||||
}
|
||||
else if ( lwgeom_is_collection(subgeom) )
|
||||
{
|
||||
if ( subgeom->type == COLLECTIONTYPE )
|
||||
ptr += asx3d3_collection_buf((LWCOLLECTION*)subgeom, 0, ptr, precision, opts, defid);
|
||||
else
|
||||
ptr += asx3d3_multi_buf((LWCOLLECTION*)subgeom, 0, ptr, precision, opts, defid);
|
||||
}
|
||||
else
|
||||
lwerror("asx3d3_collection_buf: unknown geometry type");
|
||||
|
||||
ptr += sprintf(ptr, "</%sgeometryMember>", defid);
|
||||
}
|
||||
|
||||
/* Close outmost tag */
|
||||
ptr += sprintf(ptr, "</%sMultiGeometry>", defid);
|
||||
|
||||
return (ptr-output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this with single-geoms inspected!
|
||||
*/
|
||||
static char *
|
||||
asx3d3_collection(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid)
|
||||
{
|
||||
char *x3d;
|
||||
size_t size;
|
||||
|
||||
size = asx3d3_collection_size(col, srs, precision, opts, defid);
|
||||
x3d = lwalloc(size);
|
||||
asx3d3_collection_buf(col, srs, x3d, precision, opts, defid);
|
||||
return x3d;
|
||||
}
|
||||
|
||||
|
||||
/** In X3D3, coordinates are separated by a space separator
|
||||
*/
|
||||
static size_t
|
||||
pointArray_toX3D3(POINTARRAY *pa, char *output, int precision, int opts, int is_closed)
|
||||
{
|
||||
int i;
|
||||
char *ptr;
|
||||
char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
|
||||
char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
|
||||
char z[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
|
||||
|
||||
ptr = output;
|
||||
|
||||
if ( ! FLAGS_GET_Z(pa->flags) )
|
||||
{
|
||||
for (i=0; i<pa->npoints; i++)
|
||||
{
|
||||
/** Only output the point if it is not the last point of a closed object or it is a non-closed type **/
|
||||
if ( !is_closed || i < (pa->npoints - 1) )
|
||||
{
|
||||
POINT2D pt;
|
||||
getPoint2d_p(pa, i, &pt);
|
||||
|
||||
if (fabs(pt.x) < OUT_MAX_DOUBLE)
|
||||
sprintf(x, "%.*f", precision, pt.x);
|
||||
else
|
||||
sprintf(x, "%g", pt.x);
|
||||
trim_trailing_zeros(x);
|
||||
|
||||
if (fabs(pt.y) < OUT_MAX_DOUBLE)
|
||||
sprintf(y, "%.*f", precision, pt.y);
|
||||
else
|
||||
sprintf(y, "%g", pt.y);
|
||||
trim_trailing_zeros(y);
|
||||
|
||||
if ( i )
|
||||
ptr += sprintf(ptr, " ");
|
||||
ptr += sprintf(ptr, "%s %s", x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<pa->npoints; i++)
|
||||
{
|
||||
/** Only output the point if it is not the last point of a closed object or it is a non-closed type **/
|
||||
if ( !is_closed || i < (pa->npoints - 1) )
|
||||
{
|
||||
POINT4D pt;
|
||||
getPoint4d_p(pa, i, &pt);
|
||||
|
||||
if (fabs(pt.x) < OUT_MAX_DOUBLE)
|
||||
sprintf(x, "%.*f", precision, pt.x);
|
||||
else
|
||||
sprintf(x, "%g", pt.x);
|
||||
trim_trailing_zeros(x);
|
||||
|
||||
if (fabs(pt.y) < OUT_MAX_DOUBLE)
|
||||
sprintf(y, "%.*f", precision, pt.y);
|
||||
else
|
||||
sprintf(y, "%g", pt.y);
|
||||
trim_trailing_zeros(y);
|
||||
|
||||
if (fabs(pt.z) < OUT_MAX_DOUBLE)
|
||||
sprintf(z, "%.*f", precision, pt.z);
|
||||
else
|
||||
sprintf(z, "%g", pt.z);
|
||||
trim_trailing_zeros(z);
|
||||
|
||||
if ( i )
|
||||
ptr += sprintf(ptr, " ");
|
||||
|
||||
ptr += sprintf(ptr, "%s %s %s", x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ptr-output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns maximum size of rendered pointarray in bytes.
|
||||
*/
|
||||
static size_t
|
||||
pointArray_X3Dsize(POINTARRAY *pa, int precision)
|
||||
{
|
||||
if (FLAGS_NDIMS(pa->flags) == 2)
|
||||
return (OUT_MAX_DIGS_DOUBLE + precision + sizeof(" "))
|
||||
* 2 * pa->npoints;
|
||||
|
||||
return (OUT_MAX_DIGS_DOUBLE + precision + sizeof(" ")) * 3 * pa->npoints;
|
||||
}
|
1548
liblwgeom/measures.c
1548
liblwgeom/measures.c
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,72 @@
|
|||
|
||||
/**********************************************************************
|
||||
* $Id: measures.h 4715 2009-11-01 17:58:42Z nicklas $
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.refractions.net
|
||||
* Copyright 2010 Nicklas Avén
|
||||
*
|
||||
* This is free software; you can redistribute and/or modify it under
|
||||
* the terms of the GNU General Public Licence. See the COPYING file.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "liblwgeom_internal.h"
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Structure used in distance-calculations
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
double distance; /*the distance between p1 and p2*/
|
||||
POINT2D p1;
|
||||
POINT2D p2;
|
||||
int mode; /*the direction of looking, if thedir = -1 then we look for maxdistance and if it is 1 then we look for mindistance*/
|
||||
int twisted; /*To preserve the order of incoming points to match the first and secon point in shortest and longest line*/
|
||||
double tolerance; /*the tolerance for dwithin and dfullywithin*/
|
||||
} DISTPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double themeasure; /*a value calculated to compare distances*/
|
||||
int pnr; /*pointnumber. the ordernumber of the point*/
|
||||
} LISTSTRUCT;
|
||||
|
||||
|
||||
/*
|
||||
Preprocessing functions
|
||||
*/
|
||||
int lw_dist2d_comp(LWGEOM *lw1, LWGEOM *lw2, DISTPTS *dl);
|
||||
int lw_dist2d_distribute_bruteforce(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl);
|
||||
int lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl);
|
||||
int lw_dist2d_check_overlap(LWGEOM *lwg1,LWGEOM *lwg2);
|
||||
int lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl);
|
||||
/*
|
||||
Brute force functions
|
||||
*/
|
||||
|
||||
int lw_dist2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D, DISTPTS *dl);
|
||||
int lw_dist2d_pt_ptarray(POINT2D *p, POINTARRAY *pa, DISTPTS *dl);
|
||||
int lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2, DISTPTS *dl);
|
||||
int lw_dist2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly, DISTPTS *dl);
|
||||
int lw_dist2d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS *dl);
|
||||
int lw_dist2d_point_line(LWPOINT *point, LWLINE *line, DISTPTS *dl);
|
||||
int lw_dist2d_line_line(LWLINE *line1, LWLINE *line2, DISTPTS *dl);
|
||||
int lw_dist2d_point_poly(LWPOINT *point, LWPOLY *poly, DISTPTS *dl);
|
||||
int lw_dist2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2, DISTPTS *dl);
|
||||
int lw_dist2d_line_poly(LWLINE *line, LWPOLY *poly, DISTPTS *dl);
|
||||
/*
|
||||
New faster distance calculations
|
||||
*/
|
||||
|
||||
int lw_dist2d_pre_seg_seg(POINTARRAY *l1, POINTARRAY *l2,LISTSTRUCT *list1, LISTSTRUCT *list2,double k, DISTPTS *dl);
|
||||
int lw_dist2d_selected_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D, DISTPTS *dl);
|
||||
int struct_cmp_by_measure(const void *a, const void *b);
|
||||
int lw_dist2d_fast_ptarray_ptarray(POINTARRAY *l1,POINTARRAY *l2, DISTPTS *dl, GBOX *box1, GBOX *box2);
|
||||
/*
|
||||
Functions in common for Brute force and new calculation
|
||||
*/
|
||||
int lw_dist2d_pt_pt(POINT2D *p1, POINT2D *p2, DISTPTS *dl);
|
||||
int lw_dist2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B, DISTPTS *dl);
|
|
@ -0,0 +1,543 @@
|
|||
/**********************************************************************
|
||||
* $Id:$
|
||||
*
|
||||
* PostGIS - Export functions for PostgreSQL/PostGIS
|
||||
* Copyright 2009-2011 Olivier Courtin <olivier.courtin@oslandia.com>
|
||||
*
|
||||
* This is free software; you can redistribute and/or modify it under
|
||||
* the terms of the GNU General Public Licence. See the COPYING file.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
/** @file
|
||||
* Commons functions for all export functions
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
#include "executor/spi.h"
|
||||
|
||||
#include "../postgis_config.h"
|
||||
#include "lwgeom_pg.h"
|
||||
#include "liblwgeom.h"
|
||||
#include "lwgeom_export.h"
|
||||
|
||||
Datum LWGEOM_asGML(PG_FUNCTION_ARGS);
|
||||
Datum LWGEOM_asKML(PG_FUNCTION_ARGS);
|
||||
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS);
|
||||
Datum LWGEOM_asSVG(PG_FUNCTION_ARGS);
|
||||
Datum LWGEOM_asX3D(PG_FUNCTION_ARGS);
|
||||
|
||||
/*
|
||||
* Retrieve an SRS from a given SRID
|
||||
* Require valid spatial_ref_sys table entry
|
||||
*
|
||||
* Could return SRS as short one (i.e EPSG:4326)
|
||||
* or as long one: (i.e urn:ogc:def:crs:EPSG::4326)
|
||||
*/
|
||||
char * getSRSbySRID(int srid, bool short_crs)
|
||||
{
|
||||
char query[256];
|
||||
char *srs, *srscopy;
|
||||
int size, err;
|
||||
|
||||
if (SPI_OK_CONNECT != SPI_connect ())
|
||||
{
|
||||
elog(NOTICE, "getSRSbySRID: could not connect to SPI manager");
|
||||
SPI_finish();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (short_crs)
|
||||
sprintf(query, "SELECT auth_name||':'||auth_srid \
|
||||
FROM spatial_ref_sys WHERE srid='%d'", srid);
|
||||
else
|
||||
sprintf(query, "SELECT 'urn:ogc:def:crs:'||auth_name||'::'||auth_srid \
|
||||
FROM spatial_ref_sys WHERE srid='%d'", srid);
|
||||
|
||||
err = SPI_exec(query, 1);
|
||||
if ( err < 0 )
|
||||
{
|
||||
elog(NOTICE, "getSRSbySRID: error executing query %d", err);
|
||||
SPI_finish();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* no entry in spatial_ref_sys */
|
||||
if (SPI_processed <= 0)
|
||||
{
|
||||
SPI_finish();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get result */
|
||||
srs = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
|
||||
|
||||
/* NULL result */
|
||||
if ( ! srs )
|
||||
{
|
||||
SPI_finish();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy result to upper executor context */
|
||||
size = strlen(srs)+1;
|
||||
srscopy = SPI_palloc(size);
|
||||
memcpy(srscopy, srs, size);
|
||||
|
||||
/* disconnect from SPI */
|
||||
SPI_finish();
|
||||
|
||||
return srscopy;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Retrieve an SRID from a given SRS
|
||||
* Require valid spatial_ref_sys table entry
|
||||
*
|
||||
*/
|
||||
int getSRIDbySRS(const char* srs)
|
||||
{
|
||||
char query[256];
|
||||
int srid, err;
|
||||
|
||||
if (srs == NULL)
|
||||
return 0;
|
||||
|
||||
if (SPI_OK_CONNECT != SPI_connect ())
|
||||
{
|
||||
elog(NOTICE, "getSRIDbySRS: could not connect to SPI manager");
|
||||
SPI_finish();
|
||||
return 0;
|
||||
}
|
||||
sprintf(query, "SELECT srid \
|
||||
FROM spatial_ref_sys WHERE auth_name||':'||auth_srid = '%s'", srs);
|
||||
|
||||
err = SPI_exec(query, 1);
|
||||
if ( err < 0 )
|
||||
{
|
||||
elog(NOTICE, "getSRIDbySRS: error executing query %d", err);
|
||||
SPI_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no entry in spatial_ref_sys */
|
||||
if (SPI_processed <= 0)
|
||||
{
|
||||
sprintf(query, "SELECT srid \
|
||||
FROM spatial_ref_sys WHERE \
|
||||
'urn:ogc:def:crs:'||auth_name||'::'||auth_srid = '%s'", srs);
|
||||
|
||||
err = SPI_exec(query, 1);
|
||||
if ( err < 0 )
|
||||
{
|
||||
elog(NOTICE, "getSRIDbySRS: error executing query %d", err);
|
||||
SPI_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SPI_processed <= 0) {
|
||||
SPI_finish();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
srid = atoi(SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1));
|
||||
if ( ! srs )
|
||||
{
|
||||
SPI_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPI_finish();
|
||||
|
||||
return srid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode feature in GML
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(LWGEOM_asGML);
|
||||
Datum LWGEOM_asGML(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GSERIALIZED *geom;
|
||||
LWGEOM *lwgeom;
|
||||
char *gml = NULL;
|
||||
text *result;
|
||||
int version;
|
||||
char *srs;
|
||||
int srid;
|
||||
int option = 0;
|
||||
int lwopts = LW_GML_IS_DIMS;
|
||||
int precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
static const char* default_prefix = "gml:"; /* default prefix */
|
||||
char *prefixbuf;
|
||||
const char* prefix = default_prefix;
|
||||
text *prefix_text;
|
||||
|
||||
/* Get the version */
|
||||
version = PG_GETARG_INT32(0);
|
||||
if ( version != 2 && version != 3 )
|
||||
{
|
||||
elog(ERROR, "Only GML 2 and GML 3 are supported");
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
/* Get the geometry */
|
||||
if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
|
||||
geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
|
||||
/* Retrieve precision if any (default is max) */
|
||||
if (PG_NARGS() >2 && !PG_ARGISNULL(2))
|
||||
{
|
||||
precision = PG_GETARG_INT32(2);
|
||||
if ( precision > OUT_MAX_DOUBLE_PRECISION )
|
||||
precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
else if ( precision < 0 ) precision = 0;
|
||||
}
|
||||
|
||||
/* retrieve option */
|
||||
if (PG_NARGS() >3 && !PG_ARGISNULL(3))
|
||||
option = PG_GETARG_INT32(3);
|
||||
|
||||
/* retrieve prefix */
|
||||
if (PG_NARGS() >4 && !PG_ARGISNULL(4))
|
||||
{
|
||||
prefix_text = PG_GETARG_TEXT_P(4);
|
||||
if ( VARSIZE(prefix_text)-VARHDRSZ == 0 )
|
||||
{
|
||||
prefix = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* +2 is one for the ':' and one for term null */
|
||||
prefixbuf = palloc(VARSIZE(prefix_text)-VARHDRSZ+2);
|
||||
memcpy(prefixbuf, VARDATA(prefix_text),
|
||||
VARSIZE(prefix_text)-VARHDRSZ);
|
||||
/* add colon and null terminate */
|
||||
prefixbuf[VARSIZE(prefix_text)-VARHDRSZ] = ':';
|
||||
prefixbuf[VARSIZE(prefix_text)-VARHDRSZ+1] = '\0';
|
||||
prefix = prefixbuf;
|
||||
}
|
||||
}
|
||||
|
||||
srid = gserialized_get_srid(geom);
|
||||
if (srid == SRID_UNKNOWN) srs = NULL;
|
||||
else if (option & 1) srs = getSRSbySRID(srid, false);
|
||||
else srs = getSRSbySRID(srid, true);
|
||||
|
||||
if (option & 2) lwopts &= ~LW_GML_IS_DIMS;
|
||||
if (option & 4) lwopts |= LW_GML_SHORTLINE;
|
||||
if (option & 16) lwopts |= LW_GML_IS_DEGREE;
|
||||
if (option & 32) lwopts |= LW_GML_EXTENT;
|
||||
|
||||
lwgeom = lwgeom_from_gserialized(geom);
|
||||
|
||||
if (version == 2 && lwopts & LW_GML_EXTENT)
|
||||
gml = lwgeom_extent_to_gml2(lwgeom, srs, precision, prefix);
|
||||
else if (version == 2)
|
||||
gml = lwgeom_to_gml2(lwgeom, srs, precision, prefix);
|
||||
else if (version == 3 && lwopts & LW_GML_EXTENT)
|
||||
gml = lwgeom_extent_to_gml3(lwgeom, srs, precision, lwopts, prefix);
|
||||
else if (version == 3)
|
||||
gml = lwgeom_to_gml3(lwgeom, srs, precision, lwopts, prefix);
|
||||
|
||||
lwgeom_free(lwgeom);
|
||||
PG_FREE_IF_COPY(geom, 1);
|
||||
|
||||
/* Return null on null */
|
||||
if ( ! gml )
|
||||
PG_RETURN_NULL();
|
||||
|
||||
result = cstring2text(gml);
|
||||
lwfree(gml);
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode feature in KML
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(LWGEOM_asKML);
|
||||
Datum LWGEOM_asKML(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GSERIALIZED *geom;
|
||||
LWGEOM *lwgeom;
|
||||
char *kml;
|
||||
text *result;
|
||||
int version;
|
||||
int precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
static const char* default_prefix = ""; /* default prefix */
|
||||
char *prefixbuf;
|
||||
const char* prefix = default_prefix;
|
||||
text *prefix_text;
|
||||
|
||||
|
||||
/* Get the version */
|
||||
version = PG_GETARG_INT32(0);
|
||||
if ( version != 2)
|
||||
{
|
||||
elog(ERROR, "Only KML 2 is supported");
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
/* Get the geometry */
|
||||
if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
|
||||
geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
|
||||
/* Retrieve precision if any (default is max) */
|
||||
if (PG_NARGS() >2 && !PG_ARGISNULL(2))
|
||||
{
|
||||
precision = PG_GETARG_INT32(2);
|
||||
if ( precision > OUT_MAX_DOUBLE_PRECISION )
|
||||
precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
else if ( precision < 0 ) precision = 0;
|
||||
}
|
||||
|
||||
/* retrieve prefix */
|
||||
if (PG_NARGS() >3 && !PG_ARGISNULL(3))
|
||||
{
|
||||
prefix_text = PG_GETARG_TEXT_P(3);
|
||||
if ( VARSIZE(prefix_text)-VARHDRSZ == 0 )
|
||||
{
|
||||
prefix = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* +2 is one for the ':' and one for term null */
|
||||
prefixbuf = palloc(VARSIZE(prefix_text)-VARHDRSZ+2);
|
||||
memcpy(prefixbuf, VARDATA(prefix_text),
|
||||
VARSIZE(prefix_text)-VARHDRSZ);
|
||||
/* add colon and null terminate */
|
||||
prefixbuf[VARSIZE(prefix_text)-VARHDRSZ] = ':';
|
||||
prefixbuf[VARSIZE(prefix_text)-VARHDRSZ+1] = '\0';
|
||||
prefix = prefixbuf;
|
||||
}
|
||||
}
|
||||
|
||||
lwgeom = lwgeom_from_gserialized(geom);
|
||||
kml = lwgeom_to_kml2(lwgeom, precision, prefix);
|
||||
lwgeom_free(lwgeom);
|
||||
PG_FREE_IF_COPY(geom, 1);
|
||||
|
||||
if( ! kml )
|
||||
PG_RETURN_NULL();
|
||||
|
||||
result = cstring2text(kml);
|
||||
lwfree(kml);
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode Feature in GeoJson
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(LWGEOM_asGeoJson);
|
||||
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GSERIALIZED *geom;
|
||||
LWGEOM *lwgeom;
|
||||
char *geojson;
|
||||
text *result;
|
||||
int srid;
|
||||
int version;
|
||||
int option = 0;
|
||||
int has_bbox = 0;
|
||||
int precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
char * srs = NULL;
|
||||
|
||||
/* Get the version */
|
||||
version = PG_GETARG_INT32(0);
|
||||
if ( version != 1)
|
||||
{
|
||||
elog(ERROR, "Only GeoJSON 1 is supported");
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
/* Get the geometry */
|
||||
if (PG_ARGISNULL(1) ) PG_RETURN_NULL();
|
||||
geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
|
||||
/* Retrieve precision if any (default is max) */
|
||||
if (PG_NARGS() >2 && !PG_ARGISNULL(2))
|
||||
{
|
||||
precision = PG_GETARG_INT32(2);
|
||||
if ( precision > OUT_MAX_DOUBLE_PRECISION )
|
||||
precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
else if ( precision < 0 ) precision = 0;
|
||||
}
|
||||
|
||||
/* Retrieve output option
|
||||
* 0 = without option (default)
|
||||
* 1 = bbox
|
||||
* 2 = short crs
|
||||
* 4 = long crs
|
||||
*/
|
||||
if (PG_NARGS() >3 && !PG_ARGISNULL(3))
|
||||
option = PG_GETARG_INT32(3);
|
||||
|
||||
if (option & 2 || option & 4)
|
||||
{
|
||||
srid = gserialized_get_srid(geom);
|
||||
if ( srid != SRID_UNKNOWN )
|
||||
{
|
||||
if (option & 2) srs = getSRSbySRID(srid, true);
|
||||
if (option & 4) srs = getSRSbySRID(srid, false);
|
||||
if (!srs)
|
||||
{
|
||||
elog( ERROR,
|
||||
"SRID %i unknown in spatial_ref_sys table",
|
||||
srid);
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (option & 1) has_bbox = 1;
|
||||
|
||||
lwgeom = lwgeom_from_gserialized(geom);
|
||||
geojson = lwgeom_to_geojson(lwgeom, srs, precision, has_bbox);
|
||||
lwgeom_free(lwgeom);
|
||||
|
||||
PG_FREE_IF_COPY(geom, 1);
|
||||
if (srs) pfree(srs);
|
||||
|
||||
result = cstring2text(geojson);
|
||||
|
||||
lwfree(geojson);
|
||||
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SVG features
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(LWGEOM_asSVG);
|
||||
Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GSERIALIZED *geom;
|
||||
LWGEOM *lwgeom;
|
||||
char *svg;
|
||||
text *result;
|
||||
int relative = 0;
|
||||
int precision=OUT_MAX_DOUBLE_PRECISION;
|
||||
|
||||
if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
|
||||
|
||||
geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
|
||||
/* check for relative path notation */
|
||||
if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
|
||||
relative = PG_GETARG_INT32(1) ? 1:0;
|
||||
|
||||
if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
|
||||
{
|
||||
precision = PG_GETARG_INT32(2);
|
||||
if ( precision > OUT_MAX_DOUBLE_PRECISION )
|
||||
precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
else if ( precision < 0 ) precision = 0;
|
||||
}
|
||||
|
||||
lwgeom = lwgeom_from_gserialized(geom);
|
||||
svg = lwgeom_to_svg(lwgeom, precision, relative);
|
||||
result = cstring2text(svg);
|
||||
lwgeom_free(lwgeom);
|
||||
pfree(svg);
|
||||
PG_FREE_IF_COPY(geom, 0);
|
||||
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode feature as X3D
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(LWGEOM_asX3D);
|
||||
Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GSERIALIZED *geom;
|
||||
LWGEOM *lwgeom;
|
||||
char *x3d;
|
||||
text *result;
|
||||
int version;
|
||||
char *srs;
|
||||
int srid;
|
||||
int option = 0;
|
||||
int is_deegree = 0;
|
||||
int is_dims = 1;
|
||||
int precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
static const char* default_defid = "x3d:"; /* default defid */
|
||||
char *defidbuf;
|
||||
const char* defid = default_defid;
|
||||
text *defid_text;
|
||||
|
||||
/* Get the version */
|
||||
version = PG_GETARG_INT32(0);
|
||||
if ( version != 3 )
|
||||
{
|
||||
elog(ERROR, "Only X3D version 3 are supported");
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
/* Get the geometry */
|
||||
if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
|
||||
geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
|
||||
/* Retrieve precision if any (default is max) */
|
||||
if (PG_NARGS() >2 && !PG_ARGISNULL(2))
|
||||
{
|
||||
precision = PG_GETARG_INT32(2);
|
||||
if ( precision > OUT_MAX_DOUBLE_PRECISION )
|
||||
precision = OUT_MAX_DOUBLE_PRECISION;
|
||||
else if ( precision < 0 ) precision = 0;
|
||||
}
|
||||
|
||||
/* retrieve option */
|
||||
if (PG_NARGS() >3 && !PG_ARGISNULL(3))
|
||||
option = PG_GETARG_INT32(3);
|
||||
|
||||
/* retrieve defid */
|
||||
if (PG_NARGS() >4 && !PG_ARGISNULL(4))
|
||||
{
|
||||
defid_text = PG_GETARG_TEXT_P(4);
|
||||
if ( VARSIZE(defid_text)-VARHDRSZ == 0 )
|
||||
{
|
||||
defid = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* +2 is one for the ':' and one for term null */
|
||||
defidbuf = palloc(VARSIZE(defid_text)-VARHDRSZ+2);
|
||||
memcpy(defidbuf, VARDATA(defid_text),
|
||||
VARSIZE(defid_text)-VARHDRSZ);
|
||||
/* add colon and null terminate */
|
||||
defidbuf[VARSIZE(defid_text)-VARHDRSZ] = ':';
|
||||
defidbuf[VARSIZE(defid_text)-VARHDRSZ+1] = '\0';
|
||||
defid = defidbuf;
|
||||
}
|
||||
}
|
||||
|
||||
srid = gserialized_get_srid(geom);
|
||||
if (srid == SRID_UNKNOWN) srs = NULL;
|
||||
else if (option & 1) srs = getSRSbySRID(srid, false);
|
||||
else srs = getSRSbySRID(srid, true);
|
||||
|
||||
if (option & 2) is_dims = 0;
|
||||
if (option & 16) is_deegree = 1;
|
||||
|
||||
lwgeom = lwgeom_from_gserialized(geom);
|
||||
|
||||
|
||||
x3d = lwgeom_to_x3d3(lwgeom, srs, precision,option, defid);
|
||||
|
||||
lwgeom_free(lwgeom);
|
||||
PG_FREE_IF_COPY(geom, 1);
|
||||
|
||||
result = cstring2text(x3d);
|
||||
lwfree(x3d);
|
||||
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef _LWGEOM_RTREE_H
|
||||
#define _LWGEOM_RTREE_H
|
||||
|
||||
#include "liblwgeom.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double min;
|
||||
double max;
|
||||
}
|
||||
INTERVAL;
|
||||
|
||||
/* Returns 1 if min < value <= max, 0 otherwise */
|
||||
uint32 isContained(INTERVAL *interval, double value);
|
||||
/* Creates an interval given the min and max values, in whatever order. */
|
||||
INTERVAL *createInterval(double value1, double value2);
|
||||
/* Creates an interval with the total extents of the two given intervals. */
|
||||
INTERVAL *mergeIntervals(INTERVAL *inter1, INTERVAL *inter2);
|
||||
|
||||
/*
|
||||
* The following struct and methods are used for a 1D RTree implementation,
|
||||
* described at:
|
||||
* http://lin-ear-th-inking.blogspot.com/2007/06/packed-1-dimensional-r-tree.html
|
||||
*/
|
||||
typedef struct rtree_node
|
||||
{
|
||||
INTERVAL *interval;
|
||||
struct rtree_node *leftNode;
|
||||
struct rtree_node *rightNode;
|
||||
LWLINE *segment;
|
||||
}
|
||||
RTREE_NODE;
|
||||
|
||||
/* Creates an interior node given the children. */
|
||||
RTREE_NODE *createInteriorNode(RTREE_NODE *left, RTREE_NODE *right);
|
||||
/* Creates a leaf node given the pointer to the start point of the segment. */
|
||||
RTREE_NODE *createLeafNode(POINTARRAY *pa, int startPoint);
|
||||
/*
|
||||
* Creates an rtree given a pointer to the point array.
|
||||
* Must copy the point array.
|
||||
*/
|
||||
RTREE_NODE *createTree(POINTARRAY *pointArray);
|
||||
/* Frees the tree. */
|
||||
void freeTree(RTREE_NODE *root);
|
||||
/* Retrieves a collection of line segments given the root and crossing value. */
|
||||
LWMLINE *findLineSegments(RTREE_NODE *root, double value);
|
||||
/* Merges two multilinestrings into a single multilinestring. */
|
||||
LWMLINE *mergeMultiLines(LWMLINE *line1, LWMLINE *line2);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char type;
|
||||
RTREE_NODE **ringIndices;
|
||||
int* ringCounts;
|
||||
int polyCount;
|
||||
GSERIALIZED *poly;
|
||||
}
|
||||
RTREE_POLY_CACHE;
|
||||
|
||||
/*
|
||||
* Creates a new cachable index if needed, or returns the current cache if
|
||||
* it is applicable to the current polygon.
|
||||
*/
|
||||
RTREE_POLY_CACHE *retrieveCache(LWGEOM *lwgeom, GSERIALIZED *serializedPoly, RTREE_POLY_CACHE *currentCache);
|
||||
RTREE_POLY_CACHE *createCache(void);
|
||||
/* Frees the cache. */
|
||||
void populateCache(RTREE_POLY_CACHE *cache, LWGEOM *lwgeom, GSERIALIZED *serializedPoly);
|
||||
void clearCache(RTREE_POLY_CACHE *cache);
|
||||
|
||||
|
||||
|
||||
#endif /* !defined _LIBLWGEOM_H */
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue