# 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.
- Learn about Bézier curves.
- 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:

Reference rectangle (0,L_{1}) × (0,L_{2}), where the first and second directions are subdivided into
N_{1} and N_{2} pieces, respectively, can be created using the PRODUCT command:

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

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.

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

maps the reference interval (0, 2π) to a circle in the xy-plane, as shown in Fig. 120.

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

maps the reference interval (0, 2π) to a circle in the yz-plane, as shown in Fig. 121.

Example 4: The map

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.

#### 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(t_{1},t_{2}) is a function of two variables – it
still returns 3D points. Let us show a few examples.

Example 1: The map

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.

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

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 11^{2} points were transformed via the map P(t_{
1},t_{2}). The
corresponding wireframe plot with 100 linearly interpolated cells is shown in Fig.
124.

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

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.

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

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.

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,

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.

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

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.

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

(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 P_{1} and P_{2}.
All Bézier curves are parameterized from the interval [0, 1], so in the linear case the exact
mathematical definition is

_{1}(substitute t = 0 to the above formula), and that it ends at P

_{2}(substitute there t = 1).

Quadratic Bézier curves are defined using three control points P_{1},P_{2} and P_{3}. Again they
are parameterized from [0, 1], and their definition is

_{1},P

_{2},P

_{3}and P

_{4}. 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):

point_list = [[3, 0], [0, 6]]

# Show the Bezier curve:

c = DRAWBEZIER2D(point_list)

SHOW(c)

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

point_list = [[3, 0], [3,4], [0, 6]]

# Show the Bezier curve:

c = DRAWBEZIER2D(point_list)

SHOW(c)

#### 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:

c1 = BEZIER([0, 0], [0, 4])

# Cubic Bezier curve:

c2 = BEZIER([2, 0], [4, 1], [0, 2], [1, 3])

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.

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 x_{min}
and x_{max} 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 = x_{min}, then it is a straight line
connecting the beginning points of the curves c1 and c2. When x = x_{max}, 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 x_{min} and x_{max}. 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.

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

Next let us construct a Bézier surface defined via four Bézier 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.

#### 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.

[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.

#### 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:

# 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.

#### 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:

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.

#### 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:

# 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.

#### 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

In the first example, the map p(x,y) = p(x) is defined as

x = point[0]

return [x, 0, 0]

The map q(x,y) = q(x) is given by

x = point[0]

return [0, 1, x]

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

refdomain = UNITSQUARE(32, 32)

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

surf = RUSU(p, q)

out = MAP(refdomain, surf)

The output is displayed in Fig. 138.

#### 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.

from numpy import sin, cos

def p(point):

x = point[0]

return [0, 0, 0.5*x]

def q(point):

x = point[0]

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.

#### 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.

from numpy import sin, cos

# Cylinder radius:

r = 3.0

# Cylinder height:

h = 10.0

def p(point):

x = point[0]

return [r*cos(x), r*sin(x), 0]

def q(point):

x = point[0]

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.

#### 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.

from numpy import sin, cos

# Cylinder radius:

r = 3.0

# Cylinder height:

h = 10.0

# Angular shift:

alpha = 0.7 * PI

def p(point):

x = point[0]

return [r*cos(x), r*sin(x), 0]

x = point[0]

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.

#### 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:

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[0]

return c1(x)

# Return a vector pointing from one curve to the other:

def q(point):

x = point[0]

return [c2(x)[0] - c1(x)[0], c2(x)[1] - c1(x)[1],

c2(x)[2] - c1(x)[2]]

# 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.

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:

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[0]

return c1(x)

# Return a vector pointing from one curve to the other:

def q(point):

x = point[0]

return [c2(x)[0] - c1(x)[0], c2(x)[1] - c1(x)[1],

c2(x)[2] - c1(x)[2]]

# 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.

#### 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:

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.

#### 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:

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.

#### 7.21 Profile product surface

Profile product surface (PROFILEPRODSURFACE, PPSU) is the Cartesian product of a curve c_{1}
in the z-direction with another curve c_{2} 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 z_{0}, then we obtain a curve similar in shape to
c_{2}. The size difference between the cutline and the original curve c_{2} is given by c_{1}(z_{0}). Let us
show two examples. In the first one, c_{1} will be a straight line and c_{2} a quadratic Bézier
curve:

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.

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

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.

#### 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

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

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

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:

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.

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.

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

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.

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):

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.

Last we create a cubic Hermite surface between two arcs:

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.