/// <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); }
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)); }
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")); }
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); } } } }
public static bool IsInsidePolygon(Vector2d point, Polygon2d polygon) { return(polygon.Contains(point)); }
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); }
public static bool OnPolygon2d(this Vector2d vector2d, Polygon2d polygon2d) { return(polygon2d.Contains(vector2d)); }
/// <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)); } }
/// <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)); } } }
/// <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); } }
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(); }