[postgis-devel] Interpolating a point along a line
Joe Sunday
sunday at csh.rit.edu
Wed Jan 21 10:07:32 PST 2004
On Wed, Jan 21, 2004 at 09:00:39AM -0800, David Blasby wrote:
> This is a good function - but I think we should make 2 minor changes to
> strk to apply the patch and make sure its working.
Corrected patch applied.
--Joe
--
Joe Sunday <sunday at csh.rit.edu> http://www.csh.rit.edu/~sunday/
Computer Science House, Rochester Inst. Of Technology
-------------- next part --------------
Index: postgis.h
===================================================================
RCS file: /home/cvs/postgis/postgis/postgis.h,v
retrieving revision 1.39
diff -u -5 -p -r1.39 postgis.h
--- postgis.h 28 Nov 2003 11:06:49 -0000 1.39
+++ postgis.h 21 Jan 2004 18:04:21 -0000
@@ -631,10 +631,11 @@ Datum geometry_from_text_mpoint(PG_FUNCT
Datum geometry_from_text_line(PG_FUNCTION_ARGS);
Datum geometry_from_text_mline(PG_FUNCTION_ARGS);
Datum geometry_from_text_gc(PG_FUNCTION_ARGS);
Datum isempty(PG_FUNCTION_ARGS);
Datum simplify(PG_FUNCTION_ARGS);
+Datum line_interpolate_point(PG_FUNCTION_ARGS);
/*--------------------------------------------------------------------
* Useful floating point utilities and constants.
* from postgres geo_decls.c
* EPSILON modified to be more "double" friendly
Index: postgis_algo.c
===================================================================
RCS file: /home/cvs/postgis/postgis/postgis_algo.c,v
retrieving revision 1.1
diff -u -5 -p -r1.1 postgis_algo.c
--- postgis_algo.c 27 Oct 2003 10:21:15 -0000 1.1
+++ postgis_algo.c 21 Jan 2004 18:04:21 -0000
@@ -405,5 +405,101 @@ Datum simplify(PG_FUNCTION_ARGS)
}
/***********************************************************************
* --strk at keybit.net;
***********************************************************************/
+
+/***********************************************************************
+ * Interpolate a point along a line, useful for Geocoding applications
+ * SELECT line_interpolate_point( 'LINESTRING( 0 0, 2 2'::geometry, .5 )
+ * returns POINT( 1 1 )
+ *
+ * -- jsunday at rochgrp.com;
+ ***********************************************************************/
+PG_FUNCTION_INFO_V1(line_interpolate_point);
+Datum line_interpolate_point(PG_FUNCTION_ARGS)
+{
+ GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ double distance = PG_GETARG_FLOAT8(1);
+
+ int32 *offsets1;
+ LINE3D *line;
+ POINT3D point;
+ int nsegs, i;
+ double length, slength, tlength;
+
+ if( distance < 0 || distance > 1 ) {
+ elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]");
+ PG_RETURN_NULL();
+ }
+
+ if( geom->type != LINETYPE ) {
+ elog(ERROR,"line_interpolate_point: 1st arg isnt a line");
+ PG_RETURN_NULL();
+ }
+
+ offsets1 = (int32 *) ( ((char *) &(geom->objType[0] )) +
+ sizeof(int32) * geom->nobjs );
+ line = (LINE3D*) ( (char *)geom + offsets1[0] );
+
+ /* If distance is one of the two extremes, return the point on that
+ * end rather than doing any expensive computations
+ */
+ if( distance == 0.0 ) {
+ PG_RETURN_POINTER(
+ make_oneobj_geometry(sizeof(POINT3D),
+ /*(char*)&(line->points[0]), POINTTYPE, */
+ (char*)&(line->points[0]), POINTTYPE,
+ geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY
+ )
+ );
+ }
+
+ if( distance == 1.0 ) {
+ PG_RETURN_POINTER(
+ make_oneobj_geometry(sizeof(POINT3D),
+ (char*)&(line->points[line->npoints-1]), POINTTYPE,
+ geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY
+ )
+ );
+ }
+
+ /* Interpolate a point on the line */
+ nsegs = line->npoints - 1;
+ length = line_length2d( line );
+ tlength = 0;
+ for( i = 0; i < nsegs; i++ ) {
+ POINT3D *p1, *p2;
+ p1 = &(line->points[i]);
+ p2 = &(line->points[i+1]);
+ /* Find the relative length of this segment */
+ slength = distance_pt_pt( p1, p2 )/length;
+ /* If our target distance is before the total length we've seen
+ * so far. create a new point some distance down the current
+ * segment.
+ */
+ if( distance < tlength + slength ) {
+ double dseg = (distance - tlength) / slength;
+ point.x = (p1->x) + ((p2->x - p1->x) * dseg);
+ point.y = (p1->y) + ((p2->y - p1->y) * dseg);
+ point.z = 0;
+ PG_RETURN_POINTER(
+ make_oneobj_geometry(sizeof(POINT3D),
+ (char*)&point, POINTTYPE,
+ geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY
+ )
+ );
+ }
+ tlength += slength;
+ }
+ /* Return the last point on the line. This shouldn't happen, but
+ * could if there's some floating point rounding errors. */
+ PG_RETURN_POINTER(
+ make_oneobj_geometry(sizeof(POINT3D),
+ (char*)&(line->points[line->npoints-1]), POINTTYPE,
+ geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY
+ )
+ );
+}
+/***********************************************************************
+ * --jsunday at rochgrp.com;
+ ***********************************************************************/
Index: postgis_sql_common.sql.in
===================================================================
RCS file: /home/cvs/postgis/postgis/postgis_sql_common.sql.in,v
retrieving revision 1.26
diff -u -5 -p -r1.26 postgis_sql_common.sql.in
--- postgis_sql_common.sql.in 23 Dec 2003 09:00:12 -0000 1.26
+++ postgis_sql_common.sql.in 21 Jan 2004 18:04:24 -0000
@@ -1243,5 +1243,11 @@ CREATE FUNCTION geosnoop(geometry)
CREATE FUNCTION simplify(geometry, float8)
RETURNS geometry
AS '@MODULE_FILENAME@'
LANGUAGE 'C' WITH (isstrict);
+
+CREATE FUNCTION line_interpolate_point(geometry, float8)
+ RETURNS geometry
+ AS '@MODULE_FILENAME@'
+ LANGUAGE 'C' WITH (isstrict);
+
More information about the postgis-devel
mailing list