Carna  Version 3.3.2
VolumeGridHelper.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 - 2015 Leonid Kostrykin
3  *
4  * Chair of Medical Engineering (mediTEC)
5  * RWTH Aachen University
6  * Pauwelsstr. 20
7  * 52074 Aachen
8  * Germany
9  *
10  */
11 
12 #ifndef VOLUMEGRIDHELPER_H_6014714286
13 #define VOLUMEGRIDHELPER_H_6014714286
14 
16 #include <Carna/Carna.h>
17 #include <Carna/base/Node.h>
18 #include <Carna/base/math.h>
19 #include <Carna/base/VolumeGrid.h>
21 #include <Carna/base/Geometry.h>
22 #include <Carna/base/BoundingBox.h>
23 #include <memory>
24 #include <cmath>
25 
30 namespace Carna
31 {
32 
33 namespace helpers
34 {
35 
36 
37 
38 // ----------------------------------------------------------------------------------
39 // VolumeGridHelperBase
40 // ----------------------------------------------------------------------------------
41 
48 class CARNA_LIB VolumeGridHelperBase
49 {
50 
51 public:
52 
59  const static std::size_t DEFAULT_MAX_SEGMENT_BYTESIZE = 2 * 300 * 300 * 300;
60 
68  VolumeGridHelperBase( const base::math::Vector3ui& nativeResolution );
69 
74 
78  virtual ~VolumeGridHelperBase();
79 
86  virtual void releaseGeometryFeatures() = 0;
87 
91  struct CARNA_LIB Spacing
92  {
96  explicit Spacing( const base::math::Vector3f& millimeters );
97 
102  };
103 
107  struct CARNA_LIB Dimensions
108  {
112  explicit Dimensions( const base::math::Vector3f& millimeters );
113 
118  };
119 
136  virtual base::Node* createNode( unsigned int geometryType, const Spacing& spacing ) const = 0;
137 
153  virtual base::Node* createNode( unsigned int geometryType, const Dimensions& dimensions ) const = 0;
154 
160  virtual void loadIntensities( const std::function< float( const base::math::Vector3ui& ) >& intensityData ) = 0;
161 
164  template< typename LoadIntensitiesFunction >
165  void loadIntensities( const LoadIntensitiesFunction& intensityData );
166 
172  void loadHUData( const std::function< base::HUV( const base::math::Vector3ui& ) >& huData );
173 
176  template< typename LoadHUDataFunction >
177  void loadHUData( const LoadHUDataFunction& huData );
178 
179 }; // VolumeGridHelperBase
180 
181 
182 template< typename LoadIntensitiesFunction >
183 void VolumeGridHelperBase::loadIntensities( const LoadIntensitiesFunction& intensityData )
184 {
185  loadIntensities( static_cast< const std::function< float( const base::math::Vector3ui& ) >& >
186  (
187  [&intensityData]( const base::math::Vector3ui& loc ) -> float
188  {
189  return intensityData( loc );
190  }
191  )
192  );
193 }
194 
195 
196 template< typename LoadHUDataFunction >
197 void VolumeGridHelperBase::loadHUData( const LoadHUDataFunction& huData )
198 {
199  loadHUData( static_cast< const std::function< base::HUV( const base::math::Vector3ui& ) >& >
200  (
201  [&huData]( const base::math::Vector3ui& loc )
202  {
203  return huData( loc );
204  }
205  )
206  );
207 }
208 
209 
210 
211 // ----------------------------------------------------------------------------------
212 // VolumeGridHelper
213 // ----------------------------------------------------------------------------------
214 
253 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
254 class VolumeGridHelper
255  : public VolumeGridHelperBase
256  , public details::VolumeGridHelper::IntensityComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType >
257  , public details::VolumeGridHelper:: NormalsComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType >
258 {
259 
261 
263  typedef details::VolumeGridHelper:: NormalsComponent< SegmentIntensityVolumeType, SegmentNormalsVolumeType > NormalsComponent;
264 
268  std::unique_ptr< base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType > > myGrid;
269 
270 public:
271 
272  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
273 
287  VolumeGridHelper( const base::math::Vector3ui& nativeResolution, std::size_t maxSegmentBytesize = DEFAULT_MAX_SEGMENT_BYTESIZE );
288 
292  const std::size_t maxSegmentBytesize;
293 
298 
303 
308 
313 
318 
330  virtual void loadIntensities( const std::function< float( const base::math::Vector3ui& ) >& intensityData ) override;
331 
342  virtual void releaseGeometryFeatures() override;
343 
348 
349  virtual base::Node* createNode( unsigned int geometryType, const Spacing& spacing ) const override;
350 
351  virtual base::Node* createNode( unsigned int geometryType, const Dimensions& dimensions ) const override;
352 
353 protected:
354 
355  virtual base::math::Vector3ui gridResolution() const override;
356 
357 private:
358 
359  base::Node* createNode
360  ( unsigned int geometryType
361  , const Spacing& spacing
362  , const Dimensions& dimensions ) const;
363 
364  static base::math::Vector3ui computeMaxSegmentSize( const base::math::Vector3ui& nativeResolution, std::size_t maxSegmentBytesize );
365 
366 }; // VolumeGridHelper
367 
368 
369 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
371  ( const base::math::Vector3ui& nativeResolution, std::size_t maxSegmentBytesize )
372 {
373  const float maxSideLengthF = std::pow
374  ( maxSegmentBytesize / static_cast< float >( sizeof( typename SegmentIntensityVolumeType::Voxel ) ), 1.f / 3 );
375  const unsigned int maxSideLength = base::math::makeEven( base::math::round_ui( maxSideLengthF ), -1 );
376 
377  /* We subtract the redundant texels from effective segment size.
378  * Note that this causes the effective maximum segment size to be odd.
379  */
380  return base::math::Vector3ui( maxSideLength - 1, maxSideLength - 1, maxSideLength - 1 );
381 }
382 
383 
384 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
386  ( const base::math::Vector3ui& nativeResolution
387  , std::size_t maxSegmentBytesize )
388  : VolumeGridHelperBase( nativeResolution )
389  , maxSegmentBytesize( maxSegmentBytesize )
390  , maxSegmentSize( computeMaxSegmentSize( nativeResolution, maxSegmentBytesize ) )
391  , partitioningX( nativeResolution.x(), maxSegmentSize.x() )
392  , partitioningY( nativeResolution.y(), maxSegmentSize.y() )
393  , partitioningZ( nativeResolution.z(), maxSegmentSize.z() )
394  , resolution( partitioningX.totalSize(), partitioningY.totalSize(), partitioningZ.totalSize() )
395 {
396  const base::math::Vector3ui segmentCounts
397  ( partitioningX.partitionsCount()
398  , partitioningY.partitionsCount()
399  , partitioningZ.partitionsCount() );
400  myGrid.reset( new base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType >( maxSegmentSize, segmentCounts ) );
401  NormalsComponent::setGrid( *myGrid );
402 
403  CARNA_FOR_VECTOR3UI( segmentCoord, myGrid->segmentCounts )
404  {
405  /* Here we add the redundant texels to the buffer size considerations.
406  */
407  const base::math::Vector3ui segmentSize
408  ( segmentCoord.x() + 1 == myGrid->segmentCounts.x() ? partitioningX.tailSize : partitioningX.regularPartitionSize + 1
409  , segmentCoord.y() + 1 == myGrid->segmentCounts.y() ? partitioningY.tailSize : partitioningY.regularPartitionSize + 1
410  , segmentCoord.z() + 1 == myGrid->segmentCounts.z() ? partitioningZ.tailSize : partitioningZ.regularPartitionSize + 1 );
411 
412  IntensityComponent::initializeSegment( myGrid->segmentAt( segmentCoord ), segmentSize );
413  NormalsComponent ::initializeSegment( myGrid->segmentAt( segmentCoord ), segmentSize );
414  }
415 }
416 
417 
418 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
420 {
421  IntensityComponent::releaseGeometryFeatures();
422  NormalsComponent ::releaseGeometryFeatures();
423 }
424 
425 
426 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
428  ( const std::function< float( const base::math::Vector3ui& ) >& data )
429 {
430  releaseGeometryFeatures();
431  CARNA_FOR_VECTOR3UI( coord, resolution )
432  {
433  const bool outOfNativeBounds
434  = coord.x() >= nativeResolution.x()
435  || coord.y() >= nativeResolution.y()
436  || coord.z() >= nativeResolution.z();
437  const float intensity = outOfNativeBounds ? 0 : data( coord );
438  myGrid->template setVoxel< typename base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType >::IntensitySelector >( coord, intensity );
439  }
440  NormalsComponent::computeNormals();
441 }
442 
443 
444 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
447 {
448  return *myGrid;
449 }
450 
451 
452 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
454  ( unsigned int geometryType, const Spacing& spacing, const Dimensions& dimensions ) const
455 {
456  /* Compute dimensions of a regular grid segment, taking the redundant texels into
457  * account. Regular segments have `regularPartitionSize + 1` texels per dimension
458  * which is due to the redundant pixels.
459  */
460  const base::math::Vector3f regularSegmentDimensions = dimensions.millimeters.cwiseMin( base::math::Vector3f
461  ( spacing.millimeters.x() * partitioningX.regularPartitionSize
462  , spacing.millimeters.y() * partitioningY.regularPartitionSize
463  , spacing.millimeters.z() * partitioningZ.regularPartitionSize ) );
464 
465  /* Create pivot node that centers its children.
466  *
467  * Suppose the following example grid layout, where p is the absolute center and
468  * q is the center of the first segment:
469  *
470  * o-------o-------o---o
471  * | q | | |
472  * o-------o-------o---o
473  * | | p | |
474  * o-------o-------o---o
475  * | | | |
476  * o-------o-------o---o
477  *
478  * Each segment is rendered around its local center. Thus, the translation T
479  * required to center the volume geometry in the origin, corresponds to:
480  *
481  * T = -p + q
482  */
483  base::Node* const pivot = new base::Node();
484  pivot->localTransform = base::math::translation4f( ( regularSegmentDimensions - dimensions.millimeters ) / 2 );
485  pivot->setMovable( false );
486 
487  /* Create geometry nodes for all grid segments.
488  */
489  CARNA_FOR_VECTOR3UI( segmentCoord, myGrid->segmentCounts )
490  {
491  const base::VolumeSegment< SegmentIntensityVolumeType, SegmentNormalsVolumeType >& segment = myGrid->segmentAt( segmentCoord );
492 
493  /* Compute dimensions of particular grid segment.
494  */
495  const bool isTailX = segmentCoord.x() + 1 == myGrid->segmentCounts.x();
496  const bool isTailY = segmentCoord.y() + 1 == myGrid->segmentCounts.y();
497  const bool isTailZ = segmentCoord.z() + 1 == myGrid->segmentCounts.z();
498  const base::math::Vector3ui& volumeSize = segment.intensities().size; // includes redundant pixels (only along non-tail dimensions)
499  const base::math::Vector3f segmentDimensions
500  ( isTailX ? ( volumeSize.x() - 1 ) * spacing.millimeters.x() : regularSegmentDimensions.x()
501  , isTailY ? ( volumeSize.y() - 1 ) * spacing.millimeters.y() : regularSegmentDimensions.y()
502  , isTailZ ? ( volumeSize.z() - 1 ) * spacing.millimeters.z() : regularSegmentDimensions.z() );
503 
504  /* Create geometry node for particular grid segment.
505  */
506  base::Geometry* const geom = new base::Geometry( geometryType );
507  pivot->attachChild( geom );
508  IntensityComponent::attachTexture( *geom, segment );
509  NormalsComponent ::attachTexture( *geom, segment );
510  geom->setMovable( false );
511  geom->setBoundingVolume( new base::BoundingBox( 1, 1, 1 ) );
512  geom->localTransform
514  ( segmentCoord.x() * regularSegmentDimensions.x() - ( isTailX ? ( regularSegmentDimensions.x() - segmentDimensions.x() ) / 2 : 0 )
515  , segmentCoord.y() * regularSegmentDimensions.y() - ( isTailY ? ( regularSegmentDimensions.y() - segmentDimensions.y() ) / 2 : 0 )
516  , segmentCoord.z() * regularSegmentDimensions.z() - ( isTailZ ? ( regularSegmentDimensions.z() - segmentDimensions.z() ) / 2 : 0 ) )
517  * base::math::scaling4f( segmentDimensions );
518  }
519 
520  /* We're done.
521  */
523  , "VolumeGridHelper computed "
524  + base::text::lexical_cast< std::string >( 8 * sizeof( typename SegmentIntensityVolumeType::Voxel ) )
525  + "bit grid data using "
526  + base::text::lexical_cast< std::string >( myGrid->segmentCounts.x() ) + "×"
527  + base::text::lexical_cast< std::string >( myGrid->segmentCounts.y() ) + "×"
528  + base::text::lexical_cast< std::string >( myGrid->segmentCounts.z() ) + " segments" );
529  return pivot;
530 }
531 
532 
533 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
535  ( unsigned int geometryType, const Spacing& spacing ) const
536 {
537  const base::math::Vector3f dimensions
538  = ( nativeResolution.cast< int >() - base::math::Vector3i( 1, 1, 1 ) ).cast< float >().cwiseProduct( spacing.millimeters );
539  return createNode( geometryType, spacing, Dimensions( dimensions ) );
540 }
541 
542 
543 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
545  ( unsigned int geometryType, const Dimensions& dimensions ) const
546 {
547  const base::math::Vector3f& mmDimensions = dimensions.millimeters;
548  const base::math::Vector3f spacing
549  = mmDimensions.cast< float >().cwiseQuotient( ( nativeResolution.cast< int >() - base::math::Vector3i( 1, 1, 1 ) ).cast< float >() );
550  return createNode( geometryType, Spacing( spacing ), dimensions );
551 }
552 
553 
554 template< typename SegmentIntensityVolumeType, typename SegmentNormalsVolumeType >
556 {
557  return resolution;
558 }
559 
560 
561 
562 } // namespace Carna :: helpers
563 
564 } // namespace Carna
565 
566 #endif // VOLUMEGRIDHELPER_H_6014714286
Defines Carna::base::math namespace and CARNA_FOR_VECTOR3UI.
std::size_t partitionsCount() const
Tells the total partitions number.
unsigned int round_ui(ScalarType x)
Rounds x to the closest . Either the data type of must be unsigned or .
Definition: math.h:597
ScalarType makeEven(ScalarType x, int s)
Returns if is even and if is odd, where . The data type of must be integral. ...
Definition: math.h:625
Defines Carna::helpers::details::VolumeGridHelper.
Matrix4f scaling4f(float x, float y, float z)
Creates scaling matrix for homogeneous coordinates.
Definition: math.h:292
const std::size_t maxSegmentBytesize
Maximum memory size of a single segment volume.
Defines scene graph leafs. Instances of this class represent visible geometry that can be rendered...
Definition: Geometry.h:59
void attachChild(Spatial *child)
Attaches child to this node in and takes it&#39;s possession.
Defines Carna::base::Node.
Indicates messages that might be of interest when searching bugs.
Definition: Log.h:88
Defines type-parameters-independent VolumeGridHelper base interface.
Eigen::Matrix< unsigned int, 3, 1 > Vector3ui
Defines vector.
Definition: math.h:199
Represents a single volumetric data partition.
virtual base::Node * createNode(unsigned int geometryType, const Spacing &spacing) const override
Creates renderable representation of the underlying grid, that can be put anywhere in the scene graph...
Defines the helpers::VolumeGridHelper component that maintains intensity volume data.
virtual void releaseGeometryFeatures() override
Releases all previously acquired textures. Invoke this method when the volume data changes...
Defines a Geometry minimal boundary box.
Definition: BoundingBox.h:40
Eigen::Matrix< float, 3, 1 > Vector3f
Defines vector.
Definition: math.h:196
Matrix4f translation4f(float x, float y, float z)
Returns matrix that translates homogeneous coordinates.
Definition: math.h:271
Defines the inner node of a scene graph. Implements a spatial scene element that is allowed to have c...
Definition: Node.h:44
const details::VolumeGridHelper::Partionining partitioningX
Describes the partitioning along the x-axis.
#define CARNA_FOR_VECTOR3UI(vecName, vecLimit)
Loops vecName over all where is vecLimit.
Definition: math.h:747
base::math::Vector3f millimeters
Holds the dimensions of the whole dataset in millimeters.
Defines Carna::base::VolumeGrid.
static Log & instance()
Returns the only instance from class InstanceType.
Definition: Singleton.h:109
base::math::Vector3f millimeters
Holds the spacing between two succeeding voxel centers in millimeters.
const details::VolumeGridHelper::Partionining partitioningZ
Describes the partitioning along the z-axis.
VolumeGridHelper(const base::math::Vector3ui &nativeResolution, std::size_t maxSegmentBytesize=DEFAULT_MAX_SEGMENT_BYTESIZE)
Creates new base::VolumeGrid object. Initializes its&#39; segments s.t. the totally covered resolution is...
void setMovable(bool movable)
Sets whether this spatial may be displaced w.r.t. it&#39;s parent through user interaction. Usually this will be false when this spatial represents a component of it&#39;s parent, like the shaft of an arrow.
virtual void loadIntensities(const std::function< float(const base::math::Vector3ui &) > &intensityData) override
Updates the data of the volume grid.
Specifies the spacing between two succeeding voxel centers in millimeters.
std::size_t tailSize
Holds the resolution of the last partition that may also be 0.
Defines Carna::base::VolumeSegment.
const base::math::Vector3ui maxSegmentSize
The maximum effective resolution of a single grid segment.
SegmentIntensityVolumeType & intensities()
References the intensity volume data of this partition.
const details::VolumeGridHelper::Partionining partitioningY
Describes the partitioning along the y-axis.
Computes the partitioning of volumetric data and the corresponding normal map. Also creates scene nod...
Definition: Carna.h:216
const base::math::Vector3ui resolution
Holds the effective resolution, i.e. the resolution covered by the grid.
const base::math::Vector3ui nativeResolution
Holds the original resolution of the loaded data.
void record(Severity severity, const std::string &entry) const
Instructs current writer to write entry with severity.
Represents values in .
Definition: HUV.h:34
base::VolumeGrid< SegmentIntensityVolumeType, SegmentNormalsVolumeType > & grid() const
References the underlying grid.
virtual void loadIntensities(const std::function< float(const base::math::Vector3ui &) > &intensityData)=0
Updates the data of the volume grid.
std::size_t totalSize() const
Computes the effective total resolution.
Defines Carna::base::BoundingBox.
Specifies the dimensions of the whole dataset in millimeters.
Computes the partitioning that VolumeGridHelper uses along one dimension.
#define NON_COPYABLE
Features class it is placed in as non-copyable.
Definition: noncopyable.h:109
std::size_t regularPartitionSize
Holds the always odd, effective resolution of a single regular partition.
Defines Carna::base::Geometry.
Represents a particular partitioning of volumetric data.
Definition: VolumeGrid.h:63
void loadHUData(const std::function< base::HUV(const base::math::Vector3ui &) > &huData)
Updates the data of the volume grid.
Eigen::Matrix< signed int, 3, 1 > Vector3i
Defines vector.
Definition: math.h:198
math::Matrix4f localTransform
Defines the location, rotation and scale of this spatial in relation to it&#39;s parent. If this spatial has no parent, the value has no meaning.
Definition: Spatial.h:132