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:
40
utils/annotation.scad
Normal file
40
utils/annotation.scad
Normal 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
57
utils/bezier.scad
Normal 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
112
utils/core/bom.scad
Normal 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
49
utils/core/clip.scad
Normal 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
64
utils/core/global.scad
Normal 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
79
utils/core/polyholes.scad
Normal 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);
|
||||
}
|
33
utils/core/rounded_rectangle.scad
Normal file
33
utils/core/rounded_rectangle.scad
Normal 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
28
utils/core/sphere.scad
Normal 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
53
utils/core/teardrops.scad
Normal 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
46
utils/dogbones.scad
Normal 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
32
utils/fillet.scad
Normal 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
64
utils/hanging_hole.scad
Normal 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
33
utils/layout.scad
Normal 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
76
utils/maths.scad
Normal 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
63
utils/offset.scad
Normal 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
40
utils/quadrant.scad
Normal 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
44
utils/round.scad
Normal 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();
|
||||
}
|
47
utils/rounded_cylinder.scad
Normal file
47
utils/rounded_cylinder.scad
Normal 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);
|
||||
}
|
93
utils/rounded_polygon.scad
Normal file
93
utils/rounded_polygon.scad
Normal 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
36
utils/sector.scad
Normal 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
160
utils/sweep.scad
Normal 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
33
utils/tube.scad
Normal 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);
|
Reference in New Issue
Block a user