PostGIS  3.1.6dev-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 5930 of file lwgeom_topo.c.

5931 {
5932  uint32_t i;
5933  *nfaces = -1; /* error condition, by default */
5934  int num;
5935  LWT_ISO_FACE *faces;
5936  uint64_t nfacesinbox;
5937  uint64_t j;
5938  LWT_ELEMID *ids = NULL;
5939  GBOX qbox;
5940  const GEOSPreparedGeometry *ppoly;
5941  GEOSGeometry *polyg;
5942 
5943  /* Nothing to add, in an empty polygon */
5944  if ( lwpoly_is_empty(poly) )
5945  {
5946  *nfaces = 0;
5947  return NULL;
5948  }
5949 
5950  /* Get tolerance, if 0 was given */
5951  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5952  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5953 
5954  /* Add each ring as an edge */
5955  for ( i=0; i<poly->nrings; ++i )
5956  {
5957  LWLINE *line;
5958  POINTARRAY *pa;
5959  LWT_ELEMID *eids;
5960  int nedges;
5961 
5962  pa = ptarray_clone(poly->rings[i]);
5963  line = lwline_construct(topo->srid, NULL, pa);
5964  eids = lwt_AddLine( topo, line, tol, &nedges );
5965  if ( nedges < 0 ) {
5966  /* probably too late as lwt_AddLine invoked lwerror */
5967  lwline_free(line);
5968  lwerror("Error adding ring %d of polygon", i);
5969  return NULL;
5970  }
5971  lwline_free(line);
5972  lwfree(eids);
5973  }
5974 
5975  /*
5976  -- Find faces covered by input polygon
5977  -- NOTE: potential snapping changed polygon edges
5978  */
5979  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5980  gbox_expand(&qbox, tol);
5981  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5982  LWT_COL_FACE_ALL, 0 );
5983  if (nfacesinbox == UINT64_MAX)
5984  {
5985  lwfree(ids);
5986  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5987  return NULL;
5988  }
5989 
5990  num = 0;
5991  if ( nfacesinbox )
5992  {
5993  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5994  if ( ! polyg )
5995  {
5996  _lwt_release_faces(faces, nfacesinbox);
5997  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5998  return NULL;
5999  }
6000  ppoly = GEOSPrepare(polyg);
6001  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
6002  for ( j=0; j<nfacesinbox; ++j )
6003  {
6004  LWT_ISO_FACE *f = &(faces[j]);
6005  LWGEOM *fg;
6006  GEOSGeometry *fgg, *sp;
6007  int covers;
6008 
6009  /* check if a point on this face surface is covered by our polygon */
6010  fg = lwt_GetFaceGeometry( topo, f->face_id );
6011  if ( ! fg )
6012  {
6013  j = f->face_id; /* so we can destroy faces */
6014  GEOSPreparedGeom_destroy(ppoly);
6015  GEOSGeom_destroy(polyg);
6016  lwfree(ids);
6017  _lwt_release_faces(faces, nfacesinbox);
6018  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
6019  return NULL;
6020  }
6021  /* check if a point on this face's surface is covered by our polygon */
6022  fgg = LWGEOM2GEOS(fg, 0);
6023  lwgeom_free(fg);
6024  if ( ! fgg )
6025  {
6026  GEOSPreparedGeom_destroy(ppoly);
6027  GEOSGeom_destroy(polyg);
6028  _lwt_release_faces(faces, nfacesinbox);
6029  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6030  return NULL;
6031  }
6032  sp = GEOSPointOnSurface(fgg);
6033  GEOSGeom_destroy(fgg);
6034  if ( ! sp )
6035  {
6036  GEOSPreparedGeom_destroy(ppoly);
6037  GEOSGeom_destroy(polyg);
6038  _lwt_release_faces(faces, nfacesinbox);
6039  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
6040  return NULL;
6041  }
6042  covers = GEOSPreparedCovers( ppoly, sp );
6043  GEOSGeom_destroy(sp);
6044  if (covers == 2)
6045  {
6046  GEOSPreparedGeom_destroy(ppoly);
6047  GEOSGeom_destroy(polyg);
6048  _lwt_release_faces(faces, nfacesinbox);
6049  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
6050  return NULL;
6051  }
6052  if ( ! covers )
6053  {
6054  continue; /* we're not composed by this face */
6055  }
6056 
6057  /* TODO: avoid duplicates ? */
6058  ids[num++] = f->face_id;
6059  }
6060  GEOSPreparedGeom_destroy(ppoly);
6061  GEOSGeom_destroy(polyg);
6062  _lwt_release_faces(faces, nfacesinbox);
6063  }
6064 
6065  /* possibly 0 if non face's surface point was found
6066  * to be covered by input polygon */
6067  *nfaces = num;
6068 
6069  return ids;
6070 }
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:2824
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5918
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:441
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4942
#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: