internal static bool DoesIntersect(Line line, DSPoint point) { gEdge edge = gEdge.ByStartVertexEndVertex(Points.ToVertex(line.StartPoint), Points.ToVertex(line.EndPoint)); gVertex vertex = Points.ToVertex(point); return(vertex.OnEdge(edge)); }
internal EdgeKey(gVertex centre, gVertex end, gEdge e) { Centre = centre; Vertex = end; Edge = e; RayEdge = gEdge.ByStartVertexEndVertex(centre, end); }
private void AddNewEvent(gEdge edge, PolygonType polType = PolygonType.None) { SweepEvent swStart = new SweepEvent(edge.StartVertex, edge) { Label = SweepEventLabel.Normal }; SweepEvent swEnd = new SweepEvent(edge.EndVertex, edge) { Label = SweepEventLabel.Normal }; swStart.Pair = swEnd; swEnd.Pair = swStart; swStart.IsLeft = swStart < swEnd; swEnd.IsLeft = !swStart.IsLeft; if (polType != PolygonType.None) { swStart.polygonType = polType; swEnd.polygonType = polType; } eventsList.AddItemSorted(swStart); eventsList.AddItemSorted(swEnd); }
internal EdgeKey(gEdge rayEdge, gEdge e) { RayEdge = rayEdge; Edge = e; Centre = RayEdge.StartVertex; Vertex = RayEdge.EndVertex; }
internal static void AddColouredEdge(IRenderPackage package, gEdge edge, DSCore.Color color) { package.AddLineStripVertex(edge.StartVertex.X, edge.StartVertex.Y, edge.StartVertex.Z); package.AddLineStripVertex(edge.EndVertex.X, edge.EndVertex.Y, edge.EndVertex.Z); package.AddLineStripVertexColor(color.Red, color.Green, color.Blue, color.Alpha); package.AddLineStripVertexColor(color.Red, color.Green, color.Blue, color.Alpha); package.AddLineStripVertexCount(2); }
internal static bool EdgeIntersect(gVertex start, gVertex end, gEdge edge) { //For simplicity, it only takes into acount the 2d projection to the xy plane, //so the result will be based on a porjection even if points have z values. bool intersects = EdgeIntersectProjection( start, end, edge.StartVertex, edge.EndVertex, "xy"); return(intersects); }
internal List <gEdge> VisibilityAnalysis(Graph baseGraph, List <gVertex> vertices, bool reducedGraph, bool halfScan) { List <gEdge> visibleEdges = new List <gEdge>(); foreach (gVertex v in vertices) { foreach (gVertex v2 in VisibleVertices(v, baseGraph, null, null, null, halfScan, reducedGraph)) { gEdge newEdge = new gEdge(v, v2); if (!visibleEdges.Contains(newEdge)) { visibleEdges.Add(newEdge); } } } return(visibleEdges); }
/// <summary> /// Computes edges and creates polygons from those connected by vertices. /// </summary> public void BuildPolygons() { var computedVertices = new List <gVertex>(); foreach (gVertex v in vertices) { // If already belongs to a polygon or is not a polygon vertex or already computed if (computedVertices.Contains(v) || v.polygonId >= 0 || graph[v].Count > 2) { continue; } computedVertices.Add(v); gPolygon polygon = new gPolygon(GetNextId(), false); polygon.AddVertex(v); foreach (gEdge edge in GetVertexEdges(v)) { gEdge nextEdge = edge; gVertex nextVertex = edge.GetVertexPair(v); while (!polygon.vertices.Contains(nextVertex)) { computedVertices.Add(nextVertex); polygon.AddVertex(nextVertex); polygon.edges.Add(nextEdge); //It is extreme vertex, polygon not closed if (graph[nextVertex].Count < 2) { break; } nextEdge = graph[nextVertex].Where(e => !e.Equals(nextEdge)).First(); nextVertex = nextEdge.GetVertexPair(nextVertex); } if (!polygon.edges.Last().Equals(nextEdge)) { polygon.edges.Add(nextEdge); } } this.polygons.Add(polygon.id, polygon); } }
/// <summary> /// Adds specific points as gVertices to the VisibilityGraph Graph /// </summary> /// <param name="visibilityGraph">VisibilityGraph Graph</param> /// <param name="vertices">Points to add as gVertices</param> /// <returns></returns> public static VisibilityGraph AddVertices(VisibilityGraph visibilityGraph, List <gVertex> vertices, bool reducedGraph = true) { //TODO: Seems that original graph gets updated as well if (vertices == null) { throw new NullReferenceException("vertices"); } VisibilityGraph newVisGraph = (VisibilityGraph)visibilityGraph.Clone(); List <gVertex> singleVertices = new List <gVertex>(); foreach (gVertex v in vertices) { if (newVisGraph.Contains(v)) { continue; } gEdge closestEdge = newVisGraph.baseGraph.edges.OrderBy(e => e.DistanceTo(v)).First(); if (!gBase.Threshold(closestEdge.DistanceTo(v), 0)) { singleVertices.Add(v); } else if (v.OnEdge(closestEdge.StartVertex, closestEdge.EndVertex)) { v.polygonId = closestEdge.StartVertex.polygonId; newVisGraph.baseGraph.polygons[v.polygonId] = newVisGraph.baseGraph.polygons[v.polygonId].AddVertex(v, closestEdge); singleVertices.Add(v); } } newVisGraph.baseGraph.ResetEdgesFromPolygons(); foreach (gVertex centre in singleVertices) { foreach (gVertex v in VisibleVertices(centre, newVisGraph.baseGraph, null, null, singleVertices, false, reducedGraph)) { newVisGraph.AddEdge(new gEdge(centre, v)); } } return(newVisGraph); }
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); } }
/// <summary> /// Add edge to the analisys graph /// </summary> /// <param name="edge">New edge</param> public void AddEdge(gEdge edge) { List <gEdge> startEdgesList = new List <gEdge>(); List <gEdge> endEdgesList = new List <gEdge>(); if (graph.TryGetValue(edge.StartVertex, out startEdgesList)) { if (!startEdgesList.Contains(edge)) { startEdgesList.Add(edge); } } else { graph.Add(edge.StartVertex, new List <gEdge>() { edge }); } if (graph.TryGetValue(edge.EndVertex, out endEdgesList)) { if (!endEdgesList.Contains(edge)) { endEdgesList.Add(edge); } } else { graph.Add(edge.EndVertex, new List <gEdge>() { edge }); } if (!edges.Contains(edge)) { edges.Add(edge); } }
internal static bool DoesIntersect(Line line1, Line line2) { gEdge edge1 = gEdge.ByStartVertexEndVertex(Points.ToVertex(line1.StartPoint), Points.ToVertex(line1.EndPoint)); gEdge edge2 = gEdge.ByStartVertexEndVertex(Points.ToVertex(line2.StartPoint), Points.ToVertex(line2.EndPoint)); if (edge1.Intersects(edge2)) { if (edge2.StartVertex.OnEdge(edge1)) { return(false); } if (edge2.EndVertex.OnEdge(edge1)) { return(false); } return(true); } else { return(false); } }
/// <summary> /// Contains method for edges in graph /// </summary> /// <param name="edge"></param> /// <returns></returns> public bool Contains(gEdge edge) { return(edges.Contains(edge)); }
internal void ProcessIntersection(SweepEvent next, SweepEvent prev, List <gBase> intersections = null) { gBase intersection = next.Edge.Intersection(prev.Edge); bool inserted = false; #region Is gVertex if (intersection is gVertex) { gVertex v = intersection as gVertex; // Intersection is between extremes vertices foreach (SweepEvent sw in new List <SweepEvent>() { next, prev }) { if (!sw.Edge.Contains(v)) { if (intersections != null && !inserted) { intersections.Add(v); inserted = true; } UpdateEventPair(sw, v); } } } #endregion #region Is gEdge else if (intersection is gEdge) { gEdge e = intersection as gEdge; // On Case 3 below, last half of prev event is added as intersection, // and on next loop it will be case 1 with the same edge, so this avoids duplicates if (intersections != null && (!intersections.Any() || !intersections.Last().Equals(e))) { intersections.Add(e); inserted = true; } // Case 1: events are coincident (same edge) // (prev)--------------------(prevPair) // (next)--------------------(nextPair) if (next.Equals(prev)) { // Setting nextEvent as not contributing instead of deleting it // as doing so will make it's pair a lonely poor thing. next.Label = SweepEventLabel.NoContributing; prev.Label = next.InOut == prev.InOut ? SweepEventLabel.SameTransition : SweepEventLabel.DifferentTransition; } // Case 2: same start point, prev will be always shorter // as on PriorityQ it must have been sorted before next // (prev)----------(prevPair) // (next)--------------------(nextPair) else if (prev.Vertex.Equals(next.Vertex)) { // TODO: check this is true in all cases gVertex dividingVtx = prev.Pair.Vertex; UpdateEventPair(next, dividingVtx); } // Case 3: same end point, next will be always shorter // as on PriorityQ it must have been sorted after next // (prev)--------------------(prevPair) // (next)-------------(nextPair) else if (prev.Pair.Vertex.Equals(next.Pair.Vertex)) { // TODO: check this is true in all cases gVertex dividingVtx = next.Vertex; UpdateEventPair(prev, dividingVtx); } // Case 4: events overlap // (prev)--------------------(prevPair) // (next)--------------------(nextPair) else if (prev < next && prev.Pair < next.Pair) { // TODO: check this is true in all cases gVertex prevDividingVtx = next.Vertex; gVertex nextDividingVtx = prev.Pair.Vertex; UpdateEventPair(prev, prevDividingVtx); UpdateEventPair(next, nextDividingVtx); } // Case 5: prev fully contains next // (prev)--------------------(prevPair) // (next)---(nextPair) else if (prev < next && prev.Pair > next.Pair) { next.Label = SweepEventLabel.NoContributing; gVertex dividingVtx = next.Vertex; gVertex pairDividingVtx = next.Pair.Vertex; // Storing reference to prevPair before updating it var prevPair = prev.Pair; UpdateEventPair(prev, dividingVtx); UpdateEventPair(prevPair, pairDividingVtx); } else { throw new Exception("Case not contemplated? Damm!"); } } #endregion #endregion }
public Graph(List <gPolygon> gPolygonsSet) { edges = new List <gEdge>(); graphID = Guid.NewGuid(); //Setting up Graph instance by adding vertices, edges and polygons foreach (gPolygon gPolygon in gPolygonsSet) { List <gVertex> vertices = gPolygon.vertices; // Clear pre-existing edges in the case this is an updating process. gPolygon.edges.Clear(); //If there is only one polygon, treat it as boundary if (gPolygonsSet.Count() == 1) { gPolygon.isBoundary = true; } //If first and last point of vertices list are the same, remove last. if (vertices.First().Equals(vertices.Last()) && vertices.Count() > 1) { vertices = vertices.Take(vertices.Count() - 1).ToList(); } //For each point, creates vertex and associated edge and adds them //to the polygons Dictionary int vertexCount = vertices.Count(); // If valid polygon if (vertexCount >= 3) { int newId = GetNextId(); for (var j = 0; j < vertexCount; j++) { int next_index = (j + 1) % vertexCount; gVertex vertex = vertices[j]; gVertex next_vertex = vertices[next_index]; gEdge edge = new gEdge(vertex, next_vertex); //If is a valid polygon, add id to vertex and //edge to vertices dictionary if (vertexCount > 2) { vertex.polygonId = newId; next_vertex.polygonId = newId; gPolygon gPol = new gPolygon(); if (polygons.TryGetValue(newId, out gPol)) { gPol.edges.Add(edge); } else { gPolygon.edges.Add(edge); gPolygon.id = newId; polygons.Add(newId, gPolygon); } } AddEdge(edge); } } } }
/// <summary> /// SweepEvent default constructor /// </summary> /// <param name="vertex"></param> /// <param name="edge"></param> public SweepEvent(gVertex vertex, gEdge edge) { this.Vertex = vertex; this.Edge = edge; }
/// <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); }