# Drawing Curves

## How To Draw Curves

If you want to draw a circular path then it is easy enough to generate the points, in the XY plane, for this using

`const path = [];for(let theta = 0; theta < 2 * Math.PI; theta +=deltaTheta ) { path.push(new BABYLON.Vector3(radius * Math.cos(theta), radius * Math.sin(theta), 0));`

When you are of a mind to do it you can work out some quite complex paths by hand.

What follows is how to draw some mathematical curves by using the Babylon.js *Curve3* object, from which you can extract the array of points you need to draw lines, ribbons, tubes and extruded shapes.

The general form is

`const curve = BABYLON.Curve3.Create.CURVETYPE(parameters);`

## Arc Through Three Points

Available from version 5.0.0. Given three points in space, not in a straight line, it is always possible to draw join the points up using a circular arc or to draw a circle through the three points.

`const arc = BABYLON.Curve3.ArcThru3Points(first, second, third, steps, closed, fullCircle);`

**first***Vector3*the first point the arc must pass through.**second***Vector3*the second point the arc must pass through.**third***Vector3*the third point the arc must pass through.**steps***number*the larger the number of steps the more detailed the arc.**closed***boolean*optional with default false, when true forms the chord from the first and third point**fullCircle***boolean*optional with default false, when true forms the complete circle through the three points

This static method returns an instance of *Curve3*.

Just use the Curve3 *getPoints()* method to fill your array : *getPoints()* returns an array of successive *Vector3*.

The *length()* method returns the curve length.

`const path = arc.getPoints();const l = arc.length();`

## Quadratic Bezier Curve

http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_curves

`const bezier2 = BABYLON.Curve3.CreateQuadraticBezier(origin, control, destination, nb_of_points);`

**origin**:*Vector3*the origin point,**control**:*Vector3*the control point,**destination**:*Vector3*the destination point,**nb_of_points**:*number*number of points wanted in the path array.

This static method returns an instance of *Curve3*.

Just use the Curve3 *getPoints()* method to fill your array : *getPoints()* returns an array of successive *Vector3*.

The *length()* method returns the curve length.

`const path = bezier2.getPoints();const l = bezier2.length();`

## Cubic Bezier curve

http://en.wikipedia.org/wiki/B%C3%A9zier_curve# Higher-order_curves

`const bezier3 = BABYLON.Curve3.CreateCubicBezier(origin, control1, control2, destination, nb_of_points);`

**origin**:*Vector3*the origin point,**control1**:*Vector3*the first control point,**control2**:*Vector3*the second control point,**destination**:*Vector3*the destination point,**nb_of_points**:*number*the wanted final curve number of points in the array.

This static method returns an instance of *Curve3*.

Just use the Curve3 *getPoints()* method to fill your array : *getPoints()* returns an array of successive *Vector3*.

The *length()* method returns the curve length.

`const path = bezier3.getPoints();const l = bezier3.length();`

## Hermite Spline

http://en.wikipedia.org/wiki/Cubic_Hermite_spline

`const hermite = BABYLON.Curve3.CreateHermiteSpline(p1, t1, p2, t2, nbPoints);`

**p1**:*Vector3*the origin point,**t1**:*Vector3*the origin tangent vector,**p2**:*Vector3*the destination point,**t2**:*Vector3*the destination tangent vector,**nbPoints**:*number*the wanted final curve number of points in the array.

*Curve3*.

Just use the Curve3 *getPoints()* method to fill your array : *getPoints()* returns an array of successive *Vector3*.

The *length()* method returns the curve length.

`const path = hermite.getPoints();const l = hermite.length();`

## Catmull-Rom Spline

https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline

`const nbPoints = 20; // the number of points between each Vector3 control pointsconst points = [vec1, vec2, ..., vecN]; // an array of Vector3 the curve must pass through : the control pointsconst closed = true; // closes the curve when trueconst catmullRom = BABYLON.Curve3.CreateCatmullRomSpline(points, nbPoints, closed);`

**points**:*Vector3*an array of Vector3 (the control points) the curve will pass through,**nbPoints**:*number*the wanted curve number of points between each control point,**closed**:*boolean*optional with default*false*; available from BJS V3.3; when true forms a closed curve.

*Curve3*.

