public void ContainsInsideTest() { Assert.IsTrue(m_arrow.ContainsInside(new Vector2(1.5f, 0))); Assert.IsFalse(m_arrow.ContainsInside(new Vector2(0, 0))); Assert.IsTrue(m_diamond.ContainsInside(new Vector2(0, 0))); Assert.IsFalse(m_diamond.ContainsInside(new Vector2(-999, 999))); Assert.IsTrue(m_containsPoly.ContainsInside(new Vector2(1, 3))); Assert.IsFalse(m_containsPoly.ContainsInside(new Vector2(3, 1))); }
/// <inheritdoc /> public bool VisibleToOtherVertex( Vector2 vertex1, Vector2 vertex2, Polygon2D polygon) { LineSegment seg1 = new LineSegment(vertex1, vertex2); foreach (LineSegment lineSegment in polygon.Segments) { // Check if any of the line segments intersect with the // line segments between the two vertices. If they so then // the two vertices cannot see each other. With the exception // that an intersection with an endpoint does not count as // blocking visibility Vector2?intersection = seg1.IntersectProper(lineSegment); if (intersection != null) { // Check if the two lines are parallel. We allow two vertices // to see each other if they they are along a straight line if (!seg1.IsParallel(lineSegment)) { return(false); } } } // Non of the line segments of the polygon intersect with the // visibility line between the two points. Next we need to check if // the visibility line is inside of the polygon // We take the midpoint of the line. If this is inside the polygon // then the two points can see each other return(polygon.ContainsInside(seg1.Midpoint)); }
/// <summary> /// Dirty method O(n^2) /// </summary> /// <param name="a_poly1"></param> /// <param name="a_poly2"></param> /// <returns></returns> public static Polygon2D IntersectConvex(Polygon2D a_poly1, Polygon2D a_poly2) { if (!(a_poly1.IsConvex())) { throw new GeomException("Method not defined for nonconvex polygons" + a_poly1); } if (!(a_poly2.IsConvex())) { throw new GeomException("Method not defined for nonconvex polygons" + a_poly2); } // obtain vertices that lie inside both polygons var resultVertices = a_poly1.Vertices .Where(v => a_poly2.ContainsInside(v)) .Concat(a_poly2.Vertices.Where(v => a_poly1.ContainsInside(v))) .ToList(); // add intersections between two polygon segments resultVertices.AddRange(a_poly1.Segments.SelectMany(seg => seg.Intersect(a_poly2.Segments))); // remove any duplicates resultVertices = resultVertices.Distinct().ToList(); // retrieve convex hull of relevant vertices if (resultVertices.Count() >= 3) { var poly = ConvexHull.ComputeConvexHull(resultVertices); Debug.Assert(poly.IsConvex()); return(poly); } return(null); }
public static int TrianglePoints(List <Vector2> pts, int Anum, int Bnum, int Cnum) { int cnt = 0; var triangleABC = new Polygon2D(); triangleABC.AddVertex(pts[Anum]); triangleABC.AddVertex(pts[Bnum]); triangleABC.AddVertex(pts[Cnum]); for (int i = 0; i < pts.Count; i++) { if ((i == Bnum) || (i == Anum) || (i == Cnum)) { continue; } if (triangleABC.ContainsInside(pts[i])) { cnt++; } } //Debug.Log(cnt); triangleABC.Clear(); return(cnt); }
private int HullRate() { m_selected_Hull = ConvexHull.ComputeConvexHull(m_selected_points.Select(v => v.Pos)); if (m_selected_Hull.VertexCount < 3) { return(0); } int tot = m_selected_Hull.VertexCount; foreach (var point in m_points) { if (m_selected_Hull.ContainsInside(point.Pos)) { tot++; } } m_selected_Hull.SetPointNumber(tot); //Draw new convex hull line segments. foreach (var segmesh in lineMeshes) { Destroy(segmesh); } lineMeshes.Clear(); foreach (var seg in m_selected_Hull.Segments) { //Add a line renderer // instantiate new road mesh var roadmesh = Instantiate(m_userLineMeshPrefab, Vector3.forward, Quaternion.identity) as GameObject; roadmesh.transform.parent = this.transform; instantObjects.Add(roadmesh); lineMeshes.Add(roadmesh); //roadmesh.GetComponent<P1HullSegment>().Segment =seg; var roadmeshScript = roadmesh.GetComponent <ReshapingMesh>(); roadmeshScript.CreateNewMesh(seg.Point1, seg.Point2); } //Update current area in information panel GameObject.Find("PointsNumber").GetComponent <Text>().text = m_selected_Hull.PointNumber.ToString(); // 60%, 80%, 95% pass level for (int i = 0; i < m_rateList.Count; i++) { if (m_selected_Hull.PointNumber < (int)(m_rateList[i] * m_solutionHull.PointNumber)) { return(i); } } return(m_rateList.Count - 1); }
public static int PolygonPoints(List <Vector2> pts, Polygon2D plg) { int tot = 0; foreach (var p in pts) { if (plg.ContainsInside(p) || plg.OnBoundary(p)) { tot++; } } return(tot); }
/// <summary> /// check if intersect /// </summary> /// <param name="a_poly1"></param> /// <param name="a_poly2"></param> /// <returns></returns> public static bool ifIntersect(Polygon2D a_poly1, Polygon2D a_poly2) { if (!(a_poly1.IsConvex())) { throw new GeomException("Method not defined for nonconvex polygons" + a_poly1); } if (!(a_poly2.IsConvex())) { throw new GeomException("Method not defined for nonconvex polygons" + a_poly2); } // obtain vertices that lie inside both polygons var resultVertices = a_poly1.Vertices .Where(v => a_poly2.ContainsInside(v)) .Concat(a_poly2.Vertices.Where(v => a_poly1.ContainsInside(v))) .ToList(); Debug.Log("result Vertices in Intersector: " + resultVertices.Count); return(resultVertices.Count > 0); }
public WeilerAtherton(Polygon2D a_subject, Polygon2D a_clip) { // initialize variables Subject = a_subject; Clip = a_clip; SubjectList = new LinkedList <WAPoint>(); ClipList = new LinkedList <WAPoint>(); SubjectNode = new Dictionary <WAPoint, LinkedListNode <WAPoint> >(); ClipNode = new Dictionary <WAPoint, LinkedListNode <WAPoint> >(); EntryIntersections = new HashSet <WAPoint>(); // store intersections for clipping line segment // saves recomputation of intersections and entry-exit categorization var intersectSegmentsClip = new Dictionary <LineSegment, List <WAPoint> >(); foreach (var seg in a_clip.Segments) { intersectSegmentsClip.Add(seg, new List <WAPoint>()); } // find all intersections and create subject list foreach (var seg1 in a_subject.Segments) { // retrieve intersection list var vertices = new List <WAPoint>(); var point = new WAPoint(seg1.Point1, WAList.Vertex); var node = SubjectList.AddLast(point); SubjectNode.Add(point, node); foreach (var seg2 in a_clip.Segments) { var intersect = seg1.Intersect(seg2); if (intersect.HasValue) { // store intersection point point = new WAPoint(intersect.Value, WAList.Ignore); vertices.Add(point); intersectSegmentsClip[seg2].Add(point); } } // sort intersections on distance to start vertex vertices.Sort(new ClosestToPointComparer(seg1.Point1)); foreach (var vertex in vertices) { node = SubjectList.AddLast(vertex); SubjectNode.Add(vertex, node); } } // remove duplicates for (var node = SubjectList.First; node != null; node = node.Next) { var next = node.Next ?? SubjectList.First; while (node != next && MathUtil.EqualsEps(node.Value.Pos, next.Value.Pos)) { if (node.Value.Type == WAList.Vertex) { node.Value.Type = WAList.Ignore; SubjectList.Remove(node); EntryIntersections.Remove(node.Value); node = next; } else { next.Value.Type = WAList.Ignore; SubjectList.Remove(next); EntryIntersections.Remove(next.Value); } next = node.Next ?? SubjectList.First; } } // set entry/exit types correctly for (var node = SubjectList.First; node != null; node = node.Next) { var prev = node.Previous ?? SubjectList.Last; var vertex = node.Value; var inside1 = Clip.ContainsInside(prev.Value.Pos); var inside2 = Clip.ContainsInside(vertex.Pos); if (!inside1 && inside2) { vertex.Type = WAList.Entry; } else if (inside1 && !inside2) { prev.Value.Type = WAList.Exit; EntryIntersections.Remove(vertex); } if (vertex.Type == WAList.Entry) { EntryIntersections.Add(vertex); } } // create clip list and intersections foreach (var seg in a_clip.Segments) { var vertices = intersectSegmentsClip[seg]; // sort intersections on distance to start vertex intersectSegmentsClip[seg].Sort(new ClosestToPointComparer(seg.Point1)); vertices.Insert(0, new WAPoint(seg.Point1, WAList.Vertex)); // loop over intersections foreach (var vertex in vertices) { if (vertex.Type == WAList.Ignore) { continue; } // add intersection to clipping list var node = ClipList.AddLast(vertex); ClipNode.Add(vertex, node); } } }
/// <summary> /// Computes the visibility polygon from the given point /// inside of a simple polygon (given as n vertices in CCW order) in O(n) time. /// Based on: https://cs.uwaterloo.ca/research/tr/1985/CS-85-38.pdf /// </summary> /// <param name="polygon"></param> /// <param name="z"></param> /// <returns></returns> public static Polygon2D Vision(Polygon2D polygon, Vector2 z) { // check for invalid polygon if (polygon.VertexCount < 3) { return(null); } if (!(polygon.ContainsInside(z) || polygon.OnBoundary(z))) { throw new ArgumentException("Visibility point must be inside polygon"); } // list v, satisfies assumptions made in paper (section 2, paragraph 1 // and 2). double initAngle; var vs = Preprocess(polygon, z, out initAngle); var s = new Stack <VertDispl>(); var i = 0; VertDispl w = null; var ccw = true; var v0 = vs.Get(0); s.Push(v0); Debug.Assert(vs.n > 1); NextCall m_nextCall; if (MathUtil.GEQEps(vs.Get(1).alpha, v0.alpha)) { m_nextCall = Advance(ref vs, ref s, ref i, ref w, ref ccw); } else { m_nextCall = Scan(ref vs, ref s, ref i, ref w, ref ccw); // CounterClockWise } while (m_nextCall != NextCall.STOP) { switch (m_nextCall) { case NextCall.ADVANCE: m_nextCall = Advance(ref vs, ref s, ref i, ref w, ref ccw); break; case NextCall.RETARD: m_nextCall = Retard(ref vs, ref s, ref i, ref w, ref ccw); break; case NextCall.SCAN: m_nextCall = Scan(ref vs, ref s, ref i, ref w, ref ccw); break; } } var sList = s.ToList(); // error occurred due to robustness if (sList.Count == 0) { return(new Polygon2D()); } Debug.Assert(MathUtil.EqualsEps(sList[s.Count - 1].p.Cartesian, v0.p.Cartesian)); var poly = Postprocess(sList, vs, z, initAngle); return(poly); }
public WeilerAtherton(Polygon2D a_subject, Polygon2D a_clip) { // initialize variables Subject = a_subject; Clip = a_clip; SubjectList = new LinkedList <WAPoint>(Subject.Vertices.Select(v => new WAPoint(v, WAList.Vertex))); ClipList = new LinkedList <WAPoint>(Clip.Vertices.Select(v => new WAPoint(v, WAList.Vertex))); SubjectNode = new Dictionary <WAPoint, LinkedListNode <WAPoint> >(); ClipNode = new Dictionary <WAPoint, LinkedListNode <WAPoint> >(); Entry = new HashSet <WAPoint>(); Exit = new HashSet <WAPoint>(); // find all intersections and create subject and clip list for (var node1 = SubjectList.First; node1 != null; node1 = node1.Next) { // calculate subject segment var next1 = node1.Next ?? SubjectList.First; var seg1 = new LineSegment(node1.Value.Pos, next1.Value.Pos); // obtain intersection lists var intersections = new List <Vector2>(); var intersectNodes = new Dictionary <Vector2, LinkedListNode <WAPoint> >(); for (var node2 = ClipList.Last; node2 != null; node2 = node2.Previous) { var prev2 = node2.Previous ?? ClipList.Last; var seg2 = new LineSegment(node2.Value.Pos, prev2.Value.Pos); var intersect = seg1.Intersect(seg2); if (intersect.HasValue && !intersectNodes.ContainsKey(intersect.Value)) { // store intersection point intersectNodes.Add(intersect.Value, node2); intersections.Add(intersect.Value); } } // sort intersections on distance to start vertex intersections.Sort(new ClosestToPointComparer(seg1.Point1)); // insert intersections into subject/clip lists foreach (var vertex in intersections) { var point = new WAPoint(vertex, WAList.Ignore); var newNode1 = SubjectList.AddAfter(node1, point); SubjectNode.Add(point, newNode1); var newNode2 = ClipList.AddBefore(intersectNodes[vertex], point); ClipNode.Add(point, newNode2); // increment node1 since we added a vertex node1 = newNode1; } } // remove duplicates of subject for (var node = SubjectList.First; node != null;) { var next = node.Next ?? SubjectList.First; while (MathUtil.EqualsEps(node.Value.Pos, next.Value.Pos, MathUtil.EPS * 10)) { if (next.Value.Type != WAList.Vertex) { if (ClipNode.ContainsKey(node.Value)) { ClipList.Remove(ClipNode[node.Value]); } SubjectList.Remove(node); node = next; } else { SubjectList.Remove(next); } if (node == null) { break; } next = node.Next ?? SubjectList.First; } if (node != null) { node = node.Next; } } // remove duplicates of clip for (var node = ClipList.Last; node != null;) { var prev = node.Previous ?? ClipList.Last; while (MathUtil.EqualsEps(node.Value.Pos, prev.Value.Pos, MathUtil.EPS * 10)) { if (prev.Value.Type != WAList.Vertex) { if (SubjectNode.ContainsKey(node.Value)) { SubjectList.Remove(SubjectNode[node.Value]); } ClipList.Remove(node); node = prev; } else { ClipList.Remove(prev); } if (node == null) { break; } prev = node.Previous ?? ClipList.Last; } if (node != null) { node = node.Previous; } } // set entry/exit types correctly for (var node = SubjectList.First; node != null; node = node.Next) { if (node.Value.Type == WAList.Vertex) { continue; } var prev = node.Previous ?? SubjectList.Last; var next = node.Next ?? SubjectList.First; var inside1 = Clip.ContainsInside(prev.Value.Pos) || Clip.OnBoundary(prev.Value.Pos); var inside2 = Clip.ContainsInside(next.Value.Pos) || Clip.OnBoundary(next.Value.Pos); if (!inside1 && inside2) { node.Value.Type = WAList.Entry; Entry.Add(node.Value); } else if (inside1 && !inside2) { node.Value.Type = WAList.Exit; Exit.Add(node.Value); } } }