54#include "PolyLinePlugin.hh"
56#include <ACG/Scenegraph/ManipulatorNode.hh>
57#include <ACG/Scenegraph/LineNode.hh>
58#include <ACG/Scenegraph/GlutPrimitiveNode.hh>
59#include <ACG/QtScenegraph/QtTranslationManipulatorNode.hh>
67 GlutPrimitiveNode(
PolyLineObject* L,
const std::string& name,
int _index = -1)
68 :
ACG::SceneGraph::GlutPrimitiveNode(
ACG::SceneGraph::GlutPrimitiveNode::SPHERE, L->manipulatorNode(), name)
86 :
ACG::SceneGraph::LineNode(LineSegmentsMode, L->manipulatorNode(), name)
105 polyLineAction_(nullptr),
106 toolBarActions_(nullptr),
108 pickToolbar_(nullptr),
109 pickToolBarActions_(nullptr),
110 insertAction_(nullptr),
111 insertCircleAction_(nullptr),
112 insertSplineAction_(nullptr),
113 deleteAction_(nullptr),
114 moveAction_(nullptr),
115 smartMoveAction_(nullptr),
116 mergeAction_(nullptr),
117 splitAction_(nullptr),
119 cutMultipleAction_(nullptr),
121 cur_polyline_obj_(nullptr),
123 move_point_ref_(nullptr),
124 create_point_ref_(nullptr),
125 createCircle_CurrSelIndex_(-1),
126 createCircle_LastSelIndex_(-1),
127 moveCircle_SelNode_(nullptr),
128 moveCircle_IsLocked(false),
129 moveCircle_IsFloating(false),
130 copyPaste_Action_(nullptr),
131 copyPaste_ObjectId_(-1),
132 copyPaste_ActionType_(-1),
133 copyPaste_NewObjectId_(-1),
134 createSpline_CurrSelIndex_(-1),
135 createSpline_LastSelIndex_(-1),
136 moveBezSpline_SelNode_(nullptr),
137 moveBezSpline_SelIndex_(-1),
138 moveBezSpline_SelSubIndex_(0),
140 smart_move_timer_(nullptr),
141 cur_smart_move_obj_(nullptr),
142 planeSelect_(nullptr)
150 delete copyPaste_Action_;
160 QSize size(100, 100);
162 tool_->setObjectName(
"PolyLineToolbar");
165 connect(
tool_->pb_subdivide,SIGNAL(clicked() ),
this,SLOT(slot_subdivide()));
166 connect(
tool_->subdivide_relative,SIGNAL(toggled(
bool) ),
this,SLOT(slot_subdivide_percent(
bool)));
167 connect(
tool_->pb_decimate,SIGNAL(clicked() ),
this,SLOT(slot_decimate()));
168 connect(
tool_->decimate_relative,SIGNAL(toggled(
bool) ),
this,SLOT(slot_decimate_percent(
bool)));
169#ifdef EXTENDED_POLY_LINE
170 connect(
tool_->pb_resample_on_edges,SIGNAL(clicked() ),
this,SLOT(slot_resample_on_edges()));
172 tool_->pb_resample_on_edges->setDisabled(
true);
174 connect(
tool_->pb_smooth,SIGNAL(clicked() ),
this,SLOT(slot_smooth()));
175 connect(
tool_->pb_smooth,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
176 connect(
tool_->pb_project,SIGNAL(clicked() ),
this,SLOT(slot_project()));
177 connect(
tool_->pb_project,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
178 connect(
tool_->pb_smooth_project,SIGNAL(clicked() ),
this,SLOT(slot_smooth_project()));
179 connect(
tool_->pb_smooth_project,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
181 connect(
tool_->rb_insert, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
182 connect(
tool_->rb_InsertCircle, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
183 connect(
tool_->rb_InsertSpline, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
184 connect(
tool_->rb_delete, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
185 connect(
tool_->rb_move, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
186 connect(
tool_->rb_smart_move, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
187 connect(
tool_->rb_merge, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
188 connect(
tool_->rb_split, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
190 connect(
tool_->sb_CirclePointNum, SIGNAL(valueChanged(
int)),
this, SLOT(slot_setCirclePointNum(
int)));
191 connect(
tool_->sb_SplineSegNum, SIGNAL(valueChanged(
int)),
this, SLOT(slot_setSplinePointNum(
int)));
193 tool_->rb_insert->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_insert.png") );
194 tool_->rb_InsertCircle->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_circle.png") );
195 tool_->rb_InsertSpline->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_bezier.png") );
196 tool_->rb_delete->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_delete.png") );
197 tool_->rb_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_move.png") );
198 tool_->rb_smart_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_move.png") );
199 tool_->rb_merge->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_merge.png") );
200 tool_->rb_split->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_split.png") );
207 toolIcon_ =
new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polyline.png");
217slotMouseEvent( QMouseEvent* _event )
219 copyPaste_LastMouse = _event->pos();
222 if (_event->modifiers() & (Qt::ControlModifier))
226 && _event->button() != Qt::RightButton) {
233 case PL_INSERTCIRCLE:
234 me_insertCircle(_event);
237 case PL_INSERTSPLINE:
238 me_insertSpline(_event);
258 me_smart_move(_event);
262 me_copyPasteMouse(_event);
273void PolyLinePlugin::slotKeyEvent(QKeyEvent* event) {
274 switch (event->key()) {
277 if(mode() == PL_INSERT && cur_polyline_obj_ && cur_insert_id_ != -1) {
280 if (event->modifiers() & (Qt::ShiftModifier))
286 cur_polyline_obj_ = 0;
287 create_point_ref_ = 0;
289 clearStatusMessage();
291 else if(mode() == PL_INSERTSPLINE) {
304slotPickModeChanged(
const std::string& _mode)
307 cutAction_->setChecked( _mode == CREATE_CUT_POLYLINE );
320 emit addHiddenPickMode(
"PolyLine");
321 emit setPickModeMouseTracking(
"PolyLine",
true);
322 emit addHiddenPickMode( CREATE_CUT_POLYLINE );
323 emit addHiddenPickMode( CREATE_CUT_POLYLINES );
325 emit registerKey(Qt::Key_Return, Qt::NoModifier, tr(
"Terminate creation of poly line."),
true);
326 emit registerKey(Qt::Key_Return, Qt::ShiftModifier, tr(
"Terminate creation of poly line and create loop."),
true);
329 toolbar_ =
new QToolBar(tr(
"PolyLine Editing"));
330 toolbar_->setObjectName(
"PolyLineEditingToolbar");
338 polyLineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_insert.png") );
343 cutAction_ =
new QAction(tr(
"&Create polyline at intersection with plane"),
this);
345 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."));
346 cutAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polyline.png") );
351 cutMultipleAction_ =
new QAction(tr(
"&Create polylines at intersection with plane"),
this);
353 cutMultipleAction_->setStatusTip(tr(
"Create polylines by specifying a plane with which the object is then intersected. The polylines will be created at the intersection."));
354 cutMultipleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polylines.png") );
364 pickToolbar_->setObjectName(
"PolyLine_Editing_Toolbar");
365 pickToolbar_->setAttribute(Qt::WA_AlwaysShowToolTips,
true);
372 "Use <Doubleclick> to finish the line.\n"
373 "Hold <Shift> to close line on finish."));
374 insertAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_insert.png") );
381 "<Click> to select the center.\n"
382 "Drag to specify the radius."));
384 insertCircleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_circle.png") );
391 "<Click> to select the points."));
393 insertSplineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_bezier.png") );
398 deleteAction_->setStatusTip(tr(
"Delete a complete PolyLine."));
399 deleteAction_->setToolTip(tr(
"Delete a complete PolyLine.\n"
400 "<Click> on the lines you want to delete."));
401 deleteAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_delete.png") );
408 smartMoveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_move.png") );
415 "Drag one endpoint of a PolyLine to the EndPoint of another one.\n"));
416 mergeAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_merge.png") );
421 splitAction_->setStatusTip(tr(
"Split a PolyLine at a given point."));
422 splitAction_->setToolTip(tr(
"Split a PolyLine at a given point.\n"
423 "<Click> on the vertex where you want to split the PolyLine and drag it away."));
424 splitAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_split.png") );
431 moveAction_->setStatusTip(tr(
"Move a Vertex of a PolyLine"));
432 moveAction_->setToolTip(tr(
"Move a single Vertex of a PolyLine."));
433 moveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_move.png") );
442 smart_move_timer_ =
new QTimer(
this);
443 connect(smart_move_timer_, SIGNAL(timeout()),
this, SLOT(slot_smart_move_timer()));
448 connect(
planeSelect_, SIGNAL( updateViewProxy( ) ),
this, SIGNAL( updateView() ) );
449 connect(
planeSelect_, SIGNAL( nodeVisChangedProxy(
int) ),
this, SIGNAL(nodeVisibilityChanged(
int) ) );
452 copyPaste_Action_ =
new QAction(
"Duplicate", 0);
453 connect(copyPaste_Action_,SIGNAL(triggered() ),
this,SLOT(slot_duplicate()));
492 emit log(
"Cutting object " + object->
name());
495 emit log(
"Only Meshes are supported at the moment ");
506 QString command =
"generatePolyLineFromCut(" + QString::number(object->
id()) +
",Vector("
507 + QString::number(point[0]) +
"," + QString::number(point[1]) +
"," + QString::number(point[2]) +
"),Vector("
508 + QString::number(normal[0]) +
"," + QString::number(normal[1]) +
"," + QString::number(normal[2]) +
"));";
509 emit scriptInfo(command);
514 if (o_it->id() !=
object->id()) {
526 QString command =
"generatePolyLinesFromCut(" + QString::number(object->
id()) +
",Vector("
527 + QString::number(point[0]) +
"," + QString::number(point[1]) +
"," + QString::number(point[2]) +
"),Vector("
528 + QString::number(normal[0]) +
"," + QString::number(normal[1]) +
"," + QString::number(normal[2]) +
"));";
529 emit scriptInfo(command);
534 if (o_it->id() !=
object->id()) {
539 for (
unsigned int i = 0 ; i < objectIds.size() ; ++i ) {
541 if ( objectIds[i] != -1)
557 double max_length =
tool_->dsb_subdivide->value();
560 if (max_length == 0.0)
579void PolyLinePlugin::slot_subdivide_percent(
bool _checked) {
583 double total_length = 0;
594 double v = total_length / double(n_active_pl);
599 if (n_active_pl > 0) {
600 double val_new =
tool_->dsb_subdivide->value() / v;
601 tool_->dsb_subdivide->setValue(val_new);
603 emit log(
LOGWARN,
"Could not find any active polyline!");
608 if (n_active_pl > 0) {
609 double val_new =
tool_->dsb_subdivide->value() * v;
610 tool_->dsb_subdivide->setValue(val_new);
612 emit log(
LOGWARN,
"Could not find any active polyline!");
626 double min_length =
tool_->dsb_decimate->value();
643void PolyLinePlugin::slot_decimate_percent(
bool _checked)
648 double total_length = 0;
659 double v = total_length / double(n_active_pl);
664 if (n_active_pl > 0) {
665 double val_new =
tool_->dsb_subdivide->value() / v;
666 tool_->dsb_decimate->setValue(val_new);
668 emit log(
LOGWARN,
"Could not find any active polyline!");
673 if (n_active_pl > 0) {
674 double val_new =
tool_->dsb_subdivide->value() * v;
675 tool_->dsb_decimate->setValue(val_new);
677 emit log(
LOGWARN,
"Could not find any active polyline!");
685#ifdef EXTENDED_POLY_LINE
689slot_resample_on_edges()
693 unsigned int n_targetMeshes(0);
697 if( n_targetMeshes != 1)
699 std::cerr <<
"Warning: resample_on_edges needs exactly 1 target mesh! Otherwise no operation is performed! \n";
712 TriMesh* mesh = tmesh_obj->
mesh();
723 std::cerr <<
"resample " << o_it2->name().toStdString() << std::endl;
747 for(
int i=0; i<
tool_->sb_smooth_iter->value(); ++i)
748 if(
tool_->rb_smooth_c0->isChecked())
752 if(
tool_->rb_smooth_c1->isChecked())
756 if(
tool_->rb_smooth_c2->isChecked())
775 for (
int i = 0; i <
tool_->sb_smooth_iter->value(); ++i)
776 if (
tool_->rb_smooth_c0->isChecked())
779 else if (
tool_->rb_smooth_c1->isChecked())
782 else if (
tool_->rb_smooth_c2->isChecked())
798 std::vector<TriMesh*> meshes;
799 std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
808 meshes.push_back(tmesh_obj->
mesh());
835 std::vector<TriMesh*> meshes;
836 std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
846 meshes.push_back(tmesh_obj->
mesh());
865 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
867 for (
int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
886 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
888 for (
int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
905slot_smart_move_timer()
907 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
909 if (smooth_project_iter)
910 slot_smooth_project(cur_smart_move_obj_);
912 slot_smooth(cur_smart_move_obj_);
920PolyLinePlugin::slotObjectUpdated(
int _identifier,
const UpdateType &_type )
927 GlutPrimitiveNode* H = 0, *C = 0;
930 if(circleData && !C) {
931 createCircle_createUI(_identifier);
933 else if(splineData && !H) {
934 createSpline_createUI(_identifier);
944 if(copyPaste_ObjectId_ != -1 && copyPaste_ActionType_ != -1)
945 return PL_COPY_PASTE;
949 if(
tool_->rb_insert->isChecked() )
return PL_INSERT;
950 if(
tool_->rb_InsertCircle->isChecked() )
return PL_INSERTCIRCLE;
951 if(
tool_->rb_InsertSpline->isChecked() )
return PL_INSERTSPLINE;
952 else if(
tool_->rb_delete->isChecked() )
return PL_DELETE;
953 else if(
tool_->rb_move->isChecked() )
return PL_MOVE;
954 else if(
tool_->rb_split->isChecked() )
return PL_SPLIT;
955 else if(
tool_->rb_merge->isChecked() )
return PL_MERGE;
956 else if(
tool_->rb_smart_move->isChecked())
return PL_SMART_MOVE;
966me_insert( QMouseEvent* _event )
968 if (_event->type() == QEvent::MouseMove) {
970 if (create_point_ref_) {
972 size_t node_idx, target_idx;
975 *create_point_ref_ = (PolyLine::Point) hit_point;
985 size_t node_idx, target_idx;
989 switch (_event->type()) {
991 case QEvent::MouseButtonPress: {
1011 cur_polyline_obj_->
line()->
add_point((PolyLine::Point) hit_point);
1013 emit showStatusMessage(tr(
"Double click/Enter to terminate poly line. Use with shift to create loop."));
1017 cur_polyline_obj_->
line()->
add_point((PolyLine::Point) hit_point);
1018 create_point_ref_ = &cur_polyline_obj_->
line()->
points().back();
1027 case QEvent::MouseButtonDblClick: {
1029 if (_event->modifiers() & (Qt::ShiftModifier)) {
1042 cur_insert_id_ = -1;
1043 cur_polyline_obj_ = 0;
1044 create_point_ref_ = 0;
1046 clearStatusMessage();
1059double getRad(
int meshIdx)
1064 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1065 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1066 mesh->boundingBox(bbMin, bbMax);
1067 return 0.005*(bbMax-bbMin).
norm();
1074void PolyLinePlugin::
1075createCircle_createUI(
int _polyLineObjectID)
1084 double rad = getRad(lineData->circleMeshIndex_);
1086 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle0");
1087 handle0->get_primitive(0).color =
ACG::Vec4f(1,0,0,1);
1088 handle0->set_size(rad);
1090 handle0->enablePicking(
true);
1091 handle0->set_position(lineData->circleCenter_ + lineData->circleMainAxis_ * lineData->circleMainRadius_);
1095 GlutPrimitiveNode* handle1 =
new GlutPrimitiveNode(lineObject,
"N_Handle1");
1096 handle1->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1097 handle1->set_size(rad);
1099 handle1->enablePicking(
true);
1100 handle1->set_position(lineData->circleCenter_ + lineData->circleSideAxis_ * lineData->circleSideRadius_);
1104 GlutPrimitiveNode* cenNode =
new GlutPrimitiveNode(lineObject,
"N_Center");
1105 cenNode->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1106 cenNode->set_size(rad);
1108 cenNode->enablePicking(
true);
1109 cenNode->set_position(lineData->circleCenter_);
1113 emit updatedObject(_polyLineObjectID,
UPDATE_ALL);
1118void PolyLinePlugin::
1119me_insertCircle(QMouseEvent* _event)
1125 if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point) && _event->type() != QEvent::MouseButtonRelease)
1134 const ACG::Vec3d n = circleData->circleNormal_, x0 = circleData->circleCenter_;
1135 const double t = ((n | x0) - (n | hit_point)) / n.
sqrnorm();
1136 const ACG::Vec3d onPlane = hit_point + t * n, d = onPlane - x0;
1138 circleData->circleMainAxis_ = (onPlane - x0).normalize();
1139 circleData->circleSideRadius_ = circleData->circleMainRadius_ = d.norm();
1140 circleData->circleSideAxis_ = (circleData->circleMainAxis_ % n).normalize();
1156 if(!mesh->mesh()->has_face_normals())
1157 mesh->mesh()->request_face_normals();
1167 else if(_event->type() == QEvent::MouseButtonRelease ) {
1181void PolyLinePlugin::
1182createSpline_createUI(
int _polyLineObjectID)
1193 GlutLineNode* lineN =
new GlutLineNode(lineObject,
"N_Line");
1195 lineN->enablePicking(
false);
1199 for(
unsigned int i = 0; i < splineData->points_.size(); i++) {
1200 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Control", i);
1201 handle0->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1202 handle0->set_size(rad);
1204 handle0->set_position(splineData->points_[i].position);
1206 handle0->enablePicking(
true);
1210 for(
unsigned int i = 0; i < splineData->handles_.size(); i++) {
1212 const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = control.position;
1214 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle", i);
1215 handle0->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1216 handle0->set_size(rad * 0.75);
1218 handle0->enablePicking(
true);
1219 handle0->set_position(hndlPos);
1223 GlutLineNode* lineNode;
1225 lineNode->add_line(ctrlPos, hndlPos);
1231 emit updatedObject(_polyLineObjectID,
UPDATE_ALL);
1250 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1251 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1252 mesh->boundingBox(bbMin, bbMax);
1257 GlutPrimitiveNode* control = 0;
1259 for(
unsigned int i = 0; i < splineData->points_.size(); i++) {
1261 control->enablePicking(
true);
1264 for(
unsigned int i = 0; i < splineData->handles_.size(); i++) {
1266 const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = controlPoint.position;
1268 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle", i);
1269 handle0->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1270 handle0->set_size(0.004*sizeBB.norm());
1272 handle0->enablePicking(
true);
1273 handle0->set_position(hndlPos);
1277 GlutLineNode* lineN;
1279 lineN->add_line(ctrlPos, hndlPos);
1290void PolyLinePlugin::
1291me_insertSpline(QMouseEvent* _event)
1299 if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point))
1302 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1303 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1304 mesh->boundingBox(bbMin, bbMax);
1307 if(!mesh->mesh()->has_face_normals())
1308 mesh->mesh()->request_face_normals();
1312 if(_event->type() == QEvent::MouseButtonPress) {
1332 GlutLineNode* lineN =
new GlutLineNode(newLine,
"N_Line");
1334 lineN->enablePicking(
false);
1339 ACG::Vec3d insert_Point = hit_point + nor * 0.003 * sizeBB.
norm();
1346 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Control", splineData->points_.size());
1347 handle0->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1348 handle0->set_size(0.005*sizeBB.norm());
1350 handle0->set_position(insert_Point);
1352 handle0->enablePicking(
false);
1359 if(_event->type() == QEvent::MouseButtonDblClick) {
1368me_delete( QMouseEvent* _event )
1371 if (_event->type() == QEvent::MouseButtonPress) {
1373 size_t node_idx, target_idx;
1383 emit deleteObject(obj->
id());
1399 if(moveCircle_SelNode_)
1402 if(moveCircle_SelNode_)
1407 _node_idx = obj->
id();
1413 if(!_moveCircle_SelNode_->
name().compare(
"N_Center"))
1415 _lineData->circleNormal_ = _nor;
1416 _lineData->circleCenter_ = _hit_point;
1417 _lineData->circleSideAxis_ = (_lineData->circleMainAxis_ % _lineData->circleNormal_).
normalize();
1418 _lineData->circleMainAxis_ = (_lineData->circleNormal_ % _lineData->circleSideAxis_).
normalize();
1422 const double cr = (_onPlane - _lineData->circleCenter_).
norm();
1424 if (!_moveCircle_SelNode_->
name().compare(
"N_Handle0")) {
1426 _lineData->circleMainRadius_ = cr;
1429 _lineData->circleSideRadius_ = cr;
1431 _lineData->circleMainAxis_ = axisa;
1432 _lineData->circleSideAxis_ = axisb;
1435 _lineData->circleSideRadius_ = cr;
1438 _lineData->circleMainRadius_ = cr;
1440 _lineData->circleSideAxis_ = axisa;
1441 _lineData->circleMainAxis_ = axisb;
1449me_move( QMouseEvent* _event )
1451 if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier && moveCircle_IsLocked)
1452 moveCircle_IsLocked = moveCircle_IsFloating =
false;
1455 if (_event->type() == QEvent::MouseButtonPress) {
1457 size_t node_idx, target_idx;
1462 GlutPrimitiveNode* glutNode =
dynamic_cast<GlutPrimitiveNode*
>(node);
1491 cur_move_id_ = cur_pol->
id();
1493 move_point_ref_ = &(cur_pol->
line()->
point(target_idx));
1500 if (_event->type() == QEvent::MouseMove){
1508 bool hasHit = me_GetMeshHit(_event,
moveCircle_SelNode_, hit_point, lineData->circleMeshIndex_, target_idx);
1509 if(lineData->circleMeshIndex_ == std::numeric_limits<unsigned int>::max())
return;
1510 if(!moveCircle_IsLocked && hasHit) {
1511 moveCircle_IsFloating =
false;
1512 ACG::Vec3d x0 = lineData->circleCenter_, n = lineData->circleNormal_;
1514 double t = ((n | x0) - (n | onMesh)) / n.
sqrnorm();
1520 me_UpdateCircleData(onMesh, onPlane, mesh->mesh()->normal(mesh->mesh()->face_handle(target_idx)),
moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1523 if((_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) {
1524 moveCircle_IsLocked =
true;
1525 moveCircle_LastHitNor_ = lineData->circleNormal_;
1531 moveCircle_IsFloating =
true;
1540 : lineData->circleNormal_;
1541 const double t = ((x0 | n) - (cameraPos | n)) / (cameraDir | n);
1542 const ACG::Vec3d onPlane = cameraPos + cameraDir * t;
1544 me_UpdateCircleData(onPlane, onPlane, n,
moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1558 if(lineData->
meshIndex_ == std::numeric_limits<unsigned int>::max())
1564 ACG::Vec3d onMesh = hit_point, onMeshNor = mesh->mesh()->normal(mesh->mesh()->face_handle(target_idx));
1568 lineData->points_[controlIndex].position = onMesh;
1569 lineData->points_[controlIndex].normal = onMeshNor;
1571 int handleIndex = 2 * controlIndex - 1;
1572 ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
1574 lineData->handles_[handleIndex] = point;
1576 if(controlIndex != ((
int)lineData->points_.size() - 1)) {
1577 int handleIndex = 2 * controlIndex;
1578 ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
1580 lineData->handles_[handleIndex] = point;
1591 double t = ((control.normal | control.position) - (control.normal | cameraPos)) / (control.normal | cameraDir);
1592 ACG::Vec3d onPlane = cameraPos + t * cameraDir;
1594 lineData->handles_[handleIndex] = onPlane;
1595 if(handleIndex % 2 == 1 && handleIndex != ((
int)lineData->handles_.size() - 1)) {
1596 double dist = (lineData->handles_[handleIndex + 1] - control.position).norm();
1597 if(_event->modifiers() & Qt::ShiftModifier)
1598 dist = (onPlane - control.position).norm();
1599 ACG::Vec3d dir = -(onPlane - control.position).normalize();
1600 lineData->handles_[handleIndex + 1] = control.position + dir * dist;
1602 if(handleIndex % 2 == 0 && handleIndex) {
1603 double dist = (lineData->handles_[handleIndex - 1] - control.position).norm();
1604 if(_event->modifiers() & Qt::ShiftModifier)
1605 dist = (onPlane - control.position).norm();
1606 ACG::Vec3d dir = -(onPlane - control.position).normalize();
1607 lineData->handles_[handleIndex - 1] = control.position + dir * dist;
1610 GlutLineNode* lineN;
1616 else if (move_point_ref_ != 0) {
1618 size_t node_idx, target_idx;
1620 (*move_point_ref_) = (PolyLine::Point) hit_point;
1628 if (_event->type() == QEvent::MouseButtonRelease) {
1629 if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier) {
1632 moveCircle_IsLocked = moveCircle_IsFloating =
false;
1636 moveCircle_IsLocked =
false;
1641 move_point_ref_ = 0;
1653me_split( QMouseEvent* _event )
1656 if (_event->type() == QEvent::MouseButtonPress) {
1658 move_point_ref_ = 0;
1660 size_t node_idx, target_idx;
1682 cur_move_id_ = cur_pol->
id();
1713 cur_move_id_ = cur_pol->
id();
1729 if (_event->type() == QEvent::MouseMove)
1730 if (move_point_ref_ != 0) {
1732 size_t node_idx, target_idx;
1736 (*move_point_ref_) = (PolyLine::Point) hit_point;
1745 if (_event->type() == QEvent::MouseButtonRelease) {
1747 if (cur_move_id_ != -1)
1750 move_point_ref_ = 0;
1761me_merge( QMouseEvent* _event )
1764 if (_event->type() == QEvent::MouseButtonPress) {
1766 move_point_ref_ = 0;
1769 size_t node_idx, target_idx;
1784 if (target_idx == cur_pol->
line()->
n_vertices() - 1 || target_idx == 0) {
1785 if (target_idx == 0) {
1791 cur_merge_id_ = cur_pol->
id();
1804 if (_event->type() == QEvent::MouseMove && cur_merge_id_ != -1)
1805 if (move_point_ref_ != 0) {
1806 size_t node_idx, target_idx;
1810 (*move_point_ref_) = (PolyLine::Point) hit_point;
1819 if (_event->type() == QEvent::MouseButtonRelease && cur_merge_id_ != -1) {
1820 PolyLine::Point p_save;
1823 if (move_point_ref_ != 0) {
1835 move_point_ref_ = 0;
1838 size_t node_idx, target_idx;
1847 PluginFunctions::invalidatePickCaches();
1849 bool merged =
false;
1862 if ( target_idx < second_pol->line()->n_vertices() ) {
1865 unsigned int second_idx = target_idx;
1870 bool inv_first(
false), inv_second(
false);
1873 if (first_idx == 0) {
1885 if (first_idx == first_pol->
line()->
n_vertices() - 1 && second_idx == 0) {
1887 if (first_pol->
id() == second_pol->
id()) {
1904 emit deleteObject(second_pol->
id());
1915 PluginFunctions::invalidatePickCaches();
1928 if ( target_idx < second_pol->line()->n_vertices() ) {
1931 unsigned int second_idx = target_idx;
1937 if (first_idx == 0) {
1946 if (first_pol->
id() == second_pol->
id() && first_idx == first_pol->
line()->
n_vertices() - 1 && second_idx == 0) {
1971 move_point_ref_ = 0;
1983me_smart_move( QMouseEvent* _event )
1986 if (_event->type() == QEvent::MouseButtonPress) {
1988 size_t node_idx, target_idx;
2001 cur_polyline_obj_ = cur_pol;
2008 cur_smart_move_obj_ = cur_pol;
2009 if (cur_pol->
line()->vertex_selections_available()) {
2010 if (!(_event->modifiers() & (Qt::ShiftModifier)))
2011 cur_pol->
line()->vertex_selection(target_idx) =
true;
2013 cur_pol->
line()->vertex_selection(target_idx) =
false;
2021 if (!(_event->modifiers() & (Qt::ShiftModifier)))
2022 smart_move_timer_->start(20);
2029 if( _event->type() == QEvent::MouseButtonRelease)
2031 smart_move_timer_->stop();
2032 cur_smart_move_obj_ = NULL;
2044slotEditModeChanged()
2057 GlutPrimitiveNode* H0, *H1, *C;
2061 ACG::Vec3d h0 = circleData->circleCenter_ + circleData->circleMainAxis_ * circleData->circleMainRadius_,
2062 h1 = circleData->circleCenter_ + circleData->circleSideAxis_ * circleData->circleSideRadius_;
2064 C->set_position(circleData->circleCenter_);
2075slot_setCirclePointNum(
int i)
2086slot_setSplinePointNum(
int i)
2099 tool_->rb_insert->setChecked(
true);
2101 tool_->rb_InsertCircle->setChecked(
true);
2103 tool_->rb_InsertSpline->setChecked(
true);
2105 tool_->rb_delete->setChecked(
true);
2107 tool_->rb_move->setChecked(
true);
2109 tool_->rb_smart_move->setChecked(
true);
2111 tool_->rb_merge->setChecked(
true);
2113 tool_->rb_split->setChecked(
true);
2133slotEnablePickMode(
const QString& _name)
2140 if(_name ==
"INSERT")
2141 tool_->rb_insert->setChecked(
true);
2142 else if(_name ==
"DELETE")
2143 tool_->rb_delete->setChecked(
true);
2144 else if(_name ==
"MOVE")
2145 tool_->rb_move->setChecked(
true);
2146 else if(_name ==
"SPLIT")
2147 tool_->rb_split->setChecked(
true);
2148 else if(_name ==
"MERGE")
2149 tool_->rb_merge->setChecked(
true);
2150 else if( _name ==
"SMART_MOVE")
2151 tool_->rb_smart_move->setChecked(
true);
2159pick_triangle_mesh( QPoint mPos,
2166 size_t target_idx = 0, node_idx = 0;
2184 _fh = m.face_handle(target_idx);
2188 float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
2191 if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2192 shortest_distance = (m.point(*fv_it ) - hit_point).sqrnorm();
2197 if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2204 _hitPoint = hit_point;
2217slotUpdateContextMenu(
int objectId)
2219 copyPaste_ObjectId_ = objectId;
2220 copyPaste_Action_->setVisible(
pickToolbar_->isVisible());
2225me_copyPasteMouse(QMouseEvent* _event)
2232 copyPaste_ObjectId_ = copyPaste_ActionType_ - 1;
2235 size_t target_idx = 0, node_idx = 0;
2238 if(copyPaste_ActionType_ == 1) {
2248 GlutPrimitiveNode* glutNode =
dynamic_cast<GlutPrimitiveNode*
>(node);
2250 me_GetMeshHit(_event, glutNode, hit_point, circleData->circleMeshIndex_, target_idx);
2252 circleData-> circleCenter_ = hit_point;
2256 else if(oldSplineData) {
2257 for(
int i = 0; i < (int)splineData->points_.size(); i++) {
2258 ACG::Vec3d onMeshNor, oldPos = splineData->points_[i].position;
2260 splineData->points_[i].position = onMesh;
2261 splineData->points_[i].normal = onMeshNor;
2263 int handleIndex = 2 * i - 1;
2264 ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
2266 splineData->handles_[handleIndex] = point;
2268 if(i != ((
int)splineData->points_.size() - 1)) {
2269 int handleIndex = 2 * i;
2270 ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
2272 splineData->handles_[handleIndex] = point;
2275 GlutLineNode* lineN;
2282 for(
size_t i = 0; i < newObj->
line()->n_vertices(); i++)
2283 newObj->
line()->
point(i) = hit_point + copyPaste_RelativePoints_[i];
2288 if(_event->type() == QEvent::MouseButtonPress) {
2289 copyPaste_ActionType_ = copyPaste_ObjectId_ = -1;
2292 else if(copyPaste_ActionType_ == 2) {
2306 size_t target_idx = 0, node_idx = 0;
2309 QPoint mPos = copyPaste_LastMouse;
2311 copyPaste_ActionType_ = 1;
2325 copyPaste_RelativePoints_.clear();
2330 createCircle_createUI(new_line_id);
2332 else if(splineData) {
2335 createSpline_createUI(new_line_id);
2338 for(
size_t i = 0; i < newData->points_.size(); i++)
2339 copyPaste_RelativePoints_.push_back(newData->points_[i].position - hit_point);
2344 for(
size_t i = 0; i < obj->
line()->n_vertices(); i++) {
2346 copyPaste_RelativePoints_.push_back(obj->
line()->
point(i) - hit_point);
2350 copyPaste_NewObjectId_ = new_line_id;
2361 copyPaste_ActionType_ = 2;
#define DATA_TRIANGLE_MESH
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
size_t n_vertices() const
Get number of vertices.
void split_closed(unsigned int _split_idx)
Split closed polyline at vertex with index _split_idx.
void smooth_uniform_laplace()
Laplacian smoothing.
void set_closed(const bool _c)
Set if the polyline should be closed and therefore forms a loop.
Point & point(unsigned int _i)
Get a point of the polyline.
Scalar vertex_radius() const
get ball-radius of vertices
std::vector< Point > & points()
Get all points of the polyline.
void set_vertex_radius(const Scalar _r)
set ball-radius of vertices
void delete_point(int _idx)
Delete point at _idx.
void resize(unsigned int _n)
Resize current polyline.
void collapse(Scalar _smallest)
Collapse polyline.
void smooth_uniform_laplace2()
Squared laplacian smoothing.
void invert()
Invert polyline that first vertex becomes last.
void project_to_mesh(const MeshT &_mesh, SpatialSearchT *_ssearch=0)
Project polyline points to nearest surface points (use spatial search!!!)
void smooth_uniform_laplace3()
Cubic laplacian smoothing.
void subdivide(Scalar _largest)
Subdivide polyline.
bool is_closed() const
Check if the polyline is marked as closed.
void split(unsigned int _split_idx, PolyLineT< PointT > &_new_pl)
Split closed polyline at vertex with index _split_idx.
Scalar length() const
Compute the length of the polyline (in future cached method)
void add_point(const Point &_p)
Append a point to the polyline.
void append(const PolyLineT< PointT > &_pl)
Append second polyline _pl to this one.
Point & back()
Get last point of the polyline ( no range check!!!)
void enablePicking(bool _enable)
std::string name() const
Returns: name of node (needs not be unique)
void set_position(const Vec3d &_p, int _idx=0)
set position
const Vec3d get_position(int _idx=0) const
get position
void set_random_color()
Generates a random color and sets it.
bool getAdditionalNode(NodeT *&_node, QString _pluginName, QString _nodeName, int _id=0)
get an addition node from the object
MaterialNode * materialNode()
get a pointer to the materialnode
void setObjectDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, const bool &_force=false)
Set the draw mode for the object.
bool addAdditionalNode(NodeT *_node, QString _pluginName, QString _nodeName, int _id=0)
add an additional node to the object
void setObjectData(QString _dataName, PerObjectData *_data)
QString name() const
return the name of the object. The name defaults to NONAME if unset.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
bool dataType(DataType _type) const
OMTriangleBSP * requestTriangleBsp()
MeshT * mesh()
return a pointer to the mesh
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Kernel::FaceVertexIter FaceVertexIter
Circulator.
Kernel::FaceHandle FaceHandle
Scalar type.
VectorT< Scalar, DIM > & normalize(VectorT< Scalar, DIM > &_v)
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM > >().sqrnorm()))
compute euclidean norm
Scalar norm(const VectorT< Scalar, DIM > &_v)
void addInterpolatePoint(ACG::Vec3d _position, ACG::Vec3d _normal)
Adds a point to the end of the list and inserts control points.
size_t meshIndex_
Index of the corresponding mesh.
InterpolatePoint & getInterpolatePoint(unsigned int _handleIndex)
Retrieves the interpolate point based on the handle.
bool finishSpline()
If possible calculates handles.
void enablePicking(bool _enable)
Enable or disable picking for this Object.
ACG::SceneGraph::PolyLineNodeT< PolyLine > * lineNode()
Get the scenegraph Node.
PolyLine * line()
return a pointer to the line
QString name()
Name of the Plugin.
QAction * mergeAction_
Called by pick Toolbar.
QActionGroup * toolBarActions_
Called by Toolbar to enable pick mode.
void updatePolyBezierHandles(PolyLineObject *_lineObject, ACG::SceneGraph::LineNode *_line)
Updates all the handles on the PolyBezier.
void slotTriggerCutPlaneSelect()
Generate PolyLine after the cutPlane has been drawn.
int createCircle_LastSelIndex_
Use this one to mark the last index to update the number of points.
int createCircle_CurrSelIndex_
The object which is being modified(created, dragged)
void slotScissorLinesButton()
Scissor Button for multiple polylines was hit.
QAction * insertAction_
Called by pick Toolbar.
IdList generatePolyLinesFromCut(int _objectId, Vector _planePoint, Vector _planeNormal)
Generates a polyLine of a plane intersection.
int moveBezSpline_SelIndex_
The object which is being moved.
QIcon * toolIcon_
Icon for the toolbox.
QAction * deleteAction_
Called by pick Toolbar.
int generatePolyLineFromCut(int _objectId, Vector _planePoint, Vector _planeNormal, int _polyLineId=-1)
Generates a polyLine of a plane intersection.
ACG::Vec3d moveCircle_LastHitPos_
The last valid hit on the mesh.
ACG::Vec3d createCircle_getHit(PolyLineCircleData *_circleData, ACG::Vec3d _hit_point)
Returns point on mesh or point on the normal plane.
QAction * splitAction_
Called by pick Toolbar.
int createSpline_CurrSelIndex_
The index of the currently created spline.
QAction * polyLineAction_
Called by Toolbar to enable pick mode.
int moveBezSpline_SelSubIndex_
The index of the control or handle being moved.
PolyLineToolbarWidget * tool_
Widget for Toolbox.
void slotPickToolbarAction(QAction *_action)
Called by pick Toolbar.
QAction * cutMultipleAction_
Called by pick Toolbar.
int createSpline_LastSelIndex_
Use this one to mark the last index to update the number of points.
QtPlaneSelect * planeSelect_
Plane selection tool.
void slotSetPolyLineMode(QAction *_action)
Called by Toolbar to enable pick mode.
QToolBar * toolbar_
Called by Toolbar to enable pick mode.
ACG::SceneGraph::GlutPrimitiveNode * moveCircle_SelNode_
The handle which is being dragged.
QAction * smartMoveAction_
Called by pick Toolbar.
QActionGroup * pickToolBarActions_
Called by pick Toolbar.
QAction * cutAction_
Called by pick Toolbar.
void updatePolyBezierSpline(PolyLineObject *_lineObject, unsigned int _pointsPerSegment)
Generates points for the spline, updates handles.
PolyLinePlugin()
default constructor
QAction * insertSplineAction_
Called by pick Toolbar.
QAction * moveAction_
Called by pick Toolbar.
ACG::SceneGraph::GlutPrimitiveNode * moveBezSpline_SelNode_
The handle which is being dragged.
void updateHandles(PolyLineObject *_lineObject)
Updates the center, forward and side handle of the Poly ellipse.
void updatePolyEllipse(PolyLineObject *_lineObject, unsigned int _pointCount)
Generates points for the ellipse.
QToolBar * pickToolbar_
Called by pick Toolbar.
EditMode
Edit Mode of PolyLinePlugin.
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.
void slotScissorButton()
Scissor Button was hit.
QAction * insertCircleAction_
Called by pick Toolbar.
~PolyLinePlugin()
default destructor
void slotMouseEvent(QMouseEvent *_event)
Type for a MeshObject containing a triangle mesh.
ACG::GLState & glState()
Get the glState of the Viewer.
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(8))
Topology updated.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
DrawMode WIREFRAME
draw wireframe
DrawMode POINTS_SHADED
draw shaded points (requires point normals)
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
BaseNode * find_node(BaseNode *_root, unsigned int _node_idx)
Find a node in the scene graph.
@ PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
@ PICK_FACE
picks faces (should be implemented for all nodes)
@ PICK_VERTEX
picks verices (may not be implemented for all nodes)
Namespace providing different geometric functions concerning angles.
VectorT< float, 4 > Vec4f
double sceneRadius()
Returns the current scene radius from the active examiner widget.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
void viewingDirection(const ACG::Vec3d &_dir, const ACG::Vec3d &_up, int _viewer)
Set the viewing direction.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
ACG::SceneGraph::BaseNode * getRootNode()
Get the root node for data objects.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
const std::string pickMode()
Get the current Picking mode.
bool getPickedObject(const size_t _node_idx, BaseObjectData *&_object)
Get the picked mesh.
BaseObject *& objectRoot()
Get the root of the object structure.
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
Viewer::ActionMode actionMode()
Get the current Action mode.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
PolyLineObject * polyLineObject(BaseObjectData *_object)
Cast an BaseObject to a PolyLineObject if possible.