Added source code

This commit is contained in:
Chris Palmer 2019-06-08 22:10:47 +01:00
parent d80facf2ca
commit 34a9b0e87b
246 changed files with 18858 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
*_canute.bat
Thumbs.db
__pycache__
*.pyc
tests/bom/
tests/deps/
*.log
*.html

471
box.scad Normal file
View File

@ -0,0 +1,471 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! A box made from routed or laser cut sheet sheets and printed profiles and bezels. It can be arbitrarily large
//! compared to the 3D printed parts because they can be cut into interlocking sections and solvent welded
//! together. The box panels can be customised to have holes and parts mounted on them by overriding the
//! definitions of `box_base()`, `box_front()`, etc.
//!
//! `box.scad` should be ```use```d and `box_assembly.scad` ```include```d.
//!
//! A box is defined with a list that specifies the inside dimensions, top, bottom and side sheet materials, the
//! screw type and printed part wall thickness. This diagram shows how the various dimensions are labelled:
//! ![](docs/box.png)
//!
//! Normally the side sheets are the same type but they can be overridden individually as long as the substitute has the same thickness.
//
include <core.scad>
use <vitamins/sheet.scad>
use <vitamins/screw.scad>
use <vitamins/washer.scad>
include <vitamins/inserts.scad>
use <utils/quadrant.scad>
bezel_clearance = 0.2;
sheet_end_clearance = 1;
sheet_slot_clearance = 0.2;
function box_screw(type) = type[0]; //! Screw type to be used at the corners
function box_wall(type) = type[1]; //! Wall thickness of 3D parts
function box_sheets(type) = type[2]; //! Sheet type used for the sides
function box_top_sheet(type) = type[3]; //! Sheet type for the top
function box_base_sheet(type)= type[4]; //! Sheet type for the bottom
function box_feet(type) = type[5]; //! True to enable feet on the bottom bezel
function box_width(type) = type[6]; //! Internal width
function box_depth(type) = type[7]; //! Internal depth
function box_height(type) = type[8]; //! Internal height
function box_bezel_clearance(type) = bezel_clearance;
function box_corner_gap(type) = 3; //! Gap between box_sheets at the corners to connect inside and outside profiles
function box_profile_overlap(type) = 3 + sheet_end_clearance / 2;
function box_washer(type) = screw_washer(box_screw(type));
function box_insert(type) = screw_insert(box_screw(type));
function box_hole_inset(type) = washer_radius(box_washer(type)) + 1;
function box_insert_r(type) = insert_hole_radius(box_insert(type));
function box_insert_l(type) = insert_length(box_insert(type));
function box_boss_r(type) = ceil(corrected_radius(box_insert_r(type)) + box_wall(type));
function box_sheet_slot(type) = sheet_thickness(box_sheets(type)) + sheet_slot_clearance; // add some clearance
function box_corner_overlap(type) = box_wall(type);
function box_corner_rad(type) = box_sheet_slot(type) - sheet_slot_clearance / 2 + box_corner_gap(type) + box_corner_overlap(type);
function box_sheet_r(type) = box_corner_rad(type) - box_sheet_slot(type) - box_corner_overlap(type);
function box_screw_length(type, top) = screw_longer_than(2 * washer_thickness(box_washer(type))
+ sheet_thickness(top ? box_top_sheet(type) : box_base_sheet(type))
+ box_corner_gap(type) + box_profile_overlap(type) + box_insert_l(type) - 1);
function box_wall_clearance(type) = box_sheet_slot(type) / 2 - sheet_thickness(box_sheets(type)) / 2;
function box_margin(type) = box_profile_overlap(type) + box_corner_gap(type); //! How much the bezel intrudes on the specified height
function box_intrusion(type) = box_hole_inset(type) + box_boss_r(type); //! Corner profile intrusion
function sheet_reduction(type) = 2 * box_corner_gap(type) + sheet_end_clearance;
function box_outset(type) = box_sheet_slot(type) + box_wall(type) - sheet_slot_clearance / 2; //! How much the bezel expands the specified internal size
function box_inset(type) = box_wall(type) + sheet_slot_clearance / 2; //! How much the bezel intrudes on the specified width and length, away from the corners
function box_bezel_height(type, bottom) = //! Bezel height for top or bottom
let(t1 = sheet_thickness(box_base_sheet(type)), t2 = sheet_thickness(box_top_sheet(type)))
box_corner_rad(type) + box_profile_overlap(type) + (bottom ? max(t1, t2) : t2) - sheet_thickness(box_sheets(type));
grill_hole = 5;
grill_gap = 1.9;
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
nx = floor(width / (grill_hole + grill_gap));
xpitch = width / nx;
ny = floor(height / ((grill_hole + grill_gap) * cos(30)));
ypitch = height / ny;
extrude_if(h)
for(y = [0 : ny - 1], x = [0 : nx - 1 - (y % 2)]) {
x = -width / 2 + (x + 0.5 + (y % 2) / 2) * xpitch;
y = -height / 2 + (y + 0.5) * ypitch;
if(sqrt(sqr(x) + sqr(y)) + grill_hole / 2 <= r)
translate([x, y])
if(poly)
poly_circle(r = grill_hole / 2);
else
circle(d = grill_hole);
}
}
module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
t = box_sheet_slot(type);
difference() {
union() {
quadrant(box_hole_inset(type) + box_boss_r(type), box_boss_r(type)); // inside corner
translate([box_corner_gap(type) + box_profile_overlap(type), box_corner_gap(type) + box_profile_overlap(type)])
rotate(180)
quadrant(box_profile_overlap(type) + box_corner_rad(type), box_corner_rad(type)); // outside corner
}
translate([box_corner_gap(type), -t + sheet_slot_clearance / 2])
square([100, t]);
translate([-t + sheet_slot_clearance / 2, box_corner_gap(type)])
square([t, 100]);
}
}
module box_corner_profile(type) { //! Generates the corner profile STL for 3D printing.
stl("box_corner_profile");
length = box_height(type) - 2 * box_margin(type);
difference() {
linear_extrude(height = length, center = true, convexity = 5)
box_corner_profile_2D(type);
for(z = [-1, 1])
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
insert_hole(box_insert(type), 5);
}
}
module box_corner_profile_section(type, section, sections) { //! Generates interlocking sections of the corner profile to allow it to be taller than the printer
overlap = 4;
length = box_height(type) - 2 * box_margin(type);
section_length = round_to_layer((length - overlap) / sections);
last_section = section >= sections - 1;
h = last_section ? length - (sections - 1) * section_length : section_length;
overlap_wall = 2;
difference() {
union() {
linear_extrude(height = h, convexity = 5)
box_corner_profile_2D(type);
if(!last_section) // male end always at the top
translate_z(section_length - 1)
for(i = [0 : 1], offset = i * layer_height)
linear_extrude(height = overlap + 1 - offset)
offset(1 + offset - layer_height)
offset(-overlap_wall - 1)
box_corner_profile_2D(type);
}
if(section > 0)
translate_z(last_section ? h : 0) { // female at bottom unless last section
linear_extrude(height = 2 * (overlap + layer_height), center = true, convexity = 5)
offset(-overlap_wall)
box_corner_profile_2D(type);
linear_extrude(height = 2 * layer_height, center = true, convexity = 5)
offset(-overlap_wall + layer_height)
box_corner_profile_2D(type);
}
if(!section || last_section) // insert holes always at the bottom
translate([box_hole_inset(type), box_hole_inset(type)])
insert_hole(box_insert(type), 5);
}
}
module box_corner_quadrants(type, width, depth)
for(corner = [0:3]) {
x = [-1,1,1,-1][corner];
y = [-1,-1,1,1][corner];
translate([x * width / 2, y * depth / 2, 0])
rotate(corner * 90)
quadrant(box_intrusion(type), box_boss_r(type));
}
module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
stl(bottom ? "bottom_bezel" : "top_bezel");
feet = bottom && box_feet(type);
t = box_sheet_slot(type);
outset = box_outset(type);
inner_r = box_sheet_r(type);
foot_height = box_corner_gap(type) + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
foot_length = box_corner_rad(type) * 2;
height = box_bezel_height(type, bottom);
foot_extension = foot_height - height;
difference() {
translate_z(-box_profile_overlap(type)) difference() {
rounded_rectangle([box_width(type) + 2 * outset, box_depth(type) + 2 * outset, feet ? foot_height : height], box_corner_rad(type), false);
//
// Remove edges between the feet
//
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) - 2 * foot_length, box_depth(type) + 2 * outset + 1, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) - 2 * (foot_length - foot_extension), box_depth(type) + 2 * outset + 1, 1], center = true);
}
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * foot_length, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * (foot_length - foot_extension), 1], center = true);
}
}
//
// slots for side panels
//
translate_z(-box_profile_overlap(type))
linear_extrude(height = 2 * box_profile_overlap(type), center = true)
for(i = [-1, 1]) {
translate([i * (box_width(type) / 2 + t / 2 - sheet_slot_clearance / 2), 0])
square([t, box_depth(type) - 2 * box_corner_gap(type)], center = true);
translate([0, i * (box_depth(type) / 2 + t / 2 - sheet_slot_clearance / 2)])
square([box_width(type) - 2 * box_corner_gap(type), t], center = true);
}
//
// recess for top / bottom panel
//
translate_z(box_corner_gap(type))
rounded_rectangle([box_width(type) + bezel_clearance, box_depth(type) + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
//
// leave plastic over the corner profiles
//
translate_z(-box_profile_overlap(type) - 1)
linear_extrude(height = box_profile_overlap(type) + box_corner_gap(type) + 2)
union() {
difference() {
square([box_width(type) - 2 * box_inset(type),
box_depth(type) - 2 * box_inset(type)], center = true);
box_corner_quadrants(type, box_width(type), box_depth(type));
}
box_screw_hole_positions(type)
poly_circle(screw_clearance_radius(box_screw(type)));
}
}
}
dowel_length = 20;
dowel_wall = extrusion_width * 3;
dowel_h_wall = layer_height * 6;
module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlocking sections of the bezel to allow it to be bigger than the printer
w = (box_width(type) + 2 * box_outset(type)) / cols;
h = (box_depth(type) + 2 * box_outset(type)) / rows;
bw = box_outset(type) - bezel_clearance / 2;
bw2 = box_outset(type) + box_inset(type);
dw = bw - 2 * dowel_wall;
dh = box_bezel_height(type, bottom) - dowel_h_wall;
dh2 = box_profile_overlap(type) + box_corner_gap(type) - dowel_h_wall;
end_clearance = 0.5;
module male() {
rotate([90, 0, 90])
linear_extrude(height = dowel_length - 2 * end_clearance, center = true)
difference() {
union() {
h = dh - layer_height;
h2 = dh2 - layer_height;
hull() {
translate([bw / 2, h / 2])
square([dw - 1, h], center = true);
translate([bw / 2, (h - 1) / 2])
square([dw, h - 1], center = true);
}
hull() {
translate([bw2 / 2, h2 / 2])
square([bw2 - 2 * dowel_wall - 1, h2], center = true);
translate([bw2 / 2, (h2 - 1) / 2])
square([bw2 - 2 * dowel_wall, h2 - 1], center = true);
}
}
translate([bw2 / 2, 0])
square([box_sheet_slot(type), 2 * box_profile_overlap(type)], center = true);
}
}
module female() {
union() {
translate([0, bw / 2, dh / 2])
cube([dowel_length, dw, dh], center = true);
translate([0, bw2 / 2])
cube([dowel_length, bw2 - 2 * dowel_wall, dh2 * 2], center = true);
hull() {
translate([0, bw / 2, dh / 2])
cube([2, dw, dh], center = true);
translate([0, bw / 2, dh / 2])
cube([eps, dw + 2 * extrusion_width, dh], center = true);
}
hull() {
translate([0, bw2 / 2, dh2 / 2])
cube([2, bw2 - 2 * dowel_wall, dh2], center = true);
translate([0, bw2 / 2, dh2 / 2])
cube([eps, bw2 - 2 * dowel_wall + 2 * extrusion_width, dh2], center = true);
}
}
}
module support() {
if(!$preview)
translate([0, bw / 2 + dw / 2])
cube([dowel_length / 2 - 0.25, 2 * extrusion_width + 0.2, dh2]);
}
union() {
render() difference() {
union() {
clip(xmin = 0, xmax = w, ymin = 0, ymax = h)
translate([box_width(type) / 2 + box_outset(type) - x * w, box_depth(type) / 2 + box_outset(type) - y * h, box_profile_overlap(type)])
box_bezel(type, bottom);
if(x < cols - 1 && y == 0)
translate([w, 0])
male();
if(x > 0 && y == rows - 1)
translate([0, h])
rotate(180)
male();
if(y < rows - 1 && x == cols - 1)
translate([w, h])
rotate(90)
male();
if(y > 0 && x == 0)
rotate(-90)
male();
}
if(x < cols - 1 && y == rows - 1)
translate([w, h])
rotate(180)
female();
if(x > 0 && y == 0)
female();
if(y < rows - 1 && x == 0)
translate([0, h])
rotate(-90)
female();
if(y > 0 && x == cols - 1)
translate([w, 0])
rotate(90)
female();
}
if(x < cols - 1 && y == rows - 1)
translate([w, h])
rotate(180)
support();
if(x > 0 && y == 0)
support();
if(y < rows - 1 && x == 0)
translate([0, h])
rotate(-90)
support();
if(y > 0 && x == cols - 1)
translate([w, 0])
rotate(90)
support();
}
}
module box_shelf_blank(type) { //! Generates a 2D template for a shelf sheet
dxf("box_shelf");
difference() {
sheet_2D(box_sheets(type), box_width(type) - bezel_clearance, box_depth(type) - bezel_clearance, 1);
offset(bezel_clearance / 2)
box_corner_quadrants(type, box_width(type), box_depth(type));
}
}
module box_screw_hole_positions(type)
for(x = [-1, 1], y = [-1, 1])
translate([x * (box_width(type) / 2 - box_hole_inset(type)), y * (box_depth(type) / 2 - box_hole_inset(type))])
children();
module box_base_blank(type) { //! Generates a 2D template for the base sheet
dxf("box_base");
difference() {
sheet_2D(box_base_sheet(type), box_width(type), box_depth(type), box_sheet_r(type));
box_screw_hole_positions(type)
drill(screw_clearance_radius(box_screw(type)), 0);
}
}
module box_top_blank(type) { //! Generates a 2D template for the top sheet
dxf("box_top");
difference() {
sheet_2D(box_top_sheet(type), box_width(type), box_depth(type), box_sheet_r(type));
box_screw_hole_positions(type)
drill(screw_clearance_radius(box_screw(type)), 0);
}
}
function subst_sheet(type, sheet) =
let(s = box_sheets(type))
sheet ? assert(sheet_thickness(sheet) == sheet_thickness(s)) sheet : s;
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, ```sheet``` can be set to override the type
dxf("box_left");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, ```sheet``` can be set to override the type
dxf("box_right");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, ```sheet``` can be set to override the type
dxf("box_front");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, ```sheet``` can be set to override the type
dxf("box_back");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_base(type) render_2D_sheet(box_base_sheet(type)) box_base_blank(type); //! Default base, can be overridden to customise
module box_top(type) render_2D_sheet(box_top_sheet(type)) box_top_blank(type); //! Default top, can be overridden to customise
module box_back(type) render_2D_sheet(box_sheets(type)) box_back_blank(type); //! Default back, can be overridden to customise
module box_front(type) render_2D_sheet(box_sheets(type)) box_front_blank(type); //! Default front, can be overridden to customise
module box_left(type) render_2D_sheet(box_sheets(type)) box_left_blank(type); //! Default left side, can be overridden to customise
module box_right(type) render_2D_sheet(box_sheets(type)) box_right_blank(type); //! Default right side, can be overridden to customise

94
box_assembly.scad Normal file
View File

@ -0,0 +1,94 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
// The assembly is ```include```d so the panel definitions can be overridden to add holes and components.
// The _box_module also needs to be wrapped in the file that uses it so it can be called without
// parameters to make the assembly views. E.g. module box_assembly() _box_assembly(box);
//
module _box_assembly(type, top = true, base = true, left = true, right = true, back = true, front = true, bezels = true, corners = 4)
assembly("box") {
echo("Box:", box_width(type), box_depth(type), box_height(type));
t = sheet_thickness(box_sheets(type));
for(corner = [0 : corners - 1]) {
x = [-1,1,1,-1][corner];
y = [-1,-1,1,1][corner];
translate([x * (box_width(type) / 2 + 25 * exploded()), y * (box_depth(type) / 2 + 25 * exploded())])
rotate(corner * 90) {
color(pp2_colour) render()
box_corner_profile(type);
translate([box_hole_inset(type), box_hole_inset(type)])
for(z = [-1, 1])
rotate([z * 90 -90, 0, 0])
translate_z(box_height(type) / 2 - box_margin(type))
insert(box_insert(type));
}
}
for(z = [-1, 1]) {
sheet_thickness = sheet_thickness(z > 0 ? box_top_sheet(type) : box_base_sheet(type));
translate_z(z * (box_height(type) / 2 - box_corner_gap(type) + 50 * exploded()))
rotate([z * 90 - 90, 0, 0])
if(bezels && (z > 0 ? top : base))
color(pp1_colour) render() box_bezel(type, z < 0);
translate_z(z * (box_height(type) / 2 + sheet_thickness + 50 * exploded()))
box_screw_hole_positions(type)
rotate([z * 90 -90, 0, 0])
explode(50, true)
screw_and_washer(box_screw(type), box_screw_length(type, z > 0), true);
}
for(x = [-1, 1])
translate([x * (box_width(type) / 2 + t / 2 + 25 * exploded()), 0])
rotate([90, 0, x * 90])
if(x > 0) {
if(right)
box_right(type);
}
else
if(left)
box_left(type);
for(y = [-1, 1])
translate([0, y * (box_depth(type) / 2 + t / 2 + 25 * exploded())])
rotate([90, 0, y * 90 + 90])
if(y < 0) {
if(front)
box_front(type);
}
else
if(back)
box_back(type);
for(z = [-1, 1]) {
sheet_thickness = sheet_thickness(z > 0 ? box_top_sheet(type) : box_base_sheet(type));
translate_z(z * (box_height(type) / 2 + sheet_thickness / 2 + eps + 100 * exploded()))
if(z > 0) {
if(top)
box_top(type);
}
else
if(base)
box_base(type);
}
}

261
butt_box.scad Normal file
View File

@ -0,0 +1,261 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! A box made from CNC cut panels butted together using printed fixing blocks. Useful for making large
//! boxes with minimal 3D printing. More blocks are added as the box gets bigger.
//!
//! Needs to be ```include```d rather than ```use```d to allow the panel definitions to be overridden to add holes
//! and mounted components.
//!
//! A list specifies the internal dimensions, screw type, top, bottom and side sheet types and the block
//! maximum spacing.
//!
//! Uses [fixing blocks](#fixing_block) and [corner blocks](#corner_block).
//
use <fixing_block.scad>
use <corner_block.scad>
use <utils/maths.scad>
function bbox_screw(type) = type[0]; //! Screw type for corner blocks
function bbox_sheets(type) = type[1]; //! Sheet type for the sides
function bbox_base_sheet(type)= type[2]; //! Sheet type for the base
function bbox_top_sheet(type) = type[3]; //! Sheet type for the top
function bbox_span(type) = type[4]; //! Maximum span between fixing blocks
function bbox_width(type) = type[5]; //! Internal width
function bbox_depth(type) = type[6]; //! Internal depth
function bbox_height(type) = type[7]; //! Internal height
module bbox_shelf_blank(type) { //! 2D template for a shelf
dxf("bbox_shelf");
sheet_2D(bbox_sheets(type), bbox_width(type), bbox_depth(type), 1);
}
function corner_block_positions(type) = let(
width = bbox_width(type),
depth = bbox_depth(type),
height = bbox_height(type)
)
[for(corner = [0 : 3], z = [-1, 1])
let(
x = [-1,1,1,-1][corner],
y = [-1,-1,1,1][corner]
) translate([x * (width / 2), y * (depth / 2), z * height / 2]) *
rotate([z > 0 ? 180 : 0, 0, corner * 90 + (z > 0 ? 90 : 0)])
];
module corner_block_positions(type) {
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
for(p = corner_block_positions(type))
let($thickness = transform([0, 0, 0], p).z > 0 ? tt : bt)
multmatrix(p)
children();
}
function corner_holes(type) = [for(p = corner_block_positions(type), q = corner_block_holes(bbox_screw(type))) p * q];
function fixing_block_positions(type) = let(
width = bbox_width(type),
depth = bbox_depth(type),
height = bbox_height(type),
span = bbox_span(type),
wspans = floor(width / span),
wspan = width / (wspans + 1),
dspans = floor(depth / span),
dspan = depth / (dspans + 1),
hspans = floor(height / span),
hspan = height / (hspans + 1)
)
[
for(i = [0 : 1 : wspans - 1], y = [-1, 1], z = [-1, 1])
translate([(i - (wspans - 1) / 2) * wspan, y * depth / 2, z * height / 2]) *
rotate([0, z * 90 + 90, y * 90 + 90]),
for(i = [0 : 1 : dspans - 1], x = [-1, 1], z = [-1, 1])
translate([x * width / 2, (i - (dspans - 1) / 2) * dspan, z * height / 2]) *
rotate([0, z * 90 + 90, x * 90]),
for(i = [0 : 1 : hspans - 1], x = [-1, 1], y = [-1, 1])
translate([x * width / 2, y * depth / 2, (i - (hspans - 1) / 2) * hspan]) *
rotate([y > 0 ? 180 : 0, x * y * 90]),
];
function side_holes(type) = [for(p = fixing_block_positions(type), q = fixing_block_holes(bbox_screw(type))) p * q];
module fixing_block_positions(type) {
t = sheet_thickness(bbox_sheets(type));
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
h = bbox_height(type) / 2 - 1;
for(p = fixing_block_positions(type))
let(z = transform([0, 0, 0], p).z, $thickness = z > h ? tt : z < -h ? bt : t)
multmatrix(p)
children();
}
module drill_holes(type, t)
for(list = [corner_holes(type), side_holes(type)], p = list)
let(q = t * p)
if(abs(transform([0, 0, 0], q).z) < eps)
multmatrix(q)
drill(screw_clearance_radius(bbox_screw(type)), 0);
module bbox_base_blank(type) { //! 2D template for the base
dxf("bbox_base");
difference() {
sheet_2D(bbox_base_sheet(type), bbox_width(type), bbox_depth(type), 1);
drill_holes(type, translate(bbox_height(type) / 2));
}
}
module bbox_top_blank(type) { //! 2D template for the top
dxf("bbox_top");
t = sheet_thickness(bbox_sheets(type));
difference() {
translate([0, t / 2])
sheet_2D(bbox_top_sheet(type), bbox_width(type) + 2 * t, bbox_depth(type) + t);
drill_holes(type, translate(-bbox_height(type) / 2));
}
}
module bbox_left_blank(type) { //! 2D template for the left side
dxf("bbox_left");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
difference() {
translate([-t / 2, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_depth(type) + t, bbox_height(type) + bb);
drill_holes(type, rotate([0, 90, 90]) * translate([bbox_width(type) / 2, 0]));
}
}
module bbox_right_blank(type) { //! 2D template for the right side
dxf("bbox_right");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
difference() {
translate([t / 2, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_depth(type) + t, bbox_height(type) + bb);
drill_holes(type, rotate([0, -90, 90]) * translate([-bbox_width(type) / 2, 0]));
}
}
module bbox_front_blank(type) { //! 2D template for the front
dxf("bbox_front");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
bt = sheet_thickness(bbox_top_sheet(type));
difference() {
translate([0, (bt - bb) / 2])
sheet_2D(bbox_sheets(type), bbox_width(type) + 2 * t, bbox_height(type) + bb + bt);
drill_holes(type, rotate([-90, 0, 0]) * translate([0, bbox_depth(type) / 2]));
}
}
module bbox_back_blank(type) { //! 2D template for the back
dxf("bbox_back");
bb = sheet_thickness(bbox_base_sheet(type));
t = sheet_thickness(bbox_sheets(type));
difference() {
translate([0, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_width(type), bbox_height(type) + bb);
drill_holes(type, rotate([90, 0, 0]) * translate([0, -bbox_depth(type) / 2]));
}
}
module bbox_base(type) render_2D_sheet(bbox_base_sheet(type)) bbox_base_blank(type); //! Default base, can be overridden to customise
module bbox_top(type) render_2D_sheet(bbox_top_sheet(type)) bbox_top_blank(type); //! Default top, can be overridden to customise
module bbox_back(type) render_2D_sheet(bbox_sheets(type)) bbox_back_blank(type); //! Default back, can be overridden to customise
module bbox_front(type) render_2D_sheet(bbox_sheets(type)) bbox_front_blank(type); //! Default front, can be overridden to customise
module bbox_left(type) render_2D_sheet(bbox_sheets(type)) bbox_left_blank(type); //! Default left side, can be overridden to customise
module bbox_right(type) render_2D_sheet(bbox_sheets(type)) bbox_right_blank(type); //! Default right side, can be overridden to customise
module _bbox_assembly(type, top = true, base = true, left = true, right = true, back = true, front = true) //! The box assembly, wrap with a local copy without parameters
assembly("bbox") {
width = bbox_width(type);
depth = bbox_depth(type);
height = bbox_height(type);
echo("Box:", width, depth, height);
t = sheet_thickness(bbox_sheets(type));
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
corner_block_positions(type)
fastened_corner_block_assembly(t, bbox_screw(type), $thickness);
fixing_block_positions(type)
fastened_fixing_block_assembly(t, bbox_screw(type), thickness2 = $thickness);
for(x = [-1, 1])
translate([x * (width / 2 + t / 2 + eps + 25 * exploded()), 0])
rotate([90, 0, x * 90])
if(x > 0) {
if(right)
bbox_right(type);
}
else
if(left)
bbox_left(type);
for(y = [-1, 1])
translate([0, y * (depth / 2 + t / 2 + eps + 25 * exploded())])
rotate([90, 0, y * 90 + 90])
if(y < 0) {
if(front)
bbox_front(type);
}
else
if(back)
bbox_back(type);
for(z = [-1, 1]) {
sheet_thickness = z > 0 ? tt : bt;
translate_z(z * (height / 2 + sheet_thickness / 2 + eps + 100 * exploded()))
if(z > 0) {
if(top)
bbox_top(type);
}
else
if(base)
bbox_base(type);
}
}

187
cable_grommets.scad Normal file
View File

@ -0,0 +1,187 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Printed cable grommets for passing cables through panels avoiding sharp edges and in the case
//! of conductive panels, an extra layer of insulation.
//
include <core.scad>
use <vitamins/cable_strip.scad>
base = 1.25;
slot_height = round_to_layer(1.27) + layer_height;
wall = 1.6;
overlap = 1.5;
height = base + slot_height + wall + overlap;
rad = wall + overlap;
clearance = 0.1;
module ribbon_grommet_hole(ways, h = 50, expand = true) { //! Generate a hole for a ribbon grommet
length = ribbon_clamp_slot(ways) + 2 * wall;
rad = cnc_bit_r;
height = base + slot_height + wall;
extrude_if(h)
offset(expand ? clearance : 0)
hull() {
translate([-length / 2, 0])
square([length, base]);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
drill(rad, 0);
}
}
module ribbon_grommet(ways, thickness) { //! Generate the STL for a printed ribbon grommet
stl(str("ribbon_grommet_", ways, "_", thickness));
width = 2 * (wall + clearance) + thickness;
slot_length = ribbon_clamp_slot(ways);
length = slot_length + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(height = wall, center = true, convexity = 5)
difference() {
hull() {
translate([-length / 2, 0])
square([length, base]);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
semi_circle(rad);
}
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
linear_extrude(height = width -1, center = true)
difference() {
ribbon_grommet_hole(ways, expand = false, h = 0);
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
}
}
module round_grommet_top(diameter, thickness, od = undef) { //! Generate the STL for a round grommet top half
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness));
chamfer = layer_height;
h = wall + thickness + wall;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + overlap;
r0 = r1 + 1;
union() {
rotate_extrude()
polygon([
[r0, 0],
[r3 - chamfer, 0],
[r3, chamfer],
[r3, wall],
[r2, wall],
[r2, h - chamfer],
[r2 - chamfer, h],
[r0, h],
]);
render() difference() {
cylinder(r = r0 + eps, h = h);
poly_cylinder(r = r1, h = 100, center = true);
}
}
}
module round_grommet_bottom(diameter, od = undef) { //! Generate the STL for a round grommet bottom half
stl(str("round_grommet_bottom_", round(diameter * 10)));
chamfer = layer_height;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + max(overlap, wall + chamfer);
rotate_extrude()
polygon([
[r2, chamfer],
[r2 + chamfer, 0],
[r3, 0],
[r3, wall - chamfer],
[r3 - chamfer, wall],
[r2, wall],
]);
}
module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
drill(diameter / 2 + wall + clearance, h);
module round_grommet_assembly(diameter, thickness, od = undef) {
color(pp1_colour)
translate_z(wall)
vflip()
round_grommet_top(diameter, thickness, od);
color(pp2_colour)
translate_z(-thickness)
vflip()
round_grommet_bottom(diameter, od);
}
module mouse_grommet_hole(r, h = 50, z = undef, expand = wall + clearance) //! Make a hole for a mouse grommet
extrude_if(h)
hull(){
R = r + expand;
translate([0, z == undef ? R : z])
semi_circle(R);
translate([-R, 0])
square([2 * R, eps]);
}
module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
stl(str("mouse_grommet_", r * 10, "_", thickness));
width = 2 * (wall + clearance) + thickness;
length = 2 * r + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(height = wall, center = true)
difference() {
mouse_grommet_hole(r + wall + overlap, z = r + wall, h = 0, expand = 0);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
linear_extrude(height = width - 1, center = true)
difference() {
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
}
}
module ribbon_grommet_20_3_stl() ribbon_grommet(20, 3);
module mouse_grommet_20_3_stl() mouse_grommet(2,3);
module mouse_grommet_30_3_stl() mouse_grommet(3,3);

63
carriers.scad Normal file
View File

@ -0,0 +1,63 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Adapts ESP12 module to 0.1" grid. See <https://hydraraptor.blogspot.com/2018/04/esp-12-module-breakout-adaptor.html>.
//
$extrusion_width = 0.5;
include <core.scad>
module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
stl("ESP12F_carrier");
pins = 8;
pitch1 = 2;
pitch2 = 2.54;
hole = pitch1 - squeezed_wall;
hole2 = pitch2 - 3 * extrusion_width;
length1 = (pins - 1) * pitch1 + hole + squeezed_wall * 2;
length2 = (pins - 1) * pitch2 + hole + squeezed_wall * 2;
height = 3;
wpitch1 = (pins - 1) * pitch1;
wpitch2 = ceil(wpitch1 / 2.54) * 2.54;
width1 = wpitch1 + hole + squeezed_wall * 2;
width2 = wpitch2 + hole2 + squeezed_wall * 2;
difference() {
hull() {
translate_z(height - eps / 2)
cube([width1, length1, eps], center = true);
translate_z(eps / 2)
cube([width2, length2, eps], center = true);
}
for(side = [-1, 1])
for(i = [0 : pins - 1])
hull() {
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
cube([hole, hole, eps], center = true);
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
cube([hole2, hole2, eps], center = true);
}
}
}

27
core.scad Normal file
View File

@ -0,0 +1,27 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 this file to use the library
//
include <global_defs.scad>
//
// Global functions and modules
//
use <utils/core/global.scad>

181
corner_block.scad Normal file
View File

@ -0,0 +1,181 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Corner brackets using threaded inserts for fastening three sheets together at right angles.
//! Defaults to M3 but other screws sizes can be specified provided they have inserts defined.
//!
//! See [butt_box](#Butt_box) for an example of usage.
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
use <utils/rounded_cylinder.scad>
use <utils/maths.scad>
def_screw = M3_cap_screw;
wall = 3;
overshoot = 2; // how far screw can overshoot the insert
function corner_block_screw() = def_screw; //! Default screw type
function corner_block_hole_offset(screw = def_screw) = //! Hole offset from the edge
let(insert = screw_insert(screw))
insert_length(insert) + max(overshoot + screw_clearance_radius(screw), insert_hole_radius(insert)) + 1;
function corner_block_width(screw = def_screw) = //! Block width, depth and height
corner_block_hole_offset(screw) + insert_outer_d(screw_insert(screw)) / 2 + wall;
function corner_block_v_hole(screw = def_screw) = let(offset = corner_block_hole_offset(screw)) translate([offset, offset]) * rotate([180, 0, 0]); //! Transform to bottom hole
function corner_block_h_holes(screw = def_screw) = //! List of transforms to side holes
let(offset = corner_block_hole_offset(screw))
[translate([offset, 0, offset]) * rotate([90, 0, 0]),
translate([0, offset, offset - layer_height]) * rotate([90, 0, -90])];
function corner_block_holes(screw) = concat([corner_block_v_hole(screw)], corner_block_h_holes(screw)); //! List of transforms to all holes
module corner_block_v_hole(screw = def_screw) //! Place children at the bottom screw hole
multmatrix(corner_block_v_hole(screw))
children();
module corner_block_h_holes(screw = def_screw) //! Place children at the side screw holes
for(p = corner_block_h_holes(screw))
multmatrix(p)
children();
module corner_block_holes(screw = def_screw) //! Place children at all the holes
for(p = corner_block_holes(screw))
multmatrix(p)
children();
module corner_block(screw = def_screw, name = false) { //! Generate the STL for a printed corner block
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20));
r = 1;
cb_width = corner_block_width(screw);
cb_height = cb_width;
cb_depth = cb_width;
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
offset = corner_block_hole_offset(screw);
difference() {
hull() {
translate([r, r])
rounded_cylinder(r = r, h = cb_height, r2 = r);
translate([r, cb_depth - r])
cylinder(r = r, h = cb_height - corner_rad);
translate([cb_width - r, r])
cylinder(r = r, h = cb_height - corner_rad);
translate([offset, offset, offset])
sphere(corner_rad);
translate([offset, offset])
cylinder(r = corner_rad, h = offset);
translate([offset, r, offset])
rotate([-90, 0, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
translate([r, offset, offset])
rotate([0, 90, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
}
corner_block_v_hole(screw)
insert_hole(insert, overshoot);
corner_block_h_holes(screw)
insert_hole(insert, overshoot, true);
children();
}
}
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
assembly(str("corner_block_M", 20 * screw_radius(screw))) {
insert = screw_insert(screw);
color(name ? pp2_colour : pp1_colour)
render() corner_block(screw, name) children();
corner_block_h_holes(screw)
insert(insert);
corner_block_v_hole(screw)
insert(insert);
}
module fastened_corner_block_assembly(thickness, screw = def_screw, thickness_below = undef, name = false) { //! Printed block with all fasteners
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + insert_length(insert) + overshoot);
corner_block_assembly(screw, name) children();
corner_block_h_holes(screw)
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
thickness2 = thickness_below ? thickness_below : thickness;
screw_length2 = screw_shorter_than(2 * washer_thickness(washer) + thickness2 + insert_length(insert) + overshoot);
corner_block_v_hole(screw)
translate_z(thickness2)
screw_and_washer(screw, screw_length2, true);
}
module corner_block_M20_stl() corner_block(M2_cap_screw);
module corner_block_M25_stl() corner_block(M2p5_cap_screw);
module corner_block_M30_stl() corner_block(M3_cap_screw);
module corner_block_M40_stl() corner_block(M4_cap_screw);
//
//! 1. Lay the blocks out and place an M2 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M20_assembly() corner_block_assembly(M2_cap_screw);
//
//! 1. Lay the blocks out and place an M2.5 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M25_assembly() corner_block_assembly(M2p5_cap_screw);
//
//! 1. Lay the blocks out and place an M3 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M30_assembly() corner_block_assembly(M3_cap_screw);
//
//! 1. Lay the blocks out and place an M4 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M40_assembly() corner_block_assembly(M4_cap_screw);

187
door_hinge.scad Normal file
View File

@ -0,0 +1,187 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Door hinges to hang an acrylic sheet door on a 3D printer, default 6mm thick.
//!
//! The screws are tapped into the acrylic.
//! Rubber door [sealing strip](#sealing_strip) is used to make it airtight and a [door_latch](#door_latch) holds it closed.
//
include <core.scad>
include <vitamins/screws.scad>
width = 18;
thickness = 4;
rad = 3;
dia = 12;
pin_screw = M3_cap_screw;
screw = M3_dome_screw;
stat_screw = M4_dome_screw;
stat_width = 15;
stat_length = 34;
stat_clearance = 0.75;
function door_hinge_pin_x() = -dia / 2; //! X offset of the hinge pin
function door_hinge_pin_y() = -dia / 2 - stat_clearance; //! Y offset of the hinge pin
function door_hinge_screw() = screw; //! Screw type used for hinge pin
function door_hinge_stat_screw() = stat_screw; //! Screw use to fasten the stationary part
function door_hinge_stat_width() = stat_width; //! Width of the stationary part
function door_hinge_stat_length() = stat_length; //! Length of the stationary part
module door_hinge_hole_positions(dir = 0) { //! Position chidren at the door hole positions
hole_pitch = width - 10;
for(side = [-1, 1])
translate([width / 2 + side * hole_pitch / 2, -dir * width / 2 -side * hole_pitch / 2])
children();
}
module door_hinge(door_thickness) { //! Generates STL for the moving part of the hinge
stl(str("door_hinge_", door_thickness));
hole_pitch = width - 10;
union() {
rotate([90, 0, 0])
linear_extrude(height = width, center = true)
difference() {
hull() {
translate([dia / 2, thickness + door_thickness / 2])
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0, truncate = false);
square([dia + 1, 2 * thickness + door_thickness], center = true);
}
square([1, thickness + door_thickness]);
}
translate([dia / 2, thickness + door_thickness / 2])
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
}
linear_extrude(height = thickness)
difference() {
hull() {
translate([0, -width / 2])
square([1, width]);
for(side = [-1, 1])
translate([-width + rad, side * (width / 2 - rad)])
circle4n(rad);
}
rotate(180)
vflip()
door_hinge_hole_positions()
poly_circle(screw_clearance_radius(screw));
}
}
}
module door_hinge_6_stl() door_hinge(6);
module door_hinge_stat_hole_positions(dir = 0) { //! Position children over the screws holes of the stationary part
hole_pitch = dia + (stat_length - dia) / 2;
for(side = [-1, 1])
translate([side * hole_pitch / 2, dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw))), thickness])
children();
}
module door_hinge_stat_stl() { //! Generates the STL for the stationary part
stl("door_hinge_stat");
union() {
linear_extrude(height = thickness)
difference() {
rounded_square([stat_length, stat_width], rad);
door_hinge_stat_hole_positions()
poly_circle(screw_clearance_radius(stat_screw));
}
rotate([90, 0, 0])
linear_extrude(height = stat_width, center = true)
difference() {
hull() {
translate([0, dia / 2 + stat_clearance])
circle(d = dia);
translate([0, 0.5])
square([dia, 1], center = true);
}
translate([0, dia / 2 + stat_clearance])
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
}
}
}
module door_hinge_assembly(top, door_thickness = 6) { //! The moving assembly that goes on the door
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
pin_y = door_hinge_pin_y();
washer = screw_washer(screw);
screw_length = screw_shorter_than(thickness + door_thickness + washer_thickness(washer));
translate([0, pin_y - (thickness + door_thickness / 2), dir * width / 2]) {
rotate([90, 0, 180])
color("red") door_hinge(door_thickness);
rotate([90, 0, 0])
door_hinge_hole_positions()
screw_and_washer(screw, screw_length);
}
translate([pin_x, pin_y, top ? 0 : -washer_thickness(screw_washer(pin_screw))])
washer(screw_washer(pin_screw));
translate([pin_x, pin_y, top ? washer_thickness(screw_washer(pin_screw)) + stat_width : width])
screw_and_washer(pin_screw, screw_longer_than(2 * washer_thickness(screw_washer(pin_screw)) + width + stat_width));
}
module door_hinge_static_assembly(top, sheet_thickness = 3) { //! The stationary assembly
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
stat_washer = screw_washer(stat_screw);
stat_nut = screw_nut(stat_screw);
stat_screw_length = screw_longer_than(thickness + sheet_thickness + 2 * washer_thickness(stat_washer) + nut_thickness(stat_nut, true));
translate([pin_x, 0, -dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw)))])
rotate([90, 0, 0]) {
color("lime") door_hinge_stat_stl();
door_hinge_stat_hole_positions() {
screw_and_washer(stat_screw, stat_screw_length);
translate_z(-thickness - sheet_thickness)
vflip()
nut_and_washer(stat_nut, true);
}
}
}
module door_hinge_parts_stl() { //! Generates the STL for both parts of the hinge
translate([2, width / 2 + 1])
door_hinge_6_stl();
translate([0, -stat_width / 2 - 1])
door_hinge_stat_stl();
}

81
door_latch.scad Normal file
View File

@ -0,0 +1,81 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Door latch for 6mm acrylic door for 3D printer. See [door_hinge](#door_hinge).
//
include <core.scad>
use <utils/hanging_hole.scad>
include <vitamins/screws.scad>
length = 35;
width = 12;
height = 14.25;
thickness = 5;
rad = 3;
screw = M4_hex_screw;
function door_latch_screw() = screw; //! The screw used for the axle
function door_latch_offset() = width / 2 + 1; //! Offset of the axle from the door edge
nut_trap_depth = round_to_layer(screw_head_height(screw)) + 4 * layer_height;
module door_latch_stl() { //! Generates the STL for the printed part
stl("door_latch");
ridge = 4;
difference() {
union() {
hull() {
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
translate_z(thickness / 2)
cube([length, ridge, thickness], center = true);
}
cylinder(d = width, h = height);
}
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickess
washer = screw_washer(screw);
nut = screw_nut(screw);
screw_length = screw_longer_than(height - nut_trap_depth + sheet_thickness + 2 * washer_thickness(washer) + nut_thickness(nut, true));
translate([0, -height - washer_thickness(washer)])
rotate([-90, 0, 0]) {
color("lime") render() door_latch_stl();
translate_z(nut_trap_depth)
vflip()
screw(screw, screw_length);
translate_z(height)
washer(washer);
translate_z(height + sheet_thickness + washer_thickness(washer))
nut_and_washer(nut, true);
}
}

92
fan_guard.scad Normal file
View File

@ -0,0 +1,92 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//! Pintable fan finger guard to match the specified fan. To be ```include```d, not ```use```d.
//!
//! The ring spacing as well as the number of spokes can be specified, if zero a gasket is generated instead of a guard.
//
use <utils/tube.scad>
function fan_guard_thickness() = 2; //! Default thickness
function fan_guard_wall() = extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2;
function fan_guard_corner_r(type) = washer_diameter(screw_washer(fan_screw(type))) / 2 + 0.5; //! Corner radius of the guard
function fan_guard_width(type) = max(2 * (fan_hole_pitch(type) + fan_guard_corner_r(type)), fan_bore(type) + 4 * fan_guard_wall()); //! Width of the guard
module fan_guard(type, name = false, thickness = fan_guard_thickness(), spokes = 4, finger_width = 7, grill = false) { //! Generate the STL
if(thickness)
stl(name ? name : str("fan_guard_", fan_width(type)));
hole_pitch = fan_hole_pitch(type);
corner_radius = fan_guard_corner_r(type);
wall = grill ? 2 : fan_guard_wall();
spoke = grill ? 3 : wall;
width = fan_guard_width(type);
hole = fan_aperture(type) / 2;
max_ring_pitch = finger_width + wall;
inner_ring = max_ring_pitch / 2;
gap = hole + wall / 2 - inner_ring;
rings = ceil(gap / max_ring_pitch);
ring_pitch = gap / rings;
spoke_end = grill && fan_aperture(type) > fan_bore(type) ? hole - ring_pitch : hole;
spoke_start = grill && rings > 1 ? inner_ring + ring_pitch : inner_ring;
rounding = grill ? 1.5 : 0;
extrude_if(thickness) {
difference() {
offset(-rounding) offset(rounding) {
difference() {
rounded_square([width, width], r = width / 2 - hole_pitch);
fan_holes(type, !grill, !grill, h = 0);
}
if(spokes) {
intersection() {
union() {
for(i = [(grill ? 1 : 0) : 1 : rings - 1]) {
r = inner_ring + i * ring_pitch;
ring(or = r + wall / 2, ir = r - wall / 2);
}
for(i = [0 : spokes - 1])
rotate(i * 360 / spokes + 45)
translate([spoke_start, -spoke / 2])
square([spoke_end - spoke_start + eps, spoke]);
}
square(width - eps, center = true);
}
}
}
if(grill)
fan_hole_positions(type, z = 0)
drill(screw_clearance_radius(fan_screw(type)), 0);
}
if(grill)
difference() {
r = min(inner_ring + ring_pitch, fan_hub(type) / 2);
circle(r);
for(a = [45 : 90 : 360])
rotate(a)
translate([r / 2, 0])
circle(wall);
}
}
}

170
fixing_block.scad Normal file
View File

@ -0,0 +1,170 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Fixing block to mount two sheets at right angles using threaded inserts.
//! Defaults to M3 but other screw sizes can be specified provided they have inserts defined.
//!
//! See [butt_box](#Butt_box) for an example of usage.
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
use <utils/maths.scad>
def_screw = M3_cap_screw;
wall = 2.5;
function fixing_block_screw() = def_screw; //! Default screw type
function fixing_block_width(screw = def_screw) = 4 * wall + 3 * insert_outer_d(screw_insert(screw)); //! Width given screw size
function fixing_block_depth(screw = def_screw) = //! Depth given screw size
let(insert = screw_insert(screw))
max(insert_length(insert) + wall, insert_outer_d(insert) + 2 * wall);
function fixing_block_height(screw = def_screw) = fixing_block_depth(screw); //! Height given screw size, same as depth
function fixing_block_h_hole(screw = def_screw) = translate(fixing_block_depth(screw) / 2) * rotate([90, 0, 0]); //! Returns transform to position the horizontal screw
function fixing_block_v_holes(screw = def_screw) = //! Returns a list of transforms to position the vertical screws
let(pitch = 2 * insert_outer_d(screw_insert(screw)) + 2 * wall, offset = fixing_block_depth(screw) / 2)
[for(end = [-1, 1]) translate([end * pitch / 2, offset]) * rotate([180, 0, 0])];
function fixing_block_holes(screw) = concat([fixing_block_h_hole(screw)], fixing_block_v_holes(screw)); //! Returns a list of transforms to position all the screws
module fixing_block_h_hole(screw = def_screw) //! Position children on the horizontal hole
multmatrix(fixing_block_h_hole(screw))
children();
module fixing_block_v_holes(screw = def_screw) //! Position children on the vertical holes
for(p = fixing_block_v_holes(screw))
multmatrix(p)
children();
module fixing_block_holes(screw = def_screw) //! Position children on all the holes
for(p = fixing_block_holes(screw))
multmatrix(p)
children();
module fixing_block_h_hole_2D(screw = def_screw) //! Position 2D child on the horizontal hole
translate([0, fixing_block_depth(screw) / 2])
children();
module fixing_block(screw = def_screw) { //! Generate the STL
stl(str("fixing_block_M", screw_radius(screw) * 20));
r = 1;
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
fb_width = fixing_block_width(screw);
fb_height = fixing_block_height(screw);
fb_depth = fixing_block_depth(screw);
difference() {
union() {
linear_extrude(height = fb_height, convexity = 5)
difference() {
hull() {
for(side = [-1, 1]) {
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
circle4n(corner_rad);
translate([side * (fb_width / 2 - r), r])
circle4n(r);
}
}
fixing_block_v_holes(screw)
poly_circle(screw_clearance_radius(screw));
}
}
translate_z(fb_height)
fixing_block_v_holes(screw)
insert_hole(insert);
fixing_block_h_hole(screw)
insert_hole(insert, 10, true);
}
}
module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8]) //! Printed part with the inserts inserted
assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
translate_z(fixing_block_height(screw))
rotate([0, 180, 0])
color(pp1_colour) render() fixing_block(screw);
insert = screw_insert(screw);
fixing_block_v_holes(screw)
insert(insert);
fixing_block_h_hole(screw)
insert(insert);
}
module fastened_fixing_block_assembly(thickness, screw = def_screw, screw2 = undef, thickness2 = undef) { //! Assembly with fasteners in place
module fb_screw(screw, thickness) {
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_longer_than(2 * washer_thickness(washer) + thickness + insert_length(insert));
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}
no_pose() fixing_block_assembly(screw);
fixing_block_v_holes(screw)
fb_screw(screw, thickness2 ? thickness2 : thickness);
fixing_block_h_hole(screw)
fb_screw(screw2 ? screw2 : screw, thickness);
}
module fixing_block_M20_stl() fixing_block(M2_cap_screw);
module fixing_block_M25_stl() fixing_block(M2p5_cap_screw);
module fixing_block_M30_stl() fixing_block(M3_cap_screw);
module fixing_block_M40_stl() fixing_block(M4_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M2 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M20_assembly() fixing_block_assembly(M2_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M2.5 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M25_assembly() fixing_block_assembly(M2p5_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M3 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M30_assembly() fixing_block_assembly(M3_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M4 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M40_assembly() fixing_block_assembly(M4_cap_screw);

151
foot.scad Normal file
View File

@ -0,0 +1,151 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 printed rubber feet for equipment cases. The insert variant is better for solid feet because
//! inserts don't grip well in rubber.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
foot = [25, 12, 3, 2, M4_cap_screw, 10];
insert_foot = [20, 10, 0, 2, M3_cap_screw, 10];
function foot() = foot; //! Default foot used unless a list of parameters is passed
function insert_foot() = insert_foot; //! Default foot with insert
function foot_diameter(type = foot) = type[0]; //! Outside maximum diameter
function foot_height(type = foot) = type[1]; //! Total height
function foot_thickness(type = foot)= type[2]; //! Thickness under the screw
function foot_rad(type = foot) = type[3]; //! Rounded corner radius
function foot_screw(type = foot) = type[4]; //! Screw type
function foot_slant(type = foot) = type[5]; //! Taper angle
module foot(type = foot) { //! Generate STL
stl("foot");
h = foot_height(type);
t = foot_thickness(type);
r1 = washer_radius(screw_washer(foot_screw(type)));
r3 = foot_diameter(type) / 2;
r2 = r3 - h * tan(foot_slant(type));
r = foot_rad(type);
union() {
rotate_extrude(convexity = 3) {
hull() {
translate([r1, 0])
square([r3 - r1, eps]);
for(x = [r1 + r, r2 - r])
translate([x, h - r])
circle4n(r);
}
}
linear_extrude(height = t)
difference() {
circle(r1 + eps);
poly_circle( screw_clearance_radius(foot_screw(type)));
}
}
}
module foot_assembly(t = 0, type = foot) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
nut = screw_nut(screw);
squeeze = 0.5;
screw_length = screw_longer_than(foot_thickness(type) + t + 2 * washer_thickness(washer) + nut_thickness(nut, true) - squeeze);
vflip() explode(15, true) {
color(pp4_colour) foot(type);
if(t)
explode(15, true)
translate_z(foot_thickness(type))
screw_and_washer(screw, screw_length);
}
if(t)
translate_z(t)
nut_and_washer(nut, true);
}
module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
stl("insert_foot");
h = foot_height(type);
r3 = foot_diameter(type) / 2;
r2 = r3 - h * tan(foot_slant(type));
r = foot_rad(type);
insert = screw_insert(foot_screw(type));
h2 = insert_hole_length(insert);
r4 = insert_hole_radius(insert);
r5 = r4 + 1;
union() {
rotate_extrude() {
union() {
hull() {
translate([r5, 0]) {
square([r3 - r5, eps]);
square([eps, h]);
}
translate([r2 - r, h - r])
circle4n(r);
}
}
}
linear_extrude(height = h2 + eps)
difference() {
circle(r5 + eps);
poly_circle(r4);
}
translate_z(h2)
cylinder(r = r5 + eps, h = h - h2);
}
}
//
//! Place the insert in the bottom of the foot and push home with a soldering iron with a conical bit heated to 200&deg;C.
//
module insert_foot_assembly(type = insert_foot) //! Printed part with insert in place
assembly("insert_foot") {
screw = foot_screw(type);
insert = screw_insert(screw);
vflip()
color(pp1_colour) insert_foot(type);
translate_z(-foot_thickness(type))
insert(insert);
}
module fastened_insert_foot_assembly(t = 3, type = insert_foot) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_shorter_than(insert_length(insert) + t + 2 * washer_thickness(washer));
explode(-10) insert_foot_assembly(type);
translate_z(t)
screw_and_washer(screw, screw_length, true);
}

90
global_defs.scad Normal file
View File

@ -0,0 +1,90 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
// This file included directly or indirectly in every scad file.
//
// This scheme allows the following:
// bom defaults to 0
// Setting $bom on the command line or in the main file before including lib.scad overrides it everywhere.
// Setting $bom after including lib overrides bom in the libs but not in the local file.
// Setting $_bom in the local file overrides it in the local file but not in the libs.
//
//function is_undef(x) = x == undef;
$_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well
$exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view
layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth when printing
extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing
nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle
cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // miniumum tool radius when milling 2D objects
pp1_colour = is_undef($pp1_colour) ? "lime" : $pp1_colour; // printed part colour 1
pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // printed part colour 2
pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3
pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4
show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction
// Minimum wall is about two filaments wide but we extrude it closer to get better bonding
squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4)
: extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2;
inf = 1e10; // very big
eps = 1/128; // small fudge factor to stop CSG barfing on coincident faces.
$fa = 6;
$fs = extrusion_width / 2;
function round_to_layer(z) = ceil(z / layer_height) * layer_height;
// Some additional named colors
grey20 = [0.2, 0.2, 0.2];
grey30 = [0.3, 0.3, 0.3];
grey40 = [0.4, 0.4, 0.4];
grey50 = [0.5, 0.5, 0.5];
grey60 = [0.6, 0.6, 0.6];
grey70 = [0.7, 0.7, 0.7];
grey80 = [0.8, 0.8, 0.8];
grey90 = [0.9, 0.9, 0.9];
brass = "gold";
/*
* Enums
*/
//
// Screws
//
hs_cap = 0;
hs_pan = 1;
hs_cs = 2; // counter sunk
hs_hex = 3;
hs_grub = 4; // pulley set screw
hs_cs_cap = 5;
hs_dome = 6;
//
// Hot end descriptions
//
jhead = 1;
e3d = 2;
//
// Face enumeration
//
f_bottom = 0;
f_top = 1;
f_left = 2;
f_right = 3;
f_front = 4;
f_back = 5;

103
handle.scad Normal file
View File

@ -0,0 +1,103 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Printed handle that can be printed without needing support material due to its truncated teardrop profile.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
dia = 18;
length = 90; // inside length
height = 30; // inside height
screw = M4_cap_screw;
insert = screw_insert(screw);
pitch = length + dia;
function handle_length() = pitch + dia; //! Outside length
function handle_width() = dia; //! The width, i.e. diameter
function handle_height() = height + dia; //! Total height
function handle_screw() = screw; //! The screw type
module handle_screw_positions() //! Position children at the screw positions
for(end = [-1, 1])
translate([end * pitch / 2, 0])
children();
module handle_holes(h = 100) //! Drills holes for the screws
handle_screw_positions()
drill(screw_clearance_radius(screw), h);
module handle_stl() { //! generate the STL
stl("handle");
module end(end)
translate([end * pitch / 2, 0])
rotate_extrude()
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0);
translate([0, - (dia + 1) / 2])
square([dia / 2 + 1, dia + 1]);
}
translate_z(dia / 2)
union() {
hull() {
end(-1);
end(1);
}
handle_screw_positions()
render() difference() {
h = height + dia / 2;
cylinder(d = dia, h = h);
translate_z(h)
insert_hole(insert, 6);
}
}
}
//
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") {
translate_z(handle_height())
color(pp1_colour) vflip() handle_stl();
handle_screw_positions()
vflip()
insert(insert);
}
module handle_fastened_assembly(thickness) { //! Assembly with fasteners in place
screw_length = screw_longer_than(thickness + insert_length(insert) + 2 * washer_thickness(screw_washer(screw)));
handle_assembly();
handle_screw_positions()
vflip()
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}

89
lib.scad Normal file
View File

@ -0,0 +1,89 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 this file to use the library
//
include <core.scad>
include <vitamins/fans.scad>
include <vitamins/inserts.scad>
include <vitamins/ring_terminals.scad>
include <vitamins/rails.scad>
include <vitamins/belts.scad>
include <vitamins/pulleys.scad>
include <vitamins/sheets.scad>
include <vitamins/stepper_motors.scad>
include <vitamins/components.scad>
include <vitamins/hot_ends.scad>
include <vitamins/tubings.scad>
include <vitamins/zipties.scad>
include <vitamins/linear_bearings.scad>
include <vitamins/rod.scad>
include <vitamins/leadnuts.scad>
include <vitamins/bulldogs.scad>
include <vitamins/pillars.scad>
include <vitamins/psus.scad>
include <vitamins/iecs.scad>
include <vitamins/rockers.scad>
include <vitamins/ssrs.scad>
include <vitamins/d_connectors.scad>
include <vitamins/buttons.scad>
include <vitamins/pcbs.scad>
include <vitamins/modules.scad>
include <vitamins/displays.scad>
include <vitamins/blowers.scad>
include <vitamins/leds.scad>
include <vitamins/toggles.scad>
include <vitamins/transformers.scad>
include <vitamins/variacs.scad>
include <vitamins/springs.scad>
include <vitamins/batteries.scad>
include <vitamins/microswitches.scad>
include <vitamins/ball_bearings.scad>
include <vitamins/light_strips.scad>
include <vitamins/spools.scad>
include <vitamins/mains_sockets.scad>
use <vitamins/jack.scad>
use <vitamins/meter.scad>
use <vitamins/fuseholder.scad>
use <vitamins/opengrab.scad>
use <vitamins/wire.scad>
use <vitamins/sealing_strip.scad>
use <vitamins/cable_strip.scad>
use <vitamins/veroboard.scad>
use <vitamins/o_ring.scad>
use <vitamins/microview.scad>
use <utils/maths.scad>
use <utils/bezier.scad>
use <utils/sweep.scad>
use <utils/rounded_cylinder.scad>
use <utils/dogbones.scad>
use <utils/tube.scad>
use <utils/quadrant.scad>
use <utils/hanging_hole.scad>
use <utils/fillet.scad>
use <utils/rounded_polygon.scad>
use <utils/layout.scad>
use <utils/round.scad>
use <utils/offset.scad>
use <utils/sector.scad>

339
libtest.scad Normal file
View File

@ -0,0 +1,339 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
// This file shows all the parts in the library.
//
include <lib.scad>
use <tests/ball_bearings.scad>
use <tests/batteries.scad>
use <tests/belts.scad>
use <tests/blowers.scad>
use <tests/bulldogs.scad>
use <tests/buttons.scad>
use <tests/cable_strips.scad>
use <tests/components.scad>
use <tests/d_connectors.scad>
use <tests/displays.scad>
use <tests/fans.scad>
use <tests/fuseholder.scad>
use <tests/hot_ends.scad>
use <tests/iecs.scad>
use <tests/inserts.scad>
use <tests/jack.scad>
use <tests/leadnuts.scad>
use <tests/leds.scad>
use <tests/light_strips.scad>
use <tests/linear_bearings.scad>
use <tests/meter.scad>
use <tests/microswitches.scad>
use <tests/modules.scad>
use <tests/nuts.scad>
use <tests/o_ring.scad>
use <tests/opengrab.scad>
use <tests/pcbs.scad>
use <tests/pillars.scad>
use <tests/psus.scad>
use <tests/pulleys.scad>
use <tests/rails.scad>
use <tests/ring_terminals.scad>
use <tests/rockers.scad>
use <tests/rod.scad>
use <tests/screws.scad>
use <tests/sealing_strip.scad>
use <tests/sheets.scad>
use <tests/spades.scad>
use <tests/springs.scad>
use <tests/ssrs.scad>
use <tests/stepper_motors.scad>
use <tests/toggles.scad>
use <tests/transformers.scad>
use <tests/tubings.scad>
use <tests/veroboard.scad>
use <tests/washers.scad>
use <tests/variacs.scad>
use <tests/zipties.scad>
use <tests/box.scad>
use <tests/butt_box.scad>
use <tests/cable_grommets.scad>
use <tests/carriers.scad>
use <tests/corner_block.scad>
use <tests/door_hinge.scad>
use <tests/door_latch.scad>
use <tests/fan_guard.scad>
use <tests/fixing_block.scad>
use <tests/foot.scad>
use <tests/handle.scad>
use <tests/ribbon_clamp.scad>
use <tests/screw_knob.scad>
use <tests/socket_box.scad>
use <tests/strap_handle.scad>
x5 = 800;
cable_grommets_y = 0;
translate([x5, cable_grommets_y])
cable_grommets();
translate([x5, cable_grommets_y + 50])
feet();
translate([x5, cable_grommets_y + 75])
fixing_blocks();
translate([x5, cable_grommets_y + 100])
corner_blocks();
translate([x5, cable_grommets_y + 150])
ribbon_clamps();
translate([x5 + 70, cable_grommets_y + 150])
screw_knobs();
translate([x5, cable_grommets_y + 470]) {
door_hinges()
door_latches();
}
translate([x5, cable_grommets_y + 370])
no_explode() socket_boxes();
translate([x5 + 60, cable_grommets_y + 200])
strap_handles();
translate([x5, cable_grommets_y + 250])
handle();
translate([900, 600])
box_test();
translate([850, 1170])
bbox_test();
x0 = 0;
inserts_y = 0;
nuts_y = inserts_y + 20;
washers_y = nuts_y + 60;
screws_y = washers_y + 120;
o_rings_y = screws_y + 130;
springs_y = o_rings_y + 20;
sealing_strip_y = springs_y + 20;
tubings_y = sealing_strip_y + 20;
pillars_y = tubings_y + 20;
leadnuts_y = pillars_y + 40;
pulleys_y = leadnuts_y +40;
hot_ends_y = pulleys_y + 60;
linear_bearings_y = hot_ends_y + 50;
sheets_y = linear_bearings_y + 50;
pcbs_y = sheets_y + 40;
displays_y = pcbs_y + 150;
fans_y = displays_y + 100;
transformers_y = fans_y + 120;
psus_y = transformers_y + 190;
translate([x0 + 20, inserts_y])
inserts();
translate([x0, inserts_y])
ring_terminals();
translate([x0, nuts_y])
nuts();
translate([x0, washers_y])
washers();
translate([x0, screws_y])
screws();
translate([x0, o_rings_y])
o_rings();
translate([x0, springs_y])
springs();
translate([x0 + 50, sealing_strip_y])
sealing_strip_test();
translate([x0, tubings_y])
tubings();
translate([x0, pillars_y])
pillars();
translate([x0, leadnuts_y ])
leadnuts();
translate([x0 + 80, leadnuts_y])
ball_bearings();
translate([x0, pulleys_y])
pulleys();
translate([x0, linear_bearings_y]) {
linear_bearings();
rods();
}
translate([x0 + 10, hot_ends_y])
hot_ends();
translate([x0, sheets_y])
sheets();
translate([x0, pcbs_y])
pcbs();
translate([x0, displays_y])
displays();
translate([x0, fans_y]) {
fans();
translate_z(3)
fan_guards();
}
translate([x0, transformers_y])
variacs();
translate([x0, psus_y])
psus();
x1 = x0 + 100;
zipties_y = 0;
bulldogs_y = zipties_y + 40;
translate([x1, zipties_y])
zipties();
translate([x1, bulldogs_y])
bulldogs();
x2 = x1 + 90;
leds_y = 0;
carriers_y = leds_y + 40;
spades_y = carriers_y + 40;
buttons_y = spades_y + 40;
jacks_y = buttons_y + 40;
microswitches_y = jacks_y + 40;
rockers_y = microswitches_y + 40;
toggles_y = rockers_y + 40;
components_y = toggles_y + 40;
translate([x2, leds_y])
leds();
translate([x2 + 8, carriers_y])
carriers();
translate([x2+ 38, carriers_y])
meters();
translate([x2 + 68, carriers_y])
fuseholders();
translate([x2, spades_y])
spades();
translate([x2, buttons_y])
buttons();
translate([x2, jacks_y])
jacks();
translate([x2, microswitches_y])
microswitches();
translate([x2, rockers_y])
rockers();
translate([x2, toggles_y])
toggles();
translate([x2, components_y])
components();
x3 = x2 + 150;
veroboard_y = 0;
d_connectors_y = veroboard_y + 110;
iecs_y = d_connectors_y + 80;
modules_y = iecs_y + 60;
ssrs_y = modules_y + 80;
blowers_y = ssrs_y + 60;
batteries_y = blowers_y + 100;
steppers_y = batteries_y + 70;
translate([x3, veroboard_y])
veroboard_test();
translate([x3, d_connectors_y])
d_connectors();
translate([x3, iecs_y])
iecs();
translate([x3 + 15, modules_y])
microview();
translate([x3 + 40, modules_y])
modules();
translate([x3, ssrs_y])
ssrs();
translate([x3, blowers_y])
blowers();
translate([x3, batteries_y])
batteries();
translate([x2, steppers_y]) // interloper
stepper_motors();
translate([x3, transformers_y])
transformers();
x4 = x3 + 220;
belts_y = 0;
rails_y = belts_y + 200;
cable_strips_y = rails_y + 300;
translate([x4 + 112, belts_y + 58]) {
belt_test();
translate([0, 60])
opengrab_test();
}
translate([x4, rails_y + 130])
rails();
translate([x4, cable_strips_y])
cable_strips();
x6 = x5 + 150;
translate([x6, 125])
light_strips();

119
ribbon_clamp.scad Normal file
View File

@ -0,0 +1,119 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Clamp for ribbon cable and polypropylene strip.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
use <vitamins/cable_strip.scad>
wall = 2;
min_wall = 2 * extrusion_width;
screw = M3_cap_screw;
insert = screw_insert(screw);
screw_depth = insert_length(insert) + 1;
function ribbon_clamp_hole_pitch(ways) = ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(insert)); //! Hole pitch
function ribbon_clamp_width() = 2 * (insert_hole_radius(insert) + 2); //! Width
function ribbon_clamp_length(ways) = ribbon_clamp_hole_pitch(ways) + ribbon_clamp_width(); //! Length given ways
function ribbon_clamp_height() = screw_depth + 1; //! Height
module ribbon_clamp_hole_positions(ways, side = undef) //! Place children at hole positions
for(x = is_undef(side) ? [-1, 1] : side)
translate([x * ribbon_clamp_hole_pitch(ways) / 2, 0])
children();
module ribbon_clamp_holes(ways, h = 20) //! Drill screw holes
ribbon_clamp_hole_positions(ways)
drill(screw_clearance_radius(screw), h);
module ribbon_clamp(ways) { //! Generate STL for given number of ways
stl(str("ribbon_clamp_", ways));
pitch = ribbon_clamp_hole_pitch(ways);
d = ribbon_clamp_width();
h = ribbon_clamp_height();
t = h - ribbon_clamp_slot_depth() - wall;
difference() {
union() {
hull() {
translate_z(h - t / 2)
cube([ribbon_clamp_hole_pitch(ways), d, t], center = true);
translate_z(1)
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
}
ribbon_clamp_hole_positions(ways, -1)
cylinder(d = d, h = h);
ribbon_clamp_hole_positions(ways, 1)
cylinder(d = d, h = h);
}
translate_z(h)
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
ribbon_clamp_hole_positions(ways)
translate_z(h)
rotate(22.5)
insert_hole(insert, screw_depth - insert_length(insert));
}
}
module ribbon_clamp_assembly(ways) pose([55, 180, 25]) //! Printed part with inserts in place
assembly(str("ribbon_clamp_", ways)) {
h = ribbon_clamp_height();
color(pp1_colour) render()
translate_z(h) vflip() ribbon_clamp(ways);
ribbon_clamp_hole_positions(ways)
vflip()
insert(insert);
}
module ribbon_clamp_fastened_assembly(ways, thickness, screw = screw) { //! Clamp with fasteners in place
tape_l = floor(ribbon_clamp_slot(ways));
tape_width = 25;
tape_thickness = 0.5;
vitamin(str(": Tape self amalgamating silicone ",tape_l," x 25mm"));
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + screw_depth);
ribbon_clamp_assembly(ways);
color("red") translate_z(tape_thickness / 2)
cube([tape_l, tape_width, tape_thickness], center = true);
ribbon_clamp_hole_positions(ways)
vflip()
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}
module ribbon_clamp_20_stl() ribbon_clamp(20);
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200&deg;C.
module ribbon_clamp_20_assembly() ribbon_clamp_assembly(20);

77
screw_knob.scad Normal file
View File

@ -0,0 +1,77 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Knob with embedded hex head screw.
//
include <core.scad>
include <vitamins/screws.scad>
use <utils/hanging_hole.scad>
knob_wall = 2;
function knob_nut_trap_depth(screw) = round_to_layer(screw_head_height(screw));
knob_stem_h = 6;
knob_thickness = 4;
knob_r = 8;
knob_wave = 1;
knob_waves = 9;
knob_height = knob_stem_h + knob_thickness;
function knob_height() = knob_height;
module screw_knob(screw) { //! Generate the STL foe a knob to fit the specified hex screw
stl(str("screw_knob_M", screw_radius(screw) * 20));
knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;
function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;
union() {
render() difference() {
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
linear_extrude(height = knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
circle(knob_stem_r - eps);
}
}
}
//! Place the screw through the printed part
module screw_knob_assembly(screw, length) //! Assembly with the screw in place
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length)) {
translate_z(knob_height)
vflip()
color(pp1_colour) screw_knob(screw);
translate_z(knob_height - knob_nut_trap_depth(screw))
rotate(-45)
screw(screw, length);
}
module screw_knob_M30_stl() screw_knob(M3_hex_screw);
module screw_knob_M40_stl() screw_knob(M4_hex_screw);
module screw_knob_M30_16_assembly() screw_knob_assembly(M3_hex_screw, 16);
module screw_knob_M40_16_assembly() screw_knob_assembly(M4_hex_screw, 16);

80
scripts/blurb.py Normal file
View File

@ -0,0 +1,80 @@
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
"""
Capture Markup lines in OpenSCAD source code denoted by '//!'.
"""
import re
def parse_line(line):
""" process a line, add blurb to text and return true if got to a module or function """
if line[:3] == '//!':
line = line.replace('~\n', ' \n')
start = 4 if line[3] == ' ' else 3
return False, line[start :]
else:
words = line.split()
return len(words) and (words[0] == "module" or words[0] == "function"), ""
def _scrape_blurb(lines):
""" Find Markup lines before the first function or module given a list of lines."""
text = ""
for line in lines:
b, t = parse_line(line)
if b:
break
text += t
if len(text):
text += '\n'
return text
def scrape_blurb(scad_file):
""" Find Markup lines before the first function or module."""
with open(scad_file, "rt") as file:
lines = file.readlines()
return _scrape_blurb(lines)
def scrape_module_blurb(lines):
""" Find the Markup lines before the last function or module. """
text = ""
for line in lines:
b, t = parse_line(line)
text = "" if b else text + t
return text
def scrape_code(scad_file):
""" Find the Markup lines on the first line of functions and modules. """
with open(scad_file, "rt") as file:
lines = file.readlines()
blurb = _scrape_blurb(lines)
properties = {}
functions = {}
modules = {}
for line in lines:
match = re.match(r'^function (.*\(type\)|.*\(type ?= ?.*?\)) *= *type\[.*\].*?(?://! ?(.*))?$', line)
if match:
properties[match.group(1)] = match.group(2)
else:
match = re.match(r'^function (.*?\(.*?\)).*?(?://! ?(.*))$', line)
if match:
functions[match.group(1)] = match.group(2)
match = re.match(r'^module (.*?\(.*?\)).*?(?://! ?(.*))$', line)
if match:
modules[match.group(1)] = match.group(2)
return { "blurb" : blurb, "properties" : properties, "functions" : functions, "modules": modules}

248
scripts/bom.py Normal file
View File

@ -0,0 +1,248 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import os
import sys
import shutil
import openscad
from time import *
from set_config import *
import json
def find_scad_file(mname):
for filename in os.listdir(source_dir):
if filename[-5:] == ".scad":
#
# look for module which makes the assembly
#
with open(source_dir + "/" + filename, "r") as f:
for line in f.readlines():
words = line.split()
if len(words) and words[0] == "module":
module = words[1].split('(')[0]
if module == mname:
return filename
return None
class BOM:
def __init__(self, name):
self.name = name
self.count = 1
self.vitamins = {}
self.printed = {}
self.routed = {}
self.assemblies = {}
def data(self, main):
return {
"name" : self.name,
"count" : self.count,
"assemblies" : [main.assemblies[ass].data(main) for ass in self.assemblies],
"vitamins" : self.vitamins,
"printed" : self.printed,
"routed" : self.routed
}
def flat_data(self):
assemblies = {}
for ass in self.assemblies:
assemblies[ass] = self.assemblies[ass].count
return {
"assemblies" : assemblies,
"vitamins" : self.vitamins,
"printed" : self.printed,
"routed" : self.routed
}
def add_part(self, s):
if s[-4:] == ".stl":
parts = self.printed
else:
if s[-4:] == ".dxf":
parts = self.routed
else:
parts = self.vitamins
if s in parts:
parts[s] += 1
else:
parts[s] = 1
def add_assembly(self, ass):
if ass in self.assemblies:
self.assemblies[ass].count += 1
else:
self.assemblies[ass] = BOM(ass)
def make_name(self, ass):
if self.count == 1:
return ass
return ass.replace("assembly", "assemblies")
def print_bom(self, breakdown, file = None):
if self.vitamins:
print("Vitamins:", file=file)
if breakdown:
longest = 0
for ass in self.assemblies:
name = ass.replace("_assembly","")
longest = max(longest, len(name))
for i in range(longest):
line = ""
for ass in sorted(self.assemblies):
name = ass.replace("_assembly","").replace("_"," ").capitalize()
index = i - (longest - len(name))
if index < 0:
line += " "
else:
line += (" %s " % name[index])
print(line[:-1], file=file)
for part in sorted(self.vitamins):
if ': ' in part:
part_no, description = part.split(': ')
else:
part_no, description = "", part
if breakdown:
for ass in sorted(self.assemblies):
bom = self.assemblies[ass]
if part in bom.vitamins:
file.write("%2d|" % bom.vitamins[part])
else:
file.write(" |")
print("%3d" % self.vitamins[part], description, file=file)
if self.printed:
if self.vitamins:
print(file=file)
print("Printed:", file=file)
for part in sorted(self.printed):
if breakdown:
for ass in sorted(self.assemblies):
bom = self.assemblies[ass]
if part in bom.printed:
file.write("%2d|" % bom.printed[part])
else:
file.write(" |")
print("%3d" % self.printed[part], part, file=file)
if self.routed:
print(file=file)
print("CNC cut:", file=file)
for part in sorted(self.routed):
if breakdown:
for ass in sorted(self.assemblies):
bom = self.assemblies[ass]
if part in bom.routed:
file.write("%2d|" % bom.routed[part])
else:
file.write(" |")
print("%3d" % self.routed[part], part, file=file)
if self.assemblies:
print(file=file)
print("Assemblies:", file=file)
for ass in sorted(self.assemblies):
print("%3d %s" % (self.assemblies[ass].count, self.assemblies[ass].make_name(ass)), file=file)
def parse_bom(file = "openscad.log", name = None):
main = BOM(name)
stack = []
for line in open(file):
pos = line.find('ECHO: "~')
if pos > -1:
s = line[pos + 8 : line.rfind('"')]
if s[-1] == '{':
ass = s[:-1]
if stack:
main.assemblies[stack[-1]].add_assembly(ass) #add to nested BOM
stack.append(ass)
main.add_assembly(ass) #add to flat BOM
else:
if s[0] == '}':
if s[1:] != stack[-1]:
raise Exception("Mismatched assembly " + s[1:] + str(stack))
stack.pop()
else:
main.add_part(s)
if stack:
main.assemblies[stack[-1]].add_part(s)
return main
def boms(target = None, assembly = None):
bom_dir = set_config(target) + "bom"
if assembly:
bom_dir += "/accessories"
if not os.path.isdir(bom_dir):
os.makedirs(bom_dir)
else:
assembly = "main_assembly"
if os.path.isdir(bom_dir):
shutil.rmtree(bom_dir)
sleep(0.1)
os.makedirs(bom_dir)
#
# Find the scad file that makes the module
#
scad_file = find_scad_file(assembly)
if not scad_file:
raise Exception("can't find source for " + assembly)
#
# make a file to use the module
#
bom_maker_name = source_dir + "/bom.scad"
with open(bom_maker_name, "w") as f:
f.write("use <%s>\n" % scad_file)
f.write("%s();\n" % assembly);
#
# Run openscad
#
openscad.run("-D","$bom=2","-D","$preview=true","-o", "openscad.echo", bom_maker_name)
os.remove(bom_maker_name)
print("Generating bom ...", end=" ")
main = parse_bom("openscad.echo", assembly)
if assembly == "main_assembly":
main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
for ass in sorted(main.assemblies):
with open(bom_dir + "/" + ass + ".txt", "wt") as f:
bom = main.assemblies[ass]
print(bom.make_name(ass) + ":", file=f)
bom.print_bom(False, f)
with open(bom_dir + "/bom.json", 'w') as outfile:
json.dump(main.assemblies[assembly].data(main), outfile, indent = 4)
print("done")
if __name__ == '__main__':
args = len(sys.argv)
if args > 1:
if args > 2:
boms(sys.argv[1], sys.argv[2])
else:
boms(sys.argv[1])
else:
boms();

108
scripts/c14n_stl.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
#
# OpenSCAD produces randomly ordered STL files so source control like GIT can't tell if they have changed or not.
# This scrip orders each triangle to start with the lowest vertex first (comparing x, then y, then z)
# It then sorts the triangles to start with the one with the lowest vertices first (comparing first vertex, second, then third)
# This has no effect on the model but makes the STL consistent. I.e. it makes a canonical form.
#
from __future__ import print_function
import sys
def cmz(x):
''' Convert "-0" to "0". '''
return '0' if x == '-0' else x
class Vertex:
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
self.key = (float(x), float(y), float(z))
class Normal:
def __init__(self, dx, dy, dz):
self.dx, self.dy, self.dz = dx, dy, dz
class Facet:
def __init__(self, normal, v1, v2, v3):
self.normal = normal
if v1.key < v2.key:
if v1.key < v3.key:
self.vertices = (v1, v2, v3) #v1 is the smallest
else:
self.vertices = (v3, v1, v2) #v3 is the smallest
else:
if v2.key < v3.key:
self.vertices = (v2, v3, v1) #v2 is the smallest
else:
self.vertices = (v3, v1, v2) #v3 is the smallest
def key(self):
return (self.vertices[0].x, self.vertices[0].y, self.vertices[0].z,
self.vertices[1].x, self.vertices[1].y, self.vertices[1].z,
self.vertices[2].x, self.vertices[2].y, self.vertices[2].z)
class STL:
def __init__(self, fname):
self.facets = []
with open(fname) as f:
words = [cmz(s.strip()) for s in f.read().split()]
if words[0] == 'solid' and words[1] == 'OpenSCAD_Model':
i = 2
while words[i] == 'facet':
norm = Normal(words[i + 2], words[i + 3], words[i + 4])
v1 = Vertex(words[i + 8], words[i + 9], words[i + 10])
v2 = Vertex(words[i + 12], words[i + 13], words[i + 14])
v3 = Vertex(words[i + 16], words[i + 17], words[i + 18])
i += 21
self.facets.append(Facet(norm, v1, v2, v3))
self.facets.sort(key = Facet.key)
else:
print("Not an OpenSCAD ascii STL file")
sys.exit(1)
def write(self, fname):
with open(fname,"wt") as f:
print('solid OpenSCAD_Model', file=f)
for facet in self.facets:
print(' facet normal %s %s %s' % (facet.normal.dx, facet.normal.dy, facet.normal.dz), file=f)
print(' outer loop', file=f)
for vertex in facet.vertices:
print(' vertex %s %s %s' % (vertex.x, vertex.y, vertex.z), file=f)
print(' endloop', file=f)
print(' endfacet', file=f)
print('endsolid OpenSCAD_Model', file=f)
def canonicalise(fname):
stl = STL(fname)
stl.write(fname)
if __name__ == '__main__':
if len(sys.argv) == 2:
canonicalise(sys.argv[1])
else:
print("usage: c14n_stl file")
sys.exit(1)

49
scripts/deps.py Normal file
View File

@ -0,0 +1,49 @@
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
import os
def mtime(file):
if os.path.isfile(file):
return os.path.getmtime(file)
return 0
def deps_name(dir, scad_name):
return dir + '/' + scad_name[:-5] + '.deps'
def read_deps(dname):
with open(dname, "rt") as file:
lines = file.readlines()
deps = []
for line in lines:
if line.startswith('\t'):
dep = line[1 : -1].rstrip(' \\')
if not dep in ['stl.scad', 'dxf.scad', 'svf.scad', 'png.scad']:
deps.append(dep)
return deps
def check_deps(target_mtime, dname):
if not target_mtime:
return "target missing"
if not os.path.isfile(dname):
return "no deps"
deps = read_deps(dname)
for dep in deps:
if mtime(dep) > target_mtime:
return dep + ' changed'
return None

32
scripts/dxfs.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import sys
from exports import make_parts
if __name__ == '__main__':
if len(sys.argv) > 1 and not '.' in sys.argv[1]:
target, parts = sys.argv[1], sys.argv[2:]
else:
target, parts = None, sys.argv[1:]
make_parts(target, 'dxf', parts)

133
scripts/exports.py Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import os
import openscad
import sys
import c14n_stl
from set_config import *
import time
import times
from deps import *
def bom_to_parts(target_dir, part_type, assembly = None):
#
# Make a list of all the parts in the BOM
#
part_files = []
bom = assembly + '.txt' if assembly else "bom.txt"
suffix = ".dxf" if part_type == 'svg' else '.' + part_type
with open(target_dir + "/../bom/" + bom, "rt") as f:
for line in f.readlines():
words = line.split()
if words:
last_word = words[-1]
if last_word.endswith(suffix):
part_files.append(last_word[:-4] + '.' + part_type)
return part_files
def make_parts(target, part_type, parts = None):
#
# Make the target directory
#
top_dir = set_config(target)
target_dir = top_dir + part_type + 's'
deps_dir = top_dir + "deps"
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
if not os.path.isdir(deps_dir):
os.makedirs(deps_dir)
times.read_times(target_dir)
#
# Decide which files to make
#
if parts:
targets = list(parts) #copy the list so we dont modify the list passed in
else:
targets = bom_to_parts(target_dir, part_type)
for file in os.listdir(target_dir):
if file.endswith('.' + part_type):
if not file in targets:
print("Removing %s" % file)
os.remove(target_dir + '/' + file)
#
# Find all the scad files
#
lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib'
used = []
module_suffix = '_dxf' if part_type == 'svg' else '_' + part_type
for dir in [source_dir, lib_dir]:
for filename in os.listdir(dir):
if filename[-5:] == ".scad":
#
# find any modules ending in _<part_type>
#
with open(dir + "/" + filename, "r") as f:
for line in f.readlines():
words = line.split()
if(len(words) and words[0] == "module"):
module = words[1].split('(')[0]
if module.endswith(module_suffix):
base_name = module[:-4]
part = base_name + '.' + part_type
if part in targets:
#
# make a file to use the module
#
part_maker_name = part_type + ".scad"
with open(part_maker_name, "w") as f:
f.write("use <%s/%s>\n" % (dir, filename))
f.write("%s();\n" % module);
#
# Run openscad on the created file
#
part_file = target_dir + "/" + part
dname = deps_name(deps_dir, filename)
changed = check_deps(mtime(part_file), dname)
changed = times.check_have_time(changed, part)
if changed:
print(changed)
t = time.time()
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
times.add_time(part, t)
if part_type == 'stl':
c14n_stl.canonicalise(part_file)
targets.remove(part)
os.remove(part_maker_name)
#
# Add the files on the BOM to the used list for plates.py
#
for line in open("openscad.log"):
if line[:7] == 'ECHO: "' and line[-6:] == '.' + part_type + '"\n':
used.append(line[7:-2])
#
# List the ones we didn't find
#
if targets:
for part in targets:
if part[-4:] != '.' + part_type:
print(part, "is not a", part_type, "file")
else:
print("Could not find a module called", part[:-4] + module_suffix, "to make", part)
sys.exit(1)
times.print_times()
return used

68
scripts/gallery.py Normal file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
#
# Find projects and add them to the gallery
#
from __future__ import print_function
import os
from colorama import Fore, init
from tests import do_cmd
import re
from shutil import copyfile
project_dir = '../..'
target_dir = 'gallery'
output_name = target_dir + '/readme.md'
def gallery():
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
projects = [i for i in os.listdir(project_dir) if os.path.isdir(project_dir + '/' + i + '/assemblies')]
with open(output_name, 'wt') as output_file:
for project in projects:
path = project_dir + '/' + project
print(project)
document = path + '/readme.md'
if os.path.isfile(document):
with open(document, 'rt') as readme:
for line in readme.readlines():
match = re.match(r"^.*!(\[.*\]\(.*\)).*$", line)
if match:
image = match.group(0)
if image.startswith('![Main Assembly](assemblies/'):
file = image[17 : -1]
line = line.replace(image, '![](%s.png)' % project)
copyfile(path + '/' + file, '%s/%s.png' %(target_dir, project))
else:
line = line.replace(image, '')
print(line[:-1], file = output_file)
if line == '---\n':
break;
else:
print(Fore.MAGENTA + "Can't find", document, Fore.WHITE);
with open(target_dir + "/readme.html", "wt") as html_file:
do_cmd(("python -m markdown -x tables " + output_name).split(), html_file)
if __name__ == '__main__':
init()
gallery()

35
scripts/make_all.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
import sys
from exports import make_parts
from bom import boms
from render import render
from views import views
if __name__ == '__main__':
target = None if len(sys.argv) == 1 else sys.argv[1]
boms(target)
for part in ['stl', 'dxf']:
make_parts(target, part)
render(target, part)
views(target)

38
scripts/openscad.py Normal file
View File

@ -0,0 +1,38 @@
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
#
# Run openscad
#
from __future__ import print_function
import subprocess, sys
def run(*args):
cmd = ["openscad"] + list(args)
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"):
if 'ERROR:' in line or 'WARNING:' in line:
print(line[:-1])
if rc:
sys.exit(rc)

69
scripts/render.py Normal file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
from set_config import *
from exports import bom_to_parts
import os
import openscad
from tests import do_cmd
from deps import mtime
def render(target, type):
#
# Make the target directory
#
target_dir = set_config(target) + type + 's'
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
#
# Find all the parts
#
parts = bom_to_parts(target_dir, type)
#
# Remove unused png files
#
for file in os.listdir(target_dir):
if file.endswith('.png'):
if not file[:-4] + '.' + type in parts:
print("Removing %s" % file)
os.remove(target_dir + '/' + file)
for part in parts:
part_file = target_dir + '/' + part
png_name = target_dir + '/' + part[:-4] + '.png'
#
# make a file to import the stl
#
if mtime(part_file) > mtime(png_name):
png_maker_name = "png.scad"
with open(png_maker_name, "w") as f:
f.write('color("lime") import("%s");\n' % part_file)
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' else "--render"
openscad.run("--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", png_name, png_maker_name);
do_cmd(("magick "+ png_name + " -trim -resize 280x280 -background #ffffe5 -gravity Center -extent 280x280 -bordercolor #ffffe5 -border 10 " + png_name).split())
os.remove(png_maker_name)
if __name__ == '__main__':
target = sys.argv[1] if len(sys.argv) > 1 else None
render(target, 'stl')
render(target, 'dxf')

84
scripts/set_config.py Normal file
View File

@ -0,0 +1,84 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
#
# Set target configuration for multi-target projects that have variable configurations.
#
from __future__ import print_function
source_dir = 'scad'
import sys
import os
def valid_targets():
return [i[7:-5] for i in os.listdir(source_dir) if i[0:7] == "config_" and i[-5:] == ".scad"]
def valid_targets_string():
result = ''
targets = valid_targets()
for t in targets:
if result:
if t == targets[-1]:
result += ' and '
else:
result += ', '
result += t
return result
def set_config(target):
targets = valid_targets()
if not target:
if not targets:
return ""
print("Must specify a configuration: " + valid_targets_string())
sys.exit(1)
if not targets:
print("Not a muli-configuration project (no config_<target>.scad files found)")
sys.exit(1)
if not target in targets:
print(target + " is not a configuration, avaliable configurations are: " + valid_targets_string())
sys.exit(1)
fname = source_dir + "/target.scad"
text = "include <config_%s.scad>\n" % target;
line = ""
try:
with open(fname,"rt") as f:
line = f.read()
except:
pass
if line != text:
with open(fname,"wt") as f:
f. write(text);
return target + "/"
if __name__ == '__main__':
args = len(sys.argv)
if args == 2:
set_config(sys.argv[1])
else:
print("usage: set_config config_name")
sys.exit(1)

32
scripts/stls.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import sys
from exports import make_parts
if __name__ == '__main__':
if len(sys.argv) > 1 and not '.' in sys.argv[1]:
target, parts = sys.argv[1], sys.argv[2:]
else:
target, parts = None, sys.argv[1:]
make_parts(target, 'stl', parts)

32
scripts/svgs.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import sys
from exports import make_parts
if __name__ == '__main__':
if len(sys.argv) > 1 and not '.' in sys.argv[1]:
target, parts = sys.argv[1], sys.argv[2:]
else:
target, parts = None, sys.argv[1:]
make_parts(target, 'svg', parts)

230
scripts/tests.py Normal file
View File

