1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-08-20 06:11:41 +02:00

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

40
utils/annotation.scad Normal file
View File

@@ -0,0 +1,40 @@
//
// 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>
//
//! Annotation used in this documentation
module label(str, scale = 0.25, valign = "baseline", halign = "left") //! Draw text that always faces the camera
color("black")
%rotate($vpr != [0, 0, 0] ? $vpr : [70, 0, 315])
linear_extrude(height = eps)
scale(scale)
text(str, valign = valign, halign = halign);
module arrow(length = 20) { //! Draw an arrow that faces downwards
d = length / 20;
head_r = 1.5 * d;
color("grey") %union() {
translate_z(head_r)
cylinder(d = d, h = length - head_r, $fn = 32);
cylinder(r1 = 0, r2 = head_r, h = head_r);
}
}

57
utils/bezier.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/>.
//
//
//! Bezier curves and function to get and adjust the length or minimum z point.
//
include <../global_defs.scad>
function bezier(t, v) = //! Returns a point at distance ```t``` [0 - 1] along the curve with control points ```v```
(len(v) > 2) ? bezier(t, [for (i = [0 : len(v) - 2]) v[i] * (1 - t) + v[i + 1] * (t)])
: v[0] * (1 - t) + v[1] * (t);
function bezier_path(v, steps = 100) = //! Returns a Bezier path from control points ```v``` with ```steps``` segments
[for(i = [0 : steps], t = i / steps) bezier(t, v)];
function bezier_length(v, delta = 0.01, t = 0, length = 0) = //! Calculate the length of a Bezier curve from control points ```v```
t > 1 ? length
: bezier_length(v, delta, t + delta, length + norm(bezier(t, v) - bezier(t + delta, v)));
function adjust_bezier(v, r) =
let(extension = (v[1] - v[0]) * (r - 1))
[v[0], v[1] + extension, v[2] + extension, v[3]];
function adjust_bezier_length(v, l, eps = 0.001, r1 = 1.0, r2 = 1.5, l1, l2) = //! Adjust Bezier control points ```v``` to get the required curve length ```l```
let(l1 = l1 != undef ? l1 : bezier_length(adjust_bezier(v, r1)),
l2 = l2 != undef ? l2 : bezier_length(adjust_bezier(v, r2))
) abs(l1 - l) < eps ? adjust_bezier(v, r1)
: let(r = r1 + (l - l1) * (r2 - r1) / (l2 - l1))
abs(r - r1) < abs(r - r2) ? adjust_bezier_length(v, l, eps, r, r1, undef, l1)
: adjust_bezier_length(v, l, eps, r, r2, undef, l2);
function bezier_min_z(v, steps = 100, z = inf, i = 0) = //! Calculate the minimum z coordinate of a Bezier curve from control points ```v```
i <= steps ? bezier_min_z(v, steps, min(z, bezier(i / steps, v).z), i + 1) : z;
function adjust_bezier_z(v, z, eps = 0.001, r1 = 1, r2 = 1.5, z1, z2) = //! Adjust Bezier control points ```v``` to get the required minimum ```z```
let(z1 = z1 != undef ? z1 : bezier_min_z(adjust_bezier(v, r1)),
z2 = z2 != undef ? z2 : bezier_min_z(adjust_bezier(v, r2))
) abs(z1 - z) < eps ? adjust_bezier(v, r1)
: let(r = r1 + (z - z1) * (r2 - r1) / (z2 - z1))
abs(r - r1) < abs(r - r2) ? adjust_bezier_z(v, z, eps, r, r1, undef, z1)
: adjust_bezier_z(v, z, eps, r, r2, undef, z2);

112
utils/core/bom.scad Normal file
View File

@@ -0,0 +1,112 @@
//
// 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/>.
//
//
//! Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing. Assembly instructions can precede the module
//! definition that makes the assembly.
//!
//! The example below shows how to define a vitamin and incorporate it into an assembly with sub-assemblies and make an exploded view. The resulting flat BOM is shown but
//! heirachical BOMs are also generated for real projects.
//
function bom_mode(n = 1) = $_bom >= n && (is_undef($on_bom) || $on_bom); //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well
function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of ```$exploded``` if it is defined, else ```0```
function show_supports() = !$preview || exploded(); //! True if printed support material should be shown
module no_explode() let($exploded_parent = true) children(); //! Prevent children being exploded
module no_pose() let($posed = true) children(); //! Force children not to be posed even if parent is
module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector ```d```, option to explode grand children
v = is_list(d) ? d : [0, 0, d];
o = is_list(offset) ? offset : [0, 0, offset];
if($exploded && is_undef($exploded_parent)) {
translate(o) // Draw the line first in case the child is transparent
hull() {
sphere(0.2);
translate(v * $exploded)
sphere(0.2);
}
translate(v * $exploded)
let($exploded_parent = explode_children ? undef : true)
children();
}
else
children();
}
module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an STL or assembly for rendering to png by specifying rotation ```a``` and translation ```t```, ```exploded = true for``` just the exploded view or ```false``` for unexploded only.
if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded()))
children();
else
let($posed = true) // only pose the top level
rotate([55, 0, 25])
rotate([-a.x, 0, 0])
rotate([0, -a.y, 0])
rotate([0, 0, -a.z])
translate(-t)
children();
module assembly(name) { //! Name an assembly that will appear on the BOM, there needs to a module named ```<name>_assembly``` to make it
if(bom_mode())
echo(str("~", name, "_assembly{"));
no_pose()
if(is_undef($child_assembly))
let($child_assembly = true)
children();
else
no_explode()
children();
if(bom_mode())
echo(str("~}", name, "_assembly"));
}
module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named ```<name>_stl``` to make it
if(bom_mode())
echo(str("~", name, ".stl"));
}
module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named ```<name>_dxf``` to make it
if(bom_mode())
echo(str("~", name, ".dxf"));
}
function value_string(value) = is_string(value) ? str("\"", value, "\"") : str(value); //! Convert ```value``` to a string or quote it if it is already a string
function arg(value, default, name = "") = //! Create string for arg if not default, helper for ```vitamin()```
value == default ? ""
: name ? str(", ", name, " = ", value_string(value))
: str(", ", value_string(value));
module vitamin(description) { //! Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "wigit(42): Type 42 widget"
if(bom_mode(2))
echo(str("~", description, !is_undef($hidden) ? " - not shown" : ""));
}
module not_on_bom(on = false) //! Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled
let($on_bom = on)
children();
module hidden() //! Make item invisible, except on the BOM
scale(1 / sqr(1024))
let($hidden = true)
children();

49
utils/core/clip.scad 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/>.
//
//
//! Construct arbirarily large box to partition 3D space and clip objects, useful for creating cross sections to see the inside when debugging.
//!
//! Original version by Doug Moen on the OpenSCAD forum
//
//
module box(xmin, ymin, zmin, xmax, ymax, zmax) //! Construct a box given its bounds
polyhedron(
[[xmin, ymin, zmin], // 0
[xmin, ymin, zmax], // 1
[xmin, ymax, zmin], // 2
[xmin, ymax, zmax], // 3
[xmax, ymin, zmin], // 4
[xmax, ymin, zmax], // 5
[xmax, ymax, zmin], // 6
[xmax, ymax, zmax]], // 7
[[7,5,1,3], // top
[2,0,4,6], // bottom
[5,4,0,1], // front
[3,2,6,7], // back
[5,7,6,4], // right
[0,2,3,1]] // left
);
module clip(xmin = -inf, ymin = -inf, zmin = -inf, xmax = inf, ymax = inf, zmax = inf) //! Clip child to specified boundaries
render() intersection() {
children();
box(xmin, ymin, zmin, xmax, ymax, zmax);
}

64
utils/core/global.scad Normal file
View File

@@ -0,0 +1,64 @@
//
// 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/>.
//
//
//! Global constants, functions and modules. This file is used directly or indirectly in every scad file.
//
include <../../global_defs.scad>
function sqr(x) = x * x; //! Returns the square of ```x```
function inch(x) = x * 25.4; //! Inch to mm conversion
function echoit(x) = echo(x) x; //! Echo expression and return it, useful for debugging
function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if ```x``` is an element in the ```list```
function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if ```x``` is not a list
function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius
function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes
module translate_z(z) translate([0, 0, z]) children(); //! Shortcut for Z only translations
module vflip() rotate([180, 0, 0]) children(); //! Invert children by doing a 180 flip around the X axis
module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); //! Draw an ellipse
module extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D
if(h)
linear_extrude(height = h, center = center) // 3D
children();
else
children(); // 2D
module circle4n(r, d = undef) { //! Circle with multiple of 4 vertices
R = is_undef(d) ? r : d / 2;
circle(R, $fn = r2sides4n(R));
}
module semi_circle(r, d = undef) //! A semi circle in the positive Y domain
intersection() {
R = is_undef(d) ? r : d / 2;
circle4n(R);
sq = R + 1;
translate([-sq, 0])
square([2 * sq, sq]);
}
include <sphere.scad>
include <bom.scad>
include <polyholes.scad>
include <teardrops.scad>
include <rounded_rectangle.scad>
include <clip.scad>

79
utils/core/polyholes.scad Normal file
View File

@@ -0,0 +1,79 @@
//
// 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 method of making 3D printed holes come out the right size regardless of the printer, providing
//! it gets the linear dimensions right. See <https://hydraraptor.blogspot.com/2011/02/polyholes.html>
//!
//! The module provides `poly_circle()`, `poly_cylinder()` and `poly_ring()` that is useful for making printed washers and pillars.
//
function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius
function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle
function corrected_diameter(d, n = 0) = d / cos(180 / (n ? n : sides(d / 2))); //! Adjusted diameter to make flats lie on the circle
module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the correct size
n = sides ? sides : sides(r);
circle(r = corrected_radius(r,n), $fn = n);
}
module poly_cylinder(r, h, center = false, sides = 0) //! Make a cylinder adjusted to print the correct size
extrude_if(h, center)
poly_circle(r, sides);
module poly_ring(or, ir) { //! Make a 2D ring adjusted to have the correct internal radius
cir = corrected_radius(ir);
filaments = floor((or - cir) / extrusion_width);
if(filaments > 3)
difference() {
circle(or);
poly_circle(ir);
}
else
if(filaments >= 2)
difference() {
offset(or - cir)
poly_circle(ir);
poly_circle(ir);
}
else
difference() {
poly_circle(or);
offset(-squeezed_wall)
poly_circle(or);
}
}
module drill(r, h = 100) //! Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle
extrude_if(h)
circle(r = corrected_radius(r, r2sides(r)));
//
// Horizontal slot
//
module slot(r, l, h = 100) //! Make a horizontal slot suitable for CNC routing, set h = 0 for 2D version
extrude_if(h)
hull() {
translate([l / 2,0])
drill(r, 0);
translate([-l / 2,0])
drill(r, 0);
}

View File

@@ -0,0 +1,33 @@
//
// 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/>.
//
//
//! Rectangle with rounded corners.
//
module rounded_square(size, r, center = true) //! Like ```square()``` but with with rounded corners
{
$fn = r2sides4n(r);
offset(r) offset(-r) square(size, center = center);
}
module rounded_rectangle(size, r, center = true, xy_center = true) //! Like ```cube()``` but corners rounded in XY plane and separate centre options for xy and z.
{
linear_extrude(height = size[2], center = center)
rounded_square([size[0], size[1]], r, xy_center);
}

28
utils/core/sphere.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/>.
//
//! Redefines `sphere()` to always have a vertex on all six half axes I.e. vertices at the poles and the equator and `$fn` a multiple of four.
//! This ensures `hull` and `minkowski` results have the correct dimensions when spheres are placed at the corners.
module sphere(r = 1, d = undef) { //! Override ```sphere``` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled
R = is_undef(d) ? r : d / 2;
rotate_extrude($fn = r2sides4n(R))
rotate(-90)
semi_circle(R);
}

53
utils/core/teardrops.scad Normal file
View File

@@ -0,0 +1,53 @@
//
// 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/>.
//
//
//! For making horizontal holes that don't need support material.
//! Small holes can get away without it, but they print better with truncated teardrops.
//
module teardrop(h, r, center = true, truncate = true) //! For making horizontal holes that don't need support material, set ```truncate = false``` to make traditional RepRap teardrops that don't even need bridging
render(convexity = 5)
extrude_if(h, center)
hull() {
circle4n(r);
if(truncate)
translate([0, r / 2])
square([2 * r * (sqrt(2) - 1), r], center = true);
else
polygon([[0, 0], [eps, 0], [0, r * sqrt(2)]]);
}
module teardrop_plus(h, r, center = true, truncate = true) //! Slightly bigger teardrop to allow for the 3D printing staircase effect
teardrop(h, r + layer_height / 4, center, truncate);
module tearslot(h, r, w, center = true) //! A horizontal slot that doesn't need support material
extrude_if(h, center)
hull() {
translate([-w/2,0,0]) teardrop(r = r, h = 0);
translate([ w/2,0,0]) teardrop(r = r, h = 0);
}
module vertical_tearslot(h, r, l, center = true) //! A vertical slot that doesn't need support material
extrude_if(h, center)
hull() {
translate([0, l / 2]) teardrop(0, r, true);
translate([0, -l / 2])
circle4n(r);
}

46
utils/dogbones.scad Normal file
View File

@@ -0,0 +1,46 @@
//
// 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/>.
//
//
//! When square holes are cut with a CNC bit they get rounded corners. If it is important that
//! a square cornered part fits in the hole then circles are placed in the corners making a bone shape.
//
include <../core.scad>
module dogbone_square(size, r = cnc_bit_r, center = true) //! Square with circles at the corners
{
union() {
square(size, center = center);
if(r > 0) {
origin = center ? [0, 0] : size / 2;
offset = r / sqrt(2);
for(x = [-1, 1], y = [-1, 1])
translate(origin + [x * (size.x / 2 - offset), y * (size.y / 2 - offset)])
drill(r, 0);
}
}
}
module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners
{
extrude_if(h = size.z, center = center)
dogbone_square([size.x, size.y], r, xy_center);
}

32
utils/fillet.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/>.
//
//
//! Rounded fillet for adding to corners.
//
include <../core.scad>
module fillet(r, h, center = false) //! Fillet with specified radius and height
extrude_if(h, center = center)
difference() {
translate([-eps, -eps, 0])
square(r + eps);
circle(r + eps);
}

64
utils/hanging_hole.scad Normal file
View File

@@ -0,0 +1,64 @@
//
// 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/>.
//
//
//! Method to print holes in mid air. See <https://hydraraptor.blogspot.com/2014/03/buried-nuts-and-hanging-holes.html>
//
include <../core.scad>
module hanging_hole(z, ir, h = 100, h2 = 100) { //! Hole radius ```ir``` hanging at the specified ```z``` value above a void who's shape is given by a 2D child
module polyhole(r, h, n = 8) {
if(h > 0)
rotate(180 / n) {
poly_cylinder(r = r, h = layer_height, sides = n);
translate_z(layer_height)
if(2 * n <= sides(r))
polyhole(r - eps, h - layer_height, n * 2);
else
poly_cylinder(r - eps, h - layer_height);
}
}
assert(z % layer_height == 0, str(z));
infill_angle = z % (2 * layer_height) ? -45 : 45;
below = min(z + eps, h2);
big = 1000;
render(convexity = 3) translate_z(z)
union() {
translate_z(2 * layer_height)
polyhole(ir - eps, h - 2 * layer_height);
difference() {
translate_z(-below)
linear_extrude(height = below + 2 * layer_height)
children();
rotate(infill_angle)
for(side = [-1, 1]) {
translate([side * (ir + big), 0, big + layer_height])
cube(2 * big, center = true);
translate([0, side * (ir + big), big])
cube(2 * big, center = true);
}
}
}
}

33
utils/layout.scad Normal file
View File

@@ -0,0 +1,33 @@
//
// 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/>.
//
//
//! Layout objects in a line with equal gaps given a vector of their widths.
//
include <../global_defs.scad>
function layout_offset(widths, i, gap = 2) = //! Calculate the offset for the ```i```th item
i == 0 ? widths[0] / 2
: layout_offset(widths, i - 1, gap) + widths[i - 1] / 2 + gap + widths[i] / 2;
module layout(widths, gap = 2, no_offset = false) //! Layout children passing ```$i```
translate([no_offset ? -widths[0] / 2 : 0, 0])
for($i = [0 : len(widths) - 1])
translate([layout_offset(widths, $i, gap), 0])
children();

