-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuilder_3d.py
More file actions
60 lines (48 loc) · 1.99 KB
/
builder_3d.py
File metadata and controls
60 lines (48 loc) · 1.99 KB
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
import numpy as np
from itertools import combinations
from typing import List, Dict, Tuple
def build_panes(speakers: List[Dict]) -> List[Dict]:
panes = []
# Create optimized list of (id, position) for iteration
speaker_nodes: List[Tuple[int, np.ndarray]] = [
(s["id"], np.array(s["pos"])) for s in speakers
]
for triplet in combinations(speaker_nodes, 3):
(id1, pos1), (id2, pos2), (id3, pos3) = triplet
# Calculate Triangle Surface Normal
edge_vector_a = pos2 - pos1
edge_vector_b = pos3 - pos1
surface_normal = np.cross(edge_vector_a, edge_vector_b)
# Skip degenerate (area ~ 0) triangles
if np.linalg.norm(surface_normal) < 0.001:
continue
# Convex Hull Check: A valid external face has all other points on ONE side
is_external_face = True
has_positive_side_points = False
has_negative_side_points = False
for other_id, other_pos in speaker_nodes:
if other_id in [id1, id2, id3]:
continue
distance_from_plane = np.dot(surface_normal, other_pos - pos1)
if distance_from_plane > 0.001:
has_positive_side_points = True
elif distance_from_plane < -0.001:
has_negative_side_points = True
# If points exist on both sides, the triangle intersects the volume
if has_positive_side_points and has_negative_side_points:
is_external_face = False
break
if is_external_face:
basis_matrix = np.array([pos1, pos2, pos3]).T
try:
inverse_matrix = np.linalg.inv(basis_matrix)
panes.append(
{
"type": "3D",
"ids": [id1, id2, id3],
"inv_matrix": inverse_matrix.tolist(),
}
)
except np.linalg.LinAlgError:
continue
return panes