# Text and sphere

You've known how to design Character tower generator. Would you like to challenge Text Sphere?

It's hard to print; however, some people still printed it beautifully. I used supports while printing and the make seem acceptable.

# Getting started basics

Wrapping text around a sphere requires more mathematics. Let's get started from basics. First, you have to rotate a list of cubes around the z-axis from 0 to 180 degrees.

``````radius = 40;
step_angle = 10;
length = 5;
for(a = [0:step_angle:180]) {
rotate([0, 0, a]) translate([radius, 0, 0])
cube([length, length, length], center = true);
}
``````

It's a very simple program. We create the model below. If the cubes rotate not only around the z-axis but also the y-axis, what will it be? For example, rotate -45 degrees around the y-axis at the same time.

``````radius = 40;
step_angle = 10;
length = 5;
for(a = [0:step_angle:180]) {
rotate([0, -45, a]) translate([radius, 0, 0])
cube([length, length, length], center = true);
}
``````

The arc now appears at the place where the vector is 45 degrees to the x-y plane. I add a transparent sphere to highlight this situation. You can try numbers other than 45, such as 30 or 60, to move the arc to the place where the vector is 30 or 60 degrees to the x-y plane respectively.

When rotating around the y-axis, if you increase angle from -90 to 90 degrees, the cubes will be wrapped around the sphere.

``````radius = 40;
step_angle = 10;
length = 5;
for(a = [0:step_angle:180]) {
rotate([0, -90 + a, a]) translate([radius, 0, 0])
cube([length, length, length], center = true);
}
`````` If the `step_angle` parameter has a smaller value, what will happen?

``````radius = 40;
step_angle = 0.25;
length = 5;
for(a = [0:step_angle:180]) {
rotate([0, -90 + a, a]) translate([radius, 0, 0])
cube([length, length, length], center = true);
}
``````

We have a spiral. Try to repeat the spiral eight times and rotate them around the z-axis 45, 90, 135, 180 and so on. You'll know how to create the spirals of Spinning picture ornament. As mentioned in 3D line, we have an elegant way to create these spirals. If you forget, review the document again.

# Wrapping text around a sphere

Now it's time to replace cubes by characters. The font size is set to 10 temporarily. Let's see how it looks.

``````radius = 40;
step_angle = 10;
font_size = 10;
thickness = 1;

for(a = [0:step_angle:180]) {
rotate([0, -90 + a, a]) translate([radius, 0, 0])
rotate([90, 0, 90])
linear_extrude(thickness)
text("A", size = font_size, valign = "center", halign = "center");
}
``````

Wow, we have characters around a sphere. But, it seems still different from Text sphere. One reason is that the characters drop too quickly. The other reason is that the characters only rotate 180 degrees around the z-axis. The characters of Text sphere turns many circles around the z-axis.

We can't only decrease the `step_angle` value because it only slows down the speed around the y-axis and the total degrees the characters rotate around the z-axis is still 180.

If the whole degrees around the z-axis remain 180 first and the degrees around the y-axis are from -90 to 90, what will it be? Umm, the characters stop on the x-y plane. That's because we only rotate 180 degrees around the z-axis. If we want to stop at the bottom of the sphere, we just have to increase 180 to 360 degrees. If we only increase 45, that's 180 / 4, from -90 degrees around the y-axis, we have to rotate 180 * 4 degrees around the z-axis to make the characters stop at the bottom of the sphere. You might have noticed that there's an inversely proportional relationship here so that we can write down the code below.

``````radius = 40;
step_angle = 10;
font_size = 10;
thickness = 1;

total_semi_circles = 15;

for(a = [0:step_angle:180 * total_semi_circles]) {
rotate([0, -90 + a / total_semi_circles, a]) translate([radius, 0, 0])
rotate([90, 0, 90])
linear_extrude(thickness)
text("A", size = font_size, valign = "center", halign = "center");
}
``````

Ya! A sphere wrapped by characters is out. You can change the `total_semi_circles` value. The bigger it is, the more intensive characters are. Text sphere has an open rim. We can adjust the initial value of `a` to decide its radius.

``````radius = 40;
step_angle = 10;
font_size = 10;
thickness = 1;

total_semi_circles = 15;
open_begin = 500;

for(a = [open_begin:step_angle:180 * total_semi_circles]) {
rotate([0, -90 + a / total_semi_circles, a]) translate([radius, 0, 0])
rotate([90, 0, 90])
linear_extrude(thickness)
text("A", size = font_size, valign = "center", halign = "center");
}
``````

The result is as below. You may choose suitable parameters until the characters have acceptable intensity. Then, you'll have your text sphere.

I can close this case here, and that's what I did for my work on Thingiverse. But, how to choose suitable parameters? Hmm, just try and error until the model looks good.

A good look here means that the characters don't overlap and the height between the upper layer and the lower layer is the size of a character. Moreover, we have an acceptable radius of the open rim. Isn't there a way to calculate these values automatically? In fact, there's a way to do that, but I was just too lazy to go further at that time :p

Let's try to realize the first requirement. We hope that the characters don't overlap. First, we should decide that how many characters a circle has and what the angle of the rim is. After that, we can calculate the circumference of the rim. Suppose `angle` has the relationship.

``````angle = 180 * open_begin_ratio;
``````

The circumference of the rim is `2 * PI * (radius * sin(angle))`. If each circle has `chars_per_circle` characters, the `font_size` has the relationship.

``````font_size = 2 * PI * radius * sin(angle) / chars_per_circle;
``````

The angle between two characters is:

``````step_angle = 360 / chars_per_circle;
``````

Now we have to decide the first value of `a`. Still remember the figure below? Suppose we want to start from 45 degrees. That is, we want `-90 + a / total_semi_circles = -45`, so `a / total_semi_circles = 45`. If we use `angle` to replace the value 45, we have `a / total_semi_circles = angle`, so `a = angle * total_semi_circles`. The first value of `a` is …

``````begin_angle = angle * total_semi_circles;
``````

How about the `total_semi_circles`? After rotating a circle, the character of the upper layer should be on the top of the character of the lower layer. So, the total layers are `2 * PI * radius / font_size`.

``````total_semi_circles = 2 * PI * radius / font_size;
``````

Based on the above, we can rewrite the code below.

``````radius = 40;
thickness = 1;
chars_per_circle = 20;
open_begin_ratio = 0.25;

angle = 180 * open_begin_ratio;
font_size = 2 * PI * radius * sin(angle) / chars_per_circle;
step_angle = 360 / chars_per_circle;
total_semi_circles = 2 * PI * radius / font_size;
begin_angle = angle * total_semi_circles;

for(a = [begin_angle:step_angle:180 * total_semi_circles]) {
rotate([0, -90 + a / total_semi_circles, a]) translate([radius, 0, 0])
rotate([90, 0, 90])
linear_extrude(thickness)
text("A", size = font_size, valign = "center", halign = "center");
} Now that, you just have to decide the values of `radius`, `thickness`, `chars_per_circle` and `open_begin_ratio`. Other required values will be calculated automatically. It's friendly for normal users.