bruce-cesium 7.2.7 → 7.2.9

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.
@@ -1,6 +1,6 @@
1
1
  import * as Cesium from 'cesium';
2
- import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, ShaderSource, Cartesian3, Math as Math$1, Ellipsoid, Transforms, Matrix4, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, Cartesian2, DistanceDisplayCondition, ClassificationType, ArcType, HeightReference, CornerType, ShadowMode, ConstantPositionProperty, JulianDate, Quaternion, HeadingPitchRoll, ColorBlendMode, Model, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, HorizontalOrigin, VerticalOrigin, NearFarScalar, Matrix3, KmlDataSource, SceneMode, GeoJsonDataSource, Cesium3DTileStyle, HeadingPitchRange, Ion, Cesium3DTileColorBlendMode, IonResource, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, OrthographicFrustum, EasingFunction, Intersect, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, CustomDataSource, ScreenSpaceEventHandler, ScreenSpaceEventType, GeometryInstance, Fullscreen, CzmlDataSource } from 'cesium';
3
- import { Cartes, Entity as Entity$1, ProjectViewTile, ENVIRONMENT, Calculator, Carto, EntityTag, EntityType, Geometry as Geometry$1, ObjectUtils, Style, ClientFile, EntityLod, LRUCache, Bounds, Color as Color$1, Api, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DelayQueue, DataLab, EntityRelation, BruceApi, AccountConcept, RecordChangeFeed, EntitySource, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, ProjectViewBookmarkGroup, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType, EntityHistoricData } from 'bruce-models';
2
+ import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, DistanceDisplayCondition, ShaderSource, Cartesian3, Math as Math$1, Ellipsoid, Transforms, Matrix4, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, Cartesian2, JulianDate, Quaternion, HeadingPitchRoll, HeightReference, ColorBlendMode, ShadowMode, ClassificationType, Model, ArcType, CornerType, ConstantPositionProperty, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, HorizontalOrigin, VerticalOrigin, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Ion, IonResource, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, Intersect, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, PolygonPipeline, CustomDataSource, GeometryInstance, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
3
+ import { Cartes, Entity as Entity$1, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, EntityLod, EntityTag, EntityType, LRUCache, ObjectUtils, Style, Carto, Geometry as Geometry$1, Bounds, ClientFileValueMap, Color as Color$1, Api, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DelayQueue, DataLab, EntityRelation, BruceApi, AccountConcept, RecordChangeFeed, EntitySource, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType, EntityHistoricData } from 'bruce-models';
4
4
 
5
5
  /**
6
6
  * Ensures a number is returned from a given value.
@@ -40717,61 +40717,27 @@ function loadImage(src) {
40717
40717
 
40718
40718
  var TextureFrameSeriesAnimator;
40719
40719
  (function (TextureFrameSeriesAnimator) {
40720
- TextureFrameSeriesAnimator.LAYOUT_TILES = "tiles";
40721
- // The only generation this renderer draws. Anything else is refused rather than half read: the
40722
- // shapes differ enough that a partial reading produces a plausible wrong surface, which is worse
40723
- // than an empty one.
40724
- TextureFrameSeriesAnimator.SUPPORTED_VERSION = 3;
40725
- // Value in R at 8 bits, or high in R and low in G at 16.
40726
- TextureFrameSeriesAnimator.FORMAT_U8 = "u8";
40727
- TextureFrameSeriesAnimator.FORMAT_RG16 = "rg16";
40728
- // Declared as a field with one value, so a second mode can be added later without an absent
40729
- // Encoding having to mean anything.
40730
- TextureFrameSeriesAnimator.ENCODING_ABSOLUTE = "absolute";
40731
- TextureFrameSeriesAnimator.LAYER_VALUE = "Value";
40732
- TextureFrameSeriesAnimator.LAYER_VALUE_MIN = "ValueMin";
40733
- TextureFrameSeriesAnimator.LAYER_VALUE_MAX = "ValueMax";
40734
- TextureFrameSeriesAnimator.LAYER_BASELINE = "Baseline";
40735
- // The per-texel correction that was applied, published only on an archive that was transformed.
40736
- TextureFrameSeriesAnimator.LAYER_VALUE_SHIFT = "ValueShift";
40737
40720
  /**
40738
40721
  * Turns a published value map into the flat shape this renderer works in, or null when it cannot be drawn.
40739
40722
  * @param published the archive's Data.generation
40740
40723
  */
