Я загрузил карту со шведскими районами в виде файлов 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
.
Текущий код:
Модель:
/// <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