- full autoconf-based configuration
- added scale() and transscale() companion methods to translate()
- initial implementation of postgis_proc_upgrade script
+ - NEW line_substring() function
PostGIS 1.0.1
2005/05/24
Returns a float, representing the proportional distance the
point is located along the line.
-- line_interpolate_line(geometry, proportion, direction)
-
- Returns a line, representing the subset of the input line
- that is the proportional distance along the line. Direction
- determines what end to measure from. (??)
-
- MakeValidShape() to remove consecutive vertexes and any eventual
other cleanup aimed at making pgsql2shp produce "valid" Shapefiles.
</varlistentry>
<varlistentry>
- <term>scale(geometry,float8,float8,float8)</term>
+ <term>Scale(geometry,float8,float8,float8)</term>
<listitem>
<para>scales the geometry to a new size by multiplying the
ordinates with the parameters. Ie: scale(geom, Xfactor, Yfactor, Zfactor).</para>
+ <para>
+ Availability: 1.1.0
+ </para>
</listitem>
</varlistentry>
<varlistentry>
- <term>transscale(geometry,float8,float8,float8,float8)</term>
+ <term>TransScale(geometry,float8,float8,float8,float8)</term>
<listitem>
<para>First, translates the geometry using the first two floats, then scales it
using the second two floats, working in 2D only. Using
transscale(geom, X, Y, XFactor, YFactor) effectively is an efficient shortcut
for scale(translate(geom,X,Y,0),Xfactor,YFactor,1).</para>
+ <para>
+ Availability: 1.1.0
+ </para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
+ <sect2>
+ <title>Linear Referencing</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>line_interpolate_point(geometry, proportion)</term>
+
+ <listitem>
+ <para>Interpolates a point along a line. First argument must be a
+ LINESTRING. Second argument is a float between 0 and 1. Returns a
+ point.</para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>line_substring(geometry, start, end)</term>
+
+ <listitem>
+ <para>
+ Return a linestring being a substring of the input one starting
+ and ending at the given fractions of total length. Second
+ and third arguments are float8 values between 0 and 1.
+ </para>
+ <para>
+ Availability: 1.1.0
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </sect2>
+
<sect2>
<title>Misc</title>
<variablelist>
</listitem>
</varlistentry>
- <varlistentry>
- <term>line_interpolate_point(geometry, proportion)</term>
-
- <listitem>
- <para>Interpolates a point along a line. First argument must be a
- LINESTRING. Second argument is a float between 0 and 1. Returns a
- point.</para>
- </listitem>
- </varlistentry>
-
<varlistentry id="Accum">
<term>Accum(geometry set)</term>
</sect2>
+
</sect1>
</chapter>
extern int32 lwgeom_nrings_recursive(uchar *serialized);
extern void ptarray_reverse(POINTARRAY *pa);
+extern POINTARRAY *ptarray_substring(POINTARRAY *, double, double);
// Ensure every segment is at most 'dist' long.
// Returned LWGEOM might is unchanged if a POINT.
/***********************************************************************
* --strk@keybit.net
***********************************************************************/
+
+Datum LWGEOM_line_substring(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(LWGEOM_line_substring);
+Datum LWGEOM_line_substring(PG_FUNCTION_ARGS)
+{
+ PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ double from = PG_GETARG_FLOAT8(1);
+ double to = PG_GETARG_FLOAT8(2);
+ LWLINE *iline;
+ LWLINE *oline;
+ POINTARRAY *ipa, *opa;
+ PG_LWGEOM *ret;
+
+ if( from < 0 || from > 1 ) {
+ elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]");
+ PG_RETURN_NULL();
+ }
+
+ if( to < 0 || to > 1 ) {
+ elog(ERROR,"line_interpolate_point: 3rd arg isnt within [0,1]");
+ PG_RETURN_NULL();
+ }
+
+ if( lwgeom_getType(geom->type) != LINETYPE ) {
+ elog(ERROR,"line_interpolate_point: 1st arg isnt a line");
+ PG_RETURN_NULL();
+ }
+
+ iline = lwline_deserialize(SERIALIZED_FORM(geom));
+ ipa = iline->points;
+
+ opa = ptarray_substring(ipa, from, to);
+
+ oline = lwline_construct(iline->SRID, 0, opa);
+ ret = pglwgeom_serialize((LWGEOM *)oline);
+ PG_FREE_IF_COPY(geom, 0);
+ lwgeom_release((LWGEOM *)oline);
+ PG_RETURN_POINTER(ret);
+}
AS '@MODULE_FILENAME@', 'LWGEOM_line_interpolate_point'
LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+CREATEFUNCTION line_substring(geometry, float8, float8)
+ RETURNS geometry
+ AS '@MODULE_FILENAME@', 'LWGEOM_line_substring'
+ LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (isstrict,iscachable);
+
CREATEFUNCTION segmentize(geometry, float8)
RETURNS geometry
AS '@MODULE_FILENAME@', 'LWGEOM_segmentize2d'
return 1;
}
+
+POINTARRAY *
+ptarray_substring(POINTARRAY *ipa, double from, double to)
+{
+ POINTARRAY *opa;
+ int nopts=0;
+ uchar *opts;
+ uchar *optsptr;
+ POINT4D pt;
+ POINT2D p1, p2;
+ int nsegs, i;
+ int ptsize;
+ double length, slength, tlength;
+ int state = 0; // 0=before, 1=inside, 2=after
+
+ /* Allocate memory for a full copy of input points */
+ ptsize=TYPE_NDIMS(ipa->dims)*sizeof(double);
+ opts = lwalloc(ptsize*ipa->npoints);
+ optsptr = opts;
+
+ /* Interpolate a point on the line */
+ nsegs = ipa->npoints - 1;
+ length = lwgeom_pointarray_length2d(ipa);
+
+ //lwnotice("Total length: %g", length);
+
+ from = length*from;
+ to = length*to;
+
+ //lwnotice("From/To: %g/%g", from, to);
+
+ tlength = 0;
+ getPoint2d_p(ipa, 0, &p1);
+ for( i = 0; i < nsegs; i++ ) {
+
+ getPoint2d_p(ipa, i+1, &p2);
+
+ /* Find the relative length of this segment */
+ slength = distance2d_pt_pt(&p1, &p2);
+
+ /*
+ * 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 ( state == 0 )
+ {
+ if ( from < tlength + slength ) {
+ double dseg = (from - tlength) / slength;
+ pt.x = (p1.x) + ((p2.x - p1.x) * dseg);
+ pt.y = (p1.y) + ((p2.y - p1.y) * dseg);
+ pt.z = 0; pt.m = 0;
+ memcpy(optsptr, &pt, ptsize);
+ optsptr+=ptsize;
+ nopts++; state++;
+ }
+ }
+
+ if ( state == 1 )
+ {
+ if ( to < tlength + slength ) {
+ double dseg = (to - tlength) / slength;
+ pt.x = (p1.x) + ((p2.x - p1.x) * dseg);
+ pt.y = (p1.y) + ((p2.y - p1.y) * dseg);
+ pt.z = 0; pt.m = 0;
+ memcpy(optsptr, &pt, ptsize);
+ optsptr+=ptsize;
+ nopts++; break;
+ } else {
+ memcpy(optsptr, &p2, ptsize);
+ optsptr+=ptsize;
+ nopts++;
+ }
+ }
+
+
+ tlength += slength;
+ memcpy(&p1, &p2, sizeof(POINT2D));
+ }
+
+ //lwnotice("Out of loop, constructing ptarray with %d points", nopts);
+
+ opa = pointArray_construct(opts,
+ TYPE_HASZ(ipa->dims),
+ TYPE_HASM(ipa->dims),
+ nopts);
+
+ return opa;
+}