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 WeaklySimplePolygon Clone() { WeaklySimplePolygon res = new WeaklySimplePolygon { verts = verts.Clone(), holes = new List <LineLoop>() }; foreach (LineLoop hole in holes) { res.holes.Add(hole.Clone()); } return(res); }
public void AccumulateWeaklySimplyPolygons(List <WeaklySimplePolygon> accumulator) { if (loop.Winding == WindingDir.ccw) { WeaklySimplePolygon p = new WeaklySimplePolygon(); p.verts = loop; foreach (PolygonNode n in children) { p.holes.Add(n.loop); } accumulator.Add(p); } foreach (PolygonNode n in children) { n.AccumulateWeaklySimplyPolygons(accumulator); } }
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); }