PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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:735
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
#define MULTILINETYPE
Definition liblwgeom.h:106
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
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
void * lwalloc(size_t size)
Definition lwutil.c:227
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
void lwfree(void *mem)
Definition lwutil.c:248
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:179
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
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
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
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.
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition lwgeom_api.c:369
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
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: