Объединить два полигона C # DbGeography в один мультиполигон - PullRequest
0 голосов
/ 04 мая 2018

Я загрузил карту со шведскими районами в виде файлов Shape из официального источника. Затем я использовал QGIS для преобразования данных в geojson, а затем преобразовал geojson в DbGeography следующим образом:

https://stackoverflow.com/a/49225753/3850405

Источник карты:

https://www.lantmateriet.se/sv/Kartor-och-geografisk-information/Kartor/oppna-data/hamta-oppna-geodata/#faq:gsd-distriktsindelning

Районы могут иметь две или более областей, но не являются multipolygon, а polygon, где каждая область имеет один и тот же ключ (код). Используя другие официальные источники, я получил multipolygon напрямую, но не из этого источника. Когда я сохраняю его в своей базе данных, я хотел бы сделать это правильно и иметь свойства кода и имени только один раз и сохранить его как multipolygon. Я использую Entity Framework для хранения информации в моей базе данных.

Как объединить два или более полигонов в мультиполигон?

Пример для Stora Hammars distrikt с кодом 101019.

enter image description here

Текущий код:

Модель:

/// <summary>
/// GSD means Geografiska Sverigedata and is available via Lantmäteriet in Sweden.
/// </summary>
public class GSDDistrict
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public string Code { get; set; }

    public string Name { get; set; }

    public string ObjectId { get; set; }

    public string ObjectVer { get; set; }

    public DateTime ValidFrom { get; set; }

    public DbGeography Area { get; set; }
}

Метод:

public void AddGsdDistricts()
{
    using (var reader = File.OpenText($"{path}\\GIS\\lantmateriet-gsd-distriktsindelning.geojson"))
    {
        var json = reader.ReadToEnd();
        var featureCollection = JsonConvert.DeserializeObject<GeoJSON.Net.Feature.FeatureCollection>(json);

        foreach (var feature in featureCollection.Features)
        {
            var code = feature.Properties["DISTRKOD"].ToString();

            var gsdDistrict = new GSDDistrict();
            string geoJson = JsonConvert.SerializeObject(feature.Geometry);
            var dbGeography = JsonConvert.DeserializeObject<DbGeography>(geoJson, new DbGeographyGeoJsonConverter());
            gsdDistrict.Area = dbGeography;
            gsdDistrict.Area = gsdDistrict.Area.MakePolygonValid();

            if (db.GSDDistricts.All(x => x.Code != code))
            {
                gsdDistrict.Code = feature.Properties["DISTRKOD"].ToString();
                gsdDistrict.Name = feature.Properties["DISTRNAMN"].ToString();
                gsdDistrict.ObjectId = feature.Properties["OBJEKT_ID"].ToString();
                gsdDistrict.ObjectVer = feature.Properties["OBJEKT_VER"].ToString();
                gsdDistrict.ValidFrom = DateTime.ParseExact(feature.Properties["GALLERFRAN"].ToString(), "yyyy/MM/dd", CultureInfo.InvariantCulture);
                db.GSDDistricts.Add(gsdDistrict);
                //Yes this will be slow but the method will only run once
                db.SaveChanges();
                Program.LogWithGreenConsoleColour($"Added geo data for {gsdDistrict.Name}");
            }
            else if (db.GSDDistricts.Any(x => x.Code == code && x.Area.Disjoint(gsdDistrict.Area)))
            {
                //Add the other area here
                Program.LogWithGreenConsoleColour($"Here");
            }
        }

        if (db.ChangeTracker.HasChanges())
        {
            db.SaveChanges();
            Program.LogWithGreenConsoleColour($"Saved geo data GSD District from Lantmäteriet to database");
        }
    }
}

Метод расширения MakePolygonValid() заключается в устранении ошибки ориентации кольца, поскольку SQL Server использует ориентацию для левой руки, а почти все источники в Швеции используют ориентацию для правой руки. Метод расширения описан здесь:

https://stackoverflow.com/a/49454154/3850405

1 Ответ

0 голосов
/ 05 мая 2018

Оказывается, мне не нужно было конвертировать его в multipolygon. Ключ был DbGeography.Union.

https://msdn.microsoft.com/en-us/library/system.data.spatial.dbgeography.union(v=vs.110).aspx

else if (db.GSDDistricts.Any(x => x.Code == code && x.Area.Disjoint(gsdDistrict.Area)))
{
    var district = db.GSDDistricts.FirstOrDefault(x => x.Code == code);
    Program.LogWithGreenConsoleColour($"Adding another area for {district.Name}");
    district.Area = district.Area.Union(gsdDistrict.Area);
    db.SaveChanges();                      
}

Похоже, что при загрузке в Google Maps, красная линия вместо чирка выше.

enter image description here

...