623 lines
22 KiB
C#
623 lines
22 KiB
C#
using LY.App.Model;
|
||
using NetTopologySuite.Features;
|
||
using NetTopologySuite.Geometries;
|
||
using NetTopologySuite.IO;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
|
||
namespace LY.App.Common
|
||
{
|
||
public class GeoJsonHelper
|
||
{
|
||
/// <summary>
|
||
/// 格式为json字符串
|
||
/// </summary>
|
||
/// <param name="str"></param>
|
||
/// <returns></returns>
|
||
public static string ConvertJsonString(string str)
|
||
{
|
||
try
|
||
{
|
||
//格式化json字符串
|
||
JsonSerializer serializer = new JsonSerializer();
|
||
TextReader tr = new StringReader(str);
|
||
JsonTextReader jtr = new JsonTextReader(tr);
|
||
object obj = serializer.Deserialize(jtr);
|
||
if (obj != null)
|
||
{
|
||
|
||
StringWriter textWriter = new StringWriter();
|
||
JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
|
||
{
|
||
Formatting = Formatting.Indented,
|
||
Indentation = 4,
|
||
IndentChar = ' '
|
||
};
|
||
serializer.Serialize(jsonWriter, obj);
|
||
return textWriter.ToString();
|
||
|
||
}
|
||
else
|
||
{
|
||
return str;
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
|
||
}
|
||
return str;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换为geojson格式字符串
|
||
/// </summary>
|
||
/// <param name="value"></param>
|
||
/// <returns></returns>
|
||
public static string GetGeoJson(object? value)
|
||
{
|
||
if (value == null)
|
||
return "";
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var sw = new System.IO.StringWriter())
|
||
{
|
||
serializer.Serialize(sw, value);
|
||
|
||
return sw.ToString();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将坐标转换为点
|
||
/// </summary>
|
||
/// <param name="x">经度</param>
|
||
/// <param name="y">纬度</param>
|
||
/// <returns></returns>
|
||
public static NetTopologySuite.Geometries.Point ConvertToPoint(double x, double y)
|
||
{
|
||
return new NetTopologySuite.Geometries.Point(x, y);
|
||
}
|
||
|
||
|
||
public static object? GetDynamicFeature(Geometry geometry, IDictionary<string, object> attributes)
|
||
{
|
||
var f = GetGeoFeature(geometry, attributes);
|
||
var geoJson = GetGeoJson(f);
|
||
return geoJson;
|
||
// return JsonConvert.DeserializeObject(geoJson);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取集合中能够组成多面的几何数据
|
||
/// </summary>
|
||
/// <param name="features"></param>
|
||
/// <returns></returns>
|
||
public static List<MultiPolygon> GetGeoMultiPolygon(FeatureCollection features)
|
||
{
|
||
var result = new List<MultiPolygon>();
|
||
if (features == null)
|
||
return result;
|
||
foreach (var feature in features)
|
||
{
|
||
if (feature.Geometry is MultiPolygon)
|
||
{
|
||
result.Add(feature.Geometry as MultiPolygon);
|
||
}
|
||
else if (feature.Geometry is Polygon)
|
||
{
|
||
result.Add(new MultiPolygon(new Polygon[] { feature.Geometry as Polygon }));
|
||
}
|
||
else if (feature.Geometry is LineString)
|
||
{
|
||
var line = (LineString)feature.Geometry;
|
||
if (line.IsRing)
|
||
{
|
||
result.Add(new MultiPolygon(new Polygon[] { new Polygon(new LinearRing(line.Coordinates)) }));
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取集合中能够组成多线的几何数据
|
||
/// </summary>
|
||
/// <param name="features"></param>
|
||
/// <returns></returns>
|
||
public static List<MultiLineString> GetGeoMultiLineString(FeatureCollection features)
|
||
{
|
||
var result = new List<MultiLineString>();
|
||
if (features == null)
|
||
return result;
|
||
foreach (var feature in features)
|
||
{
|
||
if (feature.Geometry is MultiLineString)
|
||
{
|
||
result.Add(feature.Geometry as MultiLineString);
|
||
}
|
||
else if (feature.Geometry is LineString)
|
||
{
|
||
result.Add(new MultiLineString(new LineString[] { feature.Geometry as LineString }));
|
||
}
|
||
else if (feature.Geometry is MultiPoint)
|
||
{
|
||
var mp = (MultiPoint)feature.Geometry;
|
||
if (mp.Count() > 1)
|
||
{
|
||
result.Add(new MultiLineString(new LineString[] { new LineString(mp.Coordinates) }));
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将geojson转为FeatureCollection,
|
||
/// 原json支持点、线面等
|
||
/// </summary>
|
||
/// <param name="geoJson"></param>
|
||
/// <returns></returns>
|
||
public static FeatureCollection? GetGeoFeatureCollectionBuild(string geoJson)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(geoJson)) return null;
|
||
|
||
try
|
||
{
|
||
var jObj = JObject.Parse(geoJson);
|
||
if (jObj != null)
|
||
{
|
||
if (jObj.TryGetValue("type", out var jToken))
|
||
{
|
||
if (jToken != null)
|
||
{
|
||
if (string.Compare(jToken.ToString(), "FeatureCollection") == 0)
|
||
{
|
||
return GetGeoFeatureCollection(geoJson);
|
||
}
|
||
else
|
||
{
|
||
var f = GetGeoFeatureBuild(geoJson);
|
||
if (f != null)
|
||
{
|
||
var result = new FeatureCollection();
|
||
result.Add(f);
|
||
return result;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
|
||
throw new Exception("geojson无效");
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public static Feature? GetGeoFeatureBuild(string geoJson)
|
||
{
|
||
var jObj = JObject.Parse(geoJson);
|
||
if (jObj != null)
|
||
{
|
||
//先判断type
|
||
if (jObj.TryGetValue("type", out var jToken))
|
||
{
|
||
if (jToken != null)
|
||
{
|
||
if (string.Compare(jToken.ToString(), "Feature") == 0)
|
||
{
|
||
return GetGeoFeature(geoJson);
|
||
}
|
||
|
||
Geometry? geometry = null;
|
||
if (string.Compare(jToken.ToString(), "Point") == 0)
|
||
{
|
||
geometry = GetGeoPoint(geoJson);
|
||
}
|
||
if (string.Compare(jToken.ToString(), "MultiPoint") == 0)
|
||
{
|
||
geometry = GetGeoMultiPoint(geoJson);
|
||
}
|
||
if (string.Compare(jToken.ToString(), "LineString") == 0)
|
||
{
|
||
geometry = GetGeoLineString(geoJson);
|
||
}
|
||
if (string.Compare(jToken.ToString(), "MultiLineString") == 0)
|
||
{
|
||
geometry = GetGeoMultiLineString(geoJson);
|
||
}
|
||
if (string.Compare(jToken.ToString(), "Polygon") == 0)
|
||
{
|
||
geometry = GetGeoPolygon(geoJson);
|
||
}
|
||
if (string.Compare(jToken.ToString(), "MultiPolygon") == 0)
|
||
{
|
||
geometry = GetGeoMultiPolygon(geoJson);
|
||
}
|
||
|
||
if (geometry != null)
|
||
return new Feature(geometry, new AttributesTable());
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public static Feature? GetGeoFeature(Geometry geometry, IDictionary<string, object> attributes)
|
||
{
|
||
AttributesTable attributesTable = new AttributesTable();
|
||
foreach (var item in attributes)
|
||
{
|
||
attributesTable.Add(item.Key, item.Value);
|
||
}
|
||
var result = new Feature(geometry, attributesTable);
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
public static Feature? GetGeoFeature(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Features.Feature>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static FeatureCollection? GetGeoFeatureCollection(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Features.FeatureCollection>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.Point? GetGeoPoint(string geoJson)
|
||
{
|
||
var jObj = JObject.Parse(geoJson);
|
||
if (jObj != null)
|
||
{
|
||
//先判断type
|
||
if (jObj.TryGetValue("type", out var jToken))
|
||
{
|
||
if (jToken != null)
|
||
{
|
||
if (string.Compare(jToken.ToString(), "Feature") == 0)
|
||
{
|
||
var f = GetGeoFeature(geoJson);
|
||
if (f.Geometry is Point)
|
||
return f.Geometry as NetTopologySuite.Geometries.Point;
|
||
|
||
}
|
||
else
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.Point>(jsonReader);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.MultiPoint? GetGeoMultiPoint(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.MultiPoint>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.LineString? GetGeoLineString(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.LineString>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.MultiLineString? GetGeoMultiLineString(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.MultiLineString>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.Polygon? GetGeoPolygon(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.Polygon>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static NetTopologySuite.Geometries.MultiPolygon? GetGeoMultiPolygon(string geoJson)
|
||
{
|
||
var serializer = GeoJsonSerializer.Create();
|
||
using (var stringReader = new StringReader(geoJson))
|
||
using (var jsonReader = new JsonTextReader(stringReader))
|
||
{
|
||
return serializer.Deserialize<NetTopologySuite.Geometries.MultiPolygon>(jsonReader);
|
||
}
|
||
}
|
||
|
||
public static bool TryGetGeomWKTFromGeoJson(string? geoJson, out MultiPolygon? geometry)
|
||
{
|
||
geometry = null;
|
||
try
|
||
{
|
||
if (!string.IsNullOrWhiteSpace(geoJson))
|
||
{
|
||
var features = GeoJsonHelper.GetGeoFeatureCollectionBuild(geoJson);
|
||
var multPolygons = GeoJsonHelper.GetGeoMultiPolygon(features);
|
||
if (multPolygons?.Count > 0)
|
||
{
|
||
geometry = multPolygons[0];
|
||
geometry.SRID = 4326;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
return false;
|
||
}
|
||
public static Geometry FromWKT(string wktData)
|
||
{
|
||
WKTReader reader = new WKTReader();
|
||
return reader.Read(wktData);
|
||
}
|
||
|
||
public static Geometry FromWKB(byte[] wkbData)
|
||
{
|
||
WKBReader reader = new WKBReader();
|
||
return reader.Read(wkbData);
|
||
|
||
}
|
||
public static Polygon Transfer2CoordinateByCoords(List<Point> Coords)
|
||
{
|
||
if (Coords.Any())
|
||
{
|
||
var list = Coords.Select(s => s.X + "" + s.Y).ToList();
|
||
var content = $"POLYGON(({string.Join(",", list)}))";
|
||
WKTReader wktReader = new WKTReader();
|
||
Polygon polygon = wktReader.Read(content) as Polygon;
|
||
return polygon;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
#region 坐标相关方法
|
||
|
||
private static GeometryFactory _gf = NetTopologySuite.NtsGeometryServices.Instance.CreateGeometryFactory(4326);
|
||
public static bool IsWithin(BasePoint pnt, BasePoint[] polygon)
|
||
{
|
||
if (IsValidPolygon(polygon))
|
||
{
|
||
var point = CreatPoint(pnt);
|
||
var region = CreatePolygon(polygon);
|
||
return point.Within(region);
|
||
}
|
||
return false;
|
||
}
|
||
/// <summary>
|
||
/// 判断点是否在多边形内
|
||
/// </summary>
|
||
/// <param name="pnt"></param>
|
||
/// <param name="multiPolygon"></param>
|
||
/// <returns></returns>
|
||
public static bool isWithin(BasePoint pnt, MultiPolygon multiPolygon)
|
||
{
|
||
var point = CreatPoint(pnt);
|
||
return point.Within(multiPolygon);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基本判断点数据是否有效转为面
|
||
/// </summary>
|
||
/// <param name="polygon"></param>
|
||
/// <returns></returns>
|
||
public static bool IsValidPolygon(BasePoint[] polygon)
|
||
{
|
||
if (polygon?.Count() >= 4)
|
||
{
|
||
//polygon.Distinct();//重复点?
|
||
return polygon[0].Equal(polygon[polygon.Count() - 1]);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基本判断点数据是否有效转为线
|
||
/// </summary>
|
||
/// <param name="polygon"></param>
|
||
/// <returns></returns>
|
||
public static bool IsValidLineString(BasePoint[] polygon)
|
||
{
|
||
if (polygon?.Count() >= 2)
|
||
{
|
||
//polygon.Distinct();//重复点?
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建点
|
||
/// </summary>
|
||
/// <param name="pnt"></param>
|
||
/// <returns></returns>
|
||
public static Point CreatPoint(BasePoint pnt)
|
||
{
|
||
return _gf.CreatePoint(GetCoordinate(pnt));
|
||
}
|
||
/// <summary>
|
||
/// 创建点
|
||
/// </summary>
|
||
/// <param name="pnt"></param>
|
||
/// <returns></returns>
|
||
public static Point CreatPoint(double x, double y)
|
||
{
|
||
return _gf.CreatePoint(GetCoordinate(x, y));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建线
|
||
/// </summary>
|
||
/// <param name="polygon"></param>
|
||
/// <returns></returns>
|
||
public static LineString CreateLineString(BasePoint[] points)
|
||
{
|
||
return _gf.CreateLineString(GetCoordinate(points));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建面
|
||
/// </summary>
|
||
/// <param name="polygon"></param>
|
||
/// <returns></returns>
|
||
public static Polygon CreatePolygon(BasePoint[] polygon)
|
||
{
|
||
return _gf.CreatePolygon(GetCoordinate(polygon));
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 点转换到坐标
|
||
/// </summary>
|
||
/// <param name="pnt"></param>
|
||
/// <returns></returns>
|
||
public static NetTopologySuite.Geometries.Coordinate GetCoordinate(BasePoint pnt)
|
||
{
|
||
return new NetTopologySuite.Geometries.Coordinate(pnt.X, pnt.Y);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 点转换到坐标
|
||
/// </summary>
|
||
/// <param name="pnt"></param>
|
||
/// <returns></returns>
|
||
public static NetTopologySuite.Geometries.Coordinate GetCoordinate(double x, double y)
|
||
{
|
||
return new NetTopologySuite.Geometries.Coordinate(x, y);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 点组转换坐标组
|
||
/// </summary>
|
||
/// <param name="polygon"></param>
|
||
/// <returns></returns>
|
||
public static NetTopologySuite.Geometries.Coordinate[] GetCoordinate(BasePoint[] polygon)
|
||
{
|
||
List<NetTopologySuite.Geometries.Coordinate> coordinates = new List<NetTopologySuite.Geometries.Coordinate>();
|
||
foreach (var item in polygon)
|
||
{
|
||
coordinates.Add(GetCoordinate(item));
|
||
}
|
||
return coordinates.ToArray();
|
||
}
|
||
|
||
public static Geometry CreateCircleMercator(double x, double y, double radius)
|
||
{
|
||
var geometryFactory = new GeometryFactory();
|
||
var wbp = CoordConvert.WGS84ToMercator(x, y);
|
||
var point1 = geometryFactory.CreatePoint(new NetTopologySuite.Geometries.Coordinate(wbp.X, wbp.Y));
|
||
var geo = point1.Buffer(radius, 80);
|
||
//var geo1 = point1.Buffer(radius);
|
||
return geo;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建圆形
|
||
/// </summary>
|
||
/// <param name="x"></param>
|
||
/// <param name="y"></param>
|
||
/// <param name="radius"></param>
|
||
/// <returns></returns>
|
||
public static Geometry CreateCircle(double x, double y, double radius, int pnts = 100)
|
||
{
|
||
var geo1 = CreateCircleMercator(x, y, radius);
|
||
var coordinates = geo1.Coordinates;
|
||
List<BasePoint> points = new List<BasePoint>();
|
||
foreach (var item in coordinates)
|
||
{
|
||
var wgs84 = CoordConvert.MercatorToWGS84(item.X, item.Y);
|
||
points.Add(new BasePoint(wgs84.Lon, wgs84.Lat, 0));
|
||
}
|
||
return CreatePolygon(points.ToArray());
|
||
}
|
||
public static double CalculateCircleAreaKmUnit(double x, double y, double radius)
|
||
{
|
||
if (x > 0 && y > 0 && radius > 0)
|
||
{
|
||
var area11 = CalculateCircleArea(x, y, radius);
|
||
return Math.Round(area11 / 1000000, 5);
|
||
}
|
||
return 0;
|
||
}
|
||
public static double CalculateCircleArea(double x, double y, double radius)
|
||
{
|
||
if (x > 0 && y > 0 && radius > 0)
|
||
{
|
||
var geo1 = CreateCircleMercator(x, y, radius);
|
||
return geo1.Area;
|
||
}
|
||
return 0;
|
||
}
|
||
/// <summary>
|
||
/// 计算合并后的总面积
|
||
/// </summary>
|
||
/// <param name="geometries"></param>
|
||
/// <returns></returns>
|
||
public static double CalculateAreaMercator(Geometry[] geometries)
|
||
{
|
||
//将多个 Geometry 合并成一个 Geometry,避免交集重复计算
|
||
var unionedGeometry = _gf.BuildGeometry(geometries).Union();
|
||
string geojson = GetGeoJson(unionedGeometry);
|
||
var area = unionedGeometry.Area;
|
||
// 计算合并后的总面积
|
||
return area;
|
||
}
|
||
///// <summary>
|
||
///// 计算合并后的总面积
|
||
///// </summary>
|
||
///// <param name="geometries"></param>
|
||
///// <returns></returns>
|
||
//public static double CalculateArea(Geometry[] geometries)
|
||
//{
|
||
// //将多个 Geometry 合并成一个 Geometry,避免交集重复计算
|
||
// var unionedGeometry = _gf.BuildGeometry(geometries).Union();
|
||
// string geojson = GetGeoJson(unionedGeometry);
|
||
// var area = Math.Round(unionedGeometry.ProjectTo(2855).Area / 1000000.0, 5);
|
||
// // 计算合并后的总面积
|
||
// return area;
|
||
//}
|
||
|
||
#endregion
|
||
|
||
|
||
|
||
}
|
||
}
|