OpenWalnut  1.5.0dev
WVisiTrace.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2017 OpenWalnut Community
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iterator>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "core/common/math/linearAlgebra/WPosition.h"
31 #include "core/common/WAssert.h"
32 
33 #include <boost/graph/graph_traits.hpp>
34 #include <boost/graph/adjacency_list.hpp>
35 #include <boost/graph/dijkstra_shortest_paths.hpp>
36 #include <boost/property_map/property_map.hpp>
37 
38 #include "WVisiTrace.h"
39 
41  m_candidatePositions(),
42  m_candidateJumps(),
43  m_curve3D(),
44  m_dataChanged( false )
45 {
46 }
47 
48 std::vector< WPosition > WVisiTrace::getLine()
49 {
50  if( m_dataChanged )
51  {
53  m_dataChanged = false;
54  }
55 
56  return m_curve3D;
57 }
58 
59 void WVisiTrace::addCandidatesForRay( const std::vector< std::pair< double, WPosition > > candidates )
60 {
61  std::vector< double > opacityJumps( 0 );
62  std::vector< WPosition > positions( 0 );
63 
64  for( size_t id = 0; id < candidates.size(); ++id )
65  {
66  opacityJumps.push_back( candidates[id].first );
67  positions.push_back( candidates[id].second );
68  }
69 
70  m_candidatePositions.push_back( positions );
71  m_candidateJumps.push_back( opacityJumps );
72 
73  m_dataChanged = true;
74 }
75 
76 std::vector< std::pair< int, int > > WVisiTrace::getLinearizedNodesRefs() const
77 {
78  std::vector< std::pair< int, int > > nodeRefs( 0 );
79  for( size_t outerId = 0; outerId < m_candidatePositions.size(); ++outerId )
80  {
81  for( size_t innerId = 0; innerId < m_candidatePositions[outerId].size(); ++innerId )
82  {
83  nodeRefs.push_back( std::make_pair( outerId, innerId ) );
84  }
85  }
86  return nodeRefs;
87 }
88 
89 std::vector< std::vector< int > > WVisiTrace::getInverseLinearizedNodesRefs() const
90 {
91  std::vector< std::vector< int > > inverseRefs( 0 );
92  size_t counter = 0;
93  for( size_t outerId = 0; outerId < m_candidatePositions.size(); ++outerId )
94  {
95  inverseRefs.push_back( std::vector< int >( 0 ) );
96  for( size_t innerId = 0; innerId < m_candidatePositions[outerId].size(); ++innerId )
97  {
98  inverseRefs[outerId].push_back( counter );
99  ++counter;
100  }
101  }
102  return inverseRefs;
103 }
104 
106 {
107  // Check if there is something to do
108  if( m_candidatePositions.size() == 0 || m_candidateJumps.size() == 0 )
109  {
110  return;
111  }
112 
113  typedef boost::adjacency_list< boost::listS, boost::vecS, boost::directedS,
114  boost::no_property, boost::property< boost::edge_weight_t, double > > graph_t;
115  typedef boost::graph_traits< graph_t >::vertex_descriptor vertex_descriptor;
116  typedef std::pair<int, int> Edge;
117 
118  std::vector< std::pair< int, int > > linearized = getLinearizedNodesRefs();
119  std::vector< std::vector< int > > linearizedInverse = getInverseLinearizedNodesRefs();
120 
121  const int numVirtNodes = 2; // virtual start an end nodes
122  const int startNodeId = 0;
123  const int endNodeId = 1;
124 
125  const int num_nodes = linearized.size() + numVirtNodes;
126 
127  std::vector< std::string > name( 0 );
128  name.push_back( "Start" );
129  name.push_back( "End" );
130  for( int id = 0; id < num_nodes; ++id )
131  {
132  name.push_back( std::to_string( id + numVirtNodes ) );
133  }
134 
135  std::vector< Edge > edgeVector( 0 );
136  std::vector< double > distanceWeights( 0 );
137  std::vector< double > opacityWeights( 0 );
138 
139  // Edges from virtual start node to candidates of first ray
140  for( auto candi : linearizedInverse[0] )
141  {
142  edgeVector.push_back( Edge( startNodeId, candi + numVirtNodes ) );
143  distanceWeights.push_back( 1 );
144  opacityWeights.push_back( 1 );
145  }
146 
147  // Edges from candidates of one ray to those of the next ray
148  for( size_t rayId = 0; rayId < linearizedInverse.size() - 1; ++rayId )
149  {
150  for( size_t firstId = 0; firstId < linearizedInverse[rayId].size(); ++firstId )
151  {
152  for( size_t secondId = 0; secondId < linearizedInverse[rayId+1].size(); ++secondId )
153  {
154  edgeVector.push_back( Edge( linearizedInverse[rayId][firstId] + numVirtNodes,
155  linearizedInverse[rayId+1][secondId] + numVirtNodes ) );
156  WPosition firstPos = m_candidatePositions[rayId][firstId];
157  WPosition secondPos = m_candidatePositions[rayId+1][secondId];
158  double distance = length( firstPos - secondPos );
159  distanceWeights.push_back( distance );
160  opacityWeights.push_back( 1 - m_candidateJumps[rayId+1][secondId] );
161  }
162  }
163  }
164 
165  // Normalize distance weights
166  {
167  double maxDistance = 0;
168  for( auto distance : distanceWeights )
169  {
170  if( distance > maxDistance )
171  {
172  maxDistance = distance;
173  }
174  }
175  for( double& weight : distanceWeights ) // NOLINT
176  {
177  weight /= maxDistance;
178  }
179  }
180 
181  // Edges from candidates of last ray to virtual end node
182  for( auto candi : linearizedInverse[linearizedInverse.size()-1] )
183  {
184  edgeVector.push_back( Edge( candi + numVirtNodes, endNodeId ) );
185  distanceWeights.push_back( 1 );
186  opacityWeights.push_back( 1 );
187  }
188 
189  WAssert( distanceWeights.size() == opacityWeights.size(), "Internal error: Need as many opacities as positions." );
190  std::vector< double > overallWeights( distanceWeights.size() );
191  for( size_t weightId = 0; weightId < overallWeights.size(); ++weightId )
192  {
193  overallWeights[weightId] = opacityWeights[weightId] * distanceWeights[weightId] * distanceWeights[weightId];
194  }
195 
196  Edge* edge_array = &edgeVector[0];
197  double* weights = &overallWeights[0];
198  int num_arcs = edgeVector.size();
199 
200  graph_t g( edge_array, edge_array + num_arcs, weights, num_nodes );
201  //property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
202  std::vector<vertex_descriptor> p( num_vertices( g ) );
203  std::vector<double> distResult( num_vertices( g ) );
204  vertex_descriptor s = vertex( startNodeId, g );
205 
206  dijkstra_shortest_paths( g,
207  s,
208  predecessor_map( boost::make_iterator_property_map( p.begin(), get( boost::vertex_index, g ) ) ).
209  distance_map( boost::make_iterator_property_map( distResult.begin(), get( boost::vertex_index, g ) ) ) );
210 
211  std::vector< int > shortestPathIds( 0 );
212 
213  int parentId = endNodeId;
214  shortestPathIds.push_back( parentId );
215  while( parentId != startNodeId )
216  {
217  parentId = p[parentId];
218  shortestPathIds.push_back( parentId );
219  }
220  std::reverse( shortestPathIds.begin(), shortestPathIds.end() );
221 
222  for( size_t id = 1; id < shortestPathIds.size() - 1; ++id )
223  {
224  int rayId = linearized[shortestPathIds[id]-numVirtNodes].first;
225  int candidateId = linearized[shortestPathIds[id]-numVirtNodes].second;
226  m_curve3D.push_back( m_candidatePositions[rayId][candidateId] );
227  }
228 
229  // DEBUGGING: writing solution to file and stdout
230  // {
231  // #include <iostream>
232  // #include <fstream>
233  // std::cout << "distances and parents:" << std::endl;
234  // std::cout << "distance(" << "END" << ") = " << distResult[endNodeId] << std::endl;
235  // std::cout << "distances and parents:" << std::endl;
236  // graph_traits < graph_t >::vertex_iterator vi, vend;
237  // for (boost::tie(vi, vend) = vertices(g); vi != vend; ++vi)
238  // {
239  // std::cout << "distance(" << name[*vi] << ") = " << distResult[*vi] << ", ";
240  // std::cout << "parent(" << name[*vi] << ") = " << name[p[*vi]] << std::endl;
241  // }
242  // std::cout << std::endl;
243 
244  // std::ofstream dot_file("/tmp/dijkstra-eg.dot");
245 
246  // dot_file << "digraph D {\n"
247  // << " rankdir=LR\n"
248  // << " size=\"20,20\"\n"
249  // << " ratio=\"fill\"\n"
250  // << " edge[style=\"bold\"]\n" << " node[shape=\"circle\"]\n";
251 
252  // graph_traits < graph_t >::edge_iterator ei, ei_end;
253  // for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
254  // graph_traits < graph_t >::edge_descriptor e = *ei;
255  // graph_traits < graph_t >::vertex_descriptor
256  // u = source(e, g), v = target(e, g);
257  // dot_file << name[u] << " -> " << name[v]
258  // << "[label=\"" << get(weightmap, e) << "\"";
259  // if (p[v] == u)
260  // dot_file << ", color=\"black\"";
261  // else
262  // dot_file << ", color=\"grey\"";
263  // dot_file << "]";
264  // }
265  // dot_file << "}";
266  // }
267 }
268 
270 {
271  performDijkstra();
272 }
273 
275 {
276  m_candidatePositions.clear();
277  m_candidateJumps.clear();
278  m_dataChanged = true;
279  m_curve3D.clear(); // not really needed because m_dataChanged is true.
280 }
This only is a 3d double vector.
std::vector< std::vector< WPosition > > m_candidatePositions
The candidate positions for all rays.
Definition: WVisiTrace.h:98
std::vector< std::vector< double > > m_candidateJumps
The opacity jumps belonging to the intervals of the candidate positions.
Definition: WVisiTrace.h:99
void performVisiTrace()
Optimization resulting in the desired 3D curve (m_curve3D).
Definition: WVisiTrace.cpp:269
std::vector< std::vector< int > > getInverseLinearizedNodesRefs() const
Get ids in the vector of getLinearizedNodesRefs from structure of m_candidatePositions.
Definition: WVisiTrace.cpp:89
std::vector< WPosition > getLine()
Get the final 3D line a vector of WPosition.
Definition: WVisiTrace.cpp:48
void addCandidatesForRay(const std::vector< std::pair< double, WPosition > > candidates)
Add candidate positions and corresponding opacity jump values for one viewing ray.
Definition: WVisiTrace.cpp:59
void reset()
Erases all data to be able to start a new VisiTrace computation.
Definition: WVisiTrace.cpp:274
std::vector< std::pair< int, int > > getLinearizedNodesRefs() const
Get an vector with reference ids for all nodes.
Definition: WVisiTrace.cpp:76
WVisiTrace()
Simple constructor performing initializations.
Definition: WVisiTrace.cpp:40
bool m_dataChanged
Indicates whether new data has been added since last VisiTrace computation.
Definition: WVisiTrace.h:102
std::vector< WPosition > m_curve3D
The 3D curve computed by VisiTrace.
Definition: WVisiTrace.h:100
void performDijkstra()
Create weighted graph and find shortest path from according to VisiTrace.
Definition: WVisiTrace.cpp:105