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

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