public static DataSeries SetSeriesDrawMode(DataSeries series, DrawMode mode) { series.SetDrawMode(mode); return series; }
public static DataSeries CreateHullFromSeries(DataSeries source, int iterationCount) { GraphPoint[] edges = source.GetEdgemostPoints(true); if (edges == null) return null; MaxIterationCount = iterationCount; for (int i = 0; i < edges.Length; i++) edges[i] = new GraphPoint(edges[i]); PendingFaces.Clear(); ActiveFaces.Clear(); List<GraphPoint> AvailablePoints = new List<GraphPoint>(); foreach (object point in source.DataPoints) AvailablePoints.Add(new GraphPoint((GraphPoint)point)); //DataSeries hullSeries = new DataSeries(source.Name + "_Hull", source.DrawColor); DataSeries hullSeries = new DataSeries(source.Name + "_Hull", null); GraphPoint baseLine1 = null, baseLine2 = null, farthestBaseLine = null, farthestBaseFace = null; double bestDist = 0, curDist = 0; for (int i = 0; i < edges.Length; i++) { for (int j = 1; j < edges.Length; j++) { if (i == j) continue; curDist = edges[i].DistanceFromSq(edges[j]); if (curDist > bestDist) { baseLine1 = edges[i]; baseLine2 = edges[j]; bestDist = curDist; } } } bestDist = 0; for (int i = 0; i < edges.Length; i++) { if (edges[i].pos == baseLine1.pos || edges[i].pos == baseLine2.pos) continue; curDist = edges[i].DistanceFromLineSegSq(baseLine1, baseLine2); if (curDist > bestDist) { farthestBaseLine = edges[i]; bestDist = curDist; } } Vector3 triangleNormal = GetTriangleNormal(baseLine1.pos, baseLine2.pos, farthestBaseLine.pos); Vector3 triangleCenter = GetTriangleCenter(baseLine1.pos, baseLine2.pos, farthestBaseLine.pos); float triangleDot = Vector3.Dot(triangleNormal, baseLine1.pos); bestDist = 0; bool bFlipWinding = false; for (int i = 0; i < AvailablePoints.Count; i++) { if (AvailablePoints[i] == baseLine1 || AvailablePoints[i] == baseLine2 || AvailablePoints[i] == farthestBaseLine) continue; //curDist = (AvailablePoints[i].pos - triangleCenter).LengthSquared; curDist = Math.Abs(Vector3.Dot(AvailablePoints[i].pos, triangleNormal) - triangleDot); if (curDist > bestDist) { farthestBaseFace = AvailablePoints[i]; bestDist = curDist; bFlipWinding = Vector3.Dot(triangleNormal, (AvailablePoints[i].pos - triangleCenter).Normalized()) > 0; } } if (farthestBaseFace == null) //2D series { ClojureEngine.Log("[HULL BUILD] Series is 2D, and the hull builder cannot currently work with 2D data sets"); return null; } if (bFlipWinding) { GraphPoint temp = baseLine1; baseLine1 = baseLine2; baseLine2 = temp; } List<HullFace> initialFaces = new List<HullFace>() { new HullFace(baseLine2, baseLine1, farthestBaseLine), new HullFace(baseLine1, baseLine2, farthestBaseFace), new HullFace(baseLine1, farthestBaseFace, farthestBaseLine), new HullFace(baseLine2, farthestBaseLine, farthestBaseFace), }; AssignPointsToFaces(AvailablePoints, initialFaces); for (int i = 0; i < initialFaces.Count; i++) { ActiveFaces.Add(initialFaces[i]); if(initialFaces[i].points.Count > 0) PendingFaces.Add(initialFaces[i]); } BuildFromStack(0); int unassignedPoints = 0; for (int i = 0; i < ActiveFaces.Count; i++) { ActiveFaces[i].a.AddEdges(ActiveFaces[i].b, ActiveFaces[i].c); ActiveFaces[i].b.AddEdges(ActiveFaces[i].a, ActiveFaces[i].c); ActiveFaces[i].c.AddEdges(ActiveFaces[i].a, ActiveFaces[i].b); hullSeries.AddDataPoints(new List<GraphPoint>() { ActiveFaces[i].a, ActiveFaces[i].b, ActiveFaces[i].c }); unassignedPoints += ActiveFaces[i].points.Count; //if(ActiveFaces[i].points.Count > 0) // new DataSeries(PersistentVector.create1(ActiveFaces[i].points)); } if(unassignedPoints > 0) ClojureEngine.Log("[HULL BUILD] " + unassignedPoints + " points remain outside the hull"); else ClojureEngine.Log("[HULL BUILD] All points are contained within the hull"); hullSeries.SetDrawMode(DrawMode.Triangles); return hullSeries; }