From 59e69bbe0e74ab376a173f6c310d8e2accafc7bd Mon Sep 17 00:00:00 2001 From: blobfish Date: Tue, 17 Dec 2013 09:43:55 -0500 Subject: [PATCH 1/6] Part Dimension: alterations to existing files Not sure what is happening with View3dInventorViewer.h. The only REAL change, beyond the addition of dim functions, is the removal of the member arrowrotation. It wasn't referenced anywhere. --- src/Gui/View3DInventor.cpp | 26 +++- src/Gui/View3DInventorViewer.cpp | 51 ++++++++ src/Gui/View3DInventorViewer.h | 45 ++++--- src/Mod/Part/Gui/AppPartGui.cpp | 5 +- src/Mod/Part/Gui/CMakeLists.txt | 3 + src/Mod/Part/Gui/Command.cpp | 180 ++++++++++++++++++++++++++++ src/Mod/Part/Gui/Resources/Part.qrc | 8 ++ src/Mod/Part/Gui/Workbench.cpp | 13 +- 8 files changed, 313 insertions(+), 18 deletions(-) diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 01ed3653c..890cada0e 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -152,6 +152,9 @@ View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent, Qt::W OnChange(*hGrp,"OrbitStyle"); OnChange(*hGrp,"Sensitivity"); OnChange(*hGrp,"ResetCursorPosition"); + OnChange(*hGrp,"DimensionsVisible"); + OnChange(*hGrp,"Dimensions3dVisible"); + OnChange(*hGrp,"DimensionsDeltaVisible"); stopSpinTimer = new QTimer(this); connect(stopSpinTimer, SIGNAL(timeout()), this, SLOT(stopAnimating())); @@ -360,7 +363,28 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M else _viewer->setCameraType(SoPerspectiveCamera::getClassTypeId()); } - else { + else if (strcmp(Reason, "DimensionsVisible") == 0) + { + if (rGrp.GetBool("DimensionsVisible", true)) + _viewer->turnAllDimensionsOn(); + else + _viewer->turnAllDimensionsOff(); + } + else if (strcmp(Reason, "Dimensions3dVisible") == 0) + { + if (rGrp.GetBool("Dimensions3dVisible", true)) + _viewer->turn3dDimensionsOn(); + else + _viewer->turn3dDimensionsOff(); + } + else if (strcmp(Reason, "DimensionsDeltaVisible") == 0) + { + if (rGrp.GetBool("DimensionsDeltaVisible", true)) + _viewer->turnDeltaDimensionsOn(); + else + _viewer->turnDeltaDimensionsOff(); + } + else{ unsigned long col1 = rGrp.GetUnsigned("BackgroundColor",3940932863UL); unsigned long col2 = rGrp.GetUnsigned("BackgroundColor2",859006463UL); // default color (dark blue) unsigned long col3 = rGrp.GetUnsigned("BackgroundColor3",2880160255UL); // default color (blue/grey) diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 02d410251..6aa1192d1 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -250,6 +250,11 @@ View3DInventorViewer::View3DInventorViewer (QWidget *parent, const char *name, pEventCallback->ref(); pcViewProviderRoot->addChild(pEventCallback); pEventCallback->addEventCallback(SoEvent::getClassTypeId(), handleEventCB, this); + + dimensionRoot = new SoSwitch(SO_SWITCH_NONE); + pcViewProviderRoot->addChild(dimensionRoot); + dimensionRoot->addChild(new SoSwitch()); //first one will be for the 3d dimensions. + dimensionRoot->addChild(new SoSwitch()); //second one for the delta dimensions. // This is a callback node that logs all action that traverse the Inventor tree. #if defined (FC_DEBUG) && defined(FC_LOGGING_CB) @@ -2182,3 +2187,49 @@ std::vector View3DInventorViewer::getViewProvidersOfType(const Ba } return views; } + +void View3DInventorViewer::turnAllDimensionsOn() +{ + dimensionRoot->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turnAllDimensionsOff() +{ + dimensionRoot->whichChild = SO_SWITCH_NONE; +} + +void View3DInventorViewer::eraseAllDimensions() +{ + static_cast(dimensionRoot->getChild(0))->removeAllChildren(); + static_cast(dimensionRoot->getChild(1))->removeAllChildren(); +} + +void View3DInventorViewer::turn3dDimensionsOn() +{ + static_cast(dimensionRoot->getChild(0))->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turn3dDimensionsOff() +{ + static_cast(dimensionRoot->getChild(0))->whichChild = SO_SWITCH_NONE; +} + +void View3DInventorViewer::addDimension3d(SoNode *node) +{ + static_cast(dimensionRoot->getChild(0))->addChild(node); +} + +void View3DInventorViewer::addDimensionDelta(SoNode *node) +{ + static_cast(dimensionRoot->getChild(1))->addChild(node); +} + +void View3DInventorViewer::turnDeltaDimensionsOn() +{ + static_cast(dimensionRoot->getChild(1))->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turnDeltaDimensionsOff() +{ + static_cast(dimensionRoot->getChild(1))->whichChild = SO_SWITCH_NONE; +} diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index d37fc9101..1728e381f 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -112,8 +112,8 @@ public: SbBool isBacklight(void) const; void setSceneGraph (SoNode *root); - void setAnimationEnabled(const SbBool enable); - SbBool isAnimationEnabled(void) const; + void setAnimationEnabled(const SbBool enable); + SbBool isAnimationEnabled(void) const; void setPopupMenuEnabled(const SbBool on); SbBool isPopupMenuEnabled(void) const; @@ -121,16 +121,16 @@ public: void startAnimating(const SbVec3f& axis, float velocity); void stopAnimating(void); SbBool isAnimating(void) const; - - void setFeedbackVisibility(const SbBool enable); - SbBool isFeedbackVisible(void) const; - - void setFeedbackSize(const int size); - int getFeedbackSize(void) const; - void setRenderFramebuffer(const SbBool enable); - SbBool isRenderFramebuffer() const; - void renderToFramebuffer(QGLFramebufferObject*); + void setFeedbackVisibility(const SbBool enable); + SbBool isFeedbackVisible(void) const; + + void setFeedbackSize(const int size); + int getFeedbackSize(void) const; + + void setRenderFramebuffer(const SbBool enable); + SbBool isRenderFramebuffer() const; + void renderToFramebuffer(QGLFramebufferObject*); virtual void setViewing(SbBool enable); virtual void setCursorEnabled(SbBool enable); @@ -193,8 +193,8 @@ public: void setEditingCursor (const QCursor& cursor); void setRedirectToSceneGraph(SbBool redirect) { this->redirected = redirect; } SbBool isRedirectedToSceneGraph() const { return this->redirected; } - void setRedirectToSceneGraphEnabled(SbBool enable) { this->allowredir = enable; } - SbBool isRedirectToSceneGraphEnabled(void) const { return this->allowredir; } + void setRedirectToSceneGraphEnabled(SbBool enable) { this->allowredir = enable; } + SbBool isRedirectToSceneGraphEnabled(void) const { return this->allowredir; } //@} /** @name Pick actions */ @@ -241,6 +241,23 @@ public: /** Project the given normalized 2d point onto the far plane */ SbVec3f projectOnFarPlane(const SbVec2f&) const; //@} + + /** @name Dimension controls + * the "turn*" functions are wired up to parameter groups through view3dinventor. + * don't call them directly. instead set the parameter groups. + * @see TaskDimension + */ + //@{ + void turnAllDimensionsOn(); + void turnAllDimensionsOff(); + void turn3dDimensionsOn(); + void turn3dDimensionsOff(); + void turnDeltaDimensionsOn(); + void turnDeltaDimensionsOff(); + void eraseAllDimensions(); + void addDimension3d(SoNode *node); + void addDimensionDelta(SoNode *node); + //@} /** * Set the camera's orientation. If isAnimationEnabled() returns @@ -320,7 +337,6 @@ private: SoFCBackgroundGradient *pcBackGround; SoSeparator * backgroundroot; SoSeparator * foregroundroot; - SoRotationXYZ * arrowrotation; SoDirectionalLight* backlight; SoSeparator * pcViewProviderRoot; @@ -328,6 +344,7 @@ private: NavigationStyle* navigation; SoFCUnifiedSelection* selectionRoot; QGLFramebufferObject* framebuffer; + SoSwitch *dimensionRoot; // small axis cross in the corner SbBool axiscrossEnabled; diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index 1a9848968..2a74641e6 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -53,7 +53,7 @@ #include "ViewProviderPrism.h" #include "ViewProviderSpline.h" #include "ViewProviderRegularPolygon.h" - +#include "TaskDimension.h" #include "DlgSettingsGeneral.h" #include "DlgSettingsObjectColor.h" #include "DlgSettings3DViewPartImp.h" @@ -146,6 +146,9 @@ void PartGuiExport initPartGui() PartGui::ViewProviderConeParametric ::init(); PartGui::ViewProviderTorusParametric ::init(); PartGui::ViewProviderRuledSurface ::init(); + PartGui::DimensionLinear ::initClass(); + PartGui::DimensionAngular ::initClass(); + PartGui::ArcEngine ::initClass(); PartGui::Workbench ::init(); diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index d301196b0..245e005d8 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -45,6 +45,7 @@ set(PartGui_MOC_HDRS TaskOffset.h TaskSweep.h TaskThickness.h + TaskDimension.h TaskCheckGeometry.h ) fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS}) @@ -208,6 +209,8 @@ SET(PartGui_SRCS TaskSweep.ui TaskThickness.cpp TaskThickness.h + TaskDimension.cpp + TaskDimension.h TaskCheckGeometry.cpp TaskCheckGeometry.h ) diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index c51b9b87c..65df59e90 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -63,6 +63,7 @@ #include "TaskShapeBuilder.h" #include "TaskLoft.h" #include "TaskSweep.h" +#include "TaskDimension.h" #include "TaskCheckGeometry.h" @@ -1495,6 +1496,179 @@ bool CmdColorPerFace::isActive(void) return (hasActiveDocument() && !Gui::Control().activeDialog() && objectSelected); } +//=========================================================================== +// Part_Measure_Linear +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureLinear); + +CmdMeasureLinear::CmdMeasureLinear() + : Command("Part_Measure_Linear") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Measure Linear"); + sToolTipText = QT_TR_NOOP("Measure Linear"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Linear"; +} + +void CmdMeasureLinear::activated(int iMsg) +{ + PartGui::goDimensionLinearRoot(); +} + +bool CmdMeasureLinear::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// Part_Measure_Angular +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureAngular); + +CmdMeasureAngular::CmdMeasureAngular() + : Command("Part_Measure_Angular") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Measure Angular"); + sToolTipText = QT_TR_NOOP("Measure Angular"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Angular"; +} + +void CmdMeasureAngular::activated(int iMsg) +{ + PartGui::goDimensionAngularRoot(); +} + +bool CmdMeasureAngular::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// Part_Measure_Clear_All +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureClearAll); + +CmdMeasureClearAll::CmdMeasureClearAll() + : Command("Part_Measure_Clear_All") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Clear All"); + sToolTipText = QT_TR_NOOP("Clear All"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Clear_All"; +} + +void CmdMeasureClearAll::activated(int iMsg) +{ + PartGui::eraseAllDimensions(); +} + +bool CmdMeasureClearAll::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// Part_Measure_Toggle_All +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureToggleAll); + +CmdMeasureToggleAll::CmdMeasureToggleAll() + : Command("Part_Measure_Toggle_All") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Toggle All"); + sToolTipText = QT_TR_NOOP("Toggle All"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Toggle_All"; +} + +void CmdMeasureToggleAll::activated(int iMsg) +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibility = group->GetBool("DimensionsVisible", true); + if (visibility) + group->SetBool("DimensionsVisible", false); + else + group->SetBool("DimensionsVisible", true); +} + +bool CmdMeasureToggleAll::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// Part_Measure_Toggle_3d +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureToggle3d); + +CmdMeasureToggle3d::CmdMeasureToggle3d() + : Command("Part_Measure_Toggle_3d") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Toggle 3d"); + sToolTipText = QT_TR_NOOP("Toggle 3d"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Toggle_3d"; +} + +void CmdMeasureToggle3d::activated(int iMsg) +{ + PartGui::toggle3d(); +} + +bool CmdMeasureToggle3d::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// Part_Measure_Toggle_Delta +//=========================================================================== + +DEF_STD_CMD_A(CmdMeasureToggleDelta); + +CmdMeasureToggleDelta::CmdMeasureToggleDelta() + : Command("Part_Measure_Toggle_Delta") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Toggle Delta"); + sToolTipText = QT_TR_NOOP("Toggle Delta"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Toggle_Delta"; +} + +void CmdMeasureToggleDelta::activated(int iMsg) +{ + PartGui::toggleDelta(); +} + +bool CmdMeasureToggleDelta::isActive(void) +{ + return hasActiveDocument(); +} void CreatePartCommands(void) { @@ -1531,4 +1705,10 @@ void CreatePartCommands(void) rcCmdMgr.addCommand(new CmdPartThickness()); rcCmdMgr.addCommand(new CmdCheckGeometry()); rcCmdMgr.addCommand(new CmdColorPerFace()); + rcCmdMgr.addCommand(new CmdMeasureLinear()); + rcCmdMgr.addCommand(new CmdMeasureAngular()); + rcCmdMgr.addCommand(new CmdMeasureClearAll()); + rcCmdMgr.addCommand(new CmdMeasureToggleAll()); + rcCmdMgr.addCommand(new CmdMeasureToggle3d()); + rcCmdMgr.addCommand(new CmdMeasureToggleDelta()); } diff --git a/src/Mod/Part/Gui/Resources/Part.qrc b/src/Mod/Part/Gui/Resources/Part.qrc index 1202a86c9..763035a67 100644 --- a/src/Mod/Part/Gui/Resources/Part.qrc +++ b/src/Mod/Part/Gui/Resources/Part.qrc @@ -42,6 +42,14 @@ icons/Part_Point_Parametric.svg icons/Part_Polygon_Parametric.svg icons/Part_Spline_Parametric.svg + icons/Part_Measure_Linear.svg + icons/Part_Measure_Angular.svg + icons/Part_Measure_Clear_All.svg + icons/Part_Measure_Toggle_All.svg + icons/Part_Measure_Toggle_3d.svg + icons/Part_Measure_Toggle_Delta.svg + icons/Part_Measure_Step_Active.svg + icons/Part_Measure_Step_Done.svg icons/Tree_Part_Box_Parametric.svg icons/Tree_Part_Cylinder_Parametric.svg icons/Tree_Part_Cone_Parametric.svg diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp index e827fe420..f64913a7e 100644 --- a/src/Mod/Part/Gui/Workbench.cpp +++ b/src/Mod/Part/Gui/Workbench.cpp @@ -66,6 +66,11 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* bop = new Gui::MenuItem; bop->setCommand("Boolean"); *bop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common"; + + Gui::MenuItem* measure = new Gui::MenuItem; + measure->setCommand("Measure"); + *measure << "Part_Measure_Linear" << "Part_Measure_Angular" << "Part_Measure_Clear_All" << "Part_Measure_Toggle_All" << + "Part_Measure_Toggle_3d" << "Part_Measure_Toggle_Delta"; Gui::MenuItem* part = new Gui::MenuItem; root->insertItem(item, part); @@ -74,7 +79,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *part << prim << "Part_Primitives" << "Part_Builder" << "Separator" << "Part_ShapeFromMesh" << "Part_MakeSolid" << "Part_ReverseShape" << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" - << "Separator" << bop << "Separator" + << measure << "Separator" << bop << "Separator" << "Part_CrossSections" << "Part_Compound" << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer" << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" @@ -114,6 +119,11 @@ Gui::ToolBarItem* Workbench::setupToolBars() const boolop->setCommand("Boolean"); *boolop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common" << "Part_CheckGeometry" << "Part_Section" << "Part_CrossSections"; + + Gui::ToolBarItem* measure = new Gui::ToolBarItem(root); + measure->setCommand("Measure"); + *measure << "Part_Measure_Linear" << "Part_Measure_Angular" << "Part_Measure_Clear_All" << "Part_Measure_Toggle_All" + << "Part_Measure_Toggle_3d" << "Part_Measure_Toggle_Delta"; return root; } @@ -124,4 +134,3 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const Gui::ToolBarItem* root = new Gui::ToolBarItem; return root; } - From 442c79bf5c3ff382c11133091415831510410054 Mon Sep 17 00:00:00 2001 From: blobfish Date: Tue, 17 Dec 2013 09:45:20 -0500 Subject: [PATCH 2/6] Part Dimension: new implementation files --- src/Mod/Part/Gui/TaskDimension.cpp | 1673 ++++++++++++++++++++++++++++ src/Mod/Part/Gui/TaskDimension.h | 360 ++++++ 2 files changed, 2033 insertions(+) create mode 100644 src/Mod/Part/Gui/TaskDimension.cpp create mode 100644 src/Mod/Part/Gui/TaskDimension.h diff --git a/src/Mod/Part/Gui/TaskDimension.cpp b/src/Mod/Part/Gui/TaskDimension.cpp new file mode 100644 index 000000000..7eb926d7a --- /dev/null +++ b/src/Mod/Part/Gui/TaskDimension.cpp @@ -0,0 +1,1673 @@ +/*************************************************************************** + * Copyright (c) 2013 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PreCompiled.h" +#include +#include +#include "../App/PartFeature.h" +#include +#include +#include +#include +#include +#include +#include + +#include "TaskDimension.h" + +bool PartGui::getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub) +{ + App::Document *docPointer = App::GetApplication().getDocument(doc.c_str()); + if (!docPointer) + return false; + App::DocumentObject *objectPointer = docPointer->getObject(object.c_str()); + if (!objectPointer) + return false; + Part::Feature *feature = dynamic_cast(objectPointer); + if (!feature) + return false; + shapeOut = feature->Shape.getValue(); + if (sub.size() > 0) + shapeOut = feature->Shape.getShape().getSubShape(sub.c_str()); + if (shapeOut.IsNull()) + return false; + return true; +} + +bool PartGui::evaluateLinearPreSelection(TopoDS_Shape &shape1, TopoDS_Shape &shape2) +{ + std::vector selections = Gui::Selection().getSelection(); + if (selections.size() != 2) + return false; + std::vector::iterator it; + std::vector shapes; + + for (it = selections.begin(); it != selections.end(); ++it) + { + Part::Feature *feature = dynamic_cast((*it).pObject); + if (!feature) + break; + TopoDS_Shape shape = feature->Shape.getValue(); + if (strlen((*it).SubName) > 0) + shape = feature->Shape.getShape().getSubShape((*it).SubName); + if (shape.IsNull()) + break; + shapes.push_back(shape); + } + + if (shapes.size() != 2) + return false; + + shape1 = shapes.front(); + shape2 = shapes.back(); + + return true; +} + +void PartGui::goDimensionLinearRoot() +{ + PartGui::ensureSomeDimensionVisible(); + + TopoDS_Shape shape1, shape2; + if(evaluateLinearPreSelection(shape1, shape2)) + { + goDimensionLinearNoTask(shape1, shape2); + Gui::Selection().clearSelection(); + } + else + { + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) + { + Gui::Selection().clearSelection(); + dlg = new PartGui::TaskMeasureLinear(); + } + Gui::Control().showDialog(dlg); + } +} + +void PartGui::goDimensionLinearNoTask(const TopoDS_Shape &shape1, const TopoDS_Shape &shape2) +{ + //Warning: BRepExtrema_DistShapeShape solution array is NOT 0 based. + BRepExtrema_DistShapeShape measure(shape1, shape2); + if (!measure.IsDone() || measure.NbSolution() < 1) + return; + + dumpLinearResults(measure); + addLinearDimensions(measure); + + //if we ever make this a class add viewer to member. + Gui::View3DInventorViewer *viewer = getViewer(); + if (!viewer) + return; +} + +void PartGui::dumpLinearResults(const BRepExtrema_DistShapeShape &measure) +{ + std::ostringstream out; + //switch to initializer list when switch to c++11 + std::vector typeNames; + typeNames.resize(3); + typeNames[0] = "Vertex"; + typeNames[1] = "Edge"; + typeNames[2] = "Face"; + + Base::Quantity quantity(measure.Value(), Base::Unit::Length); + out << std::endl<< std::setprecision(std::numeric_limits::digits10 + 1) << "distance = " << + measure.Value() << "mm unit distance = " << quantity.getUserString().toUtf8().constData() << std::endl << + "solution count: " << measure.NbSolution() << std::endl; + + for (int index = 1; index < measure.NbSolution() + 1; ++index) //not zero based. + { + gp_Pnt point1 = measure.PointOnShape1(index); + gp_Pnt point2 = measure.PointOnShape2(index); + out << " solution " << index << ":" << std::endl << std::setprecision(std::numeric_limits::digits10 + 1) << + " point1 " << point1.X() << " " << point1.Y() << " " << point1.Z() << std::endl << + " point2 " << point2.X() << " " << point2.Y() << " " << point2.Z() << std::endl << + " DeltaX " << fabs(point2.X() - point1.X()) << std::endl << + " DeltaY " << fabs(point2.Y() - point1.Y()) << std::endl << + " DeltaZ " << fabs(point2.Z() - point1.Z()) << std::endl << + " shape type on object1 is: " << typeNames.at(measure.SupportTypeShape1(index)) << std::endl << + " shape type on object2 is: " << typeNames.at(measure.SupportTypeShape2(index)) << std::endl; + } + out << std::endl; + Base::Console().Message(out.str().c_str()); +} + +Gui::View3DInventorViewer * PartGui::getViewer() +{ + Gui::View3DInventor *view = dynamic_cast(Gui::Application::Instance-> + activeDocument()->getActiveView()); + if (!view) + return 0; + Gui::View3DInventorViewer *viewer = view->getViewer(); + if (!viewer) + return 0; + return viewer; +} + +void PartGui::addLinearDimensions(const BRepExtrema_DistShapeShape &measure) +{ + Gui::View3DInventorViewer *viewer = getViewer(); + if (!viewer) + return; + for (int index = 1; index < measure.NbSolution() + 1; ++index) + { + gp_Pnt point1 = measure.PointOnShape1(index); + gp_Pnt point2 = measure.PointOnShape2(index); + viewer->addDimension3d(createLinearDimension(point1, point2, SbColor(1.0, 0.0, 0.0))); + + //create deltas. point1 will always be the same. + gp_Pnt temp = point1; + gp_Pnt lastTemp = temp; + temp.SetX(point2.X()); + viewer->addDimensionDelta(createLinearDimension(lastTemp, temp, SbColor(0.0, 1.0, 0.0))); + lastTemp = temp; + temp.SetY(point2.Y()); + viewer->addDimensionDelta(createLinearDimension(lastTemp, temp, SbColor(0.0, 1.0, 0.0))); + lastTemp = temp; + temp.SetZ(point2.Z()); + viewer->addDimensionDelta(createLinearDimension(lastTemp, temp, SbColor(0.0, 1.0, 0.0))); + } +} + +SoNode* PartGui::createLinearDimension(const gp_Pnt &point1, const gp_Pnt &point2, const SbColor &color) +{ + SbVec3f vec1(point1.X(), point1.Y(), point1.Z()); + SbVec3f vec2(point2.X(), point2.Y(), point2.Z()); + if ((vec2-vec1).length() < FLT_EPSILON) + return new SoSeparator(); //empty object. + PartGui::DimensionLinear *dimension = new PartGui::DimensionLinear(); + dimension->point1.setValue(vec1); + dimension->point2.setValue(vec2); + + Base::Quantity quantity(static_cast((vec2-vec1).length()), Base::Unit::Length); + dimension->text.setValue(quantity.getUserString().toUtf8().constData()); + + dimension->dColor.setValue(color); + return dimension; +} + +void PartGui::eraseAllDimensions() +{ + Gui::View3DInventor *view = dynamic_cast(Gui::Application::Instance-> + activeDocument()->getActiveView()); + if (!view) + return; + Gui::View3DInventorViewer *viewer = view->getViewer(); + if (!viewer) + return; + viewer->eraseAllDimensions(); +} + +void PartGui::toggle3d() +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibility = group->GetBool("Dimensions3dVisible", true); + if (visibility) + group->SetBool("Dimensions3dVisible", false); + else + group->SetBool("Dimensions3dVisible", true); +} + +void PartGui::toggleDelta() +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibility = group->GetBool("DimensionsDeltaVisible", true); + if (visibility) + group->SetBool("DimensionsDeltaVisible", false); + else + group->SetBool("DimensionsDeltaVisible", true); +} + +void PartGui::ensureSomeDimensionVisible() +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibilityAll = group->GetBool("DimensionsVisible", true); + if (!visibilityAll) + group->SetBool("DimensionsVisible", true); + bool visibility3d = group->GetBool("Dimensions3dVisible", true); + bool visibilityDelta = group->GetBool("DimensionsDeltaVisible", true); + + if (!visibility3d && !visibilityDelta) //both turned off. + group->SetBool("Dimensions3dVisible", true); //turn on 3d, so something is visible. +} + +void PartGui::ensure3dDimensionVisible() +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibilityAll = group->GetBool("DimensionsVisible", true); + if (!visibilityAll) + group->SetBool("DimensionsVisible", true); + bool visibility3d = group->GetBool("Dimensions3dVisible", true); + + if (!visibility3d) //both turned off. + group->SetBool("Dimensions3dVisible", true); //turn on 3d, so something is visible. +} + + +SO_KIT_SOURCE(PartGui::DimensionLinear); + +void PartGui::DimensionLinear::initClass() +{ + SO_KIT_INIT_CLASS(DimensionLinear, SoSeparatorKit, "SeparatorKit"); +} + +PartGui::DimensionLinear::DimensionLinear() +{ + SO_KIT_CONSTRUCTOR(PartGui::DimensionLinear); + + SO_KIT_ADD_CATALOG_ENTRY(transformation, SoTransform, TRUE, topSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(leftArrow, SoShapeKit, TRUE, topSeparator, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(rightArrow, SoShapeKit, TRUE, topSeparator, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(line, SoShapeKit, TRUE, annotate, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate, ,TRUE); + + SO_KIT_INIT_INSTANCE(); + + SO_NODE_ADD_FIELD(rotate, (1.0, 0.0, 0.0, 0.0));//postion orientation of the dimension. + SO_NODE_ADD_FIELD(length, (1.0));//turns into dimension length + SO_NODE_ADD_FIELD(origin, (0.0, 0.0, 0.0));//static + SO_NODE_ADD_FIELD(text, ("test"));//dimension text + SO_NODE_ADD_FIELD(dColor, (1.0, 0.0, 0.0));//dimension color. + + point1.setValue(SbVec3f(0.0, 0.0, 0.0)); + point2.setValue(SbVec3f(1.0, 0.0, 0.0)); + + setupDimension(); +} + +PartGui::DimensionLinear::~DimensionLinear() +{ + +} + +SbBool PartGui::DimensionLinear::affectsState() const +{ + return FALSE; +} + +void PartGui::DimensionLinear::setupDimension() +{ + //transformation + SoTransform *trans = static_cast(getPart("transformation", TRUE)); + trans->translation.connectFrom(&point1); + //build engine for vector subtraction and length. + SoCalculator *hyp = new SoCalculator(); + hyp->A.connectFrom(&point1); + hyp->B.connectFrom(&point2); + hyp->expression.set1Value(0, "oA = B-A"); + hyp->expression.set1Value(1, "oB = normalize(oA)"); + hyp->expression.set1Value(2, "oa = length(oA)"); + length.connectFrom(&hyp->oa); + //build engine for rotation. + SoComposeRotationFromTo *rotationEngine = new SoComposeRotationFromTo(); + rotationEngine->from.setValue(SbVec3f(1.0, 0.0, 0.0)); + rotationEngine->to.connectFrom(&hyp->oB); + trans->rotation.connectFrom(&rotationEngine->rotation); + + //color + SoMaterial *material = new SoMaterial; + material->diffuseColor.connectFrom(&dColor); + + //dimension arrows. + SoCone *cone = new SoCone(); + cone->bottomRadius.setValue(0.25); + cone->height.setValue(0.5); + + setPart("leftArrow.shape", cone); + set("leftArrow.transform", "rotation 0.0 0.0 1.0 1.5707963"); + set("leftArrow.transform", "translation 0.25 0.0 0.0"); //half cone height. + setPart("rightArrow.shape", cone); + set("rightArrow.transform", "rotation 0.0 0.0 -1.0 1.5707963"); //no constant for PI. + //have use local here to do the offset because the main is wired up to length of dimension. + set("rightArrow.localTransform", "translation 0.0 -0.25 0.0"); //half cone height. + + SoTransform *transform = static_cast(getPart("rightArrow.transform", FALSE)); + if (!transform) + return;//what to do here? + SoComposeVec3f *vec = new SoComposeVec3f; + vec->x.connectFrom(&length); + vec->y.setValue(0.0); + vec->z.setValue(0.0); + transform->translation.connectFrom(&vec->vector); + + setPart("leftArrow.material", material); + setPart("rightArrow.material", material); + + //line + SoConcatenate *catEngine = new SoConcatenate(SoMFVec3f::getClassTypeId()); + //don't know how to get around having this dummy origin. cat engine wants to connectfrom? + catEngine->input[0]->connectFrom(&origin); + catEngine->input[1]->connectFrom(&vec->vector); + + SoVertexProperty *lineVerts = new SoVertexProperty; + lineVerts->vertex.connectFrom(catEngine->output); + + int lineVertexMap[] = {0, 1}; + int lineVertexMapSize(sizeof(lineVertexMap)/sizeof(int)); + SoIndexedLineSet *line = new SoIndexedLineSet; + line->vertexProperty = lineVerts; + line->coordIndex.setValues(0, lineVertexMapSize, lineVertexMap); + + setPart("line.shape", line); + setPart("line.material", material); + + //text + SoSeparator *textSep = static_cast(getPart("textSep", TRUE)); + if (!textSep) + return; + + textSep->addChild(material); + + SoCalculator *textVecCalc = new SoCalculator(); + textVecCalc->A.connectFrom(&vec->vector); + textVecCalc->B.set1Value(0, 0.0, 0.250, 0.0); + textVecCalc->expression.set1Value(0, "oA = (A / 2) + B"); + + SoTransform *textTransform = new SoTransform(); + textTransform->translation.connectFrom(&textVecCalc->oA); + textSep->addChild(textTransform); + + SoFont *fontNode = new SoFont(); + fontNode->name.setValue("defaultFont"); + fontNode->size.setValue(30); + textSep->addChild(fontNode); + + SoText2 *textNode = new SoText2(); + textNode->justification = SoText2::CENTER; + textNode->string.connectFrom(&text); + textSep->addChild(textNode); + + //this prevents the 2d text from screwing up the bounding box for a viewall + SoResetTransform *rTrans = new SoResetTransform; + rTrans->whatToReset = SoResetTransform::BBOX; + textSep->addChild(rTrans); +} + +PartGui::TaskMeasureLinear::TaskMeasureLinear(): selections1(), selections2(), buttonSelectedIndex(0) +{ + setUpGui(); +} + +PartGui::TaskMeasureLinear::~TaskMeasureLinear() +{ + Gui::Selection().clearSelection(); +} + +void PartGui::TaskMeasureLinear::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (buttonSelectedIndex == 0) + { + if (msg.Type == Gui::SelectionChanges::AddSelection) + { + DimSelections::DimSelection newSelection; + newSelection.documentName = msg.pDocName; + newSelection.objectName = msg.pObjectName; + newSelection.subObjectName = msg.pSubName; + newSelection.x = msg.x; + newSelection.y = msg.y; + newSelection.z = msg.z; + selections1.selections.clear();//we only want one item. + selections1.selections.push_back(newSelection); + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(1)->setChecked(true); + return; + } + } + if (buttonSelectedIndex == 1) + { + if (msg.Type == Gui::SelectionChanges::AddSelection) + { + DimSelections::DimSelection newSelection; + newSelection.documentName = msg.pDocName; + newSelection.objectName = msg.pObjectName; + newSelection.subObjectName = msg.pSubName; + newSelection.x = msg.x; + newSelection.y = msg.y; + newSelection.z = msg.z; + selections2.selections.clear();//we only want one item. + selections2.selections.push_back(newSelection); + buildDimension(); + clearSelectionStrings(); + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(0)->setChecked(true); + return; + } + } +} + +void PartGui::TaskMeasureLinear::selectionClearDelayedSlot() +{ + //hack. + //clearing selections are not working as I hoped. Apparently the observer callback gets called + //before the actual selection takes place. Resulting in selections being left. this addresses this + //by being called from the event loop. + this->blockConnection(true); + Gui::Selection().clearSelection(); + this->blockConnection(false); +} + +void PartGui::TaskMeasureLinear::buildDimension() +{ + if(selections1.selections.size() != 1 || selections2.selections.size() != 1) + return; + + DimSelections::DimSelection current1 = selections1.selections.at(0); + DimSelections::DimSelection current2 = selections2.selections.at(0); + + TopoDS_Shape shape1, shape2; + if (!getShapeFromStrings(shape1, current1.documentName, current1.objectName, current1.subObjectName)) + { + Base::Console().Message("\nFailed to get shape\n\n"); + return; + } + if (!getShapeFromStrings(shape2, current2.documentName, current2.objectName, current2.subObjectName)) + { + Base::Console().Message("\nFailed to get shape\n\n"); + return; + } + goDimensionLinearNoTask(shape1, shape2); +} + +void PartGui::TaskMeasureLinear::clearSelectionStrings() +{ + selections1.selections.clear(); + selections2.selections.clear(); +} + +void PartGui::TaskMeasureLinear::setUpGui() +{ + QPixmap mainIcon = Gui::BitmapFactory().pixmap("Part_Measure_Linear"); + + Gui::TaskView::TaskBox* selectionTaskBox = new Gui::TaskView::TaskBox + (mainIcon, QObject::tr("Selections"), false, 0); + QVBoxLayout *selectionLayout = new QVBoxLayout(); + stepped = new SteppedSelection(2, selectionTaskBox); + selectionLayout->addWidget(stepped); + selectionTaskBox->groupLayout()->addLayout(selectionLayout); + + Gui::TaskView::TaskBox* controlTaskBox = new Gui::TaskView::TaskBox + (mainIcon, QObject::tr("Control"), false, 0); + QVBoxLayout *controlLayout = new QVBoxLayout(); + + QHBoxLayout *resetLayout = new QHBoxLayout(); + resetLayout->addSpacing(5); //hack for alignment. + QPushButton *resetButton = new QPushButton(mainIcon, QObject::tr("Reset Dialog"), controlTaskBox); + resetLayout->addWidget(resetButton); + resetLayout->addStretch(); + controlLayout->addLayout(resetLayout); + QObject::connect(resetButton, SIGNAL(clicked(bool)), this, SLOT(resetDialogSlot(bool))); + + DimensionControl *control = new DimensionControl(controlTaskBox); + controlLayout->addWidget(control); + controlTaskBox->groupLayout()->addLayout(controlLayout); + + this->setButtonPosition(TaskDialog::South); + Content.push_back(selectionTaskBox); + Content.push_back(controlTaskBox); + + stepped->getButton(0)->setChecked(true);//before wired up. + QObject::connect(stepped->getButton(0), SIGNAL(toggled(bool)), this, SLOT(selection1Slot(bool))); + QObject::connect(stepped->getButton(1), SIGNAL(toggled(bool)), this, SLOT(selection2Slot(bool))); +} + +void PartGui::TaskMeasureLinear::selection1Slot(bool checked) +{ + if (!checked) + { + if (selections1.selections.size() > 0) + stepped->setIconDone(0); + return; + } + buttonSelectedIndex = 0; + + this->blockConnection(true); + Gui::Selection().clearSelection(); + //we should only be working with 1 entity, but oh well do the loop anyway. + std::vector::const_iterator it; + for (it = selections1.selections.begin(); it != selections1.selections.end(); ++it) + Gui::Selection().addSelection(it->documentName.c_str(), it->objectName.c_str(), it->subObjectName.c_str()); + this->blockConnection(false); +} + +void PartGui::TaskMeasureLinear::selection2Slot(bool checked) +{ + if (!checked) + return; + buttonSelectedIndex = 1; + this->blockConnection(true); + Gui::Selection().clearSelection(); + std::vector::const_iterator it; + for (it = selections2.selections.begin(); it != selections2.selections.end(); ++it) + Gui::Selection().addSelection(it->documentName.c_str(), it->objectName.c_str(), it->subObjectName.c_str()); + this->blockConnection(false); +} + +void PartGui::TaskMeasureLinear::resetDialogSlot(bool) +{ + clearSelectionStrings(); + this->blockConnection(true); + Gui::Selection().clearSelection(); + stepped->getButton(0)->setChecked(true); + this->blockConnection(false); +} + +void PartGui::TaskMeasureLinear::toggle3dSlot(bool) +{ + PartGui::toggle3d(); +} + +void PartGui::TaskMeasureLinear::toggleDeltaSlot(bool) +{ + PartGui::toggleDelta(); +} + +void PartGui::TaskMeasureLinear::clearAllSlot(bool) +{ + PartGui::eraseAllDimensions(); +} + +PartGui::VectorAdapter::VectorAdapter() : status(false), vector() +{ +} + +PartGui::VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) : + status(false), vector(), origin(pickedPointIn) +{ + Handle_Geom_Surface surface = BRep_Tool::Surface(faceIn); + if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) + { + Handle_Geom_ElementarySurface eSurface = Handle(Geom_ElementarySurface)::DownCast(surface); + gp_Dir direction = eSurface->Axis().Direction(); + vector = direction; + vector.Normalize(); + if (faceIn.Orientation() == TopAbs_REVERSED) + vector.Reverse(); + if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) || + surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) + ) + { + origin = eSurface->Axis().Location().XYZ(); + projectOriginOntoVector(pickedPointIn); + } + else + origin = pickedPointIn + vector; + status = true; + } +} + +PartGui::VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn) : + status(false), vector(), origin(pickedPointIn) +{ + TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True); + TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True); + vector = PartGui::convert(lastVertex) - PartGui::convert(firstVertex); + if (vector.Magnitude() < Precision::Confusion()) + return; + vector.Normalize(); + + status = true; + projectOriginOntoVector(pickedPointIn); +} + +PartGui::VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In) : + status(false), vector(), origin() +{ + vector = PartGui::convert(vertex2In) - PartGui::convert(vertex1In); + vector.Normalize(); + + //build origin half way. + gp_Vec tempVector = (PartGui::convert(vertex2In) - PartGui::convert(vertex1In)); + double mag = tempVector.Magnitude(); + tempVector.Normalize(); + tempVector *= (mag / 2.0); + origin = tempVector + PartGui::convert(vertex1In); + + status = true; +} + +PartGui::VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2) : + status(false), vector(), origin() +{ + vector = vector2- vector1; + vector.Normalize(); + + //build origin half way. + gp_Vec tempVector = vector2 - vector1; + double mag = tempVector.Magnitude(); + tempVector.Normalize(); + tempVector *= (mag / 2.0); + origin = tempVector + vector1; + + status = true; +} + +void PartGui::VectorAdapter::projectOriginOntoVector(const gp_Vec &pickedPointIn) +{ + Handle_Geom_Curve heapLine = new Geom_Line(origin.XYZ(), vector.XYZ()); + gp_Pnt tempPoint(pickedPointIn.XYZ()); + GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine); + if (projection.NbPoints() < 1) + return; + origin.SetXYZ(projection.Point(1).XYZ()); +} + +PartGui::VectorAdapter::operator gp_Lin() const +{ + gp_Pnt tempOrigin; + tempOrigin.SetXYZ(origin.XYZ()); + return gp_Lin(tempOrigin, gp_Dir(vector)); +} + +gp_Vec PartGui::convert(const TopoDS_Vertex &vertex) +{ + gp_Pnt point = BRep_Tool::Pnt(vertex); + gp_Vec out(point.X(), point.Y(), point.Z()); + return out; +} + +void PartGui::goDimensionAngularRoot() +{ + PartGui::ensure3dDimensionVisible(); + + VectorAdapter adapter1, adapter2; + if(PartGui::evaluateAngularPreSelection(adapter1, adapter2)) + goDimensionAngularNoTask(adapter1, adapter2); + else + { + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) + { + Gui::Selection().clearSelection(); + dlg = new PartGui::TaskMeasureAngular(); + } + Gui::Control().showDialog(dlg); + } + Gui::Selection().clearSelection(); +} + +bool PartGui::evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapter &vector2Out) +{ + std::vector selections = Gui::Selection().getSelection(); + if (selections.size() > 4 || selections.size() < 2) + return false; + std::vector::iterator it; + std::vector adapters; + TopoDS_Vertex lastVertex; + for (it = selections.begin(); it != selections.end(); ++it) + { + Part::Feature *feature = dynamic_cast((*it).pObject); + if (!feature) + break; + TopoDS_Shape shape = feature->Shape.getValue(); + if (strlen((*it).SubName) > 0) + shape = feature->Shape.getShape().getSubShape((*it).SubName); + if (shape.IsNull()) + break; + + if (shape.ShapeType() == TopAbs_VERTEX) + { + TopoDS_Vertex currentVertex = TopoDS::Vertex(shape); + if (!lastVertex.IsNull()) + { + //need something here for 0 length vector. + //create a point half way between to vertices. + adapters.push_back(VectorAdapter(currentVertex, lastVertex)); + lastVertex = TopoDS_Vertex(); + } + else + { + lastVertex = currentVertex; + } + continue; + } + //vertices have to be selected in succession. so if we make it here clear the last vertex. + lastVertex = TopoDS_Vertex(); + + gp_Vec pickPoint(it->x, it->y, it->z); + //can't use selections without a pick point. + if (pickPoint.IsEqual(gp_Vec(0.0, 0.0, 0.0), Precision::Confusion(), Precision::Angular())) + { + Base::Console().Message("Can't use selections without a pick point.\n"); + continue; + } + + if (shape.ShapeType() == TopAbs_EDGE) + { + TopoDS_Edge edge = TopoDS::Edge(shape); + // make edge orientation so that end of edge closest to pick is head of vector. + gp_Vec firstPoint = PartGui::convert(TopExp::FirstVertex(edge, Standard_True)); + gp_Vec lastPoint = PartGui::convert(TopExp::LastVertex(edge, Standard_True)); + double firstDistance = (firstPoint - pickPoint).Magnitude(); + double lastDistance = (lastPoint - pickPoint).Magnitude(); + if (lastDistance > firstDistance) + { + if (edge.Orientation() == TopAbs_FORWARD) + edge.Orientation(TopAbs_REVERSED); + else + edge.Orientation(TopAbs_FORWARD); + } + adapters.push_back(VectorAdapter(edge, pickPoint)); + continue; + } + + if (shape.ShapeType() == TopAbs_FACE) + { + TopoDS_Face face = TopoDS::Face(shape); + adapters.push_back(VectorAdapter(face, pickPoint)); + continue; + } + } + + if (adapters.size() != 2) + return false; + if (!adapters.front().isValid() || !adapters.back().isValid()) + return false; + + vector1Out = adapters.front(); + vector2Out = adapters.back(); + + //making sure pick points are not equal + if ((vector1Out.getPickPoint() - vector2Out.getPickPoint()).Magnitude() < std::numeric_limits::epsilon()) + { + Base::Console().Message("pick points are equal\n"); + return false; + } + + return true; +} + +void PartGui::goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, const VectorAdapter &vector2Adapter) +{ + gp_Vec vector1 = vector1Adapter; + gp_Vec vector2 = vector2Adapter; + double angle = vector1.Angle(vector2); + + std::ostringstream stream; + stream << std::setprecision(std::numeric_limits::digits10 + 1) << std::fixed << std::endl << + "angle in radians is: " << angle << std::endl << + "angle in degrees is: " << 180 * angle / M_PI << std::endl; + if (angle < M_PI / 2.0d) + stream << std::setprecision(std::numeric_limits::digits10 + 1) << + "complement in radians is: " << M_PI / 2.0d - angle << std::endl << + "complement in degrees is: " << 90 - 180 * angle / M_PI << std::endl; + //I don't think we get anything over 180, but just in case. + if (angle > M_PI / 2.0d && angle < M_PI) + stream << std::setprecision(std::numeric_limits::digits10 + 1) << + "supplement in radians is: " << M_PI - angle << std::endl << + "supplement in degrees is: " << 180 - 180 * angle / M_PI << std::endl; + Base::Console().Message(stream.str().c_str()); + + SbMatrix dimSys; + double radius; + double displayAngle;//have to fake the angle in the 3d. + + if (vector1.IsParallel(vector2, Precision::Angular())) + { + //take first point project it onto second vector. + Handle_Geom_Curve heapLine2 = new Geom_Line(vector2Adapter); + gp_Pnt tempPoint(vector1Adapter.getPickPoint().XYZ()); + + GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine2); + if (projection.NbPoints() < 1) + { + Base::Console().Message("parallel vectors: couldn't project onto line\n"); + return; + } + gp_Vec newPoint2; + newPoint2.SetXYZ(projection.Point(1).XYZ()); + + //if points are colinear, projection doesn't work and returns the same point. + //In this case we just use the original point. + if ((newPoint2 - vector1Adapter.getPickPoint()).Magnitude() < Precision::Confusion()) + newPoint2 = vector2Adapter.getPickPoint(); + + //now get midpoint between for dim origin. + gp_Vec point1 = vector1Adapter.getPickPoint(); + gp_Vec midPointProjection = newPoint2 - point1; + double distance = midPointProjection.Magnitude(); + midPointProjection.Normalize(); + midPointProjection *= distance / 2.0d; + + gp_Vec origin = point1 + midPointProjection; + + //yaxis should be the same as vector1, but doing this to eliminate any potential slop from + //using precision::angular. If lines are colinear and we have no plane, we can't establish zAxis from crossing. + //we just the absolute axis. + gp_Vec xAxis = (point1 - origin).Normalized(); + gp_Vec zAxis; + if (xAxis.IsParallel(vector1, Precision::Angular())) + { + if (!xAxis.IsParallel(gp_Vec(0.0d, 0.0d, 1.0d), Precision::Angular())) + zAxis = gp_Vec(0.0d, 0.0d, 1.0d); + else + zAxis = gp_Vec(0.0d, 1.0d, 0.0d); + } + else + zAxis = xAxis.Crossed(vector1).Normalized(); + gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized(); + zAxis = xAxis.Crossed(yAxis).Normalized(); + + dimSys = SbMatrix + ( + xAxis.X(), yAxis.X(), zAxis.X(), origin.X(), + xAxis.Y(), yAxis.Y(), zAxis.Y(), origin.Y(), + xAxis.Z(), yAxis.Z(), zAxis.Z(), origin.Z(), + 0.0, 0.0, 0.0, 1.0 + ); + dimSys = dimSys.transpose(); + + radius = midPointProjection.Magnitude(); + displayAngle = M_PI; + } + else + { + Handle_Geom_Curve heapLine1 = new Geom_Line(vector1Adapter); + Handle_Geom_Curve heapLine2 = new Geom_Line(vector2Adapter); + + GeomAPI_ExtremaCurveCurve extrema(heapLine1, heapLine2); + + if (extrema.NbExtrema() < 1) + { + Base::Console().Message("couldn't get extrema\n"); + return; + } + + gp_Pnt extremaPoint1, extremaPoint2, dimensionOriginPoint; + extrema.Points(1, extremaPoint1, extremaPoint2); + if (extremaPoint1.Distance(extremaPoint2) < Precision::Confusion()) + dimensionOriginPoint = extremaPoint1; + else + { + //find half way point in between extrema points for dimension origin. + gp_Vec vec1(extremaPoint1.XYZ()); + gp_Vec vec2(extremaPoint2.XYZ()); + gp_Vec connection(vec2-vec1); + Standard_Real distance = connection.Magnitude(); + connection.Normalize(); + connection *= (distance / 2.0d); + dimensionOriginPoint.SetXYZ((vec1 + connection).XYZ()); + } + + gp_Vec thirdPoint(vector2Adapter.getPickPoint()); + gp_Vec originVector(dimensionOriginPoint.XYZ()); + gp_Vec extrema2Vector(extremaPoint2.XYZ()); + radius = (vector1Adapter.getPickPoint() - originVector).Magnitude(); + double legOne = (extrema2Vector - originVector).Magnitude(); + displayAngle = angle; + if (legOne > Precision::Confusion()) + { + double legTwo = sqrt(pow(radius, 2) - pow(legOne, 2)); + gp_Vec projectionVector(vector2); + projectionVector.Normalize(); + projectionVector *= legTwo; + thirdPoint = extrema2Vector + projectionVector; + gp_Vec hyp(thirdPoint - originVector); + hyp.Normalize(); + gp_Vec otherSide(vector1Adapter.getPickPoint() - originVector); + otherSide.Normalize(); + displayAngle = hyp.Angle(otherSide); + } + + gp_Vec xAxis = (vector1Adapter.getPickPoint() - originVector).Normalized(); + gp_Vec fakeYAxis = (thirdPoint - originVector).Normalized(); + gp_Vec zAxis = (xAxis.Crossed(fakeYAxis)).Normalized(); + gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized(); + + dimSys = SbMatrix + ( + xAxis.X(), yAxis.X(), zAxis.X(), dimensionOriginPoint.X(), + xAxis.Y(), yAxis.Y(), zAxis.Y(), dimensionOriginPoint.Y(), + xAxis.Z(), yAxis.Z(), zAxis.Z(), dimensionOriginPoint.Z(), + 0.0, 0.0, 0.0, 1.0 + ); + + dimSys = dimSys.transpose(); + } + + DimensionAngular *dimension = new DimensionAngular(); + dimension->matrix.setValue(dimSys); + dimension->radius.setValue(radius); + dimension->angle.setValue(static_cast(displayAngle)); + dimension->text.setValue((Base::Quantity(180 * angle / M_PI, Base::Unit::Angle)).getUserString().toUtf8().constData()); + dimension->dColor.setValue(SbColor(0.0, 0.0, 1.0)); + + Gui::View3DInventorViewer *viewer = getViewer(); + if (!viewer) + return; + + viewer->addDimension3d(dimension); +} + +SO_KIT_SOURCE(PartGui::DimensionAngular); + +void PartGui::DimensionAngular::initClass() +{ + SO_KIT_INIT_CLASS(DimensionAngular, SoSeparatorKit, "SeparatorKit"); +} + +PartGui::DimensionAngular::DimensionAngular() +{ + SO_KIT_CONSTRUCTOR(PartGui::DimensionAngular); + + SO_KIT_ADD_CATALOG_ENTRY(transformation, SoMatrixTransform, TRUE, topSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator, , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arrow1, SoShapeKit, TRUE, topSeparator, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arrow2, SoShapeKit, TRUE, topSeparator, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arcSep, SoSeparator, TRUE, annotate, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate, ,TRUE); + + SO_KIT_INIT_INSTANCE(); + + SO_NODE_ADD_FIELD(radius, (10.0)); + SO_NODE_ADD_FIELD(angle, (1.0)); + SO_NODE_ADD_FIELD(text, ("test"));//dimension text + SO_NODE_ADD_FIELD(dColor, (1.0, 0.0, 0.0));//dimension color. + SO_NODE_ADD_FIELD(matrix, (1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0)); + + setupDimension(); +} + +PartGui::DimensionAngular::~DimensionAngular() +{ + +} + +SbBool PartGui::DimensionAngular::affectsState() const +{ + return FALSE; +} + + +void PartGui::DimensionAngular::setupDimension() +{ + //transformation + SoMatrixTransform *trans = static_cast(getPart("transformation", TRUE)); + trans->matrix.connectFrom(&matrix); + + //color + SoMaterial *material = new SoMaterial; + material->diffuseColor.connectFrom(&dColor); + + //dimension arrows. + SoCone *cone = new SoCone(); + cone->bottomRadius.setValue(0.25); + cone->height.setValue(0.5); + + setPart("arrow1.shape", cone); + set("arrow1.localTransform", "rotation 0.0 0.0 1.0 3.1415927"); + set("arrow1.localTransform", "translation 0.0 0.25 0.0"); //half cone height. + setPart("arrow2.shape", cone); + set("arrow2.transform", "rotation 0.0 0.0 1.0 0.0"); + set("arrow2.localTransform", "translation 0.0 -0.25 0.0"); //half cone height. + + //I was getting errors if I didn't manually allocate for these transforms. Not sure why. + SoTransform *arrow1Transform = new SoTransform(); + SoComposeVec3f *arrow1Compose = new SoComposeVec3f(); + arrow1Compose->x.connectFrom(&radius); + arrow1Compose->y.setValue(0.0); + arrow1Compose->y.setValue(0.0); + arrow1Transform->translation.connectFrom(&arrow1Compose->vector); + setPart("arrow1.transform", arrow1Transform); + + SoComposeRotation *arrow2Rotation = new SoComposeRotation(); + arrow2Rotation->angle.connectFrom(&angle); + arrow2Rotation->axis.setValue(0.0, 0.0, 1.0); + SoTransform *arrow2Transform = new SoTransform(); + arrow2Transform->rotation.connectFrom(&arrow2Rotation->rotation); + SoCalculator *arrow2LocationCalc = new SoCalculator(); + arrow2LocationCalc->a.connectFrom(&angle); + arrow2LocationCalc->b.connectFrom(&radius); + arrow2LocationCalc->expression.set1Value(0, "oa = cos(a) * b"); //xLocation + arrow2LocationCalc->expression.set1Value(1, "ob = sin(a) * b"); //yLocation + SoComposeVec3f *arrow2Compose = new SoComposeVec3f(); + arrow2Compose->x.connectFrom(&arrow2LocationCalc->oa); + arrow2Compose->y.connectFrom(&arrow2LocationCalc->ob); + arrow2Compose->z.setValue(0.0f); + arrow2Transform->translation.connectFrom(&arrow2Compose->vector); + setPart("arrow2.transform", arrow2Transform); + + setPart("arrow1.material", material); + setPart("arrow2.material", material); + + ArcEngine *arcEngine = new ArcEngine(); + arcEngine->angle.connectFrom(&angle); + arcEngine->radius.connectFrom(&radius); + arcEngine->deviation.setValue(0.1); + + SoCoordinate3 *coordinates = new SoCoordinate3(); + coordinates->point.connectFrom(&arcEngine->points); + + SoLineSet *lineSet = new SoLineSet(); + lineSet->vertexProperty.setValue(coordinates); + lineSet->numVertices.connectFrom(&arcEngine->pointCount); + lineSet->startIndex.setValue(0); + + SoSeparator *arcSep = static_cast(getPart("arcSep", TRUE)); + if (!arcSep) + return; + arcSep->addChild(material); + arcSep->addChild(lineSet); + + //text + SoSeparator *textSep = static_cast(getPart("textSep", TRUE)); + if (!textSep) + return; + + textSep->addChild(material); + + SoCalculator *textVecCalc = new SoCalculator(); + textVecCalc->a.connectFrom(&angle); + textVecCalc->b.connectFrom(&radius); + textVecCalc->expression.set1Value(0, "oa = a / 2.0"); + textVecCalc->expression.set1Value(1, "ob = cos(oa) * b"); //x + textVecCalc->expression.set1Value(2, "oc = sin(oa) * b"); //y + + SoComposeVec3f *textLocation = new SoComposeVec3f(); + textLocation->x.connectFrom(&textVecCalc->ob); + textLocation->y.connectFrom(&textVecCalc->oc); + textLocation->z.setValue(0.0); + + + SoTransform *textTransform = new SoTransform(); + textTransform->translation.connectFrom(&textLocation->vector); + textSep->addChild(textTransform); + + SoFont *fontNode = new SoFont(); + fontNode->name.setValue("defaultFont"); + fontNode->size.setValue(30); + textSep->addChild(fontNode); + + SoText2 *textNode = new SoText2(); + textNode->justification = SoText2::CENTER; + textNode->string.connectFrom(&text); + textSep->addChild(textNode); + + //this prevents the 2d text from screwing up the bounding box for a viewall + SoResetTransform *rTrans = new SoResetTransform; + rTrans->whatToReset = SoResetTransform::BBOX; + textSep->addChild(rTrans); +} + +SO_ENGINE_SOURCE(PartGui::ArcEngine); + +PartGui::ArcEngine::ArcEngine() +{ + SO_ENGINE_CONSTRUCTOR(ArcEngine); + + SO_ENGINE_ADD_INPUT(radius, (10.0)); + SO_ENGINE_ADD_INPUT(angle, (1.0)); + SO_ENGINE_ADD_INPUT(deviation, (0.25)); + + SO_ENGINE_ADD_OUTPUT(points, SoMFVec3f); + SO_ENGINE_ADD_OUTPUT(pointCount, SoSFInt32); +} + +void PartGui::ArcEngine::initClass() +{ + SO_ENGINE_INIT_CLASS(ArcEngine, SoEngine, "Engine"); +} + +void PartGui::ArcEngine::evaluate() +{ + if (radius.getValue() < std::numeric_limits::epsilon() || + angle.getValue() < std::numeric_limits::epsilon() || + deviation.getValue() < std::numeric_limits::epsilon()) + { + defaultValues(); + return; + } + + float deviationAngle(acos((radius.getValue() - deviation.getValue()) / radius.getValue())); + std::vector tempPoints; + int segmentCount; + if (deviationAngle >= angle.getValue()) + segmentCount = 1; + else + { + segmentCount = static_cast(angle.getValue() / deviationAngle) + 1; + if (segmentCount < 2) + { + defaultValues(); + return; + } + } + float angleIncrement = angle.getValue() / static_cast(segmentCount); + for (int index = 0; index < segmentCount + 1; ++index) + { + SbVec3f currentNormal(1.0, 0.0, 0.0); + float currentAngle = index * angleIncrement; + SbRotation rotation(SbVec3f(0.0, 0.0, 1.0), currentAngle); + rotation.multVec(currentNormal, currentNormal); + tempPoints.push_back(currentNormal * radius.getValue()); + } + int tempCount = tempPoints.size(); //for macro. + SO_ENGINE_OUTPUT(points, SoMFVec3f, setNum(tempCount)); + SO_ENGINE_OUTPUT(pointCount, SoSFInt32, setValue(tempCount)); + std::vector::const_iterator it; + for (it = tempPoints.begin(); it != tempPoints.end(); ++it) + { + int currentIndex = it-tempPoints.begin(); //for macro. + SbVec3f temp(*it); //for macro + SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(currentIndex, temp)); + } + +} + +void PartGui::ArcEngine::defaultValues() +{ + //just some non-failing info. + SO_ENGINE_OUTPUT(points, SoMFVec3f, setNum(2)); + SbVec3f point1(10.0, 0.0, 0.0); + SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(0, point1)); + SbVec3f point2(7.07, 7.07, 0.0); + SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(1, point2)); + SO_ENGINE_OUTPUT(pointCount, SoSFInt32, setValue(2)); +} + +PartGui::SteppedSelection::SteppedSelection(const uint& buttonCountIn, QWidget* parent): + QWidget(parent) +{ + if (buttonCountIn < 1) + return; + + QVBoxLayout *mainLayout = new QVBoxLayout(); + this->setLayout(mainLayout); + + QButtonGroup *buttonGroup = new QButtonGroup(); + buttonGroup->setExclusive(true); + + for (uint index = 0; index < buttonCountIn; ++index) + { + ButtonIconPairType tempPair; + + std::ostringstream stream; + stream << "Selection " << ((index < 10) ? "0" : "") << index + 1; + QString buttonText = QObject::tr(stream.str().c_str()); + QPushButton *button = new QPushButton(buttonText, this); + button->setCheckable(true); + buttonGroup->addButton(button); + connect(button, SIGNAL(toggled(bool)), this, SLOT(selectionSlot(bool))); + + QLabel *label = new QLabel; + + tempPair.first = button; + tempPair.second = label; + buttons.push_back(tempPair); + + QHBoxLayout *layout = new QHBoxLayout(); + mainLayout->addLayout(layout); + layout->addWidget(button); + layout->addSpacing(10); + layout->addWidget(label); + layout->addStretch(); + } + mainLayout->addStretch(); + + buildPixmaps(); //uses button size +} + +PartGui::SteppedSelection::~SteppedSelection() +{ + if(stepActive) + { + delete stepActive; + stepActive = 0; + } + if (stepDone) + { + delete stepDone; + stepDone = 0; + } +} + +void PartGui::SteppedSelection::buildPixmaps() +{ + assert(buttons.size() > 0); + int iconHeight(buttons.at(0).first->height()-6); + stepActive = new QPixmap(Gui::BitmapFactory().pixmap("Part_Measure_Step_Active").scaled + (iconHeight, iconHeight, Qt::KeepAspectRatio)); + stepDone = new QPixmap(Gui::BitmapFactory().pixmap("Part_Measure_Step_Done").scaled + (iconHeight, iconHeight, Qt::KeepAspectRatio)); +} + +void PartGui::SteppedSelection::selectionSlot(bool checked) +{ + QPushButton *sender = qobject_cast(QObject::sender()); + assert(sender != 0); + std::vector::iterator it; + for (it = buttons.begin(); it != buttons.end(); ++it) + if (it->first == sender) + break; + assert(it != buttons.end()); + + if (checked) + it->second->setPixmap(*stepActive); + else + it->second->setPixmap(QPixmap()); +} + +QPushButton* PartGui::SteppedSelection::getButton(const uint& index) +{ + return buttons.at(index).first; +} + +void PartGui::SteppedSelection::setIconDone(const uint& index) +{ + buttons.at(index).second->setPixmap(*stepDone); +} + +PartGui::DimensionControl::DimensionControl(QWidget* parent): QWidget(parent) +{ + QVBoxLayout *commandLayout = new QVBoxLayout(); + this->setLayout(commandLayout); + + QPushButton *toggle3dButton = new QPushButton(Gui::BitmapFactory().pixmap("Part_Measure_Toggle_3d"), + QObject::tr("Toggle 3d"), this); + QObject::connect(toggle3dButton, SIGNAL(clicked(bool)), this, SLOT(toggle3dSlot(bool))); + QHBoxLayout *layout = new QHBoxLayout(); + layout->addWidget(toggle3dButton); + layout->addStretch(); + commandLayout->addLayout(layout); + + QPushButton *toggleDeltaButton = new QPushButton(Gui::BitmapFactory().pixmap("Part_Measure_Toggle_Delta"), + QObject::tr("Toggle Delta"), this); + QObject::connect(toggleDeltaButton, SIGNAL(clicked(bool)), this, SLOT(toggleDeltaSlot(bool))); + layout = new QHBoxLayout(); + layout->addWidget(toggleDeltaButton); + layout->addStretch(); + commandLayout->addLayout(layout); + + QPushButton *clearAllButton = new QPushButton(Gui::BitmapFactory().pixmap("Part_Measure_Clear_All"), + QObject::tr("Clear All"), this); + QObject::connect(clearAllButton, SIGNAL(clicked(bool)), this, SLOT(clearAllSlot(bool))); + layout = new QHBoxLayout(); + layout->addWidget(clearAllButton); + layout->addStretch(); + commandLayout->addLayout(layout); +} + +void PartGui::DimensionControl::toggle3dSlot(bool) +{ + PartGui::toggle3d(); +} + +void PartGui::DimensionControl::toggleDeltaSlot(bool) +{ + PartGui::toggleDelta(); +} + +void PartGui::DimensionControl::clearAllSlot(bool) +{ + PartGui::eraseAllDimensions(); +} + +PartGui::TaskMeasureAngular::TaskMeasureAngular(): selections1(), selections2(), buttonSelectedIndex(0) +{ + setUpGui(); +} + +PartGui::TaskMeasureAngular::~TaskMeasureAngular() +{ + Gui::Selection().clearSelection(); +} + +void PartGui::TaskMeasureAngular::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + TopoDS_Shape shape; + if (!getShapeFromStrings(shape, std::string(msg.pDocName), std::string(msg.pObjectName), std::string(msg.pSubName))) + return; + DimSelections::DimSelection newSelection; + newSelection.documentName = msg.pDocName; + newSelection.objectName = msg.pObjectName; + newSelection.subObjectName = msg.pSubName; + newSelection.x = msg.x; + newSelection.y = msg.y; + newSelection.z = msg.z; + gp_Vec pickPoint(msg.x, msg.y, msg.z); + if (buttonSelectedIndex == 0) + { + if (msg.Type == Gui::SelectionChanges::AddSelection) + { + if (shape.ShapeType() == TopAbs_VERTEX) + { + //if we have previous selection it should be only one vertex. + if (selections1.selections.size() > 1) + selections1.selections.clear(); + else if(selections1.selections.size() == 1) + { + //make sure it is a vertex. + if (selections1.selections.at(0).shapeType != DimSelections::Vertex) + selections1.selections.clear(); + } + + newSelection.shapeType = DimSelections::Vertex; + selections1.selections.push_back(newSelection); + if (selections1.selections.size() == 1) + return; + //here we should have 2 vertices, but will check to make sure. + assert(selections1.selections.size() == 2); + assert(selections1.selections.at(0).shapeType == DimSelections::Vertex); + assert(selections1.selections.at(1).shapeType == DimSelections::Vertex); + + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(1)->setChecked(true); + return; + } + + //here there should only be one in the selections container. so just clear it. + selections1.selections.clear(); + + if (shape.ShapeType() == TopAbs_EDGE) + { + newSelection.shapeType = DimSelections::Edge; + selections1.selections. push_back(newSelection); + } + + if (shape.ShapeType() == TopAbs_FACE) + { + newSelection.shapeType = DimSelections::Face; + selections1.selections.push_back(newSelection); + } + + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(1)->setChecked(true); + return; + } + } + if (buttonSelectedIndex == 1) + { + if (msg.Type == Gui::SelectionChanges::AddSelection) + { + if (shape.ShapeType() == TopAbs_VERTEX) + { + //if we have previous selection it should be only one vertex. + if (selections2.selections.size() > 1) + selections2.selections.clear(); + else if(selections2.selections.size() == 1) + { + //make sure it is a vertex. + if (selections2.selections.at(0).shapeType != DimSelections::Vertex) + selections2.selections.clear(); + } + + newSelection.shapeType = DimSelections::Vertex; + selections2.selections.push_back(newSelection); + if (selections2.selections.size() == 1) + return; + //here we should have 2 vertices, but will check to make sure. + assert(selections2.selections.size() == 2); + assert(selections2.selections.at(0).shapeType == DimSelections::Vertex); + assert(selections2.selections.at(1).shapeType == DimSelections::Vertex); + + buildDimension(); + clearSelection(); + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(0)->setChecked(true); + return; + } + //vertices have to be selected in succession. if we get here,clear temp selection. + selections2.selections.clear(); + + if (shape.ShapeType() == TopAbs_EDGE) + { + newSelection.shapeType = DimSelections::Edge; + selections2.selections. push_back(newSelection); + } + + if (shape.ShapeType() == TopAbs_FACE) + { + newSelection.shapeType = DimSelections::Face; + selections2.selections.push_back(newSelection); + } + + buildDimension(); + clearSelection(); + QTimer::singleShot(0, this, SLOT(selectionClearDelayedSlot())); + stepped->getButton(0)->setChecked(true); + return; + } + } +} + +void PartGui::TaskMeasureAngular::selectionClearDelayedSlot() +{ + //hack. + //clearing selections are not working as I hoped. Apparently the observer callback gets called + //before the actual selection takes place. Resulting in selections being left. this addresses this + //by being called from the event loop. + this->blockConnection(true); + Gui::Selection().clearSelection(); + this->blockConnection(false); +} + +PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::DimSelections& selection) const +{ + assert(selection.selections.size() > 0 && selection.selections.size() < 3); + if (selection.selections.size() == 1) + { + DimSelections::DimSelection current = selection.selections.at(0); + if (current.shapeType == DimSelections::Edge) + { + TopoDS_Shape edgeShape; + if (!getShapeFromStrings(edgeShape, current.documentName, current.objectName, current.subObjectName)) + return VectorAdapter(); + TopoDS_Edge edge = TopoDS::Edge(edgeShape); + // make edge orientation so that end of edge closest to pick is head of vector. + gp_Vec firstPoint = PartGui::convert(TopExp::FirstVertex(edge, Standard_True)); + gp_Vec lastPoint = PartGui::convert(TopExp::LastVertex(edge, Standard_True)); + gp_Vec pickPoint(current.x, current.y, current.z); + double firstDistance = (firstPoint - pickPoint).Magnitude(); + double lastDistance = (lastPoint - pickPoint).Magnitude(); + if (lastDistance > firstDistance) + { + if (edge.Orientation() == TopAbs_FORWARD) + edge.Orientation(TopAbs_REVERSED); + else + edge.Orientation(TopAbs_FORWARD); + } + return VectorAdapter(edge, pickPoint); + } + if (current.shapeType == DimSelections::Face) + { + TopoDS_Shape faceShape; + if (!getShapeFromStrings(faceShape, current.documentName, current.objectName, current.subObjectName)) + return VectorAdapter(); + + TopoDS_Face face = TopoDS::Face(faceShape); + gp_Vec pickPoint(current.x, current.y, current.z); + return VectorAdapter(face, pickPoint); + } + } + //selection size == 2. + DimSelections::DimSelection current1 = selection.selections.at(0); + DimSelections::DimSelection current2 = selection.selections.at(1); + assert(current1.shapeType == DimSelections::Vertex); + assert(current2.shapeType == DimSelections::Vertex); + TopoDS_Shape vertexShape1, vertexShape2; + if(!getShapeFromStrings(vertexShape1, current1.documentName, current1.objectName, current1.subObjectName)) + return VectorAdapter(); + if(!getShapeFromStrings(vertexShape2, current2.documentName, current2.objectName, current2.subObjectName)) + return VectorAdapter(); + + TopoDS_Vertex vertex1 = TopoDS::Vertex(vertexShape1); + TopoDS_Vertex vertex2 = TopoDS::Vertex(vertexShape2); + + //build a temp adapter to make sure it is valid. + return VectorAdapter(PartGui::convert(vertex2), PartGui::convert(vertex1)); +} + +void PartGui::TaskMeasureAngular::buildDimension() +{ + //build adapters. + VectorAdapter adapt1 = buildAdapter(selections1); + VectorAdapter adapt2 = buildAdapter(selections2); + + if (!adapt1.isValid() || !adapt2.isValid()) + { + Base::Console().Message("\ncouldn't build adapter\n\n"); + return; + } + goDimensionAngularNoTask(adapt1, adapt2); +} + +void PartGui::TaskMeasureAngular::clearSelection() +{ + selections1.selections.clear(); + selections2.selections.clear(); +} + +void PartGui::TaskMeasureAngular::setUpGui() +{ + QPixmap mainIcon = Gui::BitmapFactory().pixmap("Part_Measure_Angular"); + + Gui::TaskView::TaskBox* selectionTaskBox = new Gui::TaskView::TaskBox + (mainIcon, QObject::tr("Selections"), false, 0); + QVBoxLayout *selectionLayout = new QVBoxLayout(); + stepped = new SteppedSelection(2, selectionTaskBox); + selectionLayout->addWidget(stepped); + selectionTaskBox->groupLayout()->addLayout(selectionLayout); + + Gui::TaskView::TaskBox* controlTaskBox = new Gui::TaskView::TaskBox + (mainIcon, QObject::tr("Control"), false, 0); + QVBoxLayout *controlLayout = new QVBoxLayout(); + + QHBoxLayout *resetLayout = new QHBoxLayout(); + resetLayout->addSpacing(5); //hack for alignment. + QPushButton *resetButton = new QPushButton(mainIcon, QObject::tr("Reset Dialog"), controlTaskBox); + resetLayout->addWidget(resetButton); + resetLayout->addStretch(); + controlLayout->addLayout(resetLayout); + QObject::connect(resetButton, SIGNAL(clicked(bool)), this, SLOT(resetDialogSlot(bool))); + + DimensionControl *control = new DimensionControl(controlTaskBox); + controlLayout->addWidget(control); + controlTaskBox->groupLayout()->addLayout(controlLayout); + + this->setButtonPosition(TaskDialog::South); + Content.push_back(selectionTaskBox); + Content.push_back(controlTaskBox); + + stepped->getButton(0)->setChecked(true);//before wired up. + QObject::connect(stepped->getButton(0), SIGNAL(toggled(bool)), this, SLOT(selection1Slot(bool))); + QObject::connect(stepped->getButton(1), SIGNAL(toggled(bool)), this, SLOT(selection2Slot(bool))); +} + +void PartGui::TaskMeasureAngular::selection1Slot(bool checked) +{ + if (checked) + { + buttonSelectedIndex = 0; + this->blockConnection(true); + Gui::Selection().clearSelection(); + std::vector::const_iterator it; + for (it = selections1.selections.begin(); it != selections1.selections.end(); ++it) + Gui::Selection().addSelection(it->documentName.c_str(), it->objectName.c_str(), it->subObjectName.c_str()); + this->blockConnection(false); + } + else + { + if (selections1.selections.size() > 0) + stepped->setIconDone(0); + } +} + +void PartGui::TaskMeasureAngular::selection2Slot(bool checked) +{ + if (checked) + buttonSelectedIndex = 1; + this->blockConnection(true); + Gui::Selection().clearSelection(); + std::vector::const_iterator it; + for (it = selections2.selections.begin(); it != selections2.selections.end(); ++it) + Gui::Selection().addSelection(it->documentName.c_str(), it->objectName.c_str(), it->subObjectName.c_str()); + this->blockConnection(false); +} + +void PartGui::TaskMeasureAngular::resetDialogSlot(bool) +{ + clearSelection(); + this->blockConnection(true); + Gui::Selection().clearSelection(); + stepped->getButton(0)->setChecked(true); + this->blockConnection(false); +} + +void PartGui::TaskMeasureAngular::toggle3dSlot(bool) +{ + PartGui::toggle3d(); +} + +void PartGui::TaskMeasureAngular::toggleDeltaSlot(bool) +{ + PartGui::toggleDelta(); +} + +void PartGui::TaskMeasureAngular::clearAllSlot(bool) +{ + PartGui::eraseAllDimensions(); +} + +#include "moc_TaskDimension.cpp" diff --git a/src/Mod/Part/Gui/TaskDimension.h b/src/Mod/Part/Gui/TaskDimension.h new file mode 100644 index 000000000..de09b90c4 --- /dev/null +++ b/src/Mod/Part/Gui/TaskDimension.h @@ -0,0 +1,360 @@ +/*************************************************************************** + * Copyright (c) 2013 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 TASKDIMENSION_H +#define TASKDIMENSION_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class TopoDS_Shape; +class TopoDS_Face; +class TopoDS_Edge; +class TopoDS_Vertex; +class gp_Pnt; +class BRepExtrema_DistShapeShape; + +class QPushButton; +class QPixmap; +class QLabel; + +namespace Gui{class View3dInventorViewer;} + +namespace PartGui +{ + /*!find shape from selection strings + * @param shapeOut search results. + * @param doc document name to search. + * @param object object name to search. + * @param sub sub-object name to search. + * @return signal if the search was successful. + */ + bool getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub); + /*!examine pre selection + * @param shape1 firt shape in current selection + * @param shape2 second shape in current selection + * @return signal if preselection is valid. false means shape1 and shape2 are invalid. + */ + bool evaluateLinearPreSelection(TopoDS_Shape &shape1, TopoDS_Shape &shape2); + /*!start of the measure linear command*/ + void goDimensionLinearRoot(); + /*!does the measure and create dimensions without a dialog + * @param shape1 first shape. + * @param shape2 second shape. + * @todo incorporate some form of "adapt to topods_shape". so we can expand to other types outside OCC. + */ + void goDimensionLinearNoTask(const TopoDS_Shape &shape1, const TopoDS_Shape &shape2); + /*!prints results of measuring to console. + * @param measure object containing the measure information + */ + void dumpLinearResults(const BRepExtrema_DistShapeShape &measure); + /*!convenience function to get the viewer*/ + Gui::View3DInventorViewer* getViewer(); + /*!adds 3d and delta dimensions to the viewer + * @param measure object containing the measure information. + */ + void addLinearDimensions(const BRepExtrema_DistShapeShape &measure); + /*!creates one dimension from points with color + * @param point1 first point + * @param point2 second point + * @param color color of dimension + * @return an inventor node to add to a scenegraph + */ + SoNode* createLinearDimension(const gp_Pnt &point1, const gp_Pnt &point2, const SbColor &color); + /*!erases all the dimensions in the viewer.*/ + void eraseAllDimensions(); + /*!toggles the display status of the 3d dimensions*/ + void toggle3d(); + /*!toggles the display status of the delta dimensions*/ + void toggleDelta(); + /*!make sure measure command isn't working with everthing invisible. Confusing the user*/ + void ensureSomeDimensionVisible(); + /*!make sure angle measure command isn't working with 3d off. Confusing the user*/ + void ensure3dDimensionVisible(); + /*convert a vertex to vector*/ + gp_Vec convert(const TopoDS_Vertex &vertex); + +class DimensionLinear : public SoSeparatorKit +{ + SO_KIT_HEADER(DimensionLinear); + + SO_KIT_CATALOG_ENTRY_HEADER(transformation); + SO_KIT_CATALOG_ENTRY_HEADER(annotate); + SO_KIT_CATALOG_ENTRY_HEADER(leftArrow); + SO_KIT_CATALOG_ENTRY_HEADER(rightArrow); + SO_KIT_CATALOG_ENTRY_HEADER(line); + SO_KIT_CATALOG_ENTRY_HEADER(textSep); +public: + DimensionLinear(); + static void initClass(); + virtual SbBool affectsState() const; + + SoSFVec3f point1; + SoSFVec3f point2; + SoSFString text; + SoSFColor dColor; +protected: + SoSFRotation rotate; + SoSFFloat length; + SoSFVec3f origin; + +private: + virtual ~DimensionLinear(); + void setupDimension(); +}; + +/*kit for anglular dimensions*/ +class DimensionAngular : public SoSeparatorKit +{ + SO_KIT_HEADER(DimensionAngular); + + SO_KIT_CATALOG_ENTRY_HEADER(transformation); + SO_KIT_CATALOG_ENTRY_HEADER(annotate); + SO_KIT_CATALOG_ENTRY_HEADER(arrow1); + SO_KIT_CATALOG_ENTRY_HEADER(arrow2); + SO_KIT_CATALOG_ENTRY_HEADER(arcSep); + SO_KIT_CATALOG_ENTRY_HEADER(textSep); +public: + DimensionAngular(); + static void initClass(); + virtual SbBool affectsState() const; + + SoSFFloat radius;//radians. + SoSFFloat angle;//radians. + SoSFString text; + SoSFColor dColor; + SoSFMatrix matrix; +private: + virtual ~DimensionAngular(); + void setupDimension(); +}; + +/*used for generating points for arc display*/ +class ArcEngine : public SoEngine +{ + SO_ENGINE_HEADER(ArcEngine); +public: + ArcEngine(); + static void initClass(); + + SoSFFloat radius; + SoSFFloat angle; + SoSFFloat deviation; + + SoEngineOutput points; + SoEngineOutput pointCount; +protected: + virtual void evaluate(); +private: + virtual ~ArcEngine(){} + void defaultValues(); //some non error values if something goes wrong. +}; + +/*! a widget with buttons and icons for a controlled selection process*/ +class SteppedSelection : public QWidget +{ + Q_OBJECT +public: + SteppedSelection(const uint &buttonCountIn, QWidget *parent = 0); + ~SteppedSelection(); + QPushButton* getButton(const uint &index); + void setIconDone(const uint &index); + +protected: + typedef std::pair ButtonIconPairType; + std::vector buttons; + QPixmap *stepActive; + QPixmap *stepDone; + +private slots: + void selectionSlot(bool checked); + void buildPixmaps(); + +}; + +/*! just convenience container*/ +class DimSelections +{ +public: + enum ShapeType{None, Vertex, Edge, Face}; + struct DimSelection + { + std::string documentName; + std::string objectName; + std::string subObjectName; + float x; + float y; + float z; + ShapeType shapeType; + }; + std::vector selections; +}; + +/*!widget for buttons controlling the display of dimensions*/ +class DimensionControl : public QWidget +{ + Q_OBJECT +public: + explicit DimensionControl(QWidget* parent); +public slots: + void toggle3dSlot(bool); + void toggleDeltaSlot(bool); + void clearAllSlot(bool); +}; + +/*!linear dialog*/ +class TaskMeasureLinear : public Gui::TaskView::TaskDialog, public Gui::SelectionObserver +{ + Q_OBJECT +public: + TaskMeasureLinear(); + ~TaskMeasureLinear(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + {return QDialogButtonBox::Close;} + virtual bool isAllowedAlterDocument(void) const {return false;} + virtual bool needsFullSpace() const {return false;} +protected: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +protected slots: + void selection1Slot(bool checked); + void selection2Slot(bool checked); + void resetDialogSlot(bool); + void toggle3dSlot(bool); + void toggleDeltaSlot(bool); + void clearAllSlot(bool); + void selectionClearDelayedSlot(); + +private: + void setUpGui(); + void buildDimension(); + void clearSelectionStrings(); + DimSelections selections1; + DimSelections selections2; + uint buttonSelectedIndex; + SteppedSelection *stepped; + +}; + +/*! @brief Convert to vector + * + * Used to construct a vector from various input types + */ +class VectorAdapter +{ +public: + /*!default construction isValid is set to false*/ + VectorAdapter(); + /*!Build a vector from a faceIn + * @param faceIn vector will be normal to plane and equal to cylindrical axis. + * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ + VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn); + /*!Build a vector from an edgeIn + * @param edgeIn vector will be lastPoint - firstPoint. + * @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/ + VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn); + /*!Build a vector From 2 vertices. + *vector will be equal to @param vertex2In - @param vertex1In.*/ + VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In); + /*!Build a vector From 2 vectors. + *vector will be equal to @param vector2 - @param vector1.*/ + VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2); + + /*!make sure no errors in vector construction. + * @return true = vector is good. false = vector is NOT good.*/ + bool isValid() const {return status;} + /*!get the calculated vector. + * @return the vector. use isValid to ensure correct results.*/ + operator gp_Vec() const {return vector;} + /*!build occ line used for extrema calculation*/ + operator gp_Lin() const; + gp_Vec getPickPoint() const {return origin;} + +private: + void projectOriginOntoVector(const gp_Vec &pickedPointIn); + bool status; + gp_Vec vector; + gp_Vec origin; +}; + +/*!angular dialog class*/ +class TaskMeasureAngular : public Gui::TaskView::TaskDialog, public Gui::SelectionObserver +{ + Q_OBJECT +public: + TaskMeasureAngular(); + ~TaskMeasureAngular(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + {return QDialogButtonBox::Close;} + virtual bool isAllowedAlterDocument(void) const {return false;} + virtual bool needsFullSpace() const {return false;} +protected: + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +protected slots: + void selection1Slot(bool checked); + void selection2Slot(bool checked); + void resetDialogSlot(bool); + void toggle3dSlot(bool); + void toggleDeltaSlot(bool); + void clearAllSlot(bool); + void selectionClearDelayedSlot(); + +private: + void setUpGui(); + void buildDimension(); + void clearSelection(); + DimSelections selections1; + DimSelections selections2; + uint buttonSelectedIndex; + SteppedSelection *stepped; + VectorAdapter buildAdapter(const DimSelections &selection) const; +}; + +/*!start of the measure angular command*/ +void goDimensionAngularRoot(); +/*!examine angular pre selection + * @param vector1Out firt shape in current selection + * @param vector2Out second shape in current selection + * @return signal if preselection is valid. false means vector1Out and vector2Out are invalid. + */ +bool evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapter &vector2Out); +/*!build angular dimension*/ +void goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, const VectorAdapter &vector2Adapter); +} + +#endif // TASKDIMENSION_H From 840df0001430c4dad5a25dd334bb29c96e60b008 Mon Sep 17 00:00:00 2001 From: blobfish Date: Tue, 17 Dec 2013 09:46:30 -0500 Subject: [PATCH 3/6] Part Dimension: new icons --- .../Resources/icons/Part_Measure_Angular.svg | 489 +++++++++++++++ .../icons/Part_Measure_Clear_All.svg | 583 ++++++++++++++++++ .../Resources/icons/Part_Measure_Linear.svg | 448 ++++++++++++++ .../icons/Part_Measure_Step_Active.svg | 297 +++++++++ .../icons/Part_Measure_Step_Done.svg | 254 ++++++++ .../icons/Part_Measure_Toggle_3d.svg | 454 ++++++++++++++ .../icons/Part_Measure_Toggle_All.svg | 461 ++++++++++++++ .../icons/Part_Measure_Toggle_Delta.svg | 455 ++++++++++++++ 8 files changed, 3441 insertions(+) create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Angular.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Clear_All.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Active.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Done.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_3d.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_All.svg create mode 100644 src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_Delta.svg diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Angular.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Angular.svg new file mode 100644 index 000000000..b18a93812 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Angular.svg @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Clear_All.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Clear_All.svg new file mode 100644 index 000000000..5915af9ec --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Clear_All.svg @@ -0,0 +1,583 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg new file mode 100644 index 000000000..ee8ce7208 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Active.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Active.svg new file mode 100644 index 000000000..14bd3a549 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Active.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Done.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Done.svg new file mode 100644 index 000000000..0bcb47402 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Step_Done.svg @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_3d.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_3d.svg new file mode 100644 index 000000000..b972acc8b --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_3d.svg @@ -0,0 +1,454 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_All.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_All.svg new file mode 100644 index 000000000..13584665f --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_All.svg @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_Delta.svg b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_Delta.svg new file mode 100644 index 000000000..b7d5d7e84 --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Measure_Toggle_Delta.svg @@ -0,0 +1,455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4f6a82c3bc1307b3ebc3f0426f918a9082b0e115 Mon Sep 17 00:00:00 2001 From: blobfish Date: Tue, 17 Dec 2013 22:53:22 -0500 Subject: [PATCH 4/6] adding some headers --- src/Mod/Part/Gui/TaskDimension.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/Part/Gui/TaskDimension.cpp b/src/Mod/Part/Gui/TaskDimension.cpp index 7eb926d7a..aab29a1a7 100644 --- a/src/Mod/Part/Gui/TaskDimension.cpp +++ b/src/Mod/Part/Gui/TaskDimension.cpp @@ -22,6 +22,9 @@ #include #include +#include +#include +#include #include #include #include From 98f0918bec02cfa9cf33c1de0fcfda321072fd23 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 18 Dec 2013 22:49:58 +0100 Subject: [PATCH 5/6] fixes for windows --- src/Mod/Part/Gui/TaskDimension.cpp | 46 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Mod/Part/Gui/TaskDimension.cpp b/src/Mod/Part/Gui/TaskDimension.cpp index aab29a1a7..6806f668b 100644 --- a/src/Mod/Part/Gui/TaskDimension.cpp +++ b/src/Mod/Part/Gui/TaskDimension.cpp @@ -19,6 +19,9 @@ * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ +#include "PreCompiled.h" + + #include #include @@ -57,7 +60,6 @@ #include #include -#include "PreCompiled.h" #include #include #include "../App/PartFeature.h" @@ -317,12 +319,12 @@ PartGui::DimensionLinear::DimensionLinear() { SO_KIT_CONSTRUCTOR(PartGui::DimensionLinear); - SO_KIT_ADD_CATALOG_ENTRY(transformation, SoTransform, TRUE, topSeparator, , TRUE); - SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator, , TRUE); - SO_KIT_ADD_CATALOG_ENTRY(leftArrow, SoShapeKit, TRUE, topSeparator, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(rightArrow, SoShapeKit, TRUE, topSeparator, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(line, SoShapeKit, TRUE, annotate, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(transformation, SoTransform, TRUE, topSeparator,"" , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator,"" , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(leftArrow, SoShapeKit, TRUE, topSeparator,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(rightArrow, SoShapeKit, TRUE, topSeparator,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(line, SoShapeKit, TRUE, annotate,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate,"" ,TRUE); SO_KIT_INIT_INSTANCE(); @@ -849,12 +851,12 @@ void PartGui::goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, cons stream << std::setprecision(std::numeric_limits::digits10 + 1) << std::fixed << std::endl << "angle in radians is: " << angle << std::endl << "angle in degrees is: " << 180 * angle / M_PI << std::endl; - if (angle < M_PI / 2.0d) + if (angle < M_PI / 2.0) stream << std::setprecision(std::numeric_limits::digits10 + 1) << - "complement in radians is: " << M_PI / 2.0d - angle << std::endl << + "complement in radians is: " << M_PI / 2.0 - angle << std::endl << "complement in degrees is: " << 90 - 180 * angle / M_PI << std::endl; //I don't think we get anything over 180, but just in case. - if (angle > M_PI / 2.0d && angle < M_PI) + if (angle > M_PI / 2.0 && angle < M_PI) stream << std::setprecision(std::numeric_limits::digits10 + 1) << "supplement in radians is: " << M_PI - angle << std::endl << "supplement in degrees is: " << 180 - 180 * angle / M_PI << std::endl; @@ -889,7 +891,7 @@ void PartGui::goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, cons gp_Vec midPointProjection = newPoint2 - point1; double distance = midPointProjection.Magnitude(); midPointProjection.Normalize(); - midPointProjection *= distance / 2.0d; + midPointProjection *= distance / 2.0; gp_Vec origin = point1 + midPointProjection; @@ -900,10 +902,10 @@ void PartGui::goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, cons gp_Vec zAxis; if (xAxis.IsParallel(vector1, Precision::Angular())) { - if (!xAxis.IsParallel(gp_Vec(0.0d, 0.0d, 1.0d), Precision::Angular())) - zAxis = gp_Vec(0.0d, 0.0d, 1.0d); + if (!xAxis.IsParallel(gp_Vec(0.0, 0.0, 1.0), Precision::Angular())) + zAxis = gp_Vec(0.0, 0.0, 1.0); else - zAxis = gp_Vec(0.0d, 1.0d, 0.0d); + zAxis = gp_Vec(0.0, 1.0, 0.0); } else zAxis = xAxis.Crossed(vector1).Normalized(); @@ -947,7 +949,7 @@ void PartGui::goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, cons gp_Vec connection(vec2-vec1); Standard_Real distance = connection.Magnitude(); connection.Normalize(); - connection *= (distance / 2.0d); + connection *= (distance / 2.0); dimensionOriginPoint.SetXYZ((vec1 + connection).XYZ()); } @@ -1012,12 +1014,12 @@ PartGui::DimensionAngular::DimensionAngular() { SO_KIT_CONSTRUCTOR(PartGui::DimensionAngular); - SO_KIT_ADD_CATALOG_ENTRY(transformation, SoMatrixTransform, TRUE, topSeparator, , TRUE); - SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator, , TRUE); - SO_KIT_ADD_CATALOG_ENTRY(arrow1, SoShapeKit, TRUE, topSeparator, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(arrow2, SoShapeKit, TRUE, topSeparator, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(arcSep, SoSeparator, TRUE, annotate, ,TRUE); - SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate, ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(transformation, SoMatrixTransform, TRUE, topSeparator,"" , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, TRUE, topSeparator,"" , TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arrow1, SoShapeKit, TRUE, topSeparator,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arrow2, SoShapeKit, TRUE, topSeparator,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(arcSep, SoSeparator, TRUE, annotate,"" ,TRUE); + SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, TRUE, annotate,"" ,TRUE); SO_KIT_INIT_INSTANCE(); @@ -1098,7 +1100,7 @@ void PartGui::DimensionAngular::setupDimension() ArcEngine *arcEngine = new ArcEngine(); arcEngine->angle.connectFrom(&angle); arcEngine->radius.connectFrom(&radius); - arcEngine->deviation.setValue(0.1); + arcEngine->deviation.setValue(0.1f); SoCoordinate3 *coordinates = new SoCoordinate3(); coordinates->point.connectFrom(&arcEngine->points); From 109729e15eb304ab329481d57eee95ccbdfe24f1 Mon Sep 17 00:00:00 2001 From: blobfish Date: Thu, 19 Dec 2013 10:17:43 -0500 Subject: [PATCH 6/6] adding toggle and clear to context, view menu --- src/Gui/CommandView.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ src/Gui/Workbench.cpp | 6 ++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 024d46c1e..8fdfd3a98 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -2215,6 +2215,62 @@ void StdCmdDemoMode::activated(int iMsg) dlg->show(); } +//=========================================================================== +// Part_Measure_Clear_All +//=========================================================================== + +DEF_STD_CMD(CmdViewMeasureClearAll); + +CmdViewMeasureClearAll::CmdViewMeasureClearAll() + : Command("View_Measure_Clear_All") +{ + sGroup = QT_TR_NOOP("Measure"); + sMenuText = QT_TR_NOOP("Clear All"); + sToolTipText = QT_TR_NOOP("Clear All"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Clear_All"; +} + +void CmdViewMeasureClearAll::activated(int iMsg) +{ + Gui::View3DInventor *view = dynamic_cast(Gui::Application::Instance-> + activeDocument()->getActiveView()); + if (!view) + return; + Gui::View3DInventorViewer *viewer = view->getViewer(); + if (!viewer) + return; + viewer->eraseAllDimensions(); +} + +//=========================================================================== +// Part_Measure_Toggle_All +//=========================================================================== + +DEF_STD_CMD(CmdViewMeasureToggleAll); + +CmdViewMeasureToggleAll::CmdViewMeasureToggleAll() + : Command("View_Measure_Toggle_All") +{ + sGroup = QT_TR_NOOP("Measure"); + sMenuText = QT_TR_NOOP("Toggle All"); + sToolTipText = QT_TR_NOOP("Toggle All"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Measure_Toggle_All"; +} + +void CmdViewMeasureToggleAll::activated(int iMsg) +{ + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View"); + bool visibility = group->GetBool("DimensionsVisible", true); + if (visibility) + group->SetBool("DimensionsVisible", false); + else + group->SetBool("DimensionsVisible", true); +} //=========================================================================== // Instantiation @@ -2280,6 +2336,8 @@ void CreateViewStdCommands(void) rcCmdMgr.addCommand(new StdCmdDemoMode()); rcCmdMgr.addCommand(new StdCmdToggleNavigation()); rcCmdMgr.addCommand(new StdCmdAxisCross()); + rcCmdMgr.addCommand(new CmdViewMeasureClearAll()); + rcCmdMgr.addCommand(new CmdViewMeasureToggleAll()); } } // namespace Gui diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index 1e9ba4296..b8cb0cb40 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -399,7 +399,11 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const << "Std_ViewRear" << "Std_ViewBottom" << "Std_ViewLeft" << "Separator" << "Std_ViewRotateLeft" << "Std_ViewRotateRight"; - *item << "Std_ViewFitAll" << "Std_ViewFitSelection" << StdViews + MenuItem *measure = new MenuItem(); + measure->setCommand("Measure"); + *measure << "View_Measure_Toggle_All" << "View_Measure_Clear_All"; + + *item << "Std_ViewFitAll" << "Std_ViewFitSelection" << StdViews << measure << "Separator" << "Std_ViewDockUndockFullscreen"; if (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId()) > 0 )