Circular sector and arc


Heart chain with text is one of my hot things. (I also designed Text heart chain which can coil up hearts.)

There are two small rings between hearts. The rings don't overlap so you can print it in place. Before creating these hearts, what should you prepare for such a simple ring? Different people have different thoughts. As for me, it's better to define a module which can draw an arc according to given angles.

Sector

Before defining an arc module, it's better to have a module which can draw a sector. If the built-in circle module can provide an angles parameter, implementing this requirement will be easy. Unfortunately, OpenSCAD doesn't provide it, so it's time to do it yourself.

In Circle, we learned about that you can use triangles to construct a circle. Seriously speaking, this creates a regular polygon. When it comes to the polygon, we know that the built-in polygon module can create a multi-sided shape. If we can calculate every vertex's coordinate of the sector, the polygon module will be able to create a sector, right?

radius = 10;
angles = [45, 135];
points = [
    for(a = [angles[0]:1:angles[1]]) [radius * cos(a), radius * sin(a)]
];
polygon(concat([[0, 0]], points));

As you see, we are right. We draw a sector from 45 to 135 degrees.

Circular sector and arc

I have more to take into consideration. The sector module should provide a $fn parameter, maybe $fa and $fs as well, to be consistent with the circle module. Then, the users of the sector module can use angles to create a sector which looks like being cut from a circle with the given $fn. For example, we can use 0 and 135 degrees to cut a sector from a circle of $fn = 12.

Circular sector and arc

Do you see that? Because $fn is 12, the length of the leftmost side is smaller than others. I deliberately use $fn = 12 to highlight this condition. You can create a circle and difference the unwanted part to obtain the sector.

Circular sector and arc

According to the above idea, we may write a rough implementation.

radius = 20;
angles = [45, 135];
fn = 12;

module sector(radius, angles, fn = 24) {
    step = -360 / fn;

    points = concat([[0, 0]],
        [for(a = [angles[0] : step : angles[1] - 360]) 
            [radius * cos(a), radius * sin(a)]
        ],
        [[radius * cos(angles[1]), radius * sin(angles[1])]]
    );

    difference() {
        circle(radius, $fn = fn);
        #polygon(points);
    }
}

sector(radius, angles, fn);

But, the result is not what we want.

Circular sector and arc

Oh, no! The differenced part is not large enough to cover the edge of the circle. You can create a larger polygon to solve this problem, however, how large should it be? Twice the radius of the circle is surely enough. If you want to have fun with precision, let's do some calculations.

The figure below shows the worst case. One leg of the yellow triangle intersects the base of the red triangle at the middle.

Circular sector and arc

So, the polygon can cover the yellow circle if the radius of the red circle is r derived below.

a = 180 / fn;
r = radius / cos(a);

The modified version of the sector module is here.

radius = 20;
angles = [45, 135];
fn = 24;

module sector(radius, angles, fn = 24) {
    r = radius / cos(180 / fn);
    step = -360 / fn;

    points = concat([[0, 0]],
        [for(a = [angles[0] : step : angles[1] - 360]) 
            [r * cos(a), r * sin(a)]
        ],
        [[r * cos(angles[1]), r * sin(angles[1])]]
    );

    difference() {
        circle(radius, $fn = fn);
        polygon(points);
    }
}

sector(radius, angles, fn);  

We get a sector now.

Circular sector and arc

Arc

Once the sector module is ready, defining an arc module is easy. Just difference a smaller sector from a bigger sector.

radius = 20;
angles = [45, 290];
width = 2;
fn = 24;

module sector(radius, angles, fn = 24) {
    r = radius / cos(180 / fn);
    step = -360 / fn;

    points = concat([[0, 0]],
        [for(a = [angles[0] : step : angles[1] - 360]) 
            [r * cos(a), r * sin(a)]
        ],
        [[r * cos(angles[1]), r * sin(angles[1])]]
    );

    difference() {
        circle(radius, $fn = fn);
        polygon(points);
    }
}

module arc(radius, angles, width = 1, fn = 24) {
    difference() {
        sector(radius + width, angles, fn);
        sector(radius, angles, fn);
    }
} 

linear_extrude(1) arc(radius, angles, width);

We obtain an arc.

Circular sector and arc

Some of my things on Thingiverse needed sectors and arcs. The implementations of sector and arc in them are different from here. That is because they are my early works, some considerations were still immature when designing them.

Writing documents always gives me opportunities to think more about those things. Are there other considerations? Are there better designs?

Writing is not only about writing.