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