/// <summary>
        /// Returns true if the 'other' polygon is fully contained inside this polygon.
        /// </summary>
        public static bool IsFullyContainedInside(this Polygon2d self, Polygon2d other)
        {
            // check if all my vertices are inside the other polygon
            foreach (var v in self.Points)
            {
                if (!other.Contains(v))
                {
                    return(false);
                }
            }

            // check if all my edges do NOT intersect with edges of the other polygon
            foreach (var e in self.EdgeLines)
            {
                foreach (var x in other.EdgeLines)
                {
                    if (x.Intersects(e))
                    {
                        return(false);
                    }
                }
            }

            // :-)
            return(true);
        }
Exemple #2
0
 public static bool InPolygon2d(this Vector2d vector2d, Polygon2d polygon2d)
 {
     //【】判断点是否落在多边形线段上
     foreach (Segment2d segment2d in polygon2d.SegmentItr())
     {
         double distance = segment2d.DistanceSquared(vector2d);
         if (distance.EqualZreo())
         {
             return(false);
         }
     }
     return(polygon2d.Contains(vector2d));
 }
Exemple #3
0
        public static void test_convex_hull_2()
        {
            Random r = new Random(31337);

            //LocalProfiler p = new LocalProfiler();
            //p.Start("Hulls");

            QueryNumberType[] modes = new QueryNumberType[] { QueryNumberType.QT_DOUBLE, QueryNumberType.QT_INT64 };

            foreach (var queryMode in modes)
            {
                for (int k = 0; k < 1000; ++k)
                {
                    int    N     = 2500;
                    double scale = (r.NextDouble() + 0.1) * 1024.0;

                    Vector2d[] pts = TestUtil.RandomPoints2(N, r, Vector2d.Zero, scale);

                    double eps = MathUtil.Epsilonf;

                    ConvexHull2 hull     = new ConvexHull2(pts, eps, queryMode);
                    Polygon2d   hullPoly = hull.GetHullPolygon();

                    foreach (Vector2d v in pts)
                    {
                        if (hullPoly.Contains(v))
                        {
                            continue;
                        }
                        double d = hullPoly.DistanceSquared(v);
                        if (d < eps)
                        {
                            continue;
                        }
                        System.Console.WriteLine("test_convex_hull: Point {0} not contained!", v);
                    }
                }
            }

            //p.StopAll();
            //System.Console.WriteLine(p.AllTimes());

            //SVGWriter writer = new SVGWriter();
            //foreach (Vector2d v in pts) {
            //    writer.AddCircle(new Circle2d(v, 3.0), SVGWriter.Style.Outline("black", 1.0f));
            //}
            //writer.AddPolygon(hullPoly, SVGWriter.Style.Outline("red", 2.0f));
            //writer.Write(TestUtil.GetTestOutputPath("test.svg"));
        }
Exemple #4
0
        public static void test_winding()
        {
            Random r    = new Random(31337);
            int    NPTS = 1000;

            double    radius = 1;
            Polygon2d poly   = Polygon2d.MakeCircle(radius, 777);

            Vector2d[] testPts = TestUtil.RandomPoints2(NPTS, r, Vector2d.Zero, radius);
            foreach (Vector2d v in testPts)
            {
                bool   really_inside  = (v.Length < radius);
                bool   inside         = poly.Contains(v);
                double winding0       = poly.WindingIntegral(v);
                bool   inside_winding = !(Math.Abs(winding0) < MathUtil.Epsilonf);
                if (really_inside != inside || really_inside != inside_winding)
                {
                    System.Console.WriteLine("Failed! truth {0}  inside {1}   winding0 {2}",
                                             really_inside, inside, winding0);
                }
            }

            // test random polygons
            int NPOLYS = 100;

            for (int k = 0; k < NPOLYS; ++k)
            {
                poly    = new Polygon2d(TestUtil.RandomPoints2(30, r, Vector2d.Zero, radius));
                testPts = TestUtil.RandomPoints2(NPTS, r, Vector2d.Zero, radius);
                foreach (Vector2d v in testPts)
                {
                    bool   inside         = poly.Contains(v);
                    double winding0       = poly.WindingIntegral(v);
                    bool   inside_winding = !(Math.Abs(winding0) < MathUtil.Epsilonf);
                    if (inside != inside_winding)
                    {
                        System.Console.WriteLine("Failed! inside {0}   winding0 {1}", inside, winding0);
                    }
                }
            }
        }
Exemple #5
0
 public static bool IsInsidePolygon(Vector2d point, Polygon2d polygon)
 {
     return(polygon.Contains(point));
 }
Exemple #6
0
        public bool Insert()
        {
            Func <int, bool> is_contained_v = (vid) => {
                Vector3d v   = Mesh.GetVertex(vid);
                Vector2f vf2 = ProjectFrame.ToPlaneUV((Vector3f)v, 2);
                return(Polygon.Contains(vf2));
            };

            MeshVertexSelection vertexROI = new MeshVertexSelection(Mesh);
            Index3i             seedT     = Mesh.GetTriangle(SeedTriangle);

            // if a seed vert of seed triangle is containd in polygon, we will
            // flood-fill out from there, this gives a better ROI.
            // If not, we will try flood-fill from the seed triangles.
            List <int> seed_verts = new List <int>();

            for (int j = 0; j < 3; ++j)
            {
                if (is_contained_v(seedT[j]))
                {
                    seed_verts.Add(seedT[j]);
                }
            }
            if (seed_verts.Count == 0)
            {
                seed_verts.Add(seedT.a);
                seed_verts.Add(seedT.b);
                seed_verts.Add(seedT.c);
            }

            // flood-fill out from seed vertices until we have found all vertices
            // contained in polygon
            vertexROI.FloodFill(seed_verts.ToArray(), is_contained_v);

            // convert vertex ROI to face ROI
            MeshFaceSelection faceROI = new MeshFaceSelection(Mesh, vertexROI, 1);

            faceROI.ExpandToOneRingNeighbours();
            faceROI.FillEars(true);    // this might be a good idea...

            // construct submesh
            RegionOperator regionOp   = new RegionOperator(Mesh, faceROI);
            DSubmesh3      roiSubmesh = regionOp.Region;
            DMesh3         roiMesh    = roiSubmesh.SubMesh;

            // save 3D positions of unmodified mesh
            Vector3d[] initialPositions = new Vector3d[roiMesh.MaxVertexID];

            // map roi mesh to plane
            MeshTransforms.PerVertexTransform(roiMesh, roiMesh.VertexIndices(), (v, vid) => {
                Vector2f uv           = ProjectFrame.ToPlaneUV((Vector3f)v, 2);
                initialPositions[vid] = v;
                return(new Vector3d(uv.x, uv.y, 0));
            });

            // save a copy of 2D mesh and construct bvtree. we will use
            // this later to project back to 3d
            // [TODO] can we use a better spatial DS here, that takes advantage of 2D?
            DMesh3         projectMesh = new DMesh3(roiMesh);
            DMeshAABBTree3 projecter   = new DMeshAABBTree3(projectMesh, true);

            MeshInsertUVPolyCurve insertUV = new MeshInsertUVPolyCurve(roiMesh, Polygon);
            //insertUV.Validate()
            bool bOK = insertUV.Apply();

            if (!bOK)
            {
                throw new Exception("insertUV.Apply() failed");
            }

            if (SimplifyInsertion)
            {
                insertUV.Simplify();
            }

            int[] insertedPolyVerts = insertUV.CurveVertices;

            // grab inserted loop, assuming it worked
            EdgeLoop insertedLoop = null;

            if (insertUV.Loops.Count == 1)
            {
                insertedLoop = insertUV.Loops[0];
            }

            // find interior triangles
            List <int> interiorT = new List <int>();

            foreach (int tid in roiMesh.TriangleIndices())
            {
                Vector3d centroid = roiMesh.GetTriCentroid(tid);
                if (Polygon.Contains(centroid.xy))
                {
                    interiorT.Add(tid);
                }
            }
            if (RemovePolygonInterior)
            {
                MeshEditor editor = new MeshEditor(roiMesh);
                editor.RemoveTriangles(interiorT, true);
                InteriorTriangles = null;
            }
            else
            {
                InteriorTriangles = interiorT.ToArray();
            }


            // map back to 3d
            Vector3d a = Vector3d.Zero, b = Vector3d.Zero, c = Vector3d.Zero;

            foreach (int vid in roiMesh.VertexIndices())
            {
                // [TODO] somehow re-use exact positions from regionOp maps?

                // construct new 3D pos w/ barycentric interpolation
                Vector3d v   = roiMesh.GetVertex(vid);
                int      tid = projecter.FindNearestTriangle(v);
                Index3i  tri = projectMesh.GetTriangle(tid);
                projectMesh.GetTriVertices(tid, ref a, ref b, ref c);
                Vector3d bary = MathUtil.BarycentricCoords(ref v, ref a, ref b, ref c);
                Vector3d pos  = bary.x * initialPositions[tri.a] + bary.y * initialPositions[tri.b] + bary.z * initialPositions[tri.c];

                roiMesh.SetVertex(vid, pos);
            }

            bOK = BackPropagate(regionOp, insertedPolyVerts, insertedLoop);

            return(bOK);
        }
