/// <summary> /// creates the concave hull based on the convex hull and an angle threshold /// </summary> /// <param name="pConvexEdges">edges of convex hull</param> /// <param name="pPoints">the point cloud data set</param> /// <param name="pMaxAngle">angle threshold</param> /// <returns>list of concave hull edges</returns> static List <tEdge> CreateConvaveHullFromConvexEdges(List <DefaultConvexFace <Vertex> > pConvexEdges, HashSet <Vertex> pPoints, double pMaxAngle) { //initialize arrays List <tEdge> convexHull = new List <tEdge>(); foreach (var v in pConvexEdges) { convexHull.Add(new tEdge(v.Vertices[0], v.Vertices[1])); } List <tEdge> concaveHull = new List <tEdge>(); //iterate through convex hull until concave hull is found while (convexHull.Count > 0) { //find longest edge in convex hull list tEdge longestEdge = convexHull.MaxBy(t => t.length); //remove longest edge from convex hull convexHull.Remove(longestEdge); //find nearest point List <tEdge> edges = convexHull.Concat(concaveHull).ToList(); tVector nextPoint = FindPointWithSmallestAngle(pPoints, longestEdge, edges, pMaxAngle); if (nextPoint == null) //if no next point found { concaveHull.Add(longestEdge); continue; } //create edges based on nearest point tEdge e2 = new tEdge(longestEdge.v1, nextPoint.vector); tEdge e3 = new tEdge(longestEdge.v2, nextPoint.vector); //check if e2 and e3 intersect bool intersect = false; foreach (tEdge e1 in edges) { if (Intersects(e2, e1) || Intersects(e3, e1)) { intersect = true; break; } } //add e2 and e3 to List A again, if no intersection if (intersect == false) { convexHull.Add(e2); convexHull.Add(e3); continue; } //if no concaviction found, add longest edge to concaveHull list concaveHull.Add(longestEdge); } return(concaveHull); }
/// <summary> /// finds the point with the smallest angle from a given dataset towards an edge /// </summary> /// <param name="pPoints">the dataset</param> /// <param name="pLine">the edge to calculate the angle towards</param> /// <param name="pBoundaries">boundaries</param> /// <param name="pMaxAngle">angle threshold</param> /// <returns></returns> static tVector FindPointWithSmallestAngle(HashSet <Vertex> pPoints, tEdge pLine, List <tEdge> pBoundaries, double pMaxAngle) { tVector bestFit = null; Object lockObject = new object(); Parallel.ForEach(pPoints, v => { //check if point is on concave hull if (!IsPointOnConcaveHull(v, pBoundaries)) { //calculate new potential edges tEdge t1 = new tEdge(pLine.v1, v); tEdge t2 = new tEdge(pLine.v2, v); //check if local maximum < edge length if (t1.length < pLine.length && t2.length < pLine.length) { //calculate the highest angle between lines and the new point double maxAngle; double angleA = Math.Abs(CalculateAngleBetweenTwoLines(pLine, t1)); double angleB = Math.Abs(CalculateAngleBetweenTwoLines(pLine, t2)); if (angleA > angleB) { maxAngle = angleA; } else { maxAngle = angleB; } //check if highest angle is smaller than threshold if (maxAngle < pMaxAngle) { //check if bestFit has been initialized tVector currentFit = new tVector(v, maxAngle); lock (lockObject) if (bestFit == null) { bestFit = currentFit; } //check if current point has a better fit lock (lockObject) if (currentFit.maxAngle < bestFit.maxAngle) { bestFit = currentFit; } } } } }); return(bestFit); }