Commit 07b177ba authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[MERGE]

parents a7b1f7ec 13e68e35
......@@ -285,7 +285,7 @@ template< typename Index_T >
std::size_t const WTensorBase< order, dim, Data_T >::getPos( Index_T const* const pos )
{
return WTensorBase< order - 1, dim, Data_T >::getPos( pos ) * dim + pos[ order - 1 ];
};
}
template< std::size_t order, std::size_t dim, typename Data_T >
template< typename Index_T >
......
......@@ -25,6 +25,9 @@
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include "../common/WColor.h"
#include "../common/WLogger.h"
......@@ -193,3 +196,111 @@ wmath::WPosition WDataSetFibers::getTangent( size_t fiber, size_t vertex ) const
tangent.normalize();
return tangent;
}
void WDataSetFibers::saveSelected( std::string filename, boost::shared_ptr< std::vector< bool > > active ) const
{
std::vector< float > pointsToSave;
std::vector< int > linesToSave;
std::vector< unsigned char > colorsToSave;
int pointIndex = 0;
int countLines = 0;
for ( size_t l = 0; l < m_lineLengths->size(); ++l )
{
if ( ( *active )[l] )
{
unsigned int pc = ( *m_lineStartIndexes )[l] * 3;
linesToSave.push_back( ( *m_lineLengths )[l] );
for ( size_t j = 0; j < ( *m_lineLengths )[l]; ++j )
{
// TODO(schurade): replace this with a permanent solution
pointsToSave.push_back( 160 - ( *m_vertices )[pc] );
colorsToSave.push_back( static_cast<unsigned char> ( ( *m_localColors )[pc] * 255 ) );
++pc;
pointsToSave.push_back( 200 - ( *m_vertices )[pc] );
colorsToSave.push_back( static_cast<unsigned char> ( ( *m_localColors )[pc] * 255 ) );
++pc;
pointsToSave.push_back( ( *m_vertices )[pc] );
colorsToSave.push_back( static_cast<unsigned char> ( ( *m_localColors )[pc] * 255 ) );
++pc;
linesToSave.push_back( pointIndex );
++pointIndex;
}
++countLines;
}
}
converterByteINT32 c;
converterByteFloat f;
std::vector< char > vBuffer;
std::string header1 = "# vtk DataFile Version 3.0\nvtk output\nBINARY\nDATASET POLYDATA\nPOINTS ";
header1 += boost::lexical_cast<std::string>( pointsToSave.size() / 3 );
header1 += " float\n";
for ( unsigned int i = 0; i < header1.size(); ++i )
{
vBuffer.push_back( header1[i] );
}
for ( unsigned int i = 0; i < pointsToSave.size(); ++i )
{
f.f = pointsToSave[i];
vBuffer.push_back( f.b[3] );
vBuffer.push_back( f.b[2] );
vBuffer.push_back( f.b[1] );
vBuffer.push_back( f.b[0] );
}
vBuffer.push_back( '\n' );
std::string header2 = "LINES " + boost::lexical_cast<std::string>( countLines ) + " " +
boost::lexical_cast<std::string>( linesToSave.size() ) + "\n";
for ( unsigned int i = 0; i < header2.size(); ++i )
{
vBuffer.push_back( header2[i] );
}
for ( unsigned int i = 0; i < linesToSave.size(); ++i )
{
c.i = linesToSave[i];
vBuffer.push_back( c.b[3] );
vBuffer.push_back( c.b[2] );
vBuffer.push_back( c.b[1] );
vBuffer.push_back( c.b[0] );
}
vBuffer.push_back( '\n' );
std::string header3 = "POINT_DATA ";
header3 += boost::lexical_cast<std::string>( pointsToSave.size() / 3 );
header3 += " float\n";
header3 += "COLOR_SCALARS scalars 3\n";
for ( unsigned int i = 0; i < header3.size(); ++i )
{
vBuffer.push_back( header3[i] );
}
for ( unsigned int i = 0; i < colorsToSave.size(); ++i )
{
vBuffer.push_back( colorsToSave[i] );
}
vBuffer.push_back( '\n' );
boost::filesystem::path p( filename );
boost::filesystem::ofstream ofs( p );
for ( unsigned int i = 0; i < vBuffer.size(); ++i )
{
ofs << vBuffer[i];
}
}
......@@ -34,6 +34,23 @@
#include "WDataSet.h"
/**
* converts an integer into a byte array and back
*/
union converterByteINT32
{
unsigned char b[4]; //!< the bytes
int i; //!< the int
};
/**
* converts a float into a byte array and back
*/
union converterByteFloat
{
unsigned char b[4]; //!< the bytes
float f; //!< the float
};
/**
* Represents a simple set of WFibers.
......@@ -147,6 +164,13 @@ public:
*/
wmath::WPosition getTangent( size_t fiber, size_t vertex ) const;
/**
* saves the selected fiber bundles to a file
*
*\param filename
* \param active bitfield of the fiber selection
*/
void saveSelected( std::string filename, boost::shared_ptr< std::vector< bool > > active ) const;
protected:
/**
......
......@@ -43,7 +43,7 @@ namespace wge
* \param pos1 First point
* \param pos2 Second point
*/
WColor getRGBAColorFromDirection( const wmath::WPosition &pos1, const wmath::WPosition &pos2 );
WColor getRGBAColorFromDirection( const wmath::WPosition &pos1, const wmath::WPosition &pos2 );
/**
* Converts a WColor to an OSG compatible color
......@@ -78,6 +78,12 @@ namespace wge
* \param camera The matrices of this camera will used for unprojecting.
*/
osg::Vec3 unprojectFromScreen( const osg::Vec3 screen, osg::ref_ptr< osg::Camera > camera );
/**
* Conversion of WVector3D to osg::Vec3
* \param v the vector to convert.
*/
osg::Vec3 wv3D2ov3( wmath::WVector3D v );
}
inline WColor wge::getRGBAColorFromDirection( const wmath::WPosition &pos1, const wmath::WPosition &pos2 )
......@@ -96,4 +102,10 @@ inline osg::Vec3 wge::osgVec3( const wmath::WPosition& pos )
{
return osg::Vec3( pos[0], pos[1], pos[2] );
}
inline osg::Vec3 wge::wv3D2ov3( wmath::WVector3D v )
{
return osg::Vec3( v[0], v[1], v[2] );
}
#endif // WGEUTILS_H
......@@ -90,6 +90,9 @@ void WMDistanceMapIsosurface::moduleMain()
m_useTextureProp->set( true );
m_properties->addProperty( m_useTextureProp );
m_surfaceColorProp = mcProps->getProperty( "Surface Color" )->toPropColor();
m_properties->addProperty( m_surfaceColorProp );
m_opacityProp = mcProps->getProperty( "Opacity %" )->toPropInt();
m_properties->addProperty( m_opacityProp );
......
......@@ -90,6 +90,7 @@ private:
WPropDouble m_isoValueProp; //!< Property holding the value for the distance.
WPropInt m_opacityProp; //!< Property holding the value for the opacity of the surface.
WPropBool m_useTextureProp; //!< Property indicating whether to use texturing with scalar data sets.
WPropColor m_surfaceColorProp; //!< Property indicating which color to use for non-textured surface.
boost::shared_ptr< WModuleInputForwardData< WDataSetScalar > > m_input; //!< Input connector required by this module.
boost::shared_ptr< WModuleOutputForwardData< WDataSetScalar > > m_output; //!< Connector to provide the distance map to other modules.
......
......@@ -210,6 +210,8 @@ void WMFiberDisplay::properties()
boost::bind( &WMFiberDisplay::adjustTubes, this ) );
m_tubeThickness->setMin( 0 );
m_tubeThickness->setMax( 1000 );
m_save = m_properties->addProperty( "Save", "saves the selected fiber bundles.", false, boost::bind( &WMFiberDisplay::saveSelected, this ) );
m_saveFileName = m_properties->addProperty( "File Name", "no description yet", WKernel::getAppPathObject() );
}
void WMFiberDisplay::toggleTubes()
......@@ -253,3 +255,9 @@ void WMFiberDisplay::adjustTubes()
m_uniformTubeThickness->set( static_cast<float>( m_tubeThickness->get() ) );
}
}
void WMFiberDisplay::saveSelected()
{
boost::shared_ptr< std::vector< bool > > active = WKernel::getRunningKernel()->getRoiManager()->getBitField();
m_dataset->saveSelected( m_saveFileName->getAsString(), active );
}
......@@ -117,6 +117,8 @@ private:
WPropBool m_customColoring; //!< Enable/Disable custom colors
WPropBool m_useTubesProp; //!< Property indicating whether to use tubes for the fibers tracts.
WPropDouble m_tubeThickness; //!< Property determining the thickness of tubes .
WPropBool m_save; //!< this should be a button
WPropFilename m_saveFileName; //!< the filename for saving
WBoolFlag m_noData; //!< Flag indicating whether there is data to display.
......@@ -168,6 +170,11 @@ private:
*/
void adjustTubes();
/**
* saves the currently selected (active field from roi manager) fibers to a file
*/
void saveSelected();
/**
* Node callback to handle updates properly
*/
......
......@@ -50,6 +50,7 @@
#include "../../dataHandler/WDataHandler.h"
#include "../../dataHandler/WSubject.h"
#include "../../dataHandler/WDataTexture3D.h"
#include "../../graphicsEngine/WGEUtils.h"
#include "../../kernel/WKernel.h"
#include "WMMarchingCubes.h"
......@@ -210,6 +211,8 @@ void WMMarchingCubes::properties()
m_opacityProp->setMax( 100 );
m_useTextureProp = m_properties->addProperty( "Use Texture", "Use texturing of the surface?", false );
m_surfaceColor = m_properties->addProperty( "Surface Color", "Description.", WColor( 0.3, 0.3, 0.3, 1.0 ) );
}
void WMMarchingCubes::generateSurfacePre( double isoValue )
......@@ -296,9 +299,10 @@ template< typename T > void WMMarchingCubes::generateSurface( boost::shared_ptr<
m_grid = grid;
WAssert( grid, "Grid is not of type WGridRegular3D." );
m_fCellLengthX = grid->getOffsetX();
m_fCellLengthY = grid->getOffsetY();
m_fCellLengthZ = grid->getOffsetZ();
// We choose the following to be 1 as we transform the positions later.
m_fCellLengthX = 1;
m_fCellLengthY = 1;
m_fCellLengthZ = 1;
m_nCellsX = grid->getNbCoordsX() - 1;
m_nCellsY = grid->getNbCoordsY() - 1;
......@@ -647,7 +651,6 @@ void WMMarchingCubes::renderSurface()
// }
}
void WMMarchingCubes::renderMesh( boost::shared_ptr< WTriangleMesh2 > mesh )
{
// WKernel::getRunningKernel()->getGraphicsEngine()->getScene()
......@@ -684,7 +687,8 @@ void WMMarchingCubes::renderMesh( boost::shared_ptr< WTriangleMesh2 > mesh )
// colors
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back( osg::Vec4( .9f, .9f, 0.9f, 1.0f ) );
WColor c = m_surfaceColor->get( true );
colors->push_back( osg::Vec4( c.getRed(), c.getGreen(), c.getBlue(), 1.0f ) );
surfaceGeometry->setColorArray( colors );
surfaceGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
......@@ -706,16 +710,11 @@ void WMMarchingCubes::renderMesh( boost::shared_ptr< WTriangleMesh2 > mesh )
// ------------------------------------------------
// Shader stuff
// TODO(wiebel): fix texture coords.
double xext = m_grid->getOffsetX() * m_grid->getNbCoordsX();
double yext = m_grid->getOffsetY() * m_grid->getNbCoordsY();
double zext = m_grid->getOffsetZ() * m_grid->getNbCoordsZ();
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < mesh->vertSize(); ++i )
{
osg::Vec3 vertPos = mesh->getVertex( i );
texCoords->push_back( osg::Vec3( vertPos[0]/xext, vertPos[1]/yext, vertPos[2]/zext ) );
texCoords->push_back( wge::wv3D2ov3( m_grid->worldCoordToTexCoord( wmath::WPosition( vertPos[0], vertPos[1], vertPos[2] ) ) ) );
}
surfaceGeometry->setTexCoordArray( 0, texCoords );
......@@ -1012,7 +1011,7 @@ WTriangleMesh2 WMMarchingCubes::load( std::string /*fileName*/ )
return triMesh;
}
void WMMarchingCubes::updateTextures()
void WMMarchingCubes::updateGraphics()
{
if ( m_active->get() )
{
......@@ -1023,6 +1022,17 @@ void WMMarchingCubes::updateTextures()
m_surfaceGeode->setNodeMask( 0x0 );
}
if( m_surfaceColor->changed() )
{
osg::Vec4Array* colors = new osg::Vec4Array;
WColor c = m_surfaceColor->get( true );
colors->push_back( osg::Vec4( c.getRed(), c.getGreen(), c.getBlue(), 1.0f ) );
osg::ref_ptr< osg::Geometry > surfaceGeometry = m_surfaceGeode->getDrawable( 0 )->asGeometry();
surfaceGeometry->setColorArray( colors );
surfaceGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
}
if ( m_textureChanged || m_opacityProp->changed() || m_useTextureProp->changed() )
{
m_textureChanged = false;
......
......@@ -159,7 +159,7 @@ public:
/**
* updates textures and shader parameters
*/
void updateTextures();
void updateGraphics();
protected:
/**
......@@ -258,6 +258,7 @@ private:
WPropDouble m_isoValueProp; //!< Property holding the iso value
WPropInt m_opacityProp; //!< Property holding the opacity valueassigned to the surface
WPropBool m_useTextureProp; //!< Property indicating whether to use texturing with scalar data sets.
WPropColor m_surfaceColor; //!< Property determining the color for the surface if no textures are displayed
/**
* True when textures haven changed.
......@@ -348,7 +349,7 @@ inline void SurfaceNodeCallback::operator()( osg::Node* node, osg::NodeVisitor*
{
if ( m_module )
{
m_module->updateTextures();
m_module->updateGraphics();
}
traverse( node, nv );
}
......
......@@ -96,7 +96,7 @@ void lookupTex(inout vec4 col, in int type, in sampler3D tex, in float threshol
void main()
{
vec4 col = vec4(0.3, 0.3, 0.3, 1.0);
vec4 col = gl_Color;
vec4 ambient = vec4(0.0);
vec4 diffuse = vec4(0.0);
......
......@@ -8,5 +8,7 @@ void main()
prepareLight();
gl_FrontColor = gl_Color;
gl_Position = ftransform();
}
......@@ -165,6 +165,11 @@ void WMNavSlices::moduleMain()
boost::bind( &WMNavSlices::notifyTextureChange, this )
);
setMaxMinFromBoundingBox();
m_sagittalPos->set( 0.5 * ( m_bb.first[0] + m_bb.second[0] ) );
m_coronalPos->set( 0.5 * ( m_bb.first[1] + m_bb.second[1] ) );
m_axialPos->set( 0.5 * ( m_bb.first[2] + m_bb.second[2] ) );
create();
// Since the modules run in a separate thread: wait
......@@ -255,14 +260,6 @@ void WMNavSlices::create()
}
}
namespace //anonymous name space
{
osg::Vec3 wv3D2ov3( wmath::WVector3D v ) // WVector3D to osg::Vec3 conversion
{
return osg::Vec3( v[0], v[1], v[2] );
}
}
void WMNavSlices::setSlicePosFromPick( WPickInfo pickInfo )
{
if ( pickInfo.getName() == "Axial Slice"
......@@ -284,7 +281,7 @@ void WMNavSlices::setSlicePosFromPick( WPickInfo pickInfo )
osg::Vec3 endPosWorld = wge::unprojectFromScreen( endPosScreen, m_viewer->getCamera() );
osg::Vec3 moveDirWorld = endPosWorld - startPosWorld;
float diff = wv3D2ov3( normal ) * moveDirWorld;
float diff = wge::wv3D2ov3( normal ) * moveDirWorld;
// recognize also small values.
if( diff < 0 && diff > -1 )
......@@ -336,14 +333,43 @@ void WMNavSlices::setSlicePosFromPick( WPickInfo pickInfo )
}
}
void WMNavSlices::setMaxMinFromBoundingBox()
{
// grab a list of data textures
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
if ( tex.size() > 0 )
{
std::pair< wmath::WPosition, wmath::WPosition > bb = tex[0]->getGrid()->getBoundingBox();
for( size_t i = 1; i < tex.size(); ++i )
{
std::pair< wmath::WPosition, wmath::WPosition > bbTmp = tex[i]->getGrid()->getBoundingBox();
bb.first[0] = bb.first[0] < bbTmp.first[0] ? bb.first[0] : bbTmp.first[0];
bb.first[1] = bb.first[1] < bbTmp.first[1] ? bb.first[1] : bbTmp.first[1];
bb.first[2] = bb.first[2] < bbTmp.first[2] ? bb.first[2] : bbTmp.first[2];
bb.second[0] = bb.second[0] > bbTmp.second[0] ? bb.second[0] : bbTmp.second[0];
bb.second[1] = bb.second[1] > bbTmp.second[1] ? bb.second[1] : bbTmp.second[1];
bb.second[2] = bb.second[2] > bbTmp.second[2] ? bb.second[2] : bbTmp.second[2];
}
m_bb = bb;
m_sagittalPos->setMin( bb.first[0] );
m_sagittalPos->setMax( bb.second[0] );
m_coronalPos->setMin( bb.first[1] );
m_coronalPos->setMax( bb.second[1] );
m_axialPos->setMin( bb.first[2] );
m_axialPos->setMax( bb.second[2] );
}
}
osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
{
const size_t nbVerts = 4;
float maxDim = 255.0;
float xSlice = static_cast< float >( m_sagittalPos->get() );
float ySlice = static_cast< float >( m_coronalPos->get() );
float zSlice = static_cast< float >( m_axialPos->get() );
float xSlice = static_cast< float >( m_sagittalPos->get( true ) );
float ySlice = static_cast< float >( m_coronalPos->get( true ) );
float zSlice = static_cast< float >( m_axialPos->get( true ) );
float xPos = xSlice + 0.5f;
float yPos = ySlice + 0.5f;
......@@ -356,20 +382,23 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
// grab a list of data textures
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
if ( tex.size() > 0 )
{
setMaxMinFromBoundingBox();
switch ( slice )
{
case 0:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( xPos, 0, 0 ) );
vertices.push_back( wmath::WPosition( xPos, 0, maxDim ) );
vertices.push_back( wmath::WPosition( xPos, maxDim, maxDim ) );
vertices.push_back( wmath::WPosition( xPos, maxDim, 0 ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.first[1], m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.first[1], m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.second[1], m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.second[1], m_bb.first[2] ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wv3D2ov3( vertices[i] ) );
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
......@@ -382,7 +411,7 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
......@@ -392,13 +421,13 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
case 1:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( 0, yPos, 0 ) );
vertices.push_back( wmath::WPosition( maxDim, yPos, 0 ) );
vertices.push_back( wmath::WPosition( maxDim, yPos, maxDim ) );
vertices.push_back( wmath::WPosition( 0, yPos, maxDim ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], yPos, m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], yPos, m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], yPos, m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], yPos, m_bb.second[2] ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wv3D2ov3( vertices[i] ) );
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
......@@ -410,7 +439,7 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
......@@ -420,13 +449,13 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
case 2:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( 0, 0, zPos ) );
vertices.push_back( wmath::WPosition( 0, maxDim, zPos ) );
vertices.push_back( wmath::WPosition( maxDim, maxDim, zPos ) );
vertices.push_back( wmath::WPosition( maxDim, 0, zPos ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], m_bb.first[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], m_bb.second[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], m_bb.second[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], m_bb.first[1], zPos ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wv3D2ov3( vertices[i] ) );
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
......@@ -440,7 +469,7 @@ osg::ref_ptr<osg::Geometry> WMNavSlices::createGeometry( int slice )
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
......@@ -467,16 +496,23 @@ void WMNavSlices::updateGeometry()
boost::shared_lock<boost::shared_mutex> slock;
slock = boost::shared_lock<boost::shared_mutex>( m_updateLock );
osg::ref_ptr<osg::Geometry> xSliceGeometry = createGeometry( 0 );
osg::ref_ptr<osg::Geometry> ySliceGeometry = createGeometry( 1 );
osg::ref_ptr<osg::Geometry> zSliceGeometry = createGeometry( 2 );
osg::ref_ptr<osg::Drawable> oldx = osg::ref_ptr<osg::Drawable>( m_xSliceNode->getDrawable( 0 ) );
m_xSliceNode->replaceDrawable( oldx, xSliceGeometry );
osg::ref_ptr<osg::Drawable> oldy = osg::ref_ptr<osg::Drawable>( m_ySliceNode->getDrawable( 0 ) );
m_ySliceNode->replaceDrawable( oldy, ySliceGeometry );
osg::ref_ptr<osg::Drawable> oldz = osg::ref_ptr<osg::Drawa