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

◆ 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 1756 of file lwgeodetic.c.

1757{
1758 GEOGRAPHIC_EDGE e1, e2;
1759 GEOGRAPHIC_POINT g1, g2;
1760 GEOGRAPHIC_POINT nearest1, nearest2;
1761 POINT3D A1, A2, B1, B2;
1762 const POINT2D *p;
1763 double distance;
1764 uint32_t i, j;
1765 int use_sphere = (s->a == s->b ? 1 : 0);
1766
1767 /* Make result really big, so that everything will be smaller than it */
1768 distance = FLT_MAX;
1769
1770 /* Empty point arrays? Return negative */
1771 if ( pa1->npoints == 0 || pa2->npoints == 0 )
1772 return -1.0;
1773
1774 /* Handle point/point case here */
1775 if ( pa1->npoints == 1 && pa2->npoints == 1 )
1776 {
1777 p = getPoint2d_cp(pa1, 0);
1778 geographic_point_init(p->x, p->y, &g1);
1779 p = getPoint2d_cp(pa2, 0);
1780 geographic_point_init(p->x, p->y, &g2);
1781 /* Sphere special case, axes equal */
1782 distance = s->radius * sphere_distance(&g1, &g2);
1783 if ( use_sphere )
1784 return distance;
1785 /* Below tolerance, actual distance isn't of interest */
1786 else if ( distance < 0.95 * tolerance )
1787 return distance;
1788 /* Close or greater than tolerance, get the real answer to be sure */
1789 else
1790 return spheroid_distance(&g1, &g2, s);
1791 }
1792
1793 /* Handle point/line case here */
1794 if ( pa1->npoints == 1 || pa2->npoints == 1 )
1795 {
1796 /* Handle one/many case here */
1797 uint32_t i;
1798 const POINTARRAY *pa_one;
1799 const POINTARRAY *pa_many;
1800
1801 if ( pa1->npoints == 1 )
1802 {
1803 pa_one = pa1;
1804 pa_many = pa2;
1805 }
1806 else
1807 {
1808 pa_one = pa2;
1809 pa_many = pa1;
1810 }
1811
1812 /* Initialize our point */
1813 p = getPoint2d_cp(pa_one, 0);
1814 geographic_point_init(p->x, p->y, &g1);
1815
1816 /* Initialize start of line */
1817 p = getPoint2d_cp(pa_many, 0);
1818 geographic_point_init(p->x, p->y, &(e1.start));
1819
1820 /* Iterate through the edges in our line */
1821 for ( i = 1; i < pa_many->npoints; i++ )
1822 {
1823 double d;
1824 p = getPoint2d_cp(pa_many, i);
1825 geographic_point_init(p->x, p->y, &(e1.end));
1826 /* Get the spherical distance between point and edge */
1827 d = s->radius * edge_distance_to_point(&e1, &g1, &g2);
1828 /* New shortest distance! Record this distance / location */
1829 if ( d < distance )
1830 {
1831 distance = d;
1832 nearest2 = g2;
1833 }
1834 /* We've gotten closer than the tolerance... */
1835 if ( d <= tolerance )
1836 {
1837 /* Working on a sphere? The answer is correct, return */
1838 if ( use_sphere )
1839 {
1840 return d;
1841 }
1842 /* Far enough past the tolerance that the spheroid calculation won't change things */
1843 else if ( d <= tolerance * 0.95 )
1844 {
1845 return d;
1846 }
1847 /* On a spheroid and near the tolerance? Confirm that we are *actually* closer than tolerance */
1848 else
1849 {
1850 d = spheroid_distance(&g1, &nearest2, s);
1851 /* Yes, closer than tolerance, return! */
1852 if ( d <= tolerance )
1853 return d;
1854 }
1855 }
1856 e1.start = e1.end;
1857 }
1858
1859 /* On sphere, return answer */
1860 if ( use_sphere )
1861 return distance;
1862 /* On spheroid, calculate final answer based on closest approach */
1863 else
1864 return spheroid_distance(&g1, &nearest2, s);
1865
1866 }
1867
1868 /* Initialize start of line 1 */
1869 p = getPoint2d_cp(pa1, 0);
1870 geographic_point_init(p->x, p->y, &(e1.start));
1871 geog2cart(&(e1.start), &A1);
1872
1873
1874 /* Handle line/line case */
1875 for ( i = 1; i < pa1->npoints; i++ )
1876 {
1877 p = getPoint2d_cp(pa1, i);
1878 geographic_point_init(p->x, p->y, &(e1.end));
1879 geog2cart(&(e1.end), &A2);
1880
1881 /* Initialize start of line 2 */
1882 p = getPoint2d_cp(pa2, 0);
1883 geographic_point_init(p->x, p->y, &(e2.start));
1884 geog2cart(&(e2.start), &B1);
1885
1886 for ( j = 1; j < pa2->npoints; j++ )
1887 {
1888 double d;
1889
1890 p = getPoint2d_cp(pa2, j);
1891 geographic_point_init(p->x, p->y, &(e2.end));
1892 geog2cart(&(e2.end), &B2);
1893
1894 LWDEBUGF(4, "e1.start == GPOINT(%.6g %.6g) ", e1.start.lat, e1.start.lon);
1895 LWDEBUGF(4, "e1.end == GPOINT(%.6g %.6g) ", e1.end.lat, e1.end.lon);
1896 LWDEBUGF(4, "e2.start == GPOINT(%.6g %.6g) ", e2.start.lat, e2.start.lon);
1897 LWDEBUGF(4, "e2.end == GPOINT(%.6g %.6g) ", e2.end.lat, e2.end.lon);
1898
1899 if ( check_intersection && edge_intersects(&A1, &A2, &B1, &B2) )
1900 {
1901 LWDEBUG(4,"edge intersection! returning 0.0");
1902 return 0.0;
1903 }
1904 d = s->radius * edge_distance_to_edge(&e1, &e2, &g1, &g2);
1905 LWDEBUGF(4,"got edge_distance_to_edge %.8g", d);
1906
1907 if ( d < distance )
1908 {
1909 distance = d;
1910 nearest1 = g1;
1911 nearest2 = g2;
1912 }
1913 if ( d <= tolerance )
1914 {
1915 if ( use_sphere )
1916 {
1917 return d;
1918 }
1919 else
1920 {
1921 d = spheroid_distance(&nearest1, &nearest2, s);
1922 if ( d <= tolerance )
1923 return d;
1924 }
1925 }
1926
1927 /* Copy end to start to allow a new end value in next iteration */
1928 e2.start = e2.end;
1929 B1 = B2;
1930 }
1931
1932 /* Copy end to start to allow a new end value in next iteration */
1933 e1.start = e1.end;
1934 A1 = A2;
1935 LW_ON_INTERRUPT(return -1.0);
1936 }
1937 LWDEBUGF(4,"finished all loops, returning %.8g", distance);
1938
1939 if ( use_sphere )
1940 return distance;
1941 else
1942 return spheroid_distance(&nearest1, &nearest2, s);
1943}
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:896
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.
double edge_distance_to_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *gp, GEOGRAPHIC_POINT *closest)
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.
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:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
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:97
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:390
double x
Definition liblwgeom.h:390
uint32_t npoints
Definition liblwgeom.h:427

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: