PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ contains()

Datum contains ( PG_FUNCTION_ARGS  )

Definition at line 1790 of file postgis/lwgeom_geos.c.

References PrepGeomCache::argnum, containsproperly(), error_if_srid_mismatch(), errorIfGeometryCollection(), FALSE, gbox_contains_2d(), LWMPOINT::geoms, GetPrepGeomCache(), GetRtreeCache(), gserialized_get_gbox_p(), gserialized_get_srid(), gserialized_get_type(), gserialized_is_empty(), HANDLE_GEOS_ERROR, is_point(), is_poly(), LW_FALSE, LW_TRUE, lwgeom_as_lwmpoint(), lwgeom_as_lwpoint(), lwgeom_free(), lwgeom_from_gserialized(), lwgeom_geos_error(), lwmpoint_free(), MULTIPOINTTYPE, LWMPOINT::ngeoms, PG_FUNCTION_INFO_V1(), pip_short_circuit(), POINTTYPE, POSTGIS2GEOS(), and PrepGeomCache::prepared_geom.

Referenced by _lwt_AddFaceSplit(), _lwt_CheckEdgeCrossing(), lwpoly_split_by_line(), lwpoly_to_points(), lwt_AddPoint(), and overlaps().

1791 {
1792  GSERIALIZED *geom1;
1793  GSERIALIZED *geom2;
1794  GEOSGeometry *g1, *g2;
1795  GBOX box1, box2;
1796  int result;
1797  PrepGeomCache *prep_cache;
1798 
1799  geom1 = PG_GETARG_GSERIALIZED_P(0);
1800  geom2 = PG_GETARG_GSERIALIZED_P(1);
1801 
1802  errorIfGeometryCollection(geom1,geom2);
1804 
1805  /* A.Contains(Empty) == FALSE */
1806  if ( gserialized_is_empty(geom1) || gserialized_is_empty(geom2) )
1807  PG_RETURN_BOOL(false);
1808 
1809  POSTGIS_DEBUG(3, "contains called.");
1810 
1811  /*
1812  ** short-circuit 1: if geom2 bounding box is not completely inside
1813  ** geom1 bounding box we can prematurely return FALSE.
1814  */
1815  if ( gserialized_get_gbox_p(geom1, &box1) &&
1816  gserialized_get_gbox_p(geom2, &box2) )
1817  {
1818  if ( ! gbox_contains_2d(&box1, &box2) )
1819  {
1820  PG_RETURN_BOOL(FALSE);
1821  }
1822  }
1823 
1824  /*
1825  ** short-circuit 2: if geom2 is a point and geom1 is a polygon
1826  ** call the point-in-polygon function.
1827  */
1828  if (is_poly(geom1) && is_point(geom2))
1829  {
1830  GSERIALIZED* gpoly = is_poly(geom1) ? geom1 : geom2;
1831  GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
1832  RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
1833  int retval;
1834 
1835  POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
1836  if (gserialized_get_type(gpoint) == POINTTYPE)
1837  {
1838  LWGEOM* point = lwgeom_from_gserialized(gpoint);
1839  int pip_result = pip_short_circuit(cache, lwgeom_as_lwpoint(point), gpoly);
1840  lwgeom_free(point);
1841 
1842  retval = (pip_result == 1); /* completely inside */
1843  }
1844  else if (gserialized_get_type(gpoint) == MULTIPOINTTYPE)
1845  {
1847  uint32_t i;
1848  int found_completely_inside = LW_FALSE;
1849 
1850  retval = LW_TRUE;
1851  for (i = 0; i < mpoint->ngeoms; i++)
1852  {
1853  /* We need to find at least one point that's completely inside the
1854  * polygons (pip_result == 1). As long as we have one point that's
1855  * completely inside, we can have as many as we want on the boundary
1856  * itself. (pip_result == 0)
1857  */
1858  int pip_result = pip_short_circuit(cache, mpoint->geoms[i], gpoly);
1859  if (pip_result == 1)
1860  found_completely_inside = LW_TRUE;
1861 
1862  if (pip_result == -1) /* completely outside */
1863  {
1864  retval = LW_FALSE;
1865  break;
1866  }
1867  }
1868 
1869  retval = retval && found_completely_inside;
1870  lwmpoint_free(mpoint);
1871  }
1872  else
1873  {
1874  /* Never get here */
1875  elog(ERROR,"Type isn't point or multipoint!");
1876  PG_RETURN_NULL();
1877  }
1878 
1879  PG_FREE_IF_COPY(geom1, 0);
1880  PG_FREE_IF_COPY(geom2, 1);
1881  PG_RETURN_BOOL(retval);
1882  }
1883  else
1884  {
1885  POSTGIS_DEBUGF(3, "Contains: type1: %d, type2: %d", gserialized_get_type(geom1), gserialized_get_type(geom2));
1886  }
1887 
1888  initGEOS(lwpgnotice, lwgeom_geos_error);
1889 
1890  prep_cache = GetPrepGeomCache( fcinfo, geom1, 0 );
1891 
1892  if ( prep_cache && prep_cache->prepared_geom && prep_cache->argnum == 1 )
1893  {
1894  g1 = (GEOSGeometry *)POSTGIS2GEOS(geom2);
1895  if ( 0 == g1 ) /* exception thrown at construction */
1896  {
1897  HANDLE_GEOS_ERROR("Geometry could not be converted to GEOS");
1898  PG_RETURN_NULL();
1899  }
1900  POSTGIS_DEBUG(4, "containsPrepared: cache is live, running preparedcontains");
1901  result = GEOSPreparedContains( prep_cache->prepared_geom, g1);
1902  GEOSGeom_destroy(g1);
1903  }
1904  else
1905  {
1906  g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1);
1907  if ( 0 == g1 ) /* exception thrown at construction */
1908  {
1909  HANDLE_GEOS_ERROR("First argument geometry could not be converted to GEOS");
1910  PG_RETURN_NULL();
1911  }
1912  g2 = (GEOSGeometry *)POSTGIS2GEOS(geom2);
1913  if ( 0 == g2 ) /* exception thrown at construction */
1914  {
1915  HANDLE_GEOS_ERROR("Second argument geometry could not be converted to GEOS");
1916  GEOSGeom_destroy(g1);
1917  PG_RETURN_NULL();
1918  }
1919  POSTGIS_DEBUG(4, "containsPrepared: cache is not ready, running standard contains");
1920  result = GEOSContains( g1, g2);
1921  GEOSGeom_destroy(g1);
1922  GEOSGeom_destroy(g2);
1923  }
1924 
1925  if (result == 2)
1926  {
1927  HANDLE_GEOS_ERROR("GEOSContains");
1928  PG_RETURN_NULL(); /* never get here */
1929  }
1930 
1931  PG_FREE_IF_COPY(geom1, 0);
1932  PG_FREE_IF_COPY(geom2, 1);
1933 
1934  PG_RETURN_BOOL(result);
1935 
1936 }
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
Definition: g_serialized.c:642
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:86
PrepGeomCache * GetPrepGeomCache(FunctionCallInfo fcinfo, GSERIALIZED *g1, GSERIALIZED *g2)
Given a couple potential geometries and a function call context, return a prepared structure for one ...
const GEOSPreparedGeometry * prepared_geom
static char is_poly(const GSERIALIZED *g)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
The tree structure used for fast P-i-P tests by point_in_multipolygon_rtree()
Definition: lwgeom_rtree.h:57
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
Definition: g_box.c:351
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:371
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:129
static char is_point(const GSERIALIZED *g)
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:179
unsigned int uint32_t
Definition: uthash.h:78
void lwmpoint_free(LWMPOINT *mpt)
Definition: lwmpoint.c:72
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:77
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
LWPOINT ** geoms
Definition: liblwgeom.h:470
#define FALSE
Definition: dbfopen.c:168
GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *pglwgeom)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:201
#define HANDLE_GEOS_ERROR(label)
RTREE_POLY_CACHE * GetRtreeCache(FunctionCallInfo fcinfo, GSERIALIZED *g1)
Checks for a cache hit against the provided geometry and returns a pre-built index structure (RTREE_P...
Definition: lwgeom_rtree.c:432
int ngeoms
Definition: liblwgeom.h:468
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:100
static int pip_short_circuit(RTREE_POLY_CACHE *poly_cache, LWPOINT *point, GSERIALIZED *gpoly)
void errorIfGeometryCollection(GSERIALIZED *g1, GSERIALIZED *g2)
Throws an ereport ERROR if either geometry is a COLLECTIONTYPE.
Here is the call graph for this function:
Here is the caller graph for this function: