Merge branch 'master' into master

This commit is contained in:
RonaldoCMP 2021-06-23 15:40:00 +01:00 committed by GitHub
commit d1f0bb00cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 382 additions and 431 deletions

15
.github/check_for_tabs.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"problemMatcher": [
{
"owner": "check_for_tabs",
"pattern": [
{
"regexp": "^([^:]+):(\\d+):(.*)$",
"file": 1,
"line": 2,
"message": 3
}
]
}
]
}

View File

@ -1,60 +0,0 @@
name: Docs
on:
pull_request:
branches: [master]
types: [closed]
jobs:
GenerateDocs:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout Wiki
uses: actions/checkout@v2
with:
repository: revarbat/BOSL2.wiki
path: BOSL2.wiki
- name: Apt Update
run: sudo apt update
- name: Install Packages
run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
- name: Install openscad-docsgen
run: sudo pip3 install openscad_docsgen
- name: Install OpenSCAD
run: |
cd $GITHUB_WORKSPACE
wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
sudo chmod +x /usr/local/bin/openscad
echo "::add-matcher::.github/openscad_docsgen.json"
- name: Generating Docs Headless
run: |
export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
xvfb-run --server-args="-screen 0, 1280x720x24" -a \
openscad-docsgen -ticmI *.scad
- name: Commit Wiki Docs
run: |
cd $GITHUB_WORKSPACE/BOSL2.wiki
git config user.name github-actions
git config user.email github-actions@github.com
git add --all
git commit -m "Wiki docs auto-regen." && git push || true
- name: Bump Release Version
run: |
cd $GITHUB_WORKSPACE
./scripts/increment_version.sh
git config user.name github-actions
git config user.email github-actions@github.com
git add version.scad
git commit -m "Bump release version." && git push || true

View File

@ -1,49 +0,0 @@
name: FDocs
on:
workflow_dispatch:
branches: [master]
jobs:
GenerateDocs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout Wiki
uses: actions/checkout@v2
with:
repository: revarbat/BOSL2.wiki
path: BOSL2.wiki
- name: Apt Update
run: sudo apt update
- name: Install Packages
run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
- name: Install openscad-docsgen
run: sudo pip3 install openscad_docsgen
- name: Install OpenSCAD
run: |
cd $GITHUB_WORKSPACE
wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
sudo chmod +x /usr/local/bin/openscad
echo "::add-matcher::.github/openscad_docsgen.json"
- name: Generating Docs Headless
run: |
export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
xvfb-run --server-args="-screen 0, 1280x720x24" -a \
openscad-docsgen -ticmIf *.scad
- name: Commit Wiki Docs
run: |
cd $GITHUB_WORKSPACE/BOSL2.wiki
git config user.name github-actions
git config user.email github-actions@github.com
git add --all
git commit -m "Wiki docs auto-regen." && git push || true

View File

@ -1,4 +1,4 @@
name: CI name: Checks
on: [pull_request] on: [pull_request]
jobs: jobs:
@ -49,6 +49,12 @@ jobs:
sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
sudo chmod +x /usr/local/bin/openscad sudo chmod +x /usr/local/bin/openscad
- name: Tabs Check
run: |
cd $GITHUB_WORKSPACE
echo "::add-matcher::.github/check_for_tabs.json"
./scripts/check_for_tabs.sh
- name: Checking Docs - name: Checking Docs
run: | run: |
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE

View File

@ -1,49 +0,0 @@
name: TestWorkflow
on:
workflow_dispatch:
branches: [master]
jobs:
TestJob:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout Wiki
uses: actions/checkout@v2
with:
repository: revarbat/BOSL2.wiki
path: BOSL2.wiki
- name: Setup OpenGL
uses: openrndr/setup-opengl@v1.1
- name: Apt Update
run: sudo apt update
- name: Install Packages
run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
- name: Install openscad-docsgen
run: sudo pip3 install openscad_docsgen
- name: Install OpenSCAD
run: |
cd $GITHUB_WORKSPACE
wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
sudo chmod +x /usr/local/bin/openscad
echo "::add-matcher::.github/openscad_docsgen.json"
- name: Make SCAD File
run: |
cd $GITHUB_WORKSPACE
echo "cube(50, center=100);" > testwf.scad
- name: TestScript
run: |
export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
xvfb-run --server-args="-screen 0, 1280x720x24" -a \
glxinfo

View File

