// находим верхнюю левую точку CPoint GetTopPoint(List <CPoint> Q) { var p0 = Q[0]; foreach (var p in Q) { if (p.Y < p0.Y) { p0 = p; } } return(p0); }
CPoint nextHullPoint(List <CPoint> points, CPoint p) { CPoint q = p; int t; foreach (CPoint r in points) { t = turn(p, q, r); if (t == TURN_RIGHT || t == TURN_NONE && dist(p, r) > dist(p, q)) { q = r; } } return(q); }
/// <summary> /// Convex hull scan with Graham method /// </summary> /// <param name="points">All points</param> /// <returns>Convex hull points</returns> /// <remarks>not used, becouse sometimes work not correct</remarks> public List <CPoint> ConvexHullScan(List <CPoint> points) { CPoint p0 = null; foreach (CPoint value in points) { if (p0 == null) { p0 = value; } else { if (p0.Y > value.Y) { p0 = value; } } } List <CPoint> order = new List <CPoint>(); foreach (CPoint value in points) { if (p0 != value) { order.Add(value); } } order = MergeSort(p0, order); List <CPoint> result = new List <CPoint> { p0, order[0], order[1] }; order.RemoveAt(0); order.RemoveAt(0); foreach (CPoint value in order) { keepLeft(result, value); } return(result); }
int size; // количество точек исходного множества // сортирует все точки множества в порядке возрастания // полярного угла по отнощению к р0 CPoint[] sort(CPoint[] P) { bool t = true; while (t) { t = false; for (int j = 0; j < sizeP - 1; j++) { if (alpha(P[j]) > alpha(P[j + 1])) { CPoint tmp = P[j]; P[j] = P[j + 1]; P[j + 1] = tmp; t = true; } else if (alpha(P[j]) == alpha(P[j + 1])) { if (P[j].X > P[j + 1].X) { for (int k = j + 2; k < sizeP; k++) { P[k - 1] = P[k]; } sizeP--; t = true; } else if (P[j + 1].X > P[j].X) { for (int k = j + 1; k < sizeP; k++) { P[k - 1] = P[k]; } sizeP--; t = true; } } } } return(P); }
void keepLeft(List <CPoint> hull, CPoint r) { while (hull.Count > 1 && turn(hull[hull.Count - 2], hull[hull.Count - 1], r) != TURN_LEFT) { //Debug.WriteLine("Removing Point ({0}, {1}) because turning right ", hull[hull.Count - 1].X, hull[hull.Count - 1].Y); hull.RemoveAt(hull.Count - 1); } if (hull.Count == 0 || hull[hull.Count - 1] != r) { //Debug.WriteLine("Adding Point ({0}, {1})", r.X, r.Y); hull.Add(r); } //Debug.WriteLine("# Current Convex Hull #"); //foreach (Point value in hull) //{ // Debug.WriteLine("(" + value.X + "," + value.Y + ") "); //} //Debug.WriteLine(""); //Debug.WriteLine(""); }
List <CPoint> MergeSort(CPoint p0, List <CPoint> arrPoint) { if (arrPoint.Count == 1) { return(arrPoint); } List <CPoint> arrSortedInt = new List <CPoint>(); int middle = (int)arrPoint.Count / 2; List <CPoint> leftArray = arrPoint.GetRange(0, middle); List <CPoint> rightArray = arrPoint.GetRange(middle, arrPoint.Count - middle); leftArray = MergeSort(p0, leftArray); rightArray = MergeSort(p0, rightArray); int leftptr = 0; int rightptr = 0; for (int i = 0; i < leftArray.Count + rightArray.Count; i++) { if (leftptr == leftArray.Count) { arrSortedInt.Add(rightArray[rightptr]); rightptr++; } else if (rightptr == rightArray.Count) { arrSortedInt.Add(leftArray[leftptr]); leftptr++; } else if (getAngle(p0, leftArray[leftptr]) < getAngle(p0, rightArray[rightptr])) { arrSortedInt.Add(leftArray[leftptr]); leftptr++; } else { arrSortedInt.Add(rightArray[rightptr]); rightptr++; } } return(arrSortedInt); }
int turn(CPoint p, CPoint q, CPoint r) { return(((q.X - p.X) * (r.Y - p.Y) - (r.X - p.X) * (q.Y - p.Y)).CompareTo(0)); }
// через векторное произведение определяет поворот //(если величина отрицательная - поворот против часовой стрелки, и наоборот) double angle(CPoint t0, CPoint t1, CPoint t2) { return((t1.X - t0.X) * (t2.Y - t0.Y) - (t2.X - t0.X) * (t1.Y - t0.Y)); }
/// <summary> /// Convex hull scan with Graham method /// </summary> /// <param name="points">All points</param> /// <returns>Convex hull points</returns> /// <remarks>not used, becouse sometimes work not correct</remarks> public List <CPoint> ConvexHullScan(List <CPoint> points) { size = points.Count; //p0 - точка с минимальной координатой у или самая левая из таких точек при наличии совпадений p0 = GetTopPoint(points); int ind = 0; for (int i = 0; i < size; i++) { if (points[i].Y > p0.Y) { p0 = points[i]; ind = i; } else if (points[i].Y == p0.Y && points[i].X < p0.X) { p0 = points[i]; ind = i; } } //P остальные точки (все Q кроме р0) sizeP = size - 1; CPoint[] P = new CPoint[sizeP]; int j = 0; for (int i = 0; i < size; i++) { if (i != ind) { P[j] = points[i]; j++; } } P = sort(P); //сортируем Р в порядке возрастания полярного угла,измеряемого //против часовой стрелки относительно р0 var res = new List <CPoint>() { p0, P[0], P[1] }; CPoint[] S = new CPoint[size]; //массив, который будет содержать вершины оболочки против часовой стрелки S[0] = p0; S[1] = P[0]; S[2] = P[1]; int last = 2; for (int i = 2; i < sizeP; i++) { while (last > 0 && angle(S[last - 1], S[last], P[i]) >= 0) { last--; } last++; S[last] = P[i]; } //j = 1; //while (j < size && (S[j].X != 0 || S[j].Y != 0)) j++; //CPoint[] polygon = new CPoint[j]; //for (int i = 0; i < j; i++) polygon[i] = S[i]; return(S.Where(x => x.X != 0 && x.Y != 0).ToList()); // it is not correct for 0:0 point }