# Introduction to 3D Modeling. Section 7. Curves and Curved Surfaces

### 7 Curves and Curved Surfaces

Objectives:

• Learn the concept of reference domains and reference maps.
• Learn to map curves and surfaces in 3D space.
• Create Bézier curves and surfaces.
• Create coons patches.
• Create rotational surfaces.
• Learn how to solidify a surface.
• Create ruled surfaces.
• Learn to span surfaces between curves.
• Create cylindrical and conical surfaces.
• Create profile product surfaces.
• Create cubic Hermite surfaces.

PLaSM provides extensive support for curved surfaces including Bézier surfaces, coons patches, rotational surfaces, ruled surfaces, cylindrical and conical surfaces, Hermite surfaces, splines, Cartesian products of curves, etc. These techniques will be discussed in the following, but first let us explain the underlying concepts of reference domains and maps.

#### 7.1 Reference domains

In a standard way, curves in PLaSM are parameterized from an interval, and surfaces from a rectangle. These domains are called reference domains. Reference interval (0,L) that is subdivided into N equally-long pieces is created using the command INTERVALS:

ref_domain = INTERVALS(L, N)

Reference rectangle (0,L1) × (0,L2), where the first and second directions are subdivided into N1 and N2 pieces, respectively, can be created using the PRODUCT command:

dom1 = INTERVALS(L1, N1)
dom2 = INTERVALS(L2, N2)
ref_domain = PRODUCT(dom1, dom2)

#### 7.2 Mapping curves

Every curve is the graph of a function P that is defined in a reference interval (0,L) and for every value t in this interval it returns a 3D point P(t). The function P is called reference map. Let us show a few examples.

Example 1: The map P(t) = [1 + t, 1 + t, 1 + t] which in Python is written as

def P(t): return [1 + t, 1 + t, 1 + t]

renders for t in (0, 1) a curve that is a straight line connecting the points (1, 1, 1) and (2, 2, 2), as shown in Fig. 119. Fig. 119: Graph of the reference map P(t) = [1 + t, 1 + t, 1 + t].

How can we verify that this graph is correct? Insert the limit values t = 0 and t = 1 into the formula for the map P to see that the end points are (1, 1, 1) and (2, 2, 2), respectively. The fact that the curve is a straight line follows from the linearity of the map P in all three components.

Example 2: The map P(t) = [cos(t), sin(t), 0] whose Python form is

def P(t): return [cos(t), sin(t), 0]

maps the reference interval (0, 2π) to a circle in the xy-plane, as shown in Fig. 120. Fig. 120: Graph of the reference map P(t) = [cos(t), sin(t), 0].

Example 3: The map P(t) = [0, cos(t), sin(t)] a.k.a.

def P(t): return [0, cos(t), sin(t)]

maps the reference interval (0, 2π) to a circle in the yz-plane, as shown in Fig. 121. Fig. 121: Graph of the reference map P(t) = [0, cos(t), sin(t)].

Example 4: The map or

def map(t):
return [cos(t), sin(t), t]

maps the reference interval (0, 2π) to a spiral whose xy-plane projection is the unit circle and in the z-direction spans the interval (0, 2π), as shown in Fig. 122. Fig. 122: Graph of the reference map P(t) = [cos(t), sin(t),t].

#### 7.3 Mapping surfaces

Now that the reader understands the parameterization of curves, surfaces will follow easily. In fact the only difference is that the reference map P(t1,t2) is a function of two variables – it still returns 3D points. Let us show a few examples.

Example 1: The map whose code is

def P(t1, t2):
return [t1, t2, t1 + t2]

maps the reference square (0, 1) × (0, 1) to a planar surface that spans four points (0, 0, 0), (1, 0, 1), (0, 1, 1) and (1, 1, 2). No subdivision in any direction was applied to the reference square to generate the wireframe plot shown in Fig. 123. In other words, only the four vertices of the reference domain were transformed using the map, and the resulting 3D points were interpolated linearly. This was enough in this case since the resulting surface is linear. Fig. 123: Graph of the reference map P(t1,t2) = [t1,t2,t1 + t2].

Example 2: Next we render a saddle surface using the reference square (-1, 1) × (-1, 1). The map is defined as or

def P(t1, t2):
return [t1, t2, t1*t2]

The reference square was subdivided into 10 intervals in each direction, i.e., into 100 square cells. This means that 112 points were transformed via the map P(t 1,t2). The corresponding wireframe plot with 100 linearly interpolated cells is shown in Fig. 124. Fig. 124: Graph of the reference map P(t1,t2) = [t1,t2,t1t2].

Example 3: Now let us render a cylindrical surface with radius 1 and height 1 using the reference rectangle (0, 2π) × (0, 1). The interval (0, 2π) represents angular direction and (0, 1) the z-direction. The map is defined as or

def P(a, z):
return [cos(a), sin(a), z]

The reference domain was subdivided into 32 equally-long subintervals in the angular direction, and it was not subdivided in the z-direction. Hence the wireframe plot shown in Fig. 125 consists of 32 linear surfaces. Fig. 125: Graph of the reference map P(a,z) = [cos(a), sin(a),z].

In fact, PLaSM uses the same map to render cylindrical surfaces, and that’s is where the optional subdivision parameter in the CYLINDER command comes from. In PLaSM, its default value is 64.

#### 7.4 Three ways to map a sphere

Usually there is more than one way to map a given surface. The maps will differ in their properties and some of them will be better than the others. Let us illustrate this using the spherical surface as an example.

Map 1: Let us begin with the simplest map based on parameterizing the angular and radial directions. The reference rectangle is (0, 2π) × (0, 1). where (0, 2π) represents the angle and (0, 1) the radius. The map is given by the formula or

def P(a, r):
return [r*cos(a), r*sin(a), sqrt(1 - r**2)]

We subdivide the reference rectangle into 32 pieces in the angular direction and into 10 pieces in the radial one. This means that the piecewise linear wireframe plot shown in Fig. 126 has 320 cells. Fig. 126: Graph of the reference map P(a,r) = .

Notice that many points are accumulated near the pole while the lower portion of the surface is approximated rather crudely.

Map 2: This map uses the angle and the z-direction. The reference rectangle is formally the same as before, (0, 2π) × (0, 1), but the interval (0, 1) has a different meaning. Also the map is different, or

def P(a, z):
return [sqrt(1 - z**2)*cos(a), sqrt(1 - z**2)*sin(a), z]

The wireframe plot shown in Fig. 127 is based on precisely the same subdivision of the reference rectangle as in the previous case. Fig. 127: Graph of the reference map P(a,z) = .

The reader can see that while the lower portion of the surface is approximated better compared to the previous case, the accuracy suffers in the vicinity of the pole.

Map 3: The last map uses two angular directions a and b and a different reference rectangle (0, 2π) × (0,π∕2). The map is defined as P(a,b) = or

def P(a, z): return [cos(a)*cos(b), sin(a)*cos(b), sin(b)]

The wireframe plot shown in Fig. 128 is also based on a 32 × 10 subdivision of the reference rectangle which results into the same number of 320 linear cells that we had in the previous two examples. However, the reader can see that this map yields clearly the best approximation. Fig. 128: Graph of the reference map P(a,b) = .

Therefore PLaSM uses precisely this map to render spherical surfaces. In fact PLaSM uses a reference rectangle (0, 2π) × (-π∕2,π∕2) to cover the entire sphere. The default subdivision for the spherical surface in PLaSM is 48 × 24 which corresponds to

s = SPHERE(R, [24, 48])

(the order of the two subdivisions is switched).

#### 7.5 Primer on Bézier curves

Bézier curves are the most widely used curves in engineering design. Let us begin with the linear case. Linear Bézier curve is a straight line that connects two control points P1 and P2. All Bézier curves are parameterized from the interval [0, 1], so in the linear case the exact mathematical definition is You can easily check that the curve starts at P1 (substitute t = 0 to the above formula), and that it ends at P2 (substitute there t = 1).

Quadratic Bézier curves are defined using three control points P1,P2 and P3. Again they are parameterized from [0, 1], and their definition is Cubic Bézier curves are defined using four control points P1,P2,P3 and P4. They are parameterized from [0, 1] as usual, and their definition is #### 7.6 Drawing Bezier curves

