diff --git a/.gitignore b/.gitignore index 1567411..68a6176 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.stl +/build/ diff --git a/README.md b/README.md index 4cda96f..08871a4 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,21 @@ but these are the original tracks you can replicate As an overview, or why it's worth a try: They print rapidly on modern printers, and cost barely anything. -| Name | Material Cost | Print Time | -| --------------------- | ------------- | ---------- | -| C15 | ~10ct | 45m | -| C7 | ~5ct | 15m | -| S25 | ~12ct | 1h | -| S10 | ~5ct | 15m | -| S5 | ~5ct | 15m | -| Classic R28 90° Curve | ~25ct | 2h | -| Classic R28 45° Curve | ~12ct | 1h | -| Classic L32 Straight | ~20ct | 1.5h | -| Classic L16 Straight | ~10ct | 45m | -| Classic L8 Straight | ~5ct | 15m | +| Preset | Cost | Time | Image | +| ----------------------------- | ----- | ---- | -------------------------------------------------------------------------------- | +| C15 | ~10ct | 45m | ![C15](./assets/generated/C15.png) | +| C7 | ~5ct | 15m | ![C7](./assets/generated/C7.png) | +| S25 | ~12ct | 1h | ![S25](./assets/generated/S25.png) | +| S10 | ~5ct | 15m | ![S10](./assets/generated/S10.png) | +| S5 | ~5ct | 15m | ![S5](./assets/generated/S5.png) | +| S4 | ~5ct | 15m | ![S4](./assets/generated/S4.png) | +| Classic Full Curve (R28 90°) | ~25ct | 2h | ![Classic Full Curve](./assets/generated/Classic%20Full%20Curve.png) | +| Classic Half Curve (R28 45°) | ~12ct | 1h | ![Classic Half Curve](./assets/generated/Classic%20Half%20Curve.png) | +| Classic Full Straight (L32) | ~20ct | 1.5h | ![Classic Full Straight](./assets/generated/Classic%20Full%20Straight.png) | +| Classic Half Straight (L16) | ~10ct | 45m | ![Classic Half Straight](./assets/generated/Classic%20Half%20Straight.png) | +| Classic Quarter Straight (L8) | ~5ct | 15m | ![Classic Quarter Straight](./assets/generated/Classic%20Quarter%20Straight.png) | + +You can also generate your own custom rails with any length, radius or angle. Todo: ramps, switches, train assembly @@ -62,7 +65,7 @@ How it fits - An s-curve with C15 moves over 20 studs, diagonals can be done with any length divisible by 5 - An s-curve with C7 moves two studs, but diagonals require a full S25 to land cleanly again. -![](./r25.svg) +![](./assets/r25.svg) ## Printing @@ -81,10 +84,10 @@ balance of speed and quality. A short rail will take about an hour to print. ### Filament -| Color | RAL Color | Pantone | PLA Supplier | ABS Supplier | -| ----------------- | ---------- | ------- | ------------ | ------------ | -| Light Bluish Gray | `RAL 7040` | | dasfilament | | -| Light Gray | `RAL 7005` | | | | +| Color | RAL | PLA Supplier | ABS Supplier | +| ----------------- | ---------- | ------------ | ------------ | +| Light Bluish Gray | `RAL 7040` | dasfilament | | +| Light Gray | `RAL 7005` | | | - None of these colors will be an exact match, just the texture of 3d printing it can make a huge difference, but usually fall close enough in the range. - The original rails will be in _Light Gray_, not _Light Bluish Gray_, but since I barely own any pre- 2004 color change bricks I chose to match my other bricks instead. @@ -100,6 +103,6 @@ _Notes for newcomers:_ In case you are new to 3D printing: -- Most filaments (including PLA) release toxic gases when _burned_ +- Most filaments (including PLA) can release toxic gases when _burned_ - FDM printing can cause fine particle emission - ABS when heated to normal printing temperatures can release styrene fumes diff --git a/assets/generated/AntiStudInsert.png b/assets/generated/AntiStudInsert.png new file mode 100644 index 0000000..33f7ef5 Binary files /dev/null and b/assets/generated/AntiStudInsert.png differ diff --git a/assets/generated/C15.png b/assets/generated/C15.png new file mode 100644 index 0000000..28c3992 Binary files /dev/null and b/assets/generated/C15.png differ diff --git a/assets/generated/C7.png b/assets/generated/C7.png new file mode 100644 index 0000000..24bb5ab Binary files /dev/null and b/assets/generated/C7.png differ diff --git a/assets/generated/Classic Full Curve.png b/assets/generated/Classic Full Curve.png new file mode 100644 index 0000000..01f061f Binary files /dev/null and b/assets/generated/Classic Full Curve.png differ diff --git a/assets/generated/Classic Full Straight.png b/assets/generated/Classic Full Straight.png new file mode 100644 index 0000000..3e60cd2 Binary files /dev/null and b/assets/generated/Classic Full Straight.png differ diff --git a/assets/generated/Classic Half Curve.png b/assets/generated/Classic Half Curve.png new file mode 100644 index 0000000..c1eb57f Binary files /dev/null and b/assets/generated/Classic Half Curve.png differ diff --git a/assets/generated/Classic Half Straight.png b/assets/generated/Classic Half Straight.png new file mode 100644 index 0000000..62080a1 Binary files /dev/null and b/assets/generated/Classic Half Straight.png differ diff --git a/assets/generated/Classic Quarter Straight.png b/assets/generated/Classic Quarter Straight.png new file mode 100644 index 0000000..212ce01 Binary files /dev/null and b/assets/generated/Classic Quarter Straight.png differ diff --git a/assets/generated/S10.png b/assets/generated/S10.png new file mode 100644 index 0000000..9406061 Binary files /dev/null and b/assets/generated/S10.png differ diff --git a/assets/generated/S25.png b/assets/generated/S25.png new file mode 100644 index 0000000..e8e1690 Binary files /dev/null and b/assets/generated/S25.png differ diff --git a/assets/generated/S4.png b/assets/generated/S4.png new file mode 100644 index 0000000..e078725 Binary files /dev/null and b/assets/generated/S4.png differ diff --git a/assets/generated/S5.png b/assets/generated/S5.png new file mode 100644 index 0000000..b07db27 Binary files /dev/null and b/assets/generated/S5.png differ diff --git a/assets/generated/StudInsert.png b/assets/generated/StudInsert.png new file mode 100644 index 0000000..0e238b2 Binary files /dev/null and b/assets/generated/StudInsert.png differ diff --git a/r25.svg b/assets/r25.svg similarity index 100% rename from r25.svg rename to assets/r25.svg diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ae0f271 --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +rm -rf build +mkdir -p build +rm -rf assets/generated +mkdir -p assets/generated +jq -r '.parameterSets | keys[]' track.json | while read -r preset; do + echo "Rendering $preset" + openscad -o "build/$preset.stl" -p track.json -P "$preset" track.scad + openscad -o "assets/generated/$preset.png" --imgsize=48,48 --render --autocenter --viewall -p track.json -P "$preset" track.scad +done diff --git a/track.json b/track.json index 9eb2b43..4f8fc93 100644 --- a/track.json +++ b/track.json @@ -1,30 +1,88 @@ { "fileFormatVersion": "1", "parameterSets": { - "90 Degree Curve": { - "Radius": "28", - "Length": "32", - "Type": "curve" + "C15": { + "Angle": 1, + "Length": 15, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false }, - "Full Straight": { - "Radius": "28", - "Length": "32", - "Type": "straight" + "C7": { + "Angle": 1, + "Length": 7, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false }, - "Half Straight": { - "Radius": "28", - "Length": "16", - "Type": "straight" + "S25": { + "Angle": 0, + "Length": 25, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false }, - "Quarter Straight": { - "Radius": "28", - "Length": "8", - "Type": "straight" + "S10": { + "Angle": 0, + "Length": 10, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false }, - "4 Studs Straight": { - "Radius": "28", - "Length": "4", - "Type": "straight" + "S5": { + "Angle": 0, + "Length": 5, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false + }, + "S4": { + "Angle": 0, + "Length": 4, + "Radius": 25, + "UseLengthForCurveAngle": true, + "Support": false + }, + "Classic Full Straight": { + "Angle": 0, + "Length": 32, + "Radius": 28, + "UseLengthForCurveAngle": false, + "Support": false + }, + "Classic Half Straight": { + "Angle": 0, + "Length": 16, + "Radius": 28, + "UseLengthForCurveAngle": false, + "Support": false + }, + "Classic Quarter Straight": { + "Angle": 0, + "Length": 8, + "Radius": 28, + "UseLengthForCurveAngle": false, + "Support": false + }, + "Classic Full Curve": { + "Angle": 90, + "Length": 8, + "Radius": 28, + "UseLengthForCurveAngle": false, + "Support": false + }, + "Classic Half Curve": { + "Angle": 45, + "Length": 8, + "Radius": 28, + "UseLengthForCurveAngle": false, + "Support": false + }, + "StudInsert": { + "Type": "studs" + }, + "AntiStudInsert": { + "Type": "antistuds" } } } diff --git a/track.scad b/track.scad index e886ae5..959cbf7 100644 --- a/track.scad +++ b/track.scad @@ -4,13 +4,18 @@ include ; /* [Print Settings] */ // Some feature are generated with respect to the layer height LayerHeight = 0.2; // [0.1,0.13,0.2] -// Enable built-in support for 3d printing -Support = true; +// Mid-print stud inserts allowing the studs to be printed facing up seperately +StudInserts = false; +// Mid-print slot inserts eliminating the need for supports +AntiStudInserts = false; +// Part to generate +Type = "rail"; // [rail,studs,antistuds] + /* [Model Settings] */ Length = 8; // [4:1:56] // Useful when working with Pythagorean Triples UseLengthForCurveAngle = true; -Radius = 28; // [4:1:36] +Radius = 25; // [4:1:36] // The angle the track takes Angle = 0.0; @@ -59,6 +64,35 @@ module tooth() { ]); } +module antiStudInsert(carve=true, depth=$studHeight * 2, supportHeight=$LDU * 4, supportWidth=$LDU * 4) { + difference() { + union() { + cube([$tile * 2, $tile, depth + supportHeight], anchor=FRONT+BOTTOM); + translate([0, $tile, 0]) cube([$tile * 2 + supportWidth, supportWidth, depth + supportHeight], anchor=FRONT+BOTTOM); + translate([0, $tile / 2, 0]) cube([$tile * 2 + supportWidth, supportWidth, depth + supportHeight], anchor=FRONT+BOTTOM); + } + + if (carve) { + mirror_copy([1, 0, 0]) + translate([$tile / 2, $tile / 2, 0]) group() { + cube([$stud, $stud, depth], anchor=BOTTOM+CENTER); + mirror_copy([0, 1, 0]) + mirror_copy([1, 0, 0]) + translate([$LDU * 2, $LDU * 2, 0]) + cube([$stud / 2, $stud / 2, depth], anchor=BOTTOM+FRONT+LEFT); + } + } + } +} + +module studInsert(supportThickness = $LDU * 4) { + mirror_copy([0, 1, 0]) translate([0, $tile / 2, 0]) group() { + cube([supportThickness, $stud, $stud], anchor=RIGHT); + cyl(l=$studHeight, d=$stud, $fn=48, anchor=TOP, orient=LEFT); + } + translate([-supportThickness, 0, 0]) cube([supportThickness, $tile + $stud + $LDU, $stud], anchor=RIGHT); +} + module brickSlot(w=1, l=1, h=3) { cube([$tile * w, $tile * l, $plate * h], anchor=TOP); mirror_copy([1, 0, 0]) @@ -74,26 +108,20 @@ module endCapStraight(includeRail=true) { difference() { union() { cube([$width, $tile * 2, $tile], anchor=CENTER); - mirror_copy([0, 1, 0]) - translate([0, $tile / 2, 0]) - cyl(l=$width + $studHeight * 2 + $LDU / 2, d=$stud, orient=LEFT, $fn=24); + if (!StudInserts) { + mirror_copy([1, 0, 0]) translate([$width / 2, 0, 0]) studInsert(); + } // End Slot translate([$tile + $LDU, -$tile, 0]) cube([6 * $LDU, $LDU, $tile], anchor=LEFT+BACK); - - if (Support) { - mirror_copy([1, 0, 0]) difference() { - translate([$tile * 2 - $studHeight, 0, -$tile / 2]) cube([$LDU * 3, $tile * 2 - $LDU - 2, $LDU * 6], anchor=BOTTOM+RIGHT); - mirror_copy([0, 1, 0]) - translate([0, $tile / 2, 0]) - cyl(l=$width + $studHeight * 2 + $LDU / 2, d=$stud + LayerHeight * 2, orient=LEFT, $fn=24); - } - } } - // Brick slots - mirror_copy([1, 0, 0]) - translate([$tile / 2, -$tile / 2, $tile / 2 - $plate * 2]) - brickSlot(); + + if (StudInserts) { + mirror_copy([1, 0, 0]) translate([$width / 2, 0, 0]) studInsert(); + } + + translate([0, -$tile, $tile / 2 - $plate * 2]) cube([$tile * 2, $tile, $plate], anchor=FRONT+TOP); + translate([0, -$tile, $tile / 2 - $plate * 2]) antiStudInsert(carve=false); // Fingernail slot mirror_copy([1, 0, 0]) @@ -113,11 +141,8 @@ module endCapStraight(includeRail=true) { cyl(d=$fillet, h=$tile, $fn=12); } - if (Support) { - translate([0, -$tile, -$tile / 2]) - rect_tube(size=[$tile * 2 - $LDU * 2, $tile - $LDU * 2], h=$LDU * 4 - LayerHeight, wall=$LDU * 2, anchor=FRONT+BOTTOM); - translate([0, -$tile, -$tile / 2]) - cube([$LDU * 2, $tile - $LDU * 2, $LDU * 4 - LayerHeight], anchor=FRONT+BOTTOM); + if (!AntiStudInserts) { + translate([0, -$tile, $tile / 2 - $plate * 2]) antiStudInsert(); } if (includeRail) { @@ -137,6 +162,9 @@ module monorailCurve(r=28, sa, ea, p1) { angle = [180 - ea, 180 + sa]; points = arc($n_teeth, r=(r * $tile), angle=angle); + echo(points[0] / $tile); + echo(points[len(points) - 1] / $tile); + translate([r * $tile, 0, 0]) union() { translate(points[0]) rot(180 - ea) back($tile) endCapStraight(includeRail=false); translate(points[len(points) - 1]) rot(sa) back($tile) endCapStraight(includeRail=false); @@ -176,10 +204,17 @@ module monorailStraight(l) { } } -if (Angle == 0) - monorailStraight(l=Length); -else - monorailCurve(Radius, sa=0, ea=UseLengthForCurveAngle ? asin(Length / Radius) : Angle); +if (Type == "rail") { + if (Angle == 0) + monorailStraight(l=Length); + else + monorailCurve(Radius, sa=0, ea=UseLengthForCurveAngle ? asin(Length / Radius) : Angle); +} else if (Type == "studs") { + rotate([0, -90, 0]) studInsert(); +} else if (Type == "antistuds") { + rotate([180, 0, 180]) antiStudInsert(); +} + // endCapStraight(); // translate([28.75, -232, -5.75]) rotate([0, 0, 90]) import("straight.stl");