@theerapat-s28/ts-structural-eng-tools 2.0.1 → 2.1.0
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.
- package/README.md +26 -6
- package/dist/core/constants/frame.constant.d.ts +5 -0
- package/dist/core/constants/frame.constant.js +6 -1
- package/dist/core/constants/frame.constant.js.map +1 -1
- package/dist/core/errors/frame-analysis.error.d.ts +3 -0
- package/dist/core/errors/frame-analysis.error.js +14 -2
- package/dist/core/errors/frame-analysis.error.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/esm/core/constants/frame.constant.js +5 -0
- package/dist/esm/core/constants/frame.constant.js.map +1 -1
- package/dist/esm/core/errors/frame-analysis.error.js +14 -2
- package/dist/esm/core/errors/frame-analysis.error.js.map +1 -1
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/core/index.js.map +1 -1
- package/dist/esm/fea/frame/area/area-geometry.js +132 -0
- package/dist/esm/fea/frame/area/area-geometry.js.map +1 -0
- package/dist/esm/fea/frame/area/distribute-area-loads.js +267 -0
- package/dist/esm/fea/frame/area/distribute-area-loads.js.map +1 -0
- package/dist/esm/fea/frame/area/edge-members.js +62 -0
- package/dist/esm/fea/frame/area/edge-members.js.map +1 -0
- package/dist/esm/fea/frame/elements/fixed-end-forces.js +16 -3
- package/dist/esm/fea/frame/elements/fixed-end-forces.js.map +1 -1
- package/dist/esm/fea/frame/index.js +1 -0
- package/dist/esm/fea/frame/index.js.map +1 -1
- package/dist/esm/fea/frame/post/member-diagram.js +71 -28
- package/dist/esm/fea/frame/post/member-diagram.js.map +1 -1
- package/dist/esm/fea/frame/solver/analyze-frame.js +19 -11
- package/dist/esm/fea/frame/solver/analyze-frame.js.map +1 -1
- package/dist/esm/fea/frame/solver/load-case-solver.js +21 -7
- package/dist/esm/fea/frame/solver/load-case-solver.js.map +1 -1
- package/dist/esm/fea/frame/validation/validate-model.js +103 -6
- package/dist/esm/fea/frame/validation/validate-model.js.map +1 -1
- package/dist/fea/frame/area/area-geometry.d.ts +56 -0
- package/dist/fea/frame/area/area-geometry.js +142 -0
- package/dist/fea/frame/area/area-geometry.js.map +1 -0
- package/dist/fea/frame/area/distribute-area-loads.d.ts +30 -0
- package/dist/fea/frame/area/distribute-area-loads.js +272 -0
- package/dist/fea/frame/area/distribute-area-loads.js.map +1 -0
- package/dist/fea/frame/area/edge-members.d.ts +25 -0
- package/dist/fea/frame/area/edge-members.js +67 -0
- package/dist/fea/frame/area/edge-members.js.map +1 -0
- package/dist/fea/frame/elements/fixed-end-forces.d.ts +17 -3
- package/dist/fea/frame/elements/fixed-end-forces.js +18 -4
- package/dist/fea/frame/elements/fixed-end-forces.js.map +1 -1
- package/dist/fea/frame/index.d.ts +2 -1
- package/dist/fea/frame/index.js +3 -1
- package/dist/fea/frame/index.js.map +1 -1
- package/dist/fea/frame/post/member-diagram.js +71 -28
- package/dist/fea/frame/post/member-diagram.js.map +1 -1
- package/dist/fea/frame/solver/analyze-frame.d.ts +7 -4
- package/dist/fea/frame/solver/analyze-frame.js +19 -11
- package/dist/fea/frame/solver/analyze-frame.js.map +1 -1
- package/dist/fea/frame/solver/load-case-solver.js +21 -7
- package/dist/fea/frame/solver/load-case-solver.js.map +1 -1
- package/dist/fea/frame/types/model.type.d.ts +59 -1
- package/dist/fea/frame/validation/validate-model.d.ts +1 -1
- package/dist/fea/frame/validation/validate-model.js +103 -6
- package/dist/fea/frame/validation/validate-model.js.map +1 -1
- package/package.json +9 -3
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { AREA_GEOMETRY_TOLERANCE } from "../../../core/constants/frame.constant.js";
|
|
2
|
+
import { throwIssues, validateFrameModel } from "../validation/validate-model.js";
|
|
3
|
+
import { areaPlane, clipPolygon, edgeVector, resolveAreaSupports, } from "./area-geometry.js";
|
|
4
|
+
import { edgeMemberChain, memberAdjacency } from "./edge-members.js";
|
|
5
|
+
const GLOBAL_AXES = [
|
|
6
|
+
["X", 0],
|
|
7
|
+
["Y", 1],
|
|
8
|
+
["Z", 2],
|
|
9
|
+
];
|
|
10
|
+
const dot2 = (a, b) => a[0] * b[0] + a[1] * b[1];
|
|
11
|
+
/** Linear interpolation of a profile at `s` (0 outside it). */
|
|
12
|
+
const valueAt = (profile, s) => {
|
|
13
|
+
for (let k = 1; k < profile.length; k++) {
|
|
14
|
+
const a = profile[k - 1];
|
|
15
|
+
const b = profile[k];
|
|
16
|
+
if (s >= a.s && s <= b.s)
|
|
17
|
+
return b.s > a.s ? a.w + ((b.w - a.w) * (s - a.s)) / (b.s - a.s) : b.w;
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Width of a convex polygon, given in (s, d) coordinates, across the s axis: the extent in d
|
|
23
|
+
* at each vertex position s. Between vertices the width is linear, so this is exact.
|
|
24
|
+
*/
|
|
25
|
+
const widthProfile = (polygon, tolerance) => {
|
|
26
|
+
const positions = [];
|
|
27
|
+
for (const s of polygon.map((p) => p[0]).sort((a, b) => a - b)) {
|
|
28
|
+
if (positions.length === 0 || s - positions[positions.length - 1] > tolerance)
|
|
29
|
+
positions.push(s);
|
|
30
|
+
}
|
|
31
|
+
return positions.map((s) => {
|
|
32
|
+
let min = Infinity;
|
|
33
|
+
let max = -Infinity;
|
|
34
|
+
polygon.forEach((p, i) => {
|
|
35
|
+
const q = polygon[(i + 1) % polygon.length];
|
|
36
|
+
const lo = Math.min(p[0], q[0]) - tolerance;
|
|
37
|
+
const hi = Math.max(p[0], q[0]) + tolerance;
|
|
38
|
+
if (s < lo || s > hi)
|
|
39
|
+
return;
|
|
40
|
+
const ds = q[0] - p[0];
|
|
41
|
+
const values = Math.abs(ds) <= tolerance ? [p[1], q[1]] : [p[1] + ((s - p[0]) / ds) * (q[1] - p[1])];
|
|
42
|
+
for (const d of values) {
|
|
43
|
+
min = Math.min(min, d);
|
|
44
|
+
max = Math.max(max, d);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return { s, w: max - min };
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
/** Unit inward normal of edge i of a counter-clockwise polygon (the area is on its left). */
|
|
51
|
+
const inwardNormal = (corners, i) => {
|
|
52
|
+
const e = edgeVector(corners, i);
|
|
53
|
+
const L = Math.hypot(...e);
|
|
54
|
+
return [-e[1] / L, e[0] / L];
|
|
55
|
+
};
|
|
56
|
+
/** A profile pinned to the edge ends: clamped to [0, L], with breakpoints at 0 and L. */
|
|
57
|
+
const pinToEdge = (profile, L) => {
|
|
58
|
+
const inside = profile.filter((p) => p.s > 0 && p.s < L);
|
|
59
|
+
return [{ s: 0, w: valueAt(profile, 0) }, ...inside, { s: L, w: valueAt(profile, L) }];
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Two-way: every point of the area goes to the nearest edge line, so edge i takes the area
|
|
63
|
+
* clipped by `dᵢ(p) ≤ dⱼ(p)` for every other edge j (the corner-bisector, or straight-skeleton,
|
|
64
|
+
* split of a convex polygon), carried straight across onto the edge.
|
|
65
|
+
*/
|
|
66
|
+
const twoWayProfile = (plane, i, tolerance) => {
|
|
67
|
+
const { corners } = plane;
|
|
68
|
+
const ni = inwardNormal(corners, i);
|
|
69
|
+
let region = corners;
|
|
70
|
+
corners.forEach((cj, j) => {
|
|
71
|
+
if (j === i)
|
|
72
|
+
return;
|
|
73
|
+
const nj = inwardNormal(corners, j);
|
|
74
|
+
// dᵢ(p) ≤ dⱼ(p) ⇔ (nᵢ − nⱼ)·p ≤ nᵢ·cᵢ − nⱼ·cⱼ
|
|
75
|
+
region = clipPolygon(region, [ni[0] - nj[0], ni[1] - nj[1]], dot2(ni, corners[i]) - dot2(nj, cj));
|
|
76
|
+
});
|
|
77
|
+
const e = edgeVector(corners, i);
|
|
78
|
+
const L = Math.hypot(...e);
|
|
79
|
+
const t = [e[0] / L, e[1] / L];
|
|
80
|
+
const local = region.map((p) => {
|
|
81
|
+
const r = [p[0] - corners[i][0], p[1] - corners[i][1]];
|
|
82
|
+
return [dot2(r, t), dot2(r, ni)];
|
|
83
|
+
});
|
|
84
|
+
return pinToEdge(widthProfile(local, tolerance), L);
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* One-way: strips parallel to `span` run across the area and half of each strip goes to each
|
|
88
|
+
* edge it ends on. A strip of width db meets edge i (at angle θ to the span) over ds = db/sin θ,
|
|
89
|
+
* so the edge takes `chord(b) / 2 · sin θ` per unit length; edges parallel to the span take none.
|
|
90
|
+
*/
|
|
91
|
+
const oneWayProfile = (plane, i, span, tolerance) => {
|
|
92
|
+
const { corners } = plane;
|
|
93
|
+
const across = [-span[1], span[0]];
|
|
94
|
+
const chord = widthProfile(corners.map((p) => [dot2(p, across), dot2(p, span)]), tolerance);
|
|
95
|
+
const e = edgeVector(corners, i);
|
|
96
|
+
const L = Math.hypot(...e);
|
|
97
|
+
const sin = Math.abs(e[0] * span[1] - e[1] * span[0]) / L;
|
|
98
|
+
if (sin <= AREA_GEOMETRY_TOLERANCE)
|
|
99
|
+
return null;
|
|
100
|
+
const b0 = dot2(corners[i], across);
|
|
101
|
+
const b1 = b0 + dot2(e, across);
|
|
102
|
+
const at = (b) => (valueAt(chord, b) / 2) * sin;
|
|
103
|
+
const inside = chord
|
|
104
|
+
.filter((p) => (p.s - b0) * (p.s - b1) < 0)
|
|
105
|
+
.map((p) => ({ s: ((p.s - b0) / (b1 - b0)) * L, w: at(p.s) }));
|
|
106
|
+
const profile = [{ s: 0, w: at(b0) }, ...inside, { s: L, w: at(b1) }];
|
|
107
|
+
return profile.sort((a, b) => a.s - b.s);
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Cuts an edge profile at the members along the edge and maps each piece onto its member, as
|
|
111
|
+
* positions from the member start. Pieces that carry nothing are dropped.
|
|
112
|
+
*/
|
|
113
|
+
const segmentPieces = (profile, segment, memberLength, tolerance) => {
|
|
114
|
+
const { from, to, reversed } = segment;
|
|
115
|
+
const cuts = [
|
|
116
|
+
from,
|
|
117
|
+
...profile.map((p) => p.s).filter((s) => s > from + tolerance && s < to - tolerance),
|
|
118
|
+
to,
|
|
119
|
+
];
|
|
120
|
+
const x = (s) => {
|
|
121
|
+
const along = ((s - from) / (to - from)) * memberLength;
|
|
122
|
+
return Math.min(memberLength, Math.max(0, reversed ? memberLength - along : along));
|
|
123
|
+
};
|
|
124
|
+
const peak = Math.max(...profile.map((p) => Math.abs(p.w)));
|
|
125
|
+
const pieces = [];
|
|
126
|
+
for (let k = 1; k < cuts.length; k++) {
|
|
127
|
+
const wa = valueAt(profile, cuts[k - 1]);
|
|
128
|
+
const wb = valueAt(profile, cuts[k]);
|
|
129
|
+
if (Math.max(Math.abs(wa), Math.abs(wb)) <= AREA_GEOMETRY_TOLERANCE * peak)
|
|
130
|
+
continue;
|
|
131
|
+
const [xa, xb] = [x(cuts[k - 1]), x(cuts[k])];
|
|
132
|
+
pieces.push(xa < xb ? { start: xa, end: xb, w1: wa, w2: wb } : { start: xb, end: xa, w1: wb, w2: wa });
|
|
133
|
+
}
|
|
134
|
+
return pieces;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Turns the area loads of a model into member loads, assuming the model is valid (as
|
|
138
|
+
* `validateFrameModel` checks): each area's edge profiles are built once, then scaled for each
|
|
139
|
+
* of its loads and split into global X, Y and Z trapezoidal loads (plus torques for a cantilever).
|
|
140
|
+
* Everything is linear in `q`, so load-case superposition still holds.
|
|
141
|
+
*/
|
|
142
|
+
export const areaMemberLoads = (model) => {
|
|
143
|
+
const areas = model.areas ?? [];
|
|
144
|
+
const areaLoads = model.areaLoads ?? [];
|
|
145
|
+
const memberLoads = [];
|
|
146
|
+
const warnings = [];
|
|
147
|
+
if (areas.length === 0 || areaLoads.length === 0)
|
|
148
|
+
return { memberLoads, warnings };
|
|
149
|
+
const nodeById = new Map(model.nodes.map((n) => [n.id, n]));
|
|
150
|
+
const position = (id) => {
|
|
151
|
+
const node = nodeById.get(id);
|
|
152
|
+
return [node.x, node.y, node.z];
|
|
153
|
+
};
|
|
154
|
+
const lengthOf = (member) => {
|
|
155
|
+
const [a, b] = [position(member.startNodeId), position(member.endNodeId)];
|
|
156
|
+
return Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
157
|
+
};
|
|
158
|
+
const loadedAreas = new Set(areaLoads.map((l) => l.areaId));
|
|
159
|
+
const adjacency = memberAdjacency(model.members);
|
|
160
|
+
const prepared = new Map();
|
|
161
|
+
for (const area of areas) {
|
|
162
|
+
if (!loadedAreas.has(area.id))
|
|
163
|
+
continue;
|
|
164
|
+
const ids = area.nodeIds;
|
|
165
|
+
const plane = areaPlane(ids.map(position));
|
|
166
|
+
const supports = resolveAreaSupports(plane, area.distribution, area.supportEdges);
|
|
167
|
+
const tolerance = AREA_GEOMETRY_TOLERANCE * plane.size;
|
|
168
|
+
const n = ids.length;
|
|
169
|
+
const edges = [];
|
|
170
|
+
for (const i of supports.loadedEdges) {
|
|
171
|
+
const chain = edgeMemberChain(ids[i], ids[(i + 1) % n], position, adjacency);
|
|
172
|
+
const L = Math.hypot(...edgeVector(plane.corners, i));
|
|
173
|
+
if (area.distribution === "cantilever") {
|
|
174
|
+
const depth = Math.hypot(...edgeVector(plane.corners, (i + 1) % n));
|
|
175
|
+
edges.push({
|
|
176
|
+
chain,
|
|
177
|
+
profile: [
|
|
178
|
+
{ s: 0, w: depth },
|
|
179
|
+
{ s: L, w: depth },
|
|
180
|
+
],
|
|
181
|
+
torque: depth ** 2 / 2,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else if (area.distribution === "twoWay") {
|
|
185
|
+
edges.push({ chain, profile: twoWayProfile(plane, i, tolerance) });
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const profile = oneWayProfile(plane, i, supports.span, tolerance);
|
|
189
|
+
if (profile)
|
|
190
|
+
edges.push({ chain, profile });
|
|
191
|
+
else {
|
|
192
|
+
warnings.push({
|
|
193
|
+
reference: "Null area, one-way distribution",
|
|
194
|
+
message: `Area "${String(area.id)}": support edge ${i} runs parallel to the span and receives no load.`,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
prepared.set(area.id, { plane, edges });
|
|
200
|
+
}
|
|
201
|
+
for (const load of areaLoads) {
|
|
202
|
+
const area = prepared.get(load.areaId);
|
|
203
|
+
if (!area || load.q === 0)
|
|
204
|
+
continue;
|
|
205
|
+
const { plane, edges } = area;
|
|
206
|
+
const e = load.direction === "3"
|
|
207
|
+
? plane.normal
|
|
208
|
+
: GLOBAL_AXES.map(([axis]) => (axis === load.direction ? 1 : 0));
|
|
209
|
+
const components = GLOBAL_AXES.filter(([, k]) => Math.abs(e[k]) > AREA_GEOMETRY_TOLERANCE);
|
|
210
|
+
// Lever arm (inward, in plane) × load: only the normal part of the load twists the edge,
|
|
211
|
+
// about +edge direction; validation rejects a load along a cantilever's support edge.
|
|
212
|
+
const normalPart = e[0] * plane.normal[0] + e[1] * plane.normal[1] + e[2] * plane.normal[2];
|
|
213
|
+
const tolerance = AREA_GEOMETRY_TOLERANCE * plane.size;
|
|
214
|
+
for (const { chain, profile, torque } of edges) {
|
|
215
|
+
for (const segment of chain) {
|
|
216
|
+
const { member } = segment;
|
|
217
|
+
const L = lengthOf(member);
|
|
218
|
+
for (const piece of segmentPieces(profile, segment, L, tolerance)) {
|
|
219
|
+
for (const [axis, k] of components) {
|
|
220
|
+
memberLoads.push({
|
|
221
|
+
loadCase: load.loadCase,
|
|
222
|
+
type: "trapezoidal",
|
|
223
|
+
memberId: member.id,
|
|
224
|
+
direction: axis,
|
|
225
|
+
w1: load.q * e[k] * piece.w1 * 1e-3, // kN/m² · mm → kN/m
|
|
226
|
+
w2: load.q * e[k] * piece.w2 * 1e-3,
|
|
227
|
+
start: piece.start,
|
|
228
|
+
end: piece.end,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (torque !== undefined && Math.abs(normalPart) > AREA_GEOMETRY_TOLERANCE) {
|
|
233
|
+
// member local 1 is ±edge direction
|
|
234
|
+
const sign = segment.reversed ? -1 : 1;
|
|
235
|
+
memberLoads.push({
|
|
236
|
+
loadCase: load.loadCase,
|
|
237
|
+
type: "torque",
|
|
238
|
+
memberId: member.id,
|
|
239
|
+
t: load.q * normalPart * torque * sign * 1e-6, // kN/m² · mm² → kN·m/m
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return { memberLoads, warnings };
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* The member loads that a model's null areas send to the members along their edges — what
|
|
249
|
+
* `analyzeFrame` adds to `memberLoads` — so they can be checked or previewed.
|
|
250
|
+
*
|
|
251
|
+
* Two-way areas send each point to the nearest edge (corner-bisector split); one-way areas
|
|
252
|
+
* split strips parallel to their unsupported edges half to each end; cantilever areas send
|
|
253
|
+
* `q · c` and a torque `q · c² / 2` per unit length to their support edge (c = depth). Edges
|
|
254
|
+
* split by intermediate nodes are cut at those nodes. Loads are per unit true area and come
|
|
255
|
+
* out as trapezoidal loads in global X, Y and Z (and torques), each tagged with its load case.
|
|
256
|
+
*
|
|
257
|
+
* @param model - The frame model, validated first
|
|
258
|
+
* @returns `memberLoads` and `warnings` (a one-way support edge parallel to the span)
|
|
259
|
+
* @throws {FrameAnalysisError} 301–317 for an invalid model, with every problem in `issues`
|
|
260
|
+
*/
|
|
261
|
+
export const distributeAreaLoads = (model) => {
|
|
262
|
+
const issues = validateFrameModel(model);
|
|
263
|
+
if (issues.length > 0)
|
|
264
|
+
throwIssues(issues);
|
|
265
|
+
return areaMemberLoads(model);
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=distribute-area-loads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distribute-area-loads.js","sourceRoot":"","sources":["../../../../../src/fea/frame/area/distribute-area-loads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAI7E,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EACL,SAAS,EACT,WAAW,EACX,UAAU,EACV,mBAAmB,GAIpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAoB,MAAM,gBAAgB,CAAC;AAepF,MAAM,WAAW,GAAgC;IAC/C,CAAC,GAAG,EAAE,CAAC,CAAC;IACR,CAAC,GAAG,EAAE,CAAC,CAAC;IACR,CAAC,GAAG,EAAE,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,CAAO,EAAE,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D,+DAA+D;AAC/D,MAAM,OAAO,GAAG,CAAC,OAAgB,EAAE,CAAS,EAAU,EAAE;IACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACtB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,SAAiB,EAAW,EAAE;IACnE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC/D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,SAAS;YAC3E,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACzB,IAAI,GAAG,GAAG,QAAQ,CAAC;QACnB,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QACpB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;YAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;YAC5C,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;gBAAE,OAAO;YAC7B,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,MAAM,GACV,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;gBACvB,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBACvB,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,6FAA6F;AAC7F,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,CAAS,EAAQ,EAAE;IACxD,MAAM,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,yFAAyF;AACzF,MAAM,SAAS,GAAG,CAAC,OAAgB,EAAE,CAAS,EAAW,EAAE;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACzF,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,aAAa,GAAG,CAAC,KAAgB,EAAE,CAAS,EAAE,SAAiB,EAAW,EAAE;IAChF,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC1B,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACpC,IAAI,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO;QACpB,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpC,gDAAgD;QAChD,MAAM,GAAG,WAAW,CAClB,MAAM,EACN,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAC9B,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CACpC,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAQ,EAAE;QACnC,MAAM,CAAC,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,aAAa,GAAG,CACpB,KAAgB,EAChB,CAAS,EACT,IAAU,EACV,SAAiB,EACD,EAAE;IAClB,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC1B,MAAM,MAAM,GAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,YAAY,CACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAC1D,SAAS,CACV,CAAC;IACF,MAAM,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,GAAG,IAAI,uBAAuB;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACxD,MAAM,MAAM,GAAG,KAAK;SACjB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,aAAa,GAAG,CACpB,OAAgB,EAChB,OAAoB,EACpB,YAAoB,EACpB,SAAiB,EACyC,EAAE;IAC5D,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACvC,MAAM,IAAI,GAAG;QACX,IAAI;QACJ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACpF,EAAE;KACH,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE;QACtB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,YAAY,CAAC;QACxD,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,uBAAuB,GAAG,IAAI;YAAE,SAAS;QACrF,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CACT,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAC1F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,KAAiB,EACkC,EAAE;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;IACxC,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;IAEnF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,CAAC,EAAW,EAAQ,EAAE;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsD,CAAC;IAC/E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,SAAS;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;QACzB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAc,CAAC;QACxD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAE,CAAC;QACnF,MAAM,SAAS,GAAG,uBAAuB,GAAG,KAAK,CAAC,IAAI,CAAC;QACvD,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;QAErB,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAE,CAAC;YAC9E,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YAEtD,IAAI,IAAI,CAAC,YAAY,KAAK,YAAY,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACpE,KAAK,CAAC,IAAI,CAAC;oBACT,KAAK;oBACL,OAAO,EAAE;wBACP,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE;wBAClB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE;qBACnB;oBACD,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC;iBACvB,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;gBAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;YACrE,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,IAAK,EAAE,SAAS,CAAC,CAAC;gBACnE,IAAI,OAAO;oBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;qBACvC,CAAC;oBACJ,QAAQ,CAAC,IAAI,CAAC;wBACZ,SAAS,EAAE,iCAAiC;wBAC5C,OAAO,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,kDAAkD;qBACxG,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAC9B,MAAM,CAAC,GACL,IAAI,CAAC,SAAS,KAAK,GAAG;YACpB,CAAC,CAAC,KAAK,CAAC,MAAM;YACd,CAAC,CAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAU,CAAC;QAC/E,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC;QAC3F,yFAAyF;QACzF,sFAAsF;QACtF,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5F,MAAM,SAAS,GAAG,uBAAuB,GAAG,KAAK,CAAC,IAAI,CAAC;QAEvD,KAAK,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;YAC/C,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;gBAC5B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;gBAC3B,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAC3B,KAAK,MAAM,KAAK,IAAI,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;oBAClE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC;wBACnC,WAAW,CAAC,IAAI,CAAC;4BACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;4BACvB,IAAI,EAAE,aAAa;4BACnB,QAAQ,EAAE,MAAM,CAAC,EAAE;4BACnB,SAAS,EAAE,IAAqB;4BAChC,EAAE,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,oBAAoB;4BACzD,EAAE,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI;4BACnC,KAAK,EAAE,KAAK,CAAC,KAAK;4BAClB,GAAG,EAAE,KAAK,CAAC,GAAG;yBACf,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBACD,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,uBAAuB,EAAE,CAAC;oBAC3E,oCAAoC;oBACpC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACvC,WAAW,CAAC,IAAI,CAAC;wBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,MAAM,CAAC,EAAE;wBACnB,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,EAAE,uBAAuB;qBACvE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,KAAiB,EACkC,EAAE;IACrD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AREA_GEOMETRY_TOLERANCE } from "../../../core/constants/frame.constant.js";
|
|
2
|
+
/** Indexes members by the nodes they connect. */
|
|
3
|
+
export const memberAdjacency = (members) => {
|
|
4
|
+
const adjacency = new Map();
|
|
5
|
+
const link = (node, entry) => {
|
|
6
|
+
const list = adjacency.get(node);
|
|
7
|
+
if (list)
|
|
8
|
+
list.push(entry);
|
|
9
|
+
else
|
|
10
|
+
adjacency.set(node, [entry]);
|
|
11
|
+
};
|
|
12
|
+
for (const member of members) {
|
|
13
|
+
link(member.startNodeId, { member, other: member.endNodeId });
|
|
14
|
+
link(member.endNodeId, { member, other: member.startNodeId });
|
|
15
|
+
}
|
|
16
|
+
return adjacency;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The chain of collinear members covering an area edge from `start` to `end`, found by walking
|
|
20
|
+
* the members at each node towards `end`: each step takes the member whose far node lies on the
|
|
21
|
+
* edge nearest ahead, so intermediate nodes (beams framing in) split the edge into segments.
|
|
22
|
+
*
|
|
23
|
+
* @param position - Node coordinates in mm
|
|
24
|
+
* @returns The segments in order along the edge, or `null` if a gap leaves part of it uncovered
|
|
25
|
+
*/
|
|
26
|
+
export const edgeMemberChain = (start, end, position, adjacency) => {
|
|
27
|
+
const A = position(start);
|
|
28
|
+
const B = position(end);
|
|
29
|
+
const d = [B[0] - A[0], B[1] - A[1], B[2] - A[2]];
|
|
30
|
+
const L = Math.hypot(...d);
|
|
31
|
+
const t = [d[0] / L, d[1] / L, d[2] / L];
|
|
32
|
+
const tolerance = AREA_GEOMETRY_TOLERANCE * L;
|
|
33
|
+
const segments = [];
|
|
34
|
+
let current = start;
|
|
35
|
+
let s = 0;
|
|
36
|
+
while (current !== end) {
|
|
37
|
+
let next;
|
|
38
|
+
for (const { member, other } of adjacency.get(current) ?? []) {
|
|
39
|
+
const P = position(other);
|
|
40
|
+
const r = [P[0] - A[0], P[1] - A[1], P[2] - A[2]];
|
|
41
|
+
const along = r[0] * t[0] + r[1] * t[1] + r[2] * t[2];
|
|
42
|
+
const off = Math.hypot(r[0] - along * t[0], r[1] - along * t[1], r[2] - along * t[2]);
|
|
43
|
+
if (off > tolerance || along <= s + tolerance || along > L + tolerance)
|
|
44
|
+
continue;
|
|
45
|
+
if (!next || along < next.s)
|
|
46
|
+
next = { member, other, s: along };
|
|
47
|
+
}
|
|
48
|
+
if (!next)
|
|
49
|
+
return null;
|
|
50
|
+
const to = next.other === end ? L : next.s;
|
|
51
|
+
segments.push({
|
|
52
|
+
member: next.member,
|
|
53
|
+
from: s,
|
|
54
|
+
to,
|
|
55
|
+
reversed: next.member.startNodeId !== current,
|
|
56
|
+
});
|
|
57
|
+
current = next.other;
|
|
58
|
+
s = to;
|
|
59
|
+
}
|
|
60
|
+
return segments;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=edge-members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-members.js","sourceRoot":"","sources":["../../../../../src/fea/frame/area/edge-members.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { FrameAnalysisError, FrameErrors } from "../../../core/errors/frame-analysis.error.js";
|
|
2
|
-
|
|
2
|
+
/** Intensity of a distributed load at `x` (inside its extent), in N/mm. */
|
|
3
|
+
export const loadIntensity = (load, x) => load.w1 + ((load.w2 - load.w1) * (x - load.start)) / (load.end - load.start);
|
|
4
|
+
// 4-point Gauss–Legendre rule, exact up to degree 7: cubic shape functions × linear loads
|
|
3
5
|
const GAUSS_POINTS = [
|
|
4
6
|
-0.8611363115940526, -0.3399810435848563, 0.3399810435848563, 0.8611363115940526,
|
|
5
7
|
];
|
|
@@ -54,7 +56,17 @@ export const fixedEndForces = (loads, L) => {
|
|
|
54
56
|
equivalent[i] += unit[i] * factor;
|
|
55
57
|
};
|
|
56
58
|
for (const load of loads) {
|
|
57
|
-
if (load.type === "
|
|
59
|
+
if (load.type === "torque") {
|
|
60
|
+
if (!(load.start >= 0 && load.end <= L && load.start < load.end)) {
|
|
61
|
+
throw new FrameAnalysisError(FrameErrors.LOAD_OUTSIDE_MEMBER);
|
|
62
|
+
}
|
|
63
|
+
// linear torsion shape functions 1 − ξ and ξ, integrated over [start, end]
|
|
64
|
+
const resultant = load.t * (load.end - load.start);
|
|
65
|
+
const centroid = (load.start + load.end) / 2;
|
|
66
|
+
equivalent[3] += resultant * (1 - centroid / L);
|
|
67
|
+
equivalent[9] += (resultant * centroid) / L;
|
|
68
|
+
}
|
|
69
|
+
else if (load.type === "point") {
|
|
58
70
|
if (!(load.a >= 0 && load.a <= L))
|
|
59
71
|
throw new FrameAnalysisError(FrameErrors.LOAD_OUTSIDE_MEMBER);
|
|
60
72
|
add(unitEquivalentLoad(load.axis, load.a, L), load.P);
|
|
@@ -66,7 +78,8 @@ export const fixedEndForces = (loads, L) => {
|
|
|
66
78
|
const half = (load.end - load.start) / 2;
|
|
67
79
|
const mid = (load.end + load.start) / 2;
|
|
68
80
|
GAUSS_POINTS.forEach((p, index) => {
|
|
69
|
-
|
|
81
|
+
const x = mid + half * p;
|
|
82
|
+
add(unitEquivalentLoad(load.axis, x, L), loadIntensity(load, x) * half * GAUSS_WEIGHTS[index]);
|
|
70
83
|
});
|
|
71
84
|
}
|
|
72
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixed-end-forces.js","sourceRoot":"","sources":["../../../../../src/fea/frame/elements/fixed-end-forces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"fixed-end-forces.js","sourceRoot":"","sources":["../../../../../src/fea/frame/elements/fixed-end-forces.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { analyzeFrame, createFrameAnalysis } from "./solver/analyze-frame.js";
|
|
2
2
|
export { validateFrameModel } from "./validation/validate-model.js";
|
|
3
|
+
export { distributeAreaLoads } from "./area/distribute-area-loads.js";
|
|
3
4
|
export { beam3dLocalStiffness, beam3dLocalStiffnessRightHanded, } from "./elements/beam-3d-stiffness.js";
|
|
4
5
|
export { memberAxes } from "./transformation/coordinate-transform.js";
|
|
5
6
|
export { memberDemandEnvelope } from "./post/demand-envelope.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/fea/frame/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/fea/frame/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EACL,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -7,6 +7,9 @@ const DEFLECTION_GRID_INTERVALS = 40;
|
|
|
7
7
|
/** Golden-section steps refining each deflection extreme between its neighbouring grid points. */
|
|
8
8
|
const REFINE_STEPS = 30;
|
|
9
9
|
const GOLDEN = (Math.sqrt(5) - 1) / 2;
|
|
10
|
+
// 3-point Gauss–Legendre rule on [−1, 1], exact up to degree 5
|
|
11
|
+
const GAUSS3_POINTS = [-Math.sqrt(3 / 5), 0, Math.sqrt(3 / 5)];
|
|
12
|
+
const GAUSS3_WEIGHTS = [5 / 9, 8 / 9, 5 / 9];
|
|
10
13
|
const FORCE_DECIMALS = 4;
|
|
11
14
|
const DISPLACEMENT_DECIMALS = 5;
|
|
12
15
|
/**
|
|
@@ -18,11 +21,17 @@ const DISPLACEMENT_DECIMALS = 5;
|
|
|
18
21
|
*/
|
|
19
22
|
const internalForces = (startForce, loads, x, side) => {
|
|
20
23
|
const [f1, f2, f3, m1, m2, m3] = startForce;
|
|
21
|
-
// Q[axis]: resultant of loads in [0, x]; I[axis]: ∫(s − x)·q ds over [0, x]
|
|
24
|
+
// Q[axis]: resultant of loads in [0, x]; I[axis]: ∫(s − x)·q ds over [0, x]; Qt: torque in [0, x]
|
|
22
25
|
const Q = [0, 0, 0, 0];
|
|
23
26
|
const I = [0, 0, 0, 0];
|
|
27
|
+
let Qt = 0;
|
|
24
28
|
for (const load of loads) {
|
|
25
|
-
if (load.type === "
|
|
29
|
+
if (load.type === "torque") {
|
|
30
|
+
const m = Math.min(x, load.end);
|
|
31
|
+
if (m > load.start)
|
|
32
|
+
Qt += load.t * (m - load.start);
|
|
33
|
+
}
|
|
34
|
+
else if (load.type === "point") {
|
|
26
35
|
const included = side === "left" ? load.a < x : load.a <= x;
|
|
27
36
|
if (included) {
|
|
28
37
|
Q[load.axis] += load.P;
|
|
@@ -32,8 +41,12 @@ const internalForces = (startForce, loads, x, side) => {
|
|
|
32
41
|
else {
|
|
33
42
|
const m = Math.min(x, load.end);
|
|
34
43
|
if (m > load.start) {
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
// q(s) = w1 + k·(s − start); in u = s − x over [a, b]: q = w1 + k·(u − a)
|
|
45
|
+
const k = (load.w2 - load.w1) / (load.end - load.start);
|
|
46
|
+
const a = load.start - x;
|
|
47
|
+
const b = m - x;
|
|
48
|
+
Q[load.axis] += load.w1 * (b - a) + (k * (b - a) ** 2) / 2;
|
|
49
|
+
I[load.axis] += ((load.w1 - k * a) * (b ** 2 - a ** 2)) / 2 + (k * (b ** 3 - a ** 3)) / 3;
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
52
|
}
|
|
@@ -41,7 +54,7 @@ const internalForces = (startForce, loads, x, side) => {
|
|
|
41
54
|
N: -f1 - Q[1],
|
|
42
55
|
V2: -f2 - Q[2],
|
|
43
56
|
V3: -f3 - Q[3],
|
|
44
|
-
T: -m1,
|
|
57
|
+
T: -m1 - Qt,
|
|
45
58
|
M2: -m2 - x * f3 + I[3],
|
|
46
59
|
M3: -m3 + x * f2 - I[2],
|
|
47
60
|
};
|
|
@@ -52,8 +65,8 @@ const internalForces = (startForce, loads, x, side) => {
|
|
|
52
65
|
*
|
|
53
66
|
* Each field is `a + b·x + x·∫₀ˣκ − ∫₀ˣ s·κ`, with the running integrals accumulated once along
|
|
54
67
|
* the sorted grid. The grid contains every load breakpoint, so each interval lies inside one
|
|
55
|
-
* smooth piece where N is at most
|
|
56
|
-
* interval integrates the (at most
|
|
68
|
+
* smooth piece where N is at most quadratic and M at most cubic, and one 3-point Gauss panel per
|
|
69
|
+
* interval integrates the (at most quartic) integrands exactly.
|
|
57
70
|
*
|
|
58
71
|
* The constants come from the member's own end displacements: end translations first, an end
|
|
59
72
|
* rotation only where a translation is released. A released rotation (hinge) never enters, so
|
|
@@ -64,22 +77,29 @@ const displacementsOnGrid = (member, startForce, endDisplacements, loads, grid)
|
|
|
64
77
|
const L = member.length;
|
|
65
78
|
const n = grid.length;
|
|
66
79
|
// integrands: [N/EA, M3/EI33, s·M3/EI33, −M2/EI22, −s·M2/EI22]
|
|
67
|
-
const integrands = (s
|
|
68
|
-
const f = internalForces(startForce, loads, s,
|
|
80
|
+
const integrands = (s) => {
|
|
81
|
+
const f = internalForces(startForce, loads, s, "right");
|
|
69
82
|
const k3 = f.M3 / (E * I33);
|
|
70
83
|
const k2 = -f.M2 / (E * I22);
|
|
71
84
|
return [f.N / (E * A), k3, s * k3, k2, s * k2];
|
|
72
85
|
};
|
|
86
|
+
/** ∫ₐᵇ of every integrand: one 3-point Gauss panel, interior points only (no load side). */
|
|
87
|
+
const panel = (a, b) => {
|
|
88
|
+
const half = (b - a) / 2;
|
|
89
|
+
const mid = (a + b) / 2;
|
|
90
|
+
const out = [0, 0, 0, 0, 0];
|
|
91
|
+
GAUSS3_POINTS.forEach((p, k) => {
|
|
92
|
+
const g = integrands(mid + half * p);
|
|
93
|
+
for (let c = 0; c < 5; c++)
|
|
94
|
+
out[c] += half * GAUSS3_WEIGHTS[k] * g[c];
|
|
95
|
+
});
|
|
96
|
+
return out;
|
|
97
|
+
};
|
|
73
98
|
const cumulative = Array.from({ length: 5 }, () => new Float64Array(n));
|
|
74
99
|
for (let i = 1; i < n; i++) {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const gm = integrands((a + b) / 2, "right");
|
|
79
|
-
const gb = integrands(b, "left");
|
|
80
|
-
for (let c = 0; c < 5; c++) {
|
|
81
|
-
cumulative[c][i] = cumulative[c][i - 1] + ((b - a) / 6) * (ga[c] + 4 * gm[c] + gb[c]);
|
|
82
|
-
}
|
|
100
|
+
const g = panel(grid[i - 1], grid[i]);
|
|
101
|
+
for (let c = 0; c < 5; c++)
|
|
102
|
+
cumulative[c][i] = cumulative[c][i - 1] + g[c];
|
|
83
103
|
}
|
|
84
104
|
const [strain, k3, sk3, k2, sk2] = cumulative;
|
|
85
105
|
const last = n - 1;
|
|
@@ -121,7 +141,7 @@ const displacementsOnGrid = (member, startForce, endDisplacements, loads, grid)
|
|
|
121
141
|
u2: plane2.a + plane2.b * x + P3(i),
|
|
122
142
|
u3: plane3.a + plane3.b * x + P2(i),
|
|
123
143
|
}));
|
|
124
|
-
/** Displacement anywhere: the grid value plus one exact
|
|
144
|
+
/** Displacement anywhere: the grid value plus one exact Gauss panel to x. */
|
|
125
145
|
const at = (x) => {
|
|
126
146
|
let lo = 0;
|
|
127
147
|
let hi = last;
|
|
@@ -135,10 +155,8 @@ const displacementsOnGrid = (member, startForce, endDisplacements, loads, grid)
|
|
|
135
155
|
const a = grid[lo];
|
|
136
156
|
if (x - a <= 0)
|
|
137
157
|
return onGrid[lo];
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const gx = integrands(x, "left");
|
|
141
|
-
const c = cumulative.map((col, k) => col[lo] + ((x - a) / 6) * (ga[k] + 4 * gm[k] + gx[k]));
|
|
158
|
+
const g = panel(a, x);
|
|
159
|
+
const c = cumulative.map((col, k) => col[lo] + g[k]);
|
|
142
160
|
return {
|
|
143
161
|
u1: axialStart + c[0],
|
|
144
162
|
u2: plane2.a + plane2.b * x + (x * c[1] - c[2]),
|
|
@@ -194,16 +212,40 @@ export const memberDiagram = (member, startForce, endDisplacements, loads, stati
|
|
|
194
212
|
out.push(v);
|
|
195
213
|
return out;
|
|
196
214
|
};
|
|
197
|
-
//
|
|
215
|
+
// Inside each piece between breakpoints N and V are at most quadratic (linear loads), so the
|
|
216
|
+
// quadratic through both ends and the midpoint is exact. Its roots (zero shear: the moment
|
|
217
|
+
// extremes) and its vertex (zero load: the N and V extremes) are added to the grid.
|
|
198
218
|
const roots = [];
|
|
199
219
|
for (let i = 0; i < sortedBreaks.length - 1; i++) {
|
|
200
220
|
const xa = sortedBreaks[i];
|
|
201
221
|
const xb = sortedBreaks[i + 1];
|
|
202
222
|
const fa = internalForces(startForce, loads, xa, "right");
|
|
223
|
+
const fm = internalForces(startForce, loads, (xa + xb) / 2, "right");
|
|
203
224
|
const fb = internalForces(startForce, loads, xb, "left");
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
225
|
+
const inside = (t) => t > 0 && t < 1 && roots.push(xa + (xb - xa) * t);
|
|
226
|
+
for (const key of ["N", "V2", "V3"]) {
|
|
227
|
+
// f(t) = A·t² + B·t + C on t ∈ [0, 1]
|
|
228
|
+
const C = fa[key];
|
|
229
|
+
const A = 2 * fa[key] - 4 * fm[key] + 2 * fb[key];
|
|
230
|
+
const B = 4 * fm[key] - 3 * fa[key] - fb[key];
|
|
231
|
+
const scale = Math.max(Math.abs(fa[key]), Math.abs(fm[key]), Math.abs(fb[key]));
|
|
232
|
+
const curved = Math.abs(A) > 1e-12 * scale;
|
|
233
|
+
if (curved)
|
|
234
|
+
inside(-B / (2 * A));
|
|
235
|
+
if (key === "N")
|
|
236
|
+
continue;
|
|
237
|
+
if (!curved) {
|
|
238
|
+
if (Math.abs(B) > 1e-12 * scale)
|
|
239
|
+
inside(-C / B);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const disc = B * B - 4 * A * C;
|
|
243
|
+
if (disc >= 0) {
|
|
244
|
+
const sq = Math.sqrt(disc);
|
|
245
|
+
inside((-B - sq) / (2 * A));
|
|
246
|
+
inside((-B + sq) / (2 * A));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
207
249
|
}
|
|
208
250
|
}
|
|
209
251
|
const coarse = Array.from({ length: DEFLECTION_GRID_INTERVALS + 1 }, (_, i) => (L * i) / DEFLECTION_GRID_INTERVALS);
|
|
@@ -258,8 +300,9 @@ export const memberDiagram = (member, startForce, endDisplacements, loads, stati
|
|
|
258
300
|
}
|
|
259
301
|
}
|
|
260
302
|
// ---- Extremes -------------------------------------------------------------------
|
|
261
|
-
// N
|
|
262
|
-
// breakpoint (either side) or a zero-shear point — all on the
|
|
303
|
+
// N and V are at most quadratic, T linear and M at most cubic inside each piece, so their
|
|
304
|
+
// extremes lie at a breakpoint (either side), a zero-load or a zero-shear point — all on the
|
|
305
|
+
// grid, so these are exact.
|
|
263
306
|
// Deflections are taken on the grid, then refined by golden-section search.
|
|
264
307
|
const extremes = {};
|
|
265
308
|
const best = {};
|