@ifc-lite/renderer 1.49.0 → 1.49.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.
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
* is the single source of truth.
|
|
13
13
|
*
|
|
14
14
|
* Convention:
|
|
15
|
-
* • The renderer/world is Y-up.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* • The renderer/world is Y-up. World-Y is the reference axis for every
|
|
16
|
+
* normal except exactly ±Y, where the cross product vanishes and we
|
|
17
|
+
* fall back to world-X. `tangent` is therefore horizontal and
|
|
18
|
+
* `bitangent` never points downward, so a face-picked elevation comes
|
|
19
|
+
* out upright (#2714).
|
|
18
20
|
* • For the cardinal Y-axis plane (normal = [0,1,0]) the resulting
|
|
19
|
-
* basis is `tangent
|
|
21
|
+
* basis is `tangent = [0,0,-1]`, `bitangent = [1,0,0]`. That matches
|
|
20
22
|
* the cardinal-axis cap projection (`'down'` axis maps `(x, z) →
|
|
21
23
|
* (2D.x, 2D.y)` with z mirrored on flip), so face-picking a perfectly
|
|
22
24
|
* horizontal floor reproduces the same hatch orientation as the
|
|
@@ -43,6 +45,9 @@ export interface PlaneBasis {
|
|
|
43
45
|
* hatch doesn't rotate when state is reconstructed (e.g. on reload
|
|
44
46
|
* or when the renderer rebuilds resources).
|
|
45
47
|
* 5. Every component of both axes is finite, for every input.
|
|
48
|
+
* 6. The result is *continuous* in the normal, everywhere except the two
|
|
49
|
+
* poles `n = ±Y` (#2714) — nearby normals give nearby bases, so two
|
|
50
|
+
* face picks on nearly the same face give nearly the same drawing.
|
|
46
51
|
*
|
|
47
52
|
* Normalising up front is what makes 3 and 5 true rather than aspirational
|
|
48
53
|
* (#2489). Before it, the function read the caller's magnitudes directly and
|
|
@@ -52,16 +57,17 @@ export interface PlaneBasis {
|
|
|
52
57
|
* is true and `NaN < 1e-9` is false — and reached the divisions as
|
|
53
58
|
* `Infinity / Infinity` / `NaN / NaN`. Both axes came back all-NaN and
|
|
54
59
|
* went into the section gizmo's vertex buffer and the cap's lift-to-3D.
|
|
55
|
-
* • The `|ny| < 0.9
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* because the caller had not
|
|
60
|
+
* • The reference-axis pick of the day (`|ny| < 0.9`, since removed for
|
|
61
|
+
* being discontinuous) only measures the angle to Y when `|normal| = 1`.
|
|
62
|
+
* `[10, 1, 0]` is 6° off horizontal but was routed down that fallback,
|
|
63
|
+
* flipping the hatch axis 180° purely because the caller had not
|
|
64
|
+
* normalised.
|
|
59
65
|
* • The `1e-9` tangent floor is a length, so a short-but-perfectly-valid
|
|
60
66
|
* normal such as `[1e-12, 0, 0]` was declared degenerate and returned a
|
|
61
67
|
* zero-length bitangent.
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
68
|
+
* Normalisation keeps the sole remaining fallback below an exact test — it is
|
|
69
|
+
* reachable only for a normal with no direction at all, or one pointing
|
|
70
|
+
* exactly along ±Y.
|
|
65
71
|
*/
|
|
66
72
|
export declare function planeBasis(normal: Vec3Tuple): PlaneBasis;
|
|
67
73
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section-plane-basis.d.ts","sourceRoot":"","sources":["../src/section-plane-basis.ts"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"section-plane-basis.d.ts","sourceRoot":"","sources":["../src/section-plane-basis.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,8DAA8D;IAC9D,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAkBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,CAiFxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,GAChB;IAAE,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAWvD"}
|
|
@@ -30,6 +30,9 @@ function degenerateBasis() {
|
|
|
30
30
|
* hatch doesn't rotate when state is reconstructed (e.g. on reload
|
|
31
31
|
* or when the renderer rebuilds resources).
|
|
32
32
|
* 5. Every component of both axes is finite, for every input.
|
|
33
|
+
* 6. The result is *continuous* in the normal, everywhere except the two
|
|
34
|
+
* poles `n = ±Y` (#2714) — nearby normals give nearby bases, so two
|
|
35
|
+
* face picks on nearly the same face give nearly the same drawing.
|
|
33
36
|
*
|
|
34
37
|
* Normalising up front is what makes 3 and 5 true rather than aspirational
|
|
35
38
|
* (#2489). Before it, the function read the caller's magnitudes directly and
|
|
@@ -39,16 +42,17 @@ function degenerateBasis() {
|
|
|
39
42
|
* is true and `NaN < 1e-9` is false — and reached the divisions as
|
|
40
43
|
* `Infinity / Infinity` / `NaN / NaN`. Both axes came back all-NaN and
|
|
41
44
|
* went into the section gizmo's vertex buffer and the cap's lift-to-3D.
|
|
42
|
-
* • The `|ny| < 0.9
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* because the caller had not
|
|
45
|
+
* • The reference-axis pick of the day (`|ny| < 0.9`, since removed for
|
|
46
|
+
* being discontinuous) only measures the angle to Y when `|normal| = 1`.
|
|
47
|
+
* `[10, 1, 0]` is 6° off horizontal but was routed down that fallback,
|
|
48
|
+
* flipping the hatch axis 180° purely because the caller had not
|
|
49
|
+
* normalised.
|
|
46
50
|
* • The `1e-9` tangent floor is a length, so a short-but-perfectly-valid
|
|
47
51
|
* normal such as `[1e-12, 0, 0]` was declared degenerate and returned a
|
|
48
52
|
* zero-length bitangent.
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
53
|
+
* Normalisation keeps the sole remaining fallback below an exact test — it is
|
|
54
|
+
* reachable only for a normal with no direction at all, or one pointing
|
|
55
|
+
* exactly along ±Y.
|
|
52
56
|
*/
|
|
53
57
|
export function planeBasis(normal) {
|
|
54
58
|
const nlen = Math.hypot(normal[0], normal[1], normal[2]);
|
|
@@ -60,11 +64,43 @@ export function planeBasis(normal) {
|
|
|
60
64
|
const nx = normal[0] / nlen;
|
|
61
65
|
const ny = normal[1] / nlen;
|
|
62
66
|
const nz = normal[2] / nlen;
|
|
63
|
-
// Reference axis: Y
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
67
|
+
// Reference axis: world Y, for EVERY normal that is not exactly ±Y. The
|
|
68
|
+
// resulting tangent is `normalize(normal × Ŷ)` — the horizontal in-plane
|
|
69
|
+
// direction — which depends only on the normal's azimuth and is therefore
|
|
70
|
+
// continuous over the whole sphere minus the two poles (#2714).
|
|
71
|
+
//
|
|
72
|
+
// It used to switch to world X at `|ny| >= 0.9` "to avoid a degenerate
|
|
73
|
+
// cross-product", but 0.9 is nowhere near degenerate: the cross is still
|
|
74
|
+
// 0.436 long there. All the switch bought was a JUMP. Measured at the
|
|
75
|
+
// boundary, `ny = 0.8999 → 0.9001` inverted the tangent exactly (dot = -1)
|
|
76
|
+
// at `nz = 0` and rotated it 133 degrees at `nz = 0.3`, and it was
|
|
77
|
+
// asymmetric — the `ny < 0` crossing did not move at all. `|ny| = 0.9` is a
|
|
78
|
+
// plane 25.8 degrees off horizontal, an ordinary ~6:12 roof pitch, and
|
|
79
|
+
// `setSectionPlaneFromFace` reaches it from a face pick: two picks on roof
|
|
80
|
+
// faces straddling that pitch produced drawings rotated 133-180 degrees
|
|
81
|
+
// apart, because this basis IS the drawing's coordinate frame
|
|
82
|
+
// (`useDrawingGeneration` feeds it to the cutter as `customPlane`).
|
|
83
|
+
//
|
|
84
|
+
// No construction can be continuous everywhere — the hairy-ball theorem
|
|
85
|
+
// forbids a nowhere-zero tangent field on a sphere, so at least one normal
|
|
86
|
+
// must be singular. The two poles are the right place for it: `n = ±Y` is
|
|
87
|
+
// an exactly horizontal plane, whose drawing is a plan whose in-plane
|
|
88
|
+
// rotation is a free choice. (The branchless Frisvad/Duff construction gets
|
|
89
|
+
// that down to ONE singular point, but only by winding the frame twice
|
|
90
|
+
// around it, which puts `bitangent · Y = -nx` — i.e. it turns every
|
|
91
|
+
// elevation on one half of the sphere upside down. Two poles is the price
|
|
92
|
+
// of `bitangent · Y = sin(tilt) >= 0` everywhere, which is what keeps
|
|
93
|
+
// face-picked elevations upright.)
|
|
94
|
+
//
|
|
95
|
+
// At the poles themselves the X fallback keeps the historical answer
|
|
96
|
+
// (`planeBasis([0,1,0]) = tangent [0,0,-1], bitangent [1,0,0]`), which is
|
|
97
|
+
// what makes a picked horizontal floor reproduce the "Down" preset's hatch
|
|
98
|
+
// orientation. That value cannot also be the limit from every direction —
|
|
99
|
+
// the frame winds once around the pole, so `[1e-9, 1, 0]` and `[-1e-9, 1, 0]`
|
|
100
|
+
// are 180° apart no matter what is chosen here. That is the singularity, and
|
|
101
|
+
// it is parked where its cost is lowest: the plane is exactly horizontal, so
|
|
102
|
+
// the drawing is a plan and its in-plane rotation carries no meaning.
|
|
103
|
+
const useY = nx !== 0 || nz !== 0;
|
|
68
104
|
const refX = useY ? 0 : 1;
|
|
69
105
|
const refY = useY ? 1 : 0;
|
|
70
106
|
const refZ = 0;
|
|
@@ -73,10 +109,13 @@ export function planeBasis(normal) {
|
|
|
73
109
|
let ty = nz * refX - nx * refZ;
|
|
74
110
|
let tz = nx * refY - ny * refX;
|
|
75
111
|
let tlen = Math.hypot(tx, ty, tz);
|
|
76
|
-
if (tlen
|
|
77
|
-
// Unreachable for
|
|
78
|
-
//
|
|
79
|
-
//
|
|
112
|
+
if (!(tlen > 0)) {
|
|
113
|
+
// Unreachable: `useY` is false only for `n = ±Y`, whose cross with X is
|
|
114
|
+
// exactly unit. Kept so a future edit degrades instead of dividing by
|
|
115
|
+
// zero — and tested as `> 0` rather than against a fixed floor, because
|
|
116
|
+
// any floor here is a re-run of the same defect: `|normal × Ŷ|` is the
|
|
117
|
+
// tilt's sine, so a floor would restore a jump circle at the tilt where
|
|
118
|
+
// it bites.
|
|
80
119
|
tx = 0;
|
|
81
120
|
ty = 0;
|
|
82
121
|
tz = -1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section-plane-basis.js","sourceRoot":"","sources":["../src/section-plane-basis.ts"],"names":[],"mappings":"AAAA;;+DAE+D;
|
|
1
|
+
{"version":3,"file":"section-plane-basis.js","sourceRoot":"","sources":["../src/section-plane-basis.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/renderer",
|
|
3
|
-
"version": "1.49.
|
|
3
|
+
"version": "1.49.1",
|
|
4
4
|
"description": "WebGPU renderer for IFC-Lite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@ifc-lite/geometry": "^3.8.
|
|
17
|
-
"@ifc-lite/spatial": "^1.14.
|
|
16
|
+
"@ifc-lite/geometry": "^3.8.4",
|
|
17
|
+
"@ifc-lite/spatial": "^1.14.14"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@webgpu/types": "^0.1.71",
|
|
21
|
-
"tsx": "^4.23.
|
|
21
|
+
"tsx": "^4.23.12",
|
|
22
22
|
"typescript": "^6.0.3"
|
|
23
23
|
},
|
|
24
24
|
"license": "MPL-2.0",
|