PostGIS  2.2.7dev-r@@SVN_REVISION@@
lwgeom_functions_lrs.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2001-2005 Refractions Research Inc.
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
13 #include <math.h>
14 
15 #include "postgres.h"
16 #include "fmgr.h"
17 
18 #include "../postgis_config.h"
19 #include "liblwgeom.h"
20 #include "lwgeom_pg.h"
21 
22 /*
23 * Add a measure dimension to a line, interpolating linearly from the
24 * start value to the end value.
25 * ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry
26 */
27 Datum ST_AddMeasure(PG_FUNCTION_ARGS);
29 Datum ST_AddMeasure(PG_FUNCTION_ARGS)
30 {
31  GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0);
32  GSERIALIZED *gout;
33  double start_measure = PG_GETARG_FLOAT8(1);
34  double end_measure = PG_GETARG_FLOAT8(2);
35  LWGEOM *lwin, *lwout;
36  int type = gserialized_get_type(gin);
37 
38  /* Raise an error if input is not a linestring or multilinestring */
39  if ( type != LINETYPE && type != MULTILINETYPE )
40  {
41  lwpgerror("Only LINESTRING and MULTILINESTRING are supported");
42  PG_RETURN_NULL();
43  }
44 
45  lwin = lwgeom_from_gserialized(gin);
46  if ( type == LINETYPE )
47  lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure);
48  else
49  lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure);
50 
51  lwgeom_free(lwin);
52 
53  if ( lwout == NULL )
54  PG_RETURN_NULL();
55 
56  gout = geometry_serialize(lwout);
57  lwgeom_free(lwout);
58 
59  PG_RETURN_POINTER(gout);
60 }
61 
62 
63 /*
64 * Locate a point along a feature based on a measure value.
65 * ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry
66 */
67 Datum ST_LocateAlong(PG_FUNCTION_ARGS);
69 Datum ST_LocateAlong(PG_FUNCTION_ARGS)
70 {
71  GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0);
72  GSERIALIZED *gout;
73  LWGEOM *lwin = NULL, *lwout = NULL;
74  double measure = PG_GETARG_FLOAT8(1);
75  double offset = PG_GETARG_FLOAT8(2);;
76 
77  lwin = lwgeom_from_gserialized(gin);
78  lwout = lwgeom_locate_along(lwin, measure, offset);
79  lwgeom_free(lwin);
80  PG_FREE_IF_COPY(gin, 0);
81 
82  if ( ! lwout )
83  PG_RETURN_NULL();
84 
85  gout = geometry_serialize(lwout);
86  lwgeom_free(lwout);
87 
88  PG_RETURN_POINTER(gout);
89 }
90 
91 
92 /*
93 * Locate the portion of a line between the specified measures
94 */
95 Datum ST_LocateBetween(PG_FUNCTION_ARGS);
97 Datum ST_LocateBetween(PG_FUNCTION_ARGS)
98 {
99  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
100  double from = PG_GETARG_FLOAT8(1);
101  double to = PG_GETARG_FLOAT8(2);
102  double offset = PG_GETARG_FLOAT8(3);
103  LWCOLLECTION *geom_out = NULL;
104  LWGEOM *line_in = NULL;
105  static char ordinate = 'M'; /* M */
106 
107  if ( ! gserialized_has_m(geom_in) )
108  {
109  elog(ERROR,"This function only accepts geometries that have an M dimension.");
110  PG_RETURN_NULL();
111  }
112 
113  /* This should be a call to ST_LocateAlong! */
114  if ( to == from )
115  {
116  PG_RETURN_DATUM(DirectFunctionCall3(ST_LocateAlong, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), PG_GETARG_DATUM(3)));
117  }
118 
119  line_in = lwgeom_from_gserialized(geom_in);
120  geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset);
121  lwgeom_free(line_in);
122  PG_FREE_IF_COPY(geom_in, 0);
123 
124  if ( ! geom_out )
125  {
126  elog(ERROR,"lwline_clip_to_ordinate_range returned null");
127  PG_RETURN_NULL();
128  }
129 
130  PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
131 }
132 
133 /*
134 * Locate the portion of a line between the specified elevations
135 */
136 Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS);
138 Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS)
139 {
140  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
141  double from = PG_GETARG_FLOAT8(1);
142  double to = PG_GETARG_FLOAT8(2);
143  LWCOLLECTION *geom_out = NULL;
144  LWGEOM *line_in = NULL;
145  static char ordinate = 'Z'; /* Z */
146  static double offset = 0.0;
147 
148  if ( ! gserialized_has_z(geom_in) )
149  {
150  elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions.");
151  PG_RETURN_NULL();
152  }
153 
154  line_in = lwgeom_from_gserialized(geom_in);
155  geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset);
156  lwgeom_free(line_in);
157  PG_FREE_IF_COPY(geom_in, 0);
158 
159  if ( ! geom_out )
160  {
161  elog(ERROR,"lwline_clip_to_ordinate_range returned null");
162  PG_RETURN_NULL();
163  }
164 
165  PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
166 }
167 
168 
169 Datum ST_InterpolatePoint(PG_FUNCTION_ARGS);
171 Datum ST_InterpolatePoint(PG_FUNCTION_ARGS)
172 {
173  GSERIALIZED *gser_line = PG_GETARG_GSERIALIZED_P(0);
174  GSERIALIZED *gser_point = PG_GETARG_GSERIALIZED_P(1);
175  LWGEOM *lwline;
176  LWPOINT *lwpoint;
177 
178  if ( gserialized_get_type(gser_line) != LINETYPE )
179  {
180  elog(ERROR,"ST_InterpolatePoint: 1st argument isn't a line");
181  PG_RETURN_NULL();
182  }
183  if ( gserialized_get_type(gser_point) != POINTTYPE )
184  {
185  elog(ERROR,"ST_InterpolatePoint: 2st argument isn't a point");
186  PG_RETURN_NULL();
187  }
188 
190 
191  if ( ! gserialized_has_m(gser_line) )
192  {
193  elog(ERROR,"ST_InterpolatePoint only accepts geometries that have an M dimension");
194  PG_RETURN_NULL();
195  }
196 
197  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point));
198  lwline = lwgeom_from_gserialized(gser_line);
199 
200  PG_RETURN_FLOAT8(lwgeom_interpolate_point(lwline, lwpoint));
201 }
202 
203 
204 Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS);
206 Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
207 {
208  GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
209  GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
210  LWLINE *lwline;
211  LWPOINT *lwpoint;
212  POINTARRAY *pa;
213  POINT4D p, p_proj;
214  double ret;
215 
216  if ( gserialized_get_type(geom1) != LINETYPE )
217  {
218  elog(ERROR,"line_locate_point: 1st arg isn't a line");
219  PG_RETURN_NULL();
220  }
221  if ( gserialized_get_type(geom2) != POINTTYPE )
222  {
223  elog(ERROR,"line_locate_point: 2st arg isn't a point");
224  PG_RETURN_NULL();
225  }
226 
228 
229  lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1));
230  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
231 
232  pa = lwline->points;
233  lwpoint_getPoint4d_p(lwpoint, &p);
234 
235  ret = ptarray_locate_point(pa, &p, NULL, &p_proj);
236 
237  PG_RETURN_FLOAT8(ret);
238 }
239 
240 
241 /***********************************************************************
242 * LEGACY SUPPORT FOR locate_between_measures and locate_along_measure
243 * Deprecated at PostGIS 2.0. To be removed.
244 */
245 
246 
247 typedef struct
248 {
250  uint32 nptarrays;
251 }
253 
255  POINTARRAY *ipa, double m0, double m1);
256 
258  LWCOLLECTION *lwcoll, double m0, double m1);
259 
261  LWGEOM *lwin, double m0, double m1);
262 
264  LWLINE *lwline_in, double m0, double m1);
265 
267  LWPOINT *lwpoint, double m0, double m1);
268 
269 static int clip_seg_by_m_range(
270  POINT4D *p1, POINT4D *p2, double m0, double m1);
271 
272 
273 /*
274  * Clip a segment by a range of measures.
275  * Z and M values are interpolated in case of clipping.
276  *
277  * Returns a bitfield, flags being:
278  * 0x0001 : segment intersects the range
279  * 0x0010 : first point is modified
280  * 0x0100 : second point is modified
281  *
282  * Values:
283  * - 0 segment fully outside the range, no modifications
284  * - 1 segment fully inside the range, no modifications
285  * - 7 segment crosses the range, both points modified.
286  * - 3 first point out, second in, first point modified
287  * - 5 first point in, second out, second point modified
288  */
289 static int
290 clip_seg_by_m_range(POINT4D *p1, POINT4D *p2, double m0, double m1)
291 {
292  double dM0, dM1, dX, dY, dZ;
293  POINT4D *tmp;
294  int swapped=0;
295  int ret=0;
296 
297  POSTGIS_DEBUGF(3, "m0: %g m1: %g", m0, m1);
298 
299  /* Handle corner case of m values being the same */
300  if ( p1->m == p2->m )
301  {
302  /* out of range, no clipping */
303  if ( p1->m < m0 || p1->m > m1 )
304  return 0;
305 
306  /* inside range, no clipping */
307  return 1;
308  }
309 
310  /*
311  * Order points so that p1 has the smaller M
312  */
313  if ( p1->m > p2->m )
314  {
315  tmp=p2;
316  p2=p1;
317  p1=tmp;
318  swapped=1;
319  }
320 
321  /*
322  * The M range is not intersected, segment
323  * fully out of range, no clipping.
324  */
325  if ( p2->m < m0 || p1->m > m1 )
326  return 0;
327 
328  /*
329  * The segment is fully inside the range,
330  * no clipping.
331  */
332  if ( p1->m >= m0 && p2->m <= m1 )
333  return 1;
334 
335  /*
336  * Segment intersects range, lets compute
337  * the proportional location of the two
338  * measures wrt p1/p2 m range.
339  *
340  * if p1 and p2 have the same measure
341  * this should never be reached (either
342  * both inside or both outside)
343  *
344  */
345  dM0=(m0-p1->m)/(p2->m-p1->m); /* delta-M0 */
346  dM1=(m1-p2->m)/(p2->m-p1->m); /* delta-M1 */
347  dX=p2->x-p1->x;
348  dY=p2->y-p1->y;
349  dZ=p2->z-p1->z;
350 
351  POSTGIS_DEBUGF(3, "dM0:%g dM1:%g", dM0, dM1);
352  POSTGIS_DEBUGF(3, "dX:%g dY:%g dZ:%g", dX, dY, dZ);
353  POSTGIS_DEBUGF(3, "swapped: %d", swapped);
354 
355  /*
356  * First point out of range, project
357  * it on the range
358  */
359  if ( p1->m < m0 )
360  {
361  /*
362  * To prevent rounding errors, then if m0==m1 and p2 lies within the range, copy
363  * p1 as a direct copy of p2
364  */
365  if (m0 == m1 && p2->m <= m1)
366  {
367  memcpy(p1, p2, sizeof(POINT4D));
368 
369  POSTGIS_DEBUG(3, "Projected p1 on range (as copy of p2)");
370  }
371  else
372  {
373  /* Otherwise interpolate coordinates */
374  p1->x += (dX*dM0);
375  p1->y += (dY*dM0);
376  p1->z += (dZ*dM0);
377  p1->m = m0;
378 
379  POSTGIS_DEBUG(3, "Projected p1 on range");
380  }
381 
382  if ( swapped ) ret |= 0x0100;
383  else ret |= 0x0010;
384  }
385 
386  /*
387  * Second point out of range, project
388  * it on the range
389  */
390  if ( p2->m > m1 )
391  {
392  /*
393  * To prevent rounding errors, then if m0==m1 and p1 lies within the range, copy
394  * p2 as a direct copy of p1
395  */
396  if (m0 == m1 && p1->m >= m0)
397  {
398  memcpy(p2, p1, sizeof(POINT4D));
399 
400  POSTGIS_DEBUG(3, "Projected p2 on range (as copy of p1)");
401  }
402  else
403  {
404  /* Otherwise interpolate coordinates */
405  p2->x += (dX*dM1);
406  p2->y += (dY*dM1);
407  p2->z += (dZ*dM1);
408  p2->m = m1;
409 
410  POSTGIS_DEBUG(3, "Projected p2 on range");
411  }
412 
413  if ( swapped ) ret |= 0x0010;
414  else ret |= 0x0100;
415  }
416 
417  /* Clipping occurred */
418  return ret;
419 
420 }
421 
422 static POINTARRAYSET
423 ptarray_locate_between_m(POINTARRAY *ipa, double m0, double m1)
424 {
425  POINTARRAYSET ret;
426  POINTARRAY *dpa=NULL;
427  int i;
428 
429  ret.nptarrays=0;
430 
431  /*
432  * We allocate space for as many pointarray as
433  * segments in the input POINTARRAY, as worst
434  * case is for each segment to cross the M range
435  * window.
436  * TODO: rework this to reduce used memory
437  */
438  ret.ptarrays=lwalloc(sizeof(POINTARRAY *)*ipa->npoints-1);
439 
440  POSTGIS_DEBUGF(2, "ptarray_locate...: called for pointarray %p, m0:%g, m1:%g",
441  ipa, m0, m1);
442 
443 
444  for (i=1; i<ipa->npoints; i++)
445  {
446  POINT4D p1, p2;
447  int clipval;
448 
449  getPoint4d_p(ipa, i-1, &p1);
450  getPoint4d_p(ipa, i, &p2);
451 
452  POSTGIS_DEBUGF(3, " segment %d-%d [ %g %g %g %g - %g %g %g %g ]",
453  i-1, i,
454  p1.x, p1.y, p1.z, p1.m,
455  p2.x, p2.y, p2.z, p2.m);
456 
457  clipval = clip_seg_by_m_range(&p1, &p2, m0, m1);
458 
459  /* segment completely outside, nothing to do */
460  if (! clipval ) continue;
461 
462  POSTGIS_DEBUGF(3, " clipped to: [ %g %g %g %g - %g %g %g %g ] clipval: %d", p1.x, p1.y, p1.z, p1.m,
463  p2.x, p2.y, p2.z, p2.m, clipval);
464 
465  /* If no points have been accumulated so far, then if clipval != 0 the first point must be the
466  start of the intersection */
467  if (dpa == NULL)
468  {
469  POSTGIS_DEBUGF(3, " 1 creating new POINTARRAY with first point %g,%g,%g,%g", p1.x, p1.y, p1.z, p1.m);
470 
472  ptarray_append_point(dpa, &p1, LW_TRUE);
473  }
474 
475  /* Otherwise always add the next point, avoiding duplicates */
476  if (dpa)
477  ptarray_append_point(dpa, &p2, LW_FALSE);
478 
479  /*
480  * second point has been clipped
481  */
482  if ( clipval & 0x0100 || i == ipa->npoints-1 )
483  {
484  POSTGIS_DEBUGF(3, " closing pointarray %p with %d points", dpa, dpa->npoints);
485 
486  ret.ptarrays[ret.nptarrays++] = dpa;
487  dpa = NULL;
488  }
489  }
490 
491  /*
492  * if dpa!=NULL it means we didn't close it yet.
493  * this should never happen.
494  */
495  if ( dpa != NULL ) lwpgerror("Something wrong with algorithm");
496 
497  return ret;
498 }
499 
500 /*
501  * Point is assumed to have an M value.
502  * Return NULL if point is not in the given range (inclusive)
503  * Return an LWPOINT *copy* otherwise.
504  */
505 static LWGEOM *
506 lwpoint_locate_between_m(LWPOINT *lwpoint, double m0, double m1)
507 {
508  POINT3DM p3dm;
509 
510  POSTGIS_DEBUGF(2, "lwpoint_locate_between called for lwpoint %p", lwpoint);
511 
512  lwpoint_getPoint3dm_p(lwpoint, &p3dm);
513  if ( p3dm.m >= m0 && p3dm.m <= m1)
514  {
515  POSTGIS_DEBUG(3, " lwpoint... returning a clone of input");
516 
517  return (LWGEOM *)lwpoint_clone(lwpoint);
518  }
519  else
520  {
521  POSTGIS_DEBUG(3, " lwpoint... returning a clone of input");
522 
523  return NULL;
524  }
525 }
526 
527 /*
528  * Line is assumed to have an M value.
529  *
530  * Return NULL if no parts of the line are in the given range (inclusive)
531  *
532  * Return an LWCOLLECTION with LWLINES and LWPOINT being consecutive
533  * and isolated points on the line falling in the range.
534  *
535  * X,Y and Z (if present) ordinates are interpolated.
536  *
537  */
538 static LWGEOM *
539 lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
540 {
541  POINTARRAY *ipa=lwline_in->points;
542  int i;
543  LWGEOM **geoms;
544  int ngeoms;
545  int outtype;
546  int typeflag=0; /* see flags below */
547  const int pointflag=0x01;
548  const int lineflag=0x10;
549  POINTARRAYSET paset=ptarray_locate_between_m(ipa, m0, m1);
550 
551  POSTGIS_DEBUGF(2, "lwline_locate_between called for lwline %p", lwline_in);
552 
553  POSTGIS_DEBUGF(3, " ptarray_locate... returned %d pointarrays",
554  paset.nptarrays);
555 
556  if ( paset.nptarrays == 0 )
557  {
558  return NULL;
559  }
560 
561  ngeoms=paset.nptarrays;
562  /* TODO: rework this to reduce used memory */
563  geoms=lwalloc(sizeof(LWGEOM *)*ngeoms);
564  for (i=0; i<ngeoms; i++)
565  {
566  LWPOINT *lwpoint;
567  LWLINE *lwline;
568 
569  POINTARRAY *pa=paset.ptarrays[i];
570 
571  /* This is a point */
572  if ( pa->npoints == 1 )
573  {
574  lwpoint = lwpoint_construct(lwline_in->srid, NULL, pa);
575  geoms[i]=(LWGEOM *)lwpoint;
576  typeflag|=pointflag;
577  }
578 
579  /* This is a line */
580  else if ( pa->npoints > 1 )
581  {
582  lwline = lwline_construct(lwline_in->srid, NULL, pa);
583  geoms[i]=(LWGEOM *)lwline;
584  typeflag|=lineflag;
585  }
586 
587  /* This is a bug */
588  else
589  {
590  lwpgerror("ptarray_locate_between_m returned a POINARRAY set containing POINTARRAY with 0 points");
591  }
592 
593  }
594 
595  if ( ngeoms == 1 )
596  {
597  return geoms[0];
598  }
599  else
600  {
601  /* Choose best type */
602  if ( typeflag == 1 ) outtype=MULTIPOINTTYPE;
603  else if ( typeflag == 2 ) outtype=MULTILINETYPE;
604  else outtype = COLLECTIONTYPE;
605 
606  return (LWGEOM *)lwcollection_construct(outtype,
607  lwline_in->srid, NULL, ngeoms, geoms);
608  }
609 }
610 
611 /*
612  * Return a fully new allocated LWCOLLECTION
613  * always tagged as COLLECTIONTYPE.
614  */
615 static LWGEOM *
616 lwcollection_locate_between_m(LWCOLLECTION *lwcoll, double m0, double m1)
617 {
618  int i;
619  int ngeoms=0;
620  LWGEOM **geoms;
621 
622  POSTGIS_DEBUGF(2, "lwcollection_locate_between_m called for lwcoll %p", lwcoll);
623 
624  geoms=lwalloc(sizeof(LWGEOM *)*lwcoll->ngeoms);
625  for (i=0; i<lwcoll->ngeoms; i++)
626  {
627  LWGEOM *sub=lwgeom_locate_between_m(lwcoll->geoms[i],
628  m0, m1);
629  if ( sub != NULL )
630  geoms[ngeoms++] = sub;
631  }
632 
633  if ( ngeoms == 0 ) return NULL;
634 
636  lwcoll->srid, NULL, ngeoms, geoms);
637 }
638 
639 /*
640  * Return a fully allocated LWGEOM containing elements
641  * intersected/interpolated with the given M range.
642  * Return NULL if none of the elements fall in the range.
643  *
644  * m0 is assumed to be less-or-equal to m1.
645  * input LWGEOM is assumed to contain an M value.
646  *
647  */
648 static LWGEOM *
649 lwgeom_locate_between_m(LWGEOM *lwin, double m0, double m1)
650 {
651  POSTGIS_DEBUGF(2, "lwgeom_locate_between called for lwgeom %p", lwin);
652 
653  switch (lwin->type)
654  {
655  case POINTTYPE:
657  (LWPOINT *)lwin, m0, m1);
658  case LINETYPE:
660  (LWLINE *)lwin, m0, m1);
661 
662  case MULTIPOINTTYPE:
663  case MULTILINETYPE:
664  case COLLECTIONTYPE:
666  (LWCOLLECTION *)lwin, m0, m1);
667 
668  /* Polygon types are not supported */
669  case POLYGONTYPE:
670  case MULTIPOLYGONTYPE:
671  lwpgerror("Areal geometries are not supported by locate_between_measures");
672  return NULL;
673  }
674 
675  lwpgerror("Unkonwn geometry type (%s:%d)", __FILE__, __LINE__);
676  return NULL;
677 }
678 
679 /*
680  * Return a derived geometry collection value with elements that match
681  * the specified range of measures inclusively.
682  *
683  * Implements SQL/MM ST_LocateBetween(measure, measure) method.
684  * See ISO/IEC CD 13249-3:200x(E)
685  *
686  */
687 Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS);
689 Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS)
690 {
691  GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0);
692  GSERIALIZED *gout;
693  double start_measure = PG_GETARG_FLOAT8(1);
694  double end_measure = PG_GETARG_FLOAT8(2);
695  LWGEOM *lwin, *lwout;
696  int hasz = gserialized_has_z(gin);
697  int hasm = gserialized_has_m(gin);
698  int type;
699 
700  elog(WARNING,"ST_Locate_Between_Measures and ST_Locate_Along_Measure were deprecated in 2.2.0. Please use ST_LocateAlong and ST_LocateBetween");
701 
702  if ( end_measure < start_measure )
703  {
704  lwpgerror("locate_between_m: 2nd arg must be bigger then 1st arg");
705  PG_RETURN_NULL();
706  }
707 
708  /*
709  * Return error if input doesn't have a measure
710  */
711  if ( ! hasm )
712  {
713  lwpgerror("Geometry argument does not have an 'M' ordinate");
714  PG_RETURN_NULL();
715  }
716 
717  /*
718  * Raise an error if input is a polygon, a multipolygon
719  * or a collection
720  */
721  type = gserialized_get_type(gin);
722 
723  if ( type == POLYGONTYPE || type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE )
724  {
725  lwpgerror("Areal or Collection types are not supported");
726  PG_RETURN_NULL();
727  }
728 
729  lwin = lwgeom_from_gserialized(gin);
730 
731  lwout = lwgeom_locate_between_m(lwin,
732  start_measure, end_measure);
733 
734  lwgeom_free(lwin);
735 
736  if ( lwout == NULL )
737  {
739  gserialized_get_srid(gin), hasz, hasm);
740  }
741 
742  gout = geometry_serialize(lwout);
743  lwgeom_free(lwout);
744 
745  PG_RETURN_POINTER(gout);
746 }
747 
double x
Definition: liblwgeom.h:336
#define LINETYPE
Definition: liblwgeom.h:71
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:55
LWLINE * lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end)
Add a measure dimension to a line, interpolating linearly from the start to the end value...
Definition: lwline.c:367
static POINTARRAYSET ptarray_locate_between_m(POINTARRAY *ipa, double m0, double m1)
static LWGEOM * lwcollection_locate_between_m(LWCOLLECTION *lwcoll, double m0, double m1)
double m
Definition: liblwgeom.h:336
PG_FUNCTION_INFO_V1(ST_AddMeasure)
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:30
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int npoints
Definition: liblwgeom.h:355
int gserialized_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
Definition: g_serialized.c:29
Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS)
#define POLYGONTYPE
Definition: liblwgeom.h:72
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:70
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1050
#define MULTIPOINTTYPE
Definition: liblwgeom.h:73
POINTARRAY ** ptarrays
Datum ST_LocateBetween(PG_FUNCTION_ARGS)
Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS)
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:341
Datum ST_InterpolatePoint(PG_FUNCTION_ARGS)
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:80
int32_t srid
Definition: liblwgeom.h:405
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:24
static LWGEOM * lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1)
double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt)
Find the measure value at the location on the line closest to the point.
static LWGEOM * lwgeom_locate_between_m(LWGEOM *lwin, double m0, double m1)
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located)
Definition: ptarray.c:1303
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_TRUE, then a duplicate point will not be added.
Definition: ptarray.c:156
#define LW_FALSE
Definition: liblwgeom.h:62
double m
Definition: liblwgeom.h:330
uint8_t flags
Definition: liblwgeom.h:353
Datum ST_LocateAlong(PG_FUNCTION_ARGS)
LWPOINT * lwpoint_clone(const LWPOINT *lwgeom)
Definition: lwpoint.c:208
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:61
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
LWGEOM ** geoms
Definition: liblwgeom.h:493
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Definition: lwpoint.c:44
static LWGEOM * lwpoint_locate_between_m(LWPOINT *lwpoint, double m0, double m1)
int32_t srid
Definition: liblwgeom.h:490
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:124
LWCOLLECTION * lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset)
Given a geometry clip based on the from/to range of one of its ordinates (x, y, z, m).
double z
Definition: liblwgeom.h:336
LWMLINE * lwmline_measured_from_lwmline(const LWMLINE *lwmline, double m_start, double m_end)
Re-write the measure ordinate (or add one, if it isn't already there) interpolating the measure betwe...
Definition: lwmline.c:42
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:89
LWGEOM * lwgeom_locate_along(const LWGEOM *lwin, double m, double offset)
Determine the location(s) along a measured line where m occurs and return as a multipoint.
Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:75
int lwpoint_getPoint3dm_p(const LWPOINT *point, POINT3DM *out)
Definition: lwpoint.c:39
Datum ST_AddMeasure(PG_FUNCTION_ARGS)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:70
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:125
uint8_t type
Definition: liblwgeom.h:380
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:98
void * lwalloc(size_t size)
Definition: lwutil.c:199
double y
Definition: liblwgeom.h:336
#define MULTILINETYPE
Definition: liblwgeom.h:74
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:81
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:69
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:231
#define COLLECTIONTYPE
Definition: liblwgeom.h:76
static int clip_seg_by_m_range(POINT4D *p1, POINT4D *p2, double m0, double m1)
This library is the generic geometry handling section of PostGIS.
POINTARRAY * points
Definition: liblwgeom.h:406