PostGIS  2.5.7dev-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 5807 of file lwgeom_topo.c.

5808 {
5809  uint32_t i;
5810  *nfaces = -1; /* error condition, by default */
5811  int num;
5812  LWT_ISO_FACE *faces;
5813  int nfacesinbox;
5814  int j;
5815  LWT_ELEMID *ids = NULL;
5816  GBOX qbox;
5817  const GEOSPreparedGeometry *ppoly;
5818  GEOSGeometry *polyg;
5819 
5820  /* Get tolerance, if 0 was given */
5821  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5822  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5823 
5824  /* Add each ring as an edge */
5825  for ( i=0; i<poly->nrings; ++i )
5826  {
5827  LWLINE *line;
5828  POINTARRAY *pa;
5829  LWT_ELEMID *eids;
5830  int nedges;
5831 
5832  pa = ptarray_clone(poly->rings[i]);
5833  line = lwline_construct(topo->srid, NULL, pa);
5834  eids = lwt_AddLine( topo, line, tol, &nedges );
5835  if ( nedges < 0 ) {
5836  /* probably too late as lwt_AddLine invoked lwerror */
5837  lwline_free(line);
5838  lwerror("Error adding ring %d of polygon", i);
5839  return NULL;
5840  }
5841  lwline_free(line);
5842  lwfree(eids);
5843  }
5844 
5845  /*
5846  -- Find faces covered by input polygon
5847  -- NOTE: potential snapping changed polygon edges
5848  */
5849  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5850  gbox_expand(&qbox, tol);
5851  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5852  LWT_COL_FACE_ALL, 0 );
5853  if ( nfacesinbox == -1 )
5854  {
5855  lwfree(ids);
5856  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5857  return NULL;
5858  }
5859 
5860  num = 0;
5861  if ( nfacesinbox )
5862  {
5863  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5864  if ( ! polyg )
5865  {
5866  _lwt_release_faces(faces, nfacesinbox);
5867  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5868  return NULL;
5869  }
5870  ppoly = GEOSPrepare(polyg);
5871  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
5872  for ( j=0; j<nfacesinbox; ++j )
5873  {
5874  LWT_ISO_FACE *f = &(faces[j]);
5875  LWGEOM *fg;
5876  GEOSGeometry *fgg, *sp;
5877  int covers;
5878 
5879  /* check if a point on this face surface is covered by our polygon */
5880  fg = lwt_GetFaceGeometry( topo, f->face_id );
5881  if ( ! fg )
5882  {
5883  j = f->face_id; /* so we can destroy faces */
5884  GEOSPreparedGeom_destroy(ppoly);
5885  GEOSGeom_destroy(polyg);
5886  lwfree(ids);
5887  _lwt_release_faces(faces, nfacesinbox);
5888  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
5889  return NULL;
5890  }
5891  /* check if a point on this face's surface is covered by our polygon */
5892  fgg = LWGEOM2GEOS(fg, 0);
5893  lwgeom_free(fg);
5894  if ( ! fgg )
5895  {
5896  GEOSPreparedGeom_destroy(ppoly);
5897  GEOSGeom_destroy(polyg);
5898  _lwt_release_faces(faces, nfacesinbox);
5899  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
5900  return NULL;
5901  }
5902  sp = GEOSPointOnSurface(fgg);
5903  GEOSGeom_destroy(fgg);
5904  if ( ! sp )
5905  {
5906  GEOSPreparedGeom_destroy(ppoly);
5907  GEOSGeom_destroy(polyg);
5908  _lwt_release_faces(faces, nfacesinbox);
5909  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
5910  return NULL;
5911  }
5912  covers = GEOSPreparedCovers( ppoly, sp );
5913  GEOSGeom_destroy(sp);
5914  if (covers == 2)
5915  {
5916  GEOSPreparedGeom_destroy(ppoly);
5917  GEOSGeom_destroy(polyg);
5918  _lwt_release_faces(faces, nfacesinbox);
5919  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
5920  return NULL;
5921  }
5922  if ( ! covers )
5923  {
5924  continue; /* we're not composed by this face */
5925  }
5926 
5927  /* TODO: avoid duplicates ? */
5928  ids[num++] = f->face_id;
5929  }
5930  GEOSPreparedGeom_destroy(ppoly);
5931  GEOSGeom_destroy(polyg);
5932  _lwt_release_faces(faces, nfacesinbox);
5933  }
5934 
5935  /* possibly 0 if non face's surface point was found
5936  * to be covered by input polygon */
5937  *nfaces = num;
5938 
5939  return ids;
5940 }
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:104
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:320
void lwfree(void *mem)
Definition: lwutil.c:244
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:734
void * lwalloc(size_t size)
Definition: lwutil.c:229
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwline_free(LWLINE *line)
Definition: lwline.c:76
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:659
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
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:120
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2786
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5795
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:447
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4877
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:187
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
Datum covers(PG_FUNCTION_ARGS)
POINTARRAY ** rings
Definition: liblwgeom.h:460
uint32_t nrings
Definition: liblwgeom.h:458
LWT_ELEMID face_id
const LWT_BE_IFACE * be_iface
unsigned int uint32_t
Definition: uthash.h:78

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: