GSOF-3dWireFrame 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- GSOF_3dWireFrame/Example_F16.py +141 -0
- GSOF_3dWireFrame/Example_dynamicWorld.py +99 -0
- GSOF_3dWireFrame/Example_motionWorld.py +75 -0
- GSOF_3dWireFrame/Example_staticWorld.py +112 -0
- GSOF_3dWireFrame/F16_Class.py +163 -0
- GSOF_3dWireFrame/Lib3D/Assembly.py +72 -0
- GSOF_3dWireFrame/Lib3D/Lib3D.py +145 -0
- GSOF_3dWireFrame/Lib3D/Object_WireFrame.py +66 -0
- GSOF_3dWireFrame/Lib3D/Object_base.py +122 -0
- GSOF_3dWireFrame/Lib3D/Objects.py +91 -0
- GSOF_3dWireFrame/Lib3D/Utils.py +9 -0
- GSOF_3dWireFrame/Lib3D/WireFrame_display.py +37 -0
- GSOF_3dWireFrame/Lib3D/__init__.py +7 -0
- GSOF_3dWireFrame/Lib3D/stlToObj.py +40 -0
- GSOF_3dWireFrame/MathLib/MathLib.py +460 -0
- GSOF_3dWireFrame/MathLib/__init__.py +7 -0
- GSOF_3dWireFrame/attitudeViewer.py +5 -0
- GSOF_3dWireFrame/modules/AttitudeViewer_class.py +115 -0
- GSOF_3dWireFrame/modules/Controls.py +60 -0
- GSOF_3dWireFrame/modules/__init__.py +7 -0
- GSOF_3dWireFrame/objects/Axis.json +40 -0
- GSOF_3dWireFrame/objects/F16.stl +0 -0
- GSOF_3dWireFrame/objects/LandingGear.json +28 -0
- GSOF_3dWireFrame/objects/Plume.json +34 -0
- GSOF_3dWireFrame/objects/Spark.json +15 -0
- GSOF_3dWireFrame/objects/cube.json +31 -0
- GSOF_3dWireFrame/objects/cube_flex.json +31 -0
- GSOF_3dWireFrame/objects/frame.json +16 -0
- GSOF_3dWireFrame/objects/house.json +50 -0
- GSOF_3dWireFrame/objects/net.json +3 -0
- GSOF_3dWireFrame/objects/plane.stl +0 -0
- GSOF_3dWireFrame/objects/pyramid.json +22 -0
- GSOF_3dWireFrame/stlToObject.py +32 -0
- gsof_3dwireframe-1.0.0.dist-info/METADATA +48 -0
- gsof_3dwireframe-1.0.0.dist-info/RECORD +39 -0
- gsof_3dwireframe-1.0.0.dist-info/WHEEL +5 -0
- gsof_3dwireframe-1.0.0.dist-info/licenses/AUTHORS +1 -0
- gsof_3dwireframe-1.0.0.dist-info/licenses/LICENSE +7 -0
- gsof_3dwireframe-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
## By: Guy Soffer (GSOF) 22/Feb/2024
|
|
2
|
+
__version__ = "1.0.0"
|
|
3
|
+
__author__ = "Guy Soffer"
|
|
4
|
+
__copyright__ = ""
|
|
5
|
+
__credits__ = [""]
|
|
6
|
+
__license__ = ""
|
|
7
|
+
__maintainer__ = ""
|
|
8
|
+
__email__ = "gsoffer@yahoo.com"
|
|
9
|
+
__status__ = "Development"
|
|
10
|
+
|
|
11
|
+
import math, copy
|
|
12
|
+
pi = math.pi
|
|
13
|
+
|
|
14
|
+
def radToDeg(rad) -> float:
|
|
15
|
+
""" Convert radians to degrees """
|
|
16
|
+
return 180*rad/pi # or use this math.degrees(rad)
|
|
17
|
+
|
|
18
|
+
def modulu(val, modulu):
|
|
19
|
+
""" Returns the modulus of val%modulu """
|
|
20
|
+
while val > modulu:
|
|
21
|
+
val -= modulu
|
|
22
|
+
while val < -modulu:
|
|
23
|
+
val += modulu
|
|
24
|
+
return val
|
|
25
|
+
|
|
26
|
+
def clip(val, Min, Max) -> float:
|
|
27
|
+
""" Return the cliped (clamp) result of the input value """
|
|
28
|
+
if val < Min:
|
|
29
|
+
val = Min
|
|
30
|
+
elif val > Max:
|
|
31
|
+
val = Max
|
|
32
|
+
return val
|
|
33
|
+
|
|
34
|
+
def int_V2(v) -> list:
|
|
35
|
+
return int(v[0]), int(v[1])
|
|
36
|
+
|
|
37
|
+
def int_V3(v) -> list:
|
|
38
|
+
return int(v[0]), int(v[1]), int(v[2])
|
|
39
|
+
|
|
40
|
+
def intV(v) -> list:
|
|
41
|
+
out = [0]*len(v)
|
|
42
|
+
for i, elm in enumerate(v):
|
|
43
|
+
out[i] = int(elm)
|
|
44
|
+
return out
|
|
45
|
+
|
|
46
|
+
def scale_V2(v, s) -> list:
|
|
47
|
+
return v[0] * s, v[1] * s
|
|
48
|
+
|
|
49
|
+
def scale_V3(v, s) -> list:
|
|
50
|
+
return v[0] * s, v[1] * s, v[2] * s
|
|
51
|
+
|
|
52
|
+
def negR_V2(R) -> list:
|
|
53
|
+
""" TBR """
|
|
54
|
+
R[0][1] *= -1
|
|
55
|
+
R[1][0] *= -1
|
|
56
|
+
return R
|
|
57
|
+
|
|
58
|
+
def absV_V2(V) -> float:
|
|
59
|
+
""" Return the magnitude of 2D vector """
|
|
60
|
+
return math.sqrt((V[0]**2) +(V[1]**2))
|
|
61
|
+
|
|
62
|
+
def angle_V2(V) -> float:
|
|
63
|
+
""" Return the angle of 2D vector """
|
|
64
|
+
return math.atan2(V[1], V[0])
|
|
65
|
+
|
|
66
|
+
def polar_V2(V) -> float:
|
|
67
|
+
""" Return the polar coordinates of 2D vector """
|
|
68
|
+
return [absV(V), angle_V2(V)]
|
|
69
|
+
|
|
70
|
+
def rotation_V2(rad, V) -> list:
|
|
71
|
+
#sinX = math.sin(rad)
|
|
72
|
+
#cosX = math.cos(rad)
|
|
73
|
+
#DCM = ((cosX, -sinX), (sinX, cosX))
|
|
74
|
+
return MxV_2x2(DCM_V2(rad), V)
|
|
75
|
+
|
|
76
|
+
def absV_V3(V) -> float:
|
|
77
|
+
""" Return the magnitude of 2D vector """
|
|
78
|
+
return math.sqrt((V[0]**2) +(V[1]**2) +(V[2]**2))
|
|
79
|
+
|
|
80
|
+
def angle_V3(v) -> list:
|
|
81
|
+
r = absV_V3(v)
|
|
82
|
+
_absV2 = absV_V2( v[0:2] )
|
|
83
|
+
elevation = pi / 2.0 #< For case 0 and 1
|
|
84
|
+
#elevation = 0.0 #< For case2
|
|
85
|
+
if _absV2 > 0.001:
|
|
86
|
+
elevation = math.arctan( v[2] / _absV2 ) #< Case1 - https://keisan.casio.com/exec/system/1359533867 (Passed targeting test)
|
|
87
|
+
#elevation = -math.arctan2( _absV2, v[2]) +pi/2 #< Case2 - https://keisan.casio.com/exec/system/1359533867
|
|
88
|
+
#elevation = math.arcsin( r / v[2]) #< Case3 - https://www.mechamath.com/trigonometry/cartesian-to-spherical-coordinates-formulas-and-examples/
|
|
89
|
+
azimuth = math.arctan2(v[1], v[0])
|
|
90
|
+
return azimuth, elevation, r
|
|
91
|
+
|
|
92
|
+
def cartesianToPolar_V3(pos):
|
|
93
|
+
return angle_V3(pos)
|
|
94
|
+
|
|
95
|
+
def polarToCartesian_V3(azimuth, elevation, distance):
|
|
96
|
+
abs_xy = distance * math.cos(elevation)
|
|
97
|
+
x = abs_xy * math.cos(azimuth)
|
|
98
|
+
y = abs_xy * math.sin(azimuth)
|
|
99
|
+
z = distance * math.sin(elevation)
|
|
100
|
+
return x, y, z
|
|
101
|
+
|
|
102
|
+
def DCM_V2(rad) -> list:
|
|
103
|
+
""" Return the 2D rotation matrix """
|
|
104
|
+
cosA = math.cos(rad)
|
|
105
|
+
sinA = math.sin(rad)
|
|
106
|
+
return [[cosA,-sinA],[sinA,cosA]]
|
|
107
|
+
|
|
108
|
+
### https://en.wikipedia.org/wiki/Rotation_matrix
|
|
109
|
+
def DCM_XZY(a, b, c) -> list:
|
|
110
|
+
""" a is around X, b is around Z, and c is around Y"""
|
|
111
|
+
ca = math.cos(a)
|
|
112
|
+
cb = math.cos(b)
|
|
113
|
+
cc = math.cos(c)
|
|
114
|
+
|
|
115
|
+
sa = math.sin(a)
|
|
116
|
+
sb = math.sin(b)
|
|
117
|
+
sc = math.sin(c)
|
|
118
|
+
DCM = [ [ cb*cc, -sb, cb*sc ],
|
|
119
|
+
[sa*sc+ca*cc*sb, ca*cb, ca*sb*sc-cc*sa],
|
|
120
|
+
[cc*sa*sb-ca*sc, cb*sa, ca*sb*sc ]]
|
|
121
|
+
return DCM
|
|
122
|
+
|
|
123
|
+
def get_abc_XZY(dcm) -> list:
|
|
124
|
+
R32 = dcm[2][1]
|
|
125
|
+
R11 = dcm[0][0]
|
|
126
|
+
R12 = dcm[0][1]
|
|
127
|
+
R13 = dcm[0][2]
|
|
128
|
+
R22 = dcm[1][1]
|
|
129
|
+
a = math.atan(R32/R22)
|
|
130
|
+
b = math.asin(-R12)
|
|
131
|
+
c = math.atan(R13/R11)
|
|
132
|
+
return (a,b,c)
|
|
133
|
+
|
|
134
|
+
def DCM_XYZ(a, b, c) -> list:
|
|
135
|
+
""" a is around X, b is around Y, and c is around Z"""
|
|
136
|
+
ca = math.cos(a)
|
|
137
|
+
cb = math.cos(b)
|
|
138
|
+
cc = math.cos(c)
|
|
139
|
+
|
|
140
|
+
sa = math.sin(a)
|
|
141
|
+
sb = math.sin(b)
|
|
142
|
+
sc = math.sin(c)
|
|
143
|
+
DCM = [ [ cb*cc, -cb*sc, sb ],
|
|
144
|
+
[ca*sc+sa*sb*cc, ca*cc-sa*sb*sc, -sa*cb],
|
|
145
|
+
[sa*sc-ca*sb*cc, sa*cc+ca*sb*sc, ca*cb]]
|
|
146
|
+
return DCM
|
|
147
|
+
|
|
148
|
+
def get_abc_XYZ(dcm) -> list:
|
|
149
|
+
R11 = dcm[0][0]
|
|
150
|
+
R12 = dcm[0][1]
|
|
151
|
+
R13 = dcm[0][2]
|
|
152
|
+
R23 = dcm[1][2]
|
|
153
|
+
R33 = dcm[2][2]
|
|
154
|
+
a = math.atan(-R23/R33)
|
|
155
|
+
b = math.asin(R13)
|
|
156
|
+
c = math.atan(-R12/R11)
|
|
157
|
+
return (a,b,c)
|
|
158
|
+
|
|
159
|
+
def DCM_YXZ(a, b, c) -> list:
|
|
160
|
+
""" a is around Y, b is around X, and c is around Z"""
|
|
161
|
+
ca = math.cos(a)
|
|
162
|
+
cb = math.cos(b)
|
|
163
|
+
cc = math.cos(c)
|
|
164
|
+
|
|
165
|
+
sa = math.sin(a)
|
|
166
|
+
sb = math.sin(b)
|
|
167
|
+
sc = math.sin(c)
|
|
168
|
+
DCM = [ [ca*cc+sa*sb*sc, cc*sa*sb-ca*sc, cb*sa],
|
|
169
|
+
[ cb*sc , cb*cc, -sb],
|
|
170
|
+
[ca*sb*sc-cc*sa, ca*cc*sb+sa*sc, ca*cb]]
|
|
171
|
+
return DCM
|
|
172
|
+
|
|
173
|
+
def get_abc_YXZ(dcm) -> list:
|
|
174
|
+
R13 = dcm[0][2]
|
|
175
|
+
R21 = dcm[1][0]
|
|
176
|
+
R22 = dcm[1][1]
|
|
177
|
+
R23 = dcm[1][2]
|
|
178
|
+
R33 = dcm[2][2]
|
|
179
|
+
a = math.atan(R13/R33)
|
|
180
|
+
b = math.asin(-R23)
|
|
181
|
+
c = math.atan(R21/R22)
|
|
182
|
+
return (a,b,c)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def DCM_YZX(a, b, c) -> list:
|
|
186
|
+
""" a is around Y, b is around Z, and c is around X"""
|
|
187
|
+
ca = math.cos(a)
|
|
188
|
+
cb = math.cos(b)
|
|
189
|
+
cc = math.cos(c)
|
|
190
|
+
|
|
191
|
+
sa = math.sin(a)
|
|
192
|
+
sb = math.sin(b)
|
|
193
|
+
sc = math.sin(c)
|
|
194
|
+
DCM = [ [ca*cb , sa*sc-ca*cc*sb, cc*sa+ca*sb*sc],
|
|
195
|
+
[ sb , cb*cc, -cb*sc ],
|
|
196
|
+
[-cb*sa , ca*sc+cc*sa*sb, ca*cc-sa*sb*sc]]
|
|
197
|
+
return DCM
|
|
198
|
+
|
|
199
|
+
def get_abc_YZX(dcm) -> list:
|
|
200
|
+
R31 = dcm[2][0]
|
|
201
|
+
R11 = dcm[0][0]
|
|
202
|
+
R21 = dcm[1][0]
|
|
203
|
+
R22 = dcm[1][1]
|
|
204
|
+
R23 = dcm[1][2]
|
|
205
|
+
a = math.atan(-R31/R11)
|
|
206
|
+
b = math.asin(R21)
|
|
207
|
+
c = math.atan(-R23/R22)
|
|
208
|
+
return (a,b,c)
|
|
209
|
+
|
|
210
|
+
def DCM_ZYX(a, b, c) -> list:
|
|
211
|
+
""" a is around Z, b is around Y, and c is around X"""
|
|
212
|
+
ca = math.cos(a)
|
|
213
|
+
cb = math.cos(b)
|
|
214
|
+
cc = math.cos(c)
|
|
215
|
+
|
|
216
|
+
p = pi/2
|
|
217
|
+
sa = math.cos(a -p) #<math.sin(a)
|
|
218
|
+
sb = math.cos(b -p) #<math.sin(b)
|
|
219
|
+
sc = math.cos(c -p) #<math.sin(c)
|
|
220
|
+
|
|
221
|
+
DCM = [ [ca*cb, ca*sb*sc-cc*sa, sa*sc+ca*sb*cc],
|
|
222
|
+
[sa*cb, sa*sb*sc+ca*cc, cc*sa*sb-ca*sc],
|
|
223
|
+
[ -sb, cb*sc, cb*cc ]]
|
|
224
|
+
return DCM
|
|
225
|
+
|
|
226
|
+
def get_abc_ZYX(dcm) -> list:
|
|
227
|
+
R11 = dcm[0][0]
|
|
228
|
+
R21 = dcm[1][0]
|
|
229
|
+
R31 = dcm[2][0]
|
|
230
|
+
R32 = dcm[2][1]
|
|
231
|
+
R33 = dcm[2][2]
|
|
232
|
+
a = math.atan(R21/R11)
|
|
233
|
+
b = math.asin(-R31)
|
|
234
|
+
c = math.atan(R32/R33)
|
|
235
|
+
return (a,b,c)
|
|
236
|
+
|
|
237
|
+
def DCM_ZXY(a, b, c) -> list:
|
|
238
|
+
""" a is around Z, b is around X, and c is around Y"""
|
|
239
|
+
ca = math.cos(a)
|
|
240
|
+
cb = math.cos(b)
|
|
241
|
+
cc = math.cos(c)
|
|
242
|
+
|
|
243
|
+
p = pi/2
|
|
244
|
+
sa = math.cos(a -p) #<math.sin(a)
|
|
245
|
+
sb = math.cos(b -p) #<math.sin(b)
|
|
246
|
+
sc = math.cos(c -p) #<math.sin(c)
|
|
247
|
+
|
|
248
|
+
DCM = [ [ca*cb, ca*sb*sc-cc*sa, sa*sc+ca*sb*cc],
|
|
249
|
+
[sa*cb, sa*sb*sc+ca*cc, cc*sa*sb-ca*sc],
|
|
250
|
+
[ -sb, cb*sc, cb*cc ]]
|
|
251
|
+
return DCM
|
|
252
|
+
|
|
253
|
+
def get_abc_ZXY(dcm) -> list:
|
|
254
|
+
R12 = dcm[0][1]
|
|
255
|
+
R22 = dcm[1][1]
|
|
256
|
+
R31 = dcm[2][0]
|
|
257
|
+
R32 = dcm[2][1]
|
|
258
|
+
R33 = dcm[2][2]
|
|
259
|
+
a = math.atan(-R12/R22)
|
|
260
|
+
b = math.asin(R32)
|
|
261
|
+
c = math.atan(-R31/R33)
|
|
262
|
+
return (a,b,c)
|
|
263
|
+
|
|
264
|
+
def MxV_2x2(M,V) -> list:
|
|
265
|
+
""" Return the result of 2x2 matrix and 2D vector multiplication """
|
|
266
|
+
O = [0,0]
|
|
267
|
+
O[0] = M[0][0]*V[0] +(M[0][1]*V[1])
|
|
268
|
+
O[1] = M[1][0]*V[0] +(M[1][1]*V[1])
|
|
269
|
+
return O
|
|
270
|
+
|
|
271
|
+
def MxV(M,V) -> list:
|
|
272
|
+
""" Return the result of NxM matrix and V vector multiplication """
|
|
273
|
+
N = len(M)
|
|
274
|
+
O = [0]*N
|
|
275
|
+
for r,row in enumerate(M):
|
|
276
|
+
for m,v in zip(row,V):
|
|
277
|
+
O[r] += m*v
|
|
278
|
+
return O
|
|
279
|
+
|
|
280
|
+
def getCol(M, col) -> list:
|
|
281
|
+
""" Returns a copy of column 'col' from the matrix 'M' """
|
|
282
|
+
rows = len(M)
|
|
283
|
+
V = [0]*rows
|
|
284
|
+
for i, row in enumerate(M):
|
|
285
|
+
V[i] = row[col]
|
|
286
|
+
return V
|
|
287
|
+
|
|
288
|
+
def getRow(M, row) -> list:
|
|
289
|
+
""" Returns a copy of row 'row' from the matrix 'M' """
|
|
290
|
+
return copy.copy(M[row])
|
|
291
|
+
|
|
292
|
+
def MUL_3x3(M, V):
|
|
293
|
+
return [ M[0][0]*V[0] +M[0][1]*V[1] +M[0][2]*V[2],
|
|
294
|
+
M[1][0]*V[0] +M[1][1]*V[1] +M[1][2]*V[2],
|
|
295
|
+
M[2][0]*V[0] +M[2][1]*V[1] +M[2][2]*V[2] ]
|
|
296
|
+
|
|
297
|
+
def MUL_4x4(M, V):
|
|
298
|
+
return [ M[0][0]*V[0] +M[0][1]*V[1] +M[0][2]*V[2] +M[0][3]*V[3],
|
|
299
|
+
M[1][0]*V[0] +M[1][1]*V[1] +M[1][2]*V[2] +M[1][3]*V[3],
|
|
300
|
+
M[2][0]*V[0] +M[2][1]*V[1] +M[2][2]*V[2] +M[2][3]*V[3],
|
|
301
|
+
M[3][0]*V[0] +M[3][1]*V[1] +M[3][2]*V[2] +M[3][3]*V[3] ]
|
|
302
|
+
|
|
303
|
+
def MxM(M1, M2) -> list:
|
|
304
|
+
""" Return the result two matrix multiplication """
|
|
305
|
+
rows = len(M2) #< If vector instead of matrix make a matrix
|
|
306
|
+
try:
|
|
307
|
+
colsM2 = len(M2[0])
|
|
308
|
+
except:
|
|
309
|
+
M2 = [M2]
|
|
310
|
+
rows = 1
|
|
311
|
+
|
|
312
|
+
try: #< If vector instead of matrix make a matrix
|
|
313
|
+
cols = len(M1[0])
|
|
314
|
+
except:
|
|
315
|
+
cols = len(M1)
|
|
316
|
+
M1 = [M1]
|
|
317
|
+
|
|
318
|
+
rows = len(M1) #< Rows in M1
|
|
319
|
+
cols = len(M2[0]) #< Columns in M2
|
|
320
|
+
O = zeros(rows, cols) #< The output
|
|
321
|
+
for r in range(0,rows):
|
|
322
|
+
row = getRow(M1, r)
|
|
323
|
+
for c in range(0, cols):
|
|
324
|
+
col = getCol(M2, c) #< col is a row vector
|
|
325
|
+
O[r][c] = VxV(row[0:len(col)], col)
|
|
326
|
+
return O
|
|
327
|
+
|
|
328
|
+
def add_V2(V1, V2) -> list:
|
|
329
|
+
""" Return the result of 2D vector addition """
|
|
330
|
+
return [V1[0]+V2[0], V1[1]+V2[1]]
|
|
331
|
+
|
|
332
|
+
#def addV(V1, V2) -> list:
|
|
333
|
+
# out = [0]*len(V1)
|
|
334
|
+
# for i, elm1, elm2 in enumerate(zip(V1,V2)):
|
|
335
|
+
# out[i] = elm1+elm2
|
|
336
|
+
# return out
|
|
337
|
+
|
|
338
|
+
def addV(V1, V2) -> list:
|
|
339
|
+
""" Return the result of vector addition """
|
|
340
|
+
O = [0]*len(V1)
|
|
341
|
+
i = 0
|
|
342
|
+
for v1,v2 in zip(V1, V2):
|
|
343
|
+
O[i] = v1+v2
|
|
344
|
+
i += 1
|
|
345
|
+
return O
|
|
346
|
+
|
|
347
|
+
def absV(V) -> float:
|
|
348
|
+
""" Return the magnitude of vector """
|
|
349
|
+
s2 = 0
|
|
350
|
+
for v in V:
|
|
351
|
+
s2 += v**2
|
|
352
|
+
return math.sqrt(s2)
|
|
353
|
+
|
|
354
|
+
def scaleV(V, s) -> list:
|
|
355
|
+
""" Return the scaled vector 'V' by the scaler 's' """
|
|
356
|
+
O = [0]*len(V)
|
|
357
|
+
for i, e in enumerate(V):
|
|
358
|
+
O[i] = e*s
|
|
359
|
+
return O
|
|
360
|
+
|
|
361
|
+
def VxV(V1, V2) -> float:
|
|
362
|
+
""" Returns the result of two vector multiplacation """
|
|
363
|
+
Sum = 0
|
|
364
|
+
for e1, e2 in zip(V1, V2):
|
|
365
|
+
Sum += e1*e2
|
|
366
|
+
return Sum
|
|
367
|
+
|
|
368
|
+
def matrix(rows, cols, val=0) -> list:
|
|
369
|
+
""" Returns the rows by cols matrix M filled with value val """
|
|
370
|
+
M = [0]*rows
|
|
371
|
+
for row in range(0,rows):
|
|
372
|
+
M[row] = [val]*cols
|
|
373
|
+
return M
|
|
374
|
+
|
|
375
|
+
def zeros(rows, cols) -> list:
|
|
376
|
+
""" Returns the rows by cols zero matrix Z """
|
|
377
|
+
return matrix(rows, cols, val=0)
|
|
378
|
+
|
|
379
|
+
def ones(rows, cols) -> list:
|
|
380
|
+
""" Returns the rows by cols zero matrix Z """
|
|
381
|
+
return matrix(rows, cols, val=1)
|
|
382
|
+
|
|
383
|
+
def I(size) -> list:
|
|
384
|
+
""" Returns the size by size identity matrix I """
|
|
385
|
+
I = [0]*size
|
|
386
|
+
for row in range(0,size):
|
|
387
|
+
I[row] = [0]*size
|
|
388
|
+
I[row][row] = 1
|
|
389
|
+
return I
|
|
390
|
+
|
|
391
|
+
def T(M) -> list:
|
|
392
|
+
""" Returns the transposed Matrix of M """
|
|
393
|
+
rows = len(M)
|
|
394
|
+
try:
|
|
395
|
+
cols = len(M[0])
|
|
396
|
+
except:
|
|
397
|
+
cols = rows
|
|
398
|
+
rows = 1
|
|
399
|
+
M = [M]
|
|
400
|
+
O = [0]*cols
|
|
401
|
+
for i in range(0,cols):
|
|
402
|
+
O[i] = getCol(M,i)
|
|
403
|
+
return O
|
|
404
|
+
|
|
405
|
+
def invM(M) -> list:
|
|
406
|
+
""" Not ready yet, Returns the inverse of the matrix M (Using Naive Gauss elimination method) """
|
|
407
|
+
rows = len(M)
|
|
408
|
+
cols = rows
|
|
409
|
+
O = [0]*rows
|
|
410
|
+
O[0] = copy.copy(M[0]) #scaleV(M[0], 1)
|
|
411
|
+
for col in range(0, cols-1):
|
|
412
|
+
stRow = col
|
|
413
|
+
refRow = M[stRow]
|
|
414
|
+
for i in range(stRow +1, rows):
|
|
415
|
+
row = M[i]
|
|
416
|
+
tmpRow1 = scaleV(refRow, -row[col])
|
|
417
|
+
tmpRow2 = scaleV(row, refRow[col])
|
|
418
|
+
O[i] = addV(tmpRow2, tmpRow1)
|
|
419
|
+
M = copy.copy(O)
|
|
420
|
+
return O
|
|
421
|
+
|
|
422
|
+
def LU(M) -> list:
|
|
423
|
+
""" Not ready yet, Returns the lower and upper (LU) matrixes that forms the matrix M """
|
|
424
|
+
rows = len(M)
|
|
425
|
+
cols = rows
|
|
426
|
+
L = I(rows)
|
|
427
|
+
U = [0]*rows
|
|
428
|
+
U[0] = copy.copy(M[0]) #scaleV(M[0], 1)
|
|
429
|
+
for col in range(0, cols-1):
|
|
430
|
+
stRow = col
|
|
431
|
+
refRow = M[stRow]
|
|
432
|
+
for i in range(stRow +1, rows):
|
|
433
|
+
row = M[i]
|
|
434
|
+
tmpRow1 = scaleV(refRow, -row[col])
|
|
435
|
+
tmpRow2 = scaleV(row, refRow[col])
|
|
436
|
+
L[i][col] = refRow[col]/row[col]
|
|
437
|
+
U[i] = addV(tmpRow2, tmpRow1)
|
|
438
|
+
M = copy.copy(U)
|
|
439
|
+
return (L, U)
|
|
440
|
+
|
|
441
|
+
def copyIntoMatrix(M, S, rs=0, cs=0, rn=3, cn=3) -> list:
|
|
442
|
+
for ri in range(0,rn):
|
|
443
|
+
row = S[ri]
|
|
444
|
+
for ci in range(0, cn):
|
|
445
|
+
M[rs+ri][cs+ci] = row[ci]
|
|
446
|
+
return M
|
|
447
|
+
|
|
448
|
+
if __name__ == "__main__":
|
|
449
|
+
# M = [[1,2,3,4],
|
|
450
|
+
# [4,5,60,7],
|
|
451
|
+
# [7,8,9,11],
|
|
452
|
+
# [17,18,19,10],
|
|
453
|
+
# ]
|
|
454
|
+
M = [[1,2,3],
|
|
455
|
+
[4,5,6],
|
|
456
|
+
[7,8,11],
|
|
457
|
+
]
|
|
458
|
+
|
|
459
|
+
#o = invM(M)
|
|
460
|
+
l,u = LU(M)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import pygame, math, json
|
|
2
|
+
from Lib3D import Object_WireFrame as OWF
|
|
3
|
+
from Lib3D import Object_base as OB
|
|
4
|
+
from Lib3D import WireFrame_display as DISP
|
|
5
|
+
from Lib3D import Objects
|
|
6
|
+
from modules import Controls
|
|
7
|
+
|
|
8
|
+
SCREEN_WIDTH = 800
|
|
9
|
+
SCREEN_HEIGHT = 600
|
|
10
|
+
WHITE = (255,255,255)
|
|
11
|
+
BLACK = (0,0,0)
|
|
12
|
+
PI = math.pi
|
|
13
|
+
|
|
14
|
+
def newScreen(title="New", resX=SCREEN_WIDTH, resY=SCREEN_HEIGHT, color=WHITE):
|
|
15
|
+
screen = pygame.display.set_mode( (resX, resY) )
|
|
16
|
+
screen.fill(color)
|
|
17
|
+
pygame.display.set_caption(title)
|
|
18
|
+
return screen
|
|
19
|
+
|
|
20
|
+
class AttitudeViewer():
|
|
21
|
+
def __init__(self):
|
|
22
|
+
net = OWF.Object_wireFrame(obj=Objects.net(25,25), color=(0,100,0)).rotate(x=PI/2, y=0, z=0).translate(V=(0, 0, 0), initShape=True).scale(0.2, initShape=True)
|
|
23
|
+
axis = OWF.Object_wireFrame(filename="./objects/axis.json", color=(10,10,10)).translate(V=(0, 0, 0), initShape=True).scale(5.0, initShape=True)
|
|
24
|
+
self.f16 = OWF.Object_wireFrame(filename="./objects/F16.stl", color=(0,0,255)).translate(V=(0, 0, 0), initShape=True)
|
|
25
|
+
self.f16.setOrigin( origin=self.f16.getOrigin(origin="arithCenter"), initShape=True ).scale(0.02, initShape=True)
|
|
26
|
+
# f16.translate(V=(0, 0, 200), initShape=True)
|
|
27
|
+
# f16.rotate(x=0, y=PI/2, z=PI, origin="arithCenter", initShape=True)
|
|
28
|
+
# f16.translate(V=(-50, -50, 0), initShape=True)
|
|
29
|
+
|
|
30
|
+
self.world = OB.Object_container(objList = (
|
|
31
|
+
axis,
|
|
32
|
+
net,
|
|
33
|
+
self.f16,
|
|
34
|
+
))
|
|
35
|
+
|
|
36
|
+
pygame.init()
|
|
37
|
+
self.clock = pygame.time.Clock()
|
|
38
|
+
self.screen = newScreen("3D Wire Frame - Attitude Viewer", SCREEN_WIDTH, SCREEN_HEIGHT, WHITE)
|
|
39
|
+
self.wireframe = DISP.WireFrame(self.screen, pygame.draw.line, f=50, scale=10)
|
|
40
|
+
self.viewer = Controls.Viewer( pos=(0,0,-1200),
|
|
41
|
+
center=(int(self.screen.get_width()/2),int(self.screen.get_height()/2)),
|
|
42
|
+
moveLeftKey = pygame.K_a,
|
|
43
|
+
moveRightKey = pygame.K_d,
|
|
44
|
+
moveUpKey = pygame.K_UP,
|
|
45
|
+
moveDownKey = pygame.K_DOWN,
|
|
46
|
+
moveFwdKey = pygame.K_w,
|
|
47
|
+
moveBackKey = pygame.K_x,
|
|
48
|
+
tiltLeft = pygame.K_COMMA,
|
|
49
|
+
tiltRight = pygame.K_PERIOD
|
|
50
|
+
)
|
|
51
|
+
self.uut = Controls.Object( pos=(200,200,200),
|
|
52
|
+
center=(int(self.screen.get_width()/2), int(self.screen.get_height()/2)),
|
|
53
|
+
moveLeftKey = pygame.K_a,
|
|
54
|
+
moveRightKey = pygame.K_d,
|
|
55
|
+
moveUpKey = pygame.K_UP,
|
|
56
|
+
moveDownKey = pygame.K_DOWN,
|
|
57
|
+
moveFwdKey = pygame.K_w,
|
|
58
|
+
moveBackKey = pygame.K_x,
|
|
59
|
+
tiltLeft = pygame.K_COMMA,
|
|
60
|
+
tiltRight = pygame.K_PERIOD
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
self.fps = 30
|
|
64
|
+
self.dt = 1/self.fps
|
|
65
|
+
self.t = 0.0
|
|
66
|
+
self.objects = [self.viewer, self.uut]
|
|
67
|
+
self.objSel = 0
|
|
68
|
+
self.run = False
|
|
69
|
+
|
|
70
|
+
def _clearScreen(self, color=(255,255,255)) -> None:
|
|
71
|
+
self.screen.fill(color)
|
|
72
|
+
|
|
73
|
+
def start(self):
|
|
74
|
+
self.run = True
|
|
75
|
+
while self.run:
|
|
76
|
+
### Get inputs
|
|
77
|
+
for event in pygame.event.get():
|
|
78
|
+
if event.type == pygame.QUIT:
|
|
79
|
+
self.run = False
|
|
80
|
+
|
|
81
|
+
keys = pygame.key.get_pressed()
|
|
82
|
+
(mPosX, mPosY) = pygame.mouse.get_pos()
|
|
83
|
+
if keys[pygame.K_v]:
|
|
84
|
+
self.objSel = 0
|
|
85
|
+
elif keys[pygame.K_u]:
|
|
86
|
+
self.objSel = 1
|
|
87
|
+
|
|
88
|
+
self.objects[self.objSel].update(keys, mPosX, mPosY, speed=2)
|
|
89
|
+
|
|
90
|
+
self.wireframe.f += -(keys[pygame.K_1] - keys[pygame.K_2])*10
|
|
91
|
+
|
|
92
|
+
### Calculate next step state
|
|
93
|
+
# t += dt
|
|
94
|
+
|
|
95
|
+
### Update 3D world
|
|
96
|
+
self.world.reset()
|
|
97
|
+
self.f16.rotate( *self.uut.getAttitude() ).translate( V=self.uut.getPosition() )
|
|
98
|
+
self.world.translate( V=self.viewer.getPosition() ).rotate( *self.viewer.getAttitude() )
|
|
99
|
+
|
|
100
|
+
### Draw 3D world
|
|
101
|
+
self._clearScreen(WHITE)
|
|
102
|
+
self.wireframe.draw(self.world)
|
|
103
|
+
|
|
104
|
+
### Wait for next step time
|
|
105
|
+
self.clock.tick(30)
|
|
106
|
+
|
|
107
|
+
### Display output
|
|
108
|
+
pygame.display.flip()
|
|
109
|
+
|
|
110
|
+
pygame.quit()
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
attitude = AttitudeViewer()
|
|
114
|
+
attitude.start()
|
|
115
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
class Viewer():
|
|
4
|
+
def __init__(self, pos=(0,0,0), att=(0,0,0), center=(0,0),
|
|
5
|
+
moveLeftKey=0, moveRightKey=0,
|
|
6
|
+
moveUpKey=0, moveDownKey=0,
|
|
7
|
+
moveFwdKey=0, moveBackKey=0,
|
|
8
|
+
tiltLeft=0, tiltRight=0):
|
|
9
|
+
self.posX = pos[0]
|
|
10
|
+
self.posY = pos[1]
|
|
11
|
+
self.posZ = pos[2]
|
|
12
|
+
self.attX = att[0]
|
|
13
|
+
self.attY = att[1]
|
|
14
|
+
self.attZ = att[2]
|
|
15
|
+
self.centerX = center[0]
|
|
16
|
+
self.centerY = center[1]
|
|
17
|
+
self.moveLeftKey = moveLeftKey
|
|
18
|
+
self.moveRightKey = moveRightKey
|
|
19
|
+
self.moveUpKey = moveUpKey
|
|
20
|
+
self.moveDownKey = moveDownKey
|
|
21
|
+
self.moveFwdKey = moveFwdKey
|
|
22
|
+
self.moveBackKey = moveBackKey
|
|
23
|
+
self.tiltLeft = tiltLeft
|
|
24
|
+
self.tiltRight = tiltRight
|
|
25
|
+
|
|
26
|
+
def update(self, keys, mPosX, mPosY, speed=2) -> list:
|
|
27
|
+
pos = self.updatePos(keys, mPosX, mPosY, speed)
|
|
28
|
+
att = self.updateAtt(keys, mPosX, mPosY, speed)
|
|
29
|
+
return (pos, att)
|
|
30
|
+
|
|
31
|
+
def getPosition(self):
|
|
32
|
+
return (self.posX, self.posY, self.posZ)
|
|
33
|
+
|
|
34
|
+
def getAttitude(self):
|
|
35
|
+
return (self.attX, self.attY, self.attZ)
|
|
36
|
+
|
|
37
|
+
def updateAtt(self, keys, mPosX, mPosY, speed) -> list:
|
|
38
|
+
self.attY = 0.5*math.pi*(mPosX/self.centerX -1)
|
|
39
|
+
self.attX = 0.5*math.pi*(mPosY/self.centerY -1)
|
|
40
|
+
return self.getAttitude()
|
|
41
|
+
|
|
42
|
+
def updatePos(self, keys, mPosX, mPosY, speed) -> list:
|
|
43
|
+
self.posX += -(keys[self.moveRightKey] -keys[self.moveLeftKey])*2.0*speed
|
|
44
|
+
self.posY += -(keys[self.moveUpKey] -keys[self.moveDownKey])*2.0*speed
|
|
45
|
+
self.posZ += -(keys[self.moveBackKey] -keys[self.moveFwdKey])*5.0*speed
|
|
46
|
+
return self.getPosition()
|
|
47
|
+
|
|
48
|
+
class Object(Viewer):
|
|
49
|
+
def updateAtt(self, keys, mPosX, mPosY, speed) -> list:
|
|
50
|
+
self.attY = 0.5*math.pi*(mPosX/self.centerX -1)
|
|
51
|
+
self.attX = 0.5*math.pi*(mPosY/self.centerY -1)
|
|
52
|
+
speed = 3*math.pi/180 #< 3 deg
|
|
53
|
+
self.attZ += (keys[self.tiltRight] -keys[self.tiltLeft])*speed
|
|
54
|
+
return self.getAttitude()
|
|
55
|
+
|
|
56
|
+
def updatePos(self, keys, mPosX, mPosY, speed) -> list:
|
|
57
|
+
self.posX += -(keys[self.moveRightKey] -keys[self.moveLeftKey])*2.0*speed
|
|
58
|
+
self.posY += -(keys[self.moveUpKey] -keys[self.moveDownKey])*2.0*speed
|
|
59
|
+
self.posZ += -(keys[self.moveFwdKey] -keys[self.moveBackKey])*5.0*speed
|
|
60
|
+
return self.getPosition()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{"scale":100.0,
|
|
2
|
+
"color":[10,10,10],
|
|
3
|
+
"points_xyz":[
|
|
4
|
+
[0, 0, 0],
|
|
5
|
+
[1, 0, 0],
|
|
6
|
+
[0, 1, 0],
|
|
7
|
+
[0, 0, 1],
|
|
8
|
+
|
|
9
|
+
[1.05, 0.1, 0.0],
|
|
10
|
+
[1.25, -0.1, 0.0],
|
|
11
|
+
[1.25, 0.1, 0.0],
|
|
12
|
+
[1.05, -0.1, 0.0],
|
|
13
|
+
|
|
14
|
+
[-0.1, 1.15, 0.0],
|
|
15
|
+
[ 0.0, 1.05, 0.0],
|
|
16
|
+
[ 0.1, 1.15, 0.0],
|
|
17
|
+
[-0.1, 0.95, 0.0],
|
|
18
|
+
|
|
19
|
+
[-0.1, 0.1, 1.05],
|
|
20
|
+
[ 0.1, 0.1, 1.05],
|
|
21
|
+
[-0.1, -0.1, 1.05],
|
|
22
|
+
[ 0.1, -0.1, 1.05]
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
"connections":[
|
|
26
|
+
[0,1],
|
|
27
|
+
[0,2],
|
|
28
|
+
[0,3],
|
|
29
|
+
|
|
30
|
+
[4,5],
|
|
31
|
+
[6,7],
|
|
32
|
+
|
|
33
|
+
[8,9],
|
|
34
|
+
[10,11],
|
|
35
|
+
|
|
36
|
+
[12,13],
|
|
37
|
+
[13,14],
|
|
38
|
+
[14,15]
|
|
39
|
+
]
|
|
40
|
+
}
|
|
Binary file
|