for developers
Sign In
Join
Discussions
Documentation
Tutorials
Examples
Editor
Scene
Import Scene
Export Scene
Load Last Scene
Save Current Scene
Model
Save Model
Upload Model
Show Printability
Render
Preferences
Help
Reference Guide
Examples
Tutorials
Generate
Save Model
Reset Params
Check Model
// // Ornament example using polyhedra reflection // // // author Vladimir Bulatov // author Alan Hudson // var uiParams = [ { name: "image", desc: "Image", type: "uri", defaultVal: "https:\/\/static1.sw-cdn.net\/files\/cms\/shapejs\/images\/icosa_sphere_part_thin20.png" }, { name: "xcoff", desc: "xcoff", type: "double", "rangeMin": -1, "rangeMax": 2, "step": 0.05, defaultVal: 1, onChange: "transformChanged" }, { name: "ycoff", desc: "ycoff", type: "double", "rangeMin": -1, "rangeMax": 2, "step": 0.05, defaultVal: 1, onChange: "transformChanged" }, { name: "zrot", desc: "zrot", type: "double", "rangeMin": -180, "rangeMax": 180, "step": 0.05, defaultVal: 0, onChange: "transformChanged" }, { name: "text", desc: "Text", type: "string", defaultVal:"Shapeways", onChange: "textChanged" } ]; var vs = 0.15*MM; var thickness = 1.3*MM; // last version was 1.1 up a bit for more strength var radius = 76.2*MM / 2 - thickness / 2; var rimHeight = 8*MM; var bailPadRadius = 7*MM; var bailHoleSize = 5.5*MM; var bailThickness = thickness*1.6; var TAU = (Math.sqrt(5)+1)/2; // golden ratio var PI = Math.PI; var TORAD = PI/180; var embossText = true; var imgTrans; var imgBox; var scene; var textBox; var text2d; 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 getImageReflection(xsize, ysize){ var splanes = new Array(); var count = 0; splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(-1,0,0), xsize); splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(0,-1,0), ysize); splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(1,0,0), xsize); splanes[count++] = new ReflectionSymmetry.getPlane(new Vector3d(0,1,0), ysize); return new ReflectionSymmetry(splanes); } 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.11; // correction to get var ypnt = v3.y*correction; var xpnt = v5.x*correction; var image = loadImage(path); var grid = image.getGrid(); var threshold = 0.5; var filled = getPercentFilled(grid,threshold); var thick = thickness; if (filled < 0.20) { // thicken by 20% for thin structures thick = 1.4 * thickness; } imgBox = new Image3D(grid, xpnt, ypnt, thick,0.1*MM); imgBox.setUseGrayscale(false); imgBox.setImagePlace(Image3D.IMAGE_PLACE_TOP); imgBox.setBaseThickness(0.0); imgBox.setBaseThreshold(threshold); imgBox.setBlurWidth(0.1*MM); union.add(imgBox); union.setTransform(getSphereBend(v5.x, radius - v5.z, v5.z)); return union; } /** * Analyse an image for structural issues. Change thickness based on how sparse the image is * * @param image * @return The */ function getPercentFilled(grid,threshold) { var w = grid.getWidth(); var h = grid.getHeight(); var filled = 0; var threshatt = 65636 /2 ; // not sure on this logic. for(var y=0; y < h; y++) { for (var x = 0; x < w; x++) { var att = grid.getAttribute(x,y); if (att < threshatt) { filled++; } } } return filled / (w * h); } // Create a safe attachment point by intersection sphere and cylinder. Then attach torus as bail function getBail(sphereRadius, cylinderRadius, thickness, torusInner, bailThickness) { // Create attachment patch var sphere = new Sphere(sphereRadius + thickness / 3); var cylinder = new Cylinder(new Vector3d(0,sphereRadius + thickness,0), new Vector3d(0,sphereRadius - 1.25 * thickness,0), cylinderRadius); var patch = new Intersection(sphere,cylinder); patch.setTransform(new Translation(0,thickness / 2,0)); var x0 = 0; var y0 = sphereRadius; var z0 = 0; // Create bail var R = torusInner/2 + bailThickness/2; var r = bailThickness/2; var torus = new Torus(x0,y0+torusInner/2,z0,R,r); var s = 2*R; var plane = new Plane(new Vector3d(0,1,0), new Vector3d(x0,y0-r,z0)); var subtract = new Subtraction(torus,plane); /* if(rotateBail) torus.setTransform(new Rotation(Vector3d(0,1,0),Math.PI/2)); */ var bail = new Union(patch, subtract); bail.setBlend(0.2*MM); //var bail = new Union(patch, torus); return bail; } function transformChanged(args) { 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 correction = 1.1; // correction to get var ypnt = v3.y*correction; var xpnt = v5.x; imgTrans = new CompositeTransform(); imgTrans.add(getImageReflection(xpnt/2, ypnt/2)); imgTrans.add(new Rotation(0,0,1,args.zrot*TORAD)); imgTrans.add(new Translation(args.xcoff*xpnt/2,args.ycoff*ypnt/2,v5.z)); imgBox.setTransform(imgTrans); } function makeDefaultScene() { var dr = 5 * MM; var src = new Box(dr, dr, dr); var bounds = new Bounds(-dr, dr, -dr, dr, -dr, dr); scene = new Scene(src, bounds); var ef = 0.1; scene.setVoxelSize(vs); scene.setMeshErrorFactor(ef); scene.setMaxPartsCount(1); return scene; } function getRim(loc,sphereRadius,height,thickness) { var overlap = 0.25 * MM; overlap=vs; 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+overlap,0), new Vector3d(0,loc-height-overlap,0), sphereRadius - thickness / 2); var rim = new Subtraction(outer,inner); rim.setBlend(0.1*MM); return rim; } function getText(text,loc,sphereRadius,rimHeight,height,thickness,embossed) { var tby = height; var tbx = (sphereRadius + 2 * thickness) * 2 * Math.PI; // text2d.getPreferredWidth(); var tbz = thickness; text2d = new Text2D(text); text2d.setFontName("HelveticaRounded LT Std Bd"); text2d.setFontStyle(Text2D.BOLD); var spacing = 0*MM; text2d.set("spacing", spacing); // additional spacing between characters var tvs = 0.05*MM; // text voxel size text2d.setInset(2*tvs); text2d.setVoxelSize(tvs); text2d.setFit("vertical"); // vertical, horizontal, both text2d.setHorizAlign("CENTER"); // left, right, center text2d.setHeight(tby); text2d.setWidth(tbx); textBox = new Image3D(text2d.getImage(), tbx, tby, tbz,0.1*MM); textBox.setUseGrayscale(true); textBox.setImagePlace(Image3D.IMAGE_PLACE_TOP); textBox.setBaseThickness(0.0); textBox.setBaseThreshold(0.1); //textBox.setBlurWidth(0.1*MM); var trans = new CompositeTransform(); //trans.add(new Rotation(0,1,0, 0)); trans.add(new Translation(new Vector3d(0,loc-rimHeight/2,0))); if (embossed) { trans.add(new RingWrap(sphereRadius + thickness)); } else { trans.add(new RingWrap(sphereRadius)); } textBox.setTransform(trans); return textBox; } function textChanged(args) { text2d.setText(args.text); textBox.setImage(text2d.getImage()); scene.setName(args.text+"_"+embossText); } // 150 stroke = 4mm function main(args) { scene = makeDefaultScene(); var path = args.image; if (path === undefined) return scene; var a = radius + thickness + 2 * bailHoleSize + vs; var image = getImage(radius, thickness, path); transformChanged(args); var reflectedImage = new Union(); reflectedImage.add(image); reflectedImage.setTransform(getIcosahedralSymmetry()); var rim_loc = -radius / 1.2; var rim_radius = radius / 1.84; var rim_height = rimHeight; var clip = new Plane(new Vector3d(0, 1, 0), new Vector3d(0, rim_loc, 0)); var qsphere = new Subtraction(reflectedImage, clip); var rim_geom = getRim(rim_loc, rim_radius, rim_height, thickness * 1.2); var bail = getBail(radius, bailPadRadius, thickness, bailHoleSize, bailThickness); var object = new Union(); object.add(qsphere); object.add(rim_geom); if (embossText) { var up_text = getText(args.text, rim_loc, rim_radius, rim_height, rim_height * 0.8, 1.5 * MM,true); object.add(up_text); } object.add(bail); object.setBlend(0.25 * MM); if (!embossText) { var through_text = getText(args.text, rim_loc, rim_radius, rim_height, rim_height * 0.8, 3 * MM,false); object = new Subtraction(object, through_text); } scene.setSource(object); scene.setBounds(new Bounds(-a,a,-a,a,-a,a)); return scene; }
Preferences
Close
Printability Check
Region check
Voxel size
Number of regions
Largest region
Close