{
  "schema": "vextcad.vxl.v1",
  "id": "twisted_trefoil",
  "units": {"angle": "deg", "length": "mm"},
  "std": "vxl-std-2",
  "needs": [
    {"id": "closed", "source": "user", "text": "The sculpture is a closed, consistently oriented material mesh."},
    {"id": "one_piece", "source": "user", "text": "The knot is one connected piece."},
    {"id": "separated", "source": "user", "text": "The woven strands and spiral ridges do not intersect themselves."},
    {"id": "size", "source": "user", "text": "The knot is about 90 mm across and fits within a 120 mm cube."},
    {"id": "material", "source": "user", "text": "The sculpture has between 30000 and 65000 cubic millimetres of material."}
  ],
  "params": [
    {"id": "major_radius", "type": "length", "value": "27"},
    {"id": "minor_radius", "type": "length", "value": "14"},
    {"id": "section_radius", "type": "length", "value": "5.75"},
    {"id": "ridge_depth", "type": "length", "value": "1.65"},
    {"id": "twist_turns", "type": "count", "value": "4"}
  ],
  "lets": [
    {"id": "ratio", "expr": "minor_radius / major_radius", "type": "unitless"},
    {"id": "section_step", "expr": "360deg / 24", "type": "angle"}
  ],
  "checks": [
    {"id": "open_center", "expr": "major_radius > minor_radius", "message": "The trefoil retains its central opening."},
    {"id": "positive_core", "expr": "section_radius > ridge_depth", "message": "The star section has a positive inner radius."},
    {"id": "slender_ridges", "expr": "section_radius + ridge_depth < minor_radius * 0.6", "message": "The ridge tips remain small relative to strand separation."}
  ],
  "functions": [
    {
      "id": "bx",
      "expr": "position + handle * derivative * 2 * pi / 24 / 3",
      "lets": [
        {"id": "theta", "expr": "mod(index, 24) * 360deg / 24", "type": "angle"},
        {"id": "position", "expr": "(1 + q * cos(3 * theta)) * cos(2 * theta)", "type": "unitless"},
        {"id": "derivative", "expr": "-3 * q * sin(3 * theta) * cos(2 * theta) - 2 * (1 + q * cos(3 * theta)) * sin(2 * theta)", "type": "unitless"}
      ],
      "params": [
        {"id": "index", "type": "unitless"},
        {"id": "handle", "type": "unitless"},
        {"id": "q", "type": "unitless"}
      ],
      "returns": "unitless"
    },
    {
      "id": "by",
      "expr": "position + handle * derivative * 2 * pi / 24 / 3",
      "lets": [
        {"id": "theta", "expr": "mod(index, 24) * 360deg / 24", "type": "angle"},
        {"id": "position", "expr": "(1 + q * cos(3 * theta)) * sin(2 * theta)", "type": "unitless"},
        {"id": "derivative", "expr": "-3 * q * sin(3 * theta) * sin(2 * theta) + 2 * (1 + q * cos(3 * theta)) * cos(2 * theta)", "type": "unitless"}
      ],
      "params": [
        {"id": "index", "type": "unitless"},
        {"id": "handle", "type": "unitless"},
        {"id": "q", "type": "unitless"}
      ],
      "returns": "unitless"
    },
    {
      "id": "bz",
      "expr": "position + handle * derivative * 2 * pi / 24 / 3",
      "lets": [
        {"id": "theta", "expr": "mod(index, 24) * 360deg / 24", "type": "angle"},
        {"id": "position", "expr": "q * sin(3 * theta)", "type": "unitless"},
        {"id": "derivative", "expr": "3 * q * cos(3 * theta)", "type": "unitless"}
      ],
      "params": [
        {"id": "index", "type": "unitless"},
        {"id": "handle", "type": "unitless"},
        {"id": "q", "type": "unitless"}
      ],
      "returns": "unitless"
    }
  ],
  "parts": [
    {
      "id": "trefoil",
      "deliver": "body",
      "display_color": "#C88B46",
      "rep": "mesh",
      "role": "deliverable",
      "steps": [
        {"id": "woven_ridges", "op": "curve_sweep", "bind": "body", "caps": "none", "frame": {"normal": "x"}, "path": {"closed": true, "segments": [{"control1": ["major_radius * bx(0, 1, ratio)", "major_radius * by(0, 1, ratio)", "major_radius * bz(0, 1, ratio)"], "control2": ["major_radius * bx(1, -1, ratio)", "major_radius * by(1, -1, ratio)", "major_radius * bz(1, -1, ratio)"], "end": ["major_radius * bx(1, 0, ratio)", "major_radius * by(1, 0, ratio)", "major_radius * bz(1, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(1, 1, ratio)", "major_radius * by(1, 1, ratio)", "major_radius * bz(1, 1, ratio)"], "control2": ["major_radius * bx(2, -1, ratio)", "major_radius * by(2, -1, ratio)", "major_radius * bz(2, -1, ratio)"], "end": ["major_radius * bx(2, 0, ratio)", "major_radius * by(2, 0, ratio)", "major_radius * bz(2, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(2, 1, ratio)", "major_radius * by(2, 1, ratio)", "major_radius * bz(2, 1, ratio)"], "control2": ["major_radius * bx(3, -1, ratio)", "major_radius * by(3, -1, ratio)", "major_radius * bz(3, -1, ratio)"], "end": ["major_radius * bx(3, 0, ratio)", "major_radius * by(3, 0, ratio)", "major_radius * bz(3, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(3, 1, ratio)", "major_radius * by(3, 1, ratio)", "major_radius * bz(3, 1, ratio)"], "control2": ["major_radius * bx(4, -1, ratio)", "major_radius * by(4, -1, ratio)", "major_radius * bz(4, -1, ratio)"], "end": ["major_radius * bx(4, 0, ratio)", "major_radius * by(4, 0, ratio)", "major_radius * bz(4, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(4, 1, ratio)", "major_radius * by(4, 1, ratio)", "major_radius * bz(4, 1, ratio)"], "control2": ["major_radius * bx(5, -1, ratio)", "major_radius * by(5, -1, ratio)", "major_radius * bz(5, -1, ratio)"], "end": ["major_radius * bx(5, 0, ratio)", "major_radius * by(5, 0, ratio)", "major_radius * bz(5, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(5, 1, ratio)", "major_radius * by(5, 1, ratio)", "major_radius * bz(5, 1, ratio)"], "control2": ["major_radius * bx(6, -1, ratio)", "major_radius * by(6, -1, ratio)", "major_radius * bz(6, -1, ratio)"], "end": ["major_radius * bx(6, 0, ratio)", "major_radius * by(6, 0, ratio)", "major_radius * bz(6, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(6, 1, ratio)", "major_radius * by(6, 1, ratio)", "major_radius * bz(6, 1, ratio)"], "control2": ["major_radius * bx(7, -1, ratio)", "major_radius * by(7, -1, ratio)", "major_radius * bz(7, -1, ratio)"], "end": ["major_radius * bx(7, 0, ratio)", "major_radius * by(7, 0, ratio)", "major_radius * bz(7, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(7, 1, ratio)", "major_radius * by(7, 1, ratio)", "major_radius * bz(7, 1, ratio)"], "control2": ["major_radius * bx(8, -1, ratio)", "major_radius * by(8, -1, ratio)", "major_radius * bz(8, -1, ratio)"], "end": ["major_radius * bx(8, 0, ratio)", "major_radius * by(8, 0, ratio)", "major_radius * bz(8, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(8, 1, ratio)", "major_radius * by(8, 1, ratio)", "major_radius * bz(8, 1, ratio)"], "control2": ["major_radius * bx(9, -1, ratio)", "major_radius * by(9, -1, ratio)", "major_radius * bz(9, -1, ratio)"], "end": ["major_radius * bx(9, 0, ratio)", "major_radius * by(9, 0, ratio)", "major_radius * bz(9, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(9, 1, ratio)", "major_radius * by(9, 1, ratio)", "major_radius * bz(9, 1, ratio)"], "control2": ["major_radius * bx(10, -1, ratio)", "major_radius * by(10, -1, ratio)", "major_radius * bz(10, -1, ratio)"], "end": ["major_radius * bx(10, 0, ratio)", "major_radius * by(10, 0, ratio)", "major_radius * bz(10, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(10, 1, ratio)", "major_radius * by(10, 1, ratio)", "major_radius * bz(10, 1, ratio)"], "control2": ["major_radius * bx(11, -1, ratio)", "major_radius * by(11, -1, ratio)", "major_radius * bz(11, -1, ratio)"], "end": ["major_radius * bx(11, 0, ratio)", "major_radius * by(11, 0, ratio)", "major_radius * bz(11, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(11, 1, ratio)", "major_radius * by(11, 1, ratio)", "major_radius * bz(11, 1, ratio)"], "control2": ["major_radius * bx(12, -1, ratio)", "major_radius * by(12, -1, ratio)", "major_radius * bz(12, -1, ratio)"], "end": ["major_radius * bx(12, 0, ratio)", "major_radius * by(12, 0, ratio)", "major_radius * bz(12, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(12, 1, ratio)", "major_radius * by(12, 1, ratio)", "major_radius * bz(12, 1, ratio)"], "control2": ["major_radius * bx(13, -1, ratio)", "major_radius * by(13, -1, ratio)", "major_radius * bz(13, -1, ratio)"], "end": ["major_radius * bx(13, 0, ratio)", "major_radius * by(13, 0, ratio)", "major_radius * bz(13, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(13, 1, ratio)", "major_radius * by(13, 1, ratio)", "major_radius * bz(13, 1, ratio)"], "control2": ["major_radius * bx(14, -1, ratio)", "major_radius * by(14, -1, ratio)", "major_radius * bz(14, -1, ratio)"], "end": ["major_radius * bx(14, 0, ratio)", "major_radius * by(14, 0, ratio)", "major_radius * bz(14, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(14, 1, ratio)", "major_radius * by(14, 1, ratio)", "major_radius * bz(14, 1, ratio)"], "control2": ["major_radius * bx(15, -1, ratio)", "major_radius * by(15, -1, ratio)", "major_radius * bz(15, -1, ratio)"], "end": ["major_radius * bx(15, 0, ratio)", "major_radius * by(15, 0, ratio)", "major_radius * bz(15, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(15, 1, ratio)", "major_radius * by(15, 1, ratio)", "major_radius * bz(15, 1, ratio)"], "control2": ["major_radius * bx(16, -1, ratio)", "major_radius * by(16, -1, ratio)", "major_radius * bz(16, -1, ratio)"], "end": ["major_radius * bx(16, 0, ratio)", "major_radius * by(16, 0, ratio)", "major_radius * bz(16, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(16, 1, ratio)", "major_radius * by(16, 1, ratio)", "major_radius * bz(16, 1, ratio)"], "control2": ["major_radius * bx(17, -1, ratio)", "major_radius * by(17, -1, ratio)", "major_radius * bz(17, -1, ratio)"], "end": ["major_radius * bx(17, 0, ratio)", "major_radius * by(17, 0, ratio)", "major_radius * bz(17, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(17, 1, ratio)", "major_radius * by(17, 1, ratio)", "major_radius * bz(17, 1, ratio)"], "control2": ["major_radius * bx(18, -1, ratio)", "major_radius * by(18, -1, ratio)", "major_radius * bz(18, -1, ratio)"], "end": ["major_radius * bx(18, 0, ratio)", "major_radius * by(18, 0, ratio)", "major_radius * bz(18, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(18, 1, ratio)", "major_radius * by(18, 1, ratio)", "major_radius * bz(18, 1, ratio)"], "control2": ["major_radius * bx(19, -1, ratio)", "major_radius * by(19, -1, ratio)", "major_radius * bz(19, -1, ratio)"], "end": ["major_radius * bx(19, 0, ratio)", "major_radius * by(19, 0, ratio)", "major_radius * bz(19, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(19, 1, ratio)", "major_radius * by(19, 1, ratio)", "major_radius * bz(19, 1, ratio)"], "control2": ["major_radius * bx(20, -1, ratio)", "major_radius * by(20, -1, ratio)", "major_radius * bz(20, -1, ratio)"], "end": ["major_radius * bx(20, 0, ratio)", "major_radius * by(20, 0, ratio)", "major_radius * bz(20, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(20, 1, ratio)", "major_radius * by(20, 1, ratio)", "major_radius * bz(20, 1, ratio)"], "control2": ["major_radius * bx(21, -1, ratio)", "major_radius * by(21, -1, ratio)", "major_radius * bz(21, -1, ratio)"], "end": ["major_radius * bx(21, 0, ratio)", "major_radius * by(21, 0, ratio)", "major_radius * bz(21, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(21, 1, ratio)", "major_radius * by(21, 1, ratio)", "major_radius * bz(21, 1, ratio)"], "control2": ["major_radius * bx(22, -1, ratio)", "major_radius * by(22, -1, ratio)", "major_radius * bz(22, -1, ratio)"], "end": ["major_radius * bx(22, 0, ratio)", "major_radius * by(22, 0, ratio)", "major_radius * bz(22, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(22, 1, ratio)", "major_radius * by(22, 1, ratio)", "major_radius * bz(22, 1, ratio)"], "control2": ["major_radius * bx(23, -1, ratio)", "major_radius * by(23, -1, ratio)", "major_radius * bz(23, -1, ratio)"], "end": ["major_radius * bx(23, 0, ratio)", "major_radius * by(23, 0, ratio)", "major_radius * bz(23, 0, ratio)"], "kind": "cubic"}, {"control1": ["major_radius * bx(23, 1, ratio)", "major_radius * by(23, 1, ratio)", "major_radius * bz(23, 1, ratio)"], "control2": ["major_radius * bx(24, -1, ratio)", "major_radius * by(24, -1, ratio)", "major_radius * bz(24, -1, ratio)"], "end": ["major_radius * bx(24, 0, ratio)", "major_radius * by(24, 0, ratio)", "major_radius * bz(24, 0, ratio)"], "kind": "cubic"}], "start": ["major_radius * bx(0, 0, ratio)", "major_radius * by(0, 0, ratio)", "major_radius * bz(0, 0, ratio)"]}, "sampling": {"chord_error": "0.008", "length_error": "0.002", "spacing": "1000"}, "section": {"chord_error": "0.05", "region": {"polygon": {"points": [{"each": [{"range": ["0", "23"], "var": "j"}], "emit": ["(section_radius + ridge_depth * cos(6 * j * section_step)) * cos(j * section_step)", "(section_radius + ridge_depth * cos(6 * j * section_step)) * sin(j * section_step)"]}]}}}, "twist": "twist_turns * 360deg"}
      ]
    }
  ],
  "requirements": [
    {"id": "closed", "kind": "closed_delivered_mesh", "subject": "trefoil", "covers": ["closed"], "required": true},
    {"id": "one_piece", "kind": "component_count", "subject": "trefoil", "count": "1", "covers": ["one_piece"], "required": true},
    {"id": "separated", "kind": "self_intersection_free", "subject": "trefoil", "covers": ["separated"], "required": true},
    {"id": "size", "kind": "envelope", "subject": "trefoil", "size": ["90", "94", "43"], "tol": "5", "covers": ["size"], "required": true},
    {"id": "material", "kind": "volume_range", "subject": "trefoil", "max": "65000", "min": "30000", "covers": ["material"], "required": true}
  ]
}