@ -0,0 +1,230 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
from __future__ import print_function
import os
import sys
import openscad
import subprocess
import bom
import times
import time
import json
from deps import *
from blurb import *
w = 4096
h = w
def do_cmd(cmd, output = sys.stdout):
for arg in cmd:
print(arg, end = " ")
print()
subprocess.call(cmd, stdout = output)
def depluralise(name):
if name[-3:] == "ies" and name != "zipties":
return name[:-3] + 'y'
if name[-3:] == "hes":
return name[:-2]
if name[-1:] == 's':
return name[:-1]
return name
def is_plural(name):
return name != depluralise(name)
def tests(tests):
scad_dir = "tests"
deps_dir = scad_dir + "/deps"
png_dir = scad_dir + "/png"
bom_dir = scad_dir + "/bom"
for dir in [deps_dir, png_dir, bom_dir]:
if not os.path.isdir(dir):
os.makedirs(dir)
doc_name = "readme.md"
index = {}
bodies = {}
times.read_times()
#
# Make cover pic if does not exist as very slow. Delete it to force an update.
#
png_name = "libtest.png"
scad_name = "libtest.scad"
if not os.path.isfile(png_name):
openscad.run("--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name);
do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", "#ffffe5", "-border", "10", png_name])
#
# List of individual part files
#
scads = [i for i in os.listdir(scad_dir) if i[-5:] == ".scad"]
for scad in scads:
base_name = scad[:-5]
if not tests or base_name in tests:
print(base_name)
cap_name = base_name[0].capitalize() + base_name[1:]
scad_name = scad_dir + '/' + scad
png_name = png_dir + '/' + base_name + '.png'
bom_name = bom_dir + '/' + base_name + '.json'
objects_name = None
vits_name = 'vitamins/' + base_name + '.scad'
if is_plural(base_name) and os.path.isfile(vits_name):
objects_name = vits_name
locations = [
('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'),
(base_name + '.scad', 'Printed'),
('utils/' + base_name + '.scad', 'Utilities'),
('utils/core/' + base_name + '.scad', 'Core Utilities'),
]
for name, type in locations:
if os.path.isfile(name):
impl_name = name
break
else:
print("Can't find implementation!")
continue
vsplit = "N"
vtype = locations[0][1]
types = [vtype + ' A-' + vsplit[0], vtype + ' ' + chr(ord(vsplit) + 1) + '-Z'] + [loc[1] for loc in locations[1 :]]
if type == vtype:
type = types[0] if cap_name[0] <= vsplit else types[1]
if not type in bodies:
bodies[type] = []
index[type] = []
body = bodies[type]
index[type] += [cap_name]
body += ['<a name="%s"></a>' % cap_name]
body += ["## " + cap_name]
doc = None
if impl_name:
doc = scrape_code(impl_name)
blurb = doc["blurb"]
else:
blurb = scrape_blurb(scad_name)
if not len(blurb):
print("Blurb not found!")
else:
body += [ blurb ]
if objects_name:
body += ["[%s](%s) Object definitions.\n" % (objects_name, objects_name)]
if impl_name:
body += ["[%s](%s) Implementation.\n" % (impl_name, impl_name)]
body += ["[%s](%s) Code for this example.\n" % (scad_name.replace('\\','/'), scad_name)]
if doc:
for thing in ["properties", "functions", "modules"]:
things = doc[thing]
if things:
body += ['### %s\n| | |\n|:--- |:--- |' % thing.title()]
for item in sorted(things):
body += ['| ```%s``` | %s |' % (item, things[item])]
body += ['']
body += ["![%s](%s)\n" %(base_name, png_name)]
dname = deps_name(deps_dir, scad)
oldest = min(mtime(png_name), mtime(bom_name))
changed = check_deps(oldest, dname)
changed = times.check_have_time(changed, scad_name)
if changed:
print(changed)
t = time.time()
openscad.run("-D", "$bom=2", "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", png_name, scad_name);
times.add_time(scad_name, t)
do_cmd(["magick", png_name, "-trim", "-resize", "1000x600", "-bordercolor", "#ffffe5", "-border", "10", png_name])
BOM = bom.parse_bom()
with open(bom_name, 'wt') as outfile:
json.dump(BOM.flat_data(), outfile, indent = 4)
with open(bom_name, "rt") as bom_file:
BOM = json.load(bom_file)
for thing in ["vitamins", "printed", "routed", "assemblies"]:
things = BOM[thing]
if things:
body += ['### %s\n| | | |\n| ---:|:--- |:---|' % thing.title()]
for item in sorted(things, key = lambda s: s.split(":")[-1]):
name = item
desc = ''
if thing == "vitamins":
vit = item.split(':')
name = '```' + vit[0] + '```' if vit[0] else ''
while '[[' in name and ']]' in name:
i = name.find('[[')
j = name.find(']]') + 2
name = name.replace(name[i : j], '[ ... ]')
desc = vit[1]
body += ['| %3d | %s | %s |' % (things[item], name, desc)]
body += ['']
body += ['\n<a href="#top">Top</a>']
body += ["\n---"]
with open(doc_name, "wt") as doc_file:
print('# NopSCADlib', file = doc_file)
print('''\
An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.
It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and
some utilities. There are also Python scripts to generate Bills of Materials (BOMs),
STL files for all the printed parts and DXF files for CNC routed parts in a project.
<img src="libtest.png" width="100%"/>\n
''', file = doc_file)
print('## Table of Contents<a name="top"/>', file = doc_file)
print('<table><tr>', file = doc_file)
n = 0
for type in types:
print('<th align="left"> %s </th>' % type, end = '', file = doc_file)
n = max(n, len(index[type]))
print('</tr>', file = doc_file)
for i in range(n):
print('<tr>', file = doc_file, end = '')
for type in types:
if i < len(index[type]):
name = index[type][i]
print('<td> <a href = "#' + name + '">' + name + '</a> </td>', file = doc_file, end = '')
else:
print('<td></td>', file = doc_file, end = '')
print('</tr>', file = doc_file)
print('</table>\n\n---', file = doc_file)
for type in types:
for line in bodies[type]:
print(line, file = doc_file)
with open("readme.html", "wt") as html_file:
do_cmd("python -m markdown -x tables readme.md".split(), html_file)
times.print_times()
do_cmd('codespell -L od readme.md'.split())
if __name__ == '__main__':
tests(sys.argv[1:])

71
scripts/times.py Normal file
View File

@ -0,0 +1,71 @@
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
# show execution times and how they have changed.
import json
import time
from colorama import Fore, init
def read_times(dir = '.'):
global times, last_times, times_fname
times_fname = dir + '/times.txt'
init()
try:
with open(times_fname) as json_file:
times = json.load(json_file)
last_times = dict(times)
except:
times = {}
last_times = {}
def write_times():
with open(times_fname, 'w') as outfile:
json.dump(times, outfile, indent = 4)
def got_time(name):
return name in last_times
def check_have_time(changed, name):
if not changed and not got_time(name):
changed = "no previous time"
return changed
def add_time(name, start):
times[name] = round(time.time() - start, 3)
def print_times():
write_times()
sorted_times = sorted(times.items(), key=lambda kv: kv[1])
total = 0
for entry in sorted_times:
colour = Fore.WHITE
key = entry[0]
new = entry[1]
delta = 0
if key in last_times:
old = last_times[key]
delta = new - old
if delta > 0.3:
colour = Fore.RED
if delta < -0.3:
colour = Fore.GREEN
print(colour + "%5.1f %5.1f %s" % (new, delta, key))
total += new
print(Fore.WHITE + "%5.1f" % total)

345
scripts/views.py Normal file
View File

@ -0,0 +1,345 @@
#!/usr/bin/env python
#
# NopSCADlib Copyright Chris Palmer 2018
# 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/>.
#
#
#: Generate assembly views and intructions
#
from __future__ import print_function
from set_config import *
import openscad
from tests import do_cmd
import time
import times
from deps import *
import os
import json
import blurb
import bom
from colorama import Fore
def is_assembly(s):
return s[-9:] == '_assembly' or s[-11:] == '_assemblies'
def add_assembly(flat_bom, bom):
if not bom in flat_bom:
big = False
for ass in bom["assemblies"]:
add_assembly(flat_bom, ass)
if ass["routed"]:
big = True
bom["big"] = big or bom["routed"]
flat_bom.append(bom)
def bom_to_assemblies(bom_dir):
global flat_bom
#
# Make a list of all the parts in the BOM
#
bom = {}
bom_file = bom_dir + "/bom.json"
with open(bom_file) as json_file:
bom = json.load(json_file)
flat_bom = []
add_assembly(flat_bom, bom)
ass = flat_bom[-1]
if len(ass["assemblies"]) < 2 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]:
flat_bom = flat_bom[:-1]
return [assembly["name"] for assembly in flat_bom]
def eop(print_mode, project, doc_file, last = False, first = False):
if print_mode:
print('\n<div style="page-break-after: always;"></div>', file = doc_file)
else:
if not first:
print('[Top](#%s)' % project.lower().replace(' ', '-'), file = doc_file)
if not last:
print("\n---", file = doc_file)
def pad(s, before, after = 0):
return '&nbsp;' * before + str(s) + '&nbsp;' * after
def views(target, do_assemblies = None):
done_assemblies = []
#
# Make the target directory
#
top_dir = set_config(target)
target_dir = top_dir + 'assemblies'
deps_dir = top_dir + "deps"
bom_dir = top_dir + "bom"
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
if not os.path.isdir(deps_dir):
os.makedirs(deps_dir)
times.read_times(target_dir)
#
# Find all the assemblies
#
assemblies = bom_to_assemblies(bom_dir)
for file in os.listdir(target_dir):
if file.endswith('.png'):
assembly = file[:-4].replace('_assembled', '_assembly')
if assembly.endswith('_tn'):
assembly = assembly[:-3]
if not assembly in assemblies:
print("Removing %s" % file)
os.remove(target_dir + '/' + file)
#
# Find all the scad files
#
main_blurb = None
lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib'
for dir in [source_dir, lib_dir]:
for filename in os.listdir(dir):
if filename.endswith('.scad'):
#
# find any modules with names ending in _assembly
#
with open(dir + "/" + filename, "r") as f:
lines = f.readlines()
line_no = 0
for line in lines:
words = line.split()
if len(words) and words[0] == "module":
module = words[1].split('(')[0]
if is_assembly(module):
if module in assemblies:
#
# Scrape the assembly instructions
#
for ass in flat_bom:
if ass["name"] == module:
if not "blurb" in ass:
ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no])
break
if not do_assemblies or module in do_assemblies:
#
# make a file to use the module
#
png_maker_name = 'png.scad'
with open(png_maker_name, "w") as f:
f.write("use <%s/%s>\n" % (dir, filename))
f.write("%s();\n" % module);
#
# Run openscad on the created file
#
dname = deps_name(deps_dir, filename)
for explode in [0, 1]:
png_name = target_dir + '/' + module + '.png'
if not explode:
png_name = png_name.replace('_assembly', '_assembled')
changed = check_deps(mtime(png_name), dname)
changed = times.check_have_time(changed, png_name)
if changed:
print(changed)
t = time.time()
openscad.run("-D$pose=1", "-D$explode=%d" % explode, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", png_name, png_maker_name);
times.add_time(png_name, t)
do_cmd(["magick", png_name, "-trim", "-resize", "1004x1004", "-bordercolor", "#ffffe5", "-border", "10", png_name])
tn_name = png_name.replace('.png', '_tn.png')
if mtime(png_name) > mtime(tn_name):
do_cmd(("magick "+ png_name + " -trim -resize 280x280 -background #ffffe5 -gravity Center -extent 280x280 -bordercolor #ffffe5 -border 10 " + tn_name).split())
os.remove(png_maker_name)
done_assemblies.append(module)
else:
if module == 'main_assembly':
main_blurb = blurb.scrape_module_blurb(lines[:line_no])
line_no += 1
times.print_times()
#
# Build the document
#
for print_mode in [True, False]:
doc_name = top_dir + "readme.md"
with open(doc_name, "wt") as doc_file:
#
# Title, description and picture
#
project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_'))
print('# %s' % project, file = doc_file)
main_file = bom.find_scad_file('main_assembly')
if not main_file:
raise Exception("can't find source for main_assembly")
text = blurb.scrape_blurb(source_dir + '/' + main_file)
if len(text):
print(text, file = doc_file, end = '')
else:
if print_mode:
print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
print('![Main Assembly](assemblies/%s.png)\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file)
eop(print_mode, project, doc_file, first = True)
#
# Build TOC
#
print('## Table of Contents', file = doc_file)
print('[TOC]\n', file = doc_file)
eop(print_mode, project, doc_file)
#
# Global BOM
#
print('## Parts list', file = doc_file)
vitamins = {}
printed = {}
routed = {}
for ass in flat_bom:
for v in ass["vitamins"]:
if v in vitamins:
vitamins[v] += ass["vitamins"][v]
else:
vitamins[v] = ass["vitamins"][v]
for p in ass["printed"]:
if p in printed:
printed[p] += ass["printed"][p]
else:
printed[p] = ass["printed"][p]
for ass in flat_bom:
name = ass["name"][:-9].replace('_', ' ').title().replace(' ','&nbsp;')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> ' % name, file = doc_file, end = '')
print('| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> | |', file = doc_file)
print(('|--:' * len(flat_bom) + '|--:|:--|'), file = doc_file)
for v in sorted(vitamins, key = lambda s: s.split(":")[-1]):
for ass in flat_bom:
count = ass["vitamins"][v] if v in ass["vitamins"] else '.'
print('| %s ' % pad(count, 2, 1), file = doc_file, end = '')
print('| %s | %s |' % (pad(vitamins[v], 2, 1), pad(v.split(":")[1], 2)), file = doc_file)
print(('| ' * len(flat_bom) + '| | **3D Printed parts** |'), file = doc_file)
for p in sorted(printed):
for ass in flat_bom:
count = ass["printed"][p] if p in ass["printed"] else '.'
print('| %s ' % pad(count, 2, 1), file = doc_file, end = '')
print('| %s | %s |' % (pad(printed[p], 2, 1), pad(p, 3)), file = doc_file)
eop(print_mode, project, doc_file)
#
# Assembly instructions
#
for ass in flat_bom:
name = ass["name"]
cap_name = name.replace('_', ' ').title()
if ass["count"] > 1:
print("## %d x %s" % (ass["count"], cap_name), file = doc_file)
else:
print("## %s" % cap_name, file = doc_file)
vitamins = ass["vitamins"]
if vitamins:
print("### Vitamins", file = doc_file)
print("|Qty|Description|", file = doc_file)
print("|--:|:----------|", file = doc_file)
for v in vitamins:
print("|%d|%s|" % (vitamins[v], v.split(":")[1]), file = doc_file)
print("\n", file = doc_file)
printed = ass["printed"]
if printed:
print('### 3D Printed parts', file = doc_file)
i = 0
for p in printed:
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p], p), file = doc_file, end = '')
if (i % 3) == 2 or i == len(printed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('--|' * n), file = doc_file)
for j in range(n):
part = list(printed.keys())[i - n + j + 1]
print('| ![%s](stls/%s) %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
i += 1
print('\n', file = doc_file)
routed = ass["routed"]
if routed:
print("### CNC Routed parts", file = doc_file)
i = 0
for r in routed:
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r], r), file = doc_file, end = '')
if (i % 3) == 2 or i == len(routed) - 1:
n = (i % 3) + 1
print('\n|%s' % ('--|' * n), file = doc_file)
for j in range(n):
part = list(routed.keys())[i - n + j + 1]
print('| ![%s](dxfs/%s) %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
i += 1
print('\n', file = doc_file)
sub_assemblies = ass["assemblies"]
if sub_assemblies:
print("### Sub-assemblies", file = doc_file)
i = 0
for a in sub_assemblies:
print('%s %d x %s |' % ('\n|' if not (i % 3) else '', a["count"], a["name"]), file = doc_file, end = '')
if (i % 3) == 2 or i == len(sub_assemblies) - 1:
n = (i % 3) + 1
print('\n|%s' % ('--|' * n), file = doc_file)
for j in range(n):
a = sub_assemblies[i - n + j + 1]["name"].replace('_assembly', '_assembled')
print('| ![%s](assemblies/%s) %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file)
print('\n', file = doc_file)
i += 1
print('\n', file = doc_file)
small = not ass["big"]
suffix = '_tn.png' if small else '.png'
print('### Assembly instructions', file = doc_file)
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
if "blurb" in ass and ass["blurb"]:
print(ass["blurb"], file = doc_file)
else:
if print_mode:
print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE)
name = name.replace('_assembly', '_assembled')
print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file)
eop(print_mode, project, doc_file, last = ass == flat_bom[-1] and not main_blurb)
#
# If main module is suppressed print any blurb here
#
if main_blurb:
print(main_blurb, file = doc_file)
eop(print_mode, project, doc_file, last = True)
#
# Convert to HTML
#
html_name = "printme.html" if print_mode else "readme.html"
with open(top_dir + html_name, "wt") as html_file:
do_cmd(("python -m markdown -x tables -x toc -x sane_lists " + doc_name).split(), html_file)
#
# Spell check
#
do_cmd('codespell -L od readme.md'.split())
#
# List the ones we didn't find
#
missing = set()
for assembly in assemblies + (do_assemblies if do_assemblies else []):
if assembly not in done_assemblies:
missing.add(assembly)
if missing:
for assembly in missing:
print(Fore.MAGENTA + "Could not find a module called", assembly, Fore.WHITE)
sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1][-9:] != "_assembly":
target, assemblies = sys.argv[1], sys.argv[2:]
else:
target, assemblies = None, sys.argv[1:]
views(target, assemblies)

127
socket_box.scad Normal file
View File