The command DRAWBEZIER2D takes a list of 2D points in the xy-plane, and it creates an object that can be visualized with the SHOW command. Besides the list of points, the DRAWBEZIER2D command has the following optional parameters: thickness of the curve (default value 0.02), radius of spheres that represent the points (default value 0.1), color of the curve and end points (default BLACK), color of the interior points (default BLUE), and two divisions (default 32 and 1). Here is an example of a curve given by two points (which is a straight line):

# List of XY plane points:
point_list = [[3, 0], [0, 6]]

# Show the Bezier curve:
c = DRAWBEZIER2D(point_list)
SHOW(c) Fig. 129: Bezier curve (straight line) given by two points [3, 0], [0, 6].

Another example of a curve given by three points (which is a parabola):

# List of XY plane points:
point_list = [[3, 0], [3,4], [0, 6]]

# Show the Bezier curve:
c = DRAWBEZIER2D(point_list)
SHOW(c) Fig. 130: Bezier curve (parabola) given by three points [3, 0], [3, 4], [0, 6].

#### 7.7 2D object with one straight and one curved Bézier edges

For starters, let’s create a 2D quadrilateral with one linear and one cubic Bézier edges. Bézier curves are created using the commands BEZIER and BEZIER2 (that can be abbreviated as BE and BE2). The former is mapped on the x (horizontal) coordinate in the reference rectangle, the latter on the y (vertical) coordinate. For completeness, there is also BEZIER3 that is mapped on the z coordinate of a reference 3D box. But we are going to stay with 2D surfaces for now.

First let us create two Bézier curves, one linear and one cubic:

# Linear Bezier curve:
c1 = BEZIER([0, 0], [0, 4])

# Cubic Bezier curve:
c2 = BEZIER([2, 0], [4, 1], [0, 2], [1, 3])

These are the left vertical edge, and the right (curved) vertical edge in Fig. 131. Fig. 131: 2D object with one straight and one curved Bézier edge.

The surface between these two curves needs to be treated as any other curved surface, although in this case it is a subset of the XY plane. It needs to be mapped on a reference rectangle. For simplicity we will use the unit square.

# Reference domain with 30 x 30 subdivision:
refdomain = UNITSQUARE(30, 30)

# The 2D surface:
surf = BEZIER2(c1, c2)
out = MAP(refdomain, surf)

Notice that BEZIER2 has c1, c2 as arguments. For any fixed value of x between xmin and xmax these become just a pair of points. Since there are just two of them, the BEZIER2 curve connecting them is linear in y. When x = xmin, then it is a straight line connecting the beginning points of the curves c1 and c2. When x = xmax, then the BEZIER2 curve is a straight line connecting their end points. Similarly, the BEZIER2 curve is a linear function of y, connecting just two points in the XY plane, for any fixed value of x between xmin and xmax. The output is displayed in Fig. 131.

Remarks:

• As we already saw in a different context before, a point list such as L = [[0, 0, 0], [0, 4, 0]] can be passed into the BEZIER and BEZIER2 functions as well, with an asterisk in front of it, i.e., as BEZIER(*L) or BEZIER2(*L).
• Notice that the commands accepts general 3D points, they do not have to lie in the xy-plane as they are in this example.

#### 7.8 2D object with two curved Bézier edges

This example is very similar to the last one, and we are showing it only to illustrate that both the Bézier edges can be curves. Concretely, the curve c1 is made parabolic by adding one more control point to it.

c1 = BEZIER([0, 0], [-1, 1.5], [0, 4])

# Cubic Bezier curve:
c2 = BEZIER([2, 0], [4, 1], [0, 2], [1, 3])

# Reference domain with 30 times 30 subdivision:
refdomain = UNITSQUARE(30, 30)

# The 2D surface:
surf = BEZIER2(c1, c2)
out = MAP(refdomain, surf)

The output is displayed in Fig. 132. Fig. 132: 2D object with two curved Bézier edges.

#### 7.9 3D surface defined via four Bézier curves

Next let us construct a Bézier surface defined via four Bézier curves.

