ly/Common/GeoJsonHelper.cs

623 lines
22 KiB
C#
Raw Permalink Normal View History

2025-03-22 12:16:22 +00:00
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
}
}