@ -953,26 +953,32 @@ function shuffle(list,seed) =
function _group_sort_by_index(l,idx) = function _group_sort_by_index(l,idx) =
len(l) == 0 ? [] : len(l) == 0 ? [] :
len(l) == 1 ? [l] : len(l) == 1 ? [l] :
let( pivot = l[floor(len(l)/2)][idx], let(
equal = [ for(li=l) if( li[idx]==pivot) li ] , pivot = l[floor(len(l)/2)][idx],
lesser = [ for(li=l) if( li[idx]< pivot) li ] , equal = [ for(li=l) if( li[idx]==pivot) li ],
lesser = [ for(li=l) if( li[idx]< pivot) li ],
greater = [ for(li=l) if( li[idx]> pivot) li ] greater = [ for(li=l) if( li[idx]> pivot) li ]
) )
concat( _group_sort_by_index(lesser,idx), concat(
_group_sort_by_index(lesser,idx),
[equal], [equal],
_group_sort_by_index(greater,idx) ) ; _group_sort_by_index(greater,idx)
);
function _group_sort(l) = function _group_sort(l) =
len(l) == 0 ? [] : len(l) == 0 ? [] :
len(l) == 1 ? [l] : len(l) == 1 ? [l] :
let( pivot = l[floor(len(l)/2)], let(
pivot = l[floor(len(l)/2)],
equal = [ for(li=l) if( li==pivot) li ] , equal = [ for(li=l) if( li==pivot) li ] ,
lesser = [ for(li=l) if( li< pivot) li ] , lesser = [ for(li=l) if( li< pivot) li ] ,
greater = [ for(li=l) if( li> pivot) li ] greater = [ for(li=l) if( li> pivot) li ]
) )
concat( _group_sort(lesser), concat(
_group_sort(lesser),
[equal], [equal],
_group_sort(greater) ) ; _group_sort(greater)
);
// Sort a vector of scalar values with the native comparison operator // Sort a vector of scalar values with the native comparison operator
@ -1174,7 +1180,7 @@ function group_sort(list, idx) =
is_vector(list)? _group_sort(list) : is_vector(list)? _group_sort(list) :
let( idx = is_undef(idx) ? 0 : idx ) let( idx = is_undef(idx) ? 0 : idx )
assert( [for(entry=list) if(!is_list(entry) || len(entry)<idx || !is_num(entry[idx]) ) 1]==[], assert( [for(entry=list) if(!is_list(entry) || len(entry)<idx || !is_num(entry[idx]) ) 1]==[],
"Some entry of the list is a list shorter than `idx` or the indexed entry of it is not a number." ) "Some entry of the list is a list shorter than `idx` or the indexed entry of it is not a number.")
_group_sort_by_index(list,idx); _group_sort_by_index(list,idx);
@ -1199,21 +1205,25 @@ function unique(list) =
is_homogeneous(list,1) && ! is_list(list[0]) is_homogeneous(list,1) && ! is_list(list[0])
? _unique_sort(list) ? _unique_sort(list)
: let( sorted = sort(list)) : let( sorted = sort(list))
[ for (i=[0:1:len(sorted)-1]) [
for (i=[0:1:len(sorted)-1])
if (i==0 || (sorted[i] != sorted[i-1])) if (i==0 || (sorted[i] != sorted[i-1]))
sorted[i] sorted[i]
]; ];
function _unique_sort(l) = function _unique_sort(l) =
len(l) <= 1 ? l : len(l) <= 1 ? l :
let( pivot = l[floor(len(l)/2)], let(
pivot = l[floor(len(l)/2)],
equal = [ for(li=l) if( li==pivot) li ] , equal = [ for(li=l) if( li==pivot) li ] ,
lesser = [ for(li=l) if( li<pivot ) li ] , lesser = [ for(li=l) if( li<pivot ) li ] ,
greater = [ for(li=l) if( li>pivot) li ] greater = [ for(li=l) if( li>pivot) li ]
) )
concat( _unique_sort(lesser), concat(
_unique_sort(lesser),
equal[0], equal[0],
_unique_sort(greater) ) ; _unique_sort(greater)
);
// Function: unique_count() // Function: unique_count()
@ -1232,11 +1242,21 @@ function unique_count(list) =
assert(is_list(list) || is_string(list), "Invalid input." ) assert(is_list(list) || is_string(list), "Invalid input." )
list == [] ? [[],[]] : list == [] ? [[],[]] :
is_homogeneous(list,1) && ! is_list(list[0]) is_homogeneous(list,1) && ! is_list(list[0])
? let( sorted = _group_sort(list) ) ? let( sorted = _group_sort(list) ) [
[ [for(s=sorted) s[0] ], [for(s=sorted) len(s) ] ] [for(s=sorted) s[0] ],
: let( list=sort(list) ) [for(s=sorted) len(s) ]
let( ind = [0, for(i=[1:1:len(list)-1]) if (list[i]!=list[i-1]) i] ) ]
[ select(list,ind), deltas( concat(ind,[len(list)]) ) ]; : let(
list=sort(list),
ind = [
0,
for(i=[1:1:len(list)-1])
if (list[i]!=list[i-1]) i
]
) [
select(list,ind),
deltas( concat(ind,[len(list)]) )
];
// Section: List Iteration Helpers // Section: List Iteration Helpers

View File

@ -33,7 +33,7 @@ function _point_above_below_segment(point, edge) =
let( edge = edge - [point, point] ) let( edge = edge - [point, point] )
edge[0].y <= 0 edge[0].y <= 0
? (edge[1].y > 0 && cross(edge[0], edge[1]-edge[0]) > 0) ? 1 : 0 ? (edge[1].y > 0 && cross(edge[0], edge[1]-edge[0]) > 0) ? 1 : 0
: (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0 ; : (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0;
//Internal //Internal
function _valid_line(line,dim,eps=EPSILON) = function _valid_line(line,dim,eps=EPSILON) =
@ -77,8 +77,8 @@ function collinear(a, b, c, eps=EPSILON) =
"Input should be 3 points or a list of points with same dimension.") "Input should be 3 points or a list of points with same dimension.")
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( points = is_def(c) ? [a,b,c]: a ) let( points = is_def(c) ? [a,b,c]: a )
len(points)<3 ? true len(points)<3 ? true :
: noncollinear_triple(points,error=false,eps=eps)==[]; noncollinear_triple(points,error=false,eps=eps) == [];
// Function: point_line_distance() // Function: point_line_distance()
@ -131,8 +131,7 @@ function point_segment_distance(pt, seg) =
// dist = segment_distance([[-14,3], [-15,9]], [[-10,0], [10,0]]); // Returns: 5 // 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 // dist2 = segment_distance([[-5,5], [5,-5]], [[-10,3], [10,-3]]); // Returns: 0
function segment_distance(seg1, seg2) = function segment_distance(seg1, seg2) =
assert( is_matrix(concat(seg1,seg2),4), assert( is_matrix(concat(seg1,seg2),4), "Inputs should be two valid segments." )
"Inputs should be two valid segments." )
convex_distance(seg1,seg2); convex_distance(seg1,seg2);
@ -172,7 +171,8 @@ function line_normal(p1,p2) =
function _general_line_intersection(s1,s2,eps=EPSILON) = function _general_line_intersection(s1,s2,eps=EPSILON) =
let( let(
denominator = det2([s1[0],s2[0]]-[s1[1],s2[1]]) denominator = det2([s1[0],s2[0]]-[s1[1],s2[1]])
) approx(denominator,0,eps=eps)? [undef,undef,undef] : let( ) approx(denominator,0,eps=eps)? [undef,undef,undef] :
let(
t = det2([s1[0],s2[0]]-s2) / denominator, t = det2([s1[0],s2[0]]-s2) / denominator,
u = det2([s1[0],s1[0]]-[s2[0],s1[1]]) / denominator u = det2([s1[0],s1[0]]-[s2[0],s1[1]]) / denominator
) [s1[0]+t*(s1[1]-s1[0]), t, u]; ) [s1[0]+t*(s1[1]-s1[0]), t, u];
@ -211,11 +211,10 @@ function line_intersection(l1,l2,eps=EPSILON) =
function line_ray_intersection(line,ray,eps=EPSILON) = function line_ray_intersection(line,ray,eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
assert( _valid_line(line,dim=2,eps=eps) && _valid_line(ray,dim=2,eps=eps), "Invalid line or ray." ) assert( _valid_line(line,dim=2,eps=eps) && _valid_line(ray,dim=2,eps=eps), "Invalid line or ray." )
let( let( isect = _general_line_intersection(line,ray,eps=eps) )
isect = _general_line_intersection(line,ray,eps=eps)
)
is_undef(isect[0]) ? undef : is_undef(isect[0]) ? undef :
(isect[2]<0-eps) ? undef : isect[0]; (isect[2]<0-eps) ? undef :
isect[0];
// Function: line_segment_intersection() // Function: line_segment_intersection()
@ -232,9 +231,7 @@ function line_ray_intersection(line,ray,eps=EPSILON) =
function line_segment_intersection(line,segment,eps=EPSILON) = function line_segment_intersection(line,segment,eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
assert( _valid_line(line, dim=2,eps=eps) &&_valid_line(segment,dim=2,eps=eps), "Invalid line or segment." ) assert( _valid_line(line, dim=2,eps=eps) &&_valid_line(segment,dim=2,eps=eps), "Invalid line or segment." )
let( let( isect = _general_line_intersection(line,segment,eps=eps) )
isect = _general_line_intersection(line,segment,eps=eps)
)
is_undef(isect[0]) ? undef : is_undef(isect[0]) ? undef :
isect[2]<0-eps || isect[2]>1+eps ? undef : isect[2]<0-eps || isect[2]>1+eps ? undef :
isect[0]; isect[0];
@ -254,11 +251,10 @@ function line_segment_intersection(line,segment,eps=EPSILON) =
function ray_intersection(r1,r2,eps=EPSILON) = function ray_intersection(r1,r2,eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
assert( _valid_line(r1,dim=2,eps=eps) && _valid_line(r2,dim=2,eps=eps), "Invalid ray(s)." ) assert( _valid_line(r1,dim=2,eps=eps) && _valid_line(r2,dim=2,eps=eps), "Invalid ray(s)." )
let( let( isect = _general_line_intersection(r1,r2,eps=eps) )
isect = _general_line_intersection(r1,r2,eps=eps)
)
is_undef(isect[0]) ? undef : is_undef(isect[0]) ? undef :
isect[1]<0-eps || isect[2]<0-eps ? undef : isect[0]; isect[1]<0-eps || isect[2]<0-eps ? undef :
isect[0];
// Function: ray_segment_intersection() // Function: ray_segment_intersection()
@ -275,9 +271,7 @@ function ray_intersection(r1,r2,eps=EPSILON) =
function ray_segment_intersection(ray,segment,eps=EPSILON) = function ray_segment_intersection(ray,segment,eps=EPSILON) =
assert( _valid_line(ray,dim=2,eps=eps) && _valid_line(segment,dim=2,eps=eps), "Invalid ray or segment." ) assert( _valid_line(ray,dim=2,eps=eps) && _valid_line(segment,dim=2,eps=eps), "Invalid ray or segment." )
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( let( isect = _general_line_intersection(ray,segment,eps=eps) )
isect = _general_line_intersection(ray,segment,eps=eps)
)
is_undef(isect[0]) ? undef : is_undef(isect[0]) ? undef :
isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
isect[0]; isect[0];
@ -297,9 +291,7 @@ function ray_segment_intersection(ray,segment,eps=EPSILON) =
function segment_intersection(s1,s2,eps=EPSILON) = function segment_intersection(s1,s2,eps=EPSILON) =
assert( _valid_line(s1,dim=2,eps=eps) && _valid_line(s2,dim=2,eps=eps), "Invalid segment(s)." ) assert( _valid_line(s1,dim=2,eps=eps) && _valid_line(s2,dim=2,eps=eps), "Invalid segment(s)." )
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( let( isect = _general_line_intersection(s1,s2,eps=eps) )
isect = _general_line_intersection(s1,s2,eps=eps)
)
is_undef(isect[0]) ? undef : is_undef(isect[0]) ? undef :
isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef : isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
isect[0]; isect[0];
@ -361,7 +353,7 @@ function line_closest_point(line,pt) =
assert(_valid_line(line), "Invalid line." ) assert(_valid_line(line), "Invalid line." )
assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." ) assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." )
let( n = unit( line[0]- line[1]) ) let( n = unit( line[0]- line[1]) )
line[1]+((pt- line[1]) * n) * n; line[1] + ((pt- line[1]) * n) * n;
// Function: ray_closest_point() // Function: ray_closest_point()
@ -503,7 +495,9 @@ function line_from_points(points, fast=false, eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( pb = furthest_point(points[0],points) ) let( pb = furthest_point(points[0],points) )
norm(points[pb]-points[0])<eps*max(norm(points[pb]),norm(points[0])) ? undef : norm(points[pb]-points[0])<eps*max(norm(points[pb]),norm(points[0])) ? undef :
fast || collinear(points) ? [points[pb], points[0]] : undef; fast || collinear(points)
? [points[pb], points[0]]
: undef;
@ -576,7 +570,8 @@ function law_of_sines(a, A, b, B) =
// a/sin(A) = b/sin(B) = c/sin(C) // a/sin(A) = b/sin(B) = c/sin(C)
assert(num_defined([b,B]) == 1, "Must give exactly one of b= or B=.") assert(num_defined([b,B]) == 1, "Must give exactly one of b= or B=.")
let( r = a/sin(A) ) let( r = a/sin(A) )
is_undef(b) ? r*sin(B) : asin(constrain(b/r, -1, 1)); is_undef(b) ? r*sin(B) :
asin(constrain(b/r, -1, 1));
// Function: tri_calc() // Function: tri_calc()
@ -647,11 +642,11 @@ function tri_calc(ang,ang2,adj,opp,hyp) =
hyp hyp
: (adj!=undef? (adj/cos(ang)) : (adj!=undef? (adj/cos(ang))
: (opp/sin(ang))) : (opp/sin(ang)))
) ) [adj, opp, hyp, ang, ang2];
[adj, opp, hyp, ang, ang2];
// Function: hyp_opp_to_adj() // Function: hyp_opp_to_adj()
// Alias: opp_hyp_to_adj()
// Usage: // Usage:
// adj = hyp_opp_to_adj(hyp,opp); // adj = hyp_opp_to_adj(hyp,opp);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -668,8 +663,11 @@ function hyp_opp_to_adj(hyp,opp) =
"Triangle side lengths should be a positive numbers." ) "Triangle side lengths should be a positive numbers." )
sqrt(hyp*hyp-opp*opp); sqrt(hyp*hyp-opp*opp);
function opp_hyp_to_adj(opp,hyp) = hyp_opp_to_adj(hyp,opp);
// Function: hyp_ang_to_adj() // Function: hyp_ang_to_adj()
// Alias: ang_hyp_to_adj()
// Usage: // Usage:
// adj = hyp_ang_to_adj(hyp,ang); // adj = hyp_ang_to_adj(hyp,ang);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -686,8 +684,11 @@ function hyp_ang_to_adj(hyp,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
hyp*cos(ang); hyp*cos(ang);
function ang_hyp_to_adj(ang,hyp) = hyp_ang_to_adj(hyp, ang);
// Function: opp_ang_to_adj() // Function: opp_ang_to_adj()
// Alias: ang_opp_to_adj()
// Usage: // Usage:
// adj = opp_ang_to_adj(opp,ang); // adj = opp_ang_to_adj(opp,ang);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -704,8 +705,11 @@ function opp_ang_to_adj(opp,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
opp/tan(ang); opp/tan(ang);
function ang_opp_to_adj(ang,opp) = opp_ang_to_adj(opp,ang);
// Function: hyp_adj_to_opp() // Function: hyp_adj_to_opp()
// Alias: adj_hyp_to_opp()
// Usage: // Usage:
// opp = hyp_adj_to_opp(hyp,adj); // opp = hyp_adj_to_opp(hyp,adj);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -721,8 +725,11 @@ function hyp_adj_to_opp(hyp,adj) =
"Triangle side lengths should be a positive numbers." ) "Triangle side lengths should be a positive numbers." )
sqrt(hyp*hyp-adj*adj); sqrt(hyp*hyp-adj*adj);
function adj_hyp_to_opp(adj,hyp) = hyp_adj_to_opp(hyp,adj);
// Function: hyp_ang_to_opp() // Function: hyp_ang_to_opp()
// Alias: ang_hyp_to_opp()
// Usage: // Usage:
// opp = hyp_ang_to_opp(hyp,adj); // opp = hyp_ang_to_opp(hyp,adj);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -738,8 +745,11 @@ function hyp_ang_to_opp(hyp,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
hyp*sin(ang); hyp*sin(ang);
function ang_hyp_to_opp(ang,hyp) = hyp_ang_to_opp(hyp,ang);
// Function: adj_ang_to_opp() // Function: adj_ang_to_opp()
// Alias: ang_adj_to_opp()
// Usage: // Usage:
// opp = adj_ang_to_opp(adj,ang); // opp = adj_ang_to_opp(adj,ang);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -755,8 +765,11 @@ function adj_ang_to_opp(adj,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
adj*tan(ang); adj*tan(ang);
function ang_adj_to_opp(ang,adj) = adj_ang_to_opp(adj,ang);
// Function: adj_opp_to_hyp() // Function: adj_opp_to_hyp()
// Alias: opp_adj_to_hyp()
// Usage: // Usage:
// hyp = adj_opp_to_hyp(adj,opp); // hyp = adj_opp_to_hyp(adj,opp);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -772,8 +785,11 @@ function adj_opp_to_hyp(adj,opp) =
"Triangle side lengths should be a positive numbers." ) "Triangle side lengths should be a positive numbers." )
norm([opp,adj]); norm([opp,adj]);
function opp_adj_to_hyp(opp,adj) = adj_opp_to_hyp(adj,opp);
// Function: adj_ang_to_hyp() // Function: adj_ang_to_hyp()
// Alias: ang_adj_to_hyp()
// Usage: // Usage:
// hyp = adj_ang_to_hyp(adj,ang); // hyp = adj_ang_to_hyp(adj,ang);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -789,8 +805,11 @@ function adj_ang_to_hyp(adj,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
adj/cos(ang); adj/cos(ang);
function ang_adj_to_hyp(ang,adj) = adj_ang_to_hyp(adj,ang);
// Function: opp_ang_to_hyp() // Function: opp_ang_to_hyp()
// Alias: ang_opp_to_hyp()
// Usage: // Usage:
// hyp = opp_ang_to_hyp(opp,ang); // hyp = opp_ang_to_hyp(opp,ang);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -806,8 +825,11 @@ function opp_ang_to_hyp(opp,ang) =
assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
opp/sin(ang); opp/sin(ang);
function ang_opp_to_hyp(ang,opp) = opp_ang_to_hyp(opp,ang);
// Function: hyp_adj_to_ang() // Function: hyp_adj_to_ang()
// Alias: adj_hyp_to_ang()
// Usage: // Usage:
// ang = hyp_adj_to_ang(hyp,adj); // ang = hyp_adj_to_ang(hyp,adj);
// Description: // Description:
@ -822,8 +844,11 @@ function hyp_adj_to_ang(hyp,adj) =
"Triangle side lengths should be positive numbers." ) "Triangle side lengths should be positive numbers." )
acos(adj/hyp); acos(adj/hyp);
function adj_hyp_to_ang(adj,hyp) = hyp_adj_to_ang(hyp,adj);
// Function: hyp_opp_to_ang() // Function: hyp_opp_to_ang()
// Alias: opp_hyp_to_ang()
// Usage: // Usage:
// ang = hyp_opp_to_ang(hyp,opp); // ang = hyp_opp_to_ang(hyp,opp);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -839,8 +864,11 @@ function hyp_opp_to_ang(hyp,opp) =
"Triangle side lengths should be positive numbers." ) "Triangle side lengths should be positive numbers." )
asin(opp/hyp); asin(opp/hyp);
function opp_hyp_to_ang(opp,hyp) = hyp_opp_to_ang(hyp,opp);
// Function: adj_opp_to_ang() // Function: adj_opp_to_ang()
// Alias: opp_adj_to_ang()
// Usage: // Usage:
// ang = adj_opp_to_ang(adj,opp); // ang = adj_opp_to_ang(adj,opp);
// Topics: Geometry, Triangles // Topics: Geometry, Triangles
@ -856,6 +884,8 @@ function adj_opp_to_ang(adj,opp) =
"Triangle side lengths should be positive numbers." ) "Triangle side lengths should be positive numbers." )
atan2(opp,adj); atan2(opp,adj);
function opp_adj_to_ang(opp,adj) = adj_opp_to_ang(adj,opp);
// Function: triangle_area() // Function: triangle_area()
// Usage: // Usage:
@ -900,8 +930,7 @@ function plane3pt(p1, p2, p3) =
let( let(
crx = cross(p3-p1, p2-p1), crx = cross(p3-p1, p2-p1),
nrm = norm(crx) nrm = norm(crx)
) ) approx(nrm,0) ? [] :
approx(nrm,0) ? [] :
concat(crx, crx*p1)/nrm; concat(crx, crx*p1)/nrm;
@ -928,8 +957,7 @@ function plane3pt_indexed(points, i1, i2, i3) =
p1 = points[i1], p1 = points[i1],
p2 = points[i2], p2 = points[i2],
p3 = points[i3] p3 = points[i3]
) ) plane3pt(p1,p2,p3);
plane3pt(p1,p2,p3);
// Function: plane_from_normal() // Function: plane_from_normal()
@ -1021,7 +1049,8 @@ function plane_from_points(points, fast=false, eps=EPSILON) =
pm = covmix[0], pm = covmix[0],
evec = covmix[1], evec = covmix[1],
eval0 = covmix[2], eval0 = covmix[2],
plane = [ each evec, pm*evec] ) plane = [ each evec, pm*evec]
)
!fast && _pointlist_greatest_distance(points,plane)>eps*eval0 ? undef : !fast && _pointlist_greatest_distance(points,plane)>eps*eval0 ? undef :
plane ; plane ;
@ -1197,8 +1226,7 @@ function plane_line_angle(plane, line) =
normal = plane_normal(plane), normal = plane_normal(plane),
sin_angle = linedir*normal, sin_angle = linedir*normal,
cos_angle = norm(cross(linedir,normal)) cos_angle = norm(cross(linedir,normal))
) ) atan2(sin_angle,cos_angle);
atan2(sin_angle,cos_angle);
// Function: plane_line_intersection() // Function: plane_line_intersection()
@ -1222,8 +1250,7 @@ function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) =
let( let(
bounded = is_list(bounded)? bounded : [bounded, bounded], bounded = is_list(bounded)? bounded : [bounded, bounded],
res = _general_plane_line_intersection(plane, line, eps=eps) res = _general_plane_line_intersection(plane, line, eps=eps)
) ) is_undef(res) ? undef :
is_undef(res) ? undef :
is_undef(res[1]) ? res[0] : is_undef(res[1]) ? res[0] :
bounded[0] && res[1]<0 ? undef : bounded[0] && res[1]<0 ? undef :
bounded[1] && res[1]>1 ? undef : bounded[1] && res[1]>1 ? undef :
@ -1254,41 +1281,37 @@ function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) =
bounded = is_list(bounded)? bounded : [bounded, bounded], bounded = is_list(bounded)? bounded : [bounded, bounded],
poly = deduplicate(poly), poly = deduplicate(poly),
indices = noncollinear_triple(poly) indices = noncollinear_triple(poly)
) ) indices==[] ? undef :
indices==[] ? undef :
let( let(
p1 = poly[indices[0]], p1 = poly[indices[0]],
p2 = poly[indices[1]], p2 = poly[indices[1]],
p3 = poly[indices[2]], p3 = poly[indices[2]],
plane = plane3pt(p1,p2,p3), plane = plane3pt(p1,p2,p3),
res = _general_plane_line_intersection(plane, line, eps=eps) res = _general_plane_line_intersection(plane, line, eps=eps)
) ) is_undef(res)? undef :
is_undef(res)? undef : is_undef(res[1]) ? (
is_undef(res[1]) let(// Line is on polygon plane.
? ( let(// Line is on polygon plane.
linevec = unit(line[1] - line[0]), linevec = unit(line[1] - line[0]),
lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec, lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec,
lp2 = line[1] + (bounded[1]? 0 : 1000000) * linevec, lp2 = line[1] + (bounded[1]? 0 : 1000000) * linevec,
poly2d = clockwise_polygon(project_plane(plane, poly)), poly2d = clockwise_polygon(project_plane(plane, poly)),
line2d = project_plane(plane, [lp1,lp2]), line2d = project_plane(plane, [lp1,lp2]),
parts = split_path_at_region_crossings(line2d, [poly2d], closed=false), parts = split_path_at_region_crossings(line2d, [poly2d], closed=false),
inside = [for (part = parts) inside = [
for (part = parts)
if (point_in_polygon(mean(part), poly2d)>0) part if (point_in_polygon(mean(part), poly2d)>0) part
] ]
) ) !inside? undef :
!inside? undef : let( isegs = [for (seg = inside) lift_plane(plane, seg) ] )
let(
isegs = [for (seg = inside) lift_plane(plane, seg) ]
)
isegs isegs
) ) :
: bounded[0] && res[1]<0? undef : bounded[0] && res[1]<0? undef :
bounded[1] && res[1]>1? undef : bounded[1] && res[1]>1? undef :
let( let(
proj = clockwise_polygon(project_plane([p1, p2, p3], poly)), proj = clockwise_polygon(project_plane([p1, p2, p3], poly)),
pt = project_plane([p1, p2, p3], res[0]) pt = project_plane([p1, p2, p3], res[0])
) ) point_in_polygon(pt, proj) < 0 ? undef :
point_in_polygon(pt, proj) < 0 ? undef : res[0]; res[0];
// Function: plane_intersection() // Function: plane_intersection()
@ -1321,7 +1344,8 @@ function plane_intersection(plane1,plane2,plane3) =
rhs = [plane1[3], plane2[3]], rhs = [plane1[3], plane2[3]],
point = linear_solve(matrix,rhs) point = linear_solve(matrix,rhs)
) )
point==[]? undef: [point, point+normal]; point==[]? undef:
[point, point+normal];
// Function: coplanar() // Function: coplanar()
@ -1482,6 +1506,7 @@ function circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
) )
[cp, n, tp1, tp2, dang1, dang2]; [cp, n, tp1, tp2, dang1, dang2];
module circle_2tangents(pt1, pt2, pt3, r, d, h, center=false) { module circle_2tangents(pt1, pt2, pt3, r, d, h, center=false) {
c = circle_2tangents(pt1=pt1, pt2=pt2, pt3=pt3, r=r, d=d); c = circle_2tangents(pt1=pt1, pt2=pt2, pt3=pt3, r=r, d=d);
assert(!is_undef(c), "Cannot find circle when both rays are collinear."); assert(!is_undef(c), "Cannot find circle when both rays are collinear.");
@ -1498,6 +1523,7 @@ module circle_2tangents(pt1, pt2, pt3, r, d, h, center=false) {
} }
} }
// Function&Module: circle_3points() // Function&Module: circle_3points()
// Usage: As Function // Usage: As Function
// circ = circle_3points(pt1, pt2, pt3); // circ = circle_3points(pt1, pt2, pt3);
@ -1758,17 +1784,15 @@ function noncollinear_triple(points,error=true,eps=EPSILON) =
pb = points[b], pb = points[b],
nrm = norm(pa-pb) nrm = norm(pa-pb)
) )
nrm <= eps*max(norm(pa),norm(pb)) nrm <= eps*max(norm(pa),norm(pb)) ?
? assert(!error, "Cannot find three noncollinear points in pointlist.") assert(!error, "Cannot find three noncollinear points in pointlist.") [] :
[] let(
: let(
n = (pb-pa)/nrm, n = (pb-pa)/nrm,
distlist = [for(i=[0:len(points)-1]) _dist2line(points[i]-pa, n)] distlist = [for(i=[0:len(points)-1]) _dist2line(points[i]-pa, n)]
) )
max(distlist) < eps*nrm max(distlist) < eps*nrm ?
? assert(!error, "Cannot find three noncollinear points in pointlist.") assert(!error, "Cannot find three noncollinear points in pointlist.") [] :
[] [0, b, max_index(distlist)];
: [0,b,max_index(distlist)];
// Function: pointlist_bounds() // Function: pointlist_bounds()
@ -1785,10 +1809,12 @@ function pointlist_bounds(pts) =
assert(is_path(pts,dim=undef,fast=true) , "Invalid pointlist." ) assert(is_path(pts,dim=undef,fast=true) , "Invalid pointlist." )
let( let(
select = ident(len(pts[0])), select = ident(len(pts[0])),
spread = [for(i=[0:len(pts[0])-1]) spread = [
for(i=[0:len(pts[0])-1])
let( spreadi = pts*select[i] ) let( spreadi = pts*select[i] )
[min(spreadi), max(spreadi)] ] ) [ min(spreadi), max(spreadi) ]
transpose(spread); ]
) transpose(spread);
// Function: closest_point() // Function: closest_point()
@ -1967,7 +1993,8 @@ function align_polygon(reference, poly, angles, cp) =
"The `angle` parameter must be a range or a non void list of numbers.") "The `angle` parameter must be a range or a non void list of numbers.")
let( // alignments is a vector of entries of the form: [polygon, error] let( // alignments is a vector of entries of the form: [polygon, error]
alignments = [ alignments = [
for(angle=angles) reindex_polygon( for(angle=angles)
reindex_polygon(
reference, reference,
zrot(angle,p=poly,cp=cp), zrot(angle,p=poly,cp=cp),
return_error=true return_error=true
@ -1994,19 +2021,18 @@ function centroid(poly, eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( let(
n = len(poly[0])==2 ? 1 : n = len(poly[0])==2 ? 1 :
let( let( plane = plane_from_points(poly, fast=true) )
plane = plane_from_points(poly, fast=true) )
assert( !is_undef(plane), "The polygon must be planar." ) assert( !is_undef(plane), "The polygon must be planar." )
plane_normal(plane), plane_normal(plane),
v0 = poly[0] , v0 = poly[0] ,
val = sum([for(i=[1:len(poly)-2]) val = sum([
for(i=[1:len(poly)-2])
let( let(
v1 = poly[i], v1 = poly[i],
v2 = poly[i+1], v2 = poly[i+1],
area = cross(v2-v0,v1-v0)*n area = cross(v2-v0,v1-v0)*n
) ) [ area, (v0+v1+v2)*area ]
[ area, (v0+v1+v2)*area ] ])
] )
) )
assert(!approx(val[0],0, eps), "The polygon is self-intersecting or its points are collinear.") assert(!approx(val[0],0, eps), "The polygon is self-intersecting or its points are collinear.")
val[1]/val[0]/3; val[1]/val[0]/3;
@ -2040,38 +2066,39 @@ function point_in_polygon(point, poly, nonzero=true, eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
// Does the point lie on any edges? If so return 0. // Does the point lie on any edges? If so return 0.
let( let(
on_brd = [for(i=[0:1:len(poly)-1]) on_brd = [
for (i = [0:1:len(poly)-1])
let( seg = select(poly,i,i+1) ) let( seg = select(poly,i,i+1) )
if( !approx(seg[0],seg[1],eps) ) if (!approx(seg[0],seg[1],eps) )
point_on_segment2d(point, seg, eps=eps)? 1:0 ] point_on_segment2d(point, seg, eps=eps)? 1:0
)
sum(on_brd) > 0
? 0
: nonzero
? // Compute winding number and return 1 for interior, -1 for exterior
let(
windchk = [for(i=[0:1:len(poly)-1])
let(seg=select(poly,i,i+1))
if(!approx(seg[0],seg[1],eps=eps))
_point_above_below_segment(point, seg)
] ]
) )
sum(windchk) != 0 ? 1 : -1 sum(on_brd) > 0? 0 :
nonzero
? // Compute winding number and return 1 for interior, -1 for exterior
let(
windchk = [
for(i=[0:1:len(poly)-1])
let( seg=select(poly,i,i+1) )
if (!approx(seg[0],seg[1],eps=eps))
_point_above_below_segment(point, seg)
]
) sum(windchk) != 0 ? 1 : -1
: // or compute the crossings with the ray [point, point+[1,0]] : // or compute the crossings with the ray [point, point+[1,0]]
let( let(
n = len(poly), n = len(poly),
cross = cross = [
[for(i=[0:n-1]) for(i=[0:n-1])
let( let(
p0 = poly[i]-point, p0 = poly[i]-point,
p1 = poly[(i+1)%n]-point p1 = poly[(i+1)%n]-point
) )
if( ( (p1.y>eps && p0.y<=eps) || (p1.y<=eps && p0.y>eps) ) if (
&& -eps < p0.x - p0.y *(p1.x - p0.x)/(p1.y - p0.y) ) ( (p1.y>eps && p0.y<=eps) || (p1.y<=eps && p0.y>eps) )
1 && -eps < p0.x - p0.y *(p1.x - p0.x)/(p1.y - p0.y)
) 1
] ]
) ) 2*(len(cross)%2)-1;
2*(len(cross)%2)-1;
// Function: polygon_is_clockwise() // Function: polygon_is_clockwise()
@ -2124,7 +2151,7 @@ function ccw_polygon(poly) =
// poly = The list of the path points for the perimeter of the polygon. // poly = The list of the path points for the perimeter of the polygon.
function reverse_polygon(poly) = function reverse_polygon(poly) =
assert(is_path(poly), "Input should be a polygon") assert(is_path(poly), "Input should be a polygon")
[poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ]; [ poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ];
// Function: polygon_normal() // Function: polygon_normal()
@ -2321,8 +2348,10 @@ function split_polygons_at_each_z(polys, zs, _i=0) =
// test = is_convex_polygon(spiral); // Returns: false // test = is_convex_polygon(spiral); // Returns: false
function is_convex_polygon(poly,eps=EPSILON) = function is_convex_polygon(poly,eps=EPSILON) =
assert(is_path(poly), "The input should be a 2D or 3D polygon." ) assert(is_path(poly), "The input should be a 2D or 3D polygon." )
let( lp = len(poly), let(
p0 = poly[0] ) lp = len(poly),
p0 = poly[0]
)
assert( lp>=3 , "A polygon must have at least 3 points" ) assert( lp>=3 , "A polygon must have at least 3 points" )
let( crosses = [for(i=[0:1:lp-1]) cross(poly[(i+1)%lp]-poly[i], poly[(i+2)%lp]-poly[(i+1)%lp]) ] ) let( crosses = [for(i=[0:1:lp-1]) cross(poly[(i+1)%lp]-poly[i], poly[(i+2)%lp]-poly[(i+1)%lp]) ] )
len(p0)==2 len(p0)==2

View File

@ -791,12 +791,16 @@ function _med3(a,b,c) =
// d = convolve([[1,1],[2,2],[3,1]],[[1,2],[2,1]])); // Returns: [3,9,11,7] // d = convolve([[1,1],[2,2],[3,1]],[[1,2],[2,1]])); // Returns: [3,9,11,7]
function convolve(p,q) = function convolve(p,q) =
p==[] || q==[] ? [] : p==[] || q==[] ? [] :
assert( (is_vector(p) || is_matrix(p)) assert(
(is_vector(p) || is_matrix(p))
&& ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) , && ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) ,
"The inputs should be vectors or paths all of the same dimension.") "The inputs should be vectors or paths all of the same dimension."
let( n = len(p), )
m = len(q)) let(
[for(i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) ) n = len(p),
m = len(q)
) [
for (i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) )
sum([for(j=[k1:k2]) p[i-j]*q[j] ]) sum([for(j=[k1:k2]) p[i-j]*q[j] ])
]; ];

9
scripts/check_for_tabs.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
if grep -H -n -P '\t' *.scad ; then
echo "Tabs found in source code." 2>&1
exit 1
fi
exit 0

View File

@ -405,6 +405,8 @@ function cuboid(
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0`
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP` // orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#orient). Default: `UP`
// //
// See Also: rounded_prism()
//
// Example: Rectangular Pyramid // Example: Rectangular Pyramid
// prismoid([40,40], [0,0], h=20); // prismoid([40,40], [0,0], h=20);
// Example: Prism // Example: Prism
@ -479,8 +481,8 @@ module prismoid(
anchor = get_anchor(anchor, center, BOT, BOT); anchor = get_anchor(anchor, center, BOT, BOT);
vnf = prismoid( vnf = prismoid(
size1=size1, size2=size2, h=h, shift=shift, size1=size1, size2=size2, h=h, shift=shift,
rounding=rounding, rounding1=rounding1, rounding2=rounding2, rounding1=rounding1, rounding2=rounding2,
chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2, chamfer1=chamfer1, chamfer2=chamfer2,
l=l, center=CENTER l=l, center=CENTER
); );
attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) { attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) {
@ -500,12 +502,36 @@ function prismoid(
assert(is_vector(size2,2)) assert(is_vector(size2,2))
assert(is_num(h) || is_num(l)) assert(is_num(h) || is_num(l))
assert(is_vector(shift,2)) assert(is_vector(shift,2))
assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.") assert(
assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.") (is_num(rounding) && rounding>=0) ||
assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.") (is_vector(rounding,4) && all_nonnegative(rounding)),
assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.") "Bad rounding argument."
assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.") )
assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.") assert(
is_undef(rounding1) || (is_num(rounding1) && rounding1>=0) ||
(is_vector(rounding1,4) && all_nonnegative(rounding1)),
"Bad rounding1 argument."
)
assert(
is_undef(rounding2) || (is_num(rounding2) && rounding2>=0) ||
(is_vector(rounding2,4) && all_nonnegative(rounding2)),
"Bad rounding2 argument."
)
assert(
(is_num(chamfer) && chamfer>=0) ||
(is_vector(chamfer,4) && all_nonnegative(chamfer)),
"Bad chamfer argument."
)
assert(
is_undef(chamfer1) || (is_num(chamfer1) && chamfer1>=0) ||
(is_vector(chamfer1,4) && all_nonnegative(chamfer1)),
"Bad chamfer1 argument."
)
assert(
is_undef(chamfer2) || (is_num(chamfer2) && chamfer2>=0) ||
(is_vector(chamfer2,4) && all_nonnegative(chamfer2)),
"Bad chamfer2 argument."
)
let( let(
eps = pow(2,-14), eps = pow(2,-14),
h = first_defined([h,l,1]), h = first_defined([h,l,1]),

View File

@ -1458,9 +1458,9 @@ function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENT
rounding=rounding rounding=rounding
), ),
path = reverse(cpath) path = reverse(cpath)
) simple? ) simple
reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path) : ? reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path)
reorient(anchor,spin, two_d=true, path=path, p=path); : reorient(anchor,spin, two_d=true, path=path, p=path);

View File

@ -91,10 +91,10 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, an
wall = is_num(wall)? wall : thick/2; wall = is_num(wall)? wall : thick/2;
bevel_h = strut + (thick-wall)/2/tan(ang); bevel_h = strut + (thick-wall)/2/tan(ang);
cp1 = circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=strut)[0]; cp1 = circle_2tangents([0,0,+h/2], [l2/2,0,+h/2], [l1/2,0,-h/2], r=strut)[0];
cp2 = circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=bevel_h)[0]; cp2 = circle_2tangents([0,0,+h/2], [l2/2,0,+h/2], [l1/2,0,-h/2], r=bevel_h)[0];
cp3 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=bevel_h)[0]; cp3 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,+h/2], r=bevel_h)[0];
cp4 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=strut)[0]; cp4 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,+h/2], r=strut)[0];
z1 = h/2; z1 = h/2;
z2 = cp1.z; z2 = cp1.z;
@ -116,7 +116,7 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, an
size = [l1, thick, h]; size = [l1, thick, h];
attachable(anchor,spin,orient, size=size, size2=[l2,thick]) { attachable(anchor,spin,orient, size=size, size2=[l2,thick]) {
union() { zrot(90) {
polyhedron( polyhedron(
points=[ points=[
[-x4, -y1, -z1], [-x4, -y1, -z1],