PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ pta_unstroke()

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

Definition at line 883 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().

884 {
885  int i = 0, j, k;
886  POINT4D a1, a2, a3, b;
887  POINT4D first, center;
888  char *edges_in_arcs;
889  int found_arc = LW_FALSE;
890  int current_arc = 1;
891  int num_edges;
892  int edge_type; /* non-zero if edge is part of an arc */
893  int start, end;
894  LWCOLLECTION *outcol;
895  /* Minimum number of edges, per quadrant, required to define an arc */
896  const unsigned int min_quad_edges = 2;
897 
898  /* Die on null input */
899  if ( ! points )
900  lwerror("pta_unstroke called with null pointarray");
901 
902  /* Null on empty input? */
903  if ( points->npoints == 0 )
904  return NULL;
905 
906  /* We can't desegmentize anything shorter than four points */
907  if ( points->npoints < 4 )
908  {
909  /* Return a linestring here*/
910  lwerror("pta_unstroke needs implementation for npoints < 4");
911  }
912 
913  /* Allocate our result array of vertices that are part of arcs */
914  num_edges = points->npoints - 1;
915  edges_in_arcs = lwalloc(num_edges + 1);
916  memset(edges_in_arcs, 0, num_edges + 1);
917 
918  /* We make a candidate arc of the first two edges, */
919  /* And then see if the next edge follows it */
920  while( i < num_edges-2 )
921  {
922  unsigned int arc_edges;
923  double num_quadrants;
924  double angle;
925 
926  found_arc = LW_FALSE;
927  /* Make candidate arc */
928  getPoint4d_p(points, i , &a1);
929  getPoint4d_p(points, i+1, &a2);
930  getPoint4d_p(points, i+2, &a3);
931  memcpy(&first, &a1, sizeof(POINT4D));
932 
933  for( j = i+3; j < num_edges+1; j++ )
934  {
935  LWDEBUGF(4, "i=%d, j=%d", i, j);
936  getPoint4d_p(points, j, &b);
937  /* Does this point fall on our candidate arc? */
938  if ( pt_continues_arc(&a1, &a2, &a3, &b) )
939  {
940  /* Yes. Mark this edge and the two preceding it as arc components */
941  LWDEBUGF(4, "pt_continues_arc #%d", current_arc);
942  found_arc = LW_TRUE;
943  for ( k = j-1; k > j-4; k-- )
944  edges_in_arcs[k] = current_arc;
945  }
946  else
947  {
948  /* No. So we're done with this candidate arc */
949  LWDEBUG(4, "pt_continues_arc = false");
950  current_arc++;
951  break;
952  }
953 
954  memcpy(&a1, &a2, sizeof(POINT4D));
955  memcpy(&a2, &a3, sizeof(POINT4D));
956  memcpy(&a3, &b, sizeof(POINT4D));
957  }
958  /* Jump past all the edges that were added to the arc */
959  if ( found_arc )
960  {
961  /* Check if an arc was composed by enough edges to be
962  * really considered an arc
963  * See http://trac.osgeo.org/postgis/ticket/2420
964  */
965  arc_edges = j - 1 - i;
966  LWDEBUGF(4, "arc defined by %d edges found", arc_edges);
967  if ( first.x == b.x && first.y == b.y ) {
968  LWDEBUG(4, "arc is a circle");
969  num_quadrants = 4;
970  }
971  else {
972  lw_arc_center((POINT2D*)&first, (POINT2D*)&b, (POINT2D*)&a1, (POINT2D*)&center);
973  angle = lw_arc_angle((POINT2D*)&first, (POINT2D*)&center, (POINT2D*)&b);
974  int p2_side = lw_segment_side((POINT2D*)&first, (POINT2D*)&a1, (POINT2D*)&b);
975  if ( p2_side >= 0 ) angle = -angle;
976 
977  if ( angle < 0 ) angle = 2 * M_PI + angle;
978  num_quadrants = ( 4 * angle ) / ( 2 * M_PI );
979  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);
980  }
981  /* a1 is first point, b is last point */
982  if ( arc_edges < min_quad_edges * num_quadrants ) {
983  LWDEBUGF(4, "Not enough edges for a %g quadrants arc, %g needed", num_quadrants, min_quad_edges * num_quadrants);
984  for ( k = j-1; k >= i; k-- )
985  edges_in_arcs[k] = 0;
986  }
987 
988  i = j-1;
989  }
990  else
991  {
992  /* Mark this edge as a linear edge */
993  edges_in_arcs[i] = 0;
994  i = i+1;
995  }
996  }
997 
998 #if POSTGIS_DEBUG_LEVEL > 3
999  {
1000  char *edgestr = lwalloc(num_edges+1);
1001  for ( i = 0; i < num_edges; i++ )
1002  {
1003  if ( edges_in_arcs[i] )
1004  edgestr[i] = 48 + edges_in_arcs[i];
1005  else
1006  edgestr[i] = '.';
1007  }
1008  edgestr[num_edges] = 0;
1009  LWDEBUGF(3, "edge pattern %s", edgestr);
1010  lwfree(edgestr);
1011  }
1012 #endif
1013 
1014  start = 0;
1015  edge_type = edges_in_arcs[0];
1016  outcol = lwcollection_construct_empty(COMPOUNDTYPE, srid, ptarray_has_z(points), ptarray_has_m(points));
1017  for( i = 1; i < num_edges; i++ )
1018  {
1019  if( edge_type != edges_in_arcs[i] )
1020  {
1021  end = i - 1;
1022  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
1023  start = i;
1024  edge_type = edges_in_arcs[i];
1025  }
1026  }
1027  lwfree(edges_in_arcs); /* not needed anymore */
1028 
1029  /* Roll out last item */
1030  end = num_edges - 1;
1031  lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end));
1032 
1033  /* Strip down to singleton if only one entry */
1034  if ( outcol->ngeoms == 1 )
1035  {
1036  LWGEOM *outgeom = outcol->geoms[0];
1037  outcol->ngeoms = 0; lwcollection_free(outcol);
1038  return outgeom;
1039  }
1040  return lwcollection_as_lwgeom(outcol);
1041 }
double x
Definition: liblwgeom.h:352
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:777
void lwfree(void *mem)
Definition: lwutil.c:244
int npoints
Definition: liblwgeom.h:371
#define COMPOUNDTYPE
Definition: liblwgeom.h:93
#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:799
double x
Definition: liblwgeom.h:328
#define LW_FALSE
Definition: liblwgeom.h:77
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
LWGEOM ** geoms
Definition: liblwgeom.h:509
static LWGEOM * geom_from_pa(const POINTARRAY *pa, int srid, int is_arc, int start, int end)
Definition: lwstroke.c:873
double y
Definition: liblwgeom.h:328
int ptarray_has_m(const POINTARRAY *pa)
Definition: ptarray.c:43
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:340
int ptarray_has_z(const POINTARRAY *pa)
Definition: ptarray.c:36
void * lwalloc(size_t size)
Definition: lwutil.c:229
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:352
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:190
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:122
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:268
Here is the call graph for this function:
Here is the caller graph for this function: