OpenWalnut  1.5.0dev
WBresenham.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
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 <algorithm>
26 #include <cmath>
27 #include <memory>
28 #include <shared_mutex>
29 #include <vector>
30 
31 
32 #include "WBresenham.h"
33 #include "core/common/WAssert.h"
34 #include "core/common/WLogger.h"
35 #include "core/common/math/WLine.h"
36 #include "core/common/math/linearAlgebra/WPosition.h"
37 #include "core/common/math/linearAlgebra/WVectorFixed.h"
38 #include "core/dataHandler/WGridRegular3D.h"
39 
40 WBresenham::WBresenham( std::shared_ptr< WGridRegular3D > grid, bool antialiased )
41  : WRasterAlgorithm( grid ),
42  m_antialiased( antialiased )
43 {
44 }
45 
47 {
48 }
49 
50 void WBresenham::raster( const WLine& line )
51 {
52  // lock the parameterization list for reading
53  boost::shared_lock< std::shared_mutex > lock = boost::shared_lock< std::shared_mutex >( m_parameterizationsLock );
54 
55  newLine( line );
56 
57  if( line.size() < 1 )
58  {
59  wlog::debug( "WBresenham" ) << "Tried to raster an empty line!, skipped.";
60  }
61  for( size_t i = 1; i < line.size(); ++i )
62  {
63  newSegment( line[i-1], line[i] );
64  rasterSegment( line[i-1], line[i] );
65  }
66 
67  lock.unlock();
68 }
69 
70 void WBresenham::rasterSegment( const WPosition& start, const WPosition& end )
71 {
72  int i;
73  WVector3i gridStartPos = m_grid->getVoxelCoord( start );
74  WVector3i gridEndPos = m_grid->getVoxelCoord( end );
75  int dx = gridEndPos[0] - gridStartPos[0];
76  int dy = gridEndPos[1] - gridStartPos[1];
77  int dz = gridEndPos[2] - gridStartPos[2];
78  int l = std::abs( dx );
79  int m = std::abs( dy );
80  int n = std::abs( dz );
81  int x_inc = ( dx < 0 ) ? -1 : 1;
82  int y_inc = ( dy < 0 ) ? -1 : 1;
83  int z_inc = ( dz < 0 ) ? -1 : 1;
84  double err_1, err_2;
85  int dx2 = l << 1;
86  int dy2 = m << 1;
87  int dz2 = n << 1;
88  WVector3i voxel = gridStartPos;
89 
90  if( ( l >= m ) && ( l >= n ) )
91  {
92  err_1 = dy2 - l;
93  err_2 = dz2 - l;
94  for( i = 0; i < l; i++ )
95  {
96  markVoxel( voxel, 0, start, end );
97  if( err_1 > 0 )
98  {
99  voxel[1] += y_inc;
100  err_1 -= dx2;
101  }
102  if( err_2 > 0 )
103  {
104  voxel[2] += z_inc;
105  err_2 -= dx2;
106  }
107  // end of antialiased if-else
108  err_1 += dy2;
109  err_2 += dz2;
110  voxel[0] += x_inc;
111  }
112  }
113  else if( ( m >= l ) && ( m >= n ) )
114  {
115  err_1 = dx2 - m;
116  err_2 = dz2 - m;
117  for( i = 0; i < m; i++ )
118  {
119  markVoxel( voxel, 1, start, end );
120  if( err_1 > 0 )
121  {
122  voxel[0] += x_inc;
123  err_1 -= dy2;
124  }
125  if( err_2 > 0 )
126  {
127  voxel[2] += z_inc;
128  err_2 -= dy2;
129  }
130  err_1 += dx2;
131  err_2 += dz2;
132  voxel[1] += y_inc;
133  }
134  }
135  else
136  {
137  err_1 = dy2 - n;
138  err_2 = dx2 - n;
139  for( i = 0; i < n; i++ )
140  {
141  markVoxel( voxel, 2, start, end );
142  if( err_1 > 0 )
143  {
144  voxel[1] += y_inc;
145  err_1 -= dz2;
146  }
147  if( err_2 > 0 )
148  {
149  voxel[0] += x_inc;
150  err_2 -= dz2;
151  }
152  err_1 += dy2;
153  err_2 += dx2;
154  voxel[2] += z_inc;
155  }
156  }
157  markVoxel( voxel, -1, start, end );
158 }
159 
160 std::vector< double > WBresenham::computeDistances( const size_t voxelNum,
161  const WPosition& start,
162  const WPosition& end ) const
163 {
164  WPosition u = end - start;
165  u = normalize( u );
166 
167  std::vector< WPosition > x;
168  x.reserve( 7 );
169  x.push_back( m_grid->getPosition( voxelNum ) - start );
170  x.push_back( m_grid->getPosition( voxelNum + 1 ) - start );
171  x.push_back( m_grid->getPosition( voxelNum - 1 ) - start );
172  x.push_back( m_grid->getPosition( voxelNum + m_grid->getNbCoordsX() ) - start );
173  x.push_back( m_grid->getPosition( voxelNum - m_grid->getNbCoordsX() ) - start );
174  x.push_back( m_grid->getPosition( voxelNum + m_grid->getNbCoordsX() * m_grid->getNbCoordsY() ) - start );
175  x.push_back( m_grid->getPosition( voxelNum - m_grid->getNbCoordsX() * m_grid->getNbCoordsY() ) - start );
176 
177  std::vector< double > result;
178  result.reserve( 7 );
179 
180  // now calculate distance from x to the line given via start and end
181  for( size_t i = 0; i < x.size(); ++i )
182  {
183  WPosition lot = dot( u, x[i] ) * u; // lot == perpendicular
184  result.push_back( std::abs( length( x[i] - lot ) ) );
185  }
186  return result;
187 }
188 
189 double WBresenham::composeValue( double newValue, double existingValue ) const
190 {
191  return std::max( newValue, existingValue );
192  // return newValue + existingValue;
193 }
194 
195 void WBresenham::markVoxel( const WVector3i& voxel, const int axis, const WPosition& start, const WPosition& end )
196 {
197  size_t nbX = m_grid->getNbCoordsX();
198  size_t nbXY = m_grid->getNbCoordsX() * m_grid->getNbCoordsY();
199  int x = voxel[0];
200  int y = voxel[1];
201  int z = voxel[2];
202  size_t idx = x + y * nbX + z * nbXY;
203  std::vector< double > distances;
204 
205  if( m_antialiased )
206  {
207  distances = computeDistances( idx, start, end );
208  m_values[ idx ] = composeValue( filter( distances[0] ), m_values[ idx ] );
209  parameterizeVoxel( voxel, idx, axis, m_values[ idx ], start, end );
210  }
211  else
212  {
213  m_values[ idx ] = 1.0;
214  parameterizeVoxel( voxel, idx, axis, m_values[ idx ], start, end );
215  return;
216  }
217 
218  // if the voxel is on a "border" of the dataset antialiasing would write over the bounds
219  // hence if the voxel is at least "margin" positions away from the border antialiasing
220  // takes place, but not at the borders
221  // ATM we have just a fixed margin of size 1
222  int margin = 1;
223  int nbXInt = m_grid->getNbCoordsX();
224  int nbYInt = m_grid->getNbCoordsY();
225  int nbZInt = m_grid->getNbCoordsZ();
226  if( voxel[0] < margin || voxel[0] >= nbXInt - 1 ||
227  voxel[1] < margin || voxel[1] >= nbYInt - 1 ||
228  voxel[2] < margin || voxel[2] >= nbZInt - 1
229  )
230  {
231  return; // otherwise we would write over the bounds
232  }
233 
234  if( axis == -1 ) // just mark ONE voxel even in antialising mode!
235  {
236  return;
237  }
238 
239  WAssert( distances.size() == 7, "There is an invalid number of precomputed antialiased voxels" );
240  switch( axis )
241  {
242  case 0 :
243  m_values[ idx + nbX ] = composeValue( filter( distances[3] ), m_values[ idx + nbX ] );
244  m_values[ idx - nbX ] = composeValue( filter( distances[4] ), m_values[ idx - nbX ] );
245  m_values[ idx + nbXY ] = composeValue( filter( distances[5] ), m_values[ idx + nbXY ] );
246  m_values[ idx - nbXY ] = composeValue( filter( distances[6] ), m_values[ idx - nbXY ] );
247 
248  parameterizeVoxel( voxel, idx + nbX, axis, m_values[ idx + nbX ], start, end );
249  parameterizeVoxel( voxel, idx - nbX, axis, m_values[ idx - nbX ], start, end );
250  parameterizeVoxel( voxel, idx + nbXY, axis, m_values[ idx + nbXY ], start, end );
251  parameterizeVoxel( voxel, idx - nbXY, axis, m_values[ idx - nbXY ], start, end );
252 
253  break;
254  case 1 :
255  m_values[ idx + 1 ] = composeValue( filter( distances[1] ), m_values[ idx + 1 ] );
256  m_values[ idx - 1 ] = composeValue( filter( distances[2] ), m_values[ idx - 1 ] );
257  m_values[ idx + nbXY ] = composeValue( filter( distances[5] ), m_values[ idx + nbXY ] );
258  m_values[ idx - nbXY ] = composeValue( filter( distances[6] ), m_values[ idx - nbXY ] );
259 
260  parameterizeVoxel( voxel, idx + 1, axis, m_values[ idx + 1 ], start, end );
261  parameterizeVoxel( voxel, idx - 1, axis, m_values[ idx - 1 ], start, end );
262  parameterizeVoxel( voxel, idx + nbXY, axis, m_values[ idx + nbXY ], start, end );
263  parameterizeVoxel( voxel, idx - nbXY, axis, m_values[ idx - nbXY ], start, end );
264 
265  break;
266  case 2 :
267  m_values[ idx + 1 ] = composeValue( filter( distances[1] ), m_values[ idx + 1 ] );
268  m_values[ idx - 1 ] = composeValue( filter( distances[2] ), m_values[ idx - 1 ] );
269  m_values[ idx + nbX ] = composeValue( filter( distances[3] ), m_values[ idx + nbX ] );
270  m_values[ idx - nbX ] = composeValue( filter( distances[4] ), m_values[ idx - nbX ] );
271  parameterizeVoxel( voxel, idx + 1, axis, m_values[ idx + 1 ], start, end );
272  parameterizeVoxel( voxel, idx - 1, axis, m_values[ idx - 1 ], start, end );
273  parameterizeVoxel( voxel, idx + nbX, axis, m_values[ idx + nbX ], start, end );
274  parameterizeVoxel( voxel, idx - nbX, axis, m_values[ idx - nbX ], start, end );
275 
276  break;
277  default : WAssert( 0, "Invalid axis selected for marking a voxel" );
278  }
279 }
280 
281 double WBresenham::filter( const double distance ) const
282 {
283  WAssert( distance >= 0, "Negative distances are forbidden" );
284  if( distance > 1 )
285  {
286  return 0.0;
287  }
288  size_t bucket = std::floor( distance * 10 );
289  double tableData[] = { 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1 };
290  std::vector< double > lookUpTable( tableData, tableData + sizeof( tableData ) / sizeof( double ) );
291  return lookUpTable.at( bucket );
292 }
virtual void raster(const WLine &line)
Rasterize the given line into the grid of dataset.
Definition: WBresenham.cpp:50
WBresenham(std::shared_ptr< WGridRegular3D > grid, bool antialiased=true)
Initializes new raster algo.
Definition: WBresenham.cpp:40
virtual double filter(const double distance) const
Returns the value to mark the hit voxels with, depending on their distance to the line.
Definition: WBresenham.cpp:281
bool m_antialiased
If true also some supporting voxels are marked.
Definition: WBresenham.h:140
virtual void markVoxel(const WVector3i &voxel, const int axis, const WPosition &start, const WPosition &end)
Marks the given voxel as a hit.
Definition: WBresenham.cpp:195
double composeValue(double newValue, double existingValue) const
Compose the new value for a voxel out of a new computed value and the already existing marking.
Definition: WBresenham.cpp:189
virtual ~WBresenham()
Finishes this raster algo.
Definition: WBresenham.cpp:46
std::vector< double > computeDistances(const size_t voxelNum, const WPosition &start, const WPosition &end) const
Computes the distances for a voxel to the real line segment and also for its supporting voxels.
Definition: WBresenham.cpp:160
virtual void rasterSegment(const WPosition &start, const WPosition &end)
Scans a line segment for voxels which are hit.
Definition: WBresenham.cpp:70
A line is an ordered sequence of WPositions.
Definition: WLine.h:42
A fixed size matrix class.
Definition: WMatrixFixed.h:150
size_type size() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:267
This only is a 3d double vector.
Base class for all rasterization algorithms.
std::shared_ptr< WGridRegular3D > m_grid
The grid is used for the following purposes:
virtual void parameterizeVoxel(const WVector3i &voxel, size_t voxelIdx, const int axis, const double value, const WPosition &start, const WPosition &end)
This method allows all registered parameterization algorithms to update.
std::shared_mutex m_parameterizationsLock
The mutex used to lock access to m_parameterizations.
std::vector< double > m_values
Stores the value of each voxel.
virtual void newLine(const WLine &line)
Distribute a new line getting rasterized to all parameterize algorithms.
virtual void newSegment(const WPosition &start, const WPosition &end)
Distribute a new segment of a line to all parameterization algorithms.
WStreamedLogger debug(const std::string &source)
Logging a debug message.
Definition: WLogger.h:331