## Degrafa Closed-Loop Catmull-Rom Spline

Just a quick update that support for closed-loop C-R splines has been added to Degrafa. The algorithmis is the same one as used in Singularity and is documented in this TechNote. The algorithm is designed to provide G-1 continuity at the join and works best if the knot sequence approximately represents a closed shape. If the outermost knots are ‘pointing away’ from each other, behavior is unpredictable.

The current implementation is targeted towards a use of defining a single knot set with closure and no further modification. It is not possible to add knots to an already closed C-R spline. It is not currently possible to re-open the spline after closure. These constraints are based on discussion with designers on most likely usage. They are subject to future modification if people come up with applications that require closure and then re-opening of the spline.

A screenshot of a simple example is shown below,

There is no need to manually duplicate the first knot – doing so would result in undesired consequences. The MXML is simply

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comp="components.*" xmlns:degrafa="com.degrafa.*" xmlns:paint="com.degrafa.paint.*" xmlns:geom="com.degrafa.geometry.*" xmlns:splines="com.degrafa.geometry.splines.*" layout="absolute" width="600" height="500" pageTitle="Closed Catmull-Rom Spline"> <mx:Canvas id="background" x="50" y="90" width="500" height="320" backgroundColor="#FFFFFF" /> <paint:SolidStroke id="bluestroke" weight="2" color="#0000FF"/> <mx:Canvas id="splineLayer" /> <splines:CatmullRomSpline id="spline" graphicsTarget="{[splineLayer]}" stroke="{bluestroke}" knots="150,230 230,170 370,210 390,320 280,360 160,320" closed="true" /> </mx:Application>

Not much here and not really worth a demo. Update SVN to access the new source.

## Degrafa Plottable Catmull-Rom Spline

Progress has been slow with regular work and dealing with family issues, but the Degrafa BasicSpline class now supports (interpolative) parametric splines as well as Cartesian. The previous CatmullRom utility was used to ‘decorate’ BasicSpline to create a plottable Catmull-Rom spline that can be described in MXML. A screenshot of the basic demo is shown below.

The Degrafa spline is plotted as a sequence of quad. Beziers in red. The Catmull-Rom spline utility is used to plot the same spline point-to-point in blue. As long as any (interpolative) spline utility implements the IPlottableSpline interface, it can be used to create a Degrafa-plottable spline. The code for CatmullRomSpline is simply

