PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ lwline_clip_to_ordinate_range()

static LWCOLLECTION* lwline_clip_to_ordinate_range ( const LWLINE line,
char  ordinate,
double  from,
double  to 
)
inlinestatic

Take in a LINESTRING and return a MULTILINESTRING of those portions of the LINESTRING between the from/to range for the specified ordinate (XYZM)

Definition at line 528 of file lwlinearreferencing.c.

529 {
530  POINTARRAY *pa_in = NULL;
531  LWCOLLECTION *lwgeom_out = NULL;
532  POINTARRAY *dp = NULL;
533  uint32_t i;
534  int added_last_point = 0;
535  POINT4D *p = NULL, *q = NULL, *r = NULL;
536  double ordinate_value_p = 0.0, ordinate_value_q = 0.0;
537  char hasz, hasm;
538  char dims;
539 
540  /* Null input, nothing we can do. */
541  assert(line);
542  hasz = lwgeom_has_z(lwline_as_lwgeom(line));
543  hasm = lwgeom_has_m(lwline_as_lwgeom(line));
544  dims = FLAGS_NDIMS(line->flags);
545 
546  /* Asking for an ordinate we don't have. Error. */
547  if ((ordinate == 'Z' && !hasz) || (ordinate == 'M' && !hasm))
548  {
549  lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims);
550  return NULL;
551  }
552 
553  /* Prepare our working point objects. */
554  p = lwalloc(sizeof(POINT4D));
555  q = lwalloc(sizeof(POINT4D));
556  r = lwalloc(sizeof(POINT4D));
557 
558  /* Construct a collection to hold our outputs. */
559  lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, line->srid, hasz, hasm);
560 
561  /* Get our input point array */
562  pa_in = line->points;
563 
564  for (i = 0; i < pa_in->npoints; i++)
565  {
566  if (i > 0)
567  {
568  *q = *p;
569  ordinate_value_q = ordinate_value_p;
570  }
571  getPoint4d_p(pa_in, i, p);
572  ordinate_value_p = lwpoint_get_ordinate(p, ordinate);
573 
574  /* Is this point inside the ordinate range? Yes. */
575  if (ordinate_value_p >= from && ordinate_value_p <= to)
576  {
577 
578  if (!added_last_point)
579  {
580  /* We didn't add the previous point, so this is a new segment.
581  * Make a new point array. */
582  dp = ptarray_construct_empty(hasz, hasm, 32);
583 
584  /* We're transiting into the range so add an interpolated
585  * point at the range boundary.
586  * If we're on a boundary and crossing from the far side,
587  * we also need an interpolated point. */
588  if (i > 0 &&
589  (/* Don't try to interpolate if this is the first point */
590  (ordinate_value_p > from && ordinate_value_p < to) || /* Inside */
591  (ordinate_value_p == from && ordinate_value_q > to) || /* Hopping from above */
592  (ordinate_value_p == to && ordinate_value_q < from))) /* Hopping from below */
593  {
594  double interpolation_value;
595  (ordinate_value_q > to) ? (interpolation_value = to)
596  : (interpolation_value = from);
597  point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
599  }
600  }
601  /* Add the current vertex to the point array. */
603  if (ordinate_value_p == from || ordinate_value_p == to)
604  added_last_point = 2; /* Added on boundary. */
605  else
606  added_last_point = 1; /* Added inside range. */
607  }
608  /* Is this point inside the ordinate range? No. */
609  else
610  {
611  if (added_last_point == 1)
612  {
613  /* We're transiting out of the range, so add an interpolated point
614  * to the point array at the range boundary. */
615  double interpolation_value;
616  (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);
617  point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
619  }
620  else if (added_last_point == 2)
621  {
622  /* We're out and the last point was on the boundary.
623  * If the last point was the near boundary, nothing to do.
624  * If it was the far boundary, we need an interpolated point. */
625  if (from != to && ((ordinate_value_q == from && ordinate_value_p > from) ||
626  (ordinate_value_q == to && ordinate_value_p < to)))
627  {
628  double interpolation_value;
629  (ordinate_value_p > to) ? (interpolation_value = to)
630  : (interpolation_value = from);
631  point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
633  }
634  }
635  else if (i && ordinate_value_q < from && ordinate_value_p > to)
636  {
637  /* We just hopped over the whole range, from bottom to top,
638  * so we need to add *two* interpolated points! */
639  dp = ptarray_construct(hasz, hasm, 2);
640  /* Interpolate lower point. */
641  point_interpolate(p, q, r, hasz, hasm, ordinate, from);
642  ptarray_set_point4d(dp, 0, r);
643  /* Interpolate upper point. */
644  point_interpolate(p, q, r, hasz, hasm, ordinate, to);
645  ptarray_set_point4d(dp, 1, r);
646  }
647  else if (i && ordinate_value_q > to && ordinate_value_p < from)
648  {
649  /* We just hopped over the whole range, from top to bottom,
650  * so we need to add *two* interpolated points! */
651  dp = ptarray_construct(hasz, hasm, 2);
652  /* Interpolate upper point. */
653  point_interpolate(p, q, r, hasz, hasm, ordinate, to);
654  ptarray_set_point4d(dp, 0, r);
655  /* Interpolate lower point. */
656  point_interpolate(p, q, r, hasz, hasm, ordinate, from);
657  ptarray_set_point4d(dp, 1, r);
658  }
659  /* We have an extant point-array, save it out to a multi-line. */
660  if (dp)
661  {
662  /* Only one point, so we have to make an lwpoint to hold this
663  * and set the overall output type to a generic collection. */
664  if (dp->npoints == 1)
665  {
666  LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp);
667  lwgeom_out->type = COLLECTIONTYPE;
668  lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint));
669  }
670  else
671  {
672  LWLINE *oline = lwline_construct(line->srid, NULL, dp);
673  lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline));
674  }
675 
676  /* Pointarray is now owned by lwgeom_out, so drop reference to it */
677  dp = NULL;
678  }
679  added_last_point = 0;
680  }
681  }
682 
683  /* Still some points left to be saved out. */
684  if (dp)
685  {
686  if (dp->npoints == 1)
687  {
688  LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp);
689  lwgeom_out->type = COLLECTIONTYPE;
690  lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint));
691  }
692  else if (dp->npoints > 1)
693  {
694  LWLINE *oline = lwline_construct(line->srid, NULL, dp);
695  lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline));
696  }
697  else
698  ptarray_free(dp);
699  }
700 
701  lwfree(p);
702  lwfree(q);
703  lwfree(r);
704 
705  if (line->bbox && lwgeom_out->ngeoms > 0)
706  lwgeom_refresh_bbox((LWGEOM *)lwgeom_out);
707 
708  return lwgeom_out;
709 }
char * r
Definition: cu_in_wkt.c:24
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition: lwgeom.c:707
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define MULTILINETYPE
Definition: liblwgeom.h:106
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
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwfree(void *mem)
Definition: lwutil.c:248
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:179
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
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:327
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
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
void * lwalloc(size_t size)
Definition: lwutil.c:227
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
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
double lwpoint_get_ordinate(const POINT4D *p, char ordinate)
Given a POINT4D and an ordinate number, return the value of the ordinate.
int point_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz, int hasm, char ordinate, double interpolation_value)
Given two points, a dimensionality, an ordinate, and an interpolation value generate a new point that...
uint32_t ngeoms
Definition: liblwgeom.h:580
uint8_t type
Definition: liblwgeom.h:578
lwflags_t flags
Definition: liblwgeom.h:485
GBOX * bbox
Definition: liblwgeom.h:482
POINTARRAY * points
Definition: liblwgeom.h:483
int32_t srid
Definition: liblwgeom.h:484
uint32_t npoints
Definition: liblwgeom.h:427

References LWLINE::bbox, COLLECTIONTYPE, LWLINE::flags, FLAGS_NDIMS, getPoint4d_p(), LW_FALSE, lwalloc(), lwcollection_add_lwgeom(), lwcollection_construct_empty(), lwerror(), lwfree(), lwgeom_has_m(), lwgeom_has_z(), lwgeom_refresh_bbox(), lwline_as_lwgeom(), lwline_construct(), lwpoint_as_lwgeom(), lwpoint_construct(), lwpoint_get_ordinate(), MULTILINETYPE, LWCOLLECTION::ngeoms, POINTARRAY::npoints, point_interpolate(), LWLINE::points, ptarray_append_point(), ptarray_construct(), ptarray_construct_empty(), ptarray_free(), ptarray_set_point4d(), r, LWLINE::srid, and LWCOLLECTION::type.

Referenced by lwgeom_clip_to_ordinate_range().

Here is the call graph for this function:
Here is the caller graph for this function: