@theerapat-s28/ts-structural-eng-tools 2.0.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/README.md +112 -12
  3. package/dist/core/constants/frame.constant.d.ts +5 -0
  4. package/dist/core/constants/frame.constant.js +6 -1
  5. package/dist/core/constants/frame.constant.js.map +1 -1
  6. package/dist/core/errors/frame-analysis.error.d.ts +3 -0
  7. package/dist/core/errors/frame-analysis.error.js +14 -2
  8. package/dist/core/errors/frame-analysis.error.js.map +1 -1
  9. package/dist/core/index.d.ts +1 -1
  10. package/dist/core/index.js +2 -1
  11. package/dist/core/index.js.map +1 -1
  12. package/dist/esm/core/constants/frame.constant.js +5 -0
  13. package/dist/esm/core/constants/frame.constant.js.map +1 -1
  14. package/dist/esm/core/errors/frame-analysis.error.js +14 -2
  15. package/dist/esm/core/errors/frame-analysis.error.js.map +1 -1
  16. package/dist/esm/core/index.js +1 -1
  17. package/dist/esm/core/index.js.map +1 -1
  18. package/dist/esm/fea/frame/area/area-geometry.js +132 -0
  19. package/dist/esm/fea/frame/area/area-geometry.js.map +1 -0
  20. package/dist/esm/fea/frame/area/distribute-area-loads.js +267 -0
  21. package/dist/esm/fea/frame/area/distribute-area-loads.js.map +1 -0
  22. package/dist/esm/fea/frame/area/edge-members.js +62 -0
  23. package/dist/esm/fea/frame/area/edge-members.js.map +1 -0
  24. package/dist/esm/fea/frame/elements/fixed-end-forces.js +16 -3
  25. package/dist/esm/fea/frame/elements/fixed-end-forces.js.map +1 -1
  26. package/dist/esm/fea/frame/index.js +1 -0
  27. package/dist/esm/fea/frame/index.js.map +1 -1
  28. package/dist/esm/fea/frame/post/member-diagram.js +71 -28
  29. package/dist/esm/fea/frame/post/member-diagram.js.map +1 -1
  30. package/dist/esm/fea/frame/solver/analyze-frame.js +19 -11
  31. package/dist/esm/fea/frame/solver/analyze-frame.js.map +1 -1
  32. package/dist/esm/fea/frame/solver/load-case-solver.js +21 -7
  33. package/dist/esm/fea/frame/solver/load-case-solver.js.map +1 -1
  34. package/dist/esm/fea/frame/validation/validate-model.js +103 -6
  35. package/dist/esm/fea/frame/validation/validate-model.js.map +1 -1
  36. package/dist/esm/index.js +2 -2
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/fea/frame/area/area-geometry.d.ts +56 -0
  39. package/dist/fea/frame/area/area-geometry.js +142 -0
  40. package/dist/fea/frame/area/area-geometry.js.map +1 -0
  41. package/dist/fea/frame/area/distribute-area-loads.d.ts +30 -0
  42. package/dist/fea/frame/area/distribute-area-loads.js +272 -0
  43. package/dist/fea/frame/area/distribute-area-loads.js.map +1 -0
  44. package/dist/fea/frame/area/edge-members.d.ts +25 -0
  45. package/dist/fea/frame/area/edge-members.js +67 -0
  46. package/dist/fea/frame/area/edge-members.js.map +1 -0
  47. package/dist/fea/frame/elements/fixed-end-forces.d.ts +17 -3
  48. package/dist/fea/frame/elements/fixed-end-forces.js +18 -4
  49. package/dist/fea/frame/elements/fixed-end-forces.js.map +1 -1
  50. package/dist/fea/frame/index.d.ts +2 -1
  51. package/dist/fea/frame/index.js +3 -1
  52. package/dist/fea/frame/index.js.map +1 -1
  53. package/dist/fea/frame/post/member-diagram.js +71 -28
  54. package/dist/fea/frame/post/member-diagram.js.map +1 -1
  55. package/dist/fea/frame/solver/analyze-frame.d.ts +7 -4
  56. package/dist/fea/frame/solver/analyze-frame.js +19 -11
  57. package/dist/fea/frame/solver/analyze-frame.js.map +1 -1
  58. package/dist/fea/frame/solver/load-case-solver.js +21 -7
  59. package/dist/fea/frame/solver/load-case-solver.js.map +1 -1
  60. package/dist/fea/frame/types/model.type.d.ts +59 -1
  61. package/dist/fea/frame/validation/validate-model.d.ts +1 -1
  62. package/dist/fea/frame/validation/validate-model.js +103 -6
  63. package/dist/fea/frame/validation/validate-model.js.map +1 -1
  64. package/dist/index.d.ts +3 -3
  65. package/dist/index.js +4 -2
  66. package/dist/index.js.map +1 -1
  67. package/package.json +10 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,131 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@theerapat-s28/ts-structural-eng-tools` are recorded here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the package uses [semantic versioning](https://semver.org/): a **major** release can break existing code, a **minor** release adds features, a **patch** release fixes bugs.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [2.1.1] — 2026-10-23
10
+
11
+ ### Fixed
12
+
13
+ - The package root now re-exports `distributeAreaLoads`, the `TrapezoidalMemberLoad`, `TorqueMemberLoad`, `NullArea`, `AreaLoad`, `AreaDistribution` and `AreaLoadDirection` types, and the `AREA_GEOMETRY_TOLERANCE` constant. Since 2.1.0 they were reachable only through the `/fea` and `/core` subpaths.
14
+ - The quick-start example on the docs landing page used `fc` instead of `fc_`.
15
+
16
+ ### Documentation
17
+
18
+ - README: added a quick-start example, the `core` and `utils` exports, error codes, release steps and the license.
19
+
20
+ ## [2.1.0] — 2026-10-23
21
+
22
+ ### Added
23
+
24
+ - **Trapezoidal member load** (`type: "trapezoidal"`): a load varying linearly from `w1` at `start` to `w2` at `end`. Member diagrams stay exact for it.
25
+ - **Torque member load** (`type: "torque"`): a uniform torque per unit length about the member's local 1 axis.
26
+ - **Null areas** (`model.areas`) and **area loads** (`model.areaLoads`, kN/m²): 3- or 4-node areas that add no stiffness and pass their loads to the edge members, distributed `"twoWay"`, `"oneWay"` or `"cantilever"`.
27
+ - `distributeAreaLoads(model)` returns the member loads generated from the areas, for checking or previewing (from `/fea`).
28
+ - `FrameAnalysisError` codes 315 (area geometry), 316 (an area edge without members) and 317 (supports that do not fit the distribution).
29
+
30
+ ### Changed
31
+
32
+ - Package description and README now present the library as a headless analysis engine for front-end applications.
33
+
34
+ ## [2.0.1] — 2026-10-11
35
+
36
+ Maintenance release with no changes to the library code.
37
+
38
+ ## [2.0.0] — 2026-10-11
39
+
40
+ ### Breaking changes
41
+
42
+ - `FrameModel` now requires `loadCases`. Loads move to the top-level lists `nodalLoads` and `memberLoads`, and every load names its `loadCase`.
43
+ - `analyzeFrame` returns `{ cases, combinations, envelope, … }` keyed by id, instead of a single result.
44
+
45
+ ### Added
46
+
47
+ - **3D frame analysis** (`/fea` subpath) by the direct stiffness method: uniform and point member loads in local or global directions, end releases, fixed and spring supports, ETABS-style local axes.
48
+ - **Load cases and combinations**: a self-weight multiplier per load case, combinations by superposition (including nested combinations), and an `envelope` reporting the governing combination.
49
+ - Member diagrams of forces (`N`, `V2`, `V3`, `T`, `M2`, `M3`) and deflections (`u1`–`u3` local, `ux`–`uz` global) along every member.
50
+ - `createFrameAnalysis` to compute member diagrams on demand, and `options.diagrams: "extremes"` for smaller results.
51
+ - `validateFrameModel` reports every problem in a model, with `details` locating it. `FrameAnalysisError` codes 301–314.
52
+ - `memberDemandEnvelope` turns analysis results into `MuPositive`, `MuNegative`, `Vu` and `Nu` for the RC capacity functions.
53
+ - `rectBeamToSectionProperties` (in `/rc`) converts an RC section into frame section properties, with the ACI 318-19 6.6.3.1.1 inertia modifiers and a unit weight for self-weight.
54
+ - `beam3dLocalStiffness`, `beam3dLocalStiffnessRightHanded` and `memberAxes`.
55
+ - Matrix and skyline solver helpers in `/utils`. Large models solve much faster (an 847-node model in about 1.5 s instead of 16.6 s).
56
+ - ES-module build in `dist/esm/` alongside CommonJS, with `"sideEffects": false` so bundlers can drop unused code.
57
+
58
+ ## [1.5.0] — 2026-08-17
59
+
60
+ ### Added
61
+
62
+ - **Side plate shear strengthening**, with two models because ACI 318-19 has no provisions for steel side plates:
63
+ - `sidePlateShearCapacityByWebYielding` (plate as a supplementary web, AISC 360 G2.1)
64
+ - `sidePlateShearCapacityByTensionTie` (plate as a tie across the crack, ACI 440.2R-17 §11.4 with steel in place of FRP)
65
+ - `compareSidePlateShearCapacity` runs both and reports the lower as governing.
66
+ - `hasSidePlate` type guard.
67
+ - `RCDesignError` codes 205 (inconsistent side plate geometry) and 206 (no shear headroom left for strengthening).
68
+
69
+ ## [1.4.0] — 2026-08-14
70
+
71
+ ### Changed
72
+
73
+ - Doubly reinforced sections are solved by strain compatibility. Compression steel below the neutral axis no longer throws: it is treated as tension steel and reported with a warning citing ACI 318-19 22.2.1.2.
74
+ - Steel plate jacketing measures every depth from the extreme compression fibre. A top plate now turns a singly reinforced section into a doubly reinforced one.
75
+ - `calculationDetails` reports `c`, `a`, `beta1`, `d`, `As` and `ro` for every section. `ro_` uses the same `b·d` basis as `ro`.
76
+ - `rectBeamBarLayout` takes `topBars` as optional.
77
+
78
+ ### Deprecated
79
+
80
+ - `RCDesignError` code 101 (`COMP_STEEL_DISTANCE_OVER_AC`) is no longer thrown. It will be removed in the next major release.
81
+
82
+ ## [1.3.0] — 2026-08-14
83
+
84
+ ### Added
85
+
86
+ - API reference site, published on GitHub Pages: <https://theerapat-s28.github.io/ts-structural-eng/>.
87
+ - `homepage`, `repository` and `bugs` links in the package metadata.
88
+
89
+ ## [1.2.0] — 2026-08-13
90
+
91
+ ### Added
92
+
93
+ - **Plate-to-concrete interface bolts** for steel plate jacketing:
94
+ - `plateInterfaceShearFlow` (shear flow `q = V·Q/I`, cracked or uncracked section)
95
+ - `boltShearCapacity` (ACI 318-19 17.7.1.2b)
96
+ - `plateInterfaceBoltRequirement` (required bolt pitch and count).
97
+ - Top and bottom jacketing plates are each optional, with the `hasTopPlate` and `hasBottomPlate` type guards.
98
+ - `RCDesignError` codes 201–204 for strengthening.
99
+
100
+ ### Fixed
101
+
102
+ - The RC shear functions are now exported from the package root, not only from `/rc`.
103
+
104
+ ## [1.1.0] — 2026-07-19
105
+
106
+ ### Added
107
+
108
+ - RC shear design per ACI 318-19: `concreteShearCapacity`, `stirrupShearCapacity` and `checkStirrupRequirement`, with `RCDesignError` code 105.
109
+ - `rectBeamBarLayout`: arranges bar groups into layers that meet the ACI 318-19 spacing rules and returns `d` and `d_`.
110
+
111
+ ## [1.0.1] — 2026-07-19
112
+
113
+ ### Fixed
114
+
115
+ - npm packaging: scoped package name `@theerapat-s28/ts-structural-eng-tools`, a build output that matches the `exports` map, and path aliases rewritten in the published JavaScript.
116
+
117
+ ## 1.0.0
118
+
119
+ First version, under the unscoped name `ts-structural-eng-tools`: `rectBeamMomentCapacity` (singly and doubly reinforced rectangular beams per ACI 318-19), steel plate jacketing, and concrete property helpers.
120
+
121
+ [Unreleased]: https://github.com/theerapat-s28/ts-structural-eng/compare/v2.1.1...HEAD
122
+ [2.1.1]: https://github.com/theerapat-s28/ts-structural-eng/compare/v2.1.0...v2.1.1
123
+ [2.1.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v2.0.1...v2.1.0
124
+ [2.0.1]: https://github.com/theerapat-s28/ts-structural-eng/compare/v2.0.0...v2.0.1
125
+ [2.0.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.5.0...v2.0.0
126
+ [1.5.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.4.0...v1.5.0
127
+ [1.4.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.3.0...v1.4.0
128
+ [1.3.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.2.0...v1.3.0
129
+ [1.2.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.1.0...v1.2.0
130
+ [1.1.0]: https://github.com/theerapat-s28/ts-structural-eng/compare/v1.0.1...v1.1.0
131
+ [1.0.1]: https://github.com/theerapat-s28/ts-structural-eng/releases/tag/v1.0.1
package/README.md CHANGED
@@ -2,7 +2,25 @@
2
2
 
3
3
  **📖 [API Reference — theerapat-s28.github.io/ts-structural-eng](https://theerapat-s28.github.io/ts-structural-eng/)**
4
4
 
5
- A TypeScript library of structural-engineering helper functions and beam design utilities. Designed to be copied and reused across TypeScript frameworks.
5
+ A headless structural analysis and design engine for TypeScript: 3D frame analysis by the direct stiffness method, reinforced-concrete beam design per ACI 318-19, and strengthening methods. It is built to be installed by front-end applications as their calculation core.
6
+
7
+ ## Scope: an engine, not an application
8
+
9
+ The library does the structural engineering and nothing else. A front-end application installs it, builds a model from its own UI, calls the engine, and draws the results.
10
+
11
+ | The engine (this package) | The front-end application |
12
+ | --------------------------------------------------------------------------- | ------------------------------------------------------------- |
13
+ | Model validation with located errors (`details` name the node, member, field…) | Input forms, drawing tools, highlighting the reported problems |
14
+ | Analysis: load cases, combinations, envelopes, member diagrams | Rendering the model, deformed shapes and diagrams |
15
+ | Design checks with code-clause warnings and `RCDesignError` / `FrameAnalysisError` | Display of results, member colours, view and display options |
16
+ | Typed inputs and results in SI units | Unit display, project files, undo history, other UI state |
17
+
18
+ What this means in practice:
19
+
20
+ - **No UI, no rendering, no presentation data.** Inputs and results carry structural quantities only; no colours, labels or view state.
21
+ - **Plain JSON in, plain JSON out.** Models and results are serialisable, so the engine runs in a Web Worker, in the browser or in Node.
22
+ - **No runtime dependencies** and no DOM or Node-only APIs.
23
+ - **ESM and CommonJS builds** with `.d.ts` types, tree-shakeable (`"sideEffects": false`), split into subpath exports (`/fea`, `/rc`, `/strengthening`, `/core`, `/utils`).
6
24
 
7
25
  ## Documentation
8
26
 
@@ -19,7 +37,7 @@ The pages are served from [`html-docs/`](https://github.com/theerapat-s28/ts-str
19
37
 
20
38
  - Package: `@theerapat-s28/ts-structural-eng-tools`
21
39
  - Entry: `src/index.ts`
22
- - Build output: `dist/` (JS + `.d.ts` files)
40
+ - Build output: `dist/` (CommonJS + `.d.ts` files) and `dist/esm/` (ES modules)
23
41
 
24
42
  ## Prerequisites
25
43
 
@@ -41,6 +59,58 @@ Or install this repository's dependencies to work on the library itself:
41
59
  pnpm install
42
60
  ```
43
61
 
62
+ ## Quick start
63
+
64
+ Analyse a simply supported RC beam under self-weight and live load, envelope the design demands, and check them against the section's flexural capacity:
65
+
66
+ ```ts
67
+ import { analyzeFrame, memberDemandEnvelope } from "@theerapat-s28/ts-structural-eng-tools/fea";
68
+ import type { FrameModel } from "@theerapat-s28/ts-structural-eng-tools/fea";
69
+ import {
70
+ rectBeamMomentCapacity,
71
+ rectBeamToSectionProperties,
72
+ } from "@theerapat-s28/ts-structural-eng-tools/rc";
73
+
74
+ // 300×600 beam, f'c 28 MPa, fy 420 MPa, As 1800 mm²
75
+ const beam = { Es: 200_000, fc_: 28, fy: 420, As: 1800, b: 300, h: 600, d: 540 };
76
+ const { sectionProperties } = rectBeamToSectionProperties(beam, { member: "beam" });
77
+
78
+ const model: FrameModel = {
79
+ nodes: [
80
+ { id: "A", x: 0, y: 0, z: 0 },
81
+ { id: "B", x: 6000, y: 0, z: 0 }, // mm
82
+ ],
83
+ members: [{ id: "AB", startNodeId: "A", endNodeId: "B", section: sectionProperties }],
84
+ restraints: [
85
+ { nodeId: "A", ux: true, uy: true, uz: true, rx: true },
86
+ { nodeId: "B", uy: true, uz: true },
87
+ ],
88
+ loadCases: [
89
+ { id: "D", type: "dead", selfWeight: 1 },
90
+ { id: "L", type: "live" },
91
+ ],
92
+ memberLoads: [{ loadCase: "L", type: "udl", memberId: "AB", direction: "Z", w: -15 }], // kN/m
93
+ combinations: [
94
+ {
95
+ id: "1.2D+1.6L",
96
+ terms: [
97
+ { case: "D", factor: 1.2 },
98
+ { case: "L", factor: 1.6 },
99
+ ],
100
+ },
101
+ ],
102
+ };
103
+
104
+ const result = analyzeFrame(model);
105
+ const demand = memberDemandEnvelope(result, "AB");
106
+ // demand.MuPositive → 131.328 (kN·m), demand.Vu → 87.552 (kN), governed by "1.2D+1.6L"
107
+
108
+ const { phiMn, warnings } = rectBeamMomentCapacity(beam);
109
+ // phiMn → 331.39 (kN·m), warnings → []
110
+ ```
111
+
112
+ Each module is also its own subpath export (`/fea`, `/rc`, `/strengthening`, `/core`, `/utils`), so a front end can import only what it uses. The package root re-exports the most-used functions and types from every module.
113
+
44
114
  ## Scripts
