mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Fix manifold issues with trapezoidal_threaded_rod().
This commit is contained in:
parent
99072122ce
commit
323a42177d
3 changed files with 101 additions and 109 deletions
|
@ -103,7 +103,7 @@ module thread_helix(
|
|||
// internal = If true, make this a mask for making internal threads.
|
||||
// d1 = Bottom outside diameter of threads.
|
||||
// d2 = Top outside diameter of threads.
|
||||
// higbee = Length to taper thread ends over. Default: 0
|
||||
// higbee = Length to taper thread ends over. Default: 0 (No higbee thread tapering)
|
||||
// higbee1 = Length to taper bottom thread end over.
|
||||
// higbee2 = Length to taper top thread end over.
|
||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=UP`.
|
||||
|
@ -148,90 +148,92 @@ module trapezoidal_threaded_rod(
|
|||
profile,
|
||||
internal=false,
|
||||
d1, d2,
|
||||
higbee=0, higbee1, higbee2,
|
||||
higbee, higbee1, higbee2,
|
||||
center, anchor, spin, orient
|
||||
) {
|
||||
_r1 = get_radius(d1=d1, d=d, dflt=10);
|
||||
_r2 = get_radius(d1=d2, d=d, dflt=10);
|
||||
sides = quantup(segs(max(_r1,_r2)), starts);
|
||||
rsc = internal? (1/cos(180/sides) + $slop*3) : 1;
|
||||
threads = ceil(l/pitch/starts)+(starts<4?4-starts:1);
|
||||
threads = ceil(l/pitch/starts) + 2;
|
||||
ll = threads * pitch * starts;
|
||||
depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
|
||||
pa_delta = min(pitch/4-0.01,depth*tan(thread_angle)/2)/pitch;
|
||||
dir = left_handed? -1 : 1;
|
||||
twist = 360 * l / pitch / starts;
|
||||
higbee1 = first_defined([higbee1, higbee, 0]);
|
||||
higbee2 = first_defined([higbee2, higbee, 0]);
|
||||
higang1 = 360 * higbee1 / (2 * _r1 * PI);
|
||||
higang2 = 360 * higbee2 / (2 * _r2 * PI);
|
||||
higsteps1 = ceil(higang1/360*sides);
|
||||
higsteps2 = ceil(higang2/360*sides);
|
||||
_higbee1 = first_defined([higbee1, higbee, 0]);
|
||||
_higbee2 = first_defined([higbee2, higbee, 0]);
|
||||
higang1 = 360 * _higbee1 / (2 * PI * _r1);
|
||||
higang2 = 360 * _higbee2 / (2 * PI * _r2);
|
||||
assert(higang1 < twist/2);
|
||||
assert(higang2 < twist/2);
|
||||
|
||||
higstart = twist/2 + 360/starts/4;
|
||||
higbee_table = [
|
||||
[-twist, 0.01],
|
||||
[-twist/2, 0.01],
|
||||
[-twist/2+higang1, 1],
|
||||
[ twist/2-higang2, 1],
|
||||
[ twist/2, 0.01],
|
||||
[ twist, 0.01]
|
||||
[-higstart*2, 0.01],
|
||||
[-higstart-0.001, 0.01],
|
||||
[-higstart+higang1, 1 ],
|
||||
[+higstart-higang2, 1 ],
|
||||
[+higstart+0.001, 0.01],
|
||||
[+higstart*2, 0.01]
|
||||
];
|
||||
echo(higbee_table);
|
||||
|
||||
r1 = -depth/pitch;
|
||||
z1 = 1/4-pa_delta;
|
||||
z2 = 1/4+pa_delta;
|
||||
profile = profile!=undef? profile : [
|
||||
[-z2, r1],
|
||||
[-z1, 0],
|
||||
[ z1, 0],
|
||||
[ z2, r1],
|
||||
];
|
||||
profile = pitch * (
|
||||
profile!=undef? profile : [
|
||||
[-z2, r1],
|
||||
[-z1, 0],
|
||||
[ z1, 0],
|
||||
[ z2, r1],
|
||||
]
|
||||
);
|
||||
pdepth = -min(subindex(profile,1));
|
||||
eprofile = [
|
||||
[-0.5, 0],
|
||||
each move([0,pdepth], p=profile),
|
||||
[ 0.5, 0],
|
||||
] * pitch;
|
||||
move([pitch,pdepth], p=profile[0]),
|
||||
];
|
||||
angstep = 360 / sides;
|
||||
angsteps = ceil(twist / (360 / sides)) + sides;
|
||||
angsteps = ceil(sides * (twist / 360 + 2));
|
||||
zang = atan2(_r2-_r1,l);
|
||||
thread_verts = [
|
||||
[for (x = eprofile) [0,0,-l/2]],
|
||||
for (a = [0:1:angsteps]) let (
|
||||
u = (a-angsteps/2) / (angsteps-sides),
|
||||
ang = u * twist,
|
||||
[for (i = idx(eprofile)) [0,0,-ll/2]],
|
||||
for (thread = [0:1:threads-1], side=[0:1:sides-1]) let(
|
||||
ang = ((thread - threads/2) + (side / sides)) * 360,
|
||||
u = ang / twist,
|
||||
r = lerp(_r1, _r2, u) * rsc,
|
||||
hsc = higbee1==0 && higbee2==0? 1 : lookup(ang, higbee_table),
|
||||
mat = affine3d_zrot(ang*dir) *
|
||||
affine3d_translate([r-pdepth*pitch, 0, l*u-0*pitch]) *
|
||||
affine3d_translate([r-pdepth*pitch, 0, l*u]) *
|
||||
affine3d_xrot(90) *
|
||||
affine3d_skew_xz(xa=zang) *
|
||||
affine3d_mirror([-1,1]) *
|
||||
affine3d_scale([1,hsc,1]),
|
||||
pts = apply(mat, path3d(eprofile))
|
||||
) pts,
|
||||
[for (x = eprofile) [0,0, l/2]],
|
||||
[for (x = eprofile) [0,0,+ll/2]],
|
||||
];
|
||||
thread_vnf = vnf_vertex_array(thread_verts, reverse=left_handed);
|
||||
eplen = len(eprofile);
|
||||
vlen = len(thread_vnf[0]);
|
||||
thread_vnf2 = [
|
||||
concat(thread_vnf[0], [[0,0,-l/2], [0,0,l/2]]),
|
||||
concat(thread_vnf[0], [[0,0,-ll/2], [0,0,+ll/2]]),
|
||||
concat(thread_vnf[1], [
|
||||
for (i = [0:1:sides/starts]) each
|
||||
left_handed? [
|
||||
[eplen*(i+1), eplen*i, vlen],
|
||||
[vlen-eplen*(i+1)-1, vlen-eplen*i-1, vlen+1]
|
||||
[vlen-eplen*(i+1)-1, vlen-eplen*(i+0)-1, vlen+1]
|
||||
] : [
|
||||
[eplen*i, eplen*(i+1), vlen],
|
||||
[vlen-eplen*i-1, vlen-eplen*(i+1)-1, vlen+1]
|
||||
[eplen*i, eplen*(i+1), vlen],
|
||||
[vlen-eplen*(i+0)-1, vlen-eplen*(i+1)-1, vlen+1]
|
||||
]
|
||||
])
|
||||
];
|
||||
thread_vnfs = vnf_merge([
|
||||
for (start = [0:1:starts-1]) zrot(start*360/starts, p=thread_vnf2)
|
||||
]);
|
||||
], cleanup=true);
|
||||
anchor = get_anchor(anchor, center, BOT, CENTER);
|
||||
attachable(anchor,spin,orient, r1=_r1, r2=_r2, l=l) {
|
||||
difference() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,555];
|
||||
BOSL_VERSION = [2,0,556];
|
||||
|
||||
|
||||
// Section: BOSL Library Version Functions
|
||||
|
|
134
vnf.scad
134
vnf.scad
|
@ -145,18 +145,31 @@ function vnf_add_faces(vnf=EMPTY_VNF, faces) =
|
|||
|
||||
// Function: vnf_merge()
|
||||
// Usage:
|
||||
// vnf = vnf_merge([VNF, VNF, VNF, ...]);
|
||||
// vnf = vnf_merge([VNF, VNF, VNF, ...], <cleanup>);
|
||||
// Description:
|
||||
// Given a list of VNF structures, merges them all into a single VNF structure.
|
||||
function vnf_merge(vnfs=[],_i=0,_acc=EMPTY_VNF) =
|
||||
(assert(is_vnf_list(vnfs)) _i>=len(vnfs))? _acc :
|
||||
vnf_merge(
|
||||
vnfs, _i=_i+1,
|
||||
_acc = let(base=len(_acc[0])) [
|
||||
concat(_acc[0], vnfs[_i][0]),
|
||||
concat(_acc[1], [for (f=vnfs[_i][1]) [for (i=f) i+base]]),
|
||||
function vnf_merge(vnfs, cleanup=false) =
|
||||
let (
|
||||
offs = cumsum([
|
||||
0, for (vnf = vnfs) len(vnf[0])
|
||||
])
|
||||
) [
|
||||
[for (vnf=vnfs) each vnf[0]],
|
||||
[
|
||||
for (i = idx(vnfs)) let(
|
||||
vnf = vnfs[i],
|
||||
verts = vnf[0],
|
||||
faces = vnf[1]
|
||||
)
|
||||
for (face = faces) let(
|
||||
dface = !cleanup ? face :
|
||||
deduplicate_indexed(verts, face, closed=true)
|
||||
)
|
||||
if (len(dface) >= 3)
|
||||
[ for (j = dface) offs[i] + j ]
|
||||
]
|
||||
);
|
||||
];
|
||||
|
||||
|
||||
// Function: vnf_compact()
|
||||
// Usage:
|
||||
|
@ -281,7 +294,7 @@ function vnf_vertex_array(
|
|||
rowcnt = rows - (row_wrap?0:1)
|
||||
)
|
||||
rows<=1 || cols<=1 ? vnf :
|
||||
vnf_merge([
|
||||
vnf_merge(cleanup=true, [
|
||||
vnf, [
|
||||
concat(
|
||||
pts,
|
||||
|
@ -681,13 +694,8 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
uniq_edges = edgecnts[0],
|
||||
big_faces = !show_warns? [] : [
|
||||
for (face = faces)
|
||||
if (len(face) > 3) [
|
||||
"WARNING",
|
||||
"BIG_FACE",
|
||||
"Face has more than 3 vertices, and may confuse CGAL",
|
||||
[for (i=face) varr[i]],
|
||||
"yellow"
|
||||
]
|
||||
if (len(face) > 3)
|
||||
_vnf_validate_err("BIG_FACE", [for (i=face) varr[i]])
|
||||
],
|
||||
null_faces = !show_warns? [] : [
|
||||
for (face = faces) let(
|
||||
|
@ -696,13 +704,9 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
if (len(face)>=3) let(
|
||||
faceverts = [for (k=face) varr[k]],
|
||||
area = polygon_area(faceverts)
|
||||
) if (is_num(area) && abs(area) < EPSILON) [
|
||||
"WARNING",
|
||||
"NULL_FACE",
|
||||
str("Face has zero area: ",fmt_float(abs(area),15)),
|
||||
faceverts,
|
||||
"brown"
|
||||
]
|
||||
)
|
||||
if (is_num(area) && abs(area) < EPSILON)
|
||||
_vnf_validate_err("NULL_FACE", faceverts)
|
||||
],
|
||||
nonplanars = unique([
|
||||
for (face = faces) let(
|
||||
|
@ -710,23 +714,13 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
area = polygon_area(faceverts)
|
||||
)
|
||||
if (is_num(area) && abs(area) > EPSILON)
|
||||
if (!coplanar(faceverts)) [
|
||||
"ERROR",
|
||||
"NONPLANAR",
|
||||
"Face vertices are not coplanar",
|
||||
faceverts,
|
||||
"cyan"
|
||||
]
|
||||
if (!coplanar(faceverts))
|
||||
_vnf_validate_err("NONPLANAR", faceverts)
|
||||
]),
|
||||
overpop_edges = unique([
|
||||
for (i=idx(uniq_edges))
|
||||
if (edgecnts[1][i]>2) [
|
||||
"ERROR",
|
||||
"OVRPOP_EDGE",
|
||||
"Too many faces attached at Edge",
|
||||
[for (i=uniq_edges[i]) varr[i]],
|
||||
"#f70"
|
||||
]
|
||||
if (edgecnts[1][i]>2)
|
||||
_vnf_validate_err("OVRPOP_EDGE", [for (i=uniq_edges[i]) varr[i]])
|
||||
]),
|
||||
reversals = unique([
|
||||
for(i = idx(faces), j = idx(faces)) if(i != j)
|
||||
|
@ -736,13 +730,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
for(edge2 = pair(faces[j],true))
|
||||
if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering.
|
||||
if(_edge_not_reported(edge1, varr, overpop_edges))
|
||||
[
|
||||
"ERROR",
|
||||
"REVERSAL",
|
||||
"Faces Reverse Across Edge",
|
||||
[for (i=edge1) varr[i]],
|
||||
"violet"
|
||||
]
|
||||
_vnf_validate_err("REVERSAL", [for (i=edge1) varr[i]])
|
||||
]),
|
||||
t_juncts = unique([
|
||||
for (v=idx(varr), edge=uniq_edges)
|
||||
|
@ -754,13 +742,8 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
if (a != b && b != c && a != c) let(
|
||||
pt = segment_closest_point([a,c],b)
|
||||
)
|
||||
if (pt == b) [
|
||||
"ERROR",
|
||||
"T_JUNCTION",
|
||||
"Vertex is mid-edge on another Face",
|
||||
[b],
|
||||
"red"
|
||||
]
|
||||
if (pt == b)
|
||||
_vnf_validate_err("T_JUNCTION", [b])
|
||||
]),
|
||||
isect_faces = !check_isects? [] : unique([
|
||||
for (i = [0:1:len(faces)-2])
|
||||
|
@ -791,26 +774,15 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
)
|
||||
if (!is_undef(isects2))
|
||||
for (seg=isects2)
|
||||
if (seg[0] != seg[1]) [
|
||||
"ERROR",
|
||||
"FACE_ISECT",
|
||||
"Faces intersect",
|
||||
seg,
|
||||
"blue"
|
||||
]
|
||||
if (seg[0] != seg[1])
|
||||
_vnf_validate_err("FACE_ISECT", seg)
|
||||
]),
|
||||
hole_edges = unique([
|
||||
for (i=idx(uniq_edges))
|
||||
if (edgecnts[1][i]<2)
|
||||
if (_pts_not_reported(uniq_edges[i], varr, t_juncts))
|
||||
if (_pts_not_reported(uniq_edges[i], varr, isect_faces))
|
||||
[
|
||||
"ERROR",
|
||||
"HOLE_EDGE",
|
||||
"Edge bounds Hole",
|
||||
[for (i=uniq_edges[i]) varr[i]],
|
||||
"magenta"
|
||||
]
|
||||
_vnf_validate_err("HOLE_EDGE", [for (i=uniq_edges[i]) varr[i]])
|
||||
])
|
||||
) concat(
|
||||
big_faces,
|
||||
|
@ -824,6 +796,24 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
);
|
||||
|
||||
|
||||
_vnf_validate_errs = [
|
||||
["BIG_FACE", "WARNING", "cyan", "Face has more than 3 vertices, and may confuse CGAL"],
|
||||
["NULL_FACE", "WARNING", "blue", "Face has zero area."],
|
||||
["NONPLANAR", "ERROR", "yellow", "Face vertices are not coplanar"],
|
||||
["OVRPOP_EDGE", "ERROR", "orange", "Too many faces attached at Edge"],
|
||||
["REVERSAL", "ERROR", "violet", "Faces Reverse Across Edge"],
|
||||
["T_JUNCTION", "ERROR", "magenta", "Vertex is mid-edge on another Face"],
|
||||
["FACE_ISECT", "ERROR", "brown", "Faces intersect"],
|
||||
["HOLE_EDGE", "ERROR", "red", "Edge bounds Hole"]
|
||||
];
|
||||
|
||||
|
||||
function _vnf_validate_err(name, extra) =
|
||||
let(
|
||||
info = [for (x = _vnf_validate_errs) if (x[0] == name) x][0]
|
||||
) concat(info, [extra]);
|
||||
|
||||
|
||||
function _pts_not_reported(pts, varr, reports) =
|
||||
[
|
||||
for (i = pts, report = reports, pt = report[3])
|
||||
|
@ -847,12 +837,12 @@ module vnf_validate(vnf, size=1, show_warns=true, check_isects=false) {
|
|||
check_isects=check_isects
|
||||
);
|
||||
for (fault = faults) {
|
||||
typ = fault[0];
|
||||
err = fault[1];
|
||||
msg = fault[2];
|
||||
pts = fault[3];
|
||||
clr = fault[4];
|
||||
echo(str(typ, " ", err, ": ", msg, " at ", pts));
|
||||
err = fault[0];
|
||||
typ = fault[1];
|
||||
clr = fault[2];
|
||||
msg = fault[3];
|
||||
pts = fault[4];
|
||||
echo(str(typ, " ", err, " (", clr ,"): ", msg, " at ", pts));
|
||||
color(clr) {
|
||||
if (len(pts)==2) {
|
||||
stroke(pts, width=size);
|
||||
|
|
Loading…
Reference in a new issue