PostGIS  3.0.6dev-r@@SVN_REVISION@@

◆ lwline_split_by_point_to()

int lwline_split_by_point_to ( const LWLINE ln,
const LWPOINT pt,
LWMLINE to 
)

Split a line by a point and push components to the provided multiline.

If the point doesn't split the line, push nothing to the container. Returns 0 if the point is off the line. Returns 1 if the point is on the line boundary (endpoints). Return 2 if the point is on the interior of the line (only case in which a split happens).

NOTE: the components pushed to the output vector have their SRID stripped

Definition at line 209 of file lwgeom_geos_split.c.

211 {
212  double mindist_sqr = -1;
213  POINT4D pt, pt_projected;
214  POINT4D p1, p2;
215  POINTARRAY *ipa = lwline_in->points;
216  POINTARRAY* pa1;
217  POINTARRAY* pa2;
218  uint32_t i, nsegs, seg = UINT32_MAX;
219 
220  /* Possible outcomes:
221  *
222  * 1. The point is not on the line or on the boundary
223  * -> Leave collection untouched, return 0
224  * 2. The point is on the boundary
225  * -> Leave collection untouched, return 1
226  * 3. The point is in the line
227  * -> Push 2 elements on the collection:
228  * o start_point - cut_point
229  * o cut_point - last_point
230  * -> Return 2
231  */
232 
233  getPoint4d_p(blade_in->point, 0, &pt);
234 
235  /* Find closest segment */
236  if ( ipa->npoints < 1 ) return 0; /* empty input line */
237  getPoint4d_p(ipa, 0, &p1);
238  nsegs = ipa->npoints - 1;
239  for ( i = 0; i < nsegs; i++ )
240  {
241  getPoint4d_p(ipa, i+1, &p2);
242  double dist_sqr = distance2d_sqr_pt_seg((POINT2D *)&pt, (POINT2D *)&p1, (POINT2D *)&p2);
243  LWDEBUGF(4, "Distance (squared) of point %g %g to segment %g %g, %g %g: %g",
244  pt.x, pt.y,
245  p1.x, p1.y,
246  p2.x, p2.y,
247  dist_sqr);
248  if (i == 0 || dist_sqr < mindist_sqr)
249  {
250  mindist_sqr = dist_sqr;
251  seg=i;
252  if (mindist_sqr == 0.0)
253  break; /* can't be closer than ON line */
254  }
255  p1 = p2;
256  }
257 
258  LWDEBUGF(3, "Closest segment: %d", seg);
259  LWDEBUGF(3, "mindist: %g", mindist_sqr);
260 
261  /* No intersection */
262  if (mindist_sqr > 0)
263  return 0;
264 
265  /* empty or single-point line, intersection on boundary */
266  if ( seg == UINT32_MAX ) return 1;
267 
268  /*
269  * We need to project the
270  * point on the closest segment,
271  * to interpolate Z and M if needed
272  */
273  getPoint4d_p(ipa, seg, &p1);
274  getPoint4d_p(ipa, seg+1, &p2);
275  closest_point_on_segment(&pt, &p1, &p2, &pt_projected);
276  /* But X and Y we want the ones of the input point,
277  * as on some architectures the interpolation math moves the
278  * coordinates (see #3422)
279  */
280  pt_projected.x = pt.x;
281  pt_projected.y = pt.y;
282 
283  LWDEBUGF(3, "Projected point:(%g %g), seg:%d, p1:(%g %g), p2:(%g %g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y);
284 
285  /* When closest point == an endpoint, this is a boundary intersection */
286  if ( ( (seg == nsegs-1) && p4d_same(&pt_projected, &p2) ) ||
287  ( (seg == 0) && p4d_same(&pt_projected, &p1) ) )
288  {
289  return 1;
290  }
291 
292  /* This is an internal intersection, let's build the two new pointarrays */
293 
294  pa1 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), seg+2);
295  /* TODO: replace with a memcpy ? */
296  for (i=0; i<=seg; ++i)
297  {
298  getPoint4d_p(ipa, i, &p1);
299  ptarray_append_point(pa1, &p1, LW_FALSE);
300  }
301  ptarray_append_point(pa1, &pt_projected, LW_FALSE);
302 
303  pa2 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-seg);
304  ptarray_append_point(pa2, &pt_projected, LW_FALSE);
305  /* TODO: replace with a memcpy (if so need to check for duplicated point) ? */
306  for (i=seg+1; i<ipa->npoints; ++i)
307  {
308  getPoint4d_p(ipa, i, &p1);
309  ptarray_append_point(pa2, &p1, LW_FALSE);
310  }
311 
312  /* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */
313  if ( pa1->npoints == 0 || pa2->npoints == 0 ) {
314  ptarray_free(pa1);
315  ptarray_free(pa2);
316  /* Intersection is on the boundary */
317  return 1;
318  }
319 
322  return 2;
323 }
#define LW_FALSE
Definition: liblwgeom.h:108
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:179
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:180
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
double distance2d_sqr_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B)
Definition: measures.c:2407
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:319
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
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:229
int p4d_same(const POINT4D *p1, const POINT4D *p2)
Definition: lwalgorithm.c:32
void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition: ptarray.c:1255
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define UINT32_MAX
Definition: lwin_wkt_lex.c:343
double y
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:400
double y
Definition: liblwgeom.h:400
lwflags_t flags
Definition: liblwgeom.h:417
uint32_t npoints
Definition: liblwgeom.h:413

References closest_point_on_segment(), distance2d_sqr_pt_seg(), POINTARRAY::flags, FLAGS_GET_M, FLAGS_GET_Z, getPoint4d_p(), LW_FALSE, LWDEBUGF, lwline_construct(), lwmline_add_lwline(), POINTARRAY::npoints, p4d_same(), LWPOINT::point, LWLINE::points, ptarray_append_point(), ptarray_construct_empty(), ptarray_free(), SRID_UNKNOWN, UINT32_MAX, POINT2D::x, POINT4D::x, POINT2D::y, and POINT4D::y.

Referenced by lwgeom_node(), lwline_split_by_mpoint(), lwline_split_by_point(), and test_lwline_split_by_point_to().

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