public void InsertLoop(LineLoop l) { if (!AnyIntersects(l) && !ContainsLoop(l)) { PolygonNode lowestEnclosingLoop = FindLowestNodeEnclosing(l); List <PolygonNode> highestEnclosedByLoop = FindHighestNodeEnclosedBy(l); if (lowestEnclosingLoop == null) { nodes.Add(new PolygonNode(l, null)); } else { lowestEnclosingLoop.children.Add(new PolygonNode(l, lowestEnclosingLoop)); } if (highestEnclosedByLoop != null) { foreach (PolygonNode n in highestEnclosedByLoop) { n.ChangeParent(null); } } } else { throw new Exception("Loop to be added intersects pre-existing loops"); } }
private List <PolygonNode> FindHighestNodeEnclosedBy(LineLoop l) { List <PolygonNode> found = new List <PolygonNode>(); foreach (PolygonNode n in nodes) { if (n.loop.IsInsideOther(l)) { found.Add(n); } } if (found.Count != 0) { return(found); } else { foreach (PolygonNode n in nodes) { found = n.FindHighestNodeEnclosedBy(l); if (found != null) { return(found); } } return(null); } }
public static IntersectionResolution GetIntersectionInfo(WeaklySimplePolygon lhs, WeaklySimplePolygon rhs) { IntersectionResolution res = new IntersectionResolution { intersections = new List <IntersectionPair>(), lhs = new Dictionary <int, List <int> >(), rhs = new Dictionary <int, List <int> >() }; //-1 just refers to verts and not an index into holes for (int i = -1; i < lhs.holes.Count; i++) { LineLoop lhsLoop = (i == -1) ? lhs.verts : lhs.holes[i]; for (int j = -1; j < rhs.holes.Count; j++) { LineLoop rhsLoop = (j == -1) ? rhs.verts : rhs.holes[j]; List <LineLoop.LoopLoopIntersection> theseIntersections = LineLoop.AllIntersections(lhsLoop, rhsLoop); foreach (LineLoop.LoopLoopIntersection info in theseIntersections) { gvec2 lhsDir = lhsLoop[info.lhsIndex + 1] - lhsLoop[info.lhsIndex]; gvec2 rhsDir = rhsLoop[info.rhsIndex + 1] - rhsLoop[info.rhsIndex]; TraversalMode lhsMode = gvec2.Dot(lhsDir, rhsDir.RotatedCCW90()) > 0 ? TraversalMode.entering : TraversalMode.exiting; TraversalMode rhsMode = gvec2.Dot(rhsDir, lhsDir.RotatedCCW90()) > 0 ? TraversalMode.entering : TraversalMode.exiting; res.intersections.Add(new IntersectionPair { vert = info.position, lhs = new IntersectionInfo { index = i, segment = info.lhsIndex, param = info.lhsParam, mode = lhsMode }, rhs = new IntersectionInfo { index = j, segment = info.rhsIndex, param = info.rhsParam, mode = rhsMode } }); if (!res.lhs.ContainsKey(i)) { res.lhs[i] = new List <int>(); } res.lhs[i].Add(res.intersections.Count - 1); if (!res.rhs.ContainsKey(j)) { res.rhs[j] = new List <int>(); } res.rhs[j].Add(res.intersections.Count - 1); } } } return(res); }
public void SplitLinesIntoLine() { //seriesofwords string[] lines = { "No Comment", "Not Required" }; string line = lines[0]; string actualLine1 = LineLoop.ApplyLineLoop(lines, 0); Assert.True(line == actualLine1); }
public bool ContainsLoop(LineLoop l) { foreach (PolygonNode n in nodes) { if (n.ContainsLoop(l)) { return(true); } } return(false); }
public bool AnyIntersects(LineLoop l) { foreach (PolygonNode n in nodes) { if (n.AnyIntersects(l)) { return(true); } } return(false); }
private PolygonNode FindLowestNodeEnclosing(LineLoop l) { foreach (PolygonNode n in nodes) { PolygonNode lowest = n.FindLowestNodeEnclosing(l); if (lowest != null) { return(lowest); } } return(null); }
public bool ContainsLoop(LineLoop l) { if (loop == l) { return(true); } foreach (PolygonNode n in children) { if (n.ContainsLoop(l)) { return(true); } } return(false); }
public bool AnyIntersects(LineLoop l) { if (l.IntersectsOther(loop)) { return(true); } else { foreach (PolygonNode n in children) { if (n.AnyIntersects(l)) { return(true); } } return(false); } }
public PolygonNode FindLowestNodeEnclosing(LineLoop l) { if (l.IsInsideOther(loop)) { foreach (PolygonNode n in children) { PolygonNode lowest = n.FindLowestNodeEnclosing(l); if (lowest != null) { return(lowest); } } return(this); } else { return(null); } }
/// <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; //} }
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 static WeaklySimplePolygon Union(WeaklySimplePolygon lhs, WeaklySimplePolygon rhs) { WeaklySimplePolygon res = new WeaklySimplePolygon(); IntersectionResolution ir = GetIntersectionInfo(lhs, rhs); //preprocessing for (int i = -1; i < lhs.holes.Count; i++) { if (i == -1 && (!ir.lhs.ContainsKey(-1)) && !lhs.verts[0].IsInside(rhs)) { } //if(ir.lhs.ContainsKey() } List <IntersectionPair> currentLoop = new List <IntersectionPair>(); //this loop finds the next IntersectionPair in the loop //and when a loop is complete, outputs it into res while (ir.intersections.Count != 0) { //start off a random pair if we need to if (currentLoop.Count == 0) { currentLoop.Add(ir.intersections[0]); } //find the next intersection and store it in nearestIntersection IntersectionPair nearestIntersection = null; IntersectionPair lastIntersection = currentLoop.Last(); TraversalMode mode = (lastIntersection.lhs.mode == TraversalMode.exiting) ? TraversalMode.lhs : TraversalMode.rhs; //Dictionary<int, int> nextQueue = foreach (IntersectionPair info in ir.intersections) { if (info.lhs.index == lastIntersection.lhs.index && info.rhs.index == lastIntersection.rhs.index && info != lastIntersection) { if (mode == TraversalMode.lhs) { //traversing lhs if (nearestIntersection == null) { nearestIntersection = info; } else { if (nearestIntersection.lhs.dist < lastIntersection.lhs.dist) { if (info.lhs.dist > lastIntersection.lhs.dist || info.lhs.dist < nearestIntersection.lhs.dist) { nearestIntersection = info; } } else { if (info.lhs.dist < nearestIntersection.lhs.dist && info.lhs.dist > lastIntersection.lhs.dist) { nearestIntersection = info; } } } } else { //traversing rhs if (nearestIntersection == null) { nearestIntersection = info; } else { if (nearestIntersection.rhs.dist < lastIntersection.rhs.dist) { if (info.rhs.dist > lastIntersection.rhs.dist || info.rhs.dist < nearestIntersection.rhs.dist) { nearestIntersection = info; } } else { if (info.rhs.dist < nearestIntersection.rhs.dist && info.rhs.dist > lastIntersection.rhs.dist) { nearestIntersection = info; } } } } } } //do what we must with this intersection, we might be done with the loop if (nearestIntersection == currentLoop.First()) { //loop is done, create the loop with actual segments and such LineLoop loop = new LineLoop(); //segment mode TraversalMode segMode = (currentLoop.First().lhs.mode == TraversalMode.exiting) ? TraversalMode.lhs : TraversalMode.rhs; for (int i = 0; i < currentLoop.Count; i++) { IntersectionPair info = currentLoop[i]; IntersectionPair nextInfo = currentLoop[(i + 1) % currentLoop.Count]; loop.Add(info.vert); //select the correct polygon and loop WeaklySimplePolygon opPoly = (segMode == TraversalMode.lhs) ? lhs : rhs; int loopIndex = (segMode == TraversalMode.lhs) ? info.lhs.index : info.rhs.index; LineLoop opLoop = (loopIndex == -1) ? opPoly.verts : opPoly.holes[loopIndex]; int startSegment = ((segMode == TraversalMode.lhs) ? (info.lhs.segment + 1) : info.rhs.segment + 1) % opLoop.Count; int endSegment = (segMode == TraversalMode.lhs) ? nextInfo.lhs.segment : nextInfo.rhs.segment; int endSegmentPlusOneMod = (endSegment + 1) % opLoop.Count; bool first = (segMode == TraversalMode.lhs) ? (info.lhs.dist > nextInfo.lhs.dist) : (info.rhs.dist > nextInfo.rhs.dist); for (int currentSegment = startSegment; (currentSegment != endSegmentPlusOneMod) || first; currentSegment = (currentSegment + 1) % opLoop.Count) { loop.Add(opLoop[currentSegment]); if (first) { first = false; } } if (segMode == TraversalMode.lhs) { segMode = TraversalMode.rhs; } else { segMode = TraversalMode.lhs; } } res.holes.Add(loop); foreach (IntersectionPair info in currentLoop) { ir.intersections.Remove(info); } currentLoop.Clear(); } else { currentLoop.Add(nearestIntersection); } } return(res); }
public WeaklySimplePolygon() { verts = new LineLoop(); holes = new List <LineLoop>(); }
/// <summary> /// Trim interior loops from the line /// </summary> public void Clean(Vector3 normal) { List<int> remove = new List<int>(); for (int i = 0; i < indices.Count(); i++) { Vector3 v1 = GetVertex(i); Vector3 v2 = GetVertex((i + 1) % indices.Count()); for (int j = 2; j < indices.Count() - 1; j++) { int j1 = (j + i) % indices.Count(); int j2 = (j + i + 1) % indices.Count(); Vector3 v3 = GetVertex(j1); Vector3 v4 = GetVertex(j2); Vector3 n1 = v2 - v1; Vector3 n2 = v4 - v3; n1.Normalize(); n2.Normalize(); if ((n1 - n2).Length < 0.0001f) { // No crossing, same direction continue; } Vector3 perp = Vector3.Cross(normal, n2); Plane p = new Plane (); //GL.Begin(BeginMode.Lines); //GL.Vertex3(v4); //GL.Vertex3(v4 + perp * 100); //GL.End(); p.normal = perp; p.point = v3; float distance = p.Distance(v1, n1); if (distance > 0 && distance < (v2 - v1).Length && (Vector3.Dot(perp, n1) < 0))//!float.IsInfinity(distance)) { Vector3 point = n1 * distance + v1; if (DistanceToCylinder (v3, v4, point) < 0.01f) { for (int k = 0; k < j; k++) { int removeIndex = (i + 1) % indices.Count(); indices.RemoveAt(removeIndex); } vertices.Add(point); indices.Insert(i + 1, vertices.Count() - 1); //GL.PointSize(15); //GL.Color3(Color.Turquoise); //GL.Begin(BeginMode.Points); //GL.Vertex3(point); // //GL.End(); //GL.PointSize(1); i = i - 1; continue; } } } } LineLoop n = new LineLoop(this); this.indices = n.indices; this.vertices = n.vertices; }
public PolygonNode(LineLoop loop, PolygonNode parent) { this.loop = loop; this.parent = parent; this.children = new List <PolygonNode>(); }
public LineLoop Simplify() { List <LineLoop> remainingLoops = holes.ToList(); remainingLoops.Insert(0, verts.Clone()); //iterate over each hole, trying to find a line that cuts the hole out without intersecting anything else while (remainingLoops.Count > 1) { LineLoop hole = remainingLoops[1]; bool holeDone = false; int foundVertexIndex = -1; int foundLoopIndex = -1; int foundOtherVertexIndex = -1; //we have go into each loop including the main loop at index 0 for (int loopIndex = 0; loopIndex < remainingLoops.Count; loopIndex++) { if (loopIndex == 1) { continue; // } LineLoop loop = remainingLoops[loopIndex]; //check each vertex in this hole... for (int p0Index = 0; p0Index < hole.Count; p0Index++) { gvec2 p0 = hole[p0Index]; //and make a segment with each vertex in this loop... for (int p1Index = 0; p1Index < loop.Count; p1Index++) { gvec2 p1 = loop[p1Index]; //we have now obtained our line segment that must be checked for collision against every pre-existing line segment //this operation is important enough to have its own function if (!AnyIntersections(remainingLoops.ToArray(), 1, p0Index, loopIndex, p1Index)) { //we're almost done, just make sure it isn't the wrong side of a hole cutting edge bool valid = true; { gvec2 n0 = (p0 - p1); gvec2 p0n0 = (loop[(p1Index - 1 + loop.Count) % loop.Count] - p1); gvec2 p0n1 = (loop[(p1Index + 1) % loop.Count] - p1); double ap0n0 = Math.Atan2(p0n0.y, p0n0.x) + Math.PI * 2; double an0 = Math.Atan2(n0.y, n0.x) + Math.PI * 2; if (an0 < ap0n0) { an0 += Math.PI * 2; } double ap0n1 = Math.Atan2(p0n1.y, p0n1.x) + Math.PI * 2; if (ap0n1 < ap0n0) { ap0n1 += Math.PI * 2; } if (an0 > ap0n0 && an0 < ap0n1) { valid = false; } } if (valid) { gvec2 n0 = (p1 - p0); gvec2 p0n0 = (hole[(p1Index - 1 + hole.Count) % hole.Count] - p0); gvec2 p0n1 = (hole[(p1Index + 1) % hole.Count] - p0); double ap0n0 = Math.Atan2(p0n0.y, p0n0.x) + Math.PI * 2; double an0 = Math.Atan2(n0.y, n0.x) + Math.PI * 2; if (an0 < ap0n0) { an0 += Math.PI * 2; } double ap0n1 = Math.Atan2(p0n1.y, p0n1.x) + Math.PI * 2; if (ap0n1 < ap0n0) { ap0n1 += Math.PI * 2; } if (an0 > ap0n0 && an0 < ap0n1) { valid = false; } } if (valid) { holeDone = true; foundVertexIndex = p0Index; foundLoopIndex = loopIndex; foundOtherVertexIndex = p1Index; break; } } } if (holeDone) { break; } } if (holeDone) { break; } } if (!holeDone) { throw new Exception("Found no way out for a hole"); } Console.WriteLine("holeDone: " + holeDone); Console.WriteLine("foundVertexIndex: " + foundVertexIndex); Console.WriteLine("foundHoleIndex: " + (foundLoopIndex == -1 ? "main" : foundVertexIndex.ToString())); Console.WriteLine("foundHoleVertexIndex: " + foundOtherVertexIndex); //we need this conditional to account for the main loop winding ccw and holes winding cw if (foundLoopIndex == 0) { remainingLoops[0] = LineLoop.PseudoSimpleJoin(remainingLoops[0], foundOtherVertexIndex, hole, foundVertexIndex, false, false); remainingLoops.RemoveAt(1); } else { remainingLoops[1] = LineLoop.PseudoSimpleJoin(remainingLoops[foundLoopIndex], foundOtherVertexIndex, hole, foundVertexIndex, false, false); remainingLoops.RemoveAt(foundLoopIndex); } } return(remainingLoops[0]); }