public static void Restore(PolygonFont2d font, BinaryReader reader) { int version = reader.ReadInt32(); if (version != SerializerVersion) { throw new Exception("PolygonFont2d.Restore: invalid version!"); } int nc = reader.ReadInt32(); for (int ci = 0; ci < nc; ++ci) { int buflen = reader.ReadInt32(); byte[] stringbuf = reader.ReadBytes(buflen); string s = Encoding.Unicode.GetString(stringbuf); int numpolys = reader.ReadInt32(); GeneralPolygon2d[] polys = new GeneralPolygon2d[numpolys]; for (int k = 0; k < numpolys; ++k) { polys[k] = new GeneralPolygon2d(); gSerialization.Restore(polys[k], reader); } font.AddCharacter(s, polys); } }
public void AppendPolygon(GeneralPolygon2d poly, int gid = -1) { AppendPolygon(poly.Outer, gid); foreach (var hole in poly.Holes) { AppendPolygon(hole, gid); } }
public SegmentSet2d(GeneralPolygon2d poly) { Segments = new List <Segment2d>(poly.Outer.SegmentItr()); foreach (var hole in poly.Holes) { Segments.AddRange(hole.SegmentItr()); } }
public static void LaplacianSmoothConstrained(GeneralPolygon2d solid, double alpha, int iterations, double max_dist, bool bAllowShrink, bool bAllowGrow) { LaplacianSmoothConstrained(solid.Outer, alpha, iterations, max_dist, bAllowShrink, bAllowGrow); foreach (Polygon2d hole in solid.Holes) { CurveUtils2.LaplacianSmoothConstrained(hole, alpha, iterations, max_dist, bAllowShrink, bAllowGrow); } }
public static void Store(GeneralPolygon2d polygon, BinaryWriter writer) { Store(polygon.Outer, writer); writer.Write(polygon.Holes.Count); for (int i = 0; i < polygon.Holes.Count; ++i) { Store(polygon.Holes[i], writer); } }
/// <summary> /// Actually computes the insertion. In some cases we would like more info /// coming back than we get by using Generate() api. Note that resulting /// mesh is *not* compacted. /// </summary> public DMesh3 ComputeResult(out MeshInsertPolygon insertion) { AxisAlignedBox2d bounds = Polygon.Bounds; double padding = 0.1 * bounds.DiagonalLength; bounds.Expand(padding); TrivialRectGenerator rectgen = (Subdivisions == 1) ? new TrivialRectGenerator() : new GriddedRectGenerator() { EdgeVertices = Subdivisions }; rectgen.Width = (float)bounds.Width; rectgen.Height = (float)bounds.Height; rectgen.IndicesMap = new Index2i(1, 2); rectgen.UVMode = UVMode; rectgen.Clockwise = true; // MeshPolygonInserter assumes mesh faces are CW? (except code says CCW...) rectgen.Generate(); var base_mesh = new DMesh3(); rectgen.MakeMesh(base_mesh); var shiftPolygon = new GeneralPolygon2d(Polygon); Vector2d shift = bounds.Center; shiftPolygon.Translate(-shift); var insert = new MeshInsertPolygon() { Mesh = base_mesh, Polygon = shiftPolygon }; bool bOK = insert.Insert(); if (!bOK) { throw new Exception("TriangulatedPolygonGenerator: failed to Insert()"); } MeshFaceSelection selected = insert.InteriorTriangles; var editor = new MeshEditor(base_mesh); editor.RemoveTriangles((tid) => { return(selected.IsSelected(tid) == false); }, true); var shift3 = new Vector3d(shift.x, shift.y, 0); MeshTransforms.Translate(base_mesh, shift3); insertion = insert; return(base_mesh); }
public GeneralPolygon2dBoxTree(GeneralPolygon2d poly) { Polygon = poly; OuterTree = new Polygon2dBoxTree(poly.Outer); int NH = poly.Holes.Count; if (NH > 0) { HoleTrees = new Polygon2dBoxTree[NH]; for (int k = 0; k < NH; ++k) { HoleTrees[k] = new Polygon2dBoxTree(poly.Holes[k]); } } }
/// <summary> /// Resample parametric solid into polygonal solid /// </summary> public GeneralPolygon2d Convert(double fSpacingLength, double fSpacingT, double fDeviationTolerance) { GeneralPolygon2d poly = new GeneralPolygon2d(); poly.Outer = new Polygon2d( CurveSampler2.AutoSample(this.outer, fSpacingLength, fSpacingT)); poly.Outer.Simplify(0, fDeviationTolerance); foreach (var hole in this.Holes) { Polygon2d holePoly = new Polygon2d( CurveSampler2.AutoSample(hole, fSpacingLength, fSpacingT)); holePoly.Simplify(0, fDeviationTolerance); poly.AddHole(holePoly, false); } return(poly); }
/// <summary> /// simplify outer and holes of a polygon solid with same thresholds /// </summary> public static void Simplify(GeneralPolygon2d solid, double deviationThresh) { PolySimplification2 simp = new PolySimplification2(solid.Outer); simp.SimplifyDeviationThreshold = deviationThresh; simp.Simplify(); solid.Outer.SetVertices(simp.Result, true); foreach (var hole in solid.Holes) { PolySimplification2 holesimp = new PolySimplification2(hole); holesimp.SimplifyDeviationThreshold = deviationThresh; holesimp.Simplify(); hole.SetVertices(holesimp.Result, true); } }
public static void Restore(GeneralPolygon2d polygon, BinaryReader reader) { Polygon2d outer = new Polygon2d(); Restore(outer, reader); polygon.Outer = outer; int hole_count = reader.ReadInt32(); for (int i = 0; i < hole_count; ++i) { Polygon2d holepoly = new Polygon2d(); Restore(holepoly, reader); polygon.AddHole(holepoly, false); } }
/// <summary> /// Find cells that are "inside" the container polygon. /// Currently based on finding a point inside the cell and then /// checking that it is also inside the container. /// This is perhaps not ideal!! /// </summary> public List <Polygon2d> ContainedCells(GeneralPolygon2d container) { Func <Polygon2d, bool> filterF = (poly) => { bool bIsCW = poly.IsClockwise; for (int k = 0; k < poly.VertexCount; k++) { Segment2d s = poly.Segment(k); Vector2d pt = s.Center + MathUtil.Epsilonf * s.Direction.Perp; if (poly.Contains(pt) == bIsCW) { return(container.Contains(pt)); } } // give up return(false); }; return(CellsToPolygons(filterF)); }
// 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> valid = new List <SmoothLoopElement>(LoopsItr()); int N = valid.Count; // precompute bounding boxes int maxid = 0; foreach (var v in valid) { maxid = Math.Max(maxid, v.ID + 1); } AxisAlignedBox2d[] bounds = new AxisAlignedBox2d[maxid]; foreach (var v in valid) { 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 valid) { 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??) valid.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> >(); // construct containment sets for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = valid[i]; Polygon2d polyi = polygons[loopi.ID]; for (int j = 0; j < N; ++j) { if (i == j) { continue; } SmoothLoopElement loopj = valid[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; } } } List <GeneralPolygon2d> polysolids = new List <GeneralPolygon2d>(); List <PlanarSolid2d> solids = new List <PlanarSolid2d>(); List <SmoothLoopElement> used = new List <SmoothLoopElement>(); // extract solids from containment relationships foreach (var i in ContainSets.Keys) { SmoothLoopElement outer_element = valid[i]; used.Add(outer_element); if (bIsContained[i]) { throw new Exception("PlanarComplex.FindSolidRegions: multiply-nested regions not supported!"); } Polygon2d outer_poly = polygons[outer_element.ID]; IParametricCurve2d outer_loop = (bWantCurveSolids) ? outer_element.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); } foreach (int hi in ContainSets[i]) { SmoothLoopElement he = valid[hi]; used.Add(he); Polygon2d hole_poly = polygons[he.ID]; IParametricCurve2d hole_loop = (bWantCurveSolids) ? he.source.Clone() : null; if (hole_poly.IsClockwise) { hole_poly.Reverse(); if (bWantCurveSolids) { hole_loop.Reverse(); } } try { g.AddHole(hole_poly); if (hole_loop != null) { s.AddHole(hole_loop); } } catch { // don't add this hole - must intersect or something // We should have caught this earlier! } } polysolids.Add(g); if (bWantCurveSolids) { solids.Add(s); } } for (int i = 0; i < N; ++i) { SmoothLoopElement loopi = valid[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 }); }
// Finds set of "solid" regions - eg boundary loops with interior holes. // Result has outer loops being clockwise, and holes counter-clockwise public SolidRegionInfo FindSolidRegions(FindSolidsOptions options) { var 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); } var 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 = options.SimplifyDeviationTolerance; var polygons = new Polygon2d[maxid]; foreach (var v in validLoops) { var 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]; var ContainSets = new Dictionary <int, List <int> >(); var ContainedParents = new Dictionary <int, List <int> >(); bool bUseOrient = options.TrustOrientations; bool bWantCurveSolids = options.WantCurveSolids; bool bCheckHoles = !options.AllowOverlappingHoles; // 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]; // if we are preserving orientations, holes cannot contain holes and // outers cannot contain outers! if (bUseOrient && loopj.polygon.IsClockwise == loopi.polygon.IsClockwise) { continue; } // 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); } } } var polysolids = new List <GeneralPolygon2d>(); var polySolidsInfo = new List <GeneralSolid>(); var solids = new List <PlanarSolid2d>(); var used = new HashSet <SmoothLoopElement>(); var LoopToOuterIndex = new Dictionary <SmoothLoopElement, int>(); var 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(); } } var g = new GeneralPolygon2d(); g.Outer = outer_poly; var 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); polySolidsInfo.Add(new GeneralSolid() { Outer = loopi }); if (bWantCurveSolids) { solids.Add(s); } } // keep iterating until we processed all parent loops while (ParentsToProcess.Count > 0) { var 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, bCheckHoles); polySolidsInfo[outer_idx].Holes.Add(childLoop); 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 var 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(); } } var g = new GeneralPolygon2d(); g.Outer = outer_poly; var 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); polySolidsInfo.Add(new GeneralSolid() { Outer = loopi }); 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(); } } var g = new GeneralPolygon2d(); g.Outer = outer_poly; var s = new PlanarSolid2d(); if (bWantCurveSolids) { s.SetOuter(outer_loop, true); } polysolids.Add(g); polySolidsInfo.Add(new GeneralSolid() { Outer = loopi }); if (bWantCurveSolids) { solids.Add(s); } } return(new SolidRegionInfo() { Polygons = polysolids, PolygonsSources = polySolidsInfo, Solids = (bWantCurveSolids) ? solids : null }); }