├── .gitignore
├── DefeaturingCMD.py
├── DefeaturingFeature.py
├── DefeaturingTools-a.py
├── DefeaturingTools.py
├── DefeaturingTools.ui
├── FuzzyTools.py
├── Init.py
├── InitGui.py
├── README.md
├── Resources
├── FreeCAD-addon-manager-available.svg
├── Made-with-Python_.svg
├── icons
│ ├── Defeaturing-icon.svg
│ ├── DefeaturingParametric.svg
│ ├── Freecad.svg
│ ├── FuzzyCommon.svg
│ ├── FuzzyCut.svg
│ ├── FuzzyUnion.svg
│ ├── Path-SelectLoop.svg
│ ├── RefineShapeFeature.svg
│ ├── centering-w.svg
│ ├── defeaturingTools.svg
│ └── error.svg
└── made-with-python.svg
├── dft_locator.py
└── package.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files, back, bat
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 | *.bak
17 | *.bat
18 |
19 | # Windows shortcuts
20 | *.lnk
21 |
22 | # Python executable
23 | *.pyc
24 |
25 | # =========================
26 | # Operating System Files
27 | # =========================
28 |
29 | # OSX
30 | # =========================
31 |
32 | .DS_Store
33 | .AppleDouble
34 | .LSOverride
35 |
36 | # Thumbnails
37 | ._*
38 |
39 | # Files that might appear in the root of a volume
40 | .DocumentRevisions-V100
41 | .fseventsd
42 | .Spotlight-V100
43 | .TemporaryItems
44 | .Trashes
45 | .VolumeIcon.icns
46 |
47 | # Directories potentially created on remote AFP share
48 | .AppleDB
49 | .AppleDesktop
50 | Network Trash Folder
51 | Temporary Items
52 | .apdisk
53 |
--------------------------------------------------------------------------------
/DefeaturingCMD.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #****************************************************************************
3 | #* *
4 | #* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
5 | #* 3D exporter for FreeCAD *
6 | #* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
7 | #* Copyright (c) 2015 *
8 | #* Maurice easyw@katamail.com *
9 | #* *
10 | #* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
11 | #* *
12 |
13 | import FreeCAD, FreeCADGui, Part, os
14 | import os, sys, tempfile
15 | import FreeCAD, FreeCADGui
16 | from PySide import QtGui, QtCore
17 | import dft_locator
18 |
19 |
20 | try:
21 | from PathScripts.PathUtils import horizontalEdgeLoop
22 | from PathScripts.PathUtils import horizontalFaceLoop
23 | from PathScripts.PathUtils import loopdetect
24 | except:
25 | FreeCAD.Console.PrintError('Path WB not found\n')
26 |
27 | reload_Gui=False#True
28 |
29 | def reload_lib(lib):
30 | if (sys.version_info > (3, 0)):
31 | import importlib
32 | importlib.reload(lib)
33 | else:
34 | reload (lib)
35 |
36 | DefeaturingWBpath = os.path.dirname(dft_locator.__file__)
37 | DefeaturingWB_icons_path = os.path.join( DefeaturingWBpath, 'Resources', 'icons')
38 |
39 | class DefeatShapeFeature:
40 | def IsActive(self):
41 | #print ('isactive')
42 | if hasattr(Part, "OCC_VERSION"):
43 | OCCMV = Part.OCC_VERSION.split('.')[0]
44 | OCCmV = Part.OCC_VERSION.split('.')[1]
45 | if (int(OCCMV)>= 7) and (int(OCCmV)>= 3):
46 | sel = FreeCADGui.Selection.getSelectionEx()
47 | for sub in sel:
48 | if 'Face' in str(sub.SubElementNames):
49 | return True
50 | else:
51 | return False
52 |
53 | def Activated(self):
54 | #def execute():
55 | import Part, DefeaturingFeature
56 | #print ('activated')
57 | selection=FreeCADGui.Selection.getSelectionEx()
58 | rh_faces = [];rh_faces_names=[]
59 | selEx=FreeCADGui.Selection.getSelectionEx()
60 | if len (selEx) > 0:
61 | FreeCAD.ActiveDocument.openTransaction('dft')
62 | for selFace in selEx:
63 | for i,f in enumerate(selFace.SubObjects):
64 | if 'Face' in selFace.SubElementNames[i]:
65 | rh_faces.append(f)
66 | rh_faces_names.append(selFace.ObjectName+'.'+selFace.SubElementNames[i])
67 | print(selFace.ObjectName+'.'+selFace.SubElementNames[i])
68 | #print (len(rh_faces))
69 | for selobj in selection:
70 | newobj=selobj.Document.addObject("Part::FeaturePython",'defeat')
71 | DefeaturingFeature.DefeatShape(rh_faces_names,newobj,selobj.Object)
72 | DefeaturingFeature.ViewProviderTree(newobj.ViewObject)
73 | newobj.Label='defeat_%s' % selobj.Object.Label
74 | selobj.Object.ViewObject.hide()
75 | FreeCAD.ActiveDocument.commitTransaction()
76 | FreeCAD.ActiveDocument.recompute()
77 | def GetResources(self):
78 | return {'Pixmap' : os.path.join(DefeaturingWB_icons_path,'DefeaturingParametric.svg'), 'MenuText': \
79 | QtCore.QT_TRANSLATE_NOOP('DefeatShapeFeature',\
80 | 'Defeat Shape Feature'), 'ToolTip': \
81 | QtCore.QT_TRANSLATE_NOOP('DefeatShapeFeature',\
82 | 'Create Defeat Shape Parametric Feature')}
83 | FreeCADGui.addCommand('DefeatShapeFeature',DefeatShapeFeature())
84 | ##
85 |
86 | class DefeaturingTools:
87 | "defeaturing tools object"
88 |
89 | def GetResources(self):
90 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'defeaturingTools.svg') , # the name of a svg file available in the resources
91 | 'MenuText': "Defeaturing Tools" ,
92 | 'ToolTip' : "Defeaturing workbench"}
93 |
94 | def IsActive(self):
95 | import os, sys
96 | return True
97 |
98 | def Activated(self):
99 | # do something here...
100 | import DefeaturingTools
101 | reload_lib(DefeaturingTools)
102 | FreeCAD.Console.PrintWarning( 'Defeaturing Tools active :)\n' )
103 | #import kicadStepUptools
104 |
105 | FreeCADGui.addCommand('DefeaturingTools',DefeaturingTools())
106 | ##
107 | class DF_SelectLoop:
108 | "the Path command to complete loop selection definition"
109 | def __init__(self):
110 | self.obj = None
111 | self.sub = []
112 | self.active = False
113 |
114 | def GetResources(self):
115 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'Path-SelectLoop.svg') ,
116 | 'MenuText': "Defeaturing_SelectLoop",
117 | 'ToolTip': "Defeaturing SelectLoop"}
118 |
119 | def IsActive(self):
120 | #if bool(FreeCADGui.Selection.getSelection()) is False:
121 | # return False
122 | if 0: #try:
123 | sel = FreeCADGui.Selection.getSelectionEx()[0]
124 | if sel.Object == self.obj and sel.SubElementNames == self.sub:
125 | return self.active
126 | self.obj = sel.Object
127 | self.sub = sel.SubElementNames
128 | if sel.SubObjects:
129 | self.active = self.formsPartOfALoop(sel.Object, sel.SubObjects[0], sel.SubElementNames)
130 | else:
131 | self.active = False
132 | return self.active
133 | return True
134 | #except Exception as exc:
135 | # PathLog.error(exc)
136 | # traceback.print_exc(exc)
137 | # return False
138 |
139 | def Activated(self):
140 | sel = FreeCADGui.Selection.getSelectionEx()[0]
141 | obj = sel.Object
142 | edge1 = sel.SubObjects[0]
143 | if 'Face' in sel.SubElementNames[0]:
144 | loop = horizontalFaceLoop(sel.Object, sel.SubObjects[0], sel.SubElementNames)
145 | if loop:
146 | FreeCADGui.Selection.clearSelection()
147 | FreeCADGui.Selection.addSelection(sel.Object, loop)
148 | loopwire = []
149 | elif len(sel.SubObjects) == 1:
150 | loopwire = horizontalEdgeLoop(obj, edge1)
151 | else:
152 | edge2 = sel.SubObjects[1]
153 | loopwire = loopdetect(obj, edge1, edge2)
154 |
155 | if loopwire:
156 | FreeCADGui.Selection.clearSelection()
157 | elist = obj.Shape.Edges
158 | for e in elist:
159 | for i in loopwire.Edges:
160 | if e.hashCode() == i.hashCode():
161 | FreeCADGui.Selection.addSelection(obj, "Edge"+str(elist.index(e)+1))
162 |
163 | def formsPartOfALoop(self, obj, sub, names):
164 | if names[0][0:4] != 'Edge':
165 | if names[0][0:4] == 'Face' and horizontalFaceLoop(obj, sub, names):
166 | return True
167 | return False
168 | if len(names) == 1 and horizontalEdgeLoop(obj, sub):
169 | return True
170 | if len(names) == 1 or names[1][0:4] != 'Edge':
171 | return False
172 | return True
173 |
174 | if FreeCAD.GuiUp:
175 | FreeCADGui.addCommand('DF_SelectLoop', DF_SelectLoop())
176 | ##
177 | class refineFeatureTool:
178 | "refine Feature Parametric"
179 |
180 | def GetResources(self):
181 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'RefineShapeFeature.svg') , # the name of a svg file available in the resources
182 | 'MenuText': "refine Feature" ,
183 | 'ToolTip' : "refine Feature Parametric"}
184 |
185 | def IsActive(self):
186 | if len(FreeCADGui.Selection.getSelection()) > 0:
187 | return True
188 |
189 | def Activated(self):
190 | import OpenSCADFeatures
191 | doc=FreeCAD.ActiveDocument
192 | docG = FreeCADGui.ActiveDocument
193 | sel=FreeCADGui.Selection.getSelectionEx()
194 | if len (sel) > 0:
195 | for selobj in sel:
196 | if hasattr(selobj.Object,"Shape"):
197 | newobj=selobj.Document.addObject("Part::FeaturePython",'refined')
198 | OpenSCADFeatures.RefineShape(newobj,selobj.Object)
199 | OpenSCADFeatures.ViewProviderTree(newobj.ViewObject)
200 | ## to do: see if it is possible to conserve colors in refining
201 | ao = FreeCAD.ActiveDocument.ActiveObject
202 | docG.ActiveObject.ShapeColor=docG.getObject(selobj.Object.Name).ShapeColor
203 | docG.ActiveObject.LineColor=docG.getObject(selobj.Object.Name).LineColor
204 | docG.ActiveObject.PointColor=docG.getObject(selobj.Object.Name).PointColor
205 | docG.ActiveObject.DiffuseColor=docG.getObject(selobj.Object.Name).DiffuseColor
206 | docG.ActiveObject.Transparency=docG.getObject(selobj.Object.Name).Transparency
207 | #newobj.Label='r_%s' % selobj.Object.Label
208 | newobj.Label=selobj.Object.Label
209 | selobj.Object.ViewObject.hide()
210 | doc.recompute()
211 | FreeCADGui.addCommand('refineFeatureTool',refineFeatureTool())
212 | ##
213 |
214 | class FuzzyCut:
215 | "Fuzzy boolean Cut"
216 |
217 | def GetResources(self):
218 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'FuzzyCut.svg') , # the name of a svg file available in the resources
219 | 'MenuText': "Fuzzy boolean Cut" ,
220 | 'ToolTip' : "Fuzzy boolean Cut"}
221 |
222 | def IsActive(self):
223 | doc = FreeCAD.ActiveDocument
224 | if hasattr(Part, "OCC_VERSION"):
225 | OCCMV = Part.OCC_VERSION.split('.')[0]
226 | OCCmV = Part.OCC_VERSION.split('.')[1]
227 | if (int(OCCMV)>= 7) and (int(OCCmV)>= 1):
228 | #return True
229 | if len(FreeCADGui.Selection.getSelection()) == 2:
230 | return True
231 | else:
232 | return False
233 |
234 | def Activated(self):
235 | # do something here...
236 | import FuzzyTools
237 | reload_lib(FuzzyTools)
238 | FuzzyTools.fuzzyCut()
239 | # FreeCAD.Console.PrintWarning( 'Fuzzy Boolean Tools active :)\n' )
240 |
241 | FreeCADGui.addCommand('FuzzyCut',FuzzyCut())
242 | ##
243 |
244 | class FuzzyUnion:
245 | "Fuzzy boolean Union"
246 |
247 | def GetResources(self):
248 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'FuzzyUnion.svg') , # the name of a svg file available in the resources
249 | 'MenuText': "Fuzzy boolean Union" ,
250 | 'ToolTip' : "Fuzzy boolean Union"}
251 |
252 | def IsActive(self):
253 | doc = FreeCAD.ActiveDocument
254 | if hasattr(Part, "OCC_VERSION"):
255 | OCCMV = Part.OCC_VERSION.split('.')[0]
256 | OCCmV = Part.OCC_VERSION.split('.')[1]
257 | if (int(OCCMV)>= 7) and (int(OCCmV)>= 1):
258 | #return True
259 | if len(FreeCADGui.Selection.getSelection()) > 1:
260 | return True
261 | else:
262 | return False
263 |
264 | def Activated(self):
265 | # do something here...
266 | import FuzzyTools
267 | reload_lib(FuzzyTools)
268 | FuzzyTools.fuzzyUnion()
269 | # FreeCAD.Console.PrintWarning( 'Fuzzy Boolean Tools active :)\n' )
270 |
271 | FreeCADGui.addCommand('FuzzyUnion',FuzzyUnion())
272 | ##
273 | class FuzzyCommon:
274 | "Fuzzy boolean Common"
275 |
276 | def GetResources(self):
277 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'FuzzyCommon.svg') , # the name of a svg file available in the resources
278 | 'MenuText': "Fuzzy boolean Common" ,
279 | 'ToolTip' : "Fuzzy boolean Common"}
280 |
281 | def IsActive(self):
282 | doc = FreeCAD.ActiveDocument
283 | if hasattr(Part, "OCC_VERSION"):
284 | OCCMV = Part.OCC_VERSION.split('.')[0]
285 | OCCmV = Part.OCC_VERSION.split('.')[1]
286 | if (int(OCCMV)>= 7) and (int(OCCmV)>= 1):
287 | #return True
288 | if len(FreeCADGui.Selection.getSelection()) > 1:
289 | return True
290 | else:
291 | return False
292 |
293 | def Activated(self):
294 | # do something here...
295 | import FuzzyTools
296 | reload_lib(FuzzyTools)
297 | FuzzyTools.fuzzyCommon()
298 | # FreeCAD.Console.PrintWarning( 'Fuzzy Boolean Tools active :)\n' )
299 |
300 | FreeCADGui.addCommand('FuzzyCommon',FuzzyCommon())
301 | ##
302 | class ResetPosition:
303 | "Defeaturing reset position tool"
304 |
305 | def GetResources(self):
306 | return {'Pixmap' : os.path.join( DefeaturingWB_icons_path , 'centering-w.svg') , # the name of a svg file available in the resources
307 | 'MenuText': "Centering Widgets" ,
308 | 'ToolTip' : "Centering Widgets\nManipulator workbench"}
309 |
310 | def IsActive(self):
311 | import os, sys
312 | return True #False #True
313 |
314 | def Activated(self):
315 | # do something here...
316 | #import kicadStepUptools
317 | #reload_lib( kicadStepUptools )
318 | import DefeaturingTools
319 | reload_lib(DefeaturingTools)
320 | DefeaturingTools.RHDockWidget.setFloating(True)
321 | DefeaturingTools.RH_centerOnScreen(DefeaturingTools.RHDockWidget)
322 |
323 | FreeCADGui.addCommand('ResetPosition',ResetPosition())
324 | ##
325 |
--------------------------------------------------------------------------------
/DefeaturingFeature.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #***************************************************************************
3 | #* *
4 | #* Copyright (c) 2017 *
5 | #* Maurice easyw@katamail.com *
6 | #* *
7 | # *
8 | # Defeaturing WB *
9 | # *
10 | # (C) Maurice easyw-fc 2018 *
11 | # This program is free software; you can redistribute it and/or modify *
12 | # it under the terms of the GNU Library General Public License (LGPL) *
13 | # as published by the Free Software Foundation; either version 2 of *
14 | # the License, or (at your option) any later version. *
15 | # for detail see the LICENCE text file. *
16 | #****************************************************************************
17 |
18 | import dft_locator, os
19 | DefeaturingWBpath = os.path.dirname(dft_locator.__file__)
20 | DefeaturingWB_icons_path = os.path.join( DefeaturingWBpath, 'Resources', 'icons')
21 | global defeat_icon, use_cm
22 | defeat_icon=os.path.join(DefeaturingWB_icons_path,'DefeaturingParametric.svg')
23 | use_cm = True
24 |
25 | '''
26 | This Script includes python Features to represent Defeaturing Operations
27 | '''
28 | class ViewProviderTree:
29 | "A generic View Provider for Elements with Children"
30 |
31 | def __init__(self, obj):
32 | obj.Proxy = self
33 | self.Object = obj.Object
34 |
35 | def attach(self, obj):
36 | self.Object = obj.Object
37 | return
38 |
39 | def getIcon(self):
40 | #import osc_locator, os
41 | global defeat_icon
42 | if isinstance(self.Object.Proxy,DefeatShape):
43 | #print (defeat_icon)
44 | # try:
45 | # if self.upd: return (defeat_icon)
46 | # except: pass
47 | return(defeat_icon)
48 |
49 | def updateData(self, fp, prop):
50 | #print (fp.Label)
51 | #if fp.Label.find('_ERR') != -1:
52 | # fp.touch()
53 | # #import FreeCAD
54 | # #doc = FreeCAD.ActiveDocument
55 | # #doc.getObject(fp.Name).touch()
56 | # print('touched')
57 | #self.getIcon()
58 | #try: self.upd
59 | #except: self.upd=True
60 | #self.upd=not self.upd
61 | #print('update')
62 | return
63 |
64 | def getDisplayModes(self,obj):
65 | modes=[]
66 | return modes
67 |
68 | def setDisplayMode(self,mode):
69 | return mode
70 |
71 | def onChanged(self, vp, prop):
72 | #self.getIcon()
73 | #print (prop)
74 | #self.getIcon()
75 | #print('change')
76 | return
77 |
78 | def __getstate__(self):
79 | # return {'ObjectName' : self.Object.Name}
80 | return None
81 |
82 | def __setstate__(self,state):
83 | if state is not None:
84 | import FreeCAD
85 | doc = FreeCAD.ActiveDocument #crap
86 | self.Object = doc.getObject(state['ObjectName'])
87 |
88 | # dumps and loads replace __getstate__ and __setstate__ post v. 0.21.2
89 | def dumps(self):
90 | return None
91 |
92 | def loads(self, state):
93 | if state is not None:
94 | import FreeCAD
95 | doc = FreeCAD.ActiveDocument #crap
96 | self.Object = doc.getObject(state['ObjectName'])
97 |
98 | def claimChildren(self):
99 | objs = []
100 | if hasattr(self.Object.Proxy,"Base"):
101 | objs.append(self.Object.Proxy.Base)
102 | if hasattr(self.Object,"Base"):
103 | objs.append(self.Object.Base)
104 | if hasattr(self.Object,"Objects"):
105 | objs.extend(self.Object.Objects)
106 | if hasattr(self.Object,"Components"):
107 | objs.extend(self.Object.Components)
108 | if hasattr(self.Object,"Children"):
109 | objs.extend(self.Object.Children)
110 | return objs
111 |
112 |
113 | ##
114 | class DefeatShape:
115 | '''return a refined shape'''
116 | def __init__(self, fc, obj, child=None):
117 |
118 | global use_cm
119 | import FreeCAD
120 | doc = FreeCAD.ActiveDocument
121 | obj.addProperty("App::PropertyLink","Base","Base",
122 | "The base object that must be defeatured")
123 | obj.Proxy = self
124 | obj.Base = child
125 | obj.addProperty("App::PropertyStringList","Faces","dFaces",
126 | "List of Faces to be defeatured")
127 | obj.Faces = fc
128 | if use_cm:
129 | obj.addProperty("App::PropertyStringList","CM","dFaces",
130 | "Center of Mass")
131 | #print(fc)
132 | cm = []
133 | for f in fc:
134 | oname = obj.Base.Name #f.split('.')[0]
135 | o = doc.getObject(oname)
136 | fnbr = int(f.split('.')[1].strip('Face'))-1
137 | mf = o.Shape.Faces[fnbr]
138 | cm.append('x='+"{0:.3f}".format(mf.CenterOfMass.x)+' y='+"{0:.3f}".format(mf.CenterOfMass.y)+' z='+"{0:.3f}".format(mf.CenterOfMass.z))
139 | obj.CM = cm
140 | obj.addProperty("App::PropertyBool","useFaceNbr","dFaces",
141 | "use Face Number")
142 |
143 | def onChanged(self, fp, prop):
144 | "Do something when a property has changed"
145 | import FreeCAD
146 | doc = FreeCAD.ActiveDocument
147 | d_faces=[]
148 | #print (prop,' changed')
149 | if (prop == 'useFaceNbr' or prop == 'Shape') and len (fp.Base.Shape.Faces) > 0:
150 | #print (fp.useFaceNbr)
151 | if fp.useFaceNbr: #not use_cm:
152 | cm_list=[]
153 | for fn in fp.Faces:
154 | oname = fp.Base.Name #fp.Faces[0].split('.')[0]
155 | fnbr = int(fn.split('.')[1].strip('Face'))-1
156 | o = doc.getObject(oname)
157 | for i, f in enumerate (o.Shape.Faces):
158 | if i == fnbr:
159 | #print (i)
160 | d_faces.append(f)
161 | c='x='+"{0:.3f}".format(f.CenterOfMass.x)+' y='+"{0:.3f}".format(f.CenterOfMass.y)+' z='+"{0:.3f}".format(f.CenterOfMass.z)
162 | cm_list.append(c)
163 | #print (c)
164 | #print(fp.CM)
165 | #print (f.CenterOfMass)
166 | #print (f.hashCode())
167 | fp.CM = cm_list
168 | else:
169 | #print(fp.Base.Shape.Faces)
170 | if len (fp.Base.Shape.Faces) > 0:
171 | #if fp.Base.Shape.isValid():
172 | fc = []
173 | #fc.append(fp.Faces[0])
174 | for i, c in enumerate(fp.CM):
175 | for j, f in enumerate (fp.Base.Shape.Faces):
176 | if c ==('x='+"{0:.3f}".format(f.CenterOfMass.x)+' y='+"{0:.3f}".format(f.CenterOfMass.y)+' z='+"{0:.3f}".format(f.CenterOfMass.z)):
177 | d_faces.append(f)
178 | #print (f.CenterOfMass)
179 | fc.append(str(fp.Base.Name)+'.'+'Face'+str(j+1))
180 | fp.Faces = fc
181 | else:
182 | print('loading first time')
183 | #doc.recompute()
184 | pass
185 |
186 | def execute(self, fp):
187 | global defeat_icon, use_cm
188 | import OpenSCADUtils, FreeCAD, FreeCADGui, Part, os
189 | doc = FreeCAD.ActiveDocument
190 | docG = FreeCADGui.ActiveDocument
191 | #print(fp.Base.Shape.Faces)
192 | #if 0: #
193 | if len (fp.Faces) > 0:
194 | if fp.Base and fp.Base.Shape.isValid():
195 | #print (fp.Faces)
196 | # rh_faces_names -> (selFace.ObjectName+'.'+selFace.SubElementNames[i])
197 | d_faces=[]
198 | if fp.useFaceNbr: #not use_cm:
199 | cm_list=[]
200 | for fn in fp.Faces:
201 | oname = fp.Base.Name #fp.Faces[0].split('.')[0]
202 | fnbr = int(fn.split('.')[1].strip('Face'))-1
203 | o = doc.getObject(oname)
204 | for i, f in enumerate (o.Shape.Faces):
205 | if i == fnbr:
206 | #print (i)
207 | d_faces.append(f)
208 | c='x='+"{0:.3f}".format(f.CenterOfMass.x)+' y='+"{0:.3f}".format(f.CenterOfMass.y)+' z='+"{0:.3f}".format(f.CenterOfMass.z)
209 | cm_list.append(c)
210 | #print (c)
211 | #print(fp.CM)
212 | #print (f.CenterOfMass)
213 | #print (f.hashCode())
214 | fp.CM = cm_list
215 | else:
216 | oname = fp.Base.Name #fp.Faces[0].split('.')[0]
217 | o = doc.getObject(oname)
218 | fc = []
219 | #fc.append(fp.Faces[0])
220 | for i, c in enumerate(fp.CM):
221 | for j, f in enumerate (fp.Base.Shape.Faces):
222 | if c ==('x='+"{0:.3f}".format(f.CenterOfMass.x)+' y='+"{0:.3f}".format(f.CenterOfMass.y)+' z='+"{0:.3f}".format(f.CenterOfMass.z)):
223 | d_faces.append(f)
224 | #print (f.CenterOfMass)
225 | fc.append(str(o.Name)+'.'+'Face'+str(j+1))
226 | #fp.Faces = fc
227 | check_faces = True
228 | if not fp.useFaceNbr: #use_cm:
229 | if len (d_faces) != len (fp.CM):
230 | check_faces = False
231 | elif len (d_faces) == 0:
232 | check_faces = False
233 | if check_faces:
234 | sh = fp.Base.Shape.defeaturing(d_faces)
235 | if fp.Base.Shape.isPartner(sh):
236 | #fp.touch()
237 | FreeCAD.Console.PrintError('Defeaturing failed 1\n')
238 | #defeat_icon=os.path.join(DefeaturingWB_icons_path,'error.svg')
239 | defeat_icon=os.path.join(DefeaturingWB_icons_path,'DefeaturingParametric.svg')
240 | docG.getObject(fp.Name).ShapeColor = (1.00,0.00,0.00)
241 | raise NameError('Defeaturing FAILED!')
242 | #try:
243 | # raise NameError('Defeaturing FAILED!')
244 | #except NameError:
245 | # print ('Defeaturing FAILED!')
246 | # raise
247 | #raise Exception('Defeaturing FAILED!')
248 | else:
249 | fp.Shape=OpenSCADUtils.applyPlacement(sh)
250 | if fp.Label.find('_ERR') != -1:
251 | fp.Label=fp.Label[:fp.Label.rfind('_ERR')]
252 | defeat_icon=os.path.join(DefeaturingWB_icons_path,'DefeaturingParametric.svg')
253 | docG.getObject(fp.Name).ShapeColor = docG.getObject(fp.Base.Name).ShapeColor
254 | docG.getObject(fp.Name).LineColor = docG.getObject(fp.Base.Name).LineColor
255 | docG.getObject(fp.Name).PointColor = docG.getObject(fp.Base.Name).PointColor
256 | docG.getObject(fp.Name).DiffuseColor= docG.getObject(fp.Base.Name).DiffuseColor
257 | docG.getObject(fp.Name).Transparency= docG.getObject(fp.Base.Name).Transparency
258 | else:
259 | #defeat_icon=os.path.join(DefeaturingWB_icons_path,'error.svg')
260 | defeat_icon=os.path.join(DefeaturingWB_icons_path,'DefeaturingParametric.svg')
261 | #fp.touch()
262 | FreeCAD.Console.PrintError('Defeaturing failed 2\n')
263 | sh = fp.Base.Shape
264 | fp.Shape=OpenSCADUtils.applyPlacement(sh)
265 | if fp.Label.find('_ERR') == -1:
266 | fp.Label='%s_ERR' % fp.Label
267 | docG.getObject(fp.Name).ShapeColor = (1.00,0.00,0.00)
268 | raise Exception('Defeaturing FAILED!')
269 | #doc.recompute()
270 | else:
271 | print('first executing')
272 | ##
273 |
274 | ## class UnionFuzzyShape:
275 | ## '''return a fuzzy unioned shape'''
276 | ## def __init__(self, compNames, obj, child=None):
277 | ## #obj.addProperty("App::PropertyLink","Base","Base",
278 | ## # "The base object that must be fuzzy unioned")
279 | ## obj.addProperty("App::PropertyStringList","Components","Components",
280 | ## "List of Objects to be fuzzy unioned")
281 | ## obj.Proxy = self
282 | ## obj.Base = child
283 | ## obj.Components = compNames
284 | ##
285 | ## def onChanged(self, fp, prop):
286 | ## "Do something when a property has changed"
287 | ## pass
288 | ##
289 | ## def execute(self, fp):
290 | ## if len (fp.Components) > 1:
291 | ## makeOp=True
292 | ## for name in fp.Components:
293 | ## if not doc.getObject(name).Shape.isValid():
294 | ## makeOp=False
295 | ## if makeOp:
296 | ## import OpenSCADUtils, FuzzyTools
297 | ## #sh=fp.Base.Shape.removeSplitter()
298 | ## ### do my ops
299 | ## result_shape = FuzzyTools.fuzzyUnion()
300 | ## fp.Shape=OpenSCADUtils.applyPlacement(result_shape)
301 | ##
302 |
--------------------------------------------------------------------------------
/DefeaturingTools-a.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'C:\Users\userC\Documents\GitHub\Defeaturing_WB\DefeaturingTools.ui'
4 | #
5 | # Created: Wed Jul 18 12:50:18 2018
6 | # by: pyside-uic 0.2.15 running on PySide 1.2.2
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PySide import QtCore, QtGui
11 |
12 | class Ui_DockWidget(object):
13 | def setupUi(self, DockWidget):
14 | DockWidget.setObjectName("DockWidget")
15 | DockWidget.resize(260, 534)
16 | icon = QtGui.QIcon()
17 | icon.addPixmap(QtGui.QPixmap("icons-new/Center-Align.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
18 | DockWidget.setWindowIcon(icon)
19 | DockWidget.setToolTip("Defeaturing tools")
20 | DockWidget.setLayoutDirection(QtCore.Qt.LeftToRight)
21 | DockWidget.setFeatures(QtGui.QDockWidget.AllDockWidgetFeatures)
22 | DockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)
23 | DockWidget.setWindowTitle("Defeaturing Tools")
24 | self.dockWidgetContents = QtGui.QWidget()
25 | self.dockWidgetContents.setObjectName("dockWidgetContents")
26 | self.PB_RHoles = QtGui.QPushButton(self.dockWidgetContents)
27 | self.PB_RHoles.setGeometry(QtCore.QRect(12, 288, 32, 32))
28 | self.PB_RHoles.setToolTip("remove Hole from Face")
29 | self.PB_RHoles.setText("")
30 | self.PB_RHoles.setObjectName("PB_RHoles")
31 | self.PB_Edges = QtGui.QPushButton(self.dockWidgetContents)
32 | self.PB_Edges.setGeometry(QtCore.QRect(220, 36, 32, 32))
33 | self.PB_Edges.setToolTip("add selected Edges to List")
34 | self.PB_Edges.setText("")
35 | self.PB_Edges.setObjectName("PB_Edges")
36 | self.TE_Faces = QtGui.QPlainTextEdit(self.dockWidgetContents)
37 | self.TE_Faces.setGeometry(QtCore.QRect(24, 164, 190, 71))
38 | self.TE_Faces.setToolTip("List of Face(s)")
39 | self.TE_Faces.setObjectName("TE_Faces")
40 | self.checkBox_keep_original = QtGui.QCheckBox(self.dockWidgetContents)
41 | self.checkBox_keep_original.setGeometry(QtCore.QRect(124, 252, 110, 33))
42 | self.checkBox_keep_original.setToolTip("keep the original object")
43 | self.checkBox_keep_original.setText("keep Object")
44 | self.checkBox_keep_original.setChecked(True)
45 | self.checkBox_keep_original.setObjectName("checkBox_keep_original")
46 | self.InfoLabel = QtGui.QLabel(self.dockWidgetContents)
47 | self.InfoLabel.setGeometry(QtCore.QRect(24, 0, 196, 36))
48 | self.InfoLabel.setText("Select Edge(s)\n"
49 | "Ctrl+Click")
50 | self.InfoLabel.setObjectName("InfoLabel")
51 | self.TE_Edges = QtGui.QPlainTextEdit(self.dockWidgetContents)
52 | self.TE_Edges.setEnabled(True)
53 | self.TE_Edges.setGeometry(QtCore.QRect(24, 36, 190, 66))
54 | self.TE_Edges.setToolTip("List of Edge(s)")
55 | self.TE_Edges.setPlainText("")
56 | self.TE_Edges.setObjectName("TE_Edges")
57 | self.PB_Faces = QtGui.QPushButton(self.dockWidgetContents)
58 | self.PB_Faces.setGeometry(QtCore.QRect(220, 164, 32, 32))
59 | self.PB_Faces.setToolTip("add selected Faces to List")
60 | self.PB_Faces.setText("")
61 | self.PB_Faces.setObjectName("PB_Faces")
62 | self.PB_Edges_Clear = QtGui.QPushButton(self.dockWidgetContents)
63 | self.PB_Edges_Clear.setGeometry(QtCore.QRect(220, 71, 32, 32))
64 | self.PB_Edges_Clear.setToolTip("clear List")
65 | self.PB_Edges_Clear.setText("")
66 | self.PB_Edges_Clear.setObjectName("PB_Edges_Clear")
67 | self.PB_Faces_Clear = QtGui.QPushButton(self.dockWidgetContents)
68 | self.PB_Faces_Clear.setGeometry(QtCore.QRect(220, 200, 32, 32))
69 | self.PB_Faces_Clear.setToolTip("clear List")
70 | self.PB_Faces_Clear.setText("")
71 | self.PB_Faces_Clear.setObjectName("PB_Faces_Clear")
72 | self.Edge_Nbr = QtGui.QLabel(self.dockWidgetContents)
73 | self.Edge_Nbr.setGeometry(QtCore.QRect(48, 104, 53, 16))
74 | self.Edge_Nbr.setText("0")
75 | self.Edge_Nbr.setObjectName("Edge_Nbr")
76 | self.Face_Nbr = QtGui.QLabel(self.dockWidgetContents)
77 | self.Face_Nbr.setGeometry(QtCore.QRect(48, 236, 53, 16))
78 | self.Face_Nbr.setText("0")
79 | self.Face_Nbr.setObjectName("Face_Nbr")
80 | self.label = QtGui.QLabel(self.dockWidgetContents)
81 | self.label.setGeometry(QtCore.QRect(24, 124, 177, 45))
82 | self.label.setText("Select Face(s)\n"
83 | "Ctrl+Click")
84 | self.label.setObjectName("label")
85 | self.checkBox_Refine = QtGui.QCheckBox(self.dockWidgetContents)
86 | self.checkBox_Refine.setGeometry(QtCore.QRect(12, 260, 89, 20))
87 | self.checkBox_Refine.setToolTip("refine the resulting solid\n"
88 | "after the operation ")
89 | self.checkBox_Refine.setText("refine")
90 | self.checkBox_Refine.setChecked(False)
91 | self.checkBox_Refine.setObjectName("checkBox_Refine")
92 | self.checkBox_keep_faces = QtGui.QCheckBox(self.dockWidgetContents)
93 | self.checkBox_keep_faces.setGeometry(QtCore.QRect(128, 140, 100, 20))
94 | self.checkBox_keep_faces.setToolTip("keep construction faces")
95 | self.checkBox_keep_faces.setText("keep faces")
96 | self.checkBox_keep_faces.setObjectName("checkBox_keep_faces")
97 | self.PB_RFaces = QtGui.QPushButton(self.dockWidgetContents)
98 | self.PB_RFaces.setGeometry(QtCore.QRect(68, 288, 32, 32))
99 | self.PB_RFaces.setToolTip("remove \'in List\' Faces")
100 | self.PB_RFaces.setText("")
101 | self.PB_RFaces.setObjectName("PB_RFaces")
102 | self.PB_AFaces = QtGui.QPushButton(self.dockWidgetContents)
103 | self.PB_AFaces.setGeometry(QtCore.QRect(124, 288, 32, 32))
104 | self.PB_AFaces.setToolTip("add Faces from \'in List\' Edges")
105 | self.PB_AFaces.setText("")
106 | self.PB_AFaces.setObjectName("PB_AFaces")
107 | self.PB_makeShell = QtGui.QPushButton(self.dockWidgetContents)
108 | self.PB_makeShell.setGeometry(QtCore.QRect(12, 360, 32, 32))
109 | self.PB_makeShell.setToolTip("make Solid from in list Faces")
110 | self.PB_makeShell.setText("")
111 | self.PB_makeShell.setObjectName("PB_makeShell")
112 | self.PB_makeShell_2 = QtGui.QPushButton(self.dockWidgetContents)
113 | self.PB_makeShell_2.setGeometry(QtCore.QRect(68, 360, 32, 32))
114 | self.PB_makeShell_2.setToolTip("make Solid from the Faces\n"
115 | "of the selected Objects")
116 | self.PB_makeShell_2.setText("")
117 | self.PB_makeShell_2.setObjectName("PB_makeShell_2")
118 | self.PB_check_TypeId = QtGui.QPushButton(self.dockWidgetContents)
119 | self.PB_check_TypeId.setGeometry(QtCore.QRect(124, 468, 32, 32))
120 | font = QtGui.QFont()
121 | font.setWeight(50)
122 | font.setItalic(False)
123 | font.setUnderline(False)
124 | font.setBold(False)
125 | self.PB_check_TypeId.setFont(font)
126 | self.PB_check_TypeId.setToolTip("show/hide TypeId of the Shape")
127 | self.PB_check_TypeId.setText("")
128 | self.PB_check_TypeId.setObjectName("PB_check_TypeId")
129 | self.Obj_Nbr = QtGui.QLabel(self.dockWidgetContents)
130 | self.Obj_Nbr.setGeometry(QtCore.QRect(164, 104, 53, 16))
131 | self.Obj_Nbr.setText("0")
132 | self.Obj_Nbr.setObjectName("Obj_Nbr")
133 | self.Obj_Nbr_2 = QtGui.QLabel(self.dockWidgetContents)
134 | self.Obj_Nbr_2.setGeometry(QtCore.QRect(164, 236, 53, 16))
135 | self.Obj_Nbr_2.setText("0")
136 | self.Obj_Nbr_2.setObjectName("Obj_Nbr_2")
137 | self.PB_AEdges = QtGui.QPushButton(self.dockWidgetContents)
138 | self.PB_AEdges.setGeometry(QtCore.QRect(220, 288, 32, 32))
139 | self.PB_AEdges.setToolTip("create a copy of the \'in List\' Edges")
140 | self.PB_AEdges.setText("")
141 | self.PB_AEdges.setObjectName("PB_AEdges")
142 | self.PB_showEdgeList = QtGui.QPushButton(self.dockWidgetContents)
143 | self.PB_showEdgeList.setGeometry(QtCore.QRect(12, 396, 32, 32))
144 | self.PB_showEdgeList.setToolTip("show \'in List\' Edge(s)")
145 | self.PB_showEdgeList.setText("")
146 | self.PB_showEdgeList.setObjectName("PB_showEdgeList")
147 | self.PB_showFaceList = QtGui.QPushButton(self.dockWidgetContents)
148 | self.PB_showFaceList.setGeometry(QtCore.QRect(68, 396, 32, 32))
149 | self.PB_showFaceList.setToolTip("show \'in List\' Face(s)")
150 | self.PB_showFaceList.setText("")
151 | self.PB_showFaceList.setObjectName("PB_showFaceList")
152 | self.PB_Refine = QtGui.QPushButton(self.dockWidgetContents)
153 | self.PB_Refine.setGeometry(QtCore.QRect(124, 396, 32, 32))
154 | self.PB_Refine.setToolTip("refine")
155 | self.PB_Refine.setText("")
156 | self.PB_Refine.setObjectName("PB_Refine")
157 | self.PB_RefineParametric = QtGui.QPushButton(self.dockWidgetContents)
158 | self.PB_RefineParametric.setGeometry(QtCore.QRect(220, 396, 32, 32))
159 | self.PB_RefineParametric.setToolTip("parametric Refine")
160 | self.PB_RefineParametric.setText("")
161 | self.PB_RefineParametric.setObjectName("PB_RefineParametric")
162 | self.PB_CFaces = QtGui.QPushButton(self.dockWidgetContents)
163 | self.PB_CFaces.setGeometry(QtCore.QRect(12, 324, 32, 32))
164 | self.PB_CFaces.setToolTip("copy Faces from \'in List\' Edges")
165 | self.PB_CFaces.setText("")
166 | self.PB_CFaces.setObjectName("PB_CFaces")
167 | self.PB_TFace = QtGui.QPushButton(self.dockWidgetContents)
168 | self.PB_TFace.setGeometry(QtCore.QRect(68, 324, 32, 32))
169 | self.PB_TFace.setToolTip("copy Faces from \'in List\' Edges")
170 | self.PB_TFace.setText("")
171 | self.PB_TFace.setObjectName("PB_TFace")
172 | self.offset_input = QtGui.QLineEdit(self.dockWidgetContents)
173 | self.offset_input.setGeometry(QtCore.QRect(128, 328, 73, 22))
174 | self.offset_input.setToolTip("Face offset to apply")
175 | self.offset_input.setText("0.0")
176 | self.offset_input.setObjectName("offset_input")
177 | self.PB_TEdge = QtGui.QPushButton(self.dockWidgetContents)
178 | self.PB_TEdge.setGeometry(QtCore.QRect(220, 324, 32, 32))
179 | self.PB_TEdge.setToolTip("copy Faces from \'in List\' Edges")
180 | self.PB_TEdge.setText("")
181 | self.PB_TEdge.setObjectName("PB_TEdge")
182 | self.PB_close = QtGui.QPushButton(self.dockWidgetContents)
183 | self.PB_close.setGeometry(QtCore.QRect(-1, -1, 20, 20))
184 | self.PB_close.setToolTip("add selected Edges to List")
185 | self.PB_close.setText("")
186 | self.PB_close.setObjectName("PB_close")
187 | self.Version = QtGui.QLabel(self.dockWidgetContents)
188 | self.Version.setGeometry(QtCore.QRect(200, 0, 53, 16))
189 | self.Version.setText("0")
190 | self.Version.setObjectName("Version")
191 | self.PB_left = QtGui.QPushButton(self.dockWidgetContents)
192 | self.PB_left.setGeometry(QtCore.QRect(-1, 17, 20, 20))
193 | self.PB_left.setToolTip("dock left")
194 | self.PB_left.setText("")
195 | self.PB_left.setObjectName("PB_left")
196 | self.PB_right = QtGui.QPushButton(self.dockWidgetContents)
197 | self.PB_right.setGeometry(QtCore.QRect(-1, 34, 20, 20))
198 | self.PB_right.setToolTip("dock right")
199 | self.PB_right.setText("")
200 | self.PB_right.setObjectName("PB_right")
201 | self.PB_makeEdge = QtGui.QPushButton(self.dockWidgetContents)
202 | self.PB_makeEdge.setGeometry(QtCore.QRect(12, 468, 32, 32))
203 | self.PB_makeEdge.setToolTip("make Edge from selected Vertexes")
204 | self.PB_makeEdge.setText("")
205 | self.PB_makeEdge.setObjectName("PB_makeEdge")
206 | self.PB_expSTEP = QtGui.QPushButton(self.dockWidgetContents)
207 | self.PB_expSTEP.setGeometry(QtCore.QRect(124, 360, 32, 32))
208 | self.PB_expSTEP.setToolTip("make Solid from the Faces\n"
209 | "of the selected Objects")
210 | self.PB_expSTEP.setText("")
211 | self.PB_expSTEP.setObjectName("PB_expSTEP")
212 | self.PB_PartDefeaturing = QtGui.QPushButton(self.dockWidgetContents)
213 | self.PB_PartDefeaturing.setEnabled(False)
214 | self.PB_PartDefeaturing.setGeometry(QtCore.QRect(172, 288, 32, 32))
215 | self.PB_PartDefeaturing.setToolTip("show \'in List\' Edge(s)")
216 | self.PB_PartDefeaturing.setText("")
217 | self.PB_PartDefeaturing.setObjectName("PB_PartDefeaturing")
218 | self.PB_CleaningFaces = QtGui.QPushButton(self.dockWidgetContents)
219 | self.PB_CleaningFaces.setGeometry(QtCore.QRect(220, 360, 32, 32))
220 | self.PB_CleaningFaces.setToolTip("clean Face(s) removing\n"
221 | "holes and merging Outwire")
222 | self.PB_CleaningFaces.setText("")
223 | self.PB_CleaningFaces.setObjectName("PB_CleaningFaces")
224 | self.PB_checkS = QtGui.QPushButton(self.dockWidgetContents)
225 | self.PB_checkS.setGeometry(QtCore.QRect(12, 432, 32, 32))
226 | self.PB_checkS.setToolTip("show \'in List\' Edge(s)")
227 | self.PB_checkS.setText("")
228 | self.PB_checkS.setObjectName("PB_checkS")
229 | self.tolerance_value = QtGui.QLineEdit(self.dockWidgetContents)
230 | self.tolerance_value.setGeometry(QtCore.QRect(128, 436, 73, 22))
231 | self.tolerance_value.setToolTip("Face offset to apply")
232 | self.tolerance_value.setText("0.0")
233 | self.tolerance_value.setObjectName("tolerance_value")
234 | self.PB_setTol = QtGui.QPushButton(self.dockWidgetContents)
235 | self.PB_setTol.setGeometry(QtCore.QRect(220, 432, 32, 32))
236 | self.PB_setTol.setToolTip("copy Faces from \'in List\' Edges")
237 | self.PB_setTol.setText("")
238 | self.PB_setTol.setObjectName("PB_setTol")
239 | self.PB_getTol = QtGui.QPushButton(self.dockWidgetContents)
240 | self.PB_getTol.setGeometry(QtCore.QRect(68, 432, 32, 32))
241 | self.PB_getTol.setToolTip("copy Faces from \'in List\' Edges")
242 | self.PB_getTol.setText("")
243 | self.PB_getTol.setObjectName("PB_getTol")
244 | self.PB_sewS = QtGui.QPushButton(self.dockWidgetContents)
245 | self.PB_sewS.setGeometry(QtCore.QRect(220, 468, 32, 32))
246 | self.PB_sewS.setToolTip("copy Faces from \'in List\' Edges")
247 | self.PB_sewS.setText("")
248 | self.PB_sewS.setObjectName("PB_sewS")
249 | self.PB_RHhelp = QtGui.QPushButton(self.dockWidgetContents)
250 | self.PB_RHhelp.setGeometry(QtCore.QRect(172, 468, 32, 32))
251 | self.PB_RHhelp.setToolTip("Help")
252 | self.PB_RHhelp.setText("")
253 | self.PB_RHhelp.setObjectName("PB_RHhelp")
254 | DockWidget.setWidget(self.dockWidgetContents)
255 |
256 | self.retranslateUi(DockWidget)
257 | QtCore.QMetaObject.connectSlotsByName(DockWidget)
258 |
259 | def retranslateUi(self, DockWidget):
260 | pass
261 |
262 |
263 | if __name__ == "__main__":
264 | import sys
265 | app = QtGui.QApplication(sys.argv)
266 | DockWidget = QtGui.QDockWidget()
267 | ui = Ui_DockWidget()
268 | ui.setupUi(DockWidget)
269 | DockWidget.show()
270 | sys.exit(app.exec_())
271 |
272 |
--------------------------------------------------------------------------------
/DefeaturingTools.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | DockWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 260
10 | 534
11 |
12 |
13 |
14 |
15 | icons-new/Center-Align.pngicons-new/Center-Align.png
16 |
17 |
18 | Defeaturing tools
19 |
20 |
21 | Qt::LeftToRight
22 |
23 |
24 | QDockWidget::AllDockWidgetFeatures
25 |
26 |
27 | Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea
28 |
29 |
30 | Defeaturing Tools
31 |
32 |
33 |
34 |
35 |
36 | 12
37 | 288
38 | 32
39 | 32
40 |
41 |
42 |
43 | remove Hole from Face
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | 220
53 | 36
54 | 32
55 | 32
56 |
57 |
58 |
59 | add selected Edges to List
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 24
69 | 164
70 | 190
71 | 71
72 |
73 |
74 |
75 | List of Face(s)
76 |
77 |
78 |
79 |
80 |
81 | 124
82 | 252
83 | 110
84 | 33
85 |
86 |
87 |
88 | keep the original object
89 |
90 |
91 | keep Object
92 |
93 |
94 | true
95 |
96 |
97 |
98 |
99 |
100 | 24
101 | 0
102 | 196
103 | 36
104 |
105 |
106 |
107 | Select Edge(s)
108 | Ctrl+Click
109 |
110 |
111 |
112 |
113 | true
114 |
115 |
116 |
117 | 24
118 | 36
119 | 190
120 | 66
121 |
122 |
123 |
124 | List of Edge(s)
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | 220
134 | 164
135 | 32
136 | 32
137 |
138 |
139 |
140 | add selected Faces to List
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | 220
150 | 71
151 | 32
152 | 32
153 |
154 |
155 |
156 | clear List
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 | 220
166 | 200
167 | 32
168 | 32
169 |
170 |
171 |
172 | clear List
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | 48
182 | 104
183 | 53
184 | 16
185 |
186 |
187 |
188 | 0
189 |
190 |
191 |
192 |
193 |
194 | 48
195 | 236
196 | 53
197 | 16
198 |
199 |
200 |
201 | 0
202 |
203 |
204 |
205 |
206 |
207 | 24
208 | 124
209 | 177
210 | 45
211 |
212 |
213 |
214 | Select Face(s)
215 | Ctrl+Click
216 |
217 |
218 |
219 |
220 |
221 | 12
222 | 260
223 | 89
224 | 20
225 |
226 |
227 |
228 | refine the resulting solid
229 | after the operation
230 |
231 |
232 | refine
233 |
234 |
235 | false
236 |
237 |
238 |
239 |
240 |
241 | 128
242 | 140
243 | 100
244 | 20
245 |
246 |
247 |
248 | keep construction faces
249 |
250 |
251 | keep faces
252 |
253 |
254 |
255 |
256 |
257 | 68
258 | 288
259 | 32
260 | 32
261 |
262 |
263 |
264 | remove 'in List' Faces
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 | 124
274 | 288
275 | 32
276 | 32
277 |
278 |
279 |
280 | add Faces from 'in List' Edges
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 | 12
290 | 360
291 | 32
292 | 32
293 |
294 |
295 |
296 | make Solid from in list Faces
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 | 68
306 | 360
307 | 32
308 | 32
309 |
310 |
311 |
312 | make Solid from the Faces
313 | of the selected Objects
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 | 124
323 | 468
324 | 32
325 | 32
326 |
327 |
328 |
329 |
330 | 50
331 | false
332 | false
333 | false
334 |
335 |
336 |
337 | show/hide TypeId of the Shape
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 | 164
347 | 104
348 | 53
349 | 16
350 |
351 |
352 |
353 | 0
354 |
355 |
356 |
357 |
358 |
359 | 164
360 | 236
361 | 53
362 | 16
363 |
364 |
365 |
366 | 0
367 |
368 |
369 |
370 |
371 |
372 | 220
373 | 288
374 | 32
375 | 32
376 |
377 |
378 |
379 | create a copy of the 'in List' Edges
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 | 12
389 | 396
390 | 32
391 | 32
392 |
393 |
394 |
395 | show 'in List' Edge(s)
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 | 68
405 | 396
406 | 32
407 | 32
408 |
409 |
410 |
411 | show 'in List' Face(s)
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 | 124
421 | 396
422 | 32
423 | 32
424 |
425 |
426 |
427 | refine
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 | 220
437 | 396
438 | 32
439 | 32
440 |
441 |
442 |
443 | parametric Refine
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 | 12
453 | 324
454 | 32
455 | 32
456 |
457 |
458 |
459 | copy Faces from 'in List' Edges
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 | 68
469 | 324
470 | 32
471 | 32
472 |
473 |
474 |
475 | copy Faces from 'in List' Edges
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 | 128
485 | 328
486 | 73
487 | 22
488 |
489 |
490 |
491 | Face offset to apply
492 |
493 |
494 | 0.0
495 |
496 |
497 |
498 |
499 |
500 | 220
501 | 324
502 | 32
503 | 32
504 |
505 |
506 |
507 | copy Faces from 'in List' Edges
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 | -1
517 | -1
518 | 20
519 | 20
520 |
521 |
522 |
523 | add selected Edges to List
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 | 200
533 | 0
534 | 53
535 | 16
536 |
537 |
538 |
539 | 0
540 |
541 |
542 |
543 |
544 |
545 | -1
546 | 17
547 | 20
548 | 20
549 |
550 |
551 |
552 | dock left
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 | -1
562 | 34
563 | 20
564 | 20
565 |
566 |
567 |
568 | dock right
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 | 12
578 | 468
579 | 32
580 | 32
581 |
582 |
583 |
584 | make Edge from selected Vertexes
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 | 124
594 | 360
595 | 32
596 | 32
597 |
598 |
599 |
600 | make Solid from the Faces
601 | of the selected Objects
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 | false
610 |
611 |
612 |
613 | 172
614 | 288
615 | 32
616 | 32
617 |
618 |
619 |
620 | show 'in List' Edge(s)
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 | 220
630 | 360
631 | 32
632 | 32
633 |
634 |
635 |
636 | clean Face(s) removing
637 | holes and merging Outwire
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 | 12
647 | 432
648 | 32
649 | 32
650 |
651 |
652 |
653 | show 'in List' Edge(s)
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 | 128
663 | 436
664 | 73
665 | 22
666 |
667 |
668 |
669 | Face offset to apply
670 |
671 |
672 | 0.0
673 |
674 |
675 |
676 |
677 |
678 | 220
679 | 432
680 | 32
681 | 32
682 |
683 |
684 |
685 | copy Faces from 'in List' Edges
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 | 68
695 | 432
696 | 32
697 | 32
698 |
699 |
700 |
701 | copy Faces from 'in List' Edges
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 | 220
711 | 468
712 | 32
713 | 32
714 |
715 |
716 |
717 | copy Faces from 'in List' Edges
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 | 172
727 | 468
728 | 32
729 | 32
730 |
731 |
732 |
733 | Help
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 | 172
743 | 360
744 | 32
745 | 32
746 |
747 |
748 |
749 | connect
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 | 172
759 | 396
760 | 32
761 | 32
762 |
763 |
764 |
765 | simple copy
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 | 68
775 | 468
776 | 32
777 | 32
778 |
779 |
780 |
781 | reset Placement
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 | 4
794 |
795 |
796 | 4
797 |
798 |
799 | true
800 |
801 |
802 | true
803 |
804 |
805 | true
806 |
807 |
808 |
809 |
--------------------------------------------------------------------------------
/FuzzyTools.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #****************************************************************************
4 | #* *
5 | #* Copyright (c) 2017 *
6 | #* Maurice easyw@katamail.com *
7 | #* *
8 | # *
9 | # Repair Defeaturing Macro *
10 | # *
11 | # (C) Maurice easyw-fc 2018 *
12 | # This program is free software; you can redistribute it and/or modify *
13 | # it under the terms of the GNU Library General Public License (LGPL) *
14 | # as published by the Free Software Foundation; either version 2 of *
15 | # the License, or (at your option) any later version. *
16 | # for detail see the LICENCE text file. *
17 | #****************************************************************************
18 |
19 |
20 | import FreeCAD, FreeCADGui, Draft, Part
21 | import re, os, sys
22 | from PySide import QtCore, QtGui
23 |
24 | __version__ = "v1.0.2"
25 |
26 | def f_say(msg):
27 | FreeCAD.Console.PrintMessage(msg)
28 | FreeCAD.Console.PrintMessage('\n')
29 |
30 | def f_sayw(msg):
31 | FreeCAD.Console.PrintWarning(msg)
32 | FreeCAD.Console.PrintWarning('\n')
33 |
34 | def f_sayerr(msg):
35 | FreeCAD.Console.PrintError(msg)
36 | FreeCAD.Console.PrintWarning('\n')
37 |
38 | ##
39 | def fuzzyCut():
40 | import Part
41 | global fuzzyTolerance
42 | from PySide import QtCore, QtGui
43 |
44 | fuzzyTolerance = 0.01
45 | reply = QtGui.QInputDialog.getText(None, "Tolerance","Fuzzy Tolerance",QtGui.QLineEdit.Normal,str(fuzzyTolerance))
46 | if reply[1]:
47 | # user clicked OK
48 | replyText = reply[0]
49 | fuzzyTolerance = float (replyText)
50 | else:
51 | # user clicked Cancel
52 | replyText = reply[0] # which will be "" if they clicked Cancel
53 | doc = FreeCAD.ActiveDocument
54 | docG = FreeCADGui.ActiveDocument
55 | sel = FreeCADGui.Selection.getSelection()
56 | if len(sel)==2:
57 | if 0:
58 | doc.addObject("Part::Cut","Cut")
59 | added = doc.ActiveObject
60 | added.Base = sel[0]
61 | added.Tool = sel[1]
62 | else:
63 | shapeBase = sel[0].Shape
64 | shapeTool = sel[1].Shape
65 | result_shape = shapeBase.cut(shapeTool, fuzzyTolerance)
66 | Part.show(result_shape)
67 | added = doc.ActiveObject
68 | docG.getObject(sel[0].Name).Visibility=False
69 | docG.getObject(sel[1].Name).Visibility=False
70 | docG.getObject(added.Name).ShapeColor=docG.getObject(sel[0].Name).ShapeColor
71 | docG.getObject(added.Name).Transparency=docG.getObject(sel[0].Name).Transparency
72 | docG.getObject(added.Name).DisplayMode=docG.getObject(sel[0].Name).DisplayMode
73 | added.Label = 'CutFuzzy'
74 | doc.recompute()
75 | ##
76 | def fuzzyUnion():
77 | import Part
78 | global fuzzyTolerance
79 |
80 | fuzzyTolerance = 0.01
81 | reply = QtGui.QInputDialog.getText(None, "Tolerance","Fuzzy Tolerance",QtGui.QLineEdit.Normal,str(fuzzyTolerance))
82 | if reply[1]:
83 | # user clicked OK
84 | replyText = reply[0]
85 | fuzzyTolerance = float (replyText)
86 | else:
87 | # user clicked Cancel
88 | replyText = reply[0] # which will be "" if they clicked Cancel
89 | doc = FreeCAD.ActiveDocument
90 | docG = FreeCADGui.ActiveDocument
91 | sel = FreeCADGui.Selection.getSelection()
92 | shapes = []
93 | for s in sel[1:]:
94 | shapes.append(s.Shape)
95 | c = sel[0].Shape.multiFuse(shapes, fuzzyTolerance)
96 | Part.show(c)
97 | added = doc.ActiveObject
98 | for s in sel:
99 | docG.getObject(s.Name).Visibility=False
100 | docG.getObject(added.Name).ShapeColor=docG.getObject(sel[0].Name).ShapeColor
101 | docG.getObject(added.Name).Transparency=docG.getObject(sel[0].Name).Transparency
102 | docG.getObject(added.Name).DisplayMode=docG.getObject(sel[0].Name).DisplayMode
103 | added.Label = 'UnionFuzzy'
104 | doc.recompute()
105 | ##
106 | def fuzzyCommon():
107 | import Part
108 | global fuzzyTolerance
109 |
110 | fuzzyTolerance = 0.01
111 | reply = QtGui.QInputDialog.getText(None, "Tolerance","Fuzzy Tolerance",QtGui.QLineEdit.Normal,str(fuzzyTolerance))
112 | if reply[1]:
113 | # user clicked OK
114 | replyText = reply[0]
115 | fuzzyTolerance = float (replyText)
116 | else:
117 | # user clicked Cancel
118 | replyText = reply[0] # which will be "" if they clicked Cancel
119 | doc = FreeCAD.ActiveDocument
120 | docG = FreeCADGui.ActiveDocument
121 | sel = FreeCADGui.Selection.getSelection()
122 | shapes = []
123 | for s in sel[1:]:
124 | shapes.append(s.Shape)
125 | c = sel[0].Shape.common(shapes, fuzzyTolerance)
126 | Part.show(c)
127 | added = doc.ActiveObject
128 | for s in sel:
129 | docG.getObject(s.Name).Visibility=False
130 | docG.getObject(added.Name).ShapeColor=docG.getObject(sel[0].Name).ShapeColor
131 | docG.getObject(added.Name).Transparency=docG.getObject(sel[0].Name).Transparency
132 | docG.getObject(added.Name).DisplayMode=docG.getObject(sel[0].Name).DisplayMode
133 | added.Label = 'CommonFuzzy'
134 | doc.recompute()
135 | ##
--------------------------------------------------------------------------------
/Init.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #****************************************************************************
3 | #* *
4 | #* Defeaturing WB for FreeCAD *
5 | #* Copyright (c) 2018 *
6 | #* Maurice easyw@katamail.com *
7 | #* *
8 | #* Defeaturing WB *
9 | #* *
10 |
11 |
--------------------------------------------------------------------------------
/InitGui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #***************************************************************************
3 | #* *
4 | #* Copyright (c) 2017 *
5 | #* Maurice easyw@katamail.com *
6 | #* *
7 | # *
8 | # Defeaturing WB *
9 | # *
10 | # (C) Maurice easyw-fc 2018 *
11 | # This program is free software; you can redistribute it and/or modify *
12 | # it under the terms of the GNU Library General Public License (LGPL) *
13 | # as published by the Free Software Foundation; either version 2 of *
14 | # the License, or (at your option) any later version. *
15 | # for detail see the LICENCE text file. *
16 | #****************************************************************************
17 |
18 | DWB_wb_version='v 1.2.9'
19 | global myurlDWB
20 | myurlDWB='https://github.com/easyw/Defeaturing_WB'
21 | global mycommitsDWB
22 | mycommitsDWB=80 #v 1.2.9
23 |
24 |
25 | import FreeCAD, FreeCADGui, Part, os, sys
26 | import re, time
27 |
28 | if (sys.version_info > (3, 0)): #py3
29 | import urllib
30 | from urllib import request, error #URLError, HTTPError
31 | else: #py2
32 | import urllib2
33 | from urllib2 import Request, urlopen, URLError, HTTPError
34 |
35 | import dft_locator
36 | from DefeaturingCMD import *
37 |
38 | DefeaturingWBpath = os.path.dirname(dft_locator.__file__)
39 | DefeaturingWB_icons_path = os.path.join( DefeaturingWBpath, 'Resources', 'icons')
40 |
41 | global main_DWB_Icon
42 | main_DWB_Icon = os.path.join( DefeaturingWB_icons_path , 'Defeaturing-icon.svg')
43 |
44 |
45 | #try:
46 | # from FreeCADGui import Workbench
47 | #except ImportError as e:
48 | # FreeCAD.Console.PrintWarning("error")
49 |
50 | class DefeaturingWB ( Workbench ):
51 | global main_DWB_Icon, DWB_wb_version
52 |
53 | "Defeaturing WB object"
54 | Icon = main_DWB_Icon
55 | #Icon = ":Resources/icons/kicad-StepUp-tools-WB.svg"
56 | MenuText = "Defeaturing"
57 | ToolTip = "Defeaturing workbench"
58 |
59 | def GetClassName(self):
60 | return "Gui::PythonWorkbench"
61 |
62 | def Initialize(self):
63 |
64 | self.appendToolbar("Defeaturing Tools", ["DefeaturingTools","DF_SelectLoop","refineFeatureTool","DefeatShapeFeature","ResetPosition"])
65 |
66 | #self.appendMenu("ksu Tools", ["ksuTools","ksuToolsEdit"])
67 | self.appendMenu("Defeaturing Tools", ["refineFeatureTool","DefeaturingTools","DF_SelectLoop","ResetPosition"])
68 |
69 | self.appendToolbar("Fuzzy Tools", ["FuzzyCut","FuzzyUnion","FuzzyCommon"])
70 | self.appendMenu("Fuzzy Tools", ["FuzzyCut","FuzzyUnion","FuzzyCommon"])
71 |
72 | Log ("Loading Defeaturing Module... done\n")
73 |
74 | def Activated(self):
75 | # do something here if needed...
76 | Msg ("Defeaturing WB Activated("+DWB_wb_version+")\n")
77 | from PySide import QtGui
78 | import time
79 |
80 |
81 | def Deactivated(self):
82 | # do something here if needed...
83 | Msg ("Defeaturing WB Deactivated()\n")
84 |
85 | ###
86 |
87 | FreeCADGui.addWorkbench(DefeaturingWB)
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## FreeCAD Defeaturing Workbench
2 |
3 |
4 | [](https://www.python.org/)
5 |
6 | [](https://www.freecad.org)
7 |
8 | Intended for editing STEP models, removing/adding of selected features from the model
9 |
10 | ## Features
11 |
12 | * Features a set of tools to edit a Shape or a STEP model, removing hole(s), face(s), simplifying the model, changing the tolerance, applying Fuzzy Boolean operations etc...
13 | * Tools to create more solid shape(s), from edge(s), face(s) or shell(s).
14 | * Possiblity using direct modeling of the model, when the history of operations is unavailable. (This is the case for 3D STEP models).
15 | * Useful in situations to quickly remove proprietary details of the model before sharing it. See [Defeaturing](https://wiki.freecadweb.org/Defeaturing)
16 | * More details at [wiki.freecadweb.org/Defeaturing_Workbench](https://wiki.freecadweb.org/Defeaturing_Workbench)
17 |
18 |
19 | ## Prerequisites
20 |
21 | * FreeCAD v0.15 r4671
22 | * FreeCAD v0.16 >= r6712
23 | * FreeCAD v0.17 >= r13522
24 | * FreeCAD v0.18+
25 | * Recommended: OCCT v7.3.0 or greater
26 |
27 | ## Installation
28 |
29 | Install via the FreeCAD [Addon Manager](https://wiki.freecadweb.org/Std_AddonMgr)
30 |
31 |
32 | ## Screenshots
33 |
34 | 
35 |
36 |
37 | #### Release notes:
38 |
39 | * v1.1: Improve README + typo fixes
40 | * v1.0.1: Initial version
41 |
42 | ## Developers
43 |
44 | * Defeaturing tools: Maurice [@easyw](https://github.com/easyw/Defeaturing_WB)
45 |
--------------------------------------------------------------------------------
/Resources/FreeCAD-addon-manager-available.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Resources/Made-with-Python_.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Resources/icons/Defeaturing-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
348 |
--------------------------------------------------------------------------------
/Resources/icons/DefeaturingParametric.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
540 |
--------------------------------------------------------------------------------
/Resources/icons/Freecad.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Resources/icons/FuzzyCommon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
269 |
--------------------------------------------------------------------------------
/Resources/icons/FuzzyCut.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
209 |
--------------------------------------------------------------------------------
/Resources/icons/FuzzyUnion.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
245 |
--------------------------------------------------------------------------------
/Resources/icons/Path-SelectLoop.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
155 |
--------------------------------------------------------------------------------
/Resources/icons/RefineShapeFeature.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
145 |
--------------------------------------------------------------------------------
/Resources/icons/centering-w.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
175 |
--------------------------------------------------------------------------------
/Resources/icons/defeaturingTools.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
223 |
--------------------------------------------------------------------------------
/Resources/icons/error.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
51 |
--------------------------------------------------------------------------------
/Resources/made-with-python.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dft_locator.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #****************************************************************************
3 | #* *
4 | #* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
5 | #* 3D exporter for FreeCAD *
6 | #* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
7 | #* Copyright (c) 2015 *
8 | #* Maurice easyw@katamail.com *
9 | #* *
10 | #* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
11 | #* *
12 |
13 |
14 | import os, sys
15 |
16 | def module_path():
17 | #return os.path.dirname(unicode(__file__, encoding))
18 | return os.path.dirname(__file__)
19 |
20 | def abs_module_path():
21 | #return os.path.dirname(unicode(__file__, encoding))
22 | #return os.path.dirname(__file__)
23 | return os.path.realpath(__file__)
24 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Defeaturing Workbench
4 | A set of tools to edit a Shape or a STEP model.
5 | 1.2.9
6 | Maui
7 | AGPLv3.0
8 | https://github.com/easyw/Defeaturing_WB
9 | Resources/icons/Defeaturing-icon.svg
10 |
11 |
12 |
13 | DefeaturingWB
14 | ./
15 | 0.18.0
16 | defeaturing
17 | fuzzy
18 | step
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------