OpenWalnut  1.4.0
WROIBox.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 <string>
27 #include <utility>
28 
29 #include <osg/LineWidth>
30 #include <osg/LightModel>
31 #include <osg/Geometry>
32 
33 #include "../common/WLogger.h"
34 #include "shaders/WGEShader.h"
35 
36 #include "WROIBox.h"
37 #include "WGraphicsEngine.h"
38 #include "WGEUtils.h"
39 #include "WGEGeodeUtils.h"
40 
41 size_t WROIBox::maxBoxId = 0;
42 
44  WROI(),
45  boxId( maxBoxId++ ),
46  m_pickNormal( WVector3d() ),
47  m_oldPixelPosition( WVector2d::zero() ),
48  m_oldScrollWheel( 0 ),
49  m_color( osg::Vec4( 0.391f, 0.594f, 0.828f, 0.5f ) ),
50  m_notColor( osg::Vec4( 0.828f, 0.391f, 0.391f, 0.5f ) )
51 {
52  m_propGrp = m_properties->addPropertyGroup( "ROI Box", "Properties of this ROI Box" );
53  m_minPos = m_propGrp->addProperty( "Min Position", "When a box is described by its diagonal, this is the lower, left, front corner of it.",
54  minPos, boost::bind( &WROIBox::boxPropertiesChanged, this, _1 ) );
55  m_maxPos = m_propGrp->addProperty( "Max Position", "When a box is described by its diagonal, this is the upper, right, back corner of it.",
56  maxPos, boost::bind( &WROIBox::boxPropertiesChanged, this, _1 ) );
57 
58  boost::shared_ptr< WGraphicsEngine > ge = WGraphicsEngine::getGraphicsEngine();
59  assert( ge );
60  boost::shared_ptr< WGEViewer > viewer = ge->getViewerByName( "Main View" );
61  assert( viewer );
62  m_viewer = viewer;
63  m_pickHandler = m_viewer->getPickHandler();
64  m_pickHandler->getPickSignal()->connect( boost::bind( &WROIBox::registerRedrawRequest, this, _1 ) );
65 
66  std::stringstream ss;
67  ss << "ROIBox" << boxId;
68  setName( ss.str() );
69 
70  osg::StateSet* state = getOrCreateStateSet();
71  state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
72 
73  osg::LineWidth* linewidth = new osg::LineWidth();
74  linewidth->setWidth( 2.0f );
75  state->setAttributeAndModes( linewidth, osg::StateAttribute::ON );
76 
77  osg::ref_ptr< osg::LightModel > lightModel = new osg::LightModel();
78  lightModel->setTwoSided( true );
79  //state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
80  state->setMode( GL_BLEND, osg::StateAttribute::ON );
81 
82  // add a simple default lighting shader
83  m_lightShader = new WGEShader( "WGELighting" );
84 
85  m_not->set( false );
86 
88  WGraphicsEngine::getGraphicsEngine()->getScene()->addChild( this );
89 
90  setUserData( this );
91  setUpdateCallback( osg::ref_ptr<ROIBoxNodeCallback>( new ROIBoxNodeCallback ) );
92 
93  m_lightShader->apply( this );
94 
95  m_needVertexUpdate = true;
96  setDirty();
97 }
98 
99 WROIBox::~WROIBox()
100 {
101 }
102 
104 {
105  return m_minPos->get();
106 }
107 
109 {
110  return m_maxPos->get();
111 }
112 
114 {
115  return m_minPos;
116 }
117 
119 {
120  return m_maxPos;
121 }
122 
124 {
125  boost::unique_lock< boost::shared_mutex > lock;
126  lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
127 
128  m_pickInfo = pickInfo;
129 
130  lock.unlock();
131 }
132 
133 void WROIBox::boxPropertiesChanged( boost::shared_ptr< WPropertyBase > /* property */ )
134 {
135  m_needVertexUpdate = true;
136 }
137 
139 {
140  boost::unique_lock< boost::shared_mutex > lock;
141  lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
142 
143  std::stringstream ss;
144  ss << "ROIBox" << boxId << "";
145  if( m_pickInfo.getName() == ss.str() )
146  {
147  WVector2d newPixelPos( m_pickInfo.getPickPixel() );
148  if( m_isPicked )
149  {
150  osg::Vec3 in( newPixelPos.x(), newPixelPos.y(), 0.0 );
151  osg::Vec3 world = wge::unprojectFromScreen( in, m_viewer->getCamera() );
152 
153  // we want the vector pointing into the screen in world coordinates
154  // NOTE: set w = 0 to use it as vector and ignore translation
155  osg::Vec4 toDepth = wge::unprojectFromScreen( osg::Vec4( 0.0, 0.0, 1.0, 0.0 ), m_viewer->getCamera() );
156  toDepth.normalize();
157  WPosition toDepthWorld( toDepth[0], toDepth[1], toDepth[2] );
158 
159  float depthMove = m_pickInfo.getScrollWheel() - m_oldScrollWheel;
160 
161  WPosition newPixelWorldPos( world[0], world[1], world[2] );
162  WPosition oldPixelWorldPos;
163  if( m_oldPixelPosition.x() == 0 && m_oldPixelPosition.y() == 0 )
164  {
165  oldPixelWorldPos = newPixelWorldPos;
166  }
167  else
168  {
169  osg::Vec3 in( m_oldPixelPosition.x(), m_oldPixelPosition.y(), 0.0 );
170  osg::Vec3 world = wge::unprojectFromScreen( in, m_viewer->getCamera() );
171  oldPixelWorldPos = WPosition( world[0], world[1], world[2] );
172  }
173 
174  WVector3d moveVec = newPixelWorldPos - oldPixelWorldPos;
175 
176  // resize Box
177  if( m_pickInfo.getModifierKey() == WPickInfo::SHIFT )
178  {
179  if( m_pickNormal[0] <= 0 && m_pickNormal[1] <= 0 && m_pickNormal[2] <= 0 )
180  {
181  m_maxPos->set( m_maxPos->get() + ( m_pickNormal * dot( moveVec, m_pickNormal ) ) );
182  }
183  if( m_pickNormal[0] >= 0 && m_pickNormal[1] >= 0 && m_pickNormal[2] >= 0 )
184  {
185  m_minPos->set( m_minPos->get() + ( m_pickNormal * dot( moveVec, m_pickNormal ) ) );
186  }
187  // NOTE: this sets m_needVertexUpdate
188  }
189 
190  // move Box
191  if( m_pickInfo.getModifierKey() == WPickInfo::NONE )
192  {
193  m_minPos->set( m_minPos->get() + moveVec + ( 2.0 * toDepthWorld * depthMove ) );
194  m_maxPos->set( m_maxPos->get() + moveVec + ( 2.0 * toDepthWorld * depthMove ) );
195  // NOTE: this sets m_needVertexUpdate
196  }
197  }
198  else
199  {
201  // color for moving box
202  if( m_pickInfo.getModifierKey() == WPickInfo::NONE )
203  {
204  if( m_not->get() )
205  {
207  }
208  else
209  {
210  updateColor( m_color );
211  }
212  }
213  if( m_pickInfo.getModifierKey() == WPickInfo::SHIFT )
214  {
215  updateColor( osg::Vec4( 0.0f, 1.0f, 0.0f, 0.4f ) );
216  }
217 
219  }
220  m_oldPixelPosition = newPixelPos;
221  setDirty();
222  m_isPicked = true;
224  }
225  if( m_isPicked && m_pickInfo.getName() == "unpick" )
226  {
227  // Perform all actions necessary for finishing a pick
228  if( m_not->get() )
229  {
231  }
232  else
233  {
234  updateColor( m_color );
235  }
236 
238  m_isPicked = false;
239  }
240 
241  if( m_needVertexUpdate )
242  {
243  removeDrawable( m_surfaceGeometry );
244 
245  WPosition pos = getMinPos();
246  WPosition size = getMaxPos() - getMinPos();
247 
248  // create a new geometry
249  m_surfaceGeometry = wge::createCube( pos, size, WColor( 1.0, 1.0, 1.0, 1.0 ) );
250 
251  // create nice outline
252  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 0, 4 ) );
253  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 4, 4 ) );
254  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 8, 4 ) );
255  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 12, 4 ) );
256  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 16, 4 ) );
257  m_surfaceGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 20, 4 ) );
258 
259  // name it and add to geode
260  m_surfaceGeometry->setDataVariance( osg::Object::DYNAMIC );
261  m_surfaceGeometry->setName( ss.str() );
262 
263  addDrawable( m_surfaceGeometry );
264 
265  // NOTE: as we set the roi dirty, we ensure the color gets set properly in the next if-statement.
266  setDirty();
267  m_needVertexUpdate = false;
268  }
269 
270  if( m_dirty->get() )
271  {
272  if( m_not->get() )
273  {
275  }
276  else
277  {
278  updateColor( m_color );
279  }
280  }
281 
282  lock.unlock();
283 }
284 
285 void WROIBox::setColor( osg::Vec4 color )
286 {
287  m_color = color;
288 }
289 
290 void WROIBox::setNotColor( osg::Vec4 color )
291 {
292  m_notColor = color;
293 }
294 
295 void WROIBox::updateColor( osg::Vec4 color )
296 {
297  osg::ref_ptr<osg::Vec4Array> colors = osg::ref_ptr<osg::Vec4Array>( new osg::Vec4Array );
298  colors->push_back( color );
299 
300  WColor outline( 0.0, 0.0, 0.0, 1.0 );
301  // NOTE: also add a black color for the solid outlines
302  colors->push_back( outline );
303  colors->push_back( outline );
304  colors->push_back( outline );
305  colors->push_back( outline );
306  colors->push_back( outline );
307  colors->push_back( outline );
308  m_surfaceGeometry->setColorArray( colors );
309  m_surfaceGeometry->setColorBinding( osg::Geometry::BIND_PER_PRIMITIVE_SET );
310 }