PostGIS  3.0.6dev-r@@SVN_REVISION@@

◆ _lwt_FindFaceContainingRing()

static LWT_ELEMID _lwt_FindFaceContainingRing ( LWT_TOPOLOGY topo,
LWT_EDGERING ring,
LWT_EDGERING_ARRAY shells 
)
static

Definition at line 6605 of file lwgeom_topo.c.

6607 {
6608  LWT_ELEMID foundInFace = -1;
6609  int i;
6610  const GBOX *minenv = NULL;
6611  POINT2D pt;
6612  const GBOX *testbox;
6613  GEOSGeometry *ghole;
6614 
6615  getPoint2d_p( ring->elems[0]->edge->geom->points, 0, &pt );
6616 
6617  testbox = _lwt_EdgeRingGetBbox(ring);
6618 
6619  /* Create a GEOS Point from a vertex of the hole ring */
6620  {
6621  LWPOINT *point = lwpoint_make2d(topo->srid, pt.x, pt.y);
6622  ghole = LWGEOM2GEOS( lwpoint_as_lwgeom(point), 1 );
6623  lwpoint_free(point);
6624  if ( ! ghole ) {
6625  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6626  return -1;
6627  }
6628  }
6629 
6630  /* Build STRtree of shell envelopes */
6631  if ( ! shells->tree )
6632  {
6633  static const int STRTREE_NODE_CAPACITY = 10;
6634  LWDEBUG(1, "Building STRtree");
6635  shells->tree = GEOSSTRtree_create(STRTREE_NODE_CAPACITY);
6636  if (shells->tree == NULL)
6637  {
6638  lwerror("Could not create GEOS STRTree: %s", lwgeom_geos_errmsg);
6639  return -1;
6640  }
6641  for (i=0; i<shells->size; ++i)
6642  {
6643  LWT_EDGERING *sring = shells->rings[i];
6644  const GBOX* shellbox = _lwt_EdgeRingGetBbox(sring);
6645  LWDEBUGF(2, "GBOX of shell %p for edge %d is %g %g,%g %g",
6646  sring, sring->elems[0]->edge->edge_id, shellbox->xmin,
6647  shellbox->ymin, shellbox->xmax, shellbox->ymax);
6648  POINTARRAY *pa = ptarray_construct(0, 0, 2);
6649  POINT4D pt;
6650  LWLINE *diag;
6651  pt.x = shellbox->xmin;
6652  pt.y = shellbox->ymin;
6653  ptarray_set_point4d(pa, 0, &pt);
6654  pt.x = shellbox->xmax;
6655  pt.y = shellbox->ymax;
6656  ptarray_set_point4d(pa, 1, &pt);
6657  diag = lwline_construct(topo->srid, NULL, pa);
6658  /* Record just envelope in ggeom */
6659  /* making valid, probably not needed */
6660  sring->genv = LWGEOM2GEOS( lwline_as_lwgeom(diag), 1 );
6661  lwline_free(diag);
6662  GEOSSTRtree_insert(shells->tree, sring->genv, sring);
6663  }
6664  LWDEBUG(1, "STRtree build completed");
6665  }
6666 
6667  LWT_EDGERING_ARRAY candidates;
6668  LWT_EDGERING_ARRAY_INIT(&candidates);
6669  GEOSSTRtree_query(shells->tree, ghole, &_lwt_AccumulateCanditates, &candidates);
6670  LWDEBUGF(1, "Found %d candidate shells containing first point of ring's originating edge %d",
6671  candidates.size, ring->elems[0]->edge->edge_id * ( ring->elems[0]->left ? 1 : -1 ) );
6672 
6673  /* TODO: sort candidates by bounding box size */
6674 
6675  for (i=0; i<candidates.size; ++i)
6676  {
6677  LWT_EDGERING *sring = candidates.rings[i];
6678  const GBOX* shellbox = _lwt_EdgeRingGetBbox(sring);
6679  int contains = 0;
6680 
6681  if ( sring->elems[0]->edge->edge_id == ring->elems[0]->edge->edge_id )
6682  {
6683  LWDEBUGF(1, "Shell %d is on other side of ring",
6684  _lwt_EdgeRingGetFace(sring));
6685  continue;
6686  }
6687 
6688  /* The hole envelope cannot equal the shell envelope */
6689  if ( gbox_same(shellbox, testbox) )
6690  {
6691  LWDEBUGF(1, "Bbox of shell %d equals that of hole ring",
6692  _lwt_EdgeRingGetFace(sring));
6693  continue;
6694  }
6695 
6696  /* Skip if ring box is not in shell box */
6697  if ( ! gbox_contains_2d(shellbox, testbox) )
6698  {
6699  LWDEBUGF(1, "Bbox of shell %d does not contain bbox of ring point",
6700  _lwt_EdgeRingGetFace(sring));
6701  continue;
6702  }
6703 
6704  /* Skip test if a containing shell was already found
6705  * and this shell's bbox is not contained in the other */
6706  if ( minenv && ! gbox_contains_2d(minenv, shellbox) )
6707  {
6708  LWDEBUGF(2, "Bbox of shell %d (face %d) not contained by bbox "
6709  "of last shell found to contain the point",
6710  i, _lwt_EdgeRingGetFace(sring));
6711  continue;
6712  }
6713 
6714  contains = _lwt_EdgeRingContainsPoint(sring, &pt);
6715  if ( contains )
6716  {
6717  /* Continue until all shells are tested, as we want to
6718  * use the one with the smallest bounding box */
6719  /* IDEA: sort shells by bbox size, stopping on first match */
6720  LWDEBUGF(1, "Shell %d contains hole of edge %d",
6721  _lwt_EdgeRingGetFace(sring),
6722  ring->elems[0]->edge->edge_id);
6723  minenv = shellbox;
6724  foundInFace = _lwt_EdgeRingGetFace(sring);
6725  }
6726  }
6727  if ( foundInFace == -1 ) foundInFace = 0;
6728 
6729  candidates.size = 0; /* Avoid destroying the actual shell rings */
6730  LWT_EDGERING_ARRAY_CLEAN(&candidates);
6731 
6732  GEOSGeom_destroy(ghole);
6733 
6734  return foundInFace;
6735 }
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition: gbox.c:164
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: gbox.c:339
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:321
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition: lwpoint.c:163
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:349
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:326
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:376
void lwline_free(LWLINE *line)
Definition: lwline.c:67
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static const int STRTREE_NODE_CAPACITY
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
static int _lwt_EdgeRingContainsPoint(LWT_EDGERING *ring, POINT2D *p)
Definition: lwgeom_topo.c:6465
static LWT_ELEMID _lwt_EdgeRingGetFace(LWT_EDGERING *ring)
Definition: lwgeom_topo.c:6497
static GBOX * _lwt_EdgeRingGetBbox(LWT_EDGERING *ring)
Definition: lwgeom_topo.c:6476
#define LWT_EDGERING_ARRAY_INIT(a)
Definition: lwgeom_topo.c:6097
static void _lwt_AccumulateCanditates(void *item, void *userdata)
Definition: lwgeom_topo.c:6597
#define LWT_EDGERING_ARRAY_CLEAN(a)
Definition: lwgeom_topo.c:6106
Datum contains(PG_FUNCTION_ARGS)
double ymax
Definition: liblwgeom.h:343
double xmax
Definition: liblwgeom.h:341
double ymin
Definition: liblwgeom.h:342
double xmin
Definition: liblwgeom.h:340
POINTARRAY * points
Definition: liblwgeom.h:469
GEOSSTRtree * tree
Definition: lwgeom_topo.c:6094
LWT_EDGERING ** rings
Definition: lwgeom_topo.c:6091
LWT_ISO_EDGE * edge
Definition: lwgeom_topo.c:6038
GEOSGeometry * genv
Definition: lwgeom_topo.c:6055
LWT_EDGERING_ELEM ** elems
Definition: lwgeom_topo.c:6048
LWLINE * geom
LWT_ELEMID edge_id
double y
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:400
double y
Definition: liblwgeom.h:400

