PostGIS  2.2.7dev-r@@SVN_REVISION@@
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 1479 of file measures.c.

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(), and test_lw_dist2d_arc_arc().

1482 {
1483  POINT2D CA, CB; /* Center points of arcs A and B */
1484  double radius_A, radius_B, d; /* Radii of arcs A and B */
1485  POINT2D P; /* Temporary point P */
1486  POINT2D D; /* Mid-point between the centers CA and CB */
1487  int pt_in_arc_A, pt_in_arc_B; /* Test whether potential intersection point is within the arc */
1488 
1489  if ( dl->mode != DIST_MIN )
1490  lwerror("lw_dist2d_arc_arc only supports mindistance");
1491 
1492  /* TODO: Handle case where arc is closed circle (A1 = A3) */
1493 
1494  /* What if one or both of our "arcs" is actually a point? */
1495  if ( lw_arc_is_pt(B1, B2, B3) && lw_arc_is_pt(A1, A2, A3) )
1496  return lw_dist2d_pt_pt(B1, A1, dl);
1497  else if ( lw_arc_is_pt(B1, B2, B3) )
1498  return lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1499  else if ( lw_arc_is_pt(A1, A2, A3) )
1500  return lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1501 
1502  /* Calculate centers and radii of circles. */
1503  radius_A = lw_arc_center(A1, A2, A3, &CA);
1504  radius_B = lw_arc_center(B1, B2, B3, &CB);
1505 
1506  /* Two co-linear arcs?!? That's two segments. */
1507  if ( radius_A < 0 && radius_B < 0 )
1508  return lw_dist2d_seg_seg(A1, A3, B1, B3, dl);
1509 
1510  /* A is co-linear, delegate to lw_dist_seg_arc here. */
1511  if ( radius_A < 0 )
1512  return lw_dist2d_seg_arc(A1, A3, B1, B2, B3, dl);
1513 
1514  /* B is co-linear, delegate to lw_dist_seg_arc here. */
1515  if ( radius_B < 0 )
1516  return lw_dist2d_seg_arc(B1, B3, A1, A2, A3, dl);
1517 
1518  /* Center-center distance */
1519  d = distance2d_pt_pt(&CA, &CB);
1520 
1521  /* Concentric arcs */
1522  if ( FP_EQUALS(d, 0.0) )
1523  return lw_dist2d_arc_arc_concentric(A1, A2, A3, radius_A,
1524  B1, B2, B3, radius_B,
1525  &CA, dl);
1526 
1527  /* Make sure that arc "A" has the bigger radius */
1528  if ( radius_B > radius_A )
1529  {
1530  const POINT2D *tmp;
1531  tmp = B1; B1 = A1; A1 = tmp;
1532  tmp = B2; B2 = A2; A2 = tmp;
1533  tmp = B3; B3 = A3; A3 = tmp;
1534  P = CB; CB = CA; CA = P;
1535  d = radius_B; radius_B = radius_A; radius_A = d;
1536  }
1537 
1538  /* Circles touch at a point. Is that point within the arcs? */
1539  if ( d == (radius_A + radius_B) )
1540  {
1541  D.x = CA.x + (CB.x - CA.x) * radius_A / d;
1542  D.y = CA.y + (CB.y - CA.y) * radius_A / d;
1543 
1544  pt_in_arc_A = lw_pt_in_arc(&D, A1, A2, A3);
1545  pt_in_arc_B = lw_pt_in_arc(&D, B1, B2, B3);
1546 
1547  /* Arcs do touch at D, return it */
1548  if ( pt_in_arc_A && pt_in_arc_B )
1549  {
1550  dl->distance = 0.0;
1551  dl->p1 = D;
1552  dl->p2 = D;
1553  return LW_TRUE;
1554  }
1555  }
1556  /* Disjoint or contained circles don't intersect. Closest point may be on */
1557  /* the line joining CA to CB. */
1558  else if ( d > (radius_A + radius_B) /* Disjoint */ || d < (radius_A - radius_B) /* Contained */ )
1559  {
1560  POINT2D XA, XB; /* Points where the line from CA to CB cross their circle bounds */
1561 
1562  /* Calculate hypothetical nearest points, the places on the */
1563  /* two circles where the center-center line crosses. If both */
1564  /* arcs contain their hypothetical points, that's the crossing distance */
1565  XA.x = CA.x + (CB.x - CA.x) * radius_A / d;
1566  XA.y = CA.y + (CB.y - CA.y) * radius_A / d;
1567  XB.x = CB.x + (CA.x - CB.x) * radius_B / d;
1568  XB.y = CB.y + (CA.y - CB.y) * radius_B / d;
1569 
1570  pt_in_arc_A = lw_pt_in_arc(&XA, A1, A2, A3);
1571  pt_in_arc_B = lw_pt_in_arc(&XB, B1, B2, B3);
1572 
1573  /* If the nearest points are both within the arcs, that's our answer */
1574  /* the shortest distance is at the nearest points */
1575  if ( pt_in_arc_A && pt_in_arc_B )
1576  {
1577  return lw_dist2d_pt_pt(&XA, &XB, dl);
1578  }
1579  }
1580  /* Circles cross at two points, are either of those points in both arcs? */
1581  /* http://paulbourke.net/geometry/2circle/ */
1582  else if ( d < (radius_A + radius_B) )
1583  {
1584  POINT2D E, F; /* Points where circle(A) and circle(B) cross */
1585  /* Distance from CA to D */
1586  double a = (radius_A*radius_A - radius_B*radius_B + d*d) / (2*d);
1587  /* Distance from D to E or F */
1588  double h = sqrt(radius_A*radius_A - a*a);
1589 
1590  /* Location of D */
1591  D.x = CA.x + (CB.x - CA.x) * a / d;
1592  D.y = CA.y + (CB.y - CA.y) * a / d;
1593 
1594  /* Start from D and project h units perpendicular to CA-D to get E */
1595  E.x = D.x + (D.y - CA.y) * h / a;
1596  E.y = D.y + (D.x - CA.x) * h / a;
1597 
1598  /* Crossing point E contained in arcs? */
1599  pt_in_arc_A = lw_pt_in_arc(&E, A1, A2, A3);
1600  pt_in_arc_B = lw_pt_in_arc(&E, B1, B2, B3);
1601 
1602  if ( pt_in_arc_A && pt_in_arc_B )
1603  {
1604  dl->p1 = dl->p2 = E;
1605  dl->distance = 0.0;
1606  return LW_TRUE;
1607  }
1608 
1609  /* Start from D and project h units perpendicular to CA-D to get F */
1610  F.x = D.x - (D.y - CA.y) * h / a;
1611  F.y = D.y - (D.x - CA.x) * h / a;
1612 
1613  /* Crossing point F contained in arcs? */
1614  pt_in_arc_A = lw_pt_in_arc(&F, A1, A2, A3);
1615  pt_in_arc_B = lw_pt_in_arc(&F, B1, B2, B3);
1616 
1617  if ( pt_in_arc_A && pt_in_arc_B )
1618  {
1619  dl->p1 = dl->p2 = F;
1620  dl->distance = 0.0;
1621  return LW_TRUE;
1622  }
1623  }
1624  else
1625  {
1626  lwerror("lw_dist2d_arc_arc: arcs neither touch, intersect nor are disjoint! INCONCEIVABLE!");
1627  return LW_FALSE;
1628  }
1629 
1630  /* Closest point is in the arc A, but not in the arc B, so */
1631  /* one of the B end points must be the closest. */
1632  if ( pt_in_arc_A & ! pt_in_arc_B )
1633  {
1634  lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1635  lw_dist2d_pt_arc(B3, A1, A2, A3, dl);
1636  return LW_TRUE;
1637  }
1638  /* Closest point is in the arc B, but not in the arc A, so */
1639  /* one of the A end points must be the closest. */
1640  else if ( pt_in_arc_B && ! pt_in_arc_A )
1641  {
1642  lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1643  lw_dist2d_pt_arc(A3, B1, B2, B3, dl);
1644  return LW_TRUE;
1645  }
1646  /* Finally, one of the end-point to end-point combos is the closest. */
1647  else
1648  {
1649  lw_dist2d_pt_pt(A1, B1, dl);
1650  lw_dist2d_pt_pt(A1, B3, dl);
1651  lw_dist2d_pt_pt(A2, B1, dl);
1652  lw_dist2d_pt_pt(A2, B3, dl);
1653  return LW_TRUE;
1654  }
1655 
1656  return LW_TRUE;
1657 }
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:213
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:91
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:1660
int mode
Definition: measures.h:27
POINT2D p1
Definition: measures.h:25
double x
Definition: liblwgeom.h:312
#define DIST_MIN
Definition: measures.h:17
#define LW_FALSE
Definition: liblwgeom.h:62
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:61
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition: measures.c:1421
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:1802
POINT2D p2
Definition: measures.h:26
double y
Definition: liblwgeom.h:312
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:71
double distance
Definition: measures.h:24
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
Definition: measures.c:2301
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:1274
#define FP_EQUALS(A, B)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:74
int lw_dist2d_pt_pt(const POINT2D *thep1, const POINT2D *thep2, DISTPTS *dl)
Compares incomming points and stores the points closest to each other or most far away from each othe...
Definition: measures.c:2265

Here is the call graph for this function:

Here is the caller graph for this function: