//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2017 OpenWalnut Community
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see .
//
//---------------------------------------------------------------------------
#include
#include
#include
#include "core/common/math/linearAlgebra/WPosition.h"
#include "core/common/WAssert.h"
#include
#include
#include
#include
#include "WVisiTrace.h"
WVisiTrace::WVisiTrace():
m_candidatePositions(),
m_candidateJumps(),
m_curve3D(),
m_dataChanged( false )
{
}
std::vector< WPosition > WVisiTrace::getLine()
{
if( m_dataChanged )
{
performVisiTrace();
m_dataChanged = false;
}
return m_curve3D;
}
void WVisiTrace::addCandidatesForRay( const std::vector< std::pair< double, WPosition > > candidates )
{
std::vector< double > opacityJumps( 0 );
std::vector< WPosition > positions( 0 );
for( size_t id = 0; id < candidates.size(); ++id )
{
opacityJumps.push_back( candidates[id].first );
positions.push_back( candidates[id].second );
}
m_candidatePositions.push_back( positions );
m_candidateJumps.push_back( opacityJumps );
m_dataChanged = true;
}
std::vector< std::pair< int, int > > WVisiTrace::getLinearizedNodesRefs() const
{
std::vector< std::pair< int, int > > nodeRefs( 0 );
for( size_t outerId = 0; outerId < m_candidatePositions.size(); ++outerId )
{
for( size_t innerId = 0; innerId < m_candidatePositions[outerId].size(); ++innerId )
{
nodeRefs.push_back( std::make_pair( outerId, innerId ) );
}
}
return nodeRefs;
}
std::vector< std::vector< int > > WVisiTrace::getInverseLinearizedNodesRefs() const
{
std::vector< std::vector< int > > inverseRefs( 0 );
size_t counter = 0;
for( size_t outerId = 0; outerId < m_candidatePositions.size(); ++outerId )
{
inverseRefs.push_back( std::vector< int >( 0 ) );
for( size_t innerId = 0; innerId < m_candidatePositions[outerId].size(); ++innerId )
{
inverseRefs[outerId].push_back( counter );
++counter;
}
}
return inverseRefs;
}
void WVisiTrace::performDijkstra()
{
// Check if there is something to do
if( m_candidatePositions.size() == 0 || m_candidateJumps.size() == 0 )
{
return;
}
//using namespace boost;
typedef boost::adjacency_list< boost::listS, boost::vecS, boost::directedS,
boost::no_property, boost::property< boost::edge_weight_t, double > > graph_t;
typedef boost::graph_traits< graph_t >::vertex_descriptor vertex_descriptor;
typedef std::pair Edge;
std::vector< std::pair< int, int > > linearized = getLinearizedNodesRefs();
std::vector< std::vector< int > > linearizedInverse = getInverseLinearizedNodesRefs();
const int numVirtNodes = 2; // virtual start an end nodes
const int startNodeId = 0;
const int endNodeId = 1;
const int num_nodes = linearized.size() + numVirtNodes;
std::vector< std::string > name( 0 );
name.push_back( "Start" );
name.push_back( "End" );
for( int id = 0; id < num_nodes; ++id )
{
name.push_back( std::to_string( id + numVirtNodes ) );
}
std::vector< Edge > edgeVector( 0 );
std::vector< double > weightsV( 0 );
// Edges from virtual start node to candidates of first ray
for( auto candi : linearizedInverse[0] )
{
edgeVector.push_back( Edge( startNodeId, candi + numVirtNodes ) );
weightsV.push_back( 1 );
}
// Edges from candidates of one ray to those of the next ray
for( size_t rayId = 0; rayId < linearizedInverse.size() - 1; ++rayId )
{
for( size_t firstId = 0; firstId < linearizedInverse[rayId].size(); ++firstId )
{
for( size_t secondId = 0; secondId < linearizedInverse[rayId+1].size(); ++secondId )
{
edgeVector.push_back( Edge( linearizedInverse[rayId][firstId] + numVirtNodes,
linearizedInverse[rayId+1][secondId] + numVirtNodes ) );
WPosition firstPos = m_candidatePositions[rayId][firstId];
WPosition secondPos = m_candidatePositions[rayId+1][secondId];
double distance = length( firstPos - secondPos );
weightsV.push_back( distance );
}
}
}
// Edges from candidates of last ray to virtual end node
for( auto candi : linearizedInverse[linearizedInverse.size()-1] )
{
edgeVector.push_back( Edge( candi + numVirtNodes, endNodeId ) );
weightsV.push_back( 1 );
}
Edge* edge_array = &edgeVector[0];
double* weights = &weightsV[0];
int num_arcs = edgeVector.size();
graph_t g( edge_array, edge_array + num_arcs, weights, num_nodes );
//property_map::type weightmap = get(edge_weight, g);
std::vector p( num_vertices( g ) );
std::vector distResult( num_vertices( g ) );
vertex_descriptor s = vertex( startNodeId, g );
dijkstra_shortest_paths( g,
s,
predecessor_map( boost::make_iterator_property_map( p.begin(), get( boost::vertex_index, g ) ) ).
distance_map( boost::make_iterator_property_map( distResult.begin(), get( boost::vertex_index, g ) ) ) );
std::vector< int > shortestPathIds( 0 );
int parentId = endNodeId;
shortestPathIds.push_back( parentId );
while( parentId != startNodeId )
{
parentId = p[parentId];
shortestPathIds.push_back( parentId );
}
std::reverse( shortestPathIds.begin(), shortestPathIds.end() );
for( size_t id = 1; id < shortestPathIds.size() - 1; ++id )
{
int rayId = linearized[shortestPathIds[id]-numVirtNodes].first;
int candidateId = linearized[shortestPathIds[id]-numVirtNodes].second;
m_curve3D.push_back( m_candidatePositions[rayId][candidateId] );
}
// DEBUGGING: writing solution to file and stdout
// {
// #include
// #include
// std::cout << "distances and parents:" << std::endl;
// std::cout << "distance(" << "END" << ") = " << distResult[endNodeId] << std::endl;
// std::cout << "distances and parents:" << std::endl;
// graph_traits < graph_t >::vertex_iterator vi, vend;
// for (boost::tie(vi, vend) = vertices(g); vi != vend; ++vi)
// {
// std::cout << "distance(" << name[*vi] << ") = " << distResult[*vi] << ", ";
// std::cout << "parent(" << name[*vi] << ") = " << name[p[*vi]] << std::endl;
// }
// std::cout << std::endl;
// std::ofstream dot_file("/tmp/dijkstra-eg.dot");
// dot_file << "digraph D {\n"
// << " rankdir=LR\n"
// << " size=\"20,20\"\n"
// << " ratio=\"fill\"\n"
// << " edge[style=\"bold\"]\n" << " node[shape=\"circle\"]\n";
// graph_traits < graph_t >::edge_iterator ei, ei_end;
// for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
// graph_traits < graph_t >::edge_descriptor e = *ei;
// graph_traits < graph_t >::vertex_descriptor
// u = source(e, g), v = target(e, g);
// dot_file << name[u] << " -> " << name[v]
// << "[label=\"" << get(weightmap, e) << "\"";
// if (p[v] == u)
// dot_file << ", color=\"black\"";
// else
// dot_file << ", color=\"grey\"";
// dot_file << "]";
// }
// dot_file << "}";
// }
}
void WVisiTrace::performVisiTrace()
{
performDijkstra();
}
void WVisiTrace::reset()
{
m_candidatePositions.clear();
m_candidateJumps.clear();
m_dataChanged = true;
m_curve3D.clear(); // not really needed because m_dataChanged is true.
}