# Bezier curves:
c1 = BEZIER([0, 0, 0], [5, -2, -5], [10, 0, 0])
c2 = BEZIER([0, 2, 0], [8, 3, 0], [9, 2, 0])
c3 = BEZIER([0, 4, 1], [7, 5, -1], [8, 5, 1], [12, 4, 0])
c4 = BEZIER([0, 6, 0], [9, 6, 3], [10, 6, -1])

# Reference domain with 30 times 30 subdivision:
refdomain = UNITSQUARE(30, 30)

# The surface:
surf = BEZIER2(c1, c2, c3, c4)
out = MAP(refdomain, surf)

All four curves are parameterized by x (the horizontal variable) on the reference rectangle. Three of them are parabolas and one is cubic (that’s c3). All of them are genuinely 3D, with the exception of c2 which lies in the XY plane. Since there are four of them, in this case BEZIER2 is a cubic function (of y on the reference rectangle). The output is displayed in Fig. 133. Fig. 133: 3D surface defined via four curved Bézier edges.

#### 7.10 Coons patch

Coons patch is a technique that forms a Bézier patch from four Bézier edges connected by their end points. The center control points are calculated by a blend of two linear interpolations and one bilinear interpolation.

u1 = BEZIER([0, 4, 0], [2.5, 3, 6], [5, 0, -6], [7.5, 0, 6],
[10, 0, 0])
u2 = BEZIER([0, 6, 0], [2.5, 7, 6], [5, 10, -6], [7.5, 10, 6],
[10, 10, 0])
v1 = BEZIER2([0, 0, 0], [-3, 3, 3], [-3, 7, 3], [0, 10, 0])
v2 = BEZIER2([10, 0, 0], [15, 6, 0], [10, 10, 0])

# The coons patch:
out = COONSPATCH(u1, u2, v1, v2)

The reference domain is the unit square, divided by default into 32x32 intervals. These divisions can be changed using a pair of optional parameters that comes after the four curves. The curves u1 and u2 are mapped on the bottom and top horizontal edges of the reference unit square. The curves v1 and v2 are mapped on the left and right vertical edges. The output is displayed in Fig. 134. Fig. 134: Coons patch.

#### 7.11 Rotational surface

Rotational surfaces can be created using the ROTATIONALSURFACE command (possibly abbreviated as ROSURF). The command takes a list of 2D points that define a Bezier curve in the first quadrant of the xy-plane. The curve is then rotated about the y-axis:

# List of points in the first quadrant of
# the XY plane, that define a Bezier curve:
points = [[0, 0], [2, 0], [3, 4]]

# Create the rotational surface:
out = ROSURF(points, 360, 32, 64)

The last three parameters are optional - an angle of evolution greater than zero and less or equal to 360 degrees, and two divisions. The output of the above code is displayed in Fig. 135. Fig. 135: Rotational surface created using a quadratic Bézier curve.

#### 7.12 Solidifying a surface

Surfaces can be solidified using the command JOIN. The result of this operation will always be a convex hull. Adding to the last script:

# Solidify the surface:
out = JOIN(out)

This operation may take a while since PLaSM creates a new set of volume maps from the existing set of surface maps. The output is displayed in Fig. 136. Fig. 136: Solidifying the surface from Fig. 135.

#### 7.13 Rotational solid

Rotational solids can be created using the ROTATIONALSOLID command (possibly abbreviated as ROSOL). The usage is analogous to ROTATIONALSURFACE, except that the result is a 3D volumetric object instead of a surface. Also, there is one additional parameter rmin that comes after the angle of evolution – with rmin = 0 the solid will extend all the way from the axis of rotation to the curve in the radial direction. If rmin > 0 then there will be a cylindrical void about the axis of rotation:

# List of points in the first quadrant of the XY plane,
# that defines a Bezier curve:
points = [[0, 0, 0], [2, 0, 0], [3, 0, 1], [0, 2, 0],
[3, 0, 4]]

# Create a rotational solid about the y-axis:
out = ROSOL(points, 360, 0, 32, 64)

The last four parameters are optional - an angle of evolution greater than zero and less or equal to 360 degrees, rmin, and two divisions. The output of the above code is displayed in Fig. 137. Fig. 137: Creating a rotational solid.

#### 7.14 Ruled surface - an introduction