76
utils/maths.scad Normal file
View File

@@ -0,0 +1,76 @@
//
// 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/>.
//
//
//! Maths utilities for minapulating vectors and matrices.
//
function sqr(x) = x * x;
function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z```
: v
: [0, 0, v])
[ [1, 0, 0, u.x],
[0, 1, 0, u.y],
[0, 0, 1, u.z],
[0, 0, 0, 1] ];
function rotate(a, v) = //! Generate a 4x4 rotation matrix, ```a``` can be a vector of three angles or a single angle around ```z```, or around axis ```v```
is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a],
cx = cos(av[0]),
cy = cos(av[1]),
cz = cos(av[2]),
sx = sin(av[0]),
sy = sin(av[1]),
sz = sin(av[2]))
[
[ cy * cz, cz * sx * sy - cx * sz, cx * cz * sy + sx * sz, 0],
[ cy * sz, cx * cz + sx * sy * sz,-cz * sx + cx * sy * sz, 0],
[-sy, cy * sx, cx * cy, 0],
[ 0, 0, 0, 1]
]
: let(s = sin(a),
c = cos(a),
C = 1 - c,
m = sqr(v.x) + sqr(v.y) + sqr(v.z), // m used instead of norm to avoid irrational roots as much as possible
u = v / sqrt(m))
[
[ C * v.x * v.x / m + c, C * v.x * v.y / m - u.z * s, C * v.x * v.z / m + u.y * s, 0],
[ C * v.y * v.x / m + u.z * s, C * v.y * v.y / m + c, C * v.y * v.z / m - u.x * s, 0],
[ C * v.z * v.x / m - u.y * s, C * v.z * v.y / m + u.x * s, C * v.z * v.z / m + c, 0],
[ 0, 0, 0, 1]
];
function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matrix that scales by ```v```, which can be a vector of xyz factors or a scalar to scale all axes equally
[
[s.x, 0, 0, 0],
[0, s.y, 0, 0],
[0, 0, s.z, 0],
[0, 0, 0, 1]
];
function vec3(v) = [v.x, v.y, v.z]; //! Return a 3 vector with the first three elements of ```v```
function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]); //! Apply 4x4 transform to a 3 vector by extending it and cropping it again
function transform_points(path, m) = [for(p = path) transform(p, m)]; //! Apply transform to a path
function unit(v) = let(n = norm(v)) n ? v / n : v; //! Convert ```v``` to a unit vector
function transpose(m) = [ for(j = [0 : len(m[0]) - 1]) [ for(i = [0 : len(m) - 1]) m[i][j] ] ]; //! Transpose an arbitrary size matrix
function identity(n, x = 1) = [for(i = [0 : n - 1]) [for(j = [0 : n - 1]) i == j ? x : 0] ]; //! Construct an arbitrary size identity matrix
function reverse(v) = let(n = len(v) - 1) n < 0 ? [] : [for(i = [0 : n]) v[n - i]]; //! Reverse a vector

63
utils/offset.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/>.
//
//! 3D offset using `minkowski` with a `sphere`, so very slow if `$fn` is not kept small. The offset can be positive or negative.
//!
//! Can be used to round corners. Positive offsets will round convex corners, negative offsets round concave corners. To round both use [`round_3D()`](#round).
//!
//! If `chamfer_base` is true then the bottom edge is made suitable for 3D printing by chamfering when the angle gets shallower than 45 degrees.
include <../core.scad>
module offset_3D(r, chamfer_base = false) { //! Offset 3D shape by specified radius ```r```, positive or negative.
module ball(r)
if(chamfer_base)
rotate_extrude()
intersection() {
rotate(180)
teardrop(0, r);
translate([0, -r])
square([r, 2 * r]);
}
else
sphere(r);
if(r > 0)
minkowski() {
children();
ball(r);
}
else
if(r < 0)
render() difference() {
cube(inf / 2, center = true);
minkowski() {
difference() {
cube(inf, center = true);
children();
}
ball(-r);
}
}
else
children();
}

40
utils/quadrant.scad Normal file
View File

@@ -0,0 +1,40 @@
//
// 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/>.
//
//
//! Square with one rounded corner.
//
include <../core.scad>
module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when ```center``` is ```true```.
offset = center ? r - w : 0;
translate([offset, offset])
hull() {
intersection() {
translate([w - r, w - r])
circle4n(r);
square(w);
}
square([w, eps]);
square([eps, w]);
}
}

44
utils/round.scad Normal file
View File

@@ -0,0 +1,44 @@
//
// 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/>.
//
//! Round 2D shapes uisng `offset()`, which is fast and 3D shapes with [`offset_3D()`](#offset), which is very slow.
//!
//! A single radius can be specified or separate internal and external radii.
//! If `chamfer_base` is `true` for `round_3D()` then the bottom edge is made suitable for 3D printing by chamfering once the
//! the angle gets shallower than 45 degrees.
include <../core.scad>
use <offset.scad>
module round(r, ir = undef, or = undef) { //! Round a 2D child, single radius or separate inside and outside radii
IR = is_undef(ir) ? r : ir;
OR = is_undef(or) ? r : or;
offset(OR)
offset(-OR -IR)
offset(IR)
children();
}
module round_3D(r, ir = undef, or = undef, chamfer_base = false) { //! Round a 3D child single radius or separate inside and outside radii
IR = is_undef(ir) ? r : ir;
OR = is_undef(or) ? r : or;
offset_3D(OR, chamfer_base)
offset_3D(-OR -IR, chamfer_base)
offset_3D(IR, chamfer_base)
children();
}

View File

@@ -0,0 +1,47 @@
//
// 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/>.
//
//
//! Cylinder with a rounded end.
//
include <../core.scad>
module rounded_corner(r, h, r2, ir = 0) { //! 2D version
assert(ir <= r - r2);
translate([ir , 0])
hull() {
square([eps, h]);
square([r - ir, eps]);
translate([r - r2 - ir, h - r2])
intersection() {
circle4n(r2, $fs = 0.2);
square(r2);
}
}
}
module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius ```r```, height ```h```, optional internal radius ```ir``` and optional ```angle```
{
rotate_extrude(angle = angle)
rounded_corner(r, h, r2, ir);
}

View File

@@ -0,0 +1,93 @@
//
// 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/>.
//
//
//! Draw a polygon with rounded corners. Each element of the vector is the XY coordinate and a radius. Radius can be negative for a concave corner.
//!
//! Because the tangents need to be calculated to find the length these can be calculated separately and re-used when drawing to save calculating them twice.
//
include <../core.scad>
function circle_tangent(p1, p2) =
let(
r1 = p1[2],
r2 = p2[2],
dx = p2.x - p1.x,
dy = p2.y - p1.y,
d = sqrt(dx * dx + dy * dy),
theta = atan2(dy, dx) + acos((r1 - r2) / d),
xa = p1.x +(cos(theta) * r1),
ya = p1.y +(sin(theta) * r1),
xb = p2.x +(cos(theta) * r2),
yb = p2.y +(sin(theta) * r2)
)[ [xa, ya], [xb, yb] ];
function rounded_polygon_tangents(points) = //! Compute the straight sections needed to draw and to compute the lengths
let(len = len(points))
[for(i = [0 : len - 1])
let(ends = circle_tangent(points[i], points[(i + 1) % len]))
for(end = [0, 1])
ends[end]];
function sumv(v, i = 0, sum = 0) = i == len(v) ? sum : sumv(v, i + 1, sum + v[i]);
// the cross product of 2D vectors is the area of the parallelogram between them. We use the sign of this to decide if the angle is bigger than 180.
function rounded_polygon_length(points, tangents) = //! Calculate the length given the point list and the list of tangents computed by ``` rounded_polygon_tangents```
let(
len = len(points),
indices = [0 : len - 1],
straights = [for(i = indices) norm(tangents[2 * i] - tangents[2 * i + 1])],
arcs = [for(i = indices) let(p1 = tangents[2 * i + 1],
p2 = tangents[(2 * i + 2) % (2 * len)],
corner = points[(i + 1) % len],
c = [corner.x, corner.y],
v1 = p1 - c,
v2 = p2 - c,
r = abs(corner.z),
a = acos((v1 * v2) / sqr(r))) PI * (cross(v1,v2) <= 0 ? a : 360 - a) * r / 180]
)
sumv(concat(straights, arcs));
module rounded_polygon(points, _tangents = undef) { //! Draw the rounded polygon from the point list, can pass the tangent list to save it being calculated
len = len(points);
indices = [0 : len - 1];
tangents = _tangents ? _tangents : rounded_polygon_tangents(points);
difference(convexity = points) {
union() {
for(i = indices)
if(points[i][2] > 0)
hull() {
translate([points[i].x, points[i].y])
circle(points[i][2]);
polygon([tangents[(2 * i - 1 + 2 * len) % (2 * len)], tangents[2 * i], [points[i].x, points[i].y]]);
}
polygon(tangents, convexity = points);
}
for(i = indices)
if(points[i][2] < 0)
hull() {
translate([points[i].x, points[i].y])
circle(-points[i][2]);
polygon([tangents[(2 * i - 1 + 2 * len) % (2 *len)], tangents[2 * i], [points[i].x, points[i].y]]);
}
}
}

36
utils/sector.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/>.
//
//
//! A sector of a circle between two angles.
//
include <../core.scad>
module sector(r, start_angle, end_angle) { //! Create specified sector given radius ```r```, ```start_angle``` and ```end_angle```
R = r * sqrt(2) + 1;
if(end_angle > start_angle)
intersection() {
circle4n(r);
// A 4 triangle fan
polygon([[0, 0],
for(i = [0 : 4], a = start_angle + i * (end_angle - start_angle) / 4) R * [cos(a), sin(a)] ]);
}
}

160
utils/sweep.scad Normal file
View File

@@ -0,0 +1,160 @@
//
// 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/>.
//
//
//! Utility to generate a polhedron by sweeping a 2D profile along a 3D path and utilities for generating paths.
//!
//! The initial orientation is the Y axis of the profile points towards the initial center of curvature, Frenet-Serret style.
//! This means the first three points must not be colinear. Subsequent rotations use the minimum rotation method.
//!
//! The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up.
//! An additional twist around the path can be specified. If the path is closed this should be a multiple of 360.
//
include <../core.scad>
use <maths.scad>
function transpose3(m) = [ [m[0].x, m[1].x, m[2].x],
[m[0].y, m[1].y, m[2].y],
[m[0].z, m[1].z, m[2].z] ];
//
// Frenet-Serret frame
//
function fs_frame(tangents) =
let(tangent = tangents[0],
normal = tangents[1] - tangents[0],
binormal = cross(tangent, normal),
z = unit(tangent),
x = assert(norm(binormal) > 0.00001, "first three points are colinear") unit(binormal),
y = unit(cross(z, x))
) [[x.x, y.x, z.x],
[x.y, y.y, z.y],
[x.z, y.z, z.z]];
//
// Computes the rotation with minimum angle that brings UNIT vectors a to b.
// The code fails if a and b are opposed to each other.
//
function rotate_from_to(a, b) =
let(axis = unit(cross(a, b)))
axis * axis >= 0.99 ? transpose3([b, axis, cross(axis, b)]) * [a, axis, cross(axis, a)]
: a * b > 0 ? [[ 1, 0, 0], [0, 1, 0], [0, 0, 1]]
: [[-1, 0, 0], [0, 1, 0], [0, 0, -1]];
//
// Given two rotations A and B, calculates the angle between B*[1,0,0]
// and A*[1,0,0] that is, the total torsion angle difference between A and B.
//
function calculate_twist(A, B) = let(D = transpose3(B) * A) atan2(D[1][0], D[0][0]);
//
// Compute a 4x4 matrix to orientate a frame of the sweep given the position and a 3x3 rotation matrix.
//
function orientate(p, r) =
let(x = r[0], y = r[1], z = r[2])
[[x.x, y.x, z.x],
[x.y, y.y, z.y],
[x.z, y.z, z.z],
[p.x, p.y, p.z]];
//
// Rotate around z
//
function rot3_z(a) =
let(c = cos(a),
s = sin(a))
[ [ c, -s, 0],
[ s, c, 0],
[ 0, 0, 1] ];
//
// Calculate the unit tangent at a vertex given the indices before and after. One of these can be the same as i in the case
// of the start and end of a non closed path.
//
function tangent(path, before, i, after) = unit(unit(path[after] - path[i]) - unit(path[before] - path[i]));
//
// Generate all the surface points of the swept volume.
//
function skin_points(profile, path, loop, twist = 0) =
let(len = len(path),
last = len - 1,
profile4 = [for(p = profile) [p.x, p.y, p.z, 1]],
tangents = [tangent(path, loop ? last : 0, 0, 1),
for(i = [1 : last - 1]) tangent(path, i - 1, i, i + 1),
tangent(path, last - 1, last, loop ? 0 : last)],
rotations = [for(i = 0, rot = fs_frame(tangents);
i < len;
i = i + 1,
rot = i < len ? rotate_from_to(tangents[i - 1], tangents[i]) * rot : undef) rot],
missmatch = loop ? calculate_twist(rotations[0], rotations[last]) : 0,
rotation = missmatch + twist
)
[for(i = [0 : last])
let(za = rotation * i / last)
each profile4 * orientate(path[i], rotations[i] * rot3_z(za))
];
function cap(facets, segment = 0) = [for(i = [0 : facets - 1]) segment ? facets * segment + i : facets - 1 - i];
function quad(p, a,b,c,d) = norm(p[a] - p[c]) > norm(p[b] - p[d]) ? [[b, c, d], [b, d, a]] : [[a, b, c], [a, c, d]];
function skin_faces(points, segs, facets, loop) = [for(i = [0 : facets - 1], s = [0 : segs - (loop ? 1 : 2)])
each quad(points,
s * facets + i,
s * facets + (i + 1) % facets,
((s + 1) % segs) * facets + (i + 1) % facets,
((s + 1) % segs) * facets + i)];
function sweep(path, profile, loop = false, twist = 0) = //! Generate the point list and face list of the swept volume
let(
segments = len(path),
facets = len(profile),
points = skin_points(profile, path, loop, twist),
skin_faces = skin_faces(points, segments, facets, loop),
faces = loop ? skin_faces : concat([cap(facets)], skin_faces, [cap(facets, segments - 1)])
) [points, faces];
module sweep(path, profile, loop = false, twist = 0) { //! Draw a polyhedron that is the swept volume
mesh = sweep(path, profile, loop, twist);
polyhedron(points = mesh[0], faces = mesh[1]);
}
function path_length(path, i = 0, length = 0) = //! Calculated the length along a path
i >= len(path) - 1 ? length
: path_length(path, i + 1, length + norm(path[i + 1] - path[i]));
function circle_points(r = 1, z = 0) = //! Generate the points of a circle, setting z makes a single turn spiral
let(sides = r2sides(r))
[for(i = [0 : sides - 1]) let(a = i * 360 / sides) [r * sin(a), r * cos(a), z * a / 360]];
function rectangle_points(w, h) = [[-w/2, -h/2, 0], [-w/2, h/2, 0], [w/2, h/2, 0], [w/2, -h/2, 0]]; //! Generate the points of a rectangle
function arc_points(r, a = [90, 0, 180], al = 90) = //! Generate the points of a circular arc
let(sides = ceil(r2sides(r) * al / 360), tf = rotate(a))
[for(i = [0 : sides]) let(t = i * al / sides) transform([r * sin(t), r * cos(t), 0], tf)];
function before(path1, path2) = //! Translate ```path1``` so its end meets the start of ```path2``` and then concatenate
let(end = len(path1) - 1, offset = path2[0] - path1[end])
concat([for(i = [0 : end - 1]) path1[i] + offset], path2);
function after(path1, path2) = //! Translate ```path2``` so its start meets the end of ```path1``` and then concatenate
let(end1 = len(path1) - 1, end2 = len(path2) - 1, offset = path1[end1] - path2[0])
concat(path1, [for(i = [1 : end2]) path2[i] + offset]);

33
utils/tube.scad Normal file
View File

@@ -0,0 +1,33 @@
//
// 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/>.
//
//
//! Simple tube or ring
//
include <../core.scad>
module ring(or, ir) //! Create a ring with specified external and internal radii
difference() {
circle4n(or);
circle4n(ir);
}
module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height ```h```
linear_extrude(height = h, center = center, convexity = 5)
ring(or, ir);