bruce-cesium 7.5.9 → 7.6.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.
@@ -89,7 +89,7 @@ __exportStar(require("./widgets/widget-info-view"), exports);
89
89
  __exportStar(require("./widgets/widget-left-panel"), exports);
90
90
  __exportStar(require("./widgets/widget-nav-compass"), exports);
91
91
  __exportStar(require("./widgets/widget-view-bar"), exports);
92
- exports.VERSION = "7.5.9";
92
+ exports.VERSION = "7.6.1";
93
93
  /**
94
94
  * Updates the environment instance used by bruce-cesium to one specified.
95
95
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
@@ -953,6 +953,22 @@ var EntityLabel;
953
953
  return centre && half && (axes === null || axes === void 0 ? void 0 : axes.every(Boolean)) ? { centre, axes, half } : null;
954
954
  }
955
955
  EntityLabel.ReadOrientedBox = ReadOrientedBox;
956
+ /*
957
+ * Whether a placement turns what it places. Scale alone does not count.
958
+ */
959
+ function isRotated(matrix) {
960
+ for (let column = 0; column < 3; column++) {
961
+ const axis = [0, 1, 2].map(row => Number(matrix[row][column]));
962
+ const length = Math.hypot(...axis);
963
+ if (!(length > 0)) {
964
+ return false;
965
+ }
966
+ if (axis.some((value, row) => Math.abs(value / length - Number(row === column)) > 1e-5)) {
967
+ return true;
968
+ }
969
+ }
970
+ return false;
971
+ }
956
972
  /*
957
973
  * The eight padded world corners of an assembly Entity's geometry box, or null when the record cannot give one.
958
974
  *
@@ -971,6 +987,10 @@ var EntityLabel;
971
987
  if ((matrix === null || matrix === void 0 ? void 0 : matrix.length) !== 4 || !matrix.every(row => (row === null || row === void 0 ? void 0 : row.length) === 4) || !Number.isFinite(+(root === null || root === void 0 ? void 0 : root.latitude)) || !Number.isFinite(+(root === null || root === void 0 ? void 0 : root.longitude))) {
972
988
  return null;
973
989
  }
990
+ // A pure translation can hide a rotation baked into the vertices, which leaves the extents loose.
991
+ if (!shape && !isRotated(matrix)) {
992
+ return null;
993
+ }
974
994
  const pivot = ((_c = bruce.GeometryPivot) === null || _c === void 0 ? void 0 : _c.length) >= 3 ? bruce.GeometryPivot.slice(0, 3).map(Number) : [0, 0, 0];
975
995
  // Without an oriented box the record's own extents are an axis-aligned box about the pivot.
976
996
  const box = shape || { centre: pivot, axes: [[1, 0, 0], [0, 1, 0], [0, 0, 1]], half: half };
@@ -2421,6 +2441,22 @@ var EntityLabel;
2421
2441
  radius: Math.max(width, height) / 2
2422
2442
  };
2423
2443
  };
2444
+ /*
2445
+ * The on-screen centre and half-size of a model too small for its box, so the box is ringed like a glyph.
2446
+ */
2447
+ const measureModel = (anchor) => {
2448
+ const hull = layer.modelBoxes.Hull(this.id);
2449
+ if (!(hull === null || hull === void 0 ? void 0 : hull.length)) {
2450
+ return null;
2451
+ }
2452
+ const xs = hull.map(point => point.x), ys = hull.map(point => point.y);
2453
+ const left = Math.min(...xs), top = Math.min(...ys);
2454
+ const width = Math.max(...xs) - left, height = Math.max(...ys) - top;
2455
+ if (Math.max(width, height) >= MODEL_BOX_MIN_SIZE) {
2456
+ return null;
2457
+ }
2458
+ return { x: left + width / 2 - anchor.x, y: top + height / 2 - anchor.y, radius: Math.max(width, height) / 2 };
2459
+ };
2424
2460
  // Only CAD tilesets and model Entities are assembly parts with a geometry box; anything else stays a point.
2425
2461
  const boxable = Boolean(normalLeader && ((_r = this.rego) === null || _r === void 0 ? void 0 : _r.entityId) && ((visual instanceof Cesium.Cesium3DTileFeature && this.rego.tilesetType === bruce_models_1.Tileset.EType.Cad) ||
2426
2462
  (visual instanceof Cesium.Entity && Boolean(visual.model))));
