{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openeik.org/schemas/0.1/proposed/derived/bodies.schema.json",
  "$comment": "Proposed for OpenEik 0.2: the schema of a result of the derived layer (Part IV, 1.1.2), its bodies in the kinds of Part IV, 1.1.1, by the steward's decision of 30 October 2026 (open questions, 98). Written by hand from Part IV, 1.1.1 and 1.1.2, not generated: tools/generate-schemas.mjs keeps this folder and lists none of it in index.json. No file of OpenEik 0.1 is held to it: 0.1 fixes neither the layout of .eik/derived/ nor the form of a result. @openeik/tools holds to it the results an application hands its IFC bridge (ifcOfModel(model, {bodies})), and writes its own derived layer in it (derivedLayer). It keeps the name it had when it held a result's bodies alone (26 October 2026).",
  "title": "A result of the derived layer, proposed for 0.2",
  "description": "One result of the derived layer (Part IV, 1.1.2): what a producer derived for one record, an element or a type, at `.eik/derived/elements/<id>.json` or `.eik/derived/types/<id>.json` in a folder, and keyed `elements/<id>` or `types/<id>` where it is handed from one tool to another, as a result's sources are keyed; with every record it was derived from by its hash (rule 3), so that a reader uses it only while those hashes hold (rule 4). Its result is the record's bodies in the kinds of Part IV, 1.1.1, an element's with its quantities and a member's lines, and nothing else. Coordinates are in millimetres, z up (Part I, 3): an element's in the model's coordinates, a type's in its own frame, which a `mapped` body places. Every body may carry the tags of `tags`.",
  "type": "object",
  "properties": {
    "sources": {
      "description": "Every record, and every set of records, the result was derived from, by its key and its hash (Part III, 6), or null for a key the model has none of (Part IV, 1.1.2, rule 3): `<list>/<id>` for a record of a list (`elements/<id>`, `types/<id>`, `materials/<id>` and the others), `levels` for the levels record and `project` for the project record; `referrers/<id>`, the hash of the ids of the elements that name the element by hostId or by a join's to, sorted in code-unit order; and `categories/<category>`, the hash of every element of a category, in the order of their ids. A reader uses the result only while every hash holds (Part IV, 1.1.2, rule 4).",
      "type": "object",
      "minProperties": 1,
      "propertyNames": { "type": "string", "minLength": 1, "maxLength": 1024, "pattern": "^(levels|project|[a-z][A-Za-z0-9]*/[^]+)$" },
      "additionalProperties": {
        "anyOf": [
          { "type": "string", "pattern": "^[0-9a-f]{64}$" },
          { "type": "null" }
        ]
      }
    },
    "producer": {
      "description": "The implementation that derived the result and its version, as people read it (`Acme Modeller 2.31`); a bridge names it in its fidelity report as the one that gave the bodies.",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "rule": {
      "description": "The rule, or the set of rules, that derived the result, by the producer's name for it: with its producer, what a reader that wants its own rules' result compares (Part IV, 1.1.2, rule 5).",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "result": {
      "description": "What was derived for the record (Part IV, 1.1.2, rule 2): its bodies, and, for an element, its quantities and a beam's or a column's lines; nothing else.",
      "type": "object",
      "properties": {
        "bodies": {
          "description": "The record's bodies, in the kinds of Part IV, 1.1.1 and with its tags, in the order the producer gives them; a reader keeps that order.",
          "type": "array",
          "items": { "$ref": "#/$defs/body" },
          "maxItems": 100000
        },
        "quantities": { "$ref": "#/$defs/quantities" },
        "line": { "$ref": "#/$defs/line" }
      },
      "required": ["bodies"],
      "additionalProperties": false
    }
  },
  "required": ["sources", "producer", "rule", "result"],
  "additionalProperties": false,
  "$defs": {
    "quantity": {
      "description": "A quantity, as Part IV, 9 reports one: its value, its unit, how it was measured and the rule it was measured by.",
      "type": "object",
      "properties": {
        "value": { "type": "number" },
        "unit": { "type": "string", "enum": ["m3", "m2", "m", "count"] },
        "basis": { "type": "string", "maxLength": 1000 },
        "rule": { "type": "string", "maxLength": 200 }
      },
      "required": ["value", "unit"],
      "additionalProperties": false
    },
    "quantities": {
      "description": "An element's quantities by their names (Part IV, 9): `volume`, `length`, `area`, a wall's `grossArea`, `openingArea` and `netArea`, a roof's `slopedArea`, `planArea`, `ridge` and `hips`, a room's and the others; and `layers`, a quantity by the id of each of its type's layers.",
      "type": "object",
      "properties": {
        "layers": {
          "type": "object",
          "propertyNames": { "type": "string", "minLength": 1, "maxLength": 1024 },
          "additionalProperties": { "$ref": "#/$defs/quantity" }
        }
      },
      "propertyNames": { "type": "string", "pattern": "^[a-z][A-Za-z0-9]*$", "maxLength": 64 },
      "additionalProperties": { "$ref": "#/$defs/quantity" }
    },
    "segment": {
      "description": "A line from its start to its end, or null where there is none.",
      "anyOf": [{ "type": "array", "minItems": 2, "maxItems": 2, "items": { "$ref": "#/$defs/p3" } }, { "type": "null" }]
    },
    "line": {
      "description": "A beam's or a column's lines (Part IV, 6.5): its `reference` line through the middle of its section and its `axis` through its centroid, or null where it has none; a beam's `setOut` line (Part IV, 6.2); `centroidOffset`, the centroid's offset from the middle of the section in the section's own x and y before roll or turn, or null; its `section`, its shape, width, depth, end depth where it is tapered and area, null where it is not derived; and its `length`, mm.",
      "type": "object",
      "properties": {
        "reference": { "$ref": "#/$defs/segment" },
        "axis": { "$ref": "#/$defs/segment" },
        "setOut": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "$ref": "#/$defs/p3" } },
        "centroidOffset": { "anyOf": [{ "$ref": "#/$defs/p2" }, { "type": "null" }] },
        "section": {
          "type": "object",
          "properties": {
            "shape": { "type": "string", "minLength": 1, "maxLength": 64 },
            "width": { "$ref": "#/$defs/size" },
            "depth": { "$ref": "#/$defs/size" },
            "endDepth": { "$ref": "#/$defs/size" },
            "area": { "anyOf": [{ "type": "number", "minimum": 0 }, { "type": "null" }] }
          },
          "required": ["shape", "width", "depth", "area"],
          "additionalProperties": false
        },
        "length": { "type": "number", "minimum": 0 }
      },
      "required": ["reference", "axis", "centroidOffset", "section", "length"],
      "additionalProperties": false
    },
    "length": {
      "type": "number",
      "minimum": -100000000,
      "maximum": 100000000
    },
    "size": {
      "type": "number",
      "exclusiveMinimum": 0,
      "maximum": 100000000
    },
    "p2": {
      "description": "A point in plan, or in a section's own plane: [x, y], mm.",
      "type": "array",
      "minItems": 2,
      "maxItems": 2,
      "items": { "type": "number", "minimum": -100000000, "maximum": 100000000 }
    },
    "p3": {
      "description": "A point or a vector: [x, y, z], mm, z up.",
      "type": "array",
      "minItems": 3,
      "maxItems": 3,
      "items": { "type": "number", "minimum": -100000000, "maximum": 100000000 }
    },
    "ring": {
      "description": "A closed polygon of at least three points, its first point not repeated at its end.",
      "type": "array",
      "items": { "$ref": "#/$defs/p2" },
      "minItems": 3,
      "maxItems": 100000
    },
    "loop": {
      "description": "A loop of a face: the indices of its vertices, from 0, in turn.",
      "type": "array",
      "items": { "type": "integer", "minimum": 0 },
      "minItems": 3,
      "maxItems": 100000
    },
    "section": {
      "description": "A member's cross-section by Part II, 5.2: its shape and sizes, `width` across and `depth` up, the middle of its bounding box on the body's line.",
      "type": "object",
      "properties": {
        "shape": { "type": "string", "enum": ["rectangle", "I", "T", "RHS", "CHS", "round", "L", "2L", "U", "custom"] },
        "width": { "$ref": "#/$defs/size" },
        "depth": { "$ref": "#/$defs/size" },
        "web": { "$ref": "#/$defs/size" },
        "flange": { "$ref": "#/$defs/size" },
        "radius": { "type": "number", "minimum": 0, "maximum": 500 },
        "gap": { "type": "number", "minimum": 0, "maximum": 10000 },
        "angleCorner": { "type": "string", "enum": ["bottomLeft", "bottomRight", "topLeft", "topRight"] },
        "designation": { "type": "string", "maxLength": 200 },
        "outline": {
          "description": "A custom section's outline (Part II, 5.2, rules 8 to 10): `points`, the contour of its outside, and `voids`, each `{points}`, the contour of a hole through it.",
          "type": "object",
          "properties": {
            "points": { "$ref": "#/$defs/contour" },
            "voids": { "type": "array", "maxItems": 1000, "items": { "type": "object", "properties": { "points": { "$ref": "#/$defs/contour" } }, "required": ["points"] } }
          },
          "required": ["points"]
        }
      },
      "required": ["width", "depth"],
      "if": { "properties": { "shape": { "const": "custom" } }, "required": ["shape"] },
      "then": { "required": ["outline"] },
      "else": { "properties": { "outline": false } }
    },
    "contour": {
      "description": "A contour of a custom section (Part II, 5.2, rule 8), in mm in the section's own plane, closed by its last side: each entry a corner `[x, y]`, a rounded corner `[x, y, r]`, or `{through: [x, y]}`, a point the arc between its neighbours passes through.",
      "type": "array",
      "minItems": 3,
      "maxItems": 10000,
      "items": {
        "anyOf": [
          { "type": "array", "minItems": 2, "maxItems": 3, "prefixItems": [{ "type": "number", "minimum": -100000, "maximum": 100000 }, { "type": "number", "minimum": -100000, "maximum": 100000 }, { "type": "number", "minimum": 0, "maximum": 100000 }] },
          { "type": "object", "properties": { "through": { "type": "array", "minItems": 2, "maxItems": 2, "prefixItems": [{ "type": "number", "minimum": -100000, "maximum": 100000 }, { "type": "number", "minimum": -100000, "maximum": 100000 }] } }, "required": ["through"] }
        ]
      }
    },
    "member": {
      "description": "The framing member a body is, written as a part of its element: `id` unique in the model (the reference implementation's member ids, which name their host), its IFC4 class and predefined type, a user-defined type where the predefined type is USERDEFINED, its name, and its `section` as people name it (`45x145`), by which the members of one class, predefined type and section share an IFC type, as the reference bridge writes them.",
      "type": "object",
      "properties": {
        "id": { "type": "string", "minLength": 1, "maxLength": 1024 },
        "class": { "type": "string", "pattern": "^Ifc[A-Z][A-Za-z]*$" },
        "predefined": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" },
        "objectType": { "type": "string", "minLength": 1, "maxLength": 200 },
        "name": { "type": "string", "maxLength": 1024 },
        "section": { "type": "string", "minLength": 1, "maxLength": 200 }
      },
      "required": ["id"]
    },
    "tags": {
      "description": "What a body is, for IFC and for people: its `material`, by the name of one of the model's materials or a name of its own; the `layer` of its element's type it is, by the layer's id (Part II, 5.1), which gives its material and colour where it names none; the `part` of its element it is, on the body of any element, by a name of the producer's (a door's or a window's frame, sash, glass, leaf, panel, casing or handle; a railing's post, rail or baluster; a truss's topChord or strut), where an element's bodies name two or more parts a bridge writing each as a material constituent and a shape aspect, and where they name one, the element keeping the material it has without parts (Part IV, 1.1.1); the `piece` of its element it is, written as a part of it (a stair's flight:0, winders, landing:0, stringer:0:left, beam, newel, column, bearing:0:left); the framing `member` it is; its `color`; and whether it is `glass`.",
      "type": "object",
      "properties": {
        "material": { "type": "string", "minLength": 1, "maxLength": 200 },
        "layer": { "type": "string", "minLength": 1, "maxLength": 1024 },
        "part": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]*$", "maxLength": 64 },
        "piece": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9]*(:[A-Za-z0-9_-]+)*$", "maxLength": 200 },
        "member": { "$ref": "#/$defs/member" },
        "color": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
        "glass": { "type": "boolean" }
      }
    },
    "extrusion": {
      "description": "An upright extrusion: a plan polygon, counter-clockwise seen from above, less its holes, each clockwise, from z0 up by height. As the compiler's prism (Part IV, 8, N1) with its underside and top level.",
      "type": "object",
      "properties": {
        "kind": { "const": "extrusion" },
        "profile": { "$ref": "#/$defs/ring" },
        "holes": { "type": "array", "items": { "$ref": "#/$defs/ring" }, "maxItems": 10000 },
        "z0": { "$ref": "#/$defs/length" },
        "height": { "$ref": "#/$defs/size" }
      },
      "required": ["kind", "profile", "z0", "height"]
    },
    "faces": {
      "description": "A body of plane faces (Part IV, 8, N2 and N6): its vertices, and each face an outer loop of their indices, counter-clockwise seen from outside, with its holes, each the other way; optionally a normal per vertex where the body is smooth. A face whose points do not lie on one plane is written in triangles.",
      "type": "object",
      "properties": {
        "kind": { "const": "faces" },
        "vertices": { "type": "array", "items": { "$ref": "#/$defs/p3" }, "minItems": 3, "maxItems": 1048576 },
        "faces": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "outer": { "$ref": "#/$defs/loop" },
              "holes": { "type": "array", "items": { "$ref": "#/$defs/loop" }, "maxItems": 10000 }
            },
            "required": ["outer"]
          },
          "minItems": 1,
          "maxItems": 1048576
        },
        "normals": { "type": "array", "items": { "$ref": "#/$defs/p3" }, "maxItems": 1048576 }
      },
      "required": ["kind", "vertices", "faces"]
    },
    "rod": {
      "description": "A round bar from one point to another of a diameter (Part IV, 8, N5).",
      "type": "object",
      "properties": {
        "kind": { "const": "rod" },
        "from": { "$ref": "#/$defs/p3" },
        "to": { "$ref": "#/$defs/p3" },
        "diameter": { "$ref": "#/$defs/size" }
      },
      "required": ["kind", "from", "to", "diameter"]
    },
    "cylinder": {
      "description": "An upright cylinder: a circle in plan from z0 up by height (Part IV, 8, N5), as a round pier.",
      "type": "object",
      "properties": {
        "kind": { "const": "cylinder" },
        "centre": { "$ref": "#/$defs/p2" },
        "radius": { "$ref": "#/$defs/size" },
        "z0": { "$ref": "#/$defs/length" },
        "height": { "$ref": "#/$defs/size" }
      },
      "required": ["kind", "centre", "radius", "z0", "height"]
    },
    "swept": {
      "description": "A section carried straight from one point to another (Part IV, 8, N4): a section of Part II, 5.2, or a polygon in the section's own plane, x across and y up, the line through its origin. Its frame is a member's: along the line; up square to it in the vertical plane through it, or +y for a line straight up; across = up x along; turned by `roll` degrees about the line, right-handed about its direction, as a beam's roll turns it (Part IV, 6.2, rule 5).",
      "type": "object",
      "properties": {
        "kind": { "const": "swept" },
        "section": {
          "anyOf": [{ "$ref": "#/$defs/section" }, { "$ref": "#/$defs/ring" }]
        },
        "from": { "$ref": "#/$defs/p3" },
        "to": { "$ref": "#/$defs/p3" },
        "roll": { "type": "number", "minimum": -360, "maximum": 360 }
      },
      "required": ["kind", "section", "from", "to"]
    },
    "mapped": {
      "description": "A type's representation placed: the bodies of the result `types/<type>` (the element's own type where it names none), in their frame, placed at `origin` with that frame's x along `xAxis` and its z along `zAxis` (by default the model's). A bridge writes the type's bodies once, as a representation map of its IFC type, and the element as a mapped item of it.",
      "type": "object",
      "properties": {
        "kind": { "const": "mapped" },
        "type": { "type": "string", "minLength": 1, "maxLength": 1024 },
        "origin": { "$ref": "#/$defs/p3" },
        "xAxis": { "$ref": "#/$defs/p3" },
        "zAxis": { "$ref": "#/$defs/p3" }
      },
      "required": ["kind", "origin"]
    },
    "body": {
      "description": "A body of one of the kinds, and its tags.",
      "type": "object",
      "properties": {
        "kind": { "type": "string", "enum": ["extrusion", "faces", "rod", "cylinder", "swept", "mapped"] }
      },
      "required": ["kind"],
      "allOf": [
        { "$ref": "#/$defs/tags" },
        { "if": { "properties": { "kind": { "const": "extrusion" } } }, "then": { "$ref": "#/$defs/extrusion" } },
        { "if": { "properties": { "kind": { "const": "faces" } } }, "then": { "$ref": "#/$defs/faces" } },
        { "if": { "properties": { "kind": { "const": "rod" } } }, "then": { "$ref": "#/$defs/rod" } },
        { "if": { "properties": { "kind": { "const": "cylinder" } } }, "then": { "$ref": "#/$defs/cylinder" } },
        { "if": { "properties": { "kind": { "const": "swept" } } }, "then": { "$ref": "#/$defs/swept" } },
        { "if": { "properties": { "kind": { "const": "mapped" } } }, "then": { "$ref": "#/$defs/mapped" } }
      ]
    }
  }
}
