PostGIS  3.0.6dev-r@@SVN_REVISION@@

◆ 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 1311 of file lwlinearreferencing.c.

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

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: