Skip to content

Instantly share code, notes, and snippets.

@fischman
Last active October 7, 2016 02:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fischman/1bee89022275764f74c927b43c9ec0e6 to your computer and use it in GitHub Desktop.
Save fischman/1bee89022275764f74c927b43c9ec0e6 to your computer and use it in GitHub Desktop.
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})
)
);
}
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.094488189"
height="1052.36220472"
id="svg5466"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="ghostbadge.svg">
<metadata
id="metadata5494">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1176"
id="namedview5492"
showgrid="false"
inkscape:zoom="3.5881183"
inkscape:cx="206.77956"
inkscape:cy="929.3194"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g5490" />
<desc
id="desc5468">/media/maker/1AA8-CDF8/folds.dxf - scale = 1.000000, origin = (0.000000, 0.000000), auto = False</desc>
<defs
id="defs5470">
<marker
id="DistanceX"
orient="auto"
refX="0.0"
refY="0.0"
style="overflow:visible">
<path
d="M 3,-3 L -3,3 M 0,-5 L 0,5"
style="stroke:#000000; stroke-width:0.5"
id="path5473" />
</marker>
<pattern
height="8"
id="Hatch"
patternUnits="userSpaceOnUse"
width="8"
x="0"
y="0">
<path
d="M8 4 l-4,4"
linecap="square"
stroke="#000000"
stroke-width="0.25"
id="path5476" />
<path
d="M6 2 l-4,4"
linecap="square"
stroke="#000000"
stroke-width="0.25"
id="path5478" />
<path
d="M4 0 l-4,4"
linecap="square"
stroke="#000000"
stroke-width="0.25"
id="path5480" />
</pattern>
<marker
style="overflow:visible"
refY="0.0"
refX="0.0"
orient="auto"
id="DistanceX-9">
<path
id="path6073"
style="stroke:#000000; stroke-width:0.5"
d="M 3,-3 L -3,3 M 0,-5 L 0,5" />
</marker>
<pattern
y="0"
x="0"
width="8"
patternUnits="userSpaceOnUse"
id="Hatch-4"
height="8">
<path
id="path6076"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M8 4 l-4,4" />
<path
id="path6078"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M6 2 l-4,4" />
<path
id="path6080"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M4 0 l-4,4" />
</pattern>
</defs>
<g
inkscape:groupmode="layer"
inkscape:label="cut"
id="g5482"
style="display:inline">
<g
id="g6121"
style="fill:none;stroke:#000000;stroke-opacity:1">
<g
transform="translate(85.444747,-686.71095)"
id="g6102"
style="fill:none;stroke:#000000;stroke-opacity:1">
<g
inkscape:label="OpenJsCad"
id="g6082"
style="fill:none;stroke:#000000;stroke-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 87.34252,1383.6614 37.91339,0 1.14058,0.1124 1.09676,0.3327 1.01077,0.5402 0.88595,0.7271 0.72709,0.886 0.54027,1.0107 0.33269,1.0968 0.11234,1.1406 0,0.7086 -0.11234,1.1406 -0.33269,1.0968 -0.54027,1.0108 -0.72709,0.8859 -0.88595,0.7271 -1.01077,0.5403 -1.09676,0.3327 -1.14058,0.1123 -37.91339,0 -1.140587,-0.1123 -1.096755,-0.3327 -1.010776,-0.5403 -0.885951,-0.7271 -0.727082,-0.8859 -0.540271,-1.0108 -0.332697,-1.0968 -0.112338,-1.1406 0,-0.7086 0.112338,-1.1406 0.332697,-1.0968 0.540271,-1.0107 0.727082,-0.886 0.885951,-0.7271 1.010776,-0.5402 1.096755,-0.3327 1.140587,-0.1124 0,0 z"
style="fill:none;stroke:#000000;stroke-opacity:1"
id="path6084" />
<path
inkscape:connector-curvature="0"
d="m 81.496063,715.21654 0,-0.70867 0.112338,-1.14058 0.332697,-1.09676 0.540271,-1.01077 0.727082,-0.88596 0.885951,-0.72708 1.010776,-0.54027 1.096755,-0.33269 1.140587,-0.11234 37.91339,0 1.14058,0.11234 1.09676,0.33269 1.01077,0.54027 0.88595,0.72708 0.72709,0.88596 0.54027,1.01077 0.33269,1.09676 0.11234,1.14058 0,0.70867 -0.11234,1.14058 -0.33269,1.09676 -0.54027,1.01077 -0.72709,0.88595 -0.88595,0.72709 -1.01077,0.54027 -1.09676,0.33269 -1.14058,0.11234 -37.91339,0 -1.140587,-0.11234 -1.096755,-0.33269 -1.010776,-0.54027 -0.885951,-0.72709 -0.727082,-0.88595 -0.540271,-1.01077 -0.332697,-1.09676 -0.112338,-1.14058 0,0 z"
style="fill:none;stroke:#000000;stroke-opacity:1"
id="path6086" />
<path
inkscape:connector-curvature="0"
d="m 170.07874,1401.378 0,-278.1497 0.13617,-1.3825 0.40327,-1.3294 0.65487,-1.2252 0.88131,-1.0738 1.07388,-0.8814 1.22518,-0.6548 1.3294,-0.4033 1.38253,-0.1362 28.34646,0 1.38253,-0.1361 1.3294,-0.4033 1.22518,-0.6549 1.07388,-0.8813 0.88131,-1.0739 0.65488,-1.2252 0.40327,-1.3294 0.13616,-1.3825 0,-49.6063 -0.13616,-1.3825 -0.40327,-1.3294 -0.65488,-1.2252 -0.88131,-1.0739 -1.07388,-0.8813 -1.22518,-0.6549 -1.3294,-0.4032 -1.38253,-0.1362 1.38253,-0.1362 1.3294,-0.4032 1.22518,-0.6549 1.07388,-0.8813 0.88131,-1.0739 0.65488,-1.2252 0.40327,-1.3294 0.13616,-1.3825 0,-63.77954 0.13617,1.38253 0.40327,1.3294 0.65487,1.22518 0.88132,1.07389 1.07388,0.88131 1.22518,0.65487 1.3294,0.40327 1.38253,0.13617 28.34646,0 1.38253,-0.13617 1.3294,-0.40327 1.22518,-0.65487 1.07388,-0.88131 0.88131,-1.07389 0.65487,-1.22518 0.40327,-1.3294 0.13617,-1.38253 0,-240.94488 -0.13617,-1.38253 -0.40327,-1.3294 -0.65487,-1.22518 -0.88131,-1.07388 -1.07388,-0.88131 -1.22518,-0.65488 -1.3294,-0.40327 -1.38253,-0.13616 -28.34646,0 -1.38253,0.13616 -1.3294,0.40327 -1.22518,0.65488 -1.07388,0.88131 -0.88132,1.07388 -0.65487,1.22518 -0.40327,1.3294 -0.13617,1.38253 -0.13616,-1.38253 -0.40327,-1.3294 -0.65488,-1.22518 -0.88131,-1.07388 -1.07388,-0.88131 -1.22518,-0.65488 -1.3294,-0.40327 -1.38253,-0.13616 -28.34646,0 -1.38253,-0.13617 -1.3294,-0.40327 -1.22518,-0.65487 -1.07388,-0.88131 -0.88131,-1.07389 -0.65487,-1.22518 -0.40327,-1.3294 -0.13617,-1.38253 0,-23.03149 -0.13617,-1.38253 -0.40327,-1.3294 -0.65487,-1.22518 -0.88131,-1.07389 -1.07388,-0.88131 -1.22518,-0.65487 -1.3294,-0.40327 -1.38253,-0.13617 -113.385831,0 -1.38253,0.13617 -1.3294,0.40327 -1.225182,0.65487 -1.073881,0.88131 -0.881311,1.07389 -0.654874,1.22518 -0.403269,1.3294 -0.136167,1.38253 0,23.03149 -0.136167,1.38253 -0.403269,1.3294 -0.654874,1.22518 -0.881311,1.07389 -1.073881,0.88131 -1.225182,0.65487 -1.3294,0.40327 -1.38253,0.13617 -28.346457,0 -1.38253,0.13616 -1.3294,0.40327 -1.225182,0.65488 -1.073881,0.88131 -0.881311,1.07388 -0.654874,1.22518 -0.403269,1.3294 L 0,740.55118 l -0.136167,-1.38253 -0.403269,-1.3294 -0.654874,-1.22518 -0.881311,-1.07388 -1.073881,-0.88131 -1.225182,-0.65488 -1.3294,-0.40327 -1.38253,-0.13616 -28.346457,0 -1.38253,0.13616 -1.3294,0.40327 -1.225182,0.65488 -1.073881,0.88131 -0.881311,1.07388 -0.654874,1.22518 -0.403269,1.3294 -0.136167,1.38253 0,240.94488 0.136167,1.38253 0.403269,1.3294 0.654874,1.22518 0.881311,1.07389 1.073881,0.88131 1.225182,0.65487 1.3294,0.40327 1.38253,0.13617 28.346457,0 1.38253,-0.13617 1.3294,-0.40327 1.225182,-0.65487 1.073881,-0.88131 0.881311,-1.07389 0.654874,-1.22518 0.403269,-1.3294 L 0,981.49606 l 0,63.77954 0.136167,1.3825 0.403269,1.3294 0.654874,1.2252 0.881311,1.0739 1.073881,0.8813 1.225182,0.6549 1.3294,0.4032 1.38253,0.1362 -1.38253,0.1362 -1.3294,0.4032 -1.225182,0.6549 -1.073881,0.8813 -0.881311,1.0739 -0.654874,1.2252 -0.403269,1.3294 L 0,1059.4488 l 0,49.6063 0.136167,1.3825 0.403269,1.3294 0.654874,1.2252 0.881311,1.0739 1.073881,0.8813 1.225182,0.6549 1.3294,0.4033 1.38253,0.1361 28.346457,0 1.38253,0.1362 1.3294,0.4033 1.225182,0.6548 1.073881,0.8814 0.881311,1.0738 0.654874,1.2252 0.403269,1.3294 0.136167,1.3825 0,278.1497 0.136167,1.3825 0.403269,1.3294 0.654874,1.2252 0.881311,1.0738 1.073881,0.8814 1.225182,0.6548 1.3294,0.4033 1.38253,0.1362 113.385831,0 1.38253,-0.1362 1.3294,-0.4033 1.22518,-0.6548 1.07388,-0.8814 0.88131,-1.0738 0.65487,-1.2252 0.40327,-1.3294 0.13617,-1.3825 0,0 z"
style="fill:none;stroke:#000000;stroke-opacity:1"
id="path6088" />
</g>
<g
inkscape:label="0"
id="g6090"
style="fill:none;stroke:#000000;stroke-opacity:1" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
inkscape:label="fold"
id="g5490"
style="display:inline">
<g
style="display:inline"
id="g6042"
transform="translate(86.117562,-686.71091)">
<path
id="path5484"
style="fill:#000000;fill-opacity:1;stroke:none"
d="m 7.086614,1054.1339 198.425196,0 1.77165,-1.7717 -1.77165,-1.7716 -198.425196,0 -1.771653,1.7716 1.771653,1.7717 0,0 z"
inkscape:connector-curvature="0" />
<path
id="path5486"
style="fill:#000000;fill-opacity:1;stroke:none"
d="m 214.37008,981.49606 0,-240.94488 -1.77166,-1.77165 -1.77165,1.77165 0,240.94488 1.77165,1.77166 1.77166,-1.77166 0,0 z"
inkscape:connector-curvature="0" />
<path
id="path5488"
style="fill:#000000;fill-opacity:1;stroke:none"
d="m 1.771654,981.49606 0,-240.94488 L 0,738.77953 l -1.771654,1.77165 0,240.94488 L 0,983.26772 l 1.771654,-1.77166 0,0 z"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment