Extruded surface: a full cylinder

Extruded surface: a full cylinder#

Extruding a full unit circle along the \(z\) axis produces the cylindrical surface

\[\mathbf S(u,v)=\mathbf C(u)+2v(0,0,1),\qquad (u,v)\in[0,1]^2.\]

The cylinder has radius one and height two. This example constructs the entire lateral surface, with coincident boundaries at \(u=0\) and \(u=1\). Its two circular ends remain open.

Inputs#

CircularArc represents the full \(2\pi\) circle exactly with four rational quadratic spans. Use its .NurbsCurve attribute as the input to nurbspy.nurbs_surface_extruded.NurbsSurfaceExtruded. The circle has three coordinate rows because the extrusion is spatial, even though the initial profile lies in the \(xy\) plane.

The extrusion helper normalizes D and uses d as the extrusion distance. Its .NurbsSurface attribute exposes the resulting surface. Here \(u\) follows the circle, while \(v\) follows the vertical extrusion.

Complete script#

Run python demos/documentation/extruded_surface.py, or download the script.

"""Extrude a full rational circle into an exact cylindrical surface."""
import numpy as np
import matplotlib.pyplot as plt
import nurbspy as nrb

nrb.set_plot_options()

circle = nrb.CircularArc(
    O=np.array([0., 0., 0.]),
    X=np.array([1., 0., 0.]),
    Y=np.array([0., 1., 0.]),
    R=1., theta_start=0., theta_end=2 * np.pi,
).NurbsCurve
surface = nrb.NurbsSurfaceExtruded(
    C=circle, D=np.array([0., 0., 1.]), d=2.
).NurbsSurface

uu, vv = np.meshgrid(np.linspace(0., 1., 41), np.linspace(0., 1., 31),
                     indexing="ij")
S = surface.get_value(uu.ravel(), vv.ravel())
H, K = surface.get_curvature(uu.ravel(), vv.ravel())

print("Control net shape:", surface.P.shape)
print(f"Degrees: ({surface.p}, {surface.q})")
print(f"Maximum cylinder radius error: {np.max(np.abs(np.hypot(S[0], S[1]) - 1.)):.2e}")
print(f"Maximum height error: {np.max(np.abs(S[2] - 2 * vv.ravel())):.2e}")
print(f"Maximum Gaussian curvature magnitude: {np.max(np.abs(K)):.2e}")
print(f"Maximum |H| error from 0.5: {np.max(np.abs(np.abs(H) - 0.5)):.2e}")
v = np.linspace(0., 1., 31)
seam_error = np.max(np.abs(surface.get_value(np.zeros_like(v), v)
                           - surface.get_value(np.ones_like(v), v)))
print(f"Maximum seam mismatch: {seam_error:.2e}")

fig, ax = surface.plot(surface_color=nrb.COLORS_MATLAB[0],
                       isocurves_u=13, isocurves_v=5, Nu=101, Nv=41)
ax.set_title("Full cylinder by extrusion")
ax.set_box_aspect((1, 1, 1))
ax.view_init(elev=25, azim=35)
# Leave room for the 3D axis labels when displaying or exporting the figure.
fig.set_size_inches(7, 6)
fig.subplots_adjust(left=0.05, right=0.85, bottom=0.15, top=0.9)
ax.set(xlabel="$x$", ylabel="$y$", zlabel="$z$")
for axis in (ax.xaxis, ax.yaxis, ax.zaxis):
    axis.labelpad = 4
plt.show()

Output#

The control net has shape (3, 9, 2) and degrees \((2,1)\). Both rows of weights are inherited from the circle. At every sample \(x^2+y^2=1\) and \(z=2v\), up to floating-point roundoff. The script also checks that the two sides of the circumferential seam coincide.

A unit cylinder has Gaussian curvature \(K=0\) and mean-curvature magnitude \(|H|=1/2\). The sign of \(H\) depends on the surface normal. The script prints the errors against these geometric properties.

A complete cylindrical lateral surface with circular and vertical isoparametric curves.

An exact circular profile extruded in a straight line produces a full cylinder.#

The package’s surface.plot() method draws the cylinder and its isoparametric curves. Setting control_points=True also displays the two rings of control points.