// Finds set of "solid" regions - eg boundary loops with interior holes. // Result has outer loops being clockwise, and holes counter-clockwise public SolidRegionInfo FindSolidRegions(double fSimplifyDeviationTol = 0.1, bool bWantCurveSolids = true) { List <SmoothLoopElement> validLoops = new List <SmoothLoopElement>(LoopsItr()); int N = validLoops.Count; // precompute bounding boxes int maxid = 0; foreach (var v in validLoops) { maxid = Math.Max(maxid, v.ID + 1); } AxisAlignedBox2d[] bounds = new AxisAlignedBox2d[maxid]; foreach (var v in validLoops) { bounds[v.ID] = v.Bounds(); } // copy polygons, simplify if desired double fClusterTol = 0.0; // don't do simple clustering, can lose corners double fDeviationTol = fSimplifyDeviationTol; Polygon2d[] polygons = new Polygon2d[maxid]; foreach (var v in validLoops) { Polygon2d p = new Polygon2d(v.polygon); if (fClusterTol > 0 || fDeviationTol > 0) { p.Simplify(fClusterTol, fDeviationTol); } polygons[v.ID] = p; } // sort by bbox containment to speed up testing (does it??) validLoops.Sort((x, y) => { return(bounds[x.ID].Contains(bounds[y.ID]) ? -1 : 1); }); // containment sets bool[] bIsContained = new bool[N]; Dictionary <int, List <int> > ContainSets = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > ContainedParents = new Dictionary <int, List <int> >(); // construct containment sets for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = validLoops[i]; Polygon2d polyi = polygons[loopi.ID]; for (int j = 0; j < N; ++j) { if (i == j) { continue; } SmoothLoopElement loopj = validLoops[j]; Polygon2d polyj = polygons[loopj.ID]; // cannot be contained if bounds are not contained if (bounds[loopi.ID].Contains(bounds[loopj.ID]) == false) { continue; } // any other early-outs?? if (polyi.Contains(polyj)) { if (ContainSets.ContainsKey(i) == false) { ContainSets.Add(i, new List <int>()); } ContainSets[i].Add(j); bIsContained[j] = true; if (ContainedParents.ContainsKey(j) == false) { ContainedParents.Add(j, new List <int>()); } ContainedParents[j].Add(i); } } } List <GeneralPolygon2d> polysolids = new List <GeneralPolygon2d>(); List <PlanarSolid2d> solids = new List <PlanarSolid2d>(); HashSet <SmoothLoopElement> used = new HashSet <SmoothLoopElement>(); Dictionary <SmoothLoopElement, int> LoopToOuterIndex = new Dictionary <SmoothLoopElement, int>(); List <int> ParentsToProcess = new List <int>(); // The following is a lot of code but it is very similar, just not clear how // to refactor out the common functionality // 1) we find all the top-level uncontained polys and add them to the final polys list // 2a) for any poly contained in those parent-polys, that is not also contained in anything else, // add as hole to that poly // 2b) remove all those used parents & holes from consideration // 2c) now find all the "new" top-level polys // 3) repeat 2a-c until done all polys // 4) any remaining polys must be interior solids w/ no holes // **or** weird leftovers like intersecting polys... // add all top-level uncontained polys for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = validLoops[i]; if (bIsContained[i]) { continue; } Polygon2d outer_poly = polygons[loopi.ID]; IParametricCurve2d outer_loop = (bWantCurveSolids) ? loopi.source.Clone() : null; if (outer_poly.IsClockwise == false) { outer_poly.Reverse(); if (bWantCurveSolids) { outer_loop.Reverse(); } } GeneralPolygon2d g = new GeneralPolygon2d(); g.Outer = outer_poly; PlanarSolid2d s = new PlanarSolid2d(); if (bWantCurveSolids) { s.SetOuter(outer_loop, true); } int idx = polysolids.Count; LoopToOuterIndex[loopi] = idx; used.Add(loopi); if (ContainSets.ContainsKey(i)) { ParentsToProcess.Add(i); } polysolids.Add(g); if (bWantCurveSolids) { solids.Add(s); } } // keep iterating until we processed all parent loops while (ParentsToProcess.Count > 0) { List <int> ContainersToRemove = new List <int>(); // now for all top-level polys that contain children, add those children // as long as they do not have multiple contain-parents foreach (int i in ParentsToProcess) { SmoothLoopElement parentloop = validLoops[i]; int outer_idx = LoopToOuterIndex[parentloop]; List <int> children = ContainSets[i]; foreach (int childj in children) { SmoothLoopElement childLoop = validLoops[childj]; Debug.Assert(used.Contains(childLoop) == false); // skip multiply-contained children List <int> parents = ContainedParents[childj]; if (parents.Count > 1) { continue; } Polygon2d hole_poly = polygons[childLoop.ID]; IParametricCurve2d hole_loop = (bWantCurveSolids) ? childLoop.source.Clone() : null; if (hole_poly.IsClockwise) { hole_poly.Reverse(); if (bWantCurveSolids) { hole_loop.Reverse(); } } try { polysolids[outer_idx].AddHole(hole_poly); if (hole_loop != null) { solids[outer_idx].AddHole(hole_loop); } } catch { // don't add this hole - must intersect or something? // We should have caught this earlier! } used.Add(childLoop); if (ContainSets.ContainsKey(childj)) { ContainersToRemove.Add(childj); } } ContainersToRemove.Add(i); } // remove all containers that are no longer valid foreach (int ci in ContainersToRemove) { ContainSets.Remove(ci); // have to remove from each ContainedParents list List <int> keys = new List <int>(ContainedParents.Keys); foreach (int j in keys) { if (ContainedParents[j].Contains(ci)) { ContainedParents[j].Remove(ci); } } } ParentsToProcess.Clear(); // ok now find next-level uncontained parents... for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = validLoops[i]; if (used.Contains(loopi)) { continue; } if (ContainSets.ContainsKey(i) == false) { continue; } List <int> parents = ContainedParents[i]; if (parents.Count > 0) { continue; } Polygon2d outer_poly = polygons[loopi.ID]; IParametricCurve2d outer_loop = (bWantCurveSolids) ? loopi.source.Clone() : null; if (outer_poly.IsClockwise == false) { outer_poly.Reverse(); if (bWantCurveSolids) { outer_loop.Reverse(); } } GeneralPolygon2d g = new GeneralPolygon2d(); g.Outer = outer_poly; PlanarSolid2d s = new PlanarSolid2d(); if (bWantCurveSolids) { s.SetOuter(outer_loop, true); } int idx = polysolids.Count; LoopToOuterIndex[loopi] = idx; used.Add(loopi); if (ContainSets.ContainsKey(i)) { ParentsToProcess.Add(i); } polysolids.Add(g); if (bWantCurveSolids) { solids.Add(s); } } } // any remaining loops must be top-level for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = validLoops[i]; if (used.Contains(loopi)) { continue; } Polygon2d outer_poly = polygons[loopi.ID]; IParametricCurve2d outer_loop = (bWantCurveSolids) ? loopi.source.Clone() : null; if (outer_poly.IsClockwise == false) { outer_poly.Reverse(); if (bWantCurveSolids) { outer_loop.Reverse(); } } GeneralPolygon2d g = new GeneralPolygon2d(); g.Outer = outer_poly; PlanarSolid2d s = new PlanarSolid2d(); if (bWantCurveSolids) { s.SetOuter(outer_loop, true); } polysolids.Add(g); if (bWantCurveSolids) { solids.Add(s); } } return(new SolidRegionInfo() { Polygons = polysolids, Solids = (bWantCurveSolids) ? solids : null }); }
public GeneralPolygon2d(Polygon2d outer) { Outer = outer; }
public Polygon2dBoxTree(Polygon2d poly) { Polygon = poly; build_sequential(poly); }
// build tree of boxes as sequential array void build_sequential(Polygon2d poly) { int NV = poly.VertexCount; int N = NV; int boxCount = 0; layers = 0; layer_counts = new List <int>(); // count how many boxes in each layer, building up from initial segments int bi = 0; while (N > 1) { int layer_boxes = (N / 2) + (N % 2 == 0 ? 0 : 1); boxCount += layer_boxes; N = layer_boxes; layer_counts.Add(layer_boxes); bi += layer_boxes; layers++; } boxes = new Box2d[boxCount]; bi = 0; // make first layer for (int si = 0; si < NV; si += 2) { Vector2d v1 = poly[(si + 1) % NV]; Segment2d seg1 = new Segment2d(poly[si], v1); Box2d box = new Box2d(seg1); if (si < NV - 1) { Segment2d seg2 = new Segment2d(v1, poly[(si + 2) % NV]); Box2d box2 = new Box2d(seg2); box = Box2d.Merge(ref box, ref box2); } boxes[bi++] = box; } // repeatedly build layers until we hit a single box N = bi; int prev_layer_start = 0; bool done = false; while (done == false) { int layer_start = bi; for (int k = 0; k < N; k += 2) { Box2d mbox = Box2d.Merge(ref boxes[prev_layer_start + k], ref boxes[prev_layer_start + k + 1]); boxes[bi++] = mbox; } N = (N / 2) + (N % 2 == 0 ? 0 : 1); prev_layer_start = layer_start; if (N == 1) { done = true; } } }
public void AddPolygon(Polygon2d poly, Style style) { Objects.Add(poly); Styles[poly] = style; Bounds.Contain(poly.Bounds); }
public void AddPolygon(Polygon2d poly) { Objects.Add(poly); Bounds.Contain(poly.Bounds); }