Esempio n. 1
0
        /// <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);
        }