ncca-ngl 0.1.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.
- ncca/ngl/PrimData/pack_arrays.py +20 -0
- ncca/ngl/__init__.py +100 -0
- ncca/ngl/abstract_vao.py +89 -0
- ncca/ngl/base_mesh.py +170 -0
- ncca/ngl/base_mesh.pyi +11 -0
- ncca/ngl/bbox.py +224 -0
- ncca/ngl/bezier_curve.py +75 -0
- ncca/ngl/first_person_camera.py +174 -0
- ncca/ngl/image.py +94 -0
- ncca/ngl/log.py +44 -0
- ncca/ngl/mat2.py +128 -0
- ncca/ngl/mat3.py +466 -0
- ncca/ngl/mat4.py +456 -0
- ncca/ngl/multi_buffer_vao.py +49 -0
- ncca/ngl/obj.py +416 -0
- ncca/ngl/plane.py +47 -0
- ncca/ngl/primitives.py +706 -0
- ncca/ngl/pyside_event_handling_mixin.py +318 -0
- ncca/ngl/quaternion.py +112 -0
- ncca/ngl/random.py +167 -0
- ncca/ngl/shader.py +229 -0
- ncca/ngl/shader_lib.py +536 -0
- ncca/ngl/shader_program.py +816 -0
- ncca/ngl/simple_index_vao.py +65 -0
- ncca/ngl/simple_vao.py +42 -0
- ncca/ngl/text.py +346 -0
- ncca/ngl/texture.py +75 -0
- ncca/ngl/transform.py +95 -0
- ncca/ngl/util.py +128 -0
- ncca/ngl/vao_factory.py +34 -0
- ncca/ngl/vec2.py +350 -0
- ncca/ngl/vec2_array.py +106 -0
- ncca/ngl/vec3.py +401 -0
- ncca/ngl/vec3_array.py +110 -0
- ncca/ngl/vec4.py +229 -0
- ncca/ngl/vec4_array.py +106 -0
- ncca_ngl-0.1.0.dist-info/METADATA +23 -0
- ncca_ngl-0.1.0.dist-info/RECORD +41 -0
- ncca_ngl-0.1.0.dist-info/WHEEL +5 -0
- ncca_ngl-0.1.0.dist-info/licenses/LICENSE.txt +7 -0
- ncca_ngl-0.1.0.dist-info/top_level.txt +1 -0
ncca/ngl/obj.py
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
from .base_mesh import BaseMesh, Face
|
|
2
|
+
from .texture import Texture
|
|
3
|
+
from .vec3 import Vec3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ObjParseVertexError(Exception):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ObjParseNormalError(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ObjParseUVError(Exception):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ObjParseFaceError(Exception):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Obj(BaseMesh):
|
|
23
|
+
"""
|
|
24
|
+
OBJ mesh loader and exporter.
|
|
25
|
+
|
|
26
|
+
Inherits from BaseMesh and provides methods to parse, load, and save OBJ files,
|
|
27
|
+
including support for vertices, normals, UVs, faces, and optional vertex colors.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
"""
|
|
32
|
+
Initialize an empty OBJ mesh.
|
|
33
|
+
Tracks current offsets for vertices, normals, and UVs to handle negative indices.
|
|
34
|
+
"""
|
|
35
|
+
super().__init__()
|
|
36
|
+
# as faces can use negative index values keep track of index
|
|
37
|
+
self._current_vertex_offset: int = 0
|
|
38
|
+
self._current_normal_offset: int = 0
|
|
39
|
+
self._current_uv_offset: int = 0
|
|
40
|
+
|
|
41
|
+
def _parse_vertex(self, tokens: list[str]) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Parse a vertex line from the OBJ file.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
tokens: List of string tokens from the line.
|
|
47
|
+
Raises:
|
|
48
|
+
ObjParseVertexError: If vertex parsing fails.
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
self.vertex.append(
|
|
52
|
+
Vec3(float(tokens[1]), float(tokens[2]), float(tokens[3]))
|
|
53
|
+
)
|
|
54
|
+
self._current_vertex_offset += 1
|
|
55
|
+
if len(tokens) == 7: # we have the non standard colour
|
|
56
|
+
if not hasattr(self, "colour"):
|
|
57
|
+
self.colour = []
|
|
58
|
+
self.colour.append(
|
|
59
|
+
Vec3(float(tokens[4]), float(tokens[5]), float(tokens[6]))
|
|
60
|
+
)
|
|
61
|
+
except ValueError:
|
|
62
|
+
raise ObjParseVertexError
|
|
63
|
+
|
|
64
|
+
def _parse_normal(self, tokens: list[str]) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Parse a normal line from the OBJ file.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
tokens: List of string tokens from the line.
|
|
70
|
+
Raises:
|
|
71
|
+
ObjParseNormalError: If normal parsing fails.
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
self.normals.append(
|
|
75
|
+
Vec3(float(tokens[1]), float(tokens[2]), float(tokens[3]))
|
|
76
|
+
)
|
|
77
|
+
self._current_normal_offset += 1
|
|
78
|
+
except ValueError:
|
|
79
|
+
raise ObjParseNormalError
|
|
80
|
+
|
|
81
|
+
def _parse_uv(self, tokens: list[str]) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Parse a UV line from the OBJ file.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
tokens: List of string tokens from the line.
|
|
87
|
+
Raises:
|
|
88
|
+
ObjParseUVError: If UV parsing fails.
|
|
89
|
+
"""
|
|
90
|
+
try:
|
|
91
|
+
# some DCC's use vec3 for UV so may as well support
|
|
92
|
+
z = 0.0
|
|
93
|
+
if len(tokens) == 4:
|
|
94
|
+
z = float(tokens[3])
|
|
95
|
+
self.uv.append(Vec3(float(tokens[1]), float(tokens[2]), z))
|
|
96
|
+
self._current_uv_offset += 1
|
|
97
|
+
except ValueError:
|
|
98
|
+
raise ObjParseUVError
|
|
99
|
+
|
|
100
|
+
def _parse_face_vertex_normal_uv(self, tokens: list[str]) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Parse a face line with vertex/uv/normal indices (f v/vt/vn ...).
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
tokens: List of string tokens from the line.
|
|
106
|
+
Raises:
|
|
107
|
+
ObjParseFaceError: If face parsing fails.
|
|
108
|
+
"""
|
|
109
|
+
f = Face()
|
|
110
|
+
for token in tokens[1:]: # skip f
|
|
111
|
+
# each one of these should be v/vt/vn
|
|
112
|
+
vn = token.split("/")
|
|
113
|
+
try:
|
|
114
|
+
# note we need to subtract one from the list as obj index from 1
|
|
115
|
+
idx = int(vn[0]) - 1
|
|
116
|
+
if idx < 0: # negative index so grab the index
|
|
117
|
+
# note we index from 0 not 1 like obj so adjust
|
|
118
|
+
idx = self._current_vertex_offset + (idx + 1)
|
|
119
|
+
f.vertex.append(idx)
|
|
120
|
+
# same for UV
|
|
121
|
+
idx = int(vn[1]) - 1
|
|
122
|
+
if idx < 0: # negative index so grab the index
|
|
123
|
+
# note we index from 0 not 1 like obj so adjust
|
|
124
|
+
idx = self._current_uv_offset + (idx + 1)
|
|
125
|
+
f.uv.append(idx)
|
|
126
|
+
# same for normals
|
|
127
|
+
idx = int(vn[2]) - 1
|
|
128
|
+
if idx < 0: # negative index so grab the index
|
|
129
|
+
# note we index from 0 not 1 like obj so adjust
|
|
130
|
+
idx = self._current_normal_offset + (idx + 1)
|
|
131
|
+
f.normal.append(idx)
|
|
132
|
+
except ValueError:
|
|
133
|
+
raise ObjParseFaceError
|
|
134
|
+
self.faces.append(f)
|
|
135
|
+
|
|
136
|
+
def _parse_face_vertex(self, tokens: list[str]) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Parse a face line with only vertex indices (f v v v ...).
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
tokens: List of string tokens from the line.
|
|
142
|
+
Raises:
|
|
143
|
+
ObjParseFaceError: If face parsing fails.
|
|
144
|
+
"""
|
|
145
|
+
f = Face()
|
|
146
|
+
for token in tokens[1:]: # skip f
|
|
147
|
+
# each one of these should be v v
|
|
148
|
+
try:
|
|
149
|
+
# note we need to subtract one from the list as obj index from 1
|
|
150
|
+
idx = int(token) - 1
|
|
151
|
+
if idx < 0: # negative index so grab the index
|
|
152
|
+
# note we index from 0 not 1 like obj so adjust
|
|
153
|
+
idx = self._current_vertex_offset + (idx + 1)
|
|
154
|
+
f.vertex.append(idx)
|
|
155
|
+
except ValueError:
|
|
156
|
+
raise ObjParseFaceError
|
|
157
|
+
self.faces.append(f)
|
|
158
|
+
|
|
159
|
+
def _parse_face_vertex_normal(self, tokens: list[str]) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Parse a face line with vertex//normal indices (f v//vn ...).
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
tokens: List of string tokens from the line.
|
|
165
|
+
Raises:
|
|
166
|
+
ObjParseFaceError: If face parsing fails.
|
|
167
|
+
"""
|
|
168
|
+
f = Face()
|
|
169
|
+
for token in tokens[1:]: # skip f
|
|
170
|
+
# each one of these should be v//vn
|
|
171
|
+
vn = token.split("//")
|
|
172
|
+
try:
|
|
173
|
+
# note we need to subtract one from the list as obj index from 1
|
|
174
|
+
idx = int(vn[0]) - 1
|
|
175
|
+
if idx < 0: # negative index so grab the index
|
|
176
|
+
# note we index from 0 not 1 like obj so adjust
|
|
177
|
+
idx = self._current_vertex_offset + (idx + 1)
|
|
178
|
+
f.vertex.append(idx)
|
|
179
|
+
# same for normals
|
|
180
|
+
idx = int(vn[1]) - 1
|
|
181
|
+
if idx < 0: # negative index so grab the index
|
|
182
|
+
# note we index from 0 not 1 like obj so adjust
|
|
183
|
+
idx = self._current_normal_offset + (idx + 1)
|
|
184
|
+
f.normal.append(idx)
|
|
185
|
+
except ValueError:
|
|
186
|
+
raise ObjParseFaceError
|
|
187
|
+
self.faces.append(f)
|
|
188
|
+
|
|
189
|
+
def _parse_face_vertex_uv(self, tokens: list[str]) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Parse a face line with vertex/uv indices (f v/vt ...).
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
tokens: List of string tokens from the line.
|
|
195
|
+
Raises:
|
|
196
|
+
ObjParseFaceError: If face parsing fails.
|
|
197
|
+
"""
|
|
198
|
+
f = Face()
|
|
199
|
+
for token in tokens[1:]: # skip f
|
|
200
|
+
# each one of these should be v/vt
|
|
201
|
+
vn = token.split("/")
|
|
202
|
+
try:
|
|
203
|
+
# note we need to subtract one from the list as obj index from 1
|
|
204
|
+
idx = int(vn[0]) - 1
|
|
205
|
+
if idx < 0: # negative index so grab the index
|
|
206
|
+
# note we index from 0 not 1 like obj so adjust
|
|
207
|
+
idx = self._current_vertex_offset + (idx + 1)
|
|
208
|
+
f.vertex.append(idx)
|
|
209
|
+
# same for uv
|
|
210
|
+
idx = int(vn[1]) - 1
|
|
211
|
+
if idx < 0: # negative index so grab the index
|
|
212
|
+
# note we index from 0 not 1 like obj so adjust
|
|
213
|
+
idx = self._current_uv_offset + (idx + 1)
|
|
214
|
+
f.uv.append(idx)
|
|
215
|
+
except ValueError:
|
|
216
|
+
raise ObjParseFaceError
|
|
217
|
+
self.faces.append(f)
|
|
218
|
+
|
|
219
|
+
def _parse_face(self, tokens: list[str]) -> None:
|
|
220
|
+
"""
|
|
221
|
+
Parse a face line, dispatching to the correct face parser based on format.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
tokens: List of string tokens from the line.
|
|
225
|
+
"""
|
|
226
|
+
# first let's find what sort of face we are dealing with I assume most likely case is all
|
|
227
|
+
if tokens[1].count("/") == 2 and tokens[1].find("//") == -1:
|
|
228
|
+
self._parse_face_vertex_normal_uv(tokens)
|
|
229
|
+
elif tokens[1].find("/") == -1:
|
|
230
|
+
self._parse_face_vertex(tokens)
|
|
231
|
+
elif tokens[1].find("//") != -1:
|
|
232
|
+
self._parse_face_vertex_normal(tokens)
|
|
233
|
+
# if we have 1 / it is a VertUV format
|
|
234
|
+
elif tokens[1].count("/") == 1:
|
|
235
|
+
self._parse_face_vertex_uv(tokens)
|
|
236
|
+
|
|
237
|
+
def load(self, file: str) -> bool:
|
|
238
|
+
"""
|
|
239
|
+
Load an OBJ file and parse its contents into the mesh.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
file: Path to the OBJ file.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
bool: True if loading was successful.
|
|
246
|
+
"""
|
|
247
|
+
with open(file, "r") as obj_file:
|
|
248
|
+
lines = obj_file.readlines()
|
|
249
|
+
for line in lines:
|
|
250
|
+
line = line.strip() # strip whitespace
|
|
251
|
+
if len(line) > 0: # skip empty lines
|
|
252
|
+
tokens = line.split()
|
|
253
|
+
if tokens[0] == "v":
|
|
254
|
+
self._parse_vertex(tokens)
|
|
255
|
+
elif tokens[0] == "vn":
|
|
256
|
+
self._parse_normal(tokens)
|
|
257
|
+
elif tokens[0] == "vt":
|
|
258
|
+
self._parse_uv(tokens)
|
|
259
|
+
elif tokens[0] == "f":
|
|
260
|
+
self._parse_face(tokens)
|
|
261
|
+
return True
|
|
262
|
+
|
|
263
|
+
@classmethod
|
|
264
|
+
def from_file(cls, fname: str) -> "Obj":
|
|
265
|
+
"""
|
|
266
|
+
Create an Obj instance from a file.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
fname: Path to the OBJ file.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Obj: The loaded Obj instance.
|
|
273
|
+
"""
|
|
274
|
+
obj = Obj()
|
|
275
|
+
obj.load(fname)
|
|
276
|
+
return obj
|
|
277
|
+
|
|
278
|
+
def add_vertex(self, vertex: Vec3) -> None:
|
|
279
|
+
"""
|
|
280
|
+
Add a vertex to the mesh.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
vertex: The vertex to add.
|
|
284
|
+
"""
|
|
285
|
+
self.vertex.append(vertex)
|
|
286
|
+
|
|
287
|
+
def add_vertex_colour(self, vertex: Vec3, colour: Vec3) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Add a vertex and its color to the mesh.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
vertex: The vertex to add.
|
|
293
|
+
colour: The color to associate with the vertex.
|
|
294
|
+
"""
|
|
295
|
+
self.vertex.append(vertex)
|
|
296
|
+
if not hasattr(self, "colour"):
|
|
297
|
+
self.colour = []
|
|
298
|
+
self.colour.append(colour)
|
|
299
|
+
|
|
300
|
+
def add_normal(self, normal: Vec3) -> None:
|
|
301
|
+
"""
|
|
302
|
+
Add a normal to the mesh.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
normal: The normal to add.
|
|
306
|
+
"""
|
|
307
|
+
self.normals.append(normal)
|
|
308
|
+
|
|
309
|
+
def add_uv(self, uv: Vec3) -> None:
|
|
310
|
+
"""
|
|
311
|
+
Add a UV coordinate to the mesh.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
uv: The UV coordinate to add.
|
|
315
|
+
"""
|
|
316
|
+
self.uv.append(uv)
|
|
317
|
+
|
|
318
|
+
def add_face(self, face: Face) -> None:
|
|
319
|
+
"""
|
|
320
|
+
Add a face to the mesh.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
face: The face to add.
|
|
324
|
+
"""
|
|
325
|
+
self.faces.append(face)
|
|
326
|
+
|
|
327
|
+
def save(self, filename: str) -> None:
|
|
328
|
+
"""
|
|
329
|
+
Save the mesh to an OBJ file.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
filename: Path to the output OBJ file.
|
|
333
|
+
"""
|
|
334
|
+
with open(filename, "w") as obj_file:
|
|
335
|
+
obj_file.write("# This file was created by nccapy/Geo/Obj.py exporter\n")
|
|
336
|
+
self._write_vertices(obj_file)
|
|
337
|
+
self._write_uvs(obj_file)
|
|
338
|
+
self._write_normals(obj_file)
|
|
339
|
+
self._write_faces(obj_file)
|
|
340
|
+
|
|
341
|
+
def _write_vertices(self, obj_file) -> None:
|
|
342
|
+
"""
|
|
343
|
+
Write vertices (and optional colors) to the OBJ file.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
obj_file: Open file object for writing.
|
|
347
|
+
"""
|
|
348
|
+
for i, v in enumerate(self.vertex):
|
|
349
|
+
obj_file.write(f"v {v.x} {v.y} {v.z} ")
|
|
350
|
+
if hasattr(self, "colour"): # write colour if present
|
|
351
|
+
obj_file.write(
|
|
352
|
+
f"{self.colour[i].x} {self.colour[i].y} {self.colour[i].z} "
|
|
353
|
+
)
|
|
354
|
+
obj_file.write("\n")
|
|
355
|
+
|
|
356
|
+
def _write_uvs(self, obj_file) -> None:
|
|
357
|
+
"""
|
|
358
|
+
Write UV coordinates to the OBJ file.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
obj_file: Open file object for writing.
|
|
362
|
+
"""
|
|
363
|
+
for v in self.uv:
|
|
364
|
+
obj_file.write(f"vt {v.x} {v.y} \n")
|
|
365
|
+
|
|
366
|
+
def _write_normals(self, obj_file) -> None:
|
|
367
|
+
"""
|
|
368
|
+
Write normals to the OBJ file.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
obj_file: Open file object for writing.
|
|
372
|
+
"""
|
|
373
|
+
for v in self.normals:
|
|
374
|
+
obj_file.write(f"vn {v.x} {v.y} {v.z} \n")
|
|
375
|
+
|
|
376
|
+
def _write_faces(self, obj_file) -> None:
|
|
377
|
+
"""
|
|
378
|
+
Write faces to the OBJ file.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
obj_file: Open file object for writing.
|
|
382
|
+
"""
|
|
383
|
+
for face in self.faces:
|
|
384
|
+
obj_file.write("f")
|
|
385
|
+
for i in range(len(face.vertex)):
|
|
386
|
+
obj_file.write(f" {face.vertex[i] + 1}")
|
|
387
|
+
if len(face.uv) != 0:
|
|
388
|
+
obj_file.write(f"/{face.uv[i] + 1}")
|
|
389
|
+
if len(face.normal) != 0:
|
|
390
|
+
if len(face.uv) == 0:
|
|
391
|
+
obj_file.write("//")
|
|
392
|
+
else:
|
|
393
|
+
obj_file.write("/")
|
|
394
|
+
obj_file.write(f"{face.normal[i] + 1}")
|
|
395
|
+
obj_file.write("\n")
|
|
396
|
+
|
|
397
|
+
@classmethod
|
|
398
|
+
def obj_with_vao(cls, mesh_name: str, texture_name: str = None) -> "Obj":
|
|
399
|
+
"""
|
|
400
|
+
Load an OBJ mesh and optionally a texture, then create a VAO.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
mesh_name: Path to the OBJ mesh file.
|
|
404
|
+
texture_name: Optional path to the texture file.
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
Obj: The loaded and VAO-initialized mesh.
|
|
408
|
+
"""
|
|
409
|
+
mesh = Obj()
|
|
410
|
+
mesh.load(mesh_name)
|
|
411
|
+
if texture_name:
|
|
412
|
+
texture = Texture(texture_name)
|
|
413
|
+
mesh.texture_id = texture.set_texture_gl()
|
|
414
|
+
print(f"{mesh.texture_id=}")
|
|
415
|
+
mesh.create_vao()
|
|
416
|
+
return mesh
|
ncca/ngl/plane.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from .vec3 import Vec3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Plane:
|
|
5
|
+
"""A mathematical plane."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, p1: Vec3 = None, p2: Vec3 = None, p3: Vec3 = None) -> None:
|
|
8
|
+
self._normal = Vec3(0.0, 1.0, 0.0)
|
|
9
|
+
self._point = Vec3()
|
|
10
|
+
self._d = 0.0
|
|
11
|
+
if p1 and p2 and p3:
|
|
12
|
+
self.set_points(p1, p2, p3)
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def normal(self) -> Vec3:
|
|
16
|
+
return self._normal
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def point(self) -> Vec3:
|
|
20
|
+
return self._point
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def d(self) -> float:
|
|
24
|
+
return self._d
|
|
25
|
+
|
|
26
|
+
def set_points(self, p1: Vec3, p2: Vec3, p3: Vec3) -> None:
|
|
27
|
+
aux1 = p1 - p2
|
|
28
|
+
aux2 = p3 - p2
|
|
29
|
+
self._normal = aux2.cross(aux1)
|
|
30
|
+
self._normal.normalize()
|
|
31
|
+
self._point = p2
|
|
32
|
+
self._d = -(self._normal.inner(self._point))
|
|
33
|
+
|
|
34
|
+
def set_normal_point(self, normal: Vec3, point: Vec3) -> None:
|
|
35
|
+
self._normal = normal
|
|
36
|
+
self._normal.normalize()
|
|
37
|
+
self._point = point
|
|
38
|
+
self._d = -(self._normal.inner(self._point))
|
|
39
|
+
|
|
40
|
+
def set_floats(self, a: float, b: float, c: float, d: float) -> None:
|
|
41
|
+
self._normal.set(a, b, c)
|
|
42
|
+
length = self._normal.length()
|
|
43
|
+
self._normal.normalize()
|
|
44
|
+
self._d = d / length
|
|
45
|
+
|
|
46
|
+
def distance(self, p: Vec3) -> float:
|
|
47
|
+
return self._d + self._normal.inner(p)
|