PostGIS  2.4.9dev-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 1831 of file lwgeodetic.c.

References SPHEROID::a, SPHEROID::b, 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, SPHEROID::radius, sphere_distance(), spheroid_distance(), GEOGRAPHIC_EDGE::start, POINT2D::x, and POINT2D::y.

Referenced by lwgeom_distance_spheroid().

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