-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrotation_geometry.py
More file actions
140 lines (111 loc) · 5.33 KB
/
Copy pathrotation_geometry.py
File metadata and controls
140 lines (111 loc) · 5.33 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
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
"""
Rotation Geometry - Math functions for calculating rotation effects on bounding boxes.
Used for preventing corner clipping during rotated renders.
When a rectangle is rotated, its bounding box expands:
- W_new = W × |cos(θ)| + H × |sin(θ)|
- H_new = W × |sin(θ)| + H × |cos(θ)|
This module calculates the expansion factor and safe zoom levels.
"""
import math
# Default board thickness (mm) - typical 4-layer PCB
BOARD_THICKNESS = 1.6
def calculate_rotation_expansion(width: float, height: float,
rot_x: float, rot_y: float, rot_z: float,
component_height: float = 0.0) -> float:
"""
Calculate the bounding box expansion factor when a rectangle is rotated.
Args:
width: Board width in mm
height: Board height in mm
rot_x: X-axis rotation in degrees (tilt forward/back)
rot_y: Y-axis rotation in degrees (tilt left/right)
rot_z: Z-axis rotation in degrees (spin around vertical)
component_height: Max component height in mm (for tall connectors, caps, etc.)
Returns:
Expansion factor (1.0 = no expansion, 1.414 = 45° rotation of square)
"""
# Convert to radians
rx = math.radians(rot_x % 360)
ry = math.radians(rot_y % 360)
rz = math.radians(rot_z % 360)
# Total vertical extent = board thickness + component height (top + bottom estimate)
# Components on top + potential components on bottom
total_depth = BOARD_THICKNESS + component_height * 1.5 # 1.5x to account for both sides
# For top/bottom view, Z rotation is the main concern
# The bounding box of a rotated rectangle:
# W_new = W × |cos(θ)| + H × |sin(θ)|
# H_new = W × |sin(θ)| + H × |cos(θ)|
cos_z = abs(math.cos(rz))
sin_z = abs(math.sin(rz))
new_width = width * cos_z + height * sin_z
new_height = width * sin_z + height * cos_z
# X and Y rotations also affect the projected size
# When tilted, the board appears shorter in the tilt direction
cos_x = abs(math.cos(rx))
cos_y = abs(math.cos(ry))
sin_x = abs(math.sin(rx))
sin_y = abs(math.sin(ry))
# X rotation affects height (tilting forward/back)
# The projected height = height * cos(x) + depth * sin(x)
new_height = new_height * cos_x + total_depth * sin_x
# Y rotation affects width (tilting left/right)
# The projected width = width * cos(y) + depth * sin(y)
new_width = new_width * cos_y + total_depth * sin_y
# Calculate expansion factors
width_expansion = new_width / width if width > 0 else 1.0
height_expansion = new_height / height if height > 0 else 1.0
# Return the maximum expansion (worst case)
return max(width_expansion, height_expansion, 1.0)
def calculate_safe_zoom(board_width: float, board_height: float,
rot_x: float, rot_y: float, rot_z: float,
component_height: float = 0.0,
margin: float = 0.05) -> float:
"""
Calculate the maximum safe zoom to avoid corner clipping.
Args:
board_width: Board width in mm
board_height: Board height in mm
rot_x: X-axis rotation in degrees
rot_y: Y-axis rotation in degrees
rot_z: Z-axis rotation in degrees
component_height: Max component height in mm (for tall connectors, caps, etc.)
margin: Safety margin (0.05 = 5%, 0.10 = 10%)
Returns:
Safe zoom value (e.g., 0.85 for 45° rotation)
"""
expansion = calculate_rotation_expansion(board_width, board_height, rot_x, rot_y, rot_z, component_height)
safe_zoom = (1.0 / expansion) * (1.0 - margin)
return max(0.1, min(safe_zoom, 10.0)) # Clamp to valid range
def calculate_safe_zoom_for_animation(board_width: float, board_height: float,
tilt_x: float = 0, tilt_y: float = 0,
component_height: float = 0.0,
margin: float = 0.05) -> float:
"""
Calculate safe zoom for a 360° spinning animation.
For animations, we need to account for ALL rotation angles (0-360°),
so we find the worst-case expansion.
Args:
board_width: Board width in mm
board_height: Board height in mm
tilt_x: X-axis tilt in degrees (constant during animation)
tilt_y: Y-axis tilt in degrees (constant during animation)
component_height: Max component height in mm (for tall connectors, caps, etc.)
margin: Safety margin (0.05 = 5%, 0.10 = 10%)
Returns:
Safe zoom value for the entire animation
"""
# For Z rotation, worst case is when diagonal aligns with axis
# This happens at 45°, 135°, 225°, 315° for non-square boards
# For any rectangle, worst case expansion is at 45° from the longer axis
worst_expansion = 1.0
# Check multiple angles to find worst case
for z_angle in range(0, 360, 5): # Check every 5 degrees
expansion = calculate_rotation_expansion(
board_width, board_height,
tilt_x, tilt_y, float(z_angle),
component_height
)
worst_expansion = max(worst_expansion, expansion)
# Apply safety margin
safe_zoom = (1.0 / worst_expansion) * (1.0 - margin)
return max(0.1, min(safe_zoom, 10.0))