Last active
January 6, 2025 19:23
-
-
Save GeekAndDad/121caef1462ff591802bbb4cc0b47e58 to your computer and use it in GitHub Desktop.
An answer to "distribute 3 circles evenly inside another" for OpenSCAD for Pete.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For Pete | |
// v3.0.2 | |
// by @GeekAndDad | |
// Define the outer circle radius and desired inner circle radius | |
outer_circle_radius = 100; | |
desired_inner_radius = 20; | |
// Call our function to calulate the centers of the three evenly spaced circles | |
// and | |
info = threeCenters(outer_radius = outer_circle_radius, inner_radius = desired_inner_radius, space = 1); | |
echo( info ); | |
// ECHO: [[[-46.4102, -26.314], [46.4102, -26.314], [0, 53.5898]], 20] | |
// --------- | |
// Sample 1: | |
// Can extract and use each falue individually. | |
// First extract each center from the list of centers (info[0]): | |
circle1_center = info[0][0]; | |
circle2_center = info[0][1]; | |
circle3_center = info[0][2]; | |
// Then extract the clamped radius that fits: | |
clamped_radius = info[1]; | |
// Finally, make a circular plate and cut out three holes in the locations calculated: | |
translate([125, 200, 0]) // move it out of the way so we can do a second one | |
difference() { | |
// make the plate - here we are using the outer_circle_radius, but it could | |
// be a square plate or a larger circle - just has to have a circle with | |
// radius outer_circle_radius or larger space in it's center (0,0) so | |
// the inner holes we'll cut out next fit. | |
cylinder(h = 20, r1 = outer_circle_radius, r2 = outer_circle_radius); | |
// Put the three holes in it. | |
// translating each one to the center returned by the function, | |
// making them 2 pixels longer and offsetting them one pixel in z axis | |
// so they cut through the plate | |
translate([circle1_center[0], circle1_center[1], -1]) | |
color("red") | |
cylinder(h = 22, r1 = clamped_radius, r2 = clamped_radius); | |
translate([circle2_center[0], circle2_center[1], -1]) | |
color("blue") | |
cylinder(h = 22, r1 = clamped_radius, r2 = clamped_radius); | |
translate([circle3_center[0], circle3_center[1], -1]) | |
color("green") | |
cylinder(h = 22, r1 = clamped_radius, r2 = clamped_radius); | |
} | |
// --------- | |
// Sample 2: | |
// Same result as above, but use a loop to show why the centers are | |
// returned as a list separate from the clamped radius. | |
translate([-125, 200, 0]) { // move it out of the way | |
difference() { | |
cylinder(h = 20, r1 = outer_circle_radius, r2 = outer_circle_radius); | |
// and put the holes in it | |
color("orange") | |
for (center = info[0]) | |
{ | |
translate([center[0], center[1], -1]) | |
cylinder(h = 22, r1 = clamped_radius, r2 = clamped_radius); | |
} | |
} | |
color("red") | |
cylinder(22, 2, 2, $fn = 100); | |
} | |
echo(clamped_radius); | |
// --------- | |
// Sample 3: | |
// Use a rectangular plate that is larger than outer_circle_radius. | |
translate([0, -100, 0]) // move it out of the way | |
difference() { | |
// unlike cylinders, cubes are made with one corner on the origin | |
// since our three holes are distributed around the origin, | |
// move the plate to be overlapping the origin the correct amount | |
translate([-outer_circle_radius, - (2 * outer_circle_radius), 0]) | |
cube([outer_circle_radius * 2, outer_circle_radius * 3, 10]); | |
// and put the holes in it | |
color("orange") | |
for (center = info[0]) | |
{ | |
translate([center[0], center[1], -1]) | |
cylinder(h = 22, r1 = clamped_radius, r2 = clamped_radius); | |
} | |
} | |
// ----------------------------------------------- | |
// The function that does the calculations and returns | |
// a list of centers and the desired inner circle radius clamped to | |
// the maximum size that will allow all three inner circles to fit | |
// within the outer circle radius with very thin space between them. | |
// The third parameter 'space' lets you tune the padding that is used | |
// to calculate the centers and the resulting clamped_radus, default is 1. | |
// You can pass smaller values for this value but this will override the | |
// "fits within the outer circle" restriction and may produce undesirable results. | |
// | |
// Result: | |
// [[[center1_x, center1_y], [center2_x, center2_y], [center3_x, center3_y]], clamped_radius] | |
function threeCenters(outer_radius, inner_radius, space = 1) = | |
// calculate the largest inner circle radius that will fit inside the outer circle | |
// (will touch each other and the outer circle). | |
// Do *not* take into account the space parameter here because we want to calculate the | |
// points without the spacing so that they are equally close to the edges and center of | |
// the outer circle. We subtract the spacing when we clamp the radius below. | |
let (max_inner_radius = (outer_radius) / (1 + 2 / sqrt(3)) ) | |
let (p1 = [ -(max_inner_radius), -( (sin(30) / sin(60)) * (max_inner_radius) )]) | |
let (p2 = [ (max_inner_radius), -( (sin(30) / sin(60)) * (max_inner_radius) )]) | |
let (p3 = [ 0, (max_inner_radius) / sin(60) ]) | |
// Calculate the largest inner circle radius that will fit based on the outer | |
// circle radius passed in and the "space" parameter. | |
let (clamped_inner_radius = min(inner_radius, max_inner_radius - (space * 2))) | |
// return the results as a list | |
[[p1, p2, p3], clamped_inner_radius]; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Version 3.0.2 fixes the
space
parameter and makes the layout actually correct in all cases that I've tested.