# No. 33, Elliptical spur-gears (Brown 1868).
#
# "Elliptical spur-gears. These are used where a rotary motion of varying speed is required, and
#  the variation of speed is determined by the relation between the lengths of the major and minor
#  axes of the ellipses."
#
# Laid out as in the plate (1 unit = 1 cm; the drawing plane is x-z, depth is y): two equal
# elliptical gears side by side, each turning on a shaft through one focus. Semi-axes a = 10,
# b = 8.66 (eccentricity 0.5, focal offset c = 5); the shafts stand 2a = 20 apart, which is the
# sum of the two focal radii at every angle, so the pitch ellipses roll on each other without
# slip. 24 straight-flanked teeth (20 deg) at equal arc pitch 2.446 round each pitch ellipse, each
# its own convex piece set square to the curve (generator: opencode-runs/batch7/gen033.py). At the
# start the left gear meets the right with its far vertex (focal radius a + c = 15) against the
# right one's near vertex (a - c = 5).
#
# Fully physical. Only the left gear's shaft is motor-driven. The right gear turns by tooth contact
# alone, at -r1/r2 of the driver's speed: from -(a - c)/(a + c) = -1/3 to -(a + c)/(a - c) = -3
# and back each turn, -1 on average (equal tooth counts).
number: 33
slug: elliptical-spur-gears
name: Elliptical spur-gears
brown: "Elliptical spur-gears. These are used where a rotary motion of varying speed is required, and the variation of speed is determined by the relation between the lengths of the major and minor axes of the ellipses."
units: cm
sim:
  timestep: 0.0002
  integrator: implicitfast
  iterations: 100
  solver: CG
  multiccd: true
  duration_s: 8
  floor: false
