|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using DfdIO;
|
|
|
using NetTopologySuite.Geometries;
|
|
|
|
|
|
namespace Construction.BatchCreateMap
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 凸包算法
|
|
|
/// </summary>
|
|
|
public class PointsHull
|
|
|
{
|
|
|
private static double ToleranceFactor = 1e-30;
|
|
|
/**
|
|
|
* 下面实现一下正规的braham算法
|
|
|
* 1,将满足要求的点放在[0]位置处
|
|
|
* 2,按照与[0]点的极角大小,对其它点排序,从小到达排序
|
|
|
* 3,将[0][1][2]点放入栈中,然后判断所有其它点是不是都在[top-1][top]向量的逆时针方向
|
|
|
* 3.1 如果是,则取下一点放入栈中,并继续判断,直到没有更多点再放入栈中
|
|
|
* 3.2 如果不是,则弹出[top]点,并加入下一点,继续判断
|
|
|
* */
|
|
|
/// <summary>
|
|
|
/// 凸包算法-braham扫描
|
|
|
/// </summary>
|
|
|
public static CoordinateList Brahamscan(Coordinate[] set, double distanceStep)
|
|
|
{
|
|
|
//记录下来满足起始点要求的元素的下标
|
|
|
int nCount = set.Length;
|
|
|
int unum = 0;
|
|
|
for (int i = 1; i < nCount; i++)
|
|
|
{
|
|
|
if (set[unum].Y > set[i].Y ||
|
|
|
(set[unum].Y == set[i].Y && set[unum].X > set[i].X))
|
|
|
{
|
|
|
unum = i;
|
|
|
}
|
|
|
}
|
|
|
//将满足要求的元素放在第一位
|
|
|
if (unum != 0)
|
|
|
{
|
|
|
Coordinate tmp = set[0];
|
|
|
set[0] = set[unum];
|
|
|
set[unum] = tmp;
|
|
|
}
|
|
|
//对set进行排序,快速排序
|
|
|
QSort(set, 1, nCount - 1);
|
|
|
|
|
|
CoordinateList lstReturn = new CoordinateList();
|
|
|
lstReturn.Add(set[0]);
|
|
|
for (int i = 1; i < nCount; i++)
|
|
|
{
|
|
|
if (isok(set, lstReturn[lstReturn.Count - 1], set[i]))
|
|
|
{
|
|
|
lstReturn.Add(set[i]);
|
|
|
}
|
|
|
}
|
|
|
lstReturn.Add(lstReturn[0]);
|
|
|
// 重新以中心点进行排序
|
|
|
//DfPoint dfpCenter = getCenterPoint(set);
|
|
|
//set.Insert(0, dfpCenter);
|
|
|
//QSort(set, 1, set.Count - 1);
|
|
|
|
|
|
//DfPoint dpStart, dpEnd;
|
|
|
//for (int i = 0; i < lstReturn.Count - 1; i++)
|
|
|
//{
|
|
|
// dpStart = lstReturn[i];
|
|
|
// dpEnd = lstReturn[i + 1];
|
|
|
// for (int j = 0; j < set.Count; j++)
|
|
|
// {
|
|
|
// if ((set[j].X == dpStart.X && set[j].Y == dpStart.Y)
|
|
|
// || (set[j].X == dpEnd.X && set[j].Y == dpEnd.Y))
|
|
|
// {
|
|
|
// continue;
|
|
|
// }
|
|
|
// double h = Math.Abs(Multi(dpStart, set[j], dpEnd)) / Dist(dpStart, dpEnd);
|
|
|
// // 距离小于步长,并且垂足在线段内部
|
|
|
// if (h < distanceStep && isPedalIn(dpStart, dpEnd, set[j]))
|
|
|
// {
|
|
|
// lstReturn.Insert(i + 1, set[j]);
|
|
|
// set.RemoveAt(j);
|
|
|
// j--;
|
|
|
// i++;
|
|
|
// }
|
|
|
// }
|
|
|
//}
|
|
|
return lstReturn;
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 两点距离
|
|
|
/// </summary>
|
|
|
/// <param name="arg1"> </param>
|
|
|
/// <param name="arg2"> </param>
|
|
|
/// <returns> </returns>
|
|
|
static double Dist(DfPoint arg1, DfPoint arg2)
|
|
|
{
|
|
|
return Math.Sqrt((arg1.X - arg2.X) * (arg1.X - arg2.X)
|
|
|
+ (arg1.Y - arg2.Y) * (arg1.Y - arg2.Y));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获得中心点
|
|
|
/// </summary>
|
|
|
/// <param name="trackPoints"> </param>
|
|
|
/// <returns> </returns>
|
|
|
private static DfPoint getCenterPoint(List<DfPoint> trackPoints)
|
|
|
{
|
|
|
DfPoint dfpReturn = new DfPoint();
|
|
|
int nLength = trackPoints.Count;
|
|
|
for (int i = 0; i < nLength; i++)
|
|
|
{
|
|
|
dfpReturn.X += trackPoints[i].X / nLength;
|
|
|
dfpReturn.Y += trackPoints[i].Y / nLength;
|
|
|
}
|
|
|
return dfpReturn;
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 计算垂足
|
|
|
/// </summary>
|
|
|
/// <param name="startPoint"> </param>
|
|
|
/// <param name="endPoint"> </param>
|
|
|
/// <param name="outPoint"> </param>
|
|
|
/// <returns> </returns>
|
|
|
private static DfPoint getPedal(DfPoint startPoint, DfPoint endPoint, DfPoint outPoint)
|
|
|
{
|
|
|
DfPoint dfpReturn = new DfPoint();
|
|
|
double dA, dB, dC;// 直线方程系数
|
|
|
dA = (endPoint.Y - startPoint.Y);
|
|
|
dB = startPoint.X - endPoint.X;
|
|
|
dC = dA * startPoint.X + dB * startPoint.Y;
|
|
|
double dC2 = outPoint.Y * dA - outPoint.X * dB;
|
|
|
dfpReturn.Y = (dB * dC + dC2 * dA) / (dA * dA + dB * dB);
|
|
|
dfpReturn.X = (dA * dC - dB * dC2) / (dA * dA + dB * dB);
|
|
|
return dfpReturn;
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 扫描并插入接近边界的点
|
|
|
/// </summary>
|
|
|
/// <param name="set"> </param>
|
|
|
/// <param name="distanceStep"> </param>
|
|
|
/// <returns> </returns>
|
|
|
private static List<DfPoint> insertScan(List<DfPoint> set, double distanceStep)
|
|
|
{
|
|
|
List<DfPoint> lstReturn = new List<DfPoint>();
|
|
|
|
|
|
return lstReturn;
|
|
|
}
|
|
|
|
|
|
private static bool isok(Coordinate[] set, Coordinate start, Coordinate end)
|
|
|
{
|
|
|
bool flag = true;
|
|
|
int nCount = set.Length;
|
|
|
for (int i = 0; i < nCount; i++)
|
|
|
{
|
|
|
//if((end.Y> start.Y && set[i].Y < end.Y)
|
|
|
// || (end.Y < start.Y && set[i].Y > end.Y))
|
|
|
//{
|
|
|
// continue;
|
|
|
//}
|
|
|
//<0 : 说明set[i] 在start->end向量的顺时针方向,退出
|
|
|
if (Multi(start, end, set[i]) < -ToleranceFactor)
|
|
|
{
|
|
|
flag = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return flag;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 判断垂足是否在线段内部
|
|
|
/// </summary>
|
|
|
/// <param name="startPoint"> </param>
|
|
|
/// <param name="endPoint"> </param>
|
|
|
/// <param name="outPoint"> </param>
|
|
|
/// <returns> </returns>
|
|
|
private static bool isPedalIn(DfPoint startPoint, DfPoint endPoint, DfPoint outPoint)
|
|
|
{
|
|
|
bool isIn = false;
|
|
|
double dA, dB, dC;// 直线方程系数
|
|
|
dA = (endPoint.Y - startPoint.Y);
|
|
|
dB = startPoint.X - endPoint.X;
|
|
|
dC = dA * startPoint.X + dB * startPoint.Y;
|
|
|
double dC2 = outPoint.Y * dA - outPoint.X * dB;
|
|
|
double dCrossX, dCrossY;
|
|
|
dCrossY = (dB * dC + dC2 * dA) / (dA * dA + dB * dB);
|
|
|
dCrossX = (dA * dC - dB * dC2) / (dA * dA + dB * dB);
|
|
|
if ((dCrossY - startPoint.Y) * (dCrossY - endPoint.Y) < 0
|
|
|
&& (dCrossX - startPoint.X) * (dCrossX - endPoint.X) < 0)
|
|
|
{
|
|
|
isIn = true;
|
|
|
}
|
|
|
|
|
|
return isIn;
|
|
|
}
|
|
|
/**
|
|
|
* isok:
|
|
|
* 判断set中的点是否全部都在start->end 构成的向量的逆时针方向
|
|
|
* */
|
|
|
/**
|
|
|
*
|
|
|
* 以set[0]为基点,对set[1]..set[length-1]排序
|
|
|
* 如果multi(set[0],set[i],set[j])<0,说明set[j]在set[0]->set[i]的顺时针方向,
|
|
|
* 那么set[0]->set[j]的极角就比set[0]->set[i]的极角小,那么set[j]就应该排在set[i]的前面
|
|
|
* */
|
|
|
/**
|
|
|
* 快速排序:
|
|
|
* */
|
|
|
//通过矢量叉积求极角关系(p0p1)(p0p2)
|
|
|
// 叉积可以用来判断平面向量夹角的正负。对于向量a、b,a×b=axby-bxay,其值大于0则夹角为正
|
|
|
//P*Q > 0,P在Q的顺时针方向... ...
|
|
|
/// <summary>
|
|
|
/// 叉积运算
|
|
|
/// </summary>
|
|
|
/// <param name="p0"> </param>
|
|
|
/// <param name="p1"> </param>
|
|
|
/// <param name="p2"> </param>
|
|
|
/// <returns> </returns>
|
|
|
static double Multi(Coordinate p0, Coordinate p1, Coordinate p2)
|
|
|
{
|
|
|
return (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 快速排序 以set[0]为基点,对set[1]..set[length-1]排序
|
|
|
/// </summary>
|
|
|
/// <param name="set"> </param>
|
|
|
/// <param name="start"> </param>
|
|
|
/// <param name="end"> </param>
|
|
|
private static void QSort(Coordinate[] set, int start, int end)
|
|
|
{
|
|
|
if (start < end)
|
|
|
{
|
|
|
int x = start;
|
|
|
int j = end;
|
|
|
int i = start + 1;
|
|
|
//当i=j时,所有大于set[x]的元素都在set[x]的右面,所有小于set[x]的元素都在set[x]的左面
|
|
|
while (i <= j)
|
|
|
{
|
|
|
//找到一个set[j]<set[x],并交换
|
|
|
while (j >= i)
|
|
|
{
|
|
|
//<0 : set[j]点在set[0]->set[x]向量的顺时针方向
|
|
|
//set[j]与set[x]交换
|
|
|
//==0 : 三点共线,判断距离
|
|
|
//距离近的小OrientationIndex
|
|
|
int flag = (int)Multi(set[0], set[x], set[j]);
|
|
|
if (flag < 0 || (flag == 0 && (set[j].Distance(set[0]) < set[x].Distance(set[0]))))
|
|
|
//if (flag < 0 || (flag == 0 && (Dist(set[j], set[0]) < Dist(set[x], set[0]))))
|
|
|
{
|
|
|
Coordinate tmp = set[x];
|
|
|
set[x] = set[j];
|
|
|
set[j] = tmp;
|
|
|
x = j;
|
|
|
j--;
|
|
|
break;
|
|
|
}
|
|
|
j--;
|
|
|
}
|
|
|
//找到set[i]>set[x],并交换
|
|
|
while (i <= j)
|
|
|
{
|
|
|
//>0 : set[i]点在set[0]->set[x]向量的逆时针方向
|
|
|
//set[i]与set[x]交换
|
|
|
//==0 : 三点共线,判断距离
|
|
|
//距离大的大
|
|
|
double flag = Multi(set[0], set[x], set[i]);
|
|
|
//if (flag > 0.0 || (flag == 0.0 && (Dist(set[i], set[0]) > Dist(set[x], set[0]))))
|
|
|
if (flag > 0.0 || (flag == 0.0 && (set[i].Distance(set[0]) > set[x].Distance(set[0]))))
|
|
|
{
|
|
|
Coordinate tmp = set[x];
|
|
|
set[x] = set[i];
|
|
|
set[i] = tmp;
|
|
|
x = i;
|
|
|
i++;
|
|
|
break;
|
|
|
}
|
|
|
i++;
|
|
|
}
|
|
|
}
|
|
|
QSort(set, start, x - 1);
|
|
|
QSort(set, x + 1, end);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|