forked from Zolko-123/FreeCAD_Assembly4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
makeArrayCmd.py
executable file
·250 lines (207 loc) · 8.97 KB
/
makeArrayCmd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#!/usr/bin/env python3
# coding: utf-8
#
# makeArrayCmd.py
import os
from PySide import QtGui, QtCore
import FreeCADGui as Gui
import FreeCAD as App
from FreeCAD import Console as FCC
import Asm4_libs as Asm4
from Asm4_objects import (
ViewProviderArray,
ExpressionArray,
CircularArray,
)
"""
+-----------------------------------------------+
| an expression link array class and command |
+-----------------------------------------------+
"""
class makeExpressionArray:
iconFileName = 'Asm4_ExpressionArray.svg'
menuText = 'Create an expression driven Array'
arrayType = 'Expression Array'
namePrefix = 'XArray_'
tooltip = """Create an array of the selected object where the placement of each element is calculated using expressions and an Index property.<br>
Select a source object to array and optionally an Axis that transformation will be related to.<br>
Without axis the transformations relates to the source objects origin.<br>
<br>
<b>Index</b> : Hidden but useful to reference in expressions on Element Placement. Increments for each element from <code>0</code> to <code>Count-1</code> during recompute. <br>
<br>
<b>Element Placement :</b> Set an expression for the entire placement or its sub-properties.<br>
By opening Element Placement property in Tasks panel it is possible to set expressions for euler angles too.<br>
<br>
<b>Expressions examples</b><br>
on Angle: <code>Index%2==0?30:-30</code><br>
on Position.X: <code>Index*30</code>"""
def GetResources(self):
# print('self.iconFileName',self.iconFileName)
iconFile = os.path.join(Asm4.iconPath, self.iconFileName)
return {
'MenuText': self.menuText,
'ToolTip': self.tooltip,
'Pixmap': iconFile,
}
def _getSelectionInfo(self):
"""Check axis and returns an Expression that calculates the axis placement.
Fails if it contains more than two objects."""
sourceObj = None
objParent = None
axisObj = None
# Use the Z axis of Axis Object as default
# Works well with datum axis and more
xyz = 'Z'
selection = Gui.Selection.getSelectionEx()
# check that it's an Assembly4 'Model'
if len(selection) in (1, 2):
sourceObj = selection[0].Object
objParent = sourceObj.getParentGeoFeatureGroup()
if objParent.TypeId == 'PartDesign::Body':
# Don't go there
objParent = sourceObj = None
elif len(selection) == 2:
axisSel = selection[1]
# both objects need to be in the same container or
# the Placements will get screwed
if objParent == axisSel.Object.getParentGeoFeatureGroup():
axisObj = axisSel.Object
# Origin axis goes along its placements X-axis ...
if axisSel.TypeName == 'App::Line':
xyz = 'X'
# Check if a sub element of a LCS is selected
elif axisSel.TypeName == 'PartDesign::CoordinateSystem':
if len(axisSel.SubElementNames) == 1:
xyz = axisSel.SubElementNames[0]
# return what we have found
self.selectionInfo = sourceObj, objParent, axisObj, xyz
def IsActive(self):
self._getSelectionInfo()
return self.selectionInfo[0] is not None
# Special property setup for this array type.
def _setupProperties(self, obj):
pass
def Activated(self):
srcObj, objParent, axisObj, xyz = self.selectionInfo
if srcObj and objParent:
obj = srcObj.Document.addObject(
'Part::FeaturePython',
self.namePrefix + srcObj.Name,
ExpressionArray(),
None,
True,
)
obj.ArrayType = self.arrayType
obj.setPropertyStatus('ArrayType', 'ReadOnly')
obj.Label = self.namePrefix + srcObj.Label
obj.Axis = axisObj
obj.AxisXYZ = xyz
# set the viewprovider
ViewProviderArray(obj.ViewObject)
# move array into common parent (if any)
objParent.addObject(obj)
# hide original object
srcObj.Visibility = False
# set array parameters
obj.setLink(srcObj)
# setup class specific properties
self._setupProperties(obj)
obj.recompute()
objParent = self.selectionInfo[1]
objParent.recompute()
App.ActiveDocument.recompute()
# select the new array
Gui.Selection.clearSelection()
Gui.Selection.addSelection(obj)
"""
+-----------------------------------------------+
| a circular link array class and command |
+-----------------------------------------------+
"""
class makeCircularArray(makeExpressionArray):
iconFileName = 'Asm4_PolarArray.svg'
menuText = 'Create a circular array'
arrayType = 'Circular Array'
namePrefix = 'Circular_'
tooltip = """Create a circular (polar) array of the selected object.<br>
Select first an object and then the axis.<br>
The axis can be any object with a Placement in the same container as the selected object.<br>
It's alo possible to select a sub axis of a LCS.<br>
<br>
<b>Iterval Angle</b> : The angle between two subsequent elements.<br>
To place the last element at for example 180°, set the expression to <code>180/(Count-1)</code>"""
def IsActive(self):
# print('IsActive XC')
self._getSelectionInfo()
return self.selectionInfo[2] is not None
# Special property setup for this array type.
def _setupProperties(self, obj):
obj.Count = 6
obj.addProperty('App::PropertyAngle', 'IntervalAngle', 'Array',
'Default is an expression to spread elements equal over the full angle')
obj.setExpression('IntervalAngle', '360/Count')
obj.setExpression('.ElementPlacement.Rotation.Angle', 'IntervalAngle * Index')
obj.setPropertyStatus('ElementPlacement', 'Hidden')
"""
+-----------------------------------------------+
| a linear link array class and command |
+-----------------------------------------------+
"""
class makeLinearArray(makeExpressionArray):
iconFileName = 'Asm4_LinearArray.svg'
menuText = 'Create a linear array'
arrayType = 'Linear Array'
namePrefix = 'Linear_'
tooltip = """Create a linear array of the selected object<br>
Select first an object and then an axis for the direction<br>
The axis can be any object with a Placement in the same container as the selected object<br>
It's alo possible to select a sub axis of a LCS<br>
<br>
<b>Linear Step</b> : The angle between two subsequent elements.<br>
To place the last element 100 mm from first element, set the expression to <code>100mm/(Count-1)</code>"""
def IsActive(self):
# print('IsActive XL')
self._getSelectionInfo()
return self.selectionInfo[2] is not None
# Special property setup for this array type.
def _setupProperties(self, obj):
obj.Count = 6
obj.addProperty('App::PropertyDistance', 'LinearStep', 'Array',
'Distance between elements along Axis')
obj.LinearStep = 10.0
obj.setExpression('.ElementPlacement.Base.z', 'LinearStep * Index')
obj.setPropertyStatus('ElementPlacement', 'Hidden')
"""
+-----------------------------------------------+
| test functions |
+-----------------------------------------------+
import makeArrayCmd
array = makeArrayCmd.makeMyLink(obj)
pls = []
for i in range(10):
rot_i = App.Rotation(App.Vector(0,0,1), i*20)
pla_i = App.Placement(App.Vector(0,0,0), rot_i)
plaElmt = axePla * pla_i * axePla.inverse() * ballPla
pls.append(plaElmt)
array.setPropertyStatus('PlacementList', '-Immutable')
array.PlacementList = pls
import makeArrayCmd
array = makeArrayCmd.makeCircularArray(obj,20)
def makeMyLink(obj):
# addObject() API is extended to accept extra parameters in order to
# let the python object override the type of C++ view provider
link = obj.Document.addObject("App::FeaturePython",'LinkArray',LinkArray(),None,True)
#ViewProviderArray(link.ViewObject)
link.setLink(obj)
return link
def makeArray(obj,count):
array = obj.Document.addObject("App::FeaturePython",'LinkArray',LinkArray(),None,True)
ViewProviderArray(array.ViewObject)
array.setLink(obj)
array.Count = count
return array
"""
# add the command to the workbench
Gui.addCommand('Asm4_linearArray', makeLinearArray())
Gui.addCommand('Asm4_circularArray', makeCircularArray())
Gui.addCommand('Asm4_expressionArray', makeExpressionArray())