openscad / MCAD

OpenSCAD Parametric CAD Library (LGPL 2.1)
http://reprap.org/wiki/MCAD
578 stars 192 forks source link

CGAL error found in bevel_gear #64

Open hamiltont opened 5 years ago

hamiltont commented 5 years ago

When using bevel_gear with these other values, any pressure_angle > 38 seems to cause a CGAL error. I have reduced the error example down to this one line, but it may be possible to further reduce it and identify the specific parameter combination which causes this error. The problem appears to be the gear teeth, as the model will finish rendering but will not have any gear teeth.

  bevel_gear (
    number_of_teeth=36,
    pressure_angle=40,
    outside_circular_pitch=240,
    gear_thickness = 2,
    bore_diameter=9,
    cone_distance=24.001,
    finish=bevel_gear_back_cone);

ERROR: CGAL error in CGALUtils::applyBinaryOperator union: CGAL ERROR: assertion violation! Expr: G.mark(v1,0)==G.mark(v2,0)&& G.mark(v1,1)==G.mark(v2,1) File: /Users/kintel/code/OpenSCAD/libraries/install/include/CGAL/Nef_S2/SM_overlayer.h Line: 304

--- Want to back this issue? **[Post a bounty on it!](https://app.bountysource.com/issues/80135890-cgal-error-found-in-bevel_gear?utm_campaign=plugin&utm_content=tracker%2F86517&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://app.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F86517&utm_medium=issues&utm_source=github).
MichaelAtOz commented 5 years ago

In case anyone with gear maths is looking, apex_to_apex appears to be wrong. Affecting the last cylinder in the difference (and probably more).

MichaelAtOz commented 5 years ago

Nope, more complex than that...

MichaelAtOz commented 5 years ago

\

MichaelAtOz commented 5 years ago

Getting warmer, but my head hurts...

Use this modified module

module involute_bevel_gear_tooth (
    back_cone_radius,
    root_radius,
    base_radius,
    outer_radius,
    pitch_apex,
    cone_distance,
    half_thick_angle,
    involute_facets)
{
//  echo ("involute_bevel_gear_tooth",
//      back_cone_radius,
//      root_radius,
//      base_radius,
//      outer_radius,
//      pitch_apex,
//      cone_distance,
//      half_thick_angle);

    min_radius = max (base_radius*2,root_radius*2);

    pitch_point =
        involute (
            base_radius*2,
            involute_intersect_angle (base_radius*2, back_cone_radius*2));
    pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
    centre_angle = pitch_angle + half_thick_angle;

    start_angle = involute_intersect_angle (base_radius*2, min_radius);
    stop_angle = involute_intersect_angle (base_radius*2, outer_radius*2);

    res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;
c=["red","green","blue","black","orange","purple"];
    translate ([0,0,pitch_apex])
    rotate ([0,-atan(back_cone_radius/cone_distance),0])
    translate ([-back_cone_radius*2,0,-cone_distance*2])
    !union ()
    { translate([-5260,0,0])
        for (i=[1:res])
        { 
            assign (
                point1=
                    involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i-1)/res),
                point2=
                    involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i)/res))
            {
                assign (
                    side1_point1 = rotate_point (centre_angle, point1),
                    side1_point2 = rotate_point (centre_angle, point2),
                    side2_point1 = mirror_point (rotate_point (centre_angle, point1)),
                    side2_point2 = mirror_point (rotate_point (centre_angle, point2)))
                {
                        points=[
                            [back_cone_radius*2+0.1,0,cone_distance*2],
                            [side1_point1[0],side1_point1[1],0],
                            [side1_point2[0],side1_point2[1],0],
                            [side2_point2[0],side2_point2[1],0],
                            [side2_point1[0],side2_point1[1],0],
                            [0.1,0,0]];
                        faces=[[0,2,1],[0,3,2],[0,4,3],[0,1,5],[1,2,5],[2,3,5],[3,4,5],[0,5,4]];
                    polyhedron (points=points,faces=faces);
          for (point=[0:len(points)-1])
            let( p=points[point]) {
              translate([p.x,p.y,p.z])
                color(c[i]) {
                  cube([0.01,0.01,1],true);
                  translate([0,0,-0.2*point]) 
                    linear_extrude(0.1)
                      text(str(point),size=0.5);
                }
              echo(i=i,c[i],point,p=p);
            }
                }
            }
        }
    }
}

The echo output