public class CatmullRomSpline extends BasicSpline { private var _mySpline:CatmullRom; private var _isClosed:Boolean; public function CatmullRomSpline( _myPoints:Array=null ) { super(_myPoints); _mySpline = new CatmullRom(); super.spline = _mySpline; _isClosed = false; } public function set closed(_closed:Boolean):void { if( _closed != _isClosed ) { _isClosed = _closed; // remainder tbd - current utilty supports closure but not 'unclosing' the spline } } override public function getX(_t:Number):Number { return _mySpline.getX(_t); } override public function getY(_t:Number):Number { return _mySpline.getY(_t); } override public function getXPrime(_t:Number):Number { return _mySpline.getXPrime(_t); } override public function getYPrime(_t:Number):Number { return _mySpline.getYPrime(_t); } }

I’ve got some more work to do on the internals of BasicSpline, but I hope this will make it easy to implement a wide variety of splines in Degrafa. In particular, I hope it enables people who want to port splines from other languages, but do not wish to dig into the Degrafa internals to easily implement splines in Degrafa. Or, perhaps, it will just get me committed to the mental asylum. If only people knew I was already blogging from there 🙂

A note about the demo – there are a fixed number of points used in the point-to-point plot, so it can be a bit grainy for splines with really long arc length. The Degrafa spline is drawn segment-by-segment. Click the space bar to compare vs. the C-R utility plotted point-to-point. I have not yet implemented the closure as I’m thinking about making it close and re-open. Update SVN if you want to access the source.

## Degrafa Catmull-Rom Spline Utility

The Degrafa spline architecture has been modified to structurally achieve the desired sepration between the computational elements of a spline and the internal Degrafa geometry pipeline. This is illustrated by the new NaturalCubicSpline. In MXML, the spline is treated as before,

<NaturalCubicSpline id=”cubicSpline” graphicsTarget=”{[splineLayer]}” knots=”104,299 166,168 217,236 307,225 370,142 440,299 506,309″ >

<stroke>

<SolidStroke weight=”2″ color=”#0000FF”/>

</stroke>

</NaturalCubicSpline>

The actual Degrafa code is

public class NaturalCubicSpline extends BasicSpline { private var _cubicSpline:PlottableCubicSpline; public function NaturalCubicSpline( _myPoints:Array=null ) { super(_myPoints); _cubicSpline = new PlottableCubicSpline(); super.spline = _cubicSpline; } override public function eval(_x:Number):Number { return _cubicSpline.eval(_x); } override public function derivative(_x:Number):Number { return _cubicSpline.derivative(_x); } }

The computational basis for the spline is in the PlottableCubicSpline class which implements the IPlottableSpline interface. The integration into the Degrafa geometry pipeline is handled by BasicSpline. The basic idea is to supply an external utility that conforms to an established interface to handle the spline computations. A reference to the utility is used to ‘decorate’ BasicSpline in a simplistic sense. This makes it possible for people to author splines for Degrafa without having to understand much about Flash or the internals of Degrafa.

Currently, BasicSpline is only functional for cartesian splines. To preparare a set of test cases for parametric splines, the old Singularity Catmull-Rom spline has been ported to Degrafa as two utility functions. One is a straight Catmull-Rom spline (with auto-closure) that conforms to the IPlottableSpline interface. The other extends the base utility to include approximate arc-length parameterization for use in path animation or keyframing (where the path is not intended to be drawn).

A simple demo is available to illustrate the utility. Click in the draw area to define a few points, then hit the space bar. The spline is plotted old-school (point-to-point) to illustrate the path. A set of markers is distributed along the path at roughly equal intervals of arc length. A Degrafa ellipse is drawn and animated along the path. The ellipse is also oriented to follow the path. A screen shot is shown below.

Like I said, it’s a pretty simple demo, but it should give you an overview of how to use the new utility. An SVN update is required if you want the new source.

## Spline Tangents Part II

I received a couple questions regarding this post relative to computing the angle of the tangent line relative to the horizontal. It’s a matter of a little trig once you recall the geometric interpretation of a curve’s derivative at a point. Our old friend, Math.atan2() is just what the doctor ordered. To illustrate, I modified the demo code to use the Singularity Wedge class to show the angle relative to the horizontal as shown below.

The wedge is redrawn dynamically as the slider moves. Once you know the tangent orientation, you also know the normal orientation. Along with arc-length parameterization, this means that sprites can be precisely distributed along and aligned to the spline. Stay tuned for more …

## Spline Tangents

In calculus, we are taught that the slope of the tangent to a curve, y = f(x) at some point x=c is f'(c). What about a parameteric curve? The curve is parameterized on t, not on x. We do have derivative information, but the derivatives are with respect to the curve’s parameter.

Fortunately, the chain rule provides the necessary result; dy/dx = [dy/dt]/[dx/dt]. All Singularity parametric curves (including composite curves) return position and derivative at a parameter value. This information can be used to compute the slope of a tangent to a spline such as Catmull-Rom, as shown below.

If dx/dt is sufficiently small, the tangent slope approaches infinity and this should be tested and compensated for in application code. The demo from which the above screenshot was taken allows an arbitrary number of points to be defined in the drawing area. A Catmull-Rom spline is fit to those points. Move the slider to watch a 40px segment drawn tangent to the curve as the parameter varies from 0 to 1.

To compute the tangent segment, the slope of the spline at the specified parameter along with a small positive and negative perturbation in x is used to generate two points on the tangent in opposite directions. Unit vectors in each direction are created. Two points, each 20px along each unit vector, are generated to create the line segment.

The demo is contained in a single MXML file and may be obtained from the Downloads section in this blog. Or, you can download the .zip file here along with Singularity here. You need to have Singularity on your computer in order to build a Flex project from the supplied MXML file.

If we have a well-defined tangent to a curve at a point, not only can we orient sprites along the curve, we know the angle the tangent makes with horizontal. That information, combined with arc-length parameterization allows sprites to be distributed uniformly along the curve with orientation control. Stay tuned for a new demo in a few days illustrating these observations.