Skip to content

feat(ifc): Revit 2015 to 2023 beams are drawn along their location line (#1190) (RE-362) - #1509

Draft
puzzbobb wants to merge 7 commits into
DrunkOnJava:mainfrom
puzzbobb:feat-1190-2015-2023-beams-re348
Draft

puzzbobb wants to merge 7 commits into
DrunkOnJava:mainfrom
puzzbobb:feat-1190-2015-2023-beams-re348

Conversation

@puzzbobb

@puzzbobb puzzbobb commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Revit 2015 to 2023 projects now draw beams along their location lines and write their Span, Slope, Roll and Length, as 2024 projects do. It's a third slice of #1190, measured against the same Autodesk samples saved by a later release, not against a Revit export.

Motivation

#1190 asks for each capability 2024 and 2025 have on every release from 2015 to 2027. Revit 2015 to 2023 take a branch of recover_partition_schema_mvp that ends before the beam readers, so a beam there was its record box, although walls on those releases read the same line record (RE-114, RE-180, RE-181). exported.body_sources on main:

body source rac_advanced 2023 / 2024 rst_basic 2023 / 2024
partition_beam_axis 0 / 29 0 / 345
partition_beam_box_along_axis 0 / 8 0 / 9

Changes

  • src/research/partition_schema_mvp.rs: the 2015 to 2023 branch calls attach_beam_rotations and attach_beam_axes.
  • src/research/partition_schema_mvp/framing.rs: the rotation's native read names NATIVE_RELEASES (its default stops at 2023; RE-280 measured the framing on 2015 to 2022), and the line is read through scan_first_bounded_lines behind the new gate. Both readers skip a beam a column cuts (RE-122): its record box fields are the cut box's, so attach_beam_axes would test a line against them and attach it where they coincide (5 of rst_basic's 31 cut beams on each of 2016 to 2023 in the first head); skipping restores main's bytes on those beams and cuts rst_advanced's rotation decode from 397 beams to 64.
  • src/research/partition_beam_axes.rs: BEAM_AXIS_2015_TO_2023_REVIT_VERSIONS (2015 to 2023, renamed from BEAM_AXIS_32BIT_REVIT_VERSIONS: it is not the 32-bit set, 2008 to 2023) and beam_axis_read_on. BEAM_AXIS_SUPPORTED_REVIT_VERSIONS is left alone because it also gates scan_bounded_lines, which isn't measured on these releases (feat(ifc): Revit 2025 beams and tread landings, held to the 2024 save (#1440) (RE-345) #1452 has split the sketch curves and shafts off). line_copies and all_line_copies, which only probes call, gate on beam_axis_read_on too.
  • probes/examples/probe_re362_beam_lines_pre2023.rs: probe_re328_beam_rejections on 2015 to 2027, counts only, as native readers: lines the scrub keeps for an unlicensed model.
  • reports/element-framing/RE-362-2015-2023-beam-axes.md, an addendum to docs/format-reconnaissance.md, README.md, docs/status.md, docs/evidence.md, docs/supported-profile.md, docs/support-matrix.json, changelog.d/added/1190-2015-2023-beam-axes.md.

Testing

Unit tests are banned in this repository: do not add them. Show the change working end to end on real files instead.

  • tools/check-local.sh passes (fmt, clippy, rustdoc, build, real-file / CLI / contract checks)
    • tools/check-local.sh --corpus passes on d6f69d9 (integration 300 of 300, 6 filtered out), and cargo +1.87 check --profile ci --all-targets is clean. The commit was then rebased onto 6299876, three CI-only commits that touch none of these files; cargo fmt --check and tools/ci/api-doc-ids.py were rerun there.
  • Verified end to end on real Revit files: the command, the files (and their licence), and the measured result against Revit's own export are in the PR body, with the script or probe that reproduces it
    • Not against Revit's own export: no Revit export scores any beam this rule draws on 2015 to 2023, among the models Measure fetches without a held-out pair. Measure run 42134881703 (head 0c39def, base main, -f bimcollab=true -f racadv=true -f samples=true -f sample_years="2015 2024", counts only) scored the two sources of such an export. BIMcollab's Revit 2015 example holds 91 beams in Revit's export, and rvt-rs draws all 91 as record boxes, on main and on this head: 0 drawn by line, Span and Slope missing on all 91 as on main. The three.js IFC2X3 export of rac_advanced, which racadv-2015 to racadv-2020 are scored against, holds no IfcBeam (3,308 IfcMember, 1,349 IfcPlate, 176 IfcColumn, 75 IfcBuildingElementProxy), and none of the 38 beams has an element with its Tag in it under any class. So Span and Slope are written on 25 racadv beams that export does not carry, which is what the rule does there, with nothing to score it. Measured against the same Autodesk samples saved by a later release, which can't catch an error that save shares. The files are the pinned samples in research/autodesk-sample-projects.tsv (fetched, never stored).
    • Beams the change draws, against the later save, to 3 mm on the world box and 0.1% on the volume (tools/re/save_pair_bodies.py):
      • rac_advanced 2015 to 2023, against 2024: 33 of 33 on each.
      • rst_basic 2019 to 2023, against 2024: 312 of 323 on each.
      • rst_basic 2017 and 2018, against 2024: 298 of 323.
      • rst_basic 2016, against 2024: 285 of 323.
      • rst_advanced 2015, against 2019: 54 of 54.
      • rst_basic 2015 is another model (RE-181), so it has no later save. Its 29 beams are only checked within the file.
    • The 11 have the same box and another volume: the 2024 save draws those steel beams as their type's I section (RE-103), not tried on these releases.
    • The other 14 on 2017 and 2018, and 27 on 2016, already differ in the saves' raw record boxes with no line read (main's exports, against the 2023 save: 3.9 mm, and 4.1 to 24.4 mm). Why Revit's upgrade moved them is not decoded.
    • Within each of 20 files, every beam's new body is within 3 mm of its own save's record box. The reader requires that, so it places the differences in the saves and doesn't show the box is right.
    • Span, Slope, Roll and Length written here equal the later save's to 1e-3, except Span and Length on 13 beams of rst_basic 2016, the ones whose box differs by about 25 mm. Every beam's storey and GlobalId are as on main.
    • Why BIMcollab's 91 beams read no line (Measure run 42139236978, probe_re362_beam_lines_pre2023, counts only): the release gate passes, every beam has a record box and element data in a partition, and none of the 91 has a bounded line record in it (no_line 91, nothing refused for its box). The line record this change reads is what Autodesk's 2015 samples hold for 33 of 34 rac_advanced, 29 of 39 rst_basic and 54 of 64 rst_advanced beams that RE-122 does not cut; BIMcollab's structural model, from outside those samples, holds none, so the reach is Autodesk's samples and no model from elsewhere has been read. No fix: the probe shows the line absent from the window, not where it is (RE-362 §5).
    • Byte identity, by hash in Measure run 42134881703 (Autodesk's samples 2015 to 2024, racadv, BIMcollab): 26 exports move and nothing else: 20 sample saves (rac_advanced 2015 to 2023, rst_basic 2015 to 2023, rst_advanced 2015 and 2019) and the 6 racadv models. No 2024 export moves, nor rac_basic, rme_advanced, rme_basic, Snowdon or BIMcollab; 2025 to 2027 were not in that run. The local count of 11 of 206 files, "2017 to 2023", did not hold: 2015 and 2016 draw beams too.
  • If this touches the IFC exporter: the witness verdicts replay (see CONTRIBUTING.md) or the changed observations are refreshed in this PR
    • Core Interior (2024) exports byte for byte as before, so its observations are unchanged.
  • If this is a performance change: reran tools/bench.sh and attached the before / after
    • N/A. The beams' native read adds under 0.15 s to a 1.2 s export (rst_basic 2023 and 2019, single runs).
tools/fetch-autodesk-samples.sh samples 2015 2024
for f in samples/*.rvt; do rvt-ifc "$f" -o "${f%.rvt}.ifc"; done
S=partition_beam_axis,partition_beam_box_along_axis
python3 tools/re/save_pair_bodies.py samples/2023-rstbasicsampleproject.ifc samples/2024-rstbasicsampleproject.ifc --sources $S
python3 tools/re/save_pair_bodies.py samples/2016-rst_basic_sample_project.ifc samples/2024-rstbasicsampleproject.ifc --sources $S

Audit-honesty checklist

  • README / docs reflect the current state after this PR — no claims of features that are not actually shipped in this PR
  • A user-visible change has its entry as a fragment under changelog.d/<section>/ (see changelog.d/README.md), not in CHANGELOG.md
  • If a limitation was resolved, the "Known limitations" / "What works today" section in the relevant docs is updated
    • docs/status.md, docs/evidence.md, docs/supported-profile.md. The 2008 to 2014 rows now say "as on 2015, without beams along their axes".
  • If a new limitation was introduced, it is documented in the PR body and in-code
    • None new. Still not done, RE-362 §5 and §6: on these samples 31 rst_basic and 4 rac_advanced beams keep RE-122's column cut as on main, without Span, Roll or Length (and 333 of rst_advanced's 397, 120 of rst_basic 2015's 159); I sections aren't tried; tools/re/bodies_across_saves.py and Measure's gate don't hold these saves, and no Revit export checks a beam this rule draws.
  • Commit messages describe WHAT changed and WHY, not "fix things" or "updates"
  • No emojis in code, docs, or commit messages
  • No private paths, personal email addresses, or internal jargon in committed files
  • If this is a reverse-engineering finding: a reproducible probe under probes/examples/ and a dated addendum to docs/format-reconnaissance.md are included
    • The addendum is included. No new byte layout is decoded (the records are RE-49's and RE-276's), so there is no probe; tools/re/save_pair_bodies.py reproduces the measurement.

Legal and contribution hygiene

  • I agree this work is licensable under Apache-2.0 (see CONTRIBUTING.md)
  • This PR contains no Autodesk proprietary source, decompiled internals, or NDA'd SDK content (see CLEANROOM.md)
  • Any new test fixtures use synthetic values (testuser, 111111, FY-20XX, etc.) and contain no real-world PII
    • No fixtures.

Breaking changes

None. A new public constant and function; existing names and types are unchanged.

Screenshots or output samples

rst_basic 2023 against its 2024 save, this branch:

tools/re/save_pair_bodies.py --sources partition_beam_axis,partition_beam_box_along_axis
same 312, differ 11, not in the reference 0
  IfcBeam: same 312, differ 11, not in the reference 0

Related issues

Refs #1190, #1426, #1452, #1514 (BIMcollab's 91 beams hold no line the reader finds)

Notes

Independent of #1454. #1452 has merged: beam_axis_read_on stays as it is, reading the beam list (2024 to 2027 since #1452) and the 2015 to 2023 list beside it.

Clean-room declaration

The changes in this PR are based on public byte observations of Autodesk's sample projects and of BIMcollab's example project (the bounded line record, RE-49 and RE-114; the cross-section rotation, RE-276; the native record framing, RE-280) and on Revit's own IFC exports as counts. No Autodesk SDK source, ODA SDK source, leaked internal documentation, NDA material or decompiled internal Revit implementation code beyond public symbol exports was used, and no code was copied or translated from revit-ifc. The maintainer's additions to this branch (the skip of a beam a column cuts, the probe and the corrections) are from the same sources. puzzbobb's confirmation of their part is asked.

…nes (DrunkOnJava#1190) (RE-348)

Revit 2015 to 2023 take a branch of recover_partition_schema_mvp that ends
before the beam readers, so a beam there was its record box, with no Span,
Slope, Roll or Length, although walls on those releases read the same line
record (RE-114, RE-180, RE-181). The branch now reads each beam's rotation
and line. The rotation's native read names NATIVE_RELEASES, whose framing
RE-280 measured on 2015 to 2022. BEAM_AXIS_SUPPORTED_REVIT_VERSIONS also
gates a sketch line's arcs, circles and shaft lines, which are not measured
there, so the beams get a list of their own. A beam a named column trims
keeps its cut box (RE-122). 2008 to 2014 stay as they were.

Against the same Autodesk samples' later saves, rac_advanced's 33 beams are
the 2024 save's on all of 2015 to 2023, rst_advanced 2015's 54 are the 2019
save's, and rst_basic's are the 2024 save's on 312 of 323 (2019 to 2023), 298
(2017, 2018) and 285 (2016). The 11 are the 2024 save's I sections, not tried
on these releases; the rest already differ in the saves' raw record boxes.
No Revit export of these beams is scored.
@puzzbobb
puzzbobb requested a review from DrunkOnJava as a code owner November 5, 2026 23:59
Takes DrunkOnJava#1452's separate release lists for beams, sketch curves and shafts: BEAM_AXIS_32BIT_REVIT_VERSIONS stays as the beams' list for 2015 to 2023 beside BEAM_AXIS_SUPPORTED_REVIT_VERSIONS (2024 to 2027), whose comment now says what it still gates. The report is RE-362, RE-348 being main's wall end join order, and the profile rows keep main's local-only labels with this change's beam text.
…which exports move (DrunkOnJava#1190)

Measure run 42134881703: BIMcollab's 91 beams are all record boxes on main and on this head, and the three.js export of rac_advanced holds no IfcBeam, so Span and Slope are written on 25 racadv beams that export does not carry. 26 exports move, 20 sample saves and 6 racadv models, and no 2024 export, not the nine saves of 2017 to 2023 the local count gave.
…nly, and the line-copy probes read the releases the beams do (DrunkOnJava#1190) (RE-362)

probe_re362_beam_lines_pre2023 is probe_re328_beam_rejections on the releases RE-362 reads, printing its counts as native readers: lines, which the scrub keeps for a model with no licence. line_copies and all_line_copies, only probes use them, now gate on beam_axis_read_on instead of the 2024 to 2027 list.
…eader's reach (DrunkOnJava#1190)

Measure run 42139236978, probe_re362_beam_lines_pre2023, counts only: 91 beams, each with a record box and element data found, 91 of 91 with no bounded line record in the window; nothing is refused for its box. The line the reader takes is what Autodesk's 2015 samples hold for 33 of 34, 29 of 39 and 54 of 64 of their beams that RE-122 does not cut, and none of BIMcollab's. No fix: the probe does not say where the line is.
…ion is read for it, and the docs say the reach is Autodesk's samples (DrunkOnJava#1190) (RE-362)

apply_beam_column_trim rewrites the record box fields a line is tested against, so attach_beam_axes attached the line where the cut box coincided with it: 5 of rst_basic's 31 cut beams on each of 2016 to 2023, 40 in all, with the same world box and volume and a turned description. Both readers now skip a beam carrying m_beam_body_source, which restores main's bytes on them and stops the rotation decode on cut beams (rst_advanced 397 to 64). BEAM_AXIS_32BIT_REVIT_VERSIONS is BEAM_AXIS_2015_TO_2023_REVIT_VERSIONS, its comment, RE-362, the README, the support matrix, the status, evidence and profile rows and the addendum say what is measured (Autodesk's samples, later saves of the same samples, none of BIMcollab's 91 beams reading a line), and the probe also counts the other lines a beam's data holds for a line the reader accepts.
@DrunkOnJava DrunkOnJava changed the title feat(ifc): Revit 2015 to 2023 beams are drawn along their location line feat(ifc): Revit 2015 to 2023 beams are drawn along their location line (#1190) (RE-362) Nov 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants