# No. 152 (Brown 1868): "An ellipsograph. The traverse bar (shown in an oblique position) carries two studs which slide in the grooves of the cross-piece. By turning the traverse bar an attached pencil is made to describe an ellipse by the rectilinear movement of the studs in the grooves."
#
# Model (cm, no gravity; a plan): the stud A runs in the groove along x (j_x) and the stud B in the groove along z (j_z), 8 cm apart on the traverse bar. The bar turns on the stud A (the one driven joint, 20 turns a minute, + : clockwise); the stud B is pinned to the
# bar and held in its own groove, so the bar can only go round with A drawn out and in. The pencil is fixed on the bar at 1.5 times the way from A to B (12 cm from A), and so describes an ellipse of semi-axes 4 and 12 cm.
# Generator: opencode-runs/batch10/gen152.py.
number: 152
slug: ellipsograph
name: An ellipsograph
brown: "An ellipsograph. The traverse bar (shown in an oblique position) carries two studs which slide in the grooves of the cross-piece. By turning the traverse bar an attached pencil is made to describe an ellipse by the rectilinear movement of the studs in the grooves."
units: cm
sim:
  timestep: 0.0005
  integrator: implicitfast
  iterations: 100
  solver: PGS
  duration_s: 9.0
  floor: false
  gravity: 0
bodies:
  - id: frame
    shape: part
    pos: [0, 0, 0]
    fixed: true
    color: "#cfc6b4"
    pieces:
      - {kind: poly, points: [[-11.2, -14.6], [11.2, -14.6], [11.2, 14.6], [-11.2, 14.6]], y: [0.2, 1.4], collide: 0, color: "#cfc6b4"}
      - {kind: poly, points: [[-9.0, 0.7], [9.0, 0.7], [9.0, -0.7], [-9.0, -0.7]], y: [-0.1, 0.2], collide: 0, color: "#4a4338"}
      - {kind: poly, points: [[-0.7, -9.0], [-0.7, 9.0], [0.7, 9.0], [0.7, -9.0]], y: [-0.1, 0.2], collide: 0, color: "#4a4338"}
      - {kind: poly, points: [[3.9, -0.0015], [3.8848, 1.0444], [4.0848, 1.0473], [4.1, 0.0015]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.8849, 1.0415], [3.8393, 2.0794], [4.0391, 2.0882], [4.0847, 1.0503]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.8395, 2.0764], [3.764, 3.0985], [3.9634, 3.1132], [4.039, 2.0911]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.7643, 3.0954], [3.6593, 4.0938], [3.8582, 4.1147], [3.9632, 3.1163]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.6597, 4.0906], [3.5262, 5.0577], [3.7243, 5.0851], [3.8578, 4.1179]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.5267, 5.0543], [3.3656, 5.9829], [3.5626, 6.0171], [3.7238, 5.0885]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.3663, 5.9792], [3.1788, 6.8621], [3.3744, 6.9037], [3.5619, 6.0208]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.1797, 6.8581], [2.9673, 7.6887], [3.1611, 7.7382], [3.3735, 6.9077]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.9685, 7.6842], [2.7328, 8.4561], [2.9241, 8.5145], [3.1598, 7.7427]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.7345, 8.4511], [2.4772, 9.1583], [2.6651, 9.2267], [2.9224, 8.5195]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.4794, 9.1527], [2.2026, 9.79], [2.386, 9.8697], [2.6629, 9.2324]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.2057, 9.7835], [1.9114, 10.3459], [2.0886, 10.4387], [2.3829, 9.8762]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.9158, 10.3384], [1.6063, 10.8218], [1.7747, 10.9296], [2.0842, 10.4462]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.6126, 10.813], [1.2902, 11.2136], [1.446, 11.339], [1.7684, 10.9384]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.2994, 11.2037], [0.9666, 11.5185], [1.104, 11.6638], [1.4368, 11.349]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.9799, 11.5078], [0.6392, 11.7344], [0.75, 11.901], [1.0907, 11.6744]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.6579, 11.7247], [0.3119, 11.8613], [0.3854, 12.0473], [0.7313, 11.9107]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.3356, 11.8552], [-0.013, 11.9008], [0.013, 12.0992], [0.3616, 12.0535]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.013, 11.9008], [-0.3356, 11.8552], [-0.3616, 12.0535], [-0.013, 12.0992]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.3119, 11.8613], [-0.6579, 11.7247], [-0.7313, 11.9107], [-0.3854, 12.0473]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.6392, 11.7344], [-0.9799, 11.5078], [-1.0907, 11.6744], [-0.75, 11.901]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.9666, 11.5185], [-1.2994, 11.2037], [-1.4368, 11.349], [-1.104, 11.6638]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.2902, 11.2136], [-1.6126, 10.813], [-1.7684, 10.9384], [-1.446, 11.339]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.6063, 10.8218], [-1.9158, 10.3384], [-2.0842, 10.4462], [-1.7747, 10.9296]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.9114, 10.3459], [-2.2057, 9.7835], [-2.3829, 9.8762], [-2.0886, 10.4387]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.2026, 9.79], [-2.4794, 9.1527], [-2.6629, 9.2324], [-2.386, 9.8697]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.4772, 9.1583], [-2.7345, 8.4511], [-2.9224, 8.5195], [-2.6651, 9.2267]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.7328, 8.4561], [-2.9685, 7.6842], [-3.1598, 7.7427], [-2.9241, 8.5145]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.9673, 7.6887], [-3.1797, 6.8581], [-3.3735, 6.9077], [-3.1611, 7.7382]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.1788, 6.8621], [-3.3663, 5.9792], [-3.5619, 6.0208], [-3.3744, 6.9037]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.3656, 5.9829], [-3.5267, 5.0543], [-3.7238, 5.0885], [-3.5626, 6.0171]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.5262, 5.0577], [-3.6597, 4.0906], [-3.8578, 4.1179], [-3.7243, 5.0851]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.6593, 4.0938], [-3.7643, 3.0954], [-3.9632, 3.1163], [-3.8582, 4.1147]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.764, 3.0985], [-3.8395, 2.0764], [-4.039, 2.0911], [-3.9634, 3.1132]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.8393, 2.0794], [-3.8849, 1.0415], [-4.0847, 1.0503], [-4.0391, 2.0882]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.8848, 1.0444], [-3.9, -0.0015], [-4.1, 0.0015], [-4.0848, 1.0473]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.9, 0.0015], [-3.8848, -1.0444], [-4.0848, -1.0473], [-4.1, -0.0015]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.8849, -1.0415], [-3.8393, -2.0794], [-4.0391, -2.0882], [-4.0847, -1.0503]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.8395, -2.0764], [-3.764, -3.0985], [-3.9634, -3.1132], [-4.039, -2.0911]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.7643, -3.0954], [-3.6593, -4.0938], [-3.8582, -4.1147], [-3.9632, -3.1163]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.6597, -4.0906], [-3.5262, -5.0577], [-3.7243, -5.0851], [-3.8578, -4.1179]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.5267, -5.0543], [-3.3656, -5.9829], [-3.5626, -6.0171], [-3.7238, -5.0885]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.3663, -5.9792], [-3.1788, -6.8621], [-3.3744, -6.9037], [-3.5619, -6.0208]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-3.1797, -6.8581], [-2.9673, -7.6887], [-3.1611, -7.7382], [-3.3735, -6.9077]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.9685, -7.6842], [-2.7328, -8.4561], [-2.9241, -8.5145], [-3.1598, -7.7427]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.7345, -8.4511], [-2.4772, -9.1583], [-2.6651, -9.2267], [-2.9224, -8.5195]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.4794, -9.1527], [-2.2026, -9.79], [-2.386, -9.8697], [-2.6629, -9.2324]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-2.2057, -9.7835], [-1.9114, -10.3459], [-2.0886, -10.4387], [-2.3829, -9.8762]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.9158, -10.3384], [-1.6063, -10.8218], [-1.7747, -10.9296], [-2.0842, -10.4462]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.6126, -10.813], [-1.2902, -11.2136], [-1.446, -11.339], [-1.7684, -10.9384]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-1.2994, -11.2037], [-0.9666, -11.5185], [-1.104, -11.6638], [-1.4368, -11.349]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.9799, -11.5078], [-0.6392, -11.7344], [-0.75, -11.901], [-1.0907, -11.6744]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.6579, -11.7247], [-0.3119, -11.8613], [-0.3854, -12.0473], [-0.7313, -11.9107]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.3356, -11.8552], [0.013, -11.9008], [-0.013, -12.0992], [-0.3616, -12.0535]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[-0.013, -11.9008], [0.3356, -11.8552], [0.3616, -12.0535], [0.013, -12.0992]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.3119, -11.8613], [0.6579, -11.7247], [0.7313, -11.9107], [0.3854, -12.0473]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.6392, -11.7344], [0.9799, -11.5078], [1.0907, -11.6744], [0.75, -11.901]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[0.9666, -11.5185], [1.2994, -11.2037], [1.4368, -11.349], [1.104, -11.6638]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.2902, -11.2136], [1.6126, -10.813], [1.7684, -10.9384], [1.446, -11.339]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.6063, -10.8218], [1.9158, -10.3384], [2.0842, -10.4462], [1.7747, -10.9296]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[1.9114, -10.3459], [2.2057, -9.7835], [2.3829, -9.8762], [2.0886, -10.4387]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.2026, -9.79], [2.4794, -9.1527], [2.6629, -9.2324], [2.386, -9.8697]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.4772, -9.1583], [2.7345, -8.4511], [2.9224, -8.5195], [2.6651, -9.2267]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.7328, -8.4561], [2.9685, -7.6842], [3.1598, -7.7427], [2.9241, -8.5145]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[2.9673, -7.6887], [3.1797, -6.8581], [3.3735, -6.9077], [3.1611, -7.7382]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.1788, -6.8621], [3.3663, -5.9792], [3.5619, -6.0208], [3.3744, -6.9037]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.3656, -5.9829], [3.5267, -5.0543], [3.7238, -5.0885], [3.5626, -6.0171]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.5262, -5.0577], [3.6597, -4.0906], [3.8578, -4.1179], [3.7243, -5.0851]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.6593, -4.0938], [3.7643, -3.0954], [3.9632, -3.1163], [3.8582, -4.1147]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.764, -3.0985], [3.8395, -2.0764], [4.039, -2.0911], [3.9634, -3.1132]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.8393, -2.0794], [3.8849, -1.0415], [4.0847, -1.0503], [4.0391, -2.0882]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
      - {kind: poly, points: [[3.8848, -1.0444], [3.9, 0.0015], [4.1, -0.0015], [4.0848, -1.0473]], y: [-0.12, 0.2], collide: 0, color: "#a23b2a"}
  - id: stud_a
    shape: part
    pos: [5.1423, 0, 0.0]
    mass: 0.3
    color: "#8f8a80"
    pieces:
      - {kind: rod, from: [5.1423, 0.2, 0.0], to: [5.1423, -2.6, 0.0], radius: 0.48, collide: 0, color: "#8f8a80"}
  - id: stud_b
    shape: part
    pos: [0.0, 0, 6.1284]
    mass: 0.3
    color: "#8f8a80"
    pieces:
      - {kind: rod, from: [0.0, 0.2, 6.1284], to: [0.0, -2.6, 6.1284], radius: 0.48, collide: 0, color: "#8f8a80"}
  - id: bar
    shape: part
    pos: [5.1423, 0, 0.0]
    mount: stud_a
    mass: 0.5
    color: "#b8ad97"
    pieces:
      - {kind: poly, points: [[5.2229, -1.1073], [-3.6476, 9.4642], [-2.6517, 10.2998], [6.2187, -0.2716]], y: [-2.4, -1.6], collide: 0, color: "#b8ad97"}
      - {kind: disc, center: [5.1423, 0.0], radius: 0.85, y: [-2.9, -2.4], color: "#8f8a80"}
      - {kind: disc, center: [0.0, 6.1284], radius: 0.85, y: [-2.9, -2.4], color: "#8f8a80"}
      - {kind: rod, from: [-2.5712, -1.6, 9.1925], to: [-2.5712, 0.2, 9.1925], radius: 0.22, collide: 0, color: "#a23b2a"}
      - {kind: disc, center: [-2.5712, 9.1925], radius: 0.6, y: [-2.9, -2.4], color: "#a23b2a"}
joints:
  - {id: j_x, type: slide, body: stud_a, axis: [1, 0, 0], damping: 0.02}   # the stud A in its groove; + : to the right
  - {id: j_z, type: slide, body: stud_b, axis: [0, 0, 1], damping: 0.02}   # the stud B in its groove; + : up
  - {id: j_b, type: hinge, body: bar, axis: [0, 1, 0], damping: 0.002}   # the traverse bar on the stud A, the one driven joint; + : clockwise
pins:
  - {id: pin_b, a: bar, b: stud_b, at: [0.0, 0, 6.1284]}
contact: {solref: [0.002, 1.0], solimp: [0.95, 0.99, 0.0005], margin: 0}
driver: {joint: j_b, kind: velocity, rpm: 20, kv: 5.0, max_torque: 5}
checks:
  - {type: follow, out: j_z, in: j_b, expect: 0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 5.495, window_s: 0.4167}
  - {type: follow, out: j_x, in: j_b, expect: -0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 3.245, window_s: 0.4167}
  - {type: follow, out: j_z, in: j_b, expect: -0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 3.995, window_s: 0.4167}
  - {type: follow, out: j_x, in: j_b, expect: 0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 4.745, window_s: 0.4167}
  - {type: follow, out: j_z, in: j_b, expect: 0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 5.495, window_s: 0.4167}
  - {type: follow, out: j_x, in: j_b, expect: -0.0784, tol: 0.0047, min_r2: 0.99, settle_s: 6.245, window_s: 0.4167}
  - {type: position, joint: j_x, min: -13.3423, max: 3.0577, settle_s: 0.0, window_s: 8.5}
  - {type: position, joint: j_z, min: -14.3284, max: 2.0716, settle_s: 0.0, window_s: 8.5}
camera: {target: [0, 0, -1.0], position: [-14.0, -72.0, 8.0], fov: 34}
display:
  output: j_z
  labels: {j_b: "Traverse bar (driver)", j_x: "Stud A", j_z: "Stud B"}
  proof: {label: "Stud B unpinned", sub: "the bar turns but its other stud stays put"}

