3D line


Some of my works, such as Character tower generator, Text Sphere or Spinning picture ornament, need spirals.

Character tower generator

Text Sphere

Spinning picture ornament

I will talk about how to design these models in the later documents. As for now, I'll talk about how to realize the spirals of these models. One of the solutions is using small and intensive cubes on the path of the spiral. Several of my works took this answer, but I'm not satisfied with it. I'm always looking for a better way to create these lines.

If we have a polyline3D module and calculate all points on the path of the spiral, the problem can be solved. However, how to create this polyline3D module?

A line from two points

In Line, I mentioned how to create a line on the x-y plane. We use two points to determine a line at that time. If we want to create a line in 3D space, the first task is also realizing a line from two points.

You might think that we use the built-in polygon module to realize the polyline module and there is also a built-in polyhedron module which can uses vertices to create any regular or irregular shape. Can it create a 3D line? It's possible, however, creating vertices for a 3D line is not easy. Is there an easy way?

Do you remember the hull operation mentioned in Boolean operations and hull? If you hull several modules, you create the outer covering for them. I listed an example at that time.

radius = 10;
hull() {
    circle(radius);
    translate([2 * radius, 0, 0]) 
        circle(radius);
}

The hull operation covers the two circles.

Boolean operations and hull

Think about it. If these two circles have a longer distant, the model will look like a line. We can assign the centers and use the circle's diameter as the line width. It is what I mentioned in Line. There are other ways to implement a line.

If it's not two circles but two spheres, and we hull them, what will happen? Sound like an easy way to realize a 3D line.

module line3D(p1, p2, thickness, fn = 24) {
    $fn = fn;

    hull() {
        translate(p1) sphere(thickness / 2);
        translate(p2) sphere(thickness / 2);
    }
}

line3D([1, 1, 1], [10, 10, 10], 1, 3);

Ya, we make it!

3D line

Because spheres consist of the line, we leave a fn parameter which represents the resolution of the line. The hull operation is slow, so a bigger fn takes more time to render a line.

polyline3D

Now, we have a line from two points. Similarly, you just take two points and draw a line sequentially until consuming all points.

module line3D(p1, p2, thickness, fn = 24) {
    $fn = fn;

    hull() {
        translate(p1) sphere(thickness / 2);
        translate(p2) sphere(thickness / 2);
    }
}

module polyline3D(points, thickness, fn) {
    module polyline3D_inner(points, index) {
        if(index < len(points)) {
            line3D(points[index - 1], points[index], thickness, fn);
            polyline3D_inner(points, index + 1);
        }
    }

    polyline3D_inner(points, 1);
}

points = [[1, 2, 3], [4, -5, -6], [-1, -3, -5], [0, 0, 0]];
polyline3D(points, 1, 3);

It seems pretty good.

3D line

Realizing a spiral

Here's an exercise. Try to implement the spiral in Character tower generator. The following code is one implementation.

module line3D(p1, p2, thickness, fn = 24) {
    $fn = fn;

    hull() {
        translate(p1) sphere(thickness / 2);
        translate(p2) sphere(thickness / 2);
    }
}

module polyline3D(points, thickness, fn) {
    module polyline3D_inner(points, index) {
        if(index < len(points)) {
            line3D(points[index - 1], points[index], thickness, fn);
            polyline3D_inner(points, index + 1);
        }
    }

    polyline3D_inner(points, 1);
}

r = 20;
h = 5;
fa = 15;
circles = 10;

points = [
    for(a = [0:fa:360 * circles]) 
        [r * cos(a), r * sin(a), h / (360 / fa) * (a / fa)]
];
polyline3D(points, 1, 3);

It creates the model below.

3D line

I'll explain more about the code in Text and cylinder.

One more exercise! Try to realize the spiral in Spinning picture ornament. The following code is one possible realization.

module line3D(p1, p2, thickness, fn = 24) {
    $fn = fn;

    hull() {
        translate(p1) sphere(thickness / 2);
        translate(p2) sphere(thickness / 2);
    }
}

module polyline3D(points, thickness, fn) {
    module polyline3D_inner(points, index) {
        if(index < len(points)) {
            line3D(points[index - 1], points[index], thickness, fn);
            polyline3D_inner(points, index + 1);
        }
    }

    polyline3D_inner(points, 1);
}

r = 50;
points = [
    for(a = [0:180]) 
        [r * cos(-90 + a) * cos(a), r * cos(-90 + a) * sin(a), r * sin(-90 + a)]
];

for(i = [0:7]) {
    rotate(45 * i) polyline3D(points, 2, 3);
}

The model is as follow.

3D line

I'll explain more about the code in Text and sphere.

Last words, isn't it a joy to solve a problem which always didn't have a satisfactory solution :)