Developer Documentation
PolyLinePlugin.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 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 //== INCLUDES =================================================================
52 
53 
54 #include "PolyLinePlugin.hh"
55 
56 #include <ACG/Scenegraph/ManipulatorNode.hh>
57 
58 #if QT_VERSION >= 0x050000
59 #else
60 #include <QtGui>
61 #endif
62 
63 namespace {
64 
65 class GlutPrimitiveNode : public ACG::SceneGraph::GlutPrimitiveNode {
66 
67  public:
68 
69  GlutPrimitiveNode(PolyLineObject* L, std::string name, int _index = -1)
70  : ACG::SceneGraph::GlutPrimitiveNode(ACG::SceneGraph::GlutPrimitiveNode::SPHERE, L->manipulatorNode(), name)
71  {
72  index = _index;
73  line = L;
74  }
75 
76  public:
77 
78  PolyLineObject* line;
79  int index;
80 
81 };
82 
83 class GlutLineNode : public ACG::SceneGraph::LineNode {
84 
85  public:
86 
87  GlutLineNode(PolyLineObject* L, std::string name)
88  : ACG::SceneGraph::LineNode(LineSegmentsMode, L->manipulatorNode(), name)
89  {
90  line = L;
91  }
92 
93  public:
94  PolyLineObject* line;
95 
96 };
97 
98 }
99 
100 
101 //== IMPLEMENTATION ==========================================================
102 
105  tool_(0),
106  polyLineAction_(0),
107  toolBarActions_(0),
108  toolbar_(0),
109  pickToolbar_(0),
110  pickToolBarActions_(0),
111  insertAction_(0),
112  insertCircleAction_(0),
113  insertSplineAction_(0),
114  deleteAction_(0),
115  moveAction_(0),
116  smartMoveAction_(0),
117  mergeAction_(0),
118  splitAction_(0),
119  cutAction_(0),
120  cutMultipleAction_(0),
121  cur_insert_id_(-1),
122  cur_polyline_obj_(0),
123  cur_move_id_(-1),
124  move_point_ref_(0),
125  create_point_ref_(0),
126  createCircle_CurrSelIndex_(-1),
127  createCircle_LastSelIndex_(-1),
128  moveCircle_SelNode_(0),
129  moveCircle_IsLocked(false),
130  moveCircle_IsFloating(false),
131  copyPaste_Action_(0),
132  copyPaste_ObjectId_(-1),
133  copyPaste_ActionType_(-1),
134  copyPaste_NewObjectId_(-1),
135  createSpline_CurrSelIndex_(-1),
136  createSpline_LastSelIndex_(-1),
137  moveBezSpline_SelNode_(0),
138  moveBezSpline_SelIndex_(-1),
139  moveBezSpline_SelSubIndex_(0),
140  cur_merge_id_(-1),
141  smart_move_timer_(0),
142  cur_smart_move_obj_(0),
143  planeSelect_(0)
144 {
145 }
146 
147 
148 void
149 PolyLinePlugin::
150 initializePlugin()
151 {
152  // Initialize the Toolbox
154  QSize size(100, 100);
155  tool_->resize(size);
156  tool_->setObjectName("PolyLineToolbar");
157 
158  // connect signals->slots
159  connect(tool_->pb_subdivide,SIGNAL(clicked() ),this,SLOT(slot_subdivide()));
160  connect(tool_->subdivide_relative,SIGNAL(toggled(bool) ),this,SLOT(slot_subdivide_percent(bool)));
161  connect(tool_->pb_decimate,SIGNAL(clicked() ),this,SLOT(slot_decimate()));
162  connect(tool_->decimate_relative,SIGNAL(toggled(bool) ),this,SLOT(slot_decimate_percent(bool)));
163 #ifdef EXTENDED_POLY_LINE
164  connect(tool_->pb_resample_on_edges,SIGNAL(clicked() ),this,SLOT(slot_resample_on_edges()));
165 #else
166  tool_->pb_resample_on_edges->setDisabled(true);
167 #endif
168  connect(tool_->pb_smooth,SIGNAL(clicked() ),this,SLOT(slot_smooth()));
169  connect(tool_->pb_smooth,SIGNAL(clicked() ),this,SIGNAL(updateView()));
170  connect(tool_->pb_project,SIGNAL(clicked() ),this,SLOT(slot_project()));
171  connect(tool_->pb_project,SIGNAL(clicked() ),this,SIGNAL(updateView()));
172  connect(tool_->pb_smooth_project,SIGNAL(clicked() ),this,SLOT(slot_smooth_project()));
173  connect(tool_->pb_smooth_project,SIGNAL(clicked() ),this,SIGNAL(updateView()));
174 
175  connect(tool_->rb_insert, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
176  connect(tool_->rb_InsertCircle, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
177  connect(tool_->rb_InsertSpline, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
178  connect(tool_->rb_delete, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
179  connect(tool_->rb_move, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
180  connect(tool_->rb_smart_move, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
181  connect(tool_->rb_merge, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
182  connect(tool_->rb_split, SIGNAL( clicked() ), this, SLOT( slotEditModeChanged() ));
183 
184  connect(tool_->sb_CirclePointNum, SIGNAL(valueChanged(int)), this, SLOT(slot_setCirclePointNum(int)));
185  connect(tool_->sb_SplineSegNum, SIGNAL(valueChanged(int)), this, SLOT(slot_setSplinePointNum(int)));
186  //add icons
187  tool_->rb_insert->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_insert.png") );
188  tool_->rb_InsertCircle->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_circle.png") );
189  tool_->rb_InsertSpline->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_bezier.png") );
190  tool_->rb_delete->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_delete.png") );
191  tool_->rb_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_move.png") );
192  tool_->rb_smart_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_move.png") );
193  tool_->rb_merge->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_merge.png") );
194  tool_->rb_split->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_split.png") );
195 // tool_->rb_smooth_c0->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_insert.svg") );
196 // tool_->rb_smooth_c1->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_c1.svg") );
197 // tool_->rb_smooth_c2->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "polyline_c2.svg") );
198 
199 
200  // Add the toolbox with the given icon
201  QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cut_polyline.png");
202  emit addToolbox( tr("PolyLine") , tool_, toolIcon );
203 }
204 
205 
206 //-----------------------------------------------------------------------------
207 
208 
209 void
210 PolyLinePlugin::
211 slotMouseEvent( QMouseEvent* _event )
212 {
213  copyPaste_LastMouse = _event->pos();
214 
215  // control modifier is reserved for selcting target
216  if (_event->modifiers() & (Qt::ControlModifier))
217  return;
218 
219  if (PluginFunctions::pickMode() == ("PolyLine") && PluginFunctions::actionMode() == Viewer::PickingMode
220  && _event->button() != Qt::RightButton) {
221  // handle mouse events depending on current mode
222  switch (mode()) {
223  case PL_INSERT:
224  me_insert(_event);
225  break;
226 
227  case PL_INSERTCIRCLE:
228  me_insertCircle(_event);
229  break;
230 
231  case PL_INSERTSPLINE:
232  me_insertSpline(_event);
233  break;
234 
235  case PL_DELETE:
236  me_delete(_event);
237  break;
238 
239  case PL_MOVE:
240  me_move(_event);
241  break;
242 
243  case PL_SPLIT:
244  me_split(_event);
245  break;
246 
247  case PL_MERGE:
248  me_merge(_event);
249  break;
250 
251  case PL_SMART_MOVE:
252  me_smart_move(_event);
253  break;
254 
255  case PL_COPY_PASTE:
256  me_copyPasteMouse(_event);
257  break;
258 
259  default:
260  break;
261  }
262  } else if ( (PluginFunctions::pickMode() == CREATE_CUT_POLYLINE) || (PluginFunctions::pickMode() == CREATE_CUT_POLYLINES) ) {
263  planeSelect_->slotMouseEvent(_event);
264  }
265 }
266 
267 void PolyLinePlugin::slotKeyEvent(QKeyEvent* event) {
268  switch (event->key()) {
269  case Qt::Key_Return:
270  if (PluginFunctions::pickMode() == ("PolyLine") && PluginFunctions::actionMode() == Viewer::PickingMode) {
271  if(mode() == PL_INSERT && cur_polyline_obj_ && cur_insert_id_ != -1) {
272  cur_polyline_obj_->line()->delete_point(cur_polyline_obj_->line()->n_vertices() - 1);
273 
274  if (event->modifiers() & (Qt::ShiftModifier))
275  cur_polyline_obj_->line()->set_closed(true);
276 
277  emit updatedObject(cur_insert_id_, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
278 
279  cur_insert_id_ = -1;
280  cur_polyline_obj_ = 0;
281  create_point_ref_ = 0;
282 
283  clearStatusMessage();
284  }
285  else if(mode() == PL_INSERTSPLINE) {
286  finishSpline();
287  }
288  }
289  break;
290  default:
291  break;
292  }
293 }
294 //-----------------------------------------------------------------------------
295 
296 void
297 PolyLinePlugin::
298 slotPickModeChanged( const std::string& _mode)
299 {
300  polyLineAction_->setChecked(_mode == "PolyLine");
301  cutAction_->setChecked( _mode == CREATE_CUT_POLYLINE );
302  cutMultipleAction_->setChecked( _mode == CREATE_CUT_POLYLINES );
303 }
304 
305 
306 //-----------------------------------------------------------------------------
307 
308 
309 void
310 PolyLinePlugin::
311 pluginsInitialized()
312 {
313  // Add the required Picking modes (Hidden, controlled only by the buttons)
314  emit addHiddenPickMode("PolyLine");
315  emit setPickModeMouseTracking("PolyLine", true);
316  emit addHiddenPickMode( CREATE_CUT_POLYLINE );
317  emit addHiddenPickMode( CREATE_CUT_POLYLINES );
318 
319  emit registerKey(Qt::Key_Return, Qt::NoModifier, tr("Terminate creation of poly line."), true);
320  emit registerKey(Qt::Key_Return, Qt::ShiftModifier, tr("Terminate creation of poly line and create loop."), true);
321 
322  // TOOLBAR
323  toolbar_ = new QToolBar(tr("PolyLine Editing"));
324  toolbar_->setObjectName("PolyLineEditingToolbar");
325 
326 
327  toolBarActions_ = new QActionGroup(toolbar_);
328 
329  // icon which enables the Modeling toolbar
330  polyLineAction_ = new QAction(tr("Edit PolyLines"), toolBarActions_);
331  polyLineAction_->setStatusTip(tr("Edit and create PolyLines."));
332  polyLineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_insert.png") );
333  polyLineAction_->setCheckable(true);
334  toolbar_->addAction(polyLineAction_);
335 
336  // icon for polyline cutting of objects
337  cutAction_ = new QAction(tr("&Create polyline at intersection with plane"), this);
338  cutAction_->setCheckable( true );
339  cutAction_->setStatusTip(tr("Create a polyline by specifying a plane with which the object is then intersected. The polyline will be created at the intersection."));
340  cutAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cut_polyline.png") );
341  connect(cutAction_, SIGNAL(triggered()), this, SLOT(slotScissorButton()) );
342  toolbar_->addAction(cutAction_);
343 
344  // icon for polyline cutting of objects
345  cutMultipleAction_ = new QAction(tr("&Create polylines at intersection with plane"), this);
346  cutMultipleAction_->setCheckable( true );
347  cutMultipleAction_->setStatusTip(tr("Create polylines by specifying a plane with which the object is then intersected. The polylines will be created at the intersection."));
348  cutMultipleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cut_polylines.png") );
349  connect(cutMultipleAction_, SIGNAL(triggered()), this, SLOT(slotScissorLinesButton()) );
350  toolbar_->addAction(cutMultipleAction_);
351 
352  connect(toolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotSetPolyLineMode(QAction*)) );
353 
354  emit addToolbar(toolbar_);
355 
356  // Pick Toolbar
357  pickToolbar_ = new QToolBar(tr("PolyLine Editing"));
358  pickToolbar_->setObjectName("PolyLine_Editing_Toolbar");
359  pickToolbar_->setAttribute(Qt::WA_AlwaysShowToolTips, true);
360  pickToolBarActions_ = new QActionGroup(pickToolbar_);
361  pickToolBarActions_->setExclusive (true);
362 
363  insertAction_ = new QAction(tr("Create PolyLine"), pickToolBarActions_);
364  insertAction_->setStatusTip(tr("Create a new PolyLine."));
365  insertAction_->setToolTip(tr("Create a new PolyLine.\n"
366  "Use <Doubleclick> to finish the line.\n"
367  "Hold <Shift> to close line on finish."));
368  insertAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_insert.png") );
369  insertAction_->setCheckable(true);
370  pickToolbar_->addAction(insertAction_);
371 
372  insertCircleAction_ = new QAction(tr("Create PolyCircle"), pickToolBarActions_);
373  insertCircleAction_->setStatusTip(tr("Create a new PolyCircle."));
374  insertCircleAction_->setToolTip(tr("Create a new PolyCircle.\n"
375  "<Click> to select the center.\n"
376  "Drag to specify the radius."));
377 
378  insertCircleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_circle.png") );
379  insertCircleAction_->setCheckable(true);
380  pickToolbar_->addAction(insertCircleAction_);
381 
382  insertSplineAction_ = new QAction(tr("Create PolySpline"), pickToolBarActions_);
383  insertSplineAction_->setStatusTip(tr("Create a new PolySpline."));
384  insertSplineAction_->setToolTip(tr("Create a new PolySpline.\n"
385  "<Click> to select the points."));
386 
387  insertSplineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_bezier.png") );
388  insertSplineAction_->setCheckable(true);
389  pickToolbar_->addAction(insertSplineAction_);
390 
391  deleteAction_ = new QAction(tr("Delete PolyLine"), pickToolBarActions_);
392  deleteAction_->setStatusTip(tr("Delete a complete PolyLine."));
393  deleteAction_->setToolTip(tr( "Delete a complete PolyLine.\n"
394  "<Click> on the lines you want to delete."));
395  deleteAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_delete.png") );
396  deleteAction_->setCheckable(true);
397  pickToolbar_->addAction(deleteAction_);
398 
399  smartMoveAction_ = new QAction(tr("Move PolyLine"), pickToolBarActions_);
400  smartMoveAction_->setStatusTip(tr("Move the PolyLine."));
401  smartMoveAction_->setToolTip(tr("Move the polyline."));
402  smartMoveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_move.png") );
403  smartMoveAction_->setCheckable(true);
404  pickToolbar_->addAction(smartMoveAction_);
405 
406  mergeAction_ = new QAction(tr("Merge PolyLines"), pickToolBarActions_);
407  mergeAction_->setStatusTip(tr("Merge two PolyLines."));
408  mergeAction_->setToolTip(tr("Merge two PolyLines.\n"
409  "Drag one endpoint of a PolyLine to the EndPoint of another one.\n"));
410  mergeAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_merge.png") );
411  mergeAction_->setCheckable(true);
412  pickToolbar_->addAction(mergeAction_);
413 
414  splitAction_ = new QAction(tr("Split a PolyLine"), pickToolBarActions_);
415  splitAction_->setStatusTip(tr("Split a PolyLine at a given point."));
416  splitAction_->setToolTip(tr("Split a PolyLine at a given point.\n"
417  "<Click> on the vertex where you want to split the PolyLine and drag it away."));
418  splitAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_split.png") );
419  splitAction_->setCheckable(true);
420  pickToolbar_->addAction(splitAction_);
421 
422  pickToolbar_->addSeparator ();
423 
424  moveAction_ = new QAction(tr("Move PolyLine Vertex"), pickToolBarActions_);
425  moveAction_->setStatusTip(tr("Move a Vertex of a PolyLine"));
426  moveAction_->setToolTip(tr("Move a single Vertex of a PolyLine."));
427  moveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"polyline_move.png") );
428  moveAction_->setCheckable(true);
429  pickToolbar_->addAction(moveAction_);
430 
431  emit setPickModeToolbar ("PolyLine", pickToolbar_);
432 
433  connect(pickToolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotPickToolbarAction(QAction*)) );
434 
435  // construct timer
436  smart_move_timer_ = new QTimer(this);
437  connect(smart_move_timer_, SIGNAL(timeout()), this, SLOT(slot_smart_move_timer()));
438 
439  // Instantiate plane select object
441  connect( planeSelect_, SIGNAL( signalTriggerCut( ) ), this, SLOT( slotTriggerCutPlaneSelect() ) );
442  connect( planeSelect_, SIGNAL( updateViewProxy( ) ), this, SIGNAL( updateView() ) );
443  connect( planeSelect_, SIGNAL( nodeVisChangedProxy(int) ), this, SIGNAL(nodeVisibilityChanged(int) ) );
444 
445  //create copy paste action in context menu
446  copyPaste_Action_ = new QAction("Duplicate", 0);
447  connect(copyPaste_Action_,SIGNAL(triggered() ),this,SLOT(slot_duplicate()));
448  emit addContextMenuItem(copyPaste_Action_ , DATA_POLY_LINE , CONTEXTOBJECTMENU );
449 }
450 
451 //------------------------------------------------------------------------------
452 
457 {
458  PluginFunctions::actionMode( Viewer::PickingMode );
459  PluginFunctions::pickMode( CREATE_CUT_POLYLINE );
460 }
461 
462 //------------------------------------------------------------------------------
463 
468 {
469  PluginFunctions::actionMode( Viewer::PickingMode );
470  PluginFunctions::pickMode( CREATE_CUT_POLYLINES );
471 }
472 
473 //-----------------------------------------------------------------------------
474 
479 {
480 
482 
483  // Iterate over all selected objects
484  BaseObjectData* object;
485  if (PluginFunctions::getPickedObject(planeSelect_->getNode(), object)) {
486  emit log("Cutting object " + object->name());
487 
488  if (!(object->dataType(DATA_TRIANGLE_MESH) || object->dataType(DATA_POLY_MESH))) {
489  emit log("Only Meshes are supported at the moment ");
490  return;
491  }
492 
493  ACG::Vec3d point = planeSelect_->getSourcePoint();
494  ACG::Vec3d normal = planeSelect_->getNormal();
495 
496  if ( PluginFunctions::pickMode() == CREATE_CUT_POLYLINE) {
497 
498  int objectId = generatePolyLineFromCut(object->id(), point, normal);
499 
500  QString command = "generatePolyLineFromCut(" + QString::number(object->id()) + ",Vector("
501  + QString::number(point[0]) + "," + QString::number(point[1]) + "," + QString::number(point[2]) + "),Vector("
502  + QString::number(normal[0]) + "," + QString::number(normal[1]) + "," + QString::number(normal[2]) + "));";
503  emit scriptInfo(command);
504 
505  //remove all other targets
508  if (o_it->id() != object->id()) {
509  o_it->target(false);
510  }
511  }
512 
513  // If we successfully created the polyline, we can inform the core about it.
514  if ( objectId != -1)
515  emit updatedObject(objectId,UPDATE_ALL);
516  } else {
517 
518  std::vector <int> objectIds = generatePolyLinesFromCut(object->id(), point, normal);
519 
520  QString command = "generatePolyLinesFromCut(" + QString::number(object->id()) + ",Vector("
521  + QString::number(point[0]) + "," + QString::number(point[1]) + "," + QString::number(point[2]) + "),Vector("
522  + QString::number(normal[0]) + "," + QString::number(normal[1]) + "," + QString::number(normal[2]) + "));";
523  emit scriptInfo(command);
524 
525  //remove all other targets
528  if (o_it->id() != object->id()) {
529  o_it->target(false);
530  }
531  }
532 
533  for ( unsigned int i = 0 ; i < objectIds.size() ; ++i ) {
534  // If we successfully created the polyline, we can inform the core about it.
535  if ( objectIds[i] != -1)
536  emit updatedObject(objectIds[i],UPDATE_ALL);
537  }
538 
539  }
540  }
541 
542 }
543 
544 //-----------------------------------------------------------------------------
545 
546 void
547 PolyLinePlugin::
548 slot_subdivide()
549 {
550  // get subdivision value
551  double max_length = tool_->dsb_subdivide->value();
552 
553  // safety catch
554  if (max_length == 0.0)
555  max_length = 1e-4;
556 
557  // iterate over all target polylines
559 
560  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
561  // subdivide polyline
562  PluginFunctions::polyLineObject(*o_it)->line()->subdivide(max_length);
563  }
564 
565  // update
566  emit updateView();
567 }
568 
569 
570 //-----------------------------------------------------------------------------
571 
572 
573 void PolyLinePlugin::slot_subdivide_percent(bool _checked) {
574 
575  // Get subdivision value
576  int n_active_pl = 0;
577  double total_length = 0;
578 
579  // Iterate over all target polylines
581 
582  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
583  // Add polyline length
584  total_length += PluginFunctions::polyLineObject(*o_it)->line()->length();
585  ++n_active_pl;
586  }
587 
588  double v = total_length / double(n_active_pl);
589 
590  if (_checked) {
591 
592  // Compute current absolute length to relative portion
593  if (n_active_pl > 0) {
594  double val_new = tool_->dsb_subdivide->value() / v;
595  tool_->dsb_subdivide->setValue(val_new);
596  } else {
597  emit log(LOGWARN, "Could not find any active polyline!");
598  }
599  } else {
600 
601  // Compute relative portion to absolute value
602  if (n_active_pl > 0) {
603  double val_new = tool_->dsb_subdivide->value() * v;
604  tool_->dsb_subdivide->setValue(val_new);
605  } else {
606  emit log(LOGWARN, "Could not find any active polyline!");
607  }
608  }
609 }
610 
611 
612 //-----------------------------------------------------------------------------
613 
614 
615 void
616 PolyLinePlugin::
617 slot_decimate()
618 {
619  // get subdivision value
620  double min_length = tool_->dsb_decimate->value();
621 
622  // iterate over all target polylines
624 
625  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
626  // decimate polyline
627  PluginFunctions::polyLineObject(*o_it)->line()->collapse(min_length);
628  }
629 
630  // update
631  emit updateView();
632 }
633 
634 //-----------------------------------------------------------------------------
635 
636 
637 void PolyLinePlugin::slot_decimate_percent(bool _checked)
638 {
639 
640  // Get decimation value
641  int n_active_pl = 0;
642  double total_length = 0;
643 
644  // Iterate over all target polylines
646 
647  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
648  // Add polyline length
649  total_length += PluginFunctions::polyLineObject(*o_it)->line()->length();
650  ++n_active_pl;
651  }
652 
653  double v = total_length / double(n_active_pl);
654 
655  if (_checked) {
656 
657  // Compute current absolute length to relative portion
658  if (n_active_pl > 0) {
659  double val_new = tool_->dsb_subdivide->value() / v;
660  tool_->dsb_decimate->setValue(val_new);
661  } else {
662  emit log(LOGWARN, "Could not find any active polyline!");
663  }
664  } else {
665 
666  // Compute relative portion to absolute value
667  if (n_active_pl > 0) {
668  double val_new = tool_->dsb_subdivide->value() * v;
669  tool_->dsb_decimate->setValue(val_new);
670  } else {
671  emit log(LOGWARN, "Could not find any active polyline!");
672  }
673  }
674 }
675 
676 
677 //-----------------------------------------------------------------------------
678 
679 #ifdef EXTENDED_POLY_LINE
680 
681 void
682 PolyLinePlugin::
683 slot_resample_on_edges()
684 {
685  // count target meshes
687  unsigned int n_targetMeshes(0);
688  for(; o_it != PluginFunctions::objectsEnd(); ++o_it)
689  ++n_targetMeshes;
690 
691  if( n_targetMeshes != 1)
692  {
693  std::cerr << "Warning: resample_on_edges needs exactly 1 target mesh! Otherwise no operation is performed! \n";
694  return;
695  }
696 
697  // take first target mesh
699 
700  if(o_it != PluginFunctions::objectsEnd())
701  {
702  // get pointer to TriMeshObject
703  TriMeshObject* tmesh_obj = PluginFunctions::triMeshObject(*o_it);
704 
705  // get pointer to mesh
706  TriMesh* mesh = tmesh_obj->mesh();
707 
708  // get pointer to triangle bsp
710  // OpenMeshTriangleBSPT< TriMesh >* tbsp = 0;
711 
712  // iterate over all target polylines
714 
715  for (; o_it2 != PluginFunctions::objectsEnd(); ++o_it2)
716  {
717  std::cerr << "resample " << o_it2->name().toStdString() << std::endl;
718  // decimate polyline
719  PluginFunctions::polyLineObject(*o_it2)->line()->resample_on_mesh_edges( *mesh, tbsp );
720  }
721 
722  // update
723  emit updateView();
724  }
725 }
726 
727 #endif
728 
729 //-----------------------------------------------------------------------------
730 
731 
732 void
733 PolyLinePlugin::
734 slot_smooth()
735 {
736  // iterate over all target polylines
738 
739  for ( ; o_it != PluginFunctions::objectsEnd(); ++o_it)
740  {
741  for( int i=0; i<tool_->sb_smooth_iter->value(); ++i)
742  if( tool_->rb_smooth_c0->isChecked())
743  // smooth polyline C0
745  else
746  if( tool_->rb_smooth_c1->isChecked())
747  // smooth polyline C1
749  else
750  if( tool_->rb_smooth_c2->isChecked())
751  // smooth polyline C2
753 
754  emit updatedObject( o_it->id(), UPDATE_GEOMETRY);
755  }
756 
757 }
758 
759 
760 //-----------------------------------------------------------------------------
761 
762 
763 void
764 PolyLinePlugin::
765 slot_smooth( PolyLineObject*& _pol)
766 {
767  // if polyline object is valid
768  if (_pol) {
769  for (int i = 0; i < tool_->sb_smooth_iter->value(); ++i)
770  if (tool_->rb_smooth_c0->isChecked())
771  // smooth polyline C0
772  _pol->line()->smooth_uniform_laplace();
773  else if (tool_->rb_smooth_c1->isChecked())
774  // smooth polyline C1
775  _pol->line()->smooth_uniform_laplace2();
776  else if (tool_->rb_smooth_c2->isChecked())
777  // smooth polyline C2
778  _pol->line()->smooth_uniform_laplace3();
779 
780  emit updatedObject(_pol->id(), UPDATE_GEOMETRY);
781  }
782 }
783 
784 //-----------------------------------------------------------------------------
785 
786 
787 void
788 PolyLinePlugin::
789 slot_project()
790 {
791  // create meshe and bsp vectors
792  std::vector<TriMesh*> meshes;
793  std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
794 
796 
797  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
798  // get pointer to TriMeshObject
799  TriMeshObject* tmesh_obj = PluginFunctions::triMeshObject(*o_it);
800 
801  // save meshes and bsps
802  meshes.push_back(tmesh_obj->mesh());
803  // bsps.push_back(0);
804  bsps.push_back(tmesh_obj->requestTriangleBsp());
805  }
806 
807  // iterate over all target polylines
809 
810  for (; o_it2 != PluginFunctions::objectsEnd(); ++o_it2) {
811  // project polyline
812  PluginFunctions::polyLineObject(*o_it2)->line()->project_to_mesh(meshes, &bsps);
813  emit updatedObject(o_it2->id(), UPDATE_GEOMETRY);
814  }
815 }
816 
817 
818 //-----------------------------------------------------------------------------
819 
820 
821 void
822 PolyLinePlugin::
823 slot_project( PolyLineObject*& _pol)
824 {
825  // check if polyline ok
826  if (_pol) {
827 
828  // create meshes and bsp vectors
829  std::vector<TriMesh*> meshes;
830  std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
831 
833 
834  for (; o_it != PluginFunctions::objectsEnd(); ++o_it) {
835 
836  // get pointer to TriMeshObject
837  TriMeshObject* tmesh_obj = PluginFunctions::triMeshObject(*o_it);
838 
839  // save meshes and bsps
840  meshes.push_back(tmesh_obj->mesh());
841  // bsps.push_back(0);
842  bsps.push_back(tmesh_obj->requestTriangleBsp());
843  }
844 
845  // only project given PolyLine
846  _pol->line()->project_to_mesh(meshes, &bsps);
847  }
848 
849 }
850 
851 
852 //-----------------------------------------------------------------------------
853 
854 
855 void
856 PolyLinePlugin::
857 slot_smooth_project()
858 {
859  int smooth_project_iter = tool_->sb_smooth_project_iter->value();
860 
861  for (int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
862 
863  // n smoothing steps
864  slot_smooth();
865 
866  // projection step
867  slot_project();
868 
869  }
870 }
871 
872 
873 //-----------------------------------------------------------------------------
874 
875 
876 void
877 PolyLinePlugin::
878 slot_smooth_project(PolyLineObject*& _pol)
879 {
880  int smooth_project_iter = tool_->sb_smooth_project_iter->value();
881 
882  for (int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
883 
884  // n smoothing steps
885  slot_smooth(_pol);
886 
887  // projection step
888  slot_project(_pol);
889 
890  }
891 }
892 
893 
894 //-----------------------------------------------------------------------------
895 
896 
897 void
898 PolyLinePlugin::
899 slot_smart_move_timer()
900 {
901  int smooth_project_iter = tool_->sb_smooth_project_iter->value();
902 
903  if (smooth_project_iter)
904  slot_smooth_project(cur_smart_move_obj_);
905  else // only smooth
906  slot_smooth(cur_smart_move_obj_);
907 
908  emit updateView();
909 }
910 
911 //-----------------------------------------------------------------------------
912 
913 void
914 PolyLinePlugin::slotObjectUpdated( int _identifier, const UpdateType &_type )
915 {
916  PolyLineObject* lineObject = 0;
917  if(!PluginFunctions::getObject(_identifier, lineObject))
918  return;
919  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(lineObject->objectData(CIRCLE_DATA));
920  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(lineObject->objectData(BEZSPLINE_DATA));
921  GlutPrimitiveNode* H = 0, *C = 0;
922  lineObject->getAdditionalNode(C, name(), "circle");
923  lineObject->getAdditionalNode(H, name(), "control", 0);
924  if(circleData && !C) {
925  createCircle_createUI(_identifier);
926  }
927  else if(splineData && !H) {
928  createSpline_createUI(_identifier);
929  }
930 }
931 
932 //-----------------------------------------------------------------------------
933 
935 PolyLinePlugin::
936 mode()
937 {
938  if(copyPaste_ObjectId_ != -1 && copyPaste_ActionType_ != -1)//no matter what tool is selected
939  return PL_COPY_PASTE;
940 
941  if(tool_ )
942  {
943  if( tool_->rb_insert->isChecked() ) return PL_INSERT;
944  if( tool_->rb_InsertCircle->isChecked() ) return PL_INSERTCIRCLE;
945  if( tool_->rb_InsertSpline->isChecked() ) return PL_INSERTSPLINE;
946  else if( tool_->rb_delete->isChecked() ) return PL_DELETE;
947  else if( tool_->rb_move->isChecked() ) return PL_MOVE;
948  else if( tool_->rb_split->isChecked() ) return PL_SPLIT;
949  else if( tool_->rb_merge->isChecked() ) return PL_MERGE;
950  else if( tool_->rb_smart_move->isChecked()) return PL_SMART_MOVE;
951  }
952 
953  return PL_NONE;
954 }
955 
956 //-----------------------------------------------------------------------------
957 
958 void
959 PolyLinePlugin::
960 me_insert( QMouseEvent* _event )
961 {
962  if (_event->type() == QEvent::MouseMove) {
963  if (create_point_ref_) {
964  // Pick position
965  unsigned int node_idx, target_idx;
966  ACG::Vec3d hit_point;
967  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
968  *create_point_ref_ = (PolyLine::Point) hit_point;
969 
970  // update
971  emit updatedObject(cur_insert_id_, UPDATE_GEOMETRY);
972  }
973  }
974  return;
975  }
976 
977  // Pick position
978  unsigned int node_idx, target_idx;
979  ACG::Vec3d hit_point;
980  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
981 
982  switch (_event->type()) {
983  // insert new point
984  case QEvent::MouseButtonPress: {
985  // new Polyline?
986  if (cur_insert_id_ == -1 || !PluginFunctions::objectRoot()->childExists(cur_insert_id_)) {
987  // add new polyline
988  emit addEmptyObject(DATA_POLY_LINE, cur_insert_id_);
989 
990  // get current polylineobject
991  BaseObjectData *obj = 0;
992  PluginFunctions::getObject(cur_insert_id_, obj);
993  // default: set as target
994  obj->target(true);
995  // get polyline object
996  cur_polyline_obj_ = PluginFunctions::polyLineObject(obj);
997 
998  cur_polyline_obj_->materialNode()->set_random_color();
999 
1000  cur_polyline_obj_->line()->set_vertex_radius(PluginFunctions::sceneRadius()*0.012);
1001 
1002  cur_polyline_obj_->lineNode()->drawMode(ACG::SceneGraph::DrawModes::DrawMode::getFromDescription("Points (as Spheres, constant screen size)") | ACG::SceneGraph::DrawModes::WIREFRAME);
1003 
1004  cur_polyline_obj_->line()->add_point((PolyLine::Point) hit_point);
1005 
1006  emit showStatusMessage(tr("Double click/Enter to terminate poly line. Use with shift to create loop."));
1007  }
1008 
1009  // add new point
1010  cur_polyline_obj_->line()->add_point((PolyLine::Point) hit_point);
1011  create_point_ref_ = &cur_polyline_obj_->line()->points().back();
1012 
1013  // update
1014  emit updatedObject(cur_insert_id_, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
1015 
1016  break;
1017  }
1018 
1019  // finish polyline
1020  case QEvent::MouseButtonDblClick: {
1021  // close polyline
1022  if (_event->modifiers() & (Qt::ShiftModifier)) {
1023  cur_polyline_obj_->line()->set_closed(true);
1024  }
1025 
1026  if (cur_polyline_obj_->line()->n_vertices() >= 2) {
1027 
1028  cur_polyline_obj_->line()->delete_point(cur_polyline_obj_->line()->n_vertices() - 1);
1029  }
1030 
1031  // update
1032  emit updatedObject(cur_insert_id_, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
1033 
1034  // reset current variables
1035  cur_insert_id_ = -1;
1036  cur_polyline_obj_ = 0;
1037  create_point_ref_ = 0;
1038 
1039  clearStatusMessage();
1040 
1041  break;
1042  }
1043 
1044  default:
1045  break;
1046  }
1047  }
1048 }
1049 
1050 //-----------------------------------------------------------------------------
1051 
1052 double getRad(int meshIdx)
1053 {
1054  TriMeshObject* mesh;
1055  if(PluginFunctions::getObject(meshIdx, mesh)) {
1056  //use the size of the mesh to compute the handle radii
1057  ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1058  ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1059  mesh->boundingBox(bbMin, bbMax);
1060  return 0.005*(bbMax-bbMin).norm();
1061  }
1062  else {
1063  return PluginFunctions::sceneRadius()*0.01;//use double of the above cause it is the radius
1064  }
1065 }
1066 
1067 void PolyLinePlugin::
1068 createCircle_createUI(int _polyLineObjectID)
1069 {
1070  PolyLineObject* lineObject;
1071  if (!PluginFunctions::getObject(_polyLineObjectID, lineObject) || !lineObject->objectData(CIRCLE_DATA))
1072  return;
1073  PolyLineCircleData* lineData = dynamic_cast<PolyLineCircleData*>(lineObject->objectData(CIRCLE_DATA));
1074 
1076 
1077  double rad = getRad(lineData->circleMeshIndex_);
1078 
1079  GlutPrimitiveNode* handle0 = new GlutPrimitiveNode(lineObject, "N_Handle0");
1080  handle0->get_primitive(0).color = ACG::Vec4f(1,0,0,1);
1081  handle0->set_size(rad);
1082  handle0->show();
1083  handle0->enablePicking(true);
1084  handle0->set_position(lineData->circleCenter_ + lineData->circleMainAxis_ * lineData->circleMainRadius_);
1085  lineObject->addAdditionalNode(handle0, name(), "handle0");
1087 
1088  GlutPrimitiveNode* handle1 = new GlutPrimitiveNode(lineObject, "N_Handle1");
1089  handle1->get_primitive(0).color = ACG::Vec4f(0,1,0,1);
1090  handle1->set_size(rad);
1091  handle1->show();
1092  handle1->enablePicking(true);
1093  handle1->set_position(lineData->circleCenter_ + lineData->circleSideAxis_ * lineData->circleSideRadius_);
1094  lineObject->addAdditionalNode(handle1, name(), "handle1");
1096 
1097  GlutPrimitiveNode* cenNode = new GlutPrimitiveNode(lineObject, "N_Center");
1098  cenNode->get_primitive(0).color = ACG::Vec4f(0,0,1,1);
1099  cenNode->set_size(rad);
1100  cenNode->show();
1101  cenNode->enablePicking(true);
1102  cenNode->set_position(lineData->circleCenter_);
1103  lineObject->addAdditionalNode(cenNode, name(), "circle");
1105 
1106  emit updatedObject(_polyLineObjectID, UPDATE_ALL);
1107 }
1108 
1109 //-----------------------------------------------------------------------------
1110 
1111 void PolyLinePlugin::
1112 me_insertCircle(QMouseEvent* _event)
1113 {
1114  TriMeshObject* mesh;
1115  TriMesh::FaceHandle fh;
1116  TriMesh::VertexHandle vh;
1117  ACG::Vec3d hit_point;
1118  if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point) && _event->type() != QEvent::MouseButtonRelease)
1119  return;//can't generate a circle in empty space
1120 
1121  if(_event->type() == QEvent::MouseMove && createCircle_CurrSelIndex_ != -1) {
1122  PolyLineObject* lineObject = 0;
1123  if(!PluginFunctions::getObject(createCircle_CurrSelIndex_, lineObject) || !lineObject->objectData(CIRCLE_DATA))
1124  return;
1125  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(lineObject->objectData(CIRCLE_DATA));
1126 
1127  const ACG::Vec3d n = circleData->circleNormal_, x0 = circleData->circleCenter_;
1128  const double t = ((n | x0) - (n | hit_point)) / n.sqrnorm();
1129  const ACG::Vec3d onPlane = hit_point + t * n, d = onPlane - x0;
1130 
1131  circleData->circleMainAxis_ = (onPlane - x0).normalize();
1132  circleData->circleSideRadius_ = circleData->circleMainRadius_ = d.norm();
1133  circleData->circleSideAxis_ = (circleData->circleMainAxis_ % n).normalize();
1134 
1135  updatePolyEllipse(lineObject, tool_->sb_CirclePointNum->value());
1136  updateHandles(lineObject);
1137  }
1138  else if(_event->type() == QEvent::MouseButtonPress && createCircle_CurrSelIndex_ == -1) {
1139  int new_line_id;
1140  emit addEmptyObject(DATA_POLY_LINE, new_line_id);
1141  BaseObjectData *obj = 0;
1142  PluginFunctions::getObject(new_line_id, obj);
1143  obj->target(true);
1145  newLine->materialNode()->set_random_color();
1146 
1148 
1149  if(!mesh->mesh()->has_face_normals())
1150  mesh->mesh()->request_face_normals();
1151 
1152  PolyLineCircleData* lineData = new PolyLineCircleData(hit_point, mesh->mesh()->normal(fh), ACG::Vec3d(), ACG::Vec3d(), 0, 0, mesh->id());
1153  newLine->setObjectData(CIRCLE_DATA, lineData);
1155 
1156  emit updatedObject(new_line_id, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
1157  createCircle_LastSelIndex_ = createCircle_CurrSelIndex_ = newLine->id();
1159  }
1160  else if(_event->type() == QEvent::MouseButtonRelease ) {
1161  PolyLineObject* lineObject;
1162  if(PluginFunctions::getObject(createCircle_CurrSelIndex_, lineObject))
1163  {
1165  if(lineObject->getAdditionalNode(N, name(), "handle0"))
1166  N->enablePicking(true);
1167  }
1168  createCircle_CurrSelIndex_ = -1;
1169  }
1170 }
1171 
1172 //-------------------------------------------OpenFLipper/BasePlugin/----------------------------------
1173 
1174 void PolyLinePlugin::
1175 createSpline_createUI(int _polyLineObjectID)
1176 {
1177  PolyLineObject* lineObject;
1178  if (!PluginFunctions::getObject(_polyLineObjectID, lineObject) || !lineObject->objectData(BEZSPLINE_DATA))
1179  return;
1180  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(lineObject->objectData(BEZSPLINE_DATA));
1181 
1183 
1184  double rad = getRad(splineData->meshIndex_);
1185 
1186  GlutLineNode* lineN = new GlutLineNode(lineObject, "N_Line");
1187  lineN->show();
1188  lineN->enablePicking(false);
1189  lineObject->addAdditionalNode(lineN, name(), "line");
1190  lineN->drawMode(ACG::SceneGraph::DrawModes::WIREFRAME);
1191 
1192  for(unsigned int i = 0; i < splineData->points_.size(); i++) {
1193  GlutPrimitiveNode* handle0 = new GlutPrimitiveNode(lineObject, "N_Control", i);
1194  handle0->get_primitive(0).color = ACG::Vec4f(0,1,0,1);
1195  handle0->set_size(rad);
1196  handle0->show();
1197  handle0->set_position(splineData->points_[i].position);
1199  handle0->enablePicking(true);
1200  lineObject->addAdditionalNode(handle0, name(), "control", i);
1201  }
1202 
1203  for(unsigned int i = 0; i < splineData->handles_.size(); i++) {
1204  const PolyLineBezierSplineData::InterpolatePoint& control = splineData->getInterpolatePoint(i);
1205  const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = control.position;
1206 
1207  GlutPrimitiveNode* handle0 = new GlutPrimitiveNode(lineObject, "N_Handle", i);
1208  handle0->get_primitive(0).color = ACG::Vec4f(0,0,1,1);
1209  handle0->set_size(rad * 0.75);
1210  handle0->show();
1211  handle0->enablePicking(true);
1212  handle0->set_position(hndlPos);
1213  lineObject->addAdditionalNode(handle0, name(), "handle", i);
1215 
1216  GlutLineNode* lineN;
1217  if(lineObject->getAdditionalNode(lineN, name(), "line")) {
1218  lineN->add_line(ctrlPos, hndlPos);
1219  lineN->add_color(ACG::Vec4f(1,0,0,1));
1220  }
1221  }
1222  updatePolyBezierSpline(lineObject, tool_->sb_SplineSegNum->value());
1223 
1224  emit updatedObject(_polyLineObjectID, UPDATE_ALL);
1225 }
1226 
1227 void
1228 PolyLinePlugin::
1229 finishSpline()
1230 {
1231  PolyLineObject* lineObject = 0;
1232 
1234  return;
1235 
1236 
1237  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(lineObject->objectData(BEZSPLINE_DATA));
1238 
1239  TriMeshObject* mesh;
1240  if(!PluginFunctions::getObject(splineData->meshIndex_, mesh))
1241  return;
1242 
1243  ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1244  ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1245  mesh->boundingBox(bbMin, bbMax);
1246  const ACG::Vec3d sizeBB((bbMax-bbMin));
1247 
1248  if(splineData->finishSpline()) {
1249 
1250  GlutPrimitiveNode* control = 0;
1251 
1252  for(unsigned int i = 0; i < splineData->points_.size(); i++) {
1253  lineObject->getAdditionalNode(control, name(), "control", i);
1254  control->enablePicking(true);
1255  }
1256 
1257  for(unsigned int i = 0; i < splineData->handles_.size(); i++) {
1258  const PolyLineBezierSplineData::InterpolatePoint& control = splineData->getInterpolatePoint(i);
1259  const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = control.position;
1260 
1261  GlutPrimitiveNode* handle0 = new GlutPrimitiveNode(lineObject, "N_Handle", i);
1262  handle0->get_primitive(0).color = ACG::Vec4f(0,0,1,1);
1263  handle0->set_size(0.004*sizeBB.norm());
1264  handle0->show();
1265  handle0->enablePicking(true);
1266  handle0->set_position(hndlPos);
1267  lineObject->addAdditionalNode(handle0, name(), "handle", i);
1269 
1270  GlutLineNode* lineN;
1271  if(lineObject->getAdditionalNode(lineN, name(), "line")) {
1272  lineN->add_line(ctrlPos, hndlPos);
1273  lineN->add_color(ACG::Vec4f(1,0,0,1));
1274  }
1275 
1276  emit updatedObject(createSpline_CurrSelIndex_, UPDATE_ALL);
1277  }
1278  updatePolyBezierSpline(lineObject, tool_->sb_SplineSegNum->value());
1280  }
1281 }
1282 
1283 void PolyLinePlugin::
1284 me_insertSpline(QMouseEvent* _event)
1285 {
1286 
1287  TriMeshObject* mesh;
1288  TriMesh::FaceHandle fh;
1289  TriMesh::VertexHandle vh;
1290  ACG::Vec3d hit_point;
1291 
1292  if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point))
1293  return;//can't generate a circle in empty space
1294 
1295  ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1296  ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1297  mesh->boundingBox(bbMin, bbMax);
1298  const ACG::Vec3d sizeBB((bbMax-bbMin));
1299 
1300  if(!mesh->mesh()->has_face_normals())
1301  mesh->mesh()->request_face_normals();
1302 
1303  ACG::Vec3d nor = mesh->mesh()->normal(fh);
1304 
1305  if(_event->type() == QEvent::MouseButtonPress) {
1306 
1307  if(createSpline_CurrSelIndex_ == -1) {
1308 
1309  emit addEmptyObject(DATA_POLY_LINE, createSpline_CurrSelIndex_);
1312  BaseObjectData *obj = 0;
1314  obj->target(true);
1316  newLine->materialNode()->set_random_color();
1318 
1319  newLine->lineNode()->drawMode(ACG::SceneGraph::DrawModes::WIREFRAME);
1321 
1322  PolyLineBezierSplineData* lineData = new PolyLineBezierSplineData(mesh->id());
1323  newLine->setObjectData(BEZSPLINE_DATA, lineData);
1324 
1325  GlutLineNode* lineN = new GlutLineNode(newLine, "N_Line");
1326  lineN->show();
1327  lineN->enablePicking(false);
1328  newLine->addAdditionalNode(lineN, name(), "line");
1329  lineN->drawMode(ACG::SceneGraph::DrawModes::WIREFRAME);
1330  }
1331 
1332  ACG::Vec3d insert_Point = hit_point + nor * 0.003 * sizeBB.norm();
1333  PolyLineObject* lineObject = 0;
1334 
1336  return;
1337 
1338  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(lineObject->objectData(BEZSPLINE_DATA));
1339  GlutPrimitiveNode* handle0 = new GlutPrimitiveNode(lineObject, "N_Control", splineData->points_.size());
1340  handle0->get_primitive(0).color = ACG::Vec4f(0,1,0,1);
1341  handle0->set_size(0.005*sizeBB.norm());
1342  handle0->show();
1343  handle0->set_position(insert_Point);
1345  handle0->enablePicking(false);
1346  lineObject->addAdditionalNode(handle0, name(), "control", splineData->points_.size());
1347 
1348  emit updatedObject(createSpline_CurrSelIndex_, UPDATE_ALL);
1349  splineData->addInterpolatePoint(insert_Point, nor);
1350 
1351  }
1352  if(_event->type() == QEvent::MouseButtonDblClick) {
1353  finishSpline();
1354  }
1355 }
1356 
1357 //-----------------------------------------------------------------------------
1358 
1359 void
1360 PolyLinePlugin::
1361 me_delete( QMouseEvent* _event )
1362 {
1363  // MousePress ?
1364  if (_event->type() == QEvent::MouseButtonPress) {
1365 
1366  unsigned int node_idx, target_idx;
1367  ACG::Vec3d hit_point;
1368  // pick
1369  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hit_point)) {
1370 
1371  BaseObjectData* obj = 0;
1372 
1373  if (PluginFunctions::getPickedObject(node_idx, obj))
1374  // is picked object polyline?
1376  emit deleteObject(obj->id());
1377  }
1378  }
1379 
1380  }
1381 
1382 }
1383 
1384 
1385 //-----------------------------------------------------------------------------
1386 
1387 namespace {
1388 
1389 bool me_GetMeshHit(QMouseEvent* _event, ACG::SceneGraph::GlutPrimitiveNode* moveCircle_SelNode_, ACG::Vec3d& _hit_point, unsigned int& _node_idx, unsigned int& _targetIdx)
1390 {
1391  unsigned int ndx;
1392  if(moveCircle_SelNode_)
1393  moveCircle_SelNode_->enablePicking(false);
1394  bool hasHit = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), ndx, _targetIdx, &_hit_point);
1395  if(moveCircle_SelNode_)
1396  moveCircle_SelNode_->enablePicking(true);
1397  BaseObjectData* obj;
1398  //if there is no current mesh use the newly found
1399  if(hasHit && PluginFunctions::getPickedObject(ndx, obj) && _node_idx == std::numeric_limits<unsigned int>::max())
1400  _node_idx = obj->id();
1401  return hasHit;
1402 }
1403 
1404 void me_UpdateCircleData(ACG::Vec3d _hit_point, ACG::Vec3d _onPlane, ACG::Vec3d _nor, ACG::SceneGraph::GlutPrimitiveNode* _moveCircle_SelNode_, PolyLineCircleData* _lineData, bool _isShift)
1405 {
1406  if(!_moveCircle_SelNode_->name().compare("N_Center"))
1407  {
1408  _lineData->circleNormal_ = _nor;
1409  _lineData->circleCenter_ = _hit_point;
1410  _lineData->circleSideAxis_ = (_lineData->circleMainAxis_ % _lineData->circleNormal_).normalize();
1411  _lineData->circleMainAxis_ = (_lineData->circleNormal_ % _lineData->circleSideAxis_).normalize();
1412  }
1413  else
1414  {
1415  const double cr = (_onPlane - _lineData->circleCenter_).norm();
1416  const ACG::Vec3d axisa = (_onPlane - _lineData->circleCenter_).normalize();
1417  if (!_moveCircle_SelNode_->name().compare("N_Handle0")) {
1418  const ACG::Vec3d axisb = (axisa % _lineData->circleNormal_).normalize();
1419  _lineData->circleMainRadius_ = cr;
1420 
1421  if (_isShift)
1422  _lineData->circleSideRadius_ = cr;
1423 
1424  _lineData->circleMainAxis_ = axisa;
1425  _lineData->circleSideAxis_ = axisb;
1426  } else {
1427  const ACG::Vec3d axisb = (_lineData->circleNormal_ % axisa).normalize();
1428  _lineData->circleSideRadius_ = cr;
1429 
1430  if (_isShift)
1431  _lineData->circleMainRadius_ = cr;
1432 
1433  _lineData->circleSideAxis_ = axisa;
1434  _lineData->circleMainAxis_ = axisb;
1435  }
1436  }
1437 }
1438 }
1439 
1440 void
1441 PolyLinePlugin::
1442 me_move( QMouseEvent* _event )
1443 {
1444  if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier && moveCircle_IsLocked)//alt was pressed but it isn't anymore
1445  moveCircle_IsLocked = moveCircle_IsFloating = false;
1446 
1447  // MousePress ? -> get reference point
1448  if (_event->type() == QEvent::MouseButtonPress) {
1449 
1450  unsigned int node_idx, target_idx;
1451  ACG::Vec3d hit_point;
1452  // this is for picking the handles on a circle or spline
1453  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hit_point)) {
1454  BaseNode* node = find_node( PluginFunctions::getRootNode(), node_idx );
1455  GlutPrimitiveNode* glutNode = dynamic_cast<GlutPrimitiveNode*>(node);
1456 
1457  if(glutNode) {
1458  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(glutNode->line->objectData(CIRCLE_DATA));
1459  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(glutNode->line->objectData(BEZSPLINE_DATA));
1460  if(circleData) {
1461  moveCircle_SelNode_ = glutNode;
1462  createCircle_LastSelIndex_ = createCircle_CurrSelIndex_ = glutNode->line->id();
1463  }
1464  if(splineData) {
1465  moveBezSpline_SelNode_ = glutNode;
1466  createSpline_LastSelIndex_ = moveBezSpline_SelIndex_ = glutNode->line->id();
1467  moveBezSpline_SelSubIndex_ = glutNode->index;
1468  }
1469  }
1470  }
1471  //this is for picking the normal poly lines
1472  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
1473  BaseObjectData* obj = 0;
1474  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1475  // is picked object polyline?
1477  if (cur_pol && !cur_pol->objectData(CIRCLE_DATA) && !cur_pol->objectData(BEZSPLINE_DATA)) {//no vertex dragging on circles!
1478 
1479  // Check if we got a line segment or a vertex
1480  if ( target_idx >= cur_pol->line()->n_vertices() )
1481  return;
1482 
1483  // save references
1484  cur_move_id_ = cur_pol->id();
1485 
1486  move_point_ref_ = &(cur_pol->line()->point(target_idx));
1487  }
1488  }
1489  }
1490  }
1491 
1492  // Move ? -> move reference point
1493  if (_event->type() == QEvent::MouseMove){
1494  if (moveCircle_SelNode_) {
1495  PolyLineObject* lineObject;
1496  if (!PluginFunctions::getObject(createCircle_CurrSelIndex_, lineObject) || !lineObject->objectData(CIRCLE_DATA))
1497  return;
1498  PolyLineCircleData* lineData = dynamic_cast<PolyLineCircleData*>(lineObject->objectData(CIRCLE_DATA));
1499  ACG::Vec3d hit_point;
1500  unsigned int target_idx;
1501  bool hasHit = me_GetMeshHit(_event, moveCircle_SelNode_, hit_point, lineData->circleMeshIndex_, target_idx);
1502  if(lineData->circleMeshIndex_ == std::numeric_limits<unsigned int>::max()) return;
1503  if(!moveCircle_IsLocked && hasHit) {
1504  moveCircle_IsFloating = false;
1505  ACG::Vec3d x0 = lineData->circleCenter_, n = lineData->circleNormal_;
1506  ACG::Vec3d onMesh = hit_point;
1507  double t = ((n | x0) - (n | onMesh)) / n.sqrnorm();
1508  ACG::Vec3d onPlane = onMesh + t * n;
1509  TriMeshObject* mesh;
1510  if (!PluginFunctions::getObject(lineData->circleMeshIndex_, mesh))
1511  return;
1512 
1513  me_UpdateCircleData(onMesh, onPlane, mesh->mesh()->normal(mesh->mesh()->face_handle(target_idx)), moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1514  if (!moveCircle_SelNode_->name().compare("N_Center")) {
1515  moveCircle_LastHitPos_ = onMesh;
1516  if((_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) {
1517  moveCircle_IsLocked = true;
1518  moveCircle_LastHitNor_ = lineData->circleNormal_;
1519  }
1520  }
1521  }
1522  else
1523  {
1524  moveCircle_IsFloating = true;
1525  ACG::Vec3d cameraPos, cameraDir;
1526  int l,b,w,h;
1528  PluginFunctions::viewerProperties(0).glState().viewing_ray(_event->pos().x(), h - 1 - _event->pos().y(), cameraPos, cameraDir);
1529  //intersect the camera ray with a plane located at moveCircle_LastHitPos_ facing moveCircle_LastHitNor_
1530  const ACG::Vec3d x0 = !moveCircle_SelNode_->name().compare("N_Center") ? moveCircle_LastHitPos_ : lineData->circleCenter_,
1531  //the side handles can only be moved on the normal plane
1532  n = !moveCircle_SelNode_->name().compare("N_Center") ? (moveCircle_IsLocked ? moveCircle_LastHitNor_ : PluginFunctions::viewingDirection())
1533  : lineData->circleNormal_;
1534  const double t = ((x0 | n) - (cameraPos | n)) / (cameraDir | n);
1535  const ACG::Vec3d onPlane = cameraPos + cameraDir * t;
1536 
1537  me_UpdateCircleData(onPlane, onPlane, n, moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1538 
1539  }
1540  updateHandles(lineObject);
1541  updatePolyEllipse(lineObject, tool_->sb_CirclePointNum->value());
1542  }
1543  else if(moveBezSpline_SelNode_) {
1544  PolyLineObject* lineObject;
1545  if(!PluginFunctions::getObject(moveBezSpline_SelIndex_, lineObject) || !lineObject->objectData(BEZSPLINE_DATA))
1546  return;
1547  PolyLineBezierSplineData* lineData = dynamic_cast<PolyLineBezierSplineData*>(lineObject->objectData(BEZSPLINE_DATA));
1548  ACG::Vec3d hit_point;
1549  unsigned int target_idx;
1550  bool hasHit = me_GetMeshHit(_event, moveBezSpline_SelNode_, hit_point, lineData->meshIndex_, target_idx);
1551  if(lineData->meshIndex_ == std::numeric_limits<unsigned int>::max())
1552  return;
1553  if(!moveBezSpline_SelNode_->name().compare("N_Control") && hasHit) {
1554  TriMeshObject* mesh;
1555  if (!PluginFunctions::getObject(lineData->meshIndex_, mesh))
1556  return;
1557  ACG::Vec3d onMesh = hit_point, onMeshNor = mesh->mesh()->normal(mesh->mesh()->face_handle(target_idx));
1558  int controlIndex = moveBezSpline_SelSubIndex_;
1561  lineData->points_[controlIndex].position = onMesh;
1562  lineData->points_[controlIndex].normal = onMeshNor;
1563  if(controlIndex) {
1564  int handleIndex = 2 * controlIndex - 1;
1565  ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.norm();
1566  ACG::Vec3d point = forw + onMesh;
1567  lineData->handles_[handleIndex] = point;
1568  }
1569  if(controlIndex != ((int)lineData->points_.size() - 1)) {
1570  int handleIndex = 2 * controlIndex;
1571  ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.norm();
1572  ACG::Vec3d point = forw + onMesh;
1573  lineData->handles_[handleIndex] = point;
1574  }
1575  }
1576  else if(!moveBezSpline_SelNode_->name().compare("N_Handle")) {
1577  int handleIndex = moveBezSpline_SelSubIndex_;
1578  const PolyLineBezierSplineData::InterpolatePoint& control = lineData->getInterpolatePoint(handleIndex);
1579  //we don't use the mesh location but instead the location on the normal plane!
1580  ACG::Vec3d cameraPos, cameraDir;
1581  int l,b,w,h;
1583  PluginFunctions::viewerProperties(0).glState().viewing_ray(_event->pos().x(), h - 1 - _event->pos().y(), cameraPos, cameraDir);
1584  double t = ((control.normal | control.position) - (control.normal | cameraPos)) / (control.normal | cameraDir);
1585  ACG::Vec3d onPlane = cameraPos + t * cameraDir;
1586 
1587  lineData->handles_[handleIndex] = onPlane;
1588  if(handleIndex % 2 == 1 && handleIndex != ((int)lineData->handles_.size() - 1)) {
1589  double dist = (lineData->handles_[handleIndex + 1] - control.position).norm();
1590  if(_event->modifiers() & Qt::ShiftModifier)
1591  dist = (onPlane - control.position).norm();
1592  ACG::Vec3d dir = -(onPlane - control.position).normalize();
1593  lineData->handles_[handleIndex + 1] = control.position + dir * dist;
1594  }
1595  if(handleIndex % 2 == 0 && handleIndex) {
1596  double dist = (lineData->handles_[handleIndex - 1] - control.position).norm();
1597  if(_event->modifiers() & Qt::ShiftModifier)
1598  dist = (onPlane - control.position).norm();
1599  ACG::Vec3d dir = -(onPlane - control.position).normalize();
1600  lineData->handles_[handleIndex - 1] = control.position + dir * dist;
1601  }
1602  }
1603  GlutLineNode* lineN;
1604  if(!lineObject->getAdditionalNode(lineN, name(), "line", 0))
1605  return;
1606  updatePolyBezierHandles(lineObject, lineN);
1607  updatePolyBezierSpline(lineObject, tool_->sb_SplineSegNum->value());
1608  }
1609  else if (move_point_ref_ != 0) {
1610  ACG::Vec3d hit_point;
1611  unsigned int node_idx, target_idx;
1612  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
1613  (*move_point_ref_) = (PolyLine::Point) hit_point;
1614  // update
1615  emit updatedObject(cur_move_id_, UPDATE_GEOMETRY);
1616  }
1617  }
1618  }
1619 
1620  // Release ? -> release reference point
1621  if (_event->type() == QEvent::MouseButtonRelease) {
1622  if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier) {
1623  //in case we are not dragging the center and not pressing alt -> project to mesh
1624  // if(moveCircle_SelNode_ && moveCircle_SelNode_->name().compare("N_Center"))
1625  moveCircle_IsLocked = moveCircle_IsFloating = false;
1626  PolyLineObject* lineObject;
1628  {
1629  moveCircle_IsLocked = false;
1630  updateHandles(lineObject);
1631  updatePolyEllipse(lineObject, tool_->sb_CirclePointNum->value());
1632  }
1633  }
1634  move_point_ref_ = 0;
1635  moveCircle_SelNode_ = 0;
1639  }
1640 }
1641 //-----------------------------------------------------------------------------
1642 
1643 
1644 void
1645 PolyLinePlugin::
1646 me_split( QMouseEvent* _event )
1647 {
1648  // MousePress ?
1649  if (_event->type() == QEvent::MouseButtonPress) {
1650  // release old references
1651  move_point_ref_ = 0;
1652 
1653  unsigned int node_idx, target_idx;
1654  ACG::Vec3d hit_point;
1655  // pick
1656  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
1657 
1658  BaseObjectData* obj = 0;
1659  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1660 
1661  // is picked object polyline?
1663 
1664  if (cur_pol) {
1665 
1666  // Check if we got a line segment or a vertex
1667  if ( target_idx >= cur_pol->line()->n_vertices() )
1668  return;
1669 
1670  // splitting for CLOSED PolyLines
1671  if (cur_pol->line()->is_closed()) {
1672  cur_pol->line()->split_closed(target_idx);
1673 
1674  // save references for moving
1675  cur_move_id_ = cur_pol->id();
1676  move_point_ref_ = &(cur_pol->line()->point(cur_pol->line()->n_vertices() - 1));
1677 
1678  // emit changed objects
1679  emit updatedObject(cur_pol->id(), UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1680  } else
1681  // splitting for OPEN PolyLines
1682  {
1683  // add new polyline
1684  int insert_id;
1685  emit addEmptyObject(DATA_POLY_LINE, insert_id);
1686 
1687  // get current polylineobject
1688  BaseObjectData *obj2 = 0;
1689 
1690  // get polyline object
1691  PluginFunctions::getObject(insert_id, obj2);
1692 
1693  // default: mark as target
1694  obj2->target(true);
1695 
1697 
1698  pol_obj2->materialNode()->set_random_color();
1699 
1700  pol_obj2->line()->set_vertex_radius(cur_pol->line()->vertex_radius());
1701  pol_obj2->lineNode()->drawMode(cur_pol->lineNode()->drawMode());
1702 
1703  cur_pol->line()->split(target_idx, *(pol_obj2->line()));
1704 
1705  // save references for moving
1706  cur_move_id_ = cur_pol->id();
1707  move_point_ref_ = &(cur_pol->line()->point(cur_pol->line()->n_vertices() - 1));
1708 
1709  // emit changed objects
1710  emit updatedObject(insert_id, UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1711  emit updatedObject(cur_pol->id(), UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1712  }
1713 
1714  // update
1715  emit updateView();
1716  }
1717  }
1718  }
1719  }
1720 
1721  // Move splitted ? -> move reference point
1722  if (_event->type() == QEvent::MouseMove)
1723  if (move_point_ref_ != 0) {
1724 
1725  unsigned int node_idx, target_idx;
1726  ACG::Vec3d hit_point;
1727  // pick
1728  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
1729  (*move_point_ref_) = (PolyLine::Point) hit_point;
1730 
1731  // update
1732  emit updatedObject(cur_move_id_, UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1733  emit updateView();
1734  }
1735  }
1736 
1737  // Release splitted? -> release reference point
1738  if (_event->type() == QEvent::MouseButtonRelease) {
1739 
1740  if (cur_move_id_ != -1)
1741  emit updatedObject(cur_move_id_, UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1742 
1743  move_point_ref_ = 0;
1744  cur_move_id_ = -1;
1745 
1746  }
1747 
1748 }
1749 
1750 //-----------------------------------------------------------------------------
1751 
1752 void
1753 PolyLinePlugin::
1754 me_merge( QMouseEvent* _event )
1755 {
1756  // Mouse PRESS ?
1757  if (_event->type() == QEvent::MouseButtonPress) {
1758  // release old references
1759  move_point_ref_ = 0;
1760  cur_merge_id_ = -1;
1761 
1762  unsigned int node_idx, target_idx;
1763  ACG::Vec3d hit_point;
1764  // pick
1765  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
1766  BaseObjectData* obj = 0;
1767  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1768  // is picked object polyline?
1770  if (cur_pol) {
1771 
1772  // Check if we got a line segment or a vertex
1773  if ( target_idx >= cur_pol->line()->n_vertices() ) {
1774  return;
1775  }
1776 
1777  if (target_idx == cur_pol->line()->n_vertices() - 1 || target_idx == 0) {
1778  if (target_idx == 0) {
1779  cur_pol->line()->invert();
1780  //target_idx = cur_pol->line()->n_vertices() - 1;
1781  }
1782 
1783  // save references
1784  cur_merge_id_ = cur_pol->id();
1785 
1786  // save reference for moving
1787  // cur_pol->line()->add_point( cur_pol->line()->point( cur_pol->line()->n_vertices()-1));
1788  move_point_ref_ = &(cur_pol->line()->point(cur_pol->line()->n_vertices() - 1));
1789  }
1790  }
1791 
1792  }
1793  }
1794  }
1795 
1796  // Move ? -> move reference point
1797  if (_event->type() == QEvent::MouseMove && cur_merge_id_ != -1)
1798  if (move_point_ref_ != 0) {
1799  unsigned int node_idx, target_idx;
1800  ACG::Vec3d hit_point;
1801  // pick
1802  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
1803  (*move_point_ref_) = (PolyLine::Point) hit_point;
1804 
1805  // update
1806  emit updatedObject(cur_merge_id_, UPDATE_TOPOLOGY | UPDATE_GEOMETRY);
1807  emit updateView();
1808  }
1809  }
1810 
1811  // Mouse RELEASE ?
1812  if (_event->type() == QEvent::MouseButtonRelease && cur_merge_id_ != -1) {
1813  PolyLine::Point p_save;
1814 
1815  // reset move references
1816  if (move_point_ref_ != 0) {
1817  // remove intermediate point
1818  // restore orig polyline
1819  BaseObjectData *obj = 0;
1820  PluginFunctions::getObject(cur_merge_id_, obj);
1822 
1823  // store position if merging fails
1824  p_save = opol->line()->back();
1825  opol->line()->resize(opol->line()->n_vertices() - 1);
1826 
1827  // release reference
1828  move_point_ref_ = 0;
1829  }
1830 
1831  unsigned int node_idx, target_idx;
1832  ACG::Vec3d hit_point;
1833 
1834  // pick
1835  // restore first polyline
1836  BaseObjectData *obj2 = 0;
1837  PluginFunctions::getObject(cur_merge_id_, obj2);
1839  first_pol->enablePicking(false);
1840  PluginFunctions::invalidatePickCaches();
1841 
1842  bool merged = false;
1843  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
1844 
1845  BaseObjectData* obj = 0;
1846 
1847  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1848 
1849  // is picked object polyline? -> get second polyline
1851 
1852  if (second_pol) {
1853 
1854  // Check if we got a line segment or a vertex
1855  if ( target_idx < second_pol->line()->n_vertices() ) {
1856  // get idxs
1857  unsigned int first_idx = first_pol->line()->n_vertices() - 1;
1858  unsigned int second_idx = target_idx;
1859 
1860  // both polylines open?
1861  if (!first_pol->line()->is_closed() && !second_pol->line()->is_closed()) {
1862 
1863  bool inv_first(false), inv_second(false);
1864 
1865  // wrong ordering first Polyline?
1866  if (first_idx == 0) {
1867  inv_first = true;
1868  first_idx = first_pol->line()->n_vertices() - 1;
1869  }
1870 
1871  // wrong ordering second Polyline?
1872  if (second_idx == second_pol->line()->n_vertices() - 1) {
1873  inv_second = true;
1874  second_idx = 0;
1875  }
1876 
1877  // two endpoints available?
1878  if (first_idx == first_pol->line()->n_vertices() - 1 && second_idx == 0) {
1879  // same polyline?
1880  if (first_pol->id() == second_pol->id()) {
1881  // simply close line
1882  first_pol->line()->set_closed(true);
1883  } else {
1884  // invert if necessary
1885  if (inv_first)
1886  first_pol->line()->invert();
1887  if (inv_second)
1888  second_pol->line()->invert();
1889 
1890  // append second polyline to first one
1891  first_pol->line()->append(*second_pol->line());
1892 
1893  // set flag
1894  merged = true;
1895 
1896  // delete appended
1897  emit deleteObject(second_pol->id());
1898  }
1899 
1900  }
1901  }
1902  }
1903  }
1904  }
1905  }
1906 
1907  first_pol->enablePicking(true);
1908  PluginFunctions::invalidatePickCaches();
1909 
1910  //above can't try to close a line
1911  if(!merged && PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
1912  BaseObjectData* obj = 0;
1913  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1914 
1915  // is picked object polyline? -> get second polyline
1917 
1918  if (second_pol) {
1919 
1920  // Check if we got a line segment or a vertex
1921  if ( target_idx < second_pol->line()->n_vertices() ) {
1922  // get idxs
1923  unsigned int first_idx = first_pol->line()->n_vertices() - 1;
1924  unsigned int second_idx = target_idx;
1925 
1926  // both polylines open?
1927  if (!first_pol->line()->is_closed() && !second_pol->line()->is_closed()) {
1928 
1929  // wrong ordering first Polyline?
1930  if (first_idx == 0) {
1931  first_idx = first_pol->line()->n_vertices() - 1;
1932  }
1933 
1934  // wrong ordering second Polyline?
1935  if (second_idx == second_pol->line()->n_vertices() - 1) {
1936  second_idx = 0;
1937  }
1938 
1939  if (first_pol->id() == second_pol->id() && first_idx == first_pol->line()->n_vertices() - 1 && second_idx == 0) {
1940  // simply close line
1941  first_pol->line()->set_closed(true);
1942  merged = true;
1943  }
1944  }
1945  }
1946  }
1947  }
1948  }
1949 
1950  if (!merged) {
1951  // remove intermediate point
1952  // restore orig polyline
1953  BaseObjectData *obj = 0;
1954  PluginFunctions::getObject(cur_merge_id_, obj);
1956 
1957  opol->line()->add_point(p_save);
1958  }
1959 
1960  // update
1961  emit updatedObject(cur_merge_id_, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
1962 
1963  // release old references
1964  move_point_ref_ = 0;
1965  cur_merge_id_ = -1;
1966  }
1967 
1968 }
1969 
1970 
1971 //-----------------------------------------------------------------------------
1972 
1973 
1974 void
1975 PolyLinePlugin::
1976 me_smart_move( QMouseEvent* _event )
1977 {
1978  // MousePress ? -> select vertex and start timer
1979  if (_event->type() == QEvent::MouseButtonPress) {
1980 
1981  unsigned int node_idx, target_idx;
1982  ACG::Vec3d hit_point;
1983 
1984  // pick
1985  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hit_point)) {
1986 
1987  BaseObjectData* obj = 0;
1988  if (PluginFunctions::getPickedObject(node_idx, obj)) {
1989 
1990  // is picked object polyline?
1992  if (cur_pol) {
1993 
1994  cur_polyline_obj_ = cur_pol;
1995 
1996  // Check if we got a line segment or a vertex
1997  if ( target_idx >= cur_pol->line()->n_vertices() )
1998  return;
1999 
2000  // save references
2001  cur_smart_move_obj_ = cur_pol;
2002  if (cur_pol->line()->vertex_selections_available()) {
2003  if (!(_event->modifiers() & (Qt::ShiftModifier)))
2004  cur_pol->line()->vertex_selection(target_idx) = true;
2005  else {
2006  cur_pol->line()->vertex_selection(target_idx) = false;
2007  emit updateView();
2008  }
2009  }
2010 
2011  }
2012 
2013  // start timer
2014  if (!(_event->modifiers() & (Qt::ShiftModifier)))
2015  smart_move_timer_->start(20);
2016  }
2017  }
2018  }
2019 
2020 
2021  // MouseRelease ? -> stop timer
2022  if( _event->type() == QEvent::MouseButtonRelease)
2023  {
2024  smart_move_timer_->stop();
2025  cur_smart_move_obj_ = NULL;
2026  }
2027 
2028 
2029  // call move event
2030  me_move( _event);
2031 }
2032 
2033 //-----------------------------------------------------------------------------
2034 
2035 void
2036 PolyLinePlugin::
2037 slotEditModeChanged()
2038 {
2039  PluginFunctions::pickMode("PolyLine");
2040  PluginFunctions::actionMode(Viewer::PickingMode);
2041 }
2042 
2043 //-----------------------------------------------------------------------------
2044 
2045 void
2048 {
2049  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(_lineObject->objectData(CIRCLE_DATA) );
2050  GlutPrimitiveNode* H0, *H1, *C;
2051  _lineObject->getAdditionalNode(C, name(), "circle");
2052  _lineObject->getAdditionalNode(H0, name(), "handle0");
2053  _lineObject->getAdditionalNode(H1, name(), "handle1");
2054  ACG::Vec3d h0 = circleData->circleCenter_ + circleData->circleMainAxis_ * circleData->circleMainRadius_,
2055  h1 = circleData->circleCenter_ + circleData->circleSideAxis_ * circleData->circleSideRadius_;
2056  if(C)
2057  C->set_position(circleData->circleCenter_);
2058  if(H0)
2059  H0->set_position(moveCircle_IsFloating ? h0 : createCircle_getHit(circleData, h0));
2060  if(H1)
2061  H1->set_position(moveCircle_IsFloating ? h1 : createCircle_getHit(circleData, h1));
2062 }
2063 
2064 //-----------------------------------------------------------------------------
2065 
2066 void
2067 PolyLinePlugin::
2068 slot_setCirclePointNum(int i)
2069 {
2070  PolyLineObject* _lineObject;
2072  updatePolyEllipse(_lineObject, i);
2073 }
2074 
2075 //-----------------------------------------------------------------------------
2076 
2077 void
2078 PolyLinePlugin::
2079 slot_setSplinePointNum(int i)
2080 {
2081  PolyLineObject* _lineObject;
2083  updatePolyBezierSpline(_lineObject, i);
2084 }
2085 
2086 //-----------------------------------------------------------------------------
2087 
2088 void
2090 slotPickToolbarAction(QAction* _action) {
2091  if ( _action == insertAction_ ) {
2092  tool_->rb_insert->setChecked(true);
2093  } else if ( _action == insertCircleAction_ ) {
2094  tool_->rb_InsertCircle->setChecked(true);
2095  } else if ( _action == insertSplineAction_ ) {
2096  tool_->rb_InsertSpline->setChecked(true);
2097  } else if ( _action == deleteAction_ ) {
2098  tool_->rb_delete->setChecked(true);
2099  } else if ( _action == moveAction_ ) {
2100  tool_->rb_move->setChecked(true);
2101  } else if ( _action == smartMoveAction_ ) {
2102  tool_->rb_smart_move->setChecked(true);
2103  } else if ( _action == mergeAction_ ) {
2104  tool_->rb_merge->setChecked(true);
2105  } else if ( _action == splitAction_ ) {
2106  tool_->rb_split->setChecked(true);
2107  }
2108 }
2109 
2110 void
2112 slotSetPolyLineMode(QAction* _action) {
2113  if (_action == polyLineAction_ ){
2114  PluginFunctions::actionMode(Viewer::PickingMode);
2115  PluginFunctions::pickMode("PolyLine");
2116 
2117  polyLineAction_->setChecked( true );
2118  }
2119 }
2120 
2121 //-----------------------------------------------------------------------------
2122 
2123 
2124 void
2125 PolyLinePlugin::
2126 slotEnablePickMode(QString _name)
2127 {
2128  PluginFunctions::pickMode("PolyLine");
2129  PluginFunctions::actionMode(Viewer::PickingMode);
2130 
2131  if(tool_ )
2132  {
2133  if(_name == "INSERT")
2134  tool_->rb_insert->setChecked(true);
2135  else if(_name == "DELETE")
2136  tool_->rb_delete->setChecked(true);
2137  else if(_name == "MOVE")
2138  tool_->rb_move->setChecked(true);
2139  else if(_name == "SPLIT")
2140  tool_->rb_split->setChecked(true);
2141  else if(_name == "MERGE")
2142  tool_->rb_merge->setChecked(true);
2143  else if( _name == "SMART_MOVE")
2144  tool_->rb_smart_move->setChecked(true);
2145  }
2146 }
2147 
2148 //-----------------------------------------------------------------------------
2149 
2150 bool
2151 PolyLinePlugin::
2152 pick_triangle_mesh( QPoint mPos,
2153  TriMeshObject*& _mesh_object_, TriMesh::FaceHandle& _fh, TriMesh::VertexHandle& _vh, ACG::Vec3d& _hitPoint)
2154 {
2155  // invalidate return values
2156  _fh = TriMesh::FaceHandle (-1);
2157  _vh = TriMesh::VertexHandle(-1);
2158 
2159  unsigned int target_idx = 0, node_idx = 0;
2160  ACG::Vec3d hit_point;
2161 
2162 
2163 
2164  if( PluginFunctions::scenegraphPick( ACG::SceneGraph::PICK_FACE, mPos, node_idx, target_idx, &hit_point ) )
2165  {
2166  // first check if a sphere was clicked
2167  BaseObjectData* object(0);
2168  if( PluginFunctions::getPickedObject( node_idx, object ) )
2169  {
2170  if( object->picked( node_idx ) && object->dataType(DATA_TRIANGLE_MESH) )
2171  {
2172  // get mesh object
2173  _mesh_object_ = dynamic_cast<TriMeshObject*>(object);
2174 
2175  // get mesh and face handle
2176  TriMesh & m = *PluginFunctions::triMesh(object);
2177  _fh = m.face_handle(target_idx);
2178 
2179  TriMesh::FaceVertexIter fv_it(m,_fh);
2180  TriMesh::VertexHandle closest = *fv_it;
2181  float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
2182 
2183  ++fv_it;
2184  if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2185  shortest_distance = (m.point(*fv_it ) - hit_point).sqrnorm();
2186  closest = *fv_it;
2187  }
2188 
2189  ++fv_it;
2190  if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2191  // Unnecessary : shortest_distance = (m.point(*fv_it ) - hit_point).sqrnorm();
2192  closest = *fv_it;
2193  }
2194 
2195  // stroe closest vh
2196  _vh = closest;
2197  _hitPoint = hit_point;
2198 
2199  return true;
2200  }
2201  }
2202  }
2203  return false;
2204 }
2205 
2206 //-----------------------------------------------------------------------------
2207 
2208 void
2209 PolyLinePlugin::
2210 slotUpdateContextMenu(int objectId)
2211 {
2212  copyPaste_ObjectId_ = objectId;
2213  copyPaste_Action_->setVisible(pickToolbar_->isVisible());
2214 }
2215 
2216 void
2217 PolyLinePlugin::
2218 me_copyPasteMouse(QMouseEvent* _event)
2219 {
2220  //get the object
2221  PolyLineObject* oldObj, *newObj;
2222  if(copyPaste_ObjectId_ == -1 || !PluginFunctions::getObject(copyPaste_ObjectId_, oldObj) || !PluginFunctions::getObject(copyPaste_NewObjectId_, newObj))
2223  {
2224  //something went wrong, leave the copying mode
2225  copyPaste_ObjectId_ = copyPaste_ActionType_ - 1;
2226  }
2227  //determine the world pos
2228  unsigned int target_idx = 0, node_idx = 0;
2229  ACG::Vec3d hit_point;
2230  if( PluginFunctions::scenegraphPick( ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hit_point ) ) {
2231  if(copyPaste_ActionType_ == 1) {//duplicate
2232  //object being duplicated
2233  PolyLineCircleData* oldCircleData = dynamic_cast<PolyLineCircleData*>(oldObj->objectData(CIRCLE_DATA));
2234  PolyLineBezierSplineData* oldSplineData = dynamic_cast<PolyLineBezierSplineData*>(oldObj->objectData(BEZSPLINE_DATA));
2235  //newly created object
2236  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(newObj->objectData(CIRCLE_DATA));
2237  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(newObj->objectData(BEZSPLINE_DATA));
2238 
2239  if(oldCircleData) {
2240  BaseNode* node = find_node( PluginFunctions::getRootNode(), node_idx );
2241  GlutPrimitiveNode* glutNode = dynamic_cast<GlutPrimitiveNode*>(node);
2242  if(glutNode)//the hit_point is on the center handle
2243  me_GetMeshHit(_event, glutNode, hit_point, circleData->circleMeshIndex_, target_idx);
2244 
2245  circleData-> circleCenter_ = hit_point;
2246  updatePolyEllipse(newObj, tool_->sb_CirclePointNum->value());
2247  updateHandles(newObj);
2248  }
2249  else if(oldSplineData) {
2250  for(int i = 0; i < (int)splineData->points_.size(); i++) {
2251  ACG::Vec3d onMeshNor, oldPos = splineData->points_[i].position;
2252  ACG::Vec3d onMesh = getPointOnMesh(splineData, copyPaste_RelativePoints_[i] + hit_point, &onMeshNor);
2253  splineData->points_[i].position = onMesh;
2254  splineData->points_[i].normal = onMeshNor;
2255  if(i) {
2256  int handleIndex = 2 * i - 1;
2257  ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.norm();
2258  ACG::Vec3d point = forw + onMesh;
2259  splineData->handles_[handleIndex] = point;
2260  }
2261  if(i != ((int)splineData->points_.size() - 1)) {
2262  int handleIndex = 2 * i;
2263  ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.norm();
2264  ACG::Vec3d point = forw + onMesh;
2265  splineData->handles_[handleIndex] = point;
2266  }
2267  }
2268  GlutLineNode* lineN;
2269  if(!newObj->getAdditionalNode(lineN, name(), "line", 0))
2270  return;
2271  updatePolyBezierHandles(newObj, lineN);
2272  updatePolyBezierSpline(newObj, tool_->sb_SplineSegNum->value());
2273  }
2274  else {
2275  for(size_t i = 0; i < newObj->line()->n_vertices(); i++)
2276  newObj->line()->point(i) = hit_point + copyPaste_RelativePoints_[i];
2277  emit updatedObject(newObj->id(), UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
2278  }
2279 
2280  //place the circle here and exit the copy paste state
2281  if(_event->type() == QEvent::MouseButtonPress) {
2282  copyPaste_ActionType_ = copyPaste_ObjectId_ = -1;
2283  }
2284  }
2285  else if(copyPaste_ActionType_ == 2) {//instanciate
2286 
2287  }
2288  }
2289 }
2290 
2291 void
2292 PolyLinePlugin::
2293 slot_duplicate()
2294 {
2295  PolyLineObject* obj;
2296  if(copyPaste_ObjectId_ == -1 || !PluginFunctions::getObject(copyPaste_ObjectId_, obj))
2297  return;
2298  //set mode for mouse move event
2299  unsigned int target_idx = 0, node_idx = 0;
2300  ACG::Vec3d hit_point;
2301  //determine the world coordinate of the mouse
2302  QPoint mPos = copyPaste_LastMouse;
2303  if( PluginFunctions::scenegraphPick( ACG::SceneGraph::PICK_ANYTHING, mPos, node_idx, target_idx, &hit_point ) ) {
2304  copyPaste_ActionType_ = 1;
2305 
2306  PolyLineCircleData* circleData = dynamic_cast<PolyLineCircleData*>(obj->objectData(CIRCLE_DATA));
2307  PolyLineBezierSplineData* splineData = dynamic_cast<PolyLineBezierSplineData*>(obj->objectData(BEZSPLINE_DATA));
2308 
2309  //create the new object
2310  int new_line_id;
2311  emit addEmptyObject(DATA_POLY_LINE, new_line_id);
2312  BaseObjectData *newObj = 0;
2313  PluginFunctions::getObject(new_line_id, newObj);
2314  obj->target(true);
2316  newLine->materialNode()->set_random_color();
2318  copyPaste_RelativePoints_.clear();
2319  if(circleData) {
2320  PolyLineCircleData* newData = new PolyLineCircleData(*circleData);//use a new instance!
2321  newLine->setObjectData(CIRCLE_DATA, newData);
2322  newLine->lineNode()->drawMode(ACG::SceneGraph::DrawModes::WIREFRAME);
2323  createCircle_createUI(new_line_id);
2324  }
2325  else if(splineData) {
2326  PolyLineBezierSplineData* newData = new PolyLineBezierSplineData(*splineData);
2327  newLine->setObjectData(BEZSPLINE_DATA, newData);
2328  createSpline_createUI(new_line_id);
2329  newLine->lineNode()->drawMode(ACG::SceneGraph::DrawModes::WIREFRAME);
2330 
2331  for(size_t i = 0; i < newData->points_.size(); i++)
2332  copyPaste_RelativePoints_.push_back(newData->points_[i].position - hit_point);
2333  }
2334  else {
2336  newLine->line()->set_vertex_radius(obj->line()->vertex_radius());
2337  for(size_t i = 0; i < obj->line()->n_vertices(); i++) {
2338  newLine->line()->add_point(obj->line()->point(i));
2339  copyPaste_RelativePoints_.push_back(obj->line()->point(i) - hit_point);
2340  }
2341  }
2342  emit updatedObject(new_line_id, UPDATE_GEOMETRY | UPDATE_TOPOLOGY);
2343  copyPaste_NewObjectId_ = new_line_id;
2344  }
2345 }
2346 
2347 void
2348 PolyLinePlugin::
2349 slot_instanciate()
2350 {
2351  PolyLineObject* obj;
2352  if(copyPaste_ObjectId_ == -1 || !PluginFunctions::getObject(copyPaste_ObjectId_, obj))
2353  return;
2354  copyPaste_ActionType_ = 2;
2355  //set mode for mouse move event
2356 }
2357 
2358 #if QT_VERSION < 0x050000
2359  Q_EXPORT_PLUGIN2( PolyLinePlugin , PolyLinePlugin );
2360 #endif
2361 
BaseObject *& objectRoot()
Get the root of the object structure.
QString name()
Name of the Plugin.
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
Definition: DrawModes.cc:87
Predefined datatypes.
Definition: DataTypes.hh:96
QAction * deleteAction_
Called by pick Toolbar.
QAction * splitAction_
Called by pick Toolbar.
void set_random_color()
Generates a random color and sets it.
ACG::GLState & glState()
Get the glState of the Viewer.
int createSpline_CurrSelIndex_
The index of the currently created spline.
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:144
void setObjectDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, const bool &_force=false)
Set the draw mode for the object.
void append(const PolyLineT< PointT > &_pl)
Append second polyline _pl to this one.
Definition: PolyLineT.cc:1387
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
ACG::SceneGraph::GlutPrimitiveNode * moveBezSpline_SelNode_
The handle which is being dragged.
DrawMode WIREFRAME
draw wireframe
Definition: DrawModes.cc:84
void project_to_mesh(const MeshT &_mesh, SpatialSearchT *_ssearch=0)
Project polyline points to nearest surface points (use spatial search!!!)
Definition: PolyLineT.cc:937
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
void collapse(Scalar _smallest)
Collapse polyline.
Definition: PolyLineT.cc:672
bool getObject(int _identifier, BSplineCurveObject *&_object)
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:926
PolyLinePlugin()
default constructor
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
void delete_point(int _idx)
Delete point at _idx.
Definition: PolyLineT.cc:417
Scalar vertex_radius() const
get ball-radius of vertices
Definition: PolyLineT.hh:348
ACG::SceneGraph::PolyLineNodeT< PolyLine > * lineNode()
Get the scenegraph Node.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
The Menu will be shown when an object was picked.
void smooth_uniform_laplace2()
Squared laplacian smoothing.
Definition: PolyLineT.cc:792
int createCircle_LastSelIndex_
Use this one to mark the last index to update the number of points.
Point & back()
Get last point of the polyline ( no range check!!!)
Definition: PolyLineT.hh:166
QAction * insertAction_
Called by pick Toolbar.
int createCircle_CurrSelIndex_
The object which is being modified(created, dragged)
ACG::SceneGraph::BaseNode * getRootNode()
Get the root node for data objects.
ACG::Vec3d moveCircle_LastHitPos_
The last valid hit on the mesh.
void updatePolyBezierHandles(PolyLineObject *_lineObject, ACG::SceneGraph::LineNode *_line)
Updates all the handles on the PolyBezier.
void updatePolyBezierSpline(PolyLineObject *_lineObject, unsigned int _pointsPerSegment)
Generates points for the spline, updates handles.
void enablePicking(bool _enable)
Enable or disable picking for this Object.
QToolBar * toolbar_
Called by Toolbar to enable pick mode.
void invert()
Invert polyline that first vertex becomes last.
Definition: PolyLineT.cc:1357
int moveBezSpline_SelIndex_
The object which is being moved.
bool is_closed() const
Check if the polyline is marked as closed.
Definition: PolyLineT.hh:113
double sceneRadius()
Returns the current scene radius from the active examiner widget.
void set_closed(const bool _c)
Set if the polyline should be closed and therefore forms a loop.
Definition: PolyLineT.hh:119
int id() const
Definition: BaseObject.cc:201
PolyLine * line()
return a pointer to the line
bool getPickedObject(const unsigned int _node_idx, BaseObjectData *&_object)
Get the picked mesh.
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT.cc:351
virtual bool picked(uint _node_idx)
detect if the node has been picked
#define DATA_POLY_LINE
Definition: PolyLine.hh:70
void set_vertex_radius(const Scalar _r)
set ball-radius of vertices
Definition: PolyLineT.hh:351
Update type class.
Definition: UpdateType.hh:70
void resize(unsigned int _n)
Resize current polyline.
Definition: PolyLineT.cc:231
MaterialNode * materialNode()
get a pointer to the materialnode
void setObjectData(QString _dataName, PerObjectData *_data)
Definition: BaseObject.cc:792
EditMode
Edit Mode of PolyLinePlugin.
bool target()
Definition: BaseObject.cc:284
const Vec3d get_position(int _idx=0) const
get position
void slotScissorButton()
Scissor Button was hit.
const std::string pickMode()
Get the current Picking mode.
void updateHandles(PolyLineObject *_lineObject)
Updates the center, forward and side handle of the Poly ellipse.
void set_position(const Vec3d &_p, int _idx=0)
set position
std::vector< Point > & points()
Get all points of the polyline.
Definition: PolyLineT.hh:154
PolyLineObject * polyLineObject(BaseObjectData *_object)
Cast an BaseObject to a PolyLineObject if possible.
Kernel::FaceVertexIter FaceVertexIter
Circulator.
Definition: PolyMeshT.hh:170
void smooth_uniform_laplace3()
Cubic laplacian smoothing.
Definition: PolyLineT.cc:849
bool getAdditionalNode(NodeT *&_node, QString _pluginName, QString _nodeName, int _id=0)
get an addition node from the object
void updatePolyEllipse(PolyLineObject *_lineObject, unsigned int _pointCount)
Generates points for the ellipse.
void viewingDirection(const ACG::Vec3d &_dir, const ACG::Vec3d &_up, int _viewer)
Set the viewing direction.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
void subdivide(Scalar _largest)
Subdivide polyline.
Definition: PolyLineT.cc:619
ACG::SceneGraph::GlutPrimitiveNode * moveCircle_SelNode_
The handle which is being dragged.
QAction * smartMoveAction_
Called by pick Toolbar.
void split(unsigned int _split_idx, PolyLineT< PointT > &_new_pl)
Split closed polyline at vertex with index _split_idx.
Definition: PolyLineT.cc:1463
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
QActionGroup * toolBarActions_
Called by Toolbar to enable pick mode.
void boundingBox(ACG::Vec3d &_bbMin, typename ACG::Vec3d &_bbMax)
Get the BoundingBox of this object.
Definition: MeshObjectT.cc:637
Point & point(unsigned int _i)
Get a point of the polyline.
Definition: PolyLineT.hh:148
OMTriangleBSP * requestTriangleBsp()
Definition: MeshObjectT.cc:756
void slotTriggerCutPlaneSelect()
Generate PolyLine after the cutPlane has been drawn.
void slotScissorLinesButton()
Scissor Button for multiple polylines was hit.
QActionGroup * pickToolBarActions_
Called by pick Toolbar.
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
DrawMode POINTS_SHADED
draw shaded points (requires point normals)
Definition: DrawModes.cc:81
std::string name() const
Returns: name of node (needs not be unique)
Definition: MeshNode2T.cc:446
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
picks verices (may not be implemented for all nodes)
Definition: BaseNode.hh:108
Viewer::ActionMode actionMode()
Get the current Action mode.
Scalar length() const
Compute the length of the polyline (in future cached method)
Definition: PolyLineT.cc:484
ACG::Vec3d createCircle_getHit(PolyLineCircleData *_circleData, ACG::Vec3d _hit_point)
Returns point on mesh or point on the normal plane.
unsigned int meshIndex_
Index of the corresponding mesh.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:741
QAction * cutAction_
Called by pick Toolbar.
QToolBar * pickToolbar_
Called by pick Toolbar.
QtPlaneSelect * planeSelect_
Plane selection tool.
void add_point(const Point &_p)
Append a point to the polyline.
Definition: PolyLineT.cc:288
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM >>().sqrnorm()))
compute euclidean norm
Definition: Vector11T.hh:408
PolyLineToolbarWidget * tool_
Widget for Toolbox.
decltype(std::declval< S >()*std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:396
void slotSetPolyLineMode(QAction *_action)
Called by Toolbar to enable pick mode.
QAction * mergeAction_
Called by pick Toolbar.
InterpolatePoint & getInterpolatePoint(unsigned int _handleIndex)
Retrieves the interpolate point based on the handle.
int moveBezSpline_SelSubIndex_
The index of the control or handle being moved.
void smooth_uniform_laplace()
Laplacian smoothing.
Definition: PolyLineT.cc:738
QAction * insertCircleAction_
Called by pick Toolbar.
ACG::Vec3d getPointOnMesh(PolyLineBezierSplineData *_SplineData, ACG::Vec3d _point, ACG::Vec3d *_nor=0)
Returns the nearest point on the mesh or if none could be found the input.
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool addAdditionalNode(NodeT *_node, QString _pluginName, QString _nodeName, int _id=0)
add an additional node to the object
void addInterpolatePoint(ACG::Vec3d _position, ACG::Vec3d _normal)
Adds a point to the end of the list and inserts control points.
IdList generatePolyLinesFromCut(int _objectId, Vector _planePoint, Vector _planeNormal)
Generates a polyLine of a plane intersection.
size_t n_vertices() const
Get number of vertices.
Definition: PolyLineT.hh:122
QAction * moveAction_
Called by pick Toolbar.
BaseObject * childExists(int _objectId)
Check if the element exists in the subtree of this element.
Definition: BaseObject.cc:527
QAction * insertSplineAction_
Called by pick Toolbar.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:819
int createSpline_LastSelIndex_
Use this one to mark the last index to update the number of points.
QAction * cutMultipleAction_
Called by pick Toolbar.
void split_closed(unsigned int _split_idx)
Split closed polyline at vertex with index _split_idx.
Definition: PolyLineT.cc:1431
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
bool finishSpline()
If possible calculates handles.
int generatePolyLineFromCut(int _objectId, Vector _planePoint, Vector _planeNormal, int _polyLineId=-1)
Generates a polyLine of a plane intersection.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
QAction * polyLineAction_
Called by Toolbar to enable pick mode.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void slotPickToolbarAction(QAction *_action)
Called by pick Toolbar.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:814