In geometry, a surface s is called ruled (or scroll) if it is "formed by straight lines". More precisely, if through every point of s passes a straight line that lies in s. The most familiar examples are the plane, cylinder, and cone. The standard definition of the ruled surface is where p(x,y) = p(x) and q(x,y) = q(x) are maps defined in a reference rectangle A×B. None of them depends on the y-coordinate, just on x. For every x in A, p(x,y) = p(x) returns a 3D point on the surface s. The map q(x,y) = q(x) returns for every x in A a direction vector (in the form of a 3D point). This is the direction of the straight line that lies on the surface s. The values of y are in the interval B.

In the first example, the map p(x,y) = p(x) is defined as and thus the curve lying on s is a straight line connecting the points (0, 0, 0) and (1, 0, 0).

def p(point):
x = point
return [x, 0, 0]

The map q(x,y) = q(x) is given by and it defines a direction vector that changes gradually from (0, 1, 0) to (0, 1, 1) as x goes from 0 to 1.

def q(point):
x = point
return [0, 1, x]

Reference domain is the unit square covered with a 32 × 32 division:

# Unit square covered with a 32x32 Cartesian grid:
refdomain = UNITSQUARE(32, 32)

The RULEDSURFACE command takes the two maps p, q as arguments. It can be abbreviated as RUSU:

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 138. Fig. 138: Ruled surface given by the maps p and q.

#### 7.15 Ruled surface - spiral

In this example the map p(x,y) = p(x) moves the 3D point along the z-axis and the direction vector q(x,y) = q(x) is horizontal and rotates. The resulting surface S is a spiral.

# Import sine and cosine from Numpy:
from numpy import sin, cos

def p(point):
x = point
return [0, 0, 0.5*x]

def q(point):
x = point
return [cos(x), sin(x), 0]

# Reference domain:
refdomain = REFDOMAIN(8*PI, 5, 128, 16)

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 139. Fig. 139: Spiral as a ruled surface.

#### 7.16 Ruled surface - straight cylinder

In this example the map p(x,y) = p(x) moves the 3D point on a circle that lies in the xy-plane, and the vector q(x,y) = q(x) it a unit vector in the vertical direction. Hence the resulting ruled surface is a cylinder.

# Import sine and cosine from Numpy:
from numpy import sin, cos

r = 3.0

# Cylinder height:
h = 10.0

def p(point):
x = point
return [r*cos(x), r*sin(x), 0]

def q(point):
x = point
return [0, 0, 1]

# Reference domain:
refdomain = REFDOMAIN(2*PI, h, 64, 1)

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 140. Fig. 140: Cylinder as a ruled surface.

#### 7.17 Ruled surface - curved cylinder

This example is similar to the last one, except that the directional vector q(x,y) = q(x) is not vertical. Instead, it points to a point on the upper circle of the cylinder that has an angular shift α. The script below uses a shift of 0.7π. When increased towards π, the curved surface becomes thinner in the middle portion.

# Import since and cosine from Numpy:
from numpy import sin, cos

r = 3.0

# Cylinder height:
h = 10.0

# Angular shift:
alpha = 0.7 * PI

def p(point):
x = point
return [r*cos(x), r*sin(x), 0]

def q(point):
x = point
return [r/h * (cos(x + alpha) - cos(x)),
r/h * (sin(x + alpha) - sin(x)), 1]

# Reference domain::
refdomain = REFDOMAIN(2*PI, h, 64, 32)

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 141. Fig. 141: Curved cylinder.

#### 7.18 Ruled surface - spanning arbitrary 3D curves

This is one of the most useful application of ruled surfaces. We will show two examples. In the first one we consider a 2π × 2π square, define a sine function and a parabola on the opposite edges, and connect them via a ruled surface:

# Import sine from Numpy:
from numpy import sin

# Define two 3D curves:
def c1(x):
return [x, 0, sin(x)]

def c2(x):
return [x, 2*PI, (x/PI - 1)**2]

def p(point):
x = point
return c1(x)

# Return a vector pointing from one curve to the other:
def q(point):
x = point
return [c2(x) - c1(x), c2(x) - c1(x),
c2(x) - c1(x)]

