Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a94e462f34 | ||
|
7ce991e625 | ||
|
3e15be852f | ||
|
7c1c8e92f2 | ||
|
54c3b4f600 | ||
|
d80fc5709e | ||
|
f62ca35c86 | ||
|
769cb44207 | ||
|
f327df95a3 | ||
|
09956b6219 | ||
|
f8c9adca5a | ||
|
b83e56713f | ||
|
4c12d5fca4 | ||
|
da4f9fbdc3 | ||
|
614e5f3a72 | ||
|
a7eae4f549 | ||
|
3cd5769708 | ||
|
7b770abe12 | ||
|
31ab8562a7 | ||
|
db703379a3 | ||
|
cd925bc049 | ||
|
4a2951e22f | ||
|
a93a8f99fb | ||
|
73c436ee15 | ||
|
c69100bd71 | ||
|
e0b89359aa | ||
|
041d720c39 | ||
|
03a0c2fe98 | ||
|
7c2df8d36d | ||
|
8474718884 | ||
|
fe0f32ddc5 | ||
|
f191b9b0f4 | ||
|
2b3908b6fd | ||
|
0a84bf0927 | ||
|
da825b17ab | ||
|
ca153c971d | ||
|
0199587907 | ||
|
60350eb228 | ||
|
4f9729cf86 | ||
|
26f1338ca2 | ||
|
fc44b43638 | ||
|
182f39876a | ||
|
055e90cbb3 | ||
|
832380f893 | ||
|
929d082b25 | ||
|
57212b5701 | ||
|
1c3f136657 | ||
|
cfd2fd32a1 | ||
|
f573a91a09 | ||
|
d75aff2ccd | ||
|
491d85156c | ||
|
c89ce6843f | ||
|
1915dae034 | ||
|
c4fe1d1098 | ||
|
22b7aa956c |
1705
CHANGELOG.md
Normal file
@@ -3,6 +3,7 @@
|
||||
"name": "base_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {},
|
||||
"vitamins": {
|
||||
@@ -22,6 +23,7 @@
|
||||
"name": "feet_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"base_assembly": 1
|
||||
@@ -49,6 +51,7 @@
|
||||
"name": "mains_in_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"feet_assembly": 1
|
||||
@@ -86,6 +89,7 @@
|
||||
"name": "main_assembly",
|
||||
"big": null,
|
||||
"ngb": false,
|
||||
"zoomed": 0,
|
||||
"count": 1,
|
||||
"assemblies": {
|
||||
"mains_in_assembly": 1
|
||||
|
@@ -1,40 +1,30 @@
|
||||
# A gallery of projects made with NopSCADlib
|
||||
<a name="TOP"></a>
|
||||
## ArduinoThermostat
|
||||
Arduino thermostat to control a beer fridge to use it as an environmental chamber.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## EnviroPlus
|
||||
Environmental monitor using Enviro+ sensor board and a Raspberry Pi Zero.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## FilamentDryBox
|
||||
A small fan oven with a spool holder to keep the filament warm and dry.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## HydraBot
|
||||
Current state of HydraRaptor after being modified for laser engraving.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## IOT 50V PSU
|
||||
WiFi controllable PSU
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Lab ATX PSU
|
||||
Bench power supply built around an ATX PSU.
|
||||
|
||||
@@ -47,15 +37,11 @@ Bench power supply built around an ATX PSU.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Laser Load
|
||||
15kV dummy load for testing CO2 laser PSUs
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## MainsBreakOutBox
|
||||
13A socket break out box with 4mm jacks to measure voltage and / or load current and earth leakage current.
|
||||
|
||||
@@ -72,8 +58,6 @@ Earth leakage can be measured Canadian CSA style by disconnected the neutral lin
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Mains Box
|
||||
Mains isolated and variable supply with metering.
|
||||
|
||||
@@ -81,15 +65,11 @@ Mains isolated and variable supply with metering.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## SunBot
|
||||
A solar tracker to keep a solar panel pointing at the sun.
|
||||
|
||||

|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Turntable
|
||||
WiFi enabled remote control turntable for photography
|
||||
|
||||
@@ -97,8 +77,6 @@ WiFi enabled remote control turntable for photography
|
||||
|
||||
Was actually made from DiBond but shown made with carbon fibre here.
|
||||
|
||||
|
||||
<a name="TOP"></a>
|
||||
## Variac
|
||||
Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp8266-spi-spy](https://hydraraptor.blogspot.com/2018/04/esp8266-spi-spy.html)
|
||||
|
||||
@@ -106,4 +84,3 @@ Motorised variac with WiFi control, see [hydraraptor.blogspot.com/2018/04/esp826
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
libtest.png
Before Width: | Height: | Size: 882 KiB After Width: | Height: | Size: 884 KiB |
12
libtest.scad
@@ -33,6 +33,8 @@
|
||||
//!
|
||||
//! See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
//!
|
||||
//! A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
|
||||
//!
|
||||
//! <img src="libtest.png" width="100%"/>
|
||||
//
|
||||
// This file shows all the parts in the library.
|
||||
@@ -117,6 +119,7 @@ use <tests/flat_hinge.scad>
|
||||
use <tests/foot.scad>
|
||||
use <tests/handle.scad>
|
||||
use <tests/PCB_mount.scad>
|
||||
use <tests/pocket_handle.scad>
|
||||
use <tests/printed_box.scad>
|
||||
use <tests/printed_pulleys.scad>
|
||||
use <tests/ribbon_clamp.scad>
|
||||
@@ -180,7 +183,10 @@ translate([x5, cable_grommets_y + 250])
|
||||
translate([950, 600])
|
||||
box_test();
|
||||
|
||||
translate([890, 750])
|
||||
translate([830, 770])
|
||||
pocket_handles();
|
||||
|
||||
translate([950, 750])
|
||||
printed_boxes();
|
||||
|
||||
translate([850, 1330])
|
||||
@@ -201,8 +207,8 @@ ball_bearings_y = pillars_y + 40;
|
||||
pulleys_y = ball_bearings_y +40;
|
||||
hot_ends_y = pulleys_y + 60;
|
||||
linear_bearings_y = hot_ends_y + 50;
|
||||
sheets_y = linear_bearings_y + 100;
|
||||
pcbs_y = sheets_y + 40;
|
||||
sheets_y = linear_bearings_y + 90;
|
||||
pcbs_y = sheets_y + 60;
|
||||
displays_y = pcbs_y + 170;
|
||||
fans_y = displays_y + 80;
|
||||
transformers_y = fans_y + 120;
|
||||
|
@@ -227,7 +227,7 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
translate_z(-box_profile_overlap(type)) difference() {
|
||||
tw = w + 2 * outset;
|
||||
td = d + 2 * outset;
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type), false);
|
||||
rounded_rectangle([tw, td, feet ? foot_height : height], box_corner_rad(type));
|
||||
//
|
||||
// Remove edges between the feet
|
||||
//
|
||||
@@ -264,7 +264,7 @@ module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
|
||||
// recess for top / bottom panel
|
||||
//
|
||||
translate_z(cgap)
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
|
||||
rounded_rectangle([w + bezel_clearance, d + bezel_clearance, height], inner_r + bezel_clearance / 2);
|
||||
//
|
||||
// leave plastic over the corner profiles
|
||||
//
|
||||
|
@@ -116,10 +116,10 @@ module MT3608_carrier_stl() { //! Generate the STL for an MT3608 carrier, two re
|
||||
difference() {
|
||||
hull() {
|
||||
translate([offset, 0, height - eps / 2])
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
|
||||
translate_z(eps / 2)
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1);
|
||||
rounded_rectangle([width, pcb_width - 2, eps], 1, true);
|
||||
}
|
||||
for(side = [-1, 1])
|
||||
hull() {
|
||||
|
@@ -44,7 +44,7 @@ module door_latch_stl() { //! Generates the STL for the printed part
|
||||
difference() {
|
||||
union() {
|
||||
hull() {
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
|
||||
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad);
|
||||
|
||||
translate_z(thickness / 2)
|
||||
cube([length, ridge, thickness], center = true);
|
||||
|
154
printed/pocket_handle.scad
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Customisable pocket handle
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
function pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4) = //! Construct a pocket_handle property list
|
||||
[hand_size, slant, screw, panel_t, wall, rad];
|
||||
|
||||
function pocket_handle_hand_size(type) = type[0]; //! Size of the hole for the fingers
|
||||
function pocket_handle_slant(type) = type[1]; //! Upward slant of the hand hole
|
||||
function pocket_handle_screw(type) = type[2]; //! Screw type, can be countersunk or not
|
||||
function pocket_handle_panel_t(type) = type[3]; //! Thickness of the panel it is mounted in
|
||||
function pocket_handle_wall(type) = type[4]; //! Wall thickness
|
||||
function pocket_handle_rad(type) = type[5]; //! Min corner rad
|
||||
|
||||
function pocket_handle_flange(type) = //! Size of the flange
|
||||
let(w = pocket_handle_wall(type),
|
||||
f = washer_diameter(screw_washer(pocket_handle_screw(type))) + 2 + w,
|
||||
s = pocket_handle_hand_size(type))
|
||||
[s.x + 2 * f, s.y + 2 * f, w];
|
||||
|
||||
module pocket_handle_hole_positions(type) { //! Place children at screw hole positions
|
||||
f = pocket_handle_flange(type);
|
||||
h = pocket_handle_hand_size(type);
|
||||
x_pitch = (f.x + h.x) / 4;
|
||||
y_pitch = (f.y + h.y) / 4;
|
||||
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * x_pitch, y * y_pitch])
|
||||
children();
|
||||
}
|
||||
|
||||
module pocket_handle_holes(type, h = 0) { //! Panel cutout and screw holes
|
||||
hand = pocket_handle_hand_size(type);
|
||||
w = pocket_handle_wall(type);
|
||||
slot = [hand.x + 2 * w, hand.y + 2 * w];
|
||||
t = pocket_handle_panel_t(type);
|
||||
clearance = norm([slot.y, t]) - slot.y + 0.2; // has to be enough clearance for the diagonal to swing it in
|
||||
|
||||
extrude_if(h) {
|
||||
pocket_handle_hole_positions(type)
|
||||
drill(screw_clearance_radius(pocket_handle_screw(type)), 0);
|
||||
|
||||
rounded_square([slot.x + clearance, slot.y + clearance], pocket_handle_rad(type) + w + clearance / 2);
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle(type) { //! Generate STL for pocket_handle
|
||||
f = pocket_handle_flange(type);
|
||||
r = pocket_handle_rad(type);
|
||||
s = pocket_handle_slant(type);
|
||||
o = f.z * tan(s);
|
||||
h = pocket_handle_hand_size(type);
|
||||
t = pocket_handle_panel_t(type);
|
||||
w = pocket_handle_wall(type);
|
||||
screw = pocket_handle_screw(type) ;
|
||||
|
||||
stl("pocket_handle")
|
||||
union() {
|
||||
difference() {
|
||||
hull() {
|
||||
rounded_rectangle(f, r);
|
||||
|
||||
translate_z(f.z - eps)
|
||||
rounded_rectangle([f.x + 2 * o, f.y + 2 * o, eps], r + o);
|
||||
}
|
||||
hull() {
|
||||
rounded_rectangle([h.x, h.y, f.z + eps], r);
|
||||
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x + 2 * o, h.y + 2 * o, eps], r + o);
|
||||
}
|
||||
pocket_handle_hole_positions(type) {
|
||||
if(screw_head_height(screw))
|
||||
translate_z(-eps)
|
||||
poly_cylinder(r = screw_clearance_radius(screw), h = f.z + 2 * eps, center = false);
|
||||
else
|
||||
screw_polysink(screw, h = 2 * f.z + eps, alt = true);
|
||||
}
|
||||
}
|
||||
|
||||
translate_z(f.z)
|
||||
linear_extrude(t)
|
||||
difference() {
|
||||
rounded_square([h.x + 2 * w, h.y + 2 * w], r + w);
|
||||
|
||||
rounded_square([h.x, h.y], r);
|
||||
}
|
||||
|
||||
translate_z(f.z + t)
|
||||
difference() {
|
||||
height = h.z - f.z - t;
|
||||
hull() {
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
|
||||
translate((height + w) * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x + 2 * w, h.y + 2 * w, eps], r + w);
|
||||
}
|
||||
|
||||
hull() {
|
||||
translate_z(-eps)
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
|
||||
translate(height * [0, sin(s), cos(s)])
|
||||
rounded_rectangle([h.x, h.y, eps], r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module pocket_handle_assembly(type) { //! Assembly with fasteners in place
|
||||
f = pocket_handle_flange(type);
|
||||
screw = pocket_handle_screw(type);
|
||||
nut = screw_nut(screw);
|
||||
t = pocket_handle_panel_t(type);
|
||||
washers = screw_head_height(screw) ? 2 : 1;
|
||||
screw_length = screw_length(screw, f.z + t, washers, nyloc = true);
|
||||
|
||||
translate_z(f.z + t / 2) hflip() {
|
||||
stl_colour(pp1_colour)
|
||||
pocket_handle(type);
|
||||
|
||||
pocket_handle_hole_positions(type) {
|
||||
translate_z(f.z + t)
|
||||
explode(15, true)
|
||||
nut_and_washer(nut, true);
|
||||
|
||||
vflip()
|
||||
if(washers == 2)
|
||||
screw_and_washer(screw, screw_length);
|
||||
else
|
||||
screw(screw, screw_length);
|
||||
}
|
||||
}
|
||||
}
|
@@ -182,7 +182,7 @@ module pbox(type) { //! Generate the STL for the main case
|
||||
if(ledge_h)
|
||||
translate_z(top_thickness + height - ledge_h)
|
||||
difference() {
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1, center = false);
|
||||
rounded_rectangle([pbox_width(type) + 2 * outset, pbox_depth(type) + 2 * outset, ledge_h], 1);
|
||||
|
||||
hull() {
|
||||
linear_extrude(ledge_h + eps)
|
||||
|
@@ -110,7 +110,7 @@ module psu_shroud(type, cable_d, name, cables = 1) { //! Generate the STL file f
|
||||
stl(str("psu_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([centre_x, -centre_y]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
linear_extrude(height)
|
||||
difference() {
|
||||
|
@@ -71,7 +71,7 @@ module ssr_shroud(type, cable_d, name) { //! Generate the STL file for a spec
|
||||
stl(str("ssr_shroud_", name)) {
|
||||
// base and sides
|
||||
translate([center_x, 0]) {
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad, center = false);
|
||||
rounded_rectangle([depth - eps, width - eps, top], rad);
|
||||
|
||||
linear_extrude(height) difference() {
|
||||
round(or = wall / 2 - eps, ir = 0) difference() {
|
||||
|
189
readme.md
@@ -14,6 +14,8 @@ The license is GNU General Public License v3.0, see [COPYING](COPYING).
|
||||
|
||||
See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.
|
||||
|
||||
A list of changes classified as breaking, additions or fixes is maintained in [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
<img src="libtest.png" width="100%"/>
|
||||
|
||||
## Table of Contents<a name="top"/>
|
||||
@@ -22,28 +24,28 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
|
||||
<tr><td> <a href = "#Axials">Axials</a> </td><td> <a href = "#Jack">Jack</a> </td><td> <a href = "#Rails">Rails</a> </td><td> <a href = "#Box">Box</a> </td><td> <a href = "#Annotation">Annotation</a> </td><td> <a href = "#BOM">BOM</a> </td></tr>
|
||||
<tr><td> <a href = "#Ball_bearings">Ball_bearings</a> </td><td> <a href = "#KP_pillow_blocks">KP_pillow_blocks</a> </td><td> <a href = "#Ring_terminals">Ring_terminals</a> </td><td> <a href = "#Butt_box">Butt_box</a> </td><td> <a href = "#Bezier">Bezier</a> </td><td> <a href = "#Clip">Clip</a> </td></tr>
|
||||
<tr><td> <a href = "#Batteries">Batteries</a> </td><td> <a href = "#LDRs">LDRs</a> </td><td> <a href = "#Rockers">Rockers</a> </td><td> <a href = "#Cable_grommets">Cable_grommets</a> </td><td> <a href = "#Catenary">Catenary</a> </td><td> <a href = "#Global">Global</a> </td></tr>
|
||||
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
|
||||
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
|
||||
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
|
||||
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
|
||||
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_right_triangle">Rounded_right_triangle</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Inserts">Inserts</a> </td><td></td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td> <a href = "#Zipties">Zipties</a> </td><td></td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Belts">Belts</a> </td><td> <a href = "#LED_meters">LED_meters</a> </td><td> <a href = "#Rod">Rod</a> </td><td> <a href = "#Camera_housing">Camera_housing</a> </td><td> <a href = "#Core_xy">Core_xy</a> </td><td> <a href = "#Polyholes">Polyholes</a> </td></tr>
|
||||
<tr><td> <a href = "#Blowers">Blowers</a> </td><td> <a href = "#LEDs">LEDs</a> </td><td> <a href = "#SCS_bearing_blocks">SCS_bearing_blocks</a> </td><td> <a href = "#Carriers">Carriers</a> </td><td> <a href = "#Dogbones">Dogbones</a> </td><td> <a href = "#Rounded_rectangle">Rounded_rectangle</a> </td></tr>
|
||||
<tr><td> <a href = "#Bulldogs">Bulldogs</a> </td><td> <a href = "#Leadnuts">Leadnuts</a> </td><td> <a href = "#SK_brackets">SK_brackets</a> </td><td> <a href = "#Corner_block">Corner_block</a> </td><td> <a href = "#Fillet">Fillet</a> </td><td> <a href = "#Sphere">Sphere</a> </td></tr>
|
||||
<tr><td> <a href = "#Buttons">Buttons</a> </td><td> <a href = "#Light_strips">Light_strips</a> </td><td> <a href = "#SMDs">SMDs</a> </td><td> <a href = "#Door_hinge">Door_hinge</a> </td><td> <a href = "#Gears">Gears</a> </td><td> <a href = "#Teardrops">Teardrops</a> </td></tr>
|
||||
<tr><td> <a href = "#Cable_strips">Cable_strips</a> </td><td> <a href = "#Linear_bearings">Linear_bearings</a> </td><td> <a href = "#SSRs">SSRs</a> </td><td> <a href = "#Door_latch">Door_latch</a> </td><td> <a href = "#Hanging_hole">Hanging_hole</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Cameras">Cameras</a> </td><td> <a href = "#Magnets">Magnets</a> </td><td> <a href = "#Screws">Screws</a> </td><td> <a href = "#Drag_chain">Drag_chain</a> </td><td> <a href = "#Horiholes">Horiholes</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Circlips">Circlips</a> </td><td> <a href = "#Mains_sockets">Mains_sockets</a> </td><td> <a href = "#Sealing_strip">Sealing_strip</a> </td><td> <a href = "#Fan_guard">Fan_guard</a> </td><td> <a href = "#Layout">Layout</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Components">Components</a> </td><td> <a href = "#Microswitches">Microswitches</a> </td><td> <a href = "#Shaft_couplings">Shaft_couplings</a> </td><td> <a href = "#Fixing_block">Fixing_block</a> </td><td> <a href = "#Maths">Maths</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#DIP">DIP</a> </td><td> <a href = "#Microview">Microview</a> </td><td> <a href = "#Sheets">Sheets</a> </td><td> <a href = "#Flat_hinge">Flat_hinge</a> </td><td> <a href = "#Offset">Offset</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#D_connectors">D_connectors</a> </td><td> <a href = "#Modules">Modules</a> </td><td> <a href = "#Spades">Spades</a> </td><td> <a href = "#Foot">Foot</a> </td><td> <a href = "#Quadrant">Quadrant</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Displays">Displays</a> </td><td> <a href = "#Nuts">Nuts</a> </td><td> <a href = "#Spools">Spools</a> </td><td> <a href = "#Handle">Handle</a> </td><td> <a href = "#Round">Round</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusion_brackets">Extrusion_brackets</a> </td><td> <a href = "#O_ring">O_ring</a> </td><td> <a href = "#Springs">Springs</a> </td><td> <a href = "#PCB_mount">PCB_mount</a> </td><td> <a href = "#Rounded_cylinder">Rounded_cylinder</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Extrusions">Extrusions</a> </td><td> <a href = "#Opengrab">Opengrab</a> </td><td> <a href = "#Stepper_motors">Stepper_motors</a> </td><td> <a href = "#PSU_shroud">PSU_shroud</a> </td><td> <a href = "#Rounded_polygon">Rounded_polygon</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fans">Fans</a> </td><td> <a href = "#PCB">PCB</a> </td><td> <a href = "#Swiss_clips">Swiss_clips</a> </td><td> <a href = "#Pocket_handle">Pocket_handle</a> </td><td> <a href = "#Rounded_right_triangle">Rounded_right_triangle</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Fuseholder">Fuseholder</a> </td><td> <a href = "#PCBs">PCBs</a> </td><td> <a href = "#Toggles">Toggles</a> </td><td> <a href = "#Press_fit">Press_fit</a> </td><td> <a href = "#Sector">Sector</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Geared_steppers">Geared_steppers</a> </td><td> <a href = "#PSUs">PSUs</a> </td><td> <a href = "#Transformers">Transformers</a> </td><td> <a href = "#Printed_box">Printed_box</a> </td><td> <a href = "#Sweep">Sweep</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Green_terminals">Green_terminals</a> </td><td> <a href = "#Panel_meters">Panel_meters</a> </td><td> <a href = "#Tubings">Tubings</a> </td><td> <a href = "#Printed_pulleys">Printed_pulleys</a> </td><td> <a href = "#Thread">Thread</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hot_ends">Hot_ends</a> </td><td> <a href = "#Pillars">Pillars</a> </td><td> <a href = "#Variacs">Variacs</a> </td><td> <a href = "#Ribbon_clamp">Ribbon_clamp</a> </td><td> <a href = "#Tube">Tube</a> </td><td></td></tr>
|
||||
<tr><td> <a href = "#Hygrometer">Hygrometer</a> </td><td> <a href = "#Pin_headers">Pin_headers</a> </td><td> <a href = "#Veroboard">Veroboard</a> </td><td> <a href = "#SSR_shroud">SSR_shroud</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#IECs">IECs</a> </td><td> <a href = "#Pulleys">Pulleys</a> </td><td> <a href = "#Washers">Washers</a> </td><td> <a href = "#Screw_knob">Screw_knob</a> </td><td></td><td></td></tr>
|
||||
<tr><td> <a href = "#Inserts">Inserts</a> </td><td></td><td> <a href = "#Wire">Wire</a> </td><td> <a href = "#Socket_box">Socket_box</a> </td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td> <a href = "#Zipties">Zipties</a> </td><td> <a href = "#Strap_handle">Strap_handle</a> </td><td></td><td></td></tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
@@ -3154,6 +3156,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
|
||||
| 1 | `sheet(FoilTape, 30, 30, 2)` | Aluminium foil tape 30mm x 30mm x 0.05mm |
|
||||
| 1 | `sheet(AL6, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 6mm |
|
||||
| 1 | `sheet(AL8, 30, 30, 2)` | Aluminium tooling plate 30mm x 30mm x 8mm |
|
||||
| 1 | `sheet(Spring05, 30, 30, 2)` | Bi-metal saw blade 30mm x 30mm x 0.5mm |
|
||||
| 1 | `sheet(Cardboard, 30, 30, 2)` | Corrugated cardboard 30mm x 30mm x 5mm |
|
||||
| 1 | `sheet(Foam20, 30, 30, 2)` | Foam sponge 30mm x 30mm x 20mm |
|
||||
| 1 | `sheet(DiBond, 30, 30, 2)` | Sheet DiBond 30mm x 30mm x 3mm |
|
||||
@@ -3172,6 +3175,7 @@ When woven sheets (e.g. carbon fibre) are rendered it is necessary to specify th
|
||||
| 1 | `sheet(CF3, 30, 30, 2)` | Sheet carbon fiber 30mm x 30mm x 3mm |
|
||||
| 1 | `sheet(glass2, 30, 30, 2)` | Sheet glass 30mm x 30mm x 2mm |
|
||||
| 1 | `sheet(Steel06, 30, 30, 2)` | Sheet mild steel 30mm x 30mm x 0.6mm |
|
||||
| 1 | `sheet(Silicone3, 30, 30, 2)` | Sheet silicone 30mm x 30mm x 3mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
@@ -4956,6 +4960,56 @@ The stl must be given a parameterless wrapper in the project that uses it.
|
||||
| 1 | pcb_mount_PI_IO_5.stl |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
<a name="Pocket_handle"></a>
|
||||
## Pocket_handle
|
||||
Customisable pocket handle
|
||||
|
||||
[printed/pocket_handle.scad](printed/pocket_handle.scad) Implementation.
|
||||
|
||||
[tests/pocket_handle.scad](tests/pocket_handle.scad) Code for this example.
|
||||
|
||||
### Properties
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle_hand_size(type)` | Size of the hole for the fingers |
|
||||
| `pocket_handle_panel_t(type)` | Thickness of the panel it is mounted in |
|
||||
| `pocket_handle_rad(type)` | Min corner rad |
|
||||
| `pocket_handle_screw(type)` | Screw type, can be countersunk or not |
|
||||
| `pocket_handle_slant(type)` | Upward slant of the hand hole |
|
||||
| `pocket_handle_wall(type)` | Wall thickness |
|
||||
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle(hand_size = [90, 40, 40], slant = 35, screw = M3_cs_cap_screw, panel_t = 3, wall = 4, rad = 4)` | Construct a pocket_handle property list |
|
||||
| `pocket_handle_flange(type)` | Size of the flange |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `pocket_handle(type)` | Generate STL for pocket_handle |
|
||||
| `pocket_handle_assembly(type)` | Assembly with fasteners in place |
|
||||
| `pocket_handle_hole_positions(type)` | Place children at screw hole positions |
|
||||
| `pocket_handle_holes(type, h = 0)` | Panel cutout and screw holes |
|
||||
|
||||

|
||||
|
||||
### Vitamins
|
||||
| Qty | Module call | BOM entry |
|
||||
| ---:|:--- |:---|
|
||||
| 4 | `nut(M3_nut, nyloc = true)` | Nut M3 x 2.4mm nyloc |
|
||||
| 4 | `screw(M3_cs_cap_screw, 12)` | Screw M3 cs cap x 12mm |
|
||||
| 4 | `washer(M3_washer)` | Washer M3 x 7mm x 0.5mm |
|
||||
|
||||
### Printed
|
||||
| Qty | Filename |
|
||||
| ---:|:--- |
|
||||
| 1 | pocket_handle.stl |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
@@ -5520,6 +5574,69 @@ The coordinates of the lowest point on the curve can be retrieved by calling `ca
|
||||

|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
<a name="Core_xy"></a>
|
||||
## Core_xy
|
||||
Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
|
||||
|
||||
The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
|
||||
Implementation has the following features:
|
||||
1. The drive and idler pulleys may be different sizes.
|
||||
2. The belt separation is parameterised.
|
||||
3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
|
||||
4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
|
||||
allows flexible positioning of the motors.
|
||||
|
||||
[utils/core_xy.scad](utils/core_xy.scad) Implementation.
|
||||
|
||||
[tests/core_xy.scad](tests/core_xy.scad) Code for this example.
|
||||
|
||||
### Properties
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY_belt(type)` | Belt type |
|
||||
| `coreXY_drive_pulley(type)` | Drive pulley type |
|
||||
| `coreXY_lower_belt_colour(type)` | Colour of the lower belt |
|
||||
| `coreXY_lower_tooth_colour(type)` | Colour of the lower belt's teeth |
|
||||
| `coreXY_plain_idler(type)` | Plain idler type |
|
||||
| `coreXY_toothed_idler(type)` | Toothed idler type |
|
||||
| `coreXY_upper_belt_colour(type)` | Colour of the upper belt |
|
||||
| `coreXY_upper_tooth_colour(type)` | Colour of the upper belt's teeth |
|
||||
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY_coincident_separation(type)` | Value of x, y separation to make y-carriage pulleys coincident |
|
||||
| `coreXY_drive_plain_idler_offset(type)` | Offset of plain drive idler pulley |
|
||||
| `coreXY_drive_pulley_x_alignment(type)` | Belt alignment offset of the drive pulley relative to the anchor pulley |
|
||||
| `coreXY_drive_toothed_idler_offset(type)` | Offset of toothed drive idler pulley |
|
||||
| `coreXY_plain_idler_offset(type)` | Offset of y-carriage plain idler |
|
||||
| `coreXY_toothed_idler_offset(type)` | offset of y-carriage toothed idler |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false)` | Wrapper module to draw both belts of a coreXY setup |
|
||||
| `coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false)` | Draw the coreXY belts |
|
||||
| `coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false)` | Draw one belt of a coreXY setup |
|
||||
|
||||

|
||||
|
||||
### Vitamins
|
||||
| Qty | Module call | BOM entry |
|
||||
| ---:|:--- |:---|
|
||||
| 1 | `belt(GT2x6, [ ... ], [10.0078, 11.69], [0, -24.686])` | Belt GT2 x 6mm x 742mm |
|
||||
| 1 | `belt(GT2x6, [ ... ], [10.0078, 11.69], [0, -24.686])` | Belt GT2 x 6mm x 852mm |
|
||||
| 7 | `pulley(GT2x16_toothed_idler)` | Pulley GT2 idler 16 teeth |
|
||||
| 3 | `pulley(GT2x16_plain_idler)` | Pulley GT2 idler smooth 9.63mm |
|
||||
| 2 | `pulley(GT2x20ob_pulley)` | Pulley GT2OB 20 teeth |
|
||||
| 8 | `screw(M3_cap_screw, 20)` | Screw M3 cap x 20mm |
|
||||
| 4 | `screw(M3_grub_screw, 6)` | Screw M3 grub x 6mm |
|
||||
| 2 | `NEMA(NEMA17M)` | Stepper motor NEMA17 x 40mm |
|
||||
|
||||
|
||||
<a href="#top">Top</a>
|
||||
|
||||
---
|
||||
@@ -6016,6 +6133,13 @@ If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` modu
|
||||
it with code.
|
||||
This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
|
||||
|
||||
The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
|
||||
|
||||
* Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
|
||||
* If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
|
||||
* To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
|
||||
* Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
|
||||
|
||||
[utils/core/bom.scad](utils/core/bom.scad) Implementation.
|
||||
|
||||
[tests/BOM.scad](tests/BOM.scad) Code for this example.
|
||||
@@ -6039,7 +6163,7 @@ This can speed up the generation of the build instructions greatly but isn't com
|
||||
| `no_explode()` | Prevent children being exploded |
|
||||
| `no_pose()` | Force children not to be posed even if parent is |
|
||||
| `not_on_bom(on = false)` | Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled |
|
||||
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef)` | Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose_hflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `pose_vflip(exploded = undef)` | Pose an STL or assembly for rendering to png by flipping around the X axis, `exploded = true for` just the exploded view or `false` for unexploded only. |
|
||||
| `stl(name)` | Name an stl that will appear on the BOM, there needs to a module named `<name>_stl` to make it |
|
||||
@@ -6173,18 +6297,18 @@ leaving a scar on either surface.
|
||||
### Functions
|
||||
| Function | Description |
|
||||
|:--- |:--- |
|
||||
| `corrected_diameter(d, n = 0)` | Adjusted diameter to make flats lie on the circle |
|
||||
| `corrected_radius(r, n = 0)` | Adjusted radius to make flats lie on the circle |
|
||||
| `sides(r)` | Optimium number of sides for specified radius |
|
||||
| `corrected_diameter(d, n = undef)` | Adjusted diameter to make flats lie on the circle |
|
||||
| `corrected_radius(r, n = undef)` | Adjusted radius to make flats lie on the circle |
|
||||
| `sides(r, n = undef)` | Optimium number of sides for specified radius |
|
||||
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle |
|
||||
| `poly_circle(r, sides = 0)` | Make a circle adjusted to print the correct size |
|
||||
| `poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
|
||||
| `poly_circle(r, sides = undef)` | Make a circle adjusted to print the correct size |
|
||||
| `poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0)` | Make a cylinder adjusted to print the correct size |
|
||||
| `poly_drill(r, h = 100, center = true)` | Make a cylinder for drilling holes suitable for CNC routing if cnc_bit_r is non zero, otherwise a poly_cylinder. |
|
||||
| `poly_ring(or, ir, sides = 0)` | Make a 2D ring adjusted to have the correct internal radius |
|
||||
| `poly_ring(or, ir, sides = undef)` | Make a 2D ring adjusted to have the correct internal radius |
|
||||
| `poly_tube(or, ir, h, center = false)` | Make a tube adjusted to have the correct internal radius |
|
||||
| `slot(r, l, h = 100)` | Make a horizontal slot suitable for CNC routing, set h = 0 for 2D version |
|
||||
|
||||
@@ -6236,9 +6360,10 @@ Rectangle with rounded corners.
|
||||
### Modules
|
||||
| Module | Description |
|
||||
|:--- |:--- |
|
||||
| `rounded_rectangle(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle_xz(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle_yz(size, r, center = true, xy_center = true)` | Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_xy(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_xz(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z. |
|
||||
| `rounded_cube_yz(size, r = 0, xy_center = false, z_center = false)` | Like `cube()` but corners rounded in YX plane and separate centre options for xy and z. |
|
||||
| `rounded_rectangle(size, r, center = false, xy_center = true)` | Like `cube()` but corners rounded in XY plane and separate centre options for xy and z. |
|
||||
| `rounded_square(size, r, center = true)` | Like `square()` but with with rounded corners |
|
||||
|
||||

|
||||
|
@@ -61,6 +61,7 @@ class BOM:
|
||||
self.name = name
|
||||
self.big = None
|
||||
self.ngb = False
|
||||
self.zoomed = 0
|
||||
self.count = 1
|
||||
self.vitamins = {}
|
||||
self.printed = {}
|
||||
@@ -75,6 +76,7 @@ class BOM:
|
||||
"name" : self.name,
|
||||
"big" : self.big,
|
||||
"ngb" : self.ngb,
|
||||
"zoomed" : self.zoomed,
|
||||
"count" : self.count,
|
||||
"assemblies" : assemblies,
|
||||
"vitamins" : {v : self.vitamins[v].data() for v in self.vitamins},
|
||||
|
163
scripts/changelog.py
Normal file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
#! Creates the changelog from the git log
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
filename = 'CHANGELOG.md'
|
||||
|
||||
def tag_version(t):
|
||||
""" Format a version tag """
|
||||
return 'v%d.%d.%d' % t
|
||||
|
||||
def initials(name):
|
||||
""" Convert full name to initials with a tooltip """
|
||||
i = ''.join([n[0].upper() + '.' for n in name.split(' ')])
|
||||
return '[%s](# "%s")' % (i, name)
|
||||
|
||||
def get_remote_url():
|
||||
""" Get the git remote URL for the repository """
|
||||
url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"]).decode("utf-8").strip("\n")
|
||||
if url.startswith("git@"):
|
||||
url = url.replace(":", "/", 1).replace("git@", "https://", 1)
|
||||
if url.endswith(".git"):
|
||||
url = url[:-4]
|
||||
return url
|
||||
|
||||
def iscode(word):
|
||||
""" try to guess if the word is code """
|
||||
endings = ['()', '*']
|
||||
starts = ['$', '--']
|
||||
anywhere = ['.', '_', '=', '[', '/']
|
||||
words = ['center', 'false', 'true', 'ngb']
|
||||
|
||||
for w in words:
|
||||
if word == w:
|
||||
return True
|
||||
|
||||
for end in endings:
|
||||
if word.endswith(end):
|
||||
return True
|
||||
|
||||
for start in starts:
|
||||
if word.startswith(start):
|
||||
return True
|
||||
|
||||
for any in anywhere:
|
||||
if word.find(any) >= 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def codify(word, url):
|
||||
""" if a word is deemed code enclose it backticks """
|
||||
if word:
|
||||
if re.match(r'#[0-9]+', word):
|
||||
return '[%s](%s "show issue")' % (word, url + '/issues/' + word[1:])
|
||||
if iscode(word):
|
||||
return '`' + word + '`'
|
||||
return word
|
||||
|
||||
|
||||
def fixup_comment(comment, url):
|
||||
""" markup code words and fix new paragraphs """
|
||||
result = ''
|
||||
word = ''
|
||||
code = False
|
||||
for i, c in enumerate(comment):
|
||||
if c == '`' or code: # Already a code block
|
||||
result += c # Copy verbatim
|
||||
if c == '`': code = not code # Keep track of state
|
||||
else:
|
||||
if c in ' \n' or (c == '.' and (i + 1 == len(comment) or comment[i + 1] in ' \n')): # if a word terminator
|
||||
result += codify(word, url) + c # Add codified word before terminator
|
||||
word = ''
|
||||
else:
|
||||
word += c # Accumulate next word
|
||||
result += codify(word, url) # In case comment ends without a terminator
|
||||
return result.replace('\n\n','\n\n * ') # Give new paragraphs a bullet point
|
||||
|
||||
class Commit(): # members dynamically added from commit_fields
|
||||
pass
|
||||
|
||||
blurb = """
|
||||
# %s Changelog
|
||||
This changelog is generated by `changelog.py` using manually added semantic version tags to classify commits as breaking changes, additions or fixes.
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
url = get_remote_url()
|
||||
|
||||
commit_fields = {
|
||||
'hash': "%H|", # commit commit_hash
|
||||
'tag': "%D|", # tag
|
||||
'author': "%aN|", # author name
|
||||
'date': " %as|", # author date short form
|
||||
'comment': "%B~" # body
|
||||
}
|
||||
|
||||
# Produce the git log
|
||||
format = ''.join([v for k, v in commit_fields.items()])
|
||||
text = subprocess.check_output(["git", "log", "--topo-order", "--format=" + format]).decode("utf-8")
|
||||
|
||||
# Process the log into a list of Commit objects
|
||||
commits = []
|
||||
for line in text.split('~'):
|
||||
line = line.strip('\n')
|
||||
if line:
|
||||
fields = line.split('|')
|
||||
commit = Commit()
|
||||
for i, k in enumerate(commit_fields):
|
||||
exec('commit.%s = """%s"""' % (k, fields[i]), locals())
|
||||
# Convert version tag to tuple
|
||||
if commit.tag:
|
||||
match = re.match(r'.*tag: v([0-9]+)\.([0-9]+)\.([0-9]+).*', commit.tag)
|
||||
commit.tag = (int(match.group(1)), int(match.group(2)), int(match.group(3))) if match else ''
|
||||
commits.append(commit)
|
||||
|
||||
# Format the results from the Commit objects
|
||||
with open(filename, "wt") as file:
|
||||
print(blurb % url.split('/')[-1], file = file)
|
||||
for i, c in enumerate(commits):
|
||||
if c.tag:
|
||||
ver = tag_version(c.tag)
|
||||
level, type = (3, 'Fixes') if c.tag[2] else (2, 'Additions') if c.tag[1] else (1, 'Breaking Changes') if c.tag[0] else (1, 'First publicised version')
|
||||
|
||||
# Find the previous tagged commit
|
||||
j = i + 1
|
||||
diff = ''
|
||||
while j < len(commits):
|
||||
if commits[j].tag:
|
||||
last_ver = tag_version(commits[j].tag)
|
||||
diff = '[...](%s "diff with %s")' % (url + '/compare/' + last_ver + '...' + ver, last_ver)
|
||||
break
|
||||
j += 1
|
||||
|
||||
# Print verson info
|
||||
print('%s [%s](%s "show release") %s %s' % ('#' * (level + 1), ver, url + '/releases/tag/' + ver, type, diff), file = file)
|
||||
|
||||
# Print commits excluding merges
|
||||
if not c.comment.startswith('Merge branch') and not c.comment.startswith('Merge pull'):
|
||||
print('* %s [`%s`](%s "show commit") %s %s\n' % (c.date, c.hash[:7], url + '/commit/' + c.hash, initials(c.author), fixup_comment(c.comment, url)), file = file)
|
@@ -18,6 +18,7 @@
|
||||
#
|
||||
import os
|
||||
from set_config import source_dir
|
||||
from colorama import Fore
|
||||
|
||||
def mtime(file):
|
||||
if os.path.isfile(file):
|
||||
@@ -41,13 +42,13 @@ def read_deps(dname):
|
||||
def check_deps(target, dname):
|
||||
target_mtime = mtime(target)
|
||||
if not target_mtime:
|
||||
return target + " missing"
|
||||
return Fore.CYAN + target + " missing" + Fore.WHITE
|
||||
if not os.path.isfile(dname):
|
||||
return "no deps"
|
||||
return Fore.CYAN + "no deps" + Fore.WHITE
|
||||
deps = read_deps(dname)
|
||||
for dep in deps:
|
||||
if mtime(dep) > target_mtime:
|
||||
return dep + ' changed'
|
||||
return Fore.CYAN + dep + ' changed' + Fore.WHITE
|
||||
return None
|
||||
|
||||
def source_dirs(bom_dir):
|
||||
|
@@ -28,7 +28,10 @@ from set_config import *
|
||||
import time
|
||||
import times
|
||||
from deps import *
|
||||
from tmpdir import *
|
||||
import json
|
||||
import shutil
|
||||
from colorama import Fore, init
|
||||
|
||||
def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
#
|
||||
@@ -43,7 +46,7 @@ def bom_to_parts(bom_dir, part_type, assembly = None):
|
||||
if words:
|
||||
last_word = words[-1]
|
||||
if last_word.endswith(suffix):
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
part_files.append(last_word[:-4] + '.' + part_type)
|
||||
return part_files
|
||||
|
||||
def usage(t):
|
||||
@@ -62,12 +65,20 @@ def make_parts(target, part_type, parts = None):
|
||||
#
|
||||
top_dir = set_config(target, lambda: usage(part_type))
|
||||
target_dir = top_dir + part_type + 's'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
old_deps = top_dir + 'deps' #old location
|
||||
if os.path.isdir(old_deps):
|
||||
shutil.rmtree(old_deps)
|
||||
|
||||
times.read_times(target_dir)
|
||||
#
|
||||
# Decide which files to make
|
||||
@@ -120,18 +131,18 @@ def make_parts(target, part_type, parts = None):
|
||||
changed = check_deps(part_file, dname)
|
||||
changed = times.check_have_time(changed, part)
|
||||
if part_type == 'stl' and not changed and not part in bounds_map:
|
||||
changed = "No bounds"
|
||||
changed = Fore.CYAN + "No bounds" + Fore.WHITE
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
part_maker_name = part_type + ".scad"
|
||||
part_maker_name = tmp_dir + '/' + part_type + ".scad"
|
||||
with open(part_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
|
||||
openscad.run("-o", part_file, part_maker_name, "-D$bom=1", "-d", dname)
|
||||
times.add_time(part, t)
|
||||
if part_type == 'stl':
|
||||
bounds = c14n_stl.canonicalise(part_file)
|
||||
@@ -145,6 +156,10 @@ def make_parts(target, part_type, parts = None):
|
||||
with open(bounds_fname, 'w') as outfile:
|
||||
json.dump(bounds_map, outfile, indent = 4)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# List the ones we didn't find
|
||||
#
|
||||
if targets:
|
||||
|
@@ -68,9 +68,10 @@ def gallery(force):
|
||||
match = re.match(r"^(#+).*$", line)
|
||||
if match:
|
||||
line = '#' + line
|
||||
if line == '---\n':
|
||||
break;
|
||||
print(line[:-1], file = output_file)
|
||||
if line == '---\n' or line == '<span></span>\n':
|
||||
break
|
||||
if line != '<a name="TOP"></a>\n':
|
||||
print(line[:-1], file = output_file)
|
||||
else:
|
||||
print(Fore.MAGENTA + "Can't find", document, Fore.WHITE);
|
||||
with open(target_dir + "/readme.html", "wt") as html_file:
|
||||
|
@@ -25,19 +25,25 @@ from __future__ import print_function
|
||||
import subprocess, sys
|
||||
|
||||
def run_list(args, silent = False, verbose = False):
|
||||
cmd = ["openscad", "--hardwarnings"] + args
|
||||
cmd = ["openscad"] + args + ["--hardwarnings"]
|
||||
if not silent:
|
||||
for arg in cmd:
|
||||
print(arg, end=" ")
|
||||
print()
|
||||
with open("openscad.log", "w") as log:
|
||||
rc = subprocess.call(cmd, stdout = log, stderr = log)
|
||||
for line in open("openscad.log", "rt"):
|
||||
log_file = "openscad.echo" if "openscad.echo" in cmd else "openscad.log"
|
||||
bad = False
|
||||
for line in open(log_file, "rt"):
|
||||
if verbose or 'ERROR:' in line or 'WARNING:' in line:
|
||||
bad = True
|
||||
print(line[:-1])
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
|
||||
if bad:
|
||||
sys.exit(1)
|
||||
|
||||
def run(*args):
|
||||
run_list(list(args), False)
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
# Set command line options from enviroment variables and check if they have changed
|
||||
|
||||
import json, os, deps
|
||||
from colorama import Fore, init
|
||||
|
||||
def check_options(dir = '.'):
|
||||
global options, options_mtime
|
||||
@@ -37,7 +38,7 @@ def check_options(dir = '.'):
|
||||
|
||||
def have_changed(changed, target):
|
||||
if not changed and deps.mtime(target) < options_mtime:
|
||||
return "command line options changed"
|
||||
return Fore.CYAN + "command line options changed" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def list():
|
||||
|
@@ -26,8 +26,10 @@ import sys
|
||||
import c14n_stl
|
||||
from set_config import *
|
||||
from deps import *
|
||||
from shutil import copyfile
|
||||
import shutil
|
||||
import re
|
||||
import time
|
||||
import times
|
||||
|
||||
source_dirs = { "stl" : "platters", "dxf" : "panels" }
|
||||
target_dirs = { "stl" : "printed", "dxf" : "routed" }
|
||||
@@ -41,22 +43,32 @@ def plateup(target, part_type, usage = None):
|
||||
target_dir = parts_dir + '/' + target_dirs[part_type]
|
||||
source_dir1 = source_dirs[part_type]
|
||||
source_dir2 = top_dir + source_dirs[part_type]
|
||||
|
||||
#
|
||||
# Loop through source directories
|
||||
#
|
||||
used = []
|
||||
all_used = []
|
||||
all_sources = []
|
||||
all_parts = []
|
||||
read_times = False
|
||||
for dir in [source_dir1, source_dir2]:
|
||||
if not os.path.isdir(dir):
|
||||
continue
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
|
||||
if not read_times:
|
||||
times.read_times(target_dir)
|
||||
read_times = True
|
||||
#
|
||||
# Make the deps dir
|
||||
#
|
||||
deps_dir = dir + "/deps"
|
||||
deps_dir = parts_dir + "/deps"
|
||||
if not os.path.isdir(deps_dir):
|
||||
os.makedirs(deps_dir)
|
||||
|
||||
if os.path.isdir(dir + '/deps'): #old deps
|
||||
shutil.rmtree(dir + '/deps')
|
||||
#
|
||||
# Decide which files to make
|
||||
#
|
||||
@@ -65,42 +77,55 @@ def plateup(target, part_type, usage = None):
|
||||
#
|
||||
# Run OpenSCAD on the source files to make the targets
|
||||
#
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
for src in sources:
|
||||
src_file = dir + '/' + src
|
||||
part_file = target_dir + '/' + src[:-4] + part_type
|
||||
part = src[:-4] + part_type
|
||||
all_parts.append(part)
|
||||
part_file = target_dir + '/' + part
|
||||
uses_file = deps_dir + '/' + src[:-4] + 'txt'
|
||||
dname = deps_name(deps_dir, src)
|
||||
changed = check_deps(part_file, dname)
|
||||
oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
|
||||
changed = check_deps(oldest, dname)
|
||||
used = []
|
||||
if changed:
|
||||
print(changed)
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
t = time.time()
|
||||
openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
|
||||
if part_type == 'stl':
|
||||
c14n_stl.canonicalise(part_file)
|
||||
times.add_time(part, t)
|
||||
log_name = 'openscad.log'
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "wt") as file:
|
||||
for part in used:
|
||||
print(part, file = file)
|
||||
else:
|
||||
log_name = 'openscad.echo'
|
||||
openscad.run_silent("-D$bom=1", "-o", log_name, src_file)
|
||||
#
|
||||
# Add the files on the BOM to the used list
|
||||
#
|
||||
with open(log_name) as file:
|
||||
for line in file.readlines():
|
||||
match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
|
||||
if match:
|
||||
used.append(match.group(1))
|
||||
with open(uses_file, "rt") as file:
|
||||
for line in file:
|
||||
used.append(line[:-1])
|
||||
all_used += used
|
||||
|
||||
copied = []
|
||||
if all_sources:
|
||||
#
|
||||
# Copy files that are not included
|
||||
#
|
||||
for file in os.listdir(parts_dir):
|
||||
if file.endswith('.' + part_type) and not file in used:
|
||||
if file.endswith('.' + part_type) and not file in all_used:
|
||||
src = parts_dir + '/' + file
|
||||
dst = target_dir + '/' + file
|
||||
if mtime(src) > mtime(dst):
|
||||
print("Copying %s to %s" % (src, dst))
|
||||
copyfile(src, dst)
|
||||
shutil.copyfile(src, dst)
|
||||
copied.append(file)
|
||||
#
|
||||
# Remove any cruft
|
||||
@@ -111,3 +136,12 @@ def plateup(target, part_type, usage = None):
|
||||
if not file in targets and not file in copied:
|
||||
print("Removing %s" % file)
|
||||
os.remove(target_dir + '/' + file)
|
||||
|
||||
targets = [file[:-4] + 'txt' for file in all_sources]
|
||||
for file in os.listdir(deps_dir):
|
||||
if file.endswith('.' + 'txt'):
|
||||
if not file in targets:
|
||||
print("Removing %s" % file)
|
||||
os.remove(deps_dir + '/' + file)
|
||||
|
||||
times.print_times(all_parts)
|
||||
|
@@ -8,6 +8,7 @@ They should work with both Python 2 and Python 3.
|
||||
|:---|:---|
|
||||
| `bom.py` | Generates BOM files for the project. |
|
||||
| `c14n_stl.py` | OpenSCAD produces randomly ordered STL files. This script re-orders them consistently so that GIT can tell if they have changed or not. |
|
||||
| `changelog.py` | Creates the changelog from the git log |
|
||||
| `doc_scripts.py` | Makes this document and doc/usage.md. |
|
||||
| `dxfs.py` | Generates DXF files for all the routed parts listed on the BOM or a specified list. |
|
||||
| `gallery.py` | Finds projects and adds them to the gallery. |
|
||||
|
@@ -30,6 +30,7 @@ from tests import do_cmd, update_image, colour_scheme, background
|
||||
from deps import mtime
|
||||
from colorama import init
|
||||
import json
|
||||
from tmpdir import *
|
||||
|
||||
def usage():
|
||||
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
|
||||
@@ -40,6 +41,7 @@ def render(target, type):
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + type + 's'
|
||||
bom_dir = top_dir + 'bom'
|
||||
if not os.path.isdir(target_dir):
|
||||
@@ -80,7 +82,7 @@ def render(target, type):
|
||||
# make a file to import the stl
|
||||
#
|
||||
if mtime(part_file) > mtime(png_name):
|
||||
png_maker_name = "png.scad"
|
||||
png_maker_name = tmp_dir + "/png.scad"
|
||||
pp1 = [0, 146/255, 0]
|
||||
colour = pp1
|
||||
if part in colours:
|
||||
@@ -88,15 +90,19 @@ def render(target, type):
|
||||
if not '[' in colour:
|
||||
colour = '"' + colour + '"'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write('color(%s) import("%s");\n' % (colour, part_file))
|
||||
f.write('color(%s) import("%s");\n' % (colour, reltmp(part_file, target)))
|
||||
cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500"
|
||||
render = "--preview" if type == 'stl' or colour != pp1 else "--render"
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", tmp_name, png_maker_name);
|
||||
tmp_name = tmp_dir + '/' + part[:-4] + '.png'
|
||||
openscad.run("-o", tmp_name, png_maker_name, colour_scheme, "--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall");
|
||||
do_cmd(("magick "+ tmp_name + " -trim -resize 280x280 -background %s -gravity Center -extent 280x280 -bordercolor %s -border 10 %s"
|
||||
% (background, background, tmp_name)).split())
|
||||
update_image(tmp_name, png_name)
|
||||
os.remove(png_maker_name)
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
init()
|
||||
|
@@ -69,17 +69,22 @@ def set_config(target, usage = None):
|
||||
sys.exit(1)
|
||||
|
||||
fname = source_dir + "/target.scad"
|
||||
text = "include <config_%s.scad>\n" % target;
|
||||
line = ""
|
||||
text = ['include <config_%s.scad>\n' % target,
|
||||
'$target = "%s";\n' % target,
|
||||
'$cwd="%s";\n' % os.getcwd().replace('\\', '/')
|
||||
]
|
||||
|
||||
lines = [""]
|
||||
try:
|
||||
with open(fname,"rt") as f:
|
||||
line = f.read()
|
||||
lines = f.readlines()
|
||||
except:
|
||||
pass
|
||||
|
||||
if line != text:
|
||||
if lines != text:
|
||||
with open(fname,"wt") as f:
|
||||
f. write(text);
|
||||
for t in text:
|
||||
f. write(t);
|
||||
return target + "/"
|
||||
|
||||
def usage():
|
||||
|
@@ -34,6 +34,7 @@ import shutil
|
||||
from deps import *
|
||||
from blurb import *
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
w = 4096
|
||||
h = w
|
||||
@@ -59,7 +60,8 @@ def compare_images(a, b, c):
|
||||
with open(log_name, 'w') as output:
|
||||
do_cmd(("magick compare -metric AE -fuzz %d%% %s %s %s" % (fuzz, a, b, c)).split(), output = output)
|
||||
with open(log_name, 'r') as f:
|
||||
pixels = int(float(f.read().strip()))
|
||||
pixels = f.read().strip()
|
||||
pixels = int(float(pixels if pixels.isnumeric() else -1))
|
||||
os.remove(log_name)
|
||||
return pixels
|
||||
|
||||
@@ -94,6 +96,7 @@ def usage():
|
||||
|
||||
def tests(tests):
|
||||
scad_dir = "tests"
|
||||
tmp_dir = mktmpdir(scad_dir + '/')
|
||||
deps_dir = scad_dir + "/deps"
|
||||
png_dir = scad_dir + "/png"
|
||||
bom_dir = scad_dir + "/bom"
|
||||
@@ -114,7 +117,7 @@ def tests(tests):
|
||||
libtest = True
|
||||
lib_blurb = scrape_blurb(scad_name)
|
||||
if not os.path.isfile(png_name):
|
||||
openscad.run(colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
|
||||
openscad.run(scad_name, "-o", png_name, colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall");
|
||||
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", background, "-border", "10", png_name])
|
||||
else:
|
||||
#
|
||||
@@ -234,8 +237,8 @@ def tests(tests):
|
||||
if changed:
|
||||
print(changed)
|
||||
t = time.time()
|
||||
tmp_name = 'tmp.png'
|
||||
openscad.run_list(options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, scad_name]);
|
||||
tmp_name = tmp_dir + '/tmp.png'
|
||||
openscad.run_list([scad_name, "-o", tmp_name] + options.list() + ["-D$bom=2", colour_scheme, "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname]);
|
||||
times.add_time(scad_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1000x600", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
@@ -303,6 +306,11 @@ def tests(tests):
|
||||
with open(doc_base_name + ".html", "wt") as html_file:
|
||||
do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
|
||||
times.print_times()
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
|
||||
do_cmd(('codespell -L od ' + doc_name).split())
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@@ -44,7 +44,7 @@ def got_time(name):
|
||||
|
||||
def check_have_time(changed, name):
|
||||
if not changed and not got_time(name):
|
||||
changed = "no previous time"
|
||||
changed = Fore.CYAN + "no previous time" + Fore.WHITE
|
||||
return changed
|
||||
|
||||
def add_time(name, start):
|
||||
|
40
scripts/tmpdir.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# NopSCADlib Copyright Chris Palmer 2021
|
||||
# nop.head@gmail.com
|
||||
# hydraraptor.blogspot.com
|
||||
#
|
||||
# This file is part of NopSCADlib.
|
||||
#
|
||||
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
"""
|
||||
Make a directory for tmp files.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
|
||||
def mktmpdir(top_dir):
|
||||
tmp_dir = top_dir + 'tmp'
|
||||
if not os.path.isdir(tmp_dir):
|
||||
os.makedirs(tmp_dir)
|
||||
else:
|
||||
for file in os.listdir(tmp_dir):
|
||||
os.remove(tmp_dir + '/' + file)
|
||||
return tmp_dir
|
||||
|
||||
def reltmp(dir, target):
|
||||
return dir if os.path.isabs(dir) else '../../' + dir if target else '../' + dir
|
||||
|
||||
def rmtmpdir(tmp_dir):
|
||||
os.rmdir(tmp_dir)
|
||||
while os.path.isdir(tmp_dir):
|
||||
time.sleep(0.1)
|
@@ -38,6 +38,7 @@ import shutil
|
||||
import re
|
||||
import copy
|
||||
from colorama import Fore
|
||||
from tmpdir import *
|
||||
|
||||
def is_assembly(s):
|
||||
return s[-9:] == '_assembly' or s[-11:] == '_assemblies'
|
||||
@@ -129,8 +130,9 @@ def views(target, do_assemblies = None):
|
||||
# Make the target directory
|
||||
#
|
||||
top_dir = set_config(target, usage)
|
||||
tmp_dir = mktmpdir(top_dir)
|
||||
target_dir = top_dir + 'assemblies'
|
||||
deps_dir = top_dir + "deps"
|
||||
deps_dir = target_dir + "/deps"
|
||||
bom_dir = top_dir + "bom"
|
||||
if not os.path.isdir(target_dir):
|
||||
os.makedirs(target_dir)
|
||||
@@ -183,6 +185,7 @@ def views(target, do_assemblies = None):
|
||||
#
|
||||
for ass in flat_bom:
|
||||
if ass["name"] == real_name:
|
||||
zoomed = ass['zoomed']
|
||||
if not "blurb" in ass:
|
||||
ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no])
|
||||
break
|
||||
@@ -204,20 +207,21 @@ def views(target, do_assemblies = None):
|
||||
changed = check_deps(png_name, dname)
|
||||
changed = times.check_have_time(changed, png_name)
|
||||
changed = options.have_changed(changed, png_name)
|
||||
tmp_name = 'tmp.png'
|
||||
tmp_name = tmp_dir + '/' + real_name + '.png'
|
||||
if changed:
|
||||
print(changed)
|
||||
#
|
||||
# make a file to use the module
|
||||
#
|
||||
png_maker_name = 'png.scad'
|
||||
png_maker_name = tmp_dir + '/png.scad'
|
||||
with open(png_maker_name, "w") as f:
|
||||
f.write("use <%s/%s>\n" % (dir, filename))
|
||||
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
||||
f.write("%s();\n" % module);
|
||||
t = time.time()
|
||||
target_def = ['-D$target="%s"' % target] if target else []
|
||||
cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
|
||||
openscad.run_list(options.list() + target_def + cwd_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name]);
|
||||
view_def = ['--viewall', '--autocenter'] if not (zoomed & (1 << explode)) else ['--camera=0,0,0,55,0,25,140']
|
||||
openscad.run_list(["-o", tmp_name, png_maker_name] + options.list() + target_def + cwd_def + view_def + ["-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "-d", dname]);
|
||||
times.add_time(png_name, t)
|
||||
do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name])
|
||||
update_image(tmp_name, png_name)
|
||||
@@ -439,6 +443,10 @@ def views(target, do_assemblies = None):
|
||||
dst.write(line)
|
||||
i += 1
|
||||
#
|
||||
# Remove tmp dir
|
||||
#
|
||||
rmtmpdir(tmp_dir)
|
||||
#
|
||||
# Spell check
|
||||
#
|
||||
do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())
|
||||
|
@@ -46,7 +46,7 @@ module widget(thickness) {
|
||||
module widget_stl() {
|
||||
stl("widget")
|
||||
union() {
|
||||
rounded_rectangle([30, 30, 3], 2);
|
||||
rounded_rectangle([30, 30, 3], 2, true);
|
||||
|
||||
render() insert_boss(insert, height, 2.2);
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ module pcbs() {
|
||||
rotate(90)
|
||||
pcb_assembly(pcbs[$i], 5 + $i, 3);
|
||||
|
||||
translate([0, 120])
|
||||
translate([0, 110])
|
||||
layout([for(p = perfboards) pcb_length(p)], 10)
|
||||
translate([0, -pcb_width(perfboards[$i]) / 2])
|
||||
pcb_assembly(perfboards[$i], 5 + $i, 3);
|
||||
|
134
tests/core_xy.scad
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2020
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
include <../core.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
include <../vitamins/screws.scad>
|
||||
include <../vitamins/stepper_motors.scad>
|
||||
include <../vitamins/washers.scad>
|
||||
|
||||
include <../utils/core_xy.scad>
|
||||
|
||||
|
||||
module coreXY_belts_test() {
|
||||
coreXY_type = coreXY_GT2_20_16;
|
||||
plain_idler = coreXY_plain_idler(coreXY_type);
|
||||
toothed_idler = coreXY_toothed_idler(coreXY_type);
|
||||
|
||||
coreXYPosBL = [0, 0, 0];
|
||||
coreXYPosTR = [200, 150, 0];
|
||||
separation = [0, coreXY_coincident_separation(coreXY_type).y, pulley_height(plain_idler) + washer_thickness(M3_washer)];
|
||||
pos = [100, 50];
|
||||
|
||||
upper_drive_pulley_offset = [40, 10];
|
||||
lower_drive_pulley_offset = [0, 0];
|
||||
|
||||
coreXY_belts(coreXY_type,
|
||||
carriagePosition = pos,
|
||||
coreXYPosBL = coreXYPosBL,
|
||||
coreXYPosTR = coreXYPosTR,
|
||||
separation = separation,
|
||||
x_gap = 10,
|
||||
upper_drive_pulley_offset = upper_drive_pulley_offset,
|
||||
lower_drive_pulley_offset = lower_drive_pulley_offset,
|
||||
show_pulleys = true);
|
||||
|
||||
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosTR.y + upper_drive_pulley_offset.y, separation.z/2]) {
|
||||
// add the upper drive pulley stepper motor
|
||||
translate([coreXY_drive_pulley_x_alignment(coreXY_type) + upper_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the upper drive offset idler pulleys if required
|
||||
if (upper_drive_pulley_offset.x > 0) {
|
||||
translate(coreXY_drive_plain_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (upper_drive_pulley_offset.x < 0) {
|
||||
translate([-pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosTR.y + lower_drive_pulley_offset.y, -separation.z/2]) {
|
||||
// add the lower drive pulley stepper motor
|
||||
translate([-coreXY_drive_pulley_x_alignment(coreXY_type) + lower_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||
NEMA(NEMA17M);
|
||||
|
||||
// add the screws for the lower drive offset idler pulleys if required
|
||||
if (lower_drive_pulley_offset.x < 0) {
|
||||
translate([-coreXY_drive_plain_idler_offset(coreXY_type).x, coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
} else if (lower_drive_pulley_offset.x > 0) {
|
||||
translate([pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(plain_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
translate([-2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||
translate_z(-pulley_offset(toothed_idler))
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
// add the screw for the left upper idler pulley
|
||||
translate([coreXYPosBL.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right upper idler pulley
|
||||
translate([coreXYPosTR.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
if (separation.x != 0) {
|
||||
// add the screw for the left lower idler pulley
|
||||
translate([coreXYPosBL.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
|
||||
// add the screw for the right lower idler pulley
|
||||
translate([coreXYPosTR.x - separation.x/2, coreXYPosBL.y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
|
||||
translate([-separation.x/2, pos.y + coreXYPosBL.y -separation.y/2, -separation.z/2 + pulley_height(plain_idler)/2]) {
|
||||
// add the screw for the left Y carriage toothed idler
|
||||
translate([coreXYPosBL.x, coreXY_toothed_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the left Y carriage plain idler
|
||||
translate([coreXYPosBL.x + separation.x + coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage toothed idler
|
||||
translate([coreXYPosTR.x + separation.x, coreXY_toothed_idler_offset(coreXY_type).y, separation.z])
|
||||
screw(M3_cap_screw, 20);
|
||||
// add the screw for the right Y carriage plain idler
|
||||
translate([coreXYPosTR.x - coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, 0])
|
||||
screw(M3_cap_screw, 20);
|
||||
}
|
||||
}
|
||||
|
||||
if ($preview)
|
||||
coreXY_belts_test();
|
@@ -56,7 +56,7 @@ module horiholes_stl(t = thickness) {
|
||||
}
|
||||
if(t == thickness)
|
||||
translate([length / 2, 0])
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5);
|
||||
rounded_rectangle([length + 2 * overlap_x, thickness + 2 * overlap_y, 2], 5, true);
|
||||
}
|
||||
|
||||
module horiholes() {
|
||||
|
BIN
tests/png/core_xy.png
Normal file
After Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
BIN
tests/png/pocket_handle.png
Normal file
After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 73 KiB |
40
tests/pocket_handle.scad
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2021
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
include <../core.scad>
|
||||
|
||||
include <../vitamins/sheets.scad>
|
||||
|
||||
use <../printed/pocket_handle.scad>
|
||||
|
||||
show_holes = false;
|
||||
|
||||
handle = pocket_handle();
|
||||
|
||||
module pocket_handles() {
|
||||
if($preview) {
|
||||
pocket_handle_assembly(handle);
|
||||
|
||||
if(show_holes)
|
||||
#pocket_handle_holes(handle);
|
||||
}
|
||||
else
|
||||
pocket_handle(handle);
|
||||
}
|
||||
|
||||
pocket_handles();
|
@@ -27,10 +27,13 @@ module rounded_rectangles() {
|
||||
rounded_rectangle([30, 20, 10], 3);
|
||||
|
||||
translate([80, 0])
|
||||
rounded_rectangle_xz([30, 20, 10], 3);
|
||||
rounded_cube_xy([30, 20, 10], 3);
|
||||
|
||||
translate([120, 0])
|
||||
rounded_rectangle_yz([30, 20, 10], 3);
|
||||
rounded_cube_xz([30, 20, 10], 3);
|
||||
|
||||
translate([160, 0])
|
||||
rounded_cube_yz([30, 20, 10], 3);
|
||||
}
|
||||
|
||||
rounded_rectangles();
|
||||
|
@@ -25,25 +25,30 @@ include <../vitamins/screws.scad>
|
||||
width = 30;
|
||||
2d = true;
|
||||
|
||||
module sheets()
|
||||
layout([for(s = sheets) width], 5)
|
||||
let(sheet = sheets[$i], w = sheet_is_woven(sheet) ? width : undef)
|
||||
if(2d)
|
||||
render_2D_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet_2D(sheet, width, width, 2);
|
||||
module sheets() {
|
||||
rows = 2;
|
||||
n = ceil(len(sheets) / rows);
|
||||
w = width + 5;
|
||||
for(y = [0 : rows - 1], x = [0 : n - 1], s = y * n + x)
|
||||
if(s < len(sheets))
|
||||
translate([width / 2 + x * w, y * w])
|
||||
let(sheet = sheets[s], w = sheet_is_woven(sheet) ? width : undef)
|
||||
if(2d)
|
||||
render_2D_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet_2D(sheet, width, width, 2);
|
||||
|
||||
circle(3);
|
||||
}
|
||||
else
|
||||
render_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet(sheet, width, width, 2);
|
||||
|
||||
translate_z(sheet_thickness(sheet) / 2)
|
||||
screw_countersink(M3_cs_cap_screw);
|
||||
}
|
||||
circle(3);
|
||||
}
|
||||
else
|
||||
render_sheet(sheet, w = w, d = w)
|
||||
difference() {
|
||||
sheet(sheet, width, width, 2);
|
||||
|
||||
translate_z(sheet_thickness(sheet) / 2)
|
||||
screw_countersink(M3_cs_cap_screw);
|
||||
}
|
||||
}
|
||||
|
||||
if($preview)
|
||||
sheets();
|
||||
|
@@ -34,14 +34,19 @@
|
||||
//! If the code to make an STL or DXF is made a child of the `stl()` or `dxf()` module then the STL or DXF will be used in the assembly views generated by `views.py` instead of generating
|
||||
//! it with code.
|
||||
//! This can speed up the generation of the build instructions greatly but isn't compatible with STLs that include support structures.
|
||||
//!
|
||||
//! The `pose()` module allows assembly views in the readme to be posed differently to the default view in the GUI:
|
||||
//!
|
||||
//! * Setting the `exploded` parameter to `true` allows just the exploded version to be posed and setting to `false` allows just the assembled view to be posed, the default is both.
|
||||
//! * If the `d` parameter is set to specify the camera distance then the normal `viewall` and `autocenter` options are suppressed allowing a small section to be zoomed in to fill the view.
|
||||
//! * To get the parameter values make the GUI window square, pose the view with the mouse and then copy the viewport parameters from the Edit menu and paste them into the pose invocation.
|
||||
//! * Two `pose()` modules can be chained to allow different poses for exploded and assembled views.
|
||||
//
|
||||
function bom_mode(n = 1) = $_bom >= n && (is_undef($on_bom) || $on_bom); //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well
|
||||
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of `$exploded` if it is defined, else `0`
|
||||
function show_supports() = !$preview || exploded(); //! True if printed support material should be shown
|
||||
|
||||
module no_explode() let($exploded_parent = true) children(); //! Prevent children being exploded
|
||||
module no_pose() let($posed = true) children(); //! Force children not to be posed even if parent is
|
||||
|
||||
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector `d`, option to explode grand children
|
||||
v = is_list(d) ? d : [0, 0, d];
|
||||
o = is_list(offset) ? offset : [0, 0, offset];
|
||||
@@ -62,17 +67,29 @@ module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode
|
||||
children();
|
||||
}
|
||||
|
||||
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a` and translation `t`, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
children();
|
||||
else
|
||||
let($posed = true) // only pose the top level
|
||||
rotate([55, 0, 25])
|
||||
rotate([-a.x, 0, 0])
|
||||
rotate([0, -a.y, 0])
|
||||
rotate([0, 0, -a.z])
|
||||
translate(-t)
|
||||
children();
|
||||
module no_pose() let($posed = true, $zoomed = undef) children(); //! Force children not to be posed even if parent is
|
||||
|
||||
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef, d = undef) //! Pose an STL or assembly for rendering to png by specifying rotation `a`, translation `t` and optionally `d`, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
let($zoomed = is_undef(d)
|
||||
? is_undef($zoomed)
|
||||
? undef
|
||||
: $zoomed
|
||||
: is_undef(exploded)
|
||||
? 3
|
||||
: exploded
|
||||
? 2
|
||||
: 1)
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
children();
|
||||
else
|
||||
let($posed = true) // only pose the top level
|
||||
rotate([55, 0, 25])
|
||||
translate_z(is_undef(d) ? 0 : 140 - d)
|
||||
rotate([-a.x, 0, 0])
|
||||
rotate([0, -a.y, 0])
|
||||
rotate([0, 0, -a.z])
|
||||
translate(-t)
|
||||
children();
|
||||
|
||||
module pose_hflip(exploded = undef) //! Pose an STL or assembly for rendering to png by flipping around the Y axis, `exploded = true for` just the exploded view or `false` for unexploded only.
|
||||
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
|
||||
@@ -93,7 +110,9 @@ module pose_vflip(exploded = undef) //! Pose an STL or assembly for render
|
||||
|
||||
module assembly(name, big = undef, ngb = false) { //! Name an assembly that will appear on the BOM, there needs to a module named `<name>_assembly` to make it. `big` can force big or small assembly diagrams.
|
||||
if(bom_mode()) {
|
||||
args = is_undef(big) && !ngb ? "" : str("(big=", big, ", ngb=", ngb, ")");
|
||||
zoom = is_undef($zoomed) ? 0 : $zoomed;
|
||||
arglist = str(arg(big, undef, "big"), arg(ngb, false, "ngb"), arg(zoom, 0, "zoomed"));
|
||||
args = len(arglist) ? str("(", slice(arglist, 2), ")") : "";
|
||||
echo(str("~", name, "_assembly", args, "{"));
|
||||
}
|
||||
no_pose()
|
||||
@@ -146,17 +165,11 @@ module dxf(name) { //! Name a dxf that will appear on the B
|
||||
}
|
||||
}
|
||||
|
||||
module use_stl(name) { //! Import an STL to make a build platter
|
||||
stl(name);
|
||||
path = is_undef($target) ? "/stls/" : str("/", $target, "/stls/");
|
||||
import(str($cwd, path, name, ".stl"));
|
||||
}
|
||||
module use_stl(name) //! Import an STL to make a build platter
|
||||
assert(false); // Here for documentation only, real version in core.scad
|
||||
|
||||
module use_dxf(name) { //! Import a DXF to make a build panel
|
||||
dxf(name);
|
||||
path = is_undef($target) ? "/dxfs/" : str("/", $target, "/dxfs/");
|
||||
import(str($cwd, path, name, ".dxf"));
|
||||
}
|
||||
module use_dxf(name) //! Import a DXF to make a build panel
|
||||
assert(false); // Here for documentation only, real version in core.scad
|
||||
|
||||
function value_string(value) = is_string(value) ? str("\"", value, "\"") : str(value); //! Convert `value` to a string or quote it if it is already a string
|
||||
|
||||
|
@@ -25,3 +25,15 @@ include <../../global_defs.scad>
|
||||
// Global functions and modules
|
||||
//
|
||||
use <global.scad>
|
||||
|
||||
module use_stl(name) { //! Import an STL to make a build platter
|
||||
stl(name);
|
||||
path = is_undef($target) ? "../stls/" : str($cwd, "/", $target, "/stls/");
|
||||
import(str(path, name, ".stl"));
|
||||
}
|
||||
|
||||
module use_dxf(name) { //! Import a DXF to make a build panel
|
||||
dxf(name);
|
||||
path = is_undef($target) ? "../dxfs/" : str($cwd, "/", $target, "/dxfs/");
|
||||
import(str(path, name, ".dxf"));
|
||||
}
|
||||
|
@@ -33,20 +33,20 @@
|
||||
//! When `twist` is set the resulting cylinder is extended by `eps` at each end so that the exact length of the hole can be used without
|
||||
//! leaving a scar on either surface.
|
||||
//
|
||||
function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius
|
||||
function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle
|
||||
function corrected_diameter(d, n = 0) = d / cos(180 / (n ? n : sides(d / 2))); //! Adjusted diameter to make flats lie on the circle
|
||||
function sides(r, n = undef) = is_undef(n) ? max(round(4 * r), 3) : n ? max(n, 3) : r2sides(r); //! Optimium number of sides for specified radius
|
||||
function corrected_radius(r, n = undef) = r / cos(180 / sides(r, n)); //! Adjusted radius to make flats lie on the circle
|
||||
function corrected_diameter(d, n = undef) = 2 * corrected_radius(d / 2 , n); //! Adjusted diameter to make flats lie on the circle
|
||||
|
||||
module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the correct size
|
||||
n = sides ? sides : sides(r);
|
||||
circle(r = corrected_radius(r,n), $fn = n);
|
||||
module poly_circle(r, sides = undef) { //! Make a circle adjusted to print the correct size
|
||||
n = sides(r, sides);
|
||||
circle(r = corrected_radius(r, n), $fn = n);
|
||||
}
|
||||
|
||||
module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
|
||||
module poly_cylinder(r, h, center = false, sides = undef, chamfer = false, twist = 0) {//! Make a cylinder adjusted to print the correct size
|
||||
if(twist) {
|
||||
slices = ceil(h / layer_height);
|
||||
twists = min(twist + 1, slices);
|
||||
sides = sides ? sides : sides(r);
|
||||
sides = sides(r, sides);
|
||||
rot = 360 / sides / twists * (twists < slices ? (1 + 1 / slices) : 1);
|
||||
if(center)
|
||||
for(side = [0, 1])
|
||||
@@ -64,10 +64,10 @@ module poly_cylinder(r, h, center = false, sides = 0, chamfer = false, twist = 0
|
||||
poly_circle(r, sides);
|
||||
|
||||
if(h && chamfer)
|
||||
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides ? sides : sides(r));
|
||||
poly_cylinder(r + layer_height, center ? layer_height * 2 : layer_height, center, sides = sides(r, sides));
|
||||
}
|
||||
|
||||
module poly_ring(or, ir, sides = 0) { //! Make a 2D ring adjusted to have the correct internal radius
|
||||
module poly_ring(or, ir, sides = undef) { //! Make a 2D ring adjusted to have the correct internal radius
|
||||
cir = corrected_radius(ir, sides);
|
||||
filaments = (or - cir) / extrusion_width;
|
||||
if(filaments > 3 + eps)
|
||||
|
@@ -22,26 +22,33 @@
|
||||
//
|
||||
module rounded_square(size, r, center = true) //! Like `square()` but with with rounded corners
|
||||
{
|
||||
assert(r < min(size.x, size.y) / 2);
|
||||
$fn = r2sides4n(r);
|
||||
offset(r) offset(-r) square(size, center = center);
|
||||
}
|
||||
|
||||
module rounded_rectangle(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
module rounded_rectangle(size, r, center = false, xy_center = true) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
{
|
||||
linear_extrude(size.z, center = center)
|
||||
extrude_if(size.z, center = center)
|
||||
rounded_square([size.x, size.y], r, xy_center);
|
||||
}
|
||||
|
||||
module rounded_rectangle_xz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z.
|
||||
module rounded_cube_xy(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XY plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 0])
|
||||
rounded_rectangle([size.x, size.z, size.y], r, center = true, xy_center = true);
|
||||
extrude_if(size.z, center = z_center)
|
||||
rounded_square([size.x, size.y], r, xy_center);
|
||||
}
|
||||
|
||||
module rounded_rectangle_yz(size, r, center = true, xy_center = true) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z.
|
||||
module rounded_cube_xz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in XZ plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 90])
|
||||
rounded_rectangle([size.y, size.z, size.x], r, center = true, xy_center = true);
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 0])
|
||||
rounded_cube_xy([size.x, size.z, size.y], r, xy_center = true, z_center = true);
|
||||
}
|
||||
|
||||
module rounded_cube_yz(size, r = 0, xy_center = false, z_center = false) //! Like `cube()` but corners rounded in YX plane and separate centre options for xy and z.
|
||||
{
|
||||
translate([xy_center ? 0 : size.x / 2, xy_center ? 0 : size.y / 2, z_center ? 0 : size.z / 2])
|
||||
rotate([90, 0, 90])
|
||||
rounded_cube_xy([size.y, size.z, size.x], r, xy_center = true, z_center = true);
|
||||
}
|
||||
|
196
utils/core_xy.scad
Normal file
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// NopSCADlib Copyright Chris Palmer 2020
|
||||
// nop.head@gmail.com
|
||||
// hydraraptor.blogspot.com
|
||||
//
|
||||
// This file is part of NopSCADlib.
|
||||
//
|
||||
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||
// If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
//
|
||||
//! Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
|
||||
//!
|
||||
//! The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
|
||||
//! Implementation has the following features:
|
||||
//! 1. The drive and idler pulleys may be different sizes.
|
||||
//! 2. The belt separation is parameterised.
|
||||
//! 3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
|
||||
//! 4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
|
||||
//! allows flexible positioning of the motors.
|
||||
//
|
||||
include <../core.scad>
|
||||
include <../vitamins/belts.scad>
|
||||
include <../vitamins/pulleys.scad>
|
||||
|
||||
|
||||
coreXY_GT2_20_20 = ["coreXY_20_20", GT2x6, GT2x20ob_pulley, GT2x20_toothed_idler, GT2x20_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
coreXY_GT2_20_16 = ["coreXY_20_16", GT2x6, GT2x20ob_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
coreXY_GT2_16_16 = ["coreXY_16_16", GT2x6, GT2x16_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||
|
||||
function coreXY_belt(type) = type[1]; //! Belt type
|
||||
function coreXY_drive_pulley(type) = type[2]; //! Drive pulley type
|
||||
function coreXY_toothed_idler(type) = type[3]; //! Toothed idler type
|
||||
function coreXY_plain_idler(type) = type[4]; //! Plain idler type
|
||||
function coreXY_upper_belt_colour(type) = type[5]; //! Colour of the upper belt
|
||||
function coreXY_upper_tooth_colour(type) = type[6]; //! Colour of the upper belt's teeth
|
||||
function coreXY_lower_belt_colour(type) = type[7]; //! Colour of the lower belt
|
||||
function coreXY_lower_tooth_colour(type) = type[8]; //! Colour of the lower belt's teeth
|
||||
|
||||
// used to offset the position of the drive pulley and the y-carriage plain idler pulley
|
||||
// relative to the anchor pulley so that the belts align properly
|
||||
function coreXY_drive_pulley_x_alignment(type) = //! Belt alignment offset of the drive pulley relative to the anchor pulley
|
||||
(pulley_od(coreXY_drive_pulley(type)) - pulley_od(coreXY_toothed_idler(type))) / 2;
|
||||
function coreXY_coincident_separation(type) = //! Value of x, y separation to make y-carriage pulleys coincident
|
||||
[ -coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_toothed_idler(type)))/2, 0 ];
|
||||
function coreXY_plain_idler_offset(type) = //! Offset of y-carriage plain idler
|
||||
[ (pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2 + coreXY_drive_pulley_x_alignment(type), pulley_od(coreXY_plain_idler(type))/2, 0 ];
|
||||
function coreXY_toothed_idler_offset(type) = //! offset of y-carriage toothed idler
|
||||
[ 0, -pulley_pr(coreXY_toothed_idler(type)), 0 ];
|
||||
// helper functions for positioning idlers when the stepper motor drive pulley is offset
|
||||
function coreXY_drive_toothed_idler_offset(type) = //! Offset of toothed drive idler pulley
|
||||
[ 0, coreXY_drive_pulley_x_alignment(type), 0 ];
|
||||
function coreXY_drive_plain_idler_offset(type) = //! Offset of plain drive idler pulley
|
||||
[ coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2, 0 ];
|
||||
|
||||
|
||||
module coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false) { //! Draw one belt of a coreXY setup
|
||||
|
||||
// y-carriage toothed pulley
|
||||
p0_type = coreXY_toothed_idler(type);
|
||||
p0 = [ size.x / 2, -size.y / 2 - pulley_od(p0_type) / 2 + pos.y - separation_y / 2 ];
|
||||
|
||||
// bottom right toothed idler pulley
|
||||
p1_type = p0_type;
|
||||
p1 = [ size.x / 2, -size.y / 2 ];
|
||||
|
||||
// bottom left anchor toothed idler pulley
|
||||
p2_type = p0_type;
|
||||
p2 = [ -size.x / 2, -size.y / 2 ];
|
||||
|
||||
// stepper motor drive pulley
|
||||
p3d_type = coreXY_drive_pulley(type);
|
||||
p3d = [ -size.x / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.x,
|
||||
size.y / 2 + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// toothed idler for offset stepper motor drive pulley
|
||||
p3t_type = coreXY_toothed_idler(type);
|
||||
p3t = [ -size.x / 2 + (drive_pulley_offset.x > 0 ? 0 : 2*coreXY_drive_pulley_x_alignment(type)),
|
||||
size.y / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// y-carriage plain pulley
|
||||
p4_type = coreXY_plain_idler(type);
|
||||
p4 = [ -size.x / 2 + pulley_od(p4_type) / 2 + pulley_od(p3d_type) / 2 + coreXY_drive_pulley_x_alignment(type) + plain_idler_offset,
|
||||
-size.y / 2 + pulley_od(p4_type) / 2 + pos.y + separation_y / 2
|
||||
];
|
||||
|
||||
// plain idler for offset stepper motor drive pulley
|
||||
p3p_type = p4_type;
|
||||
p3p = [ drive_pulley_offset.x > 0 ? p4.x : -p0.x - pulley_od(p0_type),
|
||||
size.y / 2 - pulley_od(p3p_type) / 2 - pulley_od(p3d_type) / 2 + drive_pulley_offset.y
|
||||
];
|
||||
|
||||
// dummy pulleys for y separation
|
||||
p5_type = p4_type;
|
||||
p5 = [ pos.x - size.x / 2, -size.y / 2 + pos.y + separation_y / 2 ];
|
||||
p6_type = p0_type;
|
||||
p6 = [ pos.x - size.x / 2, -size.y / 2 + pos.y - separation_y / 2 ];
|
||||
|
||||
module show_pulleys(show_pulleys) {// Allows the pulley colour to be set for debugging
|
||||
if (is_list(show_pulleys))
|
||||
color(show_pulleys)
|
||||
children();
|
||||
else if (show_pulleys)
|
||||
children();
|
||||
}
|
||||
|
||||
show_pulleys(show_pulleys) {
|
||||
translate(p0)
|
||||
pulley_assembly(p0_type); // y-carriage toothed pulley
|
||||
translate(p1)
|
||||
pulley_assembly(p1_type); // bottom right toothed idler pulley
|
||||
translate(p2)
|
||||
pulley_assembly(p2_type); // bottom left anchor toothed idler pulley
|
||||
translate(p3d)
|
||||
hflip(hflip)
|
||||
pulley_assembly(p3d_type); // top left stepper motor drive pulley
|
||||
if (drive_pulley_offset.x) { // idler pulleys for offset stepper motor drive pulley
|
||||
translate(p3t)
|
||||
pulley_assembly(p3t_type); // toothed idler
|
||||
translate(p3p)
|
||||
pulley_assembly(p3p_type); // plain idler
|
||||
}
|
||||
translate(p4)
|
||||
pulley_assembly(p4_type); // y-carriage plain pulley
|
||||
}
|
||||
|
||||
path0a = [
|
||||
[ p0.x, p0.y, pulley_od(p0_type) / 2 ],
|
||||
[ p1.x, p1.y, pulley_od(p1_type) / 2 ],
|
||||
[ p2.x, p2.y, pulley_od(p2_type) / 2 ]
|
||||
];
|
||||
path0b = [
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path0c = [
|
||||
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path0d = [
|
||||
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||
];
|
||||
path1 = [ // use eps for corner radius to get sharp corners so this part of the belt is deleted by the gap
|
||||
[ p5.x, p5.y, eps ],
|
||||
[ p6.x, p6.y, eps ]
|
||||
];
|
||||
|
||||
belt = coreXY_belt(type);
|
||||
|
||||
path0 = drive_pulley_offset.x == 0 ? concat(path0a, path0b) : drive_pulley_offset.x > 0 ? concat(path0a, path0c) : concat(path0a, path0d);
|
||||
path = separation_y == 0 ? path0 : concat(path0, path1);
|
||||
|
||||
belt(type = belt,
|
||||
points = path,
|
||||
gap = [ x_gap + eps, abs(separation_y) + 2 ],
|
||||
gap_pos = [ pos.x - size.x / 2, pos.y - size.y / 2 + belt_pitch_height(belt) - belt_thickness(belt) / 2 ],
|
||||
belt_colour = lower_belt ? coreXY_lower_belt_colour(type) : coreXY_upper_belt_colour(type),
|
||||
tooth_colour = lower_belt ? coreXY_lower_tooth_colour(type) : coreXY_upper_tooth_colour(type));
|
||||
}
|
||||
|
||||
module coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false) { //! Wrapper module to draw both belts of a coreXY setup
|
||||
translate([size.x / 2 - separation.x / 2, size.y / 2, -separation.z / 2]) {
|
||||
// lower belt
|
||||
hflip()
|
||||
explode(25)
|
||||
coreXY_half(type, size, [size.x - pos.x - separation.x, pos.y], separation.y, x_gap, plain_idler_offset, [-lower_drive_pulley_offset.x, lower_drive_pulley_offset.y], show_pulleys, lower_belt = true, hflip = true);
|
||||
// upper belt
|
||||
translate([separation.x, 0, separation.z])
|
||||
explode(25)
|
||||
coreXY_half(type, size, [pos.x, pos.y], separation.y, x_gap, plain_idler_offset, upper_drive_pulley_offset, show_pulleys, lower_belt = false, hflip=false);
|
||||
}
|
||||
}
|
||||
|
||||
module coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false) { //! Draw the coreXY belts
|
||||
assert(coreXYPosBL.z == coreXYPosTR.z);
|
||||
|
||||
coreXYSize = coreXYPosTR - coreXYPosBL;
|
||||
translate(coreXYPosBL)
|
||||
coreXY(type, coreXYSize, [carriagePosition.x - coreXYPosBL.x + separation.x / 2, carriagePosition.y - coreXYPosBL.y], separation = separation, x_gap = x_gap, plain_idler_offset = 0, upper_drive_pulley_offset = upper_drive_pulley_offset, lower_drive_pulley_offset = lower_drive_pulley_offset, show_pulleys = show_pulleys);
|
||||
}
|
@@ -31,15 +31,15 @@ module rounded_right_triangle(x, y, z, fillet, center = true, offset = false) {
|
||||
hull() {
|
||||
translate([0, fillet, size.z / 2])
|
||||
rotate([90, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([0, size.y, size.z / 2])
|
||||
rotate([90, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([fillet, 0, size.z / 2])
|
||||
rotate([0, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
translate([size.x, 0, size.z / 2])
|
||||
rotate([0, 90, 0])
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, center = false, xy_center = false);
|
||||
rounded_rectangle([size.z, 2 * fillet, eps], fillet - eps, xy_center = false);
|
||||
}
|
||||
}
|
||||
|
@@ -128,7 +128,7 @@ module battery_contact(type, pos = true) { //! Draw a positive or negative batte
|
||||
t = contact_thickness(type);
|
||||
|
||||
color("silver") {
|
||||
rounded_rectangle([contact_width(type), h, t], r = 1, center = false);
|
||||
rounded_rectangle([contact_width(type), h, t], r = 1);
|
||||
|
||||
translate([0, -h / 2, t])
|
||||
rotate([90, 0, 0])
|
||||
|
@@ -47,7 +47,7 @@ module square_button(type, colour = "yellow") { //! Draw square button with spec
|
||||
stem = square_button_cap_stem(type);
|
||||
|
||||
color(grey(20)) {
|
||||
rounded_rectangle([w, w, h - 0.5], r = wall, center = false);
|
||||
rounded_rectangle([w, w, h - 0.5], r = wall);
|
||||
|
||||
for(x = [-1, 1], y = [-1, 1])
|
||||
translate([x * pitch, y * pitch])
|
||||
|
@@ -37,7 +37,7 @@ module camera_lens(type, offset = 0, show_lens = true) //! Draw the lens stack,
|
||||
r = p[1] + offset;
|
||||
app = p[2];
|
||||
if(size.x)
|
||||
rounded_rectangle(size + [2 * offset, 2 * offset, round_to_layer(offset)], r, center = false);
|
||||
rounded_rectangle(size + [2 * offset, 2 * offset, round_to_layer(offset)], r);
|
||||
else
|
||||
if (show_lens)
|
||||
translate_z(size.y)
|
||||
@@ -72,7 +72,7 @@ module camera(type, show_lens = true) { //! Draw specified PCB camera
|
||||
pos = camera_connector_pos(type);
|
||||
color(grey(20))
|
||||
translate(pos)
|
||||
rounded_rectangle(conn, 0.5, center = false);
|
||||
rounded_rectangle(conn, 0.5);
|
||||
|
||||
flex = [5, 0.1];
|
||||
color("orange")
|
||||
|
@@ -326,7 +326,7 @@ module panel_USBA() { //! Draw a panel mount USBA connector
|
||||
dx = (length2 / 2 - r2);
|
||||
dy = (width / 2 - r1);
|
||||
translate_z(l)
|
||||
rounded_rectangle([length2, width, 1], r = r1, center = false);
|
||||
rounded_rectangle([length2, width, 1], r = r1);
|
||||
|
||||
translate([-dx, -dy, height2 - r2])
|
||||
rotate([90, 0, 0])
|
||||
|
@@ -80,7 +80,7 @@ module display(type) { //! Draw specified display
|
||||
translate_z(display_ts_thickness(type)) {
|
||||
difference() {
|
||||
color("silver")
|
||||
rounded_rectangle([w, h, t], 0.5, center = false);
|
||||
rounded_rectangle([w, h, t], 0.5);
|
||||
|
||||
color("black")
|
||||
translate([aperture[0].x, aperture[0].y, - eps])
|
||||
|
@@ -59,7 +59,7 @@ module panel_meter_button(type) { //! Draw panel meter button
|
||||
color(pmeter_button_colour(type))
|
||||
translate(pmeter_button_pos(type))
|
||||
if(size.x)
|
||||
rounded_rectangle(pmeter_button_size(type), r, center = false);
|
||||
rounded_rectangle(pmeter_button_size(type), r);
|
||||
else
|
||||
cylinder(r = r, h = size.z);
|
||||
}
|
||||
@@ -93,8 +93,8 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
|
||||
difference() {
|
||||
if(is_list(bevel))
|
||||
hull() {
|
||||
rounded_rectangle([bezel.x - 2 * bevel.x, bezel.y - 2 * bevel.x, bezel.z], r - bevel.x, center = false);
|
||||
rounded_rectangle([bezel.x, bezel.y, bevel[1]], r, center = false);
|
||||
rounded_rectangle([bezel.x - 2 * bevel.x, bezel.y - 2 * bevel.x, bezel.z], r - bevel.x);
|
||||
rounded_rectangle([bezel.x, bezel.y, bevel[1]], r);
|
||||
}
|
||||
else
|
||||
hull() {
|
||||
@@ -111,7 +111,7 @@ module panel_meter(type) { //! Draw panel mounted LCD meter module
|
||||
cube([ap.x + ap.z, ap.y + ap.z, eps], center = true);
|
||||
|
||||
translate_z(bezel.z + eps)
|
||||
rounded_rectangle([ap.x, ap.y, bezel.z * 2], r, center = true);
|
||||
rounded_rectangle([ap.x, ap.y, bezel.z * 2], r, true);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@@ -126,7 +126,7 @@ module usb_A(h, v_flange_l, bar, cutout) {
|
||||
if(cutout)
|
||||
rotate([90, 0, 90])
|
||||
rounded_rectangle([w + 2 * v_flange_h + 2 * panel_clearance,
|
||||
h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r, center = false);
|
||||
h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r);
|
||||
else {
|
||||
color("silver") rotate([0, 90, 0]) {
|
||||
linear_extrude(l, center = true)
|
||||
|
@@ -45,11 +45,14 @@ Foam20 = [ "Foam20", "Foam sponge", 20,[0.3, 0.3, 0.3, 1 ],
|
||||
AL6 = [ "AL6", "Aluminium tooling plate", 6, [0.9, 0.9, 0.9, 1 ], false];
|
||||
AL8 = [ "AL8", "Aluminium tooling plate", 8, [0.9, 0.9, 0.9, 1 ], false];
|
||||
Steel06 = [ "Steel06", "Sheet mild steel", 0.6,"silver" , false];
|
||||
CF1 = [ "CF1", "Sheet carbon fiber", 1, grey(30), false, 2, 2, grey(25)];
|
||||
CF2 = [ "CF2", "Sheet carbon fiber", 2, grey(30), false, 2, 2, grey(25)];
|
||||
CF3 = [ "CF3", "Sheet carbon fiber", 3, grey(30), false, 2, 2, grey(25)];
|
||||
Spring05 = [ "Spring05", "Bi-metal saw blade", 0.5,"#FBC300", false];
|
||||
Silicone3 = [ "Silicone3", "Sheet silicone", 3, [0.9, 0.9, 0.9, 0.95 ], false];
|
||||
CF1 = [ "CF1", "Sheet carbon fiber", 1, grey(35), false, 2, 2, grey(20)];
|
||||
CF2 = [ "CF2", "Sheet carbon fiber", 2, grey(35), false, 2, 2, grey(20)];
|
||||
CF3 = [ "CF3", "Sheet carbon fiber", 3, grey(35), false, 2, 2, grey(20)];
|
||||
|
||||
|
||||
sheets = [CF1, CF2, CF3, MDF6, MDF10, MDF12, MDF19, PMMA2, PMMA3, PMMA6, PMMA8, PMMA10, glass2, DiBond, DiBond6, Cardboard, FoilTape, Foam20, AL6, AL8, Steel06];
|
||||
sheets = [CF1, CF2, CF3, MDF6, MDF10, MDF12, MDF19, PMMA2, PMMA3, PMMA6, PMMA8, PMMA10,
|
||||
glass2, DiBond, DiBond6, Cardboard, FoilTape, AL6, AL8, Steel06, Spring05, Silicone3, Foam20];
|
||||
|
||||
use <sheet.scad>
|
||||
|
@@ -62,7 +62,7 @@ module sk_bracket(type) { //! SK shaft support bracket
|
||||
}
|
||||
for(x = [W / 2 - 2 * fillet, -W / 2 + 2 * fillet])
|
||||
translate([x, G / 2, 0])
|
||||
rounded_rectangle([4 * fillet, G, L], fillet);
|
||||
rounded_rectangle([4 * fillet, G, L], fillet, true);
|
||||
}
|
||||
|
||||
translate([0, -h, -L /2])
|
||||
|
@@ -56,10 +56,10 @@ module transformer(type) { //! Draw specified transformer
|
||||
|
||||
}
|
||||
|
||||
color("white") {
|
||||
color("white")
|
||||
translate_z(tx_lamination_height(type) / 2 + tx_bobbin_offset(type) / 2)
|
||||
rounded_rectangle([tx_bobbin_width(type), tx_depth(type), tx_bobbin_height(type)], r = tx_bobbin_radius(type));
|
||||
}
|
||||
rounded_rectangle([tx_bobbin_width(type), tx_depth(type), tx_bobbin_height(type)], tx_bobbin_radius(type), true);
|
||||
|
||||
terminal_height = tx_height(type) - tx_lamination_height(type);
|
||||
|
||||
if(terminal_height)
|
||||
|
@@ -62,7 +62,7 @@ module ziptie(type, r, t = 0) //! Draw specified ziptie wrapped around radius `r
|
||||
translate([lx, -r])
|
||||
rotate([90, 0, 0])
|
||||
union() {
|
||||
rounded_rectangle(latch, 0.5, center = false);
|
||||
rounded_rectangle(latch, 0.5);
|
||||
|
||||
translate_z((latch.z + 1) / 2)
|
||||
cube([ziptie_thickness(type), ziptie_width(type), latch.z + 1], center = true);
|
||||
|