Пример #1
0
        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);
            }
        }
Пример #2
0
 public void AppendPolygon(GeneralPolygon2d poly, int gid = -1)
 {
     AppendPolygon(poly.Outer, gid);
     foreach (var hole in poly.Holes)
     {
         AppendPolygon(hole, gid);
     }
 }
Пример #3
0
 public SegmentSet2d(GeneralPolygon2d poly)
 {
     Segments = new List <Segment2d>(poly.Outer.SegmentItr());
     foreach (var hole in poly.Holes)
     {
         Segments.AddRange(hole.SegmentItr());
     }
 }
Пример #4
0
 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);
     }
 }
Пример #5
0
 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);
     }
 }
Пример #6
0
        /// <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]);
                }
            }
        }
Пример #8
0
        /// <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);
        }
Пример #9
0
        /// <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);
            }
        }
Пример #10
0
        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);
            }
        }
Пример #11
0
        /// <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));
        }
Пример #12
0
        // 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
            });
        }
Пример #13
0
        // 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
            });
        }