# Reference domain:
refdomain = REFDOMAIN(2*PI, 1, 64, 1)

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 142. Fig. 142: Spanning the graphs of a sine function and a parabola.

In the next example we define two curves that start at (1, 0, π) and (-1, 0, π), respectively, and descend to the xy-plane describing a spiral trajectory:

# Import sine and cosine from Numpy:
from numpy import sin, cos

# Define two 3D curves:
def c1(t):
return [cos(t), sin(t), PI - t]

def c2(t):
return [cos(PI + t), sin(PI + t), PI - t]

def p(point):
x = point
return c1(x)

# Return a vector pointing from one curve to the other:
def q(point):
x = point
return [c2(x) - c1(x), c2(x) - c1(x),
c2(x) - c1(x)]

# Reference domain:
refdomain = REFDOMAIN(PI, 1, 64, 30)

# Creating the ruled surface:
surf = RUSU(p, q)
out = MAP(refdomain, surf)

The output is displayed in Fig. 143. Fig. 143: Spanning a pair of spirals.

#### 7.19 Generalized cylindrical surface

By generalized cylindrical surface we mean a surface that is obtained via extrusion of a curve lying in the xy-plane in a given constant direction. This can be done using the command CYLINDRICALSURFACE (that can be abbreviated using CYS) which is a simple application of RULEDSURFACE. If we use a circle as the underlying curve, and the directional vector is vertical, we obtain the traditional cylinder. Here is an example with a cubic Bézier curve:

# Cubic Bezier curve in the xy-plane:
c = BEZIER([1,1,0], [-1,1,0], [1,-1,0], [-1,-1,0])

# Directional vector:
vector = [0, 0, 2]

# Product geometry:
out = CYSU(c, vector, 64, 1)

The last two parameters are optional divisions. Their default values are 32 and 32. The output is displayed in Fig. 144. Fig. 144: Generalized cylindrical surface.

#### 7.20 Generalized conical surface

Generalized conical surface (CONICALSURFACE, COSU) is similar to the generalized cylindrical one, except that the "rays" from the curve all go to just one point that lies above the midpoint of the curve (tip of the generalized cone). If we use a circle as the underlying curve, and the tip is above the center of the curve, we obtain the traditional cone. Let us use again a cubic Bézier curve as an example:

# Bezier curve in the xy-plane:
c = BEZIER([1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0])

# Apex of the cone:
point = [0, 0, 2.0]

# Conical surface:
out = COSU(c, point, 64, 8)

The last two parameters are optional divisions - their default values and 32 and 32. The output is displayed in Fig. 145. Fig. 145: Conical surface.

#### 7.21 Profile product surface

Profile product surface (PROFILEPRODSURFACE, PPSU) is the Cartesian product of a curve c1 in the z-direction with another curve c2 in the xy-plane. The former determines the magnitude and the latter the shape. In other words, when we cut the resulting product surface horizontally at some vertical coordinate z0, then we obtain a curve similar in shape to c2. The size difference between the cutline and the original curve c2 is given by c1(z0). Let us show two examples. In the first one, c1 will be a straight line and c2 a quadratic Bézier curve:

# Vertical shape:
c1 = BEZIER([0, 0, 0], [2, 0, 5])

# Base shape in the xy-plane:
c2 = BEZIER2([-1, 0, 0], [0, 3, 0], [1, 0, 0])

# Reference domain:
refdomain = UNITSQUARE(64, 64)

# Profile product surface:
surf = PPSURFACE(c1, c2)
out = MAP(refdomain, surf)

The output is displayed in Fig. 146. Fig. 146: Product of a straight line in the z-direction with a quadratic Bézier curve in the xy-plane.

In the next example we will construct the product of two cubic Bézier curves.

# Vertical shape:
c1 = BEZIER([0, 0, 0], [2, 0, 0], [0, 0, 4], [1, 0, 5])

# Base shape in the xy-plane:
c2 = BEZIER2([0, 0, 0], [3, 0, 0], [3, 3.5, 0], [0, 3, 0])

# Reference domain:
refdomain = UNITSQUARE(64, 64)

# Profile product surface:
surf = PPSURFACE(c1, c2)
out = MAP(refdomain, surf)

