Combine (union?) and simplify/reduce DbGeometry records for GeoJson

旧城冷巷雨未停 提交于 2019-12-24 04:37:10

问题


I have a number of spatial entities in a table, with a geometry field called Boundaries. I want to produce a GeoJson file with the simplified shapes/geometries.

This is my first attempt:

var entities = await db.Entities.ToListAsync();

dynamic geoJson = new ExpandoObject();
geoJson.type = "FeatureCollection";

var features = new List<dynamic>();

foreach (var entity in entities)
{
    // simplify (uses SqlGeometry.Reduce)
    var simplified = Utilities.Geo.Simplify(entity.Boundaries, tolerance);

    // convert to GeoJSON4EntityFramework.Feature with the appropriate Id
    var feature = Utilities.Geo.GetFeature(simplified, entity.Id);

    features.Add(feature);
}

geoJson.features = features;

return geoJson;

The problem with the result is that, because the geometries are simplified individually, the boundaries aren't common, as shown below:

A second attempt is to combine the entities first, then simplify, then output as GeoJson:

var entities = await db.Entities.ToListAsync();

// bit of a hack to union all the boundaries
DbGeometry allBoundaries = null;
for (var i = 0; i < entities.Count; i++)
{
    if (i == 0) allBoundaries = entities[i].Boundaries;
    else allBoundaries = allBoundaries.Union(entities[i].Boundaries);
}

// simplify (uses SqlGeometry.Reduce)
var simplified = Utilities.Geo.Simplify(allBoundaries, tolerance);

dynamic geoJson = new ExpandoObject();
geoJson.type = "FeatureCollection";

var features = new List<dynamic>();

// convert to GeoJSON4EntityFramework.Feature with the (in)appropriate Id
var feature = Utilities.Geo.GetFeature(simplified, "ALL");

features.Add(feature);

geoJson.features = features;

return geoJson;

However, the .Union is combining the entities into a single entity, despite what is said here that this doesn't happen. (I also then don't have the opportunity to put an Id on each feature, so just used 'ALL' for now). The result is the completely merged shape:

So the question is: how do I combine the boundaries across rows, then simplify, then produce as a feature collection, with each feature having the correct Id, as can be done in MapShaper (shown below)?


回答1:


Looks like this is not possible in SQL Server.

You need to convert the geometries to topologies, then simplify, then match back to the original geometries to preserve the properties/attributes/id/etc.

See: https://trac.osgeo.org/postgis/wiki/UsersWikiSimplifyWithTopologyExt

SQL Server doesn't have support for Topologies.


EDIT

I'm working on the code below, which converts polygons (not multipolygons) to linestrings, unions the linestrings to effectively get a topology layer, then simplifies that. It works really well, but the difficulty is not in converting the multilinestrings to multipolygons, which might need a tool like this.

select
    geometry::STGeomFromText(replace(replace(e1.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326)
    .STUnion(geometry::STGeomFromText(replace(replace(e2.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326))
    .STUnion(geometry::STGeomFromText(replace(replace(e3.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326))
    .Reduce(0.1)
from entities e1
cross join entities e2 
cross join entities e3
where e1.code  = 'dc7'
and e2.code = 'dc6'
and e3.code = 'dc8'


EDIT

Using NetTopologySuite, it can be done. I've written it up here. Using the Polygonizer, you can convert the linestrings back to polygons. Then you have to match the polygons back to the originals by using a ratio of area intersection, and then (if matched) you can re-associate the properties.



来源:https://stackoverflow.com/questions/51755560/combine-union-and-simplify-reduce-dbgeometry-records-for-geojson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!