Coaster Generator: Simple Petals

Having figured out how to intersect a line with a circle, I figured I could do it twice to put arcs on both the inside and the outside of each petal:

Chipboard coaster - double arcs
Chipboard coaster – double arcs

As before, scribbling markers on plain chipboard makes for a … subdued … coaster, so I tried chipboard with one white surface:

Chipboard coaster - plain vs white
Chipboard coaster – plain vs white

Much better.

Clamping the coaster produces a flatter result:

Chipboard coaster - clamping
Chipboard coaster – clamping

With the risk of squishing excess glue through the kerf:

Chipboard coaster - excess glue
Chipboard coaster – excess glue

That’s the same coaster as in the first picture, carefully arranged with light reflecting off the flat glue surface. In real life, the nearly transparent glue doesn’t look nearly so awful, but smoothing much less glue than seems necessary across the bottom disk suffices.

The geometry doodle with the arcs:

Chipboard coaster - double arc petal geometry doodle
Chipboard coaster – double arc petal geometry doodle

I suppose I should refactor the code with a quadratic solver returning a list of roots, but copypasta suffices for now.

The GCMC and Bash source code as a GitHub Gist:

#!/bin/bash
# Simple petals test piece
# Ed Nisley KE4ZNU - 2022-07-01
Flags='-P 4 --pedantic' # quote to avoid leading hyphen gotcha
SVGFlags='-P 4 --pedantic --svg --svg-no-movelayer --svg-opacity=1.0 --svg-toolwidth=0.2'
# Set these to match your file layout
ProjPath='/mnt/bulkdata/Project Files/Laser Cutter/Coasters/Source Code'
LibPath='/opt/gcmc/library'
ScriptPath=$ProjPath
Script='Simple Petals.gcmc'
[ -z "$1" ] && petals="6" || petals="$1"
fn=Petals-$petals.svg
echo Output: $fn
gcmc $SVGFlags \
-D "NumPetals=$petals" \
--include "$LibPath" \
"$ScriptPath"/"$Script" > "$fn"
view raw petals.sh hosted with ❤ by GitHub
// Simple Petals Test Piece
// Ed Nisley KE4ZNU
// 2022-07-12 Simplest possible petals
layerstack("Frame","Petals","Rim","Base","Center","Tool1"); // SVG layers map to LightBurn colors
//-----
// Library routines
include("tracepath.inc.gcmc");
include("tracepath_comp.inc.gcmc");
include("varcs.inc.gcmc");
include("engrave.inc.gcmc");
FALSE = 0;
TRUE = !FALSE;
//-----
// Command line parameters
// -D various useful tidbits
// add unit to speeds and depths: 2000mm / -3.00mm / etc
if (!isdefined("OuterDia")) {
OuterDia = 100.0mm;
}
if (!isdefined("CenterDia")) {
CenterDia = 25.0mm;
}
if (!isdefined("NumPetals")) {
NumPetals = 6;
}
if (!isdefined("Sash")) {
Sash = 5.0mm;
}
// Petal values
PetalAngle = 360.0deg/NumPetals; // subtended by inner sides
PetalHA = PetalAngle/2;
PetalOD = OuterDia - 2*Sash;
PetalID = CenterDia + 2*Sash;
PetalOAL = OuterDia/2 - Sash - (Sash/2)/sin(PetalHA);
//message("petalOAL: ",PetalOAL);
// Find petal vertices
P0 = [(Sash/2) / sin(PetalHA),0.0mm];
t1 = tan(PetalHA);
sc = (Sash/2) / cos(PetalHA);
if (P0.x < PetalID/2) {
a = 1 + pow(t1,2);
b = -2 * t1 * sc;
c = pow(sc,2) - pow(PetalID/2,2);
xp = (-b + sqrt(pow(b,2) - 4*a*c))/(2*a);
xn = (-b - sqrt(pow(b,2) - 4*a*c))/(2*a);
y = xp*t1 - sc;
if (FALSE) {
message("a: ",a);
message("b: ",b);
message("c: ",c);
message("p: ",xp," n: ",xn," y: ",y);
}
P1 = [xp,y];
}
else {
P1 = P0;
}
a = 1 + pow(t1,2);
b = -2 * t1 * sc;
c = pow(sc,2) - pow(PetalOD/2,2);
if (FALSE) {
message("a: ",a);
message("b: ",b);
message("c: ",c);
}
xp = (-b + sqrt(pow(b,2) - 4*a*c))/(2*a);
xn = (-b - sqrt(pow(b,2) - 4*a*c))/(2*a);
y = to_mm(sqrt(pow(PetalOD/2,2) - pow(xp,2)));
//message("p: ",xp," n: ",xn," y: ",y);
P2 = [xp,y];
PetalWidth = 2*P2.y;
P3 = [PetalOD/2,0.0mm];
if (FALSE) {
message("P0: ",P0);
message("P1: ",P1);
message("P2: ",P2);
message("P3: ",P3);
}
// Construct paths
PetalPoints = {P1,P2};
OutArc = varc_cw([P2.x,-P2.y] - P2,PetalOD/2);
OutArc += P2;
PetalPoints += OutArc;
if (P0 != P1) {
PetalPoints += {[P1.x,-P1.y]};
InArc = varc_ccw(P1 - [P1.x,-P1.y],PetalID/2);
InArc += [P1.x,-P1.y];
PetalPoints += InArc;
}
else {
PetalPoints += {P0};
}
//--- Lay out the frame
linecolor(0xff0000);
layer("Frame");
if (CenterDia) {
goto([CenterDia/2,0mm]);
circle_cw([0mm,0mm]);
}
repeat(NumPetals;i) {
a = (i-1)*PetalAngle;
tracepath(rotate_xy(PetalPoints,a));
}
goto([OuterDia/2,0]);
circle_cw([0mm,0mm]);
//--- Lay out internal pieces for oriented cutting
// baseplate
layer("Base");
relocate([OuterDia + 2*Sash,0]);
goto([OuterDia/2,0]);
circle_cw([0mm,0mm]);
// central circle
if (CenterDia) {
layer("Center");
relocate([OuterDia/2 + Sash,-(OuterDia - CenterDia)/2]);
goto([CenterDia/2,0mm]);
circle_cw([0mm,0mm]);
}
// petals
layer("Petals");
repeat(NumPetals;i) {
org = [PetalWidth/2 - OuterDia/2,-(OuterDia + Sash)];
relocate([(i-1)*(PetalWidth + Sash) + org.x,org.y]);
tracepath(rotate_xy(PetalPoints,90deg));
}
// Debugging by printf()
if (FALSE) {
layer("Tool1");
linecolor(0xff1f00);
goto([Sash/2,0mm]);
circle_cw([0mm,0mm]);
goto(P0);
circle_cw([0mm,0mm]);
goto([0,0]);
move([OuterDia/2,0]);
goto([0,0]);
move(OuterDia/2 * [cos(PetalHA),sin(PetalHA)]);
goto(P2);
move_r([0,-PetalWidth/2]);
}

6 thoughts on “Coaster Generator: Simple Petals

  1. They look pretty nice, but… Just as having the subject smack dab in the center of a photo is generally a no-no, aside from the colors the geometric symmetry of the coaster does not really grab one’s eye. Maybe unequal angles might juice it up a little. ( Or make it look crappy? ).

    1. I am, if nothing else, biased strongly in favor of boring symmetry.

      Moving the pattern off-center and clipping to the perimeter should be a simple matter of software, but GCMC seems a bad language for a 2D graphics library. [grin]

Comments are closed.