https://github.com/GTMeijer/TIN_Viewsheds
Tip revision: 3228d926579e0631b255e7478f24963a508637b4 authored by Gert Meijer on 06 May 2021, 03:42:18 UTC
Base code files push
Base code files push
Tip revision: 3228d92
ViewshedRelationGraph.cpp
#include "precomp.h"
#include "ViewshedRelationGraph.h"
namespace Viewshed
{
ViewshedRelationGraph::ViewshedRelationGraph(const std::vector<VSRelationEdge>& relationEdges)
{
AddEdges(relationEdges);
}
void ViewshedRelationGraph::AddEdges(const std::vector<VSRelationEdge>& relationEdges)
{
for (const VSRelationEdge& re : relationEdges)
{
AddEdge(re);
}
}
void ViewshedRelationGraph::AddEdge(const VSRelationEdge& relationEdge)
{
assert(relationEdge.iSource >= 0);
assert(relationEdge.jDestination >= 0);
assert(!(relationEdge.obscured && relationEdge.obscures));
//Add twin of obscures as well (Handles embedded polys)
//TODO: Improve this, map of maps instead?
if (relationEdge.obscures)
{
VSRelationEdge twinEdge(relationEdge.jDestination, relationEdge.iSource);
twinEdge.obscured = true;
twinEdge.intersects = relationEdge.intersects;
AddEdge(twinEdge);
}
nodes[relationEdge.iSource].push_back(relationEdge);
}
void ViewshedRelationGraph::AddNode(const int node)
{
nodes.insert(std::pair<int, std::vector<VSRelationEdge>>(node, std::vector<VSRelationEdge>()));
}
void ViewshedRelationGraph::RemoveNode(const int node)
{
nodes.erase(node);
}
void ViewshedRelationGraph::RemoveNodes(const std::vector<int> nodes)
{
for (const int n : nodes)
{
RemoveNode(n);
}
}
//Removes all edges that contain a destination to a node that does not exist in the graph
void ViewshedRelationGraph::Trim()
{
for (auto& node : nodes)
{
node.second.erase(std::remove_if(node.second.begin(), node.second.end(), [&](VSRelationEdge edge) {return (nodes.find(edge.jDestination) == nodes.end()); }), node.second.end());
}
}
//Removes all edges that represent an intersection between two polygons
void ViewshedRelationGraph::RemoveIntersectionEdges()
{
for (auto& node : nodes)
{
node.second.erase(std::remove_if(node.second.begin(), node.second.end(), [&](VSRelationEdge edge) {return (edge.intersects); }), node.second.end());
}
}
std::vector<VSRelationEdge> ViewshedRelationGraph::GetEdges(const int nodeId) const
{
return nodes.at(nodeId);
}
//Returns the closest neighbouring node based on a given priority list (Far -> Close)
int ViewshedRelationGraph::GetClosestNeighbour(const int nodeId, const std::vector<int>& priorities) const
{
int highestPrio = -1;
int highestindex = -1;
for (const VSRelationEdge& edge : nodes.at(nodeId))
{
std::vector<int>::const_iterator it = std::find(priorities.begin(), priorities.end(), edge.jDestination);
if (it != priorities.end())
{
int index = std::distance(priorities.begin(), it);
if (index > highestindex)
{
highestPrio = priorities.at(index);
highestindex = index;
}
}
}
return highestPrio;
}
std::vector<int> ViewshedRelationGraph::GetStartingNodes() const
{
std::vector<int> startNodes;
for (auto& node : nodes)
{
//If node does not have any 'obscures' edges add to start node list
bool obscures = false;
for (const VSRelationEdge& edge : node.second)
{
obscures = (obscures || edge.obscures);
}
if (!obscures)
{
startNodes.push_back(node.first);
}
}
return startNodes;
}
//Sorts the nodes in the graph from farthest to closest polygons
std::vector<int> ViewshedRelationGraph::TopologicalSort() const
{
std::vector<int> sortedNodes;
sortedNodes.reserve(nodes.size());
//For each node set visited to false
std::map<int, bool> visited;
for (auto& n : nodes)
{
visited[n.first] = false;
}
//For each starting node recursively visit the graph depth first
std::vector<int> visitStack = GetStartingNodes();
while (!visitStack.empty())
{
TopologicalSortVisit(visitStack.back(), sortedNodes, visited);
visitStack.pop_back();
}
//Reverse the order of the sorted vector and return
std::reverse(sortedNodes.begin(), sortedNodes.end());
return sortedNodes;
}
void ViewshedRelationGraph::TopologicalSortVisit(const int node, std::vector<int>& sortedNodes, std::map<int, bool>& visited) const
{
if (visited.at(node))
{
return;
}
//Recursively visit each child node that obscures this nodes polygon
for (const VSRelationEdge& edge : nodes.at(node))
{
if (edge.obscured)
{
TopologicalSortVisit(edge.jDestination, sortedNodes, visited);
}
}
//After visiting each child mark as visited and add this node to the sorted list
visited.at(node) = true;
sortedNodes.push_back(node);
}
void ViewshedRelationGraph::PrintGraph() const
{
std::cout << "Overlap relation graph:" << std::endl;
for (auto& node : nodes)
{
std::cout << node.first << std::endl;
for (auto& edge : node.second)
{
if (edge.obscures)
{
std::cout << "\t" << edge.iSource << "<" << edge.jDestination;
}
if (edge.obscured)
{
std::cout << "\t" << edge.iSource << ">" << edge.jDestination;
}
if (!edge.intersects)
{
std::cout << "(embedded)";
}
std::cout << std::endl;
}
}
}
}