From: Sandro Santilli Date: Fri, 5 Feb 2010 17:26:23 +0000 (+0000) Subject: Add ST_isValidDetail(geom) returns valid_detail (new type!) X-Git-Tag: 2.0.0alpha1~3276 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cc3f13155e1b73bf40c9022404d7787db041c4ae;p=postgis Add ST_isValidDetail(geom) returns valid_detail (new type!) git-svn-id: http://svn.osgeo.org/postgis/trunk@5204 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index a5c90df86..51d2fae46 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -16,6 +16,7 @@ #include "lwgeom_geos.h" #include "lwgeom_rtree.h" #include "lwgeom_geos_prepared.h" +#include "funcapi.h" #include @@ -42,6 +43,7 @@ Datum covers(PG_FUNCTION_ARGS); Datum overlaps(PG_FUNCTION_ARGS); Datum isvalid(PG_FUNCTION_ARGS); Datum isvalidreason(PG_FUNCTION_ARGS); +Datum isvaliddetail(PG_FUNCTION_ARGS); Datum buffer(PG_FUNCTION_ARGS); Datum intersection(PG_FUNCTION_ARGS); Datum convexhull(PG_FUNCTION_ARGS); @@ -1449,6 +1451,99 @@ Datum isvalidreason(PG_FUNCTION_ARGS) } +/* +** IsValidDetail is only available in the GEOS +** C API >= version 3.3 +*/ +PG_FUNCTION_INFO_V1(isvaliddetail); +Datum isvaliddetail(PG_FUNCTION_ARGS) +{ +#if POSTGIS_GEOS_VERSION < 33 + lwerror("The GEOS version this postgis binary " + "was compiled against (%d) doesn't support " + "'isValidDetail' function (3.3.0+ required)", + POSTGIS_GEOS_VERSION); + PG_RETURN_NULL(); +#else /* POSTGIS_GEOS_VERSION >= 33 */ + + PG_LWGEOM *geom = NULL; + const GEOSGeometry *g1 = NULL; + char *values[3]; /* valid bool, reason text, location geometry */ + char *geos_reason = NULL; + char *reason = NULL; + const GEOSGeometry *geos_location = NULL; + LWGEOM *location = NULL; + char valid; + Datum result; + TupleDesc tupdesc; + HeapTuple tuple; + AttInMetadata *attinmeta; + + /* + * Build a tuple description for a + * valid_detail tuple + */ + tupdesc = RelationNameGetTupleDesc("valid_detail"); + if ( ! tupdesc ) + { + lwerror("TYPE valid_detail not found"); + PG_RETURN_NULL(); + } + + /* + * generate attribute metadata needed later to produce + * tuples from raw C strings + */ + attinmeta = TupleDescGetAttInMetadata(tupdesc); + + geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + initGEOS(lwnotice, lwnotice); + + g1 = (GEOSGeometry *)POSTGIS2GEOS(geom); + if ( ! g1 ) + { /* TODO: take as invalid */ + PG_RETURN_NULL(); + } + + valid = GEOSisValidDetail(g1, &geos_reason, &geos_location); + GEOSGeom_destroy((GEOSGeometry *)g1); + if ( geos_reason ) + { + reason = pstrdup(geos_reason); + GEOSFree(geos_reason); + } + if ( geos_location ) + { + location = GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location)); + GEOSGeom_destroy((GEOSGeometry *)geos_location); + } + + if (valid == 2) + { + /* NOTE: should only happen on OOM or similar */ + lwerror("GEOS isvaliddetail() threw an exception!"); + PG_RETURN_NULL(); /* never gets here */ + } + + /* the boolean validity */ + values[0] = valid ? "t" : "f"; + + /* the reason */ + values[1] = reason; + + /* the location */ + values[2] = location ? + lwgeom_to_hexwkb(location, PARSER_CHECK_NONE, -1) : 0; + + tuple = BuildTupleFromCStrings(attinmeta, values); + result = HeapTupleGetDatum(tuple); + + PG_RETURN_HEAPTUPLEHEADER(result); + +#endif /* POSTGIS_GEOS_VERSION >= 33 */ +} + /** * overlaps(PG_LWGEOM g1,PG_LWGEOM g2) * @param g1 diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index 9bcfcbdce..432f33f1b 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -3923,6 +3923,17 @@ CREATE OR REPLACE FUNCTION ST_IsValidReason(geometry) LANGUAGE 'C' IMMUTABLE STRICT COST 100; +-- Availability: 2.0.0 +CREATE TYPE valid_detail AS (valid bool, reason varchar, location geometry); + +-- Requires GEOS >= 3.3.0 +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_IsValidDetail(geometry) + RETURNS valid_detail + AS 'MODULE_PATHNAME', 'isvaliddetail' + LANGUAGE 'C' IMMUTABLE STRICT + COST 100; + #if POSTGIS_GEOS_VERSION >= 32 -- Requires GEOS >= 3.2.0 -- Availability: 1.5.0