//=============================================================================
//
// OpenFlipper
// Copyright (C) 2008 by Computer Graphics Group, RWTH Aachen
// www.openflipper.org
//
//-----------------------------------------------------------------------------
//
// License
//
// OpenFlipper is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenFlipper is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenFlipper. If not, see .
//
//-----------------------------------------------------------------------------
//
// $Revision$
// $Author$
// $Date$
//
//=============================================================================
#include
#include "MovePlugin.hh"
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef USE_OPENMP
#include
#endif
#ifdef ENABLE_POLYLINE_SUPPORT
#include
#endif
/** \brief Default Constructor
*
*/
MovePlugin::MovePlugin() :
manMode_ (QtTranslationManipulatorNode::TranslationRotation)
{
manip_size_ = 1.0;
manip_size_modifier_ = 1.0;
selectionType_ = VERTEX;
selectionConnected_ = false;
axisA_ = 0;
axisB_ = 1;
}
/*******************************************************************************
BaseInterface implementation
*******************************************************************************/
/** \brief Initialization of the plugin when it is loaded by the core
*
*/
void MovePlugin::pluginsInitialized() {
//PICKMODES
emit addPickMode("Separator");
emit addHiddenPickMode("Move");
emit setPickModeMouseTracking ("Move", true);
emit addHiddenPickMode("MoveSelection");
emit setPickModeMouseTracking ("MoveSelection", true);
//KEYS
emit registerKey (Qt::Key_Shift, Qt::ShiftModifier, "Manipulator rotation", true);
emit registerKey (Qt::Key_Shift, Qt::NoModifier, "Manipulator rotation", true);
emit registerKey (Qt::Key_Control, Qt::ControlModifier, "Resize", true);
emit registerKey (Qt::Key_Control, Qt::NoModifier, "Resize", true);
//SCRIPTING SLOT DESCRIPTIONS
setDescriptions();
// CONTEXT MENU
contextAction_ = new QAction("Set properties", this);
contextAction_->setToolTip("Set properties");
contextAction_->setStatusTip( contextAction_->toolTip() );
emit addContextMenuItem(contextAction_ , CONTEXTNODEMENU );
connect( contextAction_ , SIGNAL( triggered() ),
this, SLOT(showProps()) );
//TOOLBAR
toolbar_ = new QToolBar("Transform and Move");
toolBarActions_ = new QActionGroup(toolbar_);
moveAction_ = new QAction(tr("&Move objects"), toolBarActions_);
std::cerr << "Todo : Show all manipulators placed" << std::endl;
moveAction_->setStatusTip(tr("Move object in 3D."));
moveAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"move-objects.png") );
moveAction_->setCheckable(true);
toolbar_->addAction(moveAction_);
moveSelectionAction_ = new QAction(tr("Move selections on objects"), toolBarActions_);
moveSelectionAction_->setStatusTip(tr("Move selections in 3D."));
moveSelectionAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"move-selections.png") );
moveSelectionAction_->setCheckable(true);
toolbar_->addAction(moveSelectionAction_);
connect(toolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotSetMoveMode(QAction*)) );
emit addToolbar(toolbar_);
}
/*******************************************************************************
ToolBoxInterface implementation
*******************************************************************************/
/** \brief Create the move toolbox-widget and return a reference to it
*
* @param _widget A reference to the move toolbox that we will return
* @return return wether the widget was successfully generated
*/
bool MovePlugin::initializeToolbox(QWidget*& _widget)
{
toolboxActive_ = false;
tool_ = new moveToolbarWidget();
tool_ -> setMaximumWidth(300);
_widget = tool_;
connect(tool_->moveToOrigin,SIGNAL(clicked() ),this,SLOT(slotMoveToOrigin()));
tool_->moveToOrigin->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "moveToCOG.png") );
tool_->moveToOrigin->setIconSize(QSize(48,48));
connect(tool_->unifyBoundingBoxDiagonal,SIGNAL(clicked() ),this,SLOT(slotUnifyBoundingBoxDiagonal()));
tool_->unifyBoundingBoxDiagonal->setIcon( QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "unifyBB.png") );
tool_->unifyBoundingBoxDiagonal->setIconSize(QSize(48,48));
lastActiveManipulator_ = -1;
return true;
}
/*******************************************************************************
MouseInterface implementation
*******************************************************************************/
/** \brief MouseWheel event occured
*
* @param _event the event that occured
*/
void MovePlugin::slotMouseWheelEvent(QWheelEvent * _event, const std::string & /*_mode*/)
{
manip_size_modifier_ = manip_size_modifier_ - (float)_event->delta() / 120.0 * 0.1;
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it)
o_it->manipulatorNode()->set_size(manip_size_ * manip_size_modifier_);
emit visibilityChanged (-1);
}
//------------------------------------------------------------------------------
/** \brief MousePress event occured
*
* @param _event the event that occured
*/
void MovePlugin::slotMouseEvent( QMouseEvent* _event )
{
QtTranslationManipulatorNode::ManipulatorMode mode;
if (_event->modifiers() & Qt::ControlModifier)
mode = QtTranslationManipulatorNode::Resize;
else if (_event->modifiers() & Qt::ShiftModifier)
mode = QtTranslationManipulatorNode::LocalRotation;
else
mode = QtTranslationManipulatorNode::TranslationRotation;
if (mode != manMode_)
{
manMode_ = mode;
if ((PluginFunctions::pickMode() == "Move" ) || (PluginFunctions::pickMode() == "MoveSelection" )) {
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ;
o_it != PluginFunctions::objectsEnd(); ++o_it)
if ( o_it->manipPlaced() )
o_it->manipulatorNode()->setMode (mode);
}
}
if (((PluginFunctions::pickMode() == ("Move")) || (PluginFunctions::pickMode() == ("MoveSelection"))) &&
PluginFunctions::actionMode() == Viewer::PickingMode) {
if (_event->type() == QEvent::MouseButtonDblClick) {
placeManip(_event);
updateManipulatorDialog();
return;
}
// interaction
ACG::SceneGraph::MouseEventAction action(_event);
PluginFunctions::traverse(action);
if (_event->buttons() == Qt::LeftButton)
emit visibilityChanged (-1);
}
}
/*******************************************************************************
KeyInterface implementation
*******************************************************************************/
void MovePlugin::slotKeyEvent (QKeyEvent* _event)
{
QtTranslationManipulatorNode::ManipulatorMode mode;
if (_event->key() == Qt::Key_Control)
mode = QtTranslationManipulatorNode::Resize;
else if (_event->key () == Qt::Key_Shift)
mode = QtTranslationManipulatorNode::LocalRotation;
else
mode = QtTranslationManipulatorNode::TranslationRotation;
if (mode != manMode_)
{
if ((PluginFunctions::pickMode() == "Move" ) || (PluginFunctions::pickMode() == "MoveSelection" )) {
manMode_ = mode;
for (PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS);
o_it != PluginFunctions::objectsEnd(); ++o_it)
if (o_it->manipPlaced())
o_it->manipulatorNode()->setMode (mode);
}
}
}
//------------------------------------------------------------------------------
void MovePlugin::slotKeyReleaseEvent (QKeyEvent* _event)
{
QtTranslationManipulatorNode::ManipulatorMode mode = manMode_;
if ((_event->key() == Qt::Key_Control && manMode_ == QtTranslationManipulatorNode::Resize) ||
(_event->key() == Qt::Key_Shift && manMode_ == QtTranslationManipulatorNode::LocalRotation))
mode = QtTranslationManipulatorNode::TranslationRotation;
if (mode != manMode_)
{
if ((PluginFunctions::pickMode() == "Move" ) || (PluginFunctions::pickMode() == "MoveSelection" )) {
manMode_ = mode;
for (PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS);
o_it != PluginFunctions::objectsEnd(); ++o_it)
if (o_it->manipPlaced())
o_it->manipulatorNode()->setMode (mode);
}
}
}
/*******************************************************************************
PickingInterface implementation
*******************************************************************************/
/** \brief slot is called when the pickMode changed
*
* @param _mode new pickMode
*/
void MovePlugin::slotPickModeChanged( const std::string& _mode)
{
showManipulators();
moveAction_->setChecked(_mode == "Move");
moveSelectionAction_->setChecked(_mode == "MoveSelection");
}
/*******************************************************************************
MovePlugin implementation
*******************************************************************************/
/** \brief Move object with given transformation matrix
*
* @param mat transformation matrix
* @param _id id of the object
*/
void MovePlugin::moveObject(ACG::Matrix4x4d mat, int _id) {
BaseObjectData* object;
if ( ! PluginFunctions::getObject(_id,object) ) {
emit log(LOGERR,"moveObject called for not existing Object Id");
return;
}
switch ( object->dataType() ) {
case DATA_TRIANGLE_MESH:
transformMesh(mat , *PluginFunctions::triMesh(object) );
break;
case DATA_POLY_MESH:
transformMesh(mat , *PluginFunctions::polyMesh(object) );
break;
case DATA_POLY_LINE:
#ifdef ENABLE_POLYLINE_SUPPORT
transformPolyLine(mat , *PluginFunctions::polyLine(object) );
#endif
break;
default:
emit log(LOGERR,"moveObject called for unsupported Object Type");
return;
}
emit updatedObject(_id);
emit createBackup(_id,"Move");
}
//------------------------------------------------------------------------------
/** \brief Move selection on an object with given transformation matrix
*
* Which Selection (Vertex, Edge, Face) is used is determined by the
* current SelectionMode in SelectionPlugin.
* If the Plugin is unable to communicate with SelectionPlugin, Vertex Selection is used.
*
* @param mat
* @param _id
*/
void MovePlugin::moveSelection(ACG::Matrix4x4d mat, int _id) {
if (selectionType_ == VERTEX)
transformVertexSelection( _id , mat );
else if (selectionType_ == FACE)
transformFaceSelection( _id , mat );
else if (selectionType_ == EDGE)
transformEdgeSelection( _id , mat );
emit updatedObject(_id);
// emit createBackup(_id,"MoveSelection");
}
//------------------------------------------------------------------------------
/** \brief Hide context menu entry when right clicking on node other than manipulator node
*
* @param _nodeId Identifier of node that has been clicked
*/
void MovePlugin::slotUpdateContextMenuNode( int _nodeId ) {
ACG::SceneGraph::BaseNode* node = ACG::SceneGraph::find_node( PluginFunctions::getSceneGraphRootNode(), _nodeId );
if (node == 0) return;
if(node->className() != "QtTranslationManipulatorNode") {
contextAction_->setVisible(false);
}
else {
contextAction_->setVisible(true);
}
}
//------------------------------------------------------------------------------
/** \brief move the object when its manipulator moves
*
* @param _node the manipulator node
* @param _event the mouse event
*/
void MovePlugin::manipulatorMoved( QtTranslationManipulatorNode* _node , QMouseEvent* _event) {
// React on event only in move mode
if ( PluginFunctions::pickMode() != "Move" && PluginFunctions::pickMode() != "MoveSelection" )
return;
OpenFlipper::Options::redrawDisabled( true );
// Apply changes only on Release for moveMode and after every movement in MoveSelection Mode
if ( (_event->type() == QEvent::MouseButtonRelease) || (PluginFunctions::pickMode() == "MoveSelection") ) {
int objectId = _node->getIdentifier();
ACG::Matrix4x4d mat;
mat.identity();
mat = _node->matrix();
// Reset Node
_node->loadIdentity();
_node->set_center(mat.transform_point(_node->center()));
// Always move the object which corresponds to the manipulator
if (PluginFunctions::pickMode() != "MoveSelection")
moveObject( mat, objectId );
else
moveSelection( mat, objectId );
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS ) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
if ( ( o_it->id() != objectId ) && !o_it->manipulatorNode()->visible() ) { // If it has its own manipulator active, dont move it
if (PluginFunctions::pickMode() != "MoveSelection")
moveObject( mat,o_it->id() );
else
moveSelection( mat,o_it->id() );
}
}
lastActiveManipulator_ = objectId;
updateManipulatorDialog();
}
OpenFlipper::Options::redrawDisabled( false );
}
//------------------------------------------------------------------------------
/** \brief update object when its manipulator changes position
*
* @param _node the manipulator node
*/
void MovePlugin::ManipulatorPositionChanged(QtTranslationManipulatorNode* _node ) {
// Position has been changed of the manipulator by a direct function
int objectId = _node->getIdentifier();
BaseObjectData* object;
PluginFunctions::getObject(objectId,object);
// Assume that it has a good position now
object->manipPlaced( true );
// Show manipulator only if in Move mode
if ( PluginFunctions::pickMode() == "Move" )
_node->show();
lastActiveManipulator_ = objectId;
updateManipulatorDialog();
}
//------------------------------------------------------------------------------
/** \brief Place and show the Manipulator
*
* @param _event mouseEvent that occured
*/
void MovePlugin::placeManip(QMouseEvent * _event)
{
unsigned int node_idx, target_idx;
OpenMesh::Vec3d hitPoint;
if ( PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING,_event->pos(), node_idx, target_idx,&hitPoint) ) {
BaseObjectData* object;
if ( PluginFunctions::getPickedObject(node_idx, object) ) {
object->manipPlaced( true );
if ( !object->picked(node_idx) ) {
emit log(LOGWARN,"Picking failed");
}
object->manipulatorNode()->loadIdentity();
object->manipulatorNode()->set_center(hitPoint);
object->manipulatorNode()->set_draw_cylinder(true);
object->manipulatorNode()->set_autosize(QtTranslationManipulatorNode::Once);
object->manipulatorNode()->set_size(manip_size_ * manip_size_modifier_);
object->manipulatorNode()->setMode (manMode_);
object->manipulatorNode()->show();
object->manipulatorNode()->apply_transformation( PluginFunctions::pickMode() == "Move" );
connect(object->manipulatorNode() , SIGNAL(manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)),
this , SLOT( manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)));
connect(object->manipulatorNode() , SIGNAL(positionChanged(QtTranslationManipulatorNode*)),
this , SLOT( ManipulatorPositionChanged(QtTranslationManipulatorNode*)));
lastActiveManipulator_ = object->id();
emit updateView();
} else {
emit log(LOGERR,"Picking ok, but Object was not found in the Object list");
}
} else {
emit log(LOGWARN,"Picking failed");
}
}
//------------------------------------------------------------------------------
/** \brief Checks if the manipulators should be visible or not
*
*/
void MovePlugin::showManipulators( )
{
if ( toolboxActive_
|| (PluginFunctions::pickMode() == "Move" ) || (PluginFunctions::pickMode() == "MoveSelection" ) ) {
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ;
o_it != PluginFunctions::objectsEnd(); ++o_it)
if ( o_it->manipPlaced() ) {
o_it->manipulatorNode()->show();
o_it->manipulatorNode()->apply_transformation( PluginFunctions::pickMode() == "Move" );
}
} else {
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ;
o_it != PluginFunctions::objectsEnd(); ++o_it)
o_it->manipulatorNode()->hide();
}
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Get Dialog Widget that contains the button
*
* @param _but Reference to QPushButton object that has been pressed
*/
movePropsWidget* MovePlugin::getDialogFromButton(QPushButton* _but) {
if(_but == 0) return 0;
return dynamic_cast((((_but->parentWidget())->parentWidget())->parentWidget()));
}
//------------------------------------------------------------------------------
/** \brief Position of manipulator in tab changed
*
*/
void MovePlugin::slotSetPosition() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
TriMesh::Point newpos;
bool ok = false;
newpos[0] = (pW->nposx->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for X Coordinate"); return; }
newpos[1] = (pW->nposy->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Y Coordinate"); return; }
newpos[2] = (pW->nposz->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Z Coordinate"); return; }
BaseObjectData* object;
if ( PluginFunctions::getObject(lastActiveManipulator_ , object) ) {
if ( object->manipulatorNode()->visible() )
object->manipulatorNode()->set_center( newpos );
updateManipulatorDialog();
emit updateView();
}
}
//------------------------------------------------------------------------------
/** \brief Toggle the first axis for changing direction in tab
*
*/
void MovePlugin::slotToggleAxisA() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
axisA_ = (axisA_ + 1) % 3;
if (axisA_ == axisB_)
axisA_ = (axisA_ + 1) % 3;
switch(axisA_){
case 0: pW->axisAButton->setText("X Direction"); break;
case 1: pW->axisAButton->setText("Y Direction"); break;
case 2: pW->axisAButton->setText("Z Direction"); break;
default: break;
}
}
//------------------------------------------------------------------------------
/** \brief Toggle the second axis for changing direction in tab
*
*/
void MovePlugin::slotToggleAxisB() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
axisB_ = (axisB_ + 1) % 3;
if (axisA_ == axisB_)
axisB_ = (axisB_ + 1) % 3;
switch(axisB_){
case 0: pW->axisBButton->setText("X Direction"); break;
case 1: pW->axisBButton->setText("Y Direction"); break;
case 2: pW->axisBButton->setText("Z Direction"); break;
default: break;
}
}
//------------------------------------------------------------------------------
/** \brief Set Direction of manipulator in tab changed
*
*/
void MovePlugin::slotSetDirection() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
ACG::Vec3d newdirA,newdirB;
ACG::Vec3d dirX,dirY;
ACG::Vec3d dirZ(0.0,0.0,0.0);
bool ok = false;
newdirA[0] = (pW->ndirAx->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for X Coordinate"); return; }
newdirA[1] = (pW->ndirAy->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Y Coordinate"); return; }
newdirA[2] = (pW->ndirAz->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Z Coordinate"); return; }
newdirB[0] = (pW->ndirBx->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for X Coordinate"); return; }
newdirB[1] = (pW->ndirBy->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Y Coordinate"); return; }
newdirB[2] = (pW->ndirBz->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Z Coordinate"); return; }
bool xAxis = false;
bool yAxis = false;
switch(axisA_){
case 0: dirX = newdirA; xAxis = true; break;
case 1: dirY = newdirA; yAxis = true; break;
default: dirZ = newdirA; break;
}
switch(axisB_){
case 0: dirX = newdirB; xAxis = true; break;
case 1: dirY = newdirB; yAxis = true; break;
default: dirZ = newdirB; break;
}
if (!xAxis)
dirX = dirY % dirZ;
if (!yAxis)
dirY = dirX % dirZ;
if ( (dirX | dirY) != 0.0){
emit log(LOGERR,"The axes of the new direction have to be orthogonal");
return;
}
// // Apply to All Target Objects
// if ( pW->targetObjects->isChecked() ) {
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ;
// o_it PluginFunctions::objectsEnd(); ++o_it){
//
// o_it->manipulatorNode()->set_direction( dirX, dirY );
// }
// }
BaseObjectData* object = pW->getBaseObjectData();
if ( object != 0 ) {
if ( object->manipulatorNode()->visible() ){
object->manipulatorNode()->set_direction( dirX, dirY );
}
} else return;
updateManipulatorDialog();
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief perform a translation for Manipulator in tab
*
*/
void MovePlugin::slotTranslation() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
ACG::Vec3d translation;
bool ok = false;
translation[0] = (pW->translationX->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for X Coordinate"); return; }
translation[1] = (pW->translationY->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Y Coordinate"); return; }
translation[2] = (pW->translationZ->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Z Coordinate"); return; }
// Apply to All Target Objects
// if ( pW->targetObjects->isChecked() ) {
//
// int manipcount = 0; // Check how many of the target meshes have an visible manipulator
// int targets = 0; // Count the number of target meshes
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
// ++targets;
// if ( ! o_it->manipulatorNode()->hidden() ) {
// ++ manipcount;
// }
// }
//
// if (manipcount == 0 ) // No manipulator -> no translation
// return;
//
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType( DATA_TRIANGLE_MESH | DATA_POLY_MESH )) ;
// o_it != PluginFunctions::objectsEnd(); ++o_it) {
// if ( manipcount > 1 ) { // Use manipulator direction for each target mesh
// if ( o_it->manipulatorNode()->hidden() )
// continue;
// }
//
// translate( o_it->id() , translation );
//
// o_it->manipulatorNode()->set_center( o_it->manipulatorNode()->center() + translation );
// emit createBackup(o_it->id(),"Translation");
// emit updatedObject(o_it->id());
// }
//
// }
BaseObjectData* object = pW->getBaseObjectData();
if ( object != 0 ) {
if ( object->manipulatorNode()->visible() ){
translate( object->id() , translation );
object->manipulatorNode()->set_center( object->manipulatorNode()->center() + translation );
emit createBackup(object->id(),"Translation");
emit updatedObject(object->id());
}
} else return;
updateManipulatorDialog();
emit scriptInfo(QString("slotTranslation()"));
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Project the current manipulator onto the tangent plane of the object
*
*/
void MovePlugin::slotProjectToTangentPlane() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
if ( pW->targetObjects->isChecked() ) {
emit log(LOGWARN,"TODO Project for multiple targets");
return;
} else {
emit log(LOGWARN,"TODO Project for one target");
return;
}
}
//------------------------------------------------------------------------------
/** \brief Move the current manipulator to the cog of the object
*
*/
void MovePlugin::slotMoveManipToCOG() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
// if ( pW->targetObjects->isChecked() ) {
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
// if ( o_it->manipulatorNode()->hidden() )
// continue;
//
// if ( o_it->dataType( DATA_TRIANGLE_MESH ) )
// o_it->manipulatorNode()->set_center( MeshInfo::cog(*PluginFunctions::triMesh(*o_it) ) );
// else if ( o_it->dataType( DATA_POLY_MESH ) )
// o_it->manipulatorNode()->set_center( MeshInfo::cog(*PluginFunctions::polyMesh(*o_it)) );
//
// updateManipulatorDialog();
// o_it->manipulatorNode()->loadIdentity();
// }
// } else {
BaseObjectData* object = pW->getBaseObjectData();
if ( object != 0 ) {
if ( object->manipulatorNode()->visible() ){
if ( object->dataType( DATA_TRIANGLE_MESH ) )
object->manipulatorNode()->set_center( MeshInfo::cog(*PluginFunctions::triMesh(object)) );
else if ( object->dataType( DATA_POLY_MESH ) )
object->manipulatorNode()->set_center( MeshInfo::cog(*PluginFunctions::polyMesh(object)) );
updateManipulatorDialog();
object->manipulatorNode()->loadIdentity();
}
}
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Rotate Manipulator (with values from Tab)
*
*/
void MovePlugin::slotRotate() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
TriMesh::Point axis;
double angle;
bool ok = false;
axis[0] = (pW->rotx->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for X Coordinate"); return; }
axis[1] = (pW->roty->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Y Coordinate"); return; }
axis[2] = (pW->rotz->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Z Coordinate"); return; }
angle = (pW->rotAngle->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for Angle"); return; }
// if ( pW->targetObjects->isChecked() ) {
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
// if ( o_it->manipulatorNode()->hidden() )
// continue;
// o_it->manipulatorNode()->rotate( angle,axis);
//
// if (o_it->dataType( DATA_TRIANGLE_MESH ) )
// transformMesh( o_it->manipulatorNode()->matrix() , (*PluginFunctions::triMesh(*o_it)) );
//
// if (o_it->dataType( DATA_POLY_MESH ) )
// transformMesh( o_it->manipulatorNode()->matrix() , (*PluginFunctions::polyMesh(*o_it)) );
//
// o_it->manipulatorNode()->loadIdentity();
// updateManipulatorDialog();
//
// emit createBackup(o_it->id(),"Rotation");
// emit updatedObject(o_it->id());
// }
// } else {
BaseObjectData* object = pW->getBaseObjectData();
if ( object != 0 ) {
if ( object->manipulatorNode()->visible() ){
object->manipulatorNode()->rotate(angle,axis);
if (object->dataType( DATA_TRIANGLE_MESH ) )
transformMesh( getLastManipulatorMatrix(true) , (*PluginFunctions::triMesh(object)) );
if (object->dataType( DATA_POLY_MESH ) )
transformMesh( getLastManipulatorMatrix(true) , (*PluginFunctions::polyMesh(object)) );
updateManipulatorDialog();
emit createBackup(object->id(),"Rotation");
emit updatedObject(object->id());
}
}
emit scriptInfo(QString("slotRotate()"));
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Scale Manipulator (with values from Tab)
*
*/
void MovePlugin::slotScale() {
QPushButton* but = dynamic_cast(QObject::sender());
movePropsWidget* pW = getDialogFromButton(but);
if(pW == 0) return;
TriMesh::Point scale;
bool ok = false;
scale[0] = (pW->scalex->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for factor 1"); return; }
scale[1] = (pW->scaley->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for factor 2"); return; }
scale[2] = (pW->scalez->text()).toDouble(&ok);
if ( !ok ) { emit log(LOGERR,"Wrong Format for factor 3"); return; }
// if ( pW->targetObjects->isChecked() ) {
// for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
// if ( o_it->manipulatorNode()->hidden() )
// continue;
// o_it->manipulatorNode()->scale( scale);
//
// if (o_it->dataType( DATA_TRIANGLE_MESH ) )
// transformMesh( o_it->manipulatorNode()->matrix() , (*PluginFunctions::triMesh(*o_it)) );
//
// if (o_it->dataType( DATA_POLY_MESH ) )
// transformMesh( o_it->manipulatorNode()->matrix() , (*PluginFunctions::polyMesh(*o_it)) );
//
// o_it->manipulatorNode()->loadIdentity();
// updateManipulatorDialog();
//
// emit createBackup(o_it->id(),"Scaling");
// emit updatedObject(o_it->id());
// }
// } else {
BaseObjectData* object = pW->getBaseObjectData();
if ( object != 0 ) {
if ( object->manipulatorNode()->visible() ){
object->manipulatorNode()->scale( scale);
if (object->dataType( DATA_TRIANGLE_MESH ) )
transformMesh( getLastManipulatorMatrix(true) , (*PluginFunctions::triMesh(object)) );
if (object->dataType( DATA_POLY_MESH ) )
transformMesh( getLastManipulatorMatrix(true) , (*PluginFunctions::polyMesh(object)) );
updateManipulatorDialog();
emit createBackup(object->id(),"Scaling");
emit updatedObject(object->id());
}
}
emit scriptInfo(QString("slotScale()"));
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Move currently active or first Mesh with its COG to the origin
*
*/
void MovePlugin::slotMoveToOrigin() {
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
if ( o_it->dataType( DATA_TRIANGLE_MESH )) {
TriMesh& mesh = *PluginFunctions::triMesh(*o_it);
const TriMesh::Point cog = MeshInfo::cog(mesh);
for ( TriMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end() ; ++v_it)
mesh.set_point(v_it , ( mesh.point(v_it) ) - cog );
o_it->manipulatorNode()->set_center( o_it->manipulatorNode()->center() - cog );
}
if ( o_it->dataType( DATA_POLY_MESH )) {
PolyMesh& mesh = *PluginFunctions::polyMesh(*o_it);
const PolyMesh::Point cog = MeshInfo::cog(mesh);
for ( PolyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end() ; ++v_it)
mesh.set_point(v_it , ( mesh.point(v_it) ) - cog );
o_it->manipulatorNode()->set_center( o_it->manipulatorNode()->center() - cog );
}
emit updatedObject( o_it->id() );
updateManipulatorDialog();
o_it->manipulatorNode()->loadIdentity();
emit createBackup(o_it->id(),"Move to origin");
}
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Scale Boundingbox Diagonal to unit size
*
*/
void MovePlugin::slotUnifyBoundingBoxDiagonal()
{
if ( tool_->targetObjects->isChecked() ) {
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
if ( o_it->dataType( DATA_TRIANGLE_MESH ) )
unifyBBDiag(*PluginFunctions::triMesh(*o_it));
else if ( o_it->dataType( DATA_POLY_MESH ) )
unifyBBDiag(*PluginFunctions::polyMesh(*o_it));
emit updatedObject( o_it->id() );
}
} else {
BaseObjectData* object;
if ( PluginFunctions::getObject(lastActiveManipulator_ , object) ) {
if ( object->manipulatorNode()->visible() ) {
if ( object->dataType( DATA_TRIANGLE_MESH ) )
unifyBBDiag(*PluginFunctions::triMesh(object));
else if ( object->dataType( DATA_POLY_MESH ) )
unifyBBDiag(*PluginFunctions::polyMesh(object));
}
emit updatedObject( object->id() );
}
}
emit updateView();
}
//------------------------------------------------------------------------------
/** \brief Update the Dialog with the last clicked manipulator
*
*/
void MovePlugin::updateManipulatorDialog() {
BaseObjectData* object;
if ( !PluginFunctions::getObject(lastActiveManipulator_ , object) ) {
return;
}
if ( object->manipulatorNode()->visible() ) {
// Get properties widget that corresponds to
// to the last manipulated object
movePropsWidget* pW = getDialogWidget(object);
// If there's no properties dialog yet...
if(pW == 0) return;
const TriMesh::Point pos = object->manipulatorNode()->center();
QString num;
num = QString::number(pos[0]); pW->posx->setText(num);
num = QString::number(pos[1]); pW->posy->setText(num);
num = QString::number(pos[2]); pW->posz->setText(num);
TriMesh::Point direction = object->manipulatorNode()->directionX();
num = QString::number(direction[0]); pW->dirxx->setText(num);
num = QString::number(direction[1]); pW->dirxy->setText(num);
num = QString::number(direction[2]); pW->dirxz->setText(num);
direction = object->manipulatorNode()->directionY();
num = QString::number(direction[0]); pW->diryx->setText(num);
num = QString::number(direction[1]); pW->diryy->setText(num);
num = QString::number(direction[2]); pW->diryz->setText(num);
direction = object->manipulatorNode()->directionZ();
num = QString::number(direction[0]); pW->dirzx->setText(num);
num = QString::number(direction[1]); pW->dirzy->setText(num);
num = QString::number(direction[2]); pW->dirzz->setText(num);
}
}
//------------------------------------------------------------------------------
/** \brief Get pointer to corresponding dialog widget
*
* @param _obj the object to which the dialog is attached
*/
movePropsWidget* MovePlugin::getDialogWidget(BaseObjectData* _obj) {
for(QList::iterator it = propsWindows_.begin();
it != propsWindows_.end(); it++) {
if ((*it)->getBaseObjectData() == _obj)
return *it;
}
return 0;
}
//------------------------------------------------------------------------------
/** \brief Called by Toolbar to enable move mode
*
* @param _action the action that was triggered
*/
void MovePlugin::slotSetMoveMode(QAction* _action) {
if (_action == moveAction_){
PluginFunctions::actionMode(Viewer::PickingMode);
PluginFunctions::pickMode("Move");
moveAction_->setChecked( true );
}
if (_action == moveSelectionAction_){
connectSelectionActions();
PluginFunctions::actionMode(Viewer::PickingMode);
PluginFunctions::pickMode("MoveSelection");
moveSelectionAction_->setChecked( true );
}
}
//------------------------------------------------------------------------------
/** \brief Get the Matrix of the last active Manipulator ( Identity if not found or hidden Manipulator )
*
* @param _reset reset the transformation matrix of the manipulator to identity)
* @return current transformation matrix of the manipulator
*/
ACG::Matrix4x4d MovePlugin::getLastManipulatorMatrix(bool _reset) {
ACG::Matrix4x4d matrix;
matrix.identity();
BaseObjectData* object;
if ( PluginFunctions::getObject(lastActiveManipulator_ , object) )
if ( object->manipulatorNode()->visible() ) {
matrix = object->manipulatorNode()->matrix();
if (_reset)
object->manipulatorNode()->loadIdentity();
}
return matrix;
}
//------------------------------------------------------------------------------
/** \brief Transform a mesh with the given transformation matrix
*
* @param _mat transformation matrix
* @param _mesh the mesh
*/
template< typename MeshT >
void MovePlugin::transformMesh(ACG::Matrix4x4d _mat , MeshT& _mesh ) {
typename MeshT::VertexIter v_it = _mesh.vertices_begin();
typename MeshT::VertexIter v_end = _mesh.vertices_end();
for (; v_it!=v_end; ++v_it) {
_mesh.set_point(v_it,(typename MeshT::Point)_mat.transform_point((OpenMesh::Vec3d)(_mesh.point(v_it))));
_mesh.set_normal(v_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(v_it))));
}
typename MeshT::FaceIter f_it = _mesh.faces_begin();
typename MeshT::FaceIter f_end = _mesh.faces_end();
for (; f_it != f_end; ++f_it)
_mesh.set_normal(f_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(f_it))));
}
//------------------------------------------------------------------------------
#ifdef ENABLE_POLYLINE_SUPPORT
/** \brief Transform a polyline with the given transformation matrix
*
* @param _mat transformation matrix
* @param _polyLine the polyline
*/
template< class PolyLineT >
void MovePlugin::transformPolyLine( ACG::Matrix4x4d _mat , PolyLineT& _polyLine ) {
#ifdef USE_OPENMP
#pragma omp parallel for
#endif
for ( int i = 0 ; i < (int)_polyLine.n_vertices(); ++i )
_polyLine.point(i) = _mat.transform_point( _polyLine.point(i) );
}
#endif
//------------------------------------------------------------------------------
/** \brief scale mesh to have a boundingboxdiagonal of one
*
* @param _mesh the mesh
*/
template< typename MeshT >
void MovePlugin::unifyBBDiag(MeshT& _mesh )
{
typename MeshT::VertexIter v_it = _mesh.vertices_begin();
typename MeshT::VertexIter v_end = _mesh.vertices_end();
// no vertices?
if( v_it == v_end) return;
typename MeshT::Point bb_min = _mesh.point(v_it);
typename MeshT::Point bb_max = _mesh.point(v_it);
for(; v_it!=v_end; ++v_it)
{
bb_min.minimize( _mesh.point(v_it));
bb_max.maximize( _mesh.point(v_it));
}
typename MeshT::Point bb_center = 0.5 * (bb_min + bb_max) ;
typename MeshT::Scalar scale = 1.0/(bb_max-bb_min).norm();
for( v_it = _mesh.vertices_begin(); v_it!=v_end; ++v_it)
{
_mesh.point(v_it) = (_mesh.point(v_it) - bb_center) * scale + bb_center;
}
}
//------------------------------------------------------------------------------
/** \brief Connect to SelectionPlugin
*
*/
void MovePlugin::connectSelectionActions(){
if (!selectionConnected_){
selectionConnected_ = true;
bool connected = false;
QToolBar* selToolBar = 0;
emit getToolBar( "Selection", selToolBar );
if (selToolBar != 0){
QActionGroup* actionGroup = 0;
for (int i=0; i < selToolBar->actions().count(); i++){
if( selToolBar->actions().at(i)->text() == "Enable Vertex Selection"){
actionGroup = selToolBar->actions().at(i)->actionGroup();
if ( selToolBar->actions().at(i)->isChecked() )
selectionType_ = VERTEX;
} else if ( (selToolBar->actions().at(i)->text() == "Enable Edge Selection")
&& (selToolBar->actions().at(i)->isChecked()) )
selectionType_ = EDGE;
else if ( (selToolBar->actions().at(i)->text() == "Enable Face Selection")
&& (selToolBar->actions().at(i)->isChecked()) )
selectionType_ = FACE;
}
if (actionGroup != 0){
connect( actionGroup, SIGNAL( triggered(QAction*) ), this, SLOT(slotSelectionModeChanged(QAction*)) );
connected = true;
}
}
if (!connected)
emit log(LOGWARN, "Unable to connect to Selection-Plugin. MoveSelection will work on vertices only.");
}
}
//------------------------------------------------------------------------------
/** \brief The SelectionMode in SelectionPlugin Changed
*
* @param _action the action on the Selection-Toolbar that was hit
*/
void MovePlugin::slotSelectionModeChanged(QAction* _action){
if (_action->text() == "Enable Vertex Selection")
selectionType_ = VERTEX;
if (_action->text() == "Enable Edge Selection")
selectionType_ = EDGE;
if (_action->text() == "Enable Face Selection")
selectionType_ = FACE;
}
Q_EXPORT_PLUGIN2( moveplugin , MovePlugin );