Developer Documentation
RulerPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 #include "RulerPlugin.hh"
43 
45 #include <OpenFlipper/BasePlugin/WhatsThisGenerator.hh>
47 
48 //------------------------------------------------------------------------------
49 RulerPlugin::RulerPlugin()
50 :
51 buttonAction_(0),
52 pickModeName_("MeasureDistance"),
53 lineDrag_(-1),
54 dblClickCheck_(false),
55 optionsWidget_(0),
56 textSizeSettingName_(name()+QString("/TextSize"))
57 {
58 
59 }
60 
61 //------------------------------------------------------------------------------
62 RulerPlugin::~RulerPlugin()
63 {
64  reset();
65 }
66 //------------------------------------------------------------------------------
67 void RulerPlugin::initializePlugin()
68 {
69  QToolBar *button = new QToolBar("Ruler");
70 
71  buttonAction_ = new QAction(tr("<B>Ruler</B><br> Display the distance between two points."),this);
72 
73  button->addAction(buttonAction_);
74  buttonAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"ruler.png"));
75  buttonAction_->setCheckable(true);
76  WhatsThisGenerator whatsThisGen("Ruler");
77  whatsThisGen.setWhatsThis(buttonAction_,tr("Measures the distance between two points.<br><b>LeftClick</b>: define/change the position.<br><b>DoubleClick</b>: reset the ruler.<br>"));
78 
79  buttonAction_->setChecked(false);
80 
81  connect(buttonAction_,SIGNAL(triggered()), this , SLOT(slotChangePickMode()) );
82  emit addToolbar(button);
83 }
84 
85 //------------------------------------------------------------------------------
86 void RulerPlugin::pluginsInitialized()
87 {
88  emit addPickMode(pickModeName_);
89 }
90 
91 //------------------------------------------------------------------------------
92 void RulerPlugin::slotMouseEvent(QMouseEvent* _event)
93 {
94  if ( PluginFunctions::pickMode() != pickModeName_)
95  return;
96 
98 //set one of the points, depending on the hit state (first, second or modifying)
99  if (_event->type() == QEvent::MouseButtonRelease )
100  {
101  size_t node_idx, target_idx;
102  OpenMesh::Vec3d hitPoint;
103 
104  // Get picked object's identifier by picking in scenegraph
105  if ( PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING ,_event->pos(), node_idx, target_idx, &hitPoint) && !dblClickCheck_)
106  {
107  if (!currentRuler_)
108  {
109  //create a new Ruler
110  BaseObjectData* object;
111  if ( PluginFunctions::getPickedObject(node_idx, object) )
112  {
113  currentRuler_.reset(new Ruler(object,name(),0));
114  connect(currentRuler_.get(),SIGNAL(updateView()),this,SIGNAL(updateView()));
115  unsigned textSize = OpenFlipperSettings().value(textSizeSettingName_,16).toUInt();
116  currentRuler_->setTextSize(textSize);
117  currentRuler_->setPoints(hitPoint,hitPoint);
118  enableDragMode(1);
119  }
120 
121  }
122  else
123  {
124  //Ruler was created -> change position of a point
125  if (!dragModeActive())
126  {
127  //dragmode is disabled -> update position of nearest point
128  float distToStart = (currentRuler_->points()[0] - hitPoint).length();
129  float distToEnd = (currentRuler_->points()[1] - hitPoint).length();
130  if (distToStart < distToEnd)
131  currentRuler_->setStartPoint(hitPoint);
132  else
133  currentRuler_->setEndPoint(hitPoint);
134  }
135  else
136  {
137  //second: drag mode is enabled so we can easily update the position
138  if (lineDrag_ == 0)
139  currentRuler_->setStartPoint(hitPoint);
140  else
141  currentRuler_->setEndPoint(hitPoint);
142  disableDragMode();
143  }
144  }
145  }
146  else // if nothing was picked
147  {
148  reset();
149  }
150  }
151 
153  else if (_event->type() == QEvent::MouseButtonPress)
154  {//enable drag mode
155 
156  if (currentRuler_)
157  {
158  //decides which point is the nearest one, so
159  //it can be dragged
160  size_t node_idx, target_idx;
161  OpenMesh::Vec3d hitPoint;
162 
163  // Get picked object's identifier by picking in scenegraph
164  if ( PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING ,_event->pos(), node_idx, target_idx, &hitPoint) )
165  {
166  float distToStart = (currentRuler_->points()[0] - hitPoint).length();
167  float distToEnd = (currentRuler_->points()[1] - hitPoint).length();
168  enableDragMode( (distToStart < distToEnd)? 0 : 1);
169  }
170  }
171  }
173  else if (_event->type() == QEvent::MouseMove && dragModeActive())
174  {//mouse moved and drag mode is enabled
175 
176  size_t node_idx, target_idx;
177  OpenMesh::Vec3d hitPoint;
178  ACG::Vec3d hitPoints[2];
179  std::copy(currentRuler_->points(),currentRuler_->points()+2,hitPoints);
180 
181  // Get picked object's identifier by picking in scenegraph
182  if ( !PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING ,_event->pos(), node_idx, target_idx, &hitPoint) )
183  {
184  //if mouse is not over an object, get the unprojected coordinates and the last z-value
185  QPoint position = _event->pos();
186  ACG::Vec3d viewCoords = ACG::Vec3d(position.x(), PluginFunctions::viewerProperties().glState().context_height() - position.y(), 0.5);
187  hitPoint = PluginFunctions::viewerProperties().glState().unproject(viewCoords);
188  hitPoints[lineDrag_] = ACG::Vec3d(hitPoint.data()[0], hitPoint.data()[1], hitPoints[lineDrag_].data()[2] );
189  }
190  else
191  hitPoints[lineDrag_] = hitPoint;
192 
193  currentRuler_->setPoints(hitPoints[0],hitPoints[1]);
194  }
195 
197  else if (_event->type() == QEvent::MouseButtonDblClick)
198  {//reset
199  reset();
200  dblClickCheck_ = true;
201  }
202  if (dblClickCheck_ && _event->type() == QEvent::MouseButtonRelease)
203  dblClickCheck_ = false;
204 }
205 
206 //------------------------------------------------------------------------------
207 void RulerPlugin::reset()
208 {
209  currentRuler_.reset();
210  lineDrag_ = -1;
211 }
212 //------------------------------------------------------------------------------
213 void RulerPlugin::enableDragMode(const int _point)
214 {
215  lineDrag_ = _point;
216  emit setPickModeMouseTracking(pickModeName_,true);
217 }
218 
219 //------------------------------------------------------------------------------
220 void RulerPlugin::disableDragMode()
221 {
222  lineDrag_ = -1;
223  emit setPickModeMouseTracking(pickModeName_,false);
224 }
225 
226 //------------------------------------------------------------------------------
227 void RulerPlugin::slotChangePickMode()
228 {
229  PluginFunctions::actionMode( Viewer::PickingMode );
230  PluginFunctions::pickMode(pickModeName_);
231 
232 }
233 
234 //------------------------------------------------------------------------------
235 void RulerPlugin::slotPickModeChanged(const std::string& _mode)
236 {
237  buttonAction_->setChecked(_mode == pickModeName_);
238 }
239 
240 //------------------------------------------------------------------------------
241 void RulerPlugin::slotAllCleared()
242 {
243  disableDragMode();
244 }
245 
246 void RulerPlugin::objectDeleted(int _id)
247 {
248  if (!currentRuler_)
249  return;
250 
251  disableDragMode();
252  if (_id == currentRuler_->getBaseObj()->id())
253  {
254  disconnect(currentRuler_.get(),SIGNAL(updateView()),this,SIGNAL(updateView()));
255  currentRuler_.reset();
256  }
257 }
258 //------------------------------------------------------------------------------
260 {
261  if (!optionsWidget_)
262  {
263  optionsWidget_ = new RulerOptions();
264  }
265 
266  unsigned textSize = OpenFlipperSettings().value(textSizeSettingName_,16).toUInt();
267  optionsWidget_->textSizeSpinBox->setValue(textSize);
268  _widget = optionsWidget_;
269  return true;
270 }
271 //------------------------------------------------------------------------------
272 void RulerPlugin::applyOptions()
273 {
274  int textSize = optionsWidget_->textSizeSpinBox->value();
275  if (currentRuler_)
276  currentRuler_->setTextSize(textSize);
277  OpenFlipperSettings().setValue(textSizeSettingName_,textSize);
278 }
279 //------------------------------------------------------------------------------
280 void RulerPlugin::slotViewChanged()
281 {
282 
283  if (!currentRuler_)
284  return;
285 
286  //compute line direction
287  ACG::Vec3d lineVector = currentRuler_->points()[0] - currentRuler_->points()[1];
289 
290  float cosAngleLineRight = lineVector.normalize() | rightVec;
291  float cosAngleUpLine = PluginFunctions::upVector().normalized() | lineVector.normalized() ;
292 
293 
294  rightVec *= -0.5f*currentRuler_->textScale();
295  ACG::Vec3d updownVec = PluginFunctions::upVector()*currentRuler_->textScale();
296 
297  //compute up/down offset
298  if (cosAngleLineRight > 0.f)
299  {
300  updownVec *= (cosAngleUpLine < 0.f) ? -2.f : 0.5f;
301  }
302  else
303  {
304  updownVec *= (cosAngleUpLine < 0.f) ? 0.5f : -2.0f;
305  }
306 
307  // small offset to the right and big offset up/down depending on the line
308  currentRuler_->setTextOffset(rightVec+updownVec);
309 
310 
311 }
312 
313 
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
void viewingDirection(const ACG::Vec3d &_dir, const ACG::Vec3d &_up, int _viewer)
Set the viewing direction.
ACG::Vec3d upVector(int _viewer)
Get the current up vector.
auto normalized() const -> decltype(*this/std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:445
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:200
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:651
Viewer::ActionMode actionMode()
Get the current Action mode.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
Definition: Ruler.hh:52
const std::string pickMode()
Get the current Picking mode.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
int context_height() const
get gl context height
Definition: GLState.hh:830
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
bool getPickedObject(const size_t _node_idx, BaseObjectData *&_object)
Get the picked mesh.
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:434
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
bool initializeOptionsWidget(QWidget *&_widget)
Initialize the Options Widget.
Definition: RulerPlugin.cc:259
ACG::GLState & glState()
Get the glState of the Viewer.