diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8cd42cb6d30b..e0b7715759a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ The FreeCAD Contribution Process is expressed here with the following specific g 1. FreeCAD uses the git distributed revision control system. 2. Source code for the main application and related subprojects is hosted on github.com in the FreeCAD organization. 3. Problems are discrete, well-defined limitations or bugs. -4. FreeCAD uses GitHub's issue-tracking system to track problems and contributions. For help requests and general discussions, use the project forum. +4. FreeCAD uses GitHub's issue-tracking system to track problems and contributions. For help requests and general discussions, use the project forum. 5. Contributions are sets of code changes that resolve a single problem. 6. FreeCAD uses the Pull Request workflow for evaluating and accepting contributions. @@ -47,7 +47,7 @@ The FreeCAD Contribution Process is expressed here with the following specific g ## 5. Contribution Requirements 1. Contributions are submitted in the form of Pull Requests (PR). -2. Maintainers and Contributors MUST have a GitHub account and SHOULD use their real names or a well-known alias. +2. Maintainers and Contributors MUST have a GitHub account and SHOULD use their real names or a well-known alias. 3. If the GitHub username differs from the username on the FreeCAD Forum, effort SHOULD be taken to avoid confusion. 4. A PR SHOULD be a minimal and accurate answer to exactly one identified and agreed-on problem. 5. A PR SHOULD refrain from adding additional dependencies to the FreeCAD project unless no other option is available. diff --git a/SECURITY.md b/SECURITY.md index 9ef7934974cd..b46dbc691d35 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,18 +1,18 @@ # Security Policy -The FreeCAD project is a FOSS (Free and Open-Source Software) project that has a community of thousands of users and +The FreeCAD project is a FOSS (Free and Open-Source Software) project that has a community of thousands of users and hundreds of developers worldwide. We encourage responsible reporting of security vulnerabilities that may affect users of this software, and will endeavor to address these vulnerabilities when they are discovered. ## Bounties -FreeCAD does not have a program to pay bounties for security bugs. If you discover a vulnerability that affects a part -of the FreeCAD project (either directly in FreeCAD, in a library it depends on, or in any of the various other +FreeCAD does not have a program to pay bounties for security bugs. If you discover a vulnerability that affects a part +of the FreeCAD project (either directly in FreeCAD, in a library it depends on, or in any of the various other subprojects such as our website, forums, etc.) we ask you to join the large community of volunteer contributors and file a report about the issue. -Note that funds may be available from the [FreeCAD Project Association (FPA)](https://fpa.freecad.org) to pursue -security research and/or the development of fixes to any vulnerabilities discovered. However, vulnerabilities held as +Note that funds may be available from the [FreeCAD Project Association (FPA)](https://fpa.freecad.org) to pursue +security research and/or the development of fixes to any vulnerabilities discovered. However, vulnerabilities held as hostage in demands for "bounties" will not be entertained. Contact the FPA at fpa@freecad.org for more information. ## Supported Versions diff --git a/cMake/FindPyCXX.cmake b/cMake/FindPyCXX.cmake index e37b08eee89c..0c6144a49ec6 100644 --- a/cMake/FindPyCXX.cmake +++ b/cMake/FindPyCXX.cmake @@ -118,7 +118,7 @@ if(PYCXX_FOUND) ${PYCXX_SOURCE_DIR}/IndirectPythonInterface.cxx ) - #set old 6.2 pycxx compatibility + #set old 6.2 pycxx compatibility list(APPEND PYCXX_SOURCES ${PYCXX_SOURCE_DIR}/cxx_exceptions.cxx) add_definitions(-DPYCXX_6_2_COMPATIBILITY) #end old compatibility diff --git a/src/Doc/sphinx/DocumentObject.rst b/src/Doc/sphinx/DocumentObject.rst index c32918221499..7fb99bf725ef 100644 --- a/src/Doc/sphinx/DocumentObject.rst +++ b/src/Doc/sphinx/DocumentObject.rst @@ -5,14 +5,14 @@ The FreeCAD Document Object :maxdepth: 4 .. automodule:: DocumentObject - + .. autoclass:: DocumentObject :members: - + .. method:: __setstate__(value) - + allows to save custom attributes of this object as strings, so they can be saved when saving the FreeCAD document - + .. method:: __getstate__() - + reads values previously saved with __setstate__() diff --git a/src/Doc/sphinx/Matrix.rst b/src/Doc/sphinx/Matrix.rst index 90e4e8ba3f77..db9cc3805b58 100644 --- a/src/Doc/sphinx/Matrix.rst +++ b/src/Doc/sphinx/Matrix.rst @@ -3,7 +3,7 @@ The Matrix object .. toctree:: :maxdepth: 4 - + .. automodule:: FreeCAD .. autoclass:: Matrix diff --git a/src/Doc/sphinx/Placement.rst b/src/Doc/sphinx/Placement.rst index 56d596e9812a..6bb292f626df 100644 --- a/src/Doc/sphinx/Placement.rst +++ b/src/Doc/sphinx/Placement.rst @@ -3,7 +3,7 @@ The Placement object .. toctree:: :maxdepth: 4 - + .. automodule:: FreeCAD .. autoclass:: Placement diff --git a/src/Doc/sphinx/Vector.rst b/src/Doc/sphinx/Vector.rst index f7b8d9287b94..e952daf663a1 100644 --- a/src/Doc/sphinx/Vector.rst +++ b/src/Doc/sphinx/Vector.rst @@ -3,7 +3,7 @@ The Vector object .. toctree:: :maxdepth: 4 - + .. automodule:: FreeCAD .. autoclass:: Vector diff --git a/src/Gui/DlgCheckableMessageBox.cpp b/src/Gui/DlgCheckableMessageBox.cpp index 7954190ffd6d..815281ec2bf0 100644 --- a/src/Gui/DlgCheckableMessageBox.cpp +++ b/src/Gui/DlgCheckableMessageBox.cpp @@ -121,7 +121,7 @@ DlgCheckableMessageBox::DlgCheckableMessageBox(QWidget *parent) : m_d->ui.setupUi(this); m_d->ui.pixmapLabel->setVisible(false); connect(m_d->ui.buttonBox, &QDialogButtonBox::accepted, this, &DlgCheckableMessageBox::accept); - connect(m_d->ui.buttonBox, &QDialogButtonBox::rejected, this, &DlgCheckableMessageBox::reject); + connect(m_d->ui.buttonBox, &QDialogButtonBox::rejected, this, &DlgCheckableMessageBox::reject); connect(m_d->ui.buttonBox, &QDialogButtonBox::clicked, this, &DlgCheckableMessageBox::slotClicked); } diff --git a/src/Gui/Inventor/SoFCTransform.h b/src/Gui/Inventor/SoFCTransform.h index 806377dd7029..a5ad85fff666 100644 --- a/src/Gui/Inventor/SoFCTransform.h +++ b/src/Gui/Inventor/SoFCTransform.h @@ -33,11 +33,11 @@ namespace Gui /** * @class SoFCTransform * @brief A temporary workaround for coin3d/coin#534. - * + * * This class is a workaround for a missing feature to reduce the OpenGL stack size. * The issue was reported here: https://github.com/coin3d/coin/issues/534 * And was merged here: https://github.com/coin3d/coin/pull/535 - * + * * Once this feature is available in all supported versions of Coin3D, this class should * be removed and all instances should revert to using SoTransform. */ diff --git a/src/Mod/BIM/ArchComponent.py b/src/Mod/BIM/ArchComponent.py index 5d2890fde4ec..89e79ba173ed 100644 --- a/src/Mod/BIM/ArchComponent.py +++ b/src/Mod/BIM/ArchComponent.py @@ -315,7 +315,7 @@ def onChanged(self, obj, prop): prop: string The name of the property that has changed. """ - + import math ArchIFC.IfcProduct.onChanged(self, obj, prop) diff --git a/src/Mod/BIM/ArchWall.py b/src/Mod/BIM/ArchWall.py index 17eb4c24e1bf..6f33182f8885 100644 --- a/src/Mod/BIM/ArchWall.py +++ b/src/Mod/BIM/ArchWall.py @@ -337,7 +337,7 @@ def execute(self,obj): if hasattr(baseProxy,"getPropertySet"): # get full list of PropertySet propSetListCur = baseProxy.getPropertySet(obj.Base) - # get updated name (if any) of the selected PropertySet + # get updated name (if any) of the selected PropertySet propSetSelectedNameCur = baseProxy.getPropertySet(obj.Base, propSetUuid=propSetPickedUuidPrev) if propSetSelectedNameCur: # True if selection is not deleted @@ -613,11 +613,11 @@ def onChanged(self, obj, prop): else: FreeCAD.Console.PrintError(translate("Arch","Error: Unable to modify the base object of this wall")+"\n") - if (prop == "ArchSketchPropertySet" + if (prop == "ArchSketchPropertySet" and Draft.getType(obj.Base) == "ArchSketch"): baseProxy = obj.Base.Proxy if hasattr(baseProxy,"getPropertySet"): - uuid = baseProxy.getPropertySet(obj, + uuid = baseProxy.getPropertySet(obj, propSetName=obj.ArchSketchPropertySet) self.ArchSkPropSetPickedUuid = uuid if (hasattr(obj,"ArchSketchData") and obj.ArchSketchData diff --git a/src/Mod/BIM/Resources/ui/dialogConvertDocument.ui b/src/Mod/BIM/Resources/ui/dialogConvertDocument.ui index 978a5e047fb8..ba3e083a58d4 100644 --- a/src/Mod/BIM/Resources/ui/dialogConvertDocument.ui +++ b/src/Mod/BIM/Resources/ui/dialogConvertDocument.ui @@ -37,7 +37,7 @@ - If this is checked, you won't be asked again when creating a new FreeCAD document, + If this is checked, you won't be asked again when creating a new FreeCAD document, and that document won't be turned into an IFC document automatically. You can still turn a FreeCAD document into an IFC document manually, using Utils -> Make IFC project diff --git a/src/Mod/BIM/TestArch.py b/src/Mod/BIM/TestArch.py index a8042084b111..690a4c37c896 100644 --- a/src/Mod/BIM/TestArch.py +++ b/src/Mod/BIM/TestArch.py @@ -793,7 +793,7 @@ def testViewGeneration(self): level = Arch.makeFloor() level.addObjects([wall, column]) App.ActiveDocument.recompute() - + # Create a drawing view section = Arch.makeSectionPlane(level) drawing = Arch.make2DDrawing() @@ -803,7 +803,7 @@ def testViewGeneration(self): cut.ProjectionMode = "Cutfaces" drawing.addObjects([view, cut]) App.ActiveDocument.recompute() - + # Create a TD page tpath = os.path.join(App.getResourceDir(),"Mod","TechDraw","Templates","A3_Landscape_blank.svg") page = App.ActiveDocument.addObject("TechDraw::DrawPage", "Page") diff --git a/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp b/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp index 96af04810717..d18606ce1600 100644 --- a/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp +++ b/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp @@ -56,7 +56,7 @@ FCBRepAlgoAPI_BooleanOperation::FCBRepAlgoAPI_BooleanOperation(const TopoDS_Shap SetRunParallel(Standard_True); SetNonDestructive(Standard_True); } - + void FCBRepAlgoAPI_BooleanOperation::setAutoFuzzy() { FCBRepAlgoAPIHelper::setAutoFuzzy(this); diff --git a/src/Mod/Part/App/MeasureClient.cpp b/src/Mod/Part/App/MeasureClient.cpp index 2239b9865a4d..c6ddb5fba6e5 100644 --- a/src/Mod/Part/App/MeasureClient.cpp +++ b/src/Mod/Part/App/MeasureClient.cpp @@ -318,7 +318,7 @@ MeasureAreaInfoPtr MeasureAreaHandler(const App::SubObjectT& subject) BRepGProp::SurfaceProperties(shape, gprops); auto origin = gprops.CentreOfMass(); - // TODO: Center of Mass might not lie on the surface, somehow snap to the closest point on the surface? + // TODO: Center of Mass might not lie on the surface, somehow snap to the closest point on the surface? Base::Placement placement(Base::Vector3d(origin.X(), origin.Y(), origin.Z()), Base::Rotation()); return std::make_shared(true, getFaceArea(shape), placement); @@ -340,7 +340,7 @@ MeasurePositionInfoPtr MeasurePositionHandler(const App::SubObjectT& subject) return std::make_shared(false, Base::Vector3d()); } - TopoDS_Vertex vertex = TopoDS::Vertex(shape); + TopoDS_Vertex vertex = TopoDS::Vertex(shape); auto point = BRep_Tool::Pnt(vertex); return std::make_shared( true, Base::Vector3d(point.X(), point.Y(), point.Z())); } @@ -365,11 +365,11 @@ MeasureAngleInfoPtr MeasureAngleHandler(const App::SubObjectT& subject) Base::Vector3d position; if (sType == TopAbs_FACE) { TopoDS_Face face = TopoDS::Face(shape); - + GProp_GProps gprops; BRepGProp::SurfaceProperties(face, gprops); vec = gprops.CentreOfMass(); - + } else if (sType == TopAbs_EDGE) { TopoDS_Edge edge = TopoDS::Edge(shape); diff --git a/src/Mod/Part/App/MeasureInfo.h b/src/Mod/Part/App/MeasureInfo.h index f389454f6416..30482a1b8986 100644 --- a/src/Mod/Part/App/MeasureInfo.h +++ b/src/Mod/Part/App/MeasureInfo.h @@ -138,7 +138,7 @@ class PartExport MeasureRadiusInfo : public MeasureInfo { //! callback registrations // TODO: is there more that one place that GeometryHandler is defined? using GeometryHandler = std::function; - + class PartExport CallbackRegistrationRecord { public: @@ -146,7 +146,7 @@ class PartExport CallbackRegistrationRecord CallbackRegistrationRecord(const std::string& module, const std::string& measureType, GeometryHandler callback) : m_module(module), m_measureType(measureType), m_callback(callback) { } - + std::string m_module; std::string m_measureType; GeometryHandler m_callback; diff --git a/src/Mod/Part/App/ShapeFix/ShapeFix_FixSmallFacePy.xml b/src/Mod/Part/App/ShapeFix/ShapeFix_FixSmallFacePy.xml index de33434624c2..c13a42057dbc 100644 --- a/src/Mod/Part/App/ShapeFix/ShapeFix_FixSmallFacePy.xml +++ b/src/Mod/Part/App/ShapeFix/ShapeFix_FixSmallFacePy.xml @@ -78,7 +78,7 @@ - Fixes issues in the overall geometric shape. + Fixes issues in the overall geometric shape. This function likely encapsulates higher-level fixes that involve multiple faces or elements. diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp index 520e66675f5b..d68cab8fbf53 100644 --- a/src/Mod/Part/Gui/TaskSweep.cpp +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -199,7 +199,7 @@ void SweepWidget::findShapes() } } - if (!shape.Infinite() && + if (!shape.Infinite() && (shape.ShapeType() == TopAbs_FACE || shape.ShapeType() == TopAbs_WIRE || shape.ShapeType() == TopAbs_EDGE || diff --git a/src/Mod/Part/parttests/ColorTransparencyTest.py b/src/Mod/Part/parttests/ColorTransparencyTest.py index 273220ef8390..bf2786327a65 100644 --- a/src/Mod/Part/parttests/ColorTransparencyTest.py +++ b/src/Mod/Part/parttests/ColorTransparencyTest.py @@ -46,7 +46,7 @@ def test_default_shape_color(self): of 0 corresponds to a fully transparent color, which is not desirable. It changes the transparency when loading to 1.0 """ - + self._pg.SetUnsigned('DefaultShapeColor', 0xff000000) # red obj = self._doc.addObject('Part::Box') diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 0fe36104fe1f..f72c6409f0d2 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -1,3 +1,4 @@ + /*************************************************************************** * Copyright (c) 2010 Juergen Riegel * * 2020 David Österberg * @@ -260,7 +261,7 @@ App::DocumentObjectExecReturn* Helix::execute() if (SC.State() == TopAbs_IN) { result.Reverse(); } - + fix.LimitTolerance(result, Precision::Confusion() * size * Tolerance.getValue() ); // significant precision reduction due to helical approximation - needed to allow fusion to succeed AddSubShape.setValue(result); diff --git a/src/Mod/PartDesign/PartDesignTests/TestHelix.py b/src/Mod/PartDesign/PartDesignTests/TestHelix.py index 824693da786c..1f4a816ace9a 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestHelix.py +++ b/src/Mod/PartDesign/PartDesignTests/TestHelix.py @@ -161,7 +161,7 @@ def testGiantHelix(self): helix.Angle = 0 helix.Mode = 0 self.Doc.recompute() - + self.assertTrue(helix.Shape.isValid()) bbox = helix.Shape.BoundBox self.assertAlmostEqual(bbox.ZMin/((10**exponent)**3),0,places=4) diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui index eb5d49432331..eec55326a716 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui @@ -696,7 +696,7 @@ Shape of line end caps. The default (round) should almost -always be the right choice. Flat or square caps are useful +always be the right choice. Flat or square caps are useful if you are planning to use a drawing as a 1:1 cutting guide. diff --git a/src/Mod/TechDraw/Gui/Resources/fonts/osifont.license b/src/Mod/TechDraw/Gui/Resources/fonts/osifont.license index 0ad149ca7d21..b04111e27596 100644 --- a/src/Mod/TechDraw/Gui/Resources/fonts/osifont.license +++ b/src/Mod/TechDraw/Gui/Resources/fonts/osifont.license @@ -1,8 +1,8 @@ -osifont license: +osifont license: -osifont-lgpl3fe.ttf is used under one or more of the following licenses: -- GNU GPL licence version 3 with GPL font exception, -- GNU GPL licence version 2 with GPL font exception, +osifont-lgpl3fe.ttf is used under one or more of the following licenses: +- GNU GPL licence version 3 with GPL font exception, +- GNU GPL licence version 2 with GPL font exception, - GNU LGPL licence version 3 with GPL font exception. diff --git a/src/Mod/TechDraw/LineGroup/ASME.Y14.2.2008.ElementDef.csv b/src/Mod/TechDraw/LineGroup/ASME.Y14.2.2008.ElementDef.csv index efa491a90b29..74a1c6a9e2cb 100644 --- a/src/Mod/TechDraw/LineGroup/ASME.Y14.2.2008.ElementDef.csv +++ b/src/Mod/TechDraw/LineGroup/ASME.Y14.2.2008.ElementDef.csv @@ -1,6 +1,6 @@ # ASME Y14.2-2008 line element definitions # NOTE: ASME Y14.2-2008 explicitly does not define the lengths of line elements, -# but recommends lengths that "depict the appropriate line convention commensurate +# but recommends lengths that "depict the appropriate line convention commensurate # with the drawing size and scale". The values used here are generally those # from ISO128. # NOTE: saving this file from a spreadsheet program (like LibreOffice Calc) may diff --git a/src/Mod/TechDraw/Templates/locale/README.md b/src/Mod/TechDraw/Templates/locale/README.md index 45518445b4c2..bf6368084695 100644 --- a/src/Mod/TechDraw/Templates/locale/README.md +++ b/src/Mod/TechDraw/Templates/locale/README.md @@ -1,7 +1,7 @@ This folder (`locale`) contains translations for [TechDraw workbench templates](https://wiki.freecad.org/TechDraw_Templates) in the parent `Templates` folder. The name of each `locale` subfolder represents a language, which follows [IETF BCP 47 standardized codes](https://en.wikipedia.org/wiki/IETF_language_tag). The original TechDraw templates in the parent folder are written using American English (`en-US`). -As such, the most basic name for a locale subfolder will include an [ISO 639 language code](https://en.wikipedia.org/wiki/ISO_639) (e.g. `de` for German). If it's necessary, additional subtags can be added to describe language variants. For instance variants spoken in a particular country, or a specific script. Those subtags are combinable and are based in other standards. +As such, the most basic name for a locale subfolder will include an [ISO 639 language code](https://en.wikipedia.org/wiki/ISO_639) (e.g. `de` for German). If it's necessary, additional subtags can be added to describe language variants. For instance variants spoken in a particular country, or a specific script. Those subtags are combinable and are based in other standards. The most common additional subtag is an additional country code to describe a regional variant of the language (e.g. `de-DE` for German spoken in Germany, `es-AR` for Spanish spoken in Argentina, or `zh-CN` for Simplified Chinese in Mainland China). Country subtags are based on [the ISO 3166-1 standard's country codes](https://en.wikipedia.org/wiki/ISO_3166-1). diff --git a/src/XDGData/org.freecad.FreeCAD.metainfo.xml.in b/src/XDGData/org.freecad.FreeCAD.metainfo.xml.in index e870d71d00d8..c12ab1594173 100644 --- a/src/XDGData/org.freecad.FreeCAD.metainfo.xml.in +++ b/src/XDGData/org.freecad.FreeCAD.metainfo.xml.in @@ -64,7 +64,7 @@ architecture assembly part - coin + coin https://www.freecad.org/ https://github.com/FreeCAD/FreeCAD/issues diff --git a/tools/build/MacOS/BUILD_OSX.md b/tools/build/MacOS/BUILD_OSX.md index 8bb5207aac29..5ab1586ced30 100644 --- a/tools/build/MacOS/BUILD_OSX.md +++ b/tools/build/MacOS/BUILD_OSX.md @@ -142,7 +142,7 @@ If FreeCAD is installed via the bottle then one will have to wait for a new bott If any of the dependencies FreeCAD relies on is updated FreeCAD will likely require a rebuild. Mac homebrew does provide a feature to pin packages at specific versions to prevent them from updating, and also allows setting of an environment variable to prevent homebrew from automatically checking for updates (which can slow things down). All that said, FreeCAD can be built using all the dependencies provided by Mac homebrew, but not using the formula file: instead cloning the source to an arbitrary path on a local filesystem. This provides a couple of advantages: - If `brew cleanup` is run and FreeCAD was installed using the above-provided command, all source tarballs or bottles that were _checked out_ or downloaded during the install process will be deleted from the system. If a reinstall or upgrade is later required then homebrew will have to refetch the bottles, or reclone the git source again. -- Mac homebrew provides a method, _install flag_, for keeping the source regardless if the build succeeds or fails. The options are limited, however, and performing a standard `git clone` outside of homebrew is **much** preferred. +- Mac homebrew provides a method, _install flag_, for keeping the source regardless if the build succeeds or fails. The options are limited, however, and performing a standard `git clone` outside of homebrew is **much** preferred. - Cloning the FreeCAD source allows passing **any** cmake flags not provided by the formula file - Allowing the use of other build systems such as _ninja_ - Allowing the use of alternate compilers, e.g. _ccache_ diff --git a/tools/build/WindowsInstaller/README.md b/tools/build/WindowsInstaller/README.md index 9db81808d83a..981f11137ace 100644 --- a/tools/build/WindowsInstaller/README.md +++ b/tools/build/WindowsInstaller/README.md @@ -32,7 +32,7 @@ msvcp140.dll vcamp140.dll vccorlib140.dll vcomp140.dll -``` +``` 3. Open the file *Settings.nsh* with a text editor (both jEdit and Visual Studio Code are good editors for NSIS files). Edit the following paths to correspond to your system: `FILES_FREECAD` corresponds to your installation directory (e.g. `CMAKE_INSTALL_PREFIX` if you self-compiled) and `FILES_DEPS` is the folder you created with the MSVC redistributable files in it. ``` !define FILES_FREECAD "C:\FreeCAD\Installer\FreeCAD"