Just use the Curve3 *getPoints()* method to fill your array : *getPoints()* returns an array of successive *Vector3*.

The *length()* method returns the curve length.

`const path = catmullRom.getPoints();const l = catmullRom.length();`

## Hermite Quaternion Spline

`BABYLON.Quaternion.Hermite(point0, tangent0, point1, tangent1, amount);`

allows the interpolation of quaternions for use in animation. As a quaternion is a 4D object how can you visualize the Hermite quaternion spline that the interpolation uses? By representing the hyperspline in 3D space.

This is achieved by mapping a rotation quaternion onto a 3D vector.

### The Math

What is needed if a function $f$ from rotation quaternions to 3D vectors of the form

$f(x, y, z, w) = (x_{v}, y_{v}, z_{v})$

For a rotation quaternion there are two things to note:

- $x^2 + y^2 + z^2 + w^2 = 1$
- $(x, y, z, w)$ and $(-x, -y, -z, -w)$ are equivalent.

The equivalence of $(x, y, z, w)$ and $(-x, -y, -z, -w)$ can be seen in the following

Equivalent Rotation QuaternionsIt follows that set of rotation quaternions $(x, y, z, w)$ where $x^2 + y^2 + z^2 + w^2 = 1$ and $-1 \leq x, y, z, \leq 1$ and $0 \leq w \leq 1$ covers all possible rotations.

$x^2 + y^2 + z^2 + w^2 = 1$ and so

$x^2 + y^2 + z^2 = 1 - w^2$ - Eq 1

Since $0 \leq w \leq 1$ then $0 < 1 \leq (1 + w) \leq 2$

Dividing Eq 1 by $(1 + w)^2$, which can never be $0$

$x^2 + y^2 + z^2 \over (1 + w)^2$ = $(1 - w^2) \over (1 + w)^2$ = $(1 - w) \over (1 + w)$

This gives the mapping

$f(x, y, z, w)$ = ($x \over (1 + w)$, $y\over (1 + w)$, $z\over (1 + w)$ )

Each rotation quaternion where $0 \leq w \leq 1$ is mapped onto one of a series of concentric spherical shells of radius, $r$,

$0 \leq r^2$ = $(1 - w) \over (1 + w)$ $\leq 1$.

The center of the shells represents the rotation quaternion $(0, 0, 0, 1)$, the outer, white ,, is a unit sphere where $w = 0$.

The process can be reversed, the inverse function $f^{-1}$ returns the rotation quaternion from a point $(x, y, z)$ from the shells.

Since the radius, r, of the sphere at $(x, y, z)$ is such that $r^2 = x^2 + y^2 + z^2$ and

$r^2$ = $(1 - w) \over (1 + w)$ then

$w$ = $(1 - r^2) \over (1 + r^2)$ and

$1 + w$ = $2 \over (1 + r^2)$ and

$f^{-1}(x, y, z)$ = ($2x \over (1 + r^2)$, $2y \over (1 + r^2)$, $2z \over (1 + r^2)$, $(1 - r^2) \over (1 + r^2)$)

### Drawing

The following function will return a Curve3 within a unit sphere representing a Hermite quaternion spline in 3D space using the math above.

`const hermiteQuarternionSpline = (p1, t1, p2, t2, nbPoints) => { const hermite = new Array(); const step = 1.0 / nbPoints; for (let i = 0; i <= nbPoints; i++) { const q = BABYLON.Quaternion.Hermite(p1, t1, p2, t2, i * step); q.normalize(); if (q.w < 0) { q.scaleInPlace(-1); } const v = new BABYLON.Vector3(q.x / (1 + q.w), q.y / (1 + q.w), q.z / (1 + q.w)); hermite.push(v); } return new BABYLON.Curve3(hermite);};`

**p1**:*Quaternion*the origin point,**t1**:*Quaternion*the origin tangent vector,**p2**:*Quaternion*the destination point,**t2**:*Quaternion*the destination tangent vector,**nbPoints**:*number*the wanted final curve number of points in the array.

**Warning**

Using BABYON.Quaternion.RotationAxis(axis, angle) to create any of p1, t1, p2, t2 does not produce the expected results. Other means of producing rotation quaternions other than a direct creation should also be checked to ensure the one produced is of the range required for the mapping to work.

To produce a vector on the outer , requires a rotation quaternion with $w = 0$

