Image Lathe

Let’s start with the good stuff first. Here is a 3D print of a new ShapeJS creator called the Image Lathe. This was printed at Shapeways in Black Glossy Ceramics for $25.

IMG_0631

The basic premise of the creator is to give the user 2 images to control creation of the object. The first image is the profile image. This describes the basic shape of the object. If your familiar with using a pottery wheel or a lathe then you know how this works. You take an outline and sweep it through a 360 degree path. This is great for making a bunch of common shapes like vases, bowls, cups, chess pieces etc. After you have the basic shape then we’ll use another image to make the surface pattern. This image is reflected several times to make an interesting final pattern.

Profile
The profile is created from an image that is rotated in space. This ShapeJS script takes an image and makes a shell out of it. So the 2D images on the left is turned into the 3D vase on the right.
profile
vase_profile

function makeShell(profilePath, width, height, voxelSize){
   var radius = width/2;
   var boxDepth = 2*Math.PI*radius;
   var boxWidth = radius;
   var boxHeight = height;

   var image = new ImageBitmap(profilePath, boxWidth, boxHeight, boxDepth, voxelSize);
   image.setBaseThickness(0.0);
   image.setUseGrayscale(false);
   image.setBlurWidth(2*voxelSize);

   var ct = new CompositeTransform();
   ct.add(new Rotation(0,1,0, -Math.PI/2));
   // align side of the image box with xy lane
   ct.add(new Translation(0, 0, -radius/2));
   ct.add(new RingWrap(radius));
   image.setTransform(ct);

   return image;
}

function main(arg){

   var voxelSize = 0.4*MM;
   var vaseWidth = 80*MM;
   var vaseHeight = 100*MM;
   var profilePath = arg[0];
   var padding = 2*MM;

   var gWidth = vaseWidth + 2*padding;
   var gHeight = vaseHeight + 2*padding;

   var shell = makeShell(profilePath, vaseWidth, vaseHeight, voxelSize);
   dest = createGrid(-gWidth/2,gWidth/2,-gHeight/2,gHeight/2,-gWidth/2,gWidth/2,voxelSize);

   var maker = new GridMaker();
   maker.setSource(shell);
   maker.makeGrid(dest);

   return dest;
}

Image Symmetry
The next step is to take a second image and use that to modify the profile geometry. Here we are going to use the symmetry engine of ShapeJS. This picture shows the setup for a symmetryOrder of 12. Your image is placed in a hall of mirrors. Here 12 planes of reflection are used. The reflection causes the image to invert and then tile. So you get 6 copies of the original + inverted image across the object. The volumetric space looks like pie slices from your image projected from a center point.

image_lathe_symmetry

We take this image from the user:
side_image2

And it generates this geometry using the symmetry engine:

vase_image_symmetry

Final Object

To make the final object we intersect the profile form with the image geometry. Everyplace the image geometry intersects the profile we get material.

vase

Here is the code for the final creator:

function getDihedralSymmetry( n){
   var a = PI/(n);
   var cosa = Math.cos(a);
   var sina = Math.sin(a);

   var symm = new ReflectionSymmetry();
   var splanes = new Array();
   var count = 0;
   splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(cosa,0,-sina),0);
   splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(-cosa,0, -sina), 0);

   symm.setGroup(splanes);

   return symm;
}

function makeShell(profilePath, width, height, voxelSize){
   var radius = width/2;
   var boxDepth = 2*Math.PI*radius;
   var boxWidth = radius;
   var boxHeight = height;

   var image = new ImageBitmap(profilePath, boxWidth, boxHeight, boxDepth, voxelSize);
   image.setBaseThickness(0.0);
   image.setUseGrayscale(false);
   image.setBlurWidth(2*voxelSize);

   var ct = new CompositeTransform();
   ct.add(new Rotation(0,1,0, -Math.PI/2));
   // align side of the image box with xy lane
   ct.add(new Translation(0, 0, -radius/2));
   ct.add(new RingWrap(radius));
   image.setTransform(ct);
   return image;
}

function main(arg){
   var voxelSize = 0.4*MM;
   var vaseWidth = 80*MM;
   var vaseHeight = 100*MM;
   var symmetryOrder = 12;

   var imgPath = arg[0];
   var profilePath = arg[1];

   var img = loadImage(imgPath);

   var imgBoxHeight = vaseHeight;
   var imgBoxWidth = img.getWidth() * imgBoxHeight /img.getHeight();
   var imgBoxThickness = vaseWidth/2;

   var image = new ImageBitmap(img, imgBoxWidth, imgBoxHeight, imgBoxThickness, voxelSize);

   image.setBaseThickness(0.0);
   image.setUseGrayscale(false);
   image.setBlurWidth(voxelSize);
   image.setImagePlace(ImageBitmap.IMAGE_PLACE_TOP);

   var padding = 2*MM;

   var gWidth = vaseWidth + 2*padding;
   var gHeight = vaseHeight + 2*padding;

   var ct = new CompositeTransform();
   ct.add(new Translation(0,0,-imgBoxThickness/2));
   ct.add(new RingWrap(vaseWidth/2));
   ct.add(getDihedralSymmetry(symmetryOrder));
   image.setTransform(ct);

   var shell = makeShell(profilePath, vaseWidth, vaseHeight, voxelSize);

   var intersection = new Intersection(image, shell);

   dest = createGrid(-gWidth/2,gWidth/2,-gHeight/2,gHeight/2,-gWidth/2,gWidth/2,voxelSize);

   var maker = new GridMaker();
   maker.setSource(intersection);

   maker.makeGrid(dest);

   meshSmoothingWidth = 2;
   meshErrorFactor = 0.05;

   return dest;
}
Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

One Response to Image Lathe

  1. professorrage says:

    Thank you for posting this example!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s