@ -0,0 +1,127 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! UK 13A socket and printed backbox with earth terminal for the panel it is mounted on.
//
include <core.scad>
include <vitamins/mains_sockets.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
include <vitamins/ring_terminals.scad>
box_height = 19;
base_thickness = 2;
wall = 3.5;
cable_d = 7;
cable_z = cable_d / 2 + base_thickness + 1;
function cable_y(type) = -mains_socket_depth(type) / 2;
cable_x = 0;
earth = M3_ringterm;
earth_screw = ringterm_screw(earth);
height = base_thickness + box_height;
function socket_box_depth() = height; //! Outside depth of the backbox
module socket_box(type) { //! Generate STL of the backbox for the specified socket
stl(str("socket_box_",type[0]));
screw = mains_socket_screw(type);
screw_clearance_radius = screw_clearance_radius(screw);
insert = screw_insert(screw);
insert_length = insert_length(insert);
insert_boss = mains_socket_insert_boss(type);
insert_hole_radius = insert_hole_radius(insert);
difference() {
linear_extrude(height = height, convexity = 5)
face_plate(type);
difference() {
translate_z(base_thickness)
linear_extrude(height = height, convexity = 5)
offset(-wall) offset(1) face_plate(type);
for(side = [-1, 1])
hull()
for(x = [1, 2])
translate([side * mains_socket_pitch(type) / x, 0])
cylinder(d = insert_boss, h = 100);
}
//
// Socket holes
//
translate_z(height)
mains_socket_hole_positions(type) {
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
}
//
// Cable hole
//
translate([cable_x, cable_y(type), cable_z])
rotate([90, 0, 0])
teardrop_plus(r = cable_d / 2, h = 30);
}
}
module socket_box_MKLOGIC_stl() socket_box(MKLOGIC);
module socket_box_Contactum_stl() socket_box(Contactum);
module socket_box_assembly(type) //! The box with inserts fitted
assembly(str("socket_box_", type[0])) {
screw = mains_socket_screw(type);
insert = screw_insert(screw);
color("lime") render() socket_box(type);
mains_socket_hole_positions(type)
translate_z(height)
insert(insert);
}
//! * Place two inserts into the holes in the lugs and press them home with a soldering iron with a tapered bit heated to 200&deg;C.
module socket_box_MKLOGIC_assembly() socket_box_assembly(MKLOGIC);
module socket_box_fastened_assembly(type, thickness) { //! The socket and backbox on each side of the specified panel thickness
screw = mains_socket_screw(type);
insert = screw_insert(screw);
screw_length = screw_longer_than(mains_socket_height(type) + thickness + insert_length(insert));
explode(-50)
translate_z(-height - thickness)
socket_box_assembly(type);
explode(50, true) {
mains_socket(type);
mains_socket_hole_positions(type)
translate_z(mains_socket_height(type))
screw(screw, screw_length);
}
mains_socket_earth_position(type)
rotate(-90)
ring_terminal_assembly(earth, thickness);
}

189
strap_handle.scad Normal file
View File

@ -0,0 +1,189 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! Retracting strap handle. Print the strap with flexible filament. Shown with default dimensions but can
//! be fully customised by passing a list of properties.
//
include <core.scad>
include <vitamins/screws.scad>
include <vitamins/inserts.scad>
strap = [18, 2, M3_pan_screw, 3, 25];
function strap() = strap;
wall = 2;
clearance = 0.5;
step = 0.3;
overlap = 3;
panel_clearance = 0.25;
counterbore = 1;
function strap_width(type = strap) = type[0]; //! Width of strap
function strap_thickness(type = strap) = type[1]; //! Thickness of strap
function strap_screw(type = strap) = type[2]; //! Screw type
function strap_panel(type = strap) = type[3]; //! Panel thickness
function strap_extension(type = strap) = type[4]; //! How much length of the strap that can pull out
function strap_insert(type) = screw_insert(strap_screw(type)); //! The insert type
function strap_key(type) = strap_panel(type) - panel_clearance;
function strap_height(type) = wall + max(insert_length(strap_insert(type)) - strap_key(type), strap_thickness(type) + clearance); //! Height of the ends
function strap_end_width(type = strap) = strap_width(type) + 2 * (wall + clearance); //! Width of the ends
function strap_boss_r(type) = wall + insert_hole_radius(strap_insert(type));
function strap_min_width(type) = (strap_width(type) - 2 * (strap_boss_r(type) + clearance)) / 2;
module strap_boss_shape(type)
hull() {
r = strap_boss_r(type);
circle4n(r);
translate([r / 2, 0])
rounded_square([r, 2 * r], r = 1);
}
module strap_screw_positions(length, type = strap) //! Place children at the screw positions
for(end = [-1, 1])
translate([end * (length / 2 - wall - 2 * clearance - strap_min_width(type) - strap_boss_r(type) - strap_extension(type) / 2), 0])
rotate(end * 90 + 90)
children();
module strap_holes(length, type = strap, h = 100) //! The panel cut outs
extrude_if(h)
strap_screw_positions(length, type)
offset(cnc_bit_r + 0.05)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
module strap(length, type = strap) { //! Generate the STL for the rubber strap
stl("strap");
len = length - 2 * (wall + clearance);
w = strap_width(type);
linear_extrude(height = strap_thickness(type), convexity = 3)
difference() {
rounded_square([len, w], w / 2 - eps);
for(end = [-1, 1])
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
rotate(end * 90 + 90)
hull() {
offset(clearance)
strap_boss_shape(type);
translate([strap_extension(type) / 2, 0])
offset(clearance)
strap_boss_shape(type);
}
}
}
module strap_end(type = strap) { //! Generate the STL for end piece
stl("strap_end");
z1 = strap_height(type) - strap_thickness(type) - clearance;
z2 = strap_height(type) + strap_key(type);
r1 = strap_boss_r(type) - 1;
module outer()
hull() {
translate([0, -strap_end_width(type) / 2])
square([strap_boss_r(type) + overlap, strap_end_width(type)]);
translate([-strap_extension(type) / 2, 0])
circle(d = strap_end_width(type));
}
module with_hole()
difference() {
children();
circle(r1);
}
union() {
linear_extrude(height = z1)
with_hole()
outer();
translate_z(z1)
linear_extrude(height = strap_height(type) - z1)
difference() {
outer();
hull() {
translate([0, -strap_width(type) / 2 - clearance])
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
translate([-strap_extension(type) / 2, 0])
circle(d = strap_width(type) + 2 * clearance);
}
}
linear_extrude(height = strap_height(type) - layer_height)
with_hole()
strap_boss_shape(type);
linear_extrude(height = z2)
with_hole()
offset(cnc_bit_r)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
render() difference() {
cylinder(r = r1 + eps, h = z2);
translate_z(z2)
insert_hole(strap_insert(type), counterbore);
}
}
}
//
//! * Place the insert into the hole and push home with a soldering iron with a tapered bit heated to 200&deg;C.
//
module strap_end_assembly(type = strap)
assembly("strap_end") {
color(pp1_colour)
strap_end(type);
translate_z(strap_height(type) + strap_key(type))
insert(strap_insert(type));
}
module strap_assembly(length, type = strap) { //! Assembly with screws in place
screw = strap_screw(type);
washer = screw_washer(screw);
penny = penny_washer(washer);
insert = strap_insert(type);
screw_length = screw_shorter_than(washer_thickness(washer) + washer_thickness(penny) + insert_length(insert) + panel_clearance + counterbore);
color(pp4_colour) strap(length, type);
strap_screw_positions(length, type)
translate_z(strap_height(type))
vflip() {
explode(-50) strap_end_assembly(type);
translate_z(strap_height(type) + strap_panel(type))
screw_and_washer(screw, screw_length, true, true);
}
}

30
tests/annotation.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/annotation.scad>
module annotations() {
arrow();
translate_z(21)
label("Text", halign = "center", valign = "bottom");
}
if($preview)
annotations();

30
tests/ball_bearings.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
use <../utils/layout.scad>
include <../vitamins/ball_bearings.scad>
module ball_bearings()
layout([for(b = ball_bearings) bb_diameter(b)])
ball_bearing(ball_bearings[$i])
bearing_ball(3);
if($preview)
ball_bearings();

41
tests/batteries.scad Normal file
View File

@ -0,0 +1,41 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/springs.scad>
include <../vitamins/batteries.scad>
module batteries()
layout([for(b = batteries) battery_diameter(b)], 5) let(battery=batteries[$i]) {
battery = batteries[$i];
rotate(-135) // To show Lumintop USB socket and LEDs
battery(battery);
contact = battery_contact(battery);
translate_z(battery_length(battery) / 2 + contact_pos(contact).x)
rotate([0, 180, 0])
battery_contact(contact);
translate_z(-battery_length(battery) / 2 - contact_neg(contact).x)
battery_contact(contact, false);
}
if($preview)
batteries();

74
tests/belts.scad Normal file
View File

@ -0,0 +1,74 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/belts.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
include <../vitamins/pulleys.scad>
use <../utils/layout.scad>
module belt_test() {
p1 = [75, -50];
p2 = [-75, -50];
p3 = [-75, 100];
p4 = [75, 100];
p5 = [75 - pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)];
p6 = [-75 + pulley_pr(GT2x20ob_pulley) + pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)];
translate(p1) pulley_assembly(GT2x20ob_pulley);
translate(p2) pulley_assembly(GT2x20ob_pulley);
translate(p3) pulley_assembly(GT2x20_toothed_idler);
translate(p4) pulley_assembly(GT2x20_toothed_idler);
translate(p5) {
pulley = GT2x16_plain_idler;
screw = find_screw(hs_cs_cap, pulley_bore(pulley));
insert = screw_insert(screw);
pulley_assembly(pulley);
translate_z(pulley_height(pulley) + pulley_offset(pulley) + screw_head_depth(screw, pulley_bore(pulley)))
screw(screw, 20);
translate_z(pulley_offset(pulley) - insert_length(insert))
vflip()
insert(insert);
}
translate(p6) pulley_assembly(GT2x16_plain_idler);
path = [ [p1.x, p1.y, pulley_pr(GT2x20ob_pulley)],
[p5.x, p5.y, -pulley_pr(GT2x16_plain_idler)],
[p6.x, p6.y, -pulley_pr(GT2x16_plain_idler)],
[p2.x, p2.y, pulley_pr(GT2x20ob_pulley)],
[p3.x, p3.y, pulley_pr(GT2x20ob_pulley)],
[p4.x, p4.y, pulley_pr(GT2x20ob_pulley)]
];
belt = GT2x6;
belt(belt, path, 80, [0, belt_pitch_height(belt) - belt_thickness(belt) / 2]);
translate([-25, 0])
layout([for(b = belts) belt_width(b)], 10)
rotate([0, 90, 0])
belt(belts[$i], [[0, 0, 20], [0, 1, 20]]);
}
if($preview)
belt_test();

83
tests/bezier.scad Normal file
View File

@ -0,0 +1,83 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/bezier.scad>
use <../utils/sweep.scad>
use <../utils/annotation.scad>
function find_min_z(path, i = 1, best_i = 0) =
i >= len(path) ? best_i
: find_min_z(path, i + 1, path[i].z < path[best_i].z ? i : best_i);
module beziers() {
//
// Make Bezier control points to give specified length
//
control_points = adjust_bezier_length([[0, 0, 100], [0, 0, 0], [200, 0, 20], [100, -100, 50]], 250);
//
// Draw control points
//
color("green")
for(p = control_points)
translate(p)
sphere(1);
//
// Lines joining the control points
//
color("red")
sweep(control_points, circle_points(0.5, $fn = 64));
//
// Bezier curve path from control points
//
curve = bezier_path(control_points);
//
// Draw the curve
//
sweep(curve, circle_points(2, $fn = 64));
//
// Length computed from control points
//
length = bezier_length(control_points);
//
// Length computed from curve
//
length2 = path_length(curve);
assert(str(length) == str(length2), str(length, " ", length2));
//
// Minimum Z
//
min_z = bezier_min_z(control_points);
i = find_min_z(curve);
assert(str(min_z) == str(curve[i].z));
color("blue") {
translate(curve[i] + [0, 0, 2])
arrow();
translate(curve[i] - [0, 0, 2])
vflip()
arrow();
}
translate(control_points[1] - [0, 0, 2])
label(str("bezier_length = ", length, ", bezier_min_z = ", bezier_min_z(curve)), valign = "top");
}
if($preview)
beziers();

41
tests/blowers.scad Normal file
View File

@ -0,0 +1,41 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/blowers.scad>
module blowers()
layout([for(b = blowers) blower_width(b)], 10, true) let(b = blowers[$i]){
screw = blower_screw(b);
washer = screw_washer(screw);
h = blower_lug(b);
blower(b);
blower_hole_positions(b)
translate_z(h)
screw_and_washer(screw, screw_longer_than(h + washer_thickness(washer) + 5));
}
if($preview)
blowers();

108
tests/bom.scad Normal file
View File

@ -0,0 +1,108 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
//
//! BOM and assembly demonstration
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
include <../vitamins/sheets.scad>
$explode = 1; // Normally set on the command line when generating assembly views with views.py
screw = M3_cap_screw;
sheet = PMMA3;
height = 10;
insert = screw_insert(screw);
washer = screw_washer(screw);
module widget(thickness) {
vitamin(str("widget(", thickness, "): Rivit like thing for ", thickness, "mm sheets"));
t = 1;
color("silver") {
cylinder(d = 3, h = thickness + 2 * eps, center = true);
for(end = [-1, 1])
translate_z(end * (thickness / 2 + t / 2 + eps))
cylinder(d = 4, h = t, center = true);
}
}
module widgit_stl() {
stl("widget");
union() {
rounded_rectangle([30, 30, 3], 2);
render() insert_boss(insert, height, 2.2);
}
}
module widgit_dxf() {
dxf("widget");
difference() {
sheet_2D(sheet, 20, 20, 1);
drill(screw_clearance_radius(screw), 0);
}
}
//! * Push the insert into the base with a soldering iron heated to 200&deg;C
module widgit_base_assembly()
assembly("widgit_base") {
color(pp1_colour)
widgit_stl();
translate_z(height)
insert(insert);
}
//! * Magically insert the widget into the acrylic sheet
module widget_top_assembly()
assembly("widget_top") {
translate([-5, 5])
widget(sheet_thickness(sheet));
render_2D_sheet(sheet) // Must be last because it is transparent
widgit_dxf();
}
//! * Screw the two assemblies together
module widgit_assembly()
assembly("wigdit") {
widgit_base_assembly(); // Note this is not exloded because it is sub-assembly
translate_z(height) {
translate_z(sheet_thickness(sheet))
screw_and_washer(screw, screw_longer_than(sheet_thickness(sheet) + 2 * washer_thickness(washer) + 3), true);
explode(5)
translate_z(sheet_thickness(sheet) / 2 + eps)
widget_top_assembly();
}
}
module boms() {
widgit_assembly();
}
boms();

54
tests/box.scad Normal file
View File

@ -0,0 +1,54 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/screws.scad>
include <../vitamins/sheets.scad>
include <../vitamins/inserts.scad>
use <../box.scad>
box = [M3_dome_screw, 3, DiBond, PMMA3, DiBond6, true, 150, 100, 70];
include <../box_assembly.scad>
module box_assembly() _box_assembly(box);
module box_test() {
translate_z(box_height(box) / 2 + box_bezel_height(box, true))
box_assembly();
rows = 3;
cols = 3;
gap = 30;
x_pitch = (box_width(box) + 2 * box_outset(box)) / cols + gap;
y_pitch = (box_depth(box) + 2 * box_outset(box)) / rows + gap;
for(x = [0 : cols - 1], y = [0 : rows - 1])
translate([(x - cols / 2) * x_pitch + gap / 2, (y - rows / 2) * y_pitch + gap / 2])
color((x + y) % 2 ? pp1_colour : pp2_colour) box_bezel_section(box, true, rows, cols, x, y);
translate([-cols / 2 * x_pitch - 20, 0])
for(i = [0 : 2])
translate([0, (i - 1) * 20, 0])
color(i % 2 ? pp1_colour : pp2_colour) box_corner_profile_section(box, i, 3);
}
if($preview)
box_test();

29
tests/bulldogs.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/bulldogs.scad>
module bulldogs()
layout([for(b = bulldogs) bulldog_depth(b)], 5, true)
bulldog(bulldogs[$i]);
if($preview)
bulldogs();

66
tests/butt_box.scad Normal file
View File

@ -0,0 +1,66 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/screws.scad>
include <../vitamins/sheets.scad>
include <../vitamins/inserts.scad>
include <../butt_box.scad>
$explode = 0;
box = [M3_dome_screw, DiBond, DiBond6, PMMA3, 250, 400, 300, 120];
module bbox_assembly() _bbox_assembly(box);
module bbox_test() {
translate_z(bbox_height(box) / 2)
bbox_assembly();
}
if($preview)
bbox_test();
else {
gap = 2;
bb = sheet_thickness(bbox_base_sheet(box));
bt = sheet_thickness(bbox_top_sheet(box));
h = bbox_height(box) + bb;
h2 = h + bt;
bbox_base_blank(box);
translate([bbox_width(box) / 2 + gap + h / 2 - bb / 2, 0])
rotate(90)
bbox_right_blank(box);
translate([-bbox_width(box) / 2 - gap - h / 2 + bb / 2, 0])
rotate(-90)
bbox_left_blank(box);
translate([0, bbox_depth(box) / 2 + gap + h / 2 - bb / 2])
rotate(180)
bbox_back_blank(box);
translate([0, -bbox_depth(box) / 2 - gap - h2 / 2 - (bt - bb) / 2])
bbox_front_blank(box);
translate([0, -bbox_depth(box) / 2 - gap - h2 - gap - bbox_depth(box) / 2 - sheet_thickness(bbox_sheets(box))])
bbox_top_blank(box);
}

29
tests/buttons.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/buttons.scad>
module buttons()
layout([for(b = buttons) square_button_width(b)], 5)
square_button(buttons[$i]);
if($preview)
buttons();

36
tests/cable_grommets.scad Normal file
View File

@ -0,0 +1,36 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../cable_grommets.scad>
module cable_grommets() {
rotate(90)
color(pp1_colour) ribbon_grommet(20, 3);
translate([20, 0])
round_grommet_assembly(6, 3);
translate([40, 0])
rotate(90)
color(pp1_colour) mouse_grommet(5, 3);
}
if($preview)
cable_grommets();

38
tests/cable_strips.scad Normal file
View File

@ -0,0 +1,38 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/cable_strip.scad>
module cable_strips() {
depth = 50;
rotate(-90)
for(pos = [-100, 0, 100]) {
bezier_cable_strip(ways = 20, depth = depth, length = 150, travel = 100, pos = pos, below = 100, extra = 10);
translate([0, depth * 2])
rotate([0, -90, 0])
cable_strip(ways =20, depth = depth / 2, travel = 100, x = pos, extra = 30);
}
}
if($preview)
cable_strips();

25
tests/carriers.scad Normal file
View File

@ -0,0 +1,25 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../carriers.scad>
module carriers()
color(pp1_colour) ESP12F_carrier_stl();
carriers();

26
tests/clip.scad Normal file
View File

@ -0,0 +1,26 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
module clips() {
clip(xmin = 0, ymin = 0, zmin = 0, zmax = 40) sphere(50);
}
clips();

57
tests/components.scad Normal file
View File

@ -0,0 +1,57 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/components.scad>
module resistors()
layout([for(r = resistors) resistor_diameter(r)], 10)
resistor(resistors[$i]);
module al_clad_resistors()
layout([for(a = al_clad_resistors) al_clad_width(a)])
rotate(90)
al_clad_resistor_assembly(al_clad_resistors[$i], 4.7)
screw(al_clad_hole(al_clad_resistors[$i]) > 3 ? M3_pan_screw : M2p5_pan_screw, 16);
module thermal_cutouts()
layout([for(t = thermal_cutouts) tc_length(t)])
thermal_cutout(thermal_cutouts[$i]);
module components() {
resistors();
translate([0, 50])
TO220("Generic TO220 package");
translate([30, 50])
panel_USBA();
translate([0,80])
thermal_cutouts();
translate([0, 130])
al_clad_resistors();
}
if($preview)
components();

37
tests/corner_block.scad Normal file
View File

@ -0,0 +1,37 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../corner_block.scad>
include <../vitamins/screws.scad>
screws = [M2_cap_screw, M2p5_pan_screw, M3_dome_screw, M4_dome_screw];
module do_corner_block(screw)
if($preview)
fastened_corner_block_assembly(3, screw = screw);
else
corner_block(screw);
module corner_blocks()
for(i = [0 : len(screws) - 1])
translate([i * 30, 0])
do_corner_block(screws[i]);
corner_blocks();

38
tests/d_connectors.scad Normal file
View File

@ -0,0 +1,38 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/d_connectors.scad>
module d_connectors()
for(socket = [false, true])
translate([socket ? len(d_connectors) * (d_flange_width(d_connectors[0]) + 10) : 0, 0])
layout([for(d = d_connectors) d_flange_width(d)], 10) let(d = d_connectors[$i])
rotate(90) {
d_plug(d, socket, pcb = $i == 2, idc = $i == 1);
if(socket)
translate_z(d_flange_thickness(d))
d_connector_holes(d)
d_pillar();
}
if($preview)
d_connectors();

29
tests/displays.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
use <../utils/layout.scad>
include <../vitamins/displays.scad>
use <../vitamins/pcb.scad>
module displays()
layout([for(d = displays) pcb_length(display_pcb(d))], 10)
display(displays[$i]);
if($preview)
displays();

34
tests/dogbones.scad Normal file
View File

@ -0,0 +1,34 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/dogbones.scad>
module dogbones() {
#linear_extrude(height = eps)
dogbone_square([10, 20]);
#translate([15, 0])
dogbone_rectangle([10, 20, 5], center = false);
sq = 3;
translate([-5 + sq / 2 + eps, -10 + sq / 2 + eps])
%cube([sq, sq, 1], center = true);
}
dogbones();

57
tests/door_hinge.scad Normal file
View File

@ -0,0 +1,57 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../door_hinge.scad>
include <../vitamins/sheets.scad>
use <../vitamins/screw.scad>
door_w = 50;
door_h = 50;
sheet = PMMA6;
module door_hinges() {
translate([door_hinge_stat_length() / 2 - door_hinge_pin_x(), 0])
if($preview) {
for(side = [-1, 1])
translate_z(side * door_h / 2) {
door_hinge_assembly(side > 0, sheet_thickness(sheet));
door_hinge_static_assembly(side > 0, 3);
}
translate([door_w / 2 + eps, door_hinge_pin_y() - eps])
rotate([90, 0, 0])
render_2D_sheet(sheet)
difference() {
sheet_2D(sheet, door_w, door_h, 3);
for(z =[-1, 1])
translate([-door_w / 2, z * door_h / 2])
door_hinge_hole_positions(z)
drill(screw_pilot_hole(door_hinge_screw()), 0);
}
translate([door_w, 0])
children();
}
else
door_hinge_parts_stl();
}
door_hinges();

29
tests/door_latch.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../door_latch.scad>
module door_latches()
translate([door_latch_offset(), 0])
if($preview)
door_latch_assembly(3);
else
door_latch_stl();
door_latches();

29
tests/fan_guard.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../fan_guard.scad>
include <../vitamins/fans.scad>
module fan_guards()
layout([for(f = fans) fan_width(f)], 10)
color(pp1_colour) fan_guard(fans[$i], spokes = fan_width(fans[$i]) > 40 ? 8 : 4);
fan_guards();

31
tests/fans.scad Normal file
View File

@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../fan_guard.scad>
include <../vitamins/fans.scad>
module fans()
layout([for(f = fans) fan_width(f)], 10)
fan_assembly(fans[$i], 3 + fan_guard_thickness(), true);
if($preview)
fans();

26
tests/fillet.scad Normal file
View File

@ -0,0 +1,26 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/fillet.scad>
module fillets() {
fillet(3, 25);
}
fillets();

37
tests/fixing_block.scad Normal file
View File

@ -0,0 +1,37 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../fixing_block.scad>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
screws = [M2_cap_screw, M2p5_pan_screw, M3_dome_screw, M4_dome_screw];
module fixing_block_test(screw)
if($preview)
fastened_fixing_block_assembly(3, screw = screw);
else
fixing_block(screw);
module fixing_blocks()
layout([for(s = screws) fixing_block_width(s)], 5)
fixing_block_test(screws[$i]);
fixing_blocks();

37
tests/foot.scad Normal file
View File

@ -0,0 +1,37 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../foot.scad>
module feet()
if($preview) {
translate([50, 0])
foot_assembly(3);
translate([foot_diameter(insert_foot()) / 2, 0])
fastened_insert_foot_assembly(3);
}
else {
translate([50, 0])
foot();
insert_foot();
}
feet();

27
tests/fuseholder.scad Normal file
View File

@ -0,0 +1,27 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/fuseholder.scad>
module fuseholders()
fuseholder(6);
if($preview)
fuseholders();

31
tests/global.scad Normal file
View File

@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
module globals() {
linear_extrude(height = eps) {
semi_circle(r = 10);
translate([30, 0])
ellipse(15, 7);
}
}
rotate([70, 0, 315]) globals();

29
tests/handle.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../handle.scad>
module handle()
translate([handle_length() / 2, 0])
if($preview)
handle_fastened_assembly(3);
else
handle_stl();
handle();

28
tests/hanging_hole.scad Normal file
View File

@ -0,0 +1,28 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/hanging_hole.scad>
module hanging_holes() {
rotate(45)
#hanging_hole(z = 10, ir = 3, h = 30)
circle(r = 10);
}
hanging_holes();

31
tests/hot_ends.scad Normal file
View File

@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/hot_ends.scad>
module hot_ends()
layout([for(h = hot_ends) 40])
translate([-20, 0])
rotate(90)
hot_end(hot_ends[$i], 3);
if($preview)
hot_ends();

30
tests/iecs.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/iecs.scad>
module iecs()
layout([for(i = iecs) iec_flange_h(i)], 10)
rotate(90)
iec_assembly(iecs[$i], 3);
if($preview)
iecs();

30
tests/inserts.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/inserts.scad>
module inserts()
for(i = [0: len(inserts) -1])
translate([10 * i, 0])
insert(inserts[i]);
if($preview)
inserts();

35
tests/jack.scad Normal file
View File

@ -0,0 +1,35 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/jack.scad>
module jacks() {
translate([0, 0])
jack_4mm("blue",3, "royalblue");
translate([20, 0])
jack_4mm_shielded("brown", 3, "sienna");
translate([40, 0])
post_4mm("red",3);
}
if($preview)
jacks();

30
tests/layout.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/layout.scad>
diams = [3, 7, 5, 11];
module layouts() {
linear_extrude(height = eps)
layout(diams, gap = 1)
circle(d = diams[$i]);
}
rotate([70, 0, 315]) layouts();

30
tests/leadnuts.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/leadnuts.scad>
module leadnuts()
layout([for(n = leadnuts) leadnut_flange_dia(n)], 5)
leadnut(leadnuts[$i]);
if($preview)
leadnuts();

29
tests/leds.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/leds.scad>
module leds()
layout([for(l = LEDs) led_diameter(l)], 5)
led(LEDs[$i], ["green", "blue", "red"][$i % 3]);
if($preview)
leds();

38
tests/light_strips.scad Normal file
View File

@ -0,0 +1,38 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/light_strips.scad>
module light_strips()
layout([for(s = light_strips) light_strip_width(s)], 10)
rotate(90) let(light = light_strips[$i], segs = light_strip_segments(light, 260), d = light_strip_clip_depth(light)) {
light_strip(light, segs);
for(end = [-1, 1])
translate([end * (light_strip_cut_length(light, segs) / 2 - d / 2), 0])
rotate([90, 0, 90])
color("lime") render()
translate_z(-d / 2)
light_strip_clip(light);
}
if($preview)
light_strips();

View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/linear_bearings.scad>
module linear_bearings()
layout([for(b = linear_bearings) 2 * bearing_radius(b)])
linear_bearing(linear_bearings[$i]);
if($preview)
linear_bearings();

29
tests/mains_sockets.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/mains_sockets.scad>
module mains_sockets()
layout([for(s = mains_sockets) mains_socket_width(s)], 5)
mains_socket(mains_sockets[$i]);
if($preview)
mains_sockets();

70
tests/maths.scad Normal file
View File

@ -0,0 +1,70 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/maths.scad>
use <../utils/annotation.scad>
tip = [0, 0, 20];
module shape() {
cylinder(d1 = 20, d2 = 0, h = tip.z);
}
t = [10, 20, 30];
r = [45, 20, 70];
s = [1, 0.5, 0.75];
module maths() {
//
// Translate, rotate and scale the shape
//
translate(t)
rotate(r)
scale(s)
shape();
//
// Apply the same transformations to the vector position of the tip
//
p = transform(tip, translate(t) * rotate(r) * scale(s));
//
// Place an arrow where the tip ends up
//
translate(p)
arrow();
//
// Unit vector pointing at p
//
u = unit(p);
//
// Point arrow in same direction
//
z = [0, 0, 1];
v = cross(u, z);
a = acos(u * z);
l = 20;
rotate(-a, v)
translate_z(l)
vflip()
arrow(l);
}
rotate(45)
maths();

39
tests/meter.scad Normal file
View File

@ -0,0 +1,39 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/meter.scad>
module meters()
if($preview) {
meter_assembly();
translate([0, meter_bezel_width() + 5])
vflip()
meter_assembly();
translate([0, -meter_bezel_width()])
rotate([0, 180, 0])
meter(colour = "blue", value = "123");
}
else
meter_bezel();
meters();

29
tests/microswitches.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/microswitches.scad>
module microswitches()
layout([for(i = microswitches) microswitch_length(i)], 5)
microswitch(microswitches[$i]);
if($preview)
microswitches();

21
tests/microview.scad Normal file
View File

@ -0,0 +1,21 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
use <../vitamins/microview.scad>
microview(!$preview);

30
tests/modules.scad Normal file
View File

@ -0,0 +1,30 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/modules.scad>
module modules()
layout([for(m = modules) mod_length(m)], 5)
module_assembly(modules[$i], 3);
if($preview)
modules();

51
tests/nuts.scad Normal file
View File

@ -0,0 +1,51 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
module nuts() {
for(nyloc = [false, true])
translate([0, nyloc ? 20 : 0])
layout([for(n = nuts) 2 * nut_radius(n)], 5)
nut(nuts[$i], nyloc);
translate([0, 40])
layout([for(n = nuts) 2 * nut_radius(n)], 5) let(n = nuts[$i]) {
if(n == M3_nut)
nut(n, brass = true);
if(n == M2p5_nut)
nut(n, nylon = true);
if(n == M4_nut)
rotate(-45)
wingnut(M4_wingnut);
if(n == M6_nut)
nut_and_washer(M6_half_nut, false);
if(n == M8_nut)
#nut_trap(M8_cap_screw, n, h = 30);
}
}
if($preview)
nuts();

25
tests/o_ring.scad Normal file
View File

@ -0,0 +1,25 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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/>.
//
use <../vitamins/o_ring.scad>
module o_rings()
O_ring(2.5, 1.6, 3);
if($preview)
o_rings();

39
tests/offset.scad Normal file
View File

@ -0,0 +1,39 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/offset.scad>
module shape()
difference() {
cube(40, center = true);
cube([20, 20, 41], center = true);
}
module offsets() {
$fn = 20;
for(x = [-1, 0, 1])
translate([50 * x, 0])
offset_3D(3 * x, chamfer_base = true)
shape();
}
offsets();

32
tests/opengrab.scad Normal file
View File

@ -0,0 +1,32 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/opengrab.scad>
module opengrab_test() {
opengrab_target();
rotate(45)
translate_z(opengrab_target_thickness())
opengrab();
}
if($preview)
opengrab_test();

32
tests/pcbs.scad Normal file
View File

@ -0,0 +1,32 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/d_connectors.scad>
include <../vitamins/pcbs.scad>
module pcbs()
layout([for(p = pcbs) pcb_width(p)], 15)
translate([0, pcb_length(pcbs[$i]) / 2])
rotate(90)
pcb_assembly(pcbs[$i], 5 + $i, 3);
if($preview)
pcbs();

29
tests/pillars.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/pillars.scad>
module pillars()
layout([for(p = pillars) pillar_od(p)], 5)
pillar(pillars[$i]);
if($preview)
pillars();

77
tests/polyholes.scad Normal file
View File

@ -0,0 +1,77 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../vitamins/rod.scad>
include <../vitamins/sheets.scad>
module polyholes() {
module positions()
for(i = [1 : 10]) {
translate([(i * i + i) / 2 + 3 * i , 8])
let($r = i / 2)
children();
let(d = i + 0.5)
translate([(d * d + d) / 2 + 3 * d, 19])
let($r = d / 2)
children();
}
color(pp1_colour) linear_extrude(height = 3, center = true)
difference() {
square([100, 27]);
positions()
poly_circle(r = $r);
}
positions()
rod(d = 2 * $r, l = 8 * $r + 5);
//
// Poly rings
//
ir = 3 / 2;
cir = corrected_radius(ir);
sizes = [1.5, 2, 3, 4];
for(i = [0 : len(sizes) - 1])
translate([i * 10, -10]) {
color(pp1_colour) linear_extrude(height = 1)
poly_ring(ir = ir, or = cir + sizes[i] * extrusion_width);
rod(2 * ir, 3);
}
//
// Drill and slot
//
sheet = Steel06;
translate([10, -30])
render_2D_sheet(sheet)
difference() {
sheet_2D(sheet, 20, 20, 1);
translate([0, 5])
slot(1.5, 6, 0);
translate([0, -5])
drill(2, 0);
}
}
polyholes();

36
tests/psus.scad Normal file
View File

@ -0,0 +1,36 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/psus.scad>
module psus()
layout([for(p = psus) psu_width(p)], 10) let(p = psus[$i])
rotate(atx_psu(p) ? 0 : 90) {
psu(p);
psu_screw_positions(p)
translate_z(3)
screw_and_washer(psu_screw(p), 8);
}
if($preview)
psus();

32
tests/pulleys.scad Normal file
View File

@ -0,0 +1,32 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/belts.scad>
include <../vitamins/pulleys.scad>
module pulleys()
layout([for(p = pulleys) pulley_flange_dia(p)])
rotate(-45)
pulley_assembly(pulleys[$i]);
if($preview)
pulleys();

29
tests/quadrant.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/quadrant.scad>
module quadrants() {
linear_extrude(height = eps)
quadrant(10, 4);
}
rotate([70, 0, 315]) quadrants();

48
tests/rails.scad Normal file
View File

@ -0,0 +1,48 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/rails.scad>
use <../vitamins/nut.scad>
sheet = 3;
module rails()
layout([for(l = rails) carriage_width(rail_carriage(l))], 25)
rotate(-90) {
rail = rails[$i];
length = rail == MGN15 ? 260 : 200;
screw = rail_screw(rail);
nut = screw_nut(screw);
washer = screw_washer(screw);
rail_assembly(rail, length, rail_travel(rail, length) / 2);
rail_screws(rail, length, sheet + nut_thickness(nut, true) + washer_thickness(washer));
rail_hole_positions(rail, length, 0)
translate_z(-sheet)
vflip()
nut_and_washer(nut, true);
}
if($preview)
rails();

35
tests/ribbon_clamp.scad Normal file
View File

@ -0,0 +1,35 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../ribbon_clamp.scad>
use <../vitamins/wire.scad>
ways = 20;
module ribbon_clamps()
translate([ribbon_clamp_length(ways) / 2, 0])
if($preview) {
ribbon_clamp_fastened_assembly(ways, 3);
ribbon_cable(ways, 100);
}
else
ribbon_clamp(ways);
ribbon_clamps();

31
tests/ring_terminals.scad Normal file
View File

@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/screws.scad>
include <../vitamins/ring_terminals.scad>
module ring_terminals()
layout([for(t = ring_terminals) ringterm_od(t)], 5)
rotate(90)
ring_terminal_assembly(ring_terminals[$i], 3);
if($preview)
ring_terminals();

29
tests/rockers.scad Normal file
View File

@ -0,0 +1,29 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/rockers.scad>
module rockers()
layout([for(r = rockers) rocker_flange_w(r)], 5)
rocker(rockers[$i]);
if($preview)
rockers();

31
tests/rod.scad Normal file
View File

@ -0,0 +1,31 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/layout.scad>
include <../vitamins/linear_bearings.scad>
use <../vitamins/rod.scad>
module rods()
layout([for(b = linear_bearings) 2 * bearing_radius(b)])
rod(bearing_rod_dia(linear_bearings[$i]), 80);
if($preview)
rods();

42
tests/round.scad Normal file
View File

@ -0,0 +1,42 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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>
use <../utils/round.scad>
module shape()
difference() {
square(40, center = true);
square([20, 20], center = true);
}
module rounds() {
linear_extrude(height = eps)
round(or = 4, ir = 2)
shape();
translate([50, 0])
round_3D(or = 4, ir = 2, chamfer_base = true, $fn = 16)
linear_extrude(height = 40, center = true)
shape();
}
rounds();

View File

@ -0,0 +1,32 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <../global_defs.scad>
use <../utils/rounded_cylinder.scad>
module rounded_cylinders() {
linear_extrude(height = eps)
rounded_corner(10, 20, 3, 5);
translate([30, 10])
rounded_cylinder(10, 20, 3, 5, 270);
}
rounded_cylinders();

Some files were not shown because too many files have changed in this diff Show More