mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-12-30 12:08:13 +00:00
Merge pull request #1860 from RAMilewski/dependency-warnings
Dependency warnings
This commit is contained in:
commit
4d691c47b6
60 changed files with 447 additions and 269 deletions
|
|
@ -5,6 +5,10 @@
|
|||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_AFFINE = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: affine.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
|
||||
// Section: Affine2d 3x3 Transformation Matrices
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_ATTACHMENTS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: attachments.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Default values for attachment code.
|
||||
$tags=undef; // for backward compatibility
|
||||
$tag = "";
|
||||
|
|
@ -3452,7 +3456,7 @@ function _find_anchor(anchor, geom)=
|
|||
vec2 = anch==CENTER? UP : rot(from=UP, to=axis, p=vec),
|
||||
// Set spin for top/bottom to be clockwise
|
||||
spin = anch.z!=0 && (!approx(anch.x,0) || !approx(anch.y,0)) ? _compute_spin(vec2,rot(from=UP,to=axis,p=point3d(tangent)*anch.z))
|
||||
: anch.z==0 && norm(anch)>EPSILON ? _compute_spin(vec2, (approx(vec2,DOWN) || approx(vec2,UP))?BACK:UP)
|
||||
: anch.z==0 && norm(anch)>_EPSILON ? _compute_spin(vec2, (approx(vec2,DOWN) || approx(vec2,UP))?BACK:UP)
|
||||
: oang
|
||||
) [anchor, pos2, vec2, spin]
|
||||
) : type == "point"? (
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// FileSummary: Models for standard ball bearing cartridges.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_BALL_BEARINGS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: ball_bearings.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Ball Bearing Models
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_BEZIERS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: beziers.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
|
||||
// Terminology:
|
||||
// Path = A series of points joined by straight line segements.
|
||||
// Bezier Curve = A polynomial curve defined by a list of control points. The curve starts at the first control point and ends at the last one. The other control points define the shape of the curve and they are often *NOT* on the curve
|
||||
|
|
@ -1376,8 +1381,8 @@ function bezier_vnf_degenerate_patch(patch, splinesteps=16, reverse=false, retur
|
|||
assert(is_bezier_patch(patch), "\nInput is not a Bezier patch.")
|
||||
assert(is_int(splinesteps) && splinesteps>0, "\nsplinesteps must be a positive integer.")
|
||||
let(
|
||||
row_degen = [for(row=patch) all_equal(row,eps=EPSILON)],
|
||||
col_degen = [for(col=transpose(patch)) all_equal(col,eps=EPSILON)],
|
||||
row_degen = [for(row=patch) all_equal(row,eps=_EPSILON)],
|
||||
col_degen = [for(col=transpose(patch)) all_equal(col,eps=_EPSILON)],
|
||||
top_degen = row_degen[0],
|
||||
bot_degen = last(row_degen),
|
||||
left_degen = col_degen[0],
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
_BOSL2_BOSL1COMPAT = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: bosl2compat.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
module translate_copies(a=[[0,0,0]]) move_copies(a) children();
|
||||
|
||||
module xspread(spacing, n, l, sp) xcopies(spacing=spacing, n=n, l=l, sp=sp) children();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_BOTTLECAPS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: bottlecaps.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
|
||||
include <threading.scad>
|
||||
include <structs.scad>
|
||||
include <rounding.scad>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
/// use <BOSL2/builtins.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/// Section: Builtin Functions
|
||||
|
||||
/// Section: Builtin Modules
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_COLOR = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: color.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
use <builtins.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_COMPARISONS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: comparisons.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: List comparison operations
|
||||
|
||||
|
|
@ -31,7 +34,7 @@
|
|||
// test4 = approx(0.3333,1/3,eps=1e-3); // Returns: true
|
||||
// test5 = approx(PI,3.1415926536); // Returns: true
|
||||
// test6 = approx([0,0,sin(45)],[0,0,sqrt(2)/2]); // Returns: true
|
||||
function approx(a,b,eps=EPSILON) =
|
||||
function approx(a,b,eps=_EPSILON) =
|
||||
a == b? is_bool(a) == is_bool(b) :
|
||||
is_num(a) && is_num(b)? abs(a-b) <= eps :
|
||||
is_list(a) && is_list(b) && len(a) == len(b)? (
|
||||
|
|
@ -58,13 +61,13 @@ function approx(a,b,eps=EPSILON) =
|
|||
// Otherwise, returns false.
|
||||
// Arguments:
|
||||
// x = The value to check.
|
||||
// eps = The maximum allowed variance. Default: `EPSILON` (1e-9)
|
||||
// eps = The maximum allowed variance. Default: `_EPSILON` (1e-9)
|
||||
// Example:
|
||||
// a = all_zero(0); // Returns: true.
|
||||
// b = all_zero(1e-3); // Returns: false.
|
||||
// c = all_zero([0,0,0]); // Returns: true.
|
||||
// d = all_zero([0,0,1e-3]); // Returns: false.
|
||||
function all_zero(x, eps=EPSILON) =
|
||||
function all_zero(x, eps=_EPSILON) =
|
||||
is_finite(x)? abs(x)<eps :
|
||||
is_vector(x) && [for (xx=x) if(abs(xx)>eps) 1] == [];
|
||||
|
||||
|
|
@ -81,14 +84,14 @@ function all_zero(x, eps=EPSILON) =
|
|||
// Otherwise, returns false.
|
||||
// Arguments:
|
||||
// x = The value to check.
|
||||
// eps = The maximum allowed variance. Default: `EPSILON` (1e-9)
|
||||
// eps = The maximum allowed variance. Default: `_EPSILON` (1e-9)
|
||||
// Example:
|
||||
// a = all_nonzero(0); // Returns: false.
|
||||
// b = all_nonzero(1e-3); // Returns: true.
|
||||
// c = all_nonzero([0,0,0]); // Returns: false.
|
||||
// d = all_nonzero([0,0,1e-3]); // Returns: false.
|
||||
// e = all_nonzero([1e-3,1e-3,1e-3]); // Returns: true.
|
||||
function all_nonzero(x, eps=EPSILON) =
|
||||
function all_nonzero(x, eps=_EPSILON) =
|
||||
is_finite(x)? abs(x)>eps :
|
||||
is_vector(x) && [for (xx=x) if(abs(xx)<eps) 1] == [];
|
||||
|
||||
|
|
@ -228,8 +231,8 @@ function all_equal(vec,eps=0) =
|
|||
// Returns true if the first and last points in the given list are equal to within epsilon.
|
||||
// Arguments:
|
||||
// list = list to check
|
||||
// eps = Tolerance for approximate equality. Default: `EPSILON` (1e-9)
|
||||
function are_ends_equal(list, eps=EPSILON) =
|
||||
// eps = Tolerance for approximate equality. Default: `_EPSILON` (1e-9)
|
||||
function are_ends_equal(list, eps=_EPSILON) =
|
||||
assert(is_list(list) && len(list)>0, "Must give a nonempty list")
|
||||
approx(list[0], list[len(list)-1], eps=eps);
|
||||
|
||||
|
|
@ -405,13 +408,13 @@ function max_index(vals, all=false) =
|
|||
// ---
|
||||
// start = The index to start searching from. Default: 0
|
||||
// all = If true, returns a list of all matching item indices. Default: false
|
||||
// eps = The maximum allowed floating point rounding error for numeric comparisons. Default: EPSILON (1e-9)
|
||||
// eps = The maximum allowed floating point rounding error for numeric comparisons. Default: _EPSILON (1e-9)
|
||||
// Example:
|
||||
// find_approx(3,[4,5,3.01,2,2.99], eps=0.1); // Returns 2
|
||||
// find_approx(9,[4,5,3.01,2,2.99], eps=0.1); // Returns undef
|
||||
// find_approx(3,[4,5,3.01,2,2.99], all=true, eps=0.1); // Returns [2,4]
|
||||
// find_approx(9,[4,5,3.01,2,2.99], all=true, eps=0.1); // Returns []
|
||||
function find_approx(val, list, start=0, all=false, eps=EPSILON) =
|
||||
function find_approx(val, list, start=0, all=false, eps=_EPSILON) =
|
||||
all ? [for (i=[start:1:len(list)-1]) if (approx(val, list[i], eps=eps)) i]
|
||||
: __find_approx(val, list, eps=eps, i=start);
|
||||
|
||||
|
|
@ -439,14 +442,14 @@ function __find_approx(val, list, eps, i=0) =
|
|||
// Arguments:
|
||||
// list = The list to deduplicate.
|
||||
// closed = If true, treats first and last list entry as adjacent. Default: false
|
||||
// eps = The maximum tolerance between items. Default: EPSILON
|
||||
// eps = The maximum tolerance between items. Default: _EPSILON
|
||||
// Example:
|
||||
// a = deduplicate([8,3,4,4,4,8,2,3,3,8,8]); // Returns: [8,3,4,8,2,3,8]
|
||||
// b = deduplicate(closed=true, [8,3,4,4,4,8,2,3,3,8,8]); // Returns: [8,3,4,8,2,3]
|
||||
// c = deduplicate("Hello"); // Returns: "Helo"
|
||||
// d = deduplicate([[3,4],[7,2],[7,1.99],[1,4]],eps=0.1); // Returns: [[3,4],[7,2],[1,4]]
|
||||
// e = deduplicate([[7,undef],[7,undef],[1,4],[1,4+1e-12]],eps=0); // Returns: [[7,undef],[1,4],[1,4+1e-12]]
|
||||
function deduplicate(list, closed=false, eps=EPSILON) =
|
||||
function deduplicate(list, closed=false, eps=_EPSILON) =
|
||||
assert(is_list(list)||is_string(list))
|
||||
let(
|
||||
l = len(list),
|
||||
|
|
@ -475,7 +478,7 @@ function deduplicate(list, closed=false, eps=EPSILON) =
|
|||
// a = deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1]); // Returns: [1,4,3,2,0,1]
|
||||
// b = deduplicate_indexed([8,6,4,6,3], [1,4,3,1,2,2,0,1], closed=true); // Returns: [1,4,3,2,0]
|
||||
// c = deduplicate_indexed([[7,undef],[7,undef],[1,4],[1,4],[1,4+1e-12]],eps=0); // Returns: [0,2,4]
|
||||
function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) =
|
||||
function deduplicate_indexed(list, indices, closed=false, eps=_EPSILON) =
|
||||
assert(is_list(list)||is_string(list), "Improper list or string.")
|
||||
indices==[]? [] :
|
||||
assert(is_vector(indices), "Indices must be a list of numbers.")
|
||||
|
|
@ -516,18 +519,18 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) =
|
|||
// 1 are returned unchanged.
|
||||
// Arguments:
|
||||
// list = list to unwrap
|
||||
// eps = epsilon for comparison. Default: EPSILON (1e-9)
|
||||
// eps = epsilon for comparison. Default: _EPSILON (1e-9)
|
||||
|
||||
function list_wrap(list, eps=EPSILON) =
|
||||
function list_wrap(list, eps=_EPSILON) =
|
||||
assert(is_list(list))
|
||||
len(list)<2 || are_ends_equal(list,eps=eps)? list : [each list, list[0]];
|
||||
|
||||
|
||||
function cleanup_path(list,eps=EPSILON) =
|
||||
function cleanup_path(list,eps=_EPSILON) =
|
||||
echo("***** Function cleanup_path() has been replaced by list_unwrap() and will be removed in a future version *****")
|
||||
list_unwrap(list,eps);
|
||||
|
||||
function close_path(list,eps=EPSILON) =
|
||||
function close_path(list,eps=_EPSILON) =
|
||||
echo("***** Function close_path() has been replaced by list_wrap() and will be removed in a future version *****")
|
||||
list_wrap(list,eps);
|
||||
|
||||
|
|
@ -543,8 +546,8 @@ function close_path(list,eps=EPSILON) =
|
|||
// length 0 or 1 it is returned unchanged.
|
||||
// Arguments:
|
||||
// list = list to unwrap
|
||||
// eps = epsilon for comparison. Default: EPSILON (1e-9)
|
||||
function list_unwrap(list, eps=EPSILON) =
|
||||
// eps = epsilon for comparison. Default: _EPSILON (1e-9)
|
||||
function list_unwrap(list, eps=_EPSILON) =
|
||||
assert(is_list(list))
|
||||
len(list)>=2 && are_ends_equal(list,eps=eps)? [for (i=[0:1:len(list)-2]) list[i]] : list;
|
||||
|
||||
|
|
@ -624,7 +627,7 @@ function unique_count(list) =
|
|||
// ulist = unique_approx(data, [eps]);
|
||||
// Description:
|
||||
// Returns a subset of items that differ by more thatn eps.
|
||||
function unique_approx(data,eps=EPSILON) =
|
||||
function unique_approx(data,eps=_EPSILON) =
|
||||
is_vector(data) ?
|
||||
let(
|
||||
sdata = sort(data)
|
||||
|
|
@ -643,7 +646,7 @@ function unique_approx(data,eps=EPSILON) =
|
|||
// ulist = unique_approx(data, [eps]);
|
||||
// Description:
|
||||
// Returns the indices of a subset of items that differ by more thatn eps.
|
||||
function unique_approx_indexed(data,eps=EPSILON) =
|
||||
function unique_approx_indexed(data,eps=_EPSILON) =
|
||||
is_vector(data) ?
|
||||
let(
|
||||
sind = sortidx(data)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_CONSTANTS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: constants.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
|
||||
// a value that the user should never enter randomly;
|
||||
// result of `dd if=/dev/random bs=32 count=1 |base64` :
|
||||
_UNDEF="LRG+HX7dy89RyHvDlAKvb9Y04OTuaikpx205CTh8BSI";
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_COORDS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: coords.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Coordinate Manipulation
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
// FileSummary: Modular open-framed trusses and joiners.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_CUBETRUSS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: cubetruss.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
$cubetruss_size = 30;
|
||||
$cubetruss_strut_size = 4;
|
||||
$cubetruss_bracing = true;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_DISTRIBUTORS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: distributors.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Adaptive Children Using `$` Variables
|
||||
// The distributor methods create multiple copies of their children and place them in various ways. While many models
|
||||
// require multiple identical copies of an object, this framework is more powerful than
|
||||
|
|
@ -529,7 +533,7 @@ function line_copies(spacing, n, l, p1, p2, p=_NO_ARG) =
|
|||
assert(is_undef(p2) || is_undef(l), "Cannot give both p2 and l")
|
||||
assert(is_undef(n) || num_defined([l,spacing,p2])==1,"If n is given then must give exactly one of 'l', 'spacing', or the 'p1'/'p2' pair")
|
||||
assert(is_def(n) || num_defined([l,spacing,p2])>=1,"If n is not given then must give at least one of 'l', 'spacing', or the 'p1'/'p2' pair")
|
||||
assert(!(is_vector(spacing) && is_vector(l) && vector_angle(spacing,l)>EPSILON), "Cannot give conflicting vector 'spacing' and vector 'l' value.")
|
||||
assert(!(is_vector(spacing) && is_vector(l) && vector_angle(spacing,l)>_EPSILON), "Cannot give conflicting vector 'spacing' and vector 'l' value.")
|
||||
assert(!(is_vector(spacing) && is_def(p2)), "Cannot combine vector 'spacing' with the 'p1'/'p2' pair")
|
||||
let(
|
||||
ll = is_def(l)? scalar_vec3(l, 0)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_DRAWING = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: drawing.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Line Drawing
|
||||
|
||||
|
|
@ -646,7 +649,7 @@ function dashed_stroke(path, dashpat=[3,3], closed=false, fit=true, mindash=0.5)
|
|||
cuts = [
|
||||
for (i = [0:1:reps], off = doff*sc)
|
||||
let (x = i*dlen*sc + off)
|
||||
if (x > 0 && x < plen-EPSILON) x
|
||||
if (x > 0 && x < plen-_EPSILON) x
|
||||
],
|
||||
dashes = path_cut(path, cuts, closed=false),
|
||||
dcnt = len(dashes),
|
||||
|
|
@ -1425,7 +1428,7 @@ module _debug_poly_verts(points, size)
|
|||
labels=is_vector(points[0]) ? [for(i=idx(points)) str(i)]
|
||||
:[for(j=idx(points), i=idx(points[j])) str(chr(97+j),i)];
|
||||
points = is_vector(points[0]) ? points : flatten(points);
|
||||
dups = vector_search(points, EPSILON, points);
|
||||
dups = vector_search(points, _EPSILON, points);
|
||||
color("red") {
|
||||
for (ind=dups){
|
||||
numstr = str_join(select(labels,ind),",");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
// DefineHeader(Table;Headers=Positional|Definition||Named|Definition): FunctionLiteral Args
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_FNLITERALS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: fnliterals.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Section: Function Literal Algorithms
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
// FileSummary: Gears, racks, worms, and worm gears.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_GEARS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: gears.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
_GEAR_PITCH = 5;
|
||||
_GEAR_HELICAL = 0;
|
||||
|
|
|
|||
141
geometry.scad
141
geometry.scad
|
|
@ -11,6 +11,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_GEOMETRY = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: geometry.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Lines, Rays, and Segments
|
||||
|
||||
|
|
@ -29,14 +32,14 @@
|
|||
// point = The point to test.
|
||||
// line = Array of two points defining the line, ray, or segment to test against.
|
||||
// bounded = boolean or list of two booleans defining endpoint conditions for the line. If false treat the line as an unbounded line. If true treat it as a segment. If [true,false] treat as a ray, based at the first endpoint. Default: false
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function is_point_on_line(point, line, bounded=false, eps=EPSILON) =
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function is_point_on_line(point, line, bounded=false, eps=_EPSILON) =
|
||||
assert(is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." )
|
||||
assert(is_vector(point), "\nPoint must be a vector.")
|
||||
assert(_valid_line(line, len(point),eps),"\nGiven line is not valid.")
|
||||
_is_point_on_line(point, line, bounded,eps);
|
||||
|
||||
function _is_point_on_line(point, line, bounded=false, eps=EPSILON) =
|
||||
function _is_point_on_line(point, line, bounded=false, eps=_EPSILON) =
|
||||
let(
|
||||
v1 = (line[1]-line[0]),
|
||||
v0 = (point-line[0]),
|
||||
|
|
@ -55,12 +58,12 @@ function _dist2line(d,n) = norm(d-(d * n) * n);
|
|||
|
||||
|
||||
///Internal
|
||||
function _valid_line(line,dim,eps=EPSILON) =
|
||||
function _valid_line(line,dim,eps=_EPSILON) =
|
||||
is_matrix(line,2,dim)
|
||||
&& norm(line[1]-line[0])>eps*max(norm(line[1]),norm(line[0]));
|
||||
|
||||
//Internal
|
||||
function _valid_plane(p, eps=EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps);
|
||||
function _valid_plane(p, eps=_EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps);
|
||||
|
||||
|
||||
/// Internal Function: _is_at_left()
|
||||
|
|
@ -73,7 +76,7 @@ function _valid_plane(p, eps=EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps
|
|||
/// pt = The 2d point to check position of.
|
||||
/// line = Array of two 2d points forming the line segment to test against.
|
||||
/// eps = Tolerance in the geometrical tests.
|
||||
function _is_at_left(pt,line,eps=EPSILON) = _tri_class([pt,line[0],line[1]],eps) <= 0;
|
||||
function _is_at_left(pt,line,eps=_EPSILON) = _tri_class([pt,line[0],line[1]],eps) <= 0;
|
||||
|
||||
|
||||
/// Internal Function: _degenerate_tri()
|
||||
|
|
@ -100,7 +103,7 @@ function _degenerate_tri(tri,eps) =
|
|||
/// Arguments:
|
||||
/// tri = A list of the three 2d vertices of a triangle.
|
||||
/// eps = Tolerance in the geometrical tests.
|
||||
function _tri_class(tri, eps=EPSILON) =
|
||||
function _tri_class(tri, eps=_EPSILON) =
|
||||
let( crx = cross(tri[1]-tri[2],tri[0]-tri[2]) )
|
||||
abs( crx ) <= eps*norm(tri[1]-tri[2])*norm(tri[0]-tri[2]) ? 0 : sign( crx );
|
||||
|
||||
|
|
@ -118,7 +121,7 @@ function _tri_class(tri, eps=EPSILON) =
|
|||
/// point = The point to check position of.
|
||||
/// tri = A list of the three 2d vertices of a triangle.
|
||||
/// eps = Tolerance in the geometrical tests.
|
||||
function _pt_in_tri(point, tri, eps=EPSILON) =
|
||||
function _pt_in_tri(point, tri, eps=_EPSILON) =
|
||||
min( _tri_class([tri[0],tri[1],point],eps),
|
||||
_tri_class([tri[1],tri[2],point],eps),
|
||||
_tri_class([tri[2],tri[0],point],eps) );
|
||||
|
|
@ -135,7 +138,7 @@ function _pt_in_tri(point, tri, eps=EPSILON) =
|
|||
/// Arguments:
|
||||
/// point = The point to check position of.
|
||||
/// line = Array of two points forming the line segment to test against.
|
||||
function _point_left_of_line2d(point, line, eps=EPSILON) =
|
||||
function _point_left_of_line2d(point, line, eps=_EPSILON) =
|
||||
assert( is_vector(point,2) && is_vector(line*point, 2), "\nImproper input." )
|
||||
// cross(line[0]-point, line[1]-line[0]);
|
||||
_tri_class([point,line[1],line[0]],eps);
|
||||
|
|
@ -153,8 +156,8 @@ function _point_left_of_line2d(point, line, eps=EPSILON) =
|
|||
// a = First point or list of points.
|
||||
// b = Second point or undef; it should be undef if `c` is undef
|
||||
// c = Third point or undef.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function is_collinear(a, b, c, eps=EPSILON) =
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function is_collinear(a, b, c, eps=_EPSILON) =
|
||||
assert( is_path([a,b,c],dim=undef)
|
||||
|| ( is_undef(b) && is_undef(c) && is_path(a,dim=undef) ),
|
||||
"\nInput should be 3 points or a list of points with same dimension.")
|
||||
|
|
@ -205,7 +208,7 @@ function point_line_distance(pt, line, bounded=false) =
|
|||
// Example:
|
||||
// dist = segment_distance([[-14,3], [-15,9]], [[-10,0], [10,0]]); // Returns: 5
|
||||
// dist2 = segment_distance([[-5,5], [5,-5]], [[-10,3], [10,-3]]); // Returns: 0
|
||||
function segment_distance(seg1, seg2,eps=EPSILON) =
|
||||
function segment_distance(seg1, seg2,eps=_EPSILON) =
|
||||
assert( is_matrix(concat(seg1,seg2),4), "\nInputs should be two valid segments." )
|
||||
convex_distance(seg1,seg2,eps);
|
||||
|
||||
|
|
@ -247,7 +250,7 @@ function line_normal(p1,p2) =
|
|||
// the extension of the segment. If lines are parallel or coincident then
|
||||
// it returns undef.
|
||||
|
||||
function _general_line_intersection(s1,s2,eps=EPSILON) =
|
||||
function _general_line_intersection(s1,s2,eps=_EPSILON) =
|
||||
let(
|
||||
denominator = cross(s1[0]-s1[1],s2[0]-s2[1])
|
||||
)
|
||||
|
|
@ -281,7 +284,7 @@ function _general_line_intersection(s1,s2,eps=EPSILON) =
|
|||
// bounded2 = boolean or list of two booleans defining which ends are bounded for line2. Default: [false,false]
|
||||
// ---
|
||||
// bounded = boolean or list of two booleans defining which ends are bounded for both lines. The bounded1 and bounded2 parameters override this if both are given.
|
||||
// eps = tolerance for geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = tolerance for geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D): The segments do not intersect but the lines do in this example.
|
||||
// line1 = 10*[[9, 4], [5, 7]];
|
||||
// line2 = 10*[[2, 3], [6, 5]];
|
||||
|
|
@ -302,7 +305,7 @@ function _general_line_intersection(s1,s2,eps=EPSILON) =
|
|||
// stroke(line1);
|
||||
// stroke(line2);
|
||||
// isect = line_intersection(line1, line2, bounded=true); // Returns undef
|
||||
function line_intersection(line1, line2, bounded1, bounded2, bounded, eps=EPSILON) =
|
||||
function line_intersection(line1, line2, bounded1, bounded2, bounded, eps=_EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." )
|
||||
assert( _valid_line(line1,dim=2,eps=eps), "\nFirst line invalid.")
|
||||
assert( _valid_line(line2,dim=2,eps=eps), "\nSecond line invalid.")
|
||||
|
|
@ -421,7 +424,7 @@ function line_closest_point(line, pt, bounded=false) =
|
|||
// Arguments:
|
||||
// points = The list of points to find the line through.
|
||||
// check_collinear = If true, don't verify that all points are collinear. Default: false
|
||||
// eps = How much variance is allowed in testing each point against the line. Default: `EPSILON` (1e-9)
|
||||
// eps = How much variance is allowed in testing each point against the line. Default: `_EPSILON` (1e-9)
|
||||
// Example(FlatSpin,VPD=250): A line fitted to a cloud of points.
|
||||
// points = rot(45, v=[-0.5,1,0],
|
||||
// p=random_points(100,3,scale=[5,5,50],seed=47));
|
||||
|
|
@ -434,7 +437,7 @@ function _line_greatest_distance(points,line) = // internal function
|
|||
: let(d = [ for(p=points) point_line_distance(p, line) ])
|
||||
max(d);
|
||||
|
||||
function line_from_points(points, check_collinear=false, eps=EPSILON, fast) =
|
||||
function line_from_points(points, check_collinear=false, eps=_EPSILON, fast) =
|
||||
assert( is_path(points), "\nInvalid point list." )
|
||||
assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." )
|
||||
len(points) == 2
|
||||
|
|
@ -468,8 +471,8 @@ function line_from_points(points, check_collinear=false, eps=EPSILON, fast) =
|
|||
// Returns true if the given 3D points are non-collinear and are on a plane.
|
||||
// Arguments:
|
||||
// points = The points to test.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function is_coplanar(points, eps=EPSILON) =
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function is_coplanar(points, eps=_EPSILON) =
|
||||
assert( is_path(points,dim=3) , "\nInput should be a list of 3D points." )
|
||||
assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a non-negative value." )
|
||||
len(points)<=2 ? false
|
||||
|
|
@ -560,7 +563,7 @@ function plane_from_normal(normal, pt=[0,0,0]) =
|
|||
// Based on: https://en.wikipedia.org/wiki/Eigenvalue_algorithm
|
||||
function _eigenvals_symm_3(M) =
|
||||
let( p1 = pow(M[0][1],2) + pow(M[0][2],2) + pow(M[1][2],2) )
|
||||
(p1<EPSILON)
|
||||
(p1<_EPSILON)
|
||||
? -sort(-[ M[0][0], M[1][1], M[2][2] ]) // diagonal matrix: eigenvals in decreasing order
|
||||
: let( q = (M[0][0]+M[1][1]+M[2][2])/3,
|
||||
B = (M - q*ident(3)),
|
||||
|
|
@ -584,7 +587,7 @@ function _eigenvec_symm_3(M,evals,i=0) =
|
|||
A = (M - evals[(i+1)%3]*I) * (M - evals[(i+2)%3]*I) ,
|
||||
k = max_index( [for(i=[0:2]) norm(A[i]) ])
|
||||
)
|
||||
norm(A[k])<EPSILON ? I[k] : A[k]/norm(A[k]);
|
||||
norm(A[k])<_EPSILON ? I[k] : A[k]/norm(A[k]);
|
||||
|
||||
|
||||
// finds the eigenvector corresponding to the smallest eigenvalue of the covariance matrix of a pointlist
|
||||
|
|
@ -615,7 +618,7 @@ function _covariance_evec_eval(points, eigenvalue_id) =
|
|||
// Arguments:
|
||||
// points = The list of points to find the best-fit plane.
|
||||
// check_coplanar = If true, verify the point coplanarity within `eps` tolerance. Default: false
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(FlatSpin,VPD=320,VPT=[-2,5,-2]): 100 non-coplanar random points (yellow spheres) distributed in a volume, showing the best-fit plane (transparent square) with its normal vector.
|
||||
// points = rot(45, v=[-0.3,1,0],
|
||||
// p=random_points(100,3,scale=[50,50,15],seed=47));
|
||||
|
|
@ -626,7 +629,7 @@ function _covariance_evec_eval(points, eigenvalue_id) =
|
|||
// color("#06f") anchor_arrow(50, flag=false);
|
||||
// %linear_extrude(0.1) square(100, center=true);
|
||||
// }
|
||||
function plane_from_points(points, check_coplanar=false, eps=EPSILON, fast) =
|
||||
function plane_from_points(points, check_coplanar=false, eps=_EPSILON, fast) =
|
||||
assert( is_path(points,dim=3), "\nImproper 3d point list." )
|
||||
assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." )
|
||||
len(points) == 3
|
||||
|
|
@ -660,14 +663,14 @@ function plane_from_points(points, check_coplanar=false, eps=EPSILON, fast) =
|
|||
// Arguments:
|
||||
// poly = The planar 3D polygon to find the plane of.
|
||||
// check_coplanar = If false, doesn't verify that all points in the polygon are coplanar. Default: true
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(3D):
|
||||
// xyzpath = rot(45, v=[0,1,0], p=path3d(star(n=5,step=2,d=100), 70));
|
||||
// plane = plane_from_polygon(xyzpath);
|
||||
// #stroke(xyzpath,closed=true,width=3);
|
||||
// cp = centroid(xyzpath);
|
||||
// move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow(45);
|
||||
function plane_from_polygon(poly, check_coplanar=true, eps=EPSILON, fast) =
|
||||
function plane_from_polygon(poly, check_coplanar=true, eps=_EPSILON, fast) =
|
||||
assert( is_path(poly,dim=3), "\nInvalid polygon." )
|
||||
assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." )
|
||||
let(
|
||||
|
|
@ -718,7 +721,7 @@ function plane_offset(plane) =
|
|||
// Returns [POINT, U] if line intersects plane at one point, where U is zero at line[0] and 1 at line[1]
|
||||
// Returns [LINE, undef] if the line is on the plane.
|
||||
// Returns undef if line is parallel to, but not on the given plane.
|
||||
function _general_plane_line_intersection(plane, line, eps=EPSILON) =
|
||||
function _general_plane_line_intersection(plane, line, eps=_EPSILON) =
|
||||
let(
|
||||
a = plane*[each line[0],-1], // evaluation of the plane expression at line[0]
|
||||
b = plane*[each(line[1]-line[0]),0] // difference between the plane expression evaluation at line[1] and at line[0]
|
||||
|
|
@ -756,8 +759,8 @@ function _normalize_plane(plane) =
|
|||
// plane = The [A,B,C,D] values for the equation of the plane.
|
||||
// line = A list of two distinct 3D points that are on the line.
|
||||
// bounded = If false, the line is considered unbounded. If true, it is treated as a bounded line segment. If given as `[true, false]` or `[false, true]`, the boundedness of the points are specified individually, allowing the line to be treated as a half-bounded ray. Default: false (unbounded)
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) =
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function plane_line_intersection(plane, line, bounded=false, eps=_EPSILON) =
|
||||
assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." )
|
||||
assert(_valid_plane(plane,eps=eps) && _valid_line(line,dim=3,eps=eps), "\nInvalid plane and/or 3d line.")
|
||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition.")
|
||||
|
|
@ -912,8 +915,8 @@ function _pointlist_greatest_distance(points,plane) =
|
|||
// Arguments:
|
||||
// plane = The plane to test the points on.
|
||||
// points = The list of 3D points to test.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function are_points_on_plane(points, plane, eps=EPSILON) =
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function are_points_on_plane(points, plane, eps=_EPSILON) =
|
||||
assert( _valid_plane(plane), "\nInvalid plane." )
|
||||
assert( is_matrix(points,undef,3) && len(points)>0, "\nInvalid pointlist." ) // using is_matrix it accepts len(points)==1
|
||||
assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." )
|
||||
|
|
@ -933,7 +936,7 @@ function are_points_on_plane(points, plane, eps=EPSILON) =
|
|||
/// plane = The [A,B,C,D] coefficients for the first plane equation `Ax+By+Cz=D`.
|
||||
/// point = The 3D point to test.
|
||||
function _is_point_above_plane(plane, point) =
|
||||
point_plane_distance(plane, point) > EPSILON;
|
||||
point_plane_distance(plane, point) > _EPSILON;
|
||||
|
||||
|
||||
// Module: show_plane()
|
||||
|
|
@ -1028,14 +1031,14 @@ module show_plane(plane, size, offset=0)
|
|||
// color("black") stroke(line, endcaps="arrow2", width=0.5);
|
||||
// isects = circle_line_intersection(r=r, cp=cp, line=line);
|
||||
// color("#f44") move_copies(isects) circle(d=1);
|
||||
function circle_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) =
|
||||
function circle_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) =
|
||||
assert(_valid_line(line,2), "\nInvalid 2d line.")
|
||||
assert(is_vector(cp,2), "\nCircle center must be a 2-vector")
|
||||
_circle_or_sphere_line_intersection(r, cp, line, bounded, d, eps);
|
||||
|
||||
|
||||
|
||||
function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) =
|
||||
function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) =
|
||||
let(r=get_radius(r=r,d=d,dflt=undef))
|
||||
assert(is_num(r) && r>0, "\nRadius must be positive")
|
||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition")
|
||||
|
|
@ -1071,7 +1074,7 @@ function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=
|
|||
// cp1 = Centerpoint of the first circle.
|
||||
// r2 = Radius of the second circle.
|
||||
// cp2 = Centerpoint of the second circle.
|
||||
// eps = Tolerance for detecting tangent circles. Default: EPSILON
|
||||
// eps = Tolerance for detecting tangent circles. Default: _EPSILON
|
||||
// ---
|
||||
// d1 = Diameter of the first circle.
|
||||
// d2 = Diameter of the second circle.
|
||||
|
|
@ -1107,7 +1110,7 @@ function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=
|
|||
// move(cp1) stroke(circle(r=r1), width=0.2, closed=true);
|
||||
// move(cp2) stroke(circle(r=r2), width=0.2, closed=true);
|
||||
// color("red") move_copies(pts) circle(r=.3);
|
||||
function circle_circle_intersection(r1, cp1, r2, cp2, eps=EPSILON, d1, d2) =
|
||||
function circle_circle_intersection(r1, cp1, r2, cp2, eps=_EPSILON, d1, d2) =
|
||||
assert( is_path([cp1,cp2],dim=2), "\nInvalid center point(s)." )
|
||||
let(
|
||||
r1 = get_radius(r1=r1,d1=d1),
|
||||
|
|
@ -1418,8 +1421,8 @@ function circle_circle_tangents(r1, cp1, r2, cp2, d1, d2) =
|
|||
/// Arguments:
|
||||
/// points = List of input points.
|
||||
/// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`.
|
||||
/// eps = Tolerance for collinearity test. Default: EPSILON.
|
||||
function _noncollinear_triple(points,error=true,eps=EPSILON) =
|
||||
/// eps = Tolerance for collinearity test. Default: _EPSILON.
|
||||
function _noncollinear_triple(points,error=true,eps=_EPSILON) =
|
||||
assert( is_path(points), "\nInvalid input points." )
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
len(points)<3 ? [] :
|
||||
|
|
@ -1468,7 +1471,7 @@ function _noncollinear_triple(points,error=true,eps=EPSILON) =
|
|||
// color("cyan") stroke(line);
|
||||
// move(cp) sphere(r=r, $fn=72);
|
||||
// color("red") move_copies(isects) sphere(d=3, $fn=12);
|
||||
function sphere_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) =
|
||||
function sphere_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) =
|
||||
assert(_valid_line(line,3), "\nInvalid 3d line.")
|
||||
assert(is_vector(cp,3), "\nSphere center must be a 3-vector")
|
||||
_circle_or_sphere_line_intersection(r, cp, line, bounded, d, eps);
|
||||
|
|
@ -1543,7 +1546,7 @@ function polygon_area(poly, signed=false) =
|
|||
// linear_extrude(height=0.01) polygon(path);
|
||||
// cp = centroid(path);
|
||||
// color("red") move(cp) sphere(d=2);
|
||||
function centroid(object,eps=EPSILON) =
|
||||
function centroid(object,eps=_EPSILON) =
|
||||
assert(is_finite(eps) && (eps>=0), "\nThe tolerance should a non-negative value." )
|
||||
is_vnf(object) ? _vnf_centroid(object,eps)
|
||||
: is_path(object,[2,3]) ? _polygon_centroid(object,eps)
|
||||
|
|
@ -1553,7 +1556,7 @@ function centroid(object,eps=EPSILON) =
|
|||
|
||||
/// Internal Function: _region_centroid()
|
||||
/// Compute centroid of region
|
||||
function _region_centroid(region,eps=EPSILON) =
|
||||
function _region_centroid(region,eps=_EPSILON) =
|
||||
let(
|
||||
region=force_region(region),
|
||||
parts = region_parts(region),
|
||||
|
|
@ -1578,8 +1581,8 @@ function _region_centroid(region,eps=EPSILON) =
|
|||
/// polygons or an error is produced.
|
||||
/// Arguments:
|
||||
/// poly = Points of the polygon from which the centroid is calculated.
|
||||
/// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function _polygon_centroid(poly, eps=EPSILON) =
|
||||
/// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
function _polygon_centroid(poly, eps=_EPSILON) =
|
||||
assert( is_path(poly,dim=[2,3]), "\nThe input must be a 2D or 3D polygon." )
|
||||
let(
|
||||
n = len(poly[0])==2 ? 1 :
|
||||
|
|
@ -1680,7 +1683,7 @@ function polygon_normal(poly) =
|
|||
// point = The 2D point to check
|
||||
// poly = The list of 2D points forming the perimeter of the polygon.
|
||||
// nonzero = The rule to use: true for "Nonzero" rule and false for "Even-Odd". Default: false (Even-Odd)
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D): With nonzero set to false (the default), we get this result. Green dots are inside the polygon and red are outside:
|
||||
// a=20*2/3;
|
||||
// b=30*2/3;
|
||||
|
|
@ -1723,7 +1726,7 @@ function _point_above_below_segment(point, edge) =
|
|||
: (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0;
|
||||
|
||||
|
||||
function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
||||
function point_in_polygon(point, poly, nonzero=false, eps=_EPSILON) =
|
||||
// Original algorithms from http://geomalgorithms.com/a03-_inclusion.html
|
||||
assert( is_vector(point,2) && is_path(poly,dim=2) && len(poly)>2,
|
||||
"\nThe point and polygon should be in 2D. The polygon should have more that 2 points." )
|
||||
|
|
@ -1802,7 +1805,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// line = A list of two distinct 3D points on the line.
|
||||
// bounded = If false, the line is considered unbounded. If true, it is treated as a bounded line segment. If given as `[true, false]` or `[false, true]`, the boundedness of the points are specified individually, allowing the line to be treated as a half-bounded ray. Default: false (unbounded)
|
||||
// nonzero = set to true to use the nonzero rule for determining it points are in a polygon. See point_in_polygon. Default: false.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(3D): The line intersects the 3d hexagon in a single point.
|
||||
// hex = zrot(140,p=rot([-45,40,20],p=path3d(hexagon(r=15))));
|
||||
// line = [[5,0,-13],[-3,-5,13]];
|
||||
|
|
@ -1906,7 +1909,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// move(part[0]) circle(r=1,$fn=12);
|
||||
// else
|
||||
// stroke(part);
|
||||
function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=EPSILON) =
|
||||
function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=_EPSILON) =
|
||||
assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." )
|
||||
assert(is_path(poly,dim=[2,3]), "\nInvalid polygon." )
|
||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition.")
|
||||
|
|
@ -2000,7 +2003,7 @@ function _merge_segments(insegs,outsegs, eps, i=1) =
|
|||
// poly = Array of the polygon vertices.
|
||||
// ind = If given, a list of indices indexing the vertices of the polygon in `poly`. Default: use all the points of poly
|
||||
// error = If false, returns `undef` when the polygon cannot be triangulated; otherwise, issues an assert error. Default: true.
|
||||
// eps = A maximum tolerance in geometrical tests. Default: EPSILON
|
||||
// eps = A maximum tolerance in geometrical tests. Default: _EPSILON
|
||||
// Example(2D,NoAxes): a simple polygon; see from above
|
||||
// poly = star(id=10, od=15,n=11);
|
||||
// tris = polygon_triangulate(poly);
|
||||
|
|
@ -2037,7 +2040,7 @@ function _merge_segments(insegs,outsegs, eps, i=1) =
|
|||
// vnf_tri = [vnf[0], [for(face=vnf[1]) each polygon_triangulate(vnf[0], face) ] ];
|
||||
// color("blue")
|
||||
// vnf_wireframe(vnf_tri, width=.15);
|
||||
function polygon_triangulate(poly, ind, error=true, eps=EPSILON) =
|
||||
function polygon_triangulate(poly, ind, error=true, eps=_EPSILON) =
|
||||
assert(is_path(poly) && len(poly)>=3, "\nPolygon `poly` should be a list of at least three 2d or 3d points")
|
||||
assert(is_undef(ind) || (is_vector(ind) && min(ind)>=0 && max(ind)<len(poly) ),
|
||||
"Improper or out of bounds list of indices")
|
||||
|
|
@ -2086,7 +2089,7 @@ function polygon_triangulate(poly, ind, error=true, eps=EPSILON) =
|
|||
// implements a modified version of ear cut method for non-twisted polygons
|
||||
// the polygons accepted by this function are those decomposable in simple
|
||||
// CW polygons.
|
||||
function _triangulate(poly, ind, error, eps=EPSILON, tris=[]) =
|
||||
function _triangulate(poly, ind, error, eps=_EPSILON, tris=[]) =
|
||||
len(ind)==3
|
||||
? _degenerate_tri(select(poly,ind),eps)
|
||||
? tris // if last 3 pts perform a degenerate triangle, ignore it
|
||||
|
|
@ -2349,7 +2352,7 @@ function align_polygon(reference, poly, angles, cp, trans, return_ind=false) =
|
|||
],
|
||||
scores = column(alignments,1),
|
||||
minscore = min(scores),
|
||||
minind = [for(i=idx(scores)) if (scores[i]<minscore+EPSILON) i],
|
||||
minind = [for(i=idx(scores)) if (scores[i]<minscore+_EPSILON) i],
|
||||
dummy = is_def(angles) ? echo(best_angles = select(list(angles), minind)):0,
|
||||
best = minind[0]
|
||||
)
|
||||
|
|
@ -2375,7 +2378,7 @@ function align_polygon(reference, poly, angles, cp, trans, return_ind=false) =
|
|||
// rot(360/5, p=pentagon(r=4))); // returns true
|
||||
// are_polygons_equal(pentagon(r=4),
|
||||
// rot(90, p=pentagon(r=4))); // returns false
|
||||
function are_polygons_equal(poly1, poly2, eps=EPSILON) =
|
||||
function are_polygons_equal(poly1, poly2, eps=_EPSILON) =
|
||||
let(
|
||||
poly1 = list_unwrap(poly1),
|
||||
poly2 = list_unwrap(poly2),
|
||||
|
|
@ -2497,8 +2500,8 @@ function _backtracking(i,points,h,t,m,all) =
|
|||
|
||||
// clockwise check (2d)
|
||||
function _is_cw(a,b,c,all) =
|
||||
all ? cross(a-c,b-c)<=EPSILON*norm(a-c)*norm(b-c) :
|
||||
cross(a-c,b-c)<-EPSILON*norm(a-c)*norm(b-c);
|
||||
all ? cross(a-c,b-c)<=_EPSILON*norm(a-c)*norm(b-c) :
|
||||
cross(a-c,b-c)<-_EPSILON*norm(a-c)*norm(b-c);
|
||||
|
||||
|
||||
// Function: hull2d_path()
|
||||
|
|
@ -2624,7 +2627,7 @@ function hull3d_faces(points) =
|
|||
|
||||
|
||||
// Adds the remaining points one by one to the convex hull
|
||||
function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let( EPSILON=1e-12 )
|
||||
function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let( _EPSILON=1e-12 )
|
||||
_i >= len(remaining) ? triangles :
|
||||
let (
|
||||
// pick a point
|
||||
|
|
@ -2632,7 +2635,7 @@ function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let(
|
|||
// evaluate the triangle plane equations at point i
|
||||
planeq_val = planes*[each points[i], -1],
|
||||
// find the triangles that are in conflict with the point (point not inside)
|
||||
conflicts = [for (i = [0:1:len(planeq_val)-1]) if (planeq_val[i]>EPSILON) i ],
|
||||
conflicts = [for (i = [0:1:len(planeq_val)-1]) if (planeq_val[i]>_EPSILON) i ],
|
||||
// collect the halfedges of all triangles that are in conflict
|
||||
halfedges = [
|
||||
for(c = conflicts, i = [0:2])
|
||||
|
|
@ -2645,12 +2648,12 @@ function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let(
|
|||
// add tria2add and remove conflict triangles
|
||||
new_triangles =
|
||||
concat( tri2add,
|
||||
[ for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=EPSILON) triangles[i] ]
|
||||
[ for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=_EPSILON) triangles[i] ]
|
||||
),
|
||||
// add the plane equations of new added triangles and remove the plane equations of the conflict ones
|
||||
new_planes =
|
||||
[ for (t = tri2add) plane3pt_indexed(points, t[0], t[1], t[2]) ,
|
||||
for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=EPSILON) planes[i] ]
|
||||
for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=_EPSILON) planes[i] ]
|
||||
) _hull3d_iterative(
|
||||
points,
|
||||
new_triangles,
|
||||
|
|
@ -2692,13 +2695,13 @@ function _find_first_noncoplanar(plane, points, i=0) =
|
|||
// If the points are collinear or not coplanar an error may be generated.
|
||||
// Arguments:
|
||||
// poly = Polygon to check.
|
||||
// eps = Tolerance for the collinearity and coplanarity tests. Default: EPSILON.
|
||||
// eps = Tolerance for the collinearity and coplanarity tests. Default: _EPSILON.
|
||||
// Example:
|
||||
// test1 = is_polygon_convex(circle(d=50)); // Returns: true
|
||||
// test2 = is_polygon_convex(rot([50,120,30], p=path3d(circle(1,$fn=50)))); // Returns: true
|
||||
// spiral = [for (i=[0:36]) let(a=-i*10) (10+i)*[cos(a),sin(a)]];
|
||||
// test = is_polygon_convex(spiral); // Returns: false
|
||||
function is_polygon_convex(poly,eps=EPSILON) =
|
||||
function is_polygon_convex(poly,eps=_EPSILON) =
|
||||
assert(is_path(poly), "\nThe input should be a 2D or 3D polygon." )
|
||||
let(
|
||||
lp = len(poly),
|
||||
|
|
@ -2741,7 +2744,7 @@ function is_polygon_convex(poly,eps=EPSILON) =
|
|||
// Arguments:
|
||||
// points1 = first list of 2d or 3d points.
|
||||
// points2 = second list of 2d or 3d points.
|
||||
// eps = tolerance in distance evaluations. Default: EPSILON.
|
||||
// eps = tolerance in distance evaluations. Default: _EPSILON.
|
||||
// Example(2D):
|
||||
// pts1 = move([-3,0], p=square(3,center=true));
|
||||
// pts2 = rot(a=45, p=square(2,center=true));
|
||||
|
|
@ -2759,7 +2762,7 @@ function is_polygon_convex(poly,eps=EPSILON) =
|
|||
// vnf_polyhedron(sphr2);
|
||||
// echo(convex_distance(sphr1[0], sphr2[0])); // Returns: 0
|
||||
// echo(convex_distance(sphr1[0], sphr3[0])); // Returns: 0.5
|
||||
function convex_distance(points1, points2, eps=EPSILON) =
|
||||
function convex_distance(points1, points2, eps=_EPSILON) =
|
||||
assert(is_matrix(points1) && is_matrix(points2,undef,len(points1[0])),
|
||||
"\nThe input lists should be compatible consistent non empty lists of points.")
|
||||
assert(len(points1[0])==2 || len(points1[0])==3 ,
|
||||
|
|
@ -2773,7 +2776,7 @@ function convex_distance(points1, points2, eps=EPSILON) =
|
|||
// Finds the vector difference between the hulls of the two pointsets by the GJK algorithm
|
||||
// Based on:
|
||||
// http://www.dtecta.com/papers/jgt98convex.pdf
|
||||
function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) =
|
||||
function _GJK_distance(points1, points2, eps=_EPSILON, lbd, d, simplex=[]) =
|
||||
let( nrd = norm(d) ) // distance upper bound
|
||||
nrd<eps ? d :
|
||||
let(
|
||||
|
|
@ -2801,7 +2804,7 @@ function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) =
|
|||
// Arguments:
|
||||
// points1 = first list of 2d or 3d points.
|
||||
// points2 = second list of 2d or 3d points.
|
||||
// eps - tolerance for the intersection tests. Default: EPSILON.
|
||||
// eps - tolerance for the intersection tests. Default: _EPSILON.
|
||||
// Example(2D):
|
||||
// pts1 = move([-3,0], p=square(3,center=true));
|
||||
// pts2 = rot(a=45, p=square(2,center=true));
|
||||
|
|
@ -2820,7 +2823,7 @@ function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) =
|
|||
// echo(convex_collision(sphr1[0], sphr2[0])); // Returns: true
|
||||
// echo(convex_collision(sphr1[0], sphr3[0])); // Returns: false
|
||||
//
|
||||
function convex_collision(points1, points2, eps=EPSILON) =
|
||||
function convex_collision(points1, points2, eps=_EPSILON) =
|
||||
assert(is_matrix(points1) && is_matrix(points2,undef,len(points1[0])),
|
||||
"\nThe input lists should be compatible consistent non empty lists of points.")
|
||||
assert(len(points1[0])==2 || len(points1[0])==3 ,
|
||||
|
|
@ -2835,7 +2838,7 @@ function convex_collision(points1, points2, eps=EPSILON) =
|
|||
// http://uu.diva-portal.org/smash/get/diva2/FFULLTEXT01.pdf
|
||||
// or
|
||||
// http://www.dtecta.com/papers/jgt98convex.pdf
|
||||
function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) =
|
||||
function _GJK_collide(points1, points2, d, simplex, eps=_EPSILON) =
|
||||
norm(d) < eps ? true : // does collide
|
||||
let( v = _support_diff(points1,points2,-d) )
|
||||
v*d > eps*eps ? false : // no collision
|
||||
|
|
@ -2847,7 +2850,7 @@ function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) =
|
|||
// given a simplex s, returns a pair:
|
||||
// - the point of the s closest to the origin
|
||||
// - the smallest sub-simplex of s that contains that point
|
||||
function _closest_simplex(s,eps=EPSILON) =
|
||||
function _closest_simplex(s,eps=_EPSILON) =
|
||||
len(s)==2 ? _closest_s1(s,eps) :
|
||||
len(s)==3 ? _closest_s2(s,eps) :
|
||||
len(s)==4 ? _closest_s3(s,eps) :
|
||||
|
|
@ -2855,7 +2858,7 @@ function _closest_simplex(s,eps=EPSILON) =
|
|||
|
||||
|
||||
// find the point of a 1-simplex closest to the origin
|
||||
function _closest_s1(s,eps=EPSILON) =
|
||||
function _closest_s1(s,eps=_EPSILON) =
|
||||
norm(s[1]-s[0])<=eps*(norm(s[0])+norm(s[1]))/2 ? [ s[0], [s[0]] ] :
|
||||
let(
|
||||
c = s[1]-s[0],
|
||||
|
|
@ -2867,7 +2870,7 @@ function _closest_s1(s,eps=EPSILON) =
|
|||
|
||||
|
||||
// find the point of a 2-simplex closest to the origin
|
||||
function _closest_s2(s, eps=EPSILON) =
|
||||
function _closest_s2(s, eps=_EPSILON) =
|
||||
// considering that s[2] was the last inserted vertex in s by GJK,
|
||||
// the plane orthogonal to the triangle [ origin, s[0], s[1] ] that
|
||||
// contains [s[0],s[1]] have the origin and s[2] on the same side;
|
||||
|
|
@ -2898,7 +2901,7 @@ function _closest_s2(s, eps=EPSILON) =
|
|||
|
||||
|
||||
// find the point of a 3-simplex closest to the origin
|
||||
function _closest_s3(s,eps=EPSILON) =
|
||||
function _closest_s3(s,eps=_EPSILON) =
|
||||
let( nr = cross(s[1]-s[0],s[2]-s[0]),
|
||||
sz = [ norm(s[0]-s[1]), norm(s[1]-s[2]), norm(s[2]-s[0]) ] )
|
||||
norm(nr)<=eps*pow(max(sz),2)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
// FileSummary: Hinges and snap-locking hinged parts.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_HINGES = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: hinges.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
include <rounding.scad>
|
||||
include <screws.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
// FileSummary: Hooks and hook-like parts.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_HOOKS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: hooks.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Module: ring_hook()
|
||||
// Synopsis: A hook with a circular hole or attached cylinder
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@
|
|||
// FileSummary: Isosurfaces and metaballs.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_ISOSURFACE = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: isosurface.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
//////////////////// 3D initializations and support functions ////////////////////
|
||||
|
||||
|
|
@ -790,12 +793,12 @@ function _bbox_faces(v0, voxsize, bbox) = let(
|
|||
bb1 = bbox[1] - voxsize,
|
||||
b = v0-bb1
|
||||
) [
|
||||
if(a[0]<EPSILON) 1,
|
||||
if(a[1]<EPSILON) 2,
|
||||
if(a[2]<EPSILON) 3,
|
||||
if(b[0]>=-EPSILON) 4,
|
||||
if(b[1]>=-EPSILON) 5,
|
||||
if(b[2]>=-EPSILON) 6
|
||||
if(a[0]<_EPSILON) 1,
|
||||
if(a[1]<_EPSILON) 2,
|
||||
if(a[2]<_EPSILON) 3,
|
||||
if(b[0]>=-_EPSILON) 4,
|
||||
if(b[1]>=-_EPSILON) 5,
|
||||
if(b[2]>=-_EPSILON) 6
|
||||
];
|
||||
/// End of bounding-box face-clipping stuff
|
||||
/// -----------------------------------------------------------
|
||||
|
|
@ -1111,10 +1114,10 @@ function _bbox_sides(pc, pixsize, bbox) = let(
|
|||
bb1 = bbox[1] - pixsize,
|
||||
b = pc-bb1
|
||||
) [
|
||||
if(a[0]<EPSILON) 0,
|
||||
if(a[1]<EPSILON) 3,
|
||||
if(b[0]>=-EPSILON) 2,
|
||||
if(b[1]>=-EPSILON) 1
|
||||
if(a[0]<_EPSILON) 0,
|
||||
if(a[1]<_EPSILON) 3,
|
||||
if(b[0]>=-_EPSILON) 2,
|
||||
if(b[1]>=-_EPSILON) 1
|
||||
];
|
||||
|
||||
|
||||
|
|
@ -1142,10 +1145,10 @@ function _contour_pixels(pixsize, bbox, fieldarray, fieldfunc, pixcenters, isova
|
|||
let(i1=i+1, j1=j+1,
|
||||
pf = let(
|
||||
// clamp corner values to ±1e9, make sure no corner=isovalmin or isovalmax
|
||||
f0=let(c=min(1e9,max(-1e9,field[i][j]))) abs(c-isovalmin)<EPSILON ? isocorrectmin : abs(c-isovalmax)<EPSILON ? isocorrectmax : c,
|
||||
f1=let(c=min(1e9,max(-1e9,field[i][j1]))) abs(c-isovalmin)<EPSILON ? isocorrectmin : abs(c-isovalmax)<EPSILON ? isocorrectmax : c,
|
||||
f2=let(c=min(1e9,max(-1e9,field[i1][j]))) abs(c-isovalmin)<EPSILON ? isocorrectmin : abs(c-isovalmax)<EPSILON ? isocorrectmax : c,
|
||||
f3=let(c=min(1e9,max(-1e9,field[i1][j1]))) abs(c-isovalmin)<EPSILON ? isocorrectmin : abs(c-isovalmax)<EPSILON ? isocorrectmax : c
|
||||
f0=let(c=min(1e9,max(-1e9,field[i][j]))) abs(c-isovalmin)<_EPSILON ? isocorrectmin : abs(c-isovalmax)<_EPSILON ? isocorrectmax : c,
|
||||
f1=let(c=min(1e9,max(-1e9,field[i][j1]))) abs(c-isovalmin)<_EPSILON ? isocorrectmin : abs(c-isovalmax)<_EPSILON ? isocorrectmax : c,
|
||||
f2=let(c=min(1e9,max(-1e9,field[i1][j]))) abs(c-isovalmin)<_EPSILON ? isocorrectmin : abs(c-isovalmax)<_EPSILON ? isocorrectmax : c,
|
||||
f3=let(c=min(1e9,max(-1e9,field[i1][j1]))) abs(c-isovalmin)<_EPSILON ? isocorrectmin : abs(c-isovalmax)<_EPSILON ? isocorrectmax : c
|
||||
) [ // pixel corner field values
|
||||
f0, f1, f2, f3,
|
||||
// get center value of pixel
|
||||
|
|
@ -1335,7 +1338,7 @@ function _revsurf_basic(point, path, coef, neg, maxdist) =
|
|||
: t>1 ? norm(seg[1]-pt)
|
||||
: norm(s0+t*c)]),
|
||||
inside = [] == [for(seg=segs)
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > EPSILON) 1]
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > _EPSILON) 1]
|
||||
? -1 : 1
|
||||
)
|
||||
neg * coef / (max(0,inside*dist+maxdist));
|
||||
|
|
@ -1354,7 +1357,7 @@ function _revsurf_influence(point, path, coef, exp, neg, maxdist) =
|
|||
: t>1 ? norm(seg[1]-pt)
|
||||
: norm(s0+t*c)]),
|
||||
inside = [] == [for(seg=segs)
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > EPSILON) 1]
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > _EPSILON) 1]
|
||||
? -1 : 1
|
||||
)
|
||||
neg * (coef / (max(0,inside*dist+maxdist)))^exp;
|
||||
|
|
@ -1373,7 +1376,7 @@ function _revsurf_cutoff(point, path, coef, cutoff, neg, maxdist) =
|
|||
: t>1 ? norm(seg[1]-pt)
|
||||
: norm(s0+t*c)]),
|
||||
inside = [] == [for(seg=segs)
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > EPSILON) 1]
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > _EPSILON) 1]
|
||||
? -1 : 1,
|
||||
d=max(0,inside*dist+maxdist)
|
||||
)
|
||||
|
|
@ -1393,7 +1396,7 @@ function _revsurf_full(point, path, coef, cutoff, exp, neg, maxdist) =
|
|||
: t>1 ? norm(seg[1]-pt)
|
||||
: norm(s0+t*c)]),
|
||||
inside = [] == [for(seg=segs)
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > EPSILON) 1]
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > _EPSILON) 1]
|
||||
? -1 : 1,
|
||||
d=max(0,inside*dist+maxdist)
|
||||
)
|
||||
|
|
@ -2538,7 +2541,7 @@ function metaballs(spec, bounding_box, voxel_size, voxel_count, isovalue=1, clos
|
|||
allpts = [for(x=xset, y=yset, z=zset) [x,y,z,1]],
|
||||
trans_pts = [for(i=[0:nballs-1]) allpts*transmatrix[i]],
|
||||
allvals = [for(i=[0:nballs-1]) [for(pt=trans_pts[i]) funclist[2*i+1][0](pt)]],
|
||||
//total = _sum(allvals,allvals[0]*EPSILON),
|
||||
//total = _sum(allvals,allvals[0]*_EPSILON),
|
||||
total = _sum(slice(allvals,1,-1), allvals[0]),
|
||||
fieldarray = list_to_matrix(list_to_matrix(total,len(zset)),len(yset)),
|
||||
surface = isosurface(fieldarray, isoval, newbbox, voxsize, closed=closed, exact_bounds=true, show_stats=show_stats, _mball=true)
|
||||
|
|
@ -2640,7 +2643,7 @@ function _trapsurf_full(point, path, coef, cutoff, exp, neg, maxdist) =
|
|||
: t>1 ? norm(seg[1]-pt)
|
||||
: norm(s0+t*c)]),
|
||||
inside = [] == [for(seg=segs)
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > EPSILON) 1]
|
||||
if (cross(seg[1]-seg[0], pt-seg[0]) > _EPSILON) 1]
|
||||
? -1 : 1,
|
||||
d=max(0,inside*dist+maxdist)
|
||||
)
|
||||
|
|
@ -2710,10 +2713,10 @@ function mb_stadium(size, cutoff=INF, influence=1, negative=false, hide_debug=fa
|
|||
sl = length-2*r, // straight side length
|
||||
//dum3 = assert(sl>=0, "\nTotal length must accommodate rounded ends of rectangle."),
|
||||
neg = negative ? -1 : 1,
|
||||
poly = abs(shape)<=EPSILON ? [neg, hide_debug ? circle(r=0.02, $fn=3) : circle(r=r, $fn=20)]
|
||||
poly = abs(shape)<=_EPSILON ? [neg, hide_debug ? circle(r=0.02, $fn=3) : circle(r=r, $fn=20)]
|
||||
: shape>0 ? [neg, hide_debug ? square(0.02,center=true) : rect([2*r,length], rounding=0.999*r, $fn=20)]
|
||||
: [neg, hide_debug ? square(0.02,center=true) : rect([length,2*r], rounding=0.999*r, $fn=20)]
|
||||
) abs(shape)<EPSILON ?
|
||||
) abs(shape)<_EPSILON ?
|
||||
[function (dv) _mb_circle_full(dv, r, cutoff, 1/influence, neg), poly]
|
||||
: shape>0 ? [function (dv) _mb_stadium_full(dv, sl/2, r, cutoff, 1/influence, neg), poly]
|
||||
: [function (dv) _mb_stadium_sideways_full(dv, sl/2, r, cutoff, 1/influence, neg), poly];
|
||||
|
|
@ -3102,7 +3105,7 @@ function _metaballs2dfield(funclist, transmatrix, bbox, pixsize, nballs) = let(
|
|||
allpts = [for(x=xset, y=yset) [x,y,0,1]],
|
||||
trans_pts = [for(i=[0:nballs-1]) allpts*transmatrix[i]],
|
||||
allvals = [for(i=[0:nballs-1]) [for(pt=trans_pts[i]) funclist[2*i+1][0](pt)]],
|
||||
//total = _sum(allvals,allvals[0]*EPSILON),
|
||||
//total = _sum(allvals,allvals[0]*_EPSILON),
|
||||
total = _sum(slice(allvals,1,-1), allvals[0])
|
||||
) list_to_matrix(total,len(yset));
|
||||
|
||||
|
|
@ -3352,10 +3355,10 @@ function _metaballs2dfield(funclist, transmatrix, bbox, pixsize, nballs) = let(
|
|||
// *exp(-((y+4)/3)^2-x^2-0.5*z^2);
|
||||
//
|
||||
// left(6) isosurface(function(x,y,z) shape(x,y,z),
|
||||
// isovalue = [EPSILON,INF],
|
||||
// isovalue = [_EPSILON,INF],
|
||||
// bounding_box=bbox, voxel_size=0.25);
|
||||
// right(6) isosurface(function(x,y,z) log(shape(x,y,z)),
|
||||
// isovalue = [log(EPSILON),INF],
|
||||
// isovalue = [log(_EPSILON),INF],
|
||||
// bounding_box=bbox, voxel_size=0.25);
|
||||
// Example(3D): Using an array for the `f` argument instead of a function literal. Each row of the array represents an X index for a YZ plane with the array Z indices changing fastest in each plane. The final object may need rotation to get the orientation you want. You don't pass the `bounding_box` argument here; it is implied by the array size and voxel size, and centered on the origin.
|
||||
// field = [
|
||||
|
|
@ -3442,7 +3445,7 @@ function isosurface(f, isovalue, bounding_box, voxel_size, voxel_count=undef, re
|
|||
for(i=[0:3:len(trianglepoints)-1])
|
||||
let(i1=i+1, i2=i+2)
|
||||
if (norm(cross(trianglepoints[i1]-trianglepoints[i],
|
||||
trianglepoints[i2]-trianglepoints[i])) > EPSILON)
|
||||
trianglepoints[i2]-trianglepoints[i])) > _EPSILON)
|
||||
[i,i1,i2]
|
||||
],
|
||||
dum2 = show_stats ? _showstats_isosurface(voxsize, bbox, isovalue, cubes, trianglepoints, faces) : 0
|
||||
|
|
@ -3752,11 +3755,11 @@ function _region_smooth(reg, passes, bbox, count=0) =
|
|||
) _region_smooth(sm, passes, bbox, count+1);
|
||||
|
||||
|
||||
/// internal function: return true if a point is within EPSILON of the bounding box edge
|
||||
/// internal function: return true if a point is within _EPSILON of the bounding box edge
|
||||
function _is_pt_on_bbox(p, bbox) = let(
|
||||
a = v_abs(p-bbox[0]),
|
||||
b = v_abs(p-bbox[1])
|
||||
) a[0]<EPSILON || a[1]<EPSILON || b[0]<EPSILON || b[1]<EPSILON;
|
||||
) a[0]<_EPSILON || a[1]<_EPSILON || b[0]<_EPSILON || b[1]<_EPSILON;
|
||||
|
||||
|
||||
/// internal function: return number of path points that fall on the bounding box edge
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileSummary: Joiner shapes for connecting separately printed objects.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_JOINERS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: joiners.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
include <rounding.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_LINALG = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: linalg.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Matrices
|
||||
// The matrix, a rectangular array of numbers which represents a linear transformation,
|
||||
// is the fundamental object in linear algebra. In OpenSCAD a matrix is a list of lists of numbers
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
// FileSummary: Mounts for LMxUU style linear bearings.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_LINEAR_BEARINGS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: linear_bearings.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
include <screws.scad>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_LISTS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: lists.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Terminology:
|
||||
// **List** = An ordered collection of zero or more arbitrary items. ie: `["a", "b", "c"]`, or `[3, "a", [4,5]]`
|
||||
// **Vector** = A list of numbers. ie: `[4, 5, 6]`
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_MASKS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: masks.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
function _inset_corner(corner, mask_angle, inset, excess, flat_top) =
|
||||
let(
|
||||
|
|
|
|||
31
math.scad
31
math.scad
|
|
@ -11,33 +11,38 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_MATH = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: math.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Math Constants
|
||||
|
||||
// Constant: PHI
|
||||
// Synopsis: The golden ratio φ (phi). Approximately 1.6180339887
|
||||
// Topics: Constants, Math
|
||||
// See Also: EPSILON, INF, NAN
|
||||
// See Also: _EPSILON, INF, NAN
|
||||
// Description: The golden ratio φ (phi). Approximately 1.6180339887
|
||||
PHI = (1+sqrt(5))/2;
|
||||
|
||||
// Constant: EPSILON
|
||||
// Constant: _EPSILON
|
||||
// Synopsis: A tiny value to compare floating point values. `1e-9`
|
||||
// Topics: Constants, Math
|
||||
// See Also: PHI, EPSILON, INF, NAN
|
||||
// Description: A really small value useful in comparing floating point numbers. ie: abs(a-b)<EPSILON `1e-9`
|
||||
EPSILON = 1e-9;
|
||||
// See Also: PHI, INF, NAN
|
||||
// Description: A really small value useful in comparing floating point numbers. ie: abs(a-b)<_EPSILON `1e-9`
|
||||
_EPSILON = 1e-9;
|
||||
|
||||
// Constant: INF
|
||||
// Synopsis: The floating point value for Infinite.
|
||||
// Topics: Constants, Math
|
||||
// See Also: PHI, EPSILON, INF, NAN
|
||||
// See Also: PHI, _EPSILON, NAN
|
||||
// Description: The value `inf`, useful for comparisons.
|
||||
INF = 1/0;
|
||||
|
||||
// Constant: NAN
|
||||
// Synopsis: The floating point value for Not a Number.
|
||||
// Topics: Constants, Math
|
||||
// See Also: PHI, EPSILON, INF, NAN
|
||||
// See Also: PHI, _EPSILON, INF
|
||||
// Description: The value `nan`, useful for comparisons.
|
||||
NAN = acos(2);
|
||||
|
||||
|
|
@ -200,12 +205,12 @@ function slerp(v1, v2, u) =
|
|||
a = unit(v1),
|
||||
b = unit(v2),
|
||||
theta = acos(max(-1, min(1, a*b))),
|
||||
err = assert(abs(theta-180)>EPSILON, "\nNo solution when vectors v1 and v2 are 180° apart."),
|
||||
err = assert(abs(theta-180)>_EPSILON, "\nNo solution when vectors v1 and v2 are 180° apart."),
|
||||
sin_theta = sin(theta)
|
||||
) sin_theta < EPSILON ? unit(a+b) // fallback
|
||||
: is_finite(u) ? (sin_theta < EPSILON ? unit(a+b)
|
||||
) sin_theta < _EPSILON ? unit(a+b) // fallback
|
||||
: is_finite(u) ? (sin_theta < _EPSILON ? unit(a+b)
|
||||
: (a * sin((1 - u) * theta) + b * sin(u * theta)) / sin_theta)
|
||||
: [for(t=u) sin_theta < EPSILON ? unit(a+b)
|
||||
: [for(t=u) sin_theta < _EPSILON ? unit(a+b)
|
||||
: (a * sin((1 - t) * theta) + b * sin(t * theta)) / sin_theta];
|
||||
|
||||
|
||||
|
|
@ -236,12 +241,12 @@ function slerpn(v1, v2, n, endpoint=true) =
|
|||
a = unit(v1),
|
||||
b = unit(v2),
|
||||
theta = acos(max(-1, min(1, a*b))),
|
||||
err = assert(abs(theta-180)>EPSILON, "\nNo solution when vectors v1 and v2 are 180° apart."),
|
||||
err = assert(abs(theta-180)>_EPSILON, "\nNo solution when vectors v1 and v2 are 180° apart."),
|
||||
sin_theta = sin(theta),
|
||||
d = n - (endpoint ? 1 : 0)
|
||||
) [
|
||||
for(i=[0:n-1]) let(u=i/d)
|
||||
sin_theta < EPSILON ? unit(a+b) // fallback
|
||||
sin_theta < _EPSILON ? unit(a+b) // fallback
|
||||
: (a * sin((1 - u) * theta) + b * sin(u * theta)) / sin_theta
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@
|
|||
// FileSummary: Metric screws, nuts, and screwholes.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
include <threading.scad>
|
||||
include <screw_drive.scad>
|
||||
|
||||
_BOSL2_METRIC_SCREWS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: metric_screws.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
warn = echo("*** WARNING: metric_screws.scad is deprecated and may be removed in the future. Use screws.scad instead. ***");
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_MISCELLANEOUS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: miscellaneous.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Extrusion
|
||||
|
||||
// Module: extrude_from_to()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
// FileSummary: Modular flexible hose segments.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_MODULAR_HOSE = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: modular_hose.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Modular Hose Parts
|
||||
|
||||
_modhose_small_end = [
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileSummary: NEMA motor mounts and stepper motor models.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_NEMA_STEPPERS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: nema_steppers.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Motor Models
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
// FileSummary: NURBS and B-spline curves and surfaces.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
include<BOSL2/std.scad>
|
||||
_BOSL2_NURBS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: nurbs.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: NURBS Curves
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_PARTITIONS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: partitions.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Planar Cutting
|
||||
|
||||
|
|
|
|||
42
paths.scad
42
paths.scad
|
|
@ -15,6 +15,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_PATHS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: paths.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Utility Functions
|
||||
// Definitions:
|
||||
// Point|Points = A list of numbers, also called a vector. Usually has length 2 or 3 to represent points in the place on points in space.
|
||||
|
|
@ -146,8 +150,8 @@ function _path_select(path, s1, u1, s2, u2, closed=false) =
|
|||
// Arguments:
|
||||
// path = A path of any dimension or a 1-region
|
||||
// closed = treat as closed polygon. Default: false
|
||||
// eps = Largest positional variance allowed. Default: `EPSILON` (1-e9)
|
||||
function path_merge_collinear(path, closed, eps=EPSILON) =
|
||||
// eps = Largest positional variance allowed. Default: `_EPSILON` (1-e9)
|
||||
function path_merge_collinear(path, closed, eps=_EPSILON) =
|
||||
is_1region(path) ? path_merge_collinear(path[0], default(closed,true), eps) :
|
||||
let(closed=default(closed,false))
|
||||
assert(is_bool(closed))
|
||||
|
|
@ -258,7 +262,7 @@ function path_length_fractions(path, closed) =
|
|||
/// Arguments:
|
||||
/// path = The path to find self intersections of.
|
||||
/// closed = If true, treat path like a closed polygon. Default: true
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `_EPSILON` (1e-9)
|
||||
/// Example(2D):
|
||||
/// path = [
|
||||
/// [-100,100], [0,-50], [100,100], [100,-100], [0,50], [-100,-100]
|
||||
|
|
@ -267,7 +271,7 @@ function path_length_fractions(path, closed) =
|
|||
/// // isects == [[[-33.3333, 0], 0, 0.666667, 4, 0.333333], [[33.3333, 0], 1, 0.333333, 3, 0.666667]]
|
||||
/// stroke(path, closed=true, width=1);
|
||||
/// for (isect=isects) translate(isect[0]) color("blue") sphere(d=10);
|
||||
function _path_self_intersections(path, closed=true, eps=EPSILON) =
|
||||
function _path_self_intersections(path, closed=true, eps=_EPSILON) =
|
||||
let(
|
||||
path = closed ? list_wrap(path,eps=eps) : path,
|
||||
plen = len(path)
|
||||
|
|
@ -687,8 +691,8 @@ function _err_resample(path, maxerr, n, i1=0, i2=2, resultidx=[0], iter=0) =
|
|||
// Arguments:
|
||||
// path = 2D path or 1-region
|
||||
// closed = set to true to treat path as a polygon. Default: false
|
||||
// eps = Epsilon error value used for determine if points coincide. Default: `EPSILON` (1e-9)
|
||||
function is_path_simple(path, closed, eps=EPSILON) =
|
||||
// eps = Epsilon error value used for determine if points coincide. Default: `_EPSILON` (1e-9)
|
||||
function is_path_simple(path, closed, eps=_EPSILON) =
|
||||
is_1region(path) ? is_path_simple(path[0], default(closed,true), eps) :
|
||||
let(closed=default(closed,false))
|
||||
assert(is_path(path, 2),"\nMust give a 2D path.")
|
||||
|
|
@ -820,7 +824,7 @@ function path_normals(path, tangents, closed) =
|
|||
)
|
||||
dim == 2 ? [tangents[i].y,-tangents[i].x]
|
||||
: let( v=cross(cross(pts[1]-pts[0], pts[2]-pts[0]),tangents[i]))
|
||||
assert(norm(v)>EPSILON, "\n3D path contains collinear points.")
|
||||
assert(norm(v)>_EPSILON, "\n3D path contains collinear points.")
|
||||
unit(v)
|
||||
];
|
||||
|
||||
|
|
@ -939,8 +943,8 @@ function path_cut(path,cutdist,closed) =
|
|||
let(closed=default(closed,false))
|
||||
assert(is_bool(closed))
|
||||
assert(is_vector(cutdist))
|
||||
assert(last(cutdist)<path_length(path,closed=closed)-EPSILON,"\nCut distances must be smaller than the path length.")
|
||||
assert(cutdist[0]>EPSILON, "\nCut distances must be strictly positive.")
|
||||
assert(last(cutdist)<path_length(path,closed=closed)-_EPSILON,"\nCut distances must be smaller than the path length.")
|
||||
assert(cutdist[0]>_EPSILON, "\nCut distances must be strictly positive.")
|
||||
let(
|
||||
cutlist = path_cut_points(path,cutdist,closed=closed)
|
||||
)
|
||||
|
|
@ -1122,12 +1126,12 @@ function _cut_to_seg_u_form(pathcut, path, closed) =
|
|||
// Arguments:
|
||||
// path = A 2D path or a 1-region.
|
||||
// closed = If true, treat path as a closed polygon. Default: true
|
||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||
// eps = Acceptable variance. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D,NoAxes):
|
||||
// path = [ [-100,100], [0,-50], [100,100], [100,-100], [0,50], [-100,-100] ];
|
||||
// paths = split_path_at_self_crossings(path);
|
||||
// rainbow(paths) stroke($item, closed=false, width=3);
|
||||
function split_path_at_self_crossings(path, closed=true, eps=EPSILON) =
|
||||
function split_path_at_self_crossings(path, closed=true, eps=_EPSILON) =
|
||||
let(path = force_path(path))
|
||||
assert(is_path(path,2), "\nMust give a 2D path.")
|
||||
assert(is_bool(closed))
|
||||
|
|
@ -1160,7 +1164,7 @@ function split_path_at_self_crossings(path, closed=true, eps=EPSILON) =
|
|||
];
|
||||
|
||||
|
||||
function _tag_self_crossing_subpaths(path, nonzero, closed=true, eps=EPSILON) =
|
||||
function _tag_self_crossing_subpaths(path, nonzero, closed=true, eps=_EPSILON) =
|
||||
let(
|
||||
subpaths = split_path_at_self_crossings(
|
||||
path, closed=true, eps=eps
|
||||
|
|
@ -1193,7 +1197,7 @@ function _tag_self_crossing_subpaths(path, nonzero, closed=true, eps=EPSILON) =
|
|||
// Arguments:
|
||||
// poly = a 2D polygon or 1-region
|
||||
// nonzero = If true use the nonzero method for checking if a point is in a polygon. Otherwise use the even-odd method. Default: false
|
||||
// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
||||
// eps = The epsilon error value to determine whether two points coincide. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D,NoAxes): This cross-crossing polygon breaks up into its 3 components (regardless of the value of nonzero).
|
||||
// poly = [
|
||||
// [-100,100], [0,-50], [100,100],
|
||||
|
|
@ -1242,7 +1246,7 @@ function _tag_self_crossing_subpaths(path, nonzero, closed=true, eps=EPSILON) =
|
|||
// polygon(poly);
|
||||
// right(27)rainbow(polygon_parts(poly)) polygon($item);
|
||||
// move([16,-14])rainbow(polygon_parts(poly,nonzero=true)) polygon($item);
|
||||
function polygon_parts(poly, nonzero=false, eps=EPSILON) =
|
||||
function polygon_parts(poly, nonzero=false, eps=_EPSILON) =
|
||||
let(poly = force_path(poly))
|
||||
assert(is_path(poly,2), "\nMust give 2D polygon.")
|
||||
assert(is_bool(nonzero))
|
||||
|
|
@ -1254,7 +1258,7 @@ function polygon_parts(poly, nonzero=false, eps=EPSILON) =
|
|||
) outregion;
|
||||
|
||||
|
||||
function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
|
||||
function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=_EPSILON) =
|
||||
!fragments? [undef, []] :
|
||||
let(
|
||||
delta = seg[1] - seg[0],
|
||||
|
|
@ -1298,8 +1302,8 @@ function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
|
|||
/// fragments = List of paths to be assembled into complete polygons.
|
||||
/// rightmost = If true, assemble paths using rightmost turns. Leftmost if false.
|
||||
/// startfrag = The fragment to start with. Default: 0
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
||||
function _assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=EPSILON) =
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `_EPSILON` (1e-9)
|
||||
function _assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=_EPSILON) =
|
||||
len(fragments)==0? [[],[]] :
|
||||
len(fragments)==1? [fragments[0],[]] :
|
||||
let(
|
||||
|
|
@ -1353,8 +1357,8 @@ function _assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0,
|
|||
/// Polygons with area < eps are discarded and not returned.
|
||||
/// Arguments:
|
||||
/// fragments = List of paths to be assembled into complete polygons.
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
||||
function _assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) =
|
||||
/// eps = The epsilon error value to determine whether two points coincide. Default: `_EPSILON` (1e-9)
|
||||
function _assemble_path_fragments(fragments, eps=_EPSILON, _finished=[]) =
|
||||
len(fragments)==0? _finished :
|
||||
let(
|
||||
minxidx = min_index([
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
// FileSummary: Platonic, Archimidean, Catalan, and stellated polyhedra
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_POLYHEDRA = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: polyhedra.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// CommonCode:
|
||||
// $fn=96;
|
||||
|
|
|
|||
40
regions.scad
40
regions.scad
|
|
@ -14,6 +14,10 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_REGIONS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: regions.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// CommonCode:
|
||||
// include <BOSL2/rounding.scad>
|
||||
|
||||
|
|
@ -93,7 +97,7 @@ function is_region(x) = is_list(x) && is_path(x.x);
|
|||
// a region.
|
||||
// Arguments:
|
||||
// region = region to check
|
||||
// eps = tolerance for geometric comparisons. Default: `EPSILON` = 1e-9
|
||||
// eps = tolerance for geometric comparisons. Default: `_EPSILON` = 1e-9
|
||||
// Example(2D,NoAxes): In all of the examples each polygon in the region appears in a different color. Two non-intersecting squares make a valid region.
|
||||
// region = [square(10), right(11,square(8))];
|
||||
// rainbow(region)stroke($item, width=.2,closed=true);
|
||||
|
|
@ -192,7 +196,7 @@ function is_region(x) = is_list(x) && is_path(x.x);
|
|||
// region = difference(poly1,poly2);
|
||||
// rainbow(region)stroke($item, width=.25,closed=true);
|
||||
// move([-5,11.4])text(is_valid_region(region) ? "region" : "non-region", size=3);
|
||||
function is_valid_region(region, eps=EPSILON) =
|
||||
function is_valid_region(region, eps=_EPSILON) =
|
||||
let(region=force_region(region))
|
||||
assert(is_region(region), "\nInput is not a region.")
|
||||
// no short paths
|
||||
|
|
@ -221,7 +225,7 @@ function is_valid_region(region, eps=EPSILON) =
|
|||
// internal function:
|
||||
// returns true if the polygon crosses the region so that part of the
|
||||
// polygon is inside the region and part is outside.
|
||||
function _polygon_crosses_region(region, poly, eps=EPSILON) =
|
||||
function _polygon_crosses_region(region, poly, eps=_EPSILON) =
|
||||
let(
|
||||
subpaths = flatten(split_region_at_region_crossings(region,[poly],eps=eps)[1])
|
||||
)
|
||||
|
|
@ -251,7 +255,7 @@ function _polygon_crosses_region(region, poly, eps=EPSILON) =
|
|||
// should not create problems with CGAL.
|
||||
// Arguments:
|
||||
// region = region to check
|
||||
// eps = tolerance for geometric comparisons. Default: `EPSILON` = 1e-9
|
||||
// eps = tolerance for geometric comparisons. Default: `_EPSILON` = 1e-9
|
||||
// Example(2D,NoAxes): Corner contact means it's not simple
|
||||
// region = [move([-2,-2],square(14)), [[0,0],[10,0],[5,5]], [[5,5],[0,10],[10,10]]];
|
||||
// rainbow(region)stroke($item, width=.2,closed=true);
|
||||
|
|
@ -260,7 +264,7 @@ function _polygon_crosses_region(region, poly, eps=EPSILON) =
|
|||
// region = [move([-2,-2],square(14)), [[0,0],[10,0],[5,4.5]], [[5,5.5],[0,10],[10,10]]];
|
||||
// rainbow(region)stroke($item, width=.2,closed=true);
|
||||
// move([1,13])text(is_region_simple(region) ? "simple" : "not-simple", size=2);
|
||||
function is_region_simple(region, eps=EPSILON) =
|
||||
function is_region_simple(region, eps=_EPSILON) =
|
||||
let(region=force_region(region))
|
||||
assert(is_region(region), "\nInput is not a region.")
|
||||
[for(p=region) if (!is_path_simple(p,closed=true,eps=eps)) 1] == []
|
||||
|
|
@ -284,7 +288,7 @@ function is_region_simple(region, eps=EPSILON) =
|
|||
// Arguments:
|
||||
// polys = list of polygons to use
|
||||
// nonzero = set to true to use nonzero rule for polygon membership. Default: false
|
||||
// eps = Epsilon for geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// eps = Epsilon for geometric comparisons. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D,NoAxes): The pentagram is self-intersecting, so it is not a region. Here it becomes five triangles:
|
||||
// pentagram = turtle(["move",100,"left",144], repeat=4);
|
||||
// region = make_region(pentagram);
|
||||
|
|
@ -297,7 +301,7 @@ function is_region_simple(region, eps=EPSILON) =
|
|||
// region = make_region([square(10), move([5,5],square(8))]);
|
||||
// rainbow(region)stroke($item, width=.3,closed=true);
|
||||
|
||||
function make_region(polys,nonzero=false,eps=EPSILON) =
|
||||
function make_region(polys,nonzero=false,eps=_EPSILON) =
|
||||
let(polys=force_region(polys))
|
||||
assert(is_region(polys), "\nInput is not a region.")
|
||||
exclusive_or(
|
||||
|
|
@ -429,7 +433,7 @@ module debug_region(region, vertices=true, edges=true, convexity=2, size=1)
|
|||
// Arguments:
|
||||
// point = The point to test.
|
||||
// region = The region to test against, as a list of polygon paths.
|
||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||
// eps = Acceptable variance. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D,Med): Red points are in the region.
|
||||
// region = [for(i=[2:4:10]) hexagon(r=i)];
|
||||
// color("#ff7") region(region);
|
||||
|
|
@ -438,13 +442,13 @@ module debug_region(region, vertices=true, edges=true, convexity=2, size=1)
|
|||
// move([x,y]) color("red") circle(0.15, $fn=12);
|
||||
// else
|
||||
// move([x,y]) color("#ddf") circle(0.1, $fn=12);
|
||||
function point_in_region(point, region, eps=EPSILON) =
|
||||
function point_in_region(point, region, eps=_EPSILON) =
|
||||
let(region=force_region(region))
|
||||
assert(is_region(region), "\nRegion given to point_in_region is not a region.")
|
||||
assert(is_vector(point,2), "\nPoint must be a 2D point in point_in_region.")
|
||||
_point_in_region(point, region, eps);
|
||||
|
||||
function _point_in_region(point, region, eps=EPSILON, i=0, cnt=0) =
|
||||
function _point_in_region(point, region, eps=_EPSILON, i=0, cnt=0) =
|
||||
i >= len(region) ? ((cnt%2==1)? 1 : -1)
|
||||
: let(
|
||||
pip = point_in_polygon(point, region[i], eps=eps)
|
||||
|
|
@ -518,7 +522,7 @@ function __are_regions_equal(region1, region2, i) =
|
|||
/// Included as intersection points are points where region1 touches itself at a vertex or
|
||||
/// region2 touches itself at a vertex. (The paths are assumed to have no self crossings.
|
||||
/// Self crossings of the paths in the regions are not returned.)
|
||||
function _region_region_intersections(region1, region2, closed1=true,closed2=true, eps=EPSILON) =
|
||||
function _region_region_intersections(region1, region2, closed1=true,closed2=true, eps=_EPSILON) =
|
||||
let(
|
||||
intersections = [
|
||||
for(p1=idx(region1))
|
||||
|
|
@ -607,7 +611,7 @@ function _region_region_intersections(region1, region2, closed1=true,closed2=tru
|
|||
// region2 = second region
|
||||
// closed1 = if false then treat region1 as list of open paths. Default: true
|
||||
// closed2 = if false then treat region2 as list of open paths. Default: true
|
||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||
// eps = Acceptable variance. Default: `_EPSILON` (1e-9)
|
||||
// Example(2D):
|
||||
// path = square(50,center=false);
|
||||
// region = [circle(d=80), circle(d=40)];
|
||||
|
|
@ -618,7 +622,7 @@ function _region_region_intersections(region1, region2, closed1=true,closed2=tru
|
|||
// color("#aaa") region([path]);
|
||||
// rainbow(flatten(paths[1])) stroke($item, width=2);
|
||||
// }
|
||||
function split_region_at_region_crossings(region1, region2, closed1=true, closed2=true, eps=EPSILON) =
|
||||
function split_region_at_region_crossings(region1, region2, closed1=true, closed2=true, eps=_EPSILON) =
|
||||
let(
|
||||
region1=force_region(region1),
|
||||
region2=force_region(region2)
|
||||
|
|
@ -1171,7 +1175,7 @@ function offset(
|
|||
/// "S" - the subpath is on the 2nd region's border and the two regions interiors are on the same side of the subpath
|
||||
/// "U" - the subpath is on the 2nd region's border and the two regions meet at the subpath from opposite sides
|
||||
/// You specify which type of subpaths to keep with a string of the desired types such as "OS".
|
||||
function _filter_region_parts(region1, region2, keep, eps=EPSILON) =
|
||||
function _filter_region_parts(region1, region2, keep, eps=_EPSILON) =
|
||||
// We have to compute common vertices between paths in the region because
|
||||
// they can be places where the path must be cut, even though they aren't
|
||||
// found my the split_path function.
|
||||
|
|
@ -1243,7 +1247,7 @@ function _list_three(a,b,c) =
|
|||
// color("green") region(union(shape1,shape2));
|
||||
// for (shape = [shape1,shape2])
|
||||
// stroke(shape, width=0.5, closed=true, color="red");
|
||||
function union(regions=[],b=undef,c=undef,eps=EPSILON) =
|
||||
function union(regions=[],b=undef,c=undef,eps=_EPSILON) =
|
||||
let(regions=_list_three(regions,b,c))
|
||||
len(regions)==0? [] :
|
||||
len(regions)==1? regions[0] :
|
||||
|
|
@ -1281,7 +1285,7 @@ function union(regions=[],b=undef,c=undef,eps=EPSILON) =
|
|||
// for (shape = [shape1,shape2])
|
||||
// stroke(shape, width=0.5, color="red", closed=true);
|
||||
// color("green") region(difference(shape1,shape2));
|
||||
function difference(regions=[],b=undef,c=undef,eps=EPSILON) =
|
||||
function difference(regions=[],b=undef,c=undef,eps=_EPSILON) =
|
||||
let(regions = _list_three(regions,b,c))
|
||||
len(regions)==0? []
|
||||
: len(regions)==1? regions[0]
|
||||
|
|
@ -1317,7 +1321,7 @@ function difference(regions=[],b=undef,c=undef,eps=EPSILON) =
|
|||
// for (shape = [shape1,shape2])
|
||||
// stroke(shape,width=0.5, color="red", closed=true);
|
||||
// color("green") region(intersection(shape1,shape2));
|
||||
function intersection(regions=[],b=undef,c=undef,eps=EPSILON) =
|
||||
function intersection(regions=[],b=undef,c=undef,eps=_EPSILON) =
|
||||
let(regions = _list_three(regions,b,c))
|
||||
len(regions)==0 ? []
|
||||
: len(regions)==1? regions[0]
|
||||
|
|
@ -1362,7 +1366,7 @@ function intersection(regions=[],b=undef,c=undef,eps=EPSILON) =
|
|||
// square(40,center=false);
|
||||
// circle(d=40);
|
||||
// }
|
||||
function exclusive_or(regions=[],b=undef,c=undef,eps=EPSILON) =
|
||||
function exclusive_or(regions=[],b=undef,c=undef,eps=_EPSILON) =
|
||||
let(regions = _list_three(regions,b,c))
|
||||
len(regions)==0? []
|
||||
: len(regions)==1? force_region(regions[0])
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_ROUNDING = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: rounding.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Types of Roundovers
|
||||
// The functions and modules in this file support two different types of roundovers and some different mechanisms for specifying
|
||||
// the size of the roundover. The usual circular roundover can produce a tactile "bump" where the curvature changes from flat to
|
||||
|
|
@ -2475,21 +2478,21 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
|
|||
bot_patch = _rp_compute_patches(bottom, top, joint_bot, joint_sides_vec, k_bot, k_sides_vec, concave),
|
||||
|
||||
vertbad = [for(i=[0:N-1])
|
||||
if (norm(top[i]-top_patch[i][4][2]) + norm(bottom[i]-bot_patch[i][4][2]) > EPSILON + norm(bottom[i]-top[i])) i],
|
||||
if (norm(top[i]-top_patch[i][4][2]) + norm(bottom[i]-bot_patch[i][4][2]) > _EPSILON + norm(bottom[i]-top[i])) i],
|
||||
// Check that the patch fits on the polygon edge
|
||||
topbad = [for(i=[0:N-1])
|
||||
if (norm(top_patch[i][2][4]-top_patch[i][2][2]) + norm(select(top_patch,i+1)[2][0]-select(top_patch,i+1)[2][2])
|
||||
> EPSILON + norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
> _EPSILON + norm(top_patch[i][2][2] - select(top_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
botbad = [for(i=[0:N-1])
|
||||
if (norm(bot_patch[i][2][4]-bot_patch[i][2][2]) + norm(select(bot_patch,i+1)[2][0]-select(bot_patch,i+1)[2][2])
|
||||
> EPSILON + norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
> _EPSILON + norm(bot_patch[i][2][2] - select(bot_patch,i+1)[2][2])) [i,(i+1)%N]],
|
||||
// If top/bot is L-shaped, check that arms of L from adjacent patches don't cross
|
||||
topLbad = [for(i=[0:N-1])
|
||||
if (norm(top_patch[i][0][2]-top_patch[i][0][4]) + norm(select(top_patch,i+1)[0][0]-select(top_patch,i+1)[0][2])
|
||||
> EPSILON + norm(top_patch[i][0][2]-select(top_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
> _EPSILON + norm(top_patch[i][0][2]-select(top_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
botLbad = [for(i=[0:N-1])
|
||||
if (norm(bot_patch[i][0][2]-bot_patch[i][0][4]) + norm(select(bot_patch,i+1)[0][0]-select(bot_patch,i+1)[0][2])
|
||||
> EPSILON + norm(bot_patch[i][0][2]-select(bot_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
> _EPSILON + norm(bot_patch[i][0][2]-select(bot_patch,i+1)[0][2])) [i,(i+1)%N]],
|
||||
// Check that the inner edges of the patch don't cross
|
||||
topinbad = [for(i=[0:N-1])
|
||||
let(
|
||||
|
|
@ -3865,7 +3868,7 @@ function _prism_line_isect(poly_pairs, line, ref) =
|
|||
ref=point2d(ref),
|
||||
ilist = [for(j=idx(poly_pairs))
|
||||
let(segisect = _general_line_intersection(poly_pairs[j],line2d))
|
||||
if (segisect && segisect[1]>=-EPSILON && segisect[1]<=1+EPSILON)
|
||||
if (segisect && segisect[1]>=-_EPSILON && segisect[1]<=1+_EPSILON)
|
||||
[segisect[0],j,segisect[1],segisect[0]*ref]]
|
||||
)
|
||||
len(ilist)==0 ? [] :
|
||||
|
|
@ -3952,7 +3955,7 @@ function _prism_fillet_cyl(name, R, bot, top, d, k, N, overlap, uniform, debug)
|
|||
d_step = abs(d)*unit(top[i]-isect[i])+(uniform?isect[i]:corner)
|
||||
)
|
||||
assert(is_vector(corner,3),str("Fillet does not fit. Decrease size of fillet (",name,")."))
|
||||
assert(debug || R<0 || (d_step-corner)*(corner-isect[i])>=-EPSILON,
|
||||
assert(debug || R<0 || (d_step-corner)*(corner-isect[i])>=-_EPSILON,
|
||||
str("Unable to fit fillet, probably due to steep curvature of the cylinder (",name,")."))
|
||||
let(
|
||||
bez = _smooth_bez_fill([d_step,corner,edgepoint], k)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// FileSummary: Masks for Phillips, Torx and square (Robertson) driver holes.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_SCREW_DRIVED = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: screw_drive.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
include <structs.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
// FileSummary: ISO (metric) and UTS screws and nuts.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_SCREWS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: screws.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
include <structs.scad>
|
||||
include <threading.scad>
|
||||
include <screw_drive.scad>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
use <builtins.scad>
|
||||
BOSL2_SHAPES2D = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: shapes2d.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
use <builtins.scad>
|
||||
|
||||
|
||||
// Section: 2D Primitives
|
||||
|
||||
|
|
@ -465,7 +468,7 @@ function _ellipse_refine(a,b,N, _theta=[]) =
|
|||
meanlen = mean(lenlist),
|
||||
error = lenlist/meanlen
|
||||
)
|
||||
all_equal(error,EPSILON) ? pts
|
||||
all_equal(error,_EPSILON) ? pts
|
||||
:
|
||||
let(
|
||||
dtheta = [each deltas(_theta),
|
||||
|
|
@ -489,7 +492,7 @@ function _ellipse_refine_realign(a,b,N, _theta=[],i=0) =
|
|||
meanlen = mean(lenlist),
|
||||
error = lenlist/meanlen
|
||||
)
|
||||
all_equal(error,EPSILON) ? pts
|
||||
all_equal(error,_EPSILON) ? pts
|
||||
:
|
||||
let(
|
||||
dtheta = [each deltas(_theta),
|
||||
|
|
@ -1431,7 +1434,7 @@ function teardrop2d(r, ang=45, cap_h, d, circum=false, realign=false, anchor=CEN
|
|||
each cap,
|
||||
for (p=fullcircle)
|
||||
if (
|
||||
p.y<last(cap).y-EPSILON
|
||||
p.y<last(cap).y-_EPSILON
|
||||
&& norm([abs(p.x)-last(cap).x,p.y-last(cap.y)])>seglen/skipfactor
|
||||
) p,
|
||||
xflip(cap[1]),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_SHAPES3D = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: shapes3d.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
use <builtins.scad>
|
||||
|
||||
|
||||
|
|
@ -3211,7 +3215,7 @@ function pie_slice(
|
|||
h = lerp(-l/2,l/2,u),
|
||||
r = lerp(r1,r2,u)
|
||||
) [
|
||||
for (theta = [0:step:ang+EPSILON])
|
||||
for (theta = [0:step:ang+_EPSILON])
|
||||
cylindrical_to_xyz(r,theta,h),
|
||||
[0,0,h]
|
||||
]
|
||||
|
|
@ -3867,7 +3871,7 @@ function torus(
|
|||
right_half(p=right(maj_rad, p=circle(r=min_rad)))[0],
|
||||
profile = xrot(90, p=path3d(xyprofile)),
|
||||
vnf = vnf_vertex_array(
|
||||
points=[for (a=[0:maj_step:360-EPSILON]) zrot(a, p=profile)],
|
||||
points=[for (a=[0:maj_step:360-_EPSILON]) zrot(a, p=profile)],
|
||||
caps=false, col_wrap=true, row_wrap=true, reverse=true
|
||||
)
|
||||
) reorient(anchor,spin,orient, r=(maj_rad+min_rad), l=min_rad*2, p=vnf);
|
||||
|
|
@ -4015,8 +4019,8 @@ function teardrop(h, r, ang=45, cap_h, r1, r2, d, d1, d2, cap_h1, cap_h2, chamf
|
|||
assert(bot_corner2==0 || bot_corner2>=chamfer2, "\nchamfer2 doesn't work with bottom corner: must have chamfer2 <= bot_corner2")
|
||||
assert(bot_corner1==0 || bot_corner1>chamfer1 || sides%2==(realign?1:0),
|
||||
str("\nWith chamfer1==bot_corner1 and realign=",realign," must have ",realign?"odd":"even"," number of sides, but sides=",sides))
|
||||
assert(is_undef(cap_h1) || cap_h1-chamfer1 > r1*sin(ang)-EPSILON, "chamfer1 is too big to work with the specified cap_h1")
|
||||
assert(is_undef(cap_h2) || cap_h2-chamfer2 > r2*sin(ang)-EPSILON, "chamfer2 is too big to work with the specified cap_h2"),
|
||||
assert(is_undef(cap_h1) || cap_h1-chamfer1 > r1*sin(ang)-_EPSILON, "chamfer1 is too big to work with the specified cap_h1")
|
||||
assert(is_undef(cap_h2) || cap_h2-chamfer2 > r2*sin(ang)-_EPSILON, "chamfer2 is too big to work with the specified cap_h2"),
|
||||
cprof1 = r1==chamfer1 ? repeat([0,0],len(profile1))
|
||||
: teardrop2d(r=r1-chamfer1, ang=ang, cap_h=u_add(cap_h1,-chamfer1), bot_corner=bot_corner1==0?0:bot_corner1-chamfer1,
|
||||
$fn=sides, circum=circum, realign=realign,_extrapt=true),
|
||||
|
|
@ -4122,7 +4126,7 @@ function onion(r, ang=45, cap_h, d, anchor=CENTER, spin=0, orient=UP) =
|
|||
sides = segs(r),
|
||||
step = 360 / sides,
|
||||
vnf = vnf_vertex_array(
|
||||
points=[for (a = [0:step:360-EPSILON]) zrot(a, p=profile)],
|
||||
points=[for (a = [0:step:360-_EPSILON]) zrot(a, p=profile)],
|
||||
caps=false, col_wrap=true, row_wrap=true, reverse=true
|
||||
)
|
||||
) reorient(anchor,spin,orient, r=r, anchors=anchors, p=vnf);
|
||||
|
|
@ -5180,7 +5184,7 @@ module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3
|
|||
assert(len(colors)==2, "\n'colors' must contain a list of exactly two colors.");
|
||||
length = inch ? INCH * length : length;
|
||||
unit = inch ? INCH*unit : unit;
|
||||
maxscale = is_def(maxscale)? maxscale : floor(log(length/unit-EPSILON));
|
||||
maxscale = is_def(maxscale)? maxscale : floor(log(length/unit-_EPSILON));
|
||||
scales = unit * [for(logsize = [maxscale:-1:maxscale-depth+1]) pow(10,logsize)];
|
||||
widthfactor = (1-pipscale) / (1-pow(pipscale,depth));
|
||||
width = default(width, scales[0]);
|
||||
|
|
@ -5215,7 +5219,7 @@ module ruler(length=100, width, thickness=1, depth=3, labels=false, pipscale=1/3
|
|||
}
|
||||
}
|
||||
}
|
||||
if (labels && scales[i]/unit+EPSILON >= 1) {
|
||||
if (labels && scales[i]/unit+_EPSILON >= 1) {
|
||||
color(colors[($idx+1)%2], alpha=alpha) {
|
||||
linear_extrude(height=thickness+scales[i]/100, convexity=2, center=true) {
|
||||
back(scales[i]*.02) {
|
||||
|
|
|
|||
22
skin.scad
22
skin.scad
|
|
@ -14,6 +14,10 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_SKIN = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: skin.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
__vnf_no_n_mesg=" texture is a VNF so it does not accept n. Set sample rate for VNF textures using the tex_samples parameter to cyl(), linear_sweep(), or rotate_sweep().";
|
||||
|
||||
// Section: Skin and sweep
|
||||
|
|
@ -1608,16 +1612,16 @@ function spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fa
|
|||
// regardless of what kind of subsampling occurs for tapers.
|
||||
orig_anglist = [
|
||||
if (minang<0) minang,
|
||||
each reverse([for(ang = [-ang_step:-ang_step:minang+EPSILON]) ang]),
|
||||
for(ang = [0:ang_step:maxang-EPSILON]) ang,
|
||||
each reverse([for(ang = [-ang_step:-ang_step:minang+_EPSILON]) ang]),
|
||||
for(ang = [0:ang_step:maxang-_EPSILON]) ang,
|
||||
maxang
|
||||
],
|
||||
anglist = [
|
||||
for(a=orig_anglist) if (a<cut_ang1-EPSILON) a,
|
||||
for(a=orig_anglist) if (a<cut_ang1-_EPSILON) a,
|
||||
cut_ang1,
|
||||
for(a=orig_anglist) if (a>cut_ang1+EPSILON && a<cut_ang2-EPSILON) a,
|
||||
for(a=orig_anglist) if (a>cut_ang1+_EPSILON && a<cut_ang2-_EPSILON) a,
|
||||
cut_ang2,
|
||||
for(a=orig_anglist) if (a>cut_ang2+EPSILON) a
|
||||
for(a=orig_anglist) if (a>cut_ang2+_EPSILON) a
|
||||
],
|
||||
interp_ang = [
|
||||
for(i=idx(anglist,e=-2))
|
||||
|
|
@ -4054,8 +4058,8 @@ function texture(tex, n, border, gap, roughness, inset) =
|
|||
each path3d(square(1)),
|
||||
], [
|
||||
[4,7,3,0], [1,2,6,5],
|
||||
if (gap+border < 1-EPSILON) [4,5,6,7],
|
||||
if (gap > EPSILON) each [[1,9,10,2], [0,3,11,8]],
|
||||
if (gap+border < 1-_EPSILON) [4,5,6,7],
|
||||
if (gap > _EPSILON) each [[1,9,10,2], [0,3,11,8]],
|
||||
]
|
||||
] :
|
||||
tex=="wave_ribs"?
|
||||
|
|
@ -4063,7 +4067,7 @@ function texture(tex, n, border, gap, roughness, inset) =
|
|||
let(
|
||||
n = max(6,default(n,8))
|
||||
) [[
|
||||
for(a=[0:360/n:360-EPSILON])
|
||||
for(a=[0:360/n:360-_EPSILON])
|
||||
(cos(a)+1)/2
|
||||
]] :
|
||||
tex=="diamonds"?
|
||||
|
|
@ -4863,7 +4867,7 @@ function _textured_revolution(
|
|||
assert(taper>=0 && taper<=0.5, str("\ntex_taper must be between 0 and 0.5 but was ",taper,"."))
|
||||
function (x) lookup(x, [[0,0],
|
||||
if (taper==0.5) [taper,1]
|
||||
else each [[taper+EPSILON,1],[1-taper-EPSILON,1]],
|
||||
else each [[taper+_EPSILON,1],[1-taper-_EPSILON,1]],
|
||||
[1,0]])
|
||||
: is_path(taper,2) ?
|
||||
let(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// FileSummary: Simple sliders and rails.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_SLIDERS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: sliders.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Modules
|
||||
|
||||
|
|
|
|||
1
std.scad
1
std.scad
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
assert(version_num()>=20190500, "BOSL2 requires OpenSCAD version 2019.05 or later.");
|
||||
|
||||
_BOSL2_STD = true;
|
||||
|
||||
include <version.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_STRINGS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: strings.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
function _is_liststr(s) = is_list(s) || is_str(s);
|
||||
|
||||
|
|
@ -783,7 +785,7 @@ function _format_matrix(M, sig=4, sep=1, eps=1e-9) =
|
|||
// Example(NORENDER):
|
||||
// format("The value of {} is {:.14f}.", ["pi", PI]); // Returns: "The value of pi is 3.14159265358979."
|
||||
// format("The value {1:f} is known as {0}.", ["pi", PI]); // Returns: "The value 3.141593 is known as pi."
|
||||
// format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]); // Returns: "We use a very small value 1e-9 as EPSILON."
|
||||
// format("We use a very small value {1:.6g} as {0}.", ["_EPSILON", _EPSILON]); // Returns: "We use a very small value 1e-9 as _EPSILON."
|
||||
// format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]); // Returns: "foo 12000true"
|
||||
// format("{:-10s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostamus27.440"
|
||||
// format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostam 27.440"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_STRUCTS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: structs.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: struct operations
|
||||
//
|
||||
|
|
|
|||
|
|
@ -186,12 +186,12 @@ module test_all_zero() {
|
|||
assert(all_zero(0));
|
||||
assert(all_zero([0,0,0]));
|
||||
assert(!all_zero([[0,0,0],[0,0]]));
|
||||
assert(all_zero([EPSILON/2,EPSILON/2,EPSILON/2]));
|
||||
assert(all_zero([_EPSILON/2,_EPSILON/2,_EPSILON/2]));
|
||||
assert(!all_zero(1e-3));
|
||||
assert(!all_zero([0,0,1e-3]));
|
||||
assert(!all_zero([EPSILON*10,0,0]));
|
||||
assert(!all_zero([0,EPSILON*10,0]));
|
||||
assert(!all_zero([0,0,EPSILON*10]));
|
||||
assert(!all_zero([_EPSILON*10,0,0]));
|
||||
assert(!all_zero([0,_EPSILON*10,0]));
|
||||
assert(!all_zero([0,0,_EPSILON*10]));
|
||||
assert(!all_zero(true));
|
||||
assert(!all_zero(false));
|
||||
assert(!all_zero(INF));
|
||||
|
|
@ -218,14 +218,14 @@ module test_all_nonzero() {
|
|||
assert(!all_nonzero(0));
|
||||
assert(!all_nonzero([0,0,0]));
|
||||
assert(!all_nonzero([[0,0,0],[0,0]]));
|
||||
assert(!all_nonzero([EPSILON/2,EPSILON/2,EPSILON/2]));
|
||||
assert(!all_nonzero([_EPSILON/2,_EPSILON/2,_EPSILON/2]));
|
||||
assert(all_nonzero(1e-3));
|
||||
assert(!all_nonzero([0,0,1e-3]));
|
||||
assert(!all_nonzero([EPSILON*10,0,0]));
|
||||
assert(!all_nonzero([0,EPSILON*10,0]));
|
||||
assert(!all_nonzero([0,0,EPSILON*10]));
|
||||
assert(!all_nonzero([_EPSILON*10,0,0]));
|
||||
assert(!all_nonzero([0,_EPSILON*10,0]));
|
||||
assert(!all_nonzero([0,0,_EPSILON*10]));
|
||||
assert(all_nonzero([1e-3,1e-3,1e-3]));
|
||||
assert(all_nonzero([EPSILON*10,EPSILON*10,EPSILON*10]));
|
||||
assert(all_nonzero([_EPSILON*10,_EPSILON*10,_EPSILON*10]));
|
||||
assert(!all_nonzero(true));
|
||||
assert(!all_nonzero(false));
|
||||
assert(!all_nonzero(INF));
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ module test_line_from_points() {
|
|||
assert_approx(line_from_points([[1,0],[0,0],[-1,0]]),[[-1,0],[1,0]]);
|
||||
assert_approx(line_from_points([[1,1],[0,1],[-1,1]]),[[-1,1],[1,1]]);
|
||||
assert(line_from_points([[1,1],[0,1],[-1,0]],check_collinear=true)==undef);
|
||||
assert(line_from_points([[3,3],[0,3],[0,0]],check_collinear=false)-[[-0.5,0.5],[2.5,3.5]]<[[EPSILON,EPSILON],[EPSILON,EPSILON]]);
|
||||
assert(line_from_points([[3,3],[0,3],[0,0]],check_collinear=false)-[[-0.5,0.5],[2.5,3.5]]<[[_EPSILON,_EPSILON],[_EPSILON,_EPSILON]]);
|
||||
}
|
||||
*test_line_from_points();
|
||||
|
||||
|
|
@ -768,9 +768,9 @@ module test_polygon_area() {
|
|||
assert(approx(polygon_area(rot([13,27,75],
|
||||
p=path3d(circle(r=50,$fn=1000),fill=23)),
|
||||
signed=true), PI*50*50, eps=0.1));
|
||||
assert(abs(polygon_area([[0,0], [0,10], [10,0]],signed=true) + 50) < EPSILON);
|
||||
assert(abs(polygon_area([[0,0], [0,10], [0,15]],signed=true)) < EPSILON);
|
||||
assert(abs(polygon_area([[0,0], [10,0], [0,10]],signed=true) - 50) < EPSILON);
|
||||
assert(abs(polygon_area([[0,0], [0,10], [10,0]],signed=true) + 50) < _EPSILON);
|
||||
assert(abs(polygon_area([[0,0], [0,10], [0,15]],signed=true)) < _EPSILON);
|
||||
assert(abs(polygon_area([[0,0], [10,0], [0,10]],signed=true) - 50) < _EPSILON);
|
||||
}
|
||||
*test_polygon_area();
|
||||
|
||||
|
|
@ -902,7 +902,7 @@ module test_point_in_polygon() {
|
|||
assert(point_in_polygon([-5,5], poly) == 1);
|
||||
assert(point_in_polygon([-5,-5], poly) == 1);
|
||||
assert(point_in_polygon([5,-5], poly) == 1);
|
||||
assert(point_in_polygon([5,-5], poly,nonzero=false,eps=EPSILON) == 1);
|
||||
assert(point_in_polygon([5,-5], poly,nonzero=false,eps=_EPSILON) == 1);
|
||||
assert(point_in_polygon([-10,-10], poly) == -1);
|
||||
assert(point_in_polygon([10,0], poly) == 0);
|
||||
assert(point_in_polygon([0,10], poly) == 0);
|
||||
|
|
@ -912,7 +912,7 @@ module test_point_in_polygon() {
|
|||
assert(point_in_polygon([0,1], poly2,nonzero=true) == 0);
|
||||
assert(point_in_polygon([0,1], poly2,nonzero=false) == 0);
|
||||
assert(point_in_polygon([1,0], poly2,nonzero=false) == 0);
|
||||
assert(point_in_polygon([0,0], poly2,nonzero=false,eps=EPSILON) == -1);
|
||||
assert(point_in_polygon([0,0], poly2,nonzero=false,eps=_EPSILON) == -1);
|
||||
}
|
||||
*test_point_in_polygon();
|
||||
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ test_str_find();
|
|||
module test_format() {
|
||||
assert(format("The value of {} is {:.14f}.", ["pi", PI]) == "The value of pi is 3.14159265358979.");
|
||||
assert(format("The value {1:f} is known as {0}.", ["pi", PI]) == "The value 3.141593 is known as pi.");
|
||||
assert(format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]) == "We use a very small value 1e-9 as EPSILON.");
|
||||
assert(format("We use a very small value {1:.6g} as {0}.", ["_EPSILON", _EPSILON]) == "We use a very small value 1e-9 as _EPSILON.");
|
||||
assert(format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]) == "foo 12000true");
|
||||
assert(format("{:-10s}{:.3f}", ["plecostamus",27.43982]) == "plecostamus27.440");
|
||||
assert(format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]) == "plecostam 27.440");
|
||||
|
|
|
|||
|
|
@ -153,11 +153,11 @@ module test_unit() {
|
|||
assert(unit([10,0,0]) == [1,0,0]);
|
||||
assert(unit([0,10,0]) == [0,1,0]);
|
||||
assert(unit([0,0,10]) == [0,0,1]);
|
||||
assert(abs(norm(unit([10,10,10]))-1) < EPSILON);
|
||||
assert(abs(norm(unit([-10,-10,-10]))-1) < EPSILON);
|
||||
assert(abs(norm(unit([-10,0,0]))-1) < EPSILON);
|
||||
assert(abs(norm(unit([0,-10,0]))-1) < EPSILON);
|
||||
assert(abs(norm(unit([0,0,-10]))-1) < EPSILON);
|
||||
assert(abs(norm(unit([10,10,10]))-1) < _EPSILON);
|
||||
assert(abs(norm(unit([-10,-10,-10]))-1) < _EPSILON);
|
||||
assert(abs(norm(unit([-10,0,0]))-1) < _EPSILON);
|
||||
assert(abs(norm(unit([0,-10,0]))-1) < _EPSILON);
|
||||
assert(abs(norm(unit([0,0,-10]))-1) < _EPSILON);
|
||||
}
|
||||
test_unit();
|
||||
|
||||
|
|
@ -176,29 +176,29 @@ module test_vector_angle() {
|
|||
assert(vector_angle([a,b])==90);
|
||||
}
|
||||
}
|
||||
assert(abs(vector_angle([10,10,0],[10,0,0])-45) < EPSILON);
|
||||
assert(abs(vector_angle([[10,10,0],[10,0,0]])-45) < EPSILON);
|
||||
assert(abs(vector_angle([11,11,1],[1,1,1],[11,-9,1])-90) < EPSILON);
|
||||
assert(abs(vector_angle([[11,11,1],[1,1,1],[11,-9,1]])-90) < EPSILON);
|
||||
assert(abs(vector_angle([10,10,0],[10,0,0])-45) < _EPSILON);
|
||||
assert(abs(vector_angle([[10,10,0],[10,0,0]])-45) < _EPSILON);
|
||||
assert(abs(vector_angle([11,11,1],[1,1,1],[11,-9,1])-90) < _EPSILON);
|
||||
assert(abs(vector_angle([[11,11,1],[1,1,1],[11,-9,1]])-90) < _EPSILON);
|
||||
}
|
||||
test_vector_angle();
|
||||
|
||||
|
||||
module test_vector_axis() {
|
||||
assert(norm(vector_axis([10,0,0],[10,10,0]) - [0,0,1]) < EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[10,10,0]]) - [0,0,1]) < EPSILON);
|
||||
assert(norm(vector_axis([10,0,0],[0,10,0]) - [0,0,1]) < EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[0,10,0]]) - [0,0,1]) < EPSILON);
|
||||
assert(norm(vector_axis([0,10,0],[10,0,0]) - [0,0,-1]) < EPSILON);
|
||||
assert(norm(vector_axis([[0,10,0],[10,0,0]]) - [0,0,-1]) < EPSILON);
|
||||
assert(norm(vector_axis([0,0,10],[10,0,0]) - [0,1,0]) < EPSILON);
|
||||
assert(norm(vector_axis([[0,0,10],[10,0,0]]) - [0,1,0]) < EPSILON);
|
||||
assert(norm(vector_axis([10,0,0],[0,0,10]) - [0,-1,0]) < EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[0,0,10]]) - [0,-1,0]) < EPSILON);
|
||||
assert(norm(vector_axis([10,0,10],[0,-10,0]) - [sin(45),0,-sin(45)]) < EPSILON);
|
||||
assert(norm(vector_axis([[10,0,10],[0,-10,0]]) - [sin(45),0,-sin(45)]) < EPSILON);
|
||||
assert(norm(vector_axis([11,1,11],[1,1,1],[1,-9,1]) - [sin(45),0,-sin(45)]) < EPSILON);
|
||||
assert(norm(vector_axis([[11,1,11],[1,1,1],[1,-9,1]]) - [sin(45),0,-sin(45)]) < EPSILON);
|
||||
assert(norm(vector_axis([10,0,0],[10,10,0]) - [0,0,1]) < _EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[10,10,0]]) - [0,0,1]) < _EPSILON);
|
||||
assert(norm(vector_axis([10,0,0],[0,10,0]) - [0,0,1]) < _EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[0,10,0]]) - [0,0,1]) < _EPSILON);
|
||||
assert(norm(vector_axis([0,10,0],[10,0,0]) - [0,0,-1]) < _EPSILON);
|
||||
assert(norm(vector_axis([[0,10,0],[10,0,0]]) - [0,0,-1]) < _EPSILON);
|
||||
assert(norm(vector_axis([0,0,10],[10,0,0]) - [0,1,0]) < _EPSILON);
|
||||
assert(norm(vector_axis([[0,0,10],[10,0,0]]) - [0,1,0]) < _EPSILON);
|
||||
assert(norm(vector_axis([10,0,0],[0,0,10]) - [0,-1,0]) < _EPSILON);
|
||||
assert(norm(vector_axis([[10,0,0],[0,0,10]]) - [0,-1,0]) < _EPSILON);
|
||||
assert(norm(vector_axis([10,0,10],[0,-10,0]) - [sin(45),0,-sin(45)]) < _EPSILON);
|
||||
assert(norm(vector_axis([[10,0,10],[0,-10,0]]) - [sin(45),0,-sin(45)]) < _EPSILON);
|
||||
assert(norm(vector_axis([11,1,11],[1,1,1],[1,-9,1]) - [sin(45),0,-sin(45)]) < _EPSILON);
|
||||
assert(norm(vector_axis([[11,1,11],[1,1,1],[1,-9,1]]) - [sin(45),0,-sin(45)]) < _EPSILON);
|
||||
}
|
||||
test_vector_axis();
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
// FileSummary: Various types of threaded rods and nuts.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_THREADING = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: threading.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Thread Ends and Options
|
||||
// A standard process for making machine screws is to begin with round stock that has
|
||||
|
|
@ -1855,10 +1857,10 @@ module generic_threaded_rod(
|
|||
for (turns = [turns1:1:turns2])
|
||||
let(
|
||||
tang = turns/starts * 360 + ang,
|
||||
// EPSILON offset prevents funny looking extensions of the thread from its very tip
|
||||
// _EPSILON offset prevents funny looking extensions of the thread from its very tip
|
||||
// by forcing values near the tip to evaluate as less than zero = beyond the tip end
|
||||
hsc = tang < cut_ang1 ? lead_in_func(-EPSILON+1-(cut_ang1-tang)/lead_in_ang1,PI*2*r1adj*lead_in_ang1/360 )
|
||||
: tang > cut_ang2 ? lead_in_func(-EPSILON+1-(tang-cut_ang2)/lead_in_ang2,PI*2*r2adj*lead_in_ang2/360 )
|
||||
hsc = tang < cut_ang1 ? lead_in_func(-_EPSILON+1-(cut_ang1-tang)/lead_in_ang1,PI*2*r1adj*lead_in_ang1/360 )
|
||||
: tang > cut_ang2 ? lead_in_func(-_EPSILON+1-(tang-cut_ang2)/lead_in_ang2,PI*2*r2adj*lead_in_ang2/360 )
|
||||
: [1,1],
|
||||
shift_and_scale = [[hsc.x, 0], [0,hsc.y], [dz+turns,(1-hsc.y)*extreme]]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_TRANSFORMS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: transforms.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Affine Transformations
|
||||
// OpenSCAD provides various built-in modules to transform geometry by
|
||||
// translation, scaling, rotation, and mirroring. All of these operations
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_TRIGONOMETRY = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: triginometry.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: 2D General Triangle Functions
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileSummary: Tripod mount plates: RC2
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_TRIPOD_MOUNTS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: tripod_mounts.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Module: manfrotto_rc2_plate()
|
||||
// Synopsis: Creates a Manfrotto RC2 tripod quick release mount plate.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
// FileGroup: Advanced Modeling
|
||||
// FileSummary: 3D turtle graphics for making paths or lists of transformations.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_TURTLE3D = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: turtle3d.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
include<structs.scad>
|
||||
|
||||
// Section: Functions
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_UTILIITY = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: utility.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Type Checking
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
// FileFootnotes: STD=Included in std.scad
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_VECTORS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: vectors.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
// Section: Vector Testing
|
||||
|
||||
|
|
@ -29,7 +31,7 @@
|
|||
// ---
|
||||
// zero = If false, require that the `norm()` of the vector is not approximately zero. If true, require the `norm()` of the vector to be approximately zero. Default: `undef` (don't check vector `norm()`.)
|
||||
// all_nonzero = If true, requires all elements of the vector to be more than `eps` different from zero. Default: `false`
|
||||
// eps = The minimum vector length that is considered non-zero. Default: `EPSILON` (`1e-9`)
|
||||
// eps = The minimum vector length that is considered non-zero. Default: `_EPSILON` (`1e-9`)
|
||||
// Example:
|
||||
// is_vector(4); // Returns false
|
||||
// is_vector([4,true,false]); // Returns false
|
||||
|
|
@ -45,7 +47,7 @@
|
|||
// is_vector([0,1,0],all_nonzero=false); // Returns false
|
||||
// is_vector([1,1,1],all_nonzero=false); // Returns true
|
||||
// is_vector([],zero=false); // Returns false
|
||||
function is_vector(v, length, zero, all_nonzero=false, eps=EPSILON) =
|
||||
function is_vector(v, length, zero, all_nonzero=false, eps=_EPSILON) =
|
||||
is_list(v) && len(v)>0 && []==[for(vi=v) if(!is_finite(vi)) 0]
|
||||
&& (is_undef(length) || (assert(is_num(length))len(v)==length))
|
||||
&& (is_undef(zero) || ((norm(v) >= eps) == !zero))
|
||||
|
|
@ -222,7 +224,7 @@ function v_lookup(x, v) =
|
|||
// v6 = unit([0,0,0]); // Asserts an error.
|
||||
function unit(v, error=[[["ASSERT"]]]) =
|
||||
assert(is_vector(v), "\nInvalid vector.")
|
||||
norm(v)<EPSILON? (error==[[["ASSERT"]]]? assert(norm(v)>=EPSILON,"\nCannot normalize a zero vector.") : error) :
|
||||
norm(v)<_EPSILON? (error==[[["ASSERT"]]]? assert(norm(v)>=_EPSILON,"\nCannot normalize a zero vector.") : error) :
|
||||
v/norm(v);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_VERSION = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: version.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,716];
|
||||
|
||||
|
||||
|
|
|
|||
44
vnf.scad
44
vnf.scad
|
|
@ -14,6 +14,10 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
_BOSL2_VNF = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: vnf.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
|
||||
// Section: Creating Polyhedrons with VNF Structures
|
||||
// VNF stands for "Vertices'N'Faces". VNF structures are 2-item lists, `[VERTICES,FACES]` where the
|
||||
// first item is a list of vertex points, and the second is a list of face indices into the vertex
|
||||
|
|
@ -199,7 +203,7 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
|||
// )
|
||||
// ];
|
||||
// cap = [
|
||||
// for (a = [0:0.01:1+EPSILON]) apply(
|
||||
// for (a = [0:0.01:1+_EPSILON]) apply(
|
||||
// up(90-5*sin(a*360*2)) * scale([a,a,1]),
|
||||
// wall_points[0]
|
||||
// )
|
||||
|
|
@ -400,7 +404,7 @@ function vnf_vertex_array(
|
|||
let(
|
||||
area42 = norm(cross(pts[i2]-pts[i1], pts[i4]-pts[i1]))+norm(cross(pts[i4]-pts[i3], pts[i2]-pts[i3])),
|
||||
area13 = norm(cross(pts[i1]-pts[i4], pts[i3]-pts[i4]))+norm(cross(pts[i3]-pts[i2], pts[i1]-pts[i2])),
|
||||
minarea_edge = area42 < area13 + EPSILON
|
||||
minarea_edge = area42 < area13 + _EPSILON
|
||||
? [[i1,i4,i2],[i2,i4,i3]]
|
||||
: [[i1,i3,i2],[i1,i4,i3]]
|
||||
)
|
||||
|
|
@ -409,7 +413,7 @@ function vnf_vertex_array(
|
|||
let(
|
||||
d42=norm(pts[i4]-pts[i2]),
|
||||
d13=norm(pts[i1]-pts[i3]),
|
||||
shortedge = d42<d13+EPSILON
|
||||
shortedge = d42<d13+_EPSILON
|
||||
? [[i1,i4,i2],[i2,i4,i3]]
|
||||
: [[i1,i3,i2],[i1,i4,i3]]
|
||||
)
|
||||
|
|
@ -441,7 +445,7 @@ function vnf_vertex_array(
|
|||
// remove degenerate faces
|
||||
culled_faces= [for(face=faces)
|
||||
if (norm(cross(verts[face[1]]-verts[face[0]],
|
||||
verts[face[2]]-verts[face[0]]))>EPSILON)
|
||||
verts[face[2]]-verts[face[0]]))>_EPSILON)
|
||||
face
|
||||
],
|
||||
rfaces = reverse? [for (face=culled_faces) reverse(face)] : culled_faces
|
||||
|
|
@ -799,7 +803,7 @@ function vnf_join(vnfs) =
|
|||
// Arguments:
|
||||
// polygons = The list of 3D polygons to turn into a VNF
|
||||
// fast = Set to true to skip area and coplanarity checks for increased speed. Default: false
|
||||
// eps = Polygons with area smaller than this are discarded. Default: EPSILON
|
||||
// eps = Polygons with area smaller than this are discarded. Default: _EPSILON
|
||||
// Example(3D,VPR=[60,0,40]): Construction of a dodecahedron from pentagon faces.
|
||||
// dihedral = 2*atan(PHI); // dodecahedron face dihedral
|
||||
// rpenta = 10; // pentagon face radius
|
||||
|
|
@ -815,7 +819,7 @@ function vnf_join(vnfs) =
|
|||
// vnf = vnf_from_polygons(facepoints, fast=true);
|
||||
// vnf_polyhedron(vnf);
|
||||
|
||||
function vnf_from_polygons(polygons,fast=false,eps=EPSILON) =
|
||||
function vnf_from_polygons(polygons,fast=false,eps=_EPSILON) =
|
||||
assert(is_list(polygons) && is_path(polygons[0]),"\nInput should be a list of polygons.")
|
||||
let(
|
||||
offs = cumsum([0, for(p=polygons) len(p)]),
|
||||
|
|
@ -867,7 +871,7 @@ function _join_paths_at_vertices(path1,path2,v1,v2) =
|
|||
/// no crossings. It may return `undef` if these conditions are not met.
|
||||
/// This function implements an extension of the algorithm discussed in:
|
||||
/// https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
|
||||
function _cleave_connected_region(region, eps=EPSILON) =
|
||||
function _cleave_connected_region(region, eps=_EPSILON) =
|
||||
len(region)==1 ? region[0] :
|
||||
let(
|
||||
outer = deduplicate(region[0]), //
|
||||
|
|
@ -883,7 +887,7 @@ function _cleave_connected_region(region, eps=EPSILON) =
|
|||
// connect the hole paths one at a time to the outer path.
|
||||
// 'extremes' is the list of the right extreme vertex of each hole sorted by decreasing abscissas
|
||||
// see: _cleave_connected_region(region, eps)
|
||||
function _polyHoles(outer, holes, extremes, eps=EPSILON, n=0) =
|
||||
function _polyHoles(outer, holes, extremes, eps=_EPSILON, n=0) =
|
||||
let(
|
||||
extr = extremes[n], //
|
||||
hole = holes[extr[0]], // hole path to bridge to the outer path
|
||||
|
|
@ -1110,8 +1114,8 @@ function vnf_quantize(vnf,q=pow(2,-12)) =
|
|||
// To remove such vertices uses {{vnf_drop_unused_points()}}.
|
||||
// Arguments:
|
||||
// vnf = a VNF to consolidate
|
||||
// eps = the tolerance in finding duplicates. Default: EPSILON
|
||||
function vnf_merge_points(vnf,eps=EPSILON) =
|
||||
// eps = the tolerance in finding duplicates. Default: _EPSILON
|
||||
function vnf_merge_points(vnf,eps=_EPSILON) =
|
||||
let(
|
||||
verts = vnf[0],
|
||||
dedup = vector_search(verts,eps,verts), // collect vertex duplicates
|
||||
|
|
@ -1246,7 +1250,7 @@ function _detri_combine_faces(edgelist,faces,normals,facelist,curface) =
|
|||
edgepair = search([sort(select(thisface,i,i+1))],edgelist,0)[0],
|
||||
choices = select(edgelist,edgepair),
|
||||
good_choice=[for(choice=choices)
|
||||
if (choice[1]!=curface && in_list(choice[1],facelist) && normals[choice[1]]*normals[curface]>1-EPSILON)
|
||||
if (choice[1]!=curface && in_list(choice[1],facelist) && normals[choice[1]]*normals[curface]>1-_EPSILON)
|
||||
choice],
|
||||
d=assert(len(good_choice)<=1)
|
||||
)
|
||||
|
|
@ -1337,8 +1341,8 @@ function _split_polygon_at_x(poly, x) =
|
|||
out1 = [for (p = poly2) if(p.x <= x) p],
|
||||
out2 = [for (p = poly2) if(p.x >= x) p],
|
||||
out3 = [
|
||||
if (len(out1)>=3 && polygon_area(out1)>EPSILON) each split_path_at_self_crossings(out1),
|
||||
if (len(out2)>=3 && polygon_area(out2)>EPSILON) each split_path_at_self_crossings(out2),
|
||||
if (len(out1)>=3 && polygon_area(out1)>_EPSILON) each split_path_at_self_crossings(out1),
|
||||
if (len(out2)>=3 && polygon_area(out2)>_EPSILON) each split_path_at_self_crossings(out2),
|
||||
],
|
||||
out = [for (p=out3) if (len(p) > 2) list_unwrap(p)]
|
||||
) out;
|
||||
|
|
@ -1378,7 +1382,7 @@ function _slice_3dpolygons(polys, dir, cuts) =
|
|||
polyarea = polygon_area(poly),
|
||||
err=assert(!is_undef(polyarea), "\nvnf_slice encountered non-coplanar face.")
|
||||
)
|
||||
if (polyarea > EPSILON) // Discard zero area polygons
|
||||
if (polyarea > _EPSILON) // Discard zero area polygons
|
||||
let(
|
||||
plane = plane_from_polygon(poly,1e-4),
|
||||
err2 = assert(plane,"\nFound non-coplanar face."), // possibly redundant
|
||||
|
|
@ -1550,7 +1554,7 @@ function vnf_area(vnf) =
|
|||
/// Divide the solid up into tetrahedra with the origin as one vertex.
|
||||
/// The centroid of a tetrahedron is the average of its vertices.
|
||||
/// The centroid of the total is the volume weighted average.
|
||||
function _vnf_centroid(vnf,eps=EPSILON) =
|
||||
function _vnf_centroid(vnf,eps=_EPSILON) =
|
||||
assert(is_vnf(vnf) && len(vnf[0])!=0 && len(vnf[1])!=0,"\nInvalid or empty VNF given to centroid.")
|
||||
let(
|
||||
verts = vnf[0],
|
||||
|
|
@ -1641,7 +1645,7 @@ function vnf_bounds(vnf,fast=false) =
|
|||
// reg = projection(vnf,cut=true,z=0.3);
|
||||
// region(reg);
|
||||
|
||||
function projection(vnf,cut=false,z=0,eps=EPSILON) =
|
||||
function projection(vnf,cut=false,z=0,eps=_EPSILON) =
|
||||
assert(is_vnf(vnf))
|
||||
cut ?
|
||||
let(
|
||||
|
|
@ -1775,7 +1779,7 @@ function vnf_halfspace(plane, vnf, closed=true, boundary=false) =
|
|||
assert(_valid_plane(plane), "\nInvalid plane.")
|
||||
assert(is_vnf(vnf), "\nInvalid VNF.")
|
||||
let(
|
||||
inside = [for(x=vnf[0]) plane*[each x,-1] >= -EPSILON ? 1 : 0],
|
||||
inside = [for(x=vnf[0]) plane*[each x,-1] >= -_EPSILON ? 1 : 0],
|
||||
vertexmap = [0,each cumsum(inside)],
|
||||
faces_edges_vertices = _vnfcut(plane, vnf[0],vertexmap,inside, vnf[1], last(vertexmap)),
|
||||
newvert = concat(bselect(vnf[0],inside), faces_edges_vertices[2])
|
||||
|
|
@ -1798,7 +1802,7 @@ function vnf_halfspace(plane, vnf, closed=true, boundary=false) =
|
|||
|
||||
function _assemble_paths(vertices, edges, paths=[],i=0) =
|
||||
i==len(edges) ? paths :
|
||||
norm(vertices[edges[i][0]]-vertices[edges[i][1]])<EPSILON ? _assemble_paths(vertices,edges,paths,i+1) :
|
||||
norm(vertices[edges[i][0]]-vertices[edges[i][1]])<_EPSILON ? _assemble_paths(vertices,edges,paths,i+1) :
|
||||
let( // Find paths that connects on left side and right side of the edges (if one exists)
|
||||
left = [for(j=idx(paths)) if (approx(vertices[last(paths[j])],vertices[edges[i][0]])) j],
|
||||
right = [for(j=idx(paths)) if (approx(vertices[edges[i][1]],vertices[paths[j][0]])) j]
|
||||
|
|
@ -2291,7 +2295,7 @@ function vnf_sheet(vnf, delta, style="default", merge=true, thickness=undef) =
|
|||
/// }
|
||||
module _show_vertices(vertices, size=1, filter) {
|
||||
color("blue") {
|
||||
dups = vector_search(vertices, EPSILON, vertices);
|
||||
dups = vector_search(vertices, _EPSILON, vertices);
|
||||
for (ind = dups) {
|
||||
if (is_undef(filter) || any(ind, filter)) {
|
||||
numstr = str_join([for(i=ind) str(i)],",");
|
||||
|
|
@ -2542,7 +2546,7 @@ function _vnf_validate(vnf, show_warns=true, check_isects=false, big_face=false)
|
|||
face = faces[i],
|
||||
area = face_areas[i]
|
||||
)
|
||||
if (is_num(area) && abs(area) < EPSILON)
|
||||
if (is_num(area) && abs(area) < _EPSILON)
|
||||
_vnf_validate_err("NULL_FACE", face)
|
||||
],
|
||||
issues = concat(big_faces, null_faces)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// FileSummary: Walls and structural elements that 3D print without support.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_WALLS = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: walls.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
include<rounding.scad>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
// FileSummary: Routed bundles of wires.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
_BOSL2_WIRING = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ?
|
||||
echo("Warning: wiring.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true;
|
||||
|
||||
include <rounding.scad>
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue