From d94946781e190f0862c2e5e7323a04cbbe32008a Mon Sep 17 00:00:00 2001 From: David Osterberg Date: Tue, 2 Feb 2021 18:04:44 +0100 Subject: [PATCH] PartDesign: Add true threads to Hole - Thread runout according to DIN 76-1 - Through all length updated to be calculated based on bounding box - New properties: ModelThread, ThreadDepthType, ThreadDepth, UseCustomThreadClearance, CustomThreadClearance - Rename Old but unused parameters related to thread modeling. - Functionality exposed in UI --- src/Mod/PartDesign/App/FeatureHole.cpp | 478 ++++++++++++++---- src/Mod/PartDesign/App/FeatureHole.h | 21 +- src/Mod/PartDesign/Gui/TaskHoleParameters.cpp | 221 ++++++-- src/Mod/PartDesign/Gui/TaskHoleParameters.h | 22 +- src/Mod/PartDesign/Gui/TaskHoleParameters.ui | 204 ++++++-- 5 files changed, 764 insertions(+), 182 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp index 5825b01f06..d479bc32ec 100644 --- a/src/Mod/PartDesign/App/FeatureHole.cpp +++ b/src/Mod/PartDesign/App/FeatureHole.cpp @@ -50,6 +50,11 @@ # include # include # include +# include +# include +# include +# include +# include #endif @@ -61,6 +66,7 @@ #include #include #include +#include #include "json.hpp" #include "FeatureHole.h" @@ -70,6 +76,7 @@ namespace PartDesign { /* TRANSLATOR PartDesign::Hole */ const char* Hole::DepthTypeEnums[] = { "Dimension", "ThroughAll", /*, "UpToFirst", */ NULL }; +const char* Hole::ThreadDepthTypeEnums[] = { "Automatic", "Dimension", NULL }; const char* Hole::ThreadTypeEnums[] = { "None", "ISOMetricProfile", "ISOMetricFineProfile", "UNC", "UNF", "UNEF", NULL}; const char* Hole::ClearanceMetricEnums[] = { "Standard", "Close", "Wide", NULL}; const char* Hole::ClearanceUTSEnums[] = { "Normal", "Close", "Loose", NULL }; @@ -542,6 +549,67 @@ const char* Hole::ThreadSize_ISOmetricfine_Enums[] = { "M100x2.0", "M100x3.0", "M100x4.0", "M100x6.0", NULL }; const char* Hole::ThreadClass_ISOmetricfine_Enums[] = { "4G", "4H", "5G", "5H", "6G", "6H", "7G", "7H","8G", "8H", NULL }; +// ISO 965-1:2013 ISO general purpose metric screw threads - Tolerances - Part 1 +// Table 1 - Fundamentral deviations for internal threads ... +// reproduced in: https://www.accu.co.uk/en/p/134-iso-metric-thread-tolerances [retrived: 2021-01-11] +const double Hole::ThreadClass_ISOmetric_data[ThreadClass_ISOmetric_data_size][2] = { +// Pitch G + {0.2, 0.017}, + {0.25, 0.018}, + {0.3, 0.018}, + {0.35, 0.019}, + {0.4, 0.019}, + {0.45, 0.020}, + {0.5, 0.020}, + {0.6, 0.021}, + {0.7, 0.022}, + {0.75, 0.022}, + {0.8, 0.024}, + {1.0, 0.026}, + {1.25, 0.028}, + {1.5, 0.032}, + {1.75, 0.034}, + {2.0, 0.038}, + {2.5, 0.042}, + {3.0, 0.048}, + {3.5, 0.053}, + {4.0, 0.060}, + {4.5, 0.063}, + {5.0, 0.071}, + {5.5, 0.075}, + {6.0, 0.080}, + {8.0, 0.100} +}; + +/* According to DIN 76-1 (Thread run-outs and thread undercuts - Part 1: For ISO metric threads in accordance with DIN 13-1) */ +const double Hole::ThreadRunout[ThreadRunout_size][2] = { +// Pitch e1 + {0.2, 1.3}, + {0.25, 1.5}, + {0.3, 1.8}, + {0.35, 2.1}, + {0.4, 2.3}, + {0.45, 2.6}, + {0.5, 2.8}, + {0.6, 3.4}, + {0.7, 3.8}, + {0.75, 4.0}, + {0.8, 4.2}, + {1.0, 5.1}, + {1.25, 6.2}, + {1.5, 7.3}, + {1.75, 8.3}, + {2.0, 9.3}, + {2.5, 11.2}, + {3.0, 13.1}, + {3.5, 15.2}, + {4.0, 16.8}, + {4.5, 18.4}, + {5.0, 20.8}, + {5.5, 22.4}, + {6.0, 24.0} +}; + /* Details from https://en.wikipedia.org/wiki/Unified_Thread_Standard */ /* UTS coarse */ @@ -585,11 +653,7 @@ Hole::Hole() ADD_PROPERTY_TYPE(Threaded, (false), "Hole", App::Prop_None, "Threaded"); - ADD_PROPERTY_TYPE(ModelActualThread, (false), "Hole", App::Prop_None, "Model actual thread"); - ADD_PROPERTY_TYPE(ThreadPitch, (0.0), "Hole", App::Prop_None, "Thread pitch"); - ADD_PROPERTY_TYPE(ThreadAngle, (0.0), "Hole", App::Prop_None, "Thread angle"); - ADD_PROPERTY_TYPE(ThreadCutOffInner, (0.0), "Hole", App::Prop_None, "Thread CutOff Inner"); - ADD_PROPERTY_TYPE(ThreadCutOffOuter, (0.0), "Hole", App::Prop_None, "Thread CutOff Outer"); + ADD_PROPERTY_TYPE(ModelThread, (false), "Hole", App::Prop_None, "Model actual thread"); ADD_PROPERTY_TYPE(ThreadType, (0L), "Hole", App::Prop_None, "Thread type"); ThreadType.setEnums(ThreadTypeEnums); @@ -635,6 +699,16 @@ Hole::Hole() ADD_PROPERTY_TYPE(Tapered, (false),"Hole", App::Prop_None, "Tapered"); ADD_PROPERTY_TYPE(TaperedAngle, (90.0), "Hole", App::Prop_None, "Tapered angle"); + + ADD_PROPERTY_TYPE(ThreadDepthType, (0L), "Hole", App::Prop_None, "Thread depth type"); + ThreadDepthType.setEnums(ThreadDepthTypeEnums); + + ADD_PROPERTY_TYPE(ThreadDepth, (23.5), "Hole", App::Prop_None, "Thread Length"); // default is assuming an M1 + + ADD_PROPERTY_TYPE(UseCustomThreadClearance, (false), "Hole", App::Prop_None, "Use custom thread clearance"); + + ADD_PROPERTY_TYPE(CustomThreadClearance, (0.0), "Hole", App::Prop_None, "Custom thread clearance (overrides ThreadClass)"); + } void Hole::updateHoleCutParams() @@ -697,7 +771,7 @@ void Hole::updateHoleCutParams() const CounterSinkDimension& dimen = counter.get_sink(threadSizeStr); if (dimen.diameter != 0.0) { HoleCutDiameter.setValue(dimen.diameter); - } + } else { HoleCutDiameter.setValue(Diameter.getValue() + 0.1); } @@ -838,7 +912,7 @@ void Hole::updateHoleCutParams() if (HoleCutDiameter.getValue() == 0.0 || HoleCutDiameter.getValue() <= diameterVal) { HoleCutDiameter.setValue(diameterVal * 1.7); // 82 degrees for UTS, 90 otherwise - if (threadTypeStr != "None") + if (threadTypeStr != "None") HoleCutCountersinkAngle.setValue(82.0); else HoleCutCountersinkAngle.setValue(90.0); @@ -856,6 +930,84 @@ void Hole::updateHoleCutParams() } } +double Hole::getThreadClassClearance() +{ + double pitch = getThreadPitch(); + + // Calulate how much clearance to add based on Thread tolerance class and pitch + if (ThreadClass.getValueAsString()[1] == 'G') { + for(unsigned int i=0; i(360.0); - BRepPrimAPI_MakeRevol RevolMaker2(threadFace, gp_Ax1(gp_Pnt(0,0,0), zDir), angle); - - //TopoDS_Shape protoHole; - if (RevolMaker2.IsDone()) { - protoHole = RevolMaker2.Shape(); - - if (protoHole.IsNull()) - return new App::DocumentObjectExecReturn("Hole: Resulting shape is empty"); + //create the helix path + double threadDepth = ThreadDepth.getValue(); + double helixLength = threadDepth + P/2; + std::string threadDepthMethod(ThreadDepthType.getValueAsString()); + if ( threadDepthMethod == "Automatic" ) { + std::string depthMethod(DepthType.getValueAsString()); + if ( depthMethod == "ThroughAll" ) { + threadDepth = length; + ThreadDepth.setValue(threadDepth); + helixLength = threadDepth + 2*P; + } else { + threadDepth = Depth.getValue() - getThreadRunout(); + ThreadDepth.setValue(threadDepth); + helixLength = threadDepth + P/2; + } } - else - return new App::DocumentObjectExecReturn("Hole: Could not revolve sketch!"); + TopoDS_Shape helix = TopoShape().makeLongHelix(P, helixLength, D / 2, 0.0, leftHanded); + + gp_Pnt origo(0.0, 0.0, 0.0); + gp_Dir dir_axis1(0.0, 0.0, 1.0); // pointing along the helix axis, as created. + gp_Dir dir_axis2(1.0, 0.0, 0.0); // pointing towards the helix start point, as created. + + // Reverse the direction of the helix. So that it goes into the material + gp_Trsf mov; + mov.SetRotation(gp_Ax1(origo, dir_axis2), M_PI); + TopLoc_Location loc1(mov); + helix.Move(loc1); + + // rotate the helix so that it is pointing in the zdir. + double angle = acos(dir_axis1*zDir); + if (abs(angle) > Precision::Confusion()) { + gp_Dir rotAxis = dir_axis1^zDir; + mov.SetRotation(gp_Ax1(origo, rotAxis), angle); + TopLoc_Location loc2(mov); + helix.Move(loc2); + } + + // create the pipe shell + BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(helix)); + mkPS.SetTolerance(Precision::Confusion()); + mkPS.SetTransitionMode(BRepBuilderAPI_Transformed); + mkPS.SetMode(true); //This is for frenet + mkPS.Add(threadWire); + if (!mkPS.IsReady()) + return new App::DocumentObjectExecReturn("Error: Thread could not be built"); + TopoDS_Shape shell = mkPS.Shape(); + + // create faces at the ends of the pipe shell + TopTools_ListOfShape sim; + mkPS.Simulate(2, sim); + std::vector frontwires, backwires; + frontwires.push_back(TopoDS::Wire(sim.First())); + backwires.push_back(TopoDS::Wire(sim.Last())); + // build the end faces + TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires); + TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); + + // sew the shell and end faces + BRepBuilderAPI_Sewing sewer; + sewer.SetTolerance(Precision::Confusion()); + sewer.Add(front); + sewer.Add(back); + sewer.Add(shell); + sewer.Perform(); + + // make the closed off shell into a solid + BRepBuilderAPI_MakeSolid mkSolid; + mkSolid.Add(TopoDS::Shell(sewer.SewedShape())); + if(!mkSolid.IsDone()) + return new App::DocumentObjectExecReturn("Error: Result is not a solid"); + TopoDS_Shape result = mkSolid.Shape(); + + // check if the algorithm has confused the inside and outside of the solid + BRepClass3d_SolidClassifier SC(result); + SC.PerformInfinitePoint(Precision::Confusion()); + if (SC.State() == TopAbs_IN) + result.Reverse(); + + // we are done + TopoDS_Shape protoThread = result; + + // fuse the thread to the hole + BRepAlgoAPI_Fuse mkFuse(protoHole, protoThread); + if (!mkFuse.IsDone()) + return new App::DocumentObjectExecReturn("Error: Adding the thread failed"); + + // we reuse the name protoHole (only now it is threaded) + protoHole = mkFuse.Shape(); } -#endif BRep_Builder builder; TopoDS_Compound holes; @@ -1739,6 +2010,7 @@ App::DocumentObjectExecReturn *Hole::execute(void) remapSupportShape(base); + int solidCount = countSolids(base); if (solidCount > 1) { return new App::DocumentObjectExecReturn("Hole: Result has multiple solids. This is not supported at this time."); diff --git a/src/Mod/PartDesign/App/FeatureHole.h b/src/Mod/PartDesign/App/FeatureHole.h index 8fe3457c4f..52c05bc2b0 100644 --- a/src/Mod/PartDesign/App/FeatureHole.h +++ b/src/Mod/PartDesign/App/FeatureHole.h @@ -37,6 +37,9 @@ class XMLReader; namespace PartDesign { +static constexpr size_t ThreadClass_ISOmetric_data_size = 25; +static constexpr size_t ThreadRunout_size = 24; + class PartDesignExport Hole : public ProfileBased { PROPERTY_HEADER(PartDesign::Hole); @@ -45,11 +48,8 @@ public: Hole(); App::PropertyBool Threaded; - App::PropertyBool ModelActualThread; + App::PropertyBool ModelThread; App::PropertyLength ThreadPitch; - App::PropertyAngle ThreadAngle; - App::PropertyLength ThreadCutOffInner; - App::PropertyLength ThreadCutOffOuter; App::PropertyEnumeration ThreadType; App::PropertyEnumeration ThreadSize; App::PropertyEnumeration ThreadClass; @@ -63,11 +63,15 @@ public: App::PropertyAngle HoleCutCountersinkAngle; App::PropertyEnumeration DepthType; App::PropertyLength Depth; + App::PropertyEnumeration ThreadDepthType; + App::PropertyLength ThreadDepth; App::PropertyEnumeration DrillPoint; App::PropertyAngle DrillPointAngle; App::PropertyBool DrillForDepth; App::PropertyBool Tapered; App::PropertyAngle TaperedAngle; + App::PropertyBool UseCustomThreadClearance; + App::PropertyLength CustomThreadClearance; /** @name methods override feature */ //@{ @@ -107,6 +111,7 @@ protected: void onChanged(const App::Property* prop); private: static const char* DepthTypeEnums[]; + static const char* ThreadDepthTypeEnums[]; static const char* ThreadTypeEnums[]; static const char* ClearanceMetricEnums[]; static const char* ClearanceUTSEnums[]; @@ -122,6 +127,7 @@ private: static std::vector HoleCutType_ISOmetric_Enums; static const char* ThreadSize_ISOmetric_Enums[]; static const char* ThreadClass_ISOmetric_Enums[]; + static const double ThreadClass_ISOmetric_data[ThreadClass_ISOmetric_data_size][2]; /* ISO metric fine profile */ static std::vector HoleCutType_ISOmetricfine_Enums; @@ -143,6 +149,8 @@ private: static const char* ThreadSize_UNEF_Enums[]; static const char* ThreadClass_UNEF_Enums[]; + static const double ThreadRunout[ThreadRunout_size][2]; + /* Counter-xxx */ //public: // Dimension for counterbore @@ -203,8 +211,13 @@ private: bool isDynamicCountersink(const std::string &thread, const std::string &holeCutType); void updateHoleCutParams(); void updateDiameterParam(); + void updateThreadDepthParam(); void readCutDefinitions(); + double getThreadClassClearance(); + double getThreadRunout(int mode = 1); + double getThreadPitch(); + // helpers for nlohmann json friend void from_json(const nlohmann::json &j, CounterBoreDimension &t); friend void from_json(const nlohmann::json &j, CounterSinkDimension &t); diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp index dbd5a866bd..7ab6e774e9 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.cpp @@ -76,8 +76,12 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *pare // read values from the hole properties PartDesign::Hole* pcHole = static_cast(vp->getObject()); + ui->Threaded->setChecked(pcHole->Threaded.getValue()); + ui->Threaded->setDisabled(std::string(pcHole->ThreadType.getValueAsString()) == "None"); + ui->ThreadType->setCurrentIndex(pcHole->ThreadType.getValue()); + ui->ThreadSize->clear(); const char** cursor = pcHole->ThreadSize.getEnums(); while (*cursor) { @@ -162,6 +166,22 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *pare ui->TaperedAngle->setValue(pcHole->TaperedAngle.getValue()); ui->Reversed->setChecked(pcHole->Reversed.getValue()); + ui->ModelThread->setChecked(pcHole->ModelThread.getValue()); + ui->UseCustomThreadClearance->setChecked(pcHole->UseCustomThreadClearance.getValue()); + ui->CustomThreadClearance->setValue(pcHole->CustomThreadClearance.getValue()); + ui->ThreadDepthType->setCurrentIndex(pcHole->ThreadDepthType.getValue()); + ui->ThreadDepth->setValue(pcHole->ThreadDepth.getValue()); + + // conditional enabling of thread modeling options + ui->ModelThread->setEnabled(ui->Threaded->isChecked() && ui->ThreadType->currentIndex() != 0); + ui->UseCustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked()); + ui->labelThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked() && ui->UseCustomThreadClearance->isChecked()); + ui->CustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked() && ui->UseCustomThreadClearance->isChecked()); + ui->UpdateView->setChecked(!ui->ModelThread->isChecked()); + + ui->ThreadDepthType->setEnabled(ui->Threaded->isChecked()); + ui->ThreadDepth->setEnabled(ui->Threaded->isChecked() && std::string(pcHole->ThreadDepthType.getValueAsString()) == "Dimension"); + connect(ui->Threaded, SIGNAL(clicked(bool)), this, SLOT(threadedChanged())); connect(ui->ThreadType, SIGNAL(currentIndexChanged(int)), this, SLOT(threadTypeChanged(int))); connect(ui->ThreadSize, SIGNAL(currentIndexChanged(int)), this, SLOT(threadSizeChanged(int))); @@ -184,6 +204,12 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *pare connect(ui->Tapered, SIGNAL(clicked(bool)), this, SLOT(taperedChanged())); connect(ui->Reversed, SIGNAL(clicked(bool)), this, SLOT(reversedChanged())); connect(ui->TaperedAngle, SIGNAL(valueChanged(double)), this, SLOT(taperedAngleChanged(double))); + connect(ui->ModelThread, SIGNAL(clicked(bool)), this, SLOT(modelThreadChanged())); + connect(ui->UpdateView, SIGNAL(toggled(bool)), this, SLOT(updateViewChanged(bool))); + connect(ui->UseCustomThreadClearance, SIGNAL(toggled(bool)), this, SLOT(useCustomThreadClearanceChanged())); + connect(ui->CustomThreadClearance, SIGNAL(valueChanged(double)), this, SLOT(customThreadClearanceChanged(double))); + connect(ui->ThreadDepthType, SIGNAL(currentIndexChanged(int)), this, SLOT(threadDepthTypeChanged(int))); + connect(ui->ThreadDepth, SIGNAL(valueChanged(double)), this, SLOT(threadDepthChanged(double))); vp->show(); @@ -194,6 +220,8 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole *HoleView, QWidget *pare ui->Depth->bind(pcHole->Depth); ui->DrillPointAngle->bind(pcHole->DrillPointAngle); ui->TaperedAngle->bind(pcHole->TaperedAngle); + ui->ThreadDepth->bind(pcHole->ThreadDepth); + ui->CustomThreadClearance->bind(pcHole->CustomThreadClearance); connectPropChanged = App::GetApplication().signalChangePropertyEditor.connect( boost::bind(&TaskHoleParameters::changedObject, this, bp::_1, bp::_2)); @@ -209,15 +237,83 @@ void TaskHoleParameters::threadedChanged() { PartDesign::Hole* pcHole = static_cast(vp->getObject()); + bool isChecked = ui->Threaded->isChecked(); + pcHole->Threaded.setValue(isChecked); + + ui->ModelThread->setEnabled(isChecked); + ui->ThreadDepthType->setEnabled(isChecked); + + // conditional enabling of thread modeling options + ui->UseCustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked()); + ui->CustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked() && ui->UseCustomThreadClearance->isChecked()); + + updateViewChanged(!(isChecked && ui->ModelThread->isChecked())); + ui->UpdateView->setChecked(!(isChecked && ui->ModelThread->isChecked())); + pcHole->Threaded.setValue(ui->Threaded->isChecked()); recomputeFeature(); } -void TaskHoleParameters::modelActualThreadChanged() +void TaskHoleParameters::modelThreadChanged() +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + bool isChecked = ui->ModelThread->isChecked(); + + pcHole->ModelThread.setValue(isChecked); + + // update view not active if modeling threads + // this will also ensure that the feature is recomputed. + blockUpdate = isChecked; + ui->UpdateView->setChecked(!isChecked); + + // conditional enabling of thread modeling options + ui->UseCustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked()); + ui->CustomThreadClearance->setEnabled(ui->Threaded->isChecked() && ui->ModelThread->isChecked() && ui->UseCustomThreadClearance->isChecked()); + + recomputeFeature(); +} + +void TaskHoleParameters::updateViewChanged(bool isChecked) +{ + blockUpdate = !isChecked; + recomputeFeature(); +} + +void TaskHoleParameters::threadDepthTypeChanged(int index) { PartDesign::Hole* pcHole = static_cast(vp->getObject()); - pcHole->ModelActualThread.setValue(false); + pcHole->ThreadDepthType.setValue(index); + ui->ThreadDepth->setEnabled(index == 1); + ui->ThreadDepth->setValue(pcHole->ThreadDepth.getValue()); + recomputeFeature(); +} + +void TaskHoleParameters::threadDepthChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->ThreadDepth.setValue(value); + recomputeFeature(); +} + +void TaskHoleParameters::useCustomThreadClearanceChanged() +{ + bool isChecked = ui->UseCustomThreadClearance->isChecked(); + ui->CustomThreadClearance->setEnabled(isChecked); + ui->ThreadClass->setDisabled(isChecked); + + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->UseCustomThreadClearance.setValue(isChecked); + recomputeFeature(); +} + +void TaskHoleParameters::customThreadClearanceChanged(double value) +{ + PartDesign::Hole* pcHole = static_cast(vp->getObject()); + + pcHole->CustomThreadClearance.setValue(value); recomputeFeature(); } @@ -229,30 +325,6 @@ void TaskHoleParameters::threadPitchChanged(double value) recomputeFeature(); } -void TaskHoleParameters::threadAngleChanged(double value) -{ - PartDesign::Hole* pcHole = static_cast(vp->getObject()); - - pcHole->ThreadAngle.setValue(value); - recomputeFeature(); -} - -void TaskHoleParameters::threadCutOffInnerChanged(double value) -{ - PartDesign::Hole* pcHole = static_cast(vp->getObject()); - - pcHole->ThreadCutOffInner.setValue(value); - recomputeFeature(); -} - -void TaskHoleParameters::threadCutOffOuterChanged(double value) -{ - PartDesign::Hole* pcHole = static_cast(vp->getObject()); - - pcHole->ThreadCutOffOuter.setValue(value); - recomputeFeature(); -} - void TaskHoleParameters::holeCutTypeChanged(int index) { if (index < 0) @@ -261,7 +333,7 @@ void TaskHoleParameters::holeCutTypeChanged(int index) PartDesign::Hole* pcHole = static_cast(vp->getObject()); // the HoleCutDepth is something different for countersinks and counterbores - // therefore reset it, it will be reset to sensible values by setting the new HoleCutType + // therefore reset it, it will be reset to sensible values by setting the new HoleCutType pcHole->HoleCutDepth.setValue(0.0); // when holeCutType was changed, reset HoleCutCustomValues to false because it should @@ -280,7 +352,7 @@ void TaskHoleParameters::holeCutTypeChanged(int index) ui->HoleCutCustomValues->setChecked(pcHole->HoleCutCustomValues.getValue()); // HoleCutCustomValues is only enabled for screw definitions - // we must do this after recomputeFeature() because this gives us the info if + // we must do this after recomputeFeature() because this gives us the info if // the type is a countersink and thus if HoleCutCountersinkAngle can be enabled std::string HoleCutTypeString = pcHole->HoleCutType.getValueAsString(); if (HoleCutTypeString == "None" || HoleCutTypeString == "Counterbore" @@ -322,7 +394,7 @@ void TaskHoleParameters::holeCutCustomValuesChanged() ui->HoleCutCountersinkAngle->setEnabled(false); } - recomputeFeature(); + recomputeFeature(); } void TaskHoleParameters::holeCutDiameterChanged(double value) @@ -479,11 +551,14 @@ void TaskHoleParameters::threadTypeChanged(int index) // now set the new type, this will reset the comboboxes to item 0 pcHole->ThreadType.setValue(index); + // Threaded checkbox is meaningless if no thread profile is selected. + ui->Threaded->setDisabled(std::string(pcHole->ThreadType.getValueAsString()) == "None"); + // size and clearance if (TypeClass == QByteArray("ISO")) { // the size for ISO type has either the form "M3x0.35" or just "M3" // so we need to check if the size contains a 'x'. If yes, check if the string - // up to the 'x' is exists in the new list + // up to the 'x' is exists in the new list if (ThreadSizeString.indexOf(QString::fromLatin1("x")) > -1) { // we have an ISO fine size // cut of the part behind the 'x' @@ -499,7 +574,7 @@ void TaskHoleParameters::threadTypeChanged(int index) ui->ThreadFit->setItemText(0, QCoreApplication::translate("TaskHoleParameters", "Standard", nullptr)); ui->ThreadFit->setItemText(1, QCoreApplication::translate("TaskHoleParameters", "Close", nullptr)); ui->ThreadFit->setItemText(2, QCoreApplication::translate("TaskHoleParameters", "Wide", nullptr)); - } + } else if (TypeClass == QByteArray("UTS")) { // for all UTS types the size entries are the same int threadSizeIndex = ui->ThreadSize->findText(ThreadSizeString, Qt::MatchContains); @@ -813,6 +888,51 @@ void TaskHoleParameters::changedObject(const App::Document&, const App::Property } ui->TaperedAngle->setDisabled(ro); } + else if (&Prop == &pcHole->ModelThread) { + ui->ModelThread->setEnabled(true); + if (ui->ModelThread->isChecked() ^ pcHole->ModelThread.getValue()) { + ui->ModelThread->blockSignals(true); + ui->ModelThread->setChecked(pcHole->ModelThread.getValue()); + ui->ModelThread->blockSignals(false); + } + ui->ModelThread->setDisabled(ro); + } + else if (&Prop == &pcHole->UseCustomThreadClearance) { + ui->UseCustomThreadClearance->setEnabled(true); + if (ui->UseCustomThreadClearance->isChecked() ^ pcHole->UseCustomThreadClearance.getValue()) { + ui->UseCustomThreadClearance->blockSignals(true); + ui->UseCustomThreadClearance->setChecked(pcHole->UseCustomThreadClearance.getValue()); + ui->UseCustomThreadClearance->blockSignals(false); + } + ui->UseCustomThreadClearance->setDisabled(ro); + } + else if (&Prop == &pcHole->CustomThreadClearance) { + ui->CustomThreadClearance->setEnabled(true); + if (ui->CustomThreadClearance->value().getValue() != pcHole->CustomThreadClearance.getValue()) { + ui->CustomThreadClearance->blockSignals(true); + ui->CustomThreadClearance->setValue(pcHole->CustomThreadClearance.getValue()); + ui->CustomThreadClearance->blockSignals(false); + } + ui->CustomThreadClearance->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadDepthType) { + ui->ThreadDepthType->setEnabled(true); + if (ui->ThreadDepthType->currentIndex() != pcHole->ThreadDepthType.getValue()) { + ui->ThreadDepthType->blockSignals(true); + ui->ThreadDepthType->setCurrentIndex(pcHole->ThreadDepthType.getValue()); + ui->ThreadDepthType->blockSignals(false); + } + ui->ThreadDepthType->setDisabled(ro); + } + else if (&Prop == &pcHole->ThreadDepth) { + ui->ThreadDepth->setEnabled(true); + if (ui->ThreadDepth->value().getValue() != pcHole->ThreadDepth.getValue()) { + ui->ThreadDepth->blockSignals(true); + ui->ThreadDepth->setValue(pcHole->ThreadDepth.getValue()); + ui->ThreadDepth->blockSignals(false); + } + ui->ThreadDepth->setDisabled(ro); + } } void TaskHoleParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -934,6 +1054,31 @@ Base::Quantity TaskHoleParameters::getTaperedAngle() const return ui->TaperedAngle->value(); } +bool TaskHoleParameters::getUseCustomThreadClearance() const +{ + return ui->UseCustomThreadClearance->isChecked(); +} + +double TaskHoleParameters::getCustomThreadClearance() const +{ + return ui->CustomThreadClearance->value().getValue(); +} + +bool TaskHoleParameters::getModelThread() const +{ + return ui->ModelThread->isChecked(); +} + +long TaskHoleParameters::getThreadDepthType() const +{ + return ui->ThreadDepthType->currentIndex(); +} + +double TaskHoleParameters::getThreadDepth() const +{ + return ui->ThreadDepth->value().getValue(); +} + void TaskHoleParameters::apply() { auto obj = vp->getObject(); @@ -951,15 +1096,23 @@ void TaskHoleParameters::apply() if (!pcHole->Threaded.isReadOnly()) FCMD_OBJ_CMD(obj,"Threaded = " << (getThreaded() ? 1 : 0)); - if (!pcHole->ModelActualThread.isReadOnly()) - FCMD_OBJ_CMD(obj,"ModelActualThread = " << (getThreaded() ? 1 : 0)); + if (!pcHole->ModelThread.isReadOnly()) + FCMD_OBJ_CMD(obj,"ModelThread = " << (getModelThread() ? 1 : 0)); + if (!pcHole->ThreadDepthType.isReadOnly()) + FCMD_OBJ_CMD(obj,"ThreadDepthType = " << getThreadDepthType()); + if (!pcHole->ThreadDepth.isReadOnly()) + FCMD_OBJ_CMD(obj,"ThreadDepth = " << getThreadDepth()); + if (!pcHole->UseCustomThreadClearance.isReadOnly()) + FCMD_OBJ_CMD(obj,"UseCustomThreadClearance = " << (getUseCustomThreadClearance() ? 1 : 0) ); + if (!pcHole->CustomThreadClearance.isReadOnly()) + FCMD_OBJ_CMD(obj,"CustomThreadClearance = " << getCustomThreadClearance()); if (!pcHole->ThreadType.isReadOnly()) FCMD_OBJ_CMD(obj,"ThreadType = " << getThreadType()); if (!pcHole->ThreadSize.isReadOnly()) FCMD_OBJ_CMD(obj,"ThreadSize = " << getThreadSize()); if (!pcHole->ThreadClass.isReadOnly()) FCMD_OBJ_CMD(obj,"ThreadClass = " << getThreadClass()); - if (!pcHole->ThreadFit.isReadOnly()) + if (!pcHole->ThreadFit.isReadOnly()) FCMD_OBJ_CMD(obj,"ThreadFit = " << getThreadFit()); if (!pcHole->ThreadDirection.isReadOnly()) FCMD_OBJ_CMD(obj,"ThreadDirection = " << getThreadDirection()); diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.h b/src/Mod/PartDesign/Gui/TaskHoleParameters.h index dc366dc55e..84f55944c4 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.h @@ -47,7 +47,7 @@ namespace PartDesign { class Hole; } -namespace PartDesignGui { +namespace PartDesignGui { @@ -58,7 +58,7 @@ class TaskHoleParameters : public TaskSketchBasedParameters public: TaskHoleParameters(ViewProviderHole *HoleView, QWidget *parent = 0); ~TaskHoleParameters(); - + void apply() override; bool getThreaded() const; @@ -80,6 +80,11 @@ public: bool getDrillForDepth() const; bool getTapered() const; Base::Quantity getTaperedAngle() const; + bool getUseCustomThreadClearance() const; + double getCustomThreadClearance() const; + bool getModelThread() const; + long getThreadDepthType() const; + double getThreadDepth() const; private Q_SLOTS: void threadedChanged(); @@ -87,11 +92,7 @@ private Q_SLOTS: void threadSizeChanged(int index); void threadClassChanged(int index); void threadFitChanged(int index); - void modelActualThreadChanged(); void threadPitchChanged(double value); - void threadCutOffOuterChanged(double value); - void threadCutOffInnerChanged(double value); - void threadAngleChanged(double value); void threadDiameterChanged(double value); void threadDirectionChanged(); void holeCutTypeChanged(int index); @@ -105,8 +106,15 @@ private Q_SLOTS: void drillPointAngledValueChanged(double value); void drillForDepthChanged(); void taperedChanged(); + void taperedAngleChanged(double value); void reversedChanged(); - void taperedAngleChanged(double value); + void modelThreadChanged(); + void useCustomThreadClearanceChanged(); + void customThreadClearanceChanged(double value); + void updateViewChanged(bool isChecked); + void threadDepthTypeChanged(int index); + void threadDepthChanged(double value); + private: class Observer : public App::DocumentObserver { public: diff --git a/src/Mod/PartDesign/Gui/TaskHoleParameters.ui b/src/Mod/PartDesign/Gui/TaskHoleParameters.ui index acb1d821e9..2a0d6c9e98 100644 --- a/src/Mod/PartDesign/Gui/TaskHoleParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskHoleParameters.ui @@ -72,7 +72,91 @@ - + + + + + 0 + 0 + + + + Whether the hole gets a modelled thread + + + Model Thread + + + + + + + true + + + Live update of changes to the thread +Note that the calculation can take some time + + + Update view + + + + + + + + 0 + 0 + + + + Customize thread clearance + + + Custom Thread Clearance + + + + + + + + 0 + 0 + + + + Clearance + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Custom Thread clearance value + + + mm + + + 0.100000000000000 + + + + @@ -88,7 +172,7 @@ - + @@ -107,7 +191,7 @@ - + @@ -123,7 +207,7 @@ - + @@ -136,7 +220,7 @@ - + @@ -152,7 +236,7 @@ - + @@ -165,7 +249,7 @@ - + @@ -200,7 +284,7 @@ Only available for holes without thread - + @@ -213,7 +297,7 @@ Only available for holes without thread - + @@ -232,7 +316,7 @@ Only available for holes without thread - + @@ -245,7 +329,7 @@ Only available for holes without thread - + @@ -270,7 +354,7 @@ Only available for holes without thread - + @@ -283,7 +367,7 @@ Only available for holes without thread - + @@ -309,7 +393,7 @@ Only available for holes without thread - + @@ -322,14 +406,66 @@ Only available for holes without thread - + + + + + 0 + 0 + + + + Thread Depth + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + Automatic + + + + + Dimension + + + + + + + + + 0 + 0 + + + + mm + + + + <b>Hole cut</b> - + @@ -342,7 +478,7 @@ Only available for holes without thread - + @@ -361,7 +497,7 @@ Only available for holes without thread - + @@ -377,7 +513,7 @@ Only available for holes without thread - + @@ -390,7 +526,7 @@ Only available for holes without thread - + @@ -418,7 +554,7 @@ Only available for holes without thread - + @@ -431,7 +567,7 @@ Only available for holes without thread - + @@ -456,7 +592,7 @@ Only available for holes without thread - + @@ -469,7 +605,7 @@ Only available for holes without thread - + @@ -491,7 +627,7 @@ Only available for holes without thread - + @@ -507,7 +643,7 @@ Only available for holes without thread - + @@ -523,7 +659,7 @@ Only available for holes without thread - + @@ -539,7 +675,7 @@ Only available for holes without thread - + @@ -555,7 +691,7 @@ Only available for holes without thread - + @@ -571,7 +707,7 @@ Only available for holes without thread - + @@ -588,14 +724,14 @@ account for the depth of blind holes - + <b>Misc</b> - + @@ -608,7 +744,7 @@ account for the depth of blind holes - + @@ -630,7 +766,7 @@ over 90: larger hole radius at the bottom - +