40741
40724
  function Adapt(published) {
40742
- if (!published || published.Version !== TextureFrameSeriesAnimator.SUPPORTED_VERSION) {
40743
- const found = published && published.Version != null ? published.Version : "none";
40744
- const at = published && published.Identity ? published.Identity.Generated : undefined;
40745
- // In theory should be no files.
40746
- console.warn("bruce-cesium: value map version " + found + " is not supported (this build reads "
40747
- + TextureFrameSeriesAnimator.SUPPORTED_VERSION + "), so nothing will be drawn for it."
40748
- + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40725
+ const refused = ClientFileValueMap.Metadata.Unreadable(published);
40726
+ if (refused) {
40727
+ console.warn("bruce-cesium: " + refused + " Nothing will be drawn for it.");
40749
40728
  return null;
40750
40729
  }
40751
40730
  const geometry = published.Geometry || {};
40752
- const tiles = published.Tiles || [];
40753
- if (geometry.Layout !== TextureFrameSeriesAnimator.LAYOUT_TILES || tiles.length === 0) {
40754
- const at = published.Identity ? published.Identity.Generated : undefined;
40755
- console.warn("bruce-cesium: value map declares no tiles, so nothing will be drawn for it."
40756
- + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40757
- return null;
40758
- }
40759
40731
  const value = published.Value || {};
40760
- if (value.Encoding && value.Encoding !== TextureFrameSeriesAnimator.ENCODING_ABSOLUTE) {
40761
- const at = published.Identity ? published.Identity.Generated : undefined;
40762
- console.warn("bruce-cesium: value map encoding " + value.Encoding + " is not supported"
40763
- + " (this build reads " + TextureFrameSeriesAnimator.ENCODING_ABSOLUTE + "), so nothing will be drawn for it."
40764
- + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40765
- return null;
40766
- }
40767
40732
  const series = published.Series || {};
40768
- const layerRange = declaredRange(published, TextureFrameSeriesAnimator.LAYER_VALUE_MIN);
40733
+ const layerRange = ClientFileValueMap.Metadata.LayerRange(published, ClientFileValueMap.Metadata.LAYER_VALUE_MIN);
40734
+ const tiles = ClientFileValueMap.Metadata.TilesOf(published);
40769
40735
  const flat = {
40770
40736
  Frames: [],
40771
40737
  ValueMin: value.Min,
40772
40738
  ValueMax: value.Max,
40773
- Format: value.Format || TextureFrameSeriesAnimator.FORMAT_U8,
40774
- Encoding: value.Encoding || TextureFrameSeriesAnimator.ENCODING_ABSOLUTE,
40739
+ Format: value.Format || ClientFileValueMap.Metadata.FORMAT_U8,
40740
+ Encoding: value.Encoding || ClientFileValueMap.Metadata.ENCODING_ABSOLUTE,
40775
40741
  Units: value.Units,
40776
40742
  West: geometry.West,
40777
40743
  East: geometry.East,
@@ -40781,8 +40747,8 @@ var TextureFrameSeriesAnimator;
40781
40747
  ResolutionY: geometry.ResolutionY,
40782
40748
  PixelPlacement: geometry.PixelPlacement,
40783
40749
  Times: series.Times,
40784
- ExtremesValueMin: layerRange ? layerRange.min : undefined,
40785
- ExtremesValueMax: layerRange ? layerRange.max : undefined,
40750
+ ExtremesValueMin: layerRange ? layerRange.Min : undefined,
40751
+ ExtremesValueMax: layerRange ? layerRange.Max : undefined,
40786
40752
  // The delivered values are what gets drawn. What the source called them, and any shift
40787
40753
  // applied on the way, travel for labels and analysis rather than for placement.
40788
40754
  SourceVerticalDatum: published.ValueSource ? published.ValueSource.VerticalDatum : undefined,
@@ -40792,50 +40758,35 @@ var TextureFrameSeriesAnimator;
40792
40758
  SourceValueMax: published.ValueSource ? published.ValueSource.Max : undefined
40793
40759
  };
40794
40760
  flat.Tiles = tiles.map((tile) => adaptTile(tile, series.Times));
40795
- // The coarsest tile covers the whole extent, so it is what a caller wanting one time list reads.
40761
+ // The tiles arrive coarsest first, so the first one covers the whole extent and is what a
40762
+ // caller wanting one time list reads.
40796
40763
  flat.Frames = flat.Tiles[0].Frames;
40797
- warnIfUnshifted(published, flat);
40764
+ warnIfUnshifted(published);
40798
40765
  return flat;
40799
40766
  }
40800
40767
  TextureFrameSeriesAnimator.Adapt = Adapt;
40801
40768
  /*
40802
40769
  * Says so when an archive's heights are not on the ellipsoid they will be drawn against.
40803
40770
  */
40804
- function warnIfUnshifted(published, flat) {
40805
- const datum = flat.SourceVerticalDatum;
40806
- if (!datum || datum === TextureFrameSeriesAnimator.DATUM_ELLIPSOIDAL || flat.Transform) {
40807
- return;
40771
+ function warnIfUnshifted(published) {
40772
+ const said = ClientFileValueMap.Metadata.UnshiftedWarning(published);
40773
+ if (said) {
40774
+ console.warn("bruce-cesium: " + said);
40808
40775
  }
40809
- const at = published.Identity ? published.Identity.Generated : undefined;
40810
- console.warn("bruce-cesium: value map heights are in " + datum + " and report no transform, so"
40811
- + " they are not ellipsoidal and will draw at the wrong height when placed absolutely."
40812
- + (at ? " The archive was generated at " + at + " and needs regenerating with the shift"
40813
- + " applied." : ""));
40814
- }
40815
- /*
40816
- * The Min and Max a named layer declares, since a statistics layer is encoded over the true data
40817
- * range rather than over the frames' own.
40818
- */
40819
- function declaredRange(published, name) {
40820
- const layers = published.Layers || [];
40821
- for (const layer of layers) {
40822
- if (layer.Name === name && typeof layer.Min === "number" && typeof layer.Max === "number") {
40823
- return { min: layer.Min, max: layer.Max };
40824
- }
40825
- }
40826
- return null;
40827
40776
  }
40828
40777
  /*
40829
40778
  * One tile, with its per-time value rasters lined up against the shared time list.
40830
40779
  */
40831
40780
  function adaptTile(tile, times) {
40832
- const layers = tile.Layers || {};
40833
- const perTime = layers[TextureFrameSeriesAnimator.LAYER_VALUE] || [];
40834
- const frames = perTime.map((entry, index) => ({
40835
- Timestamp: times && times[index] ? times[index] : "",
40836
- ByteOffset: entry.Bytes.Offset,
40837
- ByteLength: entry.Bytes.Length
40838
- }));
40781
+ const perTime = (tile.Layers && tile.Layers[ClientFileValueMap.Metadata.LAYER_VALUE]) || [];
40782
+ const frames = perTime.map((_entry, index) => {
40783
+ const at = ClientFileValueMap.Metadata.BytesOf(tile, ClientFileValueMap.Metadata.LAYER_VALUE, index);
40784
+ return {
40785
+ Timestamp: times && times[index] ? times[index] : "",
40786
+ ByteOffset: at ? at.Offset : 0,
40787
+ ByteLength: at ? at.Length : 0
40788
+ };
40789
+ });
40839
40790
  return {
40840
40791
  Level: tile.Level,
40841
40792
  X: tile.X,
@@ -40848,16 +40799,17 @@ var TextureFrameSeriesAnimator;
40848
40799
  ResolutionX: tile.ResolutionX,
40849
40800
  ResolutionY: tile.ResolutionY,
40850
40801
  Frames: frames,
40851
- Floor: single(layers[TextureFrameSeriesAnimator.LAYER_VALUE_MIN]),
40852
- Ceiling: single(layers[TextureFrameSeriesAnimator.LAYER_VALUE_MAX]),
40853
- BaselineMask: single(layers[TextureFrameSeriesAnimator.LAYER_BASELINE])
40802
+ Floor: entryFor(tile, ClientFileValueMap.Metadata.LAYER_VALUE_MIN),
40803
+ Ceiling: entryFor(tile, ClientFileValueMap.Metadata.LAYER_VALUE_MAX),
40804
+ BaselineMask: entryFor(tile, ClientFileValueMap.Metadata.LAYER_BASELINE)
40854
40805
  };
40855
40806
  }
40856
- function single(layer) {
40857
- if (!layer || !layer.Bytes) {
40858
- return undefined;
40859
- }
40860
- return { ByteOffset: layer.Bytes.Offset, ByteLength: layer.Bytes.Length };
40807
+ /*
40808
+ * One tile's single copy of a layer, in the byte shape this renderer's fetching works in.
40809
+ */
40810
+ function entryFor(tile, name) {
40811
+ const at = ClientFileValueMap.Metadata.BytesOf(tile, name);
40812
+ return at ? { ByteOffset: at.Offset, ByteLength: at.Length } : undefined;
40861
40813
  }
40862
40814
  /**
40863
40815
  * How to turn a delivered value into the number the source published, or null when the archive
@@ -40903,7 +40855,7 @@ var TextureFrameSeriesAnimator;
40903
40855
  * @param metadata the archive's Data.generation
40904
40856
  */
40905
40857
  function IsPackedValue(metadata) {
40906
- return Boolean(metadata && metadata.Format === TextureFrameSeriesAnimator.FORMAT_RG16);
40858
+ return Boolean(metadata) && ClientFileValueMap.Metadata.IsPacked({ Value: { Format: metadata.Format } });
40907
40859
  }
40908
40860
  TextureFrameSeriesAnimator.IsPackedValue = IsPackedValue;
40909
40861
  /**
@@ -40913,10 +40865,7 @@ var TextureFrameSeriesAnimator;
40913
40865
  * @param at index of the texel's red channel
40914
40866
  */
40915
40867
  function NormalisedAt(metadata, pixels, at) {
40916
- if (IsPackedValue(metadata)) {
40917
- return (pixels[at] * 256 + pixels[at + 1]) / 65535;
40918
- }
40919
- return pixels[at] / 255;
40868
+ return ClientFileValueMap.Metadata.NormalisedAt(pixels, at, IsPackedValue(metadata) ? ClientFileValueMap.Metadata.FORMAT_RG16 : ClientFileValueMap.Metadata.FORMAT_U8);
40920
40869
  }
40921
40870
  TextureFrameSeriesAnimator.NormalisedAt = NormalisedAt;
40922
40871
  // Values already sit on the ellipsoid Cesium measures against, so nothing is added to place them.
@@ -40949,13 +40898,10 @@ var TextureFrameSeriesAnimator;
40949
40898
  * @param value in the attribute's units
40950
40899
  */
40951
40900
  function NormalisePosition(metadata, value) {
40952
- const lo = metadata && typeof metadata.ValueMin === "number" ? metadata.ValueMin : 0;
40953
- const hi = metadata && typeof metadata.ValueMax === "number" ? metadata.ValueMax : 1;
40954
- const span = hi - lo;
40955
- if (!(span > 0)) {
40956
- return 0;
40957
- }
40958
- return Math.min(1, Math.max(0, (value - lo) / span));
40901
+ return ClientFileValueMap.Metadata.Normalise(value, {
40902
+ Min: metadata && typeof metadata.ValueMin === "number" ? metadata.ValueMin : 0,
40903
+ Max: metadata && typeof metadata.ValueMax === "number" ? metadata.ValueMax : 1
40904
+ });
40959
40905
  }
40960
40906
  TextureFrameSeriesAnimator.NormalisePosition = NormalisePosition;
40961
40907
  /**
@@ -41433,27 +41379,8 @@ var TextureFrameSeriesAnimator;
41433
41379
  * Composite resolution, capped by what can be uploaded as a texture every frame.
41434
41380
  */
41435
41381
  compositeSize(tiles, target) {
41436
- let finest = Number.MAX_VALUE;
41437
- for (const tile of tiles) {
41438
- if (tile.TexelMetres > 0) {
41439
- finest = Math.min(finest, tile.TexelMetres);
41440
- }
41441
- }
41442
- if (!(finest > 0) || finest === Number.MAX_VALUE) {
41443
- finest = 1;
41444
- }
41445
- const mid = (target.South + target.North) / 2 * Math.PI / 180;
41446
- const widthM = Math.max((target.East - target.West) * 111320 * Math.cos(mid), 1);
41447
- const heightM = Math.max((target.North - target.South) * 110574, 1);
41448
- let width = Math.ceil(widthM / finest);
41449
- let height = Math.ceil(heightM / finest);
41450
- const longest = Math.max(width, height);
41451
- if (longest > MAX_COMPOSITE_TEXELS) {
41452
- const shrink = MAX_COMPOSITE_TEXELS / longest;
41453
- width = Math.max(1, Math.round(width * shrink));
41454
- height = Math.max(1, Math.round(height * shrink));
41455
- }
41456
- return { width: Math.max(1, width), height: Math.max(1, height) };
41382
+ const size = ClientFileValueMap.Grid.CompositeSize(tiles, target, MAX_COMPOSITE_TEXELS);
41383
+ return { width: size.Width, height: size.Height };
41457
41384
  }
41458
41385
  /*
41459
41386
  * Applies the ramp, borders and baseline mask to raw value pixels, whatever produced them.
@@ -41577,20 +41504,20 @@ var TextureFrameSeriesAnimator;
41577
41504
  const size = this.compositeSize(tiles, target);
41578
41505
  // One request for the whole extremes block. They sit contiguously after the frames, so
41579
41506
  // fetching per tile would be 164 round trips for an 82 tile pyramid.
41580
- let lo = Number.MAX_SAFE_INTEGER;
41581
- let hi = 0;
41507
+ const ranges = [];
41582
41508
  for (const tile of tiles) {
41583
41509
  for (const at of [tile.Floor, tile.Ceiling]) {
41584
- if (!at) {
41585
- continue;
41510
+ if (at) {
41511
+ ranges.push({ Offset: at.ByteOffset, Length: at.ByteLength });
41586
41512
  }
41587
- lo = Math.min(lo, at.ByteOffset);
41588
- hi = Math.max(hi, at.ByteOffset + at.ByteLength);
41589
41513
  }
41590
41514
  }
41591
- if (!(hi > lo)) {
41515
+ const span = ClientFileValueMap.Metadata.SpanOf(ranges);
41516
+ if (!span) {
41592
41517
  return;
41593
41518
  }
41519
+ const lo = span.Offset;
41520
+ const hi = span.Offset + span.Length;
41594
41521
  const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${lo}-${hi - 1}` } });
41595
41522
  const block = await response.arrayBuffer();
41596
41523
  if (this.disposed) {
@@ -41635,13 +41562,8 @@ var TextureFrameSeriesAnimator;
41635
41562
  * background shows between them.
41636
41563
  */
41637
41564
  tileRect(tile, target, size) {
41638
- const spanLon = target.East - target.West;
41639
- const spanLat = target.North - target.South;
41640
- const x0 = Math.round((tile.West - target.West) / spanLon * size.width);
41641
- const x1 = Math.round((tile.East - target.West) / spanLon * size.width);
41642
- const y0 = Math.round((target.North - tile.North) / spanLat * size.height);
41643
- const y1 = Math.round((target.North - tile.South) / spanLat * size.height);
41644
- return { x: x0, y: y0, w: Math.max(1, x1 - x0), h: Math.max(1, y1 - y0) };
41565
+ const rect = ClientFileValueMap.Grid.TileRect(tile, target, { Width: size.width, Height: size.height });
41566
+ return { x: rect.Left, y: rect.Top, w: rect.Width, h: rect.Height };
41645
41567
  }
41646
41568
  /*
41647
41569
  * Decodes many tile images at once.
@@ -42546,7 +42468,7 @@ var TextureValueLabels;
42546
42468
  var DisplacedSurfacePrimitive;
42547
42469
  (function (DisplacedSurfacePrimitive) {
42548
42470
  // Grid densities a tile can draw at, coarsest first.
42549
- const TIERS = [32, 64, 128, 192];
42471
+ const TIERS = [32, 64, 128, 192, 256, 384];
42550
42472
  // Tiles per side the extent is cut into.
42551
42473
  const TILES_PER_SIDE = 6;
42552
42474
  // Screen pixels one grid cell should cover. Lower means finer meshes sooner.
@@ -43194,6 +43116,7 @@ void main() {
43194
43116
  const camera = frameState.camera;
43195
43117
  const fovy = camera.frustum && camera.frustum.fovy ? camera.frustum.fovy : Math$1.PI_OVER_THREE;
43196
43118
  const pixelsPerRadian = frameState.context.drawingBufferHeight / fovy;
43119
+ const ceiling = this.tierCeiling();
43197
43120
  for (const tile of this.tiles) {
43198
43121
  if (!tile.centre) {
43199
43122
  tile.tier = TIERS[0];
@@ -43204,13 +43127,33 @@ void main() {
43204
43127
  const wanted = screenPixels / TARGET_CELL_PIXELS;
43205
43128
  let tier = TIERS[0];
43206
43129
  for (const candidate of TIERS) {
43207
- if (candidate <= wanted) {
43130
+ if (candidate <= wanted && candidate <= ceiling) {
43208
43131
  tier = candidate;
43209
43132
  }
43210
43133
  }
43211
43134
  tile.tier = tier;
43212
43135
  }
43213
43136
  }
43137
+ /*
43138
+ * The finest tier worth drawing for this surface, from the texture behind it.
43139
+ *
43140
+ * Subdividing past one vertex per texel spends vertices resolving detail the source does not
43141
+ * carry, so the ladder is capped one step above the texel count rather than run to its top.
43142
+ */
43143
+ tierCeiling() {
43144
+ const source = this.source;
43145
+ if (!source || !source.width || !source.height) {
43146
+ return TIERS[TIERS.length - 1];
43147
+ }
43148
+ const perSide = Math.sqrt(this.tiles.length) || TILES_PER_SIDE;
43149
+ const texelsPerTile = Math.max(source.width, source.height) / perSide;
43150
+ for (const candidate of TIERS) {
43151
+ if (candidate >= texelsPerTile) {
43152
+ return candidate;
43153
+ }
43154
+ }
43155
+ return TIERS[TIERS.length - 1];
43156
+ }
43214
43157
  shouldReselect(frameState, nowMs) {
43215
43158
  if (this.selectionDirty) {
43216
43159
  return true;
@@ -43223,9 +43166,23 @@ void main() {
43223
43166
  return true;
43224
43167
  }
43225
43168
  const moved = Cartesian3.distance(eye, this.lastEyePosition);
43226
- const anchor = this.tiles[0].centre;
43227
- const reference = anchor ? Math.max(1, Cartesian3.distance(eye, anchor)) : 1;
43228
- return moved / reference > MOVEMENT_THRESHOLD;
43169
+ return moved / this.nearestTileDistance(eye) > MOVEMENT_THRESHOLD;
43170
+ }
43171
+ /*
43172
+ * Distance to the closest tile, measured the way selectTiers measures each one.
43173
+ */
43174
+ nearestTileDistance(eye) {
43175
+ let nearest = Number.POSITIVE_INFINITY;
43176
+ for (const tile of this.tiles) {
43177
+ if (!tile.centre) {
43178
+ continue;
43179
+ }
43180
+ const distance = Cartesian3.distance(eye, tile.centre) - tile.radius;
43181
+ if (distance < nearest) {
43182
+ nearest = distance;
43183
+ }
43184
+ }
43185
+ return isFinite(nearest) ? Math.max(1, nearest) : 1;
43229
43186
  }
43230
43187
  commandFor(context, tile, mesh) {
43231
43188
  if (!this.shaderProgram) {
@@ -44462,7 +44419,7 @@ async function resolveTextureCondition(params) {
44462
44419
  return { dataUri: null, effective: null };
44463
44420
  }
44464
44421
  await api.Loading;
44465
- const clientFile = await ClientFile.FindGeneratedTexture({ api, entityTypeSourceId, attribute });
44422
+ const { file: clientFile } = await ClientFileValueMap.Get({ api, entityTypeSourceId, attribute });
44466
44423
  if (!clientFile) {
44467
44424
  return { dataUri: null, effective: null };
44468
44425
  }
@@ -45957,7 +45914,7 @@ var StyleUtils;
45957
45914
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
45958
45915
  })(StyleUtils || (StyleUtils = {}));
45959
45916
 
45960
- const VERSION = "7.2.7";
45917
+ const VERSION = "7.2.9";
45961
45918
  /**
45962
45919
  * Updates the environment instance used by bruce-cesium to one specified.
45963
45920
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.