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

◆ lwgeom_cpa_within()

int lwgeom_cpa_within ( const LWGEOM g1,
const LWGEOM g2,
double  maxdist 
)

Is the closest point of approach within a distance ?

Returns
LW_TRUE or LW_FALSE

Definition at line 1305 of file lwlinearreferencing.c.

1306{
1307 LWLINE *l1, *l2;
1308 int i;
1309 GBOX gbox1, gbox2;
1310 double tmin, tmax;
1311 double *mvals;
1312 int nmvals = 0;
1313 double maxdist2 = maxdist * maxdist;
1314 int within = LW_FALSE;
1315
1316 if (!lwgeom_has_m(g1) || !lwgeom_has_m(g2))
1317 {
1318 lwerror("Both input geometries must have a measure dimension");
1319 return LW_FALSE;
1320 }
1321
1322 l1 = lwgeom_as_lwline(g1);
1323 l2 = lwgeom_as_lwline(g2);
1324
1325 if (!l1 || !l2)
1326 {
1327 lwerror("Both input geometries must be linestrings");
1328 return LW_FALSE;
1329 }
1330
1331 if (l1->points->npoints < 2 || l2->points->npoints < 2)
1332 {
1333 /* TODO: return distance between these two points */
1334 lwerror("Both input lines must have at least 2 points");
1335 return LW_FALSE;
1336 }
1337
1338 /* We use lwgeom_calculate_gbox() instead of lwgeom_get_gbox() */
1339 /* because we cannot afford the float rounding inaccuracy when */
1340 /* we compare the ranges for overlap below */
1341 lwgeom_calculate_gbox(g1, &gbox1);
1342 lwgeom_calculate_gbox(g2, &gbox2);
1343
1344 /*
1345 * Find overlapping M range
1346 * WARNING: may be larger than the real one
1347 */
1348
1349 tmin = FP_MAX(gbox1.mmin, gbox2.mmin);
1350 tmax = FP_MIN(gbox1.mmax, gbox2.mmax);
1351
1352 if (tmax < tmin)
1353 {
1354 LWDEBUG(1, "Inputs never exist at the same time");
1355 return LW_FALSE;
1356 }
1357
1358 /*
1359 * Collect M values in common time range from inputs
1360 */
1361
1362 mvals = lwalloc(sizeof(double) * (l1->points->npoints + l2->points->npoints));
1363
1364 /* TODO: also clip the lines ? */
1365 nmvals = ptarray_collect_mvals(l1->points, tmin, tmax, mvals);
1366 nmvals += ptarray_collect_mvals(l2->points, tmin, tmax, mvals + nmvals);
1367
1368 /* Sort values in ascending order */
1369 qsort(mvals, nmvals, sizeof(double), compare_double);
1370
1371 /* Remove duplicated values */
1372 nmvals = uniq(mvals, nmvals);
1373
1374 if (nmvals < 2)
1375 {
1376 /* there's a single time, must be that one... */
1377 double t0 = mvals[0];
1378 POINT4D p0, p1;
1379 LWDEBUGF(1, "Inputs only exist both at a single time (%g)", t0);
1380 if (-1 == ptarray_locate_along_linear(l1->points, t0, &p0, 0))
1381 {
1382 lwnotice("Could not find point with M=%g on first geom", t0);
1383 return LW_FALSE;
1384 }
1385 if (-1 == ptarray_locate_along_linear(l2->points, t0, &p1, 0))
1386 {
1387 lwnotice("Could not find point with M=%g on second geom", t0);
1388 return LW_FALSE;
1389 }
1390 if (distance3d_pt_pt((POINT3D *)&p0, (POINT3D *)&p1) <= maxdist)
1391 within = LW_TRUE;
1392 lwfree(mvals);
1393 return within;
1394 }
1395
1396 /*
1397 * For each consecutive pair of measures, compute time of closest point
1398 * approach and actual distance between points at that time
1399 */
1400 for (i = 1; i < nmvals; ++i)
1401 {
1402 double t0 = mvals[i - 1];
1403 double t1 = mvals[i];
1404#if POSTGIS_DEBUG_LEVEL >= 1
1405 double t;
1406#endif
1407 POINT4D p0, p1, q0, q1;
1408 int seg;
1409 double dist2;
1410
1411 // lwnotice("T %g-%g", t0, t1);
1412
1413 seg = ptarray_locate_along_linear(l1->points, t0, &p0, 0);
1414 if (-1 == seg)
1415 continue; /* possible, if GBOX is approximated */
1416 // lwnotice("Measure %g on segment %d of line 1: %g, %g, %g", t0, seg, p0.x, p0.y, p0.z);
1417
1418 seg = ptarray_locate_along_linear(l1->points, t1, &p1, seg);
1419 if (-1 == seg)
1420 continue; /* possible, if GBOX is approximated */
1421 // lwnotice("Measure %g on segment %d of line 1: %g, %g, %g", t1, seg, p1.x, p1.y, p1.z);
1422
1423 seg = ptarray_locate_along_linear(l2->points, t0, &q0, 0);
1424 if (-1 == seg)
1425 continue; /* possible, if GBOX is approximated */
1426 // lwnotice("Measure %g on segment %d of line 2: %g, %g, %g", t0, seg, q0.x, q0.y, q0.z);
1427
1428 seg = ptarray_locate_along_linear(l2->points, t1, &q1, seg);
1429 if (-1 == seg)
1430 continue; /* possible, if GBOX is approximated */
1431 // lwnotice("Measure %g on segment %d of line 2: %g, %g, %g", t1, seg, q1.x, q1.y, q1.z);
1432
1433#if POSTGIS_DEBUG_LEVEL >= 1
1434 t =
1435#endif
1436 segments_tcpa(&p0, &p1, &q0, &q1, t0, t1);
1437
1438 /*
1439 lwnotice("Closest points: %g,%g,%g and %g,%g,%g at time %g",
1440 p0.x, p0.y, p0.z,
1441 q0.x, q0.y, q0.z, t);
1442 */
1443
1444 dist2 = (q0.x - p0.x) * (q0.x - p0.x) + (q0.y - p0.y) * (q0.y - p0.y) + (q0.z - p0.z) * (q0.z - p0.z);
1445 if (dist2 <= maxdist2)
1446 {
1447 LWDEBUGF(1, "Within distance %g at time %g, breaking", sqrt(dist2), t);
1448 within = LW_TRUE;
1449 break;
1450 }
1451 }
1452
1453 /*
1454 * Release memory
1455 */
1456
1457 lwfree(mvals);
1458
1459 return within;
1460}
#define LW_FALSE
Definition liblwgeom.h:94
void * lwalloc(size_t size)
Definition lwutil.c:227
double distance3d_pt_pt(const POINT3D *p1, const POINT3D *p2)
void lwfree(void *mem)
Definition lwutil.c:248
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition lwgeom.c:783
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
#define FP_MAX(A, B)
#define FP_MIN(A, B)
Datum within(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static int ptarray_collect_mvals(const POINTARRAY *pa, double tmin, double tmax, double *mvals)
static int compare_double(const void *pa, const void *pb)
static double segments_tcpa(POINT4D *p0, const POINT4D *p1, POINT4D *q0, const POINT4D *q1, double t0, double t1)
static int ptarray_locate_along_linear(const POINTARRAY *pa, double m, POINT4D *p, uint32_t from)
static int uniq(double *vals, int nvals)
double mmax
Definition liblwgeom.h:361
double mmin
Definition liblwgeom.h:360
POINTARRAY * points
Definition liblwgeom.h:483
double x
Definition liblwgeom.h:414
double z
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
uint32_t npoints
Definition liblwgeom.h:427

References compare_double(), distance3d_pt_pt(), FP_MAX, FP_MIN, LW_FALSE, LW_TRUE, lwalloc(), LWDEBUG, LWDEBUGF, lwerror(), lwfree(), lwgeom_as_lwline(), lwgeom_calculate_gbox(), lwgeom_has_m(), lwnotice(), GBOX::mmax, GBOX::mmin, POINTARRAY::npoints, LWLINE::points, ptarray_collect_mvals(), ptarray_locate_along_linear(), segments_tcpa(), uniq(), within(), POINT4D::x, POINT4D::y, and POINT4D::z.

Referenced by ST_CPAWithin(), and test_lwgeom_tcpa().

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