Skip to content

Instantly share code, notes, and snippets.

@ednisley
Last active July 10, 2022 22:54
Show Gist options
  • Save ednisley/1d80ea1681372d4f76c5b390349f6ca6 to your computer and use it in GitHub Desktop.
Save ednisley/1d80ea1681372d4f76c5b390349f6ca6 to your computer and use it in GitHub Desktop.
Bash and GCMC source code: Laser cutter marquetry / coaster test piece generator
#!/bin/bash
# Marquetry 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/Marquetry/Source Code'
LibPath='/opt/gcmc/library'
ScriptPath=$ProjPath
Script='Marquetry Test Piece.gcmc'
leaves="NumLeaves=$1"
aspect="LeafAspect=$2"
fn=Marq-$1-$2.svg
echo Output: $fn
gcmc $SVGFlags -D "$leaves" -D "$aspect" \
--include "$LibPath" \
"$ScriptPath"/"$Script" > "$fn"
// Marquetry Laser Cuttery Test Piece
// Ed Nisley KE4ZNU
// 2022-07-01 Simplest possible mandala
layerstack("Frame","Leaves","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 = 120.0mm;
}
if (!isdefined("CenterDia")) {
CenterDia = 20.0mm;
}
if (!isdefined("NumLeaves")) {
NumLeaves = 5;
}
if (!isdefined("Sash")) {
Sash = 4.0mm;
}
if (!isdefined("LeafAspect")) {
LeafAspect = 0.40;
}
// Leaf values
LeafStemAngle = 360.0deg/NumLeaves; // subtended by inner sides
LeafStemHA = LeafStemAngle/2;
LeafLength = OuterDia/2 - Sash - (Sash/2)/sin(LeafStemHA);
LeafWidth = LeafAspect*LeafLength;
L1 = (LeafWidth/2)/tan(LeafStemHA);
L2 = LeafLength - L1;
// message("Len: ",LeafLength," L1: ",L1," L2: ",L2);
LeafTipHA = to_deg(atan(LeafWidth/2,L2)); // subtended by outer sides
LeafTipAngle = 2*LeafTipHA;
// message("Width: ",LeafWidth);
// message("Tip HA: ",LeafTipHA);
LeafID = CenterDia + 2*Sash;
LeafOD = LeafID + LeafLength;
// message("ID: ",LeafID," OD: ",LeafOD);
// Find leaf and rim vertices
P0 = [(Sash/2) / sin(LeafStemHA),0.0mm];
if (P0.x < LeafID/2) {
a = 1 + pow(tan(LeafStemHA),2);
b = -2 * tan(LeafStemHA) * (Sash/2) / cos(LeafStemHA);
c = pow((Sash/2) / cos(LeafStemHA),2) - pow(LeafID/2,2);
// 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 = xp*tan(LeafStemHA) - (Sash/2) / cos(LeafStemHA);
// message("p: ",xp," n: ",xn," y: ",y);
P1 = [xp,y];
}
else {
P1 = P0;
}
P2 = P0 + [L1,LeafWidth/2];
P3 = P0 + [LeafLength,0mm];
P4 = P3 + [Sash/sin(LeafTipHA),0.0mm];
P5r = P4.x * sin(LeafTipHA) / sin(180deg - LeafStemHA - LeafTipHA);
P5 = rotate_xy([P5r,0.0mm],LeafStemHA);
P6 = rotate_xy(P4,LeafStemAngle);
t2 = pow(tan(-LeafTipHA),2);
a = 1 + t2;
b = -2 * t2 * P4.x;
c = t2 * pow(P4.x,2) - pow(P3.x,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 - P4.x)*tan(-LeafTipHA);
// message("p: ",xp," n: ",xn," y: ",y);
P4a = [xp,y];
P6a = rotate_xy(P4a,LeafStemAngle - 2*atan(P4a.y,P4a.x));
// message("P4a: ",P4a);
// message("P6a: ",P6a);
// message("P0: ",P0);
// message("P1: ",P1);
// message("P2: ",P2);
// message("P3: ",P3);
// message("P4: ",P4);
// message("P5: ",P5);
// message("P6: ",P6);
// Construct paths
LeafPoints = {P1,P2,P3,[P2.x,-P2.y],[P1.x,-P1.y]};
if (P0 != P1) {
StemArc = varc_ccw(P1 - [P1.x,-P1.y],LeafID/2);
StemArc += [P1.x,-P1.y];
LeafPoints += StemArc;
}
RimChord = length(P4a - P6a);
RimThick = OuterDia/2 - Sash - length(P5);
RimPoints = {P4a,P5,P6a};
RimArc = varc_cw(P4a - P6a,P4a.x);
RimArc += P6a;
RimPoints += RimArc;
//--- Lay out the frame
linecolor(0xff0000);
layer("Frame");
goto([CenterDia/2,0mm]);
circle_cw([0mm,0mm]);
repeat(NumLeaves;i) {
a = (i-1)*LeafStemAngle;
tracepath(rotate_xy(LeafPoints,a));
}
repeat(NumLeaves;i) {
a = (i-1)*LeafStemAngle;
tracepath(rotate_xy(RimPoints,a));
}
linecolor(0xff0000);
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
layer("Center");
relocate([OuterDia/2 + Sash,-(OuterDia - CenterDia)/2]);
goto([CenterDia/2,0mm]);
circle_cw([0mm,0mm]);
// leaves
layer("Leaves");
repeat(NumLeaves;i) {
org = [LeafWidth/2 - OuterDia/2,-(OuterDia + Sash)];
relocate([(i-1)*(LeafWidth + Sash) + org.x,org.y]);
tracepath(rotate_xy(LeafPoints,90deg));
}
// rim
layer("Rim");
repeat(NumLeaves;i) {
org = [-Sash,-(OuterDia + 2*Sash + RimChord/2)];
relocate([(i-1)*(RimThick + Sash) + org.x,org.y]);
tracepath(rotate_xy(RimPoints,180 - LeafStemHA));
}
// 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(LeafStemHA),sin(LeafStemHA)]);
goto(P2);
move_r([0,-LeafWidth/2]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment