using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DfdIO; using NetTopologySuite.Geometries; namespace Construction.BatchCreateMap { /// /// 凸包算法 /// 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]点,并加入下一点,继续判断 * */ /// /// 凸包算法-braham扫描 /// 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; } /// /// 两点距离 /// /// /// /// 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)); } /// /// 获得中心点 /// /// /// private static DfPoint getCenterPoint(List 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; } /// /// 计算垂足 /// /// /// /// /// 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; } /// /// 扫描并插入接近边界的点 /// /// /// /// private static List insertScan(List set, double distanceStep) { List lstReturn = new List(); 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; } /// /// 判断垂足是否在线段内部 /// /// /// /// /// 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的顺时针方向... ... /// /// 叉积运算 /// /// /// /// /// 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); } /// /// 快速排序 以set[0]为基点,对set[1]..set[length-1]排序 /// /// /// /// 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]= 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); } } } }