Woven basket
In this article I would like to explain how I combined my passion for 2D vector graphics with 3D printing. The results are a circular but also a rounded, rectangular basket that not only look really good but can also be very useful. And because we develop all the formulas, we can customise them to any size, so they fit in any cupboard or drawer.
As in the post about the shape of the spice rack, I use Svelte and SVG again to build suitable basic shapes and then transfer the code to OpenSCAD.
Motivation»
The idea for baskets came about because there are quite a few utensils lying around in the mirror cabinet and they should be kept upright in a basket. We have ready-made baskets from a decoration shop at home for storing other small items. However, it’s not so easy to find a model that fits the shallow cupboard, so why not make one ourselves and 3D print it?
We don’t have to reinvent the wheel if there’s already something and indeed I stumbled over this Reddit post of Zoé Böle which points us to Thingiverse and her OpenSCAD model, from which I learnt a lot and basically derived the circular basket version from.
Circular shape»
I started with a circle as the base. My father-in-law, who was paralysed on one side after a stroke, had once woven circular baskets in occupational therapy. There were rods pointing upwards along the circle and then the stalks were placed around them. So they bulged alternately from the centre of the circle around the outside of one rod and then around the inside of the next rod. In the next level, stalks bulged the other way round.
So it is quite simple to change computeCirclePoint
into computeBulgedCirclePoint
to add inwards and outwards bulges. And while it would be possible to directly do this in OpenSCAD, it is much easier to do with Javasript, Svelte and SVG to have an immediate visual feedback.
import { nums, TAU } from "$lib/utils/math-utils";
import { point } from "$lib/utils/path-utils";
const computeCirclePoint = (radius, angle) => point(
radius * Math.cos(angle),
radius * Math.sin(angle)
);
const computeBulgedCirclePoint = (radius, angle, bulge, numOfRods) => point(
(radius - bulge * Math.cos(angle * numOfRods / 2)) * Math.cos(angle),
(radius - bulge * Math.cos(angle * numOfRods / 2)) * Math.sin(angle)
);
export const pointsAlongCircle = (radius, numberOfPoints, bulge, numOfRods) =>
nums(numberOfPoints).map(
i => computeBulgedCirclePoint(radius, i / numberOfPoints * TAU, bulge, numOfRods)
);
- And I can represent the rods just as easily (image 1).
- For a basket, every second level should run on the other side of the rods or mirrored. We achieve this by using a negative value for bulge (image 2).
- To print the strips, we need an inner and outer wall. All you have to do is increase or decrease the radius (image 3).
- And then you already have the finished top view of the basket (image 4).
Now we only have to extrude these 2D shapes in 3D space using OpenSCAD linear_extrude
function. First we build the basket skeleton with a base plate, top and bottom rings and the rods, then we add the weaved layers of our extruded bulged shape.
module weaved_layers(basket_radius, bulge, num_of_rods, thickness,
basket_height, num_of_layers = 0, epsilon = 0.1) {
num_of_layers = num_of_layers == 0
? round(basket_height / (2 * bulge))
: num_of_layers;
layer_thickness = basket_height / num_of_layers;
for (i = [0:(num_of_layers-1)])
translate([0, 0, i * layer_thickness])
linear_extrude(layer_thickness + epsilon)
bulged_shape(basket_radius, bulge, num_of_rods, thickness, i % 2 == 0);
}
The bulged shape is created using the points_along_circle
function converted from our Svelte/JS code. We subtract a smaller bulged polygon from a bigger one to get our polygon to extrude.
module bulged_shape(radius, bulge, num_of_rods, thickness, opposite = true) {
bulge = (opposite ? 1 : -1) * bulge;
point_list_outside = points_along_circle(radius + thickness/2, num_of_rods * 60, bulge, num_of_rods);
point_list_inside = points_along_circle(radius - thickness/2, num_of_rods * 60, bulge, num_of_rods);
difference() {
polygon(point_list_outside);
polygon(point_list_inside);
}
}
Here you see a couple of screenshots from OpenSCAD for illustration and a photo of the 3D printed result. I am quite satisfied with the result. In March I first printed the basket using my i3 Mega S all metal chinese 3D printer. I fought stringing and other problems, but although the result had stripes it looked quite okay because it matched the basket optic. But now, in October, I use my newish BambuLab A1 Mini and the result is just amazing.
Rectangular shape»
If we think back to the beginning, I actually wanted a rectangular shape, also to make the best use of the space in the cupboard. Of course, the basket should also have rounded corners. The internet didn’t have an immediate answer, so I developed a formula to calculate pointsAlongRoundedRect
.
export const pointsAlongRoundedRect = (
width, height, cornerRadius,
numberOfRods, numberBetweenRods,
bulge
) => [...];
I plan to release the Svelte/SVG as well as the OpenSCAD source in the future. Here I would like to concentrate on explaining the algorithm.
I divided the rounded rect into eight segments, four rounded corners and four straight edges.
To calculate the points equally distributed along the path, I need the perimeter of the rounded rectangle, i.e. the sum of the circle perimeter (using the corner radius) and the length of all four straight sides.
For each point, I know the normal vector perpendicular to the rounded rectangle path. I can therefore add a value of a sinusoidal curve to each point to get the bulged shape of the basket.
I then wrote the offsetPath
method, which calculates parallel curves. For that I again use the normal vector perpendicular to the given closed path to calculate another set of points in the distance specified by the offset parameter.
export const offsetPath =
(points, offset) => [...];
So I have everything I need in the same way as with the circular basket and I can draw exactly the same pictures for the rounded rectangular basket.
The steps to produce a 3D model in OpenSCAD are almost the same for the rectangular basket, so I share the same Screenshots and Photo you saw for the circular basket.
Interactive Svelte component»
All the 2D illustrations of this article are done using the same Svelte component. If you are keen to player with all the options on your own, you might want to have a look at this interactive demo.
OpenSource»
Update 2024/10: I refactored and open sourced the code, updated the post with better photos of the basket printed with the BambuLab A1 Mini.
I was intrigued by the idea to produce a lot of these baskets using my 3D printer and to sell them on platforms like Etsy, but instead I will share my code with the public domain.
You can find the Svelte as well as the OpenSCAD source in this GitHub Repository.
If you found this article helpful or you’ve take advantage or profit of my code, you are more than welcome to give me some feedback or pay a fair share eg. as paypal donation