static const LWGEOM* lwgeom_subgeom(const LWGEOM* g, int n) { const LWCOLLECTION* c = lwgeom_as_lwcollection(g); if ( c ) return lwcollection_getsubgeom((LWCOLLECTION*)c, n); else return g; }
static int lwgeom_ngeoms(const LWGEOM* n) { const LWCOLLECTION* c = lwgeom_as_lwcollection(n); if ( c ) return c->ngeoms; else return 1; }
static LWGEOM* lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in) { LWGEOM** split_vector=NULL; LWCOLLECTION* out; size_t split_vector_capacity; size_t split_vector_size=0; size_t i,j; split_vector_capacity=8; split_vector = lwalloc(split_vector_capacity * sizeof(LWGEOM*)); if ( ! split_vector ) { lwerror("Out of virtual memory"); return NULL; } for (i=0; i<lwcoll_in->ngeoms; ++i) { LWCOLLECTION* col; LWGEOM* split = lwgeom_split(lwcoll_in->geoms[i], blade_in); /* an exception should prevent this from ever returning NULL */ if ( ! split ) return NULL; col = lwgeom_as_lwcollection(split); /* Output, if any, will always be a collection */ assert(col); /* Reallocate split_vector if needed */ if ( split_vector_size + col->ngeoms > split_vector_capacity ) { /* NOTE: we could be smarter on reallocations here */ split_vector_capacity += col->ngeoms; split_vector = lwrealloc(split_vector, split_vector_capacity * sizeof(LWGEOM*)); if ( ! split_vector ) { lwerror("Out of virtual memory"); return NULL; } } for (j=0; j<col->ngeoms; ++j) { col->geoms[j]->srid = SRID_UNKNOWN; /* strip srid */ split_vector[split_vector_size++] = col->geoms[j]; } lwfree(col->geoms); lwfree(col); } /* Now split_vector has split_vector_size geometries */ out = lwcollection_construct(COLLECTIONTYPE, lwcoll_in->srid, NULL, split_vector_size, split_vector); return (LWGEOM*)out; }
Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; int type = gserialized_get_type(geom); int32 idx; LWCOLLECTION *coll; LWGEOM *subgeom; POSTGIS_DEBUG(2, "LWGEOM_geometryn_collection called."); /* elog(NOTICE, "GeometryN called"); */ idx = PG_GETARG_INT32(1); idx -= 1; /* index is 1-based */ /* call is valid on multi* geoms only */ if (type==POINTTYPE || type==LINETYPE || type==CIRCSTRINGTYPE || type==COMPOUNDTYPE || type==POLYGONTYPE || type==CURVEPOLYTYPE || type==TRIANGLETYPE) { if ( idx == 0 ) PG_RETURN_POINTER(geom); PG_RETURN_NULL(); } coll = lwgeom_as_lwcollection(lwgeom_from_gserialized(geom)); if ( idx < 0 ) PG_RETURN_NULL(); if ( idx >= coll->ngeoms ) PG_RETURN_NULL(); subgeom = coll->geoms[idx]; subgeom->srid = coll->srid; /* COMPUTE_BBOX==TAINTING */ if ( coll->bbox ) lwgeom_add_bbox(subgeom); result = geometry_serialize(subgeom); lwcollection_free(coll); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
int lwgeom_is_closed(const LWGEOM *geom) { int type = geom->type; if( lwgeom_is_empty(geom) ) return LW_FALSE; /* Test linear types for closure */ switch (type) { case LINETYPE: return lwline_is_closed((LWLINE*)geom); case POLYGONTYPE: return lwpoly_is_closed((LWPOLY*)geom); case CIRCSTRINGTYPE: return lwcircstring_is_closed((LWCIRCSTRING*)geom); case COMPOUNDTYPE: return lwcompound_is_closed((LWCOMPOUND*)geom); case TINTYPE: return lwtin_is_closed((LWTIN*)geom); case POLYHEDRALSURFACETYPE: return lwpsurface_is_closed((LWPSURFACE*)geom); } /* Recurse into collections and see if anything is not closed */ if ( lwgeom_is_collection(geom) ) { LWCOLLECTION *col = lwgeom_as_lwcollection(geom); int i; int closed; for ( i = 0; i < col->ngeoms; i++ ) { closed = lwgeom_is_closed(col->geoms[i]); if ( ! closed ) return LW_FALSE; } return LW_TRUE; } /* All non-linear non-collection types we will call closed */ return LW_TRUE; }
void lwgeom_set_srid(LWGEOM *geom, int32_t srid) { int i; LWDEBUGF(4,"entered with srid=%d",srid); geom->srid = srid; if ( lwgeom_is_collection(geom) ) { /* All the children are set to the unknown SRID value TODO: change this so the children have a known SRID? */ LWCOLLECTION *col = lwgeom_as_lwcollection(geom); for ( i = 0; i < col->ngeoms; i++ ) { lwgeom_set_srid(col->geoms[i], SRID_UNKNOWN); } } }
Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM *lwgeom; int32 ret = 1; lwgeom = lwgeom_from_gserialized(geom); if ( lwgeom_is_empty(lwgeom) ) { ret = 0; } else if ( lwgeom_is_collection(lwgeom) ) { LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom); ret = col->ngeoms; } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_INT32(ret); }
/* ** Given a generic collection, return the "simplest" form. ** ** eg: GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING() ** ** GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT()) ** => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT()) ** ** In general, if the subcomponents are homogeneous, return a properly ** typed collection. ** Otherwise, return a generic collection, with the subtypes in minimal ** typed collections. */ static void lwcollection_build_buffer(const LWCOLLECTION *col, HomogenizeBuffer *buffer) { int i; if ( ! col ) return; if ( lwgeom_is_empty(lwcollection_as_lwgeom(col)) ) return; for ( i = 0; i < col->ngeoms; i++ ) { LWGEOM *geom = col->geoms[i]; switch(geom->type) { case POINTTYPE: case LINETYPE: case CIRCSTRINGTYPE: case COMPOUNDTYPE: case TRIANGLETYPE: case CURVEPOLYTYPE: case POLYGONTYPE: { /* Init if necessary */ if ( ! buffer->buf[geom->type] ) { LWCOLLECTION *bufcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags)); bufcol->type = lwtype_get_collectiontype(geom->type); buffer->buf[geom->type] = bufcol; } /* Add sub-geom to buffer */ lwcollection_add_lwgeom(buffer->buf[geom->type], lwgeom_clone(geom)); /* Increment count for this singleton type */ buffer->cnt[geom->type] = buffer->cnt[geom->type] + 1; } default: { lwcollection_build_buffer(lwgeom_as_lwcollection(geom), buffer); } } } return; }
LWGEOM* wkt_parser_collection_add_geom(LWGEOM *col, LWGEOM *geom) { LWDEBUG(4,"entered"); /* Toss error on null geometry input */ if( ! (geom && col) ) { SET_PARSER_ERROR(PARSER_ERROR_OTHER); return NULL; } /* All the elements must agree on dimensionality */ if( FLAGS_NDIMS(col->flags) != FLAGS_NDIMS(geom->flags) ) { lwgeom_free(col); lwgeom_free(geom); SET_PARSER_ERROR(PARSER_ERROR_MIXDIMS); return NULL; } return lwcollection_as_lwgeom(lwcollection_add_lwgeom(lwgeom_as_lwcollection(col), geom)); }
/* 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; }
/** This is a recursive function delivering every possible combination of subgeometries */ int lw_dist3d_recursive(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS3D *dl) { int i, j; int n1=1; int n2=1; LWGEOM *g1 = NULL; LWGEOM *g2 = NULL; LWCOLLECTION *c1 = NULL; LWCOLLECTION *c2 = NULL; LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type); if (lwgeom_is_collection(lwg1)) { LWDEBUG(3, "First geometry is collection"); c1 = lwgeom_as_lwcollection(lwg1); n1 = c1->ngeoms; } if (lwgeom_is_collection(lwg2)) { LWDEBUG(3, "Second geometry is collection"); c2 = lwgeom_as_lwcollection(lwg2); n2 = c2->ngeoms; } for ( i = 0; i < n1; i++ ) { if (lwgeom_is_collection(lwg1)) { g1 = c1->geoms[i]; } else { g1 = (LWGEOM*)lwg1; } if (lwgeom_is_empty(g1)) return LW_TRUE; if (lwgeom_is_collection(g1)) { LWDEBUG(3, "Found collection inside first geometry collection, recursing"); if (!lw_dist3d_recursive(g1, lwg2, dl)) return LW_FALSE; continue; } for ( j = 0; j < n2; j++ ) { if (lwgeom_is_collection(lwg2)) { g2 = c2->geoms[j]; } else { g2 = (LWGEOM*)lwg2; } if (lwgeom_is_collection(g2)) { LWDEBUG(3, "Found collection inside second geometry collection, recursing"); if (!lw_dist3d_recursive(g1, g2, dl)) return LW_FALSE; continue; } /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/ if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE; if (!lw_dist3d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE; if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/ } } return LW_TRUE; }
static void test_lwgeom_split(void) { LWGEOM *geom, *blade, *ret; char *wkt, *in_wkt; geom = lwgeom_from_wkt( "MULTILINESTRING((-5 -2,0 0),(0 0,10 10))", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt( "POINT(0 0)", LW_PARSER_CHECK_NONE); CU_ASSERT(blade != NULL); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(-5 -2,0 0),LINESTRING(0 0,10 10))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #1311 */ geom = lwgeom_from_wkt( "LINESTRING(0 0,10 0,20 4,0 3)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("POINT(10 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0),LINESTRING(10 0,20 4,0 3))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #2528 (1) -- memory leak test, needs valgrind to check */ geom = lwgeom_from_wkt("SRID=1;LINESTRING(0 1,10 1)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("LINESTRING(7 0,7 3)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "SRID=1;GEOMETRYCOLLECTION(LINESTRING(0 1,7 1),LINESTRING(7 1,10 1))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #2528 (2) -- memory leak test, needs valgrind to check */ geom = lwgeom_from_wkt("SRID=1;POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("LINESTRING(7 0,7 20)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "SRID=1;GEOMETRYCOLLECTION(POLYGON((7 1,0 1,0 10,7 10,7 1)),POLYGON((7 10,10 10,10 1,7 1,7 10)))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multiline */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("MULTILINESTRING((1 1,1 -1),(2 1,2 -1,3 -1,3 1))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by polygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt( "POLYGON((1 -2,1 1,2 1,2 -1,3 -1,3 1,11 1,11 -2,1 -2))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by EMPTY polygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("POLYGON EMPTY", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multipolygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt( "MULTIPOLYGON(((1 -1,1 1,2 1,2 -1,1 -1)),((3 -1,3 1,11 1,11 -1,3 -1)))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multipoint */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("MULTIPOINT(2 0,8 0,4 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(8 0,10 0),LINESTRING(0 0,2 0),LINESTRING(4 0,8 0),LINESTRING(2 0,4 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #3401 -- robustness issue */ geom = lwgeom_from_wkt("LINESTRING(-180 0,0 0)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("POINT(-20 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); { LWCOLLECTION *split = lwgeom_as_lwcollection(ret); LWLINE *l1, *l2; POINT2D pt; CU_ASSERT(split != NULL); l1 = lwgeom_as_lwline(split->geoms[0]); CU_ASSERT(l1 != NULL); getPoint2d_p(l1->points, 1, &pt); ASSERT_DOUBLE_EQUAL(pt.x, -20); ASSERT_DOUBLE_EQUAL(pt.y, 0); l2 = lwgeom_as_lwline(split->geoms[1]); CU_ASSERT(l2 != NULL); getPoint2d_p(l2->points, 0, &pt); ASSERT_DOUBLE_EQUAL(pt.x, -20); ASSERT_DOUBLE_EQUAL(pt.y, 0); } lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); }