bodies:
  - id: ga
    shape: part
    pos: [-10, 0, 0]
    density: 7800
    friction: 0.1
    color: "#e4d9bf"
    pieces:
      - {kind: disc, center: [-10, 0], radius: 1.4, y: [-1.0, 1.0], collide: 0}   # hub on the focus
      - {kind: poly, points: [[4.1506, 0.0], [4.101, 0.8115], [3.9531, 1.6121], [3.7102, 2.3913], [3.3771, 3.1398], [2.9601, 3.849], [2.4665, 4.512], [1.9042, 5.1228], [1.2811, 5.6771], [0.6053, 6.1713], [-0.1157, 6.603], [-0.8743, 6.9704], [-1.6637, 7.2722], [-2.4771, 7.5075], [-3.3083, 7.676], [-4.1513, 7.7771], [-5.0, 7.8109], [-5.8487, 7.7771], [-6.6917, 7.676], [-7.5229, 7.5075], [-8.3363, 7.2722], [-9.1257, 6.9704], [-9.8843, 6.603], [-10.6053, 6.1713], [-11.2811, 5.6771], [-11.9042, 5.1228], [-12.4665, 4.512], [-12.9601, 3.849], [-13.3771, 3.1398], [-13.7102, 2.3913], [-13.9531, 1.6121], [-14.101, 0.8115], [-14.1506, -0.0], [-14.101, -0.8115], [-13.9531, -1.6121], [-13.7102, -2.3913], [-13.3771, -3.1398], [-12.9601, -3.849], [-12.4665, -4.512], [-11.9042, -5.1228], [-11.2811, -5.6771], [-10.6053, -6.1713], [-9.8843, -6.603], [-9.1257, -6.9704], [-8.3363, -7.2722], [-7.5229, -7.5075], [-6.6917, -7.676], [-5.8487, -7.7771], [-5.0, -7.8109], [-4.1513, -7.7771], [-3.3083, -7.676], [-2.4771, -7.5075], [-1.6637, -7.2722], [-0.8743, -6.9704], [-0.1157, -6.603], [0.6053, -6.1713], [1.2811, -5.6771], [1.9042, -5.1228], [2.4665, -4.512], [2.9601, -3.849], [3.3771, -3.1398], [3.7102, -2.3913], [3.9531, -1.6121], [4.101, -0.8115]], y: [-0.6, 0.6], collide: 0}   # the plate, inside the root curve
      - {kind: poly, points: [[4.1253, 0.2023], [3.8417, 1.9319], [5.5809, 1.6037], [5.6686, 1.0688]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.7074, 2.3242], [2.9046, 3.8822], [4.6603, 4.1058], [4.9085, 3.624]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.6453, 4.2356], [1.4364, 5.5046], [3.0581, 6.2135], [3.432, 5.821]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[1.0725, 5.7929], [-0.4176, 6.7157], [0.9727, 7.8109], [1.4335, 7.5255]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-0.8581, 6.9181], [-2.5201, 7.4745], [-1.418, 8.8594], [-0.9041, 8.6873]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-3.0064, 7.5785], [-4.7492, 7.7641], [-3.9712, 9.3538], [-3.4322, 9.2964]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-5.2508, 7.7641], [-6.9936, 7.5785], [-6.5678, 9.2964], [-6.0288, 9.3538]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-7.4799, 7.4745], [-9.1419, 6.9181], [-9.0959, 8.6873], [-8.582, 8.8594]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-9.5824, 6.7157], [-11.0725, 5.7929], [-11.4335, 7.5255], [-10.9727, 7.8109]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-11.4364, 5.5046], [-12.6453, 4.2356], [-13.432, 5.821], [-13.0581, 6.2135]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-12.9046, 3.8822], [-13.7074, 2.3242], [-14.9085, 3.624], [-14.6603, 4.1058]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-13.8417, 1.9319], [-14.1253, 0.2023], [-15.6686, 1.0688], [-15.5809, 1.6037]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-14.1253, -0.2023], [-13.8417, -1.9319], [-15.5809, -1.6037], [-15.6686, -1.0688]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-13.7074, -2.3242], [-12.9046, -3.8822], [-14.6603, -4.1058], [-14.9085, -3.624]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-12.6453, -4.2356], [-11.4364, -5.5046], [-13.0581, -6.2135], [-13.432, -5.821]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-11.0725, -5.7929], [-9.5824, -6.7157], [-10.9727, -7.8109], [-11.4335, -7.5255]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-9.1419, -6.9181], [-7.4799, -7.4745], [-8.582, -8.8594], [-9.0959, -8.6873]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-6.9936, -7.5785], [-5.2508, -7.7641], [-6.0288, -9.3538], [-6.5678, -9.2964]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-4.7492, -7.7641], [-3.0064, -7.5785], [-3.4322, -9.2964], [-3.9712, -9.3538]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-2.5201, -7.4745], [-0.8581, -6.9181], [-0.9041, -8.6873], [-1.418, -8.8594]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[-0.4176, -6.7157], [1.0725, -5.7929], [1.4335, -7.5255], [0.9727, -7.8109]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[1.4364, -5.5046], [2.6453, -4.2356], [3.432, -5.821], [3.0581, -6.2135]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[2.9046, -3.8822], [3.7074, -2.3242], [4.9085, -3.624], [4.6603, -4.1058]], y: [-0.6, 0.6], collide: 1}
      - {kind: poly, points: [[3.8417, -1.9319], [4.1253, -0.2023], [5.6686, -1.0688], [5.5809, -1.6037]], y: [-0.6, 0.6], collide: 1}
  - id: gb
    shape: part
    pos: [10, 0, 0]
    density: 7800
    friction: 0.1
    color: "#e8dec6"
    pieces:
      - {kind: disc, center: [10, 0], radius: 1.4, y: [-1.0, 1.0], collide: 0}
      - {kind: poly, points: [[24.1506, 0.0], [24.101, 0.8115], [23.9531, 1.6121], [23.7102, 2.3913], [23.3771, 3.1398], [22.9601, 3.849], [22.4665, 4.512], [21.9042, 5.1228], [21.2811, 5.6771], [20.6053, 6.1713], [19.8843, 6.603], [19.1257, 6.9704], [18.3363, 7.2722], [17.5229, 7.5075], [16.6917, 7.676], [15.8487, 7.7771], [15.0, 7.8109], [14.1513, 7.7771], [13.3083, 7.676], [12.4771, 7.5075], [11.6637, 7.2722], [10.8743, 6.9704], [10.1157, 6.603], [9.3947, 6.1713], [8.7189, 5.6771], [8.0958, 5.1228], [7.5335, 4.512], [7.0399, 3.849], [6.6229, 3.1398], [6.2898, 2.3913], [6.0469, 1.6121], [5.899, 0.8115], [5.8494, -0.0], [5.899, -0.8115], [6.0469, -1.6121], [6.2898, -2.3913], [6.6229, -3.1398], [7.0399, -3.849], [7.5335, -4.512], [8.0958, -5.1228], [8.7189, -5.6771], [9.3947, -6.1713], [10.1157, -6.603], [10.8743, -6.9704], [11.6637, -7.2722], [12.4771, -7.5075], [13.3083, -7.676], [14.1513, -7.7771], [15.0, -7.8109], [15.8487, -7.7771], [16.6917, -7.676], [17.5229, -7.5075], [18.3363, -7.2722], [19.1257, -6.9704], [19.8843, -6.603], [20.6053, -6.1713], [21.2811, -5.6771], [21.9042, -5.1228], [22.4665, -4.512], [22.9601, -3.849], [23.3771, -3.1398], [23.7102, -2.3913], [23.9531, -1.6121], [24.101, -0.8115]], y: [-0.6, 0.6], collide: 0}   # the plate, inside the root curve
      - {kind: poly, points: [[24.0706, -0.8763], [24.0706, 0.8763], [25.7337, 0.271], [25.7337, -0.271]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[24.0029, 1.2779], [23.4483, 2.9406], [25.2175, 2.8926], [25.389, 2.3784]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[23.2496, 3.3168], [22.2279, 4.7409], [23.932, 5.2186], [24.248, 4.7782]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[21.9131, 5.0647], [20.5487, 6.1649], [22.0639, 7.0796], [22.4858, 6.7394]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[20.1427, 6.4123], [18.5543, 7.153], [19.8058, 8.4045], [20.2971, 8.1754]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[18.087, 7.3073], [16.3741, 7.6785], [17.3179, 9.1757], [17.8476, 9.0609]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[15.8763, 7.7309], [14.1237, 7.7309], [14.729, 9.394], [15.271, 9.394]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[13.6259, 7.6785], [11.913, 7.3073], [12.1524, 9.0609], [12.6821, 9.1757]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[11.4457, 7.153], [9.8573, 6.4123], [9.7029, 8.1754], [10.1942, 8.4045]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[9.4513, 6.1649], [8.0869, 5.0647], [7.5142, 6.7394], [7.9361, 7.0796]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[7.7721, 4.7409], [6.7504, 3.3168], [5.752, 4.7782], [6.068, 5.2186]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[6.5517, 2.9406], [5.9971, 1.2779], [4.611, 2.3784], [4.7825, 2.8926]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[5.9294, 0.8763], [5.9294, -0.8763], [4.2663, -0.271], [4.2663, 0.271]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[5.9971, -1.2779], [6.5517, -2.9406], [4.7825, -2.8926], [4.611, -2.3784]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[6.7504, -3.3168], [7.7721, -4.7409], [6.068, -5.2186], [5.752, -4.7782]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[8.0869, -5.0647], [9.4513, -6.1649], [7.9361, -7.0796], [7.5142, -6.7394]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[9.8573, -6.4123], [11.4457, -7.153], [10.1942, -8.4045], [9.7029, -8.1754]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[11.913, -7.3073], [13.6259, -7.6785], [12.6821, -9.1757], [12.1524, -9.0609]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[14.1237, -7.7309], [15.8763, -7.7309], [15.271, -9.394], [14.729, -9.394]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[16.3741, -7.6785], [18.087, -7.3073], [17.8476, -9.0609], [17.3179, -9.1757]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[18.5543, -7.153], [20.1427, -6.4123], [20.2971, -8.1754], [19.8058, -8.4045]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[20.5487, -6.1649], [21.9131, -5.0647], [22.4858, -6.7394], [22.0639, -7.0796]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[22.2279, -4.7409], [23.2496, -3.3168], [24.248, -4.7782], [23.932, -5.2186]], y: [-0.6, 0.6], collide: 2}
      - {kind: poly, points: [[23.4483, -2.9406], [24.0029, -1.2779], [25.389, -2.3784], [25.2175, -2.8926]], y: [-0.6, 0.6], collide: 2}
  - {id: stubs, shape: frame, rods: [{from: [-10, -2.4, 0], to: [-10, 2.4, 0], radius: 0.6}, {from: [10, -2.4, 0], to: [10, 2.4, 0], radius: 0.6}], color: "#8f8a80"}
joints:
  - {id: j_a, type: hinge, body: ga, axis: [0, 1, 0], damping: 0.001}
  - {id: j_b, type: hinge, body: gb, axis: [0, 1, 0], damping: 0.01}
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_a, kind: velocity, rpm: 20, kv: 6, max_torque: 8}
checks:
  - {type: ratio, out: j_b, in: j_a, expect: -1.0, tol: 0.03, settle_s: 1, window_s: 6}
  - {type: ratio_range, out: j_b, in: j_a, min: -3.3, max: -0.25, min_swing: 2.2, settle_s: 1, window_s: 6}
  - {type: penetration, max: 0.001, settle_s: 0.5}
camera: {target: [0, 0, 0], position: [0, -75, 1], fov: 34}
display:
  output: j_b
  labels: {j_a: "Driver (left)", j_b: "Driven (right)"}
  proof: {label: "Teeth out of contact", sub: "the left gear turns alone: the right one stands still"}
