PostGIS  2.3.8dev-r@@SVN_REVISION@@

◆ pta_unstroke()

LWGEOM * pta_unstroke ( const POINTARRAY points,
int  type,
int  srid 
)

Definition at line 602 of file lwstroke.c.

References COMPOUNDTYPE, geom_from_pa(), LWCOLLECTION::geoms, getPoint4d_p(), lw_arc_angle(), lw_arc_center(), LW_FALSE, lw_segment_side(), LW_TRUE, lwalloc(), lwcollection_add_lwgeom(), lwcollection_as_lwgeom(), lwcollection_construct_empty(), lwcollection_free(), LWDEBUG, LWDEBUGF, lwerror(), lwfree(), LWCOLLECTION::ngeoms, POINTARRAY::npoints, pt_continues_arc(), ptarray_has_m(), ptarray_has_z(), POINT2D::x, POINT4D::x, POINT2D::y, and POINT4D::y.

Referenced by lwline_unstroke(), and lwpolygon_unstroke().

603 {
604  int i = 0, j, k;
605  POINT4D a1, a2, a3, b;
606  POINT4D first, center;
607  char *edges_in_arcs;
608  int found_arc = LW_FALSE;
609  int current_arc = 1;
610  int num_edges;
611  int edge_type; /* non-zero if edge is part of an arc */
612  int start, end;
613  LWCOLLECTION *outcol;
614  /* Minimum number of edges, per quadrant, required to define an arc */
615  const unsigned int min_quad_edges = 2;
616 
617  /* Die on null input */
618  if ( ! points )
619  lwerror("pta_unstroke called with null pointarray");
620 
621  /* Null on empty input? */
622  if ( points->npoints == 0 )
623  return NULL;
624 
625  /* We can't desegmentize anything shorter than four points */
626  if ( points->npoints < 4 )
627  {
628  /* Return a linestring here*/
629  lwerror("pta_unstroke needs implementation for npoints < 4");
630  }
631 
632  /* Allocate our result array of vertices that are part of arcs */
633  num_edges = points->npoints - 1;
634  edges_in_arcs = lwalloc(num_edges + 1);
635  memset(edges_in_arcs, 0, num_edges + 1);
636 
637  /* We make a candidate arc of the first two edges, */
638  /* And then see if the next edge follows it */
639  while( i < num_edges-2 )
640  {
641  unsigned int arc_edges;
642  double num_quadrants;
643  double angle;
644 
645  found_arc = LW_FALSE;
646  /* Make candidate arc */
647  getPoint4d_p(points, i , &a1);
648  getPoint4d_p(points, i+1, &a2);
649  getPoint4d_p(points, i+2, &a3);
650  memcpy(&first, &a1, sizeof(POINT4D));
651 
652  for( j = i+3; j < num_edges+1; j++ )
653  {
654  LWDEBUGF(4, "i=%d, j=%d", i, j);
655  getPoint4d_p(points, j, &b);
656  /* Does this point fall on our candidate arc? */
657  if ( pt_continues_arc(&a1, &a2, &a3, &b) )
658  {
659  /* Yes. Mark this edge and the two preceding it as arc components */
660  LWDEBUGF(4, "pt_continues_arc #%d", current_arc);
661  found_arc = LW_TRUE;
662  for ( k = j-1; k > j-4; k-- )
663  edges_in_arcs[k] = current_arc;
664  }
665  else
666  {
667  /* No. So we're done with this candidate arc */
668  LWDEBUG(4, "pt_continues_arc = false");
669  current_arc++;
670  break;
671  }
672 
673  memcpy(&a1, &a2, sizeof(POINT4D));
674  memcpy(&a2, &a3, sizeof(POINT4D));
675  memcpy(&a3, &b, sizeof(POINT4D));
676  }
677  /* Jump past all the edges that were added to the arc */
678  if ( found_arc )
679  {
680  /* Check if an arc was composed by enough edges to be
681  * really considered an arc
682  * See http://trac.osgeo.org/postgis/ticket/2420
683  */
684  arc_edges = j - 1 - i;
685  LWDEBUGF(4, "arc defined by %d edges found", arc_edges);
686  if ( first.x == b.x && first.y == b.y ) {
687  LWDEBUG(4, "arc is a circle");
688  num_quadrants = 4;
689  }
690  else {
691  lw_arc_center((POINT2D*)&first, (POINT2D*)&b, (POINT2D*)&a1, (POINT2D*)&center);
692  angle = lw_arc_angle((POINT2D*)&first, (POINT2D*)&center, (POINT2D*)&b);
693  int p2_side = lw_segment_side((POINT2D*)&first, (POINT2D*)&a1, (POINT2D*)&b);
694  if ( p2_side >= 0 ) angle = -angle;
695 
696  if ( angle < 0 ) angle = 2 * M_PI + angle;
697  num_quadrants = ( 4 * angle ) / ( 2 * M_PI );
698  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);
699  }
700  /* a1 is first point, b is last point */
701  if ( arc_edges < min_quad_edges * num_quadrants ) {
702  LWDEBUGF(4, "Not enough edges for a %g quadrants arc, %g needed", num_quadrants, min_quad_edges * num_quadrants);
703  for ( k = j-1; k >= i; k-- )
704  edges_in_arcs[k] = 0;
705  }
706 
707  i = j-1;
708  }
709  else
710  {
711  /* Mark this edge as a linear edge */
712  edges_in_arcs[i] = 0;
713  i = i+1;
714  }
715  }
716 
717 #if POSTGIS_DEBUG_LEVEL > 3
718  {
719  char *edgestr = lwalloc(num_edges+1);
720  for ( i = 0; i < num_edges; i++ )
721  {
722  if ( edges_in_arcs[i] )
723  edgestr[i] = 48 + edges_in_arcs[i];
724  else
725  edgestr[i] = '.';
726  }
727  edgestr[num_edges] = 0;
728  LWDEBUGF(3, "edge pattern %s", edgestr);
729  lwfree(edgestr);
730  }
731 #endif
732 
733  start = 0;
734  edge_type = edges_in_arcs[0];
735  outcol = lwcollection_construct_empty(COMPOUNDTYPE, srid, ptarray_has_z(points), ptarray_has_m(points));
736  for( i = 1; i < num_edges; i++ )
737  {
738  if( edge_type != edges_in_arcs[i] )
739  {
740  end = i - 1;
741  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
742  start = i;
743  edge_type = edges_in_arcs[i];
744  }
745  }
746  lwfree(edges_in_arcs); /* not needed anymore */
747 
748  /* Roll out last item */
749  end = num_edges - 1;
750  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
751 
752  /* Strip down to singleton if only one entry */
753  if ( outcol->ngeoms == 1 )
754  {
755  LWGEOM *outgeom = outcol->geoms[0];
756  outcol->ngeoms = 0; lwcollection_free(outcol);
757  return outgeom;
758  }
759  return lwcollection_as_lwgeom(outcol);
760 }
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
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:496
void lwfree(void *mem)
Definition: lwutil.c:242
int npoints
Definition: liblwgeom.h:370
#define COMPOUNDTYPE
Definition: liblwgeom.h:92
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
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:518
double x
Definition: liblwgeom.h:327
#define LW_FALSE
Definition: liblwgeom.h:76
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
LWGEOM ** geoms
Definition: liblwgeom.h:508
static LWGEOM * geom_from_pa(const POINTARRAY *pa, int srid, int is_arc, int start, int end)
Definition: lwstroke.c:592
double y
Definition: liblwgeom.h:327
int ptarray_has_m(const POINTARRAY *pa)
Definition: ptarray.c:43
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:339
int ptarray_has_z(const POINTARRAY *pa)
Definition: ptarray.c:36
void * lwalloc(size_t size)
Definition: lwutil.c:227
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
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:187
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:102
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:244
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:232
Here is the call graph for this function:
Here is the caller graph for this function: