diff --git a/src/Mod/Arch/importIFCHelper.py b/src/Mod/Arch/importIFCHelper.py index 0ebb2490bf..2ccb49a695 100644 --- a/src/Mod/Arch/importIFCHelper.py +++ b/src/Mod/Arch/importIFCHelper.py @@ -385,6 +385,10 @@ def buildRelProductColors(ifcfile, prodrepr): i = 0 for p in prodrepr.keys(): + # see method getColorFromProduct() + # it is a method for the redundant code inside this loop + # which can be used to get the color from a product directly + # Representation item, see `IfcRepresentationItem` documentation. # All kinds of geometric or topological representation items # `IfcExtrudedAreaSolid`, `IfcMappedItem`, `IfcFacetedBrep`, diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index c07b5c5dea..baf51c6e22 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -80,6 +80,7 @@ SET(FemExamples_SRCS femexamples/equation_flow_elmer_2D.py femexamples/equation_flux_elmer.py femexamples/equation_magnetodynamics_elmer.py + femexamples/equation_magnetodynamics_2D_elmer.py femexamples/frequency_beamsimple.py femexamples/manager.py femexamples/material_multiple_bendingbeam_fiveboxes.py diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp index cbe1f2c122..81f4271ce5 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp @@ -712,7 +712,7 @@ bool ViewProviderFemPostObject::setupPipeline() addAbsoluteField(dset, FieldName); } - m_outline->SetInputData(dset); + m_outline->SetInputData(dset); m_points->SetInputData(dset); m_wireframe->SetInputData(dset); diff --git a/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py new file mode 100644 index 0000000000..0cfe04f4da --- /dev/null +++ b/src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py @@ -0,0 +1,279 @@ +# *************************************************************************** +# * Copyright (c) 2023 Uwe Stöhr * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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 * +# * * +# *************************************************************************** + +import sys +import FreeCAD +from FreeCAD import Placement +from FreeCAD import Rotation +from FreeCAD import Vector + +import Draft +import ObjectsFem +import Part + +from BOPTools import SplitFeatures +from . import manager +from .manager import get_meshname +from .manager import init_doc + +def get_information(): + return { + "name": "Inductive heating - Elmer 2D", + "meshtype": "solid", + "meshelement": "Tet10", + "constraints": ["current density"], + "solvers": ["elmer"], + "material": "solid", + "equations": ["magnetodynamic"] + } + +def get_explanation(header=""): + return header + """ + +To run the example from Python console use: +from femexamples.equation_magnetodynamics_2D_elmer import setup +setup() + +Magnetodynamic2D equation - Elmer solver + +""" + +def setup(doc=None, solvertype="elmer"): + + # init FreeCAD document + if doc is None: + doc = init_doc() + + # explanation object + # just keep the following line and change text string in get_explanation method + manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information()))) + + # geometric objects + + # wire defining the insulation area + p1 = Vector(0.0, 0.0, 0.0) + p2 = Vector(40.0, 0, 0.0) + p3 = Vector(40.0, 120.0, 0.0) + p4 = Vector(0.0, 120.0, 0.0) + p5 = Vector(0.0, 100.0, 0.0) + p6 = Vector(25.0, 100.0, 0.0) + p7 = Vector(25.0, 20.0, 0.0) + p8 = Vector(0.0, 20.0, 0.0) + Insulation = Draft.make_wire([p1, p2, p3, p4, p5, p6, p7, p8], closed=True) + Insulation.Label = "Insulation" + Insulation.ViewObject.Visibility = False + + # wire defining the coil volume + p1 = Vector(50.0, -10.0, 0.0) + p2 = Vector(55.0, -10, 0.0) + p3 = Vector(55.0, 110.0, 0.0) + p4 = Vector(50.0, 110.0, 0.0) + Coil = Draft.make_wire([p1, p2, p3, p4], closed=True) + Coil.Label = "Coil" + Coil.ViewObject.Visibility = False + + # wire defining the crucible area + p1 = Vector(0.0, 20.0, 0.0) + p2 = Vector(25.0, 20, 0.0) + p3 = Vector(25.0, 100.0, 0.0) + p4 = Vector(0.0, 100.0, 0.0) + p5 = Vector(0.0, 90.0, 0.0) + p6 = Vector(20.0, 90.0, 0.0) + p7 = Vector(20.0, 30.0, 0.0) + p8 = Vector(0.0, 30.0, 0.0) + Crucible = Draft.make_wire([p1, p2, p3, p4, p5, p6, p7, p8], closed=True) + Crucible.Label = "Crucible" + Crucible.ViewObject.Visibility = False + + # wire defining the powder volume + p1 = Vector(0.0, 30.0, 0.0) + p2 = Vector(20.0, 30.0, 0.0) + p3 = Vector(20.0, 40.0, 0.0) + p4 = Vector(0.0, 40.0, 0.0) + Powder = Draft.make_wire([p1, p2, p3, p4], closed=True) + Powder.Label = "Powder" + Powder.ViewObject.Visibility = False + + # a half circle defining later the air volume + Air_Circle =Part.makeCircle( + 140.0, Vector(0.0, 60.0, 0.0), Vector(0.0, 0.0, 1.0), -90.0, 90.0) + Air_Line = Part.makeLine((0.0, -80.0, 0.0), (0.0, 200.0, 0.0)) + Air_Area = doc.addObject("Part::Feature", "Air_Area") + Air_Area.Shape = Part.Face([Part.Wire([Air_Circle, Air_Line])]) + + # a link of the Insulation + InsulationLink = doc.addObject("App::Link", "Link_Insulation") + InsulationLink.LinkTransform = True + InsulationLink.LinkedObject = Insulation + InsulationLink.ViewObject.Visibility = False + + # a link of the Coil + CoilLink = doc.addObject("App::Link", "Link_Coil") + CoilLink.LinkTransform = True + CoilLink.LinkedObject = Coil + CoilLink.ViewObject.Visibility = False + + # a link of the Crucible + CrucibleLink = doc.addObject("App::Link", "Link_Crucible") + CrucibleLink.LinkTransform = True + CrucibleLink.LinkedObject = Crucible + CrucibleLink.ViewObject.Visibility = False + + # a link of the Powder + PowderLink = doc.addObject("App::Link", "Link_Powder") + PowderLink.LinkTransform = True + PowderLink.LinkedObject = Powder + PowderLink.ViewObject.Visibility = False + + # fusion of all links + Fusion = doc.addObject("Part::MultiFuse", "Fusion") + Fusion.Shapes = [InsulationLink, CoilLink, CrucibleLink, PowderLink] + Fusion.ViewObject.Visibility = False + + # cut all objects from Air wire to get volume of fluid + Cut = doc.addObject("Part::Cut", "Cut_Air") + Cut.Base = Air_Area + Cut.Tool = Fusion + Cut.ViewObject.Visibility = False + + # BooleanFregments object to combine cut with rod + BooleanFragments = SplitFeatures.makeBooleanFragments(name="BooleanFragments") + BooleanFragments.Objects = [Insulation, Coil, Crucible, Powder, Cut] + + # set view + doc.recompute() + if FreeCAD.GuiUp: + BooleanFragments.ViewObject.Document.activeView().viewTop() + BooleanFragments.ViewObject.Document.activeView().fitAll() + + # analysis + analysis = ObjectsFem.makeAnalysis(doc, "Analysis") + if FreeCAD.GuiUp: + import FemGui + FemGui.setActiveAnalysis(analysis) + + # solver + if solvertype == "elmer": + solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer") + solver_obj.CoordinateSystem = "Axi Symmetric" + equation_magnetodynamic2D = ObjectsFem.makeEquationMagnetodynamic2D(doc, solver_obj) + equation_magnetodynamic2D.AngularFrequency = "50 kHz" + equation_magnetodynamic2D.CalculateCurrentDensity = True + equation_magnetodynamic2D.CalculateElectricField = True + equation_magnetodynamic2D.CalculateJouleHeating = True + equation_magnetodynamic2D.IsHarmonic = True + else: + FreeCAD.Console.PrintWarning( + "Not known or not supported solver type: {}. " + "No solver object was created.\n".format(solvertype) + ) + return doc + analysis.addObject(solver_obj) + + # materials + + # air around the objects and inside the coil + material_obj = ObjectsFem.makeMaterialFluid(doc, "Air") + mat = material_obj.Material + mat["Name"] = "Air" + mat["Density"] = "1.204 kg/m^3" + mat["ThermalConductivity"] = "0.02587 W/m/K" + mat["ThermalExpansionCoefficient"] = "0.00343/K" + mat["SpecificHeat"] = "1010.00 J/kg/K" + mat["ElectricalConductivity"] = "1e-12 S/m" + mat["RelativePermeability"] = "1.0" + mat["RelativePermittivity"] = "1.00059" + material_obj.Material = mat + material_obj.References = [ + (BooleanFragments, "Face2"), + (BooleanFragments, "Face5"), + (BooleanFragments, "Face6")] + analysis.addObject(material_obj) + + # graphite of the crucible + material_obj = ObjectsFem.makeMaterialSolid(doc, "Material-Crucible") + mat = material_obj.Material + mat["Name"] = "Graphite" + mat["ElectricalConductivity"] = "2e4 S/m" + mat["RelativePermeability"] = "1.0" + material_obj.Material = mat + material_obj.References = [(BooleanFragments, "Face3")] + analysis.addObject(material_obj) + + # insulation of the crucible + material_obj = ObjectsFem.makeMaterialSolid(doc, "Material-Insulation") + mat = material_obj.Material + mat["Name"] = "Insulation" + mat["ElectricalConductivity"] = "2.0e3 S/m" + mat["RelativePermeability"] = "1.0" + material_obj.Material = mat + material_obj.References = [(BooleanFragments, "Face1")] + analysis.addObject(material_obj) + + # mmaterial of powder + material_obj = ObjectsFem.makeMaterialSolid(doc, "Material-Powder") + mat = material_obj.Material + mat["Name"] = "Powder" + mat["ElectricalConductivity"] = "1e4 S/m" + mat["RelativePermeability"] = "1.0" + material_obj.Material = mat + material_obj.References = [(BooleanFragments, "Face4")] + analysis.addObject(material_obj) + + # constraint inlet velocity + CurrentDensity = ObjectsFem.makeConstraintCurrentDensity(doc, "CurrentDensity") + CurrentDensity.References = [(BooleanFragments, "Face2")] + CurrentDensity.CurrentDensity_re_1 = "250000.000 A/m^2" + CurrentDensity.CurrentDensity_re_1_Disabled = False + analysis.addObject(CurrentDensity) + + # mesh + femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] + femmesh_obj.Part = BooleanFragments + femmesh_obj.CharacteristicLengthMax = "3 mm" + femmesh_obj.ViewObject.Visibility = False + + # mesh_region + mesh_region = ObjectsFem.makeMeshRegion(doc, femmesh_obj, name="MeshRegion") + mesh_region.CharacteristicLength = "1 mm" + mesh_region.References = [ + (BooleanFragments, "Face1"), + (BooleanFragments, "Face2"), + (BooleanFragments, "Face3"), + (BooleanFragments, "Face4")] + mesh_region.ViewObject.Visibility = False + + # generate the mesh + from femmesh import gmshtools + gmsh_mesh = gmshtools.GmshTools(femmesh_obj, analysis) + try: + error = gmsh_mesh.create_mesh() + except Exception: + error = sys.exc_info()[1] + FreeCAD.Console.PrintError( + "Unexpected error when creating mesh: {}\n" + .format(error) + ) + + doc.recompute() + return doc diff --git a/src/Mod/Fem/femexamples/manager.py b/src/Mod/Fem/femexamples/manager.py index 1b72f456ee..ab0cce0cdf 100644 --- a/src/Mod/Fem/femexamples/manager.py +++ b/src/Mod/Fem/femexamples/manager.py @@ -73,6 +73,7 @@ def run_all(): run_example("equation_flow_elmer_2D", run_solver=True) run_example("equation_flux_elmer", run_solver=True) run_example("equation_magnetodynamics_elmer", run_solver=True) + run_example("equation_magnetodynamics_2D_elmer.py", run_solver=True) run_example("frequency_beamsimple", run_solver=True) run_example("material_multiple_bendingbeam_fiveboxes", run_solver=True) run_example("material_multiple_bendingbeam_fivefaces", run_solver=True) @@ -108,6 +109,7 @@ def setup_all(): run_example("equation_flow_elmer_2D") run_example("equation_flux_elmer") run_example("equation_magnetodynamics_elmer") + run_example("equation_magnetodynamics_2D_elmer.py") run_example("frequency_beamsimple") run_example("material_multiple_bendingbeam_fiveboxes") run_example("material_multiple_bendingbeam_fivefaces") diff --git a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py index 50965ccaad..bef00351b1 100644 --- a/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py +++ b/src/Mod/Fem/femexamples/truss_3d_cs_circle_ele_seg3.py @@ -93,7 +93,7 @@ def setup(doc=None, solvertype="ccxtools"): if FreeCAD.GuiUp: load_line.ViewObject.hide() - # commands where generated by Python out of the original Z88 Mesh obj data + # commands were generated by Python out of the original Z88 Mesh obj data v1 = vec(0.0, 2000.0, 0.0) v2 = vec(0.0, 0.0, 0.0) v3 = vec(1000.0, 1000.0, 2000.0) @@ -408,7 +408,7 @@ def setup(doc=None, solvertype="ccxtools"): solver_obj = ObjectsFem.makeSolverZ88(doc, "SolverZ88") else: FreeCAD.Console.PrintWarning( - "Not known or not supported solver type: {}. " + "Unknown or unsupported solver type: {}. " "No solver object was created.\n".format(solvertype) ) if solvertype == "calculix" or solvertype == "ccxtools": diff --git a/src/Mod/Fem/femtaskpanels/task_material_common.py b/src/Mod/Fem/femtaskpanels/task_material_common.py index dde7cd7a6d..562b0a4b21 100644 --- a/src/Mod/Fem/femtaskpanels/task_material_common.py +++ b/src/Mod/Fem/femtaskpanels/task_material_common.py @@ -260,13 +260,43 @@ class _TaskPanel: "This parameter is not saved in the material data.\n" ) + def isfloat(self, num): + try: + float(num) + return True + except ValueError: + return False + # choose material **************************************************************************** def get_material_card(self, material): for a_mat in self.materials: # check if every item of the current material fits to a known material card # if all items were found we know it is the right card - unmatched_items = set(self.materials[a_mat].items()) ^ set(material.items()) - if len(unmatched_items) == 0: + # we can hereby not simply perform + # set(self.materials[a_mat].items()) ^ set(material.items()) + # because entries are often identical, just appear in the set in a different order + unmatched_item = False + for item in material.items(): + if item not in self.materials[a_mat].items(): + unmatched_item = True + # often the difference is just a decimal e.g. "120" to "120.0" + # therefore first check if the item name exists + for a_mat_item in self.materials[a_mat].items(): + if item[0] == a_mat_item[0]: + # now check if we have a number value in a unit + if item[1].split() != item[1]: + if not self.isfloat(item[1].split()[0]): + break + if float(item[1].split()[0]) == float(a_mat_item[1].split()[0]): + unmatched_item = False + else: + # it can be a unitless number + if not self.isfloat(item[1]): + break + if float(item[1]) == float(a_mat_item[1]): + unmatched_item = False + break + if not unmatched_item: return a_mat return "" diff --git a/src/Mod/Material/CMakeLists.txt b/src/Mod/Material/CMakeLists.txt index 890cb645bb..5ab4131956 100644 --- a/src/Mod/Material/CMakeLists.txt +++ b/src/Mod/Material/CMakeLists.txt @@ -181,7 +181,7 @@ fc_target_copy_resource(MaterialToolsLib ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/Mod/Material ${MaterialTools_Files}) - + fc_target_copy_resource(MaterialIconsLib ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/Mod/Material diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index a3b05b6945..1b79561f75 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -25,6 +25,7 @@ __author__ = "Yorik van Havre, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" import os +import sys from PySide import QtCore, QtGui, QtSvg import FreeCAD @@ -617,6 +618,8 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate): def __init__(self): "" + self.matproperty = "" + self.Value = "" super(MaterialsDelegate, self).__init__() def createEditor(self, parent, option, index): @@ -635,7 +638,7 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate): row = index.row() PP = group.child(row, 0) - matproperty = PP.text().replace(" ", "") # remove spaces + self.matproperty = PP.text().replace(" ", "") # remove spaces TT = group.child(row, 2) if TT: @@ -644,9 +647,9 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate): Type = "String" VV = group.child(row, 1) - Value = VV.text() + self.Value = VV.text() - editor = matProperWidget(parent, matproperty, Type, Value) + editor = matProperWidget(parent, self.matproperty, Type, self.Value) elif column == 0: if group.text() == "User defined": @@ -676,11 +679,39 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate): lineEdit = editor.children()[1] item.setText(lineEdit.text()) + elif Type == "Float": + # avoid rounding artifacts + inputValue = float('%.6g' % editor.value()) + item.setText(str(inputValue)) + + elif Type == "Quantity": + if not hasattr(FreeCAD.Units, self.matproperty): + FreeCAD.Console.PrintError( + "Error: property '{}' is a quantity but has no unit defined\n" + .format(self.matproperty) + ) + return + # we must use the unit of the input value because the + # "Gui::QuantitySpinBox" uses e.g. for the density always the mm-based unit + # kg/mm^3, also when the input value is in kg/^3. + # E.g. when the input is e.g. "7875 kg/m^3" and we would pass "7875" as rawValue + # and "kg/m^3" as unit, we would get "7875 kg/mm^3" as result. If we try to be + # clever and input "7875e-6" as rawValue and "kg/m^3" as unit we get + # "7875e-6 kg/m^3" as result. If we input "7875e-6" as rawValue and "kg/mm^3" + # as unit we get also "7875e-6 kg/m^3" as result. + if not self.Value: + # for empty (not yet set properties) we use the matproperty unit + unit = getattr(FreeCAD.Units, self.matproperty) + quantity = FreeCAD.Units.Quantity(1, unit) + item.setText(str(editor.value()) + " " + quantity.getUserPreferred()[2]) + else: + # since we checked we have a quantity, we can use split() to get the unit + item.setText(str(editor.value()) + " " + self.Value.split()[1]) + else: super(MaterialsDelegate, self).setEditorData(editor, index) - # ************************************************************************************************ # ************************************************************************************************ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None, @@ -715,9 +746,26 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None, lineEdit.setText(Value) elif Type == "Quantity": - widget = ui.createWidget("Gui::InputField") + # We don't use a Gui::QuantitySpinBox widget because depending on the value, + # the unit might change. For some inputs there is no way to do this right, + # see the comment above in "def setEditorData". Moreover it is error-prone to provide + # a unit as in the Gui::QuantitySpinBox widget because users likely delete the unit or + # change it accidentally. It is therefore better not to display the unit while editing. + widget = ui.createWidget("Gui::DoubleSpinBox") + + if minimum is None: + widget.setMinimum(-1*sys.float_info.max) + else: + widget.setMinimum(minimum) + if maximum is None: + widget.setMaximum(sys.float_info.max) + else: + widget.setMaximum(maximum) + + # we must increase the digits before we can set the value + # 6 is sufficient as some metarial cards use e.g. "0.000011" + widget.setDecimals(6) - # set quantity if possible # for properties with an underscored number (vectorial values), # we must strip the part after the first underscore to obtain the bound unit # since in cardutils.py in def get_material_template @@ -727,30 +775,36 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None, matpropertyNum = matproperty.rstrip('0123456789') matproperty = matpropertyNum - if hasattr(FreeCAD.Units, matproperty): - unit = getattr(FreeCAD.Units, matproperty) - quantity = FreeCAD.Units.Quantity(1, unit) - widget.setProperty("unit", quantity.getUserPreferred()[2]) - else: - FreeCAD.Console.PrintWarning( - "Not known unit for property: {}. Probably the Quantity does not have a unit.\n" - .format(matproperty) - ) + if Value: + widget.setValue(float(Value.split()[0])) elif Type == "Integer": widget = ui.createWidget("Gui::UIntSpinBox") + if minimum is None: + widget.setMinimum(0) + else: + widget.setMinimum(minimum) + if maximum is None: + widget.setMaximum(sys.maxsize) + else: + widget.setMaximum(maximum) elif Type == "Float": - widget = ui.createWidget("Gui::PrefDoubleSpinBox") + widget = ui.createWidget("Gui::DoubleSpinBox") # the magnetic permeability is the parameter for which many decimals matter # the most however, even for this, 6 digits are sufficient widget.setDecimals(6) # for almost all Float parameters of materials a step of 1 would be too large widget.setSingleStep(0.1) if minimum is None: - widget.setProperty("minimum", -1e12) + widget.setMinimum(sys.float_info.min) + else: + widget.setMinimum(minimum) if maximum is None: - widget.setProperty("maximum", 1e12) + widget.setMaximum(sys.float_info.max) + else: + widget.setMaximum(maximum) + widget.setValue(float(Value)) elif Type == "Enumerator": widget = ui.createWidget("Gui::PrefComboBox") @@ -773,15 +827,6 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None, else: widget = QtGui.QLineEdit() - if minimum is not None: - widget.setProperty("minimum", minimum) - if maximum is not None: - widget.setProperty("maximum", maximum) - if stepsize is not None: - widget.setProperty("stepsize", stepsize) - if precision is not None: - widget.setProperty("precision", precision) - widget.setProperty("Type", Type) widget.setParent(parent) diff --git a/src/Mod/PartDesign/PartDesignTests/TestInvoluteGear.py b/src/Mod/PartDesign/PartDesignTests/TestInvoluteGear.py index 2dfdbb6d71..a732c5e449 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestInvoluteGear.py +++ b/src/Mod/PartDesign/PartDesignTests/TestInvoluteGear.py @@ -125,7 +125,7 @@ class TestInvoluteGear(unittest.TestCase): root_diameter = pitch_diameter + 2 * ded_coef * m # the test purpose here is just to ensure the gear's parameters are used, # not super precise profile verification. Thus a lax delta is just file here. - delta = 0.1 # FIXME it seems that the top land arc is in the wrong direction, thus a larger tolerance. + delta = 0.01 self.assertIntersection(hub.Shape, makeCircle(pitch_diameter/2), "Expecting intersection at pitch circle") self.assertNoIntersection(hub.Shape, makeCircle(tip_diameter/2 - delta), "Teeth extent below tip circle") self.assertNoIntersection(hub.Shape, makeCircle(root_diameter/2 + delta), "Teeth extend beyond root circle") diff --git a/src/Mod/PartDesign/fcgear/involute.py b/src/Mod/PartDesign/fcgear/involute.py index d749f4b930..4bbafde3d5 100644 --- a/src/Mod/PartDesign/fcgear/involute.py +++ b/src/Mod/PartDesign/fcgear/involute.py @@ -312,11 +312,7 @@ def CreateInternalGear(w, m, Z, phi, if (not tipWithinInvolute): w.line(tip) # line from tip down to base circle - if split: - w.arc(tipR, Ra, 0) # arc across addendum circle - else: - #w.arc(tipR[-1], Ra, 0) # arc across addendum circle - w.arc(tipR, Ra, 0) + w.arc(tipR, Ra, 1) # arc across addendum circle if (not tipWithinInvolute): w.line(invR[0]) # line up to the base circle @@ -329,7 +325,7 @@ def CreateInternalGear(w, m, Z, phi, if (rootNext[1] > rootR[1]): # is there a section of root circle between fillets? w.arc(rootR, fRad, 1) # back fillet - w.arc(rootNext, Rroot, 0) # root circle arc + w.arc(rootNext, Rroot, 1) # root circle arc w.arc(filletNext, fRad, 1) diff --git a/src/Mod/Start/StartPage/LoadMRU.py b/src/Mod/Start/StartPage/LoadMRU.py index 35db24c7d8..95421f095e 100644 --- a/src/Mod/Start/StartPage/LoadMRU.py +++ b/src/Mod/Start/StartPage/LoadMRU.py @@ -32,4 +32,3 @@ FreeCADGui.loadFile(filename, mod) from StartPage import StartPage StartPage.postStart() -