45
115
 
46
116
  | Command | Description |
@@ -62,6 +132,7 @@ src/
62
132
  ├── rc/ # Reinforced concrete design
63
133
  │ ├── index.ts # Module exports
64
134
  │ ├── general.ts # Concrete properties (beta1, Ec, unit conversion)
135
+ │ ├── rc-bar-layout.ts # Bar groups → layers satisfying ACI spacing, giving d and d'
65
136
  │ ├── rc-beam-design.ts # Beam moment capacity (singly/doubly reinforced) and shear capacity (Vc, Vs, stirrup requirement)
66
137
  │ └── rc-section-properties.ts # Section properties (E, G, A, I22, I33, J) for frame analysis
67
138
  ├── strengthening/ # Strengthening methods
@@ -73,17 +144,18 @@ src/
73
144
  │ ├── index.ts
74
145
  │ └── frame/ # 3D frame analysis (direct stiffness method)
75
146
  │ ├── index.ts
147
+ │ ├── area/ # Null areas: geometry, edge-member chains, area-load distribution
76
148
  │ ├── elements/ # Reference beam stiffness matrix, fixed-end forces, end-release condensation
77
149
  │ ├── transformation/ # ETABS-style local axes and the 12×12 transformation
78
150
  │ ├── solver/ # System build + skyline factorisation, per-case solve, combinations, analyzeFrame
79
151
  │ ├── validation/ # validateFrameModel: every input problem, with its location
80
152
  │ ├── post/ # Result presentation, member force diagrams, envelopes, design demands
81
- │ └── types/ # Model (incl. load cases, combinations) and result types
153
+ │ └── types/ # Model (incl. null areas, load cases, combinations) and result types
82
154
  ├── core/ # Shared infrastructure
83
155
  │ ├── index.ts
84
- │ ├── constants/ # RC design constants (ACI 318)
85
- │ ├── errors/ # Custom error classes
86
- │ └── types/ # Shared type definitions
156
+ │ ├── constants/ # RC design constants (ACI 318) and frame-analysis tolerances
157
+ │ ├── errors/ # RCDesignError and FrameAnalysisError with their coded entries
158
+ │ └── types/ # Shared types: RC sections, plate jacketing, section properties, warnings, units
87
159
  └── utils/ # Helper utilities
88
160
  ├── index.ts
89
161
  ├── math.ts # Quadratic solver, rounding
@@ -103,6 +175,10 @@ html-docs/ # HTML API reference, deployed to GitHub Pages
103
175
  ├── rc/index.html
104
176
  ├── strengthening/index.html
105
177
  └── fea/index.html
178
+ html-implementation-plans/ # Planning notes for upcoming features (not published)
179
+ └── fea-future-features.html
180
+ .agents/skills/update-version/ # AI agent skill: bump the version and roll the changelog
181
+ .claude/skills/npm-publish/ # AI agent skill: release checklist for publishing to npm
106
182
  ```
107
183
 
108
184
  ## TypeScript path aliases
@@ -155,31 +231,55 @@ ACI 440.2R-17 11.4.2 (spacing, which defers to the ACI 318 limits) and 11.4.3 (`
155
231
 
156
232
  Linear-elastic 3D frame analysis by the direct stiffness method, imported from `@theerapat-s28/ts-structural-eng-tools/fea`. Global axes X, Y, Z (Z up) and ETABS-style local axes 1, 2, 3; inputs in mm, MPa, kN and kN·m, results in kN, kN·m, mm and rad.
157
233
 
158
- - **`analyzeFrame(model, options?)`** — Analyses every load case in `model.loadCases` (dead, superimposed dead, live, wind…, each with an optional `selfWeight` multiplier) and forms every combination in `model.combinations` by superposition. The loads are flat top-level lists, `model.nodalLoads` and `model.memberLoads` (uniform and point loads in local or global directions), each load tagged with its `loadCase`, so large models stay readable. A combination is a list of factored terms `{ case, factor }` or `{ combination, factor }`; factors are entered by the user, and nested combinations are expanded. Supports end releases and fixed or spring supports. The stiffness matrix is factorised once for all cases. Returns `cases` and `combinations` keyed by id — each with displacements, reactions, member end forces, member diagrams along each member (forces `N`, `V2`, `V3`, `T`, `M2`, `M3` and deflections `u1`–`u3` local / `ux`–`uz` global, ready for plotting) and an equilibrium check — and an `envelope` of max/min over the combinations with the governing combination. Combination diagrams are rebuilt exactly, not summed from case extremes. The stiffness is stored in skyline (banded) form with nodes in reverse Cuthill–McKee order, so a building of ~850 nodes runs in about 1.5 s. Model and result are plain JSON, so it runs in a Web Worker. Invalid models, load cases or combinations and mechanisms throw `FrameAnalysisError` (codes 301–314) with `details` locating the problem.
234
+ - **`analyzeFrame(model, options?)`** — Analyses every load case in `model.loadCases` (dead, superimposed dead, live, wind…, each with an optional `selfWeight` multiplier) and forms every combination in `model.combinations` by superposition. The loads are flat top-level lists, `model.nodalLoads` and `model.memberLoads` (uniform, trapezoidal and point loads in local or global directions, and torques about the member axis), each load tagged with its `loadCase`, so large models stay readable. Area loads (`model.areaLoads`, kN/m²) on null areas (`model.areas`) are first distributed to the members along each area's edges — see `distributeAreaLoads`. A combination is a list of factored terms `{ case, factor }` or `{ combination, factor }`; factors are entered by the user, and nested combinations are expanded. Supports end releases and fixed or spring supports. The stiffness matrix is factorised once for all cases. Returns `cases` and `combinations` keyed by id — each with displacements, reactions, member end forces, member diagrams along each member (forces `N`, `V2`, `V3`, `T`, `M2`, `M3` and deflections `u1`–`u3` local / `ux`–`uz` global, ready for plotting) and an equilibrium check — and an `envelope` of max/min over the combinations with the governing combination. Combination diagrams are rebuilt exactly, not summed from case extremes. The stiffness is stored in skyline (banded) form with nodes in reverse Cuthill–McKee order, so a building of ~850 nodes runs in about 1.5 s. Model and result are plain JSON, so it runs in a Web Worker. Invalid models, load cases or combinations and mechanisms throw `FrameAnalysisError` (codes 301–317) with `details` locating the problem.
159
235
  - **`createFrameAnalysis(model, options?)`** — Same analysis, keeping the solution: returns `{ result, memberDiagram(resultId, memberId) }` so full member diagrams can be computed on demand. Combine with `options.diagrams: "extremes"`, which keeps diagram extremes (and the envelope) but drops the station arrays, for results about 4× smaller on large models.
160
- - **`validateFrameModel(model)`** — Checks a model without analysing it and returns every problem, each with `details` (`nodeId`, `memberId`, `loadCaseId`, `combinationId`, `field`, `dof`) for highlighting in a UI. `analyzeFrame` runs it first and throws the first problem as a `FrameAnalysisError` whose `issues` lists all of them; non-finite numbers, negative springs and unknown option values are rejected (314).
236
+ - **`validateFrameModel(model)`** — Checks a model without analysing it and returns every problem, each with `details` (`nodeId`, `memberId`, `areaId`, `edge`, `loadCaseId`, `combinationId`, `field`, `dof`) for highlighting in a UI. `analyzeFrame` runs it first and throws the first problem as a `FrameAnalysisError` whose `issues` lists all of them; non-finite numbers, negative springs and unknown option values are rejected (314).
237
+ - **`distributeAreaLoads(model)`** — Returns `{ memberLoads, warnings }`: the member loads that the model's null areas send to their edge members, exactly what `analyzeFrame` adds, for checking or previewing. A null area (`{ id, nodeIds, distribution, supportEdges? }`) has 3 or 4 nodes forming a planar convex polygon and adds no stiffness. `"twoWay"` sends each point to its nearest edge (the corner-bisector split, any convex shape); `"oneWay"` spans strips between the listed `supportEdges`, parallel to the unsupported edges, half to each end; `"cantilever"` (rectangles) puts `q·c` and a torque `q·c²/2` on its one support edge. Area loads (`{ loadCase, areaId, direction: "3" | "X" | "Y" | "Z", q }`) are per unit true area, `"3"` being the area's normal. Edges split by intermediate nodes are cut at them. Area problems throw 315 (geometry), 316 (an edge without members) or 317 (supports that do not fit the distribution).
161
238
  - **`memberDemandEnvelope(result, memberId, options?)`** — Reduces a member's diagrams to `MuPositive`, `MuNegative`, `Vu` (optionally at distance `d` from the supports) and `Nu`, enveloped over all combinations (or the `combinations` / `cases` you select), with the `governing` combination of each, for the RC capacity functions.
