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

◆ lw_dist2d_seg_arc()

int lw_dist2d_seg_arc ( const POINT2D A1,
const POINT2D A2,
const POINT2D B1,
const POINT2D B2,
const POINT2D B3,
DISTPTS dl 
)

Calculate the shortest distance between an arc and an edge.

Line/circle approach from http://stackoverflow.com/questions/1073336/circle-line-collision-detection

Definition at line 1351 of file measures.c.

1357{
1358 POINT2D C; /* center of arc circle */
1359 double radius_C; /* radius of arc circle */
1360 POINT2D D; /* point on A closest to C */
1361 double dist_C_D; /* distance from C to D */
1362 int pt_in_arc, pt_in_seg;
1363 DISTPTS dltmp;
1364
1365 /* Bail out on crazy modes */
1366 if (dl->mode < 0)
1367 lwerror("lw_dist2d_seg_arc does not support maxdistance mode");
1368
1369 /* What if the "arc" is a point? */
1370 if (lw_arc_is_pt(B1, B2, B3))
1371 return lw_dist2d_pt_seg(B1, A1, A2, dl);
1372
1373 /* Calculate center and radius of the circle. */
1374 radius_C = lw_arc_center(B1, B2, B3, &C);
1375
1376 /* This "arc" is actually a line (B2 is collinear with B1,B3) */
1377 if (radius_C < 0.0)
1378 return lw_dist2d_seg_seg(A1, A2, B1, B3, dl);
1379
1380 /* Calculate distance between the line and circle center */
1382 if (lw_dist2d_pt_seg(&C, A1, A2, &dltmp) == LW_FALSE)
1383 lwerror("lw_dist2d_pt_seg failed in lw_dist2d_seg_arc");
1384
1385 D = dltmp.p1;
1386 dist_C_D = dltmp.distance;
1387
1388 /* Line intersects circle, maybe arc intersects edge? */
1389 /* If so, that's the closest point. */
1390 /* If not, the closest point is one of the end points of A */
1391 if (dist_C_D < radius_C)
1392 {
1393 double length_A; /* length of the segment A */
1394 POINT2D E, F; /* points of intersection of edge A and circle(B) */
1395 double dist_D_EF; /* distance from D to E or F (same distance both ways) */
1396
1397 dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D);
1398 length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y));
1399
1400 /* Point of intersection E */
1401 E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A;
1402 E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A;
1403 /* Point of intersection F */
1404 F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A;
1405 F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A;
1406
1407 /* If E is within A and within B then it's an intersection point */
1408 pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3);
1409 pt_in_seg = lw_pt_in_seg(&E, A1, A2);
1410
1411 if (pt_in_arc && pt_in_seg)
1412 {
1413 lw_dist2d_distpts_set(dl, 0.0, &E, &E);
1414 return LW_TRUE;
1415 }
1416
1417 /* If F is within A and within B then it's an intersection point */
1418 pt_in_arc = lw_pt_in_arc(&F, B1, B2, B3);
1419 pt_in_seg = lw_pt_in_seg(&F, A1, A2);
1420
1421 if (pt_in_arc && pt_in_seg)
1422 {
1423 lw_dist2d_distpts_set(dl, 0.0, &F, &F);
1424 return LW_TRUE;
1425 }
1426 }
1427
1428 /* Line grazes circle, maybe arc intersects edge? */
1429 /* If so, grazing point is the closest point. */
1430 /* If not, the closest point is one of the end points of A */
1431 else if (dist_C_D == radius_C)
1432 {
1433 /* Closest point D is also the point of grazing */
1434 pt_in_arc = lw_pt_in_arc(&D, B1, B2, B3);
1435 pt_in_seg = lw_pt_in_seg(&D, A1, A2);
1436
1437 /* Is D contained in both A and B? */
1438 if (pt_in_arc && pt_in_seg)
1439 {
1440 lw_dist2d_distpts_set(dl, 0.0, &D, &D);
1441 return LW_TRUE;
1442 }
1443 }
1444 /* Line misses circle. */
1445 /* If closest point to A on circle is within B, then that's the closest */
1446 /* Otherwise, the closest point will be an end point of A */
1447 else
1448 {
1449 POINT2D G; /* Point on circle closest to A */
1450 G.x = C.x + (D.x - C.x) * radius_C / dist_C_D;
1451 G.y = C.y + (D.y - C.y) * radius_C / dist_C_D;
1452
1453 pt_in_arc = lw_pt_in_arc(&G, B1, B2, B3);
1454 pt_in_seg = lw_pt_in_seg(&D, A1, A2);
1455
1456 /* Closest point is on the interior of A and B */
1457 if (pt_in_arc && pt_in_seg)
1458 return lw_dist2d_pt_pt(&D, &G, dl);
1459 }
1460
1461 /* Now we test the many combinations of end points with either */
1462 /* arcs or edges. Each previous check determined if the closest */
1463 /* potential point was within the arc/segment inscribed on the */
1464 /* line/circle holding the arc/segment. */
1465
1466 /* Closest point is in the arc, but not in the segment, so */
1467 /* one of the segment end points must be the closest. */
1468 if (pt_in_arc && !pt_in_seg)
1469 {
1470 lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1471 lw_dist2d_pt_arc(A2, B1, B2, B3, dl);
1472 return LW_TRUE;
1473 }
1474 /* or, one of the arc end points is the closest */
1475 else if (pt_in_seg && !pt_in_arc)
1476 {
1477 lw_dist2d_pt_seg(B1, A1, A2, dl);
1478 lw_dist2d_pt_seg(B3, A1, A2, dl);
1479 return LW_TRUE;
1480 }
1481 /* Finally, one of the end-point to end-point combos is the closest. */
1482 else
1483 {
1484 lw_dist2d_pt_pt(A1, B1, dl);
1485 lw_dist2d_pt_pt(A1, B3, dl);
1486 lw_dist2d_pt_pt(A2, B1, dl);
1487 lw_dist2d_pt_pt(A2, B3, dl);
1488 return LW_TRUE;
1489 }
1490
1491 return LW_FALSE;
1492}
#define LW_FALSE
Definition liblwgeom.h:94
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
int lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if P is on the same side of the plane partition defined by A1/A3 as A2 is.
Definition lwalgorithm.c:91
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition measures.c:1495
static void lw_dist2d_distpts_set(DISTPTS *dl, double distance, const POINT2D *p1, const POINT2D *p2)
Definition measures.c:81
int lw_dist2d_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B, DISTPTS *dl)
lw_dist2d_comp from p to line A->B This one is now sending every occasion to lw_dist2d_pt_pt Before i...
Definition measures.c:2217
int lw_dist2d_seg_seg(const POINT2D *A, const POINT2D *B, const POINT2D *C, const POINT2D *D, DISTPTS *dl)
Finds the shortest distance between two segments.
Definition measures.c:1830
void lw_dist2d_distpts_init(DISTPTS *dl, int mode)
Definition measures.c:67
int lw_dist2d_pt_pt(const POINT2D *thep1, const POINT2D *thep2, DISTPTS *dl)
Compares incoming points and stores the points closest to each other or most far away from each other...
Definition measures.c:2312
#define DIST_MIN
Definition measures.h:44
POINT2D p1
Definition measures.h:52
int mode
Definition measures.h:54
double distance
Definition measures.h:51
Structure used in distance-calculations.
Definition measures.h:50
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390

References DIST_MIN, DISTPTS::distance, lw_arc_center(), lw_arc_is_pt(), lw_dist2d_distpts_init(), lw_dist2d_distpts_set(), lw_dist2d_pt_arc(), lw_dist2d_pt_pt(), lw_dist2d_pt_seg(), lw_dist2d_seg_seg(), LW_FALSE, lw_pt_in_arc(), lw_pt_in_seg(), LW_TRUE, lwerror(), DISTPTS::mode, DISTPTS::p1, POINT2D::x, and POINT2D::y.

Referenced by lw_dist2d_arc_arc(), lw_dist2d_ptarray_ptarrayarc(), rect_leaf_node_distance(), rect_leaf_node_intersects(), and test_lw_dist2d_seg_arc().

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