Introduction: Laser Cut 3D Math Lotus Drawing
Having access to a laser cutter in a Fablab, I wanted to give a try making a stacked laser cut sheet sculpture. I found much inspiration in the work of Gabriel Schama, but wanted something way simpler for a first attempt.
I have better skills for parametric drawing rather than hand-made illustration. Taking a programmatic approach, my tool of choice is OpenSCAD, which allows to combine 2D and 3D techniques, and to preview the final result.
In this Instructable I'd like to share how this lotus design has been created.
Design
- A central lotus shapes gives an oriental accent, surrounded by an intricate mesh.
- Each layer is basically constructed the same way.
- For 3d preview, the layers are stacked in OpenSCAD in the Z direction.
- Laser cutting requires vector files, so the OpenSCAD project is modified to place all plates side-by-side on the floor, allowing a single SVG file export.
- Finally the SVG export is post-processed in Inkscape in order to obtain individual vector files that can be sent to the laser cutter.
Costs
The costs go into the laser time; the materials costs are negligible in comparison. Laser times for the cutter I used, to give an order of magnitude, are:
- Size 40x40cm, 3mm MDF: 135 minutes (160m to cut).
- Size 20x20cm, 3mm MDF: 64 minutes.
- Size 20x20cm, 2mm cardboard: 38 minutes.
The pricing is 1$ per laser minute in our Fablab.
Step 1: Lotus - Basic Shape - Polar Formula
You can follow this link to see how to obtain a lotus shape, in polar coordinate. We'll apply these formulae below.
So in this first OpenSCAD step, we generate such a lotus shape by defining the lotus() module. We sweep the angle for a full circle (in degree). The radius r is given by a function of the angle a, defining the lotus shape. Then a and r, which are the polar coordinates, are converted back to Cartesian coordinates. In points(), the successive Cartesian points are stuffed in a list (by means of a so-called list comprehension), and in lotus() we create the 2D polygon.
Copy-paste the following into OpenSCAD:
K = 10; function r(a) = (1 + (((abs(cos(a*3)))+(0.25-(abs(cos(a*3+90))))*2) / (2+abs(cos(a*6+90))*8)) ) * 0.7; function fx(a) = cos(a) * r(a) * K; function fy(a) = sin(a) * r(a) * K; function points() = [for(a=[0:360]) [fx(a), fy(a)]]; module lotus() { polygon(points()); } lotus();
Step 2: Lotus - More Shapes
Now we add some more lotus shapes, by making lotus() take one parameter n, which will select one of four radius functions.
Using linear_extrude(), we turn the 2D lotus polygon into a 3D shape.
In addition, we color and translate each lotus so that they are distinguishable.
K = 10; function r1(a) = (1 + (((abs(cos(a*3)))+(0.25-(abs(cos(a*3+90))))*2) / (2+abs(cos(a*6+90))*8)) ) * 0.7; function r2(a) = (2 + (((abs(cos(a*3)))+(0.25-(abs(cos(a*3+90))))*2) / (2+abs(cos(a*6+90))*8)) ) *0.6; function r3(a) = (3 + (((abs(cos(a*6)))+(0.25-(abs(cos(a*6+90))))*2) / (2+abs(cos(a*12+90))*8)) ) * 0.6; function r4(a) = (3 + (((abs(cos(a*6)))+(0.25-(abs(cos(a*6+90))))*2) / (2+abs(cos(a*12+90))*8)) ) * 0.8; function r0(a, n) = n==1 ? r1(a) : n==2 ? r2(a) : n==3 ? r3(a) : r4(a); function fx(a, n) = cos(a) * r0(a, n) * K; function fy(a, n) = sin(a) * r0(a, n) * K; function points(n) = [for(a=[0:360]) [fx(a, n), fy(a, n)]]; module lotus(n) { linear_extrude(1) polygon(points(n)); } lotus(1); color("blue") translate([0, 0, -1]) lotus(2); color("red") translate([0, 0, -2]) lotus(3); color("green") translate([0, 0, -3]) lotus(4);
Step 3: Mesh
Now let's work on the mesh pattern. We start with a simple straight grid, consisting of segments.
Each segment is directly created as 3D shape in segment(), with two small cylinders, one for each end, connected together using hull().
D = 90; THICKNESS = 1; /* * Generate a segment */ module segment(x1, y1, x2, y2) { hull() { translate([x1, y1, 0]) cylinder(d=THICKNESS); translate([x2, y2, 0]) cylinder(d=THICKNESS); } } /* * Generate mesh */ module mesh() { space = 20; step = 5; // X mesh lines for (y=[-D:space:D]) { for (x=[-D:step:D-step]) { segment(x, y, x+step, y); } } // Y mesh lines for (y=[-D:space:D]) { for (x=[-D:step:D-step]) { segment(y, x, y, x+step); } } } mesh();
Step 4: Mesh - Distortion
To make it less boring, let's distort the mesh by a radial and angular distortion. To this end, polar coordinates are yet again used.
D = 90; THICKNESS = 1; /* * Generate a segment */ module seg(x1, y1, x2, y2) { hull() { translate([x1, y1, 0]) cylinder(d=THICKNESS); translate([x2, y2, 0]) cylinder(d=THICKNESS); } } // Mesh: cartesian -> polar -> distortion -> cartesian function aa(x, y, r) = atan2(y, x); function rr(x, y) = sqrt(x*x + y*y) / 1.7 * pow(1-1/110, 2); function xx(x, y) = let(r=rr(x, y), a=aa(x, y, r)) fr(r, a)*cos(fa(r, a)); function yy(x, y) = let(r=rr(x, y), a=aa(x, y, r)) fr(r, a)*sin(fa(r, a)); // Mesh distortion function fr(r, a) = r; function fa(r, a) = a + r*r/50; /* * Generate distorted mesh */ module mesh() { space = 20; step = 5; // X mesh lines for (y=[-D:space:D]) { for (x=[-D:step:D-step]) { x0 = x; y0 = y; x1 = x+step; y1 = y; seg(xx(x, y), yy(x, y), xx(x+step, y), yy(x+step, y)); } } // Y mesh lines for (y=[-D:space:D]) { for (x=[-D:step:D-step]) { x0 = x; y0 = y; x1 = x+step; y1 = y; seg(xx(y, x), yy(y, x), xx(y, x+step), yy(y, x+step)); } } } mesh();
Step 5: Mesh - Symmetry
To make it symmetric and intricate, we superimpose an additional mesh, which is distorted in opposite direction.
The source file keeps on growing! if you are still following the details, please visit the source page on Github: 05-mesh-shape.scad.
Step 6: Mesh - Clipping and Border
Let's trim the mesh by clipping and eliminating the irregular border, and add a thin frame.
The magic value 1.7 was adjusted to zoom the mesh as desired and obtain these kind of drops exactly in each corner.
See 06-mesh-shape.scad.
Step 7: Layer - Combining Lotus and Mesh
Time to combine the lotus and mesh patterns.
The source file is now considerably growing. See 07-layer.scad.
In summary, the following features are added to a given plate:
- Vary the mesh lines thickness and add them a slight displacement according to the plate index,
- bore the mesh with a lotus shape,
- add a lotus border, which can be thin or thick, so as to match the size of the lotus of the next plate,
- translate the plate in the z direction, to simulate their physical stacking.
Step 8: Stacking All Layers
Now we generate the seven plates, color them, and stack them on one another.
We obtain a fairly realistic representation of the final object.
- Only the OpenSCAD preview mode preserves the colors, but requires tremendous CPU power.
- To inspect the model more smoothly, you can render it (which takes a long time), but then the colors are not preserved. The whole object can now be zoomed and rotated very smoothly.
- See 08-all.scad.
By slightly modifying the code, we obtain a cross-cut to get an idea of how the layers overlap.
- We add some vertical offset to the layers to separate them.
- We substract a cube in order to obtain a cross-cut.
- See 08-all-cut.scad.
The design may be fine-tuned at will in order to get the desired effects and proportions.
Final OpenSCAD file: lotus.scad.
Step 9: Generating an SVG Projection
Now that we have the final 3D model, it is time to go back into 2D and generate the vector files.
To this end, we want to have a 2D projection of the plates that we can export as SVG vector file.
First, we modify the source file so that the plates are no longer stacked vertically, but laid flat in a line on the floor.
- See lotus-projection.scad.
- On line 211, notice the statement projection(cut=true). It affects the statements following it, and transforms the 3D plate object into a 2D cross-section.
- On line 212, the statement translate() lines up the plates in one row on the floow.
Then, we render the project. This can take hours, to days.
And finally, the whole result being a bunch of 2D objects, we can properly export it as SVG (File > Export > Export as SVG). See lotus-projection.svg.
Step 10: Generating the Final SVG Files
Now we have a single SVG file containing all plates in a line.
This is not yet good for cutting:
- We need some scaling to get the desired size.
- Depending on the desired plate size and the size of available sheets, we may need to group them possibly without gap, e.g. 2-by-2, or on the contrary, have one individual plate per material sheet.
So at this point I chose to perform the operations manually, always starting from the initial exported SVG file. As we only have 7 plates, this is an acceptable approach.
Tips:
- To generate distinct SVG files, I duplicated the one exported SVG as many times as required, and, in each copy, deleted vertices so as to keep just the desired plate(s).
- To scale a plate to desired final size, I selected it and entered the W and H values numerically with the desired measurement unit.
- To align multiple plates, I selected each one and positioned it by entering the X and Y values numerically.
- To use the leftover lotus shapes for some future ornament project, I added a tiny circle in the center, as a handy marker.
You can find the final SVG files attached as ZIP archives to this step. All project files can be found on the Github project.
Step 11: Laser Cutting, Paint Job, and Frame Assembly
Now having all the SVG files for cutting, and assuming you have access to laser cutting service, or cutter (with necessary operation knowledge), I won't cover the cutting process in detail.
If using wood-based materials (MDF or plywood) I strongly advise to apply one first layer of primer.
After spraying each plate with desired color, I built a wooden frame, oiled its outer sides, and assembled the whole, by applying epoxy glue on the plates' edges touching the inner sides of the frame.
Step 12: Final Product
Et voilà!
Wow effect guaranteed.