PostGIS 3.0.6dev-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 540 of file lwlinearreferencing.c.

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

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: