PostGIS  2.2.7dev-r@@SVN_REVISION@@
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 5842 of file lwgeom_topo.c.

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.

5843 {
5844  int i;
5845  *nfaces = -1; /* error condition, by default */
5846  int num;
5847  LWT_ISO_FACE *faces;
5848  int nfacesinbox;
5849  LWT_ELEMID *ids = NULL;
5850  GBOX qbox;
5851  const GEOSPreparedGeometry *ppoly;
5852  GEOSGeometry *polyg;
5853 
5854  /* Get tolerance, if 0 was given */
5855  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5856  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5857 
5858  /* Add each ring as an edge */
5859  for ( i=0; i<poly->nrings; ++i )
5860  {
5861  LWLINE *line;
5862  POINTARRAY *pa;
5863  LWT_ELEMID *eids;
5864  int nedges;
5865 
5866  pa = ptarray_clone(poly->rings[i]);
5867  line = lwline_construct(topo->srid, NULL, pa);
5868  eids = lwt_AddLine( topo, line, tol, &nedges );
5869  if ( nedges < 0 ) {
5870  /* probably too late as lwt_AddLine invoked lwerror */
5871  lwline_free(line);
5872  lwerror("Error adding ring %d of polygon", i);
5873  return NULL;
5874  }
5875  lwline_free(line);
5876  lwfree(eids);
5877  }
5878 
5879  /*
5880  -- Find faces covered by input polygon
5881  -- NOTE: potential snapping changed polygon edges
5882  */
5883  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5884  gbox_expand(&qbox, tol);
5885  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5886  LWT_COL_FACE_ALL, 0 );
5887  if ( nfacesinbox == -1 )
5888  {
5889  lwfree(ids);
5890  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5891  return NULL;
5892  }
5893 
5894  num = 0;
5895  if ( nfacesinbox )
5896  {
5897  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5898  if ( ! polyg )
5899  {
5900  _lwt_release_faces(faces, nfacesinbox);
5901  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5902  return NULL;
5903  }
5904  ppoly = GEOSPrepare(polyg);
5905  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
5906  for ( i=0; i<nfacesinbox; ++i )
5907  {
5908  LWT_ISO_FACE *f = &(faces[i]);
5909  LWGEOM *fg;
5910  GEOSGeometry *fgg, *sp;
5911  int covers;
5912 
5913  /* check if a point on this face surface is covered by our polygon */
5914  fg = lwt_GetFaceGeometry( topo, f->face_id );
5915  if ( ! fg )
5916  {
5917  i = f->face_id; /* so we can destroy faces */
5918  GEOSPreparedGeom_destroy(ppoly);
5919  GEOSGeom_destroy(polyg);
5920  lwfree(ids);
5921  _lwt_release_faces(faces, nfacesinbox);
5922  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, i);
5923  return NULL;
5924  }
5925  /* check if a point on this face's surface is covered by our polygon */
5926  fgg = LWGEOM2GEOS(fg, 0);
5927  lwgeom_free(fg);
5928  if ( ! fgg )
5929  {
5930  GEOSPreparedGeom_destroy(ppoly);
5931  GEOSGeom_destroy(polyg);
5932  _lwt_release_faces(faces, nfacesinbox);
5933  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
5934  return NULL;
5935  }
5936  sp = GEOSPointOnSurface(fgg);
5937  GEOSGeom_destroy(fgg);
5938  if ( ! sp )
5939  {
5940  GEOSPreparedGeom_destroy(ppoly);
5941  GEOSGeom_destroy(polyg);
5942  _lwt_release_faces(faces, nfacesinbox);
5943  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
5944  return NULL;
5945  }
5946  covers = GEOSPreparedCovers( ppoly, sp );
5947  GEOSGeom_destroy(sp);
5948  if (covers == 2)
5949  {
5950  GEOSPreparedGeom_destroy(ppoly);
5951  GEOSGeom_destroy(polyg);
5952  _lwt_release_faces(faces, nfacesinbox);
5953  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
5954  return NULL;
5955  }
5956  if ( ! covers )
5957  {
5958  continue; /* we're not composed by this face */
5959  }
5960 
5961  /* TODO: avoid duplicates ? */
5962  ids[num++] = f->face_id;
5963  }
5964  GEOSPreparedGeom_destroy(ppoly);
5965  GEOSGeom_destroy(polyg);
5966  _lwt_release_faces(faces, nfacesinbox);
5967  }
5968 
5969  /* possibly 0 if non face's surface point was found
5970  * to be covered by input polygon */
5971  *nfaces = num;
5972 
5973  return ids;
5974 }
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:658
Datum covers(PG_FUNCTION_ARGS)
void lwfree(void *mem)
Definition: lwutil.c:214
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:93
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1050
void lwline_free(LWLINE *line)
Definition: lwline.c:63
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4969
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5590
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
const LWT_BE_IFACE * be_iface
LWT_ELEMID face_id
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:640
POINTARRAY ** rings
Definition: liblwgeom.h:441
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:191
int nrings
Definition: liblwgeom.h:439
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int autofix)
#define LWT_COL_FACE_ALL
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2828
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:461
void * lwalloc(size_t size)
Definition: lwutil.c:199
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:124
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:74
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:36

Here is the call graph for this function: