Handle<Value> Geometry::Relate(const Arguments& args) { HandleScope scope; Geometry *geom = ObjectWrap::Unwrap<Geometry>(args.This()); if (args.Length() < 1) return ThrowException(String::New("requires at least one argument")); Geometry *other = ObjectWrap::Unwrap<Geometry>(args[0]->ToObject()); if (args.Length() == 1) { // Gets a relation pattern (string) from the two geometries char *pattern = GEOSRelate(geom->geos_geom_, other->geos_geom_); if (pattern == NULL) return ThrowException(String::New("couldn't get relate pattern")); Local<Value> pattern_obj = String::New(pattern); GEOSFree(pattern); return scope.Close(pattern_obj); } else if (args.Length() == 2) { // Returns a boolean if the two geometries relate according to the pattern argument String::Utf8Value pattern(args[1]->ToString()); unsigned char r = GEOSRelatePattern(geom->geos_geom_, other->geos_geom_, *pattern); if (r == 2) { return ThrowException(String::New("relate by pattern failed")); } return r ? True() : False(); } return ThrowException(String::New("invalid number of arguments")); }
/* Initializes and uses GEOS internally */ static LWGEOM* lwline_split_by_line(const LWLINE* lwline_in, const LWGEOM* blade_in) { LWGEOM** components; LWGEOM* diff; LWCOLLECTION* out; GEOSGeometry* gdiff; /* difference */ GEOSGeometry* g1; GEOSGeometry* g2; int ret; /* ASSERT blade_in is LINE or MULTILINE */ assert (blade_in->type == LINETYPE || blade_in->type == MULTILINETYPE || blade_in->type == POLYGONTYPE || blade_in->type == MULTIPOLYGONTYPE ); /* Possible outcomes: * * 1. The lines do not cross or overlap * -> Return a collection with single element * 2. The lines cross * -> Return a collection of all elements resulting from the split */ initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS((LWGEOM*)lwline_in, 0); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS(blade_in, 0); if ( ! g2 ) { GEOSGeom_destroy(g1); lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* If blade is a polygon, pick its boundary */ if ( blade_in->type == POLYGONTYPE || blade_in->type == MULTIPOLYGONTYPE ) { gdiff = GEOSBoundary(g2); GEOSGeom_destroy(g2); if ( ! gdiff ) { GEOSGeom_destroy(g1); lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg); return NULL; } g2 = gdiff; gdiff = NULL; } /* If interior intersecton is linear we can't split */ ret = GEOSRelatePattern(g1, g2, "1********"); if ( 2 == ret ) { lwerror("GEOSRelatePattern: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); return NULL; } if ( ret ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("Splitter line has linear intersection with input"); return NULL; } gdiff = GEOSDifference(g1,g2); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (gdiff == NULL) { lwerror("GEOSDifference: %s", lwgeom_geos_errmsg); return NULL; } diff = GEOS2LWGEOM(gdiff, FLAGS_GET_Z(lwline_in->flags)); GEOSGeom_destroy(gdiff); if (NULL == diff) { lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL; } out = lwgeom_as_lwcollection(diff); if ( ! out ) { components = lwalloc(sizeof(LWGEOM*)*1); components[0] = diff; out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, 1, components); } else { /* Set SRID */ lwgeom_set_srid((LWGEOM*)out, lwline_in->srid); /* Force collection type */ out->type = COLLECTIONTYPE; } return (LWGEOM*)out; }
/* Initializes and uses GEOS internally */ static LWGEOM* lwline_split_by_line(const LWLINE* lwline_in, const LWLINE* blade_in) { LWGEOM** components; LWGEOM* diff; LWCOLLECTION* out; GEOSGeometry* gdiff; /* difference */ GEOSGeometry* g1; GEOSGeometry* g2; int ret; /* Possible outcomes: * * 1. The lines do not cross or overlap * -> Return a collection with single element * 2. The lines cross * -> Return a collection of all elements resulting from the split */ initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS((LWGEOM*)lwline_in); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS((LWGEOM*)blade_in); if ( ! g2 ) { GEOSGeom_destroy(g1); lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* If interior intersecton is linear we can't split */ ret = GEOSRelatePattern(g1, g2, "1********"); if ( 2 == ret ) { lwerror("GEOSRelatePattern: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); return NULL; } if ( ret ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("Splitter line has linear intersection with input"); return NULL; } gdiff = GEOSDifference(g1,g2); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (gdiff == NULL) { lwerror("GEOSDifference: %s", lwgeom_geos_errmsg); return NULL; } diff = GEOS2LWGEOM(gdiff, FLAGS_GET_Z(lwline_in->flags)); GEOSGeom_destroy(gdiff); if (NULL == diff) { lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL; } if ( ! lwtype_is_collection(diff->type) ) { components = lwalloc(sizeof(LWGEOM*)*1); components[0] = diff; out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, 1, components); } else { out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, ((LWCOLLECTION*)diff)->ngeoms, ((LWCOLLECTION*)diff)->geoms); } return (LWGEOM*)out; }
Datum coversPrepared(PG_FUNCTION_ARGS) { #ifndef PREPARED_GEOM elog(ERROR,"Not implemented in this version!"); PG_RETURN_NULL(); /* never get here */ #else PG_LWGEOM * geom1; PG_LWGEOM * geom2; bool result; BOX2DFLOAT4 box1, box2; PrepGeomCache * prep_cache; int32 key1; geom1 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); geom2 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); key1 = PG_GETARG_INT32(2); errorIfGeometryCollection(geom1,geom2); errorIfSRIDMismatch(pglwgeom_getSRID(geom1), pglwgeom_getSRID(geom2)); /* * short-circuit: if geom2 bounding box is not completely inside * geom1 bounding box we can prematurely return FALSE. * Do the test IFF BOUNDING BOX AVAILABLE. */ if ( getbox2d_p(SERIALIZED_FORM(geom1), &box1) && getbox2d_p(SERIALIZED_FORM(geom2), &box2) ) { if (( box2.xmin < box1.xmin ) || ( box2.xmax > box1.xmax ) || ( box2.ymin < box1.ymin ) || ( box2.ymax > box1.ymax )) PG_RETURN_BOOL(FALSE); } prep_cache = GetPrepGeomCache( fcinfo, geom1, 0 ); initGEOS(lwnotice, lwnotice); if ( prep_cache && prep_cache->prepared_geom && prep_cache->argnum == 1 ) { GEOSGeom g = POSTGIS2GEOS(geom2); result = GEOSPreparedCovers( prep_cache->prepared_geom, g); GEOSGeom_destroy(g); } else { GEOSGeom g1 = POSTGIS2GEOS(geom1); GEOSGeom g2 = POSTGIS2GEOS(geom2); result = GEOSRelatePattern( g1, g2, "******FF*" ); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); } if (result == 2) { elog(ERROR,"GEOS contains() threw an error!"); PG_RETURN_NULL(); /* never get here */ } PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_BOOL(result); #endif /* PREPARED_GEOM */ }