Exemple #7
0
 public static bool OnPolygon2d(this Vector2d vector2d, Polygon2d polygon2d)
 {
     return(polygon2d.Contains(vector2d));
 }
Exemple #8
0
        /// <summary>
        /// Returns the unified Polygon of the two given ones.
        /// Works only with convex-Polygons
        /// Returns an empty Polygon if the two do not intersect
        /// </summary>
        public static IEnumerable <Polygon2d> Union(this Polygon2d p0, Polygon2d p1)
        {
            Polygon2d[] arr = new Polygon2d[2];
            arr[0] = p0;
            arr[1] = p1;

            int current = 0;
            int other   = 1;

            List <V2d> points = new List <V2d>();
            bool       enter  = false;
            int        index  = -1;
            V2d        point  = V2d.NaN;

            bool firstIntersectionFound = false;
            V2d  firstIntersectionPoint = V2d.NaN;

            for (int i = 0; i >= 0; i = (i + 1) % arr[current].PointCount)
            {
                V2d start = arr[current][(i + arr[current].PointCount - 1) % arr[current].PointCount];
                V2d end   = arr[current][i];

                if (arr[other].ClosestIntersection(start, end, out enter, out index, out point))
                {
                    if (!firstIntersectionFound)
                    {
                        firstIntersectionFound = true;
                        firstIntersectionPoint = point;
                    }
                    else
                    {
                        if ((point - firstIntersectionPoint).Length < 0.001)
                        {
                            break;
                        }
                    }

                    if (enter)
                    {
                        points.Add(point);

                        while ((arr[other][(index + 1) % arr[other].PointCount] - point).Length < 0.001)
                        {
                            index = (index + 1) % arr[other].PointCount;
                        }

                        if (!arr[current].Contains(arr[other][(index + 1) % arr[other].PointCount]))
                        {
                            points.Add(arr[other][(index + 1) % arr[other].PointCount]);
                            index = (index + 1) % arr[other].PointCount;
                        }

                        i       = index;
                        current = (current == 1 ? 0 : 1);
                        other   = (current == 1 ? 0 : 1);
                    }
                    else
                    {
                        points.Add(point);
                        if (!arr[other].Contains(arr[current][i]))
                        {
                            points.Add(arr[current][i]);
                        }
                    }
                }
                else
                {
                    if (i == arr[current].PointCount - 1 && !firstIntersectionFound)
                    {
                        break;
                    }

                    if (!arr[other].Contains(end) && firstIntersectionFound)
                    {
                        points.Add(end);
                    }
                }
            }

            if (!firstIntersectionFound)
            {
                if (p0.Contains(p1[0]))
                {
                    yield return(p0);
                }
                else if (p1.Contains(p0[0]))
                {
                    yield return(p1);
                }
                else
                {
                    yield return(p0);

                    yield return(p1);
                }
            }
            else
            {
                yield return(new Polygon2d(points));
            }
        }
