private void boundaryCheckButton_Click(object sender, EventArgs e) { float xMin = -router.ToolDiameter; float xMax = router.ToolDiameter; float yMin = -router.ToolDiameter; float yMax = router.ToolDiameter; foreach (Object o in drawing3D.GetObjects()) { if (o is TriangleMeshGUI) { var triangles = o as TriangleMeshGUI; xMin = Math.Min(triangles.MinPoint.X - router.ToolDiameter + triangles.Offset.X, xMin); xMax = Math.Max(triangles.MaxPoint.X + router.ToolDiameter + triangles.Offset.X, xMax); yMin = Math.Min(triangles.MinPoint.Y - router.ToolDiameter + triangles.Offset.Y, yMin); yMax = Math.Max(triangles.MaxPoint.Y + router.ToolDiameter + triangles.Offset.Y, yMax); } } LineStrip r = new LineStrip(); r.Append(new Vector3(xMin, yMin, router.MoveHeight)); r.Append(new Vector3(xMax, yMin, router.MoveHeight)); r.Append(new Vector3(xMax, yMax, router.MoveHeight)); r.Append(new Vector3(xMin, yMax, router.MoveHeight)); r.Append(new Vector3(xMin, yMin, router.MoveHeight)); router.RoutPath(r, false, Vector3.Zero); router.Complete(); }
public void RoutPath(LineStrip line, bool backwards, Vector3 offset) { bool first = true; foreach (Vector3 point in line.Vertices) { // TODO: Pick some unit and stick with it! Inches would be fine. Vector3 pointOffset = point + offset; MoveTool m = new MoveTool(pointOffset, MoveTool.SpeedType.Cutting); if (first) { first = false; if ((finalPosition.Xy - pointOffset.Xy).Length > .0001) { // Need to move the router up, over to new position, then down again. MoveTool m1 = new MoveTool(new Vector3(finalPosition.X, finalPosition.Y, move_height), MoveTool.SpeedType.Rapid); MoveTool m2 = new MoveTool(new Vector3(m.Target.X, m.Target.Y, move_height), MoveTool.SpeedType.Rapid); AddCommand(m1); AddCommand(m2); } } AddCommand(m); } }
/// <summary> /// Generate a set of tool paths which will completely remove the material specified in /// the polygons, plus an offset equal to the radius of the tool used. /// </summary> /// <param name="polygons"></param> /// <param name="maxShrink">maximum distance between disjoint paths</param> /// <returns></returns> public static List <LineStrip> ObliterateSlice(Slice polygons, float maxShrink, bool reverse = false) { List <LineStrip> lines = new List <LineStrip>(); foreach (Slice slice in polygons.IndividualPolygons()) { PathTree tree = new PathTree(reverse); Slice inside = new Slice(slice.GetLines(Slice.LineType.Hole), slice.Plane); Slice shrink = new Slice(slice); while (shrink.Area() > 0) { shrink = new Slice(shrink.GetLines(Slice.LineType.Outside), shrink.Plane); foreach (var a in shrink.IndividualPolygons()) { if (!tree.AddPolygon(a)) { // The new polygon didn't fit into the path tree... shouldn't get here. } } shrink.Offset(-maxShrink); shrink.Subtract(inside); } LineStrip toolPath = new LineStrip(); tree.GenerateToolPath(toolPath, tree.CreatePath(), maxShrink * 2.0f); lines.Add(toolPath); } return(lines); }
public Tabs(LineStrip boundary, float toolRadius, bool inside = false) { originalBoundary = new Slice(new LineStrip[] { boundary }, new Plane(Vector3.UnitZ, Vector3.Zero)); float offset = toolRadius; if (inside) { offset = -offset; } Slice slice = new Slice(originalBoundary); slice.Offset(offset); this.boundary = slice.GetLines(Slice.LineType.Outside).First(s => true); this.toolRadius = toolRadius; float length = this.boundary.Length(LineStrip.Type.Closed); int numTabs = (int)(length / desiredSpacing); if (numTabs < minTabs) { numTabs = 0; } float tabSpacing = length / numTabs; tabLocations = new List <Vector3>(); foreach (var point in this.boundary.PointsAlongLine(tabSpacing, tabSpacing / 2.0f)) { tabLocations.Add(point); } }
/// <summary> /// Create another line strip which follows the same path, but avoids tab locations. /// NOTE: this currently only works on closed input lines. The algorithm could /// be modified to work correctly with open paths too, but that's not needed yet. /// </summary> /// <param name="input"></param> /// <returns></returns> public LineStrip AvoidTabs(LineStrip input) { LineStrip ret = new LineStrip(); foreach (var segment in input.Segments(LineStrip.Type.Closed)) { if (segment.Length < 0.0001f) { continue; } if (segment.A.Z > tabHeight && segment.B.Z > tabHeight) { ret.Append(segment.B); continue; } List <LineSegment> remainingSegments = new List <LineSegment>(); remainingSegments.Add(segment); foreach (Vector3 tab in this.TabLocations) { var i = new LineSegmentCircleIntersect(segment, tab, tabRadius + toolRadius); if (i.type == LineSegmentCircleIntersect.IntersectType.Segment) { List <LineSegment> temp = new List <LineSegment>(); foreach (var seg in remainingSegments) { temp.AddRange(seg.Subtract(i.IntersectSegment)); } remainingSegments = temp; } } remainingSegments.RemoveAll(s => s.Length < 0.0001f); if (remainingSegments.Count == 0) { // Entire segment is within a tab TestAddPoint(ClearHeight(segment.B, tabHeight), ret.Vertices); } else { // Everything described in "remainingSegments" is outside of the tab, and the spaces // between are on the tab. The path between is known since it's always a straight line. remainingSegments.Sort((s1, s2) => (s1.A - segment.A).Length.CompareTo((s2.A - segment.A).Length)); foreach (var s in remainingSegments) { TestAddPoint(ClearHeight(s.A, tabHeight), ret.Vertices); TestAddPoint(s.A, ret.Vertices); TestAddPoint(s.B, ret.Vertices); TestAddPoint(ClearHeight(s.B, tabHeight), ret.Vertices); } TestAddPoint(ClearHeight(segment.B, tabHeight), ret.Vertices); } } return(ret); }
private void AddRoutPoint(Slice currentPolygon, Vector3 newPoint, bool check = true) { if (routs.Count == 0) { routs.Add(new LineStrip()); } LineStrip currentRout = routs[routs.Count - 1]; if (check) { if (currentRout.Vertices.Count > 0) { Slice larger = new Slice(currentPolygon); larger.Offset(toolRadius * 1.05f); Vector3 lastPoint = currentRout.Vertices[currentRout.Vertices.Count - 1]; LineStrip path = new LineStrip(); path.Append(lastPoint); path.Append(newPoint); Slice test = new Slice(path, toolRadius * 2.0f, currentPolygon.Plane); if (!larger.Contains(test)) { // Can't move at this level - need to go to the save Z move height. currentRout = new LineStrip(); routs.Add(currentRout); //DrawSlice(Color.Black, Color.Red, test); } else { //DrawSlice(Color.Black, Color.Green, test); } //larger.Subtract(test); //GL.Translate(0, 0, 100); } } // If the Z height changed, move to the new position and and drop, or rise and then move. if (currentRout.Vertices.Count > 0) { var lastPoint = currentRout.Vertices[currentRout.Vertices.Count - 1]; if (newPoint.Z < lastPoint.Z) { currentRout.Vertices.Add(new Vector3(newPoint.X, newPoint.Y, lastPoint.Z)); } else if (newPoint.Z > lastPoint.Z) { currentRout.Vertices.Add(new Vector3(lastPoint.X, lastPoint.Y, newPoint.Z)); } } currentRout.Vertices.Add(newPoint); }
public override void AccumulateStrips(LineStrip vertices) { if (triangleCount <= 0 || Points.Count() < 2) { return; } vertices.NumTriangles += triangleCount; if (vertices.Vertices.Count > 0) { vertices.Vertices.Add(vertices.Vertices.Last()); vertices.Vertices.Add(triangles[0]); vertices.NumTriangles += 1; } vertices.Vertices.AddRange(triangles); }
public override void AccumulateStrips(LineStrip strips) { for (int i = 0; i < _stripVertices.Count; i++) { strips.NumTriangles += _stripTriangleCounts[i]; if (strips.Vertices.Count > 0) { strips.Vertices.Add(strips.Vertices.Last()); strips.Vertices.Add(_stripVertices[i][0]); strips.Vertices.Add(_stripVertices[i][0]); strips.NumTriangles += 1; } strips.Vertices.AddRange(_stripVertices[i]); } }
public static List <LineStrip> PlanPaths(TriangleMesh triangles, List <Tabs> tabs, Router router) { List <LineStrip> routs = new List <LineStrip>(); foreach (Tabs tab in tabs) { tab.TabHeight = router.TabHeight; } float toolRadius = router.ToolDiameter / 2.0f; float maxCutDepth = router.MaxCutDepth; float lastPassHeight = router.LastPassHeight; float cleanPassFactor = 0.90f; // 90% of the tool radius will be removed on the clean pass float minZ = triangles.MinPoint.Z; float maxZ = triangles.MaxPoint.Z; var slices = GetSlices(triangles, router); //GL.PushMatrix(); //foreach (var s in slices) //{ // GL.Translate(triangles.MaxPoint.X - triangles.MinPoint.X, 0, 0); // DrawSlice(Color.Orange, Color.Black, s); //} //GL.PopMatrix(); Slice top = slices[0]; slices.RemoveAt(0); Slice boundary = new Slice(slices[slices.Count - 1]); boundary.Offset(toolRadius * (cleanPassFactor + 1.05f)); // Note: this is slightly larger to allow some polygon width to exist // Enable complete removal of holes with no tabs foreach (var tab in tabs) { if (tab.TabLocations.Count() == 0) { boundary.Union(tab.Boundary); } } top.SubtractFrom(boundary); //GL.PushMatrix(); //GL.Translate(0, 0, 1); //DrawSlice(Color.Black, Color.DarkGray, boundary); //GL.PopMatrix(); Slice holes = top.PolygonsWithoutHoles(); List <Hole> holeRouts = new List <Hole>(); foreach (var polygon in holes.IndividualPolygons()) { holeRouts.Add(new Hole(polygon, toolRadius, cleanPassFactor)); } foreach (Slice current in slices) { current.Offset(toolRadius); //GL.PushMatrix(); //GL.Translate(0, 0, -0.001f); ////DrawSlice(Color.Tan, Color.Gray, boundary); //GL.PopMatrix(); ////DrawSlice(Color.Red, Color.Blue, current); Slice original = new Slice(current); current.SubtractFrom(boundary); // current will now be several polygons representing the area to rout out, minus the tool radius offset on either side. // Split it into polygons around the outside and inside of parts (the first two will be outside polygons, the next two inside, next two outside, ...). Slice outsidePairs = current.GetOutsidePairs(); //DrawSlice(Color.Gold, Color.Yellow, outsidePairs); Slice insidePairs = current.GetInsidePairs(); //DrawSlice(Color.Orange, Color.NavajoWhite, insidePairs); // If a polygon has no holes, that means it's a hole in the actual shape to be cut out. // These can be cut first before outside cuts are done. holes = current.PolygonsWithoutHoles(); foreach (var holePolygon in insidePairs.PolygonsWithoutHoles().IndividualPolygons()) { foreach (var hole in holeRouts) { if (hole.Contains(holePolygon)) { hole.AddPolygon(holePolygon); break; } } } // Rout all outside paths. These will be done from top down, one layer at a time for structural reasons. // For the top several layers, two paths could be combined... var outsideRouts = RoutAreasWithHoles(insidePairs.PolygonsWithHoles(), toolRadius, cleanPassFactor, tabs, true); var newLines = new List <LineStrip>(); foreach (var line in outsideRouts) { var r = new LineStrip(); r.AddRange(line.Vertices); r.Append(line.Vertices[0]); r.Vertices.Reverse(); newLines.Add(r); } routs.AddRange(newLines); outsideRouts = RoutAreasWithHoles(outsidePairs, toolRadius, cleanPassFactor, tabs, false); newLines = new List <LineStrip>(); foreach (var line in outsideRouts) { var r = new LineStrip(); r.AddRange(line.Vertices); r.Append(line.Vertices[0]); newLines.Add(r); } routs.AddRange(newLines); } foreach (var hole in holeRouts) { var newRouts = new List <LineStrip>(); foreach (var line in hole.GetRouts()) { LineStrip r = new LineStrip(); // Note: these might not start and end in the same place, but that's OK. r.AddRange(line.Vertices); newRouts.Add(r); } routs.InsertRange(0, newRouts); } // Adjust the lowest point - allow plunging through the bottom of the material for a clean cut. foreach (LineStrip r in routs) { for (int i = 0; i < r.Vertices.Count; i++) { var point = r.Vertices[i]; if (point.Z < (minZ + .005f)) { r.Vertices[i] = new Vector3(point.X, point.Y, lastPassHeight); } } } return(routs); }
/// <summary> /// Generate a tool path from the current path tree /// </summary> /// <param name="start">line strip to add path information</param> /// <param name="thisPath">line strip representing the path at the current level</param> /// <param name="maxDistance">maximum distance to jump from a parent path to a child path</param> private void GenerateToolPath(LineStrip start, LineStrip thisPath, float maxDistance) { List <PathTree> childs = new List <PathTree>(); foreach (PathTree child in children) { childs.Add(child); } var pathVertices = thisPath.Vertices.Count; for (int i = 0; i < pathVertices; i++) { var p1 = thisPath.Vertices[i]; var p2 = thisPath.Vertices[(i + 1) % pathVertices]; Segment parentSegment = new Segment(p1, p2); start.Append(p1); int childIndex = 0; int closestIndex = 0; for (int childTreeIndex = 0; childTreeIndex < childs.Count; childTreeIndex++) { var child = childs[childTreeIndex]; bool found = false; var childPath = child.CreatePath(); var childVertices = childPath.Vertices.Count; // Prefer point to point matches var closest = maxDistance; for (childIndex = 0; childIndex < childVertices; childIndex++) { var c1 = childPath.Vertices[childIndex]; var len = (c1 - p1).Length; if (len < closest) { closest = len; closestIndex = childIndex; found = true; } } // If a point to point match isn't found, look for line to point matches. if (!found) { closest = maxDistance; Vector3 insertPoint = Vector3.Zero; bool insertParent = false; // If there is no point to point match, find a point to line match. for (childIndex = 0; childIndex < childVertices; childIndex++) { var c1 = childPath.Vertices[childIndex]; var c2 = childPath.Vertices[(childIndex + 1) % childVertices]; Segment childSegment = new Segment(c1, c2); var fromParentSegment = parentSegment.DistanceTo(c1); if (fromParentSegment < closest) { insertParent = true; closest = fromParentSegment; insertPoint = parentSegment.PointOnLine; closestIndex = childIndex; found = true; } var fromChildSegment = childSegment.DistanceTo(p1); if (fromChildSegment < closest) { // Note: this happens very rarely insertParent = false; closest = fromChildSegment; insertPoint = childSegment.PointOnLine; closestIndex = childIndex; found = true; } } if (found) { if (insertParent) { p1 = insertPoint; start.Append(p1); } else { closestIndex++; childPath.Vertices.Insert(closestIndex, insertPoint); } } } if (found) { // Reorder the child vertices var last = childPath.Vertices.GetRange(0, closestIndex); childPath.Vertices.RemoveRange(0, closestIndex); childPath.Vertices.AddRange(last); child.GenerateToolPath(start, childPath, maxDistance); start.Append(p1); childs.RemoveAt(childTreeIndex); childTreeIndex--; } } } if (childs.Count > 0) { // No path to these children - need to handle them some other way badTrees.AddRange(childs); } // Complete the loop start.Append(thisPath.Vertices[0]); }
/// <summary> /// Combine one line loop with another /// </summary> /// <param name="other"></param> /// <returns>Array of LineLoops which don't intersect (will be one or two loops)</returns> public static LineLoop Intersect(LineLoop one, LineLoop another, Vector3 normal) { LineStrip one2 = new LineStrip(); List<Vector3> vv = new List<Vector3>(one.Vertices); for (int i = 0; i < vv.Count; i++) { int j = (i + 2) % vv.Count; one2.Append(vv[j]); } one2.Append(one2.GetVertex(0)); one = new LineLoop(one2); GL.PointSize(19); GL.Color3(Color.GreenYellow); GL.Begin(BeginMode.Points); GL.Vertex3(one.GetVertex(0)); GL.End(); GL.PointSize(1); LineLoop following = one; LineLoop searching = another; Vector3 startPoint = following.GetVertex(0); LineStrip ls = new LineStrip(); List<LineLoop> loops = new List<LineLoop>(); for (int i = 0; i < following.indices.Count(); i++) { Vector3 v1 = following.GetVertex(i); Vector3 v2 = following.GetVertex((i + 1) % following.indices.Count()); //if (ls.ContainsVertex(v1)) // { bool matched = false; LineStrip ls2 = new LineStrip(); foreach (Vector3 v in ls.Vertices) { if (!matched && (v - v1).Length < 0.001) { matched = true; } if (matched) { ls2.Append(v); } } if (matched) { ls2.Append(v1); GL.PushMatrix(); GL.Translate(0, 0, 50); ls2.Draw(); GL.PopMatrix(); // Done! Got a loop LineLoop l = new LineLoop(ls2); return l; } //} ls.Append(v1); int searchingCount = searching.indices.Count(); for (int j = 0; j < searchingCount; j++) { Vector3 v3 = searching.GetVertex(j); Vector3 v4 = searching.GetVertex((j + 1) % searchingCount); Vector3 n1 = (v2 - v1); Vector3 n2 = (v4 - v3); n1.Normalize(); n2.Normalize(); float d1 = DistanceToCylinder(v1, v2, v3); float d2 = DistanceToCylinder(v3, v4, v1); if (d2 < 10) { } // Point v3 is on Line v1-v2: if (DistanceToCylinder(v1, v2, v3) < 1) { // Follow the line most to the outside float angle = Angle(n1, n2, normal); if (angle < OpenTK.MathHelper.Pi) { GL.PointSize(10); GL.Color3(Color.Orange); GL.Begin(BeginMode.Points); GL.Vertex3(v3); GL.End(); GL.PointSize(1); ls.Append(v3); // Follow the line v3-v4 LineLoop temp = searching; searching = following; following = temp; i = j; break; } else { // Continue following the line v1-v2 } } // Point v2 is on the line v3-v4 else if (DistanceToCylinder(v3, v4, v1) < 1) { // Follow the line most to the outside float angle = Angle(n1, n2, normal); if (angle < OpenTK.MathHelper.Pi) { GL.PointSize(10); GL.Color3(Color.Orange); GL.Begin(BeginMode.Points); GL.Vertex3(v1); GL.End(); GL.PointSize(1); //ls.Append(v1); // Follow the line v3-v4 LineLoop temp = searching; searching = following; following = temp; i = j; break; } else { // Continue following the line v1-v2 } } // TODO: Add case for intersecting lines! //else if (0) //{ //} } } //return loops.ToArray(); ls.Append(following.GetVertex(following.indices[0])); //if (ls.ContainsVertex(v1)) //{ //ls.Append(v1); GL.PushMatrix(); GL.Translate(0, 0, 50); ls.Draw(); GL.PopMatrix(); // Done! Got a loop LineLoop l2 = new LineLoop(ls); return l2; //} }
public abstract void AccumulateStrips(LineStrip vertices);
public TabsGUI(LineStrip boundary, float toolRadius, bool inside = false) : base(boundary, toolRadius, inside) { drawSlice = new Slice(this.TabPath, toolRadius * 2.0f, new Plane(Vector3.UnitZ, Vector3.Zero), true); }
private void LineLoopFromLineStrip(LineStrip l) { foreach (Vector3 v in l.Vertices) { this.Append(v); } if (indices.Count() < 3) { throw new Exception("Cannot make a loop from a line with fewer than 3 vertices"); } if (indices[0] != indices[indices.Count() - 1]) { throw new Exception("Line is not a loop - the first and last vertex must be the same"); } // Remove the last index - it's redundant. indices.RemoveAt(indices.Count() - 1); // Test if the connection back to the first vertex makes the last vertex unnecessary Vector3 v1 = vertices[indices[indices.Count() - 1]]; Vector3 v2 = vertices[indices[0]]; Vector3 v3 = vertices[indices[1]]; if (OnSameLine(v1, v2, v3)) { indices.RemoveAt(0); } }
public LineLoop(LineStrip l) { LineLoopFromLineStrip(l); }
private void Slice(Plane p) { float epsilon = 0.01f; // TODO: compute proper epsilon value List<PolyLine> linePile = new List<PolyLine>(); // Pile of disconnected lines on the slice plane List<Vector3> all_points = new List<Vector3>(); foreach (Face f in this.faces) { PolyLine newLine = TrianglePlaneIntersect(f, p); // Only add lines with exactly 2 points - others are a no match or error if (newLine.points.Count() == 2 && (newLine.points[0] - newLine.points[1]).Length> epsilon) { linePile.Add(newLine); // Add the vertices to the all_points list - only need to add the first one, the tail will be the head of another point bool matched = false; foreach (Vector3 point in all_points) { if ((point - newLine.points[0]).Length < epsilon) { matched = true; break; } } if (!matched) { all_points.Add(newLine.points[0]); } } } // linePile is a unordered list of line segments. // If a line segment is oriented with point[0] on (0, 0, 0) and point[1] // somewhere on the positive Y axis, the solid object is in the direction of the positive x axis. // // p[1]xxxxxxxxxxxxxxxxxxxxxxxx // xx xx // xx <object over here> xx // xx xx // p[0]xxxxxxxxxxxxxxxxxxxxxxxx // List<PolyLine> newPolyLines = new List<PolyLine>(); for (int i = 0; i < linePile.Count(); i++) { int points = linePile[i].points.Count(); Vector3 v1 = linePile[i].points[0]; Vector3 v2 = linePile[i].points[1]; //DrawCone1(v1, v2); List<Vector3> points_on_line = new List<Vector3>(); foreach (Vector3 v in all_points) { if ((v1 - v).Length >= epsilon && (v2 - v).Length >= epsilon && DistanceToCylinder(v1, v2, v) < epsilon) { points_on_line.Add(v); } } points_on_line.Insert(0, v1); points_on_line.Add(v2); // Order from v1 to v2 var sorted = points_on_line.OrderBy(order_vec => (order_vec - v1).Length); PolyLine newPolyLine = new PolyLine(); foreach (Vector3 v in sorted) { if (newPolyLine.points.Count() == 0 || (newPolyLine.points[newPolyLine.points.Count() - 1] - v).Length > epsilon) { newPolyLine.points.Add(v); } } if (newPolyLine.points.Count() >= 2) { newPolyLines.Add(newPolyLine); } if (newPolyLine.points.Count() >= 3) { // Shouldn't get here! } } List<LinePointIndices> lpis = new List<LinePointIndices>(); List<Vector3> vertices = new List<Vector3>(); List<List<int>> v_lookup = new List<List<int>>(); foreach (PolyLine l in newPolyLines) { int lastIndex = -1; foreach (Vector3 pointVec in l.points) { int currentIndex = -1; for (int i = 0; i < vertices.Count(); i++) { float length = (vertices[i] - pointVec).Length; if (length < epsilon) { currentIndex = i; continue; } } if (currentIndex == -1) { vertices.Add(pointVec); v_lookup.Add(new List<int>()); currentIndex = vertices.Count() - 1; } if (lastIndex != -1 && lastIndex != currentIndex) { LinePointIndices line = new LinePointIndices(); bool already_matched = false; foreach (int line_index in v_lookup[lastIndex]) { LinePointIndices l2 = lpis[line_index]; if (l2.indices[1] == currentIndex) { already_matched = true; } } if (!already_matched) { line.indices.Add(lastIndex); line.indices.Add(currentIndex); lpis.Add(line); v_lookup[lastIndex].Add(lpis.Count() - 1); v_lookup[currentIndex].Add(lpis.Count() - 1); } } lastIndex = currentIndex; } } //List<Vector3> scaled = new List<Vector3>(); List<int> vector_indices_to_see = new List<int>(); foreach (Vector3 v in vertices) { //scaled.Add(v / 125); vector_indices_to_see.Add(vector_indices_to_see.Count()); } List<LinePointIndices> slices = new List<LinePointIndices>(); GL.PushMatrix(); GL.PointSize(10); List<int> seenVertices = new List<int>(); while(vector_indices_to_see.Count() > 0) { List<int> line_indices = v_lookup [vector_indices_to_see[0]]; vector_indices_to_see.RemoveAt(0); if (line_indices.Count() == 0) { continue; } LinePointIndices line = lpis[line_indices[0]]; // Only need to look at one line with this vertex LinePointIndices start_line = new LinePointIndices(); start_line.indices.Add(line.indices[0]); start_line.indices.Add(line.indices[1]); GL.Color3(Color.Green); DrawCone1(vertices[start_line.indices[0]], vertices[start_line.indices[1]]); LinePointIndices loop = FindLoop(seenVertices, p.normal, vertices, v_lookup, lpis, start_line); if (loop != null) { slices.Add(loop); GL.Color3(Color.LightBlue); GL.Begin(BeginMode.LineLoop); Vector3 add = new Vector3(0, 0, 0); foreach (int i in loop.indices) { vector_indices_to_see.RemoveAll(value => value == i); GL.Vertex3(vertices[i] + add); seenVertices.Add(i); //add += new Vector3(0, 0, 25); } GL.End(); //GL.Translate(new Vector3(0, 0, +100)); } //break; } GL.PointSize(1); GL.PopMatrix(); Vector3 normal = new Vector3(0, 0, 1); float toolRadius = 100; GL.LineWidth(1); List<IntPoint> boundingBox = new List<IntPoint>(); boundingBox.Add(new IntPoint(-1000, -1000)); boundingBox.Add(new IntPoint(3000, -1000)); boundingBox.Add(new IntPoint(3000, 3000)); boundingBox.Add(new IntPoint(-1000, 3000)); List<LineLoop> loops = new List<LineLoop>(); foreach (LinePointIndices l in slices) { LineStrip line = new LineStrip(); for (int i = 0; i < l.indices.Count (); i++) { line.Append(vertices[l.indices[i]]); } line.Append(vertices[l.indices[0]]); loops.Add(new LineLoop (line)); } if (loops.Count() > 0) { Vector3 up = new Vector3(0, 0, 1); if (Math.Abs (normal.Z) > 0.8) { up = new Vector3(1, 0, 0); } float distance = Vector3.Dot(loops[0].GetVertex(0), normal); Matrix4 transform = Matrix4.LookAt(normal * distance, normal * (distance - 1), up); Matrix4 inverseTransform = Matrix4.Invert(transform); Clipper c = new Clipper(); c.Clear(); try { // These loops go clockwise foreach (LineLoop loop in loops) { List<IntPoint> polygon = new List<IntPoint>(); foreach (Vector3 vertex in loop.Vertices) { Vector3 result = Vector3.Transform(vertex, transform); polygon.Add(new IntPoint((long)result.X, (long)result.Y)); } polygon.RemoveAt(0); c.AddPolygon(polygon, PolyType.ptClip); GL.PushMatrix(); GL.Translate(new Vector3(0, 0, 100)); //loop.Draw(); GL.PopMatrix(); } List<List<IntPoint>> union = new List<List<IntPoint>>(); bool r = c.Execute(ClipType.ctUnion, union, PolyFillType.pftNonZero, PolyFillType.pftNonZero); List<List<IntPoint>> with_offset = Clipper.OffsetPolygons(union, toolRadius, JoinType.jtSquare); List<List<IntPoint>> whatsLeft = Clipper.OffsetPolygons(with_offset, -toolRadius, JoinType.jtRound); List<LineStrip> strips = new List<LineStrip>(); foreach (List<IntPoint> polygon in with_offset) { LineStrip strip = new LineStrip(); foreach (IntPoint point in polygon) { strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); } strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); strips.Add(strip); //new LineLoop(strip).Draw(); } List<List<IntPoint>> removeArea = new List<List<IntPoint>>(); c.Clear(); c.AddPolygons(with_offset, PolyType.ptClip); c.AddPolygon(boundingBox, PolyType.ptSubject); List<List<IntPoint>> resultingPolygon = new List<List<IntPoint>>(); c.Execute(ClipType.ctDifference, removeArea, PolyFillType.pftNonZero, PolyFillType.pftNonZero); removeArea = Clipper.CleanPolygons(removeArea, toolRadius / 100); c.Clear(); c.AddPolygons(removeArea, PolyType.ptClip); PolyTree test = new PolyTree(); c.Execute(ClipType.ctUnion, test, PolyFillType.pftNonZero, PolyFillType.pftNonZero); //PolyNode pn = test.GetFirst(); //while (pn != null) //{ // if (pn.IsHole) // { // LineLoop l = new LineLoop(pn.Contour, inverseTransform); // l.Draw(); // } // pn = pn.GetNext(); //} List<Polygons> polys = FlattenPolyTree(test); //GL.PushMatrix(); foreach (Polygons polygons in polys) { //GL.Translate(new Vector3 (0, 0, 100)); //foreach (Polygon polygon in polygons) //{ // LineLoop l = new LineLoop(polygon, inverseTransform); // l.Draw(); //} List<Polygons> paths = ReducePolygon(polygons, toolRadius, inverseTransform); //IOrderedEnumerable<List<IntPoint>> ordered = paths.OrderBy(poly => Clipper.Area(poly)); GL.PushMatrix(); List<Polygons> paths2 = new List<Polygons>(); List<Polygons> paths3 = new List<Polygons>(); foreach (Polygons polygons2 in paths) { var newPolys = new Polygons(); foreach (Polygon poly in polygons2) { if (Clipper.Area(poly) > 0) { newPolys.Add(poly); } } paths2.Add(newPolys); //GL.Translate(new Vector3(0, 0, 100)); var newInnerPolys = new Polygons(); foreach (Polygon poly in polygons2) { if (paths3.Count() == 0) { //newInnerPoly } if (Clipper.Area(poly) < 0) { LineLoop l = new LineLoop(poly, inverseTransform); l.Draw(); } } } foreach (Polygons polygons2 in paths2) { GL.Translate(new Vector3(0, 0, 100)); foreach (Polygon poly in polygons2) { LineLoop l = new LineLoop(poly, inverseTransform); l.Draw(); } } GL.PopMatrix(); } //GL.PopMatrix(); double boundingBoxArea = Clipper.Area(boundingBox); // Outer Polygon // Inner Polygons //ReducePolygon(boundingBox, with_offset, toolRadius, inverseTransform); //strips = new List<LineStrip>(); //double area = 1; //int loopTimes = 0; //List<List<IntPoint>> cutPolygons = new List<List<IntPoint>>(); //List<Vector3> parentPoints = new List<Vector3>(); //GL.PushMatrix(); //while (removeArea.Count() > 0) //{ // List<Vector3> points = new List<Vector3>(); // foreach (List<IntPoint> polygon in removeArea) // { // double area = Clipper.Area(polygon); // // if (area > 0) // Bigger to Smaller // { // } // IntPoint[] newP = new IntPoint[polygon.Count()]; // polygon.CopyTo(newP); // cutPolygons.Add(new List<IntPoint>(newP)); // // // LineLoop l = new LineLoop(polygon, inverseTransform); // //l.Draw(); // points.AddRange(l.Vertices); // // //ReducePolygon(null, polygon, toolRadius, inverseTransform); // //area += Clipper.Area(polygon); // //LineStrip strip = new LineStrip(); // //foreach (IntPoint point in polygon) // //{ // // strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); // //} // //strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); // // //strips.Add(strip); // //new LineLoop(strip).Draw(); // } // // //GL.Color3(Color.Black); // //GL.Begin(BeginMode.Lines); // //foreach (Vector3 v in points) // //{ // // foreach (Vector3 v2 in parentPoints) // // { // // if ((v - v2).Length < toolRadius * 2) // // { // // GL.Vertex3(v); // // GL.Vertex3(v2); // // } // // } // //} // //GL.End(); // // parentPoints = points; // removeArea = Clipper.OffsetPolygons(removeArea, -toolRadius, JoinType.jtRound); // removeArea = Clipper.CleanPolygons(removeArea, toolRadius / 100); //} //GL.PopMatrix(); //IOrderedEnumerable<List<IntPoint>> ordered = cutPolygons.OrderBy(poly => Clipper.Area(poly)); // //GL.PushMatrix(); //foreach (List<IntPoint> poly in ordered) //{ // GL.Translate(new Vector3(0, 0, 100)); // LineLoop l = new LineLoop(poly, inverseTransform); // l.Draw(); //} //GL.PopMatrix(); ////strips = new List<LineStrip>(); //GL.Color3(Color.Red); //GL.LineWidth(2); //foreach (List<IntPoint> polygon in whatsLeft) //{ // LineStrip strip = new LineStrip(); // foreach (IntPoint point in polygon) // { // strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); // } // strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); // // strips.Add(strip); // new LineLoop(strip).Draw(); //} //GL.LineWidth(1); } catch (Exception e) { } } }
public override void AccumulateStrips(LineStrip vertices) { }
public LineLoop(List<IntPoint> polygon, Matrix4 transform) { LineStrip l = new LineStrip(); foreach (IntPoint point in polygon) { l.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), transform)); } l.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), transform)); LineLoopFromLineStrip(l); }