Parsing design (AST generation)...
Saved backup file: /home/mebd/.local/share/OpenSCAD/backups/unsaved-backup-knnS8520.scad
Compiling design (CSG Tree generation)...
ECHO: "bevel_gear", "teeth", 36, "cone distance", 24.001, 20, 240, 40, 0.2, 9, 0, 1
ECHO: "Num Teeth:", 36, " Pitch Angle:", 89.477, "Pitch Apex:", 0.219091, " Apex to Apex:", 2629.26
ECHO: back_cone_descent = 3.53327
DEPRECATED: The assign() module will be removed in future releases. Use a regular assignment instead. in file , line 282
DEPRECATED: The assign() module will be removed in future releases. Use a regular assignment instead. in file , line 288
ECHO: i = 1, "green", 0, p = [5258.4, 0, 48.002]
ECHO: i = 1, "green", 1, p = [5255.23, -4.66318, 0]
ECHO: i = 1, "green", 2, p = [5256.38, -3.70363, 0]
ECHO: i = 1, "green", 3, p = [5256.38, 3.70363, 0]
ECHO: i = 1, "green", 4, p = [5255.23, 4.66318, 0]
ECHO: i = 1, "green", 5, p = [0.1, 0, 0]
ECHO: i = 2, "blue", 0, p = [5258.4, 0, 48.002]
ECHO: i = 2, "blue", 1, p = [5256.38, -3.70363, 0]
ECHO: i = 2, "blue", 2, p = [5257.53, -2.74306, 0]
ECHO: i = 2, "blue", 3, p = [5257.53, 2.74306, 0]
ECHO: i = 2, "blue", 4, p = [5256.38, 3.70363, 0]
ECHO: i = 2, "blue", 5, p = [0.1, 0, 0]
ECHO: i = 3, "black", 0, p = [5258.4, 0, 48.002]
ECHO: i = 3, "black", 1, p = [5257.53, -2.74306, 0]
ECHO: i = 3, "black", 2, p = [5258.67, -1.78147, 0]
ECHO: i = 3, "black", 3, p = [5258.67, 1.78147, 0]
ECHO: i = 3, "black", 4, p = [5257.53, 2.74306, 0]
ECHO: i = 3, "black", 5, p = [0.1, 0, 0]
ECHO: i = 4, "orange", 0, p = [5258.4, 0, 48.002]
ECHO: i = 4, "orange", 1, p = [5258.67, -1.78147, 0]
ECHO: i = 4, "orange", 2, p = [5259.82, -0.81887, 0]
ECHO: i = 4, "orange", 3, p = [5259.82, 0.81887, 0]
ECHO: i = 4, "orange", 4, p = [5258.67, 1.78147, 0]
ECHO: i = 4, "orange", 5, p = [0.1, 0, 0]
ECHO: i = 5, "purple", 0, p = [5258.4, 0, 48.002]
ECHO: i = 5, "purple", 1, p = [5259.82, -0.81887, 0]
ECHO: i = 5, "purple", 2, p = [5260.97, 0.144747, 0]
ECHO: i = 5, "purple", 3, p = [5260.97, -0.144747, 0]
ECHO: i = 5, "purple", 4, p = [5259.82, 0.81887, 0]
ECHO: i = 5, "purple", 5, p = [0.1, 0, 0]
ECHO: "bgbc1"
Compiling design (CSG Products generation)...
Geometries in cache: 34
Geometry cache size in bytes: 87504
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized CSG tree has 65 elements
Compile and preview finished.
Total rendering time: 0 hours, 0 minutes, 0 seconds

These two points are the problem ECHO: i = 5, "purple", 2, p = [5260.97, 0.144747, 0] ECHO: i = 5, "purple", 3, p = [5260.97, -0.144747, 0]

They are on the opposite side of the axis to the preceeding points, making this tip crossed over. Screenshot at 2019-09-10 11-39-10

But as I said, my head hurts trying to understand why. And i don't want to learn gear geometry... TAG someone else

p.s. also swap the commented lines in bevel_gear() line ~193 to get one tooth

//              for (i = [1:number_of_teeth])
                for (i = [1:1])
MichaelAtOz commented 5 years ago

Make that line ~180

MichaelAtOz commented 5 years ago

..and it involves pressure_angle, 36 is OK, 38 crosses the tip.

MichaelAtOz commented 5 years ago

@hamiltont if you want a hack that gets past the CGAL error, in module involute_bevel_gear_tooth () at line 282 replace points= with this

points=[
  [back_cone_radius*2+0.1,0,cone_distance*2],
  [side1_point1[0],side1_point1[1],0],
  [side1_point2[0],min(side1_point2[1],side2_point2[1]),0],
  [side2_point2[0],max(side1_point2[1],side2_point2[1]),0],
  [side2_point1[0],side2_point1[1],0],
  [0.1,0,0]];

It just forces the points to be on the correct side of the axis. The end of the tooth is slightly wonky, but that end gets trimmed off.

There is also a bug with the sprocket like protrusions inside the hole, but you can fix that with a difference.

hamiltont commented 5 years ago

@MichaelAtOz Wow! Thanks for the effort here. I'm crunched with my day job, but as soon as I resume this side project I'll try to follow along with your work. Maybe I can contribute something

MichaelAtOz commented 5 years ago

@hamiltont Actually the above hack does affect the involute profile:

Capture gears wrong

This (also a hack) is closer, but also loses the flat top:

points=[
  [back_cone_radius*2+0.1,0,cone_distance*2],
  [side1_point1[0],side1_point1[1],0],
  [side1_point2[0],min(side1_point2[1],0),0],
  [side2_point2[0],max(0,side2_point2[1]),0],
  [side2_point1[0],side2_point1[1],0],
  [0.1,0,0]];

I don't know the basis for the shape of the tooth that loop is trying to calculate. Capture gears wrong 2