Skip to content

Commit 4bdb7a1

Browse files
committed
feat: rectangle and rectangular grid (in progress)
1 parent 5ae8077 commit 4bdb7a1

File tree

1 file changed

+127
-3
lines changed

1 file changed

+127
-3
lines changed

src/plotly_3d_primitives/shapes.py

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def cube(
99
y_length=1.0,
1010
z_length=1.0,
1111
bounds: Optional[tuple[float]] = None,
12-
color: str = "#aaaaaa",
12+
color: str = "#aaa",
1313
opacity: float = 0.5,
1414
) -> go.Mesh3d:
1515
if bounds is not None and len(bounds) == 6:
@@ -53,7 +53,7 @@ def prism(
5353
h: float,
5454
align: list[str],
5555
anchor: tuple = (0, 0, 0),
56-
color: str = "#aaaaaa",
56+
color: str = "#aaa",
5757
opacity: float = 0.5,
5858
) -> go.Mesh3d:
5959
anchor_x, anchor_y, anchor_z = anchor
@@ -77,7 +77,7 @@ def cone(
7777
h: float,
7878
align: list[str],
7979
anchor: tuple = (0, 0, 0),
80-
color: str = "#aaaaaa",
80+
color: str = "#aaa",
8181
opacity: float = 0.5,
8282
) -> go.Mesh3d:
8383
anchor_x, anchor_y, anchor_z = anchor
@@ -94,3 +94,127 @@ def cone(
9494
return go.Mesh3d(
9595
x=x_array, y=y_array, z=z_array, alphahull=0, color=color, opacity=opacity
9696
)
97+
98+
99+
def line(
100+
pointa=(-0.5, 0.0, 0.0),
101+
pointb=(0.5, 0.0, 0.0),
102+
resolution=1,
103+
color: str = "#aaa",
104+
opacity: float = 0.8
105+
):
106+
"""
107+
Returns a trace of a line in 3d space.
108+
"""
109+
x0, y0, z0 = pointa
110+
x1, y1, z1 = pointb
111+
112+
x_array = np.linspace(x0, x1, resolution + 1, endpoint=True)
113+
y_array = np.linspace(y0, y1, resolution + 1, endpoint=True)
114+
z_array = np.linspace(z0, z1, resolution + 1, endpoint=True)
115+
116+
return go.Scatter3d(x=x_array, y=y_array, z=z_array, color=color, opacity=opacity, mode='lines')
117+
118+
119+
def rectangle(
120+
center=(0.0, 0.0, 0.0),
121+
b=1.0,
122+
d=1.0,
123+
normal=(1.0, 0.0, 0.0),
124+
color: str = "#aaa",
125+
opacity: float = 0.5,
126+
) -> go.Mesh3d:
127+
x0 = center[0] - b / 2
128+
x1 = center[0] + b / 2
129+
130+
y0 = center[1] - d / 2
131+
y1 = center[1] + d / 2
132+
133+
z0 = center[2] - z_length / 2
134+
z1 = center[2] + z_length / 2
135+
136+
x_array = [x0, x1, x1, x0, x0, x1, x1, x0]
137+
y_array = [y0, y0, y1, y1, y0, y0, y1, y1]
138+
z_array = [z0, z0, z0, z0, z1, z1, z1, z1]
139+
140+
i_array = [0, 1]
141+
j_array = [1, 2]
142+
k_array = [3, 3]
143+
144+
mesh = go.Mesh3d(
145+
x=x_array, y=y_array, z=z_array, opacity=opacity, color=color, alphahull=0
146+
)
147+
# mesh = go.Mesh3d(
148+
# x=x_array,
149+
# y=y_array,
150+
# z=z_array,
151+
# i=i_array,
152+
# j=j_array,
153+
# k=k_array,
154+
# opacity=opacity,
155+
# color=color,
156+
# )
157+
return mesh
158+
159+
160+
def rectangular_grid(
161+
center=(0.0, 0.0, 0.0),
162+
b=1.0,
163+
d=1.0,
164+
normal=(1.0, 0.0, 0.0),
165+
rows=1,
166+
cols=1,
167+
color: str = "#aaa"
168+
) -> go.Mesh3d:
169+
"""
170+
Returns a grid like:
171+
... ... ...
172+
| . | . | . |
173+
| 3 | 4 | 5 | ...
174+
| 0 | 1 | 2 | ...
175+
176+
Where 0, 1, 2, 3, 4, ... etc. are the "indexes" of the grid
177+
rectangles. They are numbered from the bottom-left left-to-right,
178+
down-to-up until the bth rectangle which has an index of (m * n - 1)
179+
where m is rows and n is columns.
180+
181+
b: total width of grid
182+
d: total depth (height) of grid
183+
184+
color: str | dict[Callable, str] will color the rectangles either all
185+
one color (str) or conditionally color them based on whether the
186+
index value of each rectangle returns True in the dict callable key
187+
(the color in the value will be applied if True; the first matching
188+
condition applies).
189+
190+
"""
191+
# nodes
192+
center = np.array(center)
193+
normal = np.array(normal)
194+
195+
196+
# Plane equation
197+
"normal[0] * x + normal[1] * y + normal[2] * z = np.dot(center, normal)"
198+
199+
# Distance from center to "min" point
200+
"sqrt((b/2 - center[0])**2 + (d/2 - center[1])**2 + (0 - center[2])**2)"
201+
202+
# A is "min" point, B is "max" point
203+
"tan(alpha) = d / b"
204+
205+
# Assumption, the bottom edge of the rect will be parallel with the xy plane
206+
# Therefore vector of the bottom edge will be the -ve reciprocal of the xy projection of the vector normal [1, 2, 3] => [1, 2, 0]
207+
# So the bottom edge will be [-2, 1, 0]
208+
209+
210+
# triangles
211+
for j in range(rows):
212+
mod_co = cols + 1
213+
for i in range(cols):
214+
mod_ro = rows + 1
215+
rect_index = i + j * mod_co
216+
anchor_node = rect_index + j
217+
218+
tri_1 = [anchor_node, anchor_node + mod_ro, anchor_node + mod_ro + 1]
219+
tri_2 = [anchor_node, anchor_node + 1, anchor_node + mod_ro + 1]
220+

0 commit comments

Comments
 (0)