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,145 @@
|
|
|
1
|
+
from GSOF_3dWireFrame.MathLib import MathLib as ML
|
|
2
|
+
import json
|
|
3
|
+
from GSOF_3dWireFrame.Lib3D import stlToObj
|
|
4
|
+
|
|
5
|
+
def loadStl(filename, faceCount=500):
|
|
6
|
+
return stlToObj.stlToObj(filename, faceCount=faceCount)
|
|
7
|
+
|
|
8
|
+
def loadJson(filename):
|
|
9
|
+
obj = None
|
|
10
|
+
with open(filename) as f:
|
|
11
|
+
obj = json.load(f)
|
|
12
|
+
return obj
|
|
13
|
+
|
|
14
|
+
def dataToDict(points, lines, scale=1.0, color=(0,0,0)):
|
|
15
|
+
return({"scale":scale,
|
|
16
|
+
"color":color,
|
|
17
|
+
"points_xyz": points,
|
|
18
|
+
"connections": lines})
|
|
19
|
+
|
|
20
|
+
def findArithmeticCenter(points):
|
|
21
|
+
""" Return the arithmetic center from the list of points """
|
|
22
|
+
mean = [0]*(len(points[0]))
|
|
23
|
+
|
|
24
|
+
for axis in points:
|
|
25
|
+
for i in range(len(axis)):
|
|
26
|
+
mean[i]+=axis[i]
|
|
27
|
+
for i in range(len(mean)):
|
|
28
|
+
mean[i] = mean[i]/len(points)
|
|
29
|
+
return mean
|
|
30
|
+
|
|
31
|
+
def findMinMaxCenter(points):
|
|
32
|
+
""" Return the center point between the minimum and maximum
|
|
33
|
+
values in the list of points """
|
|
34
|
+
Max = 999999
|
|
35
|
+
Min = -Max
|
|
36
|
+
N = len(points[0])
|
|
37
|
+
minPoint = [Max]*N
|
|
38
|
+
maxPoint = [Min]*N
|
|
39
|
+
for point in points:
|
|
40
|
+
for i, v in enumerate(point):
|
|
41
|
+
if v < minPoint[i]:
|
|
42
|
+
minPoint[i] = v
|
|
43
|
+
if v > maxPoint[i]:
|
|
44
|
+
maxPoint[i] = v
|
|
45
|
+
|
|
46
|
+
meanPoint = [0,0,0]
|
|
47
|
+
for i in range(N):
|
|
48
|
+
meanPoint[i] = (minPoint[i]+maxPoint[i])/2
|
|
49
|
+
return meanPoint
|
|
50
|
+
|
|
51
|
+
def scalePoint(point, scale, dim) -> list:
|
|
52
|
+
new = [0]*dim
|
|
53
|
+
for i in range(0, dim):
|
|
54
|
+
new[i] = point[i]*scale[i]
|
|
55
|
+
return new
|
|
56
|
+
|
|
57
|
+
def scale(points, _scale) -> list:
|
|
58
|
+
"""Scale coordinates"""
|
|
59
|
+
dim = len(points[0])
|
|
60
|
+
if not isinstance(_scale, (tuple,list)):
|
|
61
|
+
_scale = (_scale,)*dim
|
|
62
|
+
newPoints = [None]*len(points)
|
|
63
|
+
for i, point in enumerate(points):
|
|
64
|
+
newPoints[i] = scalePoint(point, _scale, dim)
|
|
65
|
+
return newPoints
|
|
66
|
+
|
|
67
|
+
def getRotationMatrix(x=0, y=0, z=0) -> list:
|
|
68
|
+
"""Return the proper rotation matrix for our coordinate system"""
|
|
69
|
+
return ML.DCM_YXZ(y, x, z) #< the proper rotation order for our coordinate system
|
|
70
|
+
|
|
71
|
+
def getTransformMatrix(scale=(1,1,1), rotate=(0,0,0), translate=(0,0,0)) -> list:
|
|
72
|
+
"""Return the transformation matrix"""
|
|
73
|
+
M = getRotationMatrix(*rotate)
|
|
74
|
+
scaleM = ML.I(3)
|
|
75
|
+
scaleM[0][0] = scale[0]
|
|
76
|
+
scaleM[1][1] = scale[1]
|
|
77
|
+
scaleM[2][2] = scale[2]
|
|
78
|
+
M = ML.MxM(M, scaleM)
|
|
79
|
+
M[0] += [translate[0]] #< Add translation
|
|
80
|
+
M[1] += [translate[1]]
|
|
81
|
+
M[2] += [translate[2]]
|
|
82
|
+
return M +[[0,0,0,1]] #< Add last row and return
|
|
83
|
+
|
|
84
|
+
def updateTransformationMatrix(oldT, newT) -> list:
|
|
85
|
+
return ML.MxM(newT, oldT)
|
|
86
|
+
|
|
87
|
+
def rotate(points, x=0, y=0, z=0, dcm=None) -> list:
|
|
88
|
+
newPoints = [None]*len(points)
|
|
89
|
+
if dcm == None:
|
|
90
|
+
dcm = getRotationMatrix(x, y, z)
|
|
91
|
+
|
|
92
|
+
for i, point in enumerate(points):
|
|
93
|
+
newPoints[i] = ML.MxV(dcm, point)
|
|
94
|
+
return newPoints
|
|
95
|
+
|
|
96
|
+
def translate(points, x=0, y=0, z=0) -> list:
|
|
97
|
+
newPoints = [None]*len(points)
|
|
98
|
+
T = [x, y, z]
|
|
99
|
+
for i, point in enumerate(points):
|
|
100
|
+
newPoints[i] = ML.addV(point, T)
|
|
101
|
+
return newPoints
|
|
102
|
+
|
|
103
|
+
def transform(points, _scale=(1,1,1), _rotate=(0,0,0), _translate=(0,0,0), M=None) -> list:
|
|
104
|
+
if M == None:
|
|
105
|
+
M = getTransformMatrix(_scale, _rotate, _translate)
|
|
106
|
+
return _update(points, M)
|
|
107
|
+
## points = scale(points, _scale) #< Inefficient method
|
|
108
|
+
## points = rotate(points, *_rotate)
|
|
109
|
+
## return translate(points, *_translate)
|
|
110
|
+
|
|
111
|
+
def _update(points, transformation) -> list:
|
|
112
|
+
newPoints = [None]*len(points)
|
|
113
|
+
for i, point in enumerate(points):
|
|
114
|
+
if len(point) < 4:
|
|
115
|
+
point += [1] #< Add translation dimension
|
|
116
|
+
newPoints[i] = (ML.MxV(transformation, point))[0:3]
|
|
117
|
+
return newPoints
|
|
118
|
+
|
|
119
|
+
def calcLines(points, connections, color=(0,0,0)) -> list:
|
|
120
|
+
lines = [None]*len(connections)
|
|
121
|
+
for i, connect in enumerate(connections):
|
|
122
|
+
fromPnt, toPnt = connect
|
|
123
|
+
p0 = points[fromPnt]
|
|
124
|
+
p1 = points[toPnt]
|
|
125
|
+
lines[i] = Line(p0, p1, color)
|
|
126
|
+
return lines
|
|
127
|
+
|
|
128
|
+
class Line():
|
|
129
|
+
def __init__(self, p0=None, p1=None, color=(0,0,0)):
|
|
130
|
+
self.points = [p0, p1]
|
|
131
|
+
self.color = color
|
|
132
|
+
### THE METHODS BELOW ARE NOT USED
|
|
133
|
+
## def scale(self, scale):
|
|
134
|
+
## self.points = scale(self.points, scale)
|
|
135
|
+
##
|
|
136
|
+
## def translate(self, x=0, y=0, z=0):
|
|
137
|
+
## self.points = translate(self.points, x,y,z)
|
|
138
|
+
##
|
|
139
|
+
## def rotate(self, x=0, y=0, z=0, dcm=None):
|
|
140
|
+
## self.points = rotate(self.points, x,y,z,dcm)
|
|
141
|
+
|
|
142
|
+
class Triangle(Line):
|
|
143
|
+
def __init__(self, p0=None, p1=None, p2=None, color=(0,0,0)):
|
|
144
|
+
super().__init__(p0, p1, color)
|
|
145
|
+
self.points += [p2]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from GSOF_3dWireFrame.Lib3D import Lib3D as L
|
|
2
|
+
from GSOF_3dWireFrame.Lib3D.Object_base import *
|
|
3
|
+
|
|
4
|
+
class Object_wireFrame(Object_base):
|
|
5
|
+
OBJ_NUM = 0
|
|
6
|
+
def __init__(self, obj=None, filename=None, color=None, name=None):
|
|
7
|
+
if name == None:
|
|
8
|
+
name = "O" +str(Object_wireFrame.OBJ_NUM)
|
|
9
|
+
Object_wireFrame.OBJ_NUM += 1
|
|
10
|
+
self.name = name
|
|
11
|
+
super().__init__()
|
|
12
|
+
if filename != None:
|
|
13
|
+
ext = filename.split(".")[-1]
|
|
14
|
+
if ext == "json":
|
|
15
|
+
obj = L.loadJson(filename)
|
|
16
|
+
elif ext == "stl":
|
|
17
|
+
obj = L.loadStl(filename)
|
|
18
|
+
|
|
19
|
+
if color == None:
|
|
20
|
+
if "color" in obj:
|
|
21
|
+
color = obj["color"] #< Color from file
|
|
22
|
+
else:
|
|
23
|
+
color = (0,0,0) #< Default color black
|
|
24
|
+
self.color = color #< Color to draw all lines
|
|
25
|
+
self.points = obj["points_xyz"] #< xyz-coordinates of all corner-points of object
|
|
26
|
+
self.connections = obj["connections"] #< Lines between corner points of object
|
|
27
|
+
|
|
28
|
+
def update(self) -> None:
|
|
29
|
+
self.newPoints = L.transform(points=self.points, M=self.state)
|
|
30
|
+
self.stateTouched = True
|
|
31
|
+
|
|
32
|
+
def getLines(self) -> list:
|
|
33
|
+
if not self.isUpdated():
|
|
34
|
+
self.update()
|
|
35
|
+
return L.calcLines(self.newPoints, self.connections, self.color)
|
|
36
|
+
|
|
37
|
+
def setCenter(self,
|
|
38
|
+
pos=(0,0,0),
|
|
39
|
+
rotate=(0,0,0),
|
|
40
|
+
scale=(1,1,1),
|
|
41
|
+
method=None
|
|
42
|
+
):
|
|
43
|
+
"""Move all original points to the new location than rotate and scale"""
|
|
44
|
+
### Find new center and translate all points
|
|
45
|
+
center = super()._findCenter(self.points, method)
|
|
46
|
+
translate = (-(pos[0]+center[0]), -(pos[1]+center[1]), -(pos[2]+center[2]))
|
|
47
|
+
if True:
|
|
48
|
+
self.points = L.translate(self.points, *translate)
|
|
49
|
+
self.points = L.rotate(self.points, *rotate)
|
|
50
|
+
self.points = L.scale(self.points, scale)
|
|
51
|
+
else:
|
|
52
|
+
transMatrix = L.getTransformMatrix(scale=(1,1,1),
|
|
53
|
+
rotate=(0,0,0),
|
|
54
|
+
translate=translate)
|
|
55
|
+
self.points = L.transform(points=self.points, M=transMatrix)
|
|
56
|
+
|
|
57
|
+
### Rotate all points
|
|
58
|
+
if not isinstance(scale, (list, tuple)):
|
|
59
|
+
scale = (scale,)*3
|
|
60
|
+
transMatrix = L.getTransformMatrix(scale,
|
|
61
|
+
rotate,
|
|
62
|
+
translate=(0,0,0))
|
|
63
|
+
self.points = L.transform(points=self.points, M=transMatrix)
|
|
64
|
+
|
|
65
|
+
self.stateTouched = True
|
|
66
|
+
return self
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
from GSOF_3dWireFrame.MathLib import MathLib as ML
|
|
3
|
+
from GSOF_3dWireFrame.Lib3D import Lib3D as L
|
|
4
|
+
|
|
5
|
+
class Object_base():
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.stateOrigin = ML.I(4) #< 4x4 matrix to store the original state of scale, rotation and translations
|
|
8
|
+
self.reset() #< 4x4 matrix to store the correct state
|
|
9
|
+
|
|
10
|
+
def reset(self, all=True):
|
|
11
|
+
"""Reset current state to original"""
|
|
12
|
+
self.state = self.getOrigin() #< 4x4 matrix to store the correct state
|
|
13
|
+
self.stateTouched = True
|
|
14
|
+
return self
|
|
15
|
+
|
|
16
|
+
def setOrigin(self, newState=None):
|
|
17
|
+
"""Set current state as the new original state"""
|
|
18
|
+
if newState == None:
|
|
19
|
+
newState = self.state
|
|
20
|
+
self.stateOrigin = copy.deepcopy(newState)
|
|
21
|
+
return self
|
|
22
|
+
|
|
23
|
+
def getOrigin(self) -> list:
|
|
24
|
+
"""Get the original state"""
|
|
25
|
+
return copy.deepcopy(self.stateOrigin)
|
|
26
|
+
|
|
27
|
+
def _findCenter(self,
|
|
28
|
+
points: list|tuple,
|
|
29
|
+
method: str="arithCenter"
|
|
30
|
+
) -> list:
|
|
31
|
+
"""Return the center point of all points"""
|
|
32
|
+
if method == "arithCenter":
|
|
33
|
+
return L.findArithmeticCenter(points)
|
|
34
|
+
|
|
35
|
+
elif method == "minMaxCenter":
|
|
36
|
+
return L.findMinMaxCenter(points)
|
|
37
|
+
|
|
38
|
+
elif method == None:
|
|
39
|
+
return (0,0,0)
|
|
40
|
+
|
|
41
|
+
else:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
def scale(self, scale: list|tuple|float):
|
|
45
|
+
"""Apply scaling to current state"""
|
|
46
|
+
"""Apply scaling to current state"""
|
|
47
|
+
if not isinstance(scale, (list, tuple)):
|
|
48
|
+
scale = (scale,)*3
|
|
49
|
+
scaleM = ML.I(4)
|
|
50
|
+
scaleM[0][0] = scale[0]
|
|
51
|
+
scaleM[1][1] = scale[1]
|
|
52
|
+
scaleM[2][2] = scale[2]
|
|
53
|
+
self.state = ML.MxM(self.state, scaleM)
|
|
54
|
+
self.stateTouched = True
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def copyDcmIntoState(self, dcm: list) -> None:
|
|
58
|
+
#self.state = ML.copyIntoMatrix(self.state, dcm, rs=0, cs=0)
|
|
59
|
+
for ri, row in enumerate(dcm):
|
|
60
|
+
for ci, val in enumerate(row):
|
|
61
|
+
self.state[ri][ci] = val
|
|
62
|
+
|
|
63
|
+
def rotate(self, x: float, y: float, z: float, dcm: list=None, centerAt: list=None):
|
|
64
|
+
"""Apply rotation to current state"""
|
|
65
|
+
if dcm == None:
|
|
66
|
+
dcm = L.getRotationMatrix(x, y, z)
|
|
67
|
+
if centerAt == None:
|
|
68
|
+
#self.copyDcmIntoState(ML.MxM(self.state[0:3], dcm))
|
|
69
|
+
dcm[0] += [0]
|
|
70
|
+
dcm[1] += [0]
|
|
71
|
+
dcm[2] += [0]
|
|
72
|
+
else:
|
|
73
|
+
tx, ty, tz = centerAt[0],centerAt[1],centerAt[2]
|
|
74
|
+
r = dcm
|
|
75
|
+
dcm[0] += [tx*(1-r[0][0]) -r[0][1]*ty -r[0][2]*tz]
|
|
76
|
+
dcm[1] += [ty*(1-r[1][1]) -r[1][0]*tx -r[1][2]*tz]
|
|
77
|
+
dcm[2] += [tz*(1-r[2][2]) -r[2][0]*tx -r[2][1]*ty]
|
|
78
|
+
dcm += [[0,0,0,1]]
|
|
79
|
+
self.state = ML.MxM(dcm, self.state)
|
|
80
|
+
self.stateTouched = True
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
def translate(self, x, y, z):
|
|
84
|
+
"""Apply translation to current state"""
|
|
85
|
+
transM = ML.I(4)
|
|
86
|
+
transM[0][3] += x
|
|
87
|
+
transM[1][3] += y
|
|
88
|
+
transM[2][3] += z
|
|
89
|
+
self.state = ML.MxM(transM, self.state)
|
|
90
|
+
self.stateTouched = True
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
def transform(self,
|
|
94
|
+
scale: list=(1,1,1),
|
|
95
|
+
rotate: list=(0,0,0),
|
|
96
|
+
translate: list=(0,0,0),
|
|
97
|
+
transMatrix: list=None
|
|
98
|
+
):
|
|
99
|
+
"""Apply transformation to current state"""
|
|
100
|
+
if transMatrix == None:
|
|
101
|
+
self\
|
|
102
|
+
.scale(scale)\
|
|
103
|
+
.rotate(*rotate)\
|
|
104
|
+
.translate(*translate)
|
|
105
|
+
else:
|
|
106
|
+
self.state = L.updateTransformationMatrix(self.state, transMatrix)
|
|
107
|
+
self.stateTouched = True
|
|
108
|
+
return self
|
|
109
|
+
|
|
110
|
+
def isUpdated(self) -> bool:
|
|
111
|
+
return not bool(self.stateTouched)
|
|
112
|
+
|
|
113
|
+
def update(self) -> None:
|
|
114
|
+
self.stateTouched = False
|
|
115
|
+
|
|
116
|
+
def getLines(self) -> list:
|
|
117
|
+
"""Return all lines of object"""
|
|
118
|
+
return []
|
|
119
|
+
|
|
120
|
+
def getObjects(self) -> list: #< For compatibility with Assembly class
|
|
121
|
+
"""Return a list of all objects"""
|
|
122
|
+
return []
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from GSOF_3dWireFrame.Lib3D import Lib3D as L
|
|
3
|
+
|
|
4
|
+
LINE_COLOR = (0,0,0)
|
|
5
|
+
|
|
6
|
+
def net(N=1000, M=1000, dN=100, dM=100, scale=1.0, color=LINE_COLOR) -> dict:
|
|
7
|
+
points = []
|
|
8
|
+
lines = []
|
|
9
|
+
for x in range(N):
|
|
10
|
+
points.append([0, x*dN, 0])
|
|
11
|
+
points.append([M*dM, x*dN, 0])
|
|
12
|
+
|
|
13
|
+
lines.append([(x*2), (x*2)+1])
|
|
14
|
+
|
|
15
|
+
for y in range(M):
|
|
16
|
+
points.append([y*dN, 0, 0])
|
|
17
|
+
points.append([y*dM, N*dN, 0])
|
|
18
|
+
|
|
19
|
+
lines.append([N*2+(y*2), N*2+(y*2)+1])
|
|
20
|
+
|
|
21
|
+
jsonObject = L.dataToDict(points, lines, scale, color)
|
|
22
|
+
return jsonObject
|
|
23
|
+
|
|
24
|
+
def sphere(radius, resolution=10, scale=1.0, color=LINE_COLOR):
|
|
25
|
+
points = []
|
|
26
|
+
lines = []
|
|
27
|
+
|
|
28
|
+
# Create points
|
|
29
|
+
for i in range(resolution):
|
|
30
|
+
theta = i * math.pi / (resolution - 1)
|
|
31
|
+
for j in range(resolution * 2):
|
|
32
|
+
phi = j * 2 * math.pi / (resolution * 2)
|
|
33
|
+
x = radius * math.sin(theta) * math.cos(phi)
|
|
34
|
+
y = radius * math.sin(theta) * math.sin(phi)
|
|
35
|
+
z = radius * math.cos(theta)
|
|
36
|
+
points.append([x, y, z])
|
|
37
|
+
|
|
38
|
+
# Create lines
|
|
39
|
+
for i in range(resolution - 1):
|
|
40
|
+
for j in range(resolution * 2):
|
|
41
|
+
p1 = i * resolution * 2 + j
|
|
42
|
+
p2 = i * resolution * 2 + (j + 1) % (resolution * 2)
|
|
43
|
+
p3 = ((i + 1) * resolution * 2 + j) % (len(points))
|
|
44
|
+
p4 = ((i + 1) * resolution * 2 + (j + 1) % (resolution * 2)) % (len(points))
|
|
45
|
+
lines.extend(((p1, p2), (p1, p3), (p2, p4)))
|
|
46
|
+
|
|
47
|
+
# Connect the last row
|
|
48
|
+
for j in range(resolution * 2):
|
|
49
|
+
p1 = (resolution - 1) * resolution * 2 + j
|
|
50
|
+
p2 = (resolution - 1) * resolution * 2 + (j + 1) % (resolution * 2)
|
|
51
|
+
lines.append((p1, p2))
|
|
52
|
+
|
|
53
|
+
return L.dataToDict(points, lines, scale, color)
|
|
54
|
+
|
|
55
|
+
def rectangle(X, Y, Z, scale=1.0, color=LINE_COLOR):
|
|
56
|
+
X = 0.5*X
|
|
57
|
+
Y = 0.5*Y
|
|
58
|
+
X = 0.5*Z
|
|
59
|
+
|
|
60
|
+
points = [
|
|
61
|
+
[-X, Y,-Z], #<0
|
|
62
|
+
[ X, Y,-Z], #<1
|
|
63
|
+
[ X, Y, Z], #<2
|
|
64
|
+
[-X, Y, Z], #<3
|
|
65
|
+
|
|
66
|
+
[-X,-Y,-Z], #<4
|
|
67
|
+
[ X,-Y,-Z], #<5
|
|
68
|
+
[ X,-Y, Z], #<6
|
|
69
|
+
[-X,-Y, Z], #<7
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
lines = [[0,1],
|
|
73
|
+
[1,2],
|
|
74
|
+
[2,3],
|
|
75
|
+
[3,0],
|
|
76
|
+
|
|
77
|
+
[4,5],
|
|
78
|
+
[5,6],
|
|
79
|
+
[6,7],
|
|
80
|
+
[7,4],
|
|
81
|
+
|
|
82
|
+
[0,4],
|
|
83
|
+
[1,5],
|
|
84
|
+
[2,6],
|
|
85
|
+
[3,7],
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
return L.dataToDict(points, lines, scale, color)
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
print(len(sphere(1000, 25)))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class WireFrame():
|
|
2
|
+
def __init__(self, screen, line, f=50, scale=1.0):
|
|
3
|
+
self.screen = screen
|
|
4
|
+
self.line = line
|
|
5
|
+
self.f = f
|
|
6
|
+
self.scale = scale
|
|
7
|
+
self.centerX, self.centerY = (int(screen.get_width()/2), int(screen.get_height()/2))
|
|
8
|
+
|
|
9
|
+
def draw(self, obj, color=None) -> None:
|
|
10
|
+
""" """
|
|
11
|
+
for line in obj.getLines():
|
|
12
|
+
p0 = self.camera(line.points[0])
|
|
13
|
+
p1 = self.camera(line.points[1])
|
|
14
|
+
if (p0[2] > self.f) or (p1[2] > self.f): #Skip lines in the back of the viewer
|
|
15
|
+
lcolor = color
|
|
16
|
+
if lcolor == None:
|
|
17
|
+
lcolor = line.color
|
|
18
|
+
self.drawLine( lcolor, p0, p1 ) #< Line from P0 to P1
|
|
19
|
+
|
|
20
|
+
def camera(self, point) -> list:
|
|
21
|
+
""" Perspective projection <https://en.wikipedia.org/wiki/3D_projection> """
|
|
22
|
+
x, y, z = point
|
|
23
|
+
z = -z
|
|
24
|
+
if (self.f != None):
|
|
25
|
+
if (z > self.f):
|
|
26
|
+
s = (self.f/z)*self.scale
|
|
27
|
+
else:
|
|
28
|
+
s = 100000
|
|
29
|
+
x *= s
|
|
30
|
+
y *= s
|
|
31
|
+
return (x,y,z)
|
|
32
|
+
|
|
33
|
+
def drawLine(self, color, p0, p1):
|
|
34
|
+
""" """
|
|
35
|
+
p0 = (self.centerX +p0[0], self.centerY -p0[1])
|
|
36
|
+
p1 = (self.centerX +p1[0], self.centerY -p1[1])
|
|
37
|
+
self.line( self.screen, color, p0, p1 ) #< Line from P0 to P1
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from GSOF_3dWireFrame.Lib3D import Lib3D as L
|
|
2
|
+
try:
|
|
3
|
+
import pymeshlab as ml
|
|
4
|
+
except:
|
|
5
|
+
print("could not find pymeshlab. DO NOT USE STL FILES!!\nTo install, run ```pip install pymeshlab```")
|
|
6
|
+
|
|
7
|
+
def stlToObj(filename, faceCount=-1, color=(0,0,0)):
|
|
8
|
+
# Load the STL file
|
|
9
|
+
ms = ml.MeshSet()
|
|
10
|
+
ms.load_new_mesh(filename)
|
|
11
|
+
|
|
12
|
+
# Simplify the mesh
|
|
13
|
+
if faceCount > 0:
|
|
14
|
+
ms.apply_filter('meshing_decimation_quadric_edge_collapse',
|
|
15
|
+
targetfacenum=faceCount)
|
|
16
|
+
|
|
17
|
+
# Get the simplified mesh
|
|
18
|
+
simplified_mesh = ms.current_mesh()
|
|
19
|
+
faceMatrix = simplified_mesh.face_matrix()
|
|
20
|
+
vertexMatrix = simplified_mesh.vertex_matrix()
|
|
21
|
+
|
|
22
|
+
# Initialize lists for points and lines
|
|
23
|
+
points = []
|
|
24
|
+
lines = []
|
|
25
|
+
|
|
26
|
+
for i in range(simplified_mesh.face_number()):
|
|
27
|
+
# Get the vertices of the triangle
|
|
28
|
+
vertexes = faceMatrix[i]
|
|
29
|
+
|
|
30
|
+
# Add the vertices (points) to the list
|
|
31
|
+
for vertex in vertexes:
|
|
32
|
+
points.append(vertexMatrix[vertex].tolist())
|
|
33
|
+
|
|
34
|
+
# Add the edges (lines) to the list
|
|
35
|
+
lines.append([i*3, i*3+1])
|
|
36
|
+
lines.append([i*3+1, i*3+2])
|
|
37
|
+
lines.append([i*3+2, i*3])
|
|
38
|
+
|
|
39
|
+
# Now you have a list of points and lines
|
|
40
|
+
return L.dataToDict(points, lines, scale=100.0, color=color)
|