Skip to content

Commit ff5fc1f

Browse files
Merge pull request BelfrySCAD#1994 from adrianVmariano/master
Extend spheroid to make ellipsoids with vector radius/diam argument Eliminate occasional spurious warning from screw() in dev snapshots
2 parents 66f4da0 + dcdef55 commit ff5fc1f

2 files changed

Lines changed: 52 additions & 26 deletions

File tree

shapes3d.scad

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3347,7 +3347,10 @@ function sphere(r, d, anchor=CENTER, spin=0, orient=UP) =
33473347
// vnf = spheroid(r|d, [circum], [style]);
33483348
// Description:
33493349
// Creates a spheroid object, with support for anchoring and attachments.
3350-
// This is a drop-in replacement for the built-in `sphere()` module.
3350+
// This is a drop-in replacement for the built-in `sphere()` module. The `r` or `d` value can
3351+
// be a 3-vector to produce an ellipsoid. This differs from scaling the ellipsoid manually because
3352+
// it doesn't rescale children that you attach to the ellipsoid.
3353+
// .
33513354
// When called as a function, returns a [VNF](vnf.scad) for a spheroid.
33523355
// The exact triangulation of this spheroid can be controlled via the `style=`
33533356
// argument, where the value can be one of `"orig"`, `"aligned"`, `"stagger"`,
@@ -3379,10 +3382,10 @@ function sphere(r, d, anchor=CENTER, spin=0, orient=UP) =
33793382
// The "octa" style has the property that it blends neatly with a cylinder of the same $fn along any of the coordinate axes.
33803383
// This is true for both the regular and circumscribed "octa" spheroid.
33813384
// Arguments:
3382-
// r = Radius of the spheroid.
3385+
// r = Radius of the spheroid or 3-vector giving the 3 semiaxes.
33833386
// style = The style of the spheroid's construction. One of "orig", "aligned", "stagger", "octa", or "icosa". Default: "aligned"
33843387
// ---
3385-
// d = Diameter of the spheroid.
3388+
// d = Diameter of the spheroid or 3-vector giving three axes lengths.
33863389
// circum = If true, the approximate sphere circumscribes the true sphere of the requested size. Otherwise inscribes. Note that for some styles, the circumscribed sphere looks different than the inscribed sphere. Default: false (inscribes)
33873390
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
33883391
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
@@ -3415,6 +3418,8 @@ function sphere(r, d, anchor=CENTER, spin=0, orient=UP) =
34153418
// $fn=16;
34163419
// color("lightblue")spheroid(r=10, style="octa", circum=true);
34173420
// xcyl(r=10.01, h=15, anchor=RIGHT, circum=true);
3421+
// Example: Ellipsoid
3422+
// spheroid(r=[100,50,35]);
34183423
// Example: Anchoring
34193424
// spheroid(d=100, anchor=FRONT);
34203425
// Example: Spin
@@ -3445,10 +3450,11 @@ function sphere(r, d, anchor=CENTER, spin=0, orient=UP) =
34453450
module spheroid(r, style="aligned", d, circum=false, dual=false, anchor=CENTER, spin=0, orient=UP)
34463451
{
34473452
r = get_radius(r=r, d=d, dflt=1);
3448-
sides = segs(r);
3449-
vsides = ceil(sides/2);
3453+
assert((is_finite(r) && r>=0) || (is_vector(r,3) && all_positive(r)),"\nr/d must be a nonnegative value or a positive 3-vector");
34503454
attachable(anchor,spin,orient, r=r) {
34513455
if (style=="orig" && !circum) {
3456+
sides = segs(min(r));
3457+
vsides = ceil(sides/2);
34523458
merids = [ for (i=[0:1:vsides-1]) 90-(i+0.5)*180/vsides ];
34533459
path = [
34543460
let(a = merids[0]) [0, sin(a)],
@@ -3460,9 +3466,11 @@ module spheroid(r, style="aligned", d, circum=false, dual=false, anchor=CENTER,
34603466
// Don't now how to construct faces for these efficiently, so use hull_points, which
34613467
// is much faster than using hull() as happens in the spheroid() function
34623468
else if (circum && (style=="octa" || style=="icosa")) {
3463-
orig_sphere = spheroid(r,style,circum=false);
3469+
minr = min(r);
3470+
scale = r/minr;
3471+
orig_sphere = spheroid(minr,style,circum=false);
34643472
dualvert = _dual_vertices(orig_sphere);
3465-
hull_points(dualvert,fast=true);
3473+
hull_points(scale(scale,dualvert),fast=true);
34663474
} else {
34673475
vnf = spheroid(r=r, circum=circum, style=style);
34683476
vnf_polyhedron(vnf, convexity=2);
@@ -3651,8 +3659,16 @@ let(
36513659
function spheroid(r, style="aligned", d, circum=false, anchor=CENTER, spin=0, orient=UP) =
36523660
assert(in_list(style, ["orig", "aligned", "stagger", "octa", "icosa"]))
36533661
let(
3654-
r = get_radius(r=r, d=d, dflt=1),
3655-
hsides = segs(r),
3662+
r = get_radius(r=r, d=d, dflt=1)
3663+
)
3664+
is_vector(r,3) ? let(
3665+
minr = min(r),
3666+
scale = r/minr
3667+
)
3668+
scale(scale,spheroid(minr, style=style, circum=circum, anchor=anchor,
3669+
spin=spin, orient=orient))
3670+
: let(
3671+
hsides = segs(min(r)),
36563672
vsides = max(2,ceil(hsides/2)),
36573673
icosa_steps = round(max(5,hsides)/5),
36583674
stagger = style=="stagger"

threading.scad

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,26 +2029,29 @@ module generic_threaded_rod(
20292029
assert(r1adj+pmax-clip_bev1>0, "bevel1 is too large to fit screw diameter")
20302030
assert(r2adj+pmax-clip_bev2>0, "bevel2 is too large to fit screw diameter")
20312031
assert(abs(clip_bev1)+abs(clip_bev2)<len, "Combined bevel size exceeds length of screw");
2032+
20322033
attachable(anchor,spin,orient, r1=r1adj, r2=r2adj, l=len) {
20332034
union(){
20342035
difference() {
2035-
vnf_polyhedron(thread_vnf,convexity=10);
2036-
if (clip_bev1>0)
2037-
rotate_extrude()
2038-
polygon([[ 0,-len/2],
2039-
[r1adj+pmax-clip_bev1 ,-len/2],
2040-
[r1adj+pmax-slope*clip_bev1,-len/2+clip_bev1],
2041-
[ rmax+1,-len/2+clip_bev1],
2042-
[ rmax+1, len1-1],
2043-
[ 0, len1-1]]);
2044-
if (clip_bev2>0)
2045-
rotate_extrude()
2046-
polygon([[ 0, len/2],
2047-
[r2adj+pmax-clip_bev2 , len/2],
2048-
[r2adj+pmax+slope*clip_bev2, len/2-clip_bev2],
2049-
[ rmax+1, len/2-clip_bev2],
2050-
[ rmax+1, len2+1],
2051-
[ 0, len2+1]]);
2036+
vnf_polyhedron(thread_vnf,convexity=10);
2037+
__rot_if_old(){ // works around change in rotate_extrude starting point
2038+
if (clip_bev1>0)
2039+
rotate_extrude(angle=360)
2040+
polygon([[ 0,-len/2],
2041+
[r1adj+pmax-clip_bev1 ,-len/2],
2042+
[r1adj+pmax-slope*clip_bev1,-len/2+clip_bev1],
2043+
[ rmax+1,-len/2+clip_bev1],
2044+
[ rmax+1, len1-1],
2045+
[ 0, len1-1]]);
2046+
if (clip_bev2>0)
2047+
rotate_extrude(angle=360)
2048+
polygon([[ 0, len/2],
2049+
[r2adj+pmax-clip_bev2 , len/2],
2050+
[r2adj+pmax+slope*clip_bev2, len/2-clip_bev2],
2051+
[ rmax+1, len/2-clip_bev2],
2052+
[ rmax+1, len2+1],
2053+
[ 0, len2+1]]);
2054+
}
20522055
if (!blunt_start1 && clip_bev1<=0)
20532056
down(len/2) cuboid([2*rmax+1,2*rmax+1, -len1+1], anchor=TOP);
20542057
if (!blunt_start2 && clip_bev2<=0)
@@ -2094,6 +2097,13 @@ module generic_threaded_rod(
20942097

20952098

20962099

2100+
module __rot_if_old()
2101+
{
2102+
if (version_num()>=20250106) children();
2103+
else zrot(180) children();
2104+
}
2105+
2106+
20972107
// Module: generic_threaded_nut()
20982108
// Synopsis: Creates a generic threaded nut.
20992109
// SynTags: Geom

0 commit comments

Comments
 (0)