Exemple #9
0
        /// <summary>
        /// Returns the Line-Segments of line inside the Polygon (CCW ordered).
        /// Works only with Convex-Polygons
        /// </summary>
        public static Line2d ClipWithConvex(this Line2d line, Polygon2d poly)
        {
            V2d  p = V2d.NaN;
            bool i0, i1;

            i0 = poly.Contains(line.P0);
            i1 = poly.Contains(line.P1);

            if (i0 && i1)
            {
                return(line);
            }
            else if ((!i0 && i1) || (i0 && !i1))
            {
                foreach (var l in poly.EdgeLines)
                {
                    if (line.Intersects(l, out p))
                    {
                        break;
                    }
                }

                if (i0)
                {
                    return(new Line2d(line.P0, p));
                }
                else
                {
                    return(new Line2d(p, line.P1));
                }
            }
            else
            {
                V2d p0 = V2d.NaN;
                V2d p1 = V2d.NaN;
                int c  = 0;

                foreach (var l in poly.EdgeLines)
                {
                    if (line.Intersects(l, out p))
                    {
                        if (c == 0)
                        {
                            p0 = p;
                        }
                        else
                        {
                            p1 = p;
                        }
                        c++;
                    }
                }

                if (c == 2)
                {
                    V2d u = p1 - p0;

                    if (u.Dot(line.Direction) > 0)
                    {
                        return(new Line2d(p0, p1));
                    }
                    else
                    {
                        return(new Line2d(p1, p0));
                    }
                }
                else
                {
                    return(new Line2d(V2d.NaN, V2d.NaN));
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Returns the Line-Segments of line inside the Polygon (CCW ordered).
        /// Works with all (convex and non-convex) Polygons
        /// </summary>
        public static IEnumerable <Line2d> ClipWith(this Line2d line, Polygon2d poly)
        {
            bool i0, i1;

            i0 = poly.Contains(line.P0);
            i1 = poly.Contains(line.P1);


            List <V2d>  resulting = new List <V2d>();
            List <bool> enter     = new List <bool>();

            if (i0)
            {
                resulting.Add(line.P0);
                enter.Add(true);
            }
            if (i1)
            {
                resulting.Add(line.P1);
                enter.Add(false);
            }

            V2d p         = V2d.NaN;
            V2d direction = line.Direction;

            foreach (var l in poly.EdgeLines)
            {
                if (line.Intersects(l, out p))
                {
                    V2d d = l.Direction;
                    V2d n = new V2d(-d.Y, d.X);

                    if (!p.IsNaN)
                    {
                        bool addflag = true;
                        bool flag    = direction.Dot(n) > 0;

                        for (int i = 0; i < resulting.Count; i++)
                        {
                            if (Fun.IsTiny((resulting[i] - p).Length))
                            {
                                if (flag != enter[i])
                                {
                                    resulting.RemoveAt(i);
                                    enter.RemoveAt(i);
                                }

                                addflag = false;
                                break;
                            }
                        }

                        if (addflag)
                        {
                            resulting.Add(p);
                            enter.Add(flag);
                        }
                    }
                }
            }


            V2d dir = line.P1 - line.P0;

            resulting = (from r in resulting select r).OrderBy(x => x.Dot(dir)).ToList();

            int           counter = resulting.Count;
            List <Line2d> lines   = new List <Line2d>();

            for (int i = 0; i < counter - 1; i += 2)
            {
                lines.Add(new Line2d(resulting[i], resulting[i + 1]));
            }
            return(lines);
        }
        /// <summary>
        /// Trim / split a segment by a polygon.
        /// </summary>
        /// <param name="_type">0 = inside; 1 = outside ; 2 = both sides</param>
        public static List <Segment2d> Trim(this Polygon2d _polygon, Segment2d _seg, int _type)
        {
            var list = new List <Segment2d>();
            //find intersections
            List <KeyValuePair <double, Vector2d> > intPs = new List <KeyValuePair <double, Vector2d> >();

            foreach (var edge in _polygon.SegmentItr())
            {
                var  segIntr = new IntrSegment2Segment2(_seg, edge);
                bool b       = segIntr.Find();
                if (b)
                {
                    intPs.Add(new KeyValuePair <double, Vector2d>(segIntr.Parameter0, segIntr.Point0));
                }
            }
            //if no intersection
            if (intPs.Count == 0)
            {
                if (_type == 1)
                {
                    //return empty list
                }
                else
                {
                    //check if segment is contained inside polygon
                    if (_polygon.Contains(_seg))
                    {
                        list.Add(_seg);
                    }
                }
                return(list);
            }
            //sort intersection points by position
            var sortedIntPs = intPs.OrderBy(x => x.Key).Select(x => x.Value).ToList();

            //get two list of segments from intersections
            var list0 = new List <Segment2d>();
            var list1 = new List <Segment2d>()
            {
                new Segment2d(_seg.P0, sortedIntPs[0])
            };

            for (int i = 1; i < sortedIntPs.Count; i += 2)
            {
                Vector2d p0, p1, p2;
                p0 = sortedIntPs[i - 1];
                p1 = sortedIntPs[i];
                list0.Add(new Segment2d(p0, p1));
                if (i + 1 < sortedIntPs.Count)
                {
                    p2 = sortedIntPs[i + 1];
                    list1.Add(new Segment2d(p1, p2));
                }
            }
            //use even/odd of intr num to decide the last segment
            var last = new Segment2d(sortedIntPs.Last(), _seg.P1);

            if (sortedIntPs.Count % 2 == 0)
            {
                list1.Add(last);
            }
            else
            {
                list0.Add(last);
            }

            //check starting point inside or outside
            bool startInside = _polygon.Contains(_seg.P0);

            //return coresponding list of segments
            if (_type == 0)
            {
                return(startInside ? list1 : list0);
            }
            else if (_type == 1)
            {
                return(startInside ? list0 : list1);
            }
            else
            {
                list.AddRange(list0);
                list.AddRange(list1);
                return(list);
            }
        }
Exemple #12
0
        public static void test_uv_insert_segment()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_250v.obj");

            mesh.EnableVertexUVs(Vector2f.Zero);

            MeshTransforms.ConvertYUpToZUp(mesh);

            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);

            spatial.Build();
            int tid = spatial.FindNearestTriangle(Vector3d.Zero);

            //Polygon2d poly = Polygon2d.MakeRectangle(Vector2d.Zero, 5, 5);
            Polygon2d poly = Polygon2d.MakeCircle(5, 13);
            //PolyLine2d poly = new PolyLine2d( new Vector2d[] { -5 * Vector2d.One, 5 * Vector2d.One });


            //int tri_edge0 = mesh.GetTriEdge(tid, 0);
            //Index2i edge0_tris = mesh.GetEdgeT(tri_edge0);
            //Index2i edge0_verts = mesh.GetEdgeV(tri_edge0);
            //Vector3d v0 = mesh.GetVertex(edge0_verts.a), v1 = mesh.GetVertex(edge0_verts.b);
            //Vector3d c = mesh.GetTriCentroid(tid);
            //Polygon2d poly = new Polygon2d(new Vector2d[] {
            //    Vector2d.Lerp(v0.xy, v1.xy, -0.25),
            //    Vector2d.Lerp(v0.xy, v1.xy, 1.5),
            //    c.xy
            //});

            MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(mesh, poly);

            insert.Apply();



            Polygon2d     test_poly = new Polygon2d();
            List <double> distances = new List <double>();
            List <int>    nearests  = new List <int>();

            for (int i = 0; i < insert.Loops[0].VertexCount; ++i)
            {
                Vector2d v = mesh.GetVertex(insert.Loops[0].Vertices[i]).xy;
                test_poly.AppendVertex(v);
                int iNear; double fNear;
                distances.Add(poly.DistanceSquared(v, out iNear, out fNear));
                nearests.Add(iNear);
            }

            System.Console.WriteLine("inserted loop poly has {0} edges", insert.Loops[0].EdgeCount);

            // find a triangle connected to loop that is inside the polygon
            //   [TODO] maybe we could be a bit more robust about this? at least
            //   check if triangle is too degenerate...
            int seed_tri = -1;

            for (int i = 0; i < insert.Loops[0].EdgeCount; ++i)
            {
                Index2i  et   = mesh.GetEdgeT(insert.Loops[0].Edges[i]);
                Vector3d ca   = mesh.GetTriCentroid(et.a);
                bool     in_a = poly.Contains(ca.xy);
                Vector3d cb   = mesh.GetTriCentroid(et.b);
                bool     in_b = poly.Contains(cb.xy);
                if (in_a && in_b == false)
                {
                    seed_tri = et.a;
                    break;
                }
                else if (in_b && in_a == false)
                {
                    seed_tri = et.b;
                    break;
                }
            }
            Util.gDevAssert(seed_tri != -1);

            // flood-fill inside loop
            HashSet <int>     loopEdges = new HashSet <int>(insert.Loops[0].Edges);
            MeshFaceSelection sel       = new MeshFaceSelection(mesh);

            sel.FloodFill(seed_tri, null, (eid) => { return(loopEdges.Contains(eid) == false); });

            // delete inside loop
            MeshEditor editor = new MeshEditor(mesh);

            editor.RemoveTriangles(sel, true);


            MeshTransforms.ConvertZUpToYUp(mesh);

            TestUtil.WriteTestOutputMesh(mesh, "insert_uv_segment.obj");



            //OBJWriter writer = new OBJWriter();
            //var s = new System.IO.StreamWriter(Program.TEST_OUTPUT_PATH + "mesh_local_param.obj", false);
            //List<WriteMesh> wm = new List<WriteMesh>() { new WriteMesh(mesh) };
            //WriteOptions opt = new WriteOptions() {
            //    bCombineMeshes = false, bWriteGroups = false, bPerVertexColors = true, bPerVertexUVs = true,
            //    AsciiHeaderFunc = () => { return "mttllib checkerboard.mtl\r\nusemtl checkerboard\r\n"; }
            //};
            //writer.Write(s, wm, opt);
            //s.Close();
        }