Page 2: Piecewise Parameteric Curves and Continuity

CS559 Spring 2023 Sample Solution

The way that we’ll make complicated shapes is by piecing together simple pieces. We’ve already been doing this: we have been making pictures out of primitives. If we want something complicated, we make it from a bunch of lines, arcs, polygons, etc.

A specific example we have already been using are line segments. Line segments are a simple primitive. If we want to make a more complicated shape, we piece together a bunch of them. We might call the combined thing a “bigger primitive” (e.g., a polyline or whatever name you like for a list of line segments).

When we build things out of parts, we need to think about two main issues: (1) what parts do we make things out of, and (2) how do we make sure that those parts fit together nicely.

To extend the line segment example: we know the pieces very well (a line segment is well defined mathematically, and we know how to specify it by giving its endpoints or other sets of numbers). We know how to fit pieces together: we make the end of one line as the beginning of the next, and they connect without a gap. With line segments, at this connection point there will be a sharp “corner” (unless the line segments are going in the same direction). The shape won’t be “smooth”. For talking about line segments, you can probably imagine what I mean by “corner” and “smooth” - but for graphics, we’ll need to define the concept of smoothness more formally, which is what this page is about.

Two Line Segments

However, before defining smoothness (or continuity), we can learn a few things from the line segments.

First, notice the problem with “lack of smoothness” only happens the points where the lines come together. The line segment pieces themselves are smooth. The “continuity” question only happens at the specific place where the pieces meet.

Second, there are many different ways of writing the same line segment in parametric form. A simple one is:

$$\mathbf{f}(u) = \bigg[ (1-u) p_{1x} + u p_{2x}, (1-u) p_{1y} + u p_{2y}\bigg] = (1-u) \mathbf{p_1} + u \mathbf{p_2}$$

This describes a line going from point $\mathbf{p_1}$ to $\mathbf{p_2}$. I wrote it in non-vector notation first, and then in vector notation. Remember that u is a scalar, and in this case it does go from 0 to 1.

Here is another way to write the equation of the same line segment, but in terms of different parameters:

$$\mathbf{f}(u) = \bigg[ a_{0x} + u a_{1x}, a_{0y} + u a_{1y}\bigg] = \mathbf{a_0} + u \mathbf{a_1}$$

Here, I chose to specify the line with 2 vectors: $\mathbf{a_0}$ and $\mathbf{a_1}$. The equation is much simpler, but it is less easy for me to specify the line. For example, if I knew where I wanted the line to end (so it connected to the next line), I have to compute the right values of $\mathbf{a_0}$ and $\mathbf{a_1}$. In this case, the computation is simple, but it isn’t the same as just making the end of one line be the beginning of the next.

Third: each line segment gets its own range of $u$. If we wanted to have one line segment “continue” into another, we would need to introduce a new parameter. For example, suppose we have two line segments: $$\mathbf{f_1}(u) = (1-u) \mathbf{p_1} + u \mathbf{p_2}$$ $$\mathbf{f_2}(u) = (1-u) \mathbf{p_2} + u \mathbf{p_3}$$

Each of these line segments has the point $\mathbf{p_2}$ as one of its endpoints, but both of them have inputs in the range 0-1. To combine these segments into a single piecewise curve, we need to map a different part of our input range to each line segment. One approach would be to make the input range be twice as long: $$\mathbf{f}(t) = \mathrm{if}\ (t<1) \ \mathrm{then}\ \mathbf{f_1}(t) \ \mathrm{else}\ \mathbf{f_2}(t-1)$$ which makes a 2-piece polyline over the range 0-2. Notice how this maps the second half of the $t$ range (1-2) to the range of the second line segment by subtracting 1 from $t$.

If we wanted the polyline to have the input range 0-1, we could construct a slightly different equation: $$\mathbf{f}(u) = \mathrm{if}\ (u<\frac{1}{2}) \ \mathrm{then}\ \mathbf{f_1}(u*2) \ \mathrm{else}\ \mathbf{f_2}(2u-1)$$

Here we draw the curve $\mathbf{f_1}$ from $u$=0 to 0.5 and $\mathbf{f_2}$ from $u$=0.5 to 1. In each case, we scale and shift $u$ so that the input to each line segment varies over the range 0-1.

Continuity of Parametric Curves

The concept of continuity is explained in section 15.2.1 of FCG4 Chapter 15.

On this page, we’ll just emphasize some of the more important concepts.

By the way, the code snippets are taken from the previous page (or in the style of functions used on the previous page). The parametric functions are defined on the range (0,1). Given a parameter value, they return the position (x,y) and the tangent vector ($\partial x/\partial u, \partial y/\partial u$).

Continuity

On the previous page, we saw that when there was an if statement in our parametric function, there was a chance for an abrupt change (in the position or the derivative). We formalize this with a notion of continuity.