162
239
  - **`rectBeamToSectionProperties(section, options?)`** (from `rc`) — Converts a rectangular RC section into `SectionProperties` (`E`, `G`, `A`, `I22`, `I33`, `J`, `unitWeight`) with the ACI 318-19 6.6.3.1.1 inertia modifiers (0.35 beams, 0.70 columns) and a unit weight for self-weight (default 24 kN/m³, common practice rather than an ACI value).
163
240
  - **`beam3dLocalStiffness(E, G, A, I22, I33, J, L)`** — The 12×12 local stiffness matrix exactly as in the reference "Complete Beam Stiffness Matrix". Its bending rotations R2 and R3 follow the opposite sign to the right-hand rule; **`beam3dLocalStiffnessRightHanded`** returns the right-handed form that `analyzeFrame` uses.
164
241
  - **`memberAxes(start, end, angle?)`** — The ETABS-style local axes of a member as a direction-cosine matrix.
165
242
 
166
- ### General Utilities
243
+ ### Concrete properties (from `rc`)
167
244
 
168
245
  - **`concreteBeta(fc_)`** — ACI 318 β₁ factor
169
246
  - **`concreteElasticModulus(fc_)`** — Ec = 4700√f'c (MPa)
170
247
  - **`psiToMpa(psi)`** — Unit conversion
171
248
 
249
+ ### Errors and warnings (from `core`)
250
+
251
+ A design that is valid but breaks a code provision returns normally with an entry in `warnings`, citing the clause (e.g. `"ACI318-19, 9.6.1.2"`). A calculation whose assumptions break down throws instead, never returning a silently wrong result:
252
+
253
+ - **`RCDesignError`** — `code` and `message` from `Errors`: 1XX for RC beam design (e.g. 102, tensile steel not yielding; 105, `Vs` above the 22.5.1.2 limit), 2XX for strengthening and plate connections (201–206).
254
+ - **`FrameAnalysisError`** — `code` from `FrameErrors` (301–317), `details` locating the problem, and `issues` listing every problem `validateFrameModel` found.
255
+
256
+ `core` also exports the shared input types, the type guards `isSinglyReinforced`, `hasTopPlate`, `hasBottomPlate` and `hasSidePlate`, and the engineering constants (φ factors, ultimate concrete strain, inertia modifiers, frame-analysis tolerances).
257
+
258
+ ### Utilities (from `utils`)
259
+
260
+ Low-level helpers the engine is built on, exported for reuse: `solveQuadratic`, `roundToDecimalPlaces`, `mergeWarnings`, dense matrix helpers (`zeros`, `identity`, `transpose`, `matMul`, `matVec`), Cholesky and general linear solvers (`choleskyFactor`, `choleskySolveFactored`, `choleskySolve`, `solveLinearSystem`), and the skyline solver (`createSkyline`, `skylineAdd`, `skylineGet`, `skylineSize`, `skylineFactor`, `skylineSolve`, `reverseCuthillMcKee`).
261
+
172
262
  ## Build
173
263
 
174
264
  ```bash
175
265
  pnpm run build
176
- node dist/index.js
177
266
  ```
178
267
 
179
- The build emits a CommonJS build in `dist/` (for `require`, with the `.d.ts` types) and an ES-module build in `dist/esm/` (for `import` and bundlers such as Vite); `package.json` `exports` routes each subpath to the right one, and `"sideEffects": false` lets bundlers drop unused code.
268
+ The build emits a CommonJS build in `dist/` (for `require`, with the `.d.ts` types) and an ES-module build in `dist/esm/` (for `import` and bundlers such as Vite); `package.json` `exports` routes each subpath to the right one, and `"sideEffects": false` lets bundlers drop unused code. `pnpm run dev` runs [`examples/basic-usage.ts`](examples/basic-usage.ts) against the sources without building.
180
269
 
181
270
  ## Tests
182
271
 
183
272
  ```bash
184
- pnpm run test
273
+ pnpm run test # all tests
274
+ pnpm vitest run tests/rc/rc-beam-design.test.ts # one file
185
275
  ```
276
+
277
+ Tests live in `tests/`, mirroring `src/`, and check results against hand-calculated or textbook values.
278
+
279
+ ## Releasing
280
+
281
+ Releases follow semantic versioning and are published to npm with tags `vX.Y.Z`. What changed in each version is in [CHANGELOG.md](CHANGELOG.md). Preparing a version (changelog, version number, checks) is described in [`.agents/skills/update-version/SKILL.md`](.agents/skills/update-version/SKILL.md), and publishing (release commit and tag, dry run, publish, push tags) in [`.claude/skills/npm-publish/SKILL.md`](.claude/skills/npm-publish/SKILL.md).
282
+
283
+ ## License
284
+
285
+ [ISC](LICENSE)
@@ -12,3 +12,8 @@ export declare const VERTICAL_MEMBER_TOLERANCE = 0.000001;
12
12
  export declare const SINGULARITY_TOLERANCE = 1e-9;
13
13
  /** Relative global-equilibrium residual above which a warning is added. */
14
14
  export declare const EQUILIBRIUM_TOLERANCE = 0.000001;
15
+ /**
16
+ * Relative tolerance for null-area geometry (planarity, corners in line, parallel or square
17
+ * edges, nodes lying on an edge): distances are compared with this times the longest edge.
18
+ */
19
+ export declare const AREA_GEOMETRY_TOLERANCE = 0.000001;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.CONCRETE_UNIT_WEIGHT = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_POISSON_RATIO = void 0;
3
+ exports.AREA_GEOMETRY_TOLERANCE = exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.CONCRETE_UNIT_WEIGHT = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_POISSON_RATIO = void 0;
4
4
  /** Poisson's ratio of concrete, for G = E / (2(1 + ν)). */
5
5
  exports.CONCRETE_POISSON_RATIO = 0.2;
6
6
  /** ACI 318-19 Table 6.6.3.1.1(a): effective I of beams for elastic analysis at factored load. */
@@ -15,4 +15,9 @@ exports.VERTICAL_MEMBER_TOLERANCE = 1e-6;
15
15
  exports.SINGULARITY_TOLERANCE = 1e-9;
16
16
  /** Relative global-equilibrium residual above which a warning is added. */
17
17
  exports.EQUILIBRIUM_TOLERANCE = 1e-6;
18
+ /**
19
+ * Relative tolerance for null-area geometry (planarity, corners in line, parallel or square
20
+ * edges, nodes lying on an edge): distances are compared with this times the longest edge.
21
+ */
22
+ exports.AREA_GEOMETRY_TOLERANCE = 1e-6;
18
23
  //# sourceMappingURL=frame.constant.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACpF,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACxF,QAAA,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AACnF,QAAA,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC9D,QAAA,qBAAqB,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACpF,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACxF,QAAA,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AACnF,QAAA,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC9D,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;;GAGG;AACU,QAAA,uBAAuB,GAAG,IAAI,CAAC"}
