BC
Bob Carlson
Fri, Oct 25, 2024 11:44 PM
I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it did not help.
Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it did not help.
Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16*360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
SP
Sanjeev Prabhakar
Sat, Oct 26, 2024 12:04 AM
Can you post a picture of this
I will try this as well in python.
It may not interest you but just want see how tough this is to model
On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
discuss@lists.openscad.org> wrote:
I got really intrigued by the Hirth joint and have been working a library
entry that would generate them. I have it fully working, apparently,
because it renders perfectly as far as I can see. However when I load one
of the parts (a concave part) into PrusaSlicer, it reports thousands of
errors that it supposedly fixed. The visual rendering is fine, but when you
look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones
mentioned. The one I have actually encountered though is a conical one.
There is a concave part and a convex part. They fit together perfectly. I
had to invent some terminology since I did not find terms for some things I
found to be important. The outer center line is the plane that passes
through the midpoint of the teeth at the outer radius. In a flat hirth
joint all the teeth radiate from the center of this circle, call it the
origin. If the origin of the teeth is above the outer center line, then
joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth
profile is either 60 or 90 degrees. The groove angle is the angle that the
groove forms from the origin to the outer radius. It will pass below (for a
convex part) the outer radius. It’s critical for making hirth joints
because it forms the tool path. The ridge angle is the angle formed by the
corresponding ridge.
If the joint is conical, then there is an inner center line that passes
through the center of the teeth at the inner radius. The tooth height is
the critical number to calculate. It is dependent on the number of teeth,
the profile angle and the inner and out radii. Something that really
complicates the mental gymnastics is that the tooth height is smaller at
the inner radius. My code adds a “base” of extra material at the bottom of
the convex part and the top of the concave part. What’s tricky is
positioning the base of the concave part relative to the inner center line.
The concave parts base is relatively easy to place because it depends on
the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical
coordinates to make two 2d tooth profiles. Then I complete a tooth using
skin(). A for loop generates the full set of N teeth. Then intersection or
difference is used the trim the teeth at the inner and outer radii. I
discovered something at that point, but solved it pretty simply. When
diffing a cylinder from the N teeth, each tooth took up a small portion of
the cylinder being diffed out. I had to raise the $fn on the cylinder or
tube being used so that I got enough points in each tooth that diff or
intersection was accurate. I kept raising it until the results stopped
improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to
produce the chamfer at the top of the teeth. Then I add in the base. The
base also adds the “chamfer” at the bottom of the groove. It’s half the
size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL
into PrusaSlicer, it reports errors fixed, but appears to slice correctly
when supports are added.
When I add the intersection to trim the raw teeth, the number of reported
errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting
many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold
renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it
did not help.
Maybe the biggest hint is that the convex part uses almost identical code,
but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training
was 60 years ago. However I doubt a math error is responsible for the
slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight,
orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Can you post a picture of this
I will try this as well in python.
It may not interest you but just want see how tough this is to model
On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
discuss@lists.openscad.org> wrote:
> I got really intrigued by the Hirth joint and have been working a library
> entry that would generate them. I have it fully working, apparently,
> because it renders perfectly as far as I can see. However when I load one
> of the parts (a concave part) into PrusaSlicer, it reports thousands of
> errors that it supposedly fixed. The visual rendering is fine, but when you
> look at the slice it is completely screwed up.
>
> First some explanation. When I looked up hirth joints I only saw flat ones
> mentioned. The one I have actually encountered though is a conical one.
> There is a concave part and a convex part. They fit together perfectly. I
> had to invent some terminology since I did not find terms for some things I
> found to be important. The outer center line is the plane that passes
> through the midpoint of the teeth at the outer radius. In a flat hirth
> joint all the teeth radiate from the center of this circle, call it the
> origin. If the origin of the teeth is above the outer center line, then
> joint has a conical shape and the two parts are concave and convex.
>
> Each tooth at every point has the same profile, the top of the tooth
> profile is either 60 or 90 degrees. The groove angle is the angle that the
> groove forms from the origin to the outer radius. It will pass below (for a
> convex part) the outer radius. It’s critical for making hirth joints
> because it forms the tool path. The ridge angle is the angle formed by the
> corresponding ridge.
>
> If the joint is conical, then there is an inner center line that passes
> through the center of the teeth at the inner radius. The tooth height is
> the critical number to calculate. It is dependent on the number of teeth,
> the profile angle and the inner and out radii. Something that really
> complicates the mental gymnastics is that the tooth height is smaller at
> the inner radius. My code adds a “base” of extra material at the bottom of
> the convex part and the top of the concave part. What’s tricky is
> positioning the base of the concave part relative to the inner center line.
> The concave parts base is relatively easy to place because it depends on
> the outer radius and center line.
>
> I generate the raw teeth using the groove and ridge angles and spherical
> coordinates to make two 2d tooth profiles. Then I complete a tooth using
> skin(). A for loop generates the full set of N teeth. Then intersection or
> difference is used the trim the teeth at the inner and outer radii. I
> discovered something at that point, but solved it pretty simply. When
> diffing a cylinder from the N teeth, each tooth took up a small portion of
> the cylinder being diffed out. I had to raise the $fn on the cylinder or
> tube being used so that I got enough points in each tooth that diff or
> intersection was accurate. I kept raising it until the results stopped
> improving. I ended up with the 16*360 you see in the code.
>
> After I have the raw teeth, I generate a cone that is diffed away to
> produce the chamfer at the top of the teeth. Then I add in the base. The
> base also adds the “chamfer” at the bottom of the groove. It’s half the
> size of the top chamfer to leave a little gap when the parts are joined.
>
> When I comment out the everything but the raw teeth and import the STL
> into PrusaSlicer, it reports errors fixed, but appears to slice correctly
> when supports are added.
>
> When I add the intersection to trim the raw teeth, the number of reported
> errors goes way up.
>
> When I add the diff to remove the chamfer, the number goes way up again.
>
> When I add in the base, the number goes up again and it starts reporting
> many open edges.
>
> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold
> renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it
> did not help.
>
> Maybe the biggest hint is that the convex part uses almost identical code,
> but produces no errors. Very weird.
>
> So, is this an OpenSCAD problem? Or something in my code?
>
> It’s also possible that my math is off somewhere. My formal trig training
> was 60 years ago. However I doubt a math error is responsible for the
> slicing problem and STL errors.
>
> -Bob
>
>
> include <BOSL2/std.scad>
> include <BOSL2/structs.scad>
>
> // Number of Teeth
> _n = 36; // Number Of Teeth
>
> // Inner Radius
> _ir = 30;
> // Outer Radius
> _or = 50;
> // Is the coupling conical?
> _conic = 10;
> // Tooth Profile Angle
> _profile = 60; // [60, 90]
> // Percentage of tooth height
> _chamfer = 5; // Default 5%
> _base = 1;
>
> $fn = 180;
> tiny = 1 / 1024;
>
> hirth_concave();
>
> _irRatio = _ir / _or;
> _toothAngle = 360/_n;
> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
> _chamferHeight = _chamfer * _toothHeight / 100;
> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
> _innerCenterLine = (1 - _irRatio) * _conic;
> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>
> module hirth_concave() {
> zrot(_toothAngle/2)
> union() {
> difference() {
> intersection() {
> union() {
> for (i = [0 : 360/_n : 359])
> zrot(i)
> _profileF();
> }
> tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight,
> orient = UP, $fn = 16*360);
> }
> _chamferF();
> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
> }
> _baseF();
> }
> } // hirth_concave
>
> module _profileF() {
> IR = _ir * .5;
> OR = _or * 1.5;
> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>
> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
> up(_conic)
> skin([tI, tO], slices = 0);
> }
>
>
> module _chamferF() {
> A = -_toothHeight/2 - .1;
> B = -_toothHeight/2 + _chamferHeight;
>
> pts = [[0, _conic],
> [_or+tiny, A],
> [_or+tiny, B]];
>
> rotate_extrude(angle = 360, $fn = 16*360)
> polygon(pts);
> }
>
> module _baseF() {
> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
> C = _toothHeight/2 - _chamferHeight/2;
> pts = [
> [_ir, A],
> [_ir, B],
> [_or, C],
> [_or, A]
> ];
>
> rotate_extrude(angle = 360, $fn = 360*16)
> polygon(pts);
> }
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
DP
David Phillip Oster
Sat, Oct 26, 2024 12:19 AM
I may be misunderstanding your post, but I pasted the source code you
posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no
trouble viewing, rendering it, saving it as an .obj file, and slicing the
result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
I may be misunderstanding your post, but I pasted the source code you
posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no
trouble viewing, rendering it, saving it as an .obj file, and slicing the
result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
BC
Bob Carlson
Sat, Oct 26, 2024 3:19 AM
I use .stl rather than .obj and have an OpenSCAD from about a month ago. I think that’s my PS version. I’ll try .obj tomorrow. I’ll also post a screen shot.
-Bob
Sent from my iPad
On Oct 25, 2024, at 17:20, David Phillip Oster via Discuss discuss@lists.openscad.org wrote:
I may be misunderstanding your post, but I pasted the source code you posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no trouble viewing, rendering it, saving it as an .obj file, and slicing the result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
I use .stl rather than .obj and have an OpenSCAD from about a month ago. I think that’s my PS version. I’ll try .obj tomorrow. I’ll also post a screen shot.
-Bob
Sent from my iPad
> On Oct 25, 2024, at 17:20, David Phillip Oster via Discuss <discuss@lists.openscad.org> wrote:
>
>
> I may be misunderstanding your post, but I pasted the source code you posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no trouble viewing, rendering it, saving it as an .obj file, and slicing the result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
BC
Bob Carlson
Sat, Oct 26, 2024 4:56 PM