We say that a curve has continuity at a particular site (parameter value) if the value is the same whether we approach the site from above or below. For example, in the two-line-segments example from the previous page:

1
2
3
4
function disconnect(u) {
  if (u < 0.5) return [0, 200 * u, 0, 200];
  else return [20, 100 - 200 * (u - 0.5), 0, -200];
}

Consider what happens when $u$ is around 0.5.

  • When we approach $u$=0.5 from below ($u$=0.4, 0.49, 0.499, …), our curve approaches the point (0, 100).
  • When we approach $u$=0.5 from above ($u$=0.6, 0.51, 0.501, …), our curve approaches the point (20,100).

Since these values are different, we say this curve has a discontinuity in value at 0.5. Since we typically talk about discontinuities in terms of derivatives, we say that the curve has a discontinuity in its zeroth derivative.

For the V shape, something similar happens with the first derivative.

1
2
3
4
function twoLines(u) {
  if (u < 0.5) return [100 * u, 200 * u, 100, 200];
  else return [100 * u, 100 - 200 * (u - 0.5), 100, -200];
}

For the values (zeroth derivative), there is no discontinuity (the value at $u$=0.5 is (50,100) whether we approach 0.5 from above or below). But there is a discontinuity in the first derivative (tangent). Approaching 0.5 from below, the derivative (with respect to $u$) is (100,200), while approaching it from above it is (100,-200). We say this curve has a discontinuity in its first derivative.

We say a curve is continuous (or has continuity), if it has no discontinuities across its parameter range. If a curve has no discontinuities of its zeroth derivatives (its values) we call it $C(0)$. If a curve has no discontinuities in its zeroth or first derivatives, we call it $C(1)$. More generally, if a curve has no discontinuities in any of its derivatives up to $n$, we call it $C(n)$.

Note that if we say a curve is $C(1)$, that implies that it is also $C(0)$. It is possible to contrive a curve that has first derivative continuity but not value continuity, such as:

1
2
3
4
function broken(u) {
  if (u < 0.5) return [u, 0, 1, 0];
  else return [u + 1, 0, 1, 0];
}

but such curves aren’t important for graphics. We do not call this $C(1)$, because $C(1)$ is defined so as to imply $C(0)$.

Note that the V shape is $C(0)$ but not $C(1)$. Here’s an example of a shape that is $C(1)$ but not $C(2)$:

1
2
3
4
5
6
// this code has the derivatives removed to be easier to read
function twoQuarterCircles(u) {
  let pu = Math.PI * u;
  if (u < 0.5) return [50 + 50 * Math.cos(pu), 50 * Math.sin(pu)];
  else return [50 + 50 * Math.cos(pu), 100 - 50 * Math.sin(pu)];
}

Here ( 05-02-01.html), two circular arcs connect at u=0.5. At the connection point, whether you are approaching from below or above, the tangent vector is horizontal and to the left. Watch the animation on the previous page.

This connection of two arcs is $C(1)$, but it is not $C(2)$ - the second derivatives are different between the first (top) part and the second (bottom) part. In the former, at 0.5 the derivative is turning upwards, whereas in the latter it is turning downwards. The 2nd derivative discontinuity is this rapid change: elsewhere (as we go around the circle) the second derivative does change, but it changes smoothly.

Also, notice that when we talk about continuity, we have only needed to consider the points where our piecewise curves switch between different pieces. The functions we have chosen are generally continuous in between these exceptional points. When we assemble curves from smooth pieces (such as arcs and polynomials), the potential for discontinuities is at the connections.

Geometric Continuity

Suppose we aren’t animating the pen, only looking at the resulting drawing. If we have a curve that changes its derivative, but we can’t see that change, we might not care.

For example, consider the curve:

1
2
3
4
function speedUp(u) {
  if (u < 0.5) return [u, 0, 1, 0];
  else return [2 * u - 0.5, 0, 2, 0];
}

The curve is a straight line, but the pen speeds up halfway (in parameter space). This curve is not $C(1)$, since the derivative changes sharply at $u$=0.5. However, since the direction of the tangent does not change (only its speed), this might be “continuous enough”. We call this easier kind of continuity (where the direction remains the same, even if the magnitude might change) geometric continuity (as opposed to the derivative continuity we had been discussing). We denote geometric continuity as $G(n)$ (for $n$th derivatives). So $G(1)$ means that the curves’ first derivatives have no discontinuities in their direction. (Note that $C(n)$ continuity implies $G(n)$.)

More formally, geometric continuity is defined in terms of arc-length parameterizations. However, since we haven’t introduced those yet, we’ll stick to the intuition based version. The book explains the details.

Summary: Continuity

Continuity is the key to putting pieces together. On Page 3: Cubics we will look at cubic polynomial segments, which are a common piece to put together.

There are no points associated with this page.