@seatlayer/core 0.50.0 → 0.50.2
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.d.cts
CHANGED
|
@@ -325,6 +325,17 @@ interface SceneModel {
|
|
|
325
325
|
/** Half-diagonal of the horizontal footprint, metres (camera fit). */
|
|
326
326
|
radius: number;
|
|
327
327
|
groundY: number;
|
|
328
|
+
/**
|
|
329
|
+
* Axis-aligned venue extents (horizontal from the chart footprint,
|
|
330
|
+
* vertical from the rendered geometry). The overview camera fits this
|
|
331
|
+
* projected box rather than the radius sphere — a flat wide floor's
|
|
332
|
+
* sphere over-estimates wildly and framed such venues tiny (see
|
|
333
|
+
* OrbitCamera.fitDistance).
|
|
334
|
+
*/
|
|
335
|
+
box: {
|
|
336
|
+
min: [number, number, number];
|
|
337
|
+
max: [number, number, number];
|
|
338
|
+
};
|
|
328
339
|
};
|
|
329
340
|
/** Exact enclosing sphere for rendered solids plus near-field seat detail. */
|
|
330
341
|
renderBounds: {
|
package/dist/view3d/index.d.ts
CHANGED
|
@@ -325,6 +325,17 @@ interface SceneModel {
|
|
|
325
325
|
/** Half-diagonal of the horizontal footprint, metres (camera fit). */
|
|
326
326
|
radius: number;
|
|
327
327
|
groundY: number;
|
|
328
|
+
/**
|
|
329
|
+
* Axis-aligned venue extents (horizontal from the chart footprint,
|
|
330
|
+
* vertical from the rendered geometry). The overview camera fits this
|
|
331
|
+
* projected box rather than the radius sphere — a flat wide floor's
|
|
332
|
+
* sphere over-estimates wildly and framed such venues tiny (see
|
|
333
|
+
* OrbitCamera.fitDistance).
|
|
334
|
+
*/
|
|
335
|
+
box: {
|
|
336
|
+
min: [number, number, number];
|
|
337
|
+
max: [number, number, number];
|
|
338
|
+
};
|
|
328
339
|
};
|
|
329
340
|
/** Exact enclosing sphere for rendered solids plus near-field seat detail. */
|
|
330
341
|
renderBounds: {
|
package/dist/view3d/index.js
CHANGED
|
@@ -464,9 +464,9 @@ var OrbitCamera = class {
|
|
|
464
464
|
const halfV = this.fovY * DEG / 2;
|
|
465
465
|
const aspect = portraitCrop ? Math.max(0.82, this.camera.aspect || 1) : this.camera.aspect || 1;
|
|
466
466
|
const halfH = Math.atan(Math.tan(halfV) * aspect);
|
|
467
|
-
const fit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
468
467
|
this.azT = stageAzimuth ?? -30 * DEG;
|
|
469
468
|
this.polT = 55 * DEG;
|
|
469
|
+
const fit = this.fitDistance(bounds, halfV, halfH, this.azT, this.polT);
|
|
470
470
|
this.distT = fit * FRAME_MARGIN;
|
|
471
471
|
this.minDist = Math.max(2, r * 0.12);
|
|
472
472
|
this.maxDist = fit * 4;
|
|
@@ -496,15 +496,59 @@ var OrbitCamera = class {
|
|
|
496
496
|
this.panLimit = Math.max(1, bounds.radius) * 1.5;
|
|
497
497
|
this.syncFromCamera();
|
|
498
498
|
this.camera.perspective({ fov: this.fovY, aspect: this.camera.aspect });
|
|
499
|
-
const r = Math.max(1, bounds.radius);
|
|
500
499
|
const halfV = this.fovY * DEG / 2;
|
|
501
500
|
const aspect = portraitCrop ? Math.max(0.82, this.camera.aspect || 1) : this.camera.aspect || 1;
|
|
502
501
|
const halfH = Math.atan(Math.tan(halfV) * aspect);
|
|
503
|
-
const fit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
504
502
|
this.azT = stageAzimuth ?? this.azimuth;
|
|
505
503
|
this.polT = 55 * DEG;
|
|
504
|
+
const fit = this.fitDistance(bounds, halfV, halfH, this.azT, this.polT);
|
|
506
505
|
this.distT = fit * FRAME_MARGIN;
|
|
507
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Distance from the bounds centre at which the venue fits the frustum at
|
|
509
|
+
* the given pose.
|
|
510
|
+
*
|
|
511
|
+
* Radius-only callers (section / zone / row focus) get the sphere fit —
|
|
512
|
+
* exact enough for chunky targets, and their radii are hand-tuned to it.
|
|
513
|
+
* When the caller supplies the venue's axis-aligned box, fit the box's
|
|
514
|
+
* PROJECTED corners instead: a flat banquet floor's enclosing sphere is
|
|
515
|
+
* nearly all horizontal extent, and sphere-fitting it backed the camera off
|
|
516
|
+
* until the venue used a fraction of the canvas. Each corner demands
|
|
517
|
+
* `lateral/tan(half-angle) − depth` of camera distance; the venue fits when
|
|
518
|
+
* every corner does. Clamped to the sphere fit (which always contains the
|
|
519
|
+
* box) and floored so a degenerate box cannot glue the camera to the floor.
|
|
520
|
+
*/
|
|
521
|
+
fitDistance(bounds, halfV, halfH, azimuth, polar) {
|
|
522
|
+
const r = Math.max(1, bounds.radius);
|
|
523
|
+
const sphereFit = Math.max(r / Math.tan(halfV), r / Math.tan(halfH));
|
|
524
|
+
const box = bounds.box;
|
|
525
|
+
if (!box) return sphereFit;
|
|
526
|
+
const sp = Math.sin(polar);
|
|
527
|
+
const fx = -sp * Math.sin(azimuth);
|
|
528
|
+
const fy = -Math.cos(polar);
|
|
529
|
+
const fz = -sp * Math.cos(azimuth);
|
|
530
|
+
if (Math.abs(fy) > 0.999) return sphereFit;
|
|
531
|
+
let rx = -fz, rz = fx;
|
|
532
|
+
const rl = Math.hypot(rx, rz);
|
|
533
|
+
rx /= rl;
|
|
534
|
+
rz /= rl;
|
|
535
|
+
const ux = -rz * fy;
|
|
536
|
+
const uy = rz * fx - rx * fz;
|
|
537
|
+
const uz = rx * fy;
|
|
538
|
+
const tanH = Math.tan(halfH);
|
|
539
|
+
const tanV = Math.tan(halfV);
|
|
540
|
+
let fit = 1;
|
|
541
|
+
for (let i = 0; i < 8; i++) {
|
|
542
|
+
const px = (i & 1 ? box.max[0] : box.min[0]) - bounds.center[0];
|
|
543
|
+
const py = (i & 2 ? box.max[1] : box.min[1]) - bounds.center[1];
|
|
544
|
+
const pz = (i & 4 ? box.max[2] : box.min[2]) - bounds.center[2];
|
|
545
|
+
const depth = px * fx + py * fy + pz * fz;
|
|
546
|
+
const lx = Math.abs(px * rx + pz * rz);
|
|
547
|
+
const ly = Math.abs(px * ux + py * uy + pz * uz);
|
|
548
|
+
fit = Math.max(fit, lx / tanH - depth, ly / tanV - depth);
|
|
549
|
+
}
|
|
550
|
+
return Math.min(sphereFit, Math.max(fit, r * 0.35));
|
|
551
|
+
}
|
|
508
552
|
/**
|
|
509
553
|
* Tighten the depth range around the actual venue bounds for the current pose.
|
|
510
554
|
*
|
|
@@ -3523,10 +3567,44 @@ function buildSceneModel(input) {
|
|
|
3523
3567
|
renderMaxY - renderMinY,
|
|
3524
3568
|
renderMaxZ - renderMinZ
|
|
3525
3569
|
));
|
|
3570
|
+
let contentMinX = Infinity, contentMinZ = Infinity, contentMaxX = -Infinity, contentMaxZ = -Infinity;
|
|
3571
|
+
for (let i = 0; i < seatData.count; i++) {
|
|
3572
|
+
const o = i * 3;
|
|
3573
|
+
const x = seatData.iPosition[o], z = seatData.iPosition[o + 2];
|
|
3574
|
+
if (x < contentMinX) contentMinX = x;
|
|
3575
|
+
if (x > contentMaxX) contentMaxX = x;
|
|
3576
|
+
if (z < contentMinZ) contentMinZ = z;
|
|
3577
|
+
if (z > contentMaxZ) contentMaxZ = z;
|
|
3578
|
+
}
|
|
3579
|
+
for (const s of stageBounds) {
|
|
3580
|
+
contentMinX = Math.min(contentMinX, s.cx - s.halfX);
|
|
3581
|
+
contentMaxX = Math.max(contentMaxX, s.cx + s.halfX);
|
|
3582
|
+
contentMinZ = Math.min(contentMinZ, s.cz - s.halfZ);
|
|
3583
|
+
contentMaxZ = Math.max(contentMaxZ, s.cz + s.halfZ);
|
|
3584
|
+
}
|
|
3585
|
+
const fpMinX = fp.minX * M, fpMaxX = fp.maxX * M, fpMinZ = fp.minY * M, fpMaxZ = fp.maxY * M;
|
|
3586
|
+
let boxMinX = fpMinX, boxMaxX = fpMaxX, boxMinZ = fpMinZ, boxMaxZ = fpMaxZ;
|
|
3587
|
+
if (Number.isFinite(contentMinX)) {
|
|
3588
|
+
const pad = Math.max(2, 0.06 * Math.hypot(contentMaxX - contentMinX, contentMaxZ - contentMinZ));
|
|
3589
|
+
boxMinX = Math.max(fpMinX, contentMinX - pad);
|
|
3590
|
+
boxMaxX = Math.min(fpMaxX, contentMaxX + pad);
|
|
3591
|
+
boxMinZ = Math.max(fpMinZ, contentMinZ - pad);
|
|
3592
|
+
boxMaxZ = Math.min(fpMaxZ, contentMaxZ + pad);
|
|
3593
|
+
}
|
|
3526
3594
|
return {
|
|
3527
3595
|
solids,
|
|
3528
3596
|
seats: seatData,
|
|
3529
|
-
bounds: {
|
|
3597
|
+
bounds: {
|
|
3598
|
+
// Centred on the CONTENT box, so an off-centre table cluster arrives
|
|
3599
|
+
// centred on screen instead of wherever the floor's midpoint put it.
|
|
3600
|
+
center: [(boxMinX + boxMaxX) / 2, radius * 0.08, (boxMinZ + boxMaxZ) / 2],
|
|
3601
|
+
radius,
|
|
3602
|
+
groundY: 0,
|
|
3603
|
+
box: {
|
|
3604
|
+
min: [boxMinX, Math.min(0, renderMinY), boxMinZ],
|
|
3605
|
+
max: [boxMaxX, Math.max(renderMaxY, radius * 0.05), boxMaxZ]
|
|
3606
|
+
}
|
|
3607
|
+
},
|
|
3530
3608
|
renderBounds: { center: renderCenter, radius: renderRadius },
|
|
3531
3609
|
stateColorLUT: themeSeatColorLUT(theme, SEAT_STATES),
|
|
3532
3610
|
theme,
|