Skip to content

Instantly share code, notes, and snippets.

@fischman fischman/ghost-badge.jscad Secret
Last active Oct 7, 2016

Embed
What would you like to do?
const badgeWidth = 60; // Really 54mm; extra wiggle for the folds.
const badgeHeight = 90; // Really 85.55mm
const notchHeight = 3.5; // Really 2.5mm
const notchWidth = 14; // Really 12.5mm
const cornerRadius = 2;
// The wings hold the badge sides by being folded over along the Y axis.
const wingWidthRatio = 0.2;
const wingHeightRatio = 0.8;
const wingWidth = wingWidthRatio * badgeWidth;
const wingHeight = wingHeightRatio * badgeHeight;
// The flap holds the badge from below by being folded upwards along
// the X axis.
const flapHeightRatio = 1 - wingHeightRatio;
const flapWidthRatio = 1 - 2*wingWidthRatio;
function getParameterDefinitions() {
return [
{ name: 'layer',
type: 'choice',
values: ['folds', 'outline'],
captions: ['Mark (folds)', 'Cut (outline)'],
caption: 'Layer to render',
},
];
}
function main(params) {
switch (params.layer) {
case 'outline':
return outline();
case 'folds':
return folds();
default:
throw 'Unexpected layer: ' + params.layer;
}
}
function outline() {
var o = [];
o.push(roundedRectangle({
corner1: [0, 0],
corner2: [badgeWidth, badgeHeight],
roundradius: cornerRadius,
}));
const leftWing = roundedRectangle({
corner1: [-wingWidth, badgeHeight-wingHeight],
corner2: [0, badgeHeight],
roundradius: cornerRadius,
});
const rightWing = leftWing.mirroredX().translate([badgeWidth, 0, 0]);
o.push(leftWing);
o.push(rightWing);
const flapHeight = flapHeightRatio * badgeHeight;
const flap = roundedRectangle({
corner1: [0, 0],
corner2: [badgeWidth, -flapHeight],
roundradius: cornerRadius,
}).union(roundedRectangle({
corner1: [wingWidth, -flapHeight],
corner2: [badgeWidth-wingWidth, -badgeHeight],
roundradius: cornerRadius,
squareCorners: [0, 1],
outerFilletCorners: [2,3],
}));
o.push(flap);
const notchBaseWidth = badgeWidth - 2*wingWidth;
const notchBaseHeight = notchHeight * 3;
const notchBase = roundedRectangle({
corner1: [0, 0],
corner2: [notchBaseWidth, notchBaseHeight],
squareCorners: [0, 1],
outerFilletCorners: [0, 1],
roundradius: cornerRadius,
}).subtract(roundedRectangle({
corner1: [(notchBaseWidth-notchWidth)/2, notchHeight],
corner2: [(notchBaseWidth+notchWidth)/2, notchHeight * 2],
roundradius: cornerRadius,
}));
o.push(notchBase.translate([(badgeWidth - notchBaseWidth) / 2, badgeHeight, 0]));
o.push(notchBase.intersect(CAG.rectangle({
// Shave off the outer fillets for the notch on the flap.
corner1: [0, 0],
corner2: [notchBaseWidth, notchBaseHeight],
})).mirroredY().translate([(badgeWidth - notchBaseWidth) / 2, -badgeHeight, 0]));
return o;
}
function folds() {
var o = [];
const wingFold = new CSG.Path2D([[0,badgeHeight-wingHeight+cornerRadius], [0, badgeHeight-cornerRadius]]).expandToCAG(0.5, 1);
o.push(wingFold);
o.push(wingFold.translate([badgeWidth, 0, 0]));
o.push(new CSG.Path2D([[cornerRadius,0], [badgeWidth-cornerRadius, 0]]).expandToCAG(0.5, 1));
return o;
}
// Delegate to CAG.roundedRectangle() but also:
// - fill in corners noted in params.squareCorners, specified as an
// array of ints in 0..3, where 0 is lower-left and index increases
// clockwise.
// - create fillets on the outside of outerFilletCorners (same corner
// spec as above), where each fillet is 4 complements of
// quarter-discs.
// These two enhancements make it easier to build up shapes from
// touching roundedRectangles without holes (squareCorners) and making
// interior joints smooth instead of sharp (outerFilletCorners).
roundedRectangle = function(params) {
var rect = CAG.roundedRectangle(params);
var bounds = rect.getBounds();
var center = [(bounds[0].x + bounds[1].x)/2, (bounds[0].y + bounds[1].y)/2];
// Corner i is given by [bounds[t].x, bounds[s].y] where [t,s] is
// the i'th entry in this array.
var cornersByIndex = [
[0, 0],
[1, 0],
[1, 1],
[0, 1]
];
for (var c in params.squareCorners) {
var cornerBoundsIndexes = cornersByIndex[params.squareCorners[c]];
var corner = [bounds[cornerBoundsIndexes[0]].x, bounds[cornerBoundsIndexes[1]].y];
rect = union(rect, CAG.rectangle({corner1: corner, corner2: center}));
}
for (var c in params.outerFilletCorners) {
var cornerBoundsIndexes = cornersByIndex[params.outerFilletCorners[c]];
var corner = [bounds[cornerBoundsIndexes[0]].x, bounds[cornerBoundsIndexes[1]].y];
rect = union(rect, filletAt(corner, params.roundradius));
}
return rect;
}
// See description of outerFilletCorners above for what this is for.
filletAt = function(center, radius) {
var c0 = [center[0] - radius, center[1] - radius];
var c1 = [center[0] + radius, center[1] - radius];
var c2 = [center[0] + radius, center[1] + radius];
var c3 = [center[0] - radius, center[1] + radius];
return CAG.rectangle({corner1: c0, corner2: c2}).subtract(
union(
CAG.circle({center: c0, radius: radius}),
CAG.circle({center: c1, radius: radius}),
CAG.circle({center: c2, radius: radius}),
CAG.circle({center: c3, radius: radius})
)
);
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.