/*************************************************************************** * Copyright (c) 2017 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif # include /// Here the FreeCAD includes sorted by Base,App,Gui...... #include "ViewProviderDragger.h" #include "View3DInventorViewer.h" #include "Application.h" #include "Document.h" #include "Window.h" #include #include #include #include #include #include #if (COIN_MAJOR_VERSION > 2) #include #endif #include "SoFCUnifiedSelection.h" #include "SoFCCSysDragger.h" #include "Control.h" #include "TaskCSysDragger.h" #include using namespace Gui; PROPERTY_SOURCE(Gui::ViewProviderDragger, Gui::ViewProviderDocumentObject) ViewProviderDragger::ViewProviderDragger() { } ViewProviderDragger::~ViewProviderDragger() { } void ViewProviderDragger::updateData(const App::Property* prop) { if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId()) && strcmp(prop->getName(), "Placement") == 0) { // Note: If R is the rotation, c the rotation center and t the translation // vector then Inventor applies the following transformation: R*(x-c)+c+t // In FreeCAD a placement only has a rotation and a translation part but // no rotation center. This means that the following equation must be ful- // filled: R * (x-c) + c + t = R * x + t // <==> R * x + t - R * c + c = R * x + t // <==> (I-R) * c = 0 ==> c = 0 // This means that the center point must be the origin! Base::Placement p = static_cast(prop)->getValue(); updateTransform(p, pcTransform); } else { ViewProviderDocumentObject::updateData(prop); } } bool ViewProviderDragger::doubleClicked(void) { Gui::Application::Instance->activeDocument()->setEdit(this, (int)ViewProvider::Default); return true; } void ViewProviderDragger::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act = menu->addAction(QObject::tr("Transform"), receiver, member); act->setData(QVariant((int)ViewProvider::Transform)); } bool ViewProviderDragger::setEdit(int ModNum) { Q_UNUSED(ModNum); App::DocumentObject *genericObject = this->getObject(); if (genericObject->isDerivedFrom(App::GeoFeature::getClassTypeId())) { App::GeoFeature *geoFeature = static_cast(genericObject); const Base::Placement &placement = geoFeature->Placement.getValue(); SoTransform *tempTransform = new SoTransform(); tempTransform->ref(); updateTransform(placement, tempTransform); assert(!csysDragger); csysDragger = new SoFCCSysDragger(); csysDragger->draggerSize.setValue(0.05f); csysDragger->translation.setValue(tempTransform->translation.getValue()); csysDragger->rotation.setValue(tempTransform->rotation.getValue()); tempTransform->unref(); pcTransform->translation.connectFrom(&csysDragger->translation); pcTransform->rotation.connectFrom(&csysDragger->rotation); csysDragger->addStartCallback(dragStartCallback, this); csysDragger->addFinishCallback(dragFinishCallback, this); pcRoot->insertChild(csysDragger, 0); TaskCSysDragger *task = new TaskCSysDragger(this, csysDragger); Gui::Control().showDialog(task); } return true; } void ViewProviderDragger::unsetEdit(int ModNum) { Q_UNUSED(ModNum); if(csysDragger) { pcTransform->translation.disconnect(&csysDragger->translation); pcTransform->rotation.disconnect(&csysDragger->rotation); pcRoot->removeChild(csysDragger); //should delete csysDragger csysDragger = nullptr; } Gui::Control().closeDialog(); } void ViewProviderDragger::setEditViewer(Gui::View3DInventorViewer* viewer, int ModNum) { Q_UNUSED(ModNum); if (csysDragger && viewer) { SoPickStyle *rootPickStyle = new SoPickStyle(); rootPickStyle->style = SoPickStyle::UNPICKABLE; SoFCUnifiedSelection* selection = static_cast(viewer->getSceneGraph()); selection->insertChild(rootPickStyle, 0); selection->selectionRole.setValue(false); csysDragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera()); } } void ViewProviderDragger::unsetEditViewer(Gui::View3DInventorViewer* viewer) { SoEventManager* mgr = viewer->getSoEventManager(); SoHandleEventAction* heaction = mgr->getHandleEventAction(); if (heaction && heaction->getGrabber()) heaction->releaseGrabber(); SoFCUnifiedSelection* selection = static_cast(viewer->getSceneGraph()); SoNode *child = selection->getChild(0); if (child && child->isOfType(SoPickStyle::getClassTypeId())) { selection->removeChild(child); selection->selectionRole.setValue(true); } } void ViewProviderDragger::dragStartCallback(void *, SoDragger *) { // This is called when a manipulator is about to manipulating Gui::Application::Instance->activeDocument()->openCommand("Transform"); } void ViewProviderDragger::dragFinishCallback(void *data, SoDragger *d) { // This is called when a manipulator has done manipulating ViewProviderDragger* sudoThis = reinterpret_cast(data); SoFCCSysDragger *dragger = static_cast(d); updatePlacementFromDragger(sudoThis, dragger); Gui::Application::Instance->activeDocument()->commitCommand(); } void ViewProviderDragger::updatePlacementFromDragger(ViewProviderDragger* sudoThis, SoFCCSysDragger* draggerIn) { App::DocumentObject *genericObject = sudoThis->getObject(); if (!genericObject->isDerivedFrom(App::GeoFeature::getClassTypeId())) return; App::GeoFeature *geoFeature = static_cast(genericObject); Base::Placement originalPlacement = geoFeature->Placement.getValue(); double pMatrix[16]; originalPlacement.toMatrix().getMatrix(pMatrix); Base::Placement freshPlacement = originalPlacement; //local cache for brevity. double translationIncrement = draggerIn->translationIncrement.getValue(); double rotationIncrement = draggerIn->rotationIncrement.getValue(); int tCountX = draggerIn->translationIncrementCountX.getValue(); int tCountY = draggerIn->translationIncrementCountY.getValue(); int tCountZ = draggerIn->translationIncrementCountZ.getValue(); int rCountX = draggerIn->rotationIncrementCountX.getValue(); int rCountY = draggerIn->rotationIncrementCountY.getValue(); int rCountZ = draggerIn->rotationIncrementCountZ.getValue(); //just as a little sanity check make sure only 1 field has changed. int numberOfFieldChanged = 0; if (tCountX) numberOfFieldChanged++; if (tCountY) numberOfFieldChanged++; if (tCountZ) numberOfFieldChanged++; if (rCountX) numberOfFieldChanged++; if (rCountY) numberOfFieldChanged++; if (rCountZ) numberOfFieldChanged++; if (numberOfFieldChanged == 0) return; assert(numberOfFieldChanged == 1); //helper lamdas. auto getVectorX = [&pMatrix]() {return Base::Vector3d(pMatrix[0], pMatrix[4], pMatrix[8]);}; auto getVectorY = [&pMatrix]() {return Base::Vector3d(pMatrix[1], pMatrix[5], pMatrix[9]);}; auto getVectorZ = [&pMatrix]() {return Base::Vector3d(pMatrix[2], pMatrix[6], pMatrix[10]);}; if (tCountX) { Base::Vector3d movementVector(getVectorX()); movementVector *= (tCountX * translationIncrement); freshPlacement.move(movementVector); geoFeature->Placement.setValue(freshPlacement); } else if (tCountY) { Base::Vector3d movementVector(getVectorY()); movementVector *= (tCountY * translationIncrement); freshPlacement.move(movementVector); geoFeature->Placement.setValue(freshPlacement); } else if (tCountZ) { Base::Vector3d movementVector(getVectorZ()); movementVector *= (tCountZ * translationIncrement); freshPlacement.move(movementVector); geoFeature->Placement.setValue(freshPlacement); } else if (rCountX) { Base::Vector3d rotationVector(getVectorX()); Base::Rotation rotation(rotationVector, rCountX * rotationIncrement); freshPlacement.setRotation(rotation * freshPlacement.getRotation()); geoFeature->Placement.setValue(freshPlacement); } else if (rCountY) { Base::Vector3d rotationVector(getVectorY()); Base::Rotation rotation(rotationVector, rCountY * rotationIncrement); freshPlacement.setRotation(rotation * freshPlacement.getRotation()); geoFeature->Placement.setValue(freshPlacement); } else if (rCountZ) { Base::Vector3d rotationVector(getVectorZ()); Base::Rotation rotation(rotationVector, rCountZ * rotationIncrement); freshPlacement.setRotation(rotation * freshPlacement.getRotation()); geoFeature->Placement.setValue(freshPlacement); } draggerIn->clearIncrementCounts(); } void ViewProviderDragger::updateTransform(const Base::Placement& from, SoTransform* to) { float q0 = (float)from.getRotation().getValue()[0]; float q1 = (float)from.getRotation().getValue()[1]; float q2 = (float)from.getRotation().getValue()[2]; float q3 = (float)from.getRotation().getValue()[3]; float px = (float)from.getPosition().x; float py = (float)from.getPosition().y; float pz = (float)from.getPosition().z; to->rotation.setValue(q0,q1,q2,q3); to->translation.setValue(px,py,pz); to->center.setValue(0.0f,0.0f,0.0f); to->scaleFactor.setValue(1.0f,1.0f,1.0f); }