diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 366c6b1dc..49bea4d1a 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -204,6 +204,7 @@ set(Gui_MOC_HDRS DlgToolbarsImp.h DlgWorkbenchesImp.h TaskDlgRelocation.h + TaskCSysDragger.h DlgUndoRedo.h DockWindow.h DockWindowManager.h @@ -382,6 +383,7 @@ SET(Dialog_CPP_SRCS DlgExpressionInput.cpp TaskDlgRelocation.cpp DlgCheckableMessageBox.cpp + TaskCSysDragger.cpp DlgUndoRedo.cpp InputVector.cpp Placement.cpp @@ -415,6 +417,7 @@ SET(Dialog_HPP_SRCS DlgTipOfTheDayImp.h DlgExpressionInput.h TaskDlgRelocation.h + TaskCSysDragger.h DlgUndoRedo.h InputVector.h Placement.h @@ -890,6 +893,7 @@ SET(Inventor_CPP_SRCS SoAxisCrossKit.cpp SoTextLabel.cpp SoTouchEvents.cpp + SoFCCSysDragger.cpp ) SET(Inventor_SRCS ${Inventor_CPP_SRCS} @@ -913,6 +917,7 @@ SET(Inventor_SRCS SoAxisCrossKit.h SoTextLabel.h SoTouchEvents.h + SoFCCSysDragger.h ) SOURCE_GROUP("View3D\\Inventor" FILES ${Inventor_SRCS}) diff --git a/src/Gui/SoFCCSysDragger.cpp b/src/Gui/SoFCCSysDragger.cpp new file mode 100644 index 000000000..cffba95a9 --- /dev/null +++ b/src/Gui/SoFCCSysDragger.cpp @@ -0,0 +1,1131 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 + +#include +#include +#include +#include +#include "SoFCDB.h" +#include "SoFCCSysDragger.h" + +/* + GENERAL NOTE ON COIN3D CUSTOM DRAGGERS + * You basically have two choices for creating custom dragger geometry. + * 1) create an .iv file and set environment variable to the file path. This + * comes with install headaches. + * 2) create an .iv file and run through a mock compiler that generates a header + * file to include in the project. I would have gone this way but after installing + * inventor-demo(ubuntu), the mock compiler tool was there only in source and make + * didn't do anything. Didn't want to put any time into something I didn't like anyway. + * + * static SbList * defaultdraggerparts = NULL; is a global definition + * in SoInteractionKit that contains the geometry. There doesn't appear to be anyway + * to add to this other than readDefaultParts, that takes a file. So maybe a temp file? + * + * naming appears to be central to the core. It looks like as long as an object + * is alive SoNode::getByName() will find it. So maybe just create my own little + * container of objects to keep the default geometry alive....This appears to be + * working and I like this solution. + * + * SoInteractionKit warns about these + * names all being the same scope and do NOT have to be unique. Need to make names + * descriptive to avoid collisions. + + * this is point of the SoGroup accessed from SoFCDB::getStorage(). +*/ + +using namespace Gui; + +SO_KIT_SOURCE(TDragger) + +void TDragger::initClass() +{ + SO_KIT_INIT_CLASS(TDragger, SoDragger, "Dragger"); +} + +TDragger::TDragger() +{ + SO_KIT_CONSTRUCTOR(TDragger); + + SO_KIT_ADD_CATALOG_ENTRY(translatorSwitch, SoSwitch, TRUE, geomSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(translator, SoSeparator, TRUE, translatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(translatorActive, SoSeparator, TRUE, translatorSwitch, , TRUE); + + if (SO_KIT_IS_FIRST_INSTANCE()) + buildFirstInstance(); + + SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0)); + SO_KIT_ADD_FIELD(translationIncrement, (1.0)); + SO_KIT_ADD_FIELD(translationIncrementCount, (0)); + SO_KIT_ADD_FIELD(autoScaleResult, (1.0)); + + SO_KIT_INIT_INSTANCE(); + + // initialize default parts. + // first is from 'SO_KIT_CATALOG_ENTRY_HEADER' macro + // second is unique name from buildFirstInstance(). + this->setPartAsDefault("translator", "CSysDynamics_TDragger_Translator"); + this->setPartAsDefault("translatorActive", "CSysDynamics_TDragger_TranslatorActive"); + + SoSwitch *sw = SO_GET_ANY_PART(this, "translatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 0); + + this->addStartCallback(&TDragger::startCB); + this->addMotionCallback(&TDragger::motionCB); + this->addFinishCallback(&TDragger::finishCB); + + addValueChangedCallback(&TDragger::valueChangedCB); + + fieldSensor.setFunction(&TDragger::fieldSensorCB); + fieldSensor.setData(this); + fieldSensor.setPriority(0); + + this->setUpConnections(TRUE, TRUE); +} + +TDragger::~TDragger() +{ + +} + +void TDragger::buildFirstInstance() +{ + SoGroup *geometryGroup = buildGeometry(); + + SoSeparator *localTranslator = new SoSeparator(); + localTranslator->setName("CSysDynamics_TDragger_Translator"); + localTranslator->addChild(geometryGroup); + SoFCDB::getStorage()->addChild(localTranslator); + + SoSeparator *localTranslatorActive = new SoSeparator(); + localTranslatorActive->setName("CSysDynamics_TDragger_TranslatorActive"); + SoBaseColor *colorActive = new SoBaseColor(); + colorActive->rgb.setValue(1.0, 1.0, 0.0); + localTranslatorActive->addChild(colorActive); + localTranslatorActive->addChild(geometryGroup); + SoFCDB::getStorage()->addChild(localTranslatorActive); +} + +SoGroup* TDragger::buildGeometry() +{ + //this builds one leg in the Y+ direction because of default done direction. + //the location anchor for shapes is the center of shape. + + SoGroup *root = new SoGroup(); + + //cylinder + float cylinderHeight = 10.0; + float cylinderRadius = 0.2; + SoSeparator *cylinderSeparator = new SoSeparator(); + root->addChild(cylinderSeparator); + + SoTranslation *cylinderTranslation = new SoTranslation(); + cylinderTranslation->translation.setValue(0.0, cylinderHeight / 2.0, 0.0); + cylinderSeparator->addChild(cylinderTranslation); + + SoCylinder *cylinder = new SoCylinder(); + cylinder->radius.setValue(cylinderRadius); + cylinder->height.setValue(cylinderHeight); + cylinderSeparator->addChild(cylinder); + + //cone + float coneBottomRadius = 1.0; + float coneHeight = 2.0; + SoSeparator *coneSeparator = new SoSeparator(); + root->addChild(coneSeparator); + + SoPickStyle *pickStyle = new SoPickStyle(); + pickStyle->style.setValue(SoPickStyle::SHAPE); + pickStyle->setOverride(TRUE); + coneSeparator->addChild(pickStyle); + + SoTranslation *coneTranslation = new SoTranslation(); + coneTranslation->translation.setValue(0.0, cylinderHeight + coneHeight / 2.0, 0.0); + coneSeparator->addChild(coneTranslation); + + SoCone *cone = new SoCone(); + cone->bottomRadius.setValue(coneBottomRadius); + cone->height.setValue(coneHeight); + coneSeparator->addChild(cone); + + return root; +} + +void TDragger::startCB(void *, SoDragger *d) +{ + TDragger *sudoThis = dynamic_cast(d); + sudoThis->dragStart(); +} + +void TDragger::motionCB(void *, SoDragger *d) +{ + TDragger *sudoThis = dynamic_cast(d); + sudoThis->drag(); +} + +void TDragger::finishCB(void *, SoDragger *d) +{ + TDragger *sudoThis = dynamic_cast(d); + sudoThis->dragFinish(); +} + +void TDragger::fieldSensorCB(void *f, SoSensor *) +{ + TDragger *sudoThis = reinterpret_cast(f); + + SbMatrix matrix = sudoThis->getMotionMatrix(); + sudoThis->workFieldsIntoTransform(matrix); + sudoThis->setMotionMatrix(matrix); +} + +void TDragger::valueChangedCB(void *, SoDragger *d) +{ + TDragger *sudoThis = dynamic_cast(d); + assert(sudoThis); + SbMatrix matrix = sudoThis->getMotionMatrix(); + + //all this just to get the translation? + SbVec3f trans, scaleDummy; + SbRotation rotationDummy, scaleOrientationDummy; + matrix.getTransform(trans, rotationDummy, scaleDummy, scaleOrientationDummy); + + sudoThis->fieldSensor.detach(); + if (sudoThis->translation.getValue() != trans) + sudoThis->translation = trans; + sudoThis->fieldSensor.attach(&sudoThis->translation); +} + +void TDragger::dragStart() +{ + SoSwitch *sw; + sw = SO_GET_ANY_PART(this, "translatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 1); + + //do an initial projection to eliminate discrepancies + //in arrow head pick. we define the arrow in the y+ direction + //and we know local space will be relative to this. so y vector + //line projection will work. + projector.setViewVolume(this->getViewVolume()); + projector.setWorkingSpace(this->getLocalToWorldMatrix()); + projector.setLine(SbLine(SbVec3f(0.0, 0.0, 0.0), SbVec3f(0.0, 1.0, 0.0))); + SbVec3f hitPoint = projector.project(getNormalizedLocaterPosition()); + + projector.setLine(SbLine(SbVec3f(0.0, 0.0, 0.0), hitPoint)); + + SbMatrix localToWorld = getLocalToWorldMatrix(); + localToWorld.multVecMatrix(hitPoint, hitPoint); + setStartingPoint((hitPoint)); + + translationIncrementCount.setValue(0); +} +void TDragger::drag() +{ + projector.setViewVolume(this->getViewVolume()); + projector.setWorkingSpace(this->getLocalToWorldMatrix()); + + SbVec3f hitPoint = projector.project(getNormalizedLocaterPosition()); + SbVec3f startingPoint = getLocalStartingPoint(); + SbVec3f localMovement = hitPoint - startingPoint; + + //scale the increment to match local space. + float scaledIncrement = static_cast(translationIncrement.getValue()) / autoScaleResult.getValue(); + + localMovement = roundTranslation(localMovement, scaledIncrement); + //when the movement vector is null either the appendTranslation or + //the setMotionMatrix doesn't work. either way it stops translating + //back to its initial starting point. + if (localMovement.equals(SbVec3f(0.0, 0.0, 0.0), 0.00001)) + { + setMotionMatrix(getStartMotionMatrix()); + //don't know why I need the following but if I don't have it + //it won't return to original position. + this->valueChanged(); + } + else + setMotionMatrix(appendTranslation(getStartMotionMatrix(), localMovement)); + + Base::Quantity quantity( + static_cast(translationIncrementCount.getValue()) * translationIncrement.getValue(), Base::Unit::Length); + + QString message(QObject::tr("Translation: ")); + message += quantity.getUserString(); + getMainWindow()->showMessage(message, 3000); +} + +void TDragger::dragFinish() +{ + SoSwitch *sw; + sw = SO_GET_ANY_PART(this, "translatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 0); +} + +SbBool TDragger::setUpConnections(SbBool onoff, SbBool doitalways) +{ + if (!doitalways && this->connectionsSetUp == onoff) + return onoff; + + SbBool oldval = this->connectionsSetUp; + + if (onoff) + { + inherited::setUpConnections(onoff, doitalways); + TDragger::fieldSensorCB(this, NULL); + if (this->fieldSensor.getAttachedField() != &this->translation) + this->fieldSensor.attach(&this->translation); + } + else + { + if (this->fieldSensor.getAttachedField() != NULL) + this->fieldSensor.detach(); + inherited::setUpConnections(onoff, doitalways); + } + this->connectionsSetUp = onoff; + return oldval; +} + +SbVec3f TDragger::roundTranslation(const SbVec3f &vecIn, float incrementIn) +{ + //everything is transformed into local space. That means we only have + //worry about the y-value. + + int yCount = 0; + float yValue = vecIn[1]; + + if (fabs(yValue) > (incrementIn / 2.0)) + { + yCount = static_cast(yValue / incrementIn); + float remainder = fmod(yValue, incrementIn); + if (remainder >= (incrementIn / 2.0)) + yCount++; + } + + translationIncrementCount.setValue(yCount); + + SbVec3f out; + out[0] = 0.0; + out[1] = static_cast(yCount) * incrementIn; + out[2] = 0.0; + + return out; +} + +SO_KIT_SOURCE(RDragger) + +void RDragger::initClass() +{ + SO_KIT_INIT_CLASS(RDragger, SoDragger, "Dragger"); +} + +RDragger::RDragger() +{ + SO_KIT_CONSTRUCTOR(RDragger); + + SO_KIT_ADD_CATALOG_ENTRY(rotatorSwitch, SoSwitch, TRUE, geomSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(rotator, SoSeparator, TRUE, rotatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(rotatorActive, SoSeparator, TRUE, rotatorSwitch, , TRUE); + + arcRadius = 8.0; + + if (SO_KIT_IS_FIRST_INSTANCE()) + buildFirstInstance(); + + SO_KIT_ADD_FIELD(rotation, (SbVec3f(0.0, 0.0, 1.0), 0.0)); + SO_KIT_ADD_FIELD(rotationIncrement, (M_PI / 8.0)); + SO_KIT_ADD_FIELD(rotationIncrementCount, (0)); + + SO_KIT_INIT_INSTANCE(); + + // initialize default parts. + // first is from 'SO_KIT_CATALOG_ENTRY_HEADER' macro + // second is unique name from buildFirstInstance(). + this->setPartAsDefault("rotator", "CSysDynamics_RDragger_Rotator"); + this->setPartAsDefault("rotatorActive", "CSysDynamics_RDragger_RotatorActive"); + + SoSwitch *sw = SO_GET_ANY_PART(this, "rotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 0); + + this->addStartCallback(&RDragger::startCB); + this->addMotionCallback(&RDragger::motionCB); + this->addFinishCallback(&RDragger::finishCB); + + addValueChangedCallback(&RDragger::valueChangedCB); + + fieldSensor.setFunction(&RDragger::fieldSensorCB); + fieldSensor.setData(this); + fieldSensor.setPriority(0); + + this->setUpConnections(TRUE, TRUE); +} + +RDragger::~RDragger() +{ + +} + +void RDragger::buildFirstInstance() +{ + SoGroup *geometryGroup = buildGeometry(); + + SoSeparator *localRotator = new SoSeparator(); + localRotator->setName("CSysDynamics_RDragger_Rotator"); + localRotator->addChild(geometryGroup); + SoFCDB::getStorage()->addChild(localRotator); + + SoSeparator *localRotatorActive = new SoSeparator(); + localRotatorActive->setName("CSysDynamics_RDragger_RotatorActive"); + SoBaseColor *colorActive = new SoBaseColor(); + colorActive->rgb.setValue(1.0, 1.0, 0.0); + localRotatorActive->addChild(colorActive); + localRotatorActive->addChild(geometryGroup); + SoFCDB::getStorage()->addChild(localRotatorActive); +} + +SoGroup* RDragger::buildGeometry() +{ + SoGroup *root = new SoGroup(); + + //arc + SoCoordinate3 *coordinates = new SoCoordinate3(); + + unsigned int segments = 6; + + float angleIncrement = static_cast(M_PI / 2.0) / static_cast(segments); + SbRotation rotation(SbVec3f(0.0, 0.0, 1.0), angleIncrement); + SbVec3f point(arcRadius, 0.0, 0.0); + for (unsigned int index = 0; index <= segments; ++index) + { + coordinates->point.set1Value(index, point); + rotation.multVec(point, point); + } + root->addChild(coordinates); + + SoLineSet *lineSet = new SoLineSet(); + lineSet->numVertices.setValue(segments + 1); + root->addChild(lineSet); + + SoPickStyle *pickStyle = new SoPickStyle(); + pickStyle->style.setValue(SoPickStyle::SHAPE); + pickStyle->setOverride(TRUE); + root->addChild(pickStyle); + + //sphere. + SbVec3f origin(1.0, 1.0, 0.0); + origin.normalize(); + origin *= arcRadius; + SoTranslation *sphereTranslation = new SoTranslation(); + sphereTranslation->translation.setValue(origin); + root->addChild(sphereTranslation); + + SoSphere *sphere = new SoSphere(); + sphere->radius.setValue(1.0); + root->addChild(sphere); + + return root; +} + +void RDragger::startCB(void *, SoDragger *d) +{ + RDragger *sudoThis = dynamic_cast(d); + sudoThis->dragStart(); +} + +void RDragger::motionCB(void *, SoDragger *d) +{ + RDragger *sudoThis = dynamic_cast(d); + sudoThis->drag(); +} + +void RDragger::finishCB(void *, SoDragger *d) +{ + RDragger *sudoThis = dynamic_cast(d); + sudoThis->dragFinish(); +} + +void RDragger::fieldSensorCB(void *f, SoSensor *) +{ + RDragger *sudoThis = reinterpret_cast(f); + + SbMatrix matrix = sudoThis->getMotionMatrix(); + sudoThis->workFieldsIntoTransform(matrix); + sudoThis->setMotionMatrix(matrix); +} + +void RDragger::valueChangedCB(void *, SoDragger *d) +{ + RDragger *sudoThis = dynamic_cast(d); + assert(sudoThis); + SbMatrix matrix = sudoThis->getMotionMatrix(); + + //all this just to get the translation? + SbVec3f translationDummy, scaleDummy; + SbRotation localRotation, scaleOrientationDummy; + matrix.getTransform(translationDummy, localRotation, scaleDummy, scaleOrientationDummy); + + sudoThis->fieldSensor.detach(); + if (sudoThis->rotation.getValue() != localRotation) + sudoThis->rotation = localRotation; + sudoThis->fieldSensor.attach(&sudoThis->rotation); +} + +void RDragger::dragStart() +{ + SoSwitch *sw; + sw = SO_GET_ANY_PART(this, "rotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 1); + + projector.setViewVolume(this->getViewVolume()); + projector.setWorkingSpace(this->getLocalToWorldMatrix()); + projector.setPlane(SbPlane(SbVec3f(0.0, 0.0, 1.0), 0.0)); + + SbVec3f hitPoint; + if (!projector.tryProject(getNormalizedLocaterPosition(), 0.0, hitPoint)) + return; + hitPoint.normalize(); + + SbMatrix localToWorld = getLocalToWorldMatrix(); + localToWorld.multVecMatrix(hitPoint, hitPoint); + setStartingPoint((hitPoint)); + + rotationIncrementCount.setValue(0); +} + +void RDragger::drag() +{ + projector.setViewVolume(this->getViewVolume()); + projector.setWorkingSpace(this->getLocalToWorldMatrix()); + + SbVec3f hitPoint; + if (!projector.tryProject(getNormalizedLocaterPosition(), 0.0, hitPoint)) + return; + hitPoint.normalize(); + + SbVec3f startingPoint = getLocalStartingPoint(); + startingPoint.normalize(); + + SbRotation localRotation(startingPoint, hitPoint); + //getting some slop from this. grab vector and put it absolute. + SbVec3f tempVec; + float tempRadians; + localRotation.getValue(tempVec, tempRadians); + tempVec[0] = 0.0; + tempVec[1] = 0.0; + tempVec.normalize(); + if (tempVec[2] < 0.0) + { + tempRadians *= -1.0; + tempVec.negate(); + } + int incrementCount = roundIncrement(tempRadians); + rotationIncrementCount.setValue(incrementCount); + localRotation = SbRotation(tempVec, incrementCount * static_cast(rotationIncrement.getValue())); + + //same problem as described in tDragger::drag. + if (localRotation.equals(SbRotation(SbVec3f(0.0, 0.0, 1.0), 0.0), 0.00001)) + { + setMotionMatrix(getStartMotionMatrix()); + this->valueChanged(); + } + else + setMotionMatrix(appendRotation(getStartMotionMatrix(), localRotation, SbVec3f(0.0, 0.0, 0.0))); + + Base::Quantity quantity( + static_cast(rotationIncrementCount.getValue()) * (180.0 / M_PI) * + rotationIncrement.getValue(), Base::Unit::Angle); + + QString message(QObject::tr("Rotation: ")); + message += quantity.getUserString(); + getMainWindow()->showMessage(message, 3000); +} + +void RDragger::dragFinish() +{ + SoSwitch *sw; + sw = SO_GET_ANY_PART(this, "rotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, 0); +} + +SbBool RDragger::setUpConnections(SbBool onoff, SbBool doitalways) +{ + if (!doitalways && this->connectionsSetUp == onoff) + return onoff; + + SbBool oldval = this->connectionsSetUp; + + if (onoff) + { + inherited::setUpConnections(onoff, doitalways); + RDragger::fieldSensorCB(this, NULL); + if (this->fieldSensor.getAttachedField() != &this->rotation) + this->fieldSensor.attach(&this->rotation); + } + else + { + if (this->fieldSensor.getAttachedField() != NULL) + this->fieldSensor.detach(); + inherited::setUpConnections(onoff, doitalways); + } + this->connectionsSetUp = onoff; + return oldval; +} + +int RDragger::roundIncrement(const float &radiansIn) +{ + int rCount = 0; + + float increment = static_cast(rotationIncrement.getValue()); + if (fabs(radiansIn) > (increment / 2.0)) + { + rCount = static_cast(radiansIn / increment); + float remainder = fmod(radiansIn, increment); + if (remainder >= (increment / 2.0)) + rCount++; + } + + return rCount; +} + +SO_KIT_SOURCE(SoFCCSysDragger) + +void SoFCCSysDragger::initClass() +{ + TDragger::initClass(); + RDragger::initClass(); + SO_KIT_INIT_CLASS(SoFCCSysDragger, SoDragger, "Dragger"); +} + +SoFCCSysDragger::SoFCCSysDragger() +{ + SO_KIT_CONSTRUCTOR(SoFCCSysDragger); + + SO_KIT_ADD_CATALOG_ENTRY(annotation, SoAnnotation, TRUE, geomSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(scaleNode, SoScale, TRUE, annotation, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xTranslatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yTranslatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zTranslatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xTranslatorSeparator, SoSeparator, TRUE, xTranslatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yTranslatorSeparator, SoSeparator, TRUE, yTranslatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zTranslatorSeparator, SoSeparator, TRUE, zTranslatorSwitch, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xTranslatorColor, SoBaseColor, TRUE, xTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yTranslatorColor, SoBaseColor, TRUE, yTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zTranslatorColor, SoBaseColor, TRUE, zTranslatorSeparator, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xTranslatorRotation, SoRotation, TRUE, xTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yTranslatorRotation, SoRotation, TRUE, yTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zTranslatorRotation, SoRotation, TRUE, zTranslatorSeparator, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xTranslatorDragger, TDragger, TRUE, xTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yTranslatorDragger, TDragger, TRUE, yTranslatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zTranslatorDragger, TDragger, TRUE, zTranslatorSeparator, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xRotatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yRotatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zRotatorSwitch, SoSwitch, TRUE, annotation, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xRotatorSeparator, SoSeparator, TRUE, xRotatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yRotatorSeparator, SoSeparator, TRUE, yRotatorSwitch, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zRotatorSeparator, SoSeparator, TRUE, zRotatorSwitch, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xRotatorColor, SoBaseColor, TRUE, xRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yRotatorColor, SoBaseColor, TRUE, yRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zRotatorColor, SoBaseColor, TRUE, zRotatorSeparator, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xRotatorRotation, SoRotation, TRUE, xRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yRotatorRotation, SoRotation, TRUE, yRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zRotatorRotation, SoRotation, TRUE, zRotatorSeparator, , TRUE); + + SO_KIT_ADD_CATALOG_ENTRY(xRotatorDragger, RDragger, TRUE, xRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(yRotatorDragger, RDragger, TRUE, yRotatorSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(zRotatorDragger, RDragger, TRUE, zRotatorSeparator, , TRUE); + + SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0)); + SO_KIT_ADD_FIELD(translationIncrement, (1.0)); + SO_KIT_ADD_FIELD(translationIncrementCountX, (0)); + SO_KIT_ADD_FIELD(translationIncrementCountY, (0)); + SO_KIT_ADD_FIELD(translationIncrementCountZ, (0)); + + SO_KIT_ADD_FIELD(rotation, (SbVec3f(0.0, 0.0, 1.0), 0.0)); + SO_KIT_ADD_FIELD(rotationIncrement, (M_PI / 8.0)); + SO_KIT_ADD_FIELD(rotationIncrementCountX, (0)); + SO_KIT_ADD_FIELD(rotationIncrementCountY, (0)); + SO_KIT_ADD_FIELD(rotationIncrementCountZ, (0)); + + SO_KIT_ADD_FIELD(draggerSize, (1.0)); + SO_KIT_ADD_FIELD(autoScaleResult, (1.0)); + + SO_KIT_INIT_INSTANCE(); + + SoBaseColor *color; + color = SO_GET_ANY_PART(this, "xTranslatorColor", SoBaseColor); + color->rgb.setValue(1.0, 0.0, 0.0); + color = SO_GET_ANY_PART(this, "yTranslatorColor", SoBaseColor); + color->rgb.setValue(0.0, 1.0, 0.0); + color = SO_GET_ANY_PART(this, "zTranslatorColor", SoBaseColor); + color->rgb.setValue(0.0, 0.0, 1.0); + color = SO_GET_ANY_PART(this, "xRotatorColor", SoBaseColor); + color->rgb.setValue(1.0, 0.0, 0.0); + color = SO_GET_ANY_PART(this, "yRotatorColor", SoBaseColor); + color->rgb.setValue(0.0, 1.0, 0.0); + color = SO_GET_ANY_PART(this, "zRotatorColor", SoBaseColor); + color->rgb.setValue(0.0, 0.0, 1.0); + + TDragger *tDragger; + tDragger = SO_GET_ANY_PART(this, "xTranslatorDragger", TDragger); + tDragger->translationIncrement.connectFrom(&this->translationIncrement); + tDragger->autoScaleResult.connectFrom(&this->autoScaleResult); + translationIncrementCountX.connectFrom(&tDragger->translationIncrementCount); + + tDragger = SO_GET_ANY_PART(this, "yTranslatorDragger", TDragger); + tDragger->translationIncrement.connectFrom(&this->translationIncrement); + tDragger->autoScaleResult.connectFrom(&this->autoScaleResult); + translationIncrementCountY.connectFrom(&tDragger->translationIncrementCount); + + tDragger = SO_GET_ANY_PART(this, "zTranslatorDragger", TDragger); + tDragger->translationIncrement.connectFrom(&this->translationIncrement); + tDragger->autoScaleResult.connectFrom(&this->autoScaleResult); + translationIncrementCountZ.connectFrom(&tDragger->translationIncrementCount); + + RDragger *rDragger; + rDragger = SO_GET_ANY_PART(this, "xRotatorDragger", RDragger); + rDragger->rotationIncrement.connectFrom(&this->rotationIncrement); + rotationIncrementCountX.connectFrom(&rDragger->rotationIncrementCount); + rDragger = SO_GET_ANY_PART(this, "yRotatorDragger", RDragger); + rDragger->rotationIncrement.connectFrom(&this->rotationIncrement); + rotationIncrementCountY.connectFrom(&rDragger->rotationIncrementCount); + rDragger = SO_GET_ANY_PART(this, "zRotatorDragger", RDragger); + rDragger->rotationIncrement.connectFrom(&this->rotationIncrement); + rotationIncrementCountZ.connectFrom(&rDragger->rotationIncrementCount); + + SoSwitch *sw = SO_GET_ANY_PART(this, "xTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + sw = SO_GET_ANY_PART(this, "zTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + sw = SO_GET_ANY_PART(this, "xRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + sw = SO_GET_ANY_PART(this, "yRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + sw = SO_GET_ANY_PART(this, "zRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); + + SoRotation *localRotation; + SbRotation tempRotation; + localRotation = SO_GET_ANY_PART(this, "xTranslatorRotation", SoRotation); + localRotation->rotation.setValue(SbVec3f(0.0, 0.0, -1.0), M_PI / 2.0); + localRotation = SO_GET_ANY_PART(this, "yTranslatorRotation", SoRotation); + localRotation->rotation.setValue(SbRotation::identity()); + localRotation = SO_GET_ANY_PART(this, "zTranslatorRotation", SoRotation); + localRotation->rotation.setValue(SbVec3f(1.0, 0.0, 0.0), M_PI / 2.0); + + localRotation = SO_GET_ANY_PART(this, "xRotatorRotation", SoRotation); + tempRotation = SbRotation(SbVec3f(1.0, 0.0, 0.0), M_PI / 2.0); + tempRotation *= SbRotation(SbVec3f(0.0, 0.0, 1.0), M_PI / 2.0); + localRotation->rotation.setValue(tempRotation); + + localRotation = SO_GET_ANY_PART(this, "yRotatorRotation", SoRotation); + tempRotation = SbRotation(SbVec3f(0.0, -1.0, 0.0), M_PI /2.0); + tempRotation *= SbRotation(SbVec3f(0.0, 0.0, -1.0), M_PI /2.0); + localRotation->rotation.setValue(tempRotation); + + localRotation = SO_GET_ANY_PART(this, "zRotatorRotation", SoRotation); + localRotation->rotation.setValue(SbRotation::identity()); + + //this is for non-autoscale mode. this will be disconnected for autoscale + //and won't be used. see setUpAutoScale. + SoComposeVec3f *scaleEngine = new SoComposeVec3f(); //uses coin ref scheme. + scaleEngine->x.connectFrom(&draggerSize); + scaleEngine->y.connectFrom(&draggerSize); + scaleEngine->z.connectFrom(&draggerSize); + SoScale *localScaleNode = SO_GET_ANY_PART(this, "scaleNode", SoScale); + localScaleNode->scaleFactor.connectFrom(&scaleEngine->vector); + autoScaleResult.connectFrom(&draggerSize); + + addValueChangedCallback(&SoFCCSysDragger::valueChangedCB); + + translationSensor.setFunction(&SoFCCSysDragger::translationSensorCB); + translationSensor.setData(this); + translationSensor.setPriority(0); + + rotationSensor.setFunction(&SoFCCSysDragger::rotationSensorCB); + rotationSensor.setData(this); + rotationSensor.setPriority(0); + + cameraSensor.setFunction(&SoFCCSysDragger::cameraCB); + cameraSensor.setData(this); + + idleSensor.setFunction(&SoFCCSysDragger::idleCB); + idleSensor.setData(this); + + this->addFinishCallback(&SoFCCSysDragger::finishDragCB, this); + + this->setUpConnections(TRUE, TRUE); + + //we can't have user switching camera types while dragger is shown. + Gui::Application::Instance->commandManager().getCommandByName("Std_OrthographicCamera")->blockCommand(true); + Gui::Application::Instance->commandManager().getCommandByName("Std_PerspectiveCamera")->blockCommand(true); +} + +SoFCCSysDragger::~SoFCCSysDragger() +{ + Gui::Application::Instance->commandManager().getCommandByName("Std_OrthographicCamera")->blockCommand(false); + Gui::Application::Instance->commandManager().getCommandByName("Std_PerspectiveCamera")->blockCommand(false); +} + + +SbBool SoFCCSysDragger::setUpConnections(SbBool onoff, SbBool doitalways) +{ + if (!doitalways && (connectionsSetUp == onoff)) + return onoff; + + TDragger *tDraggerX = SO_GET_ANY_PART(this, "xTranslatorDragger", TDragger); + TDragger *tDraggerY = SO_GET_ANY_PART(this, "yTranslatorDragger", TDragger); + TDragger *tDraggerZ = SO_GET_ANY_PART(this, "zTranslatorDragger", TDragger); + RDragger *rDraggerX = SO_GET_ANY_PART(this, "xRotatorDragger", RDragger); + RDragger *rDraggerY = SO_GET_ANY_PART(this, "yRotatorDragger", RDragger); + RDragger *rDraggerZ = SO_GET_ANY_PART(this, "zRotatorDragger", RDragger); + + if (onoff) + { + inherited::setUpConnections(onoff, doitalways); + + registerChildDragger(tDraggerX); + registerChildDragger(tDraggerY); + registerChildDragger(tDraggerZ); + registerChildDragger(rDraggerX); + registerChildDragger(rDraggerY); + registerChildDragger(rDraggerZ); + + translationSensorCB(this, nullptr); + if (this->translationSensor.getAttachedField() != &this->translation) + this->translationSensor.attach(&this->translation); + + rotationSensorCB(this, nullptr); + if (this->rotationSensor.getAttachedField() != &this->rotation) + this->rotationSensor.attach(&this->rotation); + } + else + { + unregisterChildDragger(tDraggerX); + unregisterChildDragger(tDraggerY); + unregisterChildDragger(tDraggerZ); + unregisterChildDragger(rDraggerX); + unregisterChildDragger(rDraggerY); + unregisterChildDragger(rDraggerZ); + + inherited::setUpConnections(onoff, doitalways); + + if (this->translationSensor.getAttachedField() != NULL) + this->translationSensor.detach(); + + if (this->rotationSensor.getAttachedField() != NULL) + this->rotationSensor.detach(); + } + return !(this->connectionsSetUp = onoff); +} + +void SoFCCSysDragger::translationSensorCB(void *f, SoSensor *) +{ + SoFCCSysDragger *sudoThis = reinterpret_cast(f); + + SbMatrix matrix = sudoThis->getMotionMatrix(); + sudoThis->workFieldsIntoTransform(matrix); + sudoThis->setMotionMatrix(matrix); +} + +void SoFCCSysDragger::rotationSensorCB(void *f, SoSensor *) +{ + SoFCCSysDragger *sudoThis = reinterpret_cast(f); + + SbMatrix matrix = sudoThis->getMotionMatrix(); + sudoThis->workFieldsIntoTransform(matrix); + sudoThis->setMotionMatrix(matrix); +} + +void SoFCCSysDragger::valueChangedCB(void *, SoDragger *d) +{ + SoFCCSysDragger *sudoThis = dynamic_cast(d); + assert(sudoThis); + SbMatrix matrix = sudoThis->getMotionMatrix(); + + //all this just to get the translation? + SbVec3f localTranslation, scaleDummy; + SbRotation localRotation, scaleOrientationDummy; + matrix.getTransform(localTranslation, localRotation, scaleDummy, scaleOrientationDummy); + + sudoThis->translationSensor.detach(); + if (sudoThis->translation.getValue() != localTranslation) + sudoThis->translation = localTranslation; + sudoThis->translationSensor.attach(&sudoThis->translation); + + sudoThis->rotationSensor.detach(); + if (sudoThis->rotation.getValue() != localRotation) + sudoThis->rotation = localRotation; + sudoThis->rotationSensor.attach(&sudoThis->rotation); +} + +void SoFCCSysDragger::setUpAutoScale(SoCamera *cameraIn) +{ + //note: sofieldsensor checks if the current sensor is already attached + //and takes appropriate action. So it is safe to attach to a field without + //checking current attachment state. + camera = cameraIn; + if (cameraIn->getTypeId() == SoOrthographicCamera::getClassTypeId()) + { + SoOrthographicCamera *localCamera = dynamic_cast(cameraIn); + assert(localCamera); + cameraSensor.attach(&localCamera->height); + SoScale *localScaleNode = SO_GET_ANY_PART(this, "scaleNode", SoScale); + localScaleNode->scaleFactor.disconnect(); + autoScaleResult.disconnect(&draggerSize); + cameraCB(this, nullptr); + } + else if (cameraIn->getTypeId() == SoPerspectiveCamera::getClassTypeId()) + { + SoPerspectiveCamera *localCamera = dynamic_cast(cameraIn); + assert(localCamera); + cameraSensor.attach(&localCamera->position); + SoScale *localScaleNode = SO_GET_ANY_PART(this, "scaleNode", SoScale); + localScaleNode->scaleFactor.disconnect(); + autoScaleResult.disconnect(&draggerSize); + cameraCB(this, nullptr); + } +} + +void SoFCCSysDragger::cameraCB(void *data, SoSensor *) +{ + SoFCCSysDragger *sudoThis = reinterpret_cast(data); + if (!sudoThis->idleSensor.isScheduled()) + sudoThis->idleSensor.schedule(); +} + +void SoFCCSysDragger::idleCB(void *data, SoSensor *) +{ + SoFCCSysDragger *sudoThis = reinterpret_cast(data); + assert(sudoThis->camera); + + SbMatrix localToWorld = sudoThis->getLocalToWorldMatrix(); + SbVec3f origin; + localToWorld.multVecMatrix(SbVec3f(0.0, 0.0, 0.0), origin); + + SbViewVolume viewVolume = sudoThis->camera->getViewVolume(); + float radius = sudoThis->draggerSize.getValue() / 2.0; + float localScale = viewVolume.getWorldToScreenScale(origin, radius); + SbVec3f scaleVector(localScale, localScale, localScale); + SoScale *localScaleNode = SO_GET_ANY_PART(sudoThis, "scaleNode", SoScale); + localScaleNode->scaleFactor.setValue(scaleVector); + sudoThis->autoScaleResult.setValue(localScale); +} + +void SoFCCSysDragger::finishDragCB(void *data, SoDragger *) +{ + SoFCCSysDragger *sudoThis = reinterpret_cast(data); + + if (sudoThis->camera) + { + if (sudoThis->camera->getTypeId() == SoPerspectiveCamera::getClassTypeId()) + cameraCB(sudoThis, nullptr); + } +} + +void SoFCCSysDragger::clearIncrementCounts() +{ + translationIncrementCountX.setValue(0); + translationIncrementCountY.setValue(0); + translationIncrementCountZ.setValue(0); + rotationIncrementCountX.setValue(0); + rotationIncrementCountY.setValue(0); + rotationIncrementCountZ.setValue(0); +} + +void SoFCCSysDragger::showTranslationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::showTranslationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::showTranslationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::hideTranslationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +void SoFCCSysDragger::hideTranslationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +void SoFCCSysDragger::hideTranslationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zTranslatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +void SoFCCSysDragger::showRotationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::showRotationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::showRotationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL); +} + +void SoFCCSysDragger::hideRotationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +void SoFCCSysDragger::hideRotationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +void SoFCCSysDragger::hideRotationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zRotatorSwitch", SoSwitch); + SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isShownTranslationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isShownTranslationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isShownTranslationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isShownRotationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isShownRotationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isShownRotationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_ALL); +} + +bool SoFCCSysDragger::isHiddenTranslationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isHiddenTranslationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isHiddenTranslationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zTranslatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isHiddenRotationX() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "xRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isHiddenRotationY() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "yRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} + +bool SoFCCSysDragger::isHiddenRotationZ() +{ + SoSwitch *sw = SO_GET_ANY_PART(this, "zRotatorSwitch", SoSwitch); + return (sw->whichChild.getValue() == SO_SWITCH_NONE); +} diff --git a/src/Gui/SoFCCSysDragger.h b/src/Gui/SoFCCSysDragger.h new file mode 100644 index 000000000..8d33c3e5c --- /dev/null +++ b/src/Gui/SoFCCSysDragger.h @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef CSYSDRAGGER_H +#define CSYSDRAGGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SoCamera; + +namespace Gui +{ +/*! @brief Translation Dragger. + * + * used for translating along axis. Set the + * translationIncrement to desired step. Use + * 'translationIncrementCount' multiplied with + * 'translationIncrement' for a full double + * precision vector scalar. + */ +class TDragger : public SoDragger +{ + SO_KIT_HEADER(TDragger); + SO_KIT_CATALOG_ENTRY_HEADER(translatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(translator); + SO_KIT_CATALOG_ENTRY_HEADER(translatorActive); +public: + static void initClass(); + TDragger(); + SoSFVec3f translation; //!< set from outside and used from outside for single precision. + SoSFDouble translationIncrement; //!< set from outside and used for rounding. + SoSFInt32 translationIncrementCount; //!< number of steps. used from outside. + SoSFFloat autoScaleResult; //!< set from parent dragger. + +protected: + virtual ~TDragger() override; + virtual SbBool setUpConnections(SbBool onoff, SbBool doitalways = FALSE) override; + + static void startCB(void *, SoDragger * d); + static void motionCB(void *, SoDragger * d); + static void finishCB(void *, SoDragger * d); + static void fieldSensorCB(void *f, SoSensor *); + static void valueChangedCB(void *, SoDragger *d); + + void dragStart(); + void drag(); + void dragFinish(); + + SoFieldSensor fieldSensor; + SbLineProjector projector; + +private: + void buildFirstInstance(); + SbVec3f roundTranslation(const SbVec3f &vecIn, float incrementIn); + SoGroup* buildGeometry(); + typedef SoDragger inherited; +}; + +/*! @brief Rotation Dragger. + * + * used for rotating around an axis. Set the rotation + * increment to desired step. Use rotationIncrementCount + * multiplied with rotationIncrement for full double + * precision vector scalar. + */ +class RDragger : public SoDragger +{ + SO_KIT_HEADER(RDragger); + SO_KIT_CATALOG_ENTRY_HEADER(rotatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(rotator); + SO_KIT_CATALOG_ENTRY_HEADER(rotatorActive); +public: + static void initClass(); + RDragger(); + SoSFRotation rotation; //!< set from outside and used from outside for single precision. + SoSFDouble rotationIncrement; //!< set from outside and used for rounding. + SoSFInt32 rotationIncrementCount; //!< number of steps. used from outside. + SoSFColor color; //!< set from outside. non-active color. + +protected: + virtual ~RDragger() override; + virtual SbBool setUpConnections(SbBool onoff, SbBool doitalways = FALSE) override; + + static void startCB(void *, SoDragger * d); + static void motionCB(void *, SoDragger * d); + static void finishCB(void *, SoDragger * d); + static void fieldSensorCB(void *f, SoSensor *); + static void valueChangedCB(void *, SoDragger *d); + + void dragStart(); + void drag(); + void dragFinish(); + + SoFieldSensor fieldSensor; + SbPlaneProjector projector; + float arcRadius; + +private: + void buildFirstInstance(); + int roundIncrement(const float &radiansIn); + SoGroup* buildGeometry(); + typedef SoDragger inherited; +}; + +/*! @brief Coordinate System Dragger + * + * used to transform objects in 3d space. Set intial: + * translation, rotation, translationIncrement and + * rotationIncrement. Use *IncrementCount* multiplied + * with *Increment for full double precision output. + * + * Dragger can be displayed in 2 modes: static scale and auto scale. + * for static you can set the field scale and you are done. For + * auto scale you set the field scale and call setupAutoScale with + * the viewer camera. @see setUpAutoScale @see scale. + */ +class GuiExport SoFCCSysDragger : public SoDragger +{ + SO_KIT_HEADER(SoFCCSysDragger); + SO_KIT_CATALOG_ENTRY_HEADER(annotation); + SO_KIT_CATALOG_ENTRY_HEADER(scaleNode); + SO_KIT_CATALOG_ENTRY_HEADER(xTranslatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(yTranslatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(zTranslatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(xTranslatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(yTranslatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(zTranslatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(xTranslatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(yTranslatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(zTranslatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(xTranslatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(yTranslatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(zTranslatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(xTranslatorDragger); + SO_KIT_CATALOG_ENTRY_HEADER(yTranslatorDragger); + SO_KIT_CATALOG_ENTRY_HEADER(zTranslatorDragger); + SO_KIT_CATALOG_ENTRY_HEADER(xRotatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(yRotatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(zRotatorSwitch); + SO_KIT_CATALOG_ENTRY_HEADER(xRotatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(yRotatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(zRotatorSeparator); + SO_KIT_CATALOG_ENTRY_HEADER(xRotatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(yRotatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(zRotatorColor); + SO_KIT_CATALOG_ENTRY_HEADER(xRotatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(yRotatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(zRotatorRotation); + SO_KIT_CATALOG_ENTRY_HEADER(xRotatorDragger); + SO_KIT_CATALOG_ENTRY_HEADER(yRotatorDragger); + SO_KIT_CATALOG_ENTRY_HEADER(zRotatorDragger); +public: + static void initClass(); + SoFCCSysDragger(); + ~SoFCCSysDragger(); + + SoSFVec3f translation; //!< initial translation and reflects single precision movement. + SoSFDouble translationIncrement; //!< set from outside used for rounding. + SoSFInt32 translationIncrementCountX; //!< used from outside for translation x steps. + SoSFInt32 translationIncrementCountY; //!< used from outside for translation y steps. + SoSFInt32 translationIncrementCountZ; //!< used from outside for translation z steps. + + SoSFRotation rotation; //!< initial rotation and reflects single precision movement. + SoSFDouble rotationIncrement; //!< radians set from outside and used for rounding. + SoSFInt32 rotationIncrementCountX; //!< used from outside for rotation x steps. + SoSFInt32 rotationIncrementCountY; //!< used from outside for rotation y steps. + SoSFInt32 rotationIncrementCountZ; //!< used from outside for rotation z steps. + + void clearIncrementCounts(); //!< used to reset after drag update. + + /*! @brief Overall scale of dragger node. + * + * When using autoscale mode, this represents normalized device coordinates (0.0 to 1.0). A value + * of 0.05 is a good place to start. When NOT using autoscale mode, scale represents + * a traditional scale and a value of 1.0 is a good place to start. + */ + SoSFFloat draggerSize; + SoSFFloat autoScaleResult; //!< result of autoscale calculation and used by childdraggers. Don't use. + + SoIdleSensor idleSensor; //!< might be overkill, but want to make sure of performance. + void setUpAutoScale(SoCamera *cameraIn); //!< used to setup the auto scaling of dragger. + SoCamera *camera = nullptr; //!< don't assign directly! use setUpAutoScale. + + //! @name Visibility Functions + //@{ + void showTranslationX(); //!< show the x translation dragger. + void showTranslationY(); //!< show the y translation dragger. + void showTranslationZ(); //!< show the z translation dragger. + void hideTranslationX(); //!< hide the x translation dragger. + void hideTranslationY(); //!< hide the y translation dragger. + void hideTranslationZ(); //!< hide the z translation dragger. + + void showRotationX(); //!< show the x rotation dragger. + void showRotationY(); //!< show the y rotation dragger. + void showRotationZ(); //!< show the z rotation dragger. + void hideRotationX(); //!< hide the x rotation dragger. + void hideRotationY(); //!< hide the y rotation dragger. + void hideRotationZ(); //!< hide the z rotation dragger. + + bool isShownTranslationX(); //!< is x translation dragger shown. + bool isShownTranslationY(); //!< is y translation dragger shown. + bool isShownTranslationZ(); //!< is z translation dragger shown. + bool isShownRotationX(); //!< is x rotation dragger shown. + bool isShownRotationY(); //!< is x rotation dragger shown. + bool isShownRotationZ(); //!< is x rotation dragger shown. + + bool isHiddenTranslationX(); //!< is x translation dragger hidden. + bool isHiddenTranslationY(); //!< is y translation dragger hidden. + bool isHiddenTranslationZ(); //!< is z translation dragger hidden. + bool isHiddenRotationX(); //!< is x rotation dragger hidden. + bool isHiddenRotationY(); //!< is x rotation dragger hidden. + bool isHiddenRotationZ(); //!< is x rotation dragger hidden. + //@} + +protected: + virtual SbBool setUpConnections(SbBool onoff, SbBool doitalways = FALSE) override; + + static void translationSensorCB(void *f, SoSensor *); + static void rotationSensorCB(void *f, SoSensor *); + static void valueChangedCB(void *, SoDragger *d); + static void cameraCB(void *data, SoSensor *); + static void idleCB(void *data, SoSensor *); //!< scheduled from cameraCB to auto scale dragger. + static void finishDragCB(void *data, SoDragger *); + + + SoFieldSensor translationSensor; + SoFieldSensor rotationSensor; + SoFieldSensor cameraSensor; + +private: + typedef SoDragger inherited; +}; + +} + +#endif // CSYSDRAGGER_H diff --git a/src/Gui/TaskCSysDragger.cpp b/src/Gui/TaskCSysDragger.cpp new file mode 100644 index 000000000..8e5c06811 --- /dev/null +++ b/src/Gui/TaskCSysDragger.cpp @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 +#endif + +#include +#include + +#include +#include "QuantitySpinBox.h" +#include +#include +#include +#include +#include + +#include "TaskCSysDragger.h" + +using namespace Gui; + + +static double radiansToDegrees(const double &radiansIn) +{ + return radiansIn * (180.0 / M_PI); +} + +static double degreesToRadains(const double °reesIn) +{ + return degreesIn * (M_PI / 180.0); +} + +static double lastTranslationIncrement = 1.0; +static double lastRotationIncrement = degreesToRadains(15.0); + +TaskCSysDragger::TaskCSysDragger(Gui::ViewProviderGeometryObject* vpObjectIn, Gui::SoFCCSysDragger* draggerIn) : + vpObject(vpObjectIn), dragger(draggerIn) +{ + assert(vpObject); + assert(dragger); + + setupGui(); +} + +TaskCSysDragger::~TaskCSysDragger() +{ + +} + +void TaskCSysDragger::setupGui() +{ + Gui::TaskView::TaskBox *incrementsBox = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("button_valid"), + tr("Increments"), true, 0); + + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->setColumnStretch(1, 1); + + QLabel *tLabel = new QLabel(tr("Translation Increment: "), incrementsBox); + gridLayout->addWidget(tLabel, 0, 0, Qt::AlignRight); + + int spinBoxWidth = QApplication::fontMetrics().averageCharWidth() * 20; + tSpinBox = new QuantitySpinBox(incrementsBox); + tSpinBox->setMinimum(0.0); + tSpinBox->setMaximum(std::numeric_limits::max()); + tSpinBox->setUnit(Base::Unit::Length); + tSpinBox->setMinimumWidth(spinBoxWidth); + gridLayout->addWidget(tSpinBox, 0, 1, Qt::AlignLeft); + + QLabel *rLabel = new QLabel(tr("Rotation Increment: "), incrementsBox); + gridLayout->addWidget(rLabel, 1, 0, Qt::AlignRight); + + rSpinBox = new QuantitySpinBox(incrementsBox); + rSpinBox->setMinimum(0.0); + rSpinBox->setMaximum(180.0); + rSpinBox->setUnit(Base::Unit::Angle); + rSpinBox->setMinimumWidth(spinBoxWidth); + gridLayout->addWidget(rSpinBox, 1, 1, Qt::AlignLeft); + + incrementsBox->groupLayout()->addLayout(gridLayout); + Content.push_back(incrementsBox); + + connect(tSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onTIncrementSlot(double))); + connect(rSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onRIncrementSlot(double))); +} + +void TaskCSysDragger::onTIncrementSlot(double freshValue) +{ + dragger->translationIncrement.setValue(freshValue); +} + +void TaskCSysDragger::onRIncrementSlot(double freshValue) +{ + dragger->rotationIncrement.setValue(degreesToRadains(freshValue)); +} + +void TaskCSysDragger::open() +{ +// dragger->translationIncrement.setValue(lastTranslationIncrement); +// dragger->rotationIncrement.setValue(lastRotationIncrement); + tSpinBox->setValue(lastTranslationIncrement); + rSpinBox->setValue(radiansToDegrees(lastRotationIncrement)); + + Gui::TaskView::TaskDialog::open(); +} + +bool TaskCSysDragger::accept() +{ + lastTranslationIncrement = dragger->translationIncrement.getValue(); + lastRotationIncrement = dragger->rotationIncrement.getValue(); + + assert(vpObject); + App::DocumentObject* dObject = vpObject->getObject(); + assert(dObject); + Gui::Document* document = Gui::Application::Instance->getDocument(dObject->getDocument()); + assert(document); + document->commitCommand(); + document->resetEdit(); + document->getDocument()->recompute(); + + return Gui::TaskView::TaskDialog::accept(); +} + +#include "moc_TaskCSysDragger.cpp" diff --git a/src/Gui/TaskCSysDragger.h b/src/Gui/TaskCSysDragger.h new file mode 100644 index 000000000..c9e16d698 --- /dev/null +++ b/src/Gui/TaskCSysDragger.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef TASKCSYSDRAGGER_H +#define TASKCSYSDRAGGER_H + +#include + +class QuantitySpinBox; + +namespace Gui +{ + class SoFCCSysDragger; + class ViewProviderGeometryObject; + + class TaskCSysDragger : public Gui::TaskView::TaskDialog + { + Q_OBJECT + public: + TaskCSysDragger(ViewProviderGeometryObject *vpObjectIn, SoFCCSysDragger *draggerIn); + virtual ~TaskCSysDragger() override; + virtual QDialogButtonBox::StandardButtons getStandardButtons() const override + { return QDialogButtonBox::Ok;} + virtual void open() override; + virtual bool accept() override; + private Q_SLOTS: + void onTIncrementSlot(double freshValue); + void onRIncrementSlot(double freshValue); + private: + void setupGui(); + ViewProviderGeometryObject *vpObject; + SoFCCSysDragger *dragger; + QuantitySpinBox *tSpinBox; + QuantitySpinBox *rSpinBox; + }; +} + +#endif // TASKCSYSDRAGGER_H