54 #include "PolyLinePlugin.hh" 56 #include <ACG/Scenegraph/ManipulatorNode.hh> 58 #if QT_VERSION >= 0x050000 69 GlutPrimitiveNode(
PolyLineObject* L, std::string name,
int _index = -1)
88 :
ACG::
SceneGraph::LineNode(LineSegmentsMode, L->manipulatorNode(), name)
110 pickToolBarActions_(0),
112 insertCircleAction_(0),
113 insertSplineAction_(0),
120 cutMultipleAction_(0),
122 cur_polyline_obj_(0),
125 create_point_ref_(0),
126 createCircle_CurrSelIndex_(-1),
127 createCircle_LastSelIndex_(-1),
128 moveCircle_SelNode_(0),
129 moveCircle_IsLocked(false),
130 moveCircle_IsFloating(false),
131 copyPaste_Action_(0),
132 copyPaste_ObjectId_(-1),
133 copyPaste_ActionType_(-1),
134 copyPaste_NewObjectId_(-1),
135 createSpline_CurrSelIndex_(-1),
136 createSpline_LastSelIndex_(-1),
137 moveBezSpline_SelNode_(0),
138 moveBezSpline_SelIndex_(-1),
139 moveBezSpline_SelSubIndex_(0),
141 smart_move_timer_(0),
142 cur_smart_move_obj_(0),
154 QSize size(100, 100);
156 tool_->setObjectName(
"PolyLineToolbar");
159 connect(
tool_->pb_subdivide,SIGNAL(clicked() ),
this,SLOT(slot_subdivide()));
160 connect(
tool_->subdivide_relative,SIGNAL(toggled(
bool) ),
this,SLOT(slot_subdivide_percent(
bool)));
161 connect(
tool_->pb_decimate,SIGNAL(clicked() ),
this,SLOT(slot_decimate()));
162 connect(
tool_->decimate_relative,SIGNAL(toggled(
bool) ),
this,SLOT(slot_decimate_percent(
bool)));
163 #ifdef EXTENDED_POLY_LINE 164 connect(
tool_->pb_resample_on_edges,SIGNAL(clicked() ),
this,SLOT(slot_resample_on_edges()));
166 tool_->pb_resample_on_edges->setDisabled(
true);
168 connect(
tool_->pb_smooth,SIGNAL(clicked() ),
this,SLOT(slot_smooth()));
169 connect(
tool_->pb_smooth,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
170 connect(
tool_->pb_project,SIGNAL(clicked() ),
this,SLOT(slot_project()));
171 connect(
tool_->pb_project,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
172 connect(
tool_->pb_smooth_project,SIGNAL(clicked() ),
this,SLOT(slot_smooth_project()));
173 connect(
tool_->pb_smooth_project,SIGNAL(clicked() ),
this,SIGNAL(updateView()));
175 connect(
tool_->rb_insert, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
176 connect(
tool_->rb_InsertCircle, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
177 connect(
tool_->rb_InsertSpline, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
178 connect(
tool_->rb_delete, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
179 connect(
tool_->rb_move, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
180 connect(
tool_->rb_smart_move, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
181 connect(
tool_->rb_merge, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
182 connect(
tool_->rb_split, SIGNAL( clicked() ),
this, SLOT( slotEditModeChanged() ));
184 connect(
tool_->sb_CirclePointNum, SIGNAL(valueChanged(
int)),
this, SLOT(slot_setCirclePointNum(
int)));
185 connect(
tool_->sb_SplineSegNum, SIGNAL(valueChanged(
int)),
this, SLOT(slot_setSplinePointNum(
int)));
187 tool_->rb_insert->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_insert.png") );
188 tool_->rb_InsertCircle->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_circle.png") );
189 tool_->rb_InsertSpline->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_bezier.png") );
190 tool_->rb_delete->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_delete.png") );
191 tool_->rb_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_move.png") );
192 tool_->rb_smart_move->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_move.png") );
193 tool_->rb_merge->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_merge.png") );
194 tool_->rb_split->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() +
"polyline_split.png") );
201 QIcon* toolIcon =
new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polyline.png");
202 emit addToolbox( tr(
"PolyLine") ,
tool_, toolIcon );
211 slotMouseEvent( QMouseEvent* _event )
213 copyPaste_LastMouse = _event->pos();
216 if (_event->modifiers() & (Qt::ControlModifier))
220 && _event->button() != Qt::RightButton) {
227 case PL_INSERTCIRCLE:
228 me_insertCircle(_event);
231 case PL_INSERTSPLINE:
232 me_insertSpline(_event);
252 me_smart_move(_event);
256 me_copyPasteMouse(_event);
267 void PolyLinePlugin::slotKeyEvent(QKeyEvent* event) {
268 switch (event->key()) {
271 if(mode() == PL_INSERT && cur_polyline_obj_ && cur_insert_id_ != -1) {
274 if (event->modifiers() & (Qt::ShiftModifier))
280 cur_polyline_obj_ = 0;
281 create_point_ref_ = 0;
283 clearStatusMessage();
285 else if(mode() == PL_INSERTSPLINE) {
298 slotPickModeChanged(
const std::string& _mode)
301 cutAction_->setChecked( _mode == CREATE_CUT_POLYLINE );
314 emit addHiddenPickMode(
"PolyLine");
315 emit setPickModeMouseTracking(
"PolyLine",
true);
316 emit addHiddenPickMode( CREATE_CUT_POLYLINE );
317 emit addHiddenPickMode( CREATE_CUT_POLYLINES );
319 emit registerKey(Qt::Key_Return, Qt::NoModifier, tr(
"Terminate creation of poly line."),
true);
320 emit registerKey(Qt::Key_Return, Qt::ShiftModifier, tr(
"Terminate creation of poly line and create loop."),
true);
323 toolbar_ =
new QToolBar(tr(
"PolyLine Editing"));
324 toolbar_->setObjectName(
"PolyLineEditingToolbar");
332 polyLineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_insert.png") );
337 cutAction_ =
new QAction(tr(
"&Create polyline at intersection with plane"),
this);
339 cutAction_->setStatusTip(tr(
"Create a polyline by specifying a plane with which the object is then intersected. The polyline will be created at the intersection."));
340 cutAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polyline.png") );
345 cutMultipleAction_ =
new QAction(tr(
"&Create polylines at intersection with plane"),
this);
347 cutMultipleAction_->setStatusTip(tr(
"Create polylines by specifying a plane with which the object is then intersected. The polylines will be created at the intersection."));
348 cutMultipleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"cut_polylines.png") );
358 pickToolbar_->setObjectName(
"PolyLine_Editing_Toolbar");
359 pickToolbar_->setAttribute(Qt::WA_AlwaysShowToolTips,
true);
366 "Use <Doubleclick> to finish the line.\n" 367 "Hold <Shift> to close line on finish."));
368 insertAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_insert.png") );
375 "<Click> to select the center.\n" 376 "Drag to specify the radius."));
378 insertCircleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_circle.png") );
385 "<Click> to select the points."));
387 insertSplineAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_bezier.png") );
392 deleteAction_->setStatusTip(tr(
"Delete a complete PolyLine."));
393 deleteAction_->setToolTip(tr(
"Delete a complete PolyLine.\n" 394 "<Click> on the lines you want to delete."));
395 deleteAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_delete.png") );
402 smartMoveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_move.png") );
409 "Drag one endpoint of a PolyLine to the EndPoint of another one.\n"));
410 mergeAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_merge.png") );
415 splitAction_->setStatusTip(tr(
"Split a PolyLine at a given point."));
416 splitAction_->setToolTip(tr(
"Split a PolyLine at a given point.\n" 417 "<Click> on the vertex where you want to split the PolyLine and drag it away."));
418 splitAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_split.png") );
425 moveAction_->setStatusTip(tr(
"Move a Vertex of a PolyLine"));
426 moveAction_->setToolTip(tr(
"Move a single Vertex of a PolyLine."));
427 moveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"polyline_move.png") );
436 smart_move_timer_ =
new QTimer(
this);
437 connect(smart_move_timer_, SIGNAL(timeout()),
this, SLOT(slot_smart_move_timer()));
442 connect(
planeSelect_, SIGNAL( updateViewProxy( ) ),
this, SIGNAL( updateView() ) );
443 connect(
planeSelect_, SIGNAL( nodeVisChangedProxy(
int) ),
this, SIGNAL(nodeVisibilityChanged(
int) ) );
446 copyPaste_Action_ =
new QAction(
"Duplicate", 0);
447 connect(copyPaste_Action_,SIGNAL(triggered() ),
this,SLOT(slot_duplicate()));
486 emit log(
"Cutting object " + object->
name());
489 emit log(
"Only Meshes are supported at the moment ");
500 QString command =
"generatePolyLineFromCut(" + QString::number(object->
id()) +
",Vector(" 501 + QString::number(point[0]) +
"," + QString::number(point[1]) +
"," + QString::number(point[2]) +
"),Vector(" 502 + QString::number(normal[0]) +
"," + QString::number(normal[1]) +
"," + QString::number(normal[2]) +
"));";
503 emit scriptInfo(command);
508 if (o_it->id() !=
object->id()) {
520 QString command =
"generatePolyLinesFromCut(" + QString::number(object->
id()) +
",Vector(" 521 + QString::number(point[0]) +
"," + QString::number(point[1]) +
"," + QString::number(point[2]) +
"),Vector(" 522 + QString::number(normal[0]) +
"," + QString::number(normal[1]) +
"," + QString::number(normal[2]) +
"));";
523 emit scriptInfo(command);
528 if (o_it->id() !=
object->id()) {
533 for (
unsigned int i = 0 ; i < objectIds.size() ; ++i ) {
535 if ( objectIds[i] != -1)
551 double max_length =
tool_->dsb_subdivide->value();
554 if (max_length == 0.0)
573 void PolyLinePlugin::slot_subdivide_percent(
bool _checked) {
577 double total_length = 0;
588 double v = total_length / double(n_active_pl);
593 if (n_active_pl > 0) {
594 double val_new =
tool_->dsb_subdivide->value() / v;
595 tool_->dsb_subdivide->setValue(val_new);
597 emit log(
LOGWARN,
"Could not find any active polyline!");
602 if (n_active_pl > 0) {
603 double val_new =
tool_->dsb_subdivide->value() * v;
604 tool_->dsb_subdivide->setValue(val_new);
606 emit log(
LOGWARN,
"Could not find any active polyline!");
620 double min_length =
tool_->dsb_decimate->value();
637 void PolyLinePlugin::slot_decimate_percent(
bool _checked)
642 double total_length = 0;
653 double v = total_length / double(n_active_pl);
658 if (n_active_pl > 0) {
659 double val_new =
tool_->dsb_subdivide->value() / v;
660 tool_->dsb_decimate->setValue(val_new);
662 emit log(
LOGWARN,
"Could not find any active polyline!");
667 if (n_active_pl > 0) {
668 double val_new =
tool_->dsb_subdivide->value() * v;
669 tool_->dsb_decimate->setValue(val_new);
671 emit log(
LOGWARN,
"Could not find any active polyline!");
679 #ifdef EXTENDED_POLY_LINE 683 slot_resample_on_edges()
687 unsigned int n_targetMeshes(0);
691 if( n_targetMeshes != 1)
693 std::cerr <<
"Warning: resample_on_edges needs exactly 1 target mesh! Otherwise no operation is performed! \n";
717 std::cerr <<
"resample " << o_it2->
name().toStdString() << std::endl;
741 for(
int i=0; i<
tool_->sb_smooth_iter->value(); ++i)
742 if(
tool_->rb_smooth_c0->isChecked())
746 if(
tool_->rb_smooth_c1->isChecked())
750 if(
tool_->rb_smooth_c2->isChecked())
769 for (
int i = 0; i <
tool_->sb_smooth_iter->value(); ++i)
770 if (
tool_->rb_smooth_c0->isChecked())
773 else if (
tool_->rb_smooth_c1->isChecked())
776 else if (
tool_->rb_smooth_c2->isChecked())
792 std::vector<TriMesh*> meshes;
793 std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
802 meshes.push_back(tmesh_obj->
mesh());
829 std::vector<TriMesh*> meshes;
830 std::vector<OpenMeshTriangleBSPT<TriMesh>*> bsps;
840 meshes.push_back(tmesh_obj->
mesh());
857 slot_smooth_project()
859 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
861 for (
int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
880 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
882 for (
int i = 0, j = 1; i < smooth_project_iter; ++i, ++j) {
899 slot_smart_move_timer()
901 int smooth_project_iter =
tool_->sb_smooth_project_iter->value();
903 if (smooth_project_iter)
904 slot_smooth_project(cur_smart_move_obj_);
906 slot_smooth(cur_smart_move_obj_);
914 PolyLinePlugin::slotObjectUpdated(
int _identifier,
const UpdateType &_type )
921 GlutPrimitiveNode* H = 0, *C = 0;
924 if(circleData && !C) {
925 createCircle_createUI(_identifier);
927 else if(splineData && !H) {
928 createSpline_createUI(_identifier);
938 if(copyPaste_ObjectId_ != -1 && copyPaste_ActionType_ != -1)
939 return PL_COPY_PASTE;
943 if(
tool_->rb_insert->isChecked() )
return PL_INSERT;
944 if(
tool_->rb_InsertCircle->isChecked() )
return PL_INSERTCIRCLE;
945 if(
tool_->rb_InsertSpline->isChecked() )
return PL_INSERTSPLINE;
946 else if(
tool_->rb_delete->isChecked() )
return PL_DELETE;
947 else if(
tool_->rb_move->isChecked() )
return PL_MOVE;
948 else if(
tool_->rb_split->isChecked() )
return PL_SPLIT;
949 else if(
tool_->rb_merge->isChecked() )
return PL_MERGE;
950 else if(
tool_->rb_smart_move->isChecked())
return PL_SMART_MOVE;
960 me_insert( QMouseEvent* _event )
962 if (_event->type() == QEvent::MouseMove) {
963 if (create_point_ref_) {
965 unsigned int node_idx, target_idx;
968 *create_point_ref_ = (PolyLine::Point) hit_point;
978 unsigned int node_idx, target_idx;
982 switch (_event->type()) {
984 case QEvent::MouseButtonPress: {
1004 cur_polyline_obj_->
line()->
add_point((PolyLine::Point) hit_point);
1006 emit showStatusMessage(tr(
"Double click/Enter to terminate poly line. Use with shift to create loop."));
1010 cur_polyline_obj_->
line()->
add_point((PolyLine::Point) hit_point);
1011 create_point_ref_ = &cur_polyline_obj_->
line()->
points().back();
1020 case QEvent::MouseButtonDblClick: {
1022 if (_event->modifiers() & (Qt::ShiftModifier)) {
1035 cur_insert_id_ = -1;
1036 cur_polyline_obj_ = 0;
1037 create_point_ref_ = 0;
1039 clearStatusMessage();
1052 double getRad(
int meshIdx)
1057 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1058 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1060 return 0.005*(bbMax-bbMin).norm();
1067 void PolyLinePlugin::
1068 createCircle_createUI(
int _polyLineObjectID)
1077 double rad = getRad(lineData->circleMeshIndex_);
1079 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle0");
1080 handle0->get_primitive(0).color =
ACG::Vec4f(1,0,0,1);
1081 handle0->set_size(rad);
1083 handle0->enablePicking(
true);
1084 handle0->set_position(lineData->circleCenter_ + lineData->circleMainAxis_ * lineData->circleMainRadius_);
1088 GlutPrimitiveNode* handle1 =
new GlutPrimitiveNode(lineObject,
"N_Handle1");
1089 handle1->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1090 handle1->set_size(rad);
1092 handle1->enablePicking(
true);
1093 handle1->set_position(lineData->circleCenter_ + lineData->circleSideAxis_ * lineData->circleSideRadius_);
1097 GlutPrimitiveNode* cenNode =
new GlutPrimitiveNode(lineObject,
"N_Center");
1098 cenNode->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1099 cenNode->set_size(rad);
1101 cenNode->enablePicking(
true);
1102 cenNode->set_position(lineData->circleCenter_);
1106 emit updatedObject(_polyLineObjectID,
UPDATE_ALL);
1111 void PolyLinePlugin::
1112 me_insertCircle(QMouseEvent* _event)
1115 TriMesh::FaceHandle fh;
1116 TriMesh::VertexHandle vh;
1118 if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point) && _event->type() != QEvent::MouseButtonRelease)
1127 const ACG::Vec3d n = circleData->circleNormal_, x0 = circleData->circleCenter_;
1128 const double t = ((n | x0) - (n | hit_point)) / n.
sqrnorm();
1129 const ACG::Vec3d onPlane = hit_point + t * n, d = onPlane - x0;
1131 circleData->circleMainAxis_ = (onPlane - x0).normalize();
1132 circleData->circleSideRadius_ = circleData->circleMainRadius_ = d.norm();
1133 circleData->circleSideAxis_ = (circleData->circleMainAxis_ % n).normalize();
1149 if(!mesh->
mesh()->has_face_normals())
1150 mesh->
mesh()->request_face_normals();
1160 else if(_event->type() == QEvent::MouseButtonRelease ) {
1168 createCircle_CurrSelIndex_ = -1;
1174 void PolyLinePlugin::
1175 createSpline_createUI(
int _polyLineObjectID)
1186 GlutLineNode* lineN =
new GlutLineNode(lineObject,
"N_Line");
1188 lineN->enablePicking(
false);
1192 for(
unsigned int i = 0; i < splineData->points_.size(); i++) {
1193 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Control", i);
1194 handle0->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1195 handle0->set_size(rad);
1197 handle0->set_position(splineData->points_[i].position);
1199 handle0->enablePicking(
true);
1203 for(
unsigned int i = 0; i < splineData->handles_.size(); i++) {
1205 const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = control.position;
1207 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle", i);
1208 handle0->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1209 handle0->set_size(rad * 0.75);
1211 handle0->enablePicking(
true);
1212 handle0->set_position(hndlPos);
1216 GlutLineNode* lineN;
1218 lineN->add_line(ctrlPos, hndlPos);
1224 emit updatedObject(_polyLineObjectID,
UPDATE_ALL);
1243 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1244 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1250 GlutPrimitiveNode* control = 0;
1252 for(
unsigned int i = 0; i < splineData->points_.size(); i++) {
1254 control->enablePicking(
true);
1257 for(
unsigned int i = 0; i < splineData->handles_.size(); i++) {
1259 const ACG::Vec3d hndlPos = splineData->handles_[i], ctrlPos = control.position;
1261 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Handle", i);
1262 handle0->get_primitive(0).color =
ACG::Vec4f(0,0,1,1);
1263 handle0->set_size(0.004*sizeBB.
norm());
1265 handle0->enablePicking(
true);
1266 handle0->set_position(hndlPos);
1270 GlutLineNode* lineN;
1272 lineN->add_line(ctrlPos, hndlPos);
1283 void PolyLinePlugin::
1284 me_insertSpline(QMouseEvent* _event)
1288 TriMesh::FaceHandle fh;
1289 TriMesh::VertexHandle vh;
1292 if(!pick_triangle_mesh(_event->pos(), mesh, fh, vh, hit_point))
1295 ACG::Vec3d bbMin( FLT_MAX, FLT_MAX, FLT_MAX);
1296 ACG::Vec3d bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
1300 if(!mesh->
mesh()->has_face_normals())
1301 mesh->
mesh()->request_face_normals();
1305 if(_event->type() == QEvent::MouseButtonPress) {
1325 GlutLineNode* lineN =
new GlutLineNode(newLine,
"N_Line");
1327 lineN->enablePicking(
false);
1332 ACG::Vec3d insert_Point = hit_point + nor * 0.003 * sizeBB.
norm();
1339 GlutPrimitiveNode* handle0 =
new GlutPrimitiveNode(lineObject,
"N_Control", splineData->points_.size());
1340 handle0->get_primitive(0).color =
ACG::Vec4f(0,1,0,1);
1341 handle0->set_size(0.005*sizeBB.
norm());
1343 handle0->set_position(insert_Point);
1345 handle0->enablePicking(
false);
1352 if(_event->type() == QEvent::MouseButtonDblClick) {
1361 me_delete( QMouseEvent* _event )
1364 if (_event->type() == QEvent::MouseButtonPress) {
1366 unsigned int node_idx, target_idx;
1376 emit deleteObject(obj->
id());
1392 if(moveCircle_SelNode_)
1395 if(moveCircle_SelNode_)
1400 _node_idx = obj->
id();
1406 if(!_moveCircle_SelNode_->
name().compare(
"N_Center"))
1408 _lineData->circleNormal_ = _nor;
1409 _lineData->circleCenter_ = _hit_point;
1410 _lineData->circleSideAxis_ = (_lineData->circleMainAxis_ % _lineData->circleNormal_).normalize();
1411 _lineData->circleMainAxis_ = (_lineData->circleNormal_ % _lineData->circleSideAxis_).normalize();
1415 const double cr = (_onPlane - _lineData->circleCenter_).norm();
1416 const ACG::Vec3d axisa = (_onPlane - _lineData->circleCenter_).normalize();
1417 if (!_moveCircle_SelNode_->
name().compare(
"N_Handle0")) {
1418 const ACG::Vec3d axisb = (axisa % _lineData->circleNormal_).normalize();
1419 _lineData->circleMainRadius_ = cr;
1422 _lineData->circleSideRadius_ = cr;
1424 _lineData->circleMainAxis_ = axisa;
1425 _lineData->circleSideAxis_ = axisb;
1427 const ACG::Vec3d axisb = (_lineData->circleNormal_ % axisa).normalize();
1428 _lineData->circleSideRadius_ = cr;
1431 _lineData->circleMainRadius_ = cr;
1433 _lineData->circleSideAxis_ = axisa;
1434 _lineData->circleMainAxis_ = axisb;
1442 me_move( QMouseEvent* _event )
1444 if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier && moveCircle_IsLocked)
1445 moveCircle_IsLocked = moveCircle_IsFloating =
false;
1448 if (_event->type() == QEvent::MouseButtonPress) {
1450 unsigned int node_idx, target_idx;
1455 GlutPrimitiveNode* glutNode =
dynamic_cast<GlutPrimitiveNode*
>(node);
1484 cur_move_id_ = cur_pol->
id();
1486 move_point_ref_ = &(cur_pol->
line()->
point(target_idx));
1493 if (_event->type() == QEvent::MouseMove){
1500 unsigned int target_idx;
1501 bool hasHit = me_GetMeshHit(_event,
moveCircle_SelNode_, hit_point, lineData->circleMeshIndex_, target_idx);
1502 if(lineData->circleMeshIndex_ == std::numeric_limits<unsigned int>::max())
return;
1503 if(!moveCircle_IsLocked && hasHit) {
1504 moveCircle_IsFloating =
false;
1505 ACG::Vec3d x0 = lineData->circleCenter_, n = lineData->circleNormal_;
1507 double t = ((n | x0) - (n | onMesh)) / n.
sqrnorm();
1513 me_UpdateCircleData(onMesh, onPlane, mesh->
mesh()->normal(mesh->
mesh()->face_handle(target_idx)),
moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1516 if((_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) {
1517 moveCircle_IsLocked =
true;
1518 moveCircle_LastHitNor_ = lineData->circleNormal_;
1524 moveCircle_IsFloating =
true;
1533 : lineData->circleNormal_;
1534 const double t = ((x0 | n) - (cameraPos | n)) / (cameraDir | n);
1535 const ACG::Vec3d onPlane = cameraPos + cameraDir * t;
1537 me_UpdateCircleData(onPlane, onPlane, n,
moveCircle_SelNode_, lineData, (_event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier);
1549 unsigned int target_idx;
1551 if(lineData->
meshIndex_ == std::numeric_limits<unsigned int>::max())
1557 ACG::Vec3d onMesh = hit_point, onMeshNor = mesh->
mesh()->normal(mesh->
mesh()->face_handle(target_idx));
1561 lineData->points_[controlIndex].position = onMesh;
1562 lineData->points_[controlIndex].normal = onMeshNor;
1564 int handleIndex = 2 * controlIndex - 1;
1565 ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
1567 lineData->handles_[handleIndex] = point;
1569 if(controlIndex != ((
int)lineData->points_.size() - 1)) {
1570 int handleIndex = 2 * controlIndex;
1571 ACG::Vec3d dir = lineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
1573 lineData->handles_[handleIndex] = point;
1584 double t = ((control.normal | control.position) - (control.normal | cameraPos)) / (control.normal | cameraDir);
1585 ACG::Vec3d onPlane = cameraPos + t * cameraDir;
1587 lineData->handles_[handleIndex] = onPlane;
1588 if(handleIndex % 2 == 1 && handleIndex != ((
int)lineData->handles_.size() - 1)) {
1589 double dist = (lineData->handles_[handleIndex + 1] - control.position).norm();
1590 if(_event->modifiers() & Qt::ShiftModifier)
1591 dist = (onPlane - control.position).
norm();
1592 ACG::Vec3d dir = -(onPlane - control.position).normalize();
1593 lineData->handles_[handleIndex + 1] = control.position + dir * dist;
1595 if(handleIndex % 2 == 0 && handleIndex) {
1596 double dist = (lineData->handles_[handleIndex - 1] - control.position).norm();
1597 if(_event->modifiers() & Qt::ShiftModifier)
1598 dist = (onPlane - control.position).
norm();
1599 ACG::Vec3d dir = -(onPlane - control.position).normalize();
1600 lineData->handles_[handleIndex - 1] = control.position + dir * dist;
1603 GlutLineNode* lineN;
1609 else if (move_point_ref_ != 0) {
1611 unsigned int node_idx, target_idx;
1613 (*move_point_ref_) = (PolyLine::Point) hit_point;
1621 if (_event->type() == QEvent::MouseButtonRelease) {
1622 if((_event->modifiers() & Qt::ShiftModifier) != Qt::ShiftModifier) {
1625 moveCircle_IsLocked = moveCircle_IsFloating =
false;
1629 moveCircle_IsLocked =
false;
1634 move_point_ref_ = 0;
1646 me_split( QMouseEvent* _event )
1649 if (_event->type() == QEvent::MouseButtonPress) {
1651 move_point_ref_ = 0;
1653 unsigned int node_idx, target_idx;
1675 cur_move_id_ = cur_pol->
id();
1706 cur_move_id_ = cur_pol->
id();
1722 if (_event->type() == QEvent::MouseMove)
1723 if (move_point_ref_ != 0) {
1725 unsigned int node_idx, target_idx;
1729 (*move_point_ref_) = (PolyLine::Point) hit_point;
1738 if (_event->type() == QEvent::MouseButtonRelease) {
1740 if (cur_move_id_ != -1)
1743 move_point_ref_ = 0;
1754 me_merge( QMouseEvent* _event )
1757 if (_event->type() == QEvent::MouseButtonPress) {
1759 move_point_ref_ = 0;
1762 unsigned int node_idx, target_idx;
1777 if (target_idx == cur_pol->
line()->
n_vertices() - 1 || target_idx == 0) {
1778 if (target_idx == 0) {
1784 cur_merge_id_ = cur_pol->
id();
1797 if (_event->type() == QEvent::MouseMove && cur_merge_id_ != -1)
1798 if (move_point_ref_ != 0) {
1799 unsigned int node_idx, target_idx;
1803 (*move_point_ref_) = (PolyLine::Point) hit_point;
1812 if (_event->type() == QEvent::MouseButtonRelease && cur_merge_id_ != -1) {
1813 PolyLine::Point p_save;
1816 if (move_point_ref_ != 0) {
1828 move_point_ref_ = 0;
1831 unsigned int node_idx, target_idx;
1840 PluginFunctions::invalidatePickCaches();
1842 bool merged =
false;
1855 if ( target_idx < second_pol->line()->n_vertices() ) {
1858 unsigned int second_idx = target_idx;
1863 bool inv_first(
false), inv_second(
false);
1866 if (first_idx == 0) {
1878 if (first_idx == first_pol->
line()->
n_vertices() - 1 && second_idx == 0) {
1880 if (first_pol->
id() == second_pol->
id()) {
1897 emit deleteObject(second_pol->
id());
1908 PluginFunctions::invalidatePickCaches();
1921 if ( target_idx < second_pol->line()->n_vertices() ) {
1924 unsigned int second_idx = target_idx;
1930 if (first_idx == 0) {
1939 if (first_pol->
id() == second_pol->
id() && first_idx == first_pol->
line()->
n_vertices() - 1 && second_idx == 0) {
1964 move_point_ref_ = 0;
1976 me_smart_move( QMouseEvent* _event )
1979 if (_event->type() == QEvent::MouseButtonPress) {
1981 unsigned int node_idx, target_idx;
1994 cur_polyline_obj_ = cur_pol;
2001 cur_smart_move_obj_ = cur_pol;
2002 if (cur_pol->
line()->vertex_selections_available()) {
2003 if (!(_event->modifiers() & (Qt::ShiftModifier)))
2004 cur_pol->
line()->vertex_selection(target_idx) =
true;
2006 cur_pol->
line()->vertex_selection(target_idx) =
false;
2014 if (!(_event->modifiers() & (Qt::ShiftModifier)))
2015 smart_move_timer_->start(20);
2022 if( _event->type() == QEvent::MouseButtonRelease)
2024 smart_move_timer_->stop();
2025 cur_smart_move_obj_ = NULL;
2037 slotEditModeChanged()
2050 GlutPrimitiveNode* H0, *H1, *C;
2054 ACG::Vec3d h0 = circleData->circleCenter_ + circleData->circleMainAxis_ * circleData->circleMainRadius_,
2055 h1 = circleData->circleCenter_ + circleData->circleSideAxis_ * circleData->circleSideRadius_;
2057 C->set_position(circleData->circleCenter_);
2068 slot_setCirclePointNum(
int i)
2079 slot_setSplinePointNum(
int i)
2092 tool_->rb_insert->setChecked(
true);
2094 tool_->rb_InsertCircle->setChecked(
true);
2096 tool_->rb_InsertSpline->setChecked(
true);
2098 tool_->rb_delete->setChecked(
true);
2100 tool_->rb_move->setChecked(
true);
2102 tool_->rb_smart_move->setChecked(
true);
2104 tool_->rb_merge->setChecked(
true);
2106 tool_->rb_split->setChecked(
true);
2126 slotEnablePickMode(QString _name)
2133 if(_name ==
"INSERT")
2134 tool_->rb_insert->setChecked(
true);
2135 else if(_name ==
"DELETE")
2136 tool_->rb_delete->setChecked(
true);
2137 else if(_name ==
"MOVE")
2138 tool_->rb_move->setChecked(
true);
2139 else if(_name ==
"SPLIT")
2140 tool_->rb_split->setChecked(
true);
2141 else if(_name ==
"MERGE")
2142 tool_->rb_merge->setChecked(
true);
2143 else if( _name ==
"SMART_MOVE")
2144 tool_->rb_smart_move->setChecked(
true);
2152 pick_triangle_mesh( QPoint mPos,
2156 _fh = TriMesh::FaceHandle (-1);
2157 _vh = TriMesh::VertexHandle(-1);
2159 unsigned int target_idx = 0, node_idx = 0;
2177 _fh = m.face_handle(target_idx);
2180 TriMesh::VertexHandle closest = *fv_it;
2181 float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
2184 if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2185 shortest_distance = (m.point(*fv_it ) - hit_point).sqrnorm();
2190 if ( (m.point(*fv_it ) - hit_point).sqrnorm() < shortest_distance ) {
2197 _hitPoint = hit_point;
2210 slotUpdateContextMenu(
int objectId)
2212 copyPaste_ObjectId_ = objectId;
2213 copyPaste_Action_->setVisible(
pickToolbar_->isVisible());
2218 me_copyPasteMouse(QMouseEvent* _event)
2225 copyPaste_ObjectId_ = copyPaste_ActionType_ - 1;
2228 unsigned int target_idx = 0, node_idx = 0;
2231 if(copyPaste_ActionType_ == 1) {
2241 GlutPrimitiveNode* glutNode =
dynamic_cast<GlutPrimitiveNode*
>(node);
2243 me_GetMeshHit(_event, glutNode, hit_point, circleData->circleMeshIndex_, target_idx);
2245 circleData-> circleCenter_ = hit_point;
2249 else if(oldSplineData) {
2250 for(
int i = 0; i < (int)splineData->points_.size(); i++) {
2251 ACG::Vec3d onMeshNor, oldPos = splineData->points_[i].position;
2253 splineData->points_[i].position = onMesh;
2254 splineData->points_[i].normal = onMeshNor;
2256 int handleIndex = 2 * i - 1;
2257 ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
2259 splineData->handles_[handleIndex] = point;
2261 if(i != ((
int)splineData->points_.size() - 1)) {
2262 int handleIndex = 2 * i;
2263 ACG::Vec3d dir = splineData->handles_[handleIndex] - oldPos, side = dir % onMeshNor, forw = (onMeshNor % side).normalize() * dir.
norm();
2265 splineData->handles_[handleIndex] = point;
2268 GlutLineNode* lineN;
2276 newObj->
line()->
point(i) = hit_point + copyPaste_RelativePoints_[i];
2281 if(_event->type() == QEvent::MouseButtonPress) {
2282 copyPaste_ActionType_ = copyPaste_ObjectId_ = -1;
2285 else if(copyPaste_ActionType_ == 2) {
2299 unsigned int target_idx = 0, node_idx = 0;
2302 QPoint mPos = copyPaste_LastMouse;
2304 copyPaste_ActionType_ = 1;
2318 copyPaste_RelativePoints_.clear();
2323 createCircle_createUI(new_line_id);
2325 else if(splineData) {
2328 createSpline_createUI(new_line_id);
2331 for(
size_t i = 0; i < newData->points_.size(); i++)
2332 copyPaste_RelativePoints_.push_back(newData->points_[i].position - hit_point);
2339 copyPaste_RelativePoints_.push_back(obj->
line()->
point(i) - hit_point);
2343 copyPaste_NewObjectId_ = new_line_id;
2354 copyPaste_ActionType_ = 2;
2358 #if QT_VERSION < 0x050000 BaseObject *& objectRoot()
Get the root of the object structure.
QString name()
Name of the Plugin.
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
QAction * deleteAction_
Called by pick Toolbar.
QAction * splitAction_
Called by pick Toolbar.
void set_random_color()
Generates a random color and sets it.
ACG::GLState & glState()
Get the glState of the Viewer.
int createSpline_CurrSelIndex_
The index of the currently created spline.
VectorT< float, 4 > Vec4f
void setObjectDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, const bool &_force=false)
Set the draw mode for the object.
void append(const PolyLineT< PointT > &_pl)
Append second polyline _pl to this one.
Type for a MeshObject containing a triangle mesh.
ACG::SceneGraph::GlutPrimitiveNode * moveBezSpline_SelNode_
The handle which is being dragged.
DrawMode WIREFRAME
draw wireframe
void project_to_mesh(const MeshT &_mesh, SpatialSearchT *_ssearch=0)
Project polyline points to nearest surface points (use spatial search!!!)
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
void collapse(Scalar _smallest)
Collapse polyline.
bool getObject(int _identifier, BSplineCurveObject *&_object)
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
PolyLinePlugin()
default constructor
bool dataType(DataType _type) const
void delete_point(int _idx)
Delete point at _idx.
Scalar vertex_radius() const
get ball-radius of vertices
ACG::SceneGraph::PolyLineNodeT< PolyLine > * lineNode()
Get the scenegraph Node.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
The Menu will be shown when an object was picked.
void smooth_uniform_laplace2()
Squared laplacian smoothing.
int createCircle_LastSelIndex_
Use this one to mark the last index to update the number of points.
Point & back()
Get last point of the polyline ( no range check!!!)
QAction * insertAction_
Called by pick Toolbar.
int createCircle_CurrSelIndex_
The object which is being modified(created, dragged)
ACG::SceneGraph::BaseNode * getRootNode()
Get the root node for data objects.
ACG::Vec3d moveCircle_LastHitPos_
The last valid hit on the mesh.
void updatePolyBezierHandles(PolyLineObject *_lineObject, ACG::SceneGraph::LineNode *_line)
Updates all the handles on the PolyBezier.
void updatePolyBezierSpline(PolyLineObject *_lineObject, unsigned int _pointsPerSegment)
Generates points for the spline, updates handles.
void enablePicking(bool _enable)
Enable or disable picking for this Object.
QToolBar * toolbar_
Called by Toolbar to enable pick mode.
void invert()
Invert polyline that first vertex becomes last.
int moveBezSpline_SelIndex_
The object which is being moved.
bool is_closed() const
Check if the polyline is marked as closed.
double sceneRadius()
Returns the current scene radius from the active examiner widget.
void set_closed(const bool _c)
Set if the polyline should be closed and therefore forms a loop.
PolyLine * line()
return a pointer to the line
bool getPickedObject(const unsigned int _node_idx, BaseObjectData *&_object)
Get the picked mesh.
MeshT * mesh()
return a pointer to the mesh
virtual bool picked(uint _node_idx)
detect if the node has been picked
void set_vertex_radius(const Scalar _r)
set ball-radius of vertices
void resize(unsigned int _n)
Resize current polyline.
MaterialNode * materialNode()
get a pointer to the materialnode
void setObjectData(QString _dataName, PerObjectData *_data)
EditMode
Edit Mode of PolyLinePlugin.
const Vec3d get_position(int _idx=0) const
get position
void slotScissorButton()
Scissor Button was hit.
const std::string pickMode()
Get the current Picking mode.
void updateHandles(PolyLineObject *_lineObject)
Updates the center, forward and side handle of the Poly ellipse.
void set_position(const Vec3d &_p, int _idx=0)
set position
std::vector< Point > & points()
Get all points of the polyline.
PolyLineObject * polyLineObject(BaseObjectData *_object)
Cast an BaseObject to a PolyLineObject if possible.
Kernel::FaceVertexIter FaceVertexIter
Circulator.
void smooth_uniform_laplace3()
Cubic laplacian smoothing.
bool getAdditionalNode(NodeT *&_node, QString _pluginName, QString _nodeName, int _id=0)
get an addition node from the object
void updatePolyEllipse(PolyLineObject *_lineObject, unsigned int _pointCount)
Generates points for the ellipse.
void viewingDirection(const ACG::Vec3d &_dir, const ACG::Vec3d &_up, int _viewer)
Set the viewing direction.
void enablePicking(bool _enable)
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
void subdivide(Scalar _largest)
Subdivide polyline.
ACG::SceneGraph::GlutPrimitiveNode * moveCircle_SelNode_
The handle which is being dragged.
QAction * smartMoveAction_
Called by pick Toolbar.
void split(unsigned int _split_idx, PolyLineT< PointT > &_new_pl)
Split closed polyline at vertex with index _split_idx.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
QActionGroup * toolBarActions_
Called by Toolbar to enable pick mode.
void boundingBox(ACG::Vec3d &_bbMin, typename ACG::Vec3d &_bbMax)
Get the BoundingBox of this object.
Point & point(unsigned int _i)
Get a point of the polyline.
OMTriangleBSP * requestTriangleBsp()
void slotTriggerCutPlaneSelect()
Generate PolyLine after the cutPlane has been drawn.
void slotScissorLinesButton()
Scissor Button for multiple polylines was hit.
QActionGroup * pickToolBarActions_
Called by pick Toolbar.
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
DrawMode POINTS_SHADED
draw shaded points (requires point normals)
std::string name() const
Returns: name of node (needs not be unique)
Namespace providing different geometric functions concerning angles.
picks verices (may not be implemented for all nodes)
Viewer::ActionMode actionMode()
Get the current Action mode.
Scalar length() const
Compute the length of the polyline (in future cached method)
ACG::Vec3d createCircle_getHit(PolyLineCircleData *_circleData, ACG::Vec3d _hit_point)
Returns point on mesh or point on the normal plane.
unsigned int meshIndex_
Index of the corresponding mesh.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
QAction * cutAction_
Called by pick Toolbar.
QToolBar * pickToolbar_
Called by pick Toolbar.
QtPlaneSelect * planeSelect_
Plane selection tool.
void add_point(const Point &_p)
Append a point to the polyline.
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM >>().sqrnorm()))
compute euclidean norm
PolyLineToolbarWidget * tool_
Widget for Toolbox.
decltype(std::declval< S >()*std::declval< S >()) sqrnorm() const
compute squared euclidean norm
void slotSetPolyLineMode(QAction *_action)
Called by Toolbar to enable pick mode.
QAction * mergeAction_
Called by pick Toolbar.
InterpolatePoint & getInterpolatePoint(unsigned int _handleIndex)
Retrieves the interpolate point based on the handle.
int moveBezSpline_SelSubIndex_
The index of the control or handle being moved.
void smooth_uniform_laplace()
Laplacian smoothing.
QAction * insertCircleAction_
Called by pick Toolbar.
ACG::Vec3d getPointOnMesh(PolyLineBezierSplineData *_SplineData, ACG::Vec3d _point, ACG::Vec3d *_nor=0)
Returns the nearest point on the mesh or if none could be found the input.
pick any of the prior targets (should be implemented for all nodes)
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool addAdditionalNode(NodeT *_node, QString _pluginName, QString _nodeName, int _id=0)
add an additional node to the object
void addInterpolatePoint(ACG::Vec3d _position, ACG::Vec3d _normal)
Adds a point to the end of the list and inserts control points.
IdList generatePolyLinesFromCut(int _objectId, Vector _planePoint, Vector _planeNormal)
Generates a polyLine of a plane intersection.
size_t n_vertices() const
Get number of vertices.
QAction * moveAction_
Called by pick Toolbar.
BaseObject * childExists(int _objectId)
Check if the element exists in the subtree of this element.
QAction * insertSplineAction_
Called by pick Toolbar.
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
int createSpline_LastSelIndex_
Use this one to mark the last index to update the number of points.
QAction * cutMultipleAction_
Called by pick Toolbar.
void split_closed(unsigned int _split_idx)
Split closed polyline at vertex with index _split_idx.
VectorT< double, 3 > Vec3d
#define DATA_TRIANGLE_MESH
picks faces (should be implemented for all nodes)
bool finishSpline()
If possible calculates handles.
int generatePolyLineFromCut(int _objectId, Vector _planePoint, Vector _planeNormal, int _polyLineId=-1)
Generates a polyLine of a plane intersection.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
QAction * polyLineAction_
Called by Toolbar to enable pick mode.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void slotPickToolbarAction(QAction *_action)
Called by pick Toolbar.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.