You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetTopologySuite.Geometries;
namespace FortAnalysis
{
public class PolygonSplit
{
// 找到自相交多边形的交点
private static List<Tuple<double, double>> FindIntersectionPoints(List<Tuple<double, double>> coordinates)
{
List<Tuple<double, double>> intersectionPoints = new List<Tuple<double, double>>();
for (int i = 0; i < coordinates.Count; i++)
{
var edge1Start = coordinates[i];
var edge1End = coordinates[(i + 1) % coordinates.Count];
for (int j = i + 2; j < coordinates.Count + i - 1; j++)
{
var edge2Start = coordinates[j % coordinates.Count];
var edge2End = coordinates[(j + 1) % coordinates.Count];
var intersection = FindIntersection(edge1Start, edge1End, edge2Start, edge2End);
if (intersection != null)
{
intersectionPoints.Add(intersection);
}
}
}
return intersectionPoints;
}
// 找到两条边的交点
private static Tuple<double, double> FindIntersection(Tuple<double, double> p1, Tuple<double, double> p2, Tuple<double, double> p3, Tuple<double, double> p4)
{
double x1 = p1.Item1;
double y1 = p1.Item2;
double x2 = p2.Item1;
double y2 = p2.Item2;
double x3 = p3.Item1;
double y3 = p3.Item2;
double x4 = p4.Item1;
double y4 = p4.Item2;
double denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (Math.Abs(denominator) < double.Epsilon)
{
return null; // 平行或共线,无交点
}
double x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denominator;
double y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denominator;
return new Tuple<double, double>(x, y);
}
// 根据交点分割多边形集合
public static List<List<Coordinate>> SplitPolygons(List<List<Coordinate>> polygons, List<Coordinate> intersectionPoints)
{
List<List<Coordinate>> splittedPolygons = new List<List<Coordinate>>();
foreach (var polygon in polygons)
{
List<Coordinate> splittedPolygon = new List<Coordinate>(polygon);
foreach (var intersectionPoint in intersectionPoints)
{
if (IsInsidePolygon(intersectionPoint, polygon))
{
splittedPolygon.Add(intersectionPoint);
}
}
splittedPolygon = splittedPolygon.OrderBy(p => Math.Atan2(p.Y - intersectionPoints[0].Y, p.X - intersectionPoints[0].X)).ToList();
splittedPolygons.Add(splittedPolygon);
}
return splittedPolygons;
}
// 判断点是否在多边形内部
private static bool IsInsidePolygon(Coordinate point, List<Coordinate> polygon)
{
int count = 0;
int n = polygon.Count;
for (int i = 0; i < n; i++)
{
var p1 = polygon[i];
var p2 = polygon[(i + 1) % n];
if (IsPointOnSegment(point, p1, p2))
{
return true; // 点在多边形的边上
}
if (point.Y > Math.Min(p1.Y, p2.Y) && point.Y <= Math.Max(p1.Y, p2.Y) && point.X <= Math.Max(p1.X, p2.X) && p1.Y != p2.Y)
{
double xIntersection = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X;
if (p1.X == p2.X || point.X <= xIntersection)
{
count++;
}
}
}
return count % 2 == 1;
}
// 判断点是否在线段上
private static bool IsPointOnSegment(Coordinate point, Coordinate p1, Coordinate p2)
{
return Math.Abs(Distance(point, p1) + Distance(point, p2) - Distance(p1, p2)) < double.Epsilon;
}
// 计算两个点之间的距离
private static double Distance(Coordinate p1, Coordinate p2)
{
double dx = p1.X - p2.X;
double dy = p1.Y - p2.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
}
}