PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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
void * lwalloc(size_t size)
Definition lwutil.c:227
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
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:311
void lwline_free(LWLINE *line)
Definition lwline.c:67
int lwpoly_is_empty(const LWPOLY *poly)
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition ptarray.c:665
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
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
#define _LWT_MINTOLERANCE(topo, geom)
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
#define LWTFMT_ELEMID
Definition lwgeom_topo.c:43
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
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: