PostGIS  3.0.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 5874 of file lwgeom_topo.c.

5875 {
5876  uint32_t i;
5877  *nfaces = -1; /* error condition, by default */
5878  int num;
5879  LWT_ISO_FACE *faces;
5880  uint64_t nfacesinbox;
5881  uint64_t j;
5882  LWT_ELEMID *ids = NULL;
5883  GBOX qbox;
5884  const GEOSPreparedGeometry *ppoly;
5885  GEOSGeometry *polyg;
5886 
5887  /* Nothing to add, in an empty polygon */
5888  if ( lwpoly_is_empty(poly) )
5889  {
5890  *nfaces = 0;
5891  return NULL;
5892  }
5893 
5894  /* Get tolerance, if 0 was given */
5895  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5896  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5897 
5898  /* Add each ring as an edge */
5899  for ( i=0; i<poly->nrings; ++i )
5900  {
5901  LWLINE *line;
5902  POINTARRAY *pa;
5903  LWT_ELEMID *eids;
5904  int nedges;
5905 
5906  pa = ptarray_clone(poly->rings[i]);
5907  line = lwline_construct(topo->srid, NULL, pa);
5908  eids = lwt_AddLine( topo, line, tol, &nedges );
5909  if ( nedges < 0 ) {
5910  /* probably too late as lwt_AddLine invoked lwerror */
5911  lwline_free(line);
5912  lwerror("Error adding ring %d of polygon", i);
5913  return NULL;
5914  }
5915  lwline_free(line);
5916  lwfree(eids);
5917  }
5918 
5919  /*
5920  -- Find faces covered by input polygon
5921  -- NOTE: potential snapping changed polygon edges
5922  */
5923  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5924  gbox_expand(&qbox, tol);
5925  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5926  LWT_COL_FACE_ALL, 0 );
5927  if (nfacesinbox == UINT64_MAX)
5928  {
5929  lwfree(ids);
5930  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5931  return NULL;
5932  }
5933 
5934  num = 0;
5935  if ( nfacesinbox )
5936  {
5937  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5938  if ( ! polyg )
5939  {
5940  _lwt_release_faces(faces, nfacesinbox);
5941  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5942  return NULL;
5943  }
5944  ppoly = GEOSPrepare(polyg);
5945  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
5946  for ( j=0; j<nfacesinbox; ++j )
5947  {
5948  LWT_ISO_FACE *f = &(faces[j]);
5949  LWGEOM *fg;
5950  GEOSGeometry *fgg, *sp;
5951  int covers;
5952 
5953  /* check if a point on this face surface is covered by our polygon */
5954  fg = lwt_GetFaceGeometry( topo, f->face_id );
5955  if ( ! fg )
5956  {
5957  j = f->face_id; /* so we can destroy faces */
5958  GEOSPreparedGeom_destroy(ppoly);
5959  GEOSGeom_destroy(polyg);
5960  lwfree(ids);
5961  _lwt_release_faces(faces, nfacesinbox);
5962  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
5963  return NULL;
5964  }
5965  /* check if a point on this face's surface is covered by our polygon */
5966  fgg = LWGEOM2GEOS(fg, 0);
5967  lwgeom_free(fg);
5968  if ( ! fgg )
5969  {
5970  GEOSPreparedGeom_destroy(ppoly);
5971  GEOSGeom_destroy(polyg);
5972  _lwt_release_faces(faces, nfacesinbox);
5973  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
5974  return NULL;
5975  }
5976  sp = GEOSPointOnSurface(fgg);
5977  GEOSGeom_destroy(fgg);
5978  if ( ! sp )
5979  {
5980  GEOSPreparedGeom_destroy(ppoly);
5981  GEOSGeom_destroy(polyg);
5982  _lwt_release_faces(faces, nfacesinbox);
5983  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
5984  return NULL;
5985  }
5986  covers = GEOSPreparedCovers( ppoly, sp );
5987  GEOSGeom_destroy(sp);
5988  if (covers == 2)
5989  {
5990  GEOSPreparedGeom_destroy(ppoly);
5991  GEOSGeom_destroy(polyg);
5992  _lwt_release_faces(faces, nfacesinbox);
5993  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
5994  return NULL;
5995  }
5996  if ( ! covers )
5997  {
5998  continue; /* we're not composed by this face */
5999  }
6000 
6001  /* TODO: avoid duplicates ? */
6002  ids[num++] = f->face_id;
6003  }
6004  GEOSPreparedGeom_destroy(ppoly);
6005  GEOSGeom_destroy(polyg);
6006  _lwt_release_faces(faces, nfacesinbox);
6007  }
6008 
6009  /* possibly 0 if non face's surface point was found
6010  * to be covered by input polygon */
6011  *nfaces = num;
6012 
6013  return ids;
6014 }
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:311
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:725
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:2791
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5862
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:4890
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
Datum covers(PG_FUNCTION_ARGS)
POINTARRAY ** rings
Definition: liblwgeom.h:505
uint32_t nrings
Definition: liblwgeom.h:510
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: