PostGIS  3.7.0dev-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 together will build up the input polygon (after snapping). Caller will need to free the array using lwfree(), if not null.

Definition at line 7546 of file lwgeom_topo.c.

7547 {
7548  *nfaces = -1; /* error condition, by default */
7549  int num;
7550  LWT_ISO_FACE *faces;
7551  uint64_t nfacesinbox;
7552  uint64_t j;
7553  LWT_ELEMID *ids = NULL;
7554  GBOX qbox;
7555  const GEOSPreparedGeometry *ppoly;
7556  GEOSGeometry *polyg;
7557 
7558  /* Nothing to add, in an empty polygon */
7559  if ( lwpoly_is_empty(poly) )
7560  {
7561  *nfaces = 0;
7562  return NULL;
7563  }
7564 
7565  /* Get tolerance, if 0 was given */
7566  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
7567  LWDEBUGF(1, "Working tolerance:%.15g", tol);
7568 
7569  lwt_LoadPolygon(topo, poly, tol);
7570 
7571  /*
7572  -- Find faces covered by input polygon
7573  -- NOTE: potential snapping changed polygon edges
7574  */
7575  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
7576  gbox_expand(&qbox, tol);
7577  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
7578  LWT_COL_FACE_ALL, 0 );
7579  if (nfacesinbox == UINT64_MAX)
7580  {
7581  lwfree(ids);
7582  PGTOPO_BE_ERROR();
7583  return NULL;
7584  }
7585 
7586  num = 0;
7587  if ( nfacesinbox )
7588  {
7589  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
7590  if ( ! polyg )
7591  {
7592  _lwt_release_faces(faces, nfacesinbox);
7593  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
7594  return NULL;
7595  }
7596  ppoly = GEOSPrepare(polyg);
7597  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
7598  for ( j=0; j<nfacesinbox; ++j )
7599  {
7600  LWT_ISO_FACE *f = &(faces[j]);
7601  LWGEOM *fg;
7602  GEOSGeometry *fgg, *sp;
7603  int covers;
7604 
7605  /* check if a point on this face surface is covered by our polygon */
7606  fg = lwt_GetFaceGeometry( topo, f->face_id );
7607  if ( ! fg )
7608  {
7609  j = f->face_id; /* so we can destroy faces */
7610  GEOSPreparedGeom_destroy(ppoly);
7611  GEOSGeom_destroy(polyg);
7612  lwfree(ids);
7613  _lwt_release_faces(faces, nfacesinbox);
7614  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
7615  return NULL;
7616  }
7617  /* check if a point on this face's surface is covered by our polygon */
7618  fgg = LWGEOM2GEOS(fg, 0);
7619  lwgeom_free(fg);
7620  if ( ! fgg )
7621  {
7622  GEOSPreparedGeom_destroy(ppoly);
7623  GEOSGeom_destroy(polyg);
7624  _lwt_release_faces(faces, nfacesinbox);
7625  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
7626  return NULL;
7627  }
7628  sp = GEOSPointOnSurface(fgg);
7629  GEOSGeom_destroy(fgg);
7630  if ( ! sp )
7631  {
7632  GEOSPreparedGeom_destroy(ppoly);
7633  GEOSGeom_destroy(polyg);
7634  _lwt_release_faces(faces, nfacesinbox);
7635  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
7636  return NULL;
7637  }
7638  covers = GEOSPreparedCovers( ppoly, sp );
7639  GEOSGeom_destroy(sp);
7640  if (covers == 2)
7641  {
7642  GEOSPreparedGeom_destroy(ppoly);
7643  GEOSGeom_destroy(polyg);
7644  _lwt_release_faces(faces, nfacesinbox);
7645  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
7646  return NULL;
7647  }
7648  if ( ! covers )
7649  {
7650  continue; /* we're not composed by this face */
7651  }
7652 
7653  /* TODO: avoid duplicates ? */
7654  ids[num++] = f->face_id;
7655  }
7656  GEOSPreparedGeom_destroy(ppoly);
7657  GEOSGeom_destroy(polyg);
7658  _lwt_release_faces(faces, nfacesinbox);
7659  }
7660 
7661  /* possibly 0 if non face's surface point was found
7662  * to be covered by input polygon */
7663  *nfaces = num;
7664 
7665  return ids;
7666 }
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:1218
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
void lwfree(void *mem)
Definition: lwutil.c:248
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:743
void * lwalloc(size_t size)
Definition: lwutil.c:227
int lwpoly_is_empty(const LWPOLY *poly)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
Datum covers(PG_FUNCTION_ARGS)
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2841
void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:450
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:179
static void lwt_LoadPolygon(LWT_TOPOLOGY *topo, const LWPOLY *poly, double tol)
Definition: lwgeom_topo.c:7527
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:5062
LWT_ELEMID face_id

References _LWT_MINTOLERANCE, _lwt_release_faces(), covers(), LWT_ISO_FACE::face_id, gbox_expand(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwpoly_as_lwgeom(), lwpoly_is_empty(), lwt_be_getFaceWithinBox2D(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), lwt_LoadPolygon(), LWTFMT_ELEMID, and PGTOPO_BE_ERROR.

Here is the call graph for this function: