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

◆ lw_dist2d_arc_arc()

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

Definition at line 1575 of file measures.c.

1582{
1583 POINT2D CA, CB; /* Center points of arcs A and B */
1584 double radius_A, radius_B, d; /* Radii of arcs A and B */
1585 POINT2D D; /* Mid-point between the centers CA and CB */
1586 int pt_in_arc_A, pt_in_arc_B; /* Test whether potential intersection point is within the arc */
1587
1588 if (dl->mode != DIST_MIN)
1589 lwerror("lw_dist2d_arc_arc only supports mindistance");
1590
1591 /* TODO: Handle case where arc is closed circle (A1 = A3) */
1592
1593 /* What if one or both of our "arcs" is actually a point? */
1594 if (lw_arc_is_pt(B1, B2, B3) && lw_arc_is_pt(A1, A2, A3))
1595 return lw_dist2d_pt_pt(B1, A1, dl);
1596 else if (lw_arc_is_pt(B1, B2, B3))
1597 return lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1598 else if (lw_arc_is_pt(A1, A2, A3))
1599 return lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1600
1601 /* Calculate centers and radii of circles. */
1602 radius_A = lw_arc_center(A1, A2, A3, &CA);
1603 radius_B = lw_arc_center(B1, B2, B3, &CB);
1604
1605 /* Two co-linear arcs?!? That's two segments. */
1606 if (radius_A < 0 && radius_B < 0)
1607 return lw_dist2d_seg_seg(A1, A3, B1, B3, dl);
1608
1609 /* A is co-linear, delegate to lw_dist_seg_arc here. */
1610 if (radius_A < 0)
1611 return lw_dist2d_seg_arc(A1, A3, B1, B2, B3, dl);
1612
1613 /* B is co-linear, delegate to lw_dist_seg_arc here. */
1614 if (radius_B < 0)
1615 return lw_dist2d_seg_arc(B1, B3, A1, A2, A3, dl);
1616
1617 /* Center-center distance */
1618 d = distance2d_pt_pt(&CA, &CB);
1619
1620 /* Concentric arcs */
1621 if (FP_EQUALS(d, 0.0))
1622 return lw_dist2d_arc_arc_concentric(A1, A2, A3, radius_A, B1, B2, B3, radius_B, &CA, dl);
1623
1624 /* Make sure that arc "A" has the bigger radius */
1625 if (radius_B > radius_A)
1626 {
1627 const POINT2D *tmp;
1628 POINT2D TP; /* Temporary point P */
1629 double td;
1630 tmp = B1;
1631 B1 = A1;
1632 A1 = tmp;
1633 tmp = B2;
1634 B2 = A2;
1635 A2 = tmp;
1636 tmp = B3;
1637 B3 = A3;
1638 A3 = tmp;
1639 TP = CB;
1640 CB = CA;
1641 CA = TP;
1642 td = radius_B;
1643 radius_B = radius_A;
1644 radius_A = td;
1645 }
1646
1647 /* Circles touch at a point. Is that point within the arcs? */
1648 if (d == (radius_A + radius_B))
1649 {
1650 D.x = CA.x + (CB.x - CA.x) * radius_A / d;
1651 D.y = CA.y + (CB.y - CA.y) * radius_A / d;
1652
1653 pt_in_arc_A = lw_pt_in_arc(&D, A1, A2, A3);
1654 pt_in_arc_B = lw_pt_in_arc(&D, B1, B2, B3);
1655
1656 /* Arcs do touch at D, return it */
1657 if (pt_in_arc_A && pt_in_arc_B)
1658 {
1659 dl->distance = 0.0;
1660 dl->p1 = D;
1661 dl->p2 = D;
1662 return LW_TRUE;
1663 }
1664 }
1665 /* Disjoint or contained circles don't intersect. Closest point may be on */
1666 /* the line joining CA to CB. */
1667 else if (d > (radius_A + radius_B) /* Disjoint */ || d < (radius_A - radius_B) /* Contained */)
1668 {
1669 POINT2D XA, XB; /* Points where the line from CA to CB cross their circle bounds */
1670
1671 /* Calculate hypothetical nearest points, the places on the */
1672 /* two circles where the center-center line crosses. If both */
1673 /* arcs contain their hypothetical points, that's the crossing distance */
1674 XA.x = CA.x + (CB.x - CA.x) * radius_A / d;
1675 XA.y = CA.y + (CB.y - CA.y) * radius_A / d;
1676 XB.x = CB.x + (CA.x - CB.x) * radius_B / d;
1677 XB.y = CB.y + (CA.y - CB.y) * radius_B / d;
1678
1679 pt_in_arc_A = lw_pt_in_arc(&XA, A1, A2, A3);
1680 pt_in_arc_B = lw_pt_in_arc(&XB, B1, B2, B3);
1681
1682 /* If the nearest points are both within the arcs, that's our answer */
1683 /* the shortest distance is at the nearest points */
1684 if (pt_in_arc_A && pt_in_arc_B)
1685 {
1686 return lw_dist2d_pt_pt(&XA, &XB, dl);
1687 }
1688 }
1689 /* Circles cross at two points, are either of those points in both arcs? */
1690 /* http://paulbourke.net/geometry/2circle/ */
1691 else if (d < (radius_A + radius_B))
1692 {
1693 POINT2D E, F; /* Points where circle(A) and circle(B) cross */
1694 /* Distance from CA to D */
1695 double a = (radius_A * radius_A - radius_B * radius_B + d * d) / (2 * d);
1696 /* Distance from D to E or F */
1697 double h = sqrt(radius_A * radius_A - a * a);
1698
1699 /* Location of D */
1700 D.x = CA.x + (CB.x - CA.x) * a / d;
1701 D.y = CA.y + (CB.y - CA.y) * a / d;
1702
1703 /* Start from D and project h units perpendicular to CA-D to get E */
1704 E.x = D.x + (D.y - CA.y) * h / a;
1705 E.y = D.y + (D.x - CA.x) * h / a;
1706
1707 /* Crossing point E contained in arcs? */
1708 pt_in_arc_A = lw_pt_in_arc(&E, A1, A2, A3);
1709 pt_in_arc_B = lw_pt_in_arc(&E, B1, B2, B3);
1710
1711 if (pt_in_arc_A && pt_in_arc_B)
1712 {
1713 dl->p1 = dl->p2 = E;
1714 dl->distance = 0.0;
1715 return LW_TRUE;
1716 }
1717
1718 /* Start from D and project h units perpendicular to CA-D to get F */
1719 F.x = D.x - (D.y - CA.y) * h / a;
1720 F.y = D.y - (D.x - CA.x) * h / a;
1721
1722 /* Crossing point F contained in arcs? */
1723 pt_in_arc_A = lw_pt_in_arc(&F, A1, A2, A3);
1724 pt_in_arc_B = lw_pt_in_arc(&F, B1, B2, B3);
1725
1726 if (pt_in_arc_A && pt_in_arc_B)
1727 {
1728 dl->p1 = dl->p2 = F;
1729 dl->distance = 0.0;
1730 return LW_TRUE;
1731 }
1732 }
1733 else
1734 {
1735 lwerror("lw_dist2d_arc_arc: arcs neither touch, intersect nor are disjoint! INCONCEIVABLE!");
1736 return LW_FALSE;
1737 }
1738
1739 /* Closest point is in the arc A, but not in the arc B, so */
1740 /* one of the B end points must be the closest. */
1741 if (pt_in_arc_A && !pt_in_arc_B)
1742 {
1743 lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1744 lw_dist2d_pt_arc(B3, A1, A2, A3, dl);
1745 return LW_TRUE;
1746 }
1747 /* Closest point is in the arc B, but not in the arc A, so */
1748 /* one of the A end points must be the closest. */
1749 else if (pt_in_arc_B && !pt_in_arc_A)
1750 {
1751 lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1752 lw_dist2d_pt_arc(A3, B1, B2, B3, dl);
1753 return LW_TRUE;
1754 }
1755 /* Finally, one of the end-point to end-point combos is the closest. */
1756 else
1757 {
1758 lw_dist2d_pt_pt(A1, B1, dl);
1759 lw_dist2d_pt_pt(A1, B3, dl);
1760 lw_dist2d_pt_pt(A3, B1, dl);
1761 lw_dist2d_pt_pt(A3, B3, dl);
1762 return LW_TRUE;
1763 }
1764
1765 return LW_TRUE;
1766}
#define LW_FALSE
Definition liblwgeom.h:108
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
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.
#define FP_EQUALS(A, B)
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:86
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition lwutil.c:190
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition measures.c:2397
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition measures.c:1512
int lw_dist2d_arc_arc_concentric(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, double radius_A, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, double radius_B, const POINT2D *CENTER, DISTPTS *dl)
Definition measures.c:1769
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:1916
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.
Definition measures.c:1362
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:2365
#define DIST_MIN
Definition measures.h:44
POINT2D p1
Definition measures.h:52
POINT2D p2
Definition measures.h:53
int mode
Definition measures.h:54
double distance
Definition measures.h:51
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376

References DIST_MIN, DISTPTS::distance, distance2d_pt_pt(), FP_EQUALS, lw_arc_center(), lw_arc_is_pt(), lw_dist2d_arc_arc_concentric(), lw_dist2d_pt_arc(), lw_dist2d_pt_pt(), lw_dist2d_seg_arc(), lw_dist2d_seg_seg(), LW_FALSE, lw_pt_in_arc(), LW_TRUE, lwerror(), DISTPTS::mode, DISTPTS::p1, DISTPTS::p2, POINT2D::x, and POINT2D::y.

Referenced by lw_dist2d_ptarrayarc_ptarrayarc(), rect_leaf_node_distance(), rect_leaf_node_intersects(), and test_lw_dist2d_arc_arc().

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