@seatlayer/core 0.50.0 → 0.50.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.
- package/dist/view3d/index.cjs +82 -4
- package/dist/view3d/index.cjs.map +1 -1
- package/dist/view3d/index.d.cts +11 -0
- package/dist/view3d/index.d.ts +11 -0
- package/dist/view3d/index.js +82 -4
- package/dist/view3d/index.js.map +1 -1
- package/package.json +1 -1
package/dist/view3d/index.cjs
CHANGED
|
@@ -476,9 +476,9 @@ var OrbitCamera = class {
|
|
|
476
476
|
const halfV = this.fovY * DEG / 2;
|
|
477
477
|
const aspect = portraitCrop ? Math.max(0.82, this.camera.aspect || 1) : this.camera.aspect || 1;
|
|
478
478
|
const halfH = Math.atan(Math.tan(halfV) * aspect);
|
|
479
|
-
const fit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
480
479
|
this.azT = stageAzimuth ?? -30 * DEG;
|
|
481
480
|
this.polT = 55 * DEG;
|
|
481
|
+
const fit = this.fitDistance(bounds, halfV, halfH, this.azT, this.polT);
|
|
482
482
|
this.distT = fit * FRAME_MARGIN;
|
|
483
483
|
this.minDist = Math.max(2, r * 0.12);
|
|
484
484
|
this.maxDist = fit * 4;
|
|
@@ -508,15 +508,59 @@ var OrbitCamera = class {
|
|
|
508
508
|
this.panLimit = Math.max(1, bounds.radius) * 1.5;
|
|
509
509
|
this.syncFromCamera();
|
|
510
510
|
this.camera.perspective({ fov: this.fovY, aspect: this.camera.aspect });
|
|
511
|
-
const r = Math.max(1, bounds.radius);
|
|
512
511
|
const halfV = this.fovY * DEG / 2;
|
|
513
512
|
const aspect = portraitCrop ? Math.max(0.82, this.camera.aspect || 1) : this.camera.aspect || 1;
|
|
514
513
|
const halfH = Math.atan(Math.tan(halfV) * aspect);
|
|
515
|
-
const fit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
516
514
|
this.azT = stageAzimuth ?? this.azimuth;
|
|
517
515
|
this.polT = 55 * DEG;
|
|
516
|
+
const fit = this.fitDistance(bounds, halfV, halfH, this.azT, this.polT);
|
|
518
517
|
this.distT = fit * FRAME_MARGIN;
|
|
519
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Distance from the bounds centre at which the venue fits the frustum at
|
|
521
|
+
* the given pose.
|
|
522
|
+
*
|
|
523
|
+
* Radius-only callers (section / zone / row focus) get the sphere fit —
|
|
524
|
+
* exact enough for chunky targets, and their radii are hand-tuned to it.
|
|
525
|
+
* When the caller supplies the venue's axis-aligned box, fit the box's
|
|
526
|
+
* PROJECTED corners instead: a flat banquet floor's enclosing sphere is
|
|
527
|
+
* nearly all horizontal extent, and sphere-fitting it backed the camera off
|
|
528
|
+
* until the venue used a fraction of the canvas. Each corner demands
|
|
529
|
+
* `lateral/tan(half-angle) − depth` of camera distance; the venue fits when
|
|
530
|
+
* every corner does. Clamped to the sphere fit (which always contains the
|
|
531
|
+
* box) and floored so a degenerate box cannot glue the camera to the floor.
|
|
532
|
+
*/
|
|
533
|
+
fitDistance(bounds, halfV, halfH, azimuth, polar) {
|
|
534
|
+
const r = Math.max(1, bounds.radius);
|
|
535
|
+
const sphereFit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
536
|
+
const box = bounds.box;
|
|
537
|
+
if (!box) return sphereFit;
|
|
538
|
+
const sp = Math.sin(polar);
|
|
539
|
+
const fx = -sp * Math.sin(azimuth);
|
|
540
|
+
const fy = -Math.cos(polar);
|
|
541
|
+
const fz = -sp * Math.cos(azimuth);
|
|
542
|
+
if (Math.abs(fy) > 0.999) return sphereFit;
|
|
543
|
+
let rx = -fz, rz = fx;
|
|
544
|
+
const rl = Math.hypot(rx, rz);
|
|
545
|
+
rx /= rl;
|
|
546
|
+
rz /= rl;
|
|
547
|
+
const ux = -rz * fy;
|
|
548
|
+
const uy = rz * fx - rx * fz;
|
|
549
|
+
const uz = rx * fy;
|
|
550
|
+
const tanH = Math.tan(halfH);
|
|
551
|
+
const tanV = Math.tan(halfV);
|
|
552
|
+
let fit = 1;
|
|
553
|
+
for (let i = 0; i < 8; i++) {
|
|
554
|
+
const px = (i & 1 ? box.max[0] : box.min[0]) - bounds.center[0];
|
|
555
|
+
const py = (i & 2 ? box.max[1] : box.min[1]) - bounds.center[1];
|
|
556
|
+
const pz = (i & 4 ? box.max[2] : box.min[2]) - bounds.center[2];
|
|
557
|
+
const depth = px * fx + py * fy + pz * fz;
|
|
558
|
+
const lx = Math.abs(px * rx + pz * rz);
|
|
559
|
+
const ly = Math.abs(px * ux + py * uy + pz * uz);
|
|
560
|
+
fit = Math.max(fit, lx / tanH - depth, ly / tanV - depth);
|
|
561
|
+
}
|
|
562
|
+
return Math.min(sphereFit, Math.max(fit, r * 0.35));
|
|
563
|
+
}
|
|
520
564
|
/**
|
|
521
565
|
* Tighten the depth range around the actual venue bounds for the current pose.
|
|
522
566
|
*
|
|
@@ -3987,10 +4031,44 @@ function buildSceneModel(input) {
|
|
|
3987
4031
|
renderMaxY - renderMinY,
|
|
3988
4032
|
renderMaxZ - renderMinZ
|
|
3989
4033
|
));
|
|
4034
|
+
let contentMinX = Infinity, contentMinZ = Infinity, contentMaxX = -Infinity, contentMaxZ = -Infinity;
|
|
4035
|
+
for (let i = 0; i < seatData.count; i++) {
|
|
4036
|
+
const o = i * 3;
|
|
4037
|
+
const x = seatData.iPosition[o], z = seatData.iPosition[o + 2];
|
|
4038
|
+
if (x < contentMinX) contentMinX = x;
|
|
4039
|
+
if (x > contentMaxX) contentMaxX = x;
|
|
4040
|
+
if (z < contentMinZ) contentMinZ = z;
|
|
4041
|
+
if (z > contentMaxZ) contentMaxZ = z;
|
|
4042
|
+
}
|
|
4043
|
+
for (const s of stageBounds) {
|
|
4044
|
+
contentMinX = Math.min(contentMinX, s.cx - s.halfX);
|
|
4045
|
+
contentMaxX = Math.max(contentMaxX, s.cx + s.halfX);
|
|
4046
|
+
contentMinZ = Math.min(contentMinZ, s.cz - s.halfZ);
|
|
4047
|
+
contentMaxZ = Math.max(contentMaxZ, s.cz + s.halfZ);
|
|
4048
|
+
}
|
|
4049
|
+
const fpMinX = fp.minX * M, fpMaxX = fp.maxX * M, fpMinZ = fp.minY * M, fpMaxZ = fp.maxY * M;
|
|
4050
|
+
let boxMinX = fpMinX, boxMaxX = fpMaxX, boxMinZ = fpMinZ, boxMaxZ = fpMaxZ;
|
|
4051
|
+
if (Number.isFinite(contentMinX)) {
|
|
4052
|
+
const pad = Math.max(2, 0.06 * Math.hypot(contentMaxX - contentMinX, contentMaxZ - contentMinZ));
|
|
4053
|
+
boxMinX = Math.max(fpMinX, contentMinX - pad);
|
|
4054
|
+
boxMaxX = Math.min(fpMaxX, contentMaxX + pad);
|
|
4055
|
+
boxMinZ = Math.max(fpMinZ, contentMinZ - pad);
|
|
4056
|
+
boxMaxZ = Math.min(fpMaxZ, contentMaxZ + pad);
|
|
4057
|
+
}
|
|
3990
4058
|
return {
|
|
3991
4059
|
solids,
|
|
3992
4060
|
seats: seatData,
|
|
3993
|
-
bounds: {
|
|
4061
|
+
bounds: {
|
|
4062
|
+
// Centred on the CONTENT box, so an off-centre table cluster arrives
|
|
4063
|
+
// centred on screen instead of wherever the floor's midpoint put it.
|
|
4064
|
+
center: [(boxMinX + boxMaxX) / 2, radius * 0.08, (boxMinZ + boxMaxZ) / 2],
|
|
4065
|
+
radius,
|
|
4066
|
+
groundY: 0,
|
|
4067
|
+
box: {
|
|
4068
|
+
min: [boxMinX, Math.min(0, renderMinY), boxMinZ],
|
|
4069
|
+
max: [boxMaxX, Math.max(renderMaxY, radius * 0.05), boxMaxZ]
|
|
4070
|
+
}
|
|
4071
|
+
},
|
|
3994
4072
|
renderBounds: { center: renderCenter, radius: renderRadius },
|
|
3995
4073
|
stateColorLUT: themeSeatColorLUT(theme, SEAT_STATES),
|
|
3996
4074
|
theme,
|