[postgis-users] AsSvg

Olivier Courtin pnine at free.fr
Wed Sep 8 04:57:17 PDT 2004


Hi,

I currently use PostGIS with AsSvg for several month (mostly web carto
usage).
Current AsSvg projet from klaus Foerster is available here :
<http://svg.cc/pg/assvg/>

And i find a bit pity following things :
1) AsSvg is not a native part of PostGIS (even if SVG output is in
PostGIS TODO)
2) AsSvg output use double for decimal part (useless for most web carto 
application)


For the second point, i've decided to add a new optional parameter in 
AsSvg prototype to handle decimal precision (now default is 0 decimal).
I've also correct some very little things, like to avoid gcc to warn on
compiletime and so on...

For the first point nevertheless, i don't know why AsSvg never add been
included directly in PostGIS source... Is there a real reason ? 
I've found nothing on this ml archive...
It will be IMHO a great thing... :)


(Following code seems to work fine with PostGIS 0.8.1 or 0.8.2, not
tested with current CVS)



=============== assvg.c.in ========================================




/**
 * SVG features
 */

PG_FUNCTION_INFO_V1(assvg_geometry);
Datum assvg_geometry(PG_FUNCTION_ARGS)
{
	GEOMETRY 	*geom1 = (GEOMETRY *) 
				PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
	char	   	*wkt;
	char	   	*result;
	int	   	len;
	int32           svgrel;
	int32		precision;


	// check for relative path notation
	if ( ! PG_ARGISNULL(1) )
		svgrel = PG_GETARG_INT32(1);
	else
		svgrel = 0;

	if ( ! PG_ARGISNULL(2) )
		precision = PG_GETARG_INT32(2);
	else
		precision = 0;
		
	wkt = geometry_to_svg(geom1, svgrel, precision);

	len = strlen(wkt) + 5;

	result= palloc(len);
	*((int *) result) = len;

	memcpy(result +4, wkt, len-4);

	pfree(wkt);

	PG_RETURN_CSTRING(result);
}


//takes a GEOMETRY and returns a SVG representation
char *geometry_to_svg(GEOMETRY  *geometry, int svgrel, int precision)
{
	char		*result;
	int		t,u;
	int32		*offsets;
	char		*obj;
	POINT3D	*pts;
	POLYGON3D	*polygon;
	LINE3D	*line;
	POINT3D	*point;

	int		pt_off,size;
	bool		first_sub_obj = TRUE;
	int		mem_size,npts;

	size = 30;	//just enough to put in object type
	//try to limit number of repalloc()s
	result = (char *) palloc(30); mem_size= 30;

	// TODO BBox, from where is it called?...
	if (geometry->type == BBOXONLYTYPE)
	{
		if (svgrel == 1)
		{
			// 5 double digits+ "Mhvhz"+ spaces +null
			mem_size = MAX_DIGS_DOUBLE*5+5+6+1;
			pfree(result);
			result = (char *) palloc(mem_size); 

			sprintf(result, "M %.*f %.*f h%.*f v%.*f h%.*f z",
				precision, 
				geometry->bvol.LLB.x,
				precision, 
				geometry->bvol.URT.y*-1,
				precision, 
				(geometry->bvol.URT.x 
				 - geometry->bvol.LLB.x),
				precision, 
				(geometry->bvol.URT.y 
				 - geometry->bvol.LLB.y),
				precision, 
				(geometry->bvol.URT.x 
				 - geometry->bvol.LLB.x)*-1);
		}
		else
		{
			mem_size = MAX_DIGS_DOUBLE*4+3+1;
			pfree(result);
			result = (char *) palloc(mem_size); 
			// 4 double digits + 3 spaces +null

			sprintf(result, "%.*f %.*f %.*f %.*f",
				precision,
				geometry->bvol.LLB.x,
				precision,
				geometry->bvol.URT.y*-1,
				precision,
				(geometry->bvol.URT.x - geometry->bvol.LLB.x),
				precision, 
				(geometry->bvol.URT.y - geometry->bvol.LLB.y)
				);
		}
		return result;
	}

	// no more warnings on compiletime
	sprintf(result,"%s", "");

	if (geometry->type == COLLECTIONTYPE)
	{
		sprintf(result, "GEOMETRYCOLLECTION not yet supported");
		return result;
	}

	//where are the objects?
	offsets = (int32 *) ( ((char *) &(geometry->objType[0] ))
			+ sizeof(int32) * geometry->nobjs ) ;

	for(t=0;t<geometry->nobjs; t++)  //for each object
	{
		obj = (char *) geometry +offsets[t] ;

		if (geometry->objType[t] == 1)   //POINT
		{
			point = (POINT3D *) obj;
			size +=MAX_DIGS_DOUBLE*3 + 2 +10  ;
			//make memory bigger
			result = repalloc(result, size );

			if (!(first_sub_obj))
			{	
				// next circle ...
				strcat(result,",");
			}
			else
			{
				first_sub_obj = FALSE;
			}
			if (svgrel == 1)
			{  
				//render circle
				print_svg_coords(result, point, precision);
			}
			else
			{  
				//render circle
				print_svg_circle(result, point, precision);
			}

		}
		if (geometry->objType[t] == 2)	//LINESTRING
		{
			line = (LINE3D *) obj;

			size +=(MAX_DIGS_DOUBLE*3+5)*line->npoints +12+3;
			result = repalloc(result, size );

			// start path with moveto
			strcat(result, "M ");

			if (svgrel == 1)
				print_svg_path_rel(
						result,
						&line->points[0],
						line->npoints, 
						precision
						);
			else
				print_svg_path_abs(
						result,
						&line->points[0],
						line->npoints,
						precision
						);

			strcat(result," ");
		}
		if (geometry->objType[t] == 3)	//POLYGON
		{
			polygon = (POLYGON3D *) obj;
			pt_off = 0;	//where is the first point in this ring?

			//where are the points
			pts = (POINT3D *)
				((char *)&(polygon->npoints[polygon->nrings]));
			pts = (POINT3D *) MAXALIGN(pts);

			npts = 0;
			for (u=0; u< polygon->nrings ; u++)
				npts += polygon->npoints[u];

			size += (MAX_DIGS_DOUBLE*3+3) 
				* npts + 5* polygon->nrings;
			result = repalloc(result, size );

			for (u=0; u< polygon->nrings ; u++)  //for each ring
			{
				strcat(result,"M ");	//begin ring
				if (svgrel == 1)
					print_svg_path_rel(result, 
							&pts[pt_off] ,
							polygon->npoints[u],
							precision);
				else
					print_svg_path_abs(result,
							&pts[pt_off],
							polygon->npoints[u],
							precision);
				
				//where is first point of next ring?
				pt_off = pt_off + polygon->npoints[u]; 
				strcat(result," ");	//end ring
			}
		}
	}
	return(result);
}


