[postgis-devel] GeomRound and GeomTrunc functions
strk
strk at keybit.net
Fri Jul 2 02:41:59 PDT 2004
Some thought on your contributed functions:
- Since the inspiration come from ROUND and TRUNC
what about using ROUND and TRUNC instead of
GEOM_ROUND and GEOM_TRUNC for function names ?
- Insipiring functions work on 1-dimensional types
what about making Geometry functions take in
consideration 2 and 3 dimensions ? Do you see
any use of rounding with different values the 3
dimensions ?
- Doesn't SQL provide casting toward numeric data ?
Have you tried defining your funx as taking int2 and
see if postgresql will convert numeric values to int2 ?
- How would rounding simplify display of geoms ?
If it is a speedup in rendering computations
useless points removal seems worth it...
--strk;
On Fri, Jul 02, 2004 at 11:10:12AM +0200, Gino Lucrezi wrote:
> They are working, now.
>
> In the end, I decided that these functions are only meant for simplifying display of points or structures, and not for further processing, so I haven't yet implemented any check on identical consecutive points and the such.
>
> That would have involved more pointer handling than I liked, maybe I'll do it in the future.
>
> I left a warning to that effect in the code.
>
> I aree with strk's thoughts on the subject, though.
>
> The number of digits might be negative:
> GeomRound( GeomFromText('POINT(358808.488 701948.639)',23033), -5 )
> will result in POINT(400000 4700000), even though this is a rather extreme example.
>
> Since the number of digits can't be too high, I used an int2 as parameter type, so I had to do some SQL type casting. I don't know if it's a good idea.
> Also, I left this parameter optional (default value being 0), and I did the overloading in SQL; it might have been better to do it in the C code, I don't know.
>
> Since this was my first attempt at hacking into PostGIS I didn't know what the standard practices are.
>
> The code is shamelessly based on the translate function.
>
> I am enclosing diffs with existing files, it's just a matter of adding a few functions.
> If there is a better way to submit code, tell me. The server I develop on has no internet access, so I can't connect to a CVS server.
>
> Gino Lucrezi
> Penta Consulting Services
>
>
>
> diff ./postgis_fn.c ../postgis-cvs-originale/postgis_fn.c
> 985,1203d984
> < //round geometry
> < // rounds off all points in a geometry up to ndigits
> < // WARNING: might generate invalid geometries.
> < // It is only meant for simplifying display of points or structures.
> < // Different points in a line or polygon might "collapse" into the same
> < // coordinates. A possible improvement could be removing consecutive
> < // points with the same coordinates, but lines and polygons might
> < // degenerate into single points.
> < // Obviously, this function is not a OGC standard.
> < // It was inspired by the SQL ROUND() function (which only works on scalar data)
> < // ndigits might be negative:
> < // GeomRound( GeomFromText('POINT(358808.488 4701948.639)',23033), -5 )
> < // will result in POINT(400000 4700000)
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> <
> < PG_FUNCTION_INFO_V1(geom_round);
> < Datum geom_round(PG_FUNCTION_ARGS)
> < {
> < GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
> < GEOMETRY *geom1;
> < int2 ndigits = PG_GETARG_INT16(1);
> < int32 *offsets1;
> < char *o1;
> < int32 type,j,i;
> < POLYGON3D *poly;
> < POINT3D *point,*pts;
> < LINE3D *line;
> < int numb_points;
> <
> < //make a copy of geom so we can return a new version
> < geom1 = (GEOMETRY *) palloc (geom->size);
> < memcpy(geom1, geom, geom->size); //Will handle SRID and grid
> <
> < offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
> <
> < //now have to do a scan of each object
> <
> < for (j=0; j< geom1->nobjs; j++) //for each object in geom1
> < {
> < o1 = (char *) geom1 +offsets1[j] ;
> < type= geom1->objType[j];
> <
> < if (type == POINTTYPE) //point
> < {
> < point = (POINT3D *) o1;
> < round_points(point, 1,ndigits);
> <
> < }
> <
> < if (type == LINETYPE) //line
> < {
> < line = (LINE3D *) o1;
> < round_points(&(line->points[0]), line->npoints,ndigits);
> < }
> <
> < if (type == POLYGONTYPE) //POLYGON
> < {
> < poly = (POLYGON3D *) o1;
> < //find where the points are and where to put them
> < numb_points =0;
> < for (i=0; i<poly->nrings;i++)
> < {
> < numb_points += poly->npoints[i];
> < }
> < pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) );
> < pts = (POINT3D *) MAXALIGN(pts);
> < round_points(pts, numb_points,ndigits);
> < }
> < }
> < //round the bounding box as well
> < geom1->bvol.LLB.x = my_round( geom1->bvol.LLB.x, ndigits );
> < geom1->bvol.LLB.y = my_round( geom1->bvol.LLB.y, ndigits );
> < geom1->bvol.LLB.z = my_round( geom1->bvol.LLB.z, ndigits );
> < geom1->bvol.URT.x = my_round( geom1->bvol.URT.x, ndigits );
> < geom1->bvol.URT.y = my_round( geom1->bvol.URT.y, ndigits );
> < geom1->bvol.URT.z = my_round( geom1->bvol.URT.z, ndigits );
> <
> < PG_RETURN_POINTER(geom1);
> < }
> <
> <
> < // Round a single point to ndigits decimal places
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> <
> < void round_points(POINT3D *pt, int npoints, int2 ndigits)
> < {
> < int i;
> <
> < if (npoints <1)
> < return; //nothing to do
> <
> < for (i=0;i<npoints;i++)
> < {
> < //elog(LOG,"before: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
> <
> < pt[i].x = my_round( pt[i].x, ndigits );
> < pt[i].y = my_round( pt[i].y, ndigits );
> < pt[i].z = my_round( pt[i].z, ndigits );
> <
> < //elog(LOG,"after: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
> < }
> < }
> <
> < // round a double to a specified number of digits
> < // ndigits can be negative
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> < double my_round( double X, int2 ndigits )
> < {
> < return round( X * pow(10, ndigits) ) * pow(10, -ndigits );
> < }
> <
> <
> < //trunc geometry
> < // truncates extra digits off all points in a geometry up to ndigits
> < // WARNING: might generate invalid geometries.
> < // It is only meant for simplifying display of points or structures.
> < // See geom_round for details
> < // Obviously, this function is not a OGC standard.
> < // It was inspired by the SQL TRUNC() function (which only works on scalar data)
> < // ndigits might be negative:
> < // GeomTrunc( GeomFromText('POINT(358808.488 4701948.639)',23033), -5 )
> < // will result in POINT(300000 4700000)
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> <
> < PG_FUNCTION_INFO_V1(geom_trunc);
> < Datum geom_trunc(PG_FUNCTION_ARGS)
> < {
> < GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
> < GEOMETRY *geom1;
> < int2 ndigits = PG_GETARG_INT16(1);
> < int32 *offsets1;
> < char *o1;
> < int32 type,j,i;
> < POLYGON3D *poly;
> < POINT3D *point,*pts;
> < LINE3D *line;
> < int numb_points;
> <
> < //make a copy of geom so we can return a new version
> < geom1 = (GEOMETRY *) palloc (geom->size);
> < memcpy(geom1, geom, geom->size); //Will handle SRID and grid
> <
> < offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
> <
> < //now have to do a scan of each object
> <
> < for (j=0; j< geom1->nobjs; j++) //for each object in geom1
> < {
> < o1 = (char *) geom1 +offsets1[j] ;
> < type= geom1->objType[j];
> <
> < if (type == POINTTYPE) //point
> < {
> < point = (POINT3D *) o1;
> < trunc_points(point, 1,ndigits);
> <
> < }
> <
> < if (type == LINETYPE) //line
> < {
> < line = (LINE3D *) o1;
> < trunc_points(&(line->points[0]), line->npoints,ndigits);
> < }
> <
> < if (type == POLYGONTYPE) //POLYGON
> < {
> < poly = (POLYGON3D *) o1;
> < //find where the points are and where to put them
> < numb_points =0;
> < for (i=0; i<poly->nrings;i++)
> < {
> < numb_points += poly->npoints[i];
> < }
> < pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) );
> < pts = (POINT3D *) MAXALIGN(pts);
> < trunc_points(pts, numb_points,ndigits);
> < }
> < }
> < //truncates the bounding box as well
> < geom1->bvol.LLB.x = my_trunc( geom1->bvol.LLB.x, ndigits );
> < geom1->bvol.LLB.y = my_trunc( geom1->bvol.LLB.y, ndigits );
> < geom1->bvol.LLB.z = my_trunc( geom1->bvol.LLB.z, ndigits );
> < geom1->bvol.URT.x = my_trunc( geom1->bvol.URT.x, ndigits );
> < geom1->bvol.URT.y = my_trunc( geom1->bvol.URT.y, ndigits );
> < geom1->bvol.URT.z = my_trunc( geom1->bvol.URT.z, ndigits );
> <
> < PG_RETURN_POINTER(geom1);
> < }
> <
> <
> < // Truncate a single point to ndigits decimal places
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> <
> < void trunc_points(POINT3D *pt, int npoints, int2 ndigits)
> < {
> < int i;
> <
> < if (npoints <1)
> < return; //nothing to do
> <
> < for (i=0;i<npoints;i++)
> < {
> < //elog(LOG,"before: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
> <
> < pt[i].x = my_trunc( pt[i].x, ndigits );
> < pt[i].y = my_trunc( pt[i].y, ndigits );
> < pt[i].z = my_trunc( pt[i].z, ndigits );
> <
> < //elog(LOG,"after: [%g,%g,%g]\n", pt[i].x, pt[i].y,pt[i].z);
> < }
> < }
> <
> < // truncate a double to a specified number of digits
> < // ndigits can be negative
> < // 2004/07/01 Gino Lucrezi (gino-pgsc at lucrezi.net)
> < double my_trunc( double X, int2 ndigits )
> < {
> < return trunc( X * pow(10, ndigits) ) * pow(10, -ndigits );
> < }
>
>
>
> diff ./postgis.h ../postgis-cvs-originale/postgis.h
> 418,421d417
> < void round_points(POINT3D *pt, int npoints, int2 ndigits);
> < void trunc_points(POINT3D *pt, int npoints, int2 ndigits);
> < double my_round( double X, int2 ndigits );
> < double my_trunc( double X, int2 ndigits );
> 545,546d540
> < Datum geom_round(PG_FUNCTION_ARGS);
> < Datum geom_trunc(PG_FUNCTION_ARGS);
>
>
>
> diff ./postgis_sql_common.sql.in ../postgis-cvs-originale/postgis_sql_common.sql.in
> 509,538d508
> < CREATE FUNCTION GeomRound(geometry,smallint)
> < RETURNS geometry
> < AS '@MODULE_FILENAME@', 'geom_round'
> < LANGUAGE 'C' WITH (isstrict) ;
> <
> < CREATE FUNCTION GeomRound(geometry, numeric)
> < RETURNS geometry AS
> < 'SELECT GeomRound( $1, $2::int2)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATE FUNCTION GeomRound(geometry)
> < RETURNS geometry AS
> < 'SELECT GeomRound( $1, 0)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATE FUNCTION GeomTrunc(geometry,smallint)
> < RETURNS geometry
> < AS '@MODULE_FILENAME@', 'geom_trunc'
> < LANGUAGE 'C' WITH (isstrict) ;
> <
> < CREATE FUNCTION GeomTrunc(geometry, numeric)
> < RETURNS geometry AS
> < 'SELECT GeomTrunc( $1, $2::int2)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATE FUNCTION GeomTrunc(geometry)
> < RETURNS geometry AS
> < 'SELECT GeomTrunc( $1, 0)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
>
>
>
> diff ./postgis.sql.in ../postgis-cvs-originale/postgis.sql.in
> 956,985d955
> < CREATEFUNCTION GeomRound(geometry,smallint)
> < RETURNS geometry
> < AS '@MODULE_FILENAME@', 'geom_round'
> < LANGUAGE 'C' WITH (isstrict) ;
> <
> < CREATEFUNCTION GeomRound(geometry, numeric)
> < RETURNS geometry AS
> < 'SELECT GeomRound( $1, $2::int2)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATEFUNCTION GeomRound(geometry)
> < RETURNS geometry AS
> < 'SELECT GeomRound( $1, 0)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATEFUNCTION GeomTrunc(geometry,smallint)
> < RETURNS geometry
> < AS '@MODULE_FILENAME@', 'geom_trunc'
> < LANGUAGE 'C' WITH (isstrict) ;
> <
> < CREATEFUNCTION GeomTrunc(geometry, numeric)
> < RETURNS geometry AS
> < 'SELECT GeomTrunc( $1, $2::int2)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
> < CREATEFUNCTION GeomTrunc(geometry)
> < RETURNS geometry AS
> < 'SELECT GeomTrunc( $1, 0)'
> < LANGUAGE 'sql' WITH (isstrict) ;
> <
>
> _______________________________________________
> postgis-devel mailing list
> postgis-devel at postgis.refractions.net
> http://postgis.refractions.net/mailman/listinfo/postgis-devel
More information about the postgis-devel
mailing list