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

Definition at line 7546 of file lwgeom_topo.c.

7547{
7548 *nfaces = -1; /* error condition, by default */
7549 int num;
7550 LWT_ISO_FACE *faces;
7551 uint64_t nfacesinbox;
7552 uint64_t j;
7553 LWT_ELEMID *ids = NULL;
7554 GBOX qbox;
7555 const GEOSPreparedGeometry *ppoly;
7556 GEOSGeometry *polyg;
7557
7558 /* Nothing to add, in an empty polygon */
7559 if ( lwpoly_is_empty(poly) )
7560 {
7561 *nfaces = 0;
7562 return NULL;
7563 }
7564
7565 /* Get tolerance, if 0 was given */
7566 if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
7567 LWDEBUGF(1, "Working tolerance:%.15g", tol);
7568
7569 lwt_LoadPolygon(topo, poly, tol);
7570
7571 /*
7572 -- Find faces covered by input polygon
7573 -- NOTE: potential snapping changed polygon edges
7574 */
7575 qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
7576 gbox_expand(&qbox, tol);
7577 faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
7578 LWT_COL_FACE_ALL, 0 );
7579 if (nfacesinbox == UINT64_MAX)
7580 {
7581 lwfree(ids);
7583 return NULL;
7584 }
7585
7586 num = 0;
7587 if ( nfacesinbox )
7588 {
7589 polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
7590 if ( ! polyg )
7591 {
7592 _lwt_release_faces(faces, nfacesinbox);
7593 lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
7594 return NULL;
7595 }
7596 ppoly = GEOSPrepare(polyg);
7597 ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
7598 for ( j=0; j<nfacesinbox; ++j )
7599 {
7600 LWT_ISO_FACE *f = &(faces[j]);
7601 LWGEOM *fg;
7602 GEOSGeometry *fgg, *sp;
7603 int covers;
7604
7605 /* check if a point on this face surface is covered by our polygon */
7606 fg = lwt_GetFaceGeometry( topo, f->face_id );
7607 if ( ! fg )
7608 {
7609 j = f->face_id; /* so we can destroy faces */
7610 GEOSPreparedGeom_destroy(ppoly);
7611 GEOSGeom_destroy(polyg);
7612 lwfree(ids);
7613 _lwt_release_faces(faces, nfacesinbox);
7614 lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
7615 return NULL;
7616 }
7617 /* check if a point on this face's surface is covered by our polygon */
7618 fgg = LWGEOM2GEOS(fg, 0);
7619 lwgeom_free(fg);
7620 if ( ! fgg )
7621 {
7622 GEOSPreparedGeom_destroy(ppoly);
7623 GEOSGeom_destroy(polyg);
7624 _lwt_release_faces(faces, nfacesinbox);
7625 lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
7626 return NULL;
7627 }
7628 sp = GEOSPointOnSurface(fgg);
7629 GEOSGeom_destroy(fgg);
7630 if ( ! sp )
7631 {
7632 GEOSPreparedGeom_destroy(ppoly);
7633 GEOSGeom_destroy(polyg);
7634 _lwt_release_faces(faces, nfacesinbox);
7635 lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
7636 return NULL;
7637 }
7638 covers = GEOSPreparedCovers( ppoly, sp );
7639 GEOSGeom_destroy(sp);
7640 if (covers == 2)
7641 {
7642 GEOSPreparedGeom_destroy(ppoly);
7643 GEOSGeom_destroy(polyg);
7644 _lwt_release_faces(faces, nfacesinbox);
7645 lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
7646 return NULL;
7647 }
7648 if ( ! covers )
7649 {
7650 continue; /* we're not composed by this face */
7651 }
7652
7653 /* TODO: avoid duplicates ? */
7654 ids[num++] = f->face_id;
7655 }
7656 GEOSPreparedGeom_destroy(ppoly);
7657 GEOSGeom_destroy(polyg);
7658 _lwt_release_faces(faces, nfacesinbox);
7659 }
7660
7661 /* possibly 0 if non face's surface point was found
7662 * to be covered by input polygon */
7663 *nfaces = num;
7664
7665 return ids;
7666}
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:1218
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
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
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:329
int lwpoly_is_empty(const LWPOLY *poly)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
Datum covers(PG_FUNCTION_ARGS)
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
static void lwt_LoadPolygon(LWT_TOPOLOGY *topo, const LWPOLY *poly, double tol)
#define _LWT_MINTOLERANCE(topo, geom)
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
LWT_ELEMID face_id

References _LWT_MINTOLERANCE, _lwt_release_faces(), covers(), LWT_ISO_FACE::face_id, gbox_expand(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwpoly_as_lwgeom(), lwpoly_is_empty(), lwt_be_getFaceWithinBox2D(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), lwt_LoadPolygon(), LWTFMT_ELEMID, and PGTOPO_BE_ERROR.

Here is the call graph for this function: