# *************************************************************************** # * Copyright (c) 2023 edi * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program 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 program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** """Provides the TechDraw HoleShaftFit Task Dialog.""" __title__ = "TechDrawTools.TaskHoleShaftFit" __author__ = "edi" __url__ = "https://www.freecad.org" __version__ = "00.01" __date__ = "2023/02/07" import FreeCAD as App import FreeCADGui as Gui from functools import partial import os translate = App.Qt.translate class TaskHoleShaftFit: def __init__(self, sel): loose = translate("TechDraw_HoleShaftFit", "loose fit") snug = translate("TechDraw_HoleShaftFit", "snug fit") press = translate("TechDraw_HoleShaftFit", "press fit") self.isHole = True self.sel = sel self.holeValues = [ ["h9", "D10", loose], ["h9", "E9", loose], ["h9", "F8", loose], ["h6", "G7", loose], ["c11", "H11", loose], ["f7", "H8", loose], ["h6", "H7", loose], ["h7", "H8", loose], ["k6", "H7", snug], ["n6", "H7", snug], ["r6", "H7", press], ["s6", "H7", press], ["h6", "K7", snug], ["h6", "N7", snug], ["h6", "R7", press], ["h6", "S7", press], ] self.shaftValues = [ ["H11", "c11", loose], ["H8", "f7", loose], ["H7", "h6", loose], ["H8", "h7", loose], ["D10", "h9", loose], ["E9", "h9", loose], ["F8", "h9", loose], ["G7", "h6", loose], ["K7", "h6", snug], ["N7", "h6", snug], ["R7", "h6", press], ["S7", "h6", press], ["H7", "k6", snug], ["H7", "n6", snug], ["H7", "r6", press], ["H7", "s6", press], ] self._uiPath = App.getHomePath() self._uiPath = os.path.join( self._uiPath, "Mod/TechDraw/TechDrawTools/Gui/TaskHoleShaftFit.ui" ) self.form = Gui.PySideUic.loadUi(self._uiPath) self.form.setWindowTitle( translate("TechDraw_HoleShaftFit", "Hole / Shaft Fit ISO 286") ) self.form.rbHoleBase.clicked.connect(partial(self.on_HoleShaftChanged, True)) self.form.rbShaftBase.clicked.connect(partial(self.on_HoleShaftChanged, False)) self.form.cbField.currentIndexChanged.connect(self.on_FieldChanged) def setHoleFields(self): """set hole fields in the combo box""" for i in range(self.form.cbField.count()): self.form.cbField.removeItem(0) for value in self.holeValues: self.form.cbField.addItem(value[1]) self.form.lbBaseField.setText(" " + self.holeValues[0][0] + " /") self.form.lbFitType.setText(self.holeValues[0][2]) def setShaftFields(self): """set shaft fields in the combo box""" for i in range(self.form.cbField.count()): self.form.cbField.removeItem(0) for value in self.shaftValues: self.form.cbField.addItem(value[1]) self.form.lbBaseField.setText(" " + self.shaftValues[0][0] + " /") self.form.lbFitType.setText(self.shaftValues[0][2]) def on_HoleShaftChanged(self, isHole): """slot: change the used base fit hole/shaft""" if isHole: self.isHole = isHole self.setShaftFields() else: self.isHole = isHole self.setHoleFields() def on_FieldChanged(self): """slot: change of the desired field""" currentIndex = self.form.cbField.currentIndex() if self.isHole: self.form.lbBaseField.setText( " " + self.shaftValues[currentIndex][0] + " /" ) self.form.lbFitType.setText(self.shaftValues[currentIndex][2]) else: self.form.lbBaseField.setText( " " + self.holeValues[currentIndex][0] + " /" ) self.form.lbFitType.setText(self.holeValues[currentIndex][2]) def accept(self): """slot: OK pressed""" currentIndex = self.form.cbField.currentIndex() if self.isHole: selectedField = self.shaftValues[currentIndex][1] else: selectedField = self.holeValues[currentIndex][1] fieldChar = selectedField[0] quality = int(selectedField[1:]) dim = self.sel[0].Object value = dim.getRawValue() iso = ISO286() iso.calculate(value, fieldChar, quality) rangeValues = iso.getValues() mainFormat = dim.FormatSpec dim.FormatSpec = mainFormat + " " + selectedField dim.EqualTolerance = False dim.OverTolerance = rangeValues[0] dim.UnderTolerance = rangeValues[1] if dim.OverTolerance < 0: dim.FormatSpecOverTolerance = "(%-0.6w)" elif dim.OverTolerance > 0: dim.FormatSpecOverTolerance = "(+%-0.6w)" else: dim.FormatSpecOverTolerance = "( %-0.6w)" if dim.UnderTolerance < 0: dim.FormatSpecUnderTolerance = "(%-0.6w)" elif dim.UnderTolerance > 0: dim.FormatSpecUnderTolerance = "(+%-0.6w)" else: dim.FormatSpecUnderTolerance = "( %-0.6w)" Gui.Control.closeDialog() def reject(self): return True class ISO286: """This class represents a subset of the ISO 286 standard""" def getNominalRange(self, measureValue): """return index of selected nominal range field, 0 < measureValue < 500 mm""" measureRanges = [ 0, 3, 6, 10, 14, 18, 24, 30, 40, 50, 65, 80, 100, 120, 140, 160, 180, 200, 225, 250, 280, 315, 355, 400, 450, 500, ] index = 1 while measureValue > measureRanges[index]: index = index + 1 return index - 1 def getITValue(self, valueQuality, valueNominalRange): """return IT-value (value of quality in micrometers)""" """tables IT6 to IT11 from 0 to 500 mm""" IT6 = [ 6, 8, 9, 11, 11, 13, 13, 16, 16, 19, 19, 22, 22, 25, 25, 25, 29, 29, 29, 32, 32, 36, 36, 40, 40, ] IT7 = [ 10, 12, 15, 18, 18, 21, 21, 25, 25, 30, 30, 35, 35, 40, 40, 40, 46, 46, 46, 52, 52, 57, 57, 63, 63, ] IT8 = [ 14, 18, 22, 27, 27, 33, 33, 39, 39, 46, 46, 54, 54, 63, 63, 63, 72, 72, 72, 81, 81, 89, 89, 97, 97, ] IT9 = [ 25, 30, 36, 43, 43, 52, 52, 62, 62, 74, 74, 87, 87, 100, 100, 100, 115, 115, 115, 130, 130, 140, 140, 155, 155, ] IT10 = [ 40, 48, 58, 70, 70, 84, 84, 100, 100, 120, 120, 140, 140, 160, 160, 160, 185, 185, 185, 210, 210, 230, 230, 250, 250, ] IT11 = [ 60, 75, 90, 110, 110, 130, 130, 160, 160, 190, 190, 220, 220, 250, 250, 250, 290, 290, 290, 320, 320, 360, 360, 400, 400, ] qualityTable = [IT6, IT7, IT8, IT9, IT10, IT11] return qualityTable[valueQuality - 6][valueNominalRange] def getFieldValue(self, fieldCharacter, valueNominalRange): """return es or ES value of the field in micrometers""" cField = [ -60, -70, -80, -95, -95, -110, -110, -120, -130, -140, -150, -170, -180, -200, -210, -230, -240, -260, -280, -300, -330, -360, -400, -440, -480, ] fField = [ -6, -10, -13, -16, -16, -20, -20, -25, -25, -30, -30, -36, -36, -43, -43, -43, -50, -50, -50, -56, -56, -62, -62, -68, -68, ] gField = [ -2, -4, -5, -6, -6, -7, -7, -9, -9, -10, -10, -12, -12, -14, -14, -14, -15, -15, -15, -17, -17, -18, -18, -20, -20, ] hField = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] kField = [ 6, 9, 10, 12, 12, 15, 15, 18, 18, 21, 21, 25, 25, 28, 28, 28, 33, 33, 33, 36, 36, 40, 40, 45, 45, ] nField = [ 10, 16, 19, 23, 23, 28, 28, 33, 33, 39, 39, 45, 45, 52, 52, 60, 60, 66, 66, 73, 73, 80, 80, ] rField = [ 16, 23, 28, 34, 34, 41, 41, 50, 50, 60, 62, 73, 76, 88, 90, 93, 106, 109, 113, 126, 130, 144, 150, 166, 172, ] sField = [ 20, 27, 32, 39, 39, 48, 48, 59, 59, 72, 78, 93, 101, 117, 125, 133, 151, 159, 169, 190, 202, 226, 244, 272, 292, ] DField = [ 60, 78, 98, 120, 120, 149, 149, 180, 180, 220, 220, 260, 260, 305, 305, 305, 355, 355, 355, 400, 400, 440, 440, 480, 480, ] EField = [ 39, 50, 61, 75, 75, 92, 92, 112, 112, 134, 134, 159, 159, 185, 185, 185, 215, 215, 215, 240, 240, 265, 265, 290, 290, ] FField = [ 20, 28, 35, 43, 43, 53, 53, 64, 64, 76, 76, 90, 90, 106, 106, 106, 122, 122, 122, 137, 137, 151, 151, 165, 165, ] GField = [ 12, 16, 20, 24, 24, 28, 28, 34, 34, 40, 40, 47, 47, 54, 54, 54, 61, 61, 61, 69, 69, 75, 75, 83, 83, ] HField = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] KField = [ 0, 3, 5, 6, 6, 6, 6, 7, 7, 9, 9, 10, 10, 12, 12, 12, 13, 13, 13, 16, 16, 17, 17, 18, 18, ] NField = [ -4, -4, -4, -5, -5, -7, -7, -8, -8, -9, -9, -10, -10, -12, -12, -12, -14, -14, -14, -14, -14, -16, -16, -17, -17, ] RField = [ -10, -11, -13, -16, -16, -20, -20, -25, -25, -30, -32, -38, -41, -48, -50, -53, -60, -63, -67, -74, -78, -87, -93, -103, -109, ] SField = [ -14, -15, -17, -21, -21, -27, -27, -34, -34, -42, -48, -58, -66, -77, -85, -93, -105, -113, -123, -138, -150, -169, -187, -209, -229, ] fieldDict = { "c": cField, "f": fField, "g": gField, "h": hField, "k": kField, "n": nField, "r": rField, "s": sField, "D": DField, "E": EField, "F": FField, "G": GField, "H": HField, "K": KField, "N": NField, "R": RField, "S": SField, } return fieldDict[fieldCharacter][valueNominalRange] def calculate(self, value, fieldChar, quality): """calculate upper and lower field values""" self.nominalRange = self.getNominalRange(value) self.upperValue = self.getFieldValue(fieldChar, self.nominalRange) self.lowerValue = self.upperValue - self.getITValue(quality, self.nominalRange) if fieldChar == "H": self.upperValue = -self.lowerValue self.lowerValue = 0 def getValues(self): """return range values in mm""" return (self.upperValue / 1000, self.lowerValue / 1000)