@@ -2479,7 +2515,7 @@ var EntityLabel;
2479
2515
  }
2480
2516
  let cursorMotion = this.cursorMotion;
2481
2517
  const project = () => {
2482
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
2518
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
2483
2519
  if (this.disposed || !this.viewer || this.viewer.isDestroyed() || ((_a = this.visible) === null || _a === void 0 ? void 0 : _a.call(this)) === false ||
2484
2520
  (presentation === "icon" && this.options.iconScale === 0)) {
2485
2521
  return null;
@@ -2522,7 +2558,8 @@ var EntityLabel;
2522
2558
  const boxBlend = this.morphToBox(boxed, shownOnce ? (_f = (_e = this.options.anchorRing) === null || _e === void 0 ? void 0 : _e.transitionDuration) !== null && _f !== void 0 ? _f : 200 : 0);
2523
2559
  // Eased between the ring and where the stem meets the box, so gaining or losing a box never jumps.
2524
2560
  const boxTarget = this.boxMorph.anchor;
2525
- const ringPoint = { x: anchor.x + pixelOffset.x, y: anchor.y + pixelOffset.y };
2561
+ const model = ((_g = this.modelBox) === null || _g === void 0 ? void 0 : _g.corners) ? measureModel(anchor) : null;
2562
+ const ringPoint = { x: anchor.x + (model || pixelOffset).x, y: anchor.y + (model || pixelOffset).y };
2526
2563
  const boxAnchor = boxBlend > 0 && boxTarget ? {
2527
2564
  x: ringPoint.x + (boxTarget.x - ringPoint.x) * boxBlend,
2528
2565
  y: ringPoint.y + (boxTarget.y - ringPoint.y) * boxBlend
@@ -2533,13 +2570,13 @@ var EntityLabel;
2533
2570
  return null;
2534
2571
  if (onScreen && !this.imageAsked && this.groupId && !HasIcon(this.options) && !this.options.photo) {
2535
2572
  this.imageAsked = true;
2536
- (_g = this.visualRegister) === null || _g === void 0 ? void 0 : _g.RequestLabelImage((_h = this.rego) === null || _h === void 0 ? void 0 : _h.entityId);
2573
+ (_h = this.visualRegister) === null || _h === void 0 ? void 0 : _h.RequestLabelImage((_j = this.rego) === null || _j === void 0 ? void 0 : _j.entityId);
2537
2574
  }
2538
2575
  const transientPivot = (this.Transient && !this.Persistent ?
2539
- (this.hoverFade.to === 0 ? this.retainedHoverPosition : (_j = this.visualRegister) === null || _j === void 0 ? void 0 : _j.GetLabelHoverPosition((_k = this.rego) === null || _k === void 0 ? void 0 : _k.entityId, (_l = this.rego) === null || _l === void 0 ? void 0 : _l.menuItemId)) : undefined);
2576
+ (this.hoverFade.to === 0 ? this.retainedHoverPosition : (_k = this.visualRegister) === null || _k === void 0 ? void 0 : _k.GetLabelHoverPosition((_l = this.rego) === null || _l === void 0 ? void 0 : _l.entityId, (_m = this.rego) === null || _m === void 0 ? void 0 : _m.menuItemId)) : undefined);
2540
2577
  const hover = (presentation !== "icon" ?
2541
2578
  (this.Transient && !this.Persistent && this.hoverFade.to === 0 ? this.retainedHoverPosition :
2542
- (_m = this.visualRegister) === null || _m === void 0 ? void 0 : _m.GetLabelHoverPosition((_o = this.rego) === null || _o === void 0 ? void 0 : _o.entityId, (_p = this.rego) === null || _p === void 0 ? void 0 : _p.menuItemId)) : undefined);
2579
+ (_o = this.visualRegister) === null || _o === void 0 ? void 0 : _o.GetLabelHoverPosition((_p = this.rego) === null || _p === void 0 ? void 0 : _p.entityId, (_q = this.rego) === null || _q === void 0 ? void 0 : _q.menuItemId)) : undefined);
2543
2580
  const reused = !this.Transient || this.Persistent;
2544
2581
  const now = Date.now();