Take the rotation quaternion from

`new BABYLON.Quaternion(1, 1, 1, 0).normalize(); //giving (0.5774, 0.5774, 0.5774, 0) to 4 dp`

However using

`BABYON.Quaternion.RotationAxis(new BABYLON.Vector3(1, 1, 1), 0); // gives (0, 0, 0, 1)`

and whilst this may be an equivalent quaternion it places the vector at the center of the shells not on the outer ,.

**End Warning**

As it is difficult to visualize the spline from pure quaternions it would be useful if there was an editor to draw the representation of the spline in 3D space.

### A (Very) Basic Editor

Hermite Quaternion EditorThis playgound allows you to drag representatives of the start (green) and end (red) quaternions within the unit sphere in 3D space. The representation of the start and end quaternion tangents (purple) are attached to the respective start and end controls. The tangents may also be dragged around (invisible) sphere shells centered on the start and end controls. The shells, and hence radius, may be adjusted using the up and down arrow keys (or w and x) for the selected control. Whilst dragging or adjusting the radius the camera is detached. The camera will be attached whenever any dragging is ended or when using keys you can attach it by pressing the spacebar.

The representation of the spline in 3D space is drawn as you adjust the controls. To apply the Hermite quaternion spline created to the box click on the animate button.

## Custom Curve3 Object

You can also make your own Curve3 object from a simple array of successive Vector3.

Why would you do this and not just use the points to draw a line?

Because the *Curve3* object has a useful method, the *continue()* method, that allows you place the start of one *Curve3* onto the end of another *Curve3* without any calculations to match the start and end points of the curves.

### Example 1

Create an array of Vector3 along a simple sinus curve.

`const mySinus = [];for (let i = 0; i < 30; i++) { mySinus.push(new BABYLON.Vector3(i, Math.sin(i / 10), 0));}const mySinusCurve = new BABYLON.Curve3(mySinus);`

You would like to continue your *mySinus* curve with a *bezier3* curve and then join on a *bezier2*.

`const myFullCurve = mySinusCurve.continue(bezier3).continue(bezier2);`

The *continue()* method returns a new *Curve3* object and leaves *mySinusCurve3*, *bezier3* and *bezier2* unchanged.

If you then need to draw the curve or use it for whatever you want you just get the array of points with the *getPoints()* method. This method simply returns an array of successive *Vector3*.

`const path = myFullCurve.getPoints();const extruded = BABYLON.Mesh.ExtrudeShape("extrudedShape", shape, path, 1, 0, scene);`

If you need then to know the curve length, just use the * length()* method.

`const l = myFullCurve.length();`

### Example 2

Here is an example where a Hermite Spline is used to close smoothly a concatenation of two Bezier curves. As the spline is closing the curves the first and last points of the open continued curve need to be read from the array.

- The first and last points of the concatenation are used as last and first point of the Hermite spline.
- The first and last segments of the concatenation are used as last and first tangent vectors of the Hermite. Since these segments are quite small, they are scaled according to the concatenation
*length*so the longer the concatenation, the more curved the spline.

```
// two concatened cubic Bezierconst cubicA = BABYLON.Curve3.CreateCubicBezier(vA0, vA1, vA2, vA3, 50);const cubicB = BABYLON.Curve3.CreateCubicBezier(vB0, vB1, vB2, vB3, 50);const continued = cubicA.continue(cubicB);
// initial Hermite values from continued first and last segmentsconst t = continued.length() / 2; // tangent scale factorconst points = continued.getPoints();const p1 = points[points.length - 1]; // last continued point = first hermite pointconst t1 = p1.subtract(points[points.length - 2]).scale(t); // last segment scaled = hermite tangent t1const p2 = points[0]; // first continued point = last hermite pointconst t2 = points[1].subtract(p2).scale(t); // first segment scaled = hermite tangent t2
const hermite = BABYLON.Curve3.CreateHermiteSpline(p1, t1, p2, t2, 50);continued = continued.continue(hermite);
// finally drawing a smooth closed curveconst closedCurve = BABYLON.MeshBuilder.CreateLines("closed", { points: continued.getPoints() }, scene);
```

The orange and yellow curves are the original Bezier curves.

In light blue, these two curves are continued by each other and a hermite curve is also added in continuation to close the path.