ly/Common/GeoJsonHelper.cs

623 lines
22 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}