PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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*/
40Datum ST_AddMeasure(PG_FUNCTION_ARGS);
42Datum 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*/
80Datum ST_LocateAlong(PG_FUNCTION_ARGS);
82Datum 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*/
108Datum ST_LocateBetween(PG_FUNCTION_ARGS);
110Datum 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*/
149Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS);
151Datum 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
182Datum ST_InterpolatePoint(PG_FUNCTION_ARGS);
184Datum 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
217Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS);
219Datum 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
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)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Definition lwpoint.c:57
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:389
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
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,...
#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:1518
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
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
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.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
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:127
POINTARRAY * points
Definition liblwgeom.h:483