The output is displayed in Fig. 147. Fig. 147: Product of two cubic Bézier curves.

#### 7.22 Cubic Hermite curves

A cubic Hermite curve can be defined using the commands CUBICHERMITE and CUBICHERMITE2 that can be abbreviated via CH and CH2, respectively. The meaning of the suffixes 1 and 2 is the same as for Bézier curves.

A cubic Hermite curve is given by its endpoints and tangential vectors at the endpoints - four parameters total. These four parameters define a unique Hermite cubic spline (i.e., cubic polynomial). For example, in the definition

point1 = [0, 0, 0]
point2 = [5, 0, 0]
vector1 = [1, 0, 0]
vector2 = [1, 0, 0]
c = CUBICHERMITE1(point1, point2, vector1, vector2)

both vectors are parallel to the line connecting the endpoints, and therefore the result is a straight line. The same happens with

point1 = [0, 0, 0]
point2 = [5, 5, 5]
vector1 = [1, 1, 1]
vector2 = [1, 1, 1]
c = CUBICHERMITE1(point1, point2, vector1, vector2)

If one or both vectors are not parallel to the line connecting the endpoints, the result is not a straight line anymore. For example, with

point1 = [0, 0, 0]
point2 = [5, 5, 5]
vector1 = [0, 0, 1]
vector2 = [1, 1, 0]
c = CUBICHERMITE1(point1, point2, vector1, vector2)

we obtain a cubic curve that ascends verticaly at (0, 0, 0) with a tangential vector (0, 0, 1) and ends up flat at (5, 5, 5) with tangential vector (1, 1, 0).

#### 7.23 Cubic Hermite surfaces

Cubic Hermite surface spanning two curves differs from a ruled or Bézier surface in that it allows the user to prescribe slope vectors along the two curves. We show two examples. First, for simplicity, the two curves are the opposite edges of the unit square. Both of them are straight lines:

# First curve:
c1 = CUBICHERMITE1([0, 0, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0])

# Second curve:
c2 = CUBICHERMITE1([1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0])

Both slope vectors lie in the xz-plane and their angle to the xy-plane is π∕4. This results into a wave-like cubic surface.

# Slope vector for the first curve:
s1 = [1, 0, 1]

# Slope vector for the second curve:
s2 = [1, 0, 1]

# Reference domain:
refdomain = UNITSQUARE(32, 32)

# Cubic Hermite surface:
surf = CUBICHERMITE2(c1, c2, s1, s2)
out = MAP(refdomain, surf)

The output is displayed in Fig. 148. Fig. 148: Cubic Hermite "wave", constant in the y-direction.

Next let us deform the left edge by changing the tangential vectors at endpoints to (1, 1, 0) and (-1, 1, 0):

# First curve:
c1 = CUBICHERMITE1([0, 0, 0], [0, 1, 0], [1, 1, 0],
[-1, 1, 0])

The rest of the script stays the same. The output is displayed in Fig. 149. Fig. 149: Cubic Hermite surface after deforming the left edge.

We can also change the right edge to a cubic wave by adjusting the tangential vectors at endpoints to (0, 1, 1) and (0, 1, 1):

# Second curve:
c2 = CUBICHERMITE1([1, 0, 0], [1, 1, 0], [0, 1, 1],
[0, 1, 1])

The rest of the script remains the same. The output is displayed in Fig. 150. Fig. 150: Cubic Hermite surface after deforming also the right edge.

Last we create a cubic Hermite surface between two arcs:

# First (outer) curve:
c1 = CUBICHERMITE1([1, 0, 0], [0, 1, 0], [0, 3, 0],
[-3, 0, 0])

# Second (inner) curve:
c2 = CUBICHERMITE1([0.5, 0, 0], [0, 0.5, 0], [0, 1, 0],
[-1, 0, 0])

# Slope vector for the outer curve:
s1 = [0, 0, 1]

# Slope vector for the inner curve:
s2 = [-1, -1, -1]

# Reference domain:
refdomain = UNITSQUARE(32, 32)

# The 3D object:
surf = CUBICHERMITE2(c1, c2, s1, s2)
out = MAP(refdomain, surf)

The output is displayed in Fig. 151. Fig. 151: Cubic Hermite surface.