PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwgeodetic_measures.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * This MobilityDB code is provided under The PostgreSQL License.
4  * Copyright (c) 2016-2023, Université libre de Bruxelles and MobilityDB
5  * contributors
6  *
7  * MobilityDB includes portions of PostGIS version 3 source code released
8  * under the GNU General Public License (GPLv2 or later).
9  * Copyright (c) 2001-2023, PostGIS contributors
10  *
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose, without fee, and without a written
13  * agreement is hereby granted, provided that the above copyright notice and
14  * this paragraph and the following two paragraphs appear in all copies.
15  *
16  * IN NO EVENT SHALL UNIVERSITE LIBRE DE BRUXELLES BE LIABLE TO ANY PARTY FOR
17  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
18  * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
19  * EVEN IF UNIVERSITE LIBRE DE BRUXELLES HAS BEEN ADVISED OF THE POSSIBILITY
20  * OF SUCH DAMAGE.
21  *
22  * UNIVERSITE LIBRE DE BRUXELLES SPECIFICALLY DISCLAIMS ANY WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON
25  * AN "AS IS" BASIS, AND UNIVERSITE LIBRE DE BRUXELLES HAS NO OBLIGATIONS TO
26  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27  *
28  *****************************************************************************/
29 
39 // #include "point/geography_funcs.h"
40 
41 /* C */
42 #include <float.h>
43 /* PostGIS */
44 #include <liblwgeom_internal.h>
45 #include <lwgeodetic_tree.h>
46 
47 /*****************************************************************************/
48 
49 
50 /***********************************************************************
51  * ST_LineSubstring for geographies
52  ***********************************************************************/
53 
59 static void
61  const POINT4D *p1, const POINT4D *p2, POINT4D *p,
62  const SPHEROID *s, double f)
63 
64 {
65  GEOGRAPHIC_POINT g, g1, g2;
66  geographic_point_init(p1->x, p1->y, &g1);
67  geographic_point_init(p2->x, p2->y, &g2);
68  int success;
69  double dist, dir;
70 
71  /* Special sphere case */
72  if ( s == NULL || s->a == s->b )
73  {
74  /* Calculate distance and direction between g1 and g2 */
75  dist = sphere_distance(&g1, &g2);
76  dir = sphere_direction(&g1, &g2, dist);
77  /* Compute interpolation point */
78  success = sphere_project(&g1, dist*f, dir, &g);
79  }
80  /* Spheroid case */
81  else
82  {
83  /* Calculate distance and direction between g1 and g2 */
84  dist = spheroid_distance(&g1, &g2, s);
85  dir = spheroid_direction(&g1, &g2, s);
86  /* Compute interpolation point */
87  success = spheroid_project(&g1, s, dist*f, dir, &g);
88  }
89 
90  /* If success, use newly computed lat and lon,
91  * otherwise return precomputed cartesian result */
92  if (success == LW_SUCCESS)
93  {
96  }
97 }
98 
99 
103 LWGEOM *
105  const LWLINE *lwline,
106  const SPHEROID *s,
107  double from, double to,
108  double tolerance)
109 {
110  POINTARRAY *dpa;
111  POINTARRAY *ipa = lwline->points;
112  LWGEOM *lwresult;
113  POINT4D pt;
114  POINT4D p1, p2;
115  GEOGRAPHIC_POINT g1, g2;
116  int nsegs, i;
117  double length, slength, tlength;
118  int state = 0; /* 0 = before, 1 = inside */
119  uint32_t srid = lwline->srid;
120 
121  /*
122  * Create a dynamic pointarray with an initial capacity
123  * equal to full copy of input points
124  */
126  (char) FLAGS_GET_Z(ipa->flags),
127  (char) FLAGS_GET_M(ipa->flags),
128  ipa->npoints);
129 
130  /* Compute total line length */
131  length = ptarray_length_spheroid(ipa, s);
132 
133  /* Get 'from' and 'to' lengths */
134  from = length * from;
135  to = length * to;
136  tlength = 0;
137  getPoint4d_p(ipa, 0, &p1);
138  geographic_point_init(p1.x, p1.y, &g1);
139  nsegs = ipa->npoints - 1;
140  for (i = 0; i < nsegs; i++)
141  {
142  double dseg;
143  getPoint4d_p(ipa, (uint32_t) i+1, &p2);
144  geographic_point_init(p2.x, p2.y, &g2);
145 
146  /* Find the length of this segment */
147  /* Special sphere case */
148  if ( s->a == s->b )
149  slength = s->radius * sphere_distance(&g1, &g2);
150  /* Spheroid case */
151  else
152  slength = spheroid_distance(&g1, &g2, s);
153 
154  /* We are before requested start. */
155  if (state == 0) /* before */
156  {
157  if (fabs ( from - ( tlength + slength ) ) <= tolerance)
158  {
159  /* Second point is our start */
160  ptarray_append_point(dpa, &p2, LW_FALSE);
161  state = 1; /* we're inside now */
162  goto END;
163  }
164  else if (fabs(from - tlength) <= tolerance)
165  {
166  /* First point is our start */
167  ptarray_append_point(dpa, &p1, LW_FALSE);
168  /*
169  * We're inside now, but will check
170  * 'to' point as well
171  */
172  state = 1;
173  }
174  /*
175  * Didn't reach the 'from' point,
176  * nothing to do
177  */
178  else if (from > tlength + slength)
179  {
180  goto END;
181  }
182  else /* tlength < from < tlength+slength */
183  {
184  /* Our start is between first and second point */
185  dseg = (from - tlength) / slength;
186  interpolate_point4d_spheroid(&p1, &p2, &pt, s, dseg);
187  ptarray_append_point(dpa, &pt, LW_FALSE);
188  /* We're inside now, but will check 'to' point as well */
189  state = 1;
190  }
191  }
192 
193  if (state == 1) /* inside */
194  {
195  /* 'to' point is our second point. */
196  if (fabs(to - ( tlength + slength ) ) <= tolerance )
197  {
198  ptarray_append_point(dpa, &p2, LW_FALSE);
199  break; /* substring complete */
200  }
201  /*
202  * 'to' point is our first point.
203  * (should only happen if 'to' is 0)
204  */
205  else if (fabs(to - tlength) <= tolerance)
206  {
207  ptarray_append_point(dpa, &p1, LW_FALSE);
208  break; /* substring complete */
209  }
210  /*
211  * Didn't reach the 'end' point,
212  * just copy second point
213  */
214  else if (to > tlength + slength)
215  {
216  ptarray_append_point(dpa, &p2, LW_FALSE);
217  goto END;
218  }
219  /*
220  * 'to' point falls on this segment
221  * Interpolate and break.
222  */
223  else if (to < tlength + slength )
224  {
225  dseg = (to - tlength) / slength;
226  interpolate_point4d_spheroid(&p1, &p2, &pt, s, dseg);
227  ptarray_append_point(dpa, &pt, LW_FALSE);
228  break;
229  }
230  }
231 
232  END:
233  tlength += slength;
234  memcpy(&p1, &p2, sizeof(POINT4D));
235  geographic_point_init(p1.x, p1.y, &g1);
236  }
237 
238  if (dpa->npoints <= 1) {
239  lwresult = lwpoint_as_lwgeom(lwpoint_construct(srid, NULL, dpa));
240  }
241  else {
242  lwresult = lwline_as_lwgeom(lwline_construct(srid, NULL, dpa));
243  }
244 
245  return lwresult;
246 }
247 
248 
249 /***********************************************************************
250  * Interpolate a point along a geographic line.
251  ***********************************************************************/
252 
256 LWGEOM *
258  const LWLINE *line, double length_fraction,
259  const SPHEROID *s, char repeat)
260 {
261  POINT4D pt;
262  uint32_t i;
263  uint32_t points_to_interpolate;
264  uint32_t points_found = 0;
265  double length;
266  double length_fraction_increment = length_fraction;
267  double length_fraction_consumed = 0;
268  char has_z = (char) lwgeom_has_z(lwline_as_lwgeom(line));
269  char has_m = (char) lwgeom_has_m(lwline_as_lwgeom(line));
270  const POINTARRAY* ipa = line->points;
271  POINTARRAY *opa;
272  POINT4D p1, p2;
273  POINT3D q1, q2;
274  LWGEOM *lwresult;
275  GEOGRAPHIC_POINT g1, g2;
276  uint32_t srid = line->srid;
277 
278  /* Empty.InterpolatePoint == Point Empty */
279  if ( lwline_is_empty(line) )
280  {
281  return lwgeom_clone_deep(lwline_as_lwgeom(line));
282  }
283 
284  /*
285  * If distance is one of the two extremes, return the point on that
286  * end rather than doing any computations
287  */
288  if ( length_fraction == 0.0 || length_fraction == 1.0 )
289  {
290  if ( length_fraction == 0.0 )
291  getPoint4d_p(ipa, 0, &pt);
292  else
293  getPoint4d_p(ipa, ipa->npoints-1, &pt);
294 
295  opa = ptarray_construct(has_z, has_m, 1);
296  ptarray_set_point4d(opa, 0, &pt);
297  return lwpoint_as_lwgeom(lwpoint_construct(srid, NULL, opa));
298  }
299 
300  /* Interpolate points along the line */
301  length = ptarray_length_spheroid(ipa, s);
302  points_to_interpolate = repeat ? (uint32_t) floor(1 / length_fraction) : 1;
303  opa = ptarray_construct(has_z, has_m, points_to_interpolate);
304 
305  getPoint4d_p(ipa, 0, &p1);
306  geographic_point_init(p1.x, p1.y, &g1);
307  for ( i = 0; i < ipa->npoints - 1 && points_found < points_to_interpolate; i++ )
308  {
309  double segment_length_frac;
310  getPoint4d_p(ipa, i+1, &p2);
311  geographic_point_init(p2.x, p2.y, &g2);
312 
313  /* Special sphere case */
314  if ( s->a == s->b )
315  segment_length_frac = s->radius * sphere_distance(&g1, &g2) / length;
316  /* Spheroid case */
317  else
318  segment_length_frac = spheroid_distance(&g1, &g2, s) / length;
319 
320  /* If our target distance is before the total length we've seen
321  * so far. create a new point some distance down the current
322  * segment.
323  */
324  while ( length_fraction < length_fraction_consumed + segment_length_frac && points_found < points_to_interpolate )
325  {
326  geog2cart(&g1, &q1);
327  geog2cart(&g2, &q2);
328  double segment_fraction = (length_fraction - length_fraction_consumed) / segment_length_frac;
329  interpolate_point4d_spheroid(&p1, &p2, &pt, s, segment_fraction);
330  ptarray_set_point4d(opa, points_found++, &pt);
331  length_fraction += length_fraction_increment;
332  }
333 
334  length_fraction_consumed += segment_length_frac;
335 
336  p1 = p2;
337  g1 = g2;
338  }
339 
340  /* Return the last point on the line. This shouldn't happen, but
341  * could if there's some floating point rounding errors. */
342  if (points_found < points_to_interpolate)
343  {
344  getPoint4d_p(ipa, ipa->npoints - 1, &pt);
345  ptarray_set_point4d(opa, points_found, &pt);
346  }
347 
348  if (opa->npoints <= 1)
349  {
350  lwresult = lwpoint_as_lwgeom(lwpoint_construct(srid, NULL, opa));
351  } else {
352  lwresult = lwmpoint_as_lwgeom(lwmpoint_construct(srid, opa));
353  }
354 
355  return lwresult;
356 }
357 
361 double
363  const POINTARRAY *pa,
364  const POINT4D *p4d,
365  const SPHEROID *s,
366  double tolerance,
367  double *mindistout,
368  POINT4D *proj4d)
369 {
370  GEOGRAPHIC_EDGE e;
371  GEOGRAPHIC_POINT a, b, nearest = {0}; /* make compiler quiet */
372  POINT4D p1, p2;
373  const POINT2D *p;
374  POINT2D proj;
375  uint32_t i, seg = 0;
376  int use_sphere = (s->a == s->b ? 1 : 0);
377  int hasz;
378  double za = 0.0, zb = 0.0;
379  double distance,
380  length, /* Used for computing lengths */
381  seglength = 0.0, /* length of the segment where the closest point is located */
382  partlength = 0.0, /* length from the beginning of the point array to the closest point */
383  totlength = 0.0; /* length of the point array */
384 
385  /* Initialize our point */
386  geographic_point_init(p4d->x, p4d->y, &a);
387 
388  /* Handle point/point case here */
389  if ( pa->npoints <= 1)
390  {
391  double mindist = 0.0;
392  if ( pa->npoints == 1 )
393  {
394  p = getPoint2d_cp(pa, 0);
395  geographic_point_init(p->x, p->y, &b);
396  /* Sphere special case, axes equal */
397  mindist = s->radius * sphere_distance(&a, &b);
398  /* If close or greater than tolerance, get the real answer to be sure */
399  if ( ! use_sphere || mindist > 0.95 * tolerance )
400  {
401  mindist = spheroid_distance(&a, &b, s);
402  }
403  }
404  if ( mindistout ) *mindistout = mindist;
405  return 0.0;
406  }
407 
408  /* Make result really big, so that everything will be smaller than it */
409  distance = FLT_MAX;
410 
411  /* Initialize start of line */
412  p = getPoint2d_cp(pa, 0);
413  geographic_point_init(p->x, p->y, &(e.start));
414 
415  /* Iterate through the edges in our line */
416  for ( i = 1; i < pa->npoints; i++ )
417  {
418  double d;
419  p = getPoint2d_cp(pa, i);
420  geographic_point_init(p->x, p->y, &(e.end));
421  /* Get the spherical distance between point and edge */
422  d = s->radius * edge_distance_to_point(&e, &a, &b);
423  /* New shortest distance! Record this distance / location / segment */
424  if ( d < distance )
425  {
426  distance = d;
427  nearest = b;
428  seg = i - 1;
429  }
430  /* We've gotten closer than the tolerance... */
431  if ( d < tolerance )
432  {
433  /* Working on a sphere? The answer is correct, return */
434  if ( use_sphere )
435  {
436  break;
437  }
438  /* Far enough past the tolerance that the spheroid calculation won't change things */
439  else if ( d < tolerance * 0.95 )
440  {
441  break;
442  }
443  /* On a spheroid and near the tolerance? Confirm that we are *actually* closer than tolerance */
444  else
445  {
446  d = spheroid_distance(&a, &nearest, s);
447  /* Yes, closer than tolerance, return! */
448  if ( d < tolerance )
449  break;
450  }
451  }
452  e.start = e.end;
453  }
454 
455  if ( mindistout ) *mindistout = distance;
456 
457  /* See if we have a third dimension */
458  hasz = (bool) FLAGS_GET_Z(pa->flags);
459 
460  /* Initialize first point of array */
461  getPoint4d_p(pa, 0, &p1);
462  geographic_point_init(p1.x, p1.y, &a);
463  if ( hasz )
464  za = p1.z;
465 
466  /* Loop and sum the length for each segment */
467  for ( i = 1; i < pa->npoints; i++ )
468  {
469  getPoint4d_p(pa, i, &p1);
470  geographic_point_init(p1.x, p1.y, &b);
471  if ( hasz )
472  zb = p1.z;
473 
474  /* Special sphere case */
475  if ( s->a == s->b )
476  length = s->radius * sphere_distance(&a, &b);
477  /* Spheroid case */
478  else
479  length = spheroid_distance(&a, &b, s);
480 
481  /* Add in the vertical displacement if we're in 3D */
482  if ( hasz )
483  length = sqrt( (zb-za)*(zb-za) + length*length );
484 
485  /* Add this segment length to the total length */
486  totlength += length;
487 
488  /* Add this segment length to the partial length */
489  if (i - 1 < seg)
490  partlength += length;
491  else if (i - 1 == seg)
492  /* Save segment length for computing the final value of partlength */
493  seglength = length;
494 
495  /* B gets incremented in the next loop, so we save the value here */
496  a = b;
497  za = zb;
498  }
499 
500  /* Copy nearest into 2D/4D holder */
501  proj4d->x = proj.x = rad2deg(nearest.lon);
502  proj4d->y = proj.y = rad2deg(nearest.lat);
503 
504  /* Compute distance from beginning of the segment to closest point */
505 
506  /* Start of the segment */
507  getPoint4d_p(pa, seg, &p1);
508  geographic_point_init(p1.x, p1.y, &a);
509 
510  /* Closest point */
511  geographic_point_init(proj4d->x, proj4d->y, &b);
512 
513  /* Special sphere case */
514  if ( s->a == s->b )
515  length = s->radius * sphere_distance(&a, &b);
516  /* Spheroid case */
517  else
518  length = spheroid_distance(&a, &b, s);
519 
520  if ( hasz )
521  {
522  /* Compute Z and M values for closest point */
523  double f = length / seglength;
524  getPoint4d_p(pa, seg + 1, &p2);
525  proj4d->z = p1.z + ((p2.z - p1.z) * f);
526  proj4d->m = p1.m + ((p2.m - p1.m) * f);
527  /* Add in the vertical displacement if we're in 3D */
528  za = p1.z;
529  zb = proj4d->z;
530  length = sqrt( (zb-za)*(zb-za) + length*length );
531  }
532 
533  /* Add this segment length to the total */
534  partlength += length;
535 
536  /* Location of any point on a zero-length line is 0 */
537  /* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
538  if ( partlength == 0 || totlength == 0 )
539  return 0.0;
540 
541  /* For robustness, force 0 when closest point == startpoint */
542  p = getPoint2d_cp(pa, 0);
543  if ( seg == 0 && p2d_same(&proj, p) )
544  return 0.0;
545 
546  /* For robustness, force 1 when closest point == endpoint */
547  p = getPoint2d_cp(pa, pa->npoints - 1);
548  if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, p) )
549  return 1.0;
550 
551  return partlength / totlength;
552 }
553 
554 /*****************************************************************************/
char * s
Definition: cu_in_wkt.c:23
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
#define LW_SUCCESS
Definition: liblwgeom.h:97
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition: lwgeom.c:304
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition: lwgeom.c:529
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:165
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:166
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
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_FALSE,...
Definition: ptarray.c:147
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:941
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:369
LWMPOINT * lwmpoint_construct(int32_t srid, const POINTARRAY *pa)
Definition: lwmpoint.c:52
int lwline_is_empty(const LWLINE *line)
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:57
double longitude_radians_normalize(double lon)
Convert a longitude to the range of -PI,PI.
Definition: lwgeodetic.c:50
double latitude_radians_normalize(double lat)
Convert a latitude to the range of -PI/2,PI/2.
Definition: lwgeodetic.c:78
int sphere_project(const GEOGRAPHIC_POINT *r, double distance, double azimuth, GEOGRAPHIC_POINT *n)
Given a starting location r, a distance and an azimuth to the new point, compute the location of the ...
Definition: lwgeodetic.c:1268
void geographic_point_init(double lon, double lat, GEOGRAPHIC_POINT *g)
Initialize a geographic point.
Definition: lwgeodetic.c:180
double ptarray_length_spheroid(const POINTARRAY *pa, const SPHEROID *s)
Definition: lwgeodetic.c:3092
double sphere_distance(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
Given two points on a unit sphere, calculate their distance apart in radians.
Definition: lwgeodetic.c:896
double sphere_direction(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e, double d)
Given two points on a unit sphere, calculate the direction from s to e.
Definition: lwgeodetic.c:927
double edge_distance_to_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *gp, GEOGRAPHIC_POINT *closest)
Definition: lwgeodetic.c:1170
void geog2cart(const GEOGRAPHIC_POINT *g, POINT3D *p)
Convert spherical coordinates to cartesian coordinates on unit sphere.
Definition: lwgeodetic.c:404
#define rad2deg(r)
Definition: lwgeodetic.h:81
double spheroid_distance(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const SPHEROID *spheroid)
Computes the shortest distance along the surface of the spheroid between two points,...
Definition: lwspheroid.c:79
int spheroid_project(const GEOGRAPHIC_POINT *r, const SPHEROID *spheroid, double distance, double azimuth, GEOGRAPHIC_POINT *g)
Given a location, an azimuth and a distance, computes the location of the projected point.
Definition: lwspheroid.c:128
double spheroid_direction(const GEOGRAPHIC_POINT *r, const GEOGRAPHIC_POINT *s, const SPHEROID *spheroid)
Computes the forward azimuth of the geodesic joining two points on the spheroid, using the inverse ge...
Definition: lwspheroid.c:105
double ptarray_locate_point_spheroid(const POINTARRAY *pa, const POINT4D *p4d, const SPHEROID *s, double tolerance, double *mindistout, POINT4D *proj4d)
Locate a point along the point array defining a geographic line.
LWGEOM * geography_interpolate_points(const LWLINE *line, double length_fraction, const SPHEROID *s, char repeat)
Interpolate a point along a geographic line.
LWGEOM * geography_substring(const LWLINE *lwline, const SPHEROID *s, double from, double to, double tolerance)
Return the part of a line between two fractional locations.
static void interpolate_point4d_spheroid(const POINT4D *p1, const POINT4D *p2, POINT4D *p, const SPHEROID *s, double f)
Find interpolation point p between geography points p1 and p2 so that the len(p1,p) == len(p1,...
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:97
static double distance(double x1, double y1, double x2, double y2)
Definition: lwtree.c:1032
GEOGRAPHIC_POINT start
Definition: lwgeodetic.h:64
GEOGRAPHIC_POINT end
Definition: lwgeodetic.h:65
Two-point great circle segment from a to b.
Definition: lwgeodetic.h:63
Point in spherical coordinates on the world.
Definition: lwgeodetic.h:54
POINTARRAY * points
Definition: liblwgeom.h:483
int32_t srid
Definition: liblwgeom.h:484
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
lwflags_t flags
Definition: liblwgeom.h:431
uint32_t npoints
Definition: liblwgeom.h:427