References _lwt_AccumulateCanditates(), _lwt_EdgeRingContainsPoint(), _lwt_EdgeRingGetBbox(), _lwt_EdgeRingGetFace(), contains(), LWT_EDGERING_ELEM_T::edge, LWT_ISO_EDGE::edge_id, LWT_EDGERING_T::elems, gbox_contains_2d(), gbox_same(), LWT_EDGERING_T::genv, LWT_ISO_EDGE::geom, getPoint2d_p(), LWT_EDGERING_ELEM_T::left, LWDEBUG, LWDEBUGF, lwerror(), LWGEOM2GEOS(), lwgeom_geos_errmsg, lwline_as_lwgeom(), lwline_construct(), lwline_free(), lwpoint_as_lwgeom(), lwpoint_free(), lwpoint_make2d(), LWT_EDGERING_ARRAY_CLEAN, LWT_EDGERING_ARRAY_INIT, LWLINE::points, ptarray_construct(), ptarray_set_point4d(), LWT_EDGERING_ARRAY_T::rings, LWT_EDGERING_ARRAY_T::size, LWT_TOPOLOGY_T::srid, STRTREE_NODE_CAPACITY, LWT_EDGERING_ARRAY_T::tree, POINT2D::x, POINT4D::x, GBOX::xmax, GBOX::xmin, POINT2D::y, POINT4D::y, GBOX::ymax, and GBOX::ymin.

Referenced by lwt_Polygonize().

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