This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.

I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it did not help.
Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org

This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.

> On Oct 25, 2024, at 17:04, Sanjeev Prabhakar <sprabhakar2006@gmail.com> wrote:
>
> Can you post a picture of this
>
> I will try this as well in python.
>
> It may not interest you but just want see how tough this is to model
>
> On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote:
>> I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
>>
>> First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
>>
>> Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
>>
>> If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
>>
>> I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
>>
>> After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
>>
>> When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
>>
>> When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
>>
>> When I add the diff to remove the chamfer, the number goes way up again.
>>
>> When I add in the base, the number goes up again and it starts reporting many open edges.
>>
>> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it did not help.
>>
>> Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
>>
>> So, is this an OpenSCAD problem? Or something in my code?
>>
>> It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
>>
>> -Bob
>>
>>
>> include <BOSL2/std.scad>
>> include <BOSL2/structs.scad>
>>
>> // Number of Teeth
>> _n = 36; // Number Of Teeth
>>
>> // Inner Radius
>> _ir = 30;
>> // Outer Radius
>> _or = 50;
>> // Is the coupling conical?
>> _conic = 10;
>> // Tooth Profile Angle
>> _profile = 60; // [60, 90]
>> // Percentage of tooth height
>> _chamfer = 5; // Default 5%
>> _base = 1;
>>
>> $fn = 180;
>> tiny = 1 / 1024;
>>
>> hirth_concave();
>>
>> _irRatio = _ir / _or;
>> _toothAngle = 360/_n;
>> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
>> _chamferHeight = _chamfer * _toothHeight / 100;
>> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
>> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
>> _innerCenterLine = (1 - _irRatio) * _conic;
>> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
>> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>>
>> module hirth_concave() {
>> zrot(_toothAngle/2)
>> union() {
>> difference() {
>> intersection() {
>> union() {
>> for (i = [0 : 360/_n : 359])
>> zrot(i)
>> _profileF();
>> }
>> tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16*360);
>> }
>> _chamferF();
>> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
>> }
>> _baseF();
>> }
>> } // hirth_concave
>>
>> module _profileF() {
>> IR = _ir * .5;
>> OR = _or * 1.5;
>> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
>> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
>> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>>
>> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
>> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
>> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
>> up(_conic)
>> skin([tI, tO], slices = 0);
>> }
>>
>>
>> module _chamferF() {
>> A = -_toothHeight/2 - .1;
>> B = -_toothHeight/2 + _chamferHeight;
>>
>> pts = [[0, _conic],
>> [_or+tiny, A],
>> [_or+tiny, B]];
>>
>> rotate_extrude(angle = 360, $fn = 16*360)
>> polygon(pts);
>> }
>>
>> module _baseF() {
>> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
>> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
>> C = _toothHeight/2 - _chamferHeight/2;
>> pts = [
>> [_ir, A],
>> [_ir, B],
>> [_or, C],
>> [_or, A]
>> ];
>>
>> rotate_extrude(angle = 360, $fn = 360*16)
>> polygon(pts);
>> }
>> _______________________________________________
>> OpenSCAD mailing list
>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
AM
Adrian Mariano
Sat, Oct 26, 2024 5:27 PM
This looks like a fairly simple shape and also sort of gear like. You will
get the best performance if you make it as one polyhedron instead of making
one tooth and turning it to geometry and replicating it after and adding
chamfers after. Make the tooth point array and then rotate the point list
to make all the copies and use vnf_vertex_array one time at the end. It
will run in 0.1 s
On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <
discuss@lists.openscad.org> wrote:
[image: PastedGraphic-1.png]
This second picture shows some visual aids I have in my code to show the
center lines, the origin and the groove and ridge angles.
[image: PastedGraphic-2.png]
On Oct 25, 2024, at 17:04, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
Can you post a picture of this
I will try this as well in python.
It may not interest you but just want see how tough this is to model
On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
discuss@lists.openscad.org> wrote:
I got really intrigued by the Hirth joint and have been working a library
entry that would generate them. I have it fully working, apparently,
because it renders perfectly as far as I can see. However when I load one
of the parts (a concave part) into PrusaSlicer, it reports thousands of
errors that it supposedly fixed. The visual rendering is fine, but when you
look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat
ones mentioned. The one I have actually encountered though is a conical
one. There is a concave part and a convex part. They fit together
perfectly. I had to invent some terminology since I did not find terms for
some things I found to be important. The outer center line is the plane
that passes through the midpoint of the teeth at the outer radius. In a
flat hirth joint all the teeth radiate from the center of this circle, call
it the origin. If the origin of the teeth is above the outer center line,
then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth
profile is either 60 or 90 degrees. The groove angle is the angle that the
groove forms from the origin to the outer radius. It will pass below (for a
convex part) the outer radius. It’s critical for making hirth joints
because it forms the tool path. The ridge angle is the angle formed by the
corresponding ridge.
If the joint is conical, then there is an inner center line that passes
through the center of the teeth at the inner radius. The tooth height is
the critical number to calculate. It is dependent on the number of teeth,
the profile angle and the inner and out radii. Something that really
complicates the mental gymnastics is that the tooth height is smaller at
the inner radius. My code adds a “base” of extra material at the bottom of
the convex part and the top of the concave part. What’s tricky is
positioning the base of the concave part relative to the inner center line.
The concave parts base is relatively easy to place because it depends on
the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical
coordinates to make two 2d tooth profiles. Then I complete a tooth using
skin(). A for loop generates the full set of N teeth. Then intersection or
difference is used the trim the teeth at the inner and outer radii. I
discovered something at that point, but solved it pretty simply. When
diffing a cylinder from the N teeth, each tooth took up a small portion of
the cylinder being diffed out. I had to raise the $fn on the cylinder or
tube being used so that I got enough points in each tooth that diff or
intersection was accurate. I kept raising it until the results stopped
improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to
produce the chamfer at the top of the teeth. Then I add in the base. The
base also adds the “chamfer” at the bottom of the groove. It’s half the
size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL
into PrusaSlicer, it reports errors fixed, but appears to slice correctly
when supports are added.
When I add the intersection to trim the raw teeth, the number of reported
errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting
many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold
renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it
did not help.
Maybe the biggest hint is that the convex part uses almost identical
code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training
was 60 years ago. However I doubt a math error is responsible for the
slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l =
_tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
This looks like a fairly simple shape and also sort of gear like. You will
get the best performance if you make it as one polyhedron instead of making
one tooth and turning it to geometry and replicating it after and adding
chamfers after. Make the tooth point array and then rotate the point list
to make all the copies and use vnf_vertex_array one time at the end. It
will run in 0.1 s
On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <
discuss@lists.openscad.org> wrote:
> [image: PastedGraphic-1.png]
>
> This second picture shows some visual aids I have in my code to show the
> center lines, the origin and the groove and ridge angles.
>
> [image: PastedGraphic-2.png]
>
> On Oct 25, 2024, at 17:04, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
> wrote:
>
> Can you post a picture of this
>
> I will try this as well in python.
>
> It may not interest you but just want see how tough this is to model
>
> On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
> discuss@lists.openscad.org> wrote:
>
>> I got really intrigued by the Hirth joint and have been working a library
>> entry that would generate them. I have it fully working, apparently,
>> because it renders perfectly as far as I can see. However when I load one
>> of the parts (a concave part) into PrusaSlicer, it reports thousands of
>> errors that it supposedly fixed. The visual rendering is fine, but when you
>> look at the slice it is completely screwed up.
>>
>> First some explanation. When I looked up hirth joints I only saw flat
>> ones mentioned. The one I have actually encountered though is a conical
>> one. There is a concave part and a convex part. They fit together
>> perfectly. I had to invent some terminology since I did not find terms for
>> some things I found to be important. The outer center line is the plane
>> that passes through the midpoint of the teeth at the outer radius. In a
>> flat hirth joint all the teeth radiate from the center of this circle, call
>> it the origin. If the origin of the teeth is above the outer center line,
>> then joint has a conical shape and the two parts are concave and convex.
>>
>> Each tooth at every point has the same profile, the top of the tooth
>> profile is either 60 or 90 degrees. The groove angle is the angle that the
>> groove forms from the origin to the outer radius. It will pass below (for a
>> convex part) the outer radius. It’s critical for making hirth joints
>> because it forms the tool path. The ridge angle is the angle formed by the
>> corresponding ridge.
>>
>> If the joint is conical, then there is an inner center line that passes
>> through the center of the teeth at the inner radius. The tooth height is
>> the critical number to calculate. It is dependent on the number of teeth,
>> the profile angle and the inner and out radii. Something that really
>> complicates the mental gymnastics is that the tooth height is smaller at
>> the inner radius. My code adds a “base” of extra material at the bottom of
>> the convex part and the top of the concave part. What’s tricky is
>> positioning the base of the concave part relative to the inner center line.
>> The concave parts base is relatively easy to place because it depends on
>> the outer radius and center line.
>>
>> I generate the raw teeth using the groove and ridge angles and spherical
>> coordinates to make two 2d tooth profiles. Then I complete a tooth using
>> skin(). A for loop generates the full set of N teeth. Then intersection or
>> difference is used the trim the teeth at the inner and outer radii. I
>> discovered something at that point, but solved it pretty simply. When
>> diffing a cylinder from the N teeth, each tooth took up a small portion of
>> the cylinder being diffed out. I had to raise the $fn on the cylinder or
>> tube being used so that I got enough points in each tooth that diff or
>> intersection was accurate. I kept raising it until the results stopped
>> improving. I ended up with the 16*360 you see in the code.
>>
>> After I have the raw teeth, I generate a cone that is diffed away to
>> produce the chamfer at the top of the teeth. Then I add in the base. The
>> base also adds the “chamfer” at the bottom of the groove. It’s half the
>> size of the top chamfer to leave a little gap when the parts are joined.
>>
>> When I comment out the everything but the raw teeth and import the STL
>> into PrusaSlicer, it reports errors fixed, but appears to slice correctly
>> when supports are added.
>>
>> When I add the intersection to trim the raw teeth, the number of reported
>> errors goes way up.
>>
>> When I add the diff to remove the chamfer, the number goes way up again.
>>
>> When I add in the base, the number goes up again and it starts reporting
>> many open edges.
>>
>> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold
>> renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it
>> did not help.
>>
>> Maybe the biggest hint is that the convex part uses almost identical
>> code, but produces no errors. Very weird.
>>
>> So, is this an OpenSCAD problem? Or something in my code?
>>
>> It’s also possible that my math is off somewhere. My formal trig training
>> was 60 years ago. However I doubt a math error is responsible for the
>> slicing problem and STL errors.
>>
>> -Bob
>>
>>
>> include <BOSL2/std.scad>
>> include <BOSL2/structs.scad>
>>
>> // Number of Teeth
>> _n = 36; // Number Of Teeth
>>
>> // Inner Radius
>> _ir = 30;
>> // Outer Radius
>> _or = 50;
>> // Is the coupling conical?
>> _conic = 10;
>> // Tooth Profile Angle
>> _profile = 60; // [60, 90]
>> // Percentage of tooth height
>> _chamfer = 5; // Default 5%
>> _base = 1;
>>
>> $fn = 180;
>> tiny = 1 / 1024;
>>
>> hirth_concave();
>>
>> _irRatio = _ir / _or;
>> _toothAngle = 360/_n;
>> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
>> _chamferHeight = _chamfer * _toothHeight / 100;
>> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
>> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
>> _innerCenterLine = (1 - _irRatio) * _conic;
>> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
>> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>>
>> module hirth_concave() {
>> zrot(_toothAngle/2)
>> union() {
>> difference() {
>> intersection() {
>> union() {
>> for (i = [0 : 360/_n : 359])
>> zrot(i)
>> _profileF();
>> }
>> tube(ir = _ir, or = _or, anchor = CENTER, l =
>> _tubeHeight, orient = UP, $fn = 16*360);
>> }
>> _chamferF();
>> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
>> }
>> _baseF();
>> }
>> } // hirth_concave
>>
>> module _profileF() {
>> IR = _ir * .5;
>> OR = _or * 1.5;
>> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
>> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
>> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>>
>> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
>> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
>> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
>> up(_conic)
>> skin([tI, tO], slices = 0);
>> }
>>
>>
>> module _chamferF() {
>> A = -_toothHeight/2 - .1;
>> B = -_toothHeight/2 + _chamferHeight;
>>
>> pts = [[0, _conic],
>> [_or+tiny, A],
>> [_or+tiny, B]];
>>
>> rotate_extrude(angle = 360, $fn = 16*360)
>> polygon(pts);
>> }
>>
>> module _baseF() {
>> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
>> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
>> C = _toothHeight/2 - _chamferHeight/2;
>> pts = [
>> [_ir, A],
>> [_ir, B],
>> [_or, C],
>> [_or, A]
>> ];
>>
>> rotate_extrude(angle = 360, $fn = 360*16)
>> polygon(pts);
>> }
>> _______________________________________________
>> OpenSCAD mailing list
>> To unsubscribe send an email to discuss-leave@lists.openscad.org
>>
>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
BC
Bob Carlson
Sat, Oct 26, 2024 6:45 PM
As I understand it, the math for that would be way beyond what I want to tax my brain with. In any case I am not concerned with performance. It’s fine as is.
-Bob
On Oct 26, 2024, at 10:27, Adrian Mariano avm4@cornell.edu wrote:
This looks like a fairly simple shape and also sort of gear like. You will get the best performance if you make it as one polyhedron instead of making one tooth and turning it to geometry and replicating it after and adding chamfers after. Make the tooth point array and then rotate the point list to make all the copies and use vnf_vertex_array one time at the end. It will run in 0.1 s
On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:
<PastedGraphic-1.png>
This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.
<PastedGraphic-2.png>
I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it did not help.
Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org
As I understand it, the math for that would be way beyond what I want to tax my brain with. In any case I am not concerned with performance. It’s fine as is.
-Bob
> On Oct 26, 2024, at 10:27, Adrian Mariano <avm4@cornell.edu> wrote:
>
> This looks like a fairly simple shape and also sort of gear like. You will get the best performance if you make it as one polyhedron instead of making one tooth and turning it to geometry and replicating it after and adding chamfers after. Make the tooth point array and then rotate the point list to make all the copies and use vnf_vertex_array one time at the end. It will run in 0.1 s
>
> On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote:
>> <PastedGraphic-1.png>
>>
>> This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.
>>
>> <PastedGraphic-2.png>
>>
>>> On Oct 25, 2024, at 17:04, Sanjeev Prabhakar <sprabhakar2006@gmail.com <mailto:sprabhakar2006@gmail.com>> wrote:
>>>
>>> Can you post a picture of this
>>>
>>> I will try this as well in python.
>>>
>>> It may not interest you but just want see how tough this is to model
>>>
>>> On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote:
>>>> I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
>>>>
>>>> First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
>>>>
>>>> Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
>>>>
>>>> If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
>>>>
>>>> I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
>>>>
>>>> After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
>>>>
>>>> When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
>>>>
>>>> When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
>>>>
>>>> When I add the diff to remove the chamfer, the number goes way up again.
>>>>
>>>> When I add in the base, the number goes up again and it starts reporting many open edges.
>>>>
>>>> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it did not help.
>>>>
>>>> Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
>>>>
>>>> So, is this an OpenSCAD problem? Or something in my code?
>>>>
>>>> It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
>>>>
>>>> -Bob
>>>>
>>>>
>>>> include <BOSL2/std.scad>
>>>> include <BOSL2/structs.scad>
>>>>
>>>> // Number of Teeth
>>>> _n = 36; // Number Of Teeth
>>>>
>>>> // Inner Radius
>>>> _ir = 30;
>>>> // Outer Radius
>>>> _or = 50;
>>>> // Is the coupling conical?
>>>> _conic = 10;
>>>> // Tooth Profile Angle
>>>> _profile = 60; // [60, 90]
>>>> // Percentage of tooth height
>>>> _chamfer = 5; // Default 5%
>>>> _base = 1;
>>>>
>>>> $fn = 180;
>>>> tiny = 1 / 1024;
>>>>
>>>> hirth_concave();
>>>>
>>>> _irRatio = _ir / _or;
>>>> _toothAngle = 360/_n;
>>>> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
>>>> _chamferHeight = _chamfer * _toothHeight / 100;
>>>> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
>>>> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
>>>> _innerCenterLine = (1 - _irRatio) * _conic;
>>>> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
>>>> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>>>>
>>>> module hirth_concave() {
>>>> zrot(_toothAngle/2)
>>>> union() {
>>>> difference() {
>>>> intersection() {
>>>> union() {
>>>> for (i = [0 : 360/_n : 359])
>>>> zrot(i)
>>>> _profileF();
>>>> }
>>>> tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16*360);
>>>> }
>>>> _chamferF();
>>>> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
>>>> }
>>>> _baseF();
>>>> }
>>>> } // hirth_concave
>>>>
>>>> module _profileF() {
>>>> IR = _ir * .5;
>>>> OR = _or * 1.5;
>>>> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
>>>> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
>>>> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>>>>
>>>> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
>>>> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
>>>> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
>>>> up(_conic)
>>>> skin([tI, tO], slices = 0);
>>>> }
>>>>
>>>>
>>>> module _chamferF() {
>>>> A = -_toothHeight/2 - .1;
>>>> B = -_toothHeight/2 + _chamferHeight;
>>>>
>>>> pts = [[0, _conic],
>>>> [_or+tiny, A],
>>>> [_or+tiny, B]];
>>>>
>>>> rotate_extrude(angle = 360, $fn = 16*360)
>>>> polygon(pts);
>>>> }
>>>>
>>>> module _baseF() {
>>>> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
>>>> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
>>>> C = _toothHeight/2 - _chamferHeight/2;
>>>> pts = [
>>>> [_ir, A],
>>>> [_ir, B],
>>>> [_or, C],
>>>> [_or, A]
>>>> ];
>>>>
>>>> rotate_extrude(angle = 360, $fn = 360*16)
>>>> polygon(pts);
>>>> }
>>>> _______________________________________________
>>>> OpenSCAD mailing list
>>>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
BC
Bob Carlson
Sat, Oct 26, 2024 6:47 PM
When I do the export as a .obj, the slice appears to work correctly. Apparently the error has something to do with the STL export.
-Bob
On Oct 25, 2024, at 17:19, David Phillip Oster via Discuss discuss@lists.openscad.org wrote:
I may be misunderstanding your post, but I pasted the source code you posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no trouble viewing, rendering it, saving it as an .obj file, and slicing the result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
When I do the export as a .obj, the slice appears to work correctly. Apparently the error has something to do with the STL export.
-Bob
> On Oct 25, 2024, at 17:19, David Phillip Oster via Discuss <discuss@lists.openscad.org> wrote:
>
> I may be misunderstanding your post, but I pasted the source code you posted into OpenSCAD 2024.03.01 (git e96dd26d5) on macOS, and had no trouble viewing, rendering it, saving it as an .obj file, and slicing the result, without any indication of error in OpenSCAD or PrusaSlicer 2.8.1.
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
AM
Adrian Mariano
Sat, Oct 26, 2024 7:08 PM
The math is the same. You just accumulate a point list in your for loop
instead of looping over geometry. You have timing of 4s and then 53s which
sounds sort of slow.
On Sat, Oct 26, 2024 at 14:45 Bob Carlson bob@rjcarlson.com wrote:
As I understand it, the math for that would be way beyond what I want to
tax my brain with. In any case I am not concerned with performance. It’s
fine as is.
-Bob
On Oct 26, 2024, at 10:27, Adrian Mariano avm4@cornell.edu wrote:
This looks like a fairly simple shape and also sort of gear like. You will
get the best performance if you make it as one polyhedron instead of making
one tooth and turning it to geometry and replicating it after and adding
chamfers after. Make the tooth point array and then rotate the point list
to make all the copies and use vnf_vertex_array one time at the end. It
will run in 0.1 s
On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <
discuss@lists.openscad.org> wrote:
<PastedGraphic-1.png>
This second picture shows some visual aids I have in my code to show the
center lines, the origin and the groove and ridge angles.
<PastedGraphic-2.png>
On Oct 25, 2024, at 17:04, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
Can you post a picture of this
I will try this as well in python.
It may not interest you but just want see how tough this is to model
On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
discuss@lists.openscad.org> wrote:
I got really intrigued by the Hirth joint and have been working a
library entry that would generate them. I have it fully working,
apparently, because it renders perfectly as far as I can see. However when
I load one of the parts (a concave part) into PrusaSlicer, it reports
thousands of errors that it supposedly fixed. The visual rendering is fine,
but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat
ones mentioned. The one I have actually encountered though is a conical
one. There is a concave part and a convex part. They fit together
perfectly. I had to invent some terminology since I did not find terms for
some things I found to be important. The outer center line is the plane
that passes through the midpoint of the teeth at the outer radius. In a
flat hirth joint all the teeth radiate from the center of this circle, call
it the origin. If the origin of the teeth is above the outer center line,
then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth
profile is either 60 or 90 degrees. The groove angle is the angle that the
groove forms from the origin to the outer radius. It will pass below (for a
convex part) the outer radius. It’s critical for making hirth joints
because it forms the tool path. The ridge angle is the angle formed by the
corresponding ridge.
If the joint is conical, then there is an inner center line that passes
through the center of the teeth at the inner radius. The tooth height is
the critical number to calculate. It is dependent on the number of teeth,
the profile angle and the inner and out radii. Something that really
complicates the mental gymnastics is that the tooth height is smaller at
the inner radius. My code adds a “base” of extra material at the bottom of
the convex part and the top of the concave part. What’s tricky is
positioning the base of the concave part relative to the inner center line.
The concave parts base is relatively easy to place because it depends on
the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical
coordinates to make two 2d tooth profiles. Then I complete a tooth using
skin(). A for loop generates the full set of N teeth. Then intersection or
difference is used the trim the teeth at the inner and outer radii. I
discovered something at that point, but solved it pretty simply. When
diffing a cylinder from the N teeth, each tooth took up a small portion of
the cylinder being diffed out. I had to raise the $fn on the cylinder or
tube being used so that I got enough points in each tooth that diff or
intersection was accurate. I kept raising it until the results stopped
improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to
produce the chamfer at the top of the teeth. Then I add in the base. The
base also adds the “chamfer” at the bottom of the groove. It’s half the
size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL
into PrusaSlicer, it reports errors fixed, but appears to slice correctly
when supports are added.
When I add the intersection to trim the raw teeth, the number of
reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting
many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold
renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it
did not help.
Maybe the biggest hint is that the convex part uses almost identical
code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig
training was 60 years ago. However I doubt a math error is responsible for
the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l =
_tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor =
CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) +
_innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The math is the same. You just accumulate a point list in your for loop
instead of looping over geometry. You have timing of 4s and then 53s which
sounds sort of slow.
On Sat, Oct 26, 2024 at 14:45 Bob Carlson <bob@rjcarlson.com> wrote:
> As I understand it, the math for that would be way beyond what I want to
> tax my brain with. In any case I am not concerned with performance. It’s
> fine as is.
>
> -Bob
>
> On Oct 26, 2024, at 10:27, Adrian Mariano <avm4@cornell.edu> wrote:
>
> This looks like a fairly simple shape and also sort of gear like. You will
> get the best performance if you make it as one polyhedron instead of making
> one tooth and turning it to geometry and replicating it after and adding
> chamfers after. Make the tooth point array and then rotate the point list
> to make all the copies and use vnf_vertex_array one time at the end. It
> will run in 0.1 s
>
> On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <
> discuss@lists.openscad.org> wrote:
>
>> <PastedGraphic-1.png>
>>
>> This second picture shows some visual aids I have in my code to show the
>> center lines, the origin and the groove and ridge angles.
>>
>> <PastedGraphic-2.png>
>>
>
>> On Oct 25, 2024, at 17:04, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
>> wrote:
>>
>> Can you post a picture of this
>>
>> I will try this as well in python.
>>
>> It may not interest you but just want see how tough this is to model
>>
>> On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <
>> discuss@lists.openscad.org> wrote:
>>
>>> I got really intrigued by the Hirth joint and have been working a
>>> library entry that would generate them. I have it fully working,
>>> apparently, because it renders perfectly as far as I can see. However when
>>> I load one of the parts (a concave part) into PrusaSlicer, it reports
>>> thousands of errors that it supposedly fixed. The visual rendering is fine,
>>> but when you look at the slice it is completely screwed up.
>>>
>>> First some explanation. When I looked up hirth joints I only saw flat
>>> ones mentioned. The one I have actually encountered though is a conical
>>> one. There is a concave part and a convex part. They fit together
>>> perfectly. I had to invent some terminology since I did not find terms for
>>> some things I found to be important. The outer center line is the plane
>>> that passes through the midpoint of the teeth at the outer radius. In a
>>> flat hirth joint all the teeth radiate from the center of this circle, call
>>> it the origin. If the origin of the teeth is above the outer center line,
>>> then joint has a conical shape and the two parts are concave and convex.
>>>
>>> Each tooth at every point has the same profile, the top of the tooth
>>> profile is either 60 or 90 degrees. The groove angle is the angle that the
>>> groove forms from the origin to the outer radius. It will pass below (for a
>>> convex part) the outer radius. It’s critical for making hirth joints
>>> because it forms the tool path. The ridge angle is the angle formed by the
>>> corresponding ridge.
>>>
>>> If the joint is conical, then there is an inner center line that passes
>>> through the center of the teeth at the inner radius. The tooth height is
>>> the critical number to calculate. It is dependent on the number of teeth,
>>> the profile angle and the inner and out radii. Something that really
>>> complicates the mental gymnastics is that the tooth height is smaller at
>>> the inner radius. My code adds a “base” of extra material at the bottom of
>>> the convex part and the top of the concave part. What’s tricky is
>>> positioning the base of the concave part relative to the inner center line.
>>> The concave parts base is relatively easy to place because it depends on
>>> the outer radius and center line.
>>>
>>> I generate the raw teeth using the groove and ridge angles and spherical
>>> coordinates to make two 2d tooth profiles. Then I complete a tooth using
>>> skin(). A for loop generates the full set of N teeth. Then intersection or
>>> difference is used the trim the teeth at the inner and outer radii. I
>>> discovered something at that point, but solved it pretty simply. When
>>> diffing a cylinder from the N teeth, each tooth took up a small portion of
>>> the cylinder being diffed out. I had to raise the $fn on the cylinder or
>>> tube being used so that I got enough points in each tooth that diff or
>>> intersection was accurate. I kept raising it until the results stopped
>>> improving. I ended up with the 16*360 you see in the code.
>>>
>>> After I have the raw teeth, I generate a cone that is diffed away to
>>> produce the chamfer at the top of the teeth. Then I add in the base. The
>>> base also adds the “chamfer” at the bottom of the groove. It’s half the
>>> size of the top chamfer to leave a little gap when the parts are joined.
>>>
>>> When I comment out the everything but the raw teeth and import the STL
>>> into PrusaSlicer, it reports errors fixed, but appears to slice correctly
>>> when supports are added.
>>>
>>> When I add the intersection to trim the raw teeth, the number of
>>> reported errors goes way up.
>>>
>>> When I add the diff to remove the chamfer, the number goes way up again.
>>>
>>> When I add in the base, the number goes up again and it starts reporting
>>> many open edges.
>>>
>>> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold
>>> renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it
>>> did not help.
>>>
>>> Maybe the biggest hint is that the convex part uses almost identical
>>> code, but produces no errors. Very weird.
>>>
>>> So, is this an OpenSCAD problem? Or something in my code?
>>>
>>> It’s also possible that my math is off somewhere. My formal trig
>>> training was 60 years ago. However I doubt a math error is responsible for
>>> the slicing problem and STL errors.
>>>
>>> -Bob
>>>
>>>
>>> include <BOSL2/std.scad>
>>> include <BOSL2/structs.scad>
>>>
>>> // Number of Teeth
>>> _n = 36; // Number Of Teeth
>>>
>>> // Inner Radius
>>> _ir = 30;
>>> // Outer Radius
>>> _or = 50;
>>> // Is the coupling conical?
>>> _conic = 10;
>>> // Tooth Profile Angle
>>> _profile = 60; // [60, 90]
>>> // Percentage of tooth height
>>> _chamfer = 5; // Default 5%
>>> _base = 1;
>>>
>>> $fn = 180;
>>> tiny = 1 / 1024;
>>>
>>> hirth_concave();
>>>
>>> _irRatio = _ir / _or;
>>> _toothAngle = 360/_n;
>>> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
>>> _chamferHeight = _chamfer * _toothHeight / 100;
>>> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
>>> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
>>> _innerCenterLine = (1 - _irRatio) * _conic;
>>> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
>>> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>>>
>>> module hirth_concave() {
>>> zrot(_toothAngle/2)
>>> union() {
>>> difference() {
>>> intersection() {
>>> union() {
>>> for (i = [0 : 360/_n : 359])
>>> zrot(i)
>>> _profileF();
>>> }
>>> tube(ir = _ir, or = _or, anchor = CENTER, l =
>>> _tubeHeight, orient = UP, $fn = 16*360);
>>> }
>>> _chamferF();
>>> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor =
>>> CENTER);
>>> }
>>> _baseF();
>>> }
>>> } // hirth_concave
>>>
>>> module _profileF() {
>>> IR = _ir * .5;
>>> OR = _or * 1.5;
>>> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
>>> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
>>> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>>>
>>> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
>>> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
>>> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
>>> up(_conic)
>>> skin([tI, tO], slices = 0);
>>> }
>>>
>>>
>>> module _chamferF() {
>>> A = -_toothHeight/2 - .1;
>>> B = -_toothHeight/2 + _chamferHeight;
>>>
>>> pts = [[0, _conic],
>>> [_or+tiny, A],
>>> [_or+tiny, B]];
>>>
>>> rotate_extrude(angle = 360, $fn = 16*360)
>>> polygon(pts);
>>> }
>>>
>>> module _baseF() {
>>> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
>>> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) +
>>> _innerCenterLine;
>>> C = _toothHeight/2 - _chamferHeight/2;
>>> pts = [
>>> [_ir, A],
>>> [_ir, B],
>>> [_or, C],
>>> [_or, A]
>>> ];
>>>
>>> rotate_extrude(angle = 360, $fn = 360*16)
>>> polygon(pts);
>>> }
>>> _______________________________________________
>>> OpenSCAD mailing list
>>> To unsubscribe send an email to discuss-leave@lists.openscad.org
>>>
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> To unsubscribe send an email to discuss-leave@lists.openscad.org
>>
>
>
BC
Bob Carlson
Sat, Oct 26, 2024 9:42 PM
Maybe I misunderstand, but I don’t think it is at all the same. Doesn't your method require me to calculate the exact location of the vertices? Those at the chamfers are particularly complicated. The teeth are simple projections of a triangle. However the location of the points on the outer (and inner) periphery of the teeth are the points where the tooth intersects a cylinder. So, that outer triangle is not flat. It made my head hurt trying to figure out an easy way to get the shape right. Using diff or intersection with a cylinder let openSCAD do the nasty stuff for me.
I haven’t looked into it, but perhaps you can do all the same intersections and diffs with polyhedrons and then my method would roughly work with polyhedrons as well. However, it would take thousand of shorter renders to get back the time it would take to convert it.
As it is I went through at least 4 different methods of generating the teeth. I was delighted to discover skin() which along with spherical coordinates made it straightforward. I also went through several iterations of generating the base. The convex part base was easy, the concave base was not at all. The chamfer was pretty easy. Most of these were motivated not by performance, but by ease of understanding by me.
I’m now in the process of making the parts attachable and setting up the custom anchors. You should see an enhancement request in BOSL2 soon.
-Bob
On Oct 26, 2024, at 12:08, Adrian Mariano avm4@cornell.edu wrote:
The math is the same. You just accumulate a point list in your for loop instead of looping over geometry. You have timing of 4s and then 53s which sounds sort of slow.
On Sat, Oct 26, 2024 at 14:45 Bob Carlson <bob@rjcarlson.com mailto:bob@rjcarlson.com> wrote:
As I understand it, the math for that would be way beyond what I want to tax my brain with. In any case I am not concerned with performance. It’s fine as is.
-Bob
On Oct 26, 2024, at 10:27, Adrian Mariano <avm4@cornell.edu mailto:avm4@cornell.edu> wrote:
This looks like a fairly simple shape and also sort of gear like. You will get the best performance if you make it as one polyhedron instead of making one tooth and turning it to geometry and replicating it after and adding chamfers after. Make the tooth point array and then rotate the point list to make all the copies and use vnf_vertex_array one time at the end. It will run in 0.1 s
On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:
<PastedGraphic-1.png>
This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.
<PastedGraphic-2.png>
I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
When I add the diff to remove the chamfer, the number goes way up again.
When I add in the base, the number goes up again and it starts reporting many open edges.
Throughout, OpenSCAD reports no errors. Using $fn at 16360, manifold renders in 4+ seconds. At 32360, it’s 53+ seconds. I did check CSG and it did not help.
Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
So, is this an OpenSCAD problem? Or something in my code?
It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
-Bob
include <BOSL2/std.scad>
include <BOSL2/structs.scad>
// Number of Teeth
_n = 36; // Number Of Teeth
// Inner Radius
_ir = 30;
// Outer Radius
_or = 50;
// Is the coupling conical?
_conic = 10;
// Tooth Profile Angle
_profile = 60; // [60, 90]
// Percentage of tooth height
_chamfer = 5; // Default 5%
_base = 1;
$fn = 180;
tiny = 1 / 1024;
hirth_concave();
_irRatio = _ir / _or;
_toothAngle = 360/_n;
_toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
_chamferHeight = _chamfer * _toothHeight / 100;
_grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
_ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
_innerCenterLine = (1 - _irRatio) * _conic;
_stackHeight = _innerCenterLine + _toothHeight + 2*_base;
_tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
module hirth_concave() {
zrot(_toothAngle/2)
union() {
difference() {
intersection() {
union() {
for (i = [0 : 360/_n : 359])
zrot(i)
_profileF();
}
tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16360);
}
_chamferF();
zcyl(r = _ir, h = _tubeHeight, $fn = 16360, anchor = CENTER);
}
_baseF();
}
} // hirth_concave
module _profileF() {
IR = _ir * .5;
OR = _or * 1.5;
tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
up(_conic)
skin([tI, tO], slices = 0);
}
module _chamferF() {
A = -_toothHeight/2 - .1;
B = -_toothHeight/2 + _chamferHeight;
pts = [[0, _conic],
[_or+tiny, A],
[_or+tiny, B]];
rotate_extrude(angle = 360, $fn = 16*360)
polygon(pts);
}
module _baseF() {
A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
C = _toothHeight/2 - _chamferHeight/2;
pts = [
[_ir, A],
[_ir, B],
[_or, C],
[_or, A]
];
rotate_extrude(angle = 360, $fn = 360*16)
polygon(pts);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org
Maybe I misunderstand, but I don’t think it is at all the same. Doesn't your method require me to calculate the exact location of the vertices? Those at the chamfers are particularly complicated. The teeth are simple projections of a triangle. However the location of the points on the outer (and inner) periphery of the teeth are the points where the tooth intersects a cylinder. So, that outer triangle is not flat. It made my head hurt trying to figure out an easy way to get the shape right. Using diff or intersection with a cylinder let openSCAD do the nasty stuff for me.
I haven’t looked into it, but perhaps you can do all the same intersections and diffs with polyhedrons and then my method would roughly work with polyhedrons as well. However, it would take thousand of shorter renders to get back the time it would take to convert it.
As it is I went through at least 4 different methods of generating the teeth. I was delighted to discover skin() which along with spherical coordinates made it straightforward. I also went through several iterations of generating the base. The convex part base was easy, the concave base was not at all. The chamfer was pretty easy. Most of these were motivated not by performance, but by ease of understanding by me.
I’m now in the process of making the parts attachable and setting up the custom anchors. You should see an enhancement request in BOSL2 soon.
-Bob
> On Oct 26, 2024, at 12:08, Adrian Mariano <avm4@cornell.edu> wrote:
>
> The math is the same. You just accumulate a point list in your for loop instead of looping over geometry. You have timing of 4s and then 53s which sounds sort of slow.
>
> On Sat, Oct 26, 2024 at 14:45 Bob Carlson <bob@rjcarlson.com <mailto:bob@rjcarlson.com>> wrote:
>> As I understand it, the math for that would be way beyond what I want to tax my brain with. In any case I am not concerned with performance. It’s fine as is.
>>
>> -Bob
>>
>>> On Oct 26, 2024, at 10:27, Adrian Mariano <avm4@cornell.edu <mailto:avm4@cornell.edu>> wrote:
>>>
>>> This looks like a fairly simple shape and also sort of gear like. You will get the best performance if you make it as one polyhedron instead of making one tooth and turning it to geometry and replicating it after and adding chamfers after. Make the tooth point array and then rotate the point list to make all the copies and use vnf_vertex_array one time at the end. It will run in 0.1 s
>>>
>>> On Sat, Oct 26, 2024 at 12:57 Bob Carlson via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote:
>>>> <PastedGraphic-1.png>
>>>>
>>>> This second picture shows some visual aids I have in my code to show the center lines, the origin and the groove and ridge angles.
>>>>
>>>> <PastedGraphic-2.png>
>>
>>>>
>>>>> On Oct 25, 2024, at 17:04, Sanjeev Prabhakar <sprabhakar2006@gmail.com <mailto:sprabhakar2006@gmail.com>> wrote:
>>>>>
>>>>> Can you post a picture of this
>>>>>
>>>>> I will try this as well in python.
>>>>>
>>>>> It may not interest you but just want see how tough this is to model
>>>>>
>>>>> On Sat, 26 Oct, 2024, 5:15 am Bob Carlson via Discuss, <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote:
>>>>>> I got really intrigued by the Hirth joint and have been working a library entry that would generate them. I have it fully working, apparently, because it renders perfectly as far as I can see. However when I load one of the parts (a concave part) into PrusaSlicer, it reports thousands of errors that it supposedly fixed. The visual rendering is fine, but when you look at the slice it is completely screwed up.
>>>>>>
>>>>>> First some explanation. When I looked up hirth joints I only saw flat ones mentioned. The one I have actually encountered though is a conical one. There is a concave part and a convex part. They fit together perfectly. I had to invent some terminology since I did not find terms for some things I found to be important. The outer center line is the plane that passes through the midpoint of the teeth at the outer radius. In a flat hirth joint all the teeth radiate from the center of this circle, call it the origin. If the origin of the teeth is above the outer center line, then joint has a conical shape and the two parts are concave and convex.
>>>>>>
>>>>>> Each tooth at every point has the same profile, the top of the tooth profile is either 60 or 90 degrees. The groove angle is the angle that the groove forms from the origin to the outer radius. It will pass below (for a convex part) the outer radius. It’s critical for making hirth joints because it forms the tool path. The ridge angle is the angle formed by the corresponding ridge.
>>>>>>
>>>>>> If the joint is conical, then there is an inner center line that passes through the center of the teeth at the inner radius. The tooth height is the critical number to calculate. It is dependent on the number of teeth, the profile angle and the inner and out radii. Something that really complicates the mental gymnastics is that the tooth height is smaller at the inner radius. My code adds a “base” of extra material at the bottom of the convex part and the top of the concave part. What’s tricky is positioning the base of the concave part relative to the inner center line. The concave parts base is relatively easy to place because it depends on the outer radius and center line.
>>>>>>
>>>>>> I generate the raw teeth using the groove and ridge angles and spherical coordinates to make two 2d tooth profiles. Then I complete a tooth using skin(). A for loop generates the full set of N teeth. Then intersection or difference is used the trim the teeth at the inner and outer radii. I discovered something at that point, but solved it pretty simply. When diffing a cylinder from the N teeth, each tooth took up a small portion of the cylinder being diffed out. I had to raise the $fn on the cylinder or tube being used so that I got enough points in each tooth that diff or intersection was accurate. I kept raising it until the results stopped improving. I ended up with the 16*360 you see in the code.
>>>>>>
>>>>>> After I have the raw teeth, I generate a cone that is diffed away to produce the chamfer at the top of the teeth. Then I add in the base. The base also adds the “chamfer” at the bottom of the groove. It’s half the size of the top chamfer to leave a little gap when the parts are joined.
>>>>>>
>>>>>> When I comment out the everything but the raw teeth and import the STL into PrusaSlicer, it reports errors fixed, but appears to slice correctly when supports are added.
>>>>>>
>>>>>> When I add the intersection to trim the raw teeth, the number of reported errors goes way up.
>>>>>>
>>>>>> When I add the diff to remove the chamfer, the number goes way up again.
>>>>>>
>>>>>> When I add in the base, the number goes up again and it starts reporting many open edges.
>>>>>>
>>>>>> Throughout, OpenSCAD reports no errors. Using $fn at 16*360, manifold renders in 4+ seconds. At 32*360, it’s 53+ seconds. I did check CSG and it did not help.
>>>>>>
>>>>>> Maybe the biggest hint is that the convex part uses almost identical code, but produces no errors. Very weird.
>>>>>>
>>>>>> So, is this an OpenSCAD problem? Or something in my code?
>>>>>>
>>>>>> It’s also possible that my math is off somewhere. My formal trig training was 60 years ago. However I doubt a math error is responsible for the slicing problem and STL errors.
>>>>>>
>>>>>> -Bob
>>>>>>
>>>>>>
>>>>>> include <BOSL2/std.scad>
>>>>>> include <BOSL2/structs.scad>
>>>>>>
>>>>>> // Number of Teeth
>>>>>> _n = 36; // Number Of Teeth
>>>>>>
>>>>>> // Inner Radius
>>>>>> _ir = 30;
>>>>>> // Outer Radius
>>>>>> _or = 50;
>>>>>> // Is the coupling conical?
>>>>>> _conic = 10;
>>>>>> // Tooth Profile Angle
>>>>>> _profile = 60; // [60, 90]
>>>>>> // Percentage of tooth height
>>>>>> _chamfer = 5; // Default 5%
>>>>>> _base = 1;
>>>>>>
>>>>>> $fn = 180;
>>>>>> tiny = 1 / 1024;
>>>>>>
>>>>>> hirth_concave();
>>>>>>
>>>>>> _irRatio = _ir / _or;
>>>>>> _toothAngle = 360/_n;
>>>>>> _toothHeight = (sin(_toothAngle/2) * _or) / tan(_profile/2);
>>>>>> _chamferHeight = _chamfer * _toothHeight / 100;
>>>>>> _grooveAngle = atan(((_toothHeight/2) + _conic) / _or);
>>>>>> _ridgeAngle = -atan(((_toothHeight/2) - _conic) / _or);
>>>>>> _innerCenterLine = (1 - _irRatio) * _conic;
>>>>>> _stackHeight = _innerCenterLine + _toothHeight + 2*_base;
>>>>>> _tubeHeight = 2*_conic + 2*_base + 2*_toothHeight;
>>>>>>
>>>>>> module hirth_concave() {
>>>>>> zrot(_toothAngle/2)
>>>>>> union() {
>>>>>> difference() {
>>>>>> intersection() {
>>>>>> union() {
>>>>>> for (i = [0 : 360/_n : 359])
>>>>>> zrot(i)
>>>>>> _profileF();
>>>>>> }
>>>>>> tube(ir = _ir, or = _or, anchor = CENTER, l = _tubeHeight, orient = UP, $fn = 16*360);
>>>>>> }
>>>>>> _chamferF();
>>>>>> zcyl(r = _ir, h = _tubeHeight, $fn = 16*360, anchor = CENTER);
>>>>>> }
>>>>>> _baseF();
>>>>>> }
>>>>>> } // hirth_concave
>>>>>>
>>>>>> module _profileF() {
>>>>>> IR = _ir * .5;
>>>>>> OR = _or * 1.5;
>>>>>> tI = [spherical_to_xyz(IR, 0, _grooveAngle + 90),
>>>>>> spherical_to_xyz(IR, _toothAngle/2, _ridgeAngle + 90),
>>>>>> spherical_to_xyz(IR, -_toothAngle/2, _ridgeAngle + 90)];
>>>>>>
>>>>>> tO = [spherical_to_xyz(OR, 0, _grooveAngle + 90),
>>>>>> spherical_to_xyz(OR, _toothAngle/2, _ridgeAngle + 90),
>>>>>> spherical_to_xyz(OR, -_toothAngle/2, _ridgeAngle + 90)];
>>>>>> up(_conic)
>>>>>> skin([tI, tO], slices = 0);
>>>>>> }
>>>>>>
>>>>>>
>>>>>> module _chamferF() {
>>>>>> A = -_toothHeight/2 - .1;
>>>>>> B = -_toothHeight/2 + _chamferHeight;
>>>>>>
>>>>>> pts = [[0, _conic],
>>>>>> [_or+tiny, A],
>>>>>> [_or+tiny, B]];
>>>>>>
>>>>>> rotate_extrude(angle = 360, $fn = 16*360)
>>>>>> polygon(pts);
>>>>>> }
>>>>>>
>>>>>> module _baseF() {
>>>>>> A = _base + _irRatio*_toothHeight/2 + _innerCenterLine;
>>>>>> B = _irRatio * (_toothHeight/2 - _chamferHeight/2) + _innerCenterLine;
>>>>>> C = _toothHeight/2 - _chamferHeight/2;
>>>>>> pts = [
>>>>>> [_ir, A],
>>>>>> [_ir, B],
>>>>>> [_or, C],
>>>>>> [_or, A]
>>>>>> ];
>>>>>>
>>>>>> rotate_extrude(angle = 360, $fn = 360*16)
>>>>>> polygon(pts);
>>>>>> }
>>>>>> _______________________________________________
>>>>>> OpenSCAD mailing list
>>>>>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
>>>>
>>>> _______________________________________________
>>>> OpenSCAD mailing list
>>>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
>>