OpenWalnut  1.4.0
WROIBox.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <algorithm>
00026 #include <string>
00027 #include <utility>
00028 
00029 #include <osg/LineWidth>
00030 #include <osg/LightModel>
00031 #include <osg/Geometry>
00032 
00033 #include "../common/WLogger.h"
00034 #include "shaders/WGEShader.h"
00035 
00036 #include "WROIBox.h"
00037 #include "WGraphicsEngine.h"
00038 #include "WGEUtils.h"
00039 #include "WGEGeodeUtils.h"
00040 
00041 size_t WROIBox::maxBoxId = 0;
00042 
00043 WROIBox::WROIBox( WPosition minPos, WPosition maxPos ) :
00044     WROI(),
00045     boxId( maxBoxId++ ),
00046     m_pickNormal( WVector3d() ),
00047     m_oldPixelPosition( WVector2d::zero() ),
00048     m_oldScrollWheel( 0 ),
00049     m_color( osg::Vec4( 0.391f, 0.594f, 0.828f, 0.5f ) ),
00050     m_notColor( osg::Vec4( 0.828f, 0.391f, 0.391f, 0.5f ) )
00051 {
00052     m_propGrp = m_properties->addPropertyGroup( "ROI Box", "Properties of this ROI Box" );
00053     m_minPos = m_propGrp->addProperty( "Min Position", "When a box is described by its diagonal, this is the lower, left, front corner of it.",
00054                                           minPos, boost::bind( &WROIBox::boxPropertiesChanged, this, _1 ) );
00055     m_maxPos = m_propGrp->addProperty( "Max Position", "When a box is described by its diagonal, this is the upper, right, back corner of it.",
00056                                           maxPos, boost::bind( &WROIBox::boxPropertiesChanged, this, _1 ) );
00057 
00058     boost::shared_ptr< WGraphicsEngine > ge = WGraphicsEngine::getGraphicsEngine();
00059     assert( ge );
00060     boost::shared_ptr< WGEViewer > viewer = ge->getViewerByName( "Main View" );
00061     assert( viewer );
00062     m_viewer = viewer;
00063     m_pickHandler = m_viewer->getPickHandler();
00064     m_pickHandler->getPickSignal()->connect( boost::bind( &WROIBox::registerRedrawRequest, this, _1 ) );
00065 
00066     std::stringstream ss;
00067     ss << "ROIBox" << boxId;
00068     setName( ss.str() );
00069 
00070     osg::StateSet* state = getOrCreateStateSet();
00071     state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
00072 
00073     osg::LineWidth* linewidth = new osg::LineWidth();
00074     linewidth->setWidth( 2.0f );
00075     state->setAttributeAndModes( linewidth, osg::StateAttribute::ON );
00076 
00077     osg::ref_ptr< osg::LightModel > lightModel = new osg::LightModel();
00078     lightModel->setTwoSided( true );
00079     //state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
00080     state->setMode( GL_BLEND, osg::StateAttribute::ON );
00081 
00082     // add a simple default lighting shader
00083     m_lightShader = new WGEShader( "WGELighting" );
00084 
00085     m_not->set( false );
00086 
00087     assert( WGraphicsEngine::getGraphicsEngine() );
00088     WGraphicsEngine::getGraphicsEngine()->getScene()->addChild( this );
00089 
00090     setUserData( this );
00091     setUpdateCallback( osg::ref_ptr<ROIBoxNodeCallback>( new ROIBoxNodeCallback ) );
00092 
00093     m_lightShader->apply( this );
00094 
00095     m_needVertexUpdate = true;
00096     setDirty();
00097 }
00098 
00099 WROIBox::~WROIBox()
00100 {
00101 }
00102 
00103 WPosition WROIBox::getMinPos() const
00104 {
00105     return m_minPos->get();
00106 }
00107 
00108 WPosition WROIBox::getMaxPos() const
00109 {
00110     return m_maxPos->get();
00111 }
00112 
00113 WPropPosition WROIBox::getMinPosProperty()
00114 {
00115     return m_minPos;
00116 }
00117 
00118 WPropPosition WROIBox::getMaxPosProperty()
00119 {
00120     return m_maxPos;
00121 }
00122 
00123 void WROIBox::registerRedrawRequest( WPickInfo pickInfo )
00124 {
00125     boost::unique_lock< boost::shared_mutex > lock;
00126     lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
00127 
00128     m_pickInfo = pickInfo;
00129 
00130     lock.unlock();
00131 }
00132 
00133 void WROIBox::boxPropertiesChanged( boost::shared_ptr< WPropertyBase > /* property */ )
00134 {
00135     m_needVertexUpdate = true;
00136 }
00137 
00138 void WROIBox::updateGFX()
00139 {
00140     boost::unique_lock< boost::shared_mutex > lock;
00141     lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
00142 
00143     std::stringstream ss;
00144     ss << "ROIBox" << boxId << "";
00145     if( m_pickInfo.getName() == ss.str() )
00146     {
00147         WVector2d newPixelPos( m_pickInfo.getPickPixel() );
00148         if( m_isPicked )
00149         {
00150             osg::Vec3 in( newPixelPos.x(), newPixelPos.y(), 0.0 );
00151             osg::Vec3 world = wge::unprojectFromScreen( in, m_viewer->getCamera() );
00152 
00153             // we want the vector pointing into the screen in world coordinates
00154             // NOTE: set w = 0 to use it as vector and ignore translation
00155             osg::Vec4 toDepth = wge::unprojectFromScreen( osg::Vec4( 0.0, 0.0, 1.0, 0.0 ), m_viewer->getCamera() );
00156             toDepth.normalize();
00157             WPosition toDepthWorld( toDepth[0], toDepth[1], toDepth[2] );
00158 
00159             float depthMove = m_pickInfo.getScrollWheel() - m_oldScrollWheel;
00160 
00161             WPosition newPixelWorldPos( world[0], world[1], world[2] );
00162             WPosition oldPixelWorldPos;
00163             if(  m_oldPixelPosition.x() == 0 && m_oldPixelPosition.y() == 0 )
00164             {
00165                 oldPixelWorldPos = newPixelWorldPos;
00166             }
00167             else
00168             {
00169                 osg::Vec3 in( m_oldPixelPosition.x(), m_oldPixelPosition.y(), 0.0 );
00170                 osg::Vec3 world = wge::unprojectFromScreen( in, m_viewer->getCamera() );
00171                 oldPixelWorldPos = WPosition( world[0], world[1], world[2] );
00172             }
00173 
00174             WVector3d moveVec = newPixelWorldPos - oldPixelWorldPos;
00175 
00176             // resize Box
00177             if( m_pickInfo.getModifierKey() == WPickInfo::SHIFT )
00178             {
00179                 if( m_pickNormal[0] <= 0 && m_pickNormal[1] <= 0 && m_pickNormal[2] <= 0 )
00180                 {
00181                     m_maxPos->set( m_maxPos->get() + ( m_pickNormal * dot( moveVec, m_pickNormal ) ) );
00182                 }
00183                 if( m_pickNormal[0] >= 0 && m_pickNormal[1] >= 0 && m_pickNormal[2] >= 0 )
00184                 {
00185                     m_minPos->set( m_minPos->get() + ( m_pickNormal * dot( moveVec, m_pickNormal ) ) );
00186                 }
00187                 // NOTE: this sets m_needVertexUpdate
00188             }
00189 
00190             // move Box
00191             if( m_pickInfo.getModifierKey() == WPickInfo::NONE )
00192             {
00193                 m_minPos->set( m_minPos->get() + moveVec + ( 2.0 * toDepthWorld * depthMove ) );
00194                 m_maxPos->set( m_maxPos->get() + moveVec + ( 2.0 * toDepthWorld * depthMove ) );
00195                 // NOTE: this sets m_needVertexUpdate
00196             }
00197         }
00198         else
00199         {
00200             m_pickNormal = m_pickInfo.getPickNormal();
00201             // color for moving box
00202             if( m_pickInfo.getModifierKey() == WPickInfo::NONE )
00203             {
00204                 if( m_not->get() )
00205                 {
00206                     updateColor( m_notColor );
00207                 }
00208                 else
00209                 {
00210                     updateColor( m_color );
00211                 }
00212             }
00213             if( m_pickInfo.getModifierKey() == WPickInfo::SHIFT )
00214             {
00215                 updateColor( osg::Vec4( 0.0f, 1.0f, 0.0f, 0.4f ) );
00216             }
00217 
00218             m_oldScrollWheel = m_pickInfo.getScrollWheel();
00219         }
00220         m_oldPixelPosition = newPixelPos;
00221         setDirty();
00222         m_isPicked = true;
00223         m_oldScrollWheel = m_pickInfo.getScrollWheel();
00224     }
00225     if( m_isPicked && m_pickInfo.getName() == "unpick" )
00226     {
00227         // Perform all actions necessary for finishing a pick
00228         if( m_not->get() )
00229         {
00230             updateColor( m_notColor );
00231         }
00232         else
00233         {
00234             updateColor( m_color );
00235         }
00236 
00237         m_pickNormal = WVector3d();
00238         m_isPicked = false;
00239     }
00240 
00241     if( m_needVertexUpdate )
00242     {
00243         removeDrawable( m_surfaceGeometry );
00244 
00245         WPosition pos = getMinPos();
00246         WPosition size = getMaxPos() - getMinPos();
00247 
00248         // create a new geometry
00249         m_surfaceGeometry = wge::createCube( pos, size, WColor( 1.0, 1.0, 1.0, 1.0 ) );
00250 
00251         // create nice outline
00252         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 0, 4 ) );
00253         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 4, 4 ) );
00254         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 8, 4 ) );
00255         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 12, 4 ) );
00256         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 16, 4 ) );
00257         m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 20, 4 ) );
00258 
00259         // name it and add to geode
00260         m_surfaceGeometry->setDataVariance( osg::Object::DYNAMIC );
00261         m_surfaceGeometry->setName( ss.str() );
00262 
00263         addDrawable( m_surfaceGeometry );
00264 
00265         // NOTE: as we set the roi dirty, we ensure the color gets set properly in the next if-statement.
00266         setDirty();
00267         m_needVertexUpdate = false;
00268     }
00269 
00270     if( m_dirty->get() )
00271     {
00272         if( m_not->get() )
00273         {
00274             updateColor( m_notColor );
00275         }
00276         else
00277         {
00278             updateColor( m_color );
00279         }
00280     }
00281 
00282     lock.unlock();
00283 }
00284 
00285 void WROIBox::setColor( osg::Vec4 color )
00286 {
00287     m_color = color;
00288 }
00289 
00290 void WROIBox::setNotColor( osg::Vec4 color )
00291 {
00292     m_notColor = color;
00293 }
00294 
00295 void WROIBox::updateColor( osg::Vec4 color )
00296 {
00297     osg::ref_ptr<osg::Vec4Array> colors = osg::ref_ptr<osg::Vec4Array>( new osg::Vec4Array );
00298     colors->push_back( color );
00299 
00300     WColor outline( 0.0, 0.0, 0.0, 1.0 );
00301     // NOTE: also add a black color for the solid outlines
00302     colors->push_back( outline );
00303     colors->push_back( outline );
00304     colors->push_back( outline );
00305     colors->push_back( outline );
00306     colors->push_back( outline );
00307     colors->push_back( outline );
00308     m_surfaceGeometry->setColorArray( colors );
00309     m_surfaceGeometry->setColorBinding( osg::Geometry::BIND_PER_PRIMITIVE_SET );
00310 }