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

Definition at line 5987 of file lwgeom_topo.c.

5988 {
5989  uint32_t i;
5990  *nfaces = -1; /* error condition, by default */
5991  int num;
5992  LWT_ISO_FACE *faces;
5993  uint64_t nfacesinbox;
5994  uint64_t j;
5995  LWT_ELEMID *ids = NULL;
5996  GBOX qbox;
5997  const GEOSPreparedGeometry *ppoly;
5998  GEOSGeometry *polyg;
5999 
6000  /* Get tolerance, if 0 was given */
6001  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
6002  LWDEBUGF(1, "Working tolerance:%.15g", tol);
6003 
6004  /* Add each ring as an edge */
6005  for ( i=0; i<poly->nrings; ++i )
6006  {
6007  LWLINE *line;
6008  POINTARRAY *pa;
6009  LWT_ELEMID *eids;
6010  int nedges;
6011 
6012  pa = ptarray_clone(poly->rings[i]);
6013  line = lwline_construct(topo->srid, NULL, pa);
6014  eids = lwt_AddLine( topo, line, tol, &nedges );
6015  if ( nedges < 0 ) {
6016  /* probably too late as lwt_AddLine invoked lwerror */
6017  lwline_free(line);
6018  lwerror("Error adding ring %d of polygon", i);
6019  return NULL;
6020  }
6021  lwline_free(line);
6022  lwfree(eids);
6023  }
6024 
6025  /*
6026  -- Find faces covered by input polygon
6027  -- NOTE: potential snapping changed polygon edges
6028  */
6029  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
6030  gbox_expand(&qbox, tol);
6031  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
6032  LWT_COL_FACE_ALL, 0 );
6033  if (nfacesinbox == UINT64_MAX)
6034  {
6035  lwfree(ids);
6036  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
6037  return NULL;
6038  }
6039 
6040  num = 0;
6041  if ( nfacesinbox )
6042  {
6043  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
6044  if ( ! polyg )
6045  {
6046  _lwt_release_faces(faces, nfacesinbox);
6047  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
6048  return NULL;
6049  }
6050  ppoly = GEOSPrepare(polyg);
6051  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
6052  for ( j=0; j<nfacesinbox; ++j )
6053  {
6054  LWT_ISO_FACE *f = &(faces[j]);
6055  LWGEOM *fg;
6056  GEOSGeometry *fgg, *sp;
6057  int covers;
6058 
6059  /* check if a point on this face surface is covered by our polygon */
6060  fg = lwt_GetFaceGeometry( topo, f->face_id );
6061  if ( ! fg )
6062  {
6063  j = f->face_id; /* so we can destroy faces */
6064  GEOSPreparedGeom_destroy(ppoly);
6065  GEOSGeom_destroy(polyg);
6066  lwfree(ids);
6067  _lwt_release_faces(faces, nfacesinbox);
6068  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
6069  return NULL;
6070  }
6071  /* check if a point on this face's surface is covered by our polygon */
6072  fgg = LWGEOM2GEOS(fg, 0);
6073  lwgeom_free(fg);
6074  if ( ! fgg )
6075  {
6076  GEOSPreparedGeom_destroy(ppoly);
6077  GEOSGeom_destroy(polyg);
6078  _lwt_release_faces(faces, nfacesinbox);
6079  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6080  return NULL;
6081  }
6082  sp = GEOSPointOnSurface(fgg);
6083  GEOSGeom_destroy(fgg);
6084  if ( ! sp )
6085  {
6086  GEOSPreparedGeom_destroy(ppoly);
6087  GEOSGeom_destroy(polyg);
6088  _lwt_release_faces(faces, nfacesinbox);
6089  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
6090  return NULL;
6091  }
6092  covers = GEOSPreparedCovers( ppoly, sp );
6093  GEOSGeom_destroy(sp);
6094  if (covers == 2)
6095  {
6096  GEOSPreparedGeom_destroy(ppoly);
6097  GEOSGeom_destroy(polyg);
6098  _lwt_release_faces(faces, nfacesinbox);
6099  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
6100  return NULL;
6101  }
6102  if ( ! covers )
6103  {
6104  continue; /* we're not composed by this face */
6105  }
6106 
6107  /* TODO: avoid duplicates ? */
6108  ids[num++] = f->face_id;
6109  }
6110  GEOSPreparedGeom_destroy(ppoly);
6111  GEOSGeom_destroy(polyg);
6112  _lwt_release_faces(faces, nfacesinbox);
6113  }
6114 
6115  /* possibly 0 if non face's surface point was found
6116  * to be covered by input polygon */
6117  *nfaces = num;
6118 
6119  return ids;
6120 }
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:1155
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
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:743
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:678
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:190
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:125
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2817
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5975
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:461
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4923
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
Datum covers(PG_FUNCTION_ARGS)
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
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: