PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ ptarray_distance_spheroid()

static double ptarray_distance_spheroid ( const POINTARRAY pa1,
const POINTARRAY pa2,
const SPHEROID s,
double  tolerance,
int  check_intersection 
)
static

Definition at line 1837 of file lwgeodetic.c.

1838 {
1839  GEOGRAPHIC_EDGE e1, e2;
1840  GEOGRAPHIC_POINT g1, g2;
1841  GEOGRAPHIC_POINT nearest1, nearest2;
1842  POINT3D A1, A2, B1, B2;
1843  const POINT2D *p;
1844  double distance;
1845  uint32_t i, j;
1846  int use_sphere = (s->a == s->b ? 1 : 0);
1847 
1848  /* Make result really big, so that everything will be smaller than it */
1849  distance = FLT_MAX;
1850 
1851  /* Empty point arrays? Return negative */
1852  if ( pa1->npoints == 0 || pa2->npoints == 0 )
1853  return -1.0;
1854 
1855  /* Handle point/point case here */
1856  if ( pa1->npoints == 1 && pa2->npoints == 1 )
1857  {
1858  p = getPoint2d_cp(pa1, 0);
1859  geographic_point_init(p->x, p->y, &g1);
1860  p = getPoint2d_cp(pa2, 0);
1861  geographic_point_init(p->x, p->y, &g2);
1862  /* Sphere special case, axes equal */
1863  distance = s->radius * sphere_distance(&g1, &g2);
1864  if ( use_sphere )
1865  return distance;
1866  /* Below tolerance, actual distance isn't of interest */
1867  else if ( distance < 0.95 * tolerance )
1868  return distance;
1869  /* Close or greater than tolerance, get the real answer to be sure */
1870  else
1871  return spheroid_distance(&g1, &g2, s);
1872  }
1873 
1874  /* Handle point/line case here */
1875  if ( pa1->npoints == 1 || pa2->npoints == 1 )
1876  {
1877  /* Handle one/many case here */
1878  uint32_t i;
1879  const POINTARRAY *pa_one;
1880  const POINTARRAY *pa_many;
1881 
1882  if ( pa1->npoints == 1 )
1883  {
1884  pa_one = pa1;
1885  pa_many = pa2;
1886  }
1887  else
1888  {
1889  pa_one = pa2;
1890  pa_many = pa1;
1891  }
1892 
1893  /* Initialize our point */
1894  p = getPoint2d_cp(pa_one, 0);
1895  geographic_point_init(p->x, p->y, &g1);
1896 
1897  /* Initialize start of line */
1898  p = getPoint2d_cp(pa_many, 0);
1899  geographic_point_init(p->x, p->y, &(e1.start));
1900 
1901  /* Iterate through the edges in our line */
1902  for ( i = 1; i < pa_many->npoints; i++ )
1903  {
1904  double d;
1905  p = getPoint2d_cp(pa_many, i);
1906  geographic_point_init(p->x, p->y, &(e1.end));
1907  /* Get the spherical distance between point and edge */
1908  d = s->radius * edge_distance_to_point(&e1, &g1, &g2);
1909  /* New shortest distance! Record this distance / location */
1910  if ( d < distance )
1911  {
1912  distance = d;
1913  nearest2 = g2;
1914  }
1915  /* We've gotten closer than the tolerance... */
1916  if ( d < tolerance )
1917  {
1918  /* Working on a sphere? The answer is correct, return */
1919  if ( use_sphere )
1920  {
1921  return d;
1922  }
1923  /* Far enough past the tolerance that the spheroid calculation won't change things */
1924  else if ( d < tolerance * 0.95 )
1925  {
1926  return d;
1927  }
1928  /* On a spheroid and near the tolerance? Confirm that we are *actually* closer than tolerance */
1929  else
1930  {
1931  d = spheroid_distance(&g1, &nearest2, s);
1932  /* Yes, closer than tolerance, return! */
1933  if ( d < tolerance )
1934  return d;
1935  }
1936  }
1937  e1.start = e1.end;
1938  }
1939 
1940  /* On sphere, return answer */
1941  if ( use_sphere )
1942  return distance;
1943  /* On spheroid, calculate final answer based on closest approach */
1944  else
1945  return spheroid_distance(&g1, &nearest2, s);
1946 
1947  }
1948 
1949  /* Initialize start of line 1 */
1950  p = getPoint2d_cp(pa1, 0);
1951  geographic_point_init(p->x, p->y, &(e1.start));
1952  geog2cart(&(e1.start), &A1);
1953 
1954 
1955  /* Handle line/line case */
1956  for ( i = 1; i < pa1->npoints; i++ )
1957  {
1958  p = getPoint2d_cp(pa1, i);
1959  geographic_point_init(p->x, p->y, &(e1.end));
1960  geog2cart(&(e1.end), &A2);
1961 
1962  /* Initialize start of line 2 */
1963  p = getPoint2d_cp(pa2, 0);
1964  geographic_point_init(p->x, p->y, &(e2.start));
1965  geog2cart(&(e2.start), &B1);
1966 
1967  for ( j = 1; j < pa2->npoints; j++ )
1968  {
1969  double d;
1970 
1971  p = getPoint2d_cp(pa2, j);
1972  geographic_point_init(p->x, p->y, &(e2.end));
1973  geog2cart(&(e2.end), &B2);
1974 
1975  LWDEBUGF(4, "e1.start == GPOINT(%.6g %.6g) ", e1.start.lat, e1.start.lon);
1976  LWDEBUGF(4, "e1.end == GPOINT(%.6g %.6g) ", e1.end.lat, e1.end.lon);
1977  LWDEBUGF(4, "e2.start == GPOINT(%.6g %.6g) ", e2.start.lat, e2.start.lon);
1978  LWDEBUGF(4, "e2.end == GPOINT(%.6g %.6g) ", e2.end.lat, e2.end.lon);
1979 
1980  if ( check_intersection && edge_intersects(&A1, &A2, &B1, &B2) )
1981  {
1982  LWDEBUG(4,"edge intersection! returning 0.0");
1983  return 0.0;
1984  }
1985  d = s->radius * edge_distance_to_edge(&e1, &e2, &g1, &g2);
1986  LWDEBUGF(4,"got edge_distance_to_edge %.8g", d);
1987 
1988  if ( d < distance )
1989  {
1990  distance = d;
1991  nearest1 = g1;
1992  nearest2 = g2;
1993  }
1994  if ( d < tolerance )
1995  {
1996  if ( use_sphere )
1997  {
1998  return d;
1999  }
2000  else
2001  {
2002  d = spheroid_distance(&nearest1, &nearest2, s);
2003  if ( d < tolerance )
2004  return d;
2005  }
2006  }
2007 
2008  /* Copy end to start to allow a new end value in next iteration */
2009  e2.start = e2.end;
2010  B1 = B2;
2011  }
2012 
2013  /* Copy end to start to allow a new end value in next iteration */
2014  e1.start = e1.end;
2015  A1 = A2;
2016  LW_ON_INTERRUPT(return -1.0);
2017  }
2018  LWDEBUGF(4,"finished all loops, returning %.8g", distance);
2019 
2020  if ( use_sphere )
2021  return distance;
2022  else
2023  return spheroid_distance(&nearest1, &nearest2, s);
2024 }
char * s
Definition: cu_in_wkt.c:23
#define LW_ON_INTERRUPT(x)
void geographic_point_init(double lon, double lat, GEOGRAPHIC_POINT *g)
Initialize a geographic point.
Definition: lwgeodetic.c:180
double sphere_distance(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
Given two points on a unit sphere, calculate their distance apart in radians.
Definition: lwgeodetic.c:948
uint32_t edge_intersects(const POINT3D *A1, const POINT3D *A2, const POINT3D *B1, const POINT3D *B2)
Returns non-zero if edges A and B interact.
Definition: lwgeodetic.c:3515
double edge_distance_to_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *gp, GEOGRAPHIC_POINT *closest)
Definition: lwgeodetic.c:1218
void geog2cart(const GEOGRAPHIC_POINT *g, POINT3D *p)
Convert spherical coordinates to cartesian coordinates on unit sphere.
Definition: lwgeodetic.c:404
double edge_distance_to_edge(const GEOGRAPHIC_EDGE *e1, const GEOGRAPHIC_EDGE *e2, GEOGRAPHIC_POINT *closest1, GEOGRAPHIC_POINT *closest2)
Calculate the distance between two edges.
Definition: lwgeodetic.c:1271
double spheroid_distance(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const SPHEROID *spheroid)
Computes the shortest distance along the surface of the spheroid between two points,...
Definition: lwspheroid.c:79
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:101
static double distance(double x1, double y1, double x2, double y2)
Definition: lwtree.c:1032
GEOGRAPHIC_POINT start
Definition: lwgeodetic.h:64
GEOGRAPHIC_POINT end
Definition: lwgeodetic.h:65
Two-point great circle segment from a to b.
Definition: lwgeodetic.h:63
Point in spherical coordinates on the world.
Definition: lwgeodetic.h:54
double y
Definition: liblwgeom.h:404
double x
Definition: liblwgeom.h:404
uint32_t npoints
Definition: liblwgeom.h:441

References distance(), edge_distance_to_edge(), edge_distance_to_point(), edge_intersects(), GEOGRAPHIC_EDGE::end, geog2cart(), geographic_point_init(), getPoint2d_cp(), GEOGRAPHIC_POINT::lat, GEOGRAPHIC_POINT::lon, LW_ON_INTERRUPT, LWDEBUG, LWDEBUGF, POINTARRAY::npoints, s, sphere_distance(), spheroid_distance(), GEOGRAPHIC_EDGE::start, POINT2D::x, and POINT2D::y.

Referenced by lwgeom_distance_spheroid().

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