@@ -4,6 +4,9 @@
4
4
  export interface FrameErrorDetails {
5
5
  nodeId?: string | number;
6
6
  memberId?: string | number;
7
+ areaId?: string | number;
8
+ /** For an area: the edge index, edge i running from `nodeIds[i]` to `nodeIds[i + 1]`. */
9
+ edge?: number;
7
10
  loadCaseId?: string;
8
11
  combinationId?: string;
9
12
  /** The offending input field, e.g. "x", "fz", "w", "direction", "uz". */
@@ -20,11 +20,11 @@ exports.FrameErrors = {
20
20
  },
21
21
  UNKNOWN_NODE_REFERENCE: {
22
22
  code: 302,
23
- message: "A member, restraint or load refers to a node or member id that is not in the model.",
23
+ message: "A member, restraint, area or load refers to a node, member or area id that is not in the model.",
24
24
  },
25
25
  DUPLICATE_ID: {
26
26
  code: 303,
27
- message: "Node ids, member ids and restrained node ids must each be unique, and load case and combination ids must be unique across both lists.",
27
+ message: "Node ids, member ids, area ids and restrained node ids must each be unique, and load case and combination ids must be unique across both lists.",
28
28
  },
29
29
  STRUCTURE_UNSTABLE: {
30
30
  code: 304,
@@ -70,5 +70,17 @@ exports.FrameErrors = {
70
70
  code: 314,
71
71
  message: "An input value is invalid: a number that is not finite (NaN, Infinity or not a number), a negative spring stiffness, or a value outside its allowed options.",
72
72
  },
73
+ INVALID_AREA_GEOMETRY: {
74
+ code: 315,
75
+ message: "An area must have 3 or 4 distinct nodes forming a planar, convex polygon with no three corners in line; a cantilever area must be a rectangle.",
76
+ },
77
+ AREA_EDGE_UNSUPPORTED: {
78
+ code: 316,
79
+ message: "An area edge that carries load is not fully covered by members: every segment between the nodes along the edge needs a member.",
80
+ },
81
+ INVALID_AREA_DISTRIBUTION: {
82
+ code: 317,
83
+ message: "An area's supportEdges do not fit its distribution: two-way takes none; one-way needs at least one edge left unsupported, with every unsupported edge parallel to the others (the span direction); cantilever needs exactly one, and its loads may not act along that edge.",
84
+ },
73
85
  };
74
86
  //# sourceMappingURL=frame-analysis.error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-analysis.error.js","sourceRoot":"","sources":["../../../src/core/errors/frame-analysis.error.ts"],"names":[],"mappings":";;;AAcA,MAAa,kBAAmB,SAAQ,KAAK;IAO3C,YACE,MAA8B,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EACnE,UAA6B,EAAE,EAC/B,MAA0B;QAE1B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF;AAnBD,gDAmBC;AAcY,QAAA,WAAW,GAA2C;IACjE,8BAA8B;IAC9B,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,sEAAsE;KAChF;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,qFAAqF;KAC/F;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,GAAG;QACT,OAAO,EACL,uIAAuI;KAC1I;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,mHAAmH;KACtH;IACD,0BAA0B,EAAE;QAC1B,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,iDAAiD;KAC3D;IACD,eAAe,EAAE;QACf,IAAI,EAAE,GAAG;QACT,OAAO,EACL,yFAAyF;KAC5F;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,4EAA4E;KACtF;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,mDAAmD;KAC7D;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,4GAA4G;KAC/G;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,gEAAgE;KAC1E;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,sHAAsH;KACzH;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,8JAA8J;KACjK;CACF,CAAC"}
1
+ {"version":3,"file":"frame-analysis.error.js","sourceRoot":"","sources":["../../../src/core/errors/frame-analysis.error.ts"],"names":[],"mappings":";;;AAiBA,MAAa,kBAAmB,SAAQ,KAAK;IAO3C,YACE,MAA8B,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EACnE,UAA6B,EAAE,EAC/B,MAA0B;QAE1B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF;AAnBD,gDAmBC;AAcY,QAAA,WAAW,GAA2C;IACjE,8BAA8B;IAC9B,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,sEAAsE;KAChF;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,iGAAiG;KACpG;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,GAAG;QACT,OAAO,EACL,iJAAiJ;KACpJ;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,mHAAmH;KACtH;IACD,0BAA0B,EAAE;QAC1B,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,iDAAiD;KAC3D;IACD,eAAe,EAAE;QACf,IAAI,EAAE,GAAG;QACT,OAAO,EACL,yFAAyF;KAC5F;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,4EAA4E;KACtF;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,mDAAmD;KAC7D;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,4GAA4G;KAC/G;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,gEAAgE;KAC1E;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,sHAAsH;KACzH;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,8JAA8J;KACjK;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,gJAAgJ;KACnJ;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,gIAAgI;KACnI;IACD,yBAAyB,EAAE;QACzB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,6QAA6Q;KAChR;CACF,CAAC"}
@@ -6,7 +6,7 @@ export type { SectionProperties } from "./types/section-properties.type";
6
6
  export type { Warnings, calculationResult } from "./types/output-message.type";
7
7
  export type { unit } from "./types/unit.type";
8
8
  export { FLEXURAL_STRENGTH_REDUCTION_FACTOR, CONCRETE_ULTIMATE_STRAIN, SHEAR_STRENGTH_REDUCTION_FACTOR, ANCHOR_SHEAR_STRENGTH_REDUCTION_FACTOR, MAX_PLATE_BOLT_SPACING, PLATE_SHEAR_YIELD_COEFFICIENT, SIDE_PLATE_EFFECTIVE_STRAIN_LIMIT, SIDE_PLATE_REDUCTION_FACTOR_PSI, } from "./constants/rc.constant";
9
- export { CONCRETE_POISSON_RATIO, CONCRETE_UNIT_WEIGHT, BEAM_INERTIA_MODIFIER, COLUMN_INERTIA_MODIFIER, VERTICAL_MEMBER_TOLERANCE, SINGULARITY_TOLERANCE, EQUILIBRIUM_TOLERANCE, } from "./constants/frame.constant";
9
+ export { CONCRETE_POISSON_RATIO, CONCRETE_UNIT_WEIGHT, BEAM_INERTIA_MODIFIER, COLUMN_INERTIA_MODIFIER, VERTICAL_MEMBER_TOLERANCE, SINGULARITY_TOLERANCE, EQUILIBRIUM_TOLERANCE, AREA_GEOMETRY_TOLERANCE, } from "./constants/frame.constant";
10
10
  export { RCDesignError, Errors } from "./errors/rc-design.error";
11
11
  export { FrameAnalysisError, FrameErrors } from "./errors/frame-analysis.error";
12
12
  export type { FrameErrorDetails, FrameModelIssue } from "./errors/frame-analysis.error";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FrameErrors = exports.FrameAnalysisError = exports.Errors = exports.RCDesignError = exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_UNIT_WEIGHT = exports.CONCRETE_POISSON_RATIO = exports.SIDE_PLATE_REDUCTION_FACTOR_PSI = exports.SIDE_PLATE_EFFECTIVE_STRAIN_LIMIT = exports.PLATE_SHEAR_YIELD_COEFFICIENT = exports.MAX_PLATE_BOLT_SPACING = exports.ANCHOR_SHEAR_STRENGTH_REDUCTION_FACTOR = exports.SHEAR_STRENGTH_REDUCTION_FACTOR = exports.CONCRETE_ULTIMATE_STRAIN = exports.FLEXURAL_STRENGTH_REDUCTION_FACTOR = exports.hasSidePlate = exports.hasBottomPlate = exports.hasTopPlate = exports.isSinglyReinforced = void 0;
3
+ exports.FrameErrors = exports.FrameAnalysisError = exports.Errors = exports.RCDesignError = exports.AREA_GEOMETRY_TOLERANCE = exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_UNIT_WEIGHT = exports.CONCRETE_POISSON_RATIO = exports.SIDE_PLATE_REDUCTION_FACTOR_PSI = exports.SIDE_PLATE_EFFECTIVE_STRAIN_LIMIT = exports.PLATE_SHEAR_YIELD_COEFFICIENT = exports.MAX_PLATE_BOLT_SPACING = exports.ANCHOR_SHEAR_STRENGTH_REDUCTION_FACTOR = exports.SHEAR_STRENGTH_REDUCTION_FACTOR = exports.CONCRETE_ULTIMATE_STRAIN = exports.FLEXURAL_STRENGTH_REDUCTION_FACTOR = exports.hasSidePlate = exports.hasBottomPlate = exports.hasTopPlate = exports.isSinglyReinforced = void 0;
4
4
  var rc_beam_type_1 = require("./types/rc-beam.type");
5
5
  Object.defineProperty(exports, "isSinglyReinforced", { enumerable: true, get: function () { return rc_beam_type_1.isSinglyReinforced; } });
6
6
  var plate_jacketing_type_1 = require("./types/plate-jacketing.type");
@@ -25,6 +25,7 @@ Object.defineProperty(exports, "COLUMN_INERTIA_MODIFIER", { enumerable: true, ge
25
25
  Object.defineProperty(exports, "VERTICAL_MEMBER_TOLERANCE", { enumerable: true, get: function () { return frame_constant_1.VERTICAL_MEMBER_TOLERANCE; } });
26
26
  Object.defineProperty(exports, "SINGULARITY_TOLERANCE", { enumerable: true, get: function () { return frame_constant_1.SINGULARITY_TOLERANCE; } });
27
27
  Object.defineProperty(exports, "EQUILIBRIUM_TOLERANCE", { enumerable: true, get: function () { return frame_constant_1.EQUILIBRIUM_TOLERANCE; } });
28
+ Object.defineProperty(exports, "AREA_GEOMETRY_TOLERANCE", { enumerable: true, get: function () { return frame_constant_1.AREA_GEOMETRY_TOLERANCE; } });
28
29
  // Errors
29
30
  var rc_design_error_1 = require("./errors/rc-design.error");
30
31
  Object.defineProperty(exports, "RCDesignError", { enumerable: true, get: function () { return rc_design_error_1.RCDesignError; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;AAWA,qDAA0D;AAAjD,kHAAA,kBAAkB,OAAA;AAW3B,qEAAyF;AAAhF,mHAAA,WAAW,OAAA;AAAE,sHAAA,cAAc,OAAA;AAAE,oHAAA,YAAY,OAAA;AAKlD,YAAY;AACZ,uDASiC;AAR/B,iIAAA,kCAAkC,OAAA;AAClC,uHAAA,wBAAwB,OAAA;AACxB,8HAAA,+BAA+B,OAAA;AAC/B,qIAAA,sCAAsC,OAAA;AACtC,qHAAA,sBAAsB,OAAA;AACtB,4HAAA,6BAA6B,OAAA;AAC7B,gIAAA,iCAAiC,OAAA;AACjC,8HAAA,+BAA+B,OAAA;AAGjC,6DAQoC;AAPlC,wHAAA,sBAAsB,OAAA;AACtB,sHAAA,oBAAoB,OAAA;AACpB,uHAAA,qBAAqB,OAAA;AACrB,yHAAA,uBAAuB,OAAA;AACvB,2HAAA,yBAAyB,OAAA;AACzB,uHAAA,qBAAqB,OAAA;AACrB,uHAAA,qBAAqB,OAAA;AAGvB,SAAS;AACT,4DAAiE;AAAxD,gHAAA,aAAa,OAAA;AAAE,yGAAA,MAAM,OAAA;AAC9B,sEAAgF;AAAvE,0HAAA,kBAAkB,OAAA;AAAE,mHAAA,WAAW,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;AAWA,qDAA0D;AAAjD,kHAAA,kBAAkB,OAAA;AAW3B,qEAAyF;AAAhF,mHAAA,WAAW,OAAA;AAAE,sHAAA,cAAc,OAAA;AAAE,oHAAA,YAAY,OAAA;AAKlD,YAAY;AACZ,uDASiC;AAR/B,iIAAA,kCAAkC,OAAA;AAClC,uHAAA,wBAAwB,OAAA;AACxB,8HAAA,+BAA+B,OAAA;AAC/B,qIAAA,sCAAsC,OAAA;AACtC,qHAAA,sBAAsB,OAAA;AACtB,4HAAA,6BAA6B,OAAA;AAC7B,gIAAA,iCAAiC,OAAA;AACjC,8HAAA,+BAA+B,OAAA;AAGjC,6DASoC;AARlC,wHAAA,sBAAsB,OAAA;AACtB,sHAAA,oBAAoB,OAAA;AACpB,uHAAA,qBAAqB,OAAA;AACrB,yHAAA,uBAAuB,OAAA;AACvB,2HAAA,yBAAyB,OAAA;AACzB,uHAAA,qBAAqB,OAAA;AACrB,uHAAA,qBAAqB,OAAA;AACrB,yHAAA,uBAAuB,OAAA;AAGzB,SAAS;AACT,4DAAiE;AAAxD,gHAAA,aAAa,OAAA;AAAE,yGAAA,MAAM,OAAA;AAC9B,sEAAgF;AAAvE,0HAAA,kBAAkB,OAAA;AAAE,mHAAA,WAAW,OAAA"}
@@ -12,4 +12,9 @@ export const VERTICAL_MEMBER_TOLERANCE = 1e-6;
12
12
  export const SINGULARITY_TOLERANCE = 1e-9;
13
13
  /** Relative global-equilibrium residual above which a warning is added. */
14
14
  export const EQUILIBRIUM_TOLERANCE = 1e-6;
15
+ /**
16
+ * Relative tolerance for null-area geometry (planarity, corners in line, parallel or square
17
+ * edges, nodes lying on an edge): distances are compared with this times the longest edge.
18
+ */
19
+ export const AREA_GEOMETRY_TOLERANCE = 1e-6;
15
20
  //# sourceMappingURL=frame.constant.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACjG,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACnG,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACrG,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AAChG,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AACvG,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACjG,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACnG,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACrG,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AAChG,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AACvG,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC"}
@@ -16,11 +16,11 @@ export const FrameErrors = {
16
16
  },
17
17
  UNKNOWN_NODE_REFERENCE: {
18
18
  code: 302,
19
- message: "A member, restraint or load refers to a node or member id that is not in the model.",
19
+ message: "A member, restraint, area or load refers to a node, member or area id that is not in the model.",
20
20
  },
21
21
  DUPLICATE_ID: {
22
22
  code: 303,
23
- message: "Node ids, member ids and restrained node ids must each be unique, and load case and combination ids must be unique across both lists.",
23
+ message: "Node ids, member ids, area ids and restrained node ids must each be unique, and load case and combination ids must be unique across both lists.",
24
24
  },
25
25
  STRUCTURE_UNSTABLE: {
26
26
  code: 304,
@@ -66,5 +66,17 @@ export const FrameErrors = {
66
66
  code: 314,
67
67
  message: "An input value is invalid: a number that is not finite (NaN, Infinity or not a number), a negative spring stiffness, or a value outside its allowed options.",
68
68
  },
69
+ INVALID_AREA_GEOMETRY: {
70
+ code: 315,
71
+ message: "An area must have 3 or 4 distinct nodes forming a planar, convex polygon with no three corners in line; a cantilever area must be a rectangle.",
72
+ },
73
+ AREA_EDGE_UNSUPPORTED: {
74
+ code: 316,
75
+ message: "An area edge that carries load is not fully covered by members: every segment between the nodes along the edge needs a member.",
76
+ },
77
+ INVALID_AREA_DISTRIBUTION: {
78
+ code: 317,
79
+ message: "An area's supportEdges do not fit its distribution: two-way takes none; one-way needs at least one edge left unsupported, with every unsupported edge parallel to the others (the span direction); cantilever needs exactly one, and its loads may not act along that edge.",
80
+ },
69
81
  };
70
82
  //# sourceMappingURL=frame-analysis.error.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-analysis.error.js","sourceRoot":"","sources":["../../../../src/core/errors/frame-analysis.error.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAO3C,YACE,MAA8B,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EACnE,UAA6B,EAAE,EAC/B,MAA0B;QAE1B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF;AAcD,MAAM,CAAC,MAAM,WAAW,GAA2C;IACjE,8BAA8B;IAC9B,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,sEAAsE;KAChF;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,qFAAqF;KAC/F;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,GAAG;QACT,OAAO,EACL,uIAAuI;KAC1I;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,mHAAmH;KACtH;IACD,0BAA0B,EAAE;QAC1B,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,iDAAiD;KAC3D;IACD,eAAe,EAAE;QACf,IAAI,EAAE,GAAG;QACT,OAAO,EACL,yFAAyF;KAC5F;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,4EAA4E;KACtF;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,mDAAmD;KAC7D;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,4GAA4G;KAC/G;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,gEAAgE;KAC1E;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,sHAAsH;KACzH;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,8JAA8J;KACjK;CACF,CAAC"}
1
+ {"version":3,"file":"frame-analysis.error.js","sourceRoot":"","sources":["../../../../src/core/errors/frame-analysis.error.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAO3C,YACE,MAA8B,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EACnE,UAA6B,EAAE,EAC/B,MAA0B;QAE1B,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF;AAcD,MAAM,CAAC,MAAM,WAAW,GAA2C;IACjE,8BAA8B;IAC9B,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,sEAAsE;KAChF;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,iGAAiG;KACpG;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,GAAG;QACT,OAAO,EACL,iJAAiJ;KACpJ;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,mHAAmH;KACtH;IACD,0BAA0B,EAAE;QAC1B,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,iDAAiD;KAC3D;IACD,eAAe,EAAE;QACf,IAAI,EAAE,GAAG;QACT,OAAO,EACL,yFAAyF;KAC5F;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,4EAA4E;KACtF;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,2HAA2H;KAC9H;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,mDAAmD;KAC7D;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,4GAA4G;KAC/G;IACD,aAAa,EAAE;QACb,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,gEAAgE;KAC1E;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,sHAAsH;KACzH;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,8JAA8J;KACjK;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,gJAAgJ;KACnJ;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,gIAAgI;KACnI;IACD,yBAAyB,EAAE;QACzB,IAAI,EAAE,GAAG;QACT,OAAO,EACL,6QAA6Q;KAChR;CACF,CAAC"}
@@ -2,7 +2,7 @@ export { isSinglyReinforced } from "./types/rc-beam.type.js";
2
2
  export { hasTopPlate, hasBottomPlate, hasSidePlate } from "./types/plate-jacketing.type.js";
3
3
  // Constants
4
4
  export { FLEXURAL_STRENGTH_REDUCTION_FACTOR, CONCRETE_ULTIMATE_STRAIN, SHEAR_STRENGTH_REDUCTION_FACTOR, ANCHOR_SHEAR_STRENGTH_REDUCTION_FACTOR, MAX_PLATE_BOLT_SPACING, PLATE_SHEAR_YIELD_COEFFICIENT, SIDE_PLATE_EFFECTIVE_STRAIN_LIMIT, SIDE_PLATE_REDUCTION_FACTOR_PSI, } from "./constants/rc.constant.js";
5
- export { CONCRETE_POISSON_RATIO, CONCRETE_UNIT_WEIGHT, BEAM_INERTIA_MODIFIER, COLUMN_INERTIA_MODIFIER, VERTICAL_MEMBER_TOLERANCE, SINGULARITY_TOLERANCE, EQUILIBRIUM_TOLERANCE, } from "./constants/frame.constant.js";
5
+ export { CONCRETE_POISSON_RATIO, CONCRETE_UNIT_WEIGHT, BEAM_INERTIA_MODIFIER, COLUMN_INERTIA_MODIFIER, VERTICAL_MEMBER_TOLERANCE, SINGULARITY_TOLERANCE, EQUILIBRIUM_TOLERANCE, AREA_GEOMETRY_TOLERANCE, } from "./constants/frame.constant.js";
6
6
  // Errors
7
7
  export { RCDesignError, Errors } from "./errors/rc-design.error.js";
8
8
  export { FrameAnalysisError, FrameErrors } from "./errors/frame-analysis.error.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAW1D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAKzF,YAAY;AACZ,OAAO,EACL,kCAAkC,EAClC,wBAAwB,EACxB,+BAA+B,EAC/B,sCAAsC,EACtC,sBAAsB,EACtB,6BAA6B,EAC7B,iCAAiC,EACjC,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAW1D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAKzF,YAAY;AACZ,OAAO,EACL,kCAAkC,EAClC,wBAAwB,EACxB,+BAA+B,EAC/B,sCAAsC,EACtC,sBAAsB,EACtB,6BAA6B,EAC7B,iCAAiC,EACjC,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AAEpC,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC"}