ShapeJS Developer Tutorials

Primitives

There are a number of simple shapes, also known as primitives, available in ShapeJS through simple, built in, functions. The shapes are generally the basis for more complex shapes, as we will learn in the booleans tutorial. This tutorial will explore the various ways of creating basic shapes within ShapeJS.

1. Vectors

While not shapes themselves, you will need to be familiar with vectors in order to certain shapes. Vectors are simply defined by three numbers which are its X, Y, and Z location in space, as defined by distance from the origin. Here is an example vector:

var vector = new Vector3d(5*MM, 5*MM, 5*MM);

2. Sphere

The sphere requires only one variable to define, a radius.

function main(args) {
  var radius = 20 * MM;
  var sphere = new Sphere(radius);
  var s = 20*MM;
  return new Scene(sphere, new Bounds(-s,s,-s,s,-s,s));
}

That was simple enough, but what if you do not want the sphere right at the origin? In that case, you can try adding a center to the sphere by putting in a new center, by changing the function to either Sphere(vector, radius) or Sphere(X center, Y center, Z center, radius). This will allow you to relocate the sphere wherever you want in 3D space. Try the example below.

function main(args) {
    var radius = 9*MM;
    var center = new Vector3d(5*MM, 5*MM, 5*MM);
    var sphere = new Sphere(center, radius);
    var s = 15*MM;
    return new Scene(sphere,new Bounds(-s,s,-s,s,-s,s));
}

(Note: The Bounds size was also increased. Since we moved the sphere away from the center of the Bounds it would have been cut off.)

3. Box

Let's try a similar technique to that last one for the sphere in order to create a box.

function main(args) {
    var box = new Box(0, 1*MM, 2*MM, 10*MM, 8*MM, 6*MM);
    var s = 10*MM;
    return new Scene(box, new Bounds(-s,s,-s,s,-s,s));
}

Here, rather than create a vector, we simply put in the center of X, Y, and Z as the first three variables. If that seems hard to keep track of, we can separate out the variables into a clearer format.

function main(args) {
    var box_xcenter = 0;
    var box_ycenter = 1*MM;
    var box_zcenter = 2*MM;
    var box_xsize = 10*MM;
    var box_ysize = 8*MM;
    var box_zsize = 6*MM;
    var box = new Box(box_xcenter,box_ycenter,box_zcenter,box_xsize,box_ysize,box_zsize);
    var s = 10*MM;
    return new Scene(box, new Bounds(-s,s,-s,s,-s,s));
}

Now we know exactly what each variable is doing, and can adjust them if need be. You will especially want to do this if you have multiple data sources using the same variable, as it will allow you to update all of them with a single value change.

4. Cylinder

To create a cylinder, we will need a couple of vectors. They define the center point of the top and the bottom of the cylinder, and then the radius defining how thick it is. One of the nice things about this method is that the use of vectors means that you can rotate the data source without having to use the Rotate function (which we will cover in the next tutorial).

function main(args) {
    var top = new Vector3d(-2*MM,-2*MM,4*MM);
    var bottom = new Vector3d(2*MM,2*MM,-4*MM);
    var radius = 5*MM;
    var cylinder = new Cylinder(top, bottom, radius);
    var s = 10*MM;
    return new Scene(cylinder, new Bounds(-s,s,-s,s,-s,s));
}

This shape also highlights how important it is to check what kind of variables these functions want. If we put in doubles where it was expecting vectors, we would get an error.

5. Cone

Cones are more complicated to work with, because they are defined by an apex, but not an endpoint. Instead, they extend infinitely along an axis which, like the apex, is defined by a vector. Simply putting one into a scene will result in it being cut off, as below.

function main(args) {
    var apex = new Vector3d(0*MM, 5*MM, 0*MM);
    var axis = new Vector3d(0*MM, -1*MM, 0*MM); // extend in -Y direction
    var angle = Math.PI/6;
    var cone = new Cone(apex, axis, angle);
    var s = 10*MM;
    return new Scene(cone, new Bounds(-s,s,-s,s,-s,s));
}

This shape also highlights how important it is to check what kind of variables these functions want. If we put in doubles where it was expecting vectors, we would get an error.

6. Plane

Likewise, the plane is more complicated to use than some of the other primitives. Essentially, it takes a location and direction, and is generated on that location, facing in the direction. It extends to infinity in all other directions.

While slightly harder to implement, the plane is very helpful in modeling shapes beyond this set of primitives. Like the cone, it extends infinitely (hence the red edges you can see). It has a number of alternative methods of generation, including simply listing three points on its surface.

function main(args) {
    var normal = new Vector3d(0*MM,-1*MM,-*MM);
    var point = new Vector3d(0*MM,0*MM,-0*MM);
    var plane = new Plane(normal, point);
    var s = 10*MM;
    return new Scene(plane, new Bounds(-s,s,-s,s,-s,s));
}

7. Torus

A torus is a donut shape. There are two radii that need to be determined, the first is the size of the ring itself, the second is how thick the ring is. You can choose to define or not define a center for it. If you choose not to, as with most other shapes, it will be centered at the origin. Toruses are always created facing along the Z axis.

function main(args) {
    var center = new Vector3d(-2*MM,1*MM,1*MM);
    var rOutter = 5*MM;
    var rInner = 2*MM;
    var torus = new Torus(center, rOutter, rInner);
    var s = 10*MM;
    return new Scene(torus, new Bounds(-s,s,-s,s,-s,s));
}

We will start off the next tutorial with a torus, and then do terrible things to it.