PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ lwt_AddPolygon()

LWT_ELEMID* lwt_AddPolygon ( LWT_TOPOLOGY topo,
LWPOLY poly,
double  tol,
int *  nfaces 
)

Adds a polygon to the topology.

The boundary of the given polygon will snap to existing nodes or edges within given tolerance. Existing edges or faces may be split by the boundary of the polygon.

Parameters
topothe topology to operate on
polythe polygon to add
tolsnap tolerance, the topology tolerance will be used if 0
nfacesoutput parameter, will be set to number of faces the polygon was split into, or -1 on error (liblwgeom error handler will be invoked with error message)
Returns
an array of <nfaces> face identifiers that sewed togheter will build up the input polygon (after snapping). Caller will need to free the array using lwfree(), if not null.

Definition at line 6053 of file lwgeom_topo.c.

6054 {
6055  uint32_t i;
6056  *nfaces = -1; /* error condition, by default */
6057  int num;
6058  LWT_ISO_FACE *faces;
6059  uint64_t nfacesinbox;
6060  uint64_t j;
6061  LWT_ELEMID *ids = NULL;
6062  GBOX qbox;
6063  const GEOSPreparedGeometry *ppoly;
6064  GEOSGeometry *polyg;
6065 
6066  /* Nothing to add, in an empty polygon */
6067  if ( lwpoly_is_empty(poly) )
6068  {
6069  *nfaces = 0;
6070  return NULL;
6071  }
6072 
6073  /* Get tolerance, if 0 was given */
6074  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
6075  LWDEBUGF(1, "Working tolerance:%.15g", tol);
6076 
6077  /* Add each ring as an edge */
6078  for ( i=0; i<poly->nrings; ++i )
6079  {
6080  LWLINE *line;
6081  POINTARRAY *pa;
6082  LWT_ELEMID *eids;
6083  int nedges;
6084 
6085  pa = ptarray_clone(poly->rings[i]);
6086  line = lwline_construct(topo->srid, NULL, pa);
6087  eids = lwt_AddLine( topo, line, tol, &nedges );
6088  if ( nedges < 0 ) {
6089  /* probably too late as lwt_AddLine invoked lwerror */
6090  lwline_free(line);
6091  lwerror("Error adding ring %d of polygon", i);
6092  return NULL;
6093  }
6094  lwline_free(line);
6095  lwfree(eids);
6096  }
6097 
6098  /*
6099  -- Find faces covered by input polygon
6100  -- NOTE: potential snapping changed polygon edges
6101  */
6102  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
6103  gbox_expand(&qbox, tol);
6104  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
6105  LWT_COL_FACE_ALL, 0 );
6106  if (nfacesinbox == UINT64_MAX)
6107  {
6108  lwfree(ids);
6109  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
6110  return NULL;
6111  }
6112 
6113  num = 0;
6114  if ( nfacesinbox )
6115  {
6116  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
6117  if ( ! polyg )
6118  {
6119  _lwt_release_faces(faces, nfacesinbox);
6120  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
6121  return NULL;
6122  }
6123  ppoly = GEOSPrepare(polyg);
6124  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
6125  for ( j=0; j<nfacesinbox; ++j )
6126  {
6127  LWT_ISO_FACE *f = &(faces[j]);
6128  LWGEOM *fg;
6129  GEOSGeometry *fgg, *sp;
6130  int covers;
6131 
6132  /* check if a point on this face surface is covered by our polygon */
6133  fg = lwt_GetFaceGeometry( topo, f->face_id );
6134  if ( ! fg )
6135  {
6136  j = f->face_id; /* so we can destroy faces */
6137  GEOSPreparedGeom_destroy(ppoly);
6138  GEOSGeom_destroy(polyg);
6139  lwfree(ids);
6140  _lwt_release_faces(faces, nfacesinbox);
6141  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
6142  return NULL;
6143  }
6144  /* check if a point on this face's surface is covered by our polygon */
6145  fgg = LWGEOM2GEOS(fg, 0);
6146  lwgeom_free(fg);
6147  if ( ! fgg )
6148  {
6149  GEOSPreparedGeom_destroy(ppoly);
6150  GEOSGeom_destroy(polyg);
6151  _lwt_release_faces(faces, nfacesinbox);
6152  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6153  return NULL;
6154  }
6155  sp = GEOSPointOnSurface(fgg);
6156  GEOSGeom_destroy(fgg);
6157  if ( ! sp )
6158  {
6159  GEOSPreparedGeom_destroy(ppoly);
6160  GEOSGeom_destroy(polyg);
6161  _lwt_release_faces(faces, nfacesinbox);
6162  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
6163  return NULL;
6164  }
6165  covers = GEOSPreparedCovers( ppoly, sp );
6166  GEOSGeom_destroy(sp);
6167  if (covers == 2)
6168  {
6169  GEOSPreparedGeom_destroy(ppoly);
6170  GEOSGeom_destroy(polyg);
6171  _lwt_release_faces(faces, nfacesinbox);
6172  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
6173  return NULL;
6174  }
6175  if ( ! covers )
6176  {
6177  continue; /* we're not composed by this face */
6178  }
6179 
6180  /* TODO: avoid duplicates ? */
6181  ids[num++] = f->face_id;
6182  }
6183  GEOSPreparedGeom_destroy(ppoly);
6184  GEOSGeom_destroy(polyg);
6185  _lwt_release_faces(faces, nfacesinbox);
6186  }
6187 
6188  /* possibly 0 if non face's surface point was found
6189  * to be covered by input polygon */
6190  *nfaces = num;
6191 
6192  return ids;
6193 }
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: gbox.c:97
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1138
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:312
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwfree(void *mem)
Definition: lwutil.c:242
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:726
void * lwalloc(size_t size)
Definition: lwutil.c:227
void lwline_free(LWLINE *line)
Definition: lwline.c:67
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:665
int lwpoly_is_empty(const LWPOLY *poly)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#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 LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
Definition: lwgeom_topo.c:184
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:119
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2841
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:6041
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:449
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4983
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
Datum covers(PG_FUNCTION_ARGS)
POINTARRAY ** rings
Definition: liblwgeom.h:533
uint32_t nrings
Definition: liblwgeom.h:538
LWT_ELEMID face_id
const LWT_BE_IFACE * be_iface

References _LWT_MINTOLERANCE, _lwt_release_faces(), LWT_TOPOLOGY_T::be_iface, covers(), LWT_ISO_FACE::face_id, gbox_expand(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwline_construct(), lwline_free(), lwpoly_as_lwgeom(), lwpoly_is_empty(), lwt_AddLine(), lwt_be_getFaceWithinBox2D(), lwt_be_lastErrorMessage(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), LWTFMT_ELEMID, LWPOLY::nrings, ptarray_clone(), LWPOLY::rings, and LWT_TOPOLOGY_T::srid.

Here is the call graph for this function: