├── .gitattributes
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .lgtm.yml
├── .pre-commit-config.yaml
├── .vscode
└── settings.json
├── Conversion
├── DeepCopy.FCMacro
├── DeepCopy.svg
├── DxfToSketchLayers.FCMacro
├── MultiCopy.FCMacro
├── MultiCopy.svg
└── MultiCopy
│ ├── MultiCopyAuxFunc.py
│ ├── MultiCopyCore.py
│ ├── MultiCopyGui.py
│ ├── __init__.py
│ └── resources
│ ├── MultiCopy.svg
│ ├── MultiCopy_Commands_Dialog.ui
│ └── MultiCopy_Main_Dialog.ui
├── FCRotateViewAbsolute.FCMacro
├── FEM
├── ExportFem.FCMacro
├── FemAnimateModeShapes.FCMacro
└── fem_animate_mode_shapes.ui
├── Foto.FCMacro
├── GenevaWheelGUI.py
├── ImportExport
├── Export2Slicer.FCMacro
├── Export2Slicer.png
├── FabricationCutlist.FCMacro
├── FabricationCutlist.png
├── ObjectsToPython.FCMacro
├── ObjectsToPython.svg
└── ObjectsToPython
│ ├── ObjectsToPython.ui
│ └── README.md
├── Information
├── CenterOfMass.FCMacro
├── DatumPlaneLocalAxis.FCMacro
├── DatumPlaneLocalAxis.svg
├── DatumPlaneLocalAxis.txt
├── GetGlobalPlacement-test.txt
├── GetGlobalPlacement.FCMacro
├── GetGlobalPlacement.svg
├── InfoPlus.FCMacro
├── InfoPlus.svg
├── InfoPlus
│ └── ui
│ │ └── InfoPlus.ui
├── MeasureCircle.FCMacro
├── MeasureCircle.png
├── SimpleProperties.FCMacro
└── TreeToAscii.FCMacro
├── ObjectCreation
├── AeroFoil.FCMacro
├── AeroFoil.svg
├── AeroFoil_UI_Files
│ ├── AeroFoil_CSVInput_Dialog.ui
│ ├── AeroFoil_CurvesInput_Dialog.ui
│ ├── AeroFoil_DATInput_Dialog.ui
│ ├── AeroFoil_FileLoad_Dialog.ui
│ ├── AeroFoil_Final_Dialog.ui
│ ├── AeroFoil_Initial_Dialog.ui
│ ├── AeroFoil_Math_Functions_Box.ui
│ ├── AeroFoil_NACA4Digit_Dialog.ui
│ ├── AeroFoil_NACA5Digit_Dialog.ui
│ ├── AeroFoil_PointsInput_Dialog.ui
│ └── AeroFoil_mfb_img.gif
├── AirfoilImportAndScale.FCMacro
├── BSpline3D.FCMacro
├── BoxCreator.FCMacro
├── BoxCreator.svg
├── Draft_Circle_3_Points.FCMacro
├── EllipseCenter2Points.FCMacro
├── G3d.FCMacro
├── G3d.svg
├── HalfHull.FCMacro
├── HilbertCurve.FCMacro
├── HilbertCurve.svg
├── HyperbolaCreater.FCMacro
├── Macro_FCCircularText.FCMacro
├── ParabolaCreater.FCMacro
├── ScrewMaker.FCMacro
├── TimingGear.FCMacro
├── TimingGear.png
├── boxcreator
│ ├── Readme.md
│ ├── __init__.py
│ ├── boxcreator.py
│ ├── boxcreator.ui
│ ├── boxcreator_screenshot.jpg
│ └── boxcreator_screenshot2.jpg
└── g3d
│ ├── translations
│ ├── g3d_en.txt
│ ├── g3d_es.txt
│ └── g3d_it.txt
│ └── ui
│ └── g3d15.ui
├── ParametricObjectCreation
├── GeodesicDome.FCMacro
├── HoneycombSolid.FCMacro
├── HoneycombSolid.xpm
├── Rectellipse.FCMacro
├── geodesic_dome
│ ├── __init__.py
│ └── geodesic_dome.py
└── honeycomb_solid
│ ├── __init__.py
│ └── honeycomb_solid.py
├── PureGui
├── Camera.FCMacro
├── Camera.png
├── Camera
│ ├── accept.png
│ ├── align_object_to_view.png
│ ├── align_to_axis.png
│ ├── align_to_face.png
│ ├── axis_rotation_d.png
│ ├── axis_rotation_x.png
│ ├── axis_rotation_y.png
│ ├── axis_rotation_z.png
│ ├── create_plane_of_view.png
│ ├── detect_orientation.png
│ ├── quit.png
│ ├── reset.png
│ └── save_view.png
├── GuiResetToolbars.FCMacro
├── GuiResetToolbars.svg
├── GuiSpacemouseRotationOff.FCMacro
├── GuiSpacemouseRotationOn.FCMacro
├── GuiSpacemouseRotationToggle.FCMacro
├── SplitPropEditor.FCMacro
├── ViewRotation.FCMacro
├── ViewRotationOut.png
├── ViewRotationRight.png
└── ViewRotationUp.png
├── README.md
├── Sketcher
├── SketchUnmap.FCMacro
├── SketchUnmap.svg
├── SketcherBlockAll.FCMacro
├── SketcherClipView.FCMacro
├── SketcherClipView.svg
├── SketcherFixAllPoints.FCMacro
├── SketcherFixAllPoints.svg
├── SketcherOffset.FCMacro
└── SketcherOffset.svg
├── SolidSweep.FCMacro
├── Spreadsheet
└── .gitkeep
├── TechDraw
├── LasercutterSVGExport.FCMacro
├── LasercutterSVGExport.svg
├── LasercutterSVGExport
│ ├── LasercutterSVGExport_screenshot.png
│ ├── LasercutterTechdrawExport.py
│ ├── README.md
│ └── lasercuttersvg.ui
├── TechDrawAnnoTextFromv018.FCMacro
├── TechDrawMigrateFromv018.FCMacro
├── TechDrawSymbolsLibrary.FCMacro
├── TechDrawTools.FCMacro
├── TechDrawTools.svg
└── TechDrawViewSet.FCMacro
├── Utility
├── GroupSorting.FCMacro
├── GroupSorting.svg
├── HighlightCommon.FCMacro
├── HighlightCommon.png
├── HighlightDifference.FCMacro
├── HighlightDifference.svg
├── MessageBox.FCMacro
├── PiecesTemplates.FCMacro
├── PiecesTemplates.svg
├── PiecesTemplates
│ ├── Groups.txt
│ └── ui
│ │ └── PiecesTemplates.ui
├── PlacementAbsolufy.FCMacro
├── SelectVisible.FCMacro
├── SketchAp.FCMacro
├── SketchAp.svg
├── StraightenObject.FCMacro
├── Transparencies.FCMacro
├── Transparencies.svg
├── WikiObjectPropertiesListGenerator.FCMacro
├── WikiObjectPropertiesListGenerator.svg
├── pcbway.FCMacro
├── treeHelper.FCMacro
└── treeHelper
│ ├── treeHelper.svg
│ └── ui_treewindow.py
├── apothemBasedPrism.py
├── icons
├── Camera
│ ├── FCCamera_00.png
│ ├── FCCamera_01.png
│ ├── FCCamera_02.png
│ ├── FCCamera_03.png
│ ├── FCCamera_04.png
│ ├── FCCamera_05.png
│ ├── FCCamera_06.png
│ ├── FCCamera_07.png
│ ├── FCCamera_08.png
│ ├── FCCamera_Axis_rotation_X.png
│ ├── FCCamera_Axis_rotation_Y.png
│ └── FCCamera_Axis_rotation_Z.png
├── HyperbolaIcon.png
├── MeasureCircle.png
├── MeasureCircle.svg
├── RotateView
│ ├── out.png
│ ├── right.png
│ ├── right_abs.png
│ └── up.png
├── SelectVisible.png
└── SelectVisible.svg
├── makecamera2dview.py
└── myMacroDir
├── __init__.py
└── myMacro.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.FCMacro linguist-language=Python
2 | *.fcmacro linguist-language=Python
3 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Thank you for creating a pull request to contribute to FreeCAD-macros!
2 | To integrate your macro please make sure the following steps are complete:
3 |
4 | - [ ] Please check this box if you're not submitting a new macro.
5 | - [ ] Are you submitting a new macro ?
6 | - [ ] Have you followed the ['How to submit a macro'](../README.md#how-to-submit-a-macro) section of the README.md ?
7 | - [ ] Your macro has a [Description](../README.md#macro-description) in its header.
8 | - [ ] Your macro has a [CamelCase name](../README.md#camelcase-macro-name).
9 | - [ ] Your macro is named [appropriately](../README.md#macro-name-specifics).
10 | - [ ] Your macro contains a [Metadata section](../README.md#macro-metadata) that immediately follows the header description.
11 | - [ ] Your macro is Python3/Qt5 compliant and tested on the latest FreeCAD stable and development releases.
12 | - [ ] You're including documentation on how your macro works (bonus: screenshots and/or video on the Wiki)
13 | - [ ] Commit message is [well-written](https://chris.beams.io/posts/git-commit/)
14 | - [ ] Commit message is titled in the following way `[MacroName] Short description`.
15 | - [ ] Optional, write or update the changelog in the macro, from latest to oldest.
16 |
17 | And please remember to update the Wiki with the features added or changed once this PR is merged.
18 | **Note**: If you don't have wiki access, then please mention your contribution on the [0.19 Changelog Forum Thread](https://forum.freecadweb.org/viewtopic.php?f=10&t=34586).
19 |
20 | ---
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py?
2 |
--------------------------------------------------------------------------------
/.lgtm.yml:
--------------------------------------------------------------------------------
1 | extraction:
2 | python:
3 | python_setup:
4 | version: 3
5 | setup_py: false
6 | index:
7 | filters:
8 | - include: "**/*.FCMacro"
9 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # To use:
2 | #
3 | # pre-commit run -a
4 | #
5 | # Or:
6 | #
7 | # pre-commit install # (runs every time you commit in git)
8 | #
9 | # To update this file:
10 | #
11 | # pre-commit autoupdate
12 | #
13 | # See https://github.com/pre-commit/pre-commit for more information.
14 | # See https://pre-commit.com/hooks.html for more hooks.
15 | repos:
16 | - repo: https://github.com/pre-commit/pre-commit-hooks
17 | rev: v4.6.0
18 | hooks:
19 | - id: check-added-large-files
20 | - id: check-ast
21 | - id: check-builtin-literals
22 | - id: check-case-conflict
23 | - id: check-docstring-first
24 | # - id: check-illegal-windows-names
25 | - id: check-json
26 | - id: check-merge-conflict
27 | - id: check-symlinks
28 | - id: check-toml
29 | - id: check-xml
30 | - id: check-yaml
31 | - id: debug-statements
32 | - id: destroyed-symlinks
33 | - id: fix-byte-order-marker
34 | - id: forbid-submodules
35 | - id: mixed-line-ending
36 | - id: trailing-whitespace
37 | exclude: '(\.ui|\.svg)$'
38 | - repo: https://github.com/asottile/pyupgrade
39 | rev: v3.19.1
40 | hooks:
41 | - id: pyupgrade
42 | args: [--py38-plus]
43 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.linting.flake8Enabled": true,
3 | "python.linting.enabled": true
4 | }
--------------------------------------------------------------------------------
/Conversion/DeepCopy.FCMacro:
--------------------------------------------------------------------------------
1 | # Make a copy of the shape of all children of a part and make a compound
2 | # from them.
3 |
4 | from __future__ import annotations
5 |
6 | __Name__ = 'Deep Copy'
7 | __Comment__ = 'Takes a part and makes a compound out of it'
8 | __License__ = 'Apache-2.0'
9 | __Web__ = 'https://www.freecadweb.org/wiki/Macro_DeepCopy'
10 | __Wiki__ = 'https://www.freecadweb.org/wiki/Macro_DeepCopy'
11 | __Icon__ = 'DeepCopy.svg'
12 | __Help__ = 'Select a part and launch'
13 | __Author__ = 'galou_breizh'
14 | __Version__ = '1.1.0'
15 | __Date__ = '2023-03-22'
16 | __Status__ = 'Stable'
17 | __Requires__ = 'FreeCAD >= v0.17'
18 | __Files__ = 'DeepCopy.svg'
19 |
20 | from typing import Iterable, Optional
21 |
22 | from Arch import pruneIncluded
23 |
24 | import FreeCAD as app
25 | import FreeCADGui as gui
26 |
27 |
28 | # Typing hints.
29 | DO: app.DocumentObject
30 | AppPart: DO # TypeId == 'App::Part'.
31 | DOList: Iterable[DO]
32 |
33 |
34 | def deep_copy(doc: Optional[app.Document] = None):
35 | """Copy the shape of the selected objects.
36 |
37 | Parameters
38 | ----------
39 | - doc: document to copy the shape to. Defaults to the document of the
40 | selected objects.
41 |
42 | """
43 | sel = gui.Selection.getSelectionEx()
44 | if not sel:
45 | app.Console.PrintWarning('No objects selected')
46 | return
47 | # Check that all selected objects are in the same document.
48 | if doc is None:
49 | doc = sel[0].Object.Document
50 | for sel_object in sel:
51 | if sel_object.Object.Document is not doc:
52 | app.Console.PrintError('Selected objects belong to'
53 | ' different documents\n')
54 | return
55 |
56 | for sel_object in sel:
57 | deep_copy_part(sel_object.Object, doc)
58 |
59 |
60 | def deep_copy_part(part: AppPart, doc: Optional[app.Document] = None):
61 | """Copy the shape of a "App::Part" object.
62 |
63 | Parameters
64 | ----------
65 | - doc: document to copy the shape to. Defaults to the document of the
66 | given object.
67 |
68 | """
69 | if (not hasattr(part, 'TypeId')) or part.TypeId != 'App::Part':
70 | # Part is not a part, return.
71 | try:
72 | app.Console.PrintWarning(f'"{part.Label}" ({part.Name})'
73 | ' is not a part, ignoring\n')
74 | except AttributeError:
75 | app.Console.PrintWarning('Object is not a part, ignoring\n')
76 | return
77 |
78 | if doc is None:
79 | doc = part.Document
80 |
81 | copied_subobjects = []
82 | for o in get_all_subobjects(part):
83 | copied_subobjects += copy_subobject(doc, o)
84 |
85 | compound = doc.addObject('Part::Compound', 'Copy of ' + part.Label)
86 | compound.Links = copied_subobjects
87 | compound.Placement = part.Placement
88 | doc.recompute()
89 |
90 |
91 | def get_all_subobjects(obj: DO) -> DOList:
92 | """Recursively get all subobjects
93 |
94 | Subobjects of objects having a Shape attribute are not included otherwise
95 | each single feature of the object would be copied. The result is that
96 | bodies, compounds, and the result of boolean operations will be converted
97 | into a simple copy of their shape.
98 |
99 | """
100 | # Depth-first search algorithm.
101 | discovered = []
102 | # We do not need an extra copy for stack because OutList is already a copy.
103 | stack = obj.OutList
104 | while stack:
105 | v = stack.pop(0)
106 | if v not in discovered:
107 | discovered.append(v)
108 | if not hasattr(v, 'Shape'):
109 | stack += v.OutList
110 | return pruneIncluded(discovered)
111 |
112 |
113 | def copy_subobject(doc: app.DocumentObject, obj: DO) -> DOList:
114 | """Copy the shape of an object
115 |
116 | Some GUI attributes are also copied
117 |
118 | """
119 | copied_object = []
120 | if not hasattr(obj, 'Shape') or obj.Shape.isNull():
121 | return copied_object
122 | vobj = obj.ViewObject
123 | try:
124 | copy = doc.addObject('Part::Feature', obj.Name + '_Shape')
125 | copy.Shape = obj.Shape
126 | copy.Label = 'Copy of ' + obj.Label
127 | except AttributeError as e:
128 | app.Console.PrintLog(e)
129 | pass
130 | else:
131 | copied_object = [copy]
132 | vo_copy = copy.ViewObject
133 | # Implementation note: cannot use __setattr__ and __getattribute__.
134 | try:
135 | vo_copy.ShapeColor = vobj.ShapeColor
136 | except AttributeError:
137 | pass
138 | try:
139 | vo_copy.LineColor = vobj.LineColor
140 | except AttributeError:
141 | pass
142 | try:
143 | vo_copy.PointColor = vobj.PointColor
144 | except AttributeError:
145 | pass
146 | try:
147 | vo_copy.DiffuseColor = vobj.DiffuseColor
148 | except AttributeError:
149 | pass
150 | try:
151 | vo_copy.Transparency = vobj.Transparency
152 | except AttributeError:
153 | pass
154 | return copied_object
155 |
156 |
157 | if __name__ == '__main__':
158 | deep_copy()
159 |
--------------------------------------------------------------------------------
/Conversion/MultiCopy.FCMacro:
--------------------------------------------------------------------------------
1 |
2 |
3 | ##########################################################################################
4 | ##### L I C E N S E #####
5 | ##########################################################################################
6 | #
7 | # GNU LESSER GENERAL PUBLIC LICENSE
8 | # Version 2.1, February 1999
9 | #
10 | # Copyright (C) 1991, 1999 Free Software Foundation, Inc.
11 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
12 | # Everyone is permitted to copy and distribute verbatim copies
13 | # of this license document, but changing it is not allowed.
14 | #
15 | # [This is the first released version of the Lesser GPL. It also counts
16 | # as the successor of the GNU Library Public License, version 2, hence
17 | # the version number 2.1.]
18 | #
19 | # 'MultiCopy' is a FreeCAD macro package. MultiCopy allows the duplication
20 | # (copy and paste) of multiple FreeCAD objects that can be labelled
21 | # sequentially and in a custom manner.
22 | #
23 | # Copyright (C) 2021 Melwyn Francis Carlo
24 | #
25 | # This library is free software; you can redistribute it and/or
26 | # modify it under the terms of the GNU Lesser General Public
27 | # License as published by the Free Software Foundation; either
28 | # version 2.1 of the License, or (at your option) any later version.
29 | #
30 | # This library is distributed in the hope that it will be useful,
31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 | # Lesser General Public License for more details.
34 | #
35 | # You should have received a copy of the GNU Lesser General Public License
36 | # along with this library; if not, write to the Free Software Foundation, Inc.,
37 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 | #
39 | # Contact Information :-
40 | # Email : carlo.melwyn@outlook.com
41 | # FreeCAD UserTalk : http://www.freecadweb.org/wiki/index.php?title=User:Melwyncarlo
42 | #
43 | ##########################################################################################
44 | ##### L I C E N S E #####
45 | ##########################################################################################
46 | #
47 | #
48 | #
49 | # The MultiCopy macro was developed and tested on a platform containing the
50 | # following system and FreeCAD software specifications :
51 | #
52 | # - OS : Ubuntu 18.04.5 LTS (LXDE/Lubuntu)
53 | # - Word size of OS : 64-bit
54 | # - Word size of FreeCAD: 64-bit
55 | # - Version : 0.19
56 | # - Build type : Release
57 | # - Branch : unknown
58 | # - Hash : 32200b604d421c4dad527fe587a7d047cf953b4f
59 | # - Python version : 3.6.9
60 | # - Qt version : 5.9.5
61 | # - Coin version : 4.0.0a
62 | # - OCC version : 7.3.0
63 | # - Locale : English/UnitedKingdom (en_GB)
64 |
65 |
66 |
67 | """
68 | To use this macro, the steps to be followed are simple and straightforward :
69 | select one or more FreeCAD objects from the Tree view, and then select 'MultiCopy'.
70 | In the dialog box that pops up, choose the copy method, select and input the relevant
71 | paste parameters and commands, and then click on 'Paste'.
72 |
73 | Note (1) The single underscore prefix (e.g. _name) denotes a private
74 | function or a private variable.
75 | Note (2) Some of the short forms used in this script are as follows:
76 | 'mc' stands for MultiCopy
77 | 'pcc' stands for Paste Code Commands
78 | 'd' stands for Dialog (e.g. _d_, etc.)
79 | """
80 |
81 |
82 |
83 | __Title__='MultiCopy'
84 | __Author__='Melwyncarlo'
85 | __Version__='2.0.0'
86 | __Date__='2021-03-23'
87 | __Comment__='MultiCopy allows the duplication (copy and paste) of multiple FreeCAD objects that can be labelled sequentially and in a custom manner.'
88 | __Web__='https://github.com/melwyncarlo/MultiCopy'
89 | __Wiki__='http://www.freecadweb.org/wiki/index.php?title=Macro_MultiCopy'
90 | __Icon__='MultiCopy.svg'
91 | __Help__='Select one or more FreeCAD objects, then click on the MultiCopy button/macro, and follow the instructions in the dialog box.'
92 | __Status__='stable'
93 | __Requires__='Freecad >= v0.17'
94 | __Communication__='https://github.com/melwyncarlo/MultiCopy/issues'
95 | __Files__='MultiCopyGui.py, MultiCopyCore.py, MultiCopyAuxFunc.py, MultiCopy/resources/MultiCopy_Main_Dialog.ui, MultiCopy/resources/MultiCopy_Commands_Dialog.ui, MultiCopy/resources/MultiCopy.svg'
96 |
97 |
98 |
99 |
100 | # Library Imports
101 | #------------------------------------------------------------------------------------------------
102 |
103 | import MultiCopy
104 |
105 |
106 |
107 | ###################################################################
108 | ###-------------------------------------------------------------###
109 | ### MULTICOPY MACRO CALLS ###
110 | ###-------------------------------------------------------------###
111 | ### ###
112 | ### This is the main macro call. The code below commences ###
113 | ### the MultiCopy GUI interface. This script cannot be ###
114 | ### called externally. ###
115 | ###
116 | ###
117 | if __name__ == '__main__': ###
118 | MultiCopy.Gui.Launch() ###
119 | ###
120 | ###-------------------------------------------------------------###
121 | ### MULTICOPY MACRO CALLS ###
122 | ###-------------------------------------------------------------###
123 | ###################################################################
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/Conversion/MultiCopy/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 |
4 | ##########################################################################################
5 | ##### L I C E N S E #####
6 | ##########################################################################################
7 | #
8 | # GNU LESSER GENERAL PUBLIC LICENSE
9 | # Version 2.1, February 1999
10 | #
11 | # Copyright (C) 1991, 1999 Free Software Foundation, Inc.
12 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
13 | # Everyone is permitted to copy and distribute verbatim copies
14 | # of this license document, but changing it is not allowed.
15 | #
16 | # [This is the first released version of the Lesser GPL. It also counts
17 | # as the successor of the GNU Library Public License, version 2, hence
18 | # the version number 2.1.]
19 | #
20 | # 'MultiCopy' is a FreeCAD macro package. MultiCopy allows the duplication
21 | # (copy and paste) of multiple FreeCAD objects that can be labelled
22 | # sequentially and in a custom manner.
23 | #
24 | # Copyright (C) 2021 Melwyn Francis Carlo
25 | #
26 | # This library is free software; you can redistribute it and/or
27 | # modify it under the terms of the GNU Lesser General Public
28 | # License as published by the Free Software Foundation; either
29 | # version 2.1 of the License, or (at your option) any later version.
30 | #
31 | # This library is distributed in the hope that it will be useful,
32 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
33 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 | # Lesser General Public License for more details.
35 | #
36 | # You should have received a copy of the GNU Lesser General Public License
37 | # along with this library; if not, write to the Free Software Foundation, Inc.,
38 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
39 | #
40 | # Contact Information :-
41 | # Email : carlo.melwyn@outlook.com
42 | # FreeCAD UserTalk : http://www.freecadweb.org/wiki/index.php?title=User:Melwyncarlo
43 | #
44 | ##########################################################################################
45 | ##### L I C E N S E #####
46 | ##########################################################################################
47 |
48 |
49 | """This is the MultiCopy package documentation.
50 |
51 | NAME
52 | --------------------
53 | MultiCopy
54 |
55 | VERSION
56 | --------------------
57 | v2.0.0
58 |
59 | DESCRIPTION
60 | --------------------
61 | 'MultiCopy' is a user-created macro to be used within the FreeCAD application.
62 | MultiCopy allows the duplication (copy and paste) of multiple FreeCAD objects
63 | that can be labelled sequentially and in a custom manner.
64 |
65 | Key features include:
66 | > Two input methods: by mouse, or by keyboard (Paste Code Commands)
67 | > Standard Copy and Simple Copy methods supported
68 | > Duplication across two different documents
69 | > Delete selected objects after duplication
70 | > Duplicate with or without dependencies
71 | > Add custom label separators
72 | > Add padded numbering to labels
73 | > Numbering types: Ordinary numerals, upper/lower-case roman numerals and
74 | upper/lower-case alphabetic characters
75 | > Unique 'Paste Code Commands' that allow multiple duplication procedurally
76 | as well as in nested loops
77 | > Both CUI and GUI methods available
78 |
79 | For more details, visit:
80 | https://github.com/melwyncarlo/MultiCopy
81 | https://wiki.freecadweb.org/Macro_MultiCopy
82 |
83 | PACKAGE CONTENTS
84 | --------------------
85 | MultiCopyCore.py
86 | MultiCopyGui.py
87 | """
88 |
89 |
90 | __Title__ = 'MultiCopy'
91 | __Author__ = 'Melwyncarlo'
92 | __Version__ = '2.0.0'
93 | __Date__ = '2021-03-23'
94 | __Comment__ = 'MultiCopy allows the duplication (copy and paste) of multiple FreeCAD objects that can be labelled sequentially and in a custom manner.'
95 | __Web__ = 'https://github.com/melwyncarlo/MultiCopy'
96 | __Wiki__ = 'http://www.freecadweb.org/wiki/index.php?title=Macro_MultiCopy'
97 | __Help__ = 'Select one or more FreeCAD objects, then click on the MultiCopy button/macro, and follow the instructions in the dialog box.'
98 | __Status__ = 'stable'
99 | __Requires__ = 'Freecad >= v0.17'
100 | __Communication__ = 'https://github.com/melwyncarlo/MultiCopy/issues'
101 | __Files__ = 'MultiCopyGui.py, MultiCopyCore.py, MultiCopyAuxFunc.py, resources/MultiCopy_Main_Dialog.ui, resources/MultiCopy_Commands_Dialog.ui, resources/MultiCopy.svg'
102 |
103 |
104 | # Library Imports
105 | # ------------------------------------------------------------------------------------------------
106 |
107 | from . import MultiCopyGui as Gui
108 | from . import MultiCopyCore as Core
109 |
110 |
111 | # Alias Functions
112 | # ------------------------------------------------------------------------------------------------
113 |
114 | Run = Core.Run
115 | Launch = Gui.Launch
116 |
--------------------------------------------------------------------------------
/FCRotateViewAbsolute.FCMacro:
--------------------------------------------------------------------------------
1 | __Name__ = 'FCRotateViewAbsolute'
2 | __Comment__ = ''
3 | __License__ = ''
4 | __Web__ = ''
5 | __Wiki__ = ''
6 | __Icon__ = ''
7 | __Help__ = ''
8 | __Author__ = ''
9 | __Version__ = ''
10 | __Status__ = ''
11 | __Requires__ = ''
12 | __Files__ = ''
13 |
14 | from FreeCAD import Base
15 | import FreeCADGui as Gui
16 |
17 |
18 | from math import cos,sin,pi
19 |
20 | import sys
21 | from PySide.QtCore import *
22 | from PySide.QtGui import *
23 |
24 | from pivy import coin
25 |
26 | class Form(QDialog):
27 |
28 | def __init__(self, parent=None):
29 | super(Form, self).__init__(parent)
30 | self.alpha=00
31 | self.beta=180
32 | self.setWindowFlags(Qt.WindowStaysOnTopHint)
33 |
34 | dial = QDial()
35 | dial.setNotchesVisible(True)
36 | self.dial=dial
37 | dial.setMaximum(360)
38 | dial.setValue(self.alpha)
39 |
40 |
41 |
42 | dial2 = QDial()
43 | dial2.setNotchesVisible(True)
44 | self.dial2=dial2
45 | dial2.setMaximum(360)
46 | dial2.setValue(self.beta)
47 |
48 | spinbox = QSpinBox()
49 | spinbox.setMaximum(360)
50 |
51 | layout = QHBoxLayout()
52 |
53 |
54 | self.pushButton00 = QPushButton(QIcon('icons:freecad.svg'),"Dimetric")
55 | self.pushButton01 = QPushButton(QIcon('icons:freecad.svg'),"Trimetric")
56 | self.pushButton02 = QPushButton(QIcon('icons:freecad.svg'),"Isometric")
57 | self.pushButton03 = QPushButton(QIcon('icons:freecad.svg'),"Front")
58 | self.pushButton00.clicked.connect(self.dimetric)
59 | self.pushButton01.clicked.connect(self.trimetric)
60 | self.pushButton02.clicked.connect(self.isometric)
61 | self.pushButton03.clicked.connect(self.front)
62 | layout.addWidget(self.pushButton03)
63 | layout.addWidget(self.pushButton00)
64 | layout.addWidget(self.pushButton01)
65 | layout.addWidget(self.pushButton02)
66 |
67 |
68 | layout.addWidget(dial)
69 | layout.addWidget(dial2)
70 | # layout.addWidget(spinbox)
71 | self.setLayout(layout)
72 |
73 | #self.connect(dial, SIGNAL("valueChanged(int)"), spinbox.setValue)
74 | #self.connect(spinbox, SIGNAL("valueChanged(int)"), dial.setValue)
75 | dial.valueChanged.connect(spinbox.setValue);
76 |
77 | dial.valueChanged.connect(self.dreher);
78 | dial2.valueChanged.connect(self.heber);
79 |
80 |
81 | self.cami()
82 | self.setWindowTitle("Camera position")
83 | Gui.SendMsgToActiveView("ViewFit")
84 |
85 |
86 |
87 | def dreher(self):
88 | self.alpha=self.dial.value()
89 | self.cami()
90 |
91 | def heber(self):
92 | self.beta=self.dial2.value()
93 | self.cami()
94 |
95 | def rotY(self,delta=10):
96 | if self.beta==1:
97 | self.beta=0
98 |
99 | self.beta += delta
100 | if self.beta >360:
101 | self.beta -= 360
102 | if self.beta <0:
103 | self.beta += 360
104 | if self.beta==0:
105 | self.beta=1
106 | FreeCAD.Console.PrintMessage(str(self.beta)+" # ");
107 | self.dial2.setValue(self.beta)
108 |
109 |
110 | def rotZ(self,delta=10):
111 | self.alpha += delta
112 | if self.alpha >360:
113 | self.alpha -= 360
114 | if self.alpha <0:
115 | self.alpha += 360
116 | self.dial.setValue(self.alpha)
117 |
118 | def cami(self):
119 |
120 | from pivy import coin
121 | alpha=self.alpha
122 | beta=self.beta
123 |
124 | camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
125 |
126 | Gui=FreeCADGui
127 | if False:
128 | typeCamera="Orthographic"
129 | if typeCamera=="Orthographic":
130 | Gui.activeDocument().activeView().setCameraType("Orthographic")
131 | else:
132 | Gui.activeDocument().activeView().setCameraType("Perspective")
133 |
134 | campos=Base.Vector( 1000 * cos (pi*alpha/360*2)*sin(pi*beta/360*1), 1000*sin(pi*alpha/360*2)*sin(pi*beta/360*1), 1000*cos(pi*beta/360*1))
135 | camera.position.setValue( campos)
136 |
137 | pos3=FreeCAD.Vector(0,0,0)
138 | pos3.sub(campos)
139 |
140 | #if False:
141 | camera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))
142 |
143 | App.ActiveDocument.recompute()
144 | FreeCADGui.updateGui()
145 |
146 | def front(self):
147 | from pivy import coin
148 | pos3=FreeCAD.Vector(0,0,0)
149 | campos=FreeCAD.Vector(0,-10,0)
150 | camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
151 | camera.position.setValue( campos)
152 | camera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))
153 |
154 | def isometric(self):
155 |
156 | pos3=FreeCAD.Vector(0,0,0)
157 | campos=FreeCAD.Vector(100,-100,100)
158 | camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
159 | camera.position.setValue( campos)
160 | pos3.sub(campos)
161 | camera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))
162 |
163 | def dimetric(self):
164 | pos3=FreeCAD.Vector(0,0,0)
165 | campos=FreeCAD.Vector(68,-68,27)
166 | camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
167 | camera.position.setValue( campos)
168 | pos3.sub(campos)
169 | camera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))
170 | App.ActiveDocument.recompute()
171 | FreeCADGui.updateGui()
172 |
173 |
174 | def trimetric(self):
175 | pos3=FreeCAD.Vector(0,0,0)
176 | campos=FreeCAD.Vector(210,-790,580)
177 | camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
178 | camera.position.setValue( campos)
179 | pos3.sub(campos)
180 | camera.pointAt(coin.SbVec3f(pos3),coin.SbVec3f(0,0,1))
181 |
182 |
183 | if hasattr(FreeCAD,"ViewMgr")and FreeCAD.ViewMgr:
184 | FreeCAD.ViewMgr.show()
185 | FreeCAD.Console.PrintMessage("neu gestrte")
186 | else:
187 | FreeCAD.ViewMgr=Form()
188 | FreeCAD.ViewMgr.show()
189 | FreeCAD.Console.PrintMessage(" war schon da")
190 |
191 |
192 | t=FreeCADGui.getMainWindow()
193 | t.activateWindow()
194 |
--------------------------------------------------------------------------------
/FEM/ExportFem.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Export FreeCAD FEM Data
3 | # Author: Gomez Lucio
4 | # License: LGPL v 2.1
5 |
6 |
7 | __Name__ = "Export Fem"
8 | __Comment__ = "This macro exports FEM Data"
9 | __License__ = "LGPL v 2.1"
10 | __Web__ = "http://forum.freecadweb.org/viewtopic.php?f=18&t=11455"
11 | __Wiki__ = ""
12 | __Icon__ = ""
13 | __Help__ = "Select an object and start the macro"
14 | __Author__ ="Gomez Lucio"
15 | __Version__= ""
16 | __Status__ = ""
17 | __Requires__ = ""
18 | __Files__ = ""
19 |
20 |
21 |
22 |
23 | import os
24 | import FreeCADGui
25 | import FreeCAD
26 | import shutil
27 | from PySide import QtGui
28 |
29 | ### START OF MACRO ###
30 |
31 | # Mehcanical Analysis Select
32 | sel = FreeCADGui.Selection.getSelection() # Selection
33 | sel1=sel[0]
34 |
35 | # Save folder select
36 | dialog = QtGui.QFileDialog.getExistingDirectory()
37 | destiny_folder = str(dialog)
38 |
39 | # Proceed
40 | if sel1.TypeId == 'Fem::FemAnalysisPython':
41 | try:
42 | dir1 = sel1.Document.TransientDir # Temporary Directory
43 | nam_fold = sel1.Uid[32:] # Analysis temporary folder name
44 | # Analysis Final Directory
45 | direc = str(dir1 + '/FemAnl_' + nam_fold + '/')
46 | calculix_files = os.listdir(direc)
47 | for files in calculix_files:
48 | shutil.copy(direc + files,destiny_folder)
49 | FreeCAD.Console.PrintMessage('Mechanical Analysis files save in' + destiny_folder)
50 | except:
51 | FreeCAD.Console.PrintError('Sorry but no temporary file exists')
52 | else:
53 | FreeCAD.Console.PrintError('Error in Selection: Select a correct Mechanical Analysis')
54 |
55 | ### END OF MACRO ###
56 |
--------------------------------------------------------------------------------
/FEM/FemAnimateModeShapes.FCMacro:
--------------------------------------------------------------------------------
1 | """FreeCAD macro to animate mode shapes.
2 |
3 | These are the steps used to generate the data to be animated, these are the
4 | usual steps:
5 | - click on "CalculiXccxTools"
6 | - select "Frequency"
7 | - select "Write .inp file"
8 | - select "Run CalculiX"
9 |
10 | These are the steps to prepare for and perform the animation:
11 | - open "Macro" in the ToolBar.
12 | - select "Macros..." and choose "FemAnimateModeShapes.py" and "execute". A
13 | widget "Animate" will be generated in a separate window.
14 | - Double-click on a set of results "CalculiX_frequency_mode_7", for example.
15 | This panel must be visible for the animation to work, Note (1).
16 | - select "Abs displacement", for example.
17 | - click the radio button "Displacement/Show"
18 | - click on "Start Animation" in the widget.
19 |
20 | The entries in the widget are:
21 | - "scale" - scale for the displacements, 1 to 999, this may be a problem if the
22 | displacements are very large/small before scaling.
23 | - "factor" - enter the value for the scale, this is linked to "scale"
24 | - "number of steps..." - the number of steps in 1 vibratory cycle, if this
25 | value is increased the apparent speed of the animation will slow down.
26 | - "steps/second" - the number of steps displayed per second, if this value is
27 | increased the animation will speed up.
28 | - "number of cycles" - the number of cycles in the animation.
29 | - "Start Animation" - starts the animation, this changes to "Stop Animation"
30 | during the animation.
31 |
32 | Note(1) - if you click on "Results_mesh001", and start animation you may
33 | possibly be animating the wrong mode shape.
34 | """
35 |
36 | import math
37 | import os
38 | import time
39 |
40 | import FreeCAD as app
41 |
42 | import FreeCADGui as gui
43 |
44 | from PySide import QtGui # FreeCAD's PySide!
45 |
46 | __Name__ = 'Animate Mode Shapes for FEM'
47 | __Comment__ = 'Animate mode shapes after running CalculiX'
48 | __Author__ = 'mac_the_bike,galou'
49 | __Version__ = '1.0.1'
50 | __Date__ = '2022-02-04'
51 | __License__ = 'LGPL-2.0-or-later'
52 | __Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=39081'
53 | __Wiki__ = ''
54 | __Icon__ = ''
55 | __Help__ = ''
56 | __Status__ = ''
57 | __Requires__ = ''
58 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
59 | __Files__ = 'fem_animate_mode_shapes.ui'
60 |
61 | # Items in the widget window:
62 | # - startEndButton
63 | # - amplitude
64 | # - factor
65 | # - steps
66 | # - steps/second is coded as frames/second
67 | # - loops
68 |
69 |
70 | class FemAnimateModeShapes():
71 | def __init__(self):
72 | self.do_animation = False
73 | self.ui_file = os.path.join(app.getUserMacroDir(True),
74 | 'fem_animate_mode_shapes.ui')
75 | self.inc = 1 # TODO: find a better name and use.
76 |
77 | self.form = gui.PySideUic.loadUi(self.ui_file)
78 | self._connect_widgets()
79 | self.form.show()
80 | self.box = self._message_box()
81 |
82 | def _connect_widgets(self):
83 | self.form.startEndButton.clicked.connect(self.start_stop)
84 | self.form.amplitude.valueChanged.connect(self._on_amplitude_changed)
85 | self.form.factor.valueChanged.connect(self._on_factor_changed)
86 |
87 | def start(self):
88 | self.do_animation = True
89 | self._do_animate()
90 |
91 | def start_stop(self):
92 | if self.do_animation:
93 | self.do_animation = False
94 | else:
95 | self.do_animation = True
96 | self._do_animate()
97 |
98 | def _on_amplitude_changed(self):
99 | if self.inc == 0:
100 | self.form.factor.setValue(self.form.amplitude.value())
101 | self.inc = 1 - self.inc
102 |
103 | def _on_factor_changed(self):
104 | if self.inc == 0:
105 | self.form.amplitude.setValue(int(self.form.factor.value()))
106 | self.inc = 1 - self.inc
107 |
108 | def _message_box(self):
109 | box = QtGui.QMessageBox()
110 | box.setWindowTitle('No Results')
111 | box.setText('Select a case and select a displacement type, e.g. Abs')
112 | box.setInformativeText('Tick the displacement radio button')
113 | box.setStandardButtons(QtGui.QMessageBox.Ok)
114 | box.setDefaultButton(QtGui.QMessageBox.Save)
115 | return box
116 |
117 | def _do_animate(self):
118 | if not self.do_animation:
119 | return
120 | try:
121 | mesh_obj = app.FEM_dialog['result_obj']
122 | mesh_obj.Mesh.ViewObject.applyDisplacement(0)
123 | except:
124 | self.box.exec_()
125 | self.do_animation = False
126 | return
127 |
128 | self.form.startEndButton.setText('Stop Animation')
129 |
130 | frame_count = self.form.frames.value()
131 | steps = self.form.steps.value()
132 | loops = self.form.loops.value()
133 | inc = 2 * math.pi / steps
134 |
135 | done = False
136 | for lo in range(loops):
137 | for st in range(steps):
138 | mesh_obj.Mesh.ViewObject.applyDisplacement(
139 | math.sin(inc * st) * self.form.factor.value())
140 | gui.updateGui()
141 | if not self.do_animation:
142 | done = True
143 | break
144 | time.sleep(1. / frame_count)
145 | if done:
146 | break
147 | self.form.startEndButton.setText('Start Animation')
148 | self.do_animation = False
149 |
150 |
151 | if __name__ == '__main__':
152 | FemAnimateModeShapes()
153 |
--------------------------------------------------------------------------------
/FEM/fem_animate_mode_shapes.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | myAnimate
4 |
5 |
6 | Qt::ApplicationModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 700
13 | 400
14 |
15 |
16 |
17 | Animate
18 |
19 |
20 | -
21 |
22 |
-
23 |
24 |
25 | scale
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 | 300
34 | 0
35 |
36 |
37 |
38 | 0
39 |
40 |
41 | 999
42 |
43 |
44 | 40
45 |
46 |
47 | Qt::Horizontal
48 |
49 |
50 |
51 |
52 |
53 | -
54 |
55 |
-
56 |
57 |
58 | factor
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
66 | 142
67 | 0
68 |
69 |
70 |
71 |
72 | 142
73 | 16777215
74 |
75 |
76 |
77 | 4
78 |
79 |
80 | 999.000000000000000
81 |
82 |
83 | 40.000000000000000
84 |
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
-
92 |
93 |
94 | number of steps per cycle
95 |
96 |
97 |
98 | -
99 |
100 |
101 |
102 | 142
103 | 0
104 |
105 |
106 |
107 | 24
108 |
109 |
110 |
111 |
112 |
113 | -
114 |
115 |
-
116 |
117 |
118 | steps/second
119 |
120 |
121 |
122 | -
123 |
124 |
125 |
126 | 142
127 | 0
128 |
129 |
130 |
131 |
132 | 142
133 | 16777215
134 |
135 |
136 |
137 | 24
138 |
139 |
140 |
141 |
142 |
143 | -
144 |
145 |
-
146 |
147 |
148 | number of cycles
149 |
150 |
151 |
152 | -
153 |
154 |
155 |
156 | 142
157 | 0
158 |
159 |
160 |
161 | 999
162 |
163 |
164 | 2
165 |
166 |
167 |
168 |
169 |
170 | -
171 |
172 |
173 | Start Animation
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/Foto.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # (c) microelly 2015
3 |
4 | __Name__ = 'Foto'
5 | __Comment__ = 'Creates a real sized 300-dpi foto of the selected part from top view'
6 | __Author__ = 'microelly'
7 | __Version__ = '0.1.0'
8 | __Date__ = ''
9 | __License__ = ''
10 | __Web__ = ''
11 | __Wiki__ = ''
12 | __Icon__ = ''
13 | __Help__ = 'Select an object'
14 | __Status__ = 'alpha'
15 | __Requires__ = ''
16 | __Contact__ = 'https://forum.freecadweb.org/memberlist.php?mode=viewprofile&u=2364'
17 | __Communication__ = ''
18 | __Files__ = ''
19 |
20 | import os
21 |
22 | import FreeCADGui
23 |
24 |
25 | def foto(fn='/tmp/fc_camera_out.jpg', width=150, height=100, x=0, y=0, res=300):
26 | if res <= 0:
27 | # TODO: add a warning about wrong res value.
28 | res = 300
29 | dpmm = 11.8110 * res / 300
30 | ppy = int(dpmm * height)
31 | ppx = int(dpmm * width)
32 | y -= 1
33 | cam = '''#Inventor V2.1 ascii
34 | OrthographicCamera {{
35 | viewportMapping ADJUST_CAMERA
36 | orientation 1 0 0 0.001
37 | nearDistance 0
38 | farDistance 1000
39 | aspectRatio 100
40 | focalDistance 1
41 | position {x} {y} 999
42 | height {height}
43 | }}
44 |
45 | '''.format(x=x, y=y, height=height)
46 |
47 | FreeCADGui.activeDocument().activeView().setCamera(cam)
48 |
49 | FreeCADGui.ActiveDocument.update()
50 | FreeCADGui.activeDocument().activeView().saveImage(fn, ppx, ppy, '#ffffff')
51 |
52 | fn = "/tmp/fc_photo.jpg"
53 | res = 300
54 |
55 | sel = FreeCADGui.Selection.getSelection()
56 | sel0 = sel[0]
57 | sel0.ViewObject.LineWidth = 1
58 | bbox = sel0.Shape.BoundBox
59 | px = 0.5 * (bbox.XMin + bbox.XMax)
60 | py = 0.5 * (bbox.YMin + bbox.YMax)
61 | width = bbox.XMax - bbox.XMin
62 | height = bbox.YMax - bbox.YMin
63 |
64 | foto(fn, width, height, px, py, res)
65 | os.system('xdg-open {}'.format(fn))
66 |
--------------------------------------------------------------------------------
/ImportExport/Export2Slicer.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Opens current visible objects in Slic3r. One can use different slicing software
3 |
4 | __Title__ = '3D Print / Slice'
5 | __Author__ = 'Damian Łoziński'
6 | __Version__ = '0.4.1'
7 | __Date__ = '2024-08-28'
8 | __Comment__ = 'Export selected objects to amf/stl files and open them in slicing program'
9 | __Web__ = 'https://github.com/dlozinski/FreeCAD-macros/blob/doc/ImportExport/ExportToSlicer.md'
10 | __Wiki__ = ''
11 | __Icon__ = 'Export2Slicer.png'
12 | __Help__ = 'You may need to change slicer path. To do so open Tools > Edit parameters > BaseApp/Preferences/Macros/Export2Slicer'
13 | __Status__ = 'Stable'
14 | __Requires__ = 'freecad 0.17+'
15 | __Communication__ = 'lozinski dot d at gmail dot com'
16 | __Files__ = 'Export2Slicer.png'
17 |
18 | import os
19 | import re
20 | from subprocess import Popen
21 | import shlex
22 |
23 | import FreeCAD as app
24 | import FreeCADGui as gui
25 | import Mesh
26 | import MeshPart
27 |
28 |
29 | MACRO_PARAMS = app.ParamGet('User parameter:BaseApp/Preferences/Macros/Export2Slicer')
30 | DEFAULT_SLICER_CMD = '"/Applications/Original Prusa Drivers/PrusaSlicer.app/Contents/MacOS/PrusaSlicer" --single-instance "{file}"'
31 | DEFAULT_OUTPUT_FORMAT = 'amf'
32 | DEFAULT_ANGULAR_DEFLECTION = 0.07
33 |
34 |
35 | def get_string_param(name, default):
36 | value = MACRO_PARAMS.GetString(name)
37 | if not value:
38 | MACRO_PARAMS.SetString(name, default)
39 | value = default
40 | return value
41 |
42 |
43 | def get_float_param(name, default):
44 | value = MACRO_PARAMS.GetFloat(name)
45 | if not value:
46 | MACRO_PARAMS.SetFloat(name, default)
47 | value = default
48 | return value
49 |
50 |
51 | slicer_cmd = get_string_param('SlicerCommand', DEFAULT_SLICER_CMD)
52 | output_format = get_string_param('OutputFormat', DEFAULT_OUTPUT_FORMAT)
53 | angular_deflection = get_float_param('AngularDeflection', DEFAULT_ANGULAR_DEFLECTION)
54 |
55 |
56 | def escape(text):
57 | return re.sub(r'\W', '_', text)
58 |
59 |
60 | def get_mesh_filename(doc_filename, mesh_names):
61 | """Returns valid filename for temporary mesh file."""
62 | if doc_filename:
63 | dirname = os.path.dirname(doc_filename)
64 | filename = (
65 | os.path.basename(doc_filename).partition('.')[0]
66 | + '-'
67 | + escape('_'.join(mesh_names))
68 | + '.'
69 | + output_format)
70 | file_path = os.path.join(dirname, filename)
71 | else:
72 | file_path = 'meshes-export.' + output_format
73 | return file_path
74 |
75 |
76 | def main():
77 | doc = app.activeDocument()
78 | if not doc:
79 | raise RuntimeError('Export2Slicer: No active document')
80 |
81 | selection = gui.Selection.getSelectionEx()
82 | objects_to_export = [x.Object for x in selection] or [doc.ActiveObject]
83 | try:
84 | # Create temporary doc to store meshes so that we don't affect current doc history
85 | tmp_doc = app.newDocument('meshes_to_export', temp=True)
86 | meshes = []
87 | mesh_names = []
88 | for o in objects_to_export:
89 | if o.TypeId == 'Mesh::Feature':
90 | meshes.append(o)
91 | else:
92 | mesh = tmp_doc.addObject('Mesh::Feature', f'{doc.Label}_{o.Label}')
93 | mesh.Mesh = MeshPart.meshFromShape(o.Shape, LinearDeflection=0.1, AngularDeflection=angular_deflection, Relative=False)
94 | meshes.append(mesh)
95 | mesh_names.append(o.Label)
96 | if meshes:
97 | mesh_path = get_mesh_filename(doc.FileName, mesh_names)
98 | Mesh.export(meshes, mesh_path)
99 | else:
100 | raise RuntimeError('Export2Slicer: No objects to export')
101 | finally:
102 | app.closeDocument('meshes_to_export')
103 | for x in selection:
104 | gui.Selection.addSelection(doc.Name, x.ObjectName)
105 |
106 | # Launch Slicer with meshes
107 | Popen(shlex.split(slicer_cmd.format(file=mesh_path)))
108 | app.Console.PrintMessage(f'Export2Slicer: Objects exported into: {mesh_path}\n')
109 |
110 |
111 | try:
112 | main()
113 | except Exception as e:
114 | app.Console.PrintError('Export2Slicer: ERROR: {}\n'.format(e))
115 |
--------------------------------------------------------------------------------
/ImportExport/Export2Slicer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ImportExport/Export2Slicer.png
--------------------------------------------------------------------------------
/ImportExport/FabricationCutlist.FCMacro:
--------------------------------------------------------------------------------
1 | # This macro aims to make it easy to create an accurate cutlist when you are going to fabricate something made out of rectangles and round bar.
2 | # For example, if you're welding together a gate from commercial mild steel, you are probably using square tubing, round bar and / or angle iron.
3 | # For all of these you can use Part WB's *Box* and *Cylinder* types.
4 | # Having done so, this macro will create a comma-separated set of values that make up your cutlist. The collumns are as follows:
5 | # Timestamp: Just throw this away
6 | # Label: The label you gave the part. Perhaps use this to indicate the role of the part in your design.
7 | # Label2: The secondary label you gave the part. Perhaps use this to indicate the profile ("roundbar", "squaretube" etc)
8 | # Dim1: For round bar, this is the diameter. For box shapes, this is one dimension of the profile size.
9 | # Dim2: For round bar, this is blank. For box shapes this is the other dimension of the profile size.
10 | # Length: How long this piece is.
11 |
12 | __Name__ = 'Fabrication Cutlist Maker'
13 | __Comment__ = 'For designs made of Part WB Box and Cylinder primitives, creates a CSV cutlist.'
14 | __Author__ = 'Johan Pretorius'
15 | __Date__ = '2024-08-28'
16 | __Version__ = '2024.8.10'
17 | __License__ = 'AAL'
18 | __Web__ = 'https://github.com/FreeCAD/FreeCAD-macros'
19 | __Wiki__ = ''
20 | __Icon__ = 'FabricationCutlist.png'
21 | __Xpm__ = ''
22 | __Help__ = 'Make your design out of "Box" and "Cylinder" primitives in Part WB. Then run the macro to get a cutlist in the Report View.'
23 | __Status__ = 'Stable'
24 | __Requires__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
25 | __Communication__ = ''
26 | __Files__ = ''
27 |
28 | import FreeCAD as app
29 |
30 | doc = app.activeDocument()
31 | if doc:
32 | objects = doc.Objects
33 | warnings = []
34 |
35 | app.Console.PrintMessage('------- CSV Cutlist Begins -------\n')
36 |
37 | for obj in objects:
38 | label = obj.Label
39 | label2 = obj.Label2
40 |
41 | if (obj.TypeId == 'Part::Cylinder') and label2:
42 | diameter = obj.Radius.Value * 2
43 | length = obj.Height.Value
44 | app.Console.PrintMessage(
45 | f', {label}, {label2}, {diameter}, , {length}\n')
46 | elif obj.TypeId == 'Part::Cylinder':
47 | warnings.append(
48 | f'"{label}" not used, it is a Part::Cylinder object but has no Label2\n')
49 | elif (obj.TypeId == 'Part::Box') and label2:
50 | size = [obj.Length.Value, obj.Width.Value, obj.Height.Value]
51 | size.sort()
52 | app.Console.PrintMessage(
53 | f', {label}, {label2}, {size[0]}, {size[1]}, {size[2]}\n')
54 | elif obj.TypeId == 'Part::Box':
55 | warnings.append(
56 | f'"{label}" not used, it is a Part::Box object but has no Label2\n')
57 | else:
58 | warnings.append(
59 | f'"{label}" not used, only considering Box and Cylinder objects\n')
60 |
61 | app.Console.PrintMessage('======= CSV Cutlist Completed =======\n')
62 |
63 | for w in warnings:
64 | app.Console.PrintWarning(w)
65 |
--------------------------------------------------------------------------------
/ImportExport/FabricationCutlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ImportExport/FabricationCutlist.png
--------------------------------------------------------------------------------
/ImportExport/ObjectsToPython.svg:
--------------------------------------------------------------------------------
1 |
2 |
101 |
--------------------------------------------------------------------------------
/ImportExport/ObjectsToPython/ObjectsToPython.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 800
10 | 800
11 |
12 |
13 |
14 | Objects To Python
15 |
16 |
17 | -
18 |
19 |
20 | -
21 |
22 |
23 | Close
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/ImportExport/ObjectsToPython/README.md:
--------------------------------------------------------------------------------
1 | # Objects To Python
2 | Exports existing objects from a FreeCAD project to a python script
3 |
4 | This macro should create clean, human readable python code from already existing FreeCAD objects.
5 | When the generated code is executed, it should create all objects from scratch.
6 |
7 | ATTENTION: It does not work for all objects in FreeCAD. Especially objects created by built in python scripts like everything in the Draft workbench will not work correctly.
8 |
9 | ## How it works
10 | The macro is quite simple. It loops through the properties of all selected objects, compares then to a default object, and generates script lines for object creation and changed properties. For some objects (Sketcher or Spreadsheet objects), special handling in the macro is needed. It may not be complete.
11 |
12 | ## Usage
13 | This macro generates python code from all selected objects in a FreeCAD project.
14 | If no object is selected, all objects in the project will be selected.
15 |
16 | A dialog will open and the output will be written into it. Press CTRL-a and CTRL-c to copy the code.
17 |
18 |
--------------------------------------------------------------------------------
/Information/DatumPlaneLocalAxis.txt:
--------------------------------------------------------------------------------
1 | from FreeCAD import Vector, Placement, Rotation
2 | import FreeCAD as app
3 |
4 |
5 | def make_test_datum_plane_local_axis():
6 | doc = app.activeDocument()
7 |
8 | # Part / Body / DatumPlane + Part / LinkToBody / DatumPlane.
9 | Part = doc.addObject('App::Part', 'Part')
10 | Part.Placement = Placement(Vector(0.0, 0.0, 10.0),
11 | Rotation(0.0, 0.0, 0.0, 1.0))
12 |
13 | Body = doc.addObject('PartDesign::Body', 'Body')
14 | Part.addObject(Body)
15 | Body.Placement = Placement(Vector(0.0, 0.0, 20.0),
16 | Rotation(0.0, 0.0, 0.0, 1.0))
17 |
18 | DatumPlane = doc.addObject('PartDesign::Plane', 'DatumPlane')
19 | Body.addObject(DatumPlane)
20 | DatumPlane.AttachmentOffset = Placement(Vector(10.0, 0.0, 0.0),
21 | Rotation(0.0, 0.0, 0.0, 1.0))
22 | DatumPlane.MapMode = 'FlatFace'
23 | DatumPlane.Placement = Placement(Vector(10.0, 0.0, 0.0),
24 | Rotation(0.0, 0.0, 0.0, 1.0))
25 | DatumPlane.Support = [(Body.Origin.OriginFeatures[3], (''))] # XY-plane.
26 |
27 | Box = doc.addObject('PartDesign::AdditiveBox', 'Box')
28 | Body.addObject(Box)
29 |
30 | LinkToBody = doc.addObject('App::Link', 'LinkToBody')
31 | Part.addObject(LinkToBody)
32 | LinkToBody.LinkedObject = Body
33 | LinkToBody.LinkPlacement = Placement(Vector(0.0, 0.0, 40.0),
34 | Rotation(0.0, 0.0, 0.0, 1.0))
35 |
36 |
37 | # LinkToPart / Body / DatumPlane + LinkToPart / LinkToBody / DatumPlane
38 | LinkToPart = doc.addObject('App::Link', 'LinkToPart')
39 | LinkToPart.LinkPlacement = Placement(Vector(0.0, 50.0, 0.0),
40 | Rotation(0.0, 0.0, 0.0, 1.0))
41 | LinkToPart.LinkedObject = Part
42 |
43 | # Body / DatumPlane.
44 | Body002 = doc.addObject('PartDesign::Body', 'Body002')
45 |
46 | DatumPlane001 = doc.addObject('PartDesign::Plane', 'DatumPlane001')
47 | Body002.addObject(DatumPlane001)
48 | DatumPlane001.MapMode = 'FlatFace'
49 | DatumPlane001.Support = [(Body002.Origin.OriginFeatures[3], (''))] # XY-plane.
50 |
51 | doc.recompute()
52 |
53 |
54 | make_test_datum_plane_local_axis()
55 |
--------------------------------------------------------------------------------
/Information/GetGlobalPlacement-test.txt:
--------------------------------------------------------------------------------
1 | from FreeCAD import Vector, Placement, Rotation, activeDocument
2 |
3 | # A matrix with no rotation.
4 | g_placement_fail_1_1_1 = Placement(
5 | Vector(),
6 | Rotation(0.45642222410108496, 0.49809724456331667, 0.5849212871934979, -0.4488262203714842))
7 |
8 |
9 | def position(x, y, z):
10 | return Placement(Vector(x, y, z), Rotation ())
11 |
12 |
13 | def make_GetGlobalPlacement_test(check = False):
14 | # just a visual reference point
15 | doc = activeDocument()
16 | Ref = doc.addObject('PartDesign::CoordinateSystem', 'Ref')
17 |
18 | Cube = doc.addObject('Part::Box', 'Cube')
19 | Cube.Width = Cube.Height = Cube.Length = 2
20 | Cube.Placement = position(0, 0, -1)
21 |
22 | CubeLink = doc.addObject('App::Link', 'CubeLink')
23 | CubeLink.Placement = position(8, -2, 0)
24 | CubeLink.LinkedObject = Cube
25 | CubeLink.Scale = 0.50
26 | CubeLink.LinkTransform = True
27 |
28 | Part = doc.addObject('App::Part', 'Part')
29 | Part.Placement = position(0, 4, 0)
30 | Part.Group = [Cube]
31 |
32 | PartLink = doc.addObject('App::Link', 'PartLink')
33 | PartLink.Placement = position(-2, -2, 0)
34 | PartLink.LinkedObject = Part
35 | PartLink.ElementCount = 2
36 | PartLink.ShowElement = True
37 | PartLink.ElementList[0].Scale = 2
38 | PartLink.ElementList[0].Placement.Rotation.Yaw = 60
39 | PartLink.ElementList[1].Placement = position(5, 0, 0)
40 |
41 | # A test that fails on version 1.1.1 because of scale retrieval.
42 | # Should return the same rotation.
43 | cube_1_1_1 = doc.addObject('Part::Box', 'Fails_on_1_1_1')
44 | cube_1_1_1.Width = 1.0
45 | cube_1_1_1.Height = 1.0
46 | cube_1_1_1.Length = 1.0
47 | cube_1_1_1.Placement = g_placement_fail_1_1_1
48 |
49 | doc.recompute()
50 |
51 |
52 | # Not possible to import a .FCMacro
53 | # the suffix must be changed to .py (for example via a symlink).
54 | try:
55 | from GetGlobalPlacement import get_global_placement_and_scale as p_and_s
56 | except ImportError:
57 | pass
58 |
59 |
60 | def check_GetGlobalPlacement_test():
61 | tol = 1e-6
62 | doc = App.activeDocument()
63 | Cube = doc.getObject('Cube')
64 | CubeLink = doc.getObject('CubeLink')
65 | Part = doc.getObject('Part')
66 | PartLink = doc.getObject('PartLink')
67 | cube_1_1_1 = doc.getObject('Fails_on_1_1_1')
68 | assert p_and_s(Cube,'')[0].isSame(position(0, 0, -1), tol)
69 | assert p_and_s(CubeLink,'')[0].isSame(position(8, -2, -0.5), tol)
70 | assert p_and_s(Part,'')[0].isSame(position(0, 4, 0), tol)
71 | assert p_and_s(Part,'Cube.')[0].isSame(position(0, 4, -1), tol)
72 | assert p_and_s(PartLink,'')[0].isSame(position(-2, -2, 0), tol)
73 | p = Placement(Vector(-2, -2, 0), Rotation(60, 0, 0))
74 | assert p_and_s(PartLink,'PartLink_i0.')[0].isSame(p, tol)
75 | p = Placement(Vector(-2, -2, -2), Rotation(60, 0, 0))
76 | assert p_and_s(PartLink,'0.Cube.Edge1')[0].isSame(p, tol)
77 | assert p_and_s(PartLink,'1.')[0].isSame(position(3, -2, 0), tol)
78 | assert p_and_s(PartLink,'1.Cube.Edge1')[0].isSame(position(3, -2, -1), tol)
79 | assert p_and_s(cube_1_1_1, '')[0].isSame(g_placement_fail_1_1_1, tol)
80 | print('OK')
81 |
82 |
83 | make_GetGlobalPlacement_test()
84 |
85 | # Correct results:
86 | #
87 | # Ref: 0.000, 0.000, 0.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
88 | # CubeLink: 8.000, -2.000, -0.500; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
89 | # Part: 0.000, 4.000, 0.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
90 | # Part.Cube: 0.000, 4.000, -1.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
91 | # PartLink: -2.000, -2.000, 0.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
92 | # PartLink.PartLink_i0: -2.000, -2.000, 0.000; 0.0000, 0.0000, 0.5000, 0.8660; (rpy: 0.00, 0.00, 60.00) deg
93 | # PartLink.PartLink_i0.Origin.Z_Axis: -2.000, -2.000, 0.000; -0.1830, 0.6830, 0.1830, 0.6830; (rpy: -30.00, 90.00, 0.00) deg
94 | # PartLink.PartLink_i0.Cube: -2.000, -2.000, -2.000; 0.0000, 0.0000, 0.5000, 0.8660; (rpy: 0.00, 0.00, 60.00) deg
95 | # PartLink.PartLink_i1: 3.000, -2.000, 0.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
96 | # PartLink.PartLink_i1.Cube: 3.000, -2.000, -1.000; 0.0000, 0.0000, 0.0000, 1.0000; (rpy: 0.00, 0.00, 0.00) deg
97 | # Fails_on_1_1_1: 0.000, 0.000, 0.000; 0.4564, 0.4981, 0.5849, -0.4488; App.Placement(App.Vector(0.000, 0.000, 0.000), App.Rotation(0.45642, 0.49810, 0.58492, -0.44883)); (rpy: 63.26, -78.83, -158.70) deg
98 |
--------------------------------------------------------------------------------
/Information/MeasureCircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/Information/MeasureCircle.png
--------------------------------------------------------------------------------
/Information/SimpleProperties.FCMacro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #####################################
3 | # Copyright (c) openBrain 2019
4 | # Licensed under LGPL v2
5 | #
6 | # This FreeCAD macro will give basic properties of the selected object (volume, boundbox, ...)
7 | #
8 | #
9 | # Version history :
10 | # *0.7 : some typo improvement + commenting
11 | # *0.6 : check if selected object has a valid shape
12 | # *0.5 : beta release
13 | #
14 | #####################################
15 |
16 | __Name__ = 'Simple Properties'
17 | __Comment__ = 'Gives basic properties of object (volume, boundbox, ...)'
18 | __Author__ = 'openBrain'
19 | __Version__ = '0.7.1'
20 | __Date__ = '2019-07-10'
21 | __License__ = 'LGPL v2'
22 | __Web__ = 'https://www.freecadweb.org/wiki/Macro_SimpleProperties'
23 | __Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SimpleProperties'
24 | __Icon__ = ''
25 | __Help__ = 'Select an object and run the macro'
26 | __Status__ = 'Beta'
27 | __Requires__ = 'FreeCAD >= 0.17'
28 |
29 | __dbg__ = False # True for debugging.
30 | g_disp_width = 3 # Set the display format of numbers.
31 |
32 | from PySide import QtGui
33 |
34 | import FreeCAD as app
35 | import FreeCADGui as gui
36 |
37 | def cslM(msg): #Print message in console
38 | app.Console.PrintMessage('\n')
39 | app.Console.PrintMessage(msg)
40 |
41 |
42 | def cslW(msg): #Print warning in console
43 | app.Console.PrintMessage('\n')
44 | app.Console.PrintWarning(msg)
45 |
46 |
47 | def cslE(msg): #Print error in console
48 | app.Console.PrintMessage('\n')
49 | app.Console.PrintError(msg)
50 |
51 |
52 | def cslD(msg): #Print debug message in console
53 | if __dbg__:
54 | app.Console.PrintMessage('\n')
55 | app.Console.PrintMessage('Debug: ' + str(msg))
56 |
57 | if __dbg__: ##Clear report view in debug mode
58 | gui.getMainWindow().findChild(QtGui.QTextEdit, 'Report view').clear()
59 |
60 | cslM('Starting Simple Properties macro')
61 |
62 | if len(gui.Selection.getSelection()) != 1:
63 | # If not exactly one object selected, warn user & quit.
64 | cslE('One and only one object shall be selected ... Exiting')
65 | elif not ('Shape' in gui.Selection.getSelection()[0].PropertiesList):
66 | # If selected object has no shape, warn user & exit.
67 | cslE('Selected object has no valid shape ... Exiting')
68 | else:
69 | obj = gui.Selection.getSelection()[0]
70 | # Get selected object.
71 | retStr = ''
72 | if len(gui.Selection.getSelectionEx()[0].SubObjects) != 1:
73 | # If several object subobjects have been selected, ignore & warn user.
74 | cslW('None or several subobject(s) selected, will be ignored')
75 | else:
76 | # If one subobject selected.
77 | objEx = gui.Selection.getSelectionEx()[0].SubObjects[0]
78 | if isinstance(objEx, Part.Edge):
79 | # If it's an edge, print its length.
80 | retStr += 'Edge length: {:.{w}g} mm\n'.format(objEx.Length, w=g_disp_width)
81 | elif isinstance(objEx, Part.Face):
82 | # If it's a face, print its area.
83 | retStr += 'Face area: {:.{w}g} m²\n'.format(objEx.Area / 1000000, w=g_disp_width)
84 | else:
85 | # If other (unsupported) type, warn user.
86 | cslD('Subobject type: ' + str(objEx.ShapeType))
87 | cslW('Unsupported type of subobject')
88 | retStr += 'Object volume: {:.{w}g} l\n'.format(obj.Shape.Volume / 1000000, w=g_disp_width)
89 | bb = obj.Shape.BoundBox # Get object's bounding box.
90 | retStr += 'Object boundbox : {:.{w}g} x {:.{w}g} x {:.{w}g} mm³\n'.format(
91 | bb.XLength, bb.YLength, bb.ZLength, w=g_disp_width)
92 |
93 | # Display information in a message box.
94 | QtGui.QMessageBox(QtGui.QMessageBox.Information, 'Object Simple Props', retStr).exec_()
95 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_CurvesInput_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 425
13 | 380
14 |
15 |
16 |
17 |
18 | 425
19 | 380
20 |
21 |
22 |
23 |
24 | 425
25 | 380
26 |
27 |
28 |
29 | AeroFoil : Custom Curves
30 |
31 |
32 |
33 |
34 | 25
35 | 25
36 | 160
37 | 30
38 |
39 |
40 |
41 | Airfoil Profile Type :
42 |
43 |
44 |
45 |
46 |
47 | 295
48 | 335
49 | 100
50 | 30
51 |
52 |
53 |
54 | Next
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 335
62 | 100
63 | 30
64 |
65 |
66 |
67 | Back
68 |
69 |
70 |
71 |
72 |
73 | 200
74 | 30
75 | 125
76 | 25
77 |
78 |
79 |
80 | Symmetric
81 |
82 |
83 | true
84 |
85 |
86 | true
87 |
88 |
89 |
90 |
91 |
92 | 200
93 | 60
94 | 210
95 | 30
96 |
97 |
98 |
99 | Asymmetric / Cambered
100 |
101 |
102 | false
103 |
104 |
105 |
106 |
107 |
108 | 25
109 | 150
110 | 191
111 | 30
112 |
113 |
114 |
115 | Enter top curve function :
116 |
117 |
118 |
119 |
120 |
121 | 25
122 | 230
123 | 221
124 | 30
125 |
126 |
127 |
128 | Enter bottom curve function :
129 |
130 |
131 |
132 |
133 |
134 | 25
135 | 180
136 | 370
137 | 30
138 |
139 |
140 |
141 |
142 |
143 | false
144 |
145 |
146 |
147 | 25
148 | 260
149 | 370
150 | 30
151 |
152 |
153 |
154 | false
155 |
156 |
157 |
158 |
159 |
160 | 20
161 | 110
162 | 335
163 | 30
164 |
165 |
166 |
167 | PointingHandCursor
168 |
169 |
170 | color: navy;
171 | text-decoration: underline;
172 | border: 0px;
173 |
174 |
175 | Click here to look through the 'List of Functions'
176 |
177 |
178 |
179 |
180 | af_d2c_textbox_1
181 | af_d2c_list_button
182 | af_d2c_radio_1
183 | af_d2c_radio_2
184 | af_d2c_textbox_2
185 | af_d2c_next_button
186 | af_d2c_back_button
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_DATInput_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 350
13 | 305
14 |
15 |
16 |
17 |
18 | 350
19 | 305
20 |
21 |
22 |
23 |
24 | 350
25 | 305
26 |
27 |
28 |
29 | AeroFoil : Custom Points
30 |
31 |
32 |
33 |
34 | 220
35 | 260
36 | 100
37 | 30
38 |
39 |
40 |
41 | Next
42 |
43 |
44 |
45 |
46 |
47 | 25
48 | 260
49 | 100
50 | 30
51 |
52 |
53 |
54 | Back
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 60
62 | 240
63 | 30
64 |
65 |
66 |
67 | Commence from Line Number :
68 |
69 |
70 |
71 |
72 |
73 | 25
74 | 90
75 | 211
76 | 30
77 |
78 |
79 |
80 | Terminate to Line Number :
81 |
82 |
83 |
84 |
85 |
86 | 270
87 | 60
88 | 50
89 | 30
90 |
91 |
92 |
93 | 0
94 |
95 |
96 | 999999999
97 |
98 |
99 | 0
100 |
101 |
102 |
103 |
104 |
105 | 270
106 | 90
107 | 50
108 | 30
109 |
110 |
111 |
112 | 0
113 |
114 |
115 | 999999999
116 |
117 |
118 | 0
119 |
120 |
121 |
122 |
123 |
124 | 25
125 | 25
126 | 141
127 | 30
128 |
129 |
130 |
131 |
132 | 50
133 | false
134 | true
135 |
136 |
137 |
138 | Text File Controls :
139 |
140 |
141 |
142 |
143 |
144 | 25
145 | 130
146 | 175
147 | 30
148 |
149 |
150 |
151 |
152 | true
153 |
154 |
155 |
156 | text-decoration: underline;
157 |
158 |
159 | Decimal Point Type :
160 |
161 |
162 |
163 |
164 |
165 | 20
166 | 140
167 | 300
168 | 75
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | 15
178 | 35
179 | 150
180 | 30
181 |
182 |
183 |
184 | Period ( . )
185 |
186 |
187 | true
188 |
189 |
190 | true
191 |
192 |
193 |
194 |
195 |
196 | 180
197 | 35
198 | 211
199 | 30
200 |
201 |
202 |
203 | Comma ( , )
204 |
205 |
206 |
207 |
208 |
209 | af_d2d1a_spinBox_1
210 | af_d2d1a_spinBox_2
211 | af_d2d1a_radio_1
212 | af_d2d1a_radio_2
213 | af_d2d1a_next_button
214 | af_d2d1a_back_button
215 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_FileLoad_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 500
13 | 235
14 |
15 |
16 |
17 |
18 | 500
19 | 235
20 |
21 |
22 |
23 |
24 | 500
25 | 235
26 |
27 |
28 |
29 | AeroFoil : Load 'Data Points'
30 |
31 |
32 |
33 |
34 | 375
35 | 190
36 | 100
37 | 30
38 |
39 |
40 |
41 | Next
42 |
43 |
44 |
45 |
46 |
47 | 25
48 | 190
49 | 100
50 | 30
51 |
52 |
53 |
54 | Back
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 25
62 | 341
63 | 30
64 |
65 |
66 |
67 | Enter a File Name or Load a File :
68 |
69 |
70 |
71 |
72 |
73 | 25
74 | 90
75 | 450
76 | 30
77 |
78 |
79 |
80 | Load File
81 |
82 |
83 |
84 |
85 |
86 | 25
87 | 55
88 | 450
89 | 30
90 |
91 |
92 |
93 | true
94 |
95 |
96 |
97 |
98 |
99 | 34
100 | 125
101 | 431
102 | 30
103 |
104 |
105 |
106 |
107 | Ubuntu Mono
108 | 12
109 | 75
110 | true
111 | true
112 | false
113 | true
114 |
115 |
116 |
117 | color: black;
118 |
119 |
120 | File Not Loaded
121 |
122 |
123 | Qt::AlignCenter
124 |
125 |
126 |
127 |
128 | af_d2cd2_load_button
129 | af_d2cd2_next_button
130 | af_d2cd2_back_button
131 | af_d2cd2_textbox
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_Initial_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 390
13 | 150
14 |
15 |
16 |
17 |
18 | 390
19 | 150
20 |
21 |
22 |
23 |
24 | 390
25 | 150
26 |
27 |
28 |
29 | AeroFoil
30 |
31 |
32 |
33 |
34 | 25
35 | 25
36 | 150
37 | 30
38 |
39 |
40 |
41 | Choose airfoil type :
42 |
43 |
44 |
45 |
46 |
47 | 255
48 | 100
49 | 100
50 | 30
51 |
52 |
53 |
54 | Next
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 100
62 | 100
63 | 30
64 |
65 |
66 |
67 | Close
68 |
69 |
70 |
71 |
72 |
73 | 180
74 | 25
75 | 175
76 | 30
77 |
78 |
79 | -
80 |
81 | NACA - 4 Digit
82 |
83 |
84 | -
85 |
86 | NACA - 5 Digit
87 |
88 |
89 | -
90 |
91 | Custom - Curves
92 |
93 |
94 | -
95 |
96 | Custom - Points
97 |
98 |
99 |
100 |
101 |
102 | af_d1_combo
103 | af_d1_next_button
104 | af_d1_close_button
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_Math_Functions_Box.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 275
10 | 400
11 |
12 |
13 |
14 |
15 | 275
16 | 400
17 |
18 |
19 |
20 |
21 | 275
22 | 400
23 |
24 |
25 |
26 | AeroFoil : Functions
27 |
28 |
29 |
30 |
31 | 25
32 | 25
33 | 231
34 | 30
35 |
36 |
37 |
38 |
39 | true
40 |
41 |
42 |
43 | List of mathematical functions :
44 |
45 |
46 |
47 |
48 |
49 | 93
50 | 355
51 | 100
52 | 30
53 |
54 |
55 |
56 | Okay
57 |
58 |
59 |
60 |
61 |
62 | 30
63 | 60
64 | 100
65 | 225
66 |
67 |
68 |
69 | QFrame::StyledPanel
70 |
71 |
72 | QFrame::Raised
73 |
74 |
75 |
76 |
77 | 0
78 | 25
79 | 100
80 | 350
81 |
82 |
83 |
84 | +
85 | -
86 | *
87 | /
88 | ^
89 | e
90 | pi
91 | ln(#)
92 | log(#)
93 | sqrt(#)
94 |
95 |
96 | Qt::AlignHCenter|Qt::AlignTop
97 |
98 |
99 |
100 |
101 |
102 |
103 | 140
104 | 60
105 | 100
106 | 140
107 |
108 |
109 |
110 | QFrame::StyledPanel
111 |
112 |
113 | QFrame::Raised
114 |
115 |
116 |
117 |
118 | 0
119 | 15
120 | 100
121 | 110
122 |
123 |
124 |
125 | sin(θ)
126 | cos(θ)
127 | tan(θ)
128 | asin(θ)
129 | acos(θ)
130 | atan(θ)
131 |
132 |
133 |
134 | Qt::AlignHCenter|Qt::AlignTop
135 |
136 |
137 |
138 |
139 |
140 |
141 | 140
142 | 210
143 | 100
144 | 75
145 |
146 |
147 |
148 | QFrame::StyledPanel
149 |
150 |
151 | QFrame::Raised
152 |
153 |
154 |
155 |
156 | 0
157 | 7
158 | 100
159 | 60
160 |
161 |
162 |
163 | Function
164 | variable
165 | is 'x'.
166 |
167 |
168 | Qt::AlignCenter
169 |
170 |
171 |
172 |
173 |
174 |
175 | 35
176 | 300
177 | 50
178 | 30
179 |
180 |
181 |
182 |
183 | 75
184 | true
185 | true
186 |
187 |
188 |
189 | Note :
190 |
191 |
192 |
193 |
194 |
195 | 90
196 | 300
197 | 150
198 | 30
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_NACA4Digit_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 390
13 | 150
14 |
15 |
16 |
17 |
18 | 390
19 | 150
20 |
21 |
22 |
23 |
24 | 390
25 | 150
26 |
27 |
28 |
29 | AeroFoil : NACA - 4 Digit
30 |
31 |
32 |
33 |
34 | 25
35 | 25
36 | 160
37 | 30
38 |
39 |
40 |
41 | Enter airfoil number :
42 |
43 |
44 |
45 |
46 |
47 | 255
48 | 100
49 | 100
50 | 30
51 |
52 |
53 |
54 | Next
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 100
62 | 100
63 | 30
64 |
65 |
66 |
67 | Back
68 |
69 |
70 |
71 |
72 |
73 | 195
74 | 25
75 | 160
76 | 30
77 |
78 |
79 |
80 | 4
81 |
82 |
83 | Qt::AlignCenter
84 |
85 |
86 |
87 |
88 | af_d2a_textbox
89 | af_d2a_next_button
90 | af_d2a_back_button
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_NACA5Digit_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 390
13 | 150
14 |
15 |
16 |
17 |
18 | 390
19 | 150
20 |
21 |
22 |
23 |
24 | 390
25 | 150
26 |
27 |
28 |
29 | AeroFoil : NACA - 5 Digit
30 |
31 |
32 |
33 |
34 | 25
35 | 25
36 | 160
37 | 30
38 |
39 |
40 |
41 | Enter airfoil number :
42 |
43 |
44 |
45 |
46 |
47 | 255
48 | 100
49 | 100
50 | 30
51 |
52 |
53 |
54 | Next
55 |
56 |
57 |
58 |
59 |
60 | 25
61 | 100
62 | 100
63 | 30
64 |
65 |
66 |
67 | Back
68 |
69 |
70 |
71 |
72 |
73 | 195
74 | 25
75 | 160
76 | 30
77 |
78 |
79 |
80 | 5
81 |
82 |
83 | Qt::AlignCenter
84 |
85 |
86 |
87 |
88 | af_d2b_textbox
89 | af_d2b_next_button
90 | af_d2b_back_button
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_PointsInput_Dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | true
7 |
8 |
9 |
10 | 0
11 | 0
12 | 425
13 | 222
14 |
15 |
16 |
17 |
18 | 425
19 | 222
20 |
21 |
22 |
23 |
24 | 425
25 | 222
26 |
27 |
28 |
29 | AeroFoil : Custom Points
30 |
31 |
32 |
33 |
34 | 295
35 | 180
36 | 100
37 | 30
38 |
39 |
40 |
41 | Next
42 |
43 |
44 |
45 |
46 |
47 | 25
48 | 180
49 | 100
50 | 30
51 |
52 |
53 |
54 | Back
55 |
56 |
57 |
58 |
59 |
60 | 30
61 | 120
62 | 201
63 | 25
64 |
65 |
66 |
67 | Mirror the Airfoil Profile
68 |
69 |
70 | false
71 |
72 |
73 | true
74 |
75 |
76 |
77 |
78 |
79 | 25
80 | 25
81 | 371
82 | 71
83 |
84 |
85 |
86 | QFrame::StyledPanel
87 |
88 |
89 | QFrame::Raised
90 |
91 |
92 |
93 |
94 | 25
95 | 10
96 | 191
97 | 30
98 |
99 |
100 |
101 | Import from :
102 |
103 |
104 |
105 |
106 |
107 | 225
108 | 10
109 | 125
110 | 25
111 |
112 |
113 |
114 | Text File (*.dat)
115 |
116 |
117 | true
118 |
119 |
120 | true
121 |
122 |
123 |
124 |
125 |
126 | 225
127 | 35
128 | 210
129 | 30
130 |
131 |
132 |
133 | CSV File (*.csv)
134 |
135 |
136 | false
137 |
138 |
139 |
140 |
141 |
142 | af_d2d_radio_1
143 | af_d2d_radio_2
144 | af_d2d_checkbox
145 | af_d2d_next_button
146 | af_d2d_back_button
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/ObjectCreation/AeroFoil_UI_Files/AeroFoil_mfb_img.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ObjectCreation/AeroFoil_UI_Files/AeroFoil_mfb_img.gif
--------------------------------------------------------------------------------
/ObjectCreation/AirfoilImportAndScale.FCMacro:
--------------------------------------------------------------------------------
1 | # This Macro, when run, will first provide the user with a file browser to
2 | # locate and select a .dat airfoil text file. Once selected, a chord length is
3 | # entered and upon pressing the OK button, a properly scaled airfoil is
4 | # produced. There are two versions provided here. Version 1.5 should work on
5 | # FreeCAD versions, 0.13 stable as well as all 0.14 versions. Version 2 should
6 | # only be used with FreeCAD versions equal to or greater than 0.14 3077 and
7 | # will work best with versions built with OCE/OCC versions 6.7 or greater (See
8 | # the Wiki page for all available version).
9 | #
10 | # (c) quick61
11 |
12 | __Name__ = 'Airfoil Import and Scale'
13 | __Comment__ = 'Imports and scales an Airfoil in the form of a Draft Wire (DWire) or Basic Spline (BSpline)'
14 | __Author__ = "quick61"
15 | __Version__ = '2.1.2'
16 | __Date__ = '2024-01-14'
17 | __License__ = ''
18 | __Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=22&t=5554'
19 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Airfoil_Import_%26_Scale'
20 | __Icon__ = ''
21 | __Help__ = ''
22 | __Status__ = 'stable'
23 | __Requires__ = 'freecad >= 0.14.3706'
24 | __Communication__ = ''
25 | __Files__ = ''
26 |
27 |
28 | import FreeCAD as app
29 | import FreeCADGui as gui
30 | from PySide import QtCore, QtGui # FreeCAD's PySide!
31 | import Draft # FreeCAD.
32 | import importAirfoilDAT # From the Draft module.
33 |
34 | # Select .dat airfoil data file to be imported
35 |
36 | # PySide returns a tuple (filename, filter) instead of just a string like in PyQt
37 | filename, filefilter = QtGui.QFileDialog.getOpenFileName(
38 | gui.getMainWindow(), 'Open An Airfoil File', '*.dat')
39 |
40 |
41 | class AirfoilImporterAndScaler():
42 |
43 | def __init__(self):
44 | self.dialog = None
45 |
46 | # Make dialog box and get the scale size
47 | self.dialog = QtGui.QDialog(gui.getMainWindow())
48 | self.dialog.resize(350, 100)
49 | self.dialog.setWindowTitle('Airfoil Import & Scale')
50 | layout = QtGui.QVBoxLayout(self.dialog)
51 | label = QtGui.QLabel('Chord Length')
52 | layout.addWidget(label)
53 | self.line_edit_scale = QtGui.QLineEdit()
54 | layout.addWidget(self.line_edit_scale)
55 |
56 | # Add radio buttons to select between DWire and BSpline
57 | self.radio_dwire = QtGui.QRadioButton('Make DWire')
58 | self.radio_bspline = QtGui.QRadioButton('Make BSpline')
59 |
60 | # set default to DWire & make radio buttons - Change self.radio1.setChecked(True) to
61 | # self.radio2.setChecked(True) to set BSpline as default
62 |
63 | self.radio_dwire.setChecked(True)
64 | layout.addWidget(self.radio_dwire)
65 | layout.addWidget(self.radio_bspline)
66 |
67 | # Add OK / Cancel buttons
68 | button_box = QtGui.QDialogButtonBox(self.dialog)
69 | button_box.setOrientation(QtCore.Qt.Horizontal)
70 | button_box.setStandardButtons(
71 | QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
72 | layout.addWidget(button_box)
73 | button_box.accepted.connect(self.proceed)
74 | button_box.rejected.connect(self.close)
75 | QtCore.QMetaObject.connectSlotsByName(self.dialog)
76 | self.dialog.show()
77 | self.dialog.exec_()
78 |
79 | def proceed(self):
80 | global filename
81 | if self.radio_dwire.isChecked():
82 | try:
83 | # This produces a scaled Airfoil with a DWire
84 | scalefactor = float(self.line_edit_scale.text())
85 | f1 = str(filename)
86 | importAirfoilDAT.insert(f1, 'Unnamed')
87 | Draft.scale(
88 | app.ActiveDocument.ActiveObject,
89 | delta=app.Vector(scalefactor, scalefactor, scalefactor),
90 | center=app.Vector(0, 0, 0),
91 | legacy=True)
92 | except Exception as e:
93 | app.Console.PrintError('Error, not a valid .dat file\n')
94 |
95 | self.close()
96 |
97 | if self.radio_bspline.isChecked():
98 | try:
99 | # This produces a scaled Airfoil with a BSpline
100 | scalefactor = float(self.line_edit_scale.text())
101 | f1 = str(filename)
102 | importAirfoilDAT.insert(f1, 'Unnamed')
103 | points = app.ActiveDocument.ActiveObject.Points
104 | Draft.makeBSpline(points, closed=True)
105 | Draft.scale(app.ActiveDocument.ActiveObject,
106 | delta=app.Vector(scalefactor, scalefactor, scalefactor),
107 | center=app.Vector(0, 0, 0),
108 | legacy=True)
109 | app.getDocument('Unnamed').removeObject('DWire')
110 | except:
111 | app.Console.PrintError('Error, not a valid .dat file\n')
112 |
113 | self.close()
114 |
115 | def close(self):
116 | self.dialog.hide()
117 |
118 |
119 | AirfoilImporterAndScaler()
120 |
--------------------------------------------------------------------------------
/ObjectCreation/BoxCreator.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | __Name__ = 'BoxCreator'
4 | __Comment__ = 'Creates a box with interlocked notches'
5 | __Author__ = 'christi'
6 | __Version__ = '1.3.7'
7 | __Date__ = '2023-01-03'
8 | __License__ = 'LGPL-3.0-or-later'
9 | __Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=31795'
10 | __Wiki__ = ''
11 | __Icon__ = 'BoxCreator.svg'
12 | __Help__ = 'Try it out and play with it. It should be self explanatory'
13 | __Status__ = 'Beta'
14 | __Requires__ = 'FreeCAD >= v0.17'
15 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?p=264483'
16 | __Files__ = 'BoxCreator.svg,boxcreator/__init__.py,boxcreator/boxcreator.py,boxcreator/boxcreator.ui'
17 |
18 |
19 | import os
20 |
21 | import FreeCAD as app
22 | import FreeCADGui as gui
23 | from FreeCAD import Vector
24 |
25 | from boxcreator import boxcreator
26 |
27 |
28 | class BoxcreatorDialog():
29 | """Show a dialog for BoxCreator"""
30 | def __init__(self):
31 | self.ui_file = os.path.join(app.getUserMacroDir(True),
32 | 'boxcreator/boxcreator.ui')
33 | self.form = gui.PySideUic.loadUi(self.ui_file)
34 | self._connect_widgets()
35 | self.form.show()
36 |
37 | def _connect_widgets(self):
38 | self.form.pushButtonCreate.pressed.connect(self.createBox)
39 | self.form.pushButton_CompartX.pressed.connect(self.compartmentX)
40 | self.form.pushButton_CompartY.pressed.connect(self.compartmentY)
41 | self.form.pushButton_CompartZ.pressed.connect(self.compartmentZ)
42 |
43 | def createBox(self):
44 | boxWidth = self.form.doubleSpinBoxWidth.value()
45 | boxHeight = self.form.doubleSpinBoxHeight.value()
46 | boxLength = self.form.doubleSpinBoxLength.value()
47 | notchWidth = self.form.doubleSpinBoxNotchWidth.value()
48 | materialWidth = self.form.doubleSpinBoxMaterialWidth.value()
49 | drawSides = [self.form.checkBoxTop.isChecked(),
50 | self.form.checkBoxBottom.isChecked(),
51 | self.form.checkBoxLeft.isChecked(),
52 | self.form.checkBoxRight.isChecked(),
53 | self.form.checkBoxFront.isChecked(),
54 | self.form.checkBoxBack.isChecked()]
55 | overhangTop = [self.form.overhangTopLeft.value(),
56 | self.form.overhangTopRight.value(),
57 | self.form.overhangTopFront.value(),
58 | self.form.overhangTopBack.value()]
59 | overhangBottom = [self.form.overhangBotLeft.value(),
60 | self.form.overhangBotRight.value(),
61 | self.form.overhangBotFront.value(),
62 | self.form.overhangBotBack.value()]
63 | if (boxWidth == 0) or (boxHeight == 0) or (boxLength == 0):
64 | app.Console.PrintError('Error! None of the values can be 0!')
65 | # we bail out without doing anything
66 | return
67 |
68 | box = boxcreator.create_box(materialWidth, boxWidth, boxHeight, boxLength, notchWidth, drawSides, overhangTop, overhangBottom, app.activeDocument())
69 | gui.Selection.clearSelection()
70 | gui.Selection.addSelection(box)
71 | gui.SendMsgToActiveView('ViewFit')
72 |
73 | def compartmentX(self):
74 | self.createCompartment(Vector(1,0,0))
75 |
76 | def compartmentY(self):
77 | self.createCompartment(Vector(0,1,0))
78 |
79 | def compartmentZ(self):
80 | self.createCompartment(Vector(0,0,1))
81 |
82 | def createCompartment(self, direction):
83 | box = gui.Selection.getSelection()
84 | notchWidth = self.form.doubleSpinBoxNotchWidth.value()
85 | materialWidth = self.form.doubleSpinBoxMaterialWidth.value()
86 | drawSides = [self.form.checkBoxTop.isChecked(),
87 | self.form.checkBoxBottom.isChecked(),
88 | self.form.checkBoxLeft.isChecked(),
89 | self.form.checkBoxRight.isChecked(),
90 | self.form.checkBoxFront.isChecked(),
91 | self.form.checkBoxBack.isChecked()]
92 | offset = self.form.compartmentOffset.value()
93 | boxsize = Vector(self.form.doubleSpinBoxWidth.value(), self.form.doubleSpinBoxLength.value(), self.form.doubleSpinBoxHeight.value())
94 | compartment = boxcreator.create_compartment(box, direction, offset, materialWidth, notchWidth, drawSides, boxsize)
95 | if compartment:
96 | gui.Selection.clearSelection()
97 | gui.Selection.addSelection(compartment)
98 |
99 |
100 | if __name__ == '__main__':
101 | d = BoxcreatorDialog()
102 |
--------------------------------------------------------------------------------
/ObjectCreation/EllipseCenter2Points.FCMacro:
--------------------------------------------------------------------------------
1 | __Name__ = 'Ellipse Center + 2 Points'
2 | __Comment__ = ''
3 | __Author__ = 'Eriossoltero'
4 | __Version__ = ''
5 | __Date__ = ''
6 | __License__ = 'LGPL-2.0-or-later'
7 | __Web__ = 'http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html'
8 | __Wiki__ = ''
9 | __Icon__ = ''
10 | __Help__ = ''
11 | __Status__ = ''
12 | __Requires__ = ''
13 | __Communication__ = ''
14 | __Files__ = ''
15 |
16 | import FreeCAD as app
17 | import FreeCADGui as gui
18 | import Part, PartGui
19 | from FreeCAD import Base
20 |
21 | # get the selected objects, with first selection for the trajectory and second for the section
22 | # Adapted from:
23 | # http://freecad-tutorial.blogspot.com/2011/12/engine-9-poly-v-belt.html
24 | s = gui.Selection.getSelection()
25 | try:
26 | sel1 = s[0].Shape
27 | sel2 = s[1].Shape
28 | sel3 = s[2].Shape
29 | except:
30 | app.Console.PrintError('Wrong selection')
31 |
32 | pt_center = sel1.Point
33 | pt_radmay = sel2.Point
34 | pt_radmen = sel3.Point
35 |
36 | # create Part object in the current document
37 | myObject = app.ActiveDocument.addObject('Part::Feature', 'Ellipse')
38 |
39 | # create a shape and assign it to the current document
40 | ellipse = Part.Ellipse(pt_radmay, pt_radmen, pt_center)
41 | myObject.Shape = ellipse.toShape()
42 |
--------------------------------------------------------------------------------
/ObjectCreation/HilbertCurve.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/ObjectCreation/ParabolaCreater.FCMacro:
--------------------------------------------------------------------------------
1 | __Name__ = 'Parabola Creater'
2 | __Comment__ = 'Parabola Creater'
3 | __Author__ = 'unknown'
4 | __Version__ = '1.0.1'
5 | __Date__ = '2019-02-02'
6 | __License__ = 'LGPL-2.0-or-later'
7 | __Web__ = ''
8 | __Wiki__ = ''
9 | __Icon__ = ''
10 | __Help__ = ''
11 | __Status__ = ''
12 | __Requires__ = ''
13 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
14 | __Files__ = ''
15 |
16 | import FreeCAD as app
17 | import Part, PySide
18 | from PySide import QtCore, QtGui
19 | from PySide.QtGui import QLineEdit, QRadioButton
20 |
21 |
22 | class ParabolaCreater():
23 | def __init__(self):
24 | self.dialog = None
25 |
26 | self.dialog = QtGui.QDialog()
27 | #self.dialog.resize(450,110)
28 |
29 | self.dialog.setWindowTitle("Parabola Creator")
30 | la = QtGui.QVBoxLayout(self.dialog)
31 |
32 | self.radio1 = QRadioButton("Make 2D Shape")
33 | self.radio2 = QRadioButton("Make 3D Revolution")
34 |
35 | # set default to "Make 2D Shape" & make radio buttons - Change self.radio1.setChecked(True) to
36 | # self.radio2.setChecked(True) to set "Make 3D Revolution" as default
37 |
38 | self.radio1.setChecked(True)
39 | la.addWidget(self.radio1)
40 | la.addWidget(self.radio2)
41 |
42 | iN1 = QtGui.QLabel("Range Of Curve - Minimum")
43 | la.addWidget(iN1)
44 | self.r1 = QtGui.QLineEdit()
45 | la.addWidget(self.r1)
46 | self.r1.setText('-3')
47 |
48 | iN2 = QtGui.QLabel("Range Of Curve - Maximum")
49 | la.addWidget(iN2)
50 | self.r2 = QtGui.QLineEdit()
51 | la.addWidget(self.r2)
52 | self.r2.setText('3')
53 |
54 | iN3 = QtGui.QLabel("Focus")
55 | la.addWidget(iN3)
56 | self.f1 = QtGui.QLineEdit()
57 | la.addWidget(self.f1)
58 | self.f1.setText('2')
59 |
60 | iN4 = QtGui.QLabel("Degrees of Revolve (Only valid for 3D Revolution)")
61 | la.addWidget(iN4)
62 | self.Dg = QtGui.QLineEdit()
63 | la.addWidget(self.Dg)
64 | self.Dg.setText('360')
65 |
66 | okbox = QtGui.QDialogButtonBox(self.dialog)
67 | okbox.setOrientation(QtCore.Qt.Horizontal)
68 | okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
69 | la.addWidget(okbox)
70 | QtCore.QObject.connect(okbox, QtCore.SIGNAL("accepted()"), self.makeHyp)
71 | QtCore.QObject.connect(okbox, QtCore.SIGNAL("rejected()"), self.close)
72 | QtCore.QMetaObject.connectSlotsByName(self.dialog)
73 | self.dialog.show()
74 | self.dialog.exec_()
75 |
76 | def makeHyp(self):
77 | if self.radio1.isChecked():
78 | try:
79 | tS1 = float(self.r1.text())
80 | tS2 = float(self.r2.text())
81 | fc = float(self.f1.text())
82 |
83 | para=Part.Parabola()
84 | para.Focal = fc
85 |
86 | shape=para.toShape(tS1,tS2)
87 | Part.show(shape)
88 | except:
89 | sayexc()
90 | app.Console.PrintError("Unable to complete task")
91 |
92 | self.close()
93 |
94 | if self.radio2.isChecked():
95 | try:
96 | tS1 = float(self.r1.text())
97 | tS2 = float(self.r2.text())
98 | fc = float(self.f1.text())
99 | Dg = float(self.Dg.text())
100 |
101 | para=Part.Parabola()
102 | para.Focal = fc
103 |
104 | shape=para.toShape(tS1,tS2)
105 | rev=shape.revolve(app.Vector(1,0,0),app.Vector(1,0,0),Dg) # revolve around X axis by number of degrees
106 | Part.show(rev)
107 | except:
108 | sayexc()
109 | app.Console.PrintError("Unable to complete task")
110 |
111 | self.close()
112 |
113 | def close(self):
114 | self.dialog.hide()
115 |
116 | if __name__ == '__main__':
117 | ParabolaCreater()
118 |
--------------------------------------------------------------------------------
/ObjectCreation/TimingGear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ObjectCreation/TimingGear.png
--------------------------------------------------------------------------------
/ObjectCreation/boxcreator/Readme.md:
--------------------------------------------------------------------------------
1 | # FreeCAD Box Creator Macro
2 |
3 | Creates a box with interlocked notches.
4 |
5 | 
6 |
7 | ## Installation
8 | In menu Tools select Addon Manager
9 | Select the Macros tab
10 | find Boxcreator in the list and click Install
11 |
12 | In menu Macro select Macros...
13 | Execute boxcreatorGUI.py
14 |
15 | ### Manual Installation
16 | Copy the .py files to your FreeCAD Macro directory (on Linux: ~/.FreeCAD/Macro)
17 |
18 | ## Support for Compartments
19 | 
--------------------------------------------------------------------------------
/ObjectCreation/boxcreator/__init__.py:
--------------------------------------------------------------------------------
1 | from . import boxcreator
2 |
--------------------------------------------------------------------------------
/ObjectCreation/boxcreator/boxcreator_screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ObjectCreation/boxcreator/boxcreator_screenshot.jpg
--------------------------------------------------------------------------------
/ObjectCreation/boxcreator/boxcreator_screenshot2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ObjectCreation/boxcreator/boxcreator_screenshot2.jpg
--------------------------------------------------------------------------------
/ObjectCreation/g3d/translations/g3d_en.txt:
--------------------------------------------------------------------------------
1 | ## Strings for translation into any language (English Strings)
2 |
3 | "3D Generator",
4 | "Select a sketch in 2 or 3 views:",
5 | "Front view - (Front/Rear):",
6 | "Check this box if you want to activate the front view and assign it a sketch",
7 | "Side view - (Right/Left):",
8 | "Check this box if you want to activate the side view and assign it a sketch",
9 | "Plan view - (Top/Bott):",
10 | "Check this box if you want to activate the plan view and assign it a sketch",
11 | "Tol. 3D (mm):",
12 | "Length in millimeters. This should not influence the final object. If you do not need this tolerance, set this value to 0",
13 | "Make a new group (folder) with views (sketches)",
14 | "Hide views when generating the solid",
15 | "Fusion (intersection)",
16 | "Version:",
17 | "Brief guide to use the script:",
18 | "Create a sketch for each view required to generate your 3D solid. At least two sketches will be required.",
19 | "Then click on the script icon and select a sketch for each view.",
20 | "Finally, press the OK button to generate the solid.",
21 | "Documentation:",
22 | "Offset",
23 | "Offset from the sketch plane from which the extrusion along the Y axis will start",
24 | "Length",
25 | "Total length of the frontal extrusion along the Y axis (it must be always larger than the frontal offset)",
26 | "Offset",
27 | "Offset from the sketch plane from which the extrusion along the X axis will start",
28 | "Length",
29 | "Total length of the lateral extrusion along the X axis (it must be always larger than the lateral offset)",
30 | "Offset",
31 | "Offset from the sketch plane from which the extrusion along the Z axis will start",
32 | "Length",
33 | "Total length of the vertical extrusion along the Z axis (it must be always larger than the vertical offset)",
34 | "3D-Part",
35 | "3D-Part_Views"
36 |
--------------------------------------------------------------------------------
/ObjectCreation/g3d/translations/g3d_es.txt:
--------------------------------------------------------------------------------
1 | ## Cadenas de traducción a cualquier idioma (Spanish Strings)
2 |
3 | "Generador 3D",
4 | "Seleccione un sketch (boceto) en 2 o 3 vistas:",
5 | "Frontal -Alzado- (Front/Rear):",
6 | "Marque esta casilla si quiere activar la vista frontal y asígnele un sketch (boceto)",
7 | "Lateral -Perfil- (Right/Left):",
8 | "Marque esta casilla si quiere activar la vista lateral y asígnele un sketch (boceto)",
9 | "Planta -Sup/Inf- (Top/Bott):",
10 | "Marque esta casilla si quiere activar la vista en planta y asígnele un sketch (boceto)",
11 | "Tol. 3D (mm.):",
12 | "Es la distancia en mm. que extruirá de más. No debe influir en el objeto final. Si no desea tolerancia, ponga este valor a 0",
13 | "Crear un Grupo (Carpeta) para las vistas (sketches)",
14 | "Ocultar las vistas al generar el sólido",
15 | "Fusión (interesección)",
16 | "Versión:",
17 | "Información Breve de Uso:",
18 | "Cree un boceto (sketch) para cada vista con la que desee generar un sólido 3D. Necesitará al menos 2 bocetos.",
19 | "Luego pinche en el icono del script y seleccione un boceto para cada vista.",
20 | "Finalmente, pulse OK para generar el sólido.",
21 | "Documentación:",
22 | "Offset FR",
23 | "Es la distancia desde la cual empezará la extrusión en el eje Y (desplazamiento en Y)",
24 | "Longitud FR",
25 | "Es la distancia total de extrusión frontal (en el eje Y), que siempre será mayor que el Offset Frontal",
26 | "Offset LAT",
27 | "Es la distancia desde la cual empezará la extrusión en el eje X (desplazamiento en X)",
28 | "Longitud LAT",
29 | "Es la distancia total de extrusión lateral (en el eje X), que siempre será mayor que el Offset Lateral",
30 | "Offset PL",
31 | "Es la distancia desde la cual empezará la extrusión en el eje Z (desplazamiento en Z)",
32 | "Longitud PL",
33 | "Es la distancia total de extrusión en planta (en el eje Z), que siempre será mayor que el Offset en Planta",
34 | "Pieza3D",
35 | "VistasPieza3D"
36 |
--------------------------------------------------------------------------------
/ObjectCreation/g3d/translations/g3d_it.txt:
--------------------------------------------------------------------------------
1 | ## Stringhe per la traduzione in qualsiasi lingua (stringhe in italiano)
2 |
3 | "Generatore 3D",
4 | "Seleziona uno schizzo in 2 o 3 viste:",
5 | "Vista frontale - (Fronte/Retro):",
6 | "Spunta questa casella se desideri utilizzare la vista frontale ed assegnarle uno schizzo",
7 | "Vista laterale - (Destra/Sinistra):",
8 | "Spunta questa casella se desideri utilizzare la vista laterale ed assegnarle uno schizzo",
9 | "Vista in pianta - (Alto/Basso):",
10 | "Spunta questa casella se desideri utilizzare la vista in pianta ed assegnarle uno schizzo",
11 | "Tol. 3D (mm.):",
12 | "Lunghezza in mm di sovraestrusione. Non dovrebbe influenzare l'oggetto finale. Se non si necessita questa tolleranza impostare il valore relativo a 0 mm",
13 | "Crea un nuovo gruppo (cartella) con le viste (sketch)",
14 | "Nasconde le viste quando viene generato il solido",
15 | "Fusione (intersezione)",
16 | "Versione:",
17 | "Breve guida all'uso dello script:",
18 | "Crea uno sketch per ogni vista necessaria a generare il solido. Sono necessari almeno due sketch.",
19 | "Quindi clicca sull'icona dello script e seleziona uno schizzo per ciascuna vista necessaria.",
20 | "Infine, premi il pulsante OK per generare il solido.",
21 | "Documentazione:",
22 | "Offset",
23 | "Distanza rispetto al piano dello sketch frontale da cui inizierà l'estrusione lungo l'asse Y (spostamento in Y)",
24 | "Lunghezza",
25 | "Lunghezza totale dell'estrusione frontale lungo l'asse Y (dovrà essere sempre più grande dell'offset frontale)",
26 | "Offset",
27 | "Distanza rispetto al piano dello sketch laterale da cui inizierà l'estrusione lungo l'asse X (spostamento in X)",
28 | "Lunghezza",
29 | "Lunghezza totale dell'estrusione laterale lungo l'asse X (dovrà essere sempre più grande dell'offset laterale)",
30 | "Offset",
31 | "Distanza rispetto al piano dello sketch in pianta da cui inizierà l'estrusione lungo l'asse Z (spostamento in Z)",
32 | "Lunghezza",
33 | "Lunghezza totale dell'estrusione verticale lungo l'asse Z (dovrà essere sempre più grande dell'offset in pianta)",
34 | "Pezzo3D",
35 | "Pezzo3D_Viste"
36 |
--------------------------------------------------------------------------------
/ParametricObjectCreation/GeodesicDome.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # ************************************************************************
4 | # * Copyright (c)2015 Ulrich Brammer *
5 | # * *
6 | # * This file is a supplement to the FreeCAD CAx development system. *
7 | # * *
8 | # * This program is free software; you can redistribute it and/or modify *
9 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
10 | # * as published by the Free Software Foundation; either version 2 of *
11 | # * the License, or (at your option) any later version. *
12 | # * for detail see the LICENCE text file. *
13 | # * *
14 | # * This software is distributed in the hope that it will be useful, *
15 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 | # * GNU Library General Public License for more details. *
18 | # * *
19 | # * You should have received a copy of the GNU Library General Public *
20 | # * License along with this macro; if not, write to the Free Software *
21 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22 | # * USA *
23 | # * *
24 | # ************************************************************************
25 |
26 | __Name__ = 'Geodesic Dome'
27 | __Comment__ = 'Geodesic Dome'
28 | __Author__ = 'Ulrich Brammer'
29 | __Version__ = '1.0.0'
30 | __Date__ = '2019-03-23'
31 | __License__ = 'LGPL-2.0-or-later'
32 | __Web__ = ''
33 | __Wiki__ = ''
34 | __Icon__ = ''
35 | __Help__ = ''
36 | __Status__ = ''
37 | __Requires__ = ''
38 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
39 | __Files__ = 'geodesic_dome/__init__.py,geodesic_dome/geodesic_dome.py'
40 |
41 | if __name__ == '__main__':
42 | #running as a macro. Load as module, to support save-restore.
43 | try:
44 | from geodesic_dome.geodesic_dome import GeodesicDome
45 | except ImportError as err:
46 | FreeCAD.Console.PrintError("Macro Geodesic Dome: failed to import MacroGeodesicDome.py. The parametric object will lose functionality after saving-loading your project, sorry.")
47 | else:
48 | from geodesic_dome.geodesic_dome import showDialog
49 | showDialog()
50 |
--------------------------------------------------------------------------------
/ParametricObjectCreation/HoneycombSolid.FCMacro:
--------------------------------------------------------------------------------
1 | """
2 | HoneycombSolid --> Honeycomb solid creator.
3 | (c) 2021 Christian González Di Antonio
4 |
5 | """
6 |
7 | __Name__ = 'HoneycombSolid'
8 | __Comment__ = 'Macro to create a Honeycomb solid'
9 | __Author__ = "Christian González Di Antonio "
10 | __Version__ = 'v1.2.0'
11 | __License__ = 'LGPL-2.0-or-later'
12 | __Web__ = 'https://github.com/christiangda/FreeCAD-macros-HoneycombSolid'
13 | __Wiki__ = 'https://github.com/christiangda/FreeCAD-macros-HoneycombSolid/blob/main/README.md'
14 | __Icon__ = 'HoneycombSolid.xpm'
15 | __Help__ = ''
16 | __Status__ = 'Stable'
17 | __Requires__ = ''
18 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
19 | __Files__ = 'honeycomb_solid/__init__.py,honeycomb_solid/honeycomb_solid.py'
20 | __Xpm__ = '''
21 | /* XPM */
22 | static const char * ViewProviderHoneycombSolid_xpm[] = {
23 | "16 16 54 1",
24 | " c None",
25 | ". c #181818",
26 | "+ c #5F5F5F",
27 | "@ c #636363",
28 | "# c #353535",
29 | "$ c #474747",
30 | "% c #434343",
31 | "& c #606060",
32 | "* c #424242",
33 | "= c #111111",
34 | "- c #444444",
35 | "; c #151515",
36 | "> c #3F3F3F",
37 | ", c #1E1E1E",
38 | "' c #1C1C1C",
39 | ") c #1B1B1B",
40 | "! c #2C2C2C",
41 | "~ c #535353",
42 | "{ c #0A0A0A",
43 | "] c #363636",
44 | "^ c #383838",
45 | "/ c #2F2F2F",
46 | "( c #252525",
47 | "_ c #555555",
48 | ": c #393939",
49 | "< c #515151",
50 | "[ c #262626",
51 | "} c #161616",
52 | "| c #464646",
53 | "1 c #4F4F4F",
54 | "2 c #545454",
55 | "3 c #3A3A3A",
56 | "4 c #131313",
57 | "5 c #121212",
58 | "6 c #5E5E5E",
59 | "7 c #0C0C0C",
60 | "8 c #0F0F0F",
61 | "9 c #0B0B0B",
62 | "0 c #0D0D0D",
63 | "a c #1D1D1D",
64 | "b c #292929",
65 | "c c #3D3D3D",
66 | "d c #222222",
67 | "e c #171717",
68 | "f c #1A1A1A",
69 | "g c #282828",
70 | "h c #272727",
71 | "i c #5A5A5A",
72 | "j c #3C3C3C",
73 | "k c #595959",
74 | "l c #616161",
75 | "m c #505050",
76 | "n c #2E2E2E",
77 | "o c #565656",
78 | " .+@@ #$ ",
79 | " %@&* =-$ ",
80 | " ;>,')!~& ",
81 | " {]^ /@@ ",
82 | "@ ($$ _@@ ",
83 | "@ :$ /@@ ",
84 | "<][}|1 2~3['",
85 | "445#6@ 78889",
86 | "% '&@@ #$ ",
87 | "$ $@@ 0-$ ",
88 | " a&@+ b$$ ",
89 | " c*[de>_ ",
90 | "@ fgh {i@@ ",
91 | "@ ^$ j@@ ",
92 | "@@ 4|$ {k@@ ",
93 | "lm ,n$ ]@o^["};
94 | '''
95 |
96 | import FreeCAD as app
97 |
98 |
99 | if __name__ == '__main__':
100 | # Running as a macro. Load as module, to support save-restore.
101 | try:
102 | from honeycomb_solid.honeycomb_solid import HoneycombSolid
103 | from honeycomb_solid.honeycomb_solid import ViewProviderHoneycombSolid
104 | except ImportError as err:
105 | app.Console.PrintError('Macro HoneycombSolid: failed to import module honeycomb_solid.honeycomb_solid\n')
106 | else:
107 | from honeycomb_solid.honeycomb_solid import makeHoneycombSolid
108 | makeHoneycombSolid(__Version__)
109 | if app.GuiUp:
110 | import FreeCADGui as gui
111 | gui.SendMsgToActiveView('ViewFit')
112 |
--------------------------------------------------------------------------------
/ParametricObjectCreation/HoneycombSolid.xpm:
--------------------------------------------------------------------------------
1 | /* XPM */
2 | static const char * ViewProviderHoneycombSolid_xpm[] = {
3 | "16 16 54 1",
4 | " c None",
5 | ". c #181818",
6 | "+ c #5F5F5F",
7 | "@ c #636363",
8 | "# c #353535",
9 | "$ c #474747",
10 | "% c #434343",
11 | "& c #606060",
12 | "* c #424242",
13 | "= c #111111",
14 | "- c #444444",
15 | "; c #151515",
16 | "> c #3F3F3F",
17 | ", c #1E1E1E",
18 | "' c #1C1C1C",
19 | ") c #1B1B1B",
20 | "! c #2C2C2C",
21 | "~ c #535353",
22 | "{ c #0A0A0A",
23 | "] c #363636",
24 | "^ c #383838",
25 | "/ c #2F2F2F",
26 | "( c #252525",
27 | "_ c #555555",
28 | ": c #393939",
29 | "< c #515151",
30 | "[ c #262626",
31 | "} c #161616",
32 | "| c #464646",
33 | "1 c #4F4F4F",
34 | "2 c #545454",
35 | "3 c #3A3A3A",
36 | "4 c #131313",
37 | "5 c #121212",
38 | "6 c #5E5E5E",
39 | "7 c #0C0C0C",
40 | "8 c #0F0F0F",
41 | "9 c #0B0B0B",
42 | "0 c #0D0D0D",
43 | "a c #1D1D1D",
44 | "b c #292929",
45 | "c c #3D3D3D",
46 | "d c #222222",
47 | "e c #171717",
48 | "f c #1A1A1A",
49 | "g c #282828",
50 | "h c #272727",
51 | "i c #5A5A5A",
52 | "j c #3C3C3C",
53 | "k c #595959",
54 | "l c #616161",
55 | "m c #505050",
56 | "n c #2E2E2E",
57 | "o c #565656",
58 | " .+@@ #$ ",
59 | " %@&* =-$ ",
60 | " ;>,')!~& ",
61 | " {]^ /@@ ",
62 | "@ ($$ _@@ ",
63 | "@ :$ /@@ ",
64 | "<][}|1 2~3['",
65 | "445#6@ 78889",
66 | "% '&@@ #$ ",
67 | "$ $@@ 0-$ ",
68 | " a&@+ b$$ ",
69 | " c*[de>_ ",
70 | "@ fgh {i@@ ",
71 | "@ ^$ j@@ ",
72 | "@@ 4|$ {k@@ ",
73 | "lm ,n$ ]@o^["};
74 |
--------------------------------------------------------------------------------
/ParametricObjectCreation/Rectellipse.FCMacro:
--------------------------------------------------------------------------------
1 | #
2 | # Creates a parametric Rectellipse
3 | # (c) fcaponi78
4 | #
5 | #
6 |
7 | from __future__ import division
8 |
9 | __Comment__ = 'Creates a parametric approximation of a rectellipse'
10 | __Web__ = 'http://freecadweb.org/wiki/Macro_Rectellipse'
11 | __Wiki__ = 'http://freecadweb.org/wiki/Macro_Rectellipse'
12 | __Icon__ = ""
13 | __Help__ = 'Run, zoom fit, and change parameters'
14 | __Author__ = 'fcaponi78, shoogen and other contributors'
15 | __Version__ = 0.1
16 | __Status__ = 'alpha'
17 | __Requires__ = ''
18 |
19 | import FreeCAD
20 | from FreeCAD import Part
21 | from FreeCAD import Vector
22 |
23 |
24 | class RectEllipseFeature:
25 | def __init__(self, obj):
26 | """Add the properties: a, b, s, createFace"""
27 | obj.addProperty('App::PropertyLength', 'a', 'Rectellipse',
28 | 'Horizontal radius').a = 16.0
29 | obj.addProperty('App::PropertyLength', 'b', 'Rectellipse',
30 | 'Vertical radius').b = 9.0
31 | obj.addProperty('App::PropertyFloat', 's', 'Rectellipse',
32 | 'Squareness (0=ellipse, 1=rectangle)').s = 0.2
33 | obj.addProperty('App::PropertyBool', 'createFace', 'Rectellipse',
34 | 'true => face; false => wire').createFace = True
35 | obj.Proxy = self
36 |
37 | def onChanged(self, feature, prop):
38 | if prop in ['a', 'b', 's', 'createFace']:
39 | self.execute(feature)
40 |
41 | def execute(self, feature):
42 | r1 = feature.a
43 | r2 = feature.b
44 | if feature.s < 0:
45 | feature.s = 0
46 | elif feature.s > 1:
47 | feature.s = 1
48 | z = 0.0
49 | # TODO: tweak p, so that the curve is the exact definition of a
50 | # rectellipse (if possible).
51 | p = 1.0
52 | # NURBS knots weigts.
53 | if feature.s > 0.9999999:
54 | # If larger than 1e7, we obtain a rhombus.
55 | w = 1e7
56 | else:
57 | w = 2 ** 0.5 / 2.0 / (1 - feature.s ** p)
58 | # TODO: use a real rectangle if feature.s close to 1.
59 | curve = Part.BSplineCurve()
60 | curve.setPeriodic()
61 | curve.increaseDegree(2)
62 | # 5 knots, 8 poles
63 | curve.insertKnots([i / 4 for i in (1, 2, 3)], [2] * 3)
64 | curve.setPole(1, Vector(0, -r2, z), 1)
65 | curve.setPole(2, Vector(-r1, -r2, z), w)
66 | curve.setPole(3, Vector(-r1, 0, z), 1)
67 | curve.setPole(4, Vector(-r1, r2, z), w)
68 | curve.setPole(5, Vector(0, r2, z), 1)
69 | curve.setPole(6, Vector(r1, r2, z), w)
70 | curve.setPole(7, Vector(r1, 0, z), 1)
71 | curve.setPole(8, Vector(r1, -r2, z), w)
72 | if feature.createFace:
73 | feature.Shape = Part.Face(Part.Wire(curve.toShape()))
74 | else:
75 | feature.Shape = curve.toShape()
76 |
77 |
78 | def makeRectellipseFeature():
79 | doc = FreeCAD.activeDocument()
80 | if doc is None:
81 | doc = FreeCAD.newDocument()
82 | if doc is None:
83 | return
84 | obj = doc.addObject('Part::FeaturePython', 'RectEllipseFeature')
85 | obj.Label = 'RectEllipse'
86 | RectEllipseFeature(obj)
87 | obj.ViewObject.Proxy = 0
88 |
89 | if __name__ == "__main__":
90 | makeRectellipseFeature()
91 |
--------------------------------------------------------------------------------
/ParametricObjectCreation/geodesic_dome/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/ParametricObjectCreation/geodesic_dome/__init__.py
--------------------------------------------------------------------------------
/ParametricObjectCreation/honeycomb_solid/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | HoneycombSolid --> Honeycomb solid creator.
3 | (c) 2021 Christian González Di Antonio
4 | """
--------------------------------------------------------------------------------
/PureGui/Camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera.png
--------------------------------------------------------------------------------
/PureGui/Camera/accept.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/accept.png
--------------------------------------------------------------------------------
/PureGui/Camera/align_object_to_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/align_object_to_view.png
--------------------------------------------------------------------------------
/PureGui/Camera/align_to_axis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/align_to_axis.png
--------------------------------------------------------------------------------
/PureGui/Camera/align_to_face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/align_to_face.png
--------------------------------------------------------------------------------
/PureGui/Camera/axis_rotation_d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/axis_rotation_d.png
--------------------------------------------------------------------------------
/PureGui/Camera/axis_rotation_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/axis_rotation_x.png
--------------------------------------------------------------------------------
/PureGui/Camera/axis_rotation_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/axis_rotation_y.png
--------------------------------------------------------------------------------
/PureGui/Camera/axis_rotation_z.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/axis_rotation_z.png
--------------------------------------------------------------------------------
/PureGui/Camera/create_plane_of_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/create_plane_of_view.png
--------------------------------------------------------------------------------
/PureGui/Camera/detect_orientation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/detect_orientation.png
--------------------------------------------------------------------------------
/PureGui/Camera/quit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/quit.png
--------------------------------------------------------------------------------
/PureGui/Camera/reset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/reset.png
--------------------------------------------------------------------------------
/PureGui/Camera/save_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/Camera/save_view.png
--------------------------------------------------------------------------------
/PureGui/GuiResetToolbars.FCMacro:
--------------------------------------------------------------------------------
1 | # Reset Toolbars position
2 | # Author: Milos Petrasinovic
3 | # PROTORS, Belgrade, Serbia
4 | # info@protors.co
5 | #
6 | # --------------------
7 | #
8 | # Copyright (C) 2020 PROTORS
9 | #
10 | # This program is free software: you can redistribute it and/or modify
11 | # it under the terms of the GNU Lesser General Public License as
12 | # published by the Free Software Foundation, either version 3 of the
13 | # License, or (at your option) any later version.
14 | #
15 | # This program is distributed in the hope that it will be useful,
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | # GNU Lesser General Public License for more details.
19 | #
20 | # You should have received a copy of the GNU Lesser General Public License
21 | # along with this program. If not, see .
22 | #
23 | # --------------------
24 |
25 | __Name__ = 'GuiResetToolbars'
26 | __Comment__ = 'Reset Toolbars position'
27 | __Author__ = 'PROTORS'
28 | __Version__ = '1.0.0'
29 | __Date__ = '2020-04-21'
30 | __License__ = 'LGPL-3.0-or-later'
31 | __Web__ = "https://github.com/protors/ResetToolbars/"
32 | __Wiki__ = 'https://wiki.freecadweb.org/Macro_GuiResetToolbars'
33 | __Icon__ = 'GuiResetToolbars.svg'
34 | __Help__ = 'Run the macro within a workbench that has missing toolbar(s)'
35 | __Status__ = 'stable'
36 | __Requires__ = 'Freecad >= 0.18.4'
37 | __Communication__ = 'https://github.com/protors/ResetToolbars/issues/'
38 | __Files__ = 'GuiResetToolbars.svg'
39 |
40 | import FreeCADGui as gui
41 | from PySide import QtGui, QtCore # FreeCAD's special PySide!
42 |
43 | mw = gui.getMainWindow()
44 | tb = mw.findChildren(QtGui.QToolBar)
45 | for i in tb:
46 | mw.addToolBar(QtCore.Qt.TopToolBarArea, i)
47 |
--------------------------------------------------------------------------------
/PureGui/GuiSpacemouseRotationOff.FCMacro:
--------------------------------------------------------------------------------
1 | # Run to deactivate rotations on Spacemouse device.
2 |
3 | __Name__ = 'Spacemouse Rotation Off'
4 | __Comment__ = 'Run to deactivate rotations on Spacemouse device.'
5 | __Author__ = 'tja2468,R3D3,galou_breizh'
6 | __Version__ = '1.0.0'
7 | __Date__ = '2021-11-01'
8 | __License__ = 'LGPL-2.0-or-later'
9 | __Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'
10 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'
11 | __Icon__ = ''
12 | __Help__ = 'Run to deactivate rotations on Spacemouse device.'
13 | __Status__ = 'production'
14 | __Requires__ = 'FreeCAD 0.20'
15 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'
16 | __Files__ = ''
17 |
18 | import FreeCAD as app
19 |
20 | # Activate rotations.
21 | app.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', False)
22 |
23 | # display message to convey status
24 | app.Console.PrintMessage('Spacemouse rotations disabled\n')
25 |
--------------------------------------------------------------------------------
/PureGui/GuiSpacemouseRotationOn.FCMacro:
--------------------------------------------------------------------------------
1 | # Run to activate rotations on Spacemouse device.
2 |
3 | __Name__ = 'Spacemouse Rotation On'
4 | __Comment__ = 'Run to activate rotations on Spacemouse device.'
5 | __Author__ = 'tja2468,R3D3,galou_breizh'
6 | __Version__ = '1.0.0'
7 | __Date__ = '2021-11-01'
8 | __License__ = 'LGPL-2.0-or-later'
9 | __Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'
10 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'
11 | __Icon__ = ''
12 | __Help__ = 'Run to activate rotations on Spacemouse device.'
13 | __Status__ = 'production'
14 | __Requires__ = 'FreeCAD 0.20'
15 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'
16 | __Files__ = ''
17 |
18 | import FreeCAD as app
19 |
20 | # Activate rotations.
21 | app.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', True)
22 |
23 | # display message to convey status
24 | app.Console.PrintMessage('Spacemouse rotations enabled\n')
25 |
--------------------------------------------------------------------------------
/PureGui/GuiSpacemouseRotationToggle.FCMacro:
--------------------------------------------------------------------------------
1 | # Run to toggle the activation of rotations on Spacemouse device.
2 |
3 | __Name__ = 'Spacemouse Rotation Toggle'
4 | __Comment__ = 'Run to toggle the activation of rotations on Spacemouse device.'
5 | __Author__ = 'tja2468,R3D3,galou_breizh'
6 | __Version__ = '1.0.0'
7 | __Date__ = '2021-11-01'
8 | __License__ = 'LGPL-2.0-or-later'
9 | __Web__ = 'http://forum.freecadweb.org/viewtopic.php?f=?&t=????'
10 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Title_Of_macro'
11 | __Icon__ = ''
12 | __Help__ = 'Run to toggle the activation of rotations on Spacemouse device.'
13 | __Status__ = 'production'
14 | __Requires__ = 'FreeCAD 0.20'
15 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=61482'
16 | __Files__ = ''
17 |
18 | import FreeCAD as app
19 |
20 | rotation_active = app.ParamGet('User parameter:BaseApp/Spaceball/Motion').GetBool('Rotations')
21 |
22 | # Toggle the activation state.
23 | app.ParamGet('User parameter:BaseApp/Spaceball/Motion').SetBool('Rotations', not rotation_active)
24 |
25 | # Display a message to convey the new status.
26 | if rotation_active:
27 | app.Console.PrintMessage('Spacemouse rotations disabled\n')
28 | else:
29 | app.Console.PrintMessage('Spacemouse rotations enabled\n')
30 |
--------------------------------------------------------------------------------
/PureGui/ViewRotationOut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/ViewRotationOut.png
--------------------------------------------------------------------------------
/PureGui/ViewRotationRight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/ViewRotationRight.png
--------------------------------------------------------------------------------
/PureGui/ViewRotationUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/PureGui/ViewRotationUp.png
--------------------------------------------------------------------------------
/Sketcher/SketchUnmap.FCMacro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #####################################
3 | # Copyright (c) openBrain 2019
4 | # Licensed under LGPL v2
5 | #
6 | # This FreeCAD macro will unmap a sketch from eg. a face and make its placement absolute in the body. It proposes 3 options (forcely the first if sketch not in a body) :
7 | # * "Raw" mode => the sketch placement is made absolute in the body referential, nothing more
8 | # * "DP@Face mode" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset
9 | # * "DP@Sketch" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin
10 | #
11 | # Main use of the macro is to make design more robust to topological naming issue
12 | #
13 | # Version history :
14 | # *0.6.2 : add icon (metadata)
15 | # *0.6.1 : minor changes after PR review
16 | # *0.6 : some typo improvement + commenting for official PR
17 | # *0.5 : beta release
18 | #
19 | #####################################
20 |
21 | __Name__ = 'SketchUnmap'
22 | __Comment__ = 'Unmap a sketch & makes its placement absolute"'
23 | __Author__ = 'openBrain'
24 | __Version__ = '0.6.2'
25 | __Date__ = '2019-06-14'
26 | __License__ = 'LGPL v2'
27 | __Web__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'
28 | __Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'
29 | __Icon__ = 'SketchUnmap.svg'
30 | __Help__ = 'Select the sketch to unmap (eg. in the tree view) then run the macro'
31 | __Status__ = 'Beta'
32 | __Requires__ = 'FreeCAD >= 0.17'
33 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=36078'
34 | # __Files__ = ''
35 |
36 | __dbg__ = False #True for debugging
37 |
38 | from PySide import QtGui
39 |
40 | def cslM(msg): #Print message in console
41 | FreeCAD.Console.PrintMessage('\n')
42 | FreeCAD.Console.PrintMessage(msg)
43 |
44 | def cslW(msg): #Print warning in console
45 | FreeCAD.Console.PrintMessage('\n')
46 | FreeCAD.Console.PrintWarning(msg)
47 |
48 | def cslE(msg): #Print error in console
49 | FreeCAD.Console.PrintMessage('\n')
50 | FreeCAD.Console.PrintError(msg)
51 |
52 | def cslD(msg): #Print debug message in console
53 | if __dbg__:
54 | FreeCAD.Console.PrintMessage('\n')
55 | FreeCAD.Console.PrintMessage("Debug : " + str(msg))
56 |
57 | _0Vec_ = FreeCAD.Vector(0, 0, 0) #Shortener for null vector
58 | _ZVec_ = FreeCAD.Vector(0, 0, 1) #Shortener for Z axis
59 |
60 | if __dbg__: ##Clear report view in debug mode
61 | FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, "Report view").clear()
62 |
63 | cslM("Starting SketchUnmap macro")
64 | cslD("Checking selection")
65 |
66 | ##If selection is wrong, print error message and exit
67 | if (len(Gui.Selection.getSelection()) != 1 or str(Gui.Selection.getSelection()[0]) != ''):
68 | cslE("You must select a sketch that you want to unmap (and only one) ... Exiting")
69 | else:
70 | cslD("Selection OK")
71 | App.ActiveDocument.openTransaction("SketchUnmap") #Open transaction for undo management
72 | sk = Gui.Selection.getSelection()[0] #Get target sketch
73 | skNatPl = sk.Placement #Store placement
74 | skNatAO = sk.AttachmentOffset #Store attachment offset
75 | skInBody = False
76 | for obj in sk.InList: ##Check if sketch is inside a Body
77 | if obj.TypeId == 'PartDesign::Body':
78 | skInBody = True
79 | skBody = obj
80 | cslD("Sketch in a body : " + str(skInBody))
81 | msgb = QtGui.QMessageBox() ##Prepare the message box to choose option
82 | msgb.setWindowTitle("Unmap Sketch : Mode selection")
83 | msgb.setText("""Choose which unmapping mode you want to apply :
84 | Raw => the sketch placement is made absolute in the body referential, nothing more
85 | DP@Face => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset
86 | DP@Sketch => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin
87 | Click 'Cancel' to cancel operation""")
88 | msgb.setIcon(QtGui.QMessageBox.Question)
89 | rbut = msgb.addButton("Raw", QtGui.QMessageBox.AcceptRole)
90 | fbut = msgb.addButton("DP@Face", QtGui.QMessageBox.AcceptRole)
91 | sbut = msgb.addButton("DP@Sketch", QtGui.QMessageBox.AcceptRole)
92 | cbut = msgb.addButton("Cancel", QtGui.QMessageBox.RejectRole)
93 | if skInBody: #If sketch in a Body
94 | msgb.exec_() ##Show message box and get user choice
95 | msgbRep = msgb.clickedButton()
96 | else:
97 | msgbRep = rbut #Else apply raw mode automatically
98 | if msgbRep == rbut: #If raw mode
99 | sk.Support = None ##Just unmap the sketch so its placement is absolute
100 | sk.MapMode = 'Deactivated'
101 | elif msgbRep == fbut: #If DP@Face mode
102 | newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane
103 | if sk.Label != sk.Name: ##Eventually clarify its label
104 | newDP.Label = 'DP' + sk.Label
105 | newDP.Support = None ##Plane is placed absolute
106 | newDP.MapMode = 'Deactivated'
107 | newDP.Placement = skNatPl.multiply(skNatAO.inverse()) #Plane placement is set to former face one
108 | sk.Support = [(newDP,'')] #Sketch is mapped to plane keeping its attachment offset
109 | elif msgbRep == sbut: #If DP@Sketch mode
110 | newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane
111 | if sk.Label != sk.Name: ##Eventually clarify its label
112 | newDP.Label = 'DP' + sk.Label
113 | newDP.Support = None ##Plane is placed absolute
114 | newDP.MapMode = 'Deactivated'
115 | newDP.Placement = skNatPl #Plane placement is set to former sketch one
116 | sk.Support = [(newDP,'')] ##Sketch is mapped to plane resetting its attachment offset
117 | sk.AttachmentOffset = App.Placement(_0Vec_, App.Rotation(_ZVec_, 0))
118 | App.ActiveDocument.commitTransaction() #Commit transaction for undo management
119 | cslM("SketchUnmap Macro ended correctly")
120 |
--------------------------------------------------------------------------------
/Sketcher/SketcherBlockAll.FCMacro:
--------------------------------------------------------------------------------
1 | # Add a block constraint on all the geometry elements of a sketch.
2 |
3 | __Name__ = 'Sketcher Block All'
4 | __Comment__ = 'Add a block constraint on all the geometry elements of a sketch.'
5 | __Author__ = 'galou_breizh'
6 | __Version__ = '1.0.0'
7 | __Date__ = '2021-11-20'
8 | __License__ = 'LGPL-2.0-or-later'
9 | __Web__ = ''
10 | __Wiki__ = ''
11 | __Icon__ = ''
12 | __Help__ = ''
13 | __Status__ = ''
14 | __Requires__ = 'FreeCAD >=0.19'
15 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
16 | __Files__ = ''
17 |
18 | from typing import Optional
19 |
20 | import FreeCAD as app
21 |
22 | import FreeCADGui as gui
23 |
24 | import Sketcher
25 |
26 |
27 | def get_sketch() -> Optional[Sketcher.Sketch]:
28 | """Get the opened or selected sketch."""
29 | active_workbench = gui.activeWorkbench()
30 | if active_workbench.name() == 'SketcherWorkbench':
31 | # ActiveSketch is defined by the Sketcher Workbench.
32 | return ActiveSketch
33 | else:
34 | sel = gui.Selection.getSelection()
35 | if sel and sel[0].TypeId == 'Sketcher::SketchObject':
36 | return sel[0]
37 |
38 |
39 | def block_sketch(sketch: Sketcher.Sketch) -> None:
40 | """Add a 'Block' constraint on all geometry elements."""
41 | for i in range(len(sketch.Geometry)):
42 | try:
43 | sketch.addConstraint(Sketcher.Constraint('Block', i))
44 | except:
45 | pass
46 |
47 |
48 | sketch = get_sketch()
49 | if sketch is not None:
50 | block_sketch(sketch)
51 | else:
52 | app.Console.PrintWarning('No sketch selected, doing nothing')
53 |
54 |
--------------------------------------------------------------------------------
/Sketcher/SketcherClipView.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | ###############################################
4 | #
5 | # SketcherClipView
6 | #
7 | # This macro creates a temporary cross section at the
8 | # sketch plane in order to 'look into' an object when you
9 | # want to create a feature on the inside (i.e. create a revolved
10 | # groove on the inner side of a tube).
11 | #
12 | # The macro creates a clipping plane at the sketch plane and
13 | # activates it. Running the macro again deletes the clipping plane.
14 | #
15 | # If you map the macro to F7 it behaves almost exactly like
16 | # in Autodesk Inventor, from which I got the inspiration.
17 | #
18 | # (c) Ricardo Beck
19 | #################################################
20 |
21 | __Name__ = 'Sketcher Clip View'
22 | __Comment__ = 'Creates a temporary clipping plane at the support plane of the sketch'
23 | __License__ = ''
24 | __Web__ = 'https://forum.freecadweb.org/viewtopic.php?t=26608'
25 | __Wiki__ = ''
26 | __Icon__ = 'SketcherClipView.svg'
27 | __Help__ = 'Launch while editing a sketch'
28 | __Author__ = 'Ricardo Beck, galou_breizh'
29 | __Version__ = '1.1.0'
30 | __Date__ = '2018-05-29'
31 | __Status__ = 'Beta'
32 | __Requires__ = 'FreeCAD >= v0.17'
33 | __Files__ = 'SketcherClipView.svg'
34 |
35 | from pivy import coin
36 |
37 | import freecad as fc
38 | import FreeCAD as app
39 | import FreeCADGui as gui
40 | from PySide import QtCore
41 |
42 |
43 | def in_edit_mode():
44 | """Return True if the Sketcher is in edit mode
45 |
46 | This is done by checking whether ActiveSketch is defined and
47 | ActiveSketch.ViewObject.TempoVis is not None.
48 | """
49 | in_edit_mode = False
50 | try:
51 | in_edit_mode = (ActiveSketch.ViewObject.TempoVis is not None)
52 | except NameError:
53 | pass
54 | return in_edit_mode
55 |
56 |
57 | def check_leave_edit():
58 | if not in_edit_mode():
59 | clean()
60 |
61 |
62 | def clean():
63 | if hasattr(fc, 'SketcherClipView_clip_plane'):
64 | gui.activeDocument().ActiveView.getSceneGraph().removeChild(fc.SketcherClipView_clip_plane)
65 | del fc.SketcherClipView_clip_plane
66 | del fc.SketcherClipView_timer
67 |
68 |
69 | def main():
70 | # Check if there is a temporary clipping plane from a previous run of the
71 | # macro.
72 | if hasattr(fc, 'SketcherClipView_clip_plane'):
73 | # Clipping plane found, remove from scenegraph and delete the object.
74 | clean()
75 | return
76 |
77 | if not in_edit_mode():
78 | return
79 |
80 | # No clipping plane found, create one at the sketch base.
81 |
82 | # Get the placement information of the active sketch.
83 | try:
84 | mat = ActiveSketch.getGlobalPlacement()
85 | except NameError:
86 | # ActiveSketch undefined (i.e. not in sketch editing mode).
87 | return
88 | point = mat.Base
89 | normal = mat.Rotation.multVec(app.Vector(0, 0, 1))
90 |
91 | # Create coin3d vectors of the sketch position.
92 | coin_normal_vector = coin.SbVec3f(normal.x, normal.y, normal.z)
93 | coin_normal_vector.negate()
94 | coin_base_point = coin.SbVec3f(point.x, point.y, point.z)
95 |
96 | # Offset of the clipping plane so the sketch elements (lines, etc) are not cut off.
97 | sketch_offset_factor = -0.02
98 |
99 | coin_normal_vector_normalized = coin.SbVec3f(coin_normal_vector)
100 | coin_normal_vector_normalized.normalize()
101 |
102 | # Offset the clipping plane base by a fraction of the (normalized) normal vector.
103 | coin_base_point += (coin_normal_vector_normalized * sketch_offset_factor)
104 |
105 | # Create the clipping plane at the calculated position.
106 | fc.SketcherClipView_clip_plane = coin.SoClipPlane()
107 | fc.SketcherClipView_clip_plane.plane.setValue(coin.SbPlane(coin_normal_vector,coin_base_point))
108 | gui.activeDocument().ActiveView.getSceneGraph().insertChild(fc.SketcherClipView_clip_plane, 0)
109 |
110 | # Switch clipping plane on.
111 | fc.SketcherClipView_clip_plane.on.setValue(True)
112 |
113 | fc.SketcherClipView_timer = QtCore.QTimer()
114 | fc.SketcherClipView_timer.timeout.connect(check_leave_edit)
115 | fc.SketcherClipView_timer.start(100) # Pool every 100 ms.
116 |
117 | if __name__ == '__main__':
118 | main()
119 |
--------------------------------------------------------------------------------
/Sketcher/SketcherFixAllPoints.FCMacro:
--------------------------------------------------------------------------------
1 | __Name__ = 'SketcherFixAllPoints'
2 | __Author__ = 'edi'
3 | __Version__ = '0.0.3'
4 | __Date__ = '2021-11-20'
5 | __License__ = 'LGPL v2'
6 | __Web__ = 'https://forum.freecadweb.org/viewtopic.php?f=13&t=52451'
7 | __Icon__ = ''
8 | __Help__ = 'Open a sketch. Start the macro. All geometry is fixed by constraints.'
9 | __Status__ = 'Stable'
10 | __Requires__ = 'e.g. FreeCAD >= v0.19'
11 | __Files__ = 'SketcherFixAllPoints.svg'
12 | """
13 | This macro is intended to constrain automatically created, incompletely contrained sketches.
14 | The sketches usually have been imported from IGES, STEP or DXF files.
15 |
16 | All existing external constraints will be deleted.
17 | All points defining the sketch obtain a 'DistanceX' and 'DistanceY' constraint.
18 | Points positioned on two elements are connected using a 'Coincident' constraint.
19 | Circles obtain a 'Diameter' constraint.
20 |
21 | Workflow:
22 | - Open a sketch or select a sketch in the model tree
23 | - Start the macro
24 |
25 | Hint: The created sketch may be over constrained. In this case drag an element.
26 | The redundant constraints will be deleted automatically.
27 |
28 | """
29 |
30 | from typing import List
31 |
32 | import FreeCAD as app
33 |
34 | import FreeCADGui as gui
35 |
36 | g_all_points: List['Point'] = []
37 |
38 |
39 | class Point:
40 | """Defining a Point object, containing its position and element id's."""
41 | def __init__(self, pos, geo_id, pt_id):
42 | self.pos = pos
43 | self.ident = []
44 | self.extend(geo_id, pt_id)
45 |
46 | def extend(self, geo_id, pt_id):
47 | self.ident.append([geo_id, pt_id])
48 |
49 |
50 | def addPoint(pos, geo_id, pt_id):
51 | """Add a Point to the g_all_points list."""
52 | pt = Point(pos, geo_id, pt_id)
53 | # Extend an existing point if at the same position.
54 | for existing_pt in g_all_points:
55 | if pt.pos.isEqual(existing_pt.pos, 0.01):
56 | existing_pt.extend(geo_id, pt_id)
57 | return
58 | # No point at the same position, add a point.
59 | g_all_points.append(pt)
60 |
61 |
62 | def get_sketch():
63 | """Get the opened or selected sketch."""
64 | active_workbench = gui.activeWorkbench()
65 | if active_workbench.name() == 'SketcherWorkbench':
66 | # ActiveSketch is defined by the Sketcher Workbench.
67 | return ActiveSketch
68 | else:
69 | sel = gui.Selection.getSelection()
70 | if sel and sel[0].TypeId == 'Sketcher::SketchObject':
71 | return sel[0]
72 |
73 |
74 | def delete_constraints(sketch):
75 | """Delete all external constraints."""
76 | internals = []
77 | for i in range(sketch.ConstraintCount):
78 | if sketch.Constraints[0].Type == 'InternalAlignment':
79 | internals.append(sketch.Constraints[0])
80 | sketch.delConstraint(0)
81 | sketch.addConstraint(internals)
82 |
83 |
84 | def get_elements(sketch):
85 | """Add points of next geometry to list of points."""
86 | for i, geo in enumerate(sketch.Geometry):
87 | if geo.TypeId == 'Part::GeomLineSegment':
88 | addPoint(geo.StartPoint, i, 1)
89 | addPoint(geo.EndPoint, i, 2)
90 | elif geo.TypeId == 'Part::GeomArcOfCircle':
91 | addPoint(geo.StartPoint, i, 1)
92 | addPoint(geo.EndPoint, i, 2)
93 | addPoint(geo.Center, i, 3)
94 | elif geo.TypeId == 'Part::GeomCircle':
95 | addPoint(geo.Center, i, 3)
96 |
97 |
98 | def make_constraints(sketch):
99 | """Create the new constraints."""
100 | for pt in g_all_points:
101 | sketch.addConstraint(Sketcher.Constraint('DistanceX',
102 | pt.ident[0][0], pt.ident[0][1], pt.pos.x))
103 | sketch.addConstraint(Sketcher.Constraint('DistanceY',
104 | pt.ident[0][0], pt.ident[0][1], pt.pos.y))
105 | if len(pt.ident) > 1:
106 | sketch.addConstraint(Sketcher.Constraint('Coincident',
107 | pt.ident[0][0], pt.ident[0][1], pt.ident[1][0], pt.ident[1][1]))
108 |
109 |
110 | def make_diameters(sketch):
111 | """Diameter constraints for all circles."""
112 | for i, geo in enumerate(sketch.Geometry):
113 | if geo.TypeId == 'Part::GeomCircle':
114 | sketch.addConstraint(Sketcher.Constraint('Diameter', i, geo.Radius * 2))
115 |
116 |
117 | sketch = get_sketch()
118 | if sketch is not None:
119 | delete_constraints(sketch)
120 | get_elements(sketch)
121 | make_constraints(sketch)
122 | make_diameters(sketch)
123 | app.activeDocument().recompute()
124 | else:
125 | app.Console.PrintWarning('No sketch selected, doing nothing')
126 |
--------------------------------------------------------------------------------
/SolidSweep.FCMacro:
--------------------------------------------------------------------------------
1 | import Part, FreeCAD, math, PartGui, FreeCADGui
2 | from FreeCAD import Base
3 |
4 | # get the selected objects, with first selection for the trajectory and second for the section
5 | s = FreeCADGui.Selection.getSelection()
6 | try:
7 | shape1=s[0].Shape
8 | shape2=s[1].Shape
9 | except:
10 | print "Wrong selection"
11 |
12 | traj = Part.Wire([shape1])
13 | section = Part.Wire([shape2])
14 |
15 | # create Part object in the current document
16 | myObject=App.ActiveDocument.addObject("Part::Feature","Sweep")
17 |
18 | # variable makeSolid = 1 to create solid, 0 to create surfaces
19 | makeSolid = True #1
20 | isFrenet = True #1
21 |
22 | # create a 3D shape and assigh it to the current document
23 | Sweep = Part.Wire(traj).makePipeShell([section],makeSolid,isFrenet)
24 | myObject.Shape = Sweep
25 |
--------------------------------------------------------------------------------
/Spreadsheet/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/Spreadsheet/.gitkeep
--------------------------------------------------------------------------------
/TechDraw/LasercutterSVGExport.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | __Name__ = 'LasercutterSVGExport'
4 | __Comment__ = 'Creates contour lines for all selected objects and arranges them on a TechDraw page'
5 | __Author__ = 'christi'
6 | __Version__ = '0.7.0'
7 | __Date__ = '2022-03-03'
8 | __License__ = 'LGPL-3.0-or-later'
9 | __Web__ = 'https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw'
10 | __Wiki__ = 'https://github.com/FreeCAD/FreeCAD-macros/tree/master/TechDraw/LasercutterSVGExport'
11 | __Icon__ = 'LasercutterSVGExport.svg'
12 | __Help__ = 'LasercutterSVGExport/README.md'
13 | __Status__ = 'Alpha'
14 | __Requires__ = 'FreeCAD >= v0.18'
15 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=15&t=31796'
16 | __Files__ = 'LasercutterSVGExport/LasercutterTechdrawExport.py,LasercutterSVGExport/README.md,LasercutterSVGExport/LasercutterSVGExport_screenshot.png,LasercutterSVGExport/lasercuttersvg.ui,LasercutterSVGExport.svg'
17 |
18 | # compatible to Python 3
19 |
20 | import FreeCAD as app
21 | import FreeCADGui as gui
22 | from LasercutterSVGExport import LasercutterTechdrawExport
23 |
24 | iconPath = os.path.dirname(__file__)
25 |
26 |
27 | class LasercutterSVGExport():
28 | def Activated(self):
29 | '''Will be called when the feature is executed.'''
30 | self.ui_file = os.path.join(iconPath, 'LasercutterSVGExport', 'lasercuttersvg.ui')
31 | self.form = gui.PySideUic.loadUi(self.ui_file)
32 | self.form.pushButton.pressed.connect(self.makeExport)
33 | self.form.show()
34 |
35 | def IsActive(self):
36 | '''Here you can define if the command must be active or not (greyed) if certain conditions
37 | are met or not. This function is optional.'''
38 | if app.activeDocument():
39 | return(True)
40 | else:
41 | return(False)
42 |
43 | def makeExport(self):
44 | # Generate commands in the FreeCAD python console to create LasercutterTechdrawExport
45 | gui.doCommand('from LasercutterSVGExport import LasercutterTechdrawExport')
46 |
47 | gui.doCommand('lcparts = []')
48 | selection = gui.Selection.getSelectionEx()
49 | for sel in selection:
50 | gui.doCommand("lcparts.append(FreeCAD.ActiveDocument.getObject('%s'))"%(sel.ObjectName))
51 |
52 | gui.doCommand(f'LasercutterTechdrawExport.makeLasercutterTechdrawExport(lcparts, BeamWidth={self.form.doubleSpinBox.value()}, doc=FreeCAD.activeDocument())')
53 | self.form.close()
54 |
55 |
56 | if __name__ == '__main__':
57 | lc = LasercutterSVGExport()
58 | lc.Activated()
59 |
--------------------------------------------------------------------------------
/TechDraw/LasercutterSVGExport/LasercutterSVGExport_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/TechDraw/LasercutterSVGExport/LasercutterSVGExport_screenshot.png
--------------------------------------------------------------------------------
/TechDraw/LasercutterSVGExport/README.md:
--------------------------------------------------------------------------------
1 | # FreeCAD Lasercutter SVG Export Macro
2 |
3 | We have a lasercutter that uses .svg files as input.
4 | I would like to generate .svg files from my FreeCAD designs.
5 | The laser beam width has to be considered, but I do not want to add it in my design.
6 |
7 | I have created a script that is doing this task:
8 |
9 | * Select several parts in the FreeCAD design
10 | * Create 3D outline objects from all selected items
11 | * Rotate them into the XY-plane
12 | * Create views in a TechDraw page
13 | * Arrange the views to fit in the page with minimal gaps
14 |
15 | 
16 |
17 | ## Installation
18 | In FreeCAD, select the Addon manager from tools menu. Go to the Macros tab and find LasercutterSVGExport in the list. Click Install.
19 |
20 | or
21 | Copy LasercutterSVGExport.FCMacro and the LasercutterSVGExport folder to your FreeCAD Macro directory (on Linux: ~/.FreeCAD/Macro)
22 | In menu Macro select Macros...
23 | Execute LasercutterSVGExport.FCMacro
24 |
25 | ## Usage
26 | Do not add the laserbeam width into your design. This export tool will add the beam width.
27 |
28 | * Select several parts in the FreeCAD design
29 | * Creates outline objects from all selected items
30 | * Rotate them into the XY-plane
31 | * Create views in a TechDraw page
32 | * Arrange the views to fit in the page with minimal gaps
33 |
34 | The tool creates a folder LaserCutterExportObjects that contains an object for each selected part.
35 | There are some parameters which can be changed:
36 | * Part: Selected part
37 | * Beam Width: The width of the laser beam in mm
38 | * Normal: A vector perpendicular to the object
39 | * Method: How to create the outline
40 | *auto*: find the best method automatically
41 | *2D*: works for 2D objects
42 | *3D*: create a 3D outline and then get the biggest face
43 | *face*: find the biggest face and create a 2D offset
44 | *normal*: manually define parameter Normal and use it as a perpendicular vector to the object
45 |
46 | #### Troubleshooting
47 | Find your part in the folder LaserCutterExportObjects and play with the parameters.
48 |
49 | *Got the wrong side of your part:*
50 | Set method to normal and change the parameter Normal to be perpendicular to the wanted side
51 |
52 | *Missing lines or no view at all in Techdraw:*
53 | Change the parameter method. Try out different settings.
54 |
55 | ## Discussion
56 | [Dedicated FreeCAD forum discussion thread](https://forum.freecadweb.org/viewtopic.php?f=35&t=31869)
57 |
58 | ## License
59 | GNU Lesser General Public License v3.0
60 |
61 |
62 |
--------------------------------------------------------------------------------
/TechDraw/LasercutterSVGExport/lasercuttersvg.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 246
10 | 178
11 |
12 |
13 |
14 | Create Lasercutter SVG Export Template
15 |
16 |
17 | -
18 |
19 |
20 | Laser beam width [mm]:
21 |
22 |
23 |
24 | -
25 |
26 |
27 | 0.200000000000000
28 |
29 |
30 |
31 | -
32 |
33 |
34 | Create Lasercutter Template
35 |
36 |
37 |
38 | -
39 |
40 |
41 | <html><head/><body><p align="center">Select one or more parts in your design.<br/>Then press the button.</p></body></html>
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/TechDraw/TechDrawAnnoTextFromv018.FCMacro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # ***************************************************************************
5 | # * *
6 | # * Copyright (c) 2022 - Wanderer Fan *
7 | # * *
8 | # * This program is free software; you can redistribute it and/or modify *
9 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
10 | # * as published by the Free Software Foundation; either version 2 of *
11 | # * the License, or (at your option) any later version. *
12 | # * for detail see the LICENCE text file. *
13 | # * *
14 | # * This program is distributed in the hope that it will be useful, *
15 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 | # * GNU Library General Public License for more details. *
18 | # * *
19 | # * You should have received a copy of the GNU Library General Public *
20 | # * License along with this program; if not, write to the Free Software *
21 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22 | # * USA *
23 | # * *
24 | # ***************************************************************************
25 | """Migrates Annotation Text made in FreeCAD v0.18 to v0.19."""
26 |
27 | __Name__ = 'TechDrawAnnoTextFromv018'
28 | __Comment__ = 'Convert v018 Annotation Text size to v019'
29 | __Author__ = 'WandererFan'
30 | __Version__ = '0.1.0'
31 | __License__ = 'CC-BY-3.0'
32 | __Web__ = 'http://www.freecadweb.org/'
33 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawAnnoTextFromv018'
34 | __Icon__ = ''
35 | __Help__ = 'Open a v018 file in v019, execute'
36 | __Status__ = 'Alpha'
37 | __Requires__ = ''
38 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
39 | __Files__ = ''
40 |
41 | # font sizes were once set using QFont.setPointSize but are now set using QFont.setPixelSize.
42 | # text set the old way will be bigger than text set the new way since points are bigger than
43 | # pixels. This macro adjusts the text size in old files to give approximately the same size
44 | # result.
45 |
46 | import FreeCAD as App
47 | import TechDraw
48 |
49 | def TechDrawAnnoTextFromv018():
50 | factor = 96.0/72.0 # pixels/inch vs points/inch
51 | for obj in App.ActiveDocument.Objects:
52 | if obj.isDerivedFrom("TechDraw::DrawViewAnnotation"):
53 | oldSize = obj.TextSize
54 | obj.TextSize = oldSize * factor
55 | if obj.isDerivedFrom("TechDraw::DrawViewDimension"):
56 | oldSize = obj.ViewObject.Fontsize
57 | obj.ViewObject.Fontsize = oldSize * factor
58 | if obj.isDerivedFrom("TechDraw::DrawViewBalloon"):
59 | oldSize = obj.ViewObject.Fontsize
60 | obj.ViewObject.Fontsize = oldSize * factor
61 |
62 |
63 | if __name__ == '__main__':
64 | TechDrawAnnoTextFromv018()
65 | App.ActiveDocument.recompute()
66 |
67 |
--------------------------------------------------------------------------------
/TechDraw/TechDrawMigrateFromv018.FCMacro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # ***************************************************************************
5 | # * *
6 | # * Copyright (c) 2022 - Wanderer Fan *
7 | # * *
8 | # * This program is free software; you can redistribute it and/or modify *
9 | # * it under the terms of the GNU Lesser General Public License (LGPL) *
10 | # * as published by the Free Software Foundation; either version 2 of *
11 | # * the License, or (at your option) any later version. *
12 | # * for detail see the LICENCE text file. *
13 | # * *
14 | # * This program is distributed in the hope that it will be useful, *
15 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 | # * GNU Library General Public License for more details. *
18 | # * *
19 | # * You should have received a copy of the GNU Library General Public *
20 | # * License along with this program; if not, write to the Free Software *
21 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22 | # * USA *
23 | # * *
24 | # ***************************************************************************
25 | """Migrates drawings made in FreeCAD v0.18 to v0.19."""
26 |
27 | __Name__ = 'TechDrawMigrateFromv018'
28 | __Comment__ = 'Convert v018 Rotation property to v019'
29 | __Author__ = 'WandererFan'
30 | __Version__ = '0.1.0'
31 | __License__ = 'CC-BY-3.0'
32 | __Web__ = 'http://www.freecadweb.org/'
33 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'
34 | __Icon__ = ''
35 | __Help__ = 'Open a v018 file in v019, execute'
36 | __Status__ = 'Alpha'
37 | __Requires__ = ''
38 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
39 | __Files__ = ''
40 |
41 |
42 | # convert v0.18 Rotation values to v0.19
43 |
44 | import FreeCAD as App
45 | import TechDraw
46 |
47 | def TechDrawMigrateFromv018():
48 | increment = App.Units.Quantity(270, App.Units.Unit("deg"))
49 | for obj in App.ActiveDocument.Objects:
50 | if obj.isDerivedFrom("TechDraw::DrawViewSection"):
51 | if obj.Rotation != 0.0:
52 | obj.Rotation = obj.Rotation + increment
53 | obj.touch()
54 | for inObj in obj.InList:
55 | if obj.isDerivedFrom("TechDraw::DrawViewDimension"):
56 | inObj.touch()
57 | elif obj.isDerivedFrom("TechDraw::DrawViewPart"):
58 | if obj.Rotation != 0.0:
59 | obj.Rotation = -obj.Rotation
60 | obj.touch()
61 |
62 |
63 | if __name__ == '__main__':
64 | TechDrawMigrateFromv018()
65 | App.ActiveDocument.recompute()
66 |
67 |
--------------------------------------------------------------------------------
/TechDraw/TechDrawViewSet.FCMacro:
--------------------------------------------------------------------------------
1 | # TechDrawViewSet
2 | #
3 | # This allows you to take a view of your part from the the 3D viewer
4 | # and insert it into a TechDraw document. It's useful for when you
5 | # need a tech drawing of your part from a weird angle.
6 | #
7 | # 1. Create a TechDrawing and insert a view of your part.
8 | # 2. Open your part up in the 3D viewer
9 | # 3. Orient it however you want it
10 | # 4. While keeping the 3D view active/visible, select the TechDraw
11 | # Object/View from step 1.
12 | # 5. Run the macro. This will automatically adjust the direction of
13 | # techDraw object to match the 3D view.
14 |
15 | __Name__ = 'TechDraw View Set'
16 | __Comment__ = 'Set the parameters of the current view to correspond to the 3D Window'
17 | __Author__ = 'MechaMecca, galou_breizh'
18 | __Version__ = '0.1.0'
19 | __License__ = 'CC-BY-3.0'
20 | __Web__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'
21 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_TechDrawViewSet'
22 | __Icon__ = ''
23 | __Help__ = 'Select a TechDraw View while staying in the 3D viewer, execute'
24 | __Status__ = 'Alpha'
25 | __Requires__ = ''
26 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
27 | __Files__ = ''
28 |
29 | import freecad as fc
30 |
31 |
32 | def set_view():
33 | gui_doc = fc.gui.activeDocument()
34 | if gui_doc is None:
35 | fc.app.Console.PrintWarning('No active document\n')
36 | return
37 |
38 | try:
39 | cam_orientation = gui_doc.ActiveView.getCameraOrientation()
40 | except AttributeError:
41 | fc.app.Console.PrintWarning('The current tab is not a 3D view\n')
42 | return
43 |
44 | if not fc.gui.Selection.getSelection():
45 | fc.app.Console.PrintWarning('Nothing selected\n')
46 | return
47 |
48 | view_dir = cam_orientation.multVec(fc.app.Vector(0, 0, 1))
49 | for tech_view in fc.gui.Selection.getSelection():
50 | try:
51 | tech_view.Direction = view_dir
52 | except AttributeError:
53 | fc.app.Console.PrintMessage('"{}" is not a TechDraw View, ignoring\n'.format(tech_view.Label))
54 |
55 | if __name__ == '__main__':
56 | set_view()
57 |
--------------------------------------------------------------------------------
/Utility/GroupSorting.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # (c) 18Turbo, 2022
3 |
4 | __Name__ = 'GroupSorting (Ordenación)'
5 | __Comment__ = 'The macro sorts the groups and pieces of a piece.\nSelect groups with key, and execute the macro.'
6 | __Author__ = '18Turbo'
7 | __Version__ = '0.1.0'
8 | __Date__ = '2022-10-04'
9 | __License__ = 'LGPL-2.0-or-later'
10 | __Web__ = 'https://github.com/18turbo/OrdenacionRapidaFreeCAD'
11 | __Wiki__ = 'https://github.com/18turbo/OrdenacionRapidaFreeCAD'
12 | __Icon__ = 'GroupSorting.svg'
13 | __Help__ = ''
14 | __Status__ = 'beta'
15 | __Requires__ = 'FreeCAD >= v0.20'
16 | __Contact__ = 'https://github.com/18turbo'
17 | __Communication__ = ''
18 | __Files__ = 'GroupSorting.svg'
19 |
20 |
21 | # (Spanish:)
22 | #
23 | # Autor: 18Turbo
24 | # Fecha Incial: 22-07-2022
25 | # Versión: 0.1.0 BETA
26 | #
27 | # Funcionalidad: Ordena grupos según sean seleccionados.
28 | #
29 | # Notas Importantes: hay que saber que los grupos sin padre tienen un orden específico en FreeCAD y no se pueden ordenar con este script
30 | # porque aunque se hace el proceso correcto, FreeCAD no permite la ordenación de estos de una forma simple y escapa
31 | # a los propósitos de este script.
32 | #
33 | #
34 | # Notas de versiones:
35 | # v.0.1.0: Adaptación al Addon Manager
36 | # v.0.0.5: Depurado para que funcione con grupos sin padre, es decir, con el documento como padre, aunque FreeCAD no lo permita. Así,
37 | # si en una versión superior se permite, el script no hay que modificarlo.
38 | # v.0.0.4: Versión Alfa funcional.
39 | #
40 | #
41 | #
42 |
43 | import FreeCAD as app
44 | import FreeCADGui as gui
45 |
46 | cIntro = '\n'
47 |
48 | strLang = [
49 | [ # Español
50 | ## Strings for translation into any language
51 | "Los grupos no tienen un padre y FreeCAD no permite la ordenación en este nivel",
52 | "Debes seleccionar Grupos con el mismo padre",
53 | "Debes elegir más de un objeto"
54 |
55 | ],
56 | [ # English
57 | ## Strings for translation into any language (English Strings)
58 | "Groups do not have a parent and FreeCAD does not allow sorting at this level",
59 | "You must select Groups with the same parent",
60 | "You must choose more than one object"
61 |
62 | ]
63 | ]
64 |
65 | def tr(text):
66 | # Translate
67 | if (text not in strLang[0]) or (g_num_lang < 0) or (g_num_lang >= len(strLang)):
68 | return text
69 | primerIdioma = strLang[0]
70 | indice = primerIdioma.index(text)
71 | if (indice == -1) or (indice >= len(strLang[g_num_lang])):
72 | return text
73 | return strLang[g_num_lang][indice]
74 |
75 |
76 | lang = gui.getLocale()
77 | # Default to English.
78 | g_num_lang = 1
79 | if 'Spanish' in lang:
80 | g_num_lang = 0
81 | #elif 'Italian' in lang:
82 | # g_num_lang = 2
83 |
84 | objetosSeleccionados = Gui.Selection.getSelection()
85 |
86 | if len(objetosSeleccionados) > 1:
87 | # Comprobando que todos tienen el mismo padre, siempre que no partan de la raíz del documento
88 | distintoPadre = False
89 | padre = ""
90 | if app.ActiveDocument.getObject(objetosSeleccionados[0].Name).InList: # Esto es que tiene padre
91 | tienePadre = True
92 | for objeto in objetosSeleccionados:
93 | if (app.ActiveDocument.getObject(objeto.Name).InList[0].Name != padre):
94 | if (padre == ""):
95 | padre = app.ActiveDocument.getObject(objeto.Name).InList[0].Name
96 | else:
97 | distintoPadre = True
98 | break;
99 | else:
100 | tienePadre = False
101 | for objeto in objetosSeleccionados:
102 | if (app.ActiveDocument.getObject(objeto.Name).InList):
103 | distintoPadre = True
104 | app.Console.PrintWarning(tr("Los grupos no tienen un padre y FreeCAD no permite la ordenación en este nivel") + cIntro)
105 |
106 | if not distintoPadre:
107 | if tienePadre:
108 | nombrePadre = app.ActiveDocument.getObject(objeto.Name).InList[0].Name
109 |
110 | listaNombres = []
111 | app.activeDocument().Tip = app.activeDocument().addObject('App::DocumentObjectGroup','GrupoAuxiliarOrdenacion')
112 |
113 | for objetoA in objetosSeleccionados:
114 | # Siempre que el objeto sea un grupo
115 | if (objetoA.Name.find('Group') > -1) or (objetoA.Name.find('Part') > -1):
116 | app.ActiveDocument.getObject(objetoA.Name).removeObject(app.ActiveDocument.getObject(objetoA.Name))
117 | app.ActiveDocument.getObject("GroupAuxSorting18T").addObject(app.ActiveDocument.getObject(objetoA.Name))
118 | listaNombres.append(objetoA.Name)
119 |
120 | for nombreObjeto in listaNombres:
121 | app.ActiveDocument.getObject("GroupAuxSorting18T").removeObject(app.ActiveDocument.getObject(nombreObjeto))
122 | if tienePadre:
123 | app.ActiveDocument.getObject(nombrePadre).addObject(app.ActiveDocument.getObject(nombreObjeto))
124 |
125 | app.activeDocument().removeObject("GroupAuxSorting18T")
126 | app.activeDocument().recompute()
127 | else:
128 | app.Console.PrintWarning(tr("Debes seleccionar Grupos con el mismo padre") + cIntro)
129 | else:
130 | app.Console.PrintWarning(tr("Debes elegir más de un objeto") + cIntro)
--------------------------------------------------------------------------------
/Utility/HighlightCommon.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from __future__ import unicode_literals
4 |
5 | __Name__ = 'Highlight Common parts'
6 | __Comment__ = 'Compute the common parts between selected shapes'
7 | __Author__ = 'JMG, galou and other contributors'
8 | __Version__ = '2.3.2'
9 | __Date__ = '2021-07-01'
10 | __License__ = 'CC0-1.0'
11 | __Web__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'
12 | __Wiki__ = 'https://freecadweb.org/wiki/Macro_HighlightCommon'
13 | __Icon__ = 'HighlightCommon.png'
14 | __Help__ = 'Select at least two objects and run'
15 | __Status__ = 'Production'
16 | __Requires__ = 'FreeCAD V0.17+'
17 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
18 | __Files__ = 'HighlightCommon.png'
19 |
20 | from PySide.QtGui import QMessageBox # FreeCAD's special PySide!
21 |
22 | import FreeCAD as app
23 | import FreeCADGui as gui
24 |
25 |
26 | PREFERENCE_PATH = 'User parameter:BaseApp/Preferences/Mod/HighlightCommon'
27 |
28 |
29 | def load_and_save_settings():
30 | param_change = 'change_transparency'
31 | param_transparency = 'transparency'
32 | p = app.ParamGet(PREFERENCE_PATH)
33 | change_transparency = p.GetBool(param_change, True)
34 | transparency = p.GetInt(param_transparency, 80)
35 | p.SetBool(param_change, change_transparency)
36 | p.SetInt(param_transparency, transparency)
37 | return change_transparency, transparency
38 |
39 |
40 | def main():
41 | # Store active doc in case it may change during run.
42 | doc = app.activeDocument()
43 |
44 | if doc is None:
45 | return
46 |
47 | change_transparency, transparency = load_and_save_settings()
48 |
49 | colli_grp = None # Group object to group collisions.
50 | colli_max = 0 # Maximum collision volume.
51 |
52 | # Open a transaction in undo pile.
53 | doc.openTransaction('Seeking collisions')
54 |
55 | objectsToEnumerate = gui.Selection.getSelection()
56 | if len(objectsToEnumerate) < 2:
57 | objectsToEnumerate = doc.Objects
58 |
59 | # Ensure list of unique objects.
60 | object_list = []
61 | for obj in objectsToEnumerate:
62 | if ((obj not in object_list)
63 | and hasattr(obj, 'Shape')
64 | and hasattr(obj, 'getGlobalPlacement')
65 | and hasattr(obj, 'Label')):
66 | object_list.append(obj)
67 |
68 | # Going through selected objects (object A).
69 | for i, object_a in enumerate(object_list):
70 | shape_a = object_a.Shape.copy()
71 | shape_a.Placement = object_a.getGlobalPlacement()
72 | label_a = object_a.Label
73 |
74 | # Making selected objects transparent.
75 | if change_transparency:
76 | try:
77 | object_a.ViewObject.Transparency = transparency
78 | except AttributeError:
79 | pass
80 |
81 | # Comparing object A with all
82 | # following ones in the list (object B).
83 | for object_b in object_list[(i + 1):]:
84 |
85 | shape_b = object_b.Shape.copy()
86 | shape_b.Placement = object_b.getGlobalPlacement()
87 | label_b = object_b.Label
88 | common = shape_a.common(shape_b)
89 |
90 | # Making selected objects transparent.
91 | if change_transparency:
92 | try:
93 | object_b.ViewObject.Transparency = transparency
94 | except AttributeError:
95 | pass
96 |
97 | # If object A & object B have a collision
98 | # display a message with collision volume and
99 | # add a new representative shape in the group.
100 | if common.Volume > 1e-6:
101 | app.Console.PrintMessage(
102 | 'Volume of the intersection between {} and {}: {:.3f} mm³\n'.format(
103 | label_a,
104 | label_b,
105 | common.Volume))
106 | colli_max = common.Volume if common.Volume > colli_max else colli_max
107 | if not colli_grp:
108 | # Create group if it doesn't already exist.
109 | colli_grp = doc.addObject('App::DocumentObjectGroup',
110 | 'Collisions')
111 | intersection_object = doc.addObject(
112 | 'Part::Feature')
113 | intersection_object.Label = '{} - {}'.format(
114 | label_a, label_b)
115 | intersection_object.Shape = common
116 | intersection_object.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
117 | colli_grp.addObject(intersection_object)
118 | else:
119 | # If no collision, just inform the user.
120 | app.Console.PrintMessage(
121 | 'No intersection between {} and {}\n'.format(
122 | label_a,
123 | label_b))
124 |
125 | # If collisions have been found, commit the undo transaction and
126 | # give a summary (count + max value) to the user.
127 | if colli_grp:
128 | doc.commitTransaction()
129 | app.Console.PrintMessage(
130 | '{} collision(s) found between selected objects\nMaximum collision: {:.3f} mm³\n'.format(
131 | len(colli_grp.Group),
132 | colli_max))
133 | doc.recompute()
134 | else:
135 | # If no collision has been found, just inform the user about it.
136 | doc.abortTransaction()
137 | if len(object_list) >= 2:
138 | app.Console.PrintWarning('No collision found between selected objects\n')
139 | else:
140 | app.Console.PrintWarning('No suitable objects selected, select at least two objects\n')
141 |
142 |
143 | if __name__ == '__main__':
144 | main()
145 |
--------------------------------------------------------------------------------
/Utility/HighlightCommon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/Utility/HighlightCommon.png
--------------------------------------------------------------------------------
/Utility/HighlightDifference.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Compute the difference between two shapes. Additions are marked red, removals
4 | are marked green. Both original parts will be half transparent. The volume of
5 | the additions and removals are printed in the console.
6 | """
7 |
8 | from __future__ import unicode_literals
9 |
10 | __Name__ = 'Highlight Difference'
11 | __Comment__ = 'Compute the difference between two shapes'
12 | __Author__ = 'galou and other contributors'
13 | __Version__ = '2.2.0'
14 | __Date__ = '2021-07-01'
15 | __License__ = 'CC0-1.0'
16 | __Web__ = 'https://freecadweb.org/wiki/Macro_HighlightDifference'
17 | __Wiki__ = 'https://freecadweb.org/wiki/Macro_HighlightDifference'
18 | __Icon__ = 'HighlightDifference.svg'
19 | __Help__ = 'Select two objects and run'
20 | __Status__ = 'Production'
21 | __Requires__ = 'FreeCAD V0.17+'
22 | __Communication__ = 'https://github.com/FreeCAD/FreeCAD-macros/issues/'
23 | __Files__ = 'HighlightDifference.svg'
24 |
25 | from PySide import QtCore # FreeCAD's special PySide!
26 | from PySide.QtGui import QMessageBox # FreeCAD's special PySide!
27 |
28 | import FreeCAD as app
29 | import FreeCADGui as gui
30 |
31 |
32 | PREFERENCE_PATH = 'User parameter:BaseApp/Preferences/Mod/HighlightDifference'
33 |
34 |
35 | def error_dialog(msg):
36 | """Create a simple dialog QMessageBox with an error message."""
37 | app.Console.PrintError(msg + '\n')
38 | diag = QMessageBox(QMessageBox.Icon.Critical,
39 | 'Error in macro highlight_difference',
40 | msg)
41 | diag.setWindowModality(QtCore.Qt.ApplicationModal)
42 | diag.exec_()
43 |
44 |
45 | def load_and_save_settings():
46 | param_change = 'change_transparency'
47 | param_transparency = 'transparency'
48 | p = app.ParamGet(PREFERENCE_PATH)
49 | change_transparency = p.GetBool(param_change, True)
50 | transparency = p.GetInt(param_transparency, 80)
51 | p.SetBool(param_change, change_transparency)
52 | p.SetInt(param_transparency, transparency)
53 | return change_transparency, transparency
54 |
55 |
56 | def main():
57 | if len(gui.Selection.getSelection()) < 2:
58 | error_dialog('Select two objects')
59 | return
60 |
61 | object_a = gui.Selection.getSelection()[0]
62 | object_b = gui.Selection.getSelection()[1]
63 | try:
64 | shape_a = object_a.Shape
65 | shape_b = object_b.Shape
66 | label_a = object_a.Label
67 | label_b = object_b.Label
68 | except AttributeError:
69 | error_dialog('No suitable objects selected, select two objects\n')
70 | return
71 |
72 | shape_addition = shape_a.cut(shape_b)
73 | if shape_addition.Volume < 1e-6:
74 | app.Console.PrintMessage('No addition from {} to {}\n'.format(
75 | label_a, label_b))
76 | else:
77 | app.Console.PrintMessage(
78 | 'Volume of the addition from {} to {}: {}\n'.format(
79 | label_a, label_b, shape_addition.Volume))
80 |
81 | shape_removal = shape_b.cut(shape_a)
82 | if shape_removal.Volume < 1e-6:
83 | app.Console.PrintMessage('No removal from {} to {}\n'.format(
84 | label_a, label_b))
85 | else:
86 | app.Console.PrintMessage(
87 | 'Volume of the removal from {} to {}: {}\n'.format(
88 | label_a, label_b, shape_removal.Volume))
89 |
90 | if (shape_addition.Volume < 1e-6) and (shape_removal.Volume < 1e-6):
91 | app.Console.PrintMessage('{} and {} have the same shape\n'.format(
92 | label_a, label_b))
93 |
94 | added = app.ActiveDocument.addObject('Part::Feature')
95 | added.Label = 'Addition ({} − {})'.format(label_a, label_b)
96 | added.Shape = shape_addition
97 | added.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
98 | removed = app.ActiveDocument.addObject('Part::Feature')
99 | removed.Label = 'Removal ({} − {})'.format(label_b, label_a)
100 | removed.Shape = shape_removal
101 | removed.ViewObject.ShapeColor = (0.0, 0.5, 0.0, 1.0)
102 |
103 | change_transparency, transparency = load_and_save_settings()
104 | if change_transparency:
105 | try:
106 | object_a.ViewObject.Transparency = transparency
107 | object_b.ViewObject.Transparency = transparency
108 | except AttributeError:
109 | pass
110 |
111 |
112 | if __name__ == '__main__':
113 | main()
114 |
--------------------------------------------------------------------------------
/Utility/HighlightDifference.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
82 |
--------------------------------------------------------------------------------
/Utility/MessageBox.FCMacro:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | __Name__ = 'Message Box'
5 | __Comment__ = 'Show how to give information to the user in macros'
6 | __Web__ = 'http://freecadweb.org/wiki/Macro_MessageBox'
7 | __Wiki__ = 'http://freecadweb.org/wiki/Macro_MessageBox'
8 | __Icon__ = ""
9 | __Help__ = 'Run and be warned'
10 | __Author__ = 'galou, Mario52 and other contributors'
11 | __Version__ = 1.0
12 | __Status__ = 'Production'
13 | __Requires__ = ''
14 |
15 | from PySide import QtCore, QtGui
16 |
17 |
18 | def errorDialog(msg):
19 | """Create a simple dialog QMessageBox"""
20 | # The first argument indicates the icon used: one of
21 | # QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question}
22 | diag = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
23 | u'Warning in macro MessageBox', msg)
24 | diag.setWindowModality(QtCore.Qt.ApplicationModal)
25 | diag.exec_()
26 |
27 | # To display multiple lines in a dialog box Qt, '\n' can be added between
28 | # lines. '\t' inserts a tab. The backslash is a then a special character which
29 | # must be escaped, i.e. insert '\\' to display a backslash. Single quotes must
30 | # also be escaped in a single-quote-delimited string and double-quotes in a
31 | # double-quote-delimited string. See Python doc for details.
32 | msg = 'Example of warning message\nYou should\'t have done this.'
33 | errorDialog(msg)
34 | raise(Exception(msg))
35 |
--------------------------------------------------------------------------------
/Utility/PiecesTemplates/Groups.txt:
--------------------------------------------------------------------------------
1 | Images
2 | References
3 | Sketches
4 | Curves
5 | Solids
6 |
--------------------------------------------------------------------------------
/Utility/PlacementAbsolufy.FCMacro:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #####################################
3 | # Copyright (c) openBrain 2019
4 | # Licensed under LGPL v2
5 | #
6 | # This macro will reset position of all part containers to document origin while keeping the absolute object positions
7 | #
8 | # Version history :
9 | # *0.2 : some typo improvement + commenting for official PR
10 | # *0.1 : alpha release, almost no test performed
11 | #
12 | #####################################
13 |
14 | __Name__ = 'PlacementAbsolufy'
15 | __Comment__ = 'Reset part containers to global origin while keeping object positions'
16 | __Author__ = 'openBrain'
17 | __Version__ = '0.2'
18 | __Date__ = '2019-06-10'
19 | __License__ = 'LGPL v2'
20 | __Web__ = 'https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy'
21 | __Wiki__ = 'https://www.freecadweb.org/wiki/Macro_PlacementAbsolufy'
22 | __Icon__ = ''
23 | __Help__ = 'Run the macro with model active in the GUI'
24 | __Status__ = 'Alpha'
25 | __Requires__ = 'FreeCAD >= 0.17'
26 | __Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=3&t=36869'
27 | __Files__ = ''
28 |
29 | currState = {} #initialize a dictionary to store current object placements
30 |
31 | for obj in App.ActiveDocument.Objects: #going through active document objects
32 | if "Placement" in obj.PropertiesList: #if object has a Placement property
33 | currState[obj] = obj.getGlobalPlacement() #store the object pointer with its global placement
34 |
35 | App.ActiveDocument.openTransaction("Absolufy") #open a transaction for undo management
36 |
37 | for obj, plac in currState.items(): #going through all moveable objects
38 | if obj.isDerivedFrom("App::Part"): #if object is a part container
39 | obj.Placement = App.Placement(App.Vector(0,0,0),App.Rotation(0,0,0)) #reset its placement to global document origin
40 | elif obj.TypeId[:5] == "App::": #if object is another App type (typically an origin axis or plane)
41 | None #do nothing
42 | else: #for all other objects
43 | obj.Placement = plac #replace them at their global (absolute) placement
44 |
45 | App.ActiveDocument.commitTransaction() #commit transaction
46 |
--------------------------------------------------------------------------------
/Utility/SelectVisible.FCMacro:
--------------------------------------------------------------------------------
1 | # FreeCAD Macro SelectVisible
2 |
3 | __Name__ = 'Select Visible'
4 | __Comment__ = 'All visible objects in the tree will be selected'
5 | __Web__ = 'http://www.freecadweb.org/wiki/Macro_SelectVisible'
6 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_SelectVisible'
7 | __Icon__ = 'SelectVisible.svg'
8 | __Help__ = 'All visible objects in the tree and only these will be selected'
9 | __Author__ = 'galou_breizh'
10 | __Version__ = '1.0'
11 | __Status__ = 'Production'
12 | __Requires__ = ''
13 |
14 | import FreeCAD as App
15 | import FreeCADGui as Gui
16 |
17 | doc = App.activeDocument()
18 |
19 | if not doc:
20 | App.Console.PrintWarning('SelectVisible: no active document')
21 | else:
22 | Gui.Selection.clearSelection()
23 | for o in doc.Objects:
24 | if o.ViewObject.Visibility:
25 | Gui.Selection.addSelection(o)
26 |
--------------------------------------------------------------------------------
/Utility/Transparencies.FCMacro:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # (c) 18Turbo, 2022
3 |
4 | __Name__ = 'Transparencies'
5 | __Comment__ = 'The selected object becomes 50% transparent (if they have no transparency), and is detransparency otherwise.'
6 | __Author__ = '18Turbo (Rafael M.) and Rafael García'
7 | __Version__ = '0.0.2'
8 | __Date__ = '2022-10-18'
9 | __License__ = 'LGPL-2.0-or-later'
10 | __Web__ = 'https://github.com/18turbo/TransparenciaObjetosFreeCAD'
11 | __Wiki__ = 'https://github.com/18turbo/TransparenciaObjetosFreeCAD'
12 | __Icon__ = 'Transparencies.svg'
13 | __Help__ = ''
14 | __Status__ = 'beta'
15 | __Requires__ = 'FreeCAD >= v0.19'
16 | __Contact__ = 'https://github.com/18turbo'
17 | __Communication__ = ''
18 | __Files__ = 'Transparencies.svg'
19 |
20 | # Agradecimientos: Rafael García
21 |
22 | #El objeto seleccionado se vuelve un 50% transparente si no tiene transparencia y se le quita la transparencia si la tiene.
23 |
24 | creadaTransparencia = False
25 |
26 | objetosSeleccionados = Gui.Selection.getSelection()
27 |
28 | for objeto in objetosSeleccionados:
29 | transparenciaObjeto = objeto.ViewObject.Transparency
30 | if (transparenciaObjeto >= 0 and transparenciaObjeto<10): # Si no hay transparencia (o muy poca)
31 | objeto.ViewObject.Transparency = 50
32 | creadaTransparencia = True
33 |
34 | if creadaTransparencia == False:
35 | # Si no se ha creado ninguna transparencia, es que se debe poner todo opaco
36 | for objeto in objetosSeleccionados:
37 | objeto.ViewObject.Transparency = 0
--------------------------------------------------------------------------------
/Utility/Transparencies.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/Utility/treeHelper/treeHelper.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
87 |
--------------------------------------------------------------------------------
/Utility/treeHelper/ui_treewindow.py:
--------------------------------------------------------------------------------
1 | # Form implementation generated from reading ui file 'tree_window_.ui'
2 | #
3 | # Created by: PyQt5 UI code generator 5.15.7
4 | #
5 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
6 | # run again. Do not edit this file unless you know what you are doing.
7 |
8 |
9 | from PySide2 import QtCore, QtGui, QtWidgets
10 |
11 |
12 | class Ui_DockWidget:
13 | def setupUi(self, DockWidget):
14 | DockWidget.setObjectName("Tree helper")
15 | DockWidget.resize(400, 300)
16 | self.dockWidgetContents = QtWidgets.QWidget()
17 | self.dockWidgetContents.setObjectName("dockWidgetContents")
18 | self.gridLayout = QtWidgets.QGridLayout(self.dockWidgetContents)
19 | self.gridLayout.setObjectName("gridLayout")
20 | self.treeWidget = QtWidgets.QTreeWidget(self.dockWidgetContents)
21 | self.treeWidget.setObjectName("treeWidget")
22 | self.gridLayout.addWidget(self.treeWidget, 0, 0, 1, 1)
23 | DockWidget.setWidget(self.dockWidgetContents)
24 |
25 | self.retranslateUi(DockWidget)
26 | QtCore.QMetaObject.connectSlotsByName(DockWidget)
27 |
28 | def retranslateUi(self, DockWidget):
29 | _translate = QtCore.QCoreApplication.translate
30 | DockWidget.setWindowTitle(_translate("DockWidget", "Tree helper"))
31 | self.treeWidget.headerItem().setText(0, _translate("DockWidget", "Elementos"))
32 |
--------------------------------------------------------------------------------
/apothemBasedPrism.py:
--------------------------------------------------------------------------------
1 | # # # # # # # # # # #
2 | #
3 | # Apothem Based Prism
4 | #
5 | # This script will take the input of the distance between flats, (apothem, aka inradius),
6 | # and the number of sidesfor a regular polygon along with a height and produce a
7 | # correctly sized prism derived from the circumradius.
8 | #
9 | # # # # # # # # # # #
10 |
11 | __Name__ = 'Apothem Based Prism'
12 | __Comment__ = ''
13 | __License__ = ''
14 | __Web__ = 'http://www.freecadweb.org/wiki/Macro_Apothem_Based_Prism_GUI'
15 | __Wiki__ = 'http://www.freecadweb.org/wiki/Macro_Apothem_Based_Prism_GUI'
16 | __Icon__ = ''
17 | __Help__ = ''
18 | __Author__ = ''
19 | __Version__ = ''
20 | __Status__ = ''
21 | __Requires__ = ''
22 | __Files__ = ''
23 |
24 |
25 | import FreeCAD, FreeCADGui, Part, PartGui, math
26 | from FreeCAD import Base
27 | from PySide import QtGui, QtCore
28 | from math import cos, radians
29 | App = FreeCAD
30 | Gui = FreeCADGui
31 |
32 | class p():
33 |
34 |
35 | def priSm(self):
36 |
37 | try:
38 | dbf = float(self.d1.text())
39 | nos = int(self.d2.text())
40 | hth = float(self.d3.text())
41 | aR = dbf / 2
42 | op1 = 180/float(nos)
43 | coS = cos(math.radians(op1))
44 | cR = aR / coS
45 | prism=App.ActiveDocument.addObject("Part::Prism","Prism")
46 | prism.Polygon=nos
47 | prism.Circumradius=cR
48 | prism.Height=hth
49 | prism.Placement=Base.Placement(Base.Vector(0.00,0.00,0.00),Base.Rotation(0.00,0.00,0.00,1.00))
50 | prism.Label='Prism'
51 | App.ActiveDocument.recompute()
52 | Gui.SendMsgToActiveView("ViewFit")
53 | except:
54 | FreeCAD.Console.PrintError("Unable to complete task")
55 |
56 | self.close()
57 |
58 | def close(self):
59 | self.dialog.hide()
60 |
61 |
62 | #
63 | # Make dialog box and get input for distance between flats, number of sides, and height
64 | #
65 |
66 | def __init__(self):
67 | self.dialog = None
68 |
69 | self.dialog = QtGui.QDialog()
70 | self.dialog.resize(280,110)
71 |
72 | self.dialog.setWindowTitle("Apothem Based Prism")
73 | la = QtGui.QVBoxLayout(self.dialog)
74 |
75 | iN1 = QtGui.QLabel("Distance Between Flats")
76 | la.addWidget(iN1)
77 | self.d1 = QtGui.QLineEdit()
78 | la.addWidget(self.d1)
79 |
80 | iN2 = QtGui.QLabel("Number Of Sides (Best results - use even numbers)")
81 | la.addWidget(iN2)
82 | self.d2 = QtGui.QLineEdit()
83 | la.addWidget(self.d2)
84 |
85 | iN3 = QtGui.QLabel("Prism Height")
86 | la.addWidget(iN3)
87 | self.d3 = QtGui.QLineEdit()
88 | la.addWidget(self.d3)
89 |
90 | okbox = QtGui.QDialogButtonBox(self.dialog)
91 | okbox.setOrientation(QtCore.Qt.Horizontal)
92 | okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
93 | la.addWidget(okbox)
94 | QtCore.QObject.connect(okbox, QtCore.SIGNAL("accepted()"), self.priSm)
95 | QtCore.QObject.connect(okbox, QtCore.SIGNAL("rejected()"), self.close)
96 | QtCore.QMetaObject.connectSlotsByName(self.dialog)
97 | self.dialog.show()
98 | self.dialog.exec_()
99 |
100 |
101 | p()
102 |
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_00.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_01.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_02.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_03.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_04.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_05.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_06.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_07.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_08.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_Axis_rotation_X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_Axis_rotation_X.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_Axis_rotation_Y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_Axis_rotation_Y.png
--------------------------------------------------------------------------------
/icons/Camera/FCCamera_Axis_rotation_Z.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/Camera/FCCamera_Axis_rotation_Z.png
--------------------------------------------------------------------------------
/icons/HyperbolaIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/HyperbolaIcon.png
--------------------------------------------------------------------------------
/icons/MeasureCircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/MeasureCircle.png
--------------------------------------------------------------------------------
/icons/RotateView/out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/RotateView/out.png
--------------------------------------------------------------------------------
/icons/RotateView/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/RotateView/right.png
--------------------------------------------------------------------------------
/icons/RotateView/right_abs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/RotateView/right_abs.png
--------------------------------------------------------------------------------
/icons/RotateView/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/RotateView/up.png
--------------------------------------------------------------------------------
/icons/SelectVisible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/d643f70db1fa5a6c582473694da0a5bc8ff3bc37/icons/SelectVisible.png
--------------------------------------------------------------------------------
/makecamera2dview.py:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #-- makecamera2dview
3 | #--
4 | #-- microelly 2015
5 | #--
6 | #-- GNU Lesser General Public License (LGPL)
7 | #-------------------------------------------------
8 | # create a 2dview object from the camera position
9 |
10 | __Name__ = 'Make Camera 2D View'
11 | __Comment__ = 'create a 2DView object from the camera position'
12 | __Web__ = ""
13 | __Wiki__ = ""
14 | __Icon__ = ""
15 | __Help__ = "select an object"
16 | __Author__ = "microelly"
17 | __Version__ = "0.1.1"
18 | __Status__ = 'alpha'
19 | __Requires__ = 'numpy'
20 |
21 | import Draft
22 | import FreeCAD as app
23 | import FreeCADGui as gui
24 | import PySide # FreeCAD's PySide!
25 |
26 |
27 | import numpy as np
28 | from pivy import coin
29 |
30 |
31 | def errorDialog(msg):
32 | diag = PySide.QtGui.QMessageBox(PySide.QtGui.QMessageBox.Critical, "Error Message", msg)
33 | diag.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)
34 | diag.exec_()
35 |
36 |
37 | try:
38 | sel = gui.Selection.getSelection()[0]
39 | c = Draft.clone(sel)
40 | except Exception:
41 | errorDialog("Select one object")
42 | raise Exception()
43 |
44 |
45 | camera = gui.ActiveDocument.ActiveView.getCameraNode()
46 | # camera.position.setValue(app.Vector(100,50,10))
47 | camera.pointAt(coin.SbVec3f(0,0,0), coin.SbVec3f(0,0,1))
48 |
49 | al = str(camera.position.getValue().toString()).split(' ')
50 | vec2 = app.Vector(float(al[0]), float(al[1]), float(al[2]))
51 |
52 | yaw_deg = np.degrees(np.arctan2(vec2.x, vec2.y))
53 | pitch_deg = np.degrees(np.arctan2(vec2.z, np.sqrt(vec2.x**2 + vec2.y**2)))
54 |
55 | pla1 = app.Placement(app.Vector(0, 0, 0), app.Rotation(0, 0, -90))
56 | pla2 = app.Placement(app.Vector(0, 0, 0), app.Rotation(0, 180+yaw_deg, 0)).multiply(pla1)
57 | pla3 = app.Placement(app.Vector(0, 0, 0), app.Rotation(0, 0, pitch_deg)).multiply(pla2)
58 |
59 | c.Placement = pla3
60 | c.ViewObject.Visibility = False
61 | v = Draft.makeShape2DView(c)
62 |
--------------------------------------------------------------------------------
/myMacroDir/__init__.py:
--------------------------------------------------------------------------------
1 | import myMacro
2 |
--------------------------------------------------------------------------------
/myMacroDir/myMacro.py:
--------------------------------------------------------------------------------
1 | #
2 | # your copyright info here
3 | #
4 |
5 | # meta data for macro management
6 |
7 | __Comment__ = 'My macro is a super macro and can be used whenever other macros fail '
8 | __Web__ = "http://forum.freecadweb.org/viewtopic.php?f=8&t=11302"
9 | __Wiki__ = "http://www.freecadweb.org/wiki/Macro_FreeCAD_to_Kerkythea"
10 | __Icon__ = "Part_Common.svg"
11 | __Help__ = "This is the help text of this macro"
12 | __Author__ = "Freek Ad"
13 | __Version__ = 0.1
14 | __Status__ = 'alpha'
15 | __Requires__ = ''
16 |
17 |
18 |
19 | import FreeCAD
20 |
21 |
22 | #
23 | # the macro should have a test method to check the success of the installation
24 | #
25 | def test():
26 | errorMsg="There are some errors: a, b, c"
27 | warnMsg="There are some warnings: d, e"
28 | infoMsg="There is a info: f"
29 | errors=3
30 | warns=2
31 | infos=1
32 | result=[errors,errorMsg,warns,warnMsg,infos,infoMsg]
33 | return result
34 |
35 | #
36 | # the macro should have a main method - the macro itself
37 | #
38 | def main():
39 | t=FreeCAD.ParamGet('User parameter:BaseApp/Preferences/Macro')
40 | mp=t.GetString("MacroPath")
41 | FreeCAD.Console.PrintMessage("\n"*4+"H E L L O W O R L D,\n I'm myMacro.py located in "+ mp+ "/MyMacroDir" + "\n"*4)
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------