PostGIS  3.4.0dev-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  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2001-2005 Refractions Research Inc.
22  *
23  **********************************************************************/
24 
25 
26 #include <math.h>
27 
28 #include "postgres.h"
29 #include "fmgr.h"
30 
31 #include "../postgis_config.h"
32 #include "liblwgeom.h"
33 #include "lwgeom_pg.h"
34 
35 /*
36 * Add a measure dimension to a line, interpolating linearly from the
37 * start value to the end value.
38 * ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry
39 */
40 Datum ST_AddMeasure(PG_FUNCTION_ARGS);
42 Datum ST_AddMeasure(PG_FUNCTION_ARGS)
43 {
44  GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0);
45  GSERIALIZED *gout;
46  double start_measure = PG_GETARG_FLOAT8(1);
47  double end_measure = PG_GETARG_FLOAT8(2);
48  LWGEOM *lwin, *lwout;
49  int type = gserialized_get_type(gin);
50 
51  /* Raise an error if input is not a linestring or multilinestring */
52  if ( type != LINETYPE && type != MULTILINETYPE )
53  {
54  lwpgerror("Only LINESTRING and MULTILINESTRING are supported");
55  PG_RETURN_NULL();
56  }
57 
58  lwin = lwgeom_from_gserialized(gin);
59  if ( type == LINETYPE )
60  lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure);
61  else
62  lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure);
63 
64  lwgeom_free(lwin);
65 
66  if ( lwout == NULL )
67  PG_RETURN_NULL();
68 
69  gout = geometry_serialize(lwout);
70  lwgeom_free(lwout);
71 
72  PG_RETURN_POINTER(gout);
73 }
74 
75 
76 /*
77 * Locate a point along a feature based on a measure value.
78 * ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry
79 */
80 Datum ST_LocateAlong(PG_FUNCTION_ARGS);
82 Datum ST_LocateAlong(PG_FUNCTION_ARGS)
83 {
84  GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0);
85  GSERIALIZED *gout;
86  LWGEOM *lwin = NULL, *lwout = NULL;
87  double measure = PG_GETARG_FLOAT8(1);
88  double offset = PG_GETARG_FLOAT8(2);
89 
90  lwin = lwgeom_from_gserialized(gin);
91  lwout = lwgeom_locate_along(lwin, measure, offset);
92  lwgeom_free(lwin);
93  PG_FREE_IF_COPY(gin, 0);
94 
95  if ( ! lwout )
96  PG_RETURN_NULL();
97 
98  gout = geometry_serialize(lwout);
99  lwgeom_free(lwout);
100 
101  PG_RETURN_POINTER(gout);
102 }
103 
104 
105 /*
106 * Locate the portion of a line between the specified measures
107 */
108 Datum ST_LocateBetween(PG_FUNCTION_ARGS);
110 Datum ST_LocateBetween(PG_FUNCTION_ARGS)
111 {
112  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
113  double from = PG_GETARG_FLOAT8(1);
114  double to = PG_GETARG_FLOAT8(2);
115  double offset = PG_GETARG_FLOAT8(3);
116  LWCOLLECTION *geom_out = NULL;
117  LWGEOM *line_in = NULL;
118  static char ordinate = 'M'; /* M */
119 
120  if ( ! gserialized_has_m(geom_in) )
121  {
122  elog(ERROR,"This function only accepts geometries that have an M dimension.");
123  PG_RETURN_NULL();
124  }
125 
126  /* This should be a call to ST_LocateAlong! */
127  if ( to == from )
128  {
129  PG_RETURN_DATUM(DirectFunctionCall3(ST_LocateAlong, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), PG_GETARG_DATUM(3)));
130  }
131 
132  line_in = lwgeom_from_gserialized(geom_in);
133  geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset);
134  lwgeom_free(line_in);
135  PG_FREE_IF_COPY(geom_in, 0);
136 
137  if ( ! geom_out )
138  {
139  elog(ERROR,"lwline_clip_to_ordinate_range returned null");
140  PG_RETURN_NULL();
141  }
142 
143  PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
144 }
145 
146 /*
147 * Locate the portion of a line between the specified elevations
148 */
149 Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS);
151 Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS)
152 {
153  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
154  double from = PG_GETARG_FLOAT8(1);
155  double to = PG_GETARG_FLOAT8(2);
156  LWCOLLECTION *geom_out = NULL;
157  LWGEOM *line_in = NULL;
158  static char ordinate = 'Z'; /* Z */
159  static double offset = 0.0;
160 
161  if ( ! gserialized_has_z(geom_in) )
162  {
163  elog(ERROR, "This function only accepts geometries with Z dimensions.");
164  PG_RETURN_NULL();
165  }
166 
167  line_in = lwgeom_from_gserialized(geom_in);
168  geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset);
169  lwgeom_free(line_in);
170  PG_FREE_IF_COPY(geom_in, 0);
171 
172  if ( ! geom_out )
173  {
174  elog(ERROR,"lwline_clip_to_ordinate_range returned null");
175  PG_RETURN_NULL();
176  }
177 
178  PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out));
179 }
180 
181 
182 Datum ST_InterpolatePoint(PG_FUNCTION_ARGS);
184 Datum ST_InterpolatePoint(PG_FUNCTION_ARGS)
185 {
186  GSERIALIZED *gser_line = PG_GETARG_GSERIALIZED_P(0);
187  GSERIALIZED *gser_point = PG_GETARG_GSERIALIZED_P(1);
188  LWGEOM *lwline;
189  LWPOINT *lwpoint;
190 
191  if ( gserialized_get_type(gser_line) != LINETYPE )
192  {
193  elog(ERROR,"ST_InterpolatePoint: 1st argument isn't a line");
194  PG_RETURN_NULL();
195  }
196  if ( gserialized_get_type(gser_point) != POINTTYPE )
197  {
198  elog(ERROR,"ST_InterpolatePoint: 2nd argument isn't a point");
199  PG_RETURN_NULL();
200  }
201 
202  gserialized_error_if_srid_mismatch(gser_line, gser_point, __func__);
203 
204  if ( ! gserialized_has_m(gser_line) )
205  {
206  elog(ERROR,"ST_InterpolatePoint only accepts geometries that have an M dimension");
207  PG_RETURN_NULL();
208  }
209 
210  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point));
211  lwline = lwgeom_from_gserialized(gser_line);
212 
213  PG_RETURN_FLOAT8(lwgeom_interpolate_point(lwline, lwpoint));
214 }
215 
216 
217 Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS);
219 Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
220 {
221  GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
222  GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
223  LWLINE *lwline;
224  LWPOINT *lwpoint;
225  POINTARRAY *pa;
226  POINT4D p, p_proj;
227  double ret;
228 
229  if ( gserialized_get_type(geom1) != LINETYPE )
230  {
231  elog(ERROR,"line_locate_point: 1st arg isn't a line");
232  PG_RETURN_NULL();
233  }
234  if ( gserialized_get_type(geom2) != POINTTYPE )
235  {
236  elog(ERROR,"line_locate_point: 2nd arg isn't a point");
237  PG_RETURN_NULL();
238  }
239 
240  gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
241 
242  lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1));
243  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2));
244 
245  pa = lwline->points;
246  lwpoint_getPoint4d_p(lwpoint, &p);
247 
248  ret = ptarray_locate_point(pa, &p, NULL, &p_proj);
249 
250  PG_RETURN_FLOAT8(ret);
251 }
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
Definition: gserialized.c:403
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized.c:185
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:174
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized.c:89
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Definition: lwpoint.c:57
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
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.
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define LINETYPE
Definition: liblwgeom.h:103
double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt)
Find the measure value at the location on the line closest to the point.
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located)
Definition: ptarray.c:1386
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
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,...
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:379
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:56
This library is the generic geometry handling section of PostGIS.
PG_FUNCTION_INFO_V1(ST_AddMeasure)
Datum ST_AddMeasure(PG_FUNCTION_ARGS)
Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS)
Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS)
Datum ST_LocateBetween(PG_FUNCTION_ARGS)
Datum ST_InterpolatePoint(PG_FUNCTION_ARGS)
Datum ST_LocateAlong(PG_FUNCTION_ARGS)
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:131
type
Definition: ovdump.py:42
POINTARRAY * points
Definition: liblwgeom.h:483