Spherical Soap Dish Maker Tutorial

Discussion in 'ShapeJS' started by AlanHudson, Nov 28, 2013.

  1. AlanHudson
    AlanHudson Shapeways Employee Dev Team
    Got my first ceramics project back and my wife the potter is jealous. Seems 3D printing ceramics is easier to learn then throwing on a wheel :)

    Rectangular Base:
    https://www.shapeways.com/model/1475631

    Circular Base:
    https://www.shapeways.com/model/1475676

    I've included the ShapeJS scripts to make these objects yourselves. Paste the Javascript into https://shapejs.shapeways.com, add a File parameter. Make sure it contains no other parameters. The attached soap_dish_squiggle_150pnt.png was used to make these dishes.

    This example uses ImageBitmap to convert an image into voxels. It then uses getIcosahedralSymmetry and a Sphere bend to make a sphere were your image is reflected 120 times around the sphere. For this object we only want part of the sphere so we Subtract a Plane from the sphere. We then add a rim to object. This rim makes the transition from the user image to edge of the object always be solid. The function getRim() works by subtracting a larger Cylinder by a smaller one. The final part is to add a foot for stability. The foot in this example is a rectangular base created by subtracting a larger Box by a smaller one.

    In order to meet the minimum wall thickness of 4mm for this object you'll need to have your image use about 150 stroke width lines on an image that is 1600 x 1000 pixels. Only the left corner of the image is used, ie draw a line from the upper left corner to the lower right corner and the part of the left is what is mapped onto the sphere.

    ----
    //
    // Soap Dish example using polyhedra reflection
    //
    // author Alan Hudson
    // author Vladimir Bulatov
    //
    var TAU = (Math.sqrt(5)+1)/2; // golden ratio
    var PI = Math.PI;

    // Returns plane via 3 points (v1, 0, v2)
    // external normal points in the direction from where points are ordered counter clockwise
    function getPlane(v1,v2){
    var n = new Vector3d();
    n.cross(v2,v1);
    n.normalize();
    return ReflectionSymmetry.getPlane(n, 0);
    }

    function getIcosahedralSymmetry( ){
    var v5 = new Vector3d(1,0,TAU); // vertex of icosahedron
    var v3 = new Vector3d(0,1/TAU,TAU); // vertex of dodecahedron
    var p35 = new Vector3d(); // normal to plane via (0, v3, v5)

    p35.cross(v3, v5);
    p35.normalize();

    var splanes = new Array();
    var count = 0;
    splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(-1,0,0), 0.0);
    splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(0,-1,0), 0.0);
    splanes[count++] = new ReflectionSymmetry.getPlane(p35, 0.0);

    return new ReflectionSymmetry(splanes);
    }

    function getSphereBend(fixedRadius, bendAmount, offset){

    var center = fixedRadius*fixedRadius/bendAmount;
    var radius = Math.sqrt(center*center + fixedRadius*fixedRadius);

    var cp = new CompositeTransform();
    cp.add(new PlaneReflection(new Vector3d(0,0,1), new Vector3d(0,0,offset)));
    cp.add(new SphereInversion(new Vector3d(0,0,-center + offset), radius));
    return cp;
    }

    function getImage(radius, thickness, path){

    var s = radius/Math.sqrt(1 + 1.0/(TAU*TAU));
    var v5 = new Vector3d(s/TAU,0,s); // vertex of icosahedron
    var v3 = new Vector3d(0,s/(TAU*TAU),s); // vertex of dodecahedron

    var union = new Union();

    var correction = 1.1; // correction to get
    var ypnt = v3.y*correction;
    var xpnt = v5.x;
    var image = new ImageBitmap(path, xpnt, ypnt, thickness);
    var vs = 0.1*MM;
    image.setBaseThickness(0);
    image.setVoxelSize(vs);
    image.setUseGrayscale(false);
    image.setBlurWidth(vs);
    image.setTransform(new Translation(xpnt/2,ypnt/2,v5.z));

    union.add(image);

    union.setTransform(getSphereBend(v5.x, radius - v5.z, v5.z));

    var dt = new DataTransformer();
    dt.setSource(union);
    return dt;
    }

    // Create a rim around the bowl
    function getRim(loc,sphereRadius,height,thickness) {
    var outer = new Cylinder(new Vector3d(0,loc,0), new Vector3d(0,loc-height,0), sphereRadius + thickness / 2);
    var inner = new Cylinder(new Vector3d(0,loc,0), new Vector3d(0,loc-height,0), sphereRadius - thickness / 2);
    var rim = new Subtraction(outer,inner);

    return rim;
    }

    // Create a foot for stability
    function getFoot(loc,sphereRadius,aspect,height,thickness) {
    var outer = new Box(0,loc,0, aspect * sphereRadius + thickness,height,sphereRadius + thickness);
    var inner = new Box(0,loc,0, aspect * sphereRadius - thickness,height,sphereRadius - thickness);
    var foot = new Subtraction(outer,inner);

    return foot;
    }

    // 150 stroke = 4mm
    function main(args){

    var path = args[0];

    var thickness = 4.1*MM;
    var radius = 77.5*MM - thickness / 2;
    var voxelSize = 0.3*MM; // .6 is a good draft
    var rimHeight = 4*MM;
    var footHeight = 5.5*MM;
    var footThickness = 4.1*MM;
    var footRatio = 0.5;
    var footAspect = 1.3;


    var a = radius + 2*thickness + footHeight / 2;

    var image = getImage(radius,thickness, path);

    var reflectedImage = new Union();

    reflectedImage.add(image);
    reflectedImage.setTransform(getIcosahedralSymmetry( ));

    var cut_loc = -radius / 1.5;
    var plane = new Plane(new Vector3d(0,-1,0), new Vector3d(0,cut_loc,0));
    var bowl = new Subtraction(reflectedImage, plane);
    var rim_loc = cut_loc + rimHeight;
    var rim_radius = radius * 0.75;
    var rim = getRim(rim_loc,rim_radius,rimHeight,thickness);
    var foot_loc = -radius + footHeight*MM;
    var foot = getFoot(foot_loc, radius * footRatio, footAspect, footHeight, footThickness);
    var combined = new Union(bowl,rim);
    combined.add(foot);
    var maker = new GridMaker();

    maker.setSource(combined);

    var dest = createGrid(-a,a,-a,a,-a,a,voxelSize);

    maker.makeGrid(dest);

    return dest;
    }
     

    Attached Files:

  2. sandyr
    sandyr Member
    Very cool! love the output.
    It would be cool to create a place in the Tutorials section for stuff like this...AND to let the community update them...i.e. wiki-like or someway of adding more info, like illustrations that the community could create to help build up more of the Tutorials...Sandy
     
  3. AlanHudson
    AlanHudson Shapeways Employee Dev Team
    We'll definitely make a tutorials section for these.

    As to a wiki I'll have to ask around. Not sure we have any wiki software deployed currently at Shapeways.