I have a series of points describing a curve in 3d space. I want to loft a square profile along it, but I cannot make it close in on itself. I attach a toy example below.
Pedro
import numpy as np
import cadquery as cq
from ocp_vscode import show
import matplotlib.pyplot as plt
CLOSE = False
# Synthetic data
curve = lambda t: np.array([np.cos(t), np.sin(t), 0.2 * np.cos(3 * t)]).T
t = np.linspace(0, 2 * np.pi, 50, endpoint=False)
fig, ax = plt.subplots(subplot_kw=dict(projection="3d"))
ax.plot(*curve(t).T)
ax.set_box_aspect([1, 1, 1])
plt.show()
xyz = curve(t)
tg = np.roll(xyz, -1, axis=0) - np.roll(xyz, 1, axis=0)
tg /= np.linalg.norm(tg, axis=1)[:, None]
COM = np.sum(xyz * np.linalg.norm(tg, axis=1)[:, None], axis=0) / np.sum(
np.linalg.norm(tg, axis=1)
)
if CLOSE:
# Add last point and tangent to point arrays
xyz = np.concat([xyz, xyz[0][None, :]])
tg = np.concat([tg, tg[0][None, :]])
nrm = xyz - COM
nrm /= np.linalg.norm(nrm, axis=1)[:, None]
bnrm = np.cross(tg, nrm)
bnrm /= np.linalg.norm(bnrm, axis=1)[:, None]
ntg = np.cross(nrm, bnrm)
ntg /= np.linalg.norm(ntg, axis=1)[:, None]
WIDTH = 0.2
sq = (
0.5
* WIDTH
* np.array(
[
[-1, -1, 0],
[1, -1, 0],
[1, 1, 0],
[-1, 1, 0],
]
)
)
base = np.array([nrm, bnrm, ntg]).swapaxes(0, 1)
sec = np.array([np.vecmat(sq, b).T for b in base]) + xyz[:, :, None]
print(sec.shape)
w = cq.Workplane("XY")
for s in sec:
w = w.polyline(s.T.tolist()).close().consolidateWires()
show(w) # Shows polylines
w = w.loft(combine=True, ruled=False)
show(w)