231 lines
8.2 KiB
C#
231 lines
8.2 KiB
C#
|
|
using GeoJSON.Net.Geometry;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using TurfCS;
|
|||
|
|
|
|||
|
|
namespace Assets.Scenes.Ride.Scripts
|
|||
|
|
{
|
|||
|
|
public class TurfHelper
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
//static TurfHelper()
|
|||
|
|
//{
|
|||
|
|
// string name = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".Resources.turf.min.js";
|
|||
|
|
// System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
|||
|
|
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
private LineString _line;
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="points">坐标(lat,lon)</param>
|
|||
|
|
public TurfHelper(IEnumerable<double[]> points)
|
|||
|
|
{
|
|||
|
|
//var list = new GeoJSON.Net.Geometry.GeographicPosition();
|
|||
|
|
var list = points.Select(p => new GeoJSON.Net.Geometry.GeographicPosition(p[0], p[1]));
|
|||
|
|
|
|||
|
|
_line = new LineString(list);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="distance">km</param>
|
|||
|
|
public GeographicPosition Along(double distance)
|
|||
|
|
{
|
|||
|
|
var pt1 = Turf.Along(_line, distance);
|
|||
|
|
return ((GeographicPosition)((GeoJSON.Net.Geometry.Point)pt1.Geometry).Coordinates);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public double Bearing(double[] p1, double[] p2)
|
|||
|
|
{
|
|||
|
|
var pt1 = Turf.Point(p1);
|
|||
|
|
var pt2 = Turf.Point(p2);
|
|||
|
|
return Turf.Bearing(pt1, pt2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取两个点的距离m
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="from"></param>
|
|||
|
|
/// <param name="to"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static double GetDistances(double[] from, double[] to)
|
|||
|
|
{
|
|||
|
|
var pt1 = Turf.Point(from);
|
|||
|
|
var pt2 = Turf.Point(to);
|
|||
|
|
var value = Turf.Distance(pt1, pt2, "kilometers") * 1000;
|
|||
|
|
return Math.Round(value, 2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// https://gist.github.com/neilkennedy/9227665
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="neLng"></param>
|
|||
|
|
/// <param name="neLat"></param>
|
|||
|
|
/// <param name="swLng"></param>
|
|||
|
|
/// <param name="swLat">SouthWest</param>
|
|||
|
|
/// <param name="point">lon,lat</param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static bool Inside(double neLng, double neLat, double swLng, double swLat, double[] point)
|
|||
|
|
{
|
|||
|
|
var poly = Turf.BboxPolygon(new List<double>() { neLng, neLat, swLng, swLat });
|
|||
|
|
var ptIn = Turf.Point(point);
|
|||
|
|
|
|||
|
|
return Turf.Inside(ptIn, poly);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
///// <summary>
|
|||
|
|
/////
|
|||
|
|
///// </summary>
|
|||
|
|
///// <param name="bottomLeft">lng, lat</param>
|
|||
|
|
///// <param name="bottomRight"></param>
|
|||
|
|
///// <param name="topRight"></param>
|
|||
|
|
///// <param name="topLeft"></param>
|
|||
|
|
///// <param name="point"></param>
|
|||
|
|
///// <returns></returns>
|
|||
|
|
//public static bool Inside(List<double[]> points, double[] point)
|
|||
|
|
//{
|
|||
|
|
// var script = new StringBuilder("var points = [];");
|
|||
|
|
// foreach (var item in points)
|
|||
|
|
// {
|
|||
|
|
// script.AppendLine($"points.push([{ string.Join(",", item) }]);");
|
|||
|
|
// }
|
|||
|
|
// script.AppendLine($"points.push([{ string.Join(",", points.First()) }]);");
|
|||
|
|
// script.AppendLine("var poly = turf.polygon([points]);");
|
|||
|
|
// script.AppendLine($"turf.booleanPointInPolygon([{ string.Join(",", point) }], poly);");
|
|||
|
|
|
|||
|
|
|
|||
|
|
// var result = (bool)engine.Evaluate(script.ToString());
|
|||
|
|
|
|||
|
|
// return result;
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
public class location
|
|||
|
|
{
|
|||
|
|
public double lat;
|
|||
|
|
public double lng;
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 坐标点是否在多边形内判断
|
|||
|
|
/// https://www.cnblogs.com/yushuo/p/9304471.html
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="point"></param>
|
|||
|
|
/// <param name="pts"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static bool isPointInPolygon(location point, List<location> pts)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
//检查类型
|
|||
|
|
if (point == null || pts == null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
var N = pts.Count;
|
|||
|
|
var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
|
|||
|
|
var intersectCount = 0; //cross points count of x
|
|||
|
|
var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
|
|||
|
|
location p1, p2; //neighbour bound vertices
|
|||
|
|
var p = point; //测试点
|
|||
|
|
p1 = pts[0]; //left vertex
|
|||
|
|
for (var i = 1; i <= N; ++i)
|
|||
|
|
{
|
|||
|
|
//check all rays
|
|||
|
|
if (p.lat.Equals(p1.lat) && p.lng.Equals(p1.lng))
|
|||
|
|
{
|
|||
|
|
return boundOrVertex; //p is an vertex
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
p2 = pts[i % N]; //right vertex
|
|||
|
|
if (p.lat < Math.Min(p1.lat, p2.lat) || p.lat > Math.Max(p1.lat, p2.lat))
|
|||
|
|
{
|
|||
|
|
//ray is outside of our interests
|
|||
|
|
p1 = p2;
|
|||
|
|
continue; //next ray left point
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (p.lat > Math.Min(p1.lat, p2.lat) && p.lat < Math.Max(p1.lat, p2.lat))
|
|||
|
|
{
|
|||
|
|
//ray is crossing over by the algorithm (common part of)
|
|||
|
|
if (p.lng <= Math.Max(p1.lng, p2.lng))
|
|||
|
|
{
|
|||
|
|
//x is before of ray
|
|||
|
|
if (p1.lat == p2.lat && p.lng >= Math.Min(p1.lng, p2.lng))
|
|||
|
|
{
|
|||
|
|
//overlies on a horizontal ray
|
|||
|
|
return boundOrVertex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (p1.lng == p2.lng)
|
|||
|
|
{
|
|||
|
|
//ray is vertical
|
|||
|
|
if (p1.lng == p.lng)
|
|||
|
|
{
|
|||
|
|
//overlies on a vertical ray
|
|||
|
|
return boundOrVertex;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//before ray
|
|||
|
|
++intersectCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//cross point on the left side
|
|||
|
|
var xinters =
|
|||
|
|
(p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) +
|
|||
|
|
p1.lng; //cross point of lng
|
|||
|
|
if (Math.Abs(p.lng - xinters) < precision)
|
|||
|
|
{
|
|||
|
|
//overlies on a ray
|
|||
|
|
return boundOrVertex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (p.lng < xinters)
|
|||
|
|
{
|
|||
|
|
//before ray
|
|||
|
|
++intersectCount;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//special case when ray is crossing through the vertex
|
|||
|
|
if (p.lat == p2.lat && p.lng <= p2.lng)
|
|||
|
|
{
|
|||
|
|
//p crossing over p2
|
|||
|
|
var p3 = pts[(i + 1) % N]; //next vertex
|
|||
|
|
if (p.lat >= Math.Min(p1.lat, p3.lat) && p.lat <= Math.Max(p1.lat, p3.lat))
|
|||
|
|
{
|
|||
|
|
//p.lat lies between p1.lat & p3.lat
|
|||
|
|
++intersectCount;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
intersectCount += 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
p1 = p2; //next ray left point
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (intersectCount % 2 == 0)
|
|||
|
|
{
|
|||
|
|
//偶数在多边形外
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//奇数在多边形内
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|