void print_svg_coords(char *result, POINT3D *pt, int precision)
{
	char	temp[MAX_DIGS_DOUBLE*3 +12];

	if ( (pt == NULL) || (result == NULL) )
		return;

	sprintf(temp, "x=\"%.*f\" y=\"%.*f\"", 
			precision, pt->x, 
			precision, pt->y*-1);
	strcat(result,temp);
}


void print_svg_circle(char *result, POINT3D *pt, int precision)
{
	char	temp[MAX_DIGS_DOUBLE*3 +12];

	if ( (pt == NULL) || (result == NULL) )
		return;

	sprintf(temp, "cx=\"%.*f\" cy=\"%.*f\"", 
			precision, pt->x, 
			precision, pt->y*-1);
	strcat(result,temp);
}


void print_svg_path_abs(char *result, POINT3D *pt ,int npoints, int
precision){
	int	u;

	result += strlen(result);
	for (u=0;u<npoints;u++)
	{
		if (u != 0)
		{
			result[0] = ' ';
			result++;
		}
		result+= sprintf(result,"%.*f %.*f", 
				precision, pt[u].x, 
				precision, pt[u].y*-1);
	}
}


void print_svg_path_rel(char *result, POINT3D *pt ,int npoints, int
precision){
	int	u;

	result += strlen(result);
	for (u=0;u<npoints;u++)
	{
		if (u == 0)
		{
			result+= sprintf(result,"%.*f %.*f l", 
					precision, pt[u].x, 
					precision, pt[u].y*-1);
		}
		else
		{
			result+= sprintf(result," %.*f %.*f", 
					precision, (pt[u].x-pt[u-1].x), 
					precision, (pt[u].y-pt[u-1].y)*-1);
		}
	}
}





=========================== assvg.h.in ================================

Datum assvg_geometry(PG_FUNCTION_ARGS);
char *geometry_to_svg(GEOMETRY  *geometry, int svgrel, int precision);
void print_svg_coords(char *result, POINT3D *pt, int precision);
void print_svg_circle(char *result, POINT3D *pt, int precision);
void print_svg_path_abs(char *result, POINT3D *pt ,int npoints, int
precision); void print_svg_path_rel(char *result, POINT3D *pt ,int
npoints, int precision);


=========================== assvg.sql.in ==============================

CREATE FUNCTION assvg(geometry)
	RETURNS TEXT
	AS '@MODULE_FILENAME@','assvg_geometry'
	LANGUAGE 'c'  with (isstrict);

CREATE FUNCTION assvg(geometry,int4)
	RETURNS TEXT
	AS '@MODULE_FILENAME@','assvg_geometry'
	LANGUAGE 'c'  with (isstrict);

CREATE FUNCTION assvg(geometry,int4,int4)
	RETURNS TEXT
	AS '@MODULE_FILENAME@','assvg_geometry'
	LANGUAGE 'c'  with (isstrict);


=====================================================================

HTH :)

--
Ol




More information about the postgis-users mailing list