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 7588 of file lwgeom_topo.c.

7589 {
7590  *nfaces = -1; /* error condition, by default */
7591  int num;
7592  LWT_ISO_FACE *faces;
7593  uint64_t nfacesinbox;
7594  uint64_t j;
7595  LWT_ELEMID *ids = NULL;
7596  GBOX qbox;
7597  const GEOSPreparedGeometry *ppoly;
7598  GEOSGeometry *polyg;
7599 
7600  /* Nothing to add, in an empty polygon */
7601  if ( lwpoly_is_empty(poly) )
7602  {
7603  *nfaces = 0;
7604  return NULL;
7605  }
7606 
7607  /* Get tolerance, if 0 was given */
7608  if ( tol == -1 ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
7609  LWDEBUGF(1, "Working tolerance:%.15g", tol);
7610 
7611  lwt_LoadPolygon(topo, poly, tol);
7612 
7613  /*
7614  -- Find faces covered by input polygon
7615  -- NOTE: potential snapping changed polygon edges
7616  */
7617  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
7618  gbox_expand(&qbox, tol);
7619  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
7620  LWT_COL_FACE_ALL, 0 );
7621  if (nfacesinbox == UINT64_MAX)
7622  {
7623  lwfree(ids);
7624  PGTOPO_BE_ERROR();
7625  return NULL;
7626  }
7627 
7628  num = 0;
7629  if ( nfacesinbox )
7630  {
7631  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
7632  if ( ! polyg )
7633  {
7634  _lwt_release_faces(faces, nfacesinbox);
7635  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
7636  return NULL;
7637  }
7638  ppoly = GEOSPrepare(polyg);
7639  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
7640  for ( j=0; j<nfacesinbox; ++j )
7641  {
7642  LWT_ISO_FACE *f = &(faces[j]);
7643  LWGEOM *fg;
7644  GEOSGeometry *fgg, *sp;
7645  int covers;
7646 
7647  /* check if a point on this face surface is covered by our polygon */
7648  fg = lwt_GetFaceGeometry( topo, f->face_id );
7649  if ( ! fg )
7650  {
7651  j = f->face_id; /* so we can destroy faces */
7652  GEOSPreparedGeom_destroy(ppoly);
7653  GEOSGeom_destroy(polyg);
7654  lwfree(ids);
7655  _lwt_release_faces(faces, nfacesinbox);
7656  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
7657  return NULL;
7658  }
7659  /* check if a point on this face's surface is covered by our polygon */
7660  fgg = LWGEOM2GEOS(fg, 0);
7661  lwgeom_free(fg);
7662  if ( ! fgg )
7663  {
7664  GEOSPreparedGeom_destroy(ppoly);
7665  GEOSGeom_destroy(polyg);
7666  _lwt_release_faces(faces, nfacesinbox);
7667  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
7668  return NULL;
7669  }
7670  sp = GEOSPointOnSurface(fgg);
7671  GEOSGeom_destroy(fgg);
7672  if ( ! sp )
7673  {
7674  GEOSPreparedGeom_destroy(ppoly);
7675  GEOSGeom_destroy(polyg);
7676  _lwt_release_faces(faces, nfacesinbox);
7677  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
7678  return NULL;
7679  }
7680  covers = GEOSPreparedCovers( ppoly, sp );
7681  GEOSGeom_destroy(sp);
7682  if (covers == 2)
7683  {
7684  GEOSPreparedGeom_destroy(ppoly);
7685  GEOSGeom_destroy(polyg);
7686  _lwt_release_faces(faces, nfacesinbox);
7687  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
7688  return NULL;
7689  }
7690  if ( ! covers )
7691  {
7692  continue; /* we're not composed by this face */
7693  }
7694 
7695  /* TODO: avoid duplicates ? */
7696  ids[num++] = f->face_id;
7697  }
7698  GEOSPreparedGeom_destroy(ppoly);
7699  GEOSGeom_destroy(polyg);
7700  _lwt_release_faces(faces, nfacesinbox);
7701  }
7702 
7703  /* possibly 0 if non face's surface point was found
7704  * to be covered by input polygon */
7705  *nfaces = num;
7706 
7707  return ids;
7708 }
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:1246
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:357
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:771
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:7569
#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: