PostGIS  2.5.0dev-r@@SVN_REVISION@@
lwstroke.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-2006 Refractions Research Inc.
22  * Copyright (C) 2017 Sandro Santilli <strk@kbt.io>
23  *
24  **********************************************************************/
25 
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 
32 #include "../postgis_config.h"
33 
34 /*#define POSTGIS_DEBUG_LEVEL 3*/
35 
36 #include "lwgeom_log.h"
37 
38 #include "liblwgeom_internal.h"
39 
40 
41 LWGEOM* pta_unstroke(const POINTARRAY *points, int type, int srid);
42 LWGEOM* lwline_unstroke(const LWLINE *line);
43 LWGEOM* lwpolygon_unstroke(const LWPOLY *poly);
44 LWGEOM* lwmline_unstroke(const LWMLINE *mline);
45 LWGEOM* lwmpolygon_unstroke(const LWMPOLY *mpoly);
46 LWGEOM* lwgeom_unstroke(const LWGEOM *geom);
47 
48 
49 /*
50  * Determines (recursively in the case of collections) whether the geometry
51  * contains at least on arc geometry or segment.
52  */
53 int
54 lwgeom_has_arc(const LWGEOM *geom)
55 {
56  LWCOLLECTION *col;
57  uint32_t i;
58 
59  LWDEBUG(2, "lwgeom_has_arc called.");
60 
61  switch (geom->type)
62  {
63  case POINTTYPE:
64  case LINETYPE:
65  case POLYGONTYPE:
66  case TRIANGLETYPE:
67  case MULTIPOINTTYPE:
68  case MULTILINETYPE:
69  case MULTIPOLYGONTYPE:
71  case TINTYPE:
72  return LW_FALSE;
73  case CIRCSTRINGTYPE:
74  case CURVEPOLYTYPE:
75  case COMPOUNDTYPE:
76  return LW_TRUE;
77  /* It's a collection that MAY contain an arc */
78  default:
79  col = (LWCOLLECTION *)geom;
80  for (i=0; i<col->ngeoms; i++)
81  {
82  if (lwgeom_has_arc(col->geoms[i]) == LW_TRUE)
83  return LW_TRUE;
84  }
85  return LW_FALSE;
86  }
87 }
88 
89 
90 
91 /*******************************************************************************
92  * Begin curve segmentize functions
93  ******************************************************************************/
94 
95 static double interpolate_arc(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3)
96 {
97  LWDEBUGF(4,"angle %.05g a1 %.05g a2 %.05g a3 %.05g zm1 %.05g zm2 %.05g zm3 %.05g",angle,a1,a2,a3,zm1,zm2,zm3);
98  /* Counter-clockwise sweep */
99  if ( a1 < a2 )
100  {
101  if ( angle <= a2 )
102  return zm1 + (zm2-zm1) * (angle-a1) / (a2-a1);
103  else
104  return zm2 + (zm3-zm2) * (angle-a2) / (a3-a2);
105  }
106  /* Clockwise sweep */
107  else
108  {
109  if ( angle >= a2 )
110  return zm1 + (zm2-zm1) * (a1-angle) / (a1-a2);
111  else
112  return zm2 + (zm3-zm2) * (a2-angle) / (a2-a3);
113  }
114 }
115 
133 static int
135  const POINT4D *p1, const POINT4D *p2, const POINT4D *p3,
136  double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
137  int flags)
138 {
139  POINT2D center;
140  POINT2D *t1 = (POINT2D*)p1;
141  POINT2D *t2 = (POINT2D*)p2;
142  POINT2D *t3 = (POINT2D*)p3;
143  POINT4D pt;
144  int p2_side = 0;
145  int clockwise = LW_TRUE;
146  double radius; /* Arc radius */
147  double increment; /* Angle per segment */
148  double angle_shift = 0;
149  double a1, a2, a3, angle;
150  POINTARRAY *pa = to;
151  int is_circle = LW_FALSE;
152  int points_added = 0;
153  int reverse = 0;
154 
155  LWDEBUG(2, "lwarc_linearize called.");
156 
157  p2_side = lw_segment_side(t1, t3, t2);
158 
159  /* Force counterclockwise scan if SYMMETRIC operation is requsested */
160  if ( p2_side == -1 && flags & LW_LINEARIZE_FLAG_SYMMETRIC )
161  {
162  /* swap p1-p3 */
163  t1 = (POINT2D*)p3;
164  t3 = (POINT2D*)p1;
165  p1 = (POINT4D*)t1;
166  p3 = (POINT4D*)t3;
167  p2_side = 1;
168  reverse = 1;
169  }
170 
171  radius = lw_arc_center(t1, t2, t3, &center);
172  LWDEBUGF(2, " center is POINT(%.15g %.15g) - radius:%g", center.x, center.y, radius);
173 
174  /* Matched start/end points imply circle */
175  if ( p1->x == p3->x && p1->y == p3->y )
176  is_circle = LW_TRUE;
177 
178  /* Negative radius signals straight line, p1/p2/p3 are colinear */
179  if ( (radius < 0.0 || p2_side == 0) && ! is_circle )
180  return 0;
181 
182  /* The side of the p1/p3 line that p2 falls on dictates the sweep
183  direction from p1 to p3. */
184  if ( p2_side == -1 )
185  clockwise = LW_TRUE;
186  else
187  clockwise = LW_FALSE;
188 
189  if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD )
190  {{
191  int perQuad = rint(tol);
192  // error out if tol != perQuad ? (not-round)
193  if ( perQuad != tol )
194  {
195  lwerror("lwarc_linearize: segments per quadrant must be an integer value, got %.15g", tol, perQuad);
196  return -1;
197  }
198  if ( perQuad < 1 )
199  {
200  lwerror("lwarc_linearize: segments per quadrant must be at least 1, got %d", perQuad);
201  return -1;
202  }
203  increment = fabs(M_PI_2 / perQuad);
204  LWDEBUGF(2, "lwarc_linearize: perQuad:%d, increment:%g (%g degrees)", perQuad, increment, increment*180/M_PI);
205 
206  }}
207  else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION )
208  {{
209  double halfAngle;
210  if ( tol <= 0 )
211  {
212  lwerror("lwarc_linearize: max deviation must be bigger than 0, got %.15g", tol);
213  return -1;
214  }
215  halfAngle = acos( -tol / radius + 1 );
216  increment = 2 * halfAngle;
217  LWDEBUGF(2, "lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g (%g degrees)", tol, radius, halfAngle, increment, increment*180/M_PI);
218  }}
219  else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE )
220  {
221  increment = tol;
222  if ( increment <= 0 )
223  {
224  lwerror("lwarc_linearize: max angle must be bigger than 0, got %.15g", tol);
225  return -1;
226  }
227  }
228  else
229  {
230  lwerror("lwarc_linearize: unsupported tolerance type %d", tolerance_type);
231  return LW_FALSE;
232  }
233 
234  /* Angles of each point that defines the arc section */
235  a1 = atan2(p1->y - center.y, p1->x - center.x);
236  a2 = atan2(p2->y - center.y, p2->x - center.x);
237  a3 = atan2(p3->y - center.y, p3->x - center.x);
238 
239  LWDEBUGF(2, "lwarc_linearize A1:%g (%g) A2:%g (%g) A3:%g (%g)",
240  a1, a1*180/M_PI, a2, a2*180/M_PI, a3, a3*180/M_PI);
241 
242  if ( flags & LW_LINEARIZE_FLAG_SYMMETRIC )
243  {{
244  /* Calculate total arc angle, in radians */
245  double angle = clockwise ? a1 - a3 : a3 - a1;
246  if ( angle < 0 ) angle += M_PI * 2;
247  LWDEBUGF(2, "lwarc_linearize SYMMETRIC requested - total angle %g deg",
248  angle * 180 / M_PI);
249  if ( flags & LW_LINEARIZE_FLAG_RETAIN_ANGLE )
250  {{
251  /* Number of steps */
252  int steps = trunc(angle / increment);
253  /* Angle reminder */
254  double angle_reminder = angle - ( increment * steps );
255  angle_shift = angle_reminder / 2.0;
256 
257  LWDEBUGF(2, "lwarc_linearize RETAIN_ANGLE operation requested - "
258  "total angle %g, steps %d, increment %g, reminder %g",
259  angle * 180 / M_PI, steps, increment * 180 / M_PI,
260  angle_reminder * 180 / M_PI);
261  }}
262  else
263  {{
264  /* Number of segments in output */
265  int segs = ceil(angle / increment);
266  /* Tweak increment to be regular for all the arc */
267  increment = angle/segs;
268 
269  LWDEBUGF(2, "lwarc_linearize SYMMETRIC operation requested - "
270  "total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d - I:%g",
271  angle*180/M_PI, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
272  segs, increment*180/M_PI);
273  }}
274  }}
275 
276  /* p2 on left side => clockwise sweep */
277  if ( clockwise )
278  {
279  LWDEBUG(2, " Clockwise sweep");
280  increment *= -1;
281  angle_shift *= -1;
282  /* Adjust a3 down so we can decrement from a1 to a3 cleanly */
283  if ( a3 > a1 )
284  a3 -= 2.0 * M_PI;
285  if ( a2 > a1 )
286  a2 -= 2.0 * M_PI;
287  }
288  /* p2 on right side => counter-clockwise sweep */
289  else
290  {
291  LWDEBUG(2, " Counterclockwise sweep");
292  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
293  if ( a3 < a1 )
294  a3 += 2.0 * M_PI;
295  if ( a2 < a1 )
296  a2 += 2.0 * M_PI;
297  }
298 
299  /* Override angles for circle case */
300  if( is_circle )
301  {
302  a3 = a1 + 2.0 * M_PI;
303  a2 = a1 + M_PI;
304  increment = fabs(increment);
305  clockwise = LW_FALSE;
306  }
307 
308  LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
309  angle_shift * 180/M_PI, increment * 180/M_PI);
310 
311  if ( reverse ) {{
312  const int capacity = 8; /* TODO: compute exactly ? */
313  pa = ptarray_construct_empty(ptarray_has_z(to), ptarray_has_m(to), capacity);
314  }}
315 
316  /* Sweep from a1 to a3 */
317  if ( ! reverse )
318  {
320  }
321  ++points_added;
322  if ( angle_shift ) angle_shift -= increment;
323  LWDEBUGF(2, "a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
324  a1, a1 * 180 / M_PI, a3, a3 * 180 / M_PI, increment, angle_shift, clockwise);
325  for ( angle = a1 + increment + angle_shift; clockwise ? angle > a3 : angle < a3; angle += increment )
326  {
327  LWDEBUGF(2, " SA: %g ( %g deg )", angle, angle*180/M_PI);
328  pt.x = center.x + radius * cos(angle);
329  pt.y = center.y + radius * sin(angle);
330  pt.z = interpolate_arc(angle, a1, a2, a3, p1->z, p2->z, p3->z);
331  pt.m = interpolate_arc(angle, a1, a2, a3, p1->m, p2->m, p3->m);
332  ptarray_append_point(pa, &pt, LW_FALSE);
333  ++points_added;
334  angle_shift = 0;
335  }
336 
337  if ( reverse ) {{
338  int i;
340  for ( i=pa->npoints; i>0; i-- ) {
341  getPoint4d_p(pa, i-1, &pt);
342  ptarray_append_point(to, &pt, LW_FALSE);
343  }
344  ptarray_free(pa);
345  }}
346 
347  return points_added;
348 }
349 
350 /*
351  * @param icurve input curve
352  * @param tol tolerance, semantic driven by tolerance_type
353  * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
354  * @param flags see flags in lwarc_linearize
355  *
356  * @return a newly allocated LWLINE
357  */
358 static LWLINE *
359 lwcircstring_linearize(const LWCIRCSTRING *icurve, double tol,
360  LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
361  int flags)
362 {
363  LWLINE *oline;
364  POINTARRAY *ptarray;
365  uint32_t i, j;
366  POINT4D p1, p2, p3, p4;
367  int ret;
368 
369  LWDEBUGF(2, "lwcircstring_linearize called., dim = %d", icurve->points->flags);
370 
371  ptarray = ptarray_construct_empty(FLAGS_GET_Z(icurve->points->flags), FLAGS_GET_M(icurve->points->flags), 64);
372 
373  for (i = 2; i < icurve->points->npoints; i+=2)
374  {
375  LWDEBUGF(3, "lwcircstring_linearize: arc ending at point %d", i);
376 
377  getPoint4d_p(icurve->points, i - 2, &p1);
378  getPoint4d_p(icurve->points, i - 1, &p2);
379  getPoint4d_p(icurve->points, i, &p3);
380 
381  ret = lwarc_linearize(ptarray, &p1, &p2, &p3, tol, tolerance_type, flags);
382  if ( ret > 0 )
383  {
384  LWDEBUGF(3, "lwcircstring_linearize: generated %d points", ptarray->npoints);
385  }
386  else if ( ret == 0 )
387  {
388  LWDEBUG(3, "lwcircstring_linearize: points are colinear, returning curve points as line");
389 
390  for (j = i - 2 ; j < i ; j++)
391  {
392  getPoint4d_p(icurve->points, j, &p4);
393  ptarray_append_point(ptarray, &p4, LW_TRUE);
394  }
395  }
396  else
397  {
398  /* An error occurred, lwerror should have been called by now */
399  ptarray_free(ptarray);
400  return NULL;
401  }
402  }
403  getPoint4d_p(icurve->points, icurve->points->npoints-1, &p1);
404  ptarray_append_point(ptarray, &p1, LW_TRUE);
405 
406  oline = lwline_construct(icurve->srid, NULL, ptarray);
407  return oline;
408 }
409 
410 /*
411  * @param icompound input compound curve
412  * @param tol tolerance, semantic driven by tolerance_type
413  * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
414  * @param flags see flags in lwarc_linearize
415  *
416  * @return a newly allocated LWLINE
417  */
418 static LWLINE *
419 lwcompound_linearize(const LWCOMPOUND *icompound, double tol,
420  LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
421  int flags)
422 {
423  LWGEOM *geom;
424  POINTARRAY *ptarray = NULL, *ptarray_out = NULL;
425  LWLINE *tmp = NULL;
426  uint32_t i, j;
427  POINT4D p;
428 
429  LWDEBUG(2, "lwcompound_stroke called.");
430 
431  ptarray = ptarray_construct_empty(FLAGS_GET_Z(icompound->flags), FLAGS_GET_M(icompound->flags), 64);
432 
433  for (i = 0; i < icompound->ngeoms; i++)
434  {
435  geom = icompound->geoms[i];
436  if (geom->type == CIRCSTRINGTYPE)
437  {
438  tmp = lwcircstring_linearize((LWCIRCSTRING *)geom, tol, tolerance_type, flags);
439  for (j = 0; j < tmp->points->npoints; j++)
440  {
441  getPoint4d_p(tmp->points, j, &p);
442  ptarray_append_point(ptarray, &p, LW_TRUE);
443  }
444  lwline_free(tmp);
445  }
446  else if (geom->type == LINETYPE)
447  {
448  tmp = (LWLINE *)geom;
449  for (j = 0; j < tmp->points->npoints; j++)
450  {
451  getPoint4d_p(tmp->points, j, &p);
452  ptarray_append_point(ptarray, &p, LW_TRUE);
453  }
454  }
455  else
456  {
457  lwerror("Unsupported geometry type %d found.",
458  geom->type, lwtype_name(geom->type));
459  return NULL;
460  }
461  }
462  ptarray_out = ptarray_remove_repeated_points(ptarray, 0.0);
463  ptarray_free(ptarray);
464  return lwline_construct(icompound->srid, NULL, ptarray_out);
465 }
466 
467 /* Kept for backward compatibility - TODO: drop */
468 LWLINE *
469 lwcompound_stroke(const LWCOMPOUND *icompound, uint32_t perQuad)
470 {
472 }
473 
474 
475 /*
476  * @param icompound input curve polygon
477  * @param tol tolerance, semantic driven by tolerance_type
478  * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
479  * @param flags see flags in lwarc_linearize
480  *
481  * @return a newly allocated LWPOLY
482  */
483 static LWPOLY *
484 lwcurvepoly_linearize(const LWCURVEPOLY *curvepoly, double tol,
485  LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
486  int flags)
487 {
488  LWPOLY *ogeom;
489  LWGEOM *tmp;
490  LWLINE *line;
491  POINTARRAY **ptarray;
492  uint32_t i;
493 
494  LWDEBUG(2, "lwcurvepoly_linearize called.");
495 
496  ptarray = lwalloc(sizeof(POINTARRAY *)*curvepoly->nrings);
497 
498  for (i = 0; i < curvepoly->nrings; i++)
499  {
500  tmp = curvepoly->rings[i];
501  if (tmp->type == CIRCSTRINGTYPE)
502  {
503  line = lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, tolerance_type, flags);
504  ptarray[i] = ptarray_clone_deep(line->points);
505  lwline_free(line);
506  }
507  else if (tmp->type == LINETYPE)
508  {
509  line = (LWLINE *)tmp;
510  ptarray[i] = ptarray_clone_deep(line->points);
511  }
512  else if (tmp->type == COMPOUNDTYPE)
513  {
514  line = lwcompound_linearize((LWCOMPOUND *)tmp, tol, tolerance_type, flags);
515  ptarray[i] = ptarray_clone_deep(line->points);
516  lwline_free(line);
517  }
518  else
519  {
520  lwerror("Invalid ring type found in CurvePoly.");
521  return NULL;
522  }
523  }
524 
525  ogeom = lwpoly_construct(curvepoly->srid, NULL, curvepoly->nrings, ptarray);
526  return ogeom;
527 }
528 
529 /* Kept for backward compatibility - TODO: drop */
530 LWPOLY *
531 lwcurvepoly_stroke(const LWCURVEPOLY *curvepoly, uint32_t perQuad)
532 {
534 }
535 
536 
545 static LWMLINE *
546 lwmcurve_linearize(const LWMCURVE *mcurve, double tol,
548  int flags)
549 {
550  LWMLINE *ogeom;
551  LWGEOM **lines;
552  uint32_t i;
553 
554  LWDEBUGF(2, "lwmcurve_linearize called, geoms=%d, dim=%d.", mcurve->ngeoms, FLAGS_NDIMS(mcurve->flags));
555 
556  lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms);
557 
558  for (i = 0; i < mcurve->ngeoms; i++)
559  {
560  const LWGEOM *tmp = mcurve->geoms[i];
561  if (tmp->type == CIRCSTRINGTYPE)
562  {
563  lines[i] = (LWGEOM *)lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, type, flags);
564  }
565  else if (tmp->type == LINETYPE)
566  {
567  lines[i] = (LWGEOM *)lwline_construct(mcurve->srid, NULL, ptarray_clone_deep(((LWLINE *)tmp)->points));
568  }
569  else if (tmp->type == COMPOUNDTYPE)
570  {
571  lines[i] = (LWGEOM *)lwcompound_linearize((LWCOMPOUND *)tmp, tol, type, flags);
572  }
573  else
574  {
575  lwerror("Unsupported geometry found in MultiCurve.");
576  return NULL;
577  }
578  }
579 
580  ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->srid, NULL, mcurve->ngeoms, lines);
581  return ogeom;
582 }
583 
592 static LWMPOLY *
593 lwmsurface_linearize(const LWMSURFACE *msurface, double tol,
595  int flags)
596 {
597  LWMPOLY *ogeom;
598  LWGEOM *tmp;
599  LWPOLY *poly;
600  LWGEOM **polys;
601  POINTARRAY **ptarray;
602  uint32_t i, j;
603 
604  LWDEBUG(2, "lwmsurface_linearize called.");
605 
606  polys = lwalloc(sizeof(LWGEOM *)*msurface->ngeoms);
607 
608  for (i = 0; i < msurface->ngeoms; i++)
609  {
610  tmp = msurface->geoms[i];
611  if (tmp->type == CURVEPOLYTYPE)
612  {
613  polys[i] = (LWGEOM *)lwcurvepoly_linearize((LWCURVEPOLY *)tmp, tol, type, flags);
614  }
615  else if (tmp->type == POLYGONTYPE)
616  {
617  poly = (LWPOLY *)tmp;
618  ptarray = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
619  for (j = 0; j < poly->nrings; j++)
620  {
621  ptarray[j] = ptarray_clone_deep(poly->rings[j]);
622  }
623  polys[i] = (LWGEOM *)lwpoly_construct(msurface->srid, NULL, poly->nrings, ptarray);
624  }
625  }
626  ogeom = (LWMPOLY *)lwcollection_construct(MULTIPOLYGONTYPE, msurface->srid, NULL, msurface->ngeoms, polys);
627  return ogeom;
628 }
629 
638 static LWCOLLECTION *
639 lwcollection_linearize(const LWCOLLECTION *collection, double tol,
641  int flags)
642 {
643  LWCOLLECTION *ocol;
644  LWGEOM *tmp;
645  LWGEOM **geoms;
646  uint32_t i;
647 
648  LWDEBUG(2, "lwcollection_linearize called.");
649 
650  geoms = lwalloc(sizeof(LWGEOM *)*collection->ngeoms);
651 
652  for (i=0; i<collection->ngeoms; i++)
653  {
654  tmp = collection->geoms[i];
655  switch (tmp->type)
656  {
657  case CIRCSTRINGTYPE:
658  geoms[i] = (LWGEOM *)lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, type, flags);
659  break;
660  case COMPOUNDTYPE:
661  geoms[i] = (LWGEOM *)lwcompound_linearize((LWCOMPOUND *)tmp, tol, type, flags);
662  break;
663  case CURVEPOLYTYPE:
664  geoms[i] = (LWGEOM *)lwcurvepoly_linearize((LWCURVEPOLY *)tmp, tol, type, flags);
665  break;
666  case MULTICURVETYPE:
667  case MULTISURFACETYPE:
668  case COLLECTIONTYPE:
669  geoms[i] = (LWGEOM *)lwcollection_linearize((LWCOLLECTION *)tmp, tol, type, flags);
670  break;
671  default:
672  geoms[i] = lwgeom_clone(tmp);
673  break;
674  }
675  }
676  ocol = lwcollection_construct(COLLECTIONTYPE, collection->srid, NULL, collection->ngeoms, geoms);
677  return ocol;
678 }
679 
680 LWGEOM *
681 lwcurve_linearize(const LWGEOM *geom, double tol,
683  int flags)
684 {
685  LWGEOM * ogeom = NULL;
686  switch (geom->type)
687  {
688  case CIRCSTRINGTYPE:
689  ogeom = (LWGEOM *)lwcircstring_linearize((LWCIRCSTRING *)geom, tol, type, flags);
690  break;
691  case COMPOUNDTYPE:
692  ogeom = (LWGEOM *)lwcompound_linearize((LWCOMPOUND *)geom, tol, type, flags);
693  break;
694  case CURVEPOLYTYPE:
695  ogeom = (LWGEOM *)lwcurvepoly_linearize((LWCURVEPOLY *)geom, tol, type, flags);
696  break;
697  case MULTICURVETYPE:
698  ogeom = (LWGEOM *)lwmcurve_linearize((LWMCURVE *)geom, tol, type, flags);
699  break;
700  case MULTISURFACETYPE:
701  ogeom = (LWGEOM *)lwmsurface_linearize((LWMSURFACE *)geom, tol, type, flags);
702  break;
703  case COLLECTIONTYPE:
704  ogeom = (LWGEOM *)lwcollection_linearize((LWCOLLECTION *)geom, tol, type, flags);
705  break;
706  default:
707  ogeom = lwgeom_clone(geom);
708  }
709  return ogeom;
710 }
711 
712 /* Kept for backward compatibility - TODO: drop */
713 LWGEOM *
714 lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
715 {
717 }
718 
723 static double
724 lw_arc_angle(const POINT2D *a, const POINT2D *b, const POINT2D *c)
725 {
726  POINT2D ab, cb;
727 
728  ab.x = b->x - a->x;
729  ab.y = b->y - a->y;
730 
731  cb.x = b->x - c->x;
732  cb.y = b->y - c->y;
733 
734  double dot = (ab.x * cb.x + ab.y * cb.y); /* dot product */
735  double cross = (ab.x * cb.y - ab.y * cb.x); /* cross product */
736 
737  double alpha = atan2(cross, dot);
738 
739  return alpha;
740 }
741 
746 static int pt_continues_arc(const POINT4D *a1, const POINT4D *a2, const POINT4D *a3, const POINT4D *b)
747 {
748  POINT2D center;
749  POINT2D *t1 = (POINT2D*)a1;
750  POINT2D *t2 = (POINT2D*)a2;
751  POINT2D *t3 = (POINT2D*)a3;
752  POINT2D *tb = (POINT2D*)b;
753  double radius = lw_arc_center(t1, t2, t3, &center);
754  double b_distance, diff;
755 
756  /* Co-linear a1/a2/a3 */
757  if ( radius < 0.0 )
758  return LW_FALSE;
759 
760  b_distance = distance2d_pt_pt(tb, &center);
761  diff = fabs(radius - b_distance);
762  LWDEBUGF(4, "circle_radius=%g, b_distance=%g, diff=%g, percentage=%g", radius, b_distance, diff, diff/radius);
763 
764  /* Is the point b on the circle? */
765  if ( diff < EPSILON_SQLMM )
766  {
767  int a2_side = lw_segment_side(t1, t3, t2);
768  int b_side = lw_segment_side(t1, t3, tb);
769  double angle1 = lw_arc_angle(t1, t2, t3);
770  double angle2 = lw_arc_angle(t2, t3, tb);
771 
772  /* Is the angle similar to the previous one ? */
773  diff = fabs(angle1 - angle2);
774  LWDEBUGF(4, " angle1: %g, angle2: %g, diff:%g", angle1, angle2, diff);
775  if ( diff > EPSILON_SQLMM )
776  {
777  return LW_FALSE;
778  }
779 
780  /* Is the point b on the same side of a1/a3 as the mid-point a2 is? */
781  /* If not, it's in the unbounded part of the circle, so it continues the arc, return true. */
782  if ( b_side != a2_side )
783  return LW_TRUE;
784  }
785  return LW_FALSE;
786 }
787 
788 static LWGEOM*
789 linestring_from_pa(const POINTARRAY *pa, int srid, int start, int end)
790 {
791  int i = 0, j = 0;
792  POINT4D p;
793  POINTARRAY *pao = ptarray_construct(ptarray_has_z(pa), ptarray_has_m(pa), end-start+2);
794  LWDEBUGF(4, "srid=%d, start=%d, end=%d", srid, start, end);
795  for( i = start; i < end + 2; i++ )
796  {
797  getPoint4d_p(pa, i, &p);
798  ptarray_set_point4d(pao, j++, &p);
799  }
800  return lwline_as_lwgeom(lwline_construct(srid, NULL, pao));
801 }
802 
803 static LWGEOM*
804 circstring_from_pa(const POINTARRAY *pa, int srid, int start, int end)
805 {
806 
807  POINT4D p0, p1, p2;
809  LWDEBUGF(4, "srid=%d, start=%d, end=%d", srid, start, end);
810  getPoint4d_p(pa, start, &p0);
811  ptarray_set_point4d(pao, 0, &p0);
812  getPoint4d_p(pa, (start+end+1)/2, &p1);
813  ptarray_set_point4d(pao, 1, &p1);
814  getPoint4d_p(pa, end+1, &p2);
815  ptarray_set_point4d(pao, 2, &p2);
816  return lwcircstring_as_lwgeom(lwcircstring_construct(srid, NULL, pao));
817 }
818 
819 static LWGEOM*
820 geom_from_pa(const POINTARRAY *pa, int srid, int is_arc, int start, int end)
821 {
822  LWDEBUGF(4, "srid=%d, is_arc=%d, start=%d, end=%d", srid, is_arc, start, end);
823  if ( is_arc )
824  return circstring_from_pa(pa, srid, start, end);
825  else
826  return linestring_from_pa(pa, srid, start, end);
827 }
828 
829 LWGEOM*
830 pta_unstroke(const POINTARRAY *points, int type, int srid)
831 {
832  int i = 0, j, k;
833  POINT4D a1, a2, a3, b;
834  POINT4D first, center;
835  char *edges_in_arcs;
836  int found_arc = LW_FALSE;
837  int current_arc = 1;
838  int num_edges;
839  int edge_type; /* non-zero if edge is part of an arc */
840  int start, end;
841  LWCOLLECTION *outcol;
842  /* Minimum number of edges, per quadrant, required to define an arc */
843  const unsigned int min_quad_edges = 2;
844 
845  /* Die on null input */
846  if ( ! points )
847  lwerror("pta_unstroke called with null pointarray");
848 
849  /* Null on empty input? */
850  if ( points->npoints == 0 )
851  return NULL;
852 
853  /* We can't desegmentize anything shorter than four points */
854  if ( points->npoints < 4 )
855  {
856  /* Return a linestring here*/
857  lwerror("pta_unstroke needs implementation for npoints < 4");
858  }
859 
860  /* Allocate our result array of vertices that are part of arcs */
861  num_edges = points->npoints - 1;
862  edges_in_arcs = lwalloc(num_edges + 1);
863  memset(edges_in_arcs, 0, num_edges + 1);
864 
865  /* We make a candidate arc of the first two edges, */
866  /* And then see if the next edge follows it */
867  while( i < num_edges-2 )
868  {
869  unsigned int arc_edges;
870  double num_quadrants;
871  double angle;
872 
873  found_arc = LW_FALSE;
874  /* Make candidate arc */
875  getPoint4d_p(points, i , &a1);
876  getPoint4d_p(points, i+1, &a2);
877  getPoint4d_p(points, i+2, &a3);
878  memcpy(&first, &a1, sizeof(POINT4D));
879 
880  for( j = i+3; j < num_edges+1; j++ )
881  {
882  LWDEBUGF(4, "i=%d, j=%d", i, j);
883  getPoint4d_p(points, j, &b);
884  /* Does this point fall on our candidate arc? */
885  if ( pt_continues_arc(&a1, &a2, &a3, &b) )
886  {
887  /* Yes. Mark this edge and the two preceding it as arc components */
888  LWDEBUGF(4, "pt_continues_arc #%d", current_arc);
889  found_arc = LW_TRUE;
890  for ( k = j-1; k > j-4; k-- )
891  edges_in_arcs[k] = current_arc;
892  }
893  else
894  {
895  /* No. So we're done with this candidate arc */
896  LWDEBUG(4, "pt_continues_arc = false");
897  current_arc++;
898  break;
899  }
900 
901  memcpy(&a1, &a2, sizeof(POINT4D));
902  memcpy(&a2, &a3, sizeof(POINT4D));
903  memcpy(&a3, &b, sizeof(POINT4D));
904  }
905  /* Jump past all the edges that were added to the arc */
906  if ( found_arc )
907  {
908  /* Check if an arc was composed by enough edges to be
909  * really considered an arc
910  * See http://trac.osgeo.org/postgis/ticket/2420
911  */
912  arc_edges = j - 1 - i;
913  LWDEBUGF(4, "arc defined by %d edges found", arc_edges);
914  if ( first.x == b.x && first.y == b.y ) {
915  LWDEBUG(4, "arc is a circle");
916  num_quadrants = 4;
917  }
918  else {
919  lw_arc_center((POINT2D*)&first, (POINT2D*)&b, (POINT2D*)&a1, (POINT2D*)&center);
920  angle = lw_arc_angle((POINT2D*)&first, (POINT2D*)&center, (POINT2D*)&b);
921  int p2_side = lw_segment_side((POINT2D*)&first, (POINT2D*)&a1, (POINT2D*)&b);
922  if ( p2_side >= 0 ) angle = -angle;
923 
924  if ( angle < 0 ) angle = 2 * M_PI + angle;
925  num_quadrants = ( 4 * angle ) / ( 2 * M_PI );
926  LWDEBUGF(4, "arc angle (%g %g, %g %g, %g %g) is %g (side is %d), quandrants:%g", first.x, first.y, center.x, center.y, b.x, b.y, angle, p2_side, num_quadrants);
927  }
928  /* a1 is first point, b is last point */
929  if ( arc_edges < min_quad_edges * num_quadrants ) {
930  LWDEBUGF(4, "Not enough edges for a %g quadrants arc, %g needed", num_quadrants, min_quad_edges * num_quadrants);
931  for ( k = j-1; k >= i; k-- )
932  edges_in_arcs[k] = 0;
933  }
934 
935  i = j-1;
936  }
937  else
938  {
939  /* Mark this edge as a linear edge */
940  edges_in_arcs[i] = 0;
941  i = i+1;
942  }
943  }
944 
945 #if POSTGIS_DEBUG_LEVEL > 3
946  {
947  char *edgestr = lwalloc(num_edges+1);
948  for ( i = 0; i < num_edges; i++ )
949  {
950  if ( edges_in_arcs[i] )
951  edgestr[i] = 48 + edges_in_arcs[i];
952  else
953  edgestr[i] = '.';
954  }
955  edgestr[num_edges] = 0;
956  LWDEBUGF(3, "edge pattern %s", edgestr);
957  lwfree(edgestr);
958  }
959 #endif
960 
961  start = 0;
962  edge_type = edges_in_arcs[0];
963  outcol = lwcollection_construct_empty(COMPOUNDTYPE, srid, ptarray_has_z(points), ptarray_has_m(points));
964  for( i = 1; i < num_edges; i++ )
965  {
966  if( edge_type != edges_in_arcs[i] )
967  {
968  end = i - 1;
969  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
970  start = i;
971  edge_type = edges_in_arcs[i];
972  }
973  }
974  lwfree(edges_in_arcs); /* not needed anymore */
975 
976  /* Roll out last item */
977  end = num_edges - 1;
978  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
979 
980  /* Strip down to singleton if only one entry */
981  if ( outcol->ngeoms == 1 )
982  {
983  LWGEOM *outgeom = outcol->geoms[0];
984  outcol->ngeoms = 0; lwcollection_free(outcol);
985  return outgeom;
986  }
987  return lwcollection_as_lwgeom(outcol);
988 }
989 
990 
991 LWGEOM *
993 {
994  LWDEBUG(2, "lwline_unstroke called.");
995 
996  if ( line->points->npoints < 4 ) return lwline_as_lwgeom(lwline_clone(line));
997  else return pta_unstroke(line->points, line->flags, line->srid);
998 }
999 
1000 LWGEOM *
1002 {
1003  LWGEOM **geoms;
1004  uint32_t i, hascurve = 0;
1005 
1006  LWDEBUG(2, "lwpolygon_unstroke called.");
1007 
1008  geoms = lwalloc(sizeof(LWGEOM *)*poly->nrings);
1009  for (i=0; i<poly->nrings; i++)
1010  {
1011  geoms[i] = pta_unstroke(poly->rings[i], poly->flags, poly->srid);
1012  if (geoms[i]->type == CIRCSTRINGTYPE || geoms[i]->type == COMPOUNDTYPE)
1013  {
1014  hascurve = 1;
1015  }
1016  }
1017  if (hascurve == 0)
1018  {
1019  for (i=0; i<poly->nrings; i++)
1020  {
1021  lwfree(geoms[i]); /* TODO: should this be lwgeom_free instead ? */
1022  }
1023  return lwgeom_clone((LWGEOM *)poly);
1024  }
1025 
1026  return (LWGEOM *)lwcollection_construct(CURVEPOLYTYPE, poly->srid, NULL, poly->nrings, geoms);
1027 }
1028 
1029 LWGEOM *
1031 {
1032  LWGEOM **geoms;
1033  uint32_t i, hascurve = 0;
1034 
1035  LWDEBUG(2, "lwmline_unstroke called.");
1036 
1037  geoms = lwalloc(sizeof(LWGEOM *)*mline->ngeoms);
1038  for (i=0; i<mline->ngeoms; i++)
1039  {
1040  geoms[i] = lwline_unstroke((LWLINE *)mline->geoms[i]);
1041  if (geoms[i]->type == CIRCSTRINGTYPE || geoms[i]->type == COMPOUNDTYPE)
1042  {
1043  hascurve = 1;
1044  }
1045  }
1046  if (hascurve == 0)
1047  {
1048  for (i=0; i<mline->ngeoms; i++)
1049  {
1050  lwfree(geoms[i]); /* TODO: should this be lwgeom_free instead ? */
1051  }
1052  return lwgeom_clone((LWGEOM *)mline);
1053  }
1054  return (LWGEOM *)lwcollection_construct(MULTICURVETYPE, mline->srid, NULL, mline->ngeoms, geoms);
1055 }
1056 
1057 LWGEOM *
1059 {
1060  LWGEOM **geoms;
1061  uint32_t i, hascurve = 0;
1062 
1063  LWDEBUG(2, "lwmpoly_unstroke called.");
1064 
1065  geoms = lwalloc(sizeof(LWGEOM *)*mpoly->ngeoms);
1066  for (i=0; i<mpoly->ngeoms; i++)
1067  {
1068  geoms[i] = lwpolygon_unstroke((LWPOLY *)mpoly->geoms[i]);
1069  if (geoms[i]->type == CURVEPOLYTYPE)
1070  {
1071  hascurve = 1;
1072  }
1073  }
1074  if (hascurve == 0)
1075  {
1076  for (i=0; i<mpoly->ngeoms; i++)
1077  {
1078  lwfree(geoms[i]); /* TODO: should this be lwgeom_free instead ? */
1079  }
1080  return lwgeom_clone((LWGEOM *)mpoly);
1081  }
1082  return (LWGEOM *)lwcollection_construct(MULTISURFACETYPE, mpoly->srid, NULL, mpoly->ngeoms, geoms);
1083 }
1084 
1085 LWGEOM *
1087 {
1088  LWDEBUG(2, "lwgeom_unstroke called.");
1089 
1090  switch (geom->type)
1091  {
1092  case LINETYPE:
1093  return lwline_unstroke((LWLINE *)geom);
1094  case POLYGONTYPE:
1095  return lwpolygon_unstroke((LWPOLY *)geom);
1096  case MULTILINETYPE:
1097  return lwmline_unstroke((LWMLINE *)geom);
1098  case MULTIPOLYGONTYPE:
1099  return lwmpolygon_unstroke((LWMPOLY *)geom);
1100  default:
1101  return lwgeom_clone(geom);
1102  }
1103 }
1104 
int32_t srid
Definition: liblwgeom.h:518
double x
Definition: liblwgeom.h:351
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
Definition: lwalgorithm.c:227
#define LINETYPE
Definition: liblwgeom.h:85
static LWMLINE * lwmcurve_linearize(const LWMCURVE *mcurve, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags)
Definition: lwstroke.c:546
LWGEOM * lwgeom_unstroke(const LWGEOM *geom)
Definition: lwstroke.c:1086
uint8_t flags
Definition: liblwgeom.h:542
POINTARRAY * ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
Definition: ptarray.c:1439
static double lw_arc_angle(const POINT2D *a, const POINT2D *b, const POINT2D *c)
Return ABC angle in radians TODO: move to lwalgorithm.
Definition: lwstroke.c:724
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:62
double m
Definition: liblwgeom.h:351
uint32_t ngeoms
Definition: liblwgeom.h:558
#define MULTICURVETYPE
Definition: liblwgeom.h:94
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:43
Tolerance expresses the maximum angle between the radii generating approximation line vertices...
Definition: liblwgeom.h:2202
void lwfree(void *mem)
Definition: lwutil.c:244
LWGEOM ** rings
Definition: liblwgeom.h:534
LWLINE * lwline_clone(const LWLINE *lwgeom)
Definition: lwline.c:102
uint32_t ngeoms
Definition: liblwgeom.h:493
int32_t srid
Definition: liblwgeom.h:442
#define POLYGONTYPE
Definition: liblwgeom.h:86
LWGEOM * lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
Definition: lwgeom.c:304
#define CURVEPOLYTYPE
Definition: liblwgeom.h:93
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:70
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:328
#define COMPOUNDTYPE
Definition: liblwgeom.h:92
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
static LWLINE * lwcompound_linearize(const LWCOMPOUND *icompound, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags)
Definition: lwstroke.c:419
void lwline_free(LWLINE *line)
Definition: lwline.c:76
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:425
int32_t srid
Definition: liblwgeom.h:544
static LWPOLY * lwcurvepoly_linearize(const LWCURVEPOLY *curvepoly, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags)
Definition: lwstroke.c:484
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define TRIANGLETYPE
Definition: liblwgeom.h:97
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:96
static int pt_continues_arc(const POINT4D *a1, const POINT4D *a2, const POINT4D *a3, const POINT4D *b)
Returns LW_TRUE if b is on the arc formed by a1/a2/a3, but not within that portion already described ...
Definition: lwstroke.c:746
static LWMPOLY * lwmsurface_linearize(const LWMSURFACE *msurface, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags)
Definition: lwstroke.c:593
LWGEOM * pta_unstroke(const POINTARRAY *points, int type, int srid)
Definition: lwstroke.c:830
LW_LINEARIZE_TOLERANCE_TYPE
Semantic of the tolerance argument passed to lwcurve_linearize.
Definition: liblwgeom.h:2181
static LWGEOM * circstring_from_pa(const POINTARRAY *pa, int srid, int start, int end)
Definition: lwstroke.c:804
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
Definition: measures.c:2312
Tolerance expresses the maximum distance between an arbitrary point on the curve and the closest poin...
Definition: liblwgeom.h:2194
int32_t srid
Definition: liblwgeom.h:420
LWGEOM ** geoms
Definition: liblwgeom.h:521
uint8_t flags
Definition: liblwgeom.h:516
uint32_t ngeoms
Definition: liblwgeom.h:506
uint32_t nrings
Definition: liblwgeom.h:454
LWPOLY * lwcurvepoly_stroke(const LWCURVEPOLY *curvepoly, uint32_t perQuad)
Definition: lwstroke.c:531
static int lwarc_linearize(POINTARRAY *to, const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags)
Segmentize an arc.
Definition: lwstroke.c:134
unsigned int uint32_t
Definition: uthash.h:78
double x
Definition: liblwgeom.h:327
LWGEOM * lwpolygon_unstroke(const LWPOLY *poly)
Definition: lwstroke.c:1001
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:329
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, then a duplicate point will not be added.
Definition: ptarray.c:156
int32_t srid
Definition: liblwgeom.h:531
#define LW_FALSE
Definition: liblwgeom.h:76
uint8_t flags
Definition: liblwgeom.h:368
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:43
LWPOLY ** geoms
Definition: liblwgeom.h:495
#define EPSILON_SQLMM
Tolerance used to determine equality.
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWGEOM ** geoms
Definition: liblwgeom.h:508
LWLINE * lwcompound_stroke(const LWCOMPOUND *icompound, uint32_t perQuad)
Definition: lwstroke.c:469
static LWGEOM * geom_from_pa(const POINTARRAY *pa, int srid, int is_arc, int start, int end)
Definition: lwstroke.c:820
#define TINTYPE
Definition: liblwgeom.h:98
uint32_t ngeoms
Definition: liblwgeom.h:519
POINTARRAY ** rings
Definition: liblwgeom.h:456
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:628
static LWLINE * lwcircstring_linearize(const LWCIRCSTRING *icurve, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags)
Definition: lwstroke.c:359
int32_t srid
Definition: liblwgeom.h:505
double y
Definition: liblwgeom.h:327
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:139
static double interpolate_arc(double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3)
Definition: lwstroke.c:95
double z
Definition: liblwgeom.h:351
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:475
LWCIRCSTRING * lwcircstring_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwcircstring.c:50
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:113
Symmetric linearization means that the output vertices would be the same no matter the order of the p...
Definition: liblwgeom.h:2211
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
uint32_t ngeoms
Definition: liblwgeom.h:480
LWLINE ** geoms
Definition: liblwgeom.h:482
Tolerance expresses the number of segments to use for each quarter of circle (quadrant).
Definition: liblwgeom.h:2187
int ptarray_has_m(const POINTARRAY *pa)
Definition: ptarray.c:43
#define MULTISURFACETYPE
Definition: liblwgeom.h:95
int lwgeom_has_arc(const LWGEOM *geom)
Definition: lwstroke.c:54
int32_t srid
Definition: liblwgeom.h:453
LWGEOM * lwcurve_linearize(const LWGEOM *geom, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags)
Definition: lwstroke.c:681
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Definition: lwstroke.c:714
LWGEOM ** geoms
Definition: liblwgeom.h:560
LWGEOM * lwline_unstroke(const LWLINE *line)
Definition: lwstroke.c:992
LWGEOM ** geoms
Definition: liblwgeom.h:547
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
Retain angle instructs the engine to try its best to retain the requested angle between generating ra...
Definition: liblwgeom.h:2231
int32_t srid
Definition: liblwgeom.h:557
uint8_t type
Definition: liblwgeom.h:395
static LWGEOM * linestring_from_pa(const POINTARRAY *pa, int srid, int start, int end)
Definition: lwstroke.c:789
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:342
POINTARRAY * points
Definition: liblwgeom.h:443
static LWCOLLECTION * lwcollection_linearize(const LWCOLLECTION *collection, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags)
Definition: lwstroke.c:639
uint32_t nrings
Definition: liblwgeom.h:532
uint8_t flags
Definition: liblwgeom.h:451
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:91
int ptarray_has_z(const POINTARRAY *pa)
Definition: ptarray.c:36
void * lwalloc(size_t size)
Definition: lwutil.c:229
uint32_t ngeoms
Definition: liblwgeom.h:545
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:64
double y
Definition: liblwgeom.h:351
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
uint8_t flags
Definition: liblwgeom.h:418
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:151
LWGEOM * lwmpolygon_unstroke(const LWMPOLY *mpoly)
Definition: lwstroke.c:1058
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:187
int32_t srid
Definition: liblwgeom.h:492
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
LWGEOM * lwmline_unstroke(const LWMLINE *mline)
Definition: lwstroke.c:1030
int32_t srid
Definition: liblwgeom.h:479
POINTARRAY * points
Definition: liblwgeom.h:421
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:299
uint32_t npoints
Definition: liblwgeom.h:370