Text and cylinder


Character tower generator is one of my favorites.

Character tower generator

You may input text to generate a tower. The number of characters determines the height of the tower. The more you input, the higher it is. The text in the above picture comes from Top 20 Replies by Programmers When Their Programs Don’t Work.

Wrapping text around a cylinder

If you know how to wrap text around a circle, introduced in Text and circle, it's not hard to wrap text around a cylinder. The first of all is determining what parameters users can use. Maybe you provide radius and font_size, then calculate the number of characters of a circle automatically. You might also provide number_of_characters and font_size, and then calculate the circle radius. Calculating the font size from radius and number_of_characters is also considerable. All designs are ok. It's up to you or your target users.

If your target users are designers or developers, they may want all these versions. If they are normal users, they might be confused by too many options. As for me, I just want to verify my thoughts through modeling. I'm very casual about parameters, sometimes determined by future printing requirements. Well, it's designed by programming. You can modify the code if necessary, right?

Here, for simplification, the characters of a circle is a constant number 40, and the radius is 40mm because it's almost a pen holder's radius. Now that, if you want to wrap text around a circle, the angle between two characters is 360 / 40 = 9 degrees, and the font size of the character is 2 * PI * 40 / 40 = 2 * PI.

Of course, no magic number. It's clear if you write the code below.

chars = "3.141592653589793238462643383279502884197";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;

for(i = [0 : chars_per_circle - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, 0]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) text(
                chars[i], 
                font = "Courier New; Style = Bold", 
                size = char_size, 
                valign = "center", halign = "center"
            );
}

The model created is as below. :

Text and cylinder

Of course, the code only wraps text around a circle. Next, we have to move down each character a little. But what height should we move down for each character? Because we have 40 characters for each circle, we have to move down char_size / 40 for each character until consuming all characters.

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;
z_offset_per_char = char_size / 40;


for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) text(
                chars[i], 
                font = "Courier New; Style = Bold", 
                size = char_size, 
                valign = "center", halign = "center"
            );
}

We create the following model.

Text and cylinder

Adding a spiral

Yes, a disconnected character is not printable. We have to add a spiral to connect characters. As mentioned in 3D line, one of the solutions is using small and intensive cubes on the path of the spiral.

But, even it looks like a spiral, it still consists of cubes. The model will have too many facets so that rendering will take a long time, and the size of the exported file will be large.

Here, we take an economical way. We add a short line on the top of each character.

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
char_thickness = 1;
z_offset_per_char = char_size / 40;
line_thickness = char_size / 8;


for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) 
                  union() {
                    text(
                        chars[i], 
                        font = "Courier New; Style = Bold", 
                        size = char_size, 
                        valign = "center", halign = "center"
                    );
                    translate([0, char_size / 2, 0])
                        square([char_size, line_thickness], center = true);
                }
}

However, the result seems not okay.

Text and cylinder

There's a gap between two lines. It's not a problem. We just have to increase the line length. Here, for simplification, I just try and error to find a number 1.106 for scaling the length. It's enough for lines to touch each other.

But, we have another problem.

Text and cylinder

There's a drop between two lines. We have to tilt each line several degrees. If you don't want to try and error again, think about it. We've known the font size, the circumference, and the line width. They have the following relationship.

Text and cylinder

We can get the tangent value from the above figure, so the tilted angle is atan((font size + line width) / circumference).

chars = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481";

PI = 3.14159;
chars_per_circle = 40;
radius = 40;
step_angle = 360 / chars_per_circle;
circumference = 2 * PI * radius;
char_size = circumference / chars_per_circle;
z_offset_per_char = char_size / 40;
char_thickness = 1;
line_thickness = char_size / 8;
line_angle_offset = -atan((char_size - line_thickness)/circumference);

for(i = [0 : len(chars) - 1]) {
    rotate(i * step_angle) 
        translate([0, radius + char_size / 2, -z_offset_per_char * i]) 
            rotate([90, 0, 180]) linear_extrude(char_thickness) union() {
                text(
                    chars[i], 
                    font = "Courier New; Style = Bold", 
                    size = char_size, 
                    valign = "center", halign = "center"
                );
                rotate([0, 0, line_angle_offset]) translate([0, char_size / 2, 0])
                    square([char_size * 1.106, line_thickness], center = true);
            }
}

It looks smoother now.

Text and cylinder

What? The decimal point of 3.14159 is overhang! It's an exercise for you. Try to fix it. Making it a pen holder is also an exercise. If you want, try to align each face and character to decrease the complexity of the model.

You might remember the polyline3D module developed in 3D line. We used the module to create a spiral. That's also a way to add a spiral for you pen holder.