8e6ee31596
ci / test (push) Successful in 6m18s
History-free snapshot of the private development repository at cbe45c5 (2026-09-09). Code, docs and public catalogue only; no plant or job knowledge layers, no client or job names (tools/scrub.py clean). The intro deck is left out of this snapshot because its slide images could not be checked for job drawings.
216 lines
10 KiB
Python
216 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Gravity load chasing -- PLACEHOLDER. Nothing is implemented.
|
|
#
|
|
# It does not write to the Revit model and never will -- like Lateral
|
|
# Extract, this is meant to be an extractor: read the model, write a file
|
|
# elsewhere. This one's target is Excel -- it is meant to extract
|
|
# information and write an Excel workbook. The owner's framing, verbatim
|
|
# (2026-08-30):
|
|
#
|
|
# gravity-load-chasing 是设计,但是我一两句话说不清楚。这不是一个现在就要推的
|
|
# 项目,先做个按钮跟占位符出来。这将是一个不小于 panel_lift 的功能性按钮。
|
|
#
|
|
# "I cannot say it in a sentence or two" is a statement about the problem, so
|
|
# this file does not try to say it either. It states what is settled, states
|
|
# that the rest is not, and prints the list of open questions -- above all the
|
|
# ones only he can answer, because those are what the placeholder is FOR. A
|
|
# placeholder that quietly starts making engineering assumptions is worse than
|
|
# an empty one; a placeholder that collects the open questions is worth having.
|
|
#
|
|
# The full document is QNA/gravity-load-chasing.md. This script deliberately
|
|
# carries the substance rather than only a pointer: the person who presses the
|
|
# button is in Revit, not in a text editor, and "see the file" is how a
|
|
# placeholder becomes a dead end.
|
|
#
|
|
# WHAT THIS FILE MUST NOT GROW INTO
|
|
# ---------------------------------
|
|
# No arithmetic. No load model, no tributary rule, no accumulation. No
|
|
# knowledge key, no schema field, no config default, no data structure, no file
|
|
# format. None of that has been chosen by anybody, and structure invented ahead
|
|
# of the method is how a placeholder turns into a set of assumptions nobody
|
|
# agreed to. If something looks obviously needed, it goes in the QNA document
|
|
# as a PROPOSAL and waits.
|
|
#
|
|
# It also reads nothing. Not geometry, not parameters, not the knowledge
|
|
# layers. It opens no Transaction, because there is nothing to write and there
|
|
# never will be from this file. The only thing it touches is the model's title,
|
|
# so the report says which session printed it.
|
|
|
|
# pylint: disable=import-error,invalid-name,broad-except
|
|
# `__title__` mirrors bundle.yaml's `title:` and is otherwise dead --
|
|
# pyRevit reads it only `if not self.meta`. It is kept in step so that
|
|
# trimming a bundle file cannot bring an old name back. One line, no
|
|
# `\n`: this button is a row in a `.pulldown`, and a row has no second
|
|
# line to put one on.
|
|
__title__ = 'Gravity (WIP)'
|
|
|
|
import os
|
|
|
|
from pyrevit import revit, script
|
|
|
|
doc = revit.doc
|
|
output = script.get_output()
|
|
output.close_others()
|
|
|
|
TITLE = 'Gravity Load Chasing'
|
|
NOTES = 'QNA/gravity-load-chasing.md'
|
|
|
|
|
|
def notes_path():
|
|
"""Absolute path to the design-notes document, if it can be found.
|
|
|
|
Four levels up from this file is the extension folder; one more is the
|
|
repo. Purely a convenience for the reader -- a miss costs a line, never
|
|
the report.
|
|
"""
|
|
try:
|
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
repo = os.path.abspath(os.path.join(here, '..', '..', '..', '..'))
|
|
found = os.path.join(repo, 'QNA', 'gravity-load-chasing.md')
|
|
if os.path.isfile(found):
|
|
return found
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
|
|
# --------------------------------------------------------------- the report
|
|
|
|
output.print_md('# {0} — NOT IMPLEMENTED'.format(TITLE))
|
|
output.print_md(
|
|
'**None of this feature is built.** There is no calculation behind this '
|
|
'button, and nothing was read from the model to produce this page. That '
|
|
'is deliberate and it is the whole state of the work: a button, and a '
|
|
'document holding the questions.')
|
|
|
|
try:
|
|
output.print_md('Model **{0}** — opened, not read.'.format(doc.Title))
|
|
except Exception:
|
|
pass
|
|
|
|
output.print_md('---')
|
|
|
|
output.print_md('## What it will be')
|
|
output.print_md(
|
|
'Gravity load chasing, as the owner put it on 2026-08-30: *"it is '
|
|
'design, but I cannot say it in a sentence or two. It is not a project '
|
|
'to push right now — make a button and a placeholder first. It '
|
|
'will be a functional button no smaller than Panel Lift Check."*')
|
|
output.print_md(
|
|
'One thing beyond that quote is already settled: like Lateral Extract, '
|
|
'this tool does not write to the Revit model and never will. Both are '
|
|
'extractors — read the model, write a file elsewhere. This one\'s '
|
|
'target is **Excel**: it is meant to extract information and write an '
|
|
'Excel workbook. Nothing here does that yet.')
|
|
output.print_md(
|
|
'Only four things follow from the quote itself, and nothing here will '
|
|
'pretend to more:')
|
|
output.print_md(
|
|
'1. It is **design**, not checking.\n'
|
|
'2. It **cannot yet be specified**, and that is a fact about the '
|
|
'problem, not about anybody\'s time.\n'
|
|
'3. It is **not being pushed now**.\n'
|
|
'4. When it is built it is a **full feature** — its own '
|
|
'engineering core, its own report, its own tests — at least the '
|
|
'size of Panel Lift Check.')
|
|
|
|
output.print_md('## Two boundaries that are already settled')
|
|
|
|
output.print_md(
|
|
'**It is design, not checking, and the liability is different.** '
|
|
'Everything else on this panel reviews work that already exists — '
|
|
'Ticket QC compares a drawn ticket to the model, Panel Lift Check judges '
|
|
'rigging somebody placed, Reinforcing Suggestion proposes donors for a '
|
|
'human to accept. In each case the original work is still there to look '
|
|
'at if the tool is wrong. Gravity load chasing produces the answer '
|
|
'itself, and it goes out under an engineer\'s seal. That has to shape '
|
|
'the design from the first commit; it cannot be added at the end.')
|
|
|
|
output.print_md(
|
|
'**Its input is not the current model.** It needs old jobs and their '
|
|
'spreadsheets as samples and controls — mass-layout among them. '
|
|
'Nothing else in this extension works that way. Those files also carry '
|
|
'client and job identity, which may never enter the repository, so where '
|
|
'the controls live is a real constraint on the project layout and not a '
|
|
'detail for later.')
|
|
|
|
output.print_md(
|
|
'**Carried forward from the reinforcing work** (see '
|
|
'`QNA/reinforcing-suggestion-brief.md`): the plant standard bands '
|
|
'vertical reinforcing `0.2H / PER DESIGN / 0.2H`, and the middle band is '
|
|
'explicitly the engineer\'s own calculation for that one piece. The '
|
|
'reinforcing matcher is forbidden from proposing it, because presenting '
|
|
'one panel\'s design calculation as another panel\'s answer would look '
|
|
'exactly like an ordinary suggestion. Gravity load chasing stands on the '
|
|
'same ground — its entire output is that class of quantity. So the '
|
|
'rule here is the mirror image: **a result from one job must never '
|
|
'become an input to another by any automatic path**, and nothing this '
|
|
'tool produces may ever be presented with the confidence the checking '
|
|
'tools use.')
|
|
|
|
output.print_md('## What it will need from you before it can be built')
|
|
output.print_md(
|
|
'This is the useful half of a placeholder. None of these have answers '
|
|
'yet, and none will be invented:')
|
|
output.print_md(
|
|
'- **Old jobs, and the spreadsheets that go with them.** Which ones, and '
|
|
'where they can be reached from — they cannot live in the '
|
|
'repository.\n'
|
|
'- **Mass-layout: what it actually is.** A spreadsheet, a tool, a stage '
|
|
'of the job? Who produces it, when, in what format?\n'
|
|
'- **Which of those jobs are the controls**, and what counts as passing '
|
|
'— reproducing your number to within what tolerance, on which '
|
|
'quantities?\n'
|
|
'- **Whether the spreadsheets are machine-readable** — fixed '
|
|
'columns and stable sheet names, or hand-formatted per job. This is a '
|
|
'large fork: a parser, or an import UI.\n'
|
|
'- **What is being chased, over what unit, producing what.** One panel, '
|
|
'one wall line, a whole building; a number per piece, a table, a '
|
|
'drawing.\n'
|
|
'- **Which method governs** — which standard and edition, and '
|
|
'whether the plant has its own that supersedes it.\n'
|
|
'- **Which loads are in scope**, and what arrives as given rather than '
|
|
'computed.\n'
|
|
'- **Design, or a first pass an engineer edits.** Different products, '
|
|
'not different wordings.\n'
|
|
'- **Read-only, or not.** Everything in this extension is read-only '
|
|
'today. Is this the feature that changes that?')
|
|
|
|
output.print_md('## The five that block everything else')
|
|
output.print_md(
|
|
'The rest can be discovered while building. These cannot — each '
|
|
'one changes the shape of the whole thing, and getting one wrong is a '
|
|
'rewrite rather than a fix:')
|
|
output.print_md(
|
|
'1. What is being chased, over what unit, producing what.\n'
|
|
'2. What mass-layout is, and whether the sample spreadsheets can be read '
|
|
'by a program.\n'
|
|
'3. Where the controls live, given that they are client work.\n'
|
|
'4. Design or first pass; read-only or not.\n'
|
|
'5. Which method governs.')
|
|
|
|
output.print_md('## What was deliberately not built')
|
|
output.print_md(
|
|
'So it reads as a decision and not an oversight: no load model, no '
|
|
'tributary logic, no accumulation rule, no arithmetic. No knowledge key, '
|
|
'no schema field, no config default, no data structure, no file format. '
|
|
'No library module on either side of the CPython boundary. Anything that '
|
|
'looked obviously needed was written into the notes as a **proposal** '
|
|
'instead, so that it gets chosen rather than inherited.')
|
|
|
|
output.print_md('---')
|
|
found = notes_path()
|
|
if found:
|
|
output.print_md(
|
|
'The full scope, every open question, and the proposals are in '
|
|
'`{0}`.'.format(found))
|
|
else:
|
|
output.print_md(
|
|
'The full scope, every open question, and the proposals are in '
|
|
'`{0}` in the repository.'.format(NOTES))
|
|
output.print_md(
|
|
'Answers are welcome anywhere — in that file, or in '
|
|
'`QNA/questions.md` the usual way. Until they arrive this button stays '
|
|
'exactly as honest as it is now.')
|