PostGIS  3.1.6dev-r@@SVN_REVISION@@

◆ 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 1545 of file measures.c.

1552 {
1553  POINT2D CA, CB; /* Center points of arcs A and B */
1554  double radius_A, radius_B, d; /* Radii of arcs A and B */
1555  POINT2D D; /* Mid-point between the centers CA and CB */
1556  int pt_in_arc_A, pt_in_arc_B; /* Test whether potential intersection point is within the arc */
1557 
1558  if (dl->mode != DIST_MIN)
1559  lwerror("lw_dist2d_arc_arc only supports mindistance");
1560 
1561  /* TODO: Handle case where arc is closed circle (A1 = A3) */
1562 
1563  /* What if one or both of our "arcs" is actually a point? */
1564  if (lw_arc_is_pt(B1, B2, B3) && lw_arc_is_pt(A1, A2, A3))
1565  return lw_dist2d_pt_pt(B1, A1, dl);
1566  else if (lw_arc_is_pt(B1, B2, B3))
1567  return lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1568  else if (lw_arc_is_pt(A1, A2, A3))
1569  return lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1570 
1571  /* Calculate centers and radii of circles. */
1572  radius_A = lw_arc_center(A1, A2, A3, &CA);
1573  radius_B = lw_arc_center(B1, B2, B3, &CB);
1574 
1575  /* Two co-linear arcs?!? That's two segments. */
1576  if (radius_A < 0 && radius_B < 0)
1577  return lw_dist2d_seg_seg(A1, A3, B1, B3, dl);
1578 
1579  /* A is co-linear, delegate to lw_dist_seg_arc here. */
1580  if (radius_A < 0)
1581  return lw_dist2d_seg_arc(A1, A3, B1, B2, B3, dl);
1582 
1583  /* B is co-linear, delegate to lw_dist_seg_arc here. */
1584  if (radius_B < 0)
1585  return lw_dist2d_seg_arc(B1, B3, A1, A2, A3, dl);
1586 
1587  /* Center-center distance */
1588  d = distance2d_pt_pt(&CA, &CB);
1589 
1590  /* Concentric arcs */
1591  if (FP_EQUALS(d, 0.0))
1592  return lw_dist2d_arc_arc_concentric(A1, A2, A3, radius_A, B1, B2, B3, radius_B, &CA, dl);
1593 
1594  /* Make sure that arc "A" has the bigger radius */
1595  if (radius_B > radius_A)
1596  {
1597  const POINT2D *tmp;
1598  POINT2D TP; /* Temporary point P */
1599  double td;
1600  tmp = B1;
1601  B1 = A1;
1602  A1 = tmp;
1603  tmp = B2;
1604  B2 = A2;
1605  A2 = tmp;
1606  tmp = B3;
1607  B3 = A3;
1608  A3 = tmp;
1609  TP = CB;
1610  CB = CA;
1611  CA = TP;
1612  td = radius_B;
1613  radius_B = radius_A;
1614  radius_A = td;
1615  }
1616 
1617  /* Circles touch at a point. Is that point within the arcs? */
1618  if (d == (radius_A + radius_B))
1619  {
1620  D.x = CA.x + (CB.x - CA.x) * radius_A / d;
1621  D.y = CA.y + (CB.y - CA.y) * radius_A / d;
1622 
1623  pt_in_arc_A = lw_pt_in_arc(&D, A1, A2, A3);
1624  pt_in_arc_B = lw_pt_in_arc(&D, B1, B2, B3);
1625 
1626  /* Arcs do touch at D, return it */
1627  if (pt_in_arc_A && pt_in_arc_B)
1628  {
1629  lw_dist2d_distpts_set(dl, 0.0, &D, &D);
1630  return LW_TRUE;
1631  }
1632  }
1633  /* Disjoint or contained circles don't intersect. Closest point may be on */
1634  /* the line joining CA to CB. */
1635  else if (d > (radius_A + radius_B) /* Disjoint */ || d < (radius_A - radius_B) /* Contained */)
1636  {
1637  POINT2D XA, XB; /* Points where the line from CA to CB cross their circle bounds */
1638 
1639  /* Calculate hypothetical nearest points, the places on the */
1640  /* two circles where the center-center line crosses. If both */
1641  /* arcs contain their hypothetical points, that's the crossing distance */
1642  XA.x = CA.x + (CB.x - CA.x) * radius_A / d;
1643  XA.y = CA.y + (CB.y - CA.y) * radius_A / d;
1644  XB.x = CB.x + (CA.x - CB.x) * radius_B / d;
1645  XB.y = CB.y + (CA.y - CB.y) * radius_B / d;
1646 
1647  pt_in_arc_A = lw_pt_in_arc(&XA, A1, A2, A3);
1648  pt_in_arc_B = lw_pt_in_arc(&XB, B1, B2, B3);
1649 
1650  /* If the nearest points are both within the arcs, that's our answer */
1651  /* the shortest distance is at the nearest points */
1652  if (pt_in_arc_A && pt_in_arc_B)
1653  {
1654  return lw_dist2d_pt_pt(&XA, &XB, dl);
1655  }
1656  }
1657  /* Circles cross at two points, are either of those points in both arcs? */
1658  /* http://paulbourke.net/geometry/2circle/ */
1659  else if (d < (radius_A + radius_B))
1660  {
1661  POINT2D E, F; /* Points where circle(A) and circle(B) cross */
1662  /* Distance from CA to D */
1663  double a = (radius_A * radius_A - radius_B * radius_B + d * d) / (2 * d);
1664  /* Distance from D to E or F */
1665  double h = sqrt(radius_A * radius_A - a * a);
1666 
1667  /* Location of D */
1668  D.x = CA.x + (CB.x - CA.x) * a / d;
1669  D.y = CA.y + (CB.y - CA.y) * a / d;
1670 
1671  /* Start from D and project h units perpendicular to CA-D to get E */
1672  E.x = D.x + (D.y - CA.y) * h / a;
1673  E.y = D.y + (D.x - CA.x) * h / a;
1674 
1675  /* Crossing point E contained in arcs? */
1676  pt_in_arc_A = lw_pt_in_arc(&E, A1, A2, A3);
1677  pt_in_arc_B = lw_pt_in_arc(&E, B1, B2, B3);
1678 
1679  if (pt_in_arc_A && pt_in_arc_B)
1680  {
1681  lw_dist2d_distpts_set(dl, 0.0, &E, &E);
1682  return LW_TRUE;
1683  }
1684 
1685  /* Start from D and project h units perpendicular to CA-D to get F */
1686  F.x = D.x - (D.y - CA.y) * h / a;
1687  F.y = D.y - (D.x - CA.x) * h / a;
1688 
1689  /* Crossing point F contained in arcs? */
1690  pt_in_arc_A = lw_pt_in_arc(&F, A1, A2, A3);
1691  pt_in_arc_B = lw_pt_in_arc(&F, B1, B2, B3);
1692 
1693  if (pt_in_arc_A && pt_in_arc_B)
1694  {
1695  lw_dist2d_distpts_set(dl, 0.0, &F, &F);
1696  return LW_TRUE;
1697  }
1698  }
1699  else
1700  {
1701  lwerror("lw_dist2d_arc_arc: arcs neither touch, intersect nor are disjoint! INCONCEIVABLE!");
1702  return LW_FALSE;
1703  }
1704 
1705  /* Closest point is in the arc A, but not in the arc B, so */
1706  /* one of the B end points must be the closest. */
1707  if (pt_in_arc_A && !pt_in_arc_B)
1708  {
1709  lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1710  lw_dist2d_pt_arc(B3, A1, A2, A3, dl);
1711  return LW_TRUE;
1712  }
1713  /* Closest point is in the arc B, but not in the arc A, so */
1714  /* one of the A end points must be the closest. */
1715  else if (pt_in_arc_B && !pt_in_arc_A)
1716  {
1717  lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1718  lw_dist2d_pt_arc(A3, B1, B2, B3, dl);
1719  return LW_TRUE;
1720  }
1721  /* Finally, one of the end-point to end-point combos is the closest. */
1722  else
1723  {
1724  lw_dist2d_pt_pt(A1, B1, dl);
1725  lw_dist2d_pt_pt(A1, B3, dl);
1726  lw_dist2d_pt_pt(A3, B1, dl);
1727  lw_dist2d_pt_pt(A3, B3, dl);
1728  return LW_TRUE;
1729  }
1730 
1731  return LW_TRUE;
1732 }
#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.
Definition: lwalgorithm.c:229
#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) .
Definition: lwalgorithm.c:106
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:2340
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition: measures.c:1484
static void lw_dist2d_distpts_set(DISTPTS *dl, double distance, const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:78
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:1735
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:1863
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:1340
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:2308
#define DIST_MIN
Definition: measures.h:44
int mode
Definition: measures.h:54
double y
Definition: liblwgeom.h:404
double x
Definition: liblwgeom.h:404

References DIST_MIN, distance2d_pt_pt(), FP_EQUALS, lw_arc_center(), lw_arc_is_pt(), lw_dist2d_arc_arc_concentric(), lw_dist2d_distpts_set(), 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, 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: