Network Surfaces
A Network Surface (specifically a Coons Patch) generates a smooth surface bridging the gap between four intersecting boundary curves. The fundamental requirement is that the curves must meet at four distinct corner points.
Boundary Setup:
1# Defining 4 Boundary Curves2# A Coons Patch requires 4 curves that share endpoints.34def define_network_boundaries():5 # Curve 0 (Bottom), Curve 1 (Top)6 c0 = NurbsCurve(start=P(0,0,0), end=P(1,0,0))7 c1 = NurbsCurve(start=P(0,1,0), end=P(1,1,0))89 # Curve 2 (Left), Curve 3 (Right)10 c2 = NurbsCurve(start=P(0,0,0), end=P(0,1,0))11 c3 = NurbsCurve(start=P(1,0,0), end=P(1,1,0))1213 # Corners must match exactly:14 # c0.start == c2.start15 # c0.end == c3.start16 # c1.start == c2.end17 # c1.end == c3.end
The first mathematical component of a Coons Patch is a bilinear interpolation of the 4 corner points. This creates a flat (or ruled) surface that connects the corners, completely ignoring the shape of the boundary curves.
Bilinear Term:
1# Bilinear Interpolation of Corners2def bilinear_surface(u, v, p00, p10, p01, p11):3 """Interpolates a point based on 4 corner vertices."""4 # Interpolate along bottom edge5 bottom = p00 * (1 - u) + p10 * u6 # Interpolate along top edge7 top = p01 * (1 - u) + p11 * u89 # Interpolate between bottom and top10 return bottom * (1 - v) + top * v
The second mathematical component evaluates the shape of the U-direction curves (bottom and top boundaries). For a given parameter u, it finds the exact points on the bottom and top curves, and then draws a straight line (linear interpolation) between them based on v.
Ruled U Surface:
1# Ruled Surface in U Direction2def blend_u(u, v, curve_bottom, curve_top):3 """Interpolates between the U-direction curves."""45 # Evaluate point on bottom curve at parameter u6 pt_bottom = curve_bottom.evaluate(u)78 # Evaluate point on top curve at parameter u9 pt_top = curve_top.evaluate(u)1011 # Linearly interpolate between them based on v12 return pt_bottom * (1 - v) + pt_top * v
The third mathematical component evaluates the shape of the V-direction curves (left and right boundaries). Similar to the U-blend, it finds the exact points on the left and right curves for parameter v, and then draws a straight line between them based on u.
Ruled V Surface:
1# Ruled Surface in V Direction2def blend_v(u, v, curve_left, curve_right):3 """Interpolates between the V-direction curves."""45 # Evaluate point on left curve at parameter v6 pt_left = curve_left.evaluate(v)78 # Evaluate point on right curve at parameter v9 pt_right = curve_right.evaluate(v)1011 # Linearly interpolate between them based on u12 return pt_left * (1 - u) + pt_right * u
The brilliant insight of the Coons Patch is how it combines the three previous estimations. By adding the U-Ruled surface to the V-Ruled surface, we end up double-counting the corners. Subtracting the Bilinear surface perfectly cancels out this error, resulting in a smooth surface that exactly interpolates all four boundary curves.
Coons Formula:
1# Coons Patch Equation2def evaluate_coons_patch(u, v, c_bottom, c_top, c_left, c_right, corners):3 """Calculates the final surface point at (u, v)."""45 # Evaluate the U-ruled surface point6 pt_u = blend_u(u, v, c_bottom, c_top)78 # Evaluate the V-ruled surface point9 pt_v = blend_v(u, v, c_left, c_right)1011 # Evaluate the Bilinear surface point12 pt_bilinear = bilinear_surface(u, v, *corners)1314 # The Coons Patch formula:15 # Final Point = (Ruled U) + (Ruled V) - (Bilinear)16 return pt_u + pt_v - pt_bilinear
To render the mathematical Coons Patch as a 3D object, we must evaluate the formula across a 2D grid of (u, v) parameters, generating a structured array of vertices.
Grid Meshing:
u from 0.0 to 1.0, and v from 0.0 to 1.0. 3. Evaluate the Coons patch at each step to get 3D vertices. 4. Connect the grid into triangle pairs for rendering.1# Generating the Surface Grid2def generate_coons_mesh(c_bottom, c_top, c_left, c_right, u_segs, v_segs):3 """Evaluates the patch across a grid to build a mesh."""4 corners = get_corners(c_bottom, c_top, c_left, c_right)56 vertices = []78 # 1. Evaluate points at grid intersections9 for i in range(v_segs + 1):10 v = i / v_segs11 for j in range(u_segs + 1):12 u = j / u_segs1314 pt = evaluate_coons_patch(u, v, c_bottom, c_top, c_left, c_right, corners)15 vertices.append(pt)1617 # 2. Build quad faces connecting the vertices18 faces = build_grid_topology(u_segs, v_segs)1920 return Mesh(vertices, faces)
To render the Coons Patch smoothly and react properly to lighting, we need Surface Normals. Instead of calculating mathematically exact derivatives of the Coons equation (which can be expensive), we usually estimate normals directly from the generated mesh geometry.
Smooth Normal Estimation:
1# Surface Normals via Cross Products2def calculate_vertex_normals(mesh):3 """Calculates smoothed surface normals for rendering."""4 normals = [Vector(0,0,0) for _ in mesh.vertices]56 # 1. Calculate the face normal for every triangle7 for face in mesh.faces:8 v0, v1, v2 = mesh.vertices[face[0]], mesh.vertices[face[1]], mesh.vertices[face[2]]910 # Edge vectors11 edge1 = v1 - v012 edge2 = v2 - v01314 # Face normal via Cross Product15 face_normal = edge1.cross(edge2)1617 # 2. Add face normal to its 3 vertices18 normals[face[0]] += face_normal19 normals[face[1]] += face_normal20 normals[face[2]] += face_normal2122 # 3. Normalize to length 1.023 for i in range(len(normals)):24 normals[i].normalize()2526 return normals
Network surfaces are widely used in architecture (for tensile structures or canopy roofs) and in automotive design to smoothly fill complex multi-sided holes between other surfaces.
Dynamic Networks:
1# Interactive Grid Surface2def update_surface(time):3 """Animates the boundary curves of the network surface."""45 # Animate control points of the curves based on time6 c_bottom.control_points[1].z = math.sin(time) * 2.07 c_top.control_points[1].z = math.cos(time) * 2.089 c_left.control_points[1].y = math.sin(time * 0.5) * 2.010 c_right.control_points[1].y = math.cos(time * 0.5) * 2.01112 # Re-evaluate Coons Patch mesh13 return generate_coons_mesh(c_bottom, c_top, c_left, c_right, 20, 20)