public void ContainsVertex_Pass_WhenIsPolygonVertex([Values(true, false)] bool ccw) { Polygon polygon = GetPolygon(ccw); Vertex vertex1 = Vertex.ByCoordinates(10, 0); Vertex vertex2 = Vertex.ByCoordinates(0, 10); Assert.IsTrue(polygon.ContainsVertex(vertex1)); Assert.IsTrue(polygon.ContainsVertex(vertex2)); }
public void ContainsVertex_Pass_WhenIsOutside([Values(true, false)] bool ccw) { Polygon polygon = GetPolygon(ccw); Vertex vertex1 = Vertex.ByCoordinates(-5, 5); Vertex vertex2 = Vertex.ByCoordinates(0, 20); Assert.IsFalse(polygon.ContainsVertex(vertex1)); Assert.IsFalse(polygon.ContainsVertex(vertex2)); }
public void ContainsVertex_Pass_WhenNotInsideButAlignedWithPolygonVertex([Values(true, false)] bool ccw) { Polygon polygon = GetPolygon(ccw); Vertex vertex = Vertex.ByCoordinates(0, 15); Assert.IsFalse(polygon.ContainsVertex(vertex)); }
public void ContainsVertex_Pass_WhenInsidePolygon([Values(true, false)] bool ccw) { Polygon polygon = GetPolygon(ccw); Vertex vertex = Vertex.ByCoordinates(0, 5); Assert.IsTrue(polygon.ContainsVertex(vertex)); }
/// <summary> /// /// </summary> /// <param name="centre"></param> /// <param name="baseGraph"></param> /// <param name="origin"></param> /// <param name="destination"></param> /// <param name="singleVertices"></param> /// <param name="scan"></param> /// <returns name="visibleVertices">List of vertices visible from the analysed vertex</returns> public static List <Vertex> VisibleVertices( Vertex centre, Graph baseGraph, Vertex origin = null, Vertex destination = null, List <Vertex> singleVertices = null, bool halfScan = true, bool reducedGraph = true, bool maxVisibility = false) { #region Initialize variables and sort vertices List <Edge> edges = baseGraph.edges; List <Vertex> vertices = baseGraph.vertices; if (origin != null) { vertices.Add(origin); } if (destination != null) { vertices.Add(destination); } if (singleVertices != null) { vertices.AddRange(singleVertices); } Vertex maxVertex = vertices.OrderByDescending(v => v.DistanceTo(centre)).First(); double maxDistance = centre.DistanceTo(maxVertex) * 1.5; //vertices = vertices.OrderBy(v => Point.RadAngle(centre.point, v.point)).ThenBy(v => centre.DistanceTo(v)).ToList(); vertices = Vertex.OrderByRadianAndDistance(vertices, centre); #endregion #region Initialize openEdges //Initialize openEdges with any intersection edges on the half line //from centre to maxDistance on the XAxis List <EdgeKey> openEdges = new List <EdgeKey>(); double xMax = Math.Abs(centre.X) + 1.5 * maxDistance; Edge halfEdge = Edge.ByStartVertexEndVertex(centre, Vertex.ByCoordinates(xMax, centre.Y, centre.Z)); foreach (Edge e in edges) { if (centre.OnEdge(e)) { continue; } if (halfEdge.Intersects(e)) { if (e.StartVertex.OnEdge(halfEdge)) { continue; } if (e.EndVertex.OnEdge(halfEdge)) { continue; } EdgeKey k = new EdgeKey(halfEdge, e); openEdges.AddItemSorted(k); } } #endregion List <Vertex> visibleVertices = new List <Vertex>(); Vertex prev = null; bool prevVisible = false; for (var i = 0; i < vertices.Count; i++) { Vertex vertex = vertices[i]; if (vertex.Equals(centre) || vertex.Equals(prev)) { continue; } // v == to centre or to previous when updating graph //Check only half of vertices as eventually they will become 'v' if (halfScan && Vertex.RadAngle(centre, vertex) > Math.PI) { break; } //Removing clock wise edges incident on v if (openEdges.Count > 0 && baseGraph.graph.ContainsKey(vertex)) { foreach (Edge edge in baseGraph.graph[vertex]) { int orientation = Vertex.Orientation(centre, vertex, edge.GetVertexPair(vertex)); if (orientation == -1) { EdgeKey k = new EdgeKey(centre, vertex, edge); int index = openEdges.BisectIndex(k) - 1; index = (index < 0) ? openEdges.Count - 1 : index; if (openEdges.Count > 0 && openEdges.ElementAt(index).Equals(k)) { openEdges.RemoveAt(index); } } } } //Checking if p is visible from p. bool isVisible = false; Polygon vertexPolygon = null; if (vertex.polygonId >= 0) { baseGraph.polygons.TryGetValue(vertex.polygonId, out vertexPolygon); } // If centre is on an edge of a inner polygon vertex belongs, check if the centre-vertex edge lies inside // or if on one of vertex's edges. if (vertexPolygon != null && !vertexPolygon.isBoundary && vertexPolygon.ContainsVertex(centre)) { Vertex mid = Vertex.MidVertex(centre, vertex); // If mid is on any edge of vertex, is visible, otherwise not. foreach (Edge edge in baseGraph.graph[vertex]) { if (mid.OnEdge(edge)) { isVisible = true; break; } } } //No collinear vertices else if (prev == null || Vertex.Orientation(centre, prev, vertex) != 0 || !prev.OnEdge(centre, vertex)) { if (openEdges.Count == 0) { if (vertexPolygon != null && vertexPolygon.isBoundary && vertexPolygon.ContainsVertex(centre)) { isVisible = vertexPolygon.ContainsVertex(Vertex.MidVertex(centre, vertex)); } else { isVisible = true; } } else if (vertex.OnEdge(openEdges.First().Edge) || !openEdges.First().Edge.Intersects(new Edge(centre, vertex))) //TODO: Change this intersection to Edge.Intersects { isVisible = true; } } //For collinear vertices, if previous was not visible, vertex is not either else if (!prevVisible) { isVisible = false; } //For collinear vertices, if prev was visible need to check that //the edge from prev to vertex does not intersect with any open edge else { isVisible = true; foreach (EdgeKey k in openEdges) { //if (!k.edge.Contains(prev) && EdgeIntersect(prev, vertex, k.edge)) if (EdgeIntersect(prev, vertex, k.Edge) && !k.Edge.Contains(prev)) { isVisible = false; break; } } // If visible (doesn't intersect any open edge) and edge 'prev-vertex' // is in any polygon, vertex is visible if it belongs to a external boundary if (isVisible && EdgeInPolygon(prev, vertex, baseGraph, maxDistance)) { isVisible = IsBoundaryVertex(vertex, baseGraph); } // If still visible (not inside polygon or is boundary vertex), // if not on 'centre-prev' edge means there is a gap between prev and vertex if (isVisible && !vertex.OnEdge(centre, prev)) { isVisible = !IsBoundaryVertex(vertex, baseGraph); } } //If vertex is visible and centre belongs to any polygon, checks //if the visible edge is interior to its polygon if (isVisible && centre.polygonId >= 0 && !baseGraph.GetAdjecentVertices(centre).Contains(vertex)) { if (IsBoundaryVertex(centre, baseGraph) && IsBoundaryVertex(vertex, baseGraph)) { isVisible = EdgeInPolygon(centre, vertex, baseGraph, maxDistance); } else { isVisible = !EdgeInPolygon(centre, vertex, baseGraph, maxDistance); } } prev = vertex; prevVisible = isVisible; if (isVisible) { // Check reducedGraph if vertices belongs to different polygons if (reducedGraph && centre.polygonId != vertex.polygonId) { bool isOriginExtreme = true; bool isTargetExtreme = true; // For reduced graphs, it is checked if the edge is extrem or not. // For an edge to be extreme, the edges coincident at the start and end vertex // will have the same orientation (both clock or counter-clock wise) // Vertex belongs to a polygon if (centre.polygonId >= 0 && !IsBoundaryVertex(centre, baseGraph)) { var orientationsOrigin = baseGraph.GetAdjecentVertices(centre).Select(otherVertex => Vertex.Orientation(vertex, centre, otherVertex)).ToList(); isOriginExtreme = orientationsOrigin.All(o => o == orientationsOrigin.First()); } if (vertex.polygonId >= 0 && !IsBoundaryVertex(vertex, baseGraph)) { var orientationsTarget = baseGraph.GetAdjecentVertices(vertex).Select(otherVertex => Vertex.Orientation(centre, vertex, otherVertex)).ToList(); isTargetExtreme = orientationsTarget.All(o => o == orientationsTarget.First()); } if (isTargetExtreme || isOriginExtreme) { visibleVertices.Add(vertex); } } else { visibleVertices.Add(vertex); } } if (baseGraph.Contains(vertex)) { foreach (Edge e in baseGraph.graph[vertex]) { if (!centre.OnEdge(e) && Vertex.Orientation(centre, vertex, e.GetVertexPair(vertex)) == 1) { EdgeKey k = new EdgeKey(centre, vertex, e); openEdges.AddItemSorted(k); } } } if (isVisible && maxVisibility && vertex.polygonId >= 0) { List <Vertex> vertexPairs = baseGraph.GetAdjecentVertices(vertex); int firstOrientation = Vertex.Orientation(centre, vertex, vertexPairs[0]); int secondOrientation = Vertex.Orientation(centre, vertex, vertexPairs[1]); bool isColinear = false; //if both edges lie on the same side of the centre-vertex edge or one of them is colinear or centre is contained on any of the edges if (firstOrientation == secondOrientation || firstOrientation == 0 || secondOrientation == 0) { Vertex rayVertex = vertex.Translate(Vector.ByTwoVertices(centre, vertex), maxDistance); Edge rayEdge = Edge.ByStartVertexEndVertex(centre, rayVertex); Vertex projectionVertex = null; // if both orientation are not on the same side, means that one of them is colinear isColinear = firstOrientation != secondOrientation ? true : false; foreach (EdgeKey ek in openEdges) { Vertex intersection = rayEdge.Intersection(ek.Edge) as Vertex; if (intersection != null && !intersection.Equals(vertex)) { projectionVertex = intersection; Polygon polygon = null; baseGraph.polygons.TryGetValue(vertex.polygonId, out polygon); if (polygon != null) { // If polygon is internal, don't compute intersection if mid point lies inside the polygon but not on its edges Vertex mid = Vertex.MidVertex(vertex, intersection); bool containsEdge = Vertex.Orientation(centre, vertex, mid) != 0 && polygon.ContainsVertex(mid); if (!polygon.isBoundary && containsEdge) { projectionVertex = null; } } break; } } if (projectionVertex != null) { // if edges are before rayEdge, projection Vertex goes after vertex if (firstOrientation == -1 || secondOrientation == -1) { visibleVertices.Add(projectionVertex); } else { visibleVertices.Insert(visibleVertices.Count - 1, projectionVertex); } } } if (vertexPairs.Contains(centre) && !visibleVertices.Contains(centre)) { visibleVertices.Add(centre); } } } return(visibleVertices); }