Пример #1
0
        internal static double DistanceToIntersection(gVertex centre, gVertex maxVertex, gEdge e)
        {
            var   centreProj   = gVertex.ByCoordinates(centre.X, centre.Y, 0);
            var   maxProj      = gVertex.ByCoordinates(maxVertex.X, maxVertex.Y, 0);
            var   startProj    = gVertex.ByCoordinates(e.StartVertex.X, e.StartVertex.Y, 0);
            var   endProj      = gVertex.ByCoordinates(e.EndVertex.X, e.EndVertex.Y, 0);
            gEdge rayEdge      = gEdge.ByStartVertexEndVertex(centreProj, maxProj);
            gEdge edgeProj     = gEdge.ByStartVertexEndVertex(startProj, endProj);
            gBase intersection = rayEdge.Intersection(edgeProj);

            if (intersection != null && intersection.GetType() == typeof(gVertex))
            {
                return(centre.DistanceTo((gVertex)intersection));
            }
            else
            {
                return(0);
            }
        }
Пример #2
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="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);
        }