Merge branch 'FreeCAD:master' into master
This commit is contained in:
@@ -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`,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
279
src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py
Normal file
279
src/Mod/Fem/femexamples/equation_magnetodynamics_2D_elmer.py
Normal file
@@ -0,0 +1,279 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2023 Uwe Stöhr <uwestoehr@lyx.org> *
|
||||
# * *
|
||||
# * 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
|
||||
@@ -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")
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -32,4 +32,3 @@ FreeCADGui.loadFile(filename, mod)
|
||||
|
||||
from StartPage import StartPage
|
||||
StartPage.postStart()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user