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); } }
private LineStrip LineStripFromPolygon(Path polygon) { LineStrip line = new LineStrip(); foreach (IntPoint point in polygon) { line.Append(TransformTo3D(point)); } return(line); }
private Path LineStripToPolygon(LineStrip line) { Path polygon = new Path(); foreach (var point in line.Vertices) { Vector2 result = Vector3.Transform(point, transform).Xy; polygon.Add(new IntPoint((long)Math.Round(result.X), (long)Math.Round(result.Y))); } return(polygon); }
/// <summary> /// Convert the internal data to a list of the largest possible contiguous loops. /// NOTE: This is destructive! /// </summary> /// <returns></returns> public List <LineStrip> GetOuterLoops() { List <LineStrip> loops = new List <LineStrip>(); foreach (Segment segment in segments) { LineStrip loop = FindLargestLoop(segment); if (loop != null) { loops.Add(loop); } } return(loops); }
/// <summary> /// Create a slice from an open path with the given width /// </summary> /// <param name="path"></param> /// <param name="width"></param> /// <param name="plane"></param> public Slice(LineStrip path, float width, Plane plane, bool closed = false) { this.plane = plane; transform = plane.CreateMatrix(); transform = Matrix4.Mult(transform, Matrix4.CreateScale(scale)); inverseTransform = Matrix4.Invert(transform); polyTree = new PolyTree(); ClipperOffset co = new ClipperOffset(); co.ArcTolerance = scale * 0.0001f; if (closed) { co.AddPath(LineStripToPolygon(path), JoinType.jtRound, EndType.etClosedLine); } else { co.AddPath(LineStripToPolygon(path), JoinType.jtRound, EndType.etOpenRound); } co.Execute(ref this.polyTree, scale * width / 2.0f); }
//private float height = .050f; private LineStrip FindLargestLoop(Segment start) { //height += 0.050f; Vector3 normal = new Vector3 (0, 0, 1); Segment next = start; List<Segment> seen = new List<Segment>(); while (!seen.Contains(next)) { //GL.Disable(EnableCap.Lighting); //GL.LineWidth(3); //GL.Begin(PrimitiveType.Lines); //GL.Color3(Color.Blue); //GL.Vertex3(next.a.vector.X, next.a.vector.Y, height); //GL.Color3(Color.LightGreen); //height += .010f; //GL.Vertex3(next.b.vector.X, next.b.vector.Y, height); //GL.End(); //GL.LineWidth(1); //GL.Enable(EnableCap.Lighting); seen.Add(next); Segment best = null; float largestAngle = 0; foreach (Segment s in next.b.used_as_a) { float angle = Angle(-s.Normal, next.Normal, normal); if (angle > largestAngle) { largestAngle = angle; best = s; } } if (best == null) { // No loops return null; } // Destructive: remove references to this element so it's not searched again. // Note: only need to remove forward links (from used_as_a). The links from // used_as_b could be cleared too, but it's not necessary for the algorithm. next.b.used_as_a.Clear(); //next.b.used_as_b.Clear(); next = best; } // Remove all up to the first matched index int index = seen.IndexOf(next); seen.RemoveRange(0, index); LineStrip loop = new LineStrip(); foreach (Segment seg in seen) { loop.Append(seg.a.vector); } return loop; }
private Path LineStripToPolygon(LineStrip line) { Path polygon = new Path(); foreach (var point in line.Vertices) { Vector2 result = Vector3.Transform(point, transform).Xy; polygon.Add(new IntPoint((long)Math.Round(result.X), (long)Math.Round(result.Y))); } return polygon; }
private LineStrip LineStripFromPolygon(Path polygon) { LineStrip line = new LineStrip(); foreach (IntPoint point in polygon) { line.Append(TransformTo3D(point)); } return line; }
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 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(); }
/// <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 float height = .050f; private LineStrip FindLargestLoop(Segment start) { //height += 0.050f; Vector3 normal = new Vector3(0, 0, 1); Segment next = start; List <Segment> seen = new List <Segment>(); while (!seen.Contains(next)) { //GL.Disable(EnableCap.Lighting); //GL.LineWidth(3); //GL.Begin(PrimitiveType.Lines); //GL.Color3(Color.Blue); //GL.Vertex3(next.a.vector.X, next.a.vector.Y, height); //GL.Color3(Color.LightGreen); //height += .010f; //GL.Vertex3(next.b.vector.X, next.b.vector.Y, height); //GL.End(); //GL.LineWidth(1); //GL.Enable(EnableCap.Lighting); seen.Add(next); Segment best = null; float largestAngle = 0; foreach (Segment s in next.b.used_as_a) { float angle = Angle(-s.Normal, next.Normal, normal); if (angle > largestAngle) { largestAngle = angle; best = s; } } if (best == null) { // No loops return(null); } // Destructive: remove references to this element so it's not searched again. // Note: only need to remove forward links (from used_as_a). The links from // used_as_b could be cleared too, but it's not necessary for the algorithm. next.b.used_as_a.Clear(); //next.b.used_as_b.Clear(); next = best; } // Remove all up to the first matched index int index = seen.IndexOf(next); seen.RemoveRange(0, index); LineStrip loop = new LineStrip(); foreach (Segment seg in seen) { loop.Append(seg.a.vector); } return(loop); }
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); } }