2545
2582
  const animateCursor = () => {
@@ -2566,13 +2603,13 @@ var EntityLabel;
2566
2603
  const cursorAmount = cursorMotion.amount;
2567
2604
  leader = normalLeader || cursorAmount > 0;
2568
2605
  // An icon keeps its callout centred on the glyph rather than following the cursor across it.
2569
- const icon = boxAnchor ? null : measureIcon();
2606
+ const icon = boxAnchor ? null : measureIcon() || model;
2570
2607
  const iconRing = icon ? Math.max(ICON_RING_MIN, icon.radius + ICON_RING_PADDING) : 0;
2571
2608
  // A boxed model is pinned the same way, with its stem leaving the top of the box outline.
2572
2609
  const pinned = Boolean(icon || boxAnchor);
2573
2610
  const pivot = pinned ? undefined : transientPivot;
2574
- let x = boxAnchor ? boxAnchor.x : ((_q = pivot === null || pivot === void 0 ? void 0 : pivot.x) !== null && _q !== void 0 ? _q : anchor.x) + (icon || pixelOffset).x;
2575
- let y = boxAnchor ? boxAnchor.y : ((_r = pivot === null || pivot === void 0 ? void 0 : pivot.y) !== null && _r !== void 0 ? _r : anchor.y) + (icon || pixelOffset).y;
2611
+ let x = boxAnchor ? boxAnchor.x : ((_r = pivot === null || pivot === void 0 ? void 0 : pivot.x) !== null && _r !== void 0 ? _r : anchor.x) + (icon || pixelOffset).x;
2612
+ let y = boxAnchor ? boxAnchor.y : ((_s = pivot === null || pivot === void 0 ? void 0 : pivot.y) !== null && _s !== void 0 ? _s : anchor.y) + (icon || pixelOffset).y;
2576
2613
  if (cursorAmount > 0 && !pinned) {
2577
2614
  // A leader-less label starts centred on its anchor; preserve that box as it lifts away.
2578
2615
  if (!normalLeader) {
@@ -2628,7 +2665,7 @@ var EntityLabel;
2628
2665
  const width = ele.offsetWidth / coordinates.scaleX;
2629
2666
  const height = ele.offsetHeight / coordinates.scaleY;
2630
2667
  let clusterBounds;
2631
- if ((_s = this.options.cluster) === null || _s === void 0 ? void 0 : _s.enabled) {
2668
+ if ((_t = this.options.cluster) === null || _t === void 0 ? void 0 : _t.enabled) {
2632
2669
  const textWidth = (sourceText === null || sourceText === void 0 ? void 0 : sourceText.offsetWidth) || 0;
2633
2670
  const textHeight = (sourceText === null || sourceText === void 0 ? void 0 : sourceText.offsetHeight) || 0;
2634
2671
  // A photo is never part of the footprint, so its arrival cannot change which cluster a label joins.
@@ -2662,7 +2699,7 @@ var EntityLabel;
2662
2699
  if (!leader && (bounds.x + bounds.width < 0 || bounds.y + bounds.height < 0 || bounds.x > this.viewer.canvas.clientWidth || bounds.y > this.viewer.canvas.clientHeight)) {
2663
2700
  return null;
2664
2701
  }
2665
- const state = (_t = this.visualRegister) === null || _t === void 0 ? void 0 : _t.GetState({ entityId: (_u = this.rego) === null || _u === void 0 ? void 0 : _u.entityId, menuItemId: (_v = this.rego) === null || _v === void 0 ? void 0 : _v.menuItemId });
2702
+ const state = (_u = this.visualRegister) === null || _u === void 0 ? void 0 : _u.GetState({ entityId: (_v = this.rego) === null || _v === void 0 ? void 0 : _v.entityId, menuItemId: (_w = this.rego) === null || _w === void 0 ? void 0 : _w.menuItemId });
2666
2703
  const opacity = this.prePositioned || hoverOnly || MAX_DISTANCE === Infinity ? 1 : 1 - distance / MAX_DISTANCE;
2667
2704
  return {
2668
2705
  canFlip: leader && presentation !== "icon", hasLeader: leader,
@@ -2670,9 +2707,9 @@ var EntityLabel;
2670
2707
  transient: this.Transient || Boolean(hover) || cursorAmount > 0,
2671
2708
  extendedGeometry: visual instanceof Cesium.Entity && Boolean(visual.polygon || visual.polyline || visual.corridor),
2672
2709
  viewportWidth: this.viewer.canvas.clientWidth,
2673
- id: this.id, entityKey: ((_w = this.rego) === null || _w === void 0 ? void 0 : _w.entityId) ? JSON.stringify([this.rego.entityId, this.rego.menuItemId || "", this.Transient && !this.Persistent ? "hover" : ""]) : undefined,
2674
- entityId: (_x = this.rego) === null || _x === void 0 ? void 0 : _x.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, leaderRun, leaderSide, distance,
2675
- iconRadius: icon === null || icon === void 0 ? void 0 : icon.radius, modelBox: boxed || undefined, boxBlend,
2710
+ id: this.id, entityKey: ((_x = this.rego) === null || _x === void 0 ? void 0 : _x.entityId) ? JSON.stringify([this.rego.entityId, this.rego.menuItemId || "", this.Transient && !this.Persistent ? "hover" : ""]) : undefined,
2711
+ entityId: (_y = this.rego) === null || _y === void 0 ? void 0 : _y.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, leaderRun, leaderSide, distance,
2712
+ iconRadius: icon === null || icon === void 0 ? void 0 : icon.radius, modelBox: boxed || undefined, boxBlend, follows: !pinned && Boolean(transientPivot || cursorMotion.target),
2676
2713
  // Priority shows the hovered member individually without dragging its cluster along.
2677
2714
  opacity: waiting ? 0 : opacity, priority: hover || cursorAmount > 0 || (state === null || state === void 0 ? void 0 : state.highlighted) ? 1 : 0, options: this.options, text: originalText, clusterBounds
2678
2715
  };
@@ -2799,15 +2836,16 @@ var EntityLabel;
2799
2836
  const normalRadius = (!leader || (ring === null || ring === void 0 ? void 0 : ring.enabled) === false ? 0 : Math.max(frame.distance <= ((_l = ring === null || ring === void 0 ? void 0 : ring.nearDistance) !== null && _l !== void 0 ? _l : 100) ? ((_m = ring === null || ring === void 0 ? void 0 : ring.nearRadius) !== null && _m !== void 0 ? _m : 10) : 0, hovered ? ((_o = ring === null || ring === void 0 ? void 0 : ring.hoverRadius) !== null && _o !== void 0 ? _o : (this.Transient && !this.Persistent ? 15.4 : 22)) : 0));
2800
2837
  const targetRadius = normalRadius + (15.4 - normalRadius) * cursorMotion.amount;
2801
2838
  // Around a glyph the ring keeps the glyph's size and only fades its stroke in, so it never covers the icon.
2802
- const targetOuter = iconRing || targetRadius || 2.5;
2803
- const targetInner = iconRing ? (targetRadius > 0 ? iconRing - 2 : iconRing) : Math.max(0, targetRadius - 2);
2839
+ // A ring around the cursor marks nothing, so a riding label keeps only its leader.
2840
+ const targetOuter = frame.follows ? 0 : iconRing || targetRadius || 2.5;
2841
+ const targetInner = frame.follows ? 0 : iconRing ? (targetRadius > 0 ? iconRing - 2 : iconRing) : Math.max(0, targetRadius - 2);
2804
2842
  const now = Date.now();
2805
2843
  const duration = (_p = ring === null || ring === void 0 ? void 0 : ring.transitionDuration) !== null && _p !== void 0 ? _p : 200;
2806
2844
  const sharedRing = this.Transient && !this.Persistent && this.hoverFade.to === 1 ? this.hoverRingState : undefined;
2807
2845
  let ringAnimation = sharedRing ? sharedRing.animation : this.ringAnimation;
2808
2846
  if (!ringAnimation) {
2809
- const outer = iconRing || 2.5;
2810
- const inner = iconRing;
2847
+ const outer = frame.follows ? 0 : iconRing || 2.5;
2848
+ const inner = frame.follows ? 0 : iconRing;
2811
2849
  ringAnimation = { target: outer, targetInner: inner, start: now, outer, inner, fromOuter: outer, fromInner: inner };
2812
2850
  }
2813
2851
  ;