/// <summary> /// /// </summary> /// <param name="centre"></param> /// <param name="baseGraph"></param> /// <param name="origin"></param> /// <param name="destination"></param> /// <param name="singleVertices"></param> /// <param name="halfScan"></param> /// <returns name="visibleVertices">List of Vertices visible from the analysed vertex</returns> private 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); } vertices = Vertex.OrderByRadianAndDistance(vertices, centre); #endregion #region Initialize openEdges //Initialize openEdges with any intersecting Edge with a XAxis Ray from the centre List <EdgeKey> openEdges = new List <EdgeKey>(); Ray sweepRay = Ray.XAxis(centre); foreach (Edge e in edges) { if (centre.OnEdge(e)) { continue; } if (sweepRay.Intersects(e)) { if (sweepRay.Contains(e.StartVertex)) { continue; } if (sweepRay.Contains(e.EndVertex)) { continue; } EdgeKey k = EdgeKey.ByRayAndEdge(sweepRay, 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; } // Update Ray to new vertex; sweepRay = Ray.ByTwoVertices(centre, vertex); //Removing clock wise Edges incident on v if (openEdges.Count > 0 && baseGraph._vertexEdgesDict.ContainsKey(vertex)) { foreach (Edge edge in baseGraph._vertexEdgesDict[vertex]) { int orientation = Vertex.Orientation(centre, vertex, edge.GetVertexPair(vertex)); if (orientation == -1) { EdgeKey k = EdgeKey.ByRayAndEdge(sweepRay, 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.Parent is Polygon) { baseGraph._polygonsDict.TryGetValue(vertex.Parent.Id, 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._vertexEdgesDict[vertex]) { if (mid.OnEdge(edge)) { isVisible = true; break; } } } //No collinear Vertices else if (prev == null || !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(Edge.ByStartVertexEndVertex(centre, vertex))) { 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)) { 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.Parent is Polygon && !baseGraph.GetAdjecentVertices(centre).Contains(vertex)) { if (IsBoundaryVertex(centre, baseGraph) && IsBoundaryVertex(vertex, baseGraph)) { isVisible = EdgeInPolygon(centre, vertex, baseGraph); } else { isVisible = !EdgeInPolygon(centre, vertex, baseGraph); } } prev = vertex; prevVisible = isVisible; if (isVisible) { // Check reducedGraph if Vertices belongs to different _polygonsDict // TODO: If using ConvexHull, most of this could be removed. if (reducedGraph && centre.Parent != vertex.Parent) { 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.Parent is Polygon && !IsBoundaryVertex(centre, baseGraph)) { var orientationsOrigin = baseGraph.GetAdjecentVertices(centre).Select(otherVertex => Vertex.Orientation(vertex, centre, otherVertex)).ToList(); isOriginExtreme = orientationsOrigin.All(o => o == orientationsOrigin.First()); } if (centre.Parent is Polygon && !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._vertexEdgesDict[vertex]) { if (!centre.OnEdge(e) && Vertex.Orientation(centre, vertex, e.GetVertexPair(vertex)) == 1) { EdgeKey k = EdgeKey.ByRayAndEdge(sweepRay, e); openEdges.AddItemSorted(k); } } } if (isVisible && maxVisibility && vertex.Parent is Polygon) { 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 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 = sweepRay.Intersection(ek.Edge) as Vertex; if (intersection != null && !intersection.Equals(vertex)) { projectionVertex = intersection; Polygon polygon; if (baseGraph._polygonsDict.TryGetValue(vertex.Parent.Id, out polygon)) { // 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); }
/// <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 <gVertex> VisibleVertices( gVertex centre, Graph baseGraph, gVertex origin = null, gVertex destination = null, List <gVertex> singleVertices = null, bool halfScan = true, bool reducedGraph = true, bool maxVisibility = false) { #region Initialize variables and sort vertices List <gEdge> edges = baseGraph.edges; List <gVertex> vertices = baseGraph.vertices; if (origin != null) { vertices.Add(origin); } if (destination != null) { vertices.Add(destination); } if (singleVertices != null) { vertices.AddRange(singleVertices); } gVertex 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 = gVertex.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; gEdge halfEdge = gEdge.ByStartVertexEndVertex(centre, gVertex.ByCoordinates(xMax, centre.Y, centre.Z)); foreach (gEdge e in edges) { if (e.Contains(centre)) { continue; } if (halfEdge.Intersects(e)) { if (e.StartVertex.OnEdge(halfEdge)) { continue; } if (e.EndVertex.OnEdge(halfEdge)) { continue; } EdgeKey k = new EdgeKey(halfEdge, e); Core.List.AddItemSorted(openEdges, k); } } #endregion List <gVertex> visibleVertices = new List <gVertex>(); gVertex prev = null; bool prevVisible = false; for (var i = 0; i < vertices.Count; i++) { gVertex 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 && gVertex.RadAngle(centre, vertex) > Math.PI) { break; } //Removing clock wise edges incident on v if (openEdges.Count > 0 && baseGraph.graph.ContainsKey(vertex)) { foreach (gEdge edge in baseGraph.graph[vertex]) { int orientation = gVertex.Orientation(centre, vertex, edge.GetVertexPair(vertex)); if (orientation == -1) { EdgeKey k = new EdgeKey(centre, vertex, edge); int index = Core.List.Bisect(openEdges, 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; //No collinear vertices if (prev == null || gVertex.Orientation(centre, prev, vertex) != 0 || !prev.OnEdge(centre, vertex)) { if (openEdges.Count == 0) { isVisible = true; } else if (!EdgeIntersect(centre, vertex, openEdges[0].Edge)) { 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 => gVertex.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 => gVertex.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 (gEdge e in baseGraph.graph[vertex]) { if (!e.Contains(centre) && gVertex.Orientation(centre, vertex, e.GetVertexPair(vertex)) == 1) { EdgeKey k = new EdgeKey(centre, vertex, e); Core.List.AddItemSorted(openEdges, k); } } } if (isVisible && maxVisibility && vertex.polygonId >= 0) { List <gVertex> vertexPairs = baseGraph.GetAdjecentVertices(vertex); int firstOrientation = gVertex.Orientation(centre, vertex, vertexPairs[0]); int secondOrientation = gVertex.Orientation(centre, vertex, vertexPairs[1]); //if both edges lie on the same side of the centre-vertex edge or one of them is colinear if (firstOrientation == secondOrientation || firstOrientation == 0 || secondOrientation == 0) { gVertex rayVertex = vertex.Translate(gVector.ByTwoVertices(centre, vertex), maxDistance); gEdge rayEdge = gEdge.ByStartVertexEndVertex(centre, rayVertex); gVertex projectionVertex = null; foreach (EdgeKey ek in openEdges) { gBase intersection = rayEdge.Intersection(ek.Edge); if (intersection != null && intersection is gVertex && !(intersection as gVertex).Equals(vertex)) { projectionVertex = intersection as gVertex; 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); } } } } } return(visibleVertices); }