bruce-cesium 7.2.2 → 7.2.3

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, JulianDate, Quaternion, HeadingPitchRoll, HeightReference, ColorBlendMode, ShadowMode, ClassificationType, Model, ArcType, CornerType, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, SceneTransforms, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, NearFarScalar, Matrix3, GeoJsonDataSource, SceneMode, KmlDataSource, Ion, IonResource, Cesium3DTileStyle, HeadingPitchRange, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileColorBlendMode, Cesium3DTileset, Intersect, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, CustomDataSource, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, GeometryInstance, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, 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, Api, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, Bounds, Color as Color$1, BruceEvent, EntityCoords, DataLab, DelayQueue, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, EntitySource, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType, EntityHistoricData } from 'bruce-models';
2
+ import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, Matrix4, ShaderSource, Ellipsoid, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, Cartesian2, HeightReference, ColorBlendMode, ShadowMode, ClassificationType, Model, DistanceDisplayCondition, ArcType, CornerType, ConstantPositionProperty, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, HorizontalOrigin, VerticalOrigin, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, Cesium3DTileset, Intersect, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, CustomDataSource, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, 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, Color as Color$1, Api, BruceEvent, EntityCoords, MenuItem, Tileset, ProjectView, ProjectViewBookmark, ZoomControl, DelayQueue, DataLab, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, 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.
@@ -40400,38 +40400,221 @@ function loadImage(src) {
40400
40400
 
40401
40401
  var TextureFrameSeriesAnimator;
40402
40402
  (function (TextureFrameSeriesAnimator) {
40403
- // Values are measured up from the ground beneath them.
40404
- TextureFrameSeriesAnimator.QUANTITY_THICKNESS = "thickness";
40405
- // Values are heights against a vertical datum, so they need that datum to be placed.
40406
- TextureFrameSeriesAnimator.QUANTITY_ELEVATION = "elevation";
40407
40403
  TextureFrameSeriesAnimator.LAYOUT_TILES = "tiles";
40404
+ // The only generation this renderer draws. Anything else is refused rather than half read: the
40405
+ // shapes differ enough that a partial reading produces a plausible wrong surface, which is worse
40406
+ // than an empty one.
40407
+ TextureFrameSeriesAnimator.SUPPORTED_VERSION = 3;
40408
+ // Value in R at 8 bits, or high in R and low in G at 16.
40409
+ TextureFrameSeriesAnimator.FORMAT_U8 = "u8";
40410
+ TextureFrameSeriesAnimator.FORMAT_RG16 = "rg16";
40411
+ // Declared as a field with one value, so a second mode can be added later without an absent
40412
+ // Encoding having to mean anything.
40413
+ TextureFrameSeriesAnimator.ENCODING_ABSOLUTE = "absolute";
40414
+ TextureFrameSeriesAnimator.LAYER_VALUE = "Value";
40415
+ TextureFrameSeriesAnimator.LAYER_VALUE_MIN = "ValueMin";
40416
+ TextureFrameSeriesAnimator.LAYER_VALUE_MAX = "ValueMax";
40417
+ TextureFrameSeriesAnimator.LAYER_BASELINE = "Baseline";
40418
+ // The per-texel correction that was applied, published only on an archive that was transformed.
40419
+ TextureFrameSeriesAnimator.LAYER_VALUE_SHIFT = "ValueShift";
40408
40420
  /**
40409
- * The generator that produced an archive, for telling a stale one from a current one.
40421
+ * Turns a published value map into the flat shape this renderer works in, or null when it cannot be drawn.
40422
+ * @param published the archive's Data.generation
40423
+ */
40424
+ function Adapt(published) {
40425
+ if (!published || published.Version !== TextureFrameSeriesAnimator.SUPPORTED_VERSION) {
40426
+ const found = published && published.Version != null ? published.Version : "none";
40427
+ const at = published && published.Identity ? published.Identity.Generated : undefined;
40428
+ // In theory should be no files.
40429
+ console.warn("bruce-cesium: value map version " + found + " is not supported (this build reads "
40430
+ + TextureFrameSeriesAnimator.SUPPORTED_VERSION + "), so nothing will be drawn for it."
40431
+ + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40432
+ return null;
40433
+ }
40434
+ const geometry = published.Geometry || {};
40435
+ const tiles = published.Tiles || [];
40436
+ if (geometry.Layout !== TextureFrameSeriesAnimator.LAYOUT_TILES || tiles.length === 0) {
40437
+ const at = published.Identity ? published.Identity.Generated : undefined;
40438
+ console.warn("bruce-cesium: value map declares no tiles, so nothing will be drawn for it."
40439
+ + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40440
+ return null;
40441
+ }
40442
+ const value = published.Value || {};
40443
+ if (value.Encoding && value.Encoding !== TextureFrameSeriesAnimator.ENCODING_ABSOLUTE) {
40444
+ const at = published.Identity ? published.Identity.Generated : undefined;
40445
+ console.warn("bruce-cesium: value map encoding " + value.Encoding + " is not supported"
40446
+ + " (this build reads " + TextureFrameSeriesAnimator.ENCODING_ABSOLUTE + "), so nothing will be drawn for it."
40447
+ + (at ? " The archive was generated at " + at + " and needs regenerating." : ""));
40448
+ return null;
40449
+ }
40450
+ const series = published.Series || {};
40451
+ const layerRange = declaredRange(published, TextureFrameSeriesAnimator.LAYER_VALUE_MIN);
40452
+ const flat = {
40453
+ Frames: [],
40454
+ ValueMin: value.Min,
40455
+ ValueMax: value.Max,
40456
+ Format: value.Format || TextureFrameSeriesAnimator.FORMAT_U8,
40457
+ Encoding: value.Encoding || TextureFrameSeriesAnimator.ENCODING_ABSOLUTE,
40458
+ Units: value.Units,
40459
+ West: geometry.West,
40460
+ East: geometry.East,
40461
+ South: geometry.South,
40462
+ North: geometry.North,
40463
+ ResolutionX: geometry.ResolutionX,
40464
+ ResolutionY: geometry.ResolutionY,
40465
+ PixelPlacement: geometry.PixelPlacement,
40466
+ Times: series.Times,
40467
+ ExtremesValueMin: layerRange ? layerRange.min : undefined,
40468
+ ExtremesValueMax: layerRange ? layerRange.max : undefined,
40469
+ // The delivered values are what gets drawn. What the source called them, and any shift
40470
+ // applied on the way, travel for labels and analysis rather than for placement.
40471
+ SourceVerticalDatum: published.ValueSource ? published.ValueSource.VerticalDatum : undefined,
40472
+ Transform: published.ValueSource ? published.ValueSource.Transform : undefined,
40473
+ SourceUnits: published.ValueSource ? published.ValueSource.Units : undefined,
40474
+ SourceValueMin: published.ValueSource ? published.ValueSource.Min : undefined,
40475
+ SourceValueMax: published.ValueSource ? published.ValueSource.Max : undefined
40476
+ };
40477
+ flat.Tiles = tiles.map((tile) => adaptTile(tile, series.Times));
40478
+ // The coarsest tile covers the whole extent, so it is what a caller wanting one time list reads.
40479
+ flat.Frames = flat.Tiles[0].Frames;
40480
+ warnIfUnshifted(published, flat);
40481
+ return flat;
40482
+ }
40483
+ TextureFrameSeriesAnimator.Adapt = Adapt;
40484
+ /*
40485
+ * Says so when an archive's heights are not on the ellipsoid they will be drawn against.
40486
+ */
40487
+ function warnIfUnshifted(published, flat) {
40488
+ const datum = flat.SourceVerticalDatum;
40489
+ if (!datum || datum === TextureFrameSeriesAnimator.DATUM_ELLIPSOIDAL || flat.Transform) {
40490
+ return;
40491
+ }
40492
+ const at = published.Identity ? published.Identity.Generated : undefined;
40493
+ console.warn("bruce-cesium: value map heights are in " + datum + " and report no transform, so"
40494
+ + " they are not ellipsoidal and will draw at the wrong height when placed absolutely."
40495
+ + (at ? " The archive was generated at " + at + " and needs regenerating with the shift"
40496
+ + " applied." : ""));
40497
+ }
40498
+ /*
40499
+ * The Min and Max a named layer declares, since a statistics layer is encoded over the true data
40500
+ * range rather than over the frames' own.
40501
+ */
40502
+ function declaredRange(published, name) {
40503
+ const layers = published.Layers || [];
40504
+ for (const layer of layers) {
40505
+ if (layer.Name === name && typeof layer.Min === "number" && typeof layer.Max === "number") {
40506
+ return { min: layer.Min, max: layer.Max };
40507
+ }
40508
+ }
40509
+ return null;
40510
+ }
40511
+ /*
40512
+ * One tile, with its per-time value rasters lined up against the shared time list.
40513
+ */
40514
+ function adaptTile(tile, times) {
40515
+ const layers = tile.Layers || {};
40516
+ const perTime = layers[TextureFrameSeriesAnimator.LAYER_VALUE] || [];
40517
+ const frames = perTime.map((entry, index) => ({
40518
+ Timestamp: times && times[index] ? times[index] : "",
40519
+ ByteOffset: entry.Bytes.Offset,
40520
+ ByteLength: entry.Bytes.Length
40521
+ }));
40522
+ return {
40523
+ Level: tile.Level,
40524
+ X: tile.X,
40525
+ Y: tile.Y,
40526
+ West: tile.West,
40527
+ East: tile.East,
40528
+ South: tile.South,
40529
+ North: tile.North,
40530
+ TexelMetres: tile.TexelMetres,
40531
+ ResolutionX: tile.ResolutionX,
40532
+ ResolutionY: tile.ResolutionY,
40533
+ Frames: frames,
40534
+ Floor: single(layers[TextureFrameSeriesAnimator.LAYER_VALUE_MIN]),
40535
+ Ceiling: single(layers[TextureFrameSeriesAnimator.LAYER_VALUE_MAX]),
40536
+ BaselineMask: single(layers[TextureFrameSeriesAnimator.LAYER_BASELINE])
40537
+ };
40538
+ }
40539
+ function single(layer) {
40540
+ if (!layer || !layer.Bytes) {
40541
+ return undefined;
40542
+ }
40543
+ return { ByteOffset: layer.Bytes.Offset, ByteLength: layer.Bytes.Length };
40544
+ }
40545
+ /**
40546
+ * How to turn a delivered value into the number the source published, or null when the archive
40547
+ * does not say enough to do it.
40548
+ * @param metadata the archive's Data.generation
40549
+ */
40550
+ function SourceMap(metadata) {
40551
+ if (!metadata) {
40552
+ return null;
40553
+ }
40554
+ const { ValueMin, ValueMax, SourceValueMin, SourceValueMax } = metadata;
40555
+ if (typeof ValueMin !== "number" || typeof ValueMax !== "number"
40556
+ || typeof SourceValueMin !== "number" || typeof SourceValueMax !== "number") {
40557
+ return null;
40558
+ }
40559
+ const delivered = ValueMax - ValueMin;
40560
+ // A single delivered value describes no line, so all that can be recovered is where it sits.
40561
+ const scale = delivered !== 0 ? (SourceValueMax - SourceValueMin) / delivered : 1;
40562
+ return { scale, offset: SourceValueMin - ValueMin * scale };
40563
+ }
40564
+ TextureFrameSeriesAnimator.SourceMap = SourceMap;
40565
+ /**
40566
+ * A delivered value in the source's own terms, or unchanged when it cannot be turned back.
40567
+ * @param map from SourceMap(), null when the archive does not say enough
40568
+ */
40569
+ function ToSource(map, value) {
40570
+ return map ? value * map.scale + map.offset : value;
40571
+ }
40572
+ TextureFrameSeriesAnimator.ToSource = ToSource;
40573
+ /**
40574
+ * Whether the archive's frames carry a 16 bit value packed across R and G.
40410
40575
  *
40411
- * Read the version rather than sniffing for fields: an archive can legitimately omit Tiles or
40412
- * GeoidSeparation and still be current, so their absence says nothing about its age.
40576
+ * Every consumer that reads a texel has to ask: taking R alone from a packed frame yields a
40577
+ * plausible surface quantised to 255 steps of the full range rather than an obvious failure.
40413
40578
  * @param metadata the archive's Data.generation
40414
40579
  */
40415
- function GeneratorVersion(metadata) {
40416
- if (!metadata || typeof metadata.GeneratorVersion !== "number") {
40417
- return 1;
40580
+ function IsPackedValue(metadata) {
40581
+ return Boolean(metadata && metadata.Format === TextureFrameSeriesAnimator.FORMAT_RG16);
40582
+ }
40583
+ TextureFrameSeriesAnimator.IsPackedValue = IsPackedValue;
40584
+ /**
40585
+ * The normalised 0 to 1 value at a texel, from whichever format the archive packed it in.
40586
+ * @param metadata the archive's Data.generation
40587
+ * @param pixels untinted RGBA value pixels
40588
+ * @param at index of the texel's red channel
40589
+ */
40590
+ function NormalisedAt(metadata, pixels, at) {
40591
+ if (IsPackedValue(metadata)) {
40592
+ return (pixels[at] * 256 + pixels[at + 1]) / 65535;
40418
40593
  }
40419
- return metadata.GeneratorVersion;
40594
+ return pixels[at] / 255;
40420
40595
  }
40421
- TextureFrameSeriesAnimator.GeneratorVersion = GeneratorVersion;
40596
+ TextureFrameSeriesAnimator.NormalisedAt = NormalisedAt;
40597
+ // Values already sit on the ellipsoid Cesium measures against, so nothing is added to place them.
40598
+ TextureFrameSeriesAnimator.DATUM_ELLIPSOIDAL = "WGS84";
40422
40599
  /**
40423
- * Whether an archive is an adaptive pyramid rather than one raster.
40600
+ * Whether the values are heights against a vertical datum rather than a thickness.
40601
+ *
40602
+ * A thickness rises from wherever the polygon sits and a height already knows where it belongs, so
40603
+ * this is what decides whether the polygon's own altitude may be added underneath it.
40424
40604
  * @param metadata the archive's Data.generation
40425
40605
  */
40426
- function IsTiledLayout(metadata) {
40427
- return (Boolean(metadata && metadata.Layout === TextureFrameSeriesAnimator.LAYOUT_TILES &&
40428
- metadata.Tiles && metadata.Tiles.length > 0));
40429
- }
40430
- TextureFrameSeriesAnimator.IsTiledLayout = IsTiledLayout;
40431
- // Frames carry the value as the source reported it.
40432
- TextureFrameSeriesAnimator.MEASURE_ABSOLUTE = "absolute";
40433
- // Frames carry the value minus each cell's own minimum over the series.
40434
- TextureFrameSeriesAnimator.MEASURE_ANOMALY = "anomaly";
40606
+ function IsDatumHeight(metadata) {
40607
+ return Boolean(metadata && metadata.SourceVerticalDatum);
40608
+ }
40609
+ TextureFrameSeriesAnimator.IsDatumHeight = IsDatumHeight;
40610
+ /**
40611
+ * The archive's tiles, which Adapt() guarantees are present.
40612
+ * @param metadata the archive's Data.generation
40613
+ */
40614
+ function TilesOf(metadata) {
40615
+ return (metadata && metadata.Tiles) || [];
40616
+ }
40617
+ TextureFrameSeriesAnimator.TilesOf = TilesOf;
40435
40618
  /**
40436
40619
  * Turns a value in the attribute's own units into the 0 to 1 position the ramp is indexed by.
40437
40620
  *
@@ -40450,44 +40633,18 @@ var TextureFrameSeriesAnimator;
40450
40633
  return Math.min(1, Math.max(0, (value - lo) / span));
40451
40634
  }
40452
40635
  TextureFrameSeriesAnimator.NormalisePosition = NormalisePosition;
40453
- /**
40454
- * Whether the frames are a departure from each cell's own normal rather than a raw reading.
40455
- *
40456
- * Worth asking before labelling anything: the two measures need different words for the same
40457
- * number, and calling an anomaly "water depth" is a worse error than the coarse ramp it replaced.
40458
- * @param metadata the archive's Data.generation
40459
- */
40460
- function IsAnomalyMeasure(metadata) {
40461
- return Boolean(metadata && metadata.Measure === TextureFrameSeriesAnimator.MEASURE_ANOMALY);
40462
- }
40463
- TextureFrameSeriesAnimator.IsAnomalyMeasure = IsAnomalyMeasure;
40464
- /**
40465
- * How much the value moves anywhere in the series, in source units.
40466
- *
40467
- * Falls back to the published range, which is the right answer for an anomaly archive (its range
40468
- * IS the movement) and the only available one for an archive predating AnomalyMax.
40469
- * @param metadata the archive's Data.generation
40470
- */
40471
- function MovingRange(metadata) {
40472
- if (!metadata) {
40473
- return undefined;
40474
- }
40475
- if (typeof metadata.AnomalyMax === "number" && metadata.AnomalyMax > 0) {
40476
- return metadata.AnomalyMax;
40477
- }
40478
- if (typeof metadata.ValueMin === "number" && typeof metadata.ValueMax === "number") {
40479
- return Math.abs(metadata.ValueMax - metadata.ValueMin);
40480
- }
40481
- return undefined;
40482
- }
40483
- TextureFrameSeriesAnimator.MovingRange = MovingRange;
40484
40636
  /**
40485
40637
  * Detects whether a ClientFile's `Data.generation` metadata describes a frame archive rather than a single static image,
40486
40638
  * so a caller can decide whether to construct an Animator or fall back to the existing static-texture path.
40487
- * @param data ClientFile.Data (the `IFile.Data` field), as returned by ClientFile.Get().
40639
+ * @param data ClientFile.Data
40488
40640
  */
40489
40641
  function IsFrameArchiveMetadata(data) {
40490
- return Boolean(data && data.generation && Array.isArray(data.generation.Frames) && data.generation.Frames.length > 0);
40642
+ const generation = data && data.generation;
40643
+ if (!generation) {
40644
+ return false;
40645
+ }
40646
+ return (typeof generation.Version === "number" ||
40647
+ (Array.isArray(generation.Frames) && generation.Frames.length > 0));
40491
40648
  }
40492
40649
  TextureFrameSeriesAnimator.IsFrameArchiveMetadata = IsFrameArchiveMetadata;
40493
40650
  // First resolvable static number out of a calculator field list, since that is all a border needs.
@@ -40533,10 +40690,27 @@ var TextureFrameSeriesAnimator;
40533
40690
  TextureFrameSeriesAnimator.AppearanceSignature = AppearanceSignature;
40534
40691
  const MAX_COMPOSITE_TEXELS = 2048;
40535
40692
  const VALUE_DILATE_PASSES = 2;
40693
+ /*
40694
+ * Rewrites a packed 16 bit value as the 8 bit grey the colour ramps index on.
40695
+ *
40696
+ * All three channels, since a ramp is free to read any of them and a leftover low byte in G would
40697
+ * show up as a green cast on the one that reads them all.
40698
+ */
40699
+ function flattenPacked(pixels, packed) {
40700
+ if (!packed) {
40701
+ return;
40702
+ }
40703
+ for (let i = 0; i < pixels.length; i += 4) {
40704
+ const grey = Math.round((pixels[i] * 256 + pixels[i + 1]) / 65535 * 255);
40705
+ pixels[i] = grey;
40706
+ pixels[i + 1] = grey;
40707
+ pixels[i + 2] = grey;
40708
+ }
40709
+ }
40536
40710
  /*
40537
40711
  * Bleeds covered values outward into uncovered texels, leaving alpha untouched.
40538
40712
  */
40539
- function dilateValues(value, width, height, passes) {
40713
+ function dilateValues(value, width, height, passes, packed) {
40540
40714
  const texels = width * height;
40541
40715
  const filled = new Uint8Array(texels);
40542
40716
  for (let p = 0; p < texels; p++) {
@@ -40560,15 +40734,25 @@ var TextureFrameSeriesAnimator;
40560
40734
  if (nx < 0 || ny < 0 || nx >= width || ny >= height || !wasFilled[ny * width + nx]) {
40561
40735
  continue;
40562
40736
  }
40563
- sum += source[(ny * width + nx) * 4];
40737
+ const at = (ny * width + nx) * 4;
40738
+ // Averaged as a value rather than per byte: averaging a packed low byte
40739
+ // on its own wraps at every 256th step and speckles the bled edge.
40740
+ sum += packed ? source[at] * 256 + source[at + 1] : source[at];
40564
40741
  hits++;
40565
40742
  }
40566
40743
  }
40567
40744
  if (hits > 0) {
40568
40745
  const v = Math.round(sum / hits);
40569
- value[p * 4] = v;
40570
- value[p * 4 + 1] = v;
40571
- value[p * 4 + 2] = v;
40746
+ if (packed) {
40747
+ value[p * 4] = (v >> 8) & 255;
40748
+ value[p * 4 + 1] = v & 255;
40749
+ value[p * 4 + 2] = 0;
40750
+ }
40751
+ else {
40752
+ value[p * 4] = v;
40753
+ value[p * 4 + 1] = v;
40754
+ value[p * 4 + 2] = v;
40755
+ }
40572
40756
  filled[p] = 1;
40573
40757
  }
40574
40758
  }
@@ -40606,7 +40790,6 @@ var TextureFrameSeriesAnimator;
40606
40790
  // forcing Cesium to re-upload the texture only when something changed.
40607
40791
  this.pool = [document.createElement("canvas"), document.createElement("canvas")];
40608
40792
  this.poolIdx = 0;
40609
- this.scratch = null;
40610
40793
  this.valueDims = null;
40611
40794
  this.presentVersion = 0;
40612
40795
  this.extremesLoad = null;
@@ -40629,7 +40812,7 @@ var TextureFrameSeriesAnimator;
40629
40812
  this.highColor = (mask && Color$1.ColorFromStr(mask.maxColor)) || DEFAULT_HIGH_COLOR;
40630
40813
  // Positions are authored in the attribute's units and normalised once here, so the
40631
40814
  // per-pixel loop stays a comparison against 0 to 1 like the two-colour path.
40632
- const points = mask === null || mask === void 0 ? void 0 : mask.points;
40815
+ const points = mask && mask.points;
40633
40816
  this.rampStops = (points && points.length > 0)
40634
40817
  ? points.map((p) => ({
40635
40818
  position: NormalisePosition(options.metadata, p.position),
@@ -40655,9 +40838,8 @@ var TextureFrameSeriesAnimator;
40655
40838
  this.produceValueCanvas = Boolean(options.produceValueCanvas);
40656
40839
  this.metadata = options.metadata;
40657
40840
  this.drapeExtent = options.drapeExtent;
40658
- this.tiles = IsTiledLayout(options.metadata) ? options.metadata.Tiles : undefined;
40659
- this.baselineMaskEntry = options.baselineMask || null;
40660
- this.maskBaseline = (_c = options.maskBaseline) !== null && _c !== void 0 ? _c : Boolean(options.baselineMask);
40841
+ this.tiles = TilesOf(options.metadata);
40842
+ this.maskBaseline = (_c = options.maskBaseline) !== null && _c !== void 0 ? _c : this.tiles.some((tile) => Boolean(tile.BaselineMask));
40661
40843
  this.valueCanvas = this.produceValueCanvas ? document.createElement("canvas") : null;
40662
40844
  this.driveMaterial = options.driveMaterial !== false;
40663
40845
  this.originalMaterial = options.entity.polygon.material;
@@ -40833,32 +41015,20 @@ var TextureFrameSeriesAnimator;
40833
41015
  }
40834
41016
  async fetchAndTint(idx) {
40835
41017
  const tiles = this.tiles;
40836
- let buffer;
40837
- let span = 0;
40838
- if (tiles) {
40839
- // Every tile's frame for one timestep sits contiguously, because the generator writes
40840
- // frame major. So a tiled frame is still ONE range request, not one per tile.
40841
- let lo = Number.MAX_SAFE_INTEGER;
40842
- let hi = 0;
40843
- for (const tile of tiles) {
40844
- const at = tile.Frames[idx];
40845
- if (!at) {
40846
- continue;
40847
- }
40848
- lo = Math.min(lo, at.ByteOffset);
40849
- hi = Math.max(hi, at.ByteOffset + at.ByteLength);
41018
+ // Every tile's frame for one timestep sits contiguously, because the generator writes
41019
+ // frame major. So a tiled frame is still ONE range request, not one per tile.
41020
+ let lo = Number.MAX_SAFE_INTEGER;
41021
+ let hi = 0;
41022
+ for (const tile of tiles) {
41023
+ const at = tile.Frames[idx];
41024
+ if (!at) {
41025
+ continue;
40850
41026
  }
40851
- span = lo;
40852
- const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${lo}-${hi - 1}` } });
40853
- buffer = await response.arrayBuffer();
40854
- }
40855
- else {
40856
- const entry = this.frames[idx];
40857
- const start = entry.ByteOffset;
40858
- const end = entry.ByteOffset + entry.ByteLength - 1;
40859
- const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${start}-${end}` } });
40860
- buffer = await response.arrayBuffer();
41027
+ lo = Math.min(lo, at.ByteOffset);
41028
+ hi = Math.max(hi, at.ByteOffset + at.ByteLength);
40861
41029
  }
41030
+ const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${lo}-${hi - 1}` } });
41031
+ const buffer = await response.arrayBuffer();
40862
41032
  if (this.disposed) {
40863
41033
  return;
40864
41034
  }
@@ -40868,9 +41038,7 @@ var TextureFrameSeriesAnimator;
40868
41038
  if (this.disposed) {
40869
41039
  return;
40870
41040
  }
40871
- const decoded = tiles
40872
- ? await this.composeTiles(tiles, idx, buffer, span)
40873
- : await this.decodeAndTint(buffer);
41041
+ const decoded = await this.composeTiles(tiles, idx, buffer, lo);
40874
41042
  if (this.disposed) {
40875
41043
  return;
40876
41044
  }
@@ -40881,26 +41049,6 @@ var TextureFrameSeriesAnimator;
40881
41049
  this.beginCrossfadeTo(idx);
40882
41050
  }
40883
41051
  }
40884
- /**
40885
- * Decodes one frame's raw PNG bytes (as returned by a Range GET) and applies the grayscale color mask.
40886
- */
40887
- async decodeAndTint(buffer) {
40888
- const blob = new Blob([buffer], { type: "image/png" });
40889
- const objectUrl = URL.createObjectURL(blob);
40890
- let image;
40891
- try {
40892
- image = await loadImage(objectUrl);
40893
- }
40894
- finally {
40895
- URL.revokeObjectURL(objectUrl);
40896
- }
40897
- const canvas = document.createElement("canvas");
40898
- canvas.width = image.width;
40899
- canvas.height = image.height;
40900
- const ctx = canvas.getContext("2d");
40901
- ctx.drawImage(image, 0, 0);
40902
- return this.tint(ctx.getImageData(0, 0, canvas.width, canvas.height));
40903
- }
40904
41052
  /*
40905
41053
  * Draws every tile of one frame into a single raster covering the drape extent.
40906
41054
  */
@@ -40973,6 +41121,10 @@ var TextureFrameSeriesAnimator;
40973
41121
  // Copied before tinting: the ramp is a lerp between two colours, so the value cannot be
40974
41122
  // recovered from the tinted pixels afterwards.
40975
41123
  const valuePixels = this.produceValueCanvas ? new Uint8ClampedArray(imageData.data) : undefined;
41124
+ // The ramp indexes on R as an 8 bit grey, so a packed frame is flattened to one here
41125
+ // rather than teaching every ramp function a second format.
41126
+ // The copy above keeps the packed pair, which is what displacement and labels read.
41127
+ flattenPacked(imageData.data, IsPackedValue(this.metadata));
40976
41128
  // Stops win when supplied: they can express a band and a hidden floor, which a two
40977
41129
  // colour ramp cannot. The pair stays the fallback so an older style still draws.
40978
41130
  if (this.rampStops && this.rampStops.length > 0) {
@@ -40986,72 +41138,20 @@ var TextureFrameSeriesAnimator;
40986
41138
  }
40987
41139
  this.applyBaselineMask(imageData.data, valuePixels, canvas.width, canvas.height);
40988
41140
  if (valuePixels) {
40989
- dilateValues(valuePixels, canvas.width, canvas.height, VALUE_DILATE_PASSES);
41141
+ dilateValues(valuePixels, canvas.width, canvas.height, VALUE_DILATE_PASSES, IsPackedValue(this.metadata));
40990
41142
  }
40991
41143
  return { pixels: imageData.data, width: canvas.width, height: canvas.height, valuePixels };
40992
41144
  }
40993
41145
  /*
40994
- * Paints one frame's pixels onto a canvas, resampled into the drape extent when there is one.
41146
+ * Paints one frame's composited pixels onto a canvas.
40995
41147
  */
40996
41148
  writeInto(canvas, pixels, dims) {
40997
- const rect = this.sourceRect(dims);
40998
- if (!rect) {
40999
- canvas.width = dims.width;
41000
- canvas.height = dims.height;
41001
- const direct = canvas.getContext("2d");
41002
- const image = direct.createImageData(dims.width, dims.height);
41003
- image.data.set(pixels);
41004
- direct.putImageData(image, 0, 0);
41005
- return;
41006
- }
41007
- if (!this.scratch) {
41008
- this.scratch = document.createElement("canvas");
41009
- }
41010
- this.scratch.width = dims.width;
41011
- this.scratch.height = dims.height;
41012
- const scratchCtx = this.scratch.getContext("2d");
41013
- const image = scratchCtx.createImageData(dims.width, dims.height);
41014
- image.data.set(pixels);
41015
- scratchCtx.putImageData(image, 0, 0);
41016
41149
  canvas.width = dims.width;
41017
41150
  canvas.height = dims.height;
41018
41151
  const ctx = canvas.getContext("2d");
41019
- // Nearest neighbour: a value texel has to survive the resample exactly, or a label reads
41020
- // a blend of two cells rather than the cell it points at.
41021
- ctx.imageSmoothingEnabled = false;
41022
- ctx.clearRect(0, 0, dims.width, dims.height);
41023
- ctx.drawImage(this.scratch, rect.x, rect.y, rect.width, rect.height, 0, 0, dims.width, dims.height);
41024
- }
41025
- /*
41026
- * The part of the archive raster that the drape extent covers, in source pixels.
41027
- */
41028
- sourceRect(dims) {
41029
- const drape = this.drapeExtent;
41030
- const m = this.metadata;
41031
- // A composited frame was drawn into the drape extent already, so resampling it again
41032
- // would apply the same correction twice.
41033
- if (this.tiles) {
41034
- return null;
41035
- }
41036
- if (!drape || !m || m.West == null || m.East == null || m.South == null || m.North == null) {
41037
- return null;
41038
- }
41039
- const spanLon = m.East - m.West;
41040
- const spanLat = m.North - m.South;
41041
- if (!(spanLon > 0) || !(spanLat > 0)) {
41042
- return null;
41043
- }
41044
- const x = (drape.West - m.West) / spanLon * dims.width;
41045
- const width = (drape.East - drape.West) / spanLon * dims.width;
41046
- const y = (m.North - drape.North) / spanLat * dims.height;
41047
- const height = (drape.North - drape.South) / spanLat * dims.height;
41048
- // A drape that already matches the archive is the common case and must not pay for a
41049
- // resample, nor lose a half pixel to rounding.
41050
- if (Math.abs(x) < 0.01 && Math.abs(y) < 0.01
41051
- && Math.abs(width - dims.width) < 0.01 && Math.abs(height - dims.height) < 0.01) {
41052
- return null;
41053
- }
41054
- return { x, y, width, height };
41152
+ const image = ctx.createImageData(dims.width, dims.height);
41153
+ image.data.set(pixels);
41154
+ ctx.putImageData(image, 0, 0);
41055
41155
  }
41056
41156
  /**
41057
41157
  * The archive's per-cell floor and ceiling rasters, once EnsureExtremes has resolved.
@@ -41063,45 +41163,16 @@ var TextureFrameSeriesAnimator;
41063
41163
  * Fetches and decodes the floor and ceiling rasters, at most once.
41064
41164
  */
41065
41165
  EnsureExtremes() {
41066
- if (this.extremesLoad) {
41067
- return this.extremesLoad;
41068
- }
41069
- if (this.tiles) {
41166
+ if (!this.extremesLoad) {
41070
41167
  this.extremesLoad = this.loadTiledExtremes();
41071
- return this.extremesLoad;
41072
- }
41073
- const floor = this.metadata && this.metadata.Floor;
41074
- const ceiling = this.metadata && this.metadata.Ceiling;
41075
- if (!floor && !ceiling) {
41076
- this.extremesLoad = Promise.resolve();
41077
- return this.extremesLoad;
41078
- }
41079
- this.extremesLoad = Promise.all([
41080
- floor ? this.loadImageDataAt(floor) : Promise.resolve(null),
41081
- ceiling ? this.loadImageDataAt(ceiling) : Promise.resolve(null)
41082
- ]).then(([f, c]) => {
41083
- if (this.disposed) {
41084
- return;
41085
- }
41086
- this.floorPixels = f;
41087
- this.ceilingPixels = c;
41088
- }).catch((e) => {
41089
- // Missing extremes cost a label its range, and must not take the animation with them.
41090
- console.warn("TextureFrameSeriesAnimator: could not load the extremes rasters.", e);
41091
- });
41168
+ }
41092
41169
  return this.extremesLoad;
41093
41170
  }
41094
41171
  /*
41095
41172
  * Composites each tile's baseline mask into one covering the composited frames.
41096
- *
41097
- * A tiled archive publishes the mask per tile, so reading the archive level BaselineMask
41098
- * finds nothing and hiding dry cells silently does nothing at all.
41099
41173
  */
41100
41174
  async loadTiledBaselineMask() {
41101
41175
  const tiles = this.tiles;
41102
- if (!tiles) {
41103
- return;
41104
- }
41105
41176
  const entries = tiles.map((tile) => tile.BaselineMask);
41106
41177
  let lo = Number.MAX_SAFE_INTEGER;
41107
41178
  let hi = 0;
@@ -41155,14 +41226,11 @@ var TextureFrameSeriesAnimator;
41155
41226
  /*
41156
41227
  * Composites each tile's floor and ceiling into rasters matching the composited frames.
41157
41228
  *
41158
- * A tiled archive has no whole-extent extremes to fetch, only per-tile ones, and a label
41159
- * indexes them by the same texel as the value canvas, so they have to be laid out the same way.
41229
+ * A label indexes them by the same texel as the value canvas, so they have to be laid out the
41230
+ * same way rather than fetched as whole-extent rasters.
41160
41231
  */
41161
41232
  async loadTiledExtremes() {
41162
41233
  const tiles = this.tiles;
41163
- if (!tiles) {
41164
- return;
41165
- }
41166
41234
  const target = this.compositeExtent();
41167
41235
  const size = this.compositeSize(tiles, target);
41168
41236
  // One request for the whole extremes block. They sit contiguously after the frames, so
@@ -41257,70 +41325,6 @@ var TextureFrameSeriesAnimator;
41257
41325
  }
41258
41326
  }));
41259
41327
  }
41260
- /*
41261
- * Range GETs one entry and decodes it to an image.
41262
- */
41263
- async loadImageAt(entry) {
41264
- const start = entry.ByteOffset;
41265
- const end = entry.ByteOffset + entry.ByteLength - 1;
41266
- const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${start}-${end}` } });
41267
- const buffer = await response.arrayBuffer();
41268
- const objectUrl = URL.createObjectURL(new Blob([buffer], { type: "image/png" }));
41269
- try {
41270
- return await loadImage(objectUrl);
41271
- }
41272
- finally {
41273
- URL.revokeObjectURL(objectUrl);
41274
- }
41275
- }
41276
- /*
41277
- * Puts a static raster through the same resample the frames get.
41278
- */
41279
- remap(image) {
41280
- if (!image) {
41281
- return null;
41282
- }
41283
- const rect = this.sourceRect({ width: image.width, height: image.height });
41284
- if (!rect) {
41285
- return image;
41286
- }
41287
- const from = document.createElement("canvas");
41288
- from.width = image.width;
41289
- from.height = image.height;
41290
- from.getContext("2d").putImageData(image, 0, 0);
41291
- const to = document.createElement("canvas");
41292
- to.width = image.width;
41293
- to.height = image.height;
41294
- const ctx = to.getContext("2d");
41295
- ctx.imageSmoothingEnabled = false;
41296
- ctx.clearRect(0, 0, image.width, image.height);
41297
- ctx.drawImage(from, rect.x, rect.y, rect.width, rect.height, 0, 0, image.width, image.height);
41298
- return ctx.getImageData(0, 0, image.width, image.height);
41299
- }
41300
- /*
41301
- * Range GETs one entry out of the blob and decodes it to pixels.
41302
- */
41303
- async loadImageDataAt(entry) {
41304
- const start = entry.ByteOffset;
41305
- const end = entry.ByteOffset + entry.ByteLength - 1;
41306
- const response = await fetch(this.archiveUrl, { headers: { Range: `bytes=${start}-${end}` } });
41307
- const buffer = await response.arrayBuffer();
41308
- const blob = new Blob([buffer], { type: "image/png" });
41309
- const objectUrl = URL.createObjectURL(blob);
41310
- let image;
41311
- try {
41312
- image = await loadImage(objectUrl);
41313
- }
41314
- finally {
41315
- URL.revokeObjectURL(objectUrl);
41316
- }
41317
- const canvas = document.createElement("canvas");
41318
- canvas.width = image.width;
41319
- canvas.height = image.height;
41320
- const ctx = canvas.getContext("2d");
41321
- ctx.drawImage(image, 0, 0);
41322
- return ctx.getImageData(0, 0, canvas.width, canvas.height);
41323
- }
41324
41328
  /**
41325
41329
  * Fetches and decodes the archive's static baseline mask, at most once.
41326
41330
  */
@@ -41515,6 +41519,49 @@ var TextureValueLabels;
41515
41519
  return out;
41516
41520
  }
41517
41521
  TextureValueLabels.ClipOutline = ClipOutline;
41522
+ /**
41523
+ * One cell's numbers as a label should print them, or null where the texture has no data there.
41524
+ * @param params at is the index of the cell's red channel. sourceMap is derived from the metadata
41525
+ * when omitted, which a caller reading many cells should hoist rather than repeat.
41526
+ */
41527
+ function ReadingAt(params) {
41528
+ const { metadata, source, floor, ceiling, at } = params;
41529
+ if (source.data[at + 3] < 128) {
41530
+ return null;
41531
+ }
41532
+ const lo = metadata && typeof metadata.ValueMin === "number" ? metadata.ValueMin : 0;
41533
+ const hi = metadata && typeof metadata.ValueMax === "number" ? metadata.ValueMax : 1;
41534
+ const normalised = TextureFrameSeriesAnimator.NormalisedAt(metadata, source.data, at);
41535
+ const toSource = params.sourceMap !== undefined
41536
+ ? params.sourceMap
41537
+ : TextureFrameSeriesAnimator.SourceMap(metadata);
41538
+ const inSource = (value) => TextureFrameSeriesAnimator.ToSource(toSource, value);
41539
+ const reading = { value: inSource(lo + normalised * (hi - lo)) };
41540
+ const eLo = metadata && metadata.ExtremesValueMin;
41541
+ const eHi = metadata && metadata.ExtremesValueMax;
41542
+ if (typeof eLo === "number" && typeof eHi === "number") {
41543
+ if (floor) {
41544
+ reading.floor = inSource(eLo + decode16(floor.data, at) * (eHi - eLo));
41545
+ }
41546
+ if (ceiling) {
41547
+ reading.ceiling = inSource(eLo + decode16(ceiling.data, at) * (eHi - eLo));
41548
+ }
41549
+ }
41550
+ return reading;
41551
+ }
41552
+ TextureValueLabels.ReadingAt = ReadingAt;
41553
+ /**
41554
+ * The unit a label's value line should name, or undefined when the archive states none.
41555
+ * @param metadata the archive's Data.generation
41556
+ */
41557
+ function LabelUnits(metadata) {
41558
+ if (!metadata) {
41559
+ return undefined;
41560
+ }
41561
+ const recovered = TextureFrameSeriesAnimator.SourceMap(metadata);
41562
+ return (recovered && metadata.SourceUnits) || metadata.Units;
41563
+ }
41564
+ TextureValueLabels.LabelUnits = LabelUnits;
41518
41565
  /**
41519
41566
  * How many cells apart labels should sit, as a power of two.
41520
41567
  * @param options cellPixels is one cell's size on screen, held is the stride already in use
@@ -41541,6 +41588,7 @@ var TextureValueLabels;
41541
41588
  TextureValueLabels.ChooseLabelStride = ChooseLabelStride;
41542
41589
  class Labels {
41543
41590
  constructor(options) {
41591
+ this.sourceMap = null;
41544
41592
  this.source = null;
41545
41593
  this.painted = null;
41546
41594
  this.floor = null;
@@ -41552,6 +41600,9 @@ var TextureValueLabels;
41552
41600
  this.extent = options.extent;
41553
41601
  this.settings = options.settings || {};
41554
41602
  this.metadata = options.metadata;
41603
+ // Once per overlay rather than once per cell: a label pass probes thousands of texels
41604
+ // looking for one worth labelling, and the map cannot change while the metadata does not.
41605
+ this.sourceMap = TextureFrameSeriesAnimator.SourceMap(options.metadata);
41555
41606
  this.tiles = options.tiles;
41556
41607
  this.clipRing = options.clipRing;
41557
41608
  this.canvas = document.createElement("canvas");
@@ -41967,7 +42018,7 @@ var TextureValueLabels;
41967
42018
  widestLabel(parts) {
41968
42019
  const sample = [];
41969
42020
  if (parts.indexOf("value") >= 0) {
41970
- sample.push("-000.00");
42021
+ sample.push(valueLine("-000.00", LabelUnits(this.metadata)));
41971
42022
  }
41972
42023
  const range = [];
41973
42024
  if (parts.indexOf("floor") >= 0) {
@@ -42007,7 +42058,7 @@ var TextureValueLabels;
42007
42058
  const dp = (_a = this.settings.decimals) !== null && _a !== void 0 ? _a : (Math.abs(reading.value) < 10 ? 2 : 1);
42008
42059
  const lines = [];
42009
42060
  if (parts.indexOf("value") >= 0) {
42010
- lines.push(reading.value.toFixed(dp));
42061
+ lines.push(valueLine(reading.value.toFixed(dp), LabelUnits(this.metadata)));
42011
42062
  }
42012
42063
  // Named rather than a bare pair: two numbers under a third say nothing about which is
42013
42064
  // the series low and which is its high.
@@ -42081,29 +42132,17 @@ var TextureValueLabels;
42081
42132
  }
42082
42133
  // Decodes one cell, skipping anything the texture marks as having no data.
42083
42134
  readAt(col, row, cols) {
42084
- var _a, _b;
42085
- const i = (row * cols + col) * 4;
42086
- if (!this.source || this.source.data[i + 3] < 128) {
42135
+ if (!this.source) {
42087
42136
  return null;
42088
42137
  }
42089
- const lo = this.metadata && typeof this.metadata.ValueMin === "number" ? this.metadata.ValueMin : 0;
42090
- const hi = this.metadata && typeof this.metadata.ValueMax === "number" ? this.metadata.ValueMax : 1;
42091
- const value = lo + (this.source.data[i] / 255) * (hi - lo);
42092
- const reading = { value };
42093
- const eLo = (_a = this.metadata) === null || _a === void 0 ? void 0 : _a.ExtremesValueMin;
42094
- const eHi = (_b = this.metadata) === null || _b === void 0 ? void 0 : _b.ExtremesValueMax;
42095
- if (this.floor && typeof eLo === "number" && typeof eHi === "number") {
42096
- reading.floor = eLo + decode16(this.floor.data, i) * (eHi - eLo);
42097
- // An anomaly archive's frames are already floor-relative, so the reading a user
42098
- // wants is the absolute one. This is the whole reason the floor is published.
42099
- if (TextureFrameSeriesAnimator.IsAnomalyMeasure(this.metadata)) {
42100
- reading.value += reading.floor;
42101
- }
42102
- }
42103
- if (this.ceiling && typeof eLo === "number" && typeof eHi === "number") {
42104
- reading.ceiling = eLo + decode16(this.ceiling.data, i) * (eHi - eLo);
42105
- }
42106
- return reading;
42138
+ return ReadingAt({
42139
+ metadata: this.metadata,
42140
+ source: this.source,
42141
+ floor: this.floor,
42142
+ ceiling: this.ceiling,
42143
+ at: (row * cols + col) * 4,
42144
+ sourceMap: this.sourceMap
42145
+ });
42107
42146
  }
42108
42147
  lonAt(col, cols) {
42109
42148
  return this.extent.West + ((col + 0.5) / cols) * (this.extent.East - this.extent.West);
@@ -42142,6 +42181,13 @@ var TextureValueLabels;
42142
42181
  }
42143
42182
  }
42144
42183
  TextureValueLabels.Labels = Labels;
42184
+ /*
42185
+ * The value line. Units go on it alone: repeating them on the range underneath doubles the widest
42186
+ * label to say nothing, and the two lines are plainly the same quantity.
42187
+ */
42188
+ function valueLine(value, units) {
42189
+ return units ? `${value} (${units})` : value;
42190
+ }
42145
42191
  function decode16(data, i) {
42146
42192
  return (data[i] * 256 + data[i + 1]) / 65535;
42147
42193
  }
@@ -42167,11 +42213,6 @@ var DisplacedSurfacePrimitive;
42167
42213
  const SKIRT_FRACTION = 0.015;
42168
42214
  // Alpha below which a texel counts as no-data and is not drawn at all.
42169
42215
  const COVERAGE_CUTOFF = 0.35;
42170
- // With no exaggeration stated, the full value range is drawn as this fraction of the extent's shorter side.
42171
- const AUTO_RELIEF_FRACTION = 0.02;
42172
- // Ceiling on the derived relief. Sizing purely off the extent is fine for a parcel and absurd for
42173
- // a whole estuary: 4 m of water over an 82 km extent came out 1.6 km tall.
42174
- const AUTO_MAX_RELIEF_METRES = 250.0;
42175
42216
  // Terrain is sampled on this grid and interpolated between samples.
42176
42217
  // Per-texel sampling would be hundreds of thousands of lookups for a surface whose own data is far coarser than that.
42177
42218
  const GROUND_SAMPLES_PER_SIDE = 64;
@@ -42192,6 +42233,7 @@ in float skirt;
42192
42233
 
42193
42234
  uniform sampler2D u_valueTexture;
42194
42235
  uniform sampler2D u_groundTexture;
42236
+ uniform float u_valuePacked;
42195
42237
  uniform float u_valueMin;
42196
42238
  uniform float u_valueRange;
42197
42239
  uniform float u_exaggeration;
@@ -42229,18 +42271,37 @@ float sampleGround(vec2 uv) {
42229
42271
  return mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y);
42230
42272
  }
42231
42273
 
42274
+ /*
42275
+ * The texel's normalised value, whichever way the archive packed it.
42276
+ *
42277
+ * A packed frame keeps the high byte in R, so reading R alone would quantise the whole range to 255
42278
+ * steps and draw a plausible wrong surface rather than an obviously broken one.
42279
+ *
42280
+ * Each channel is scaled and then added, rather than reassembled to a 0..65535 integer and divided.
42281
+ * That integer is outside the range mediump guarantees, and a fragment shader only gets highp where
42282
+ * the device offers it, so the obvious form loses the low byte on exactly the older mobile hardware
42283
+ * that Cesium falls back to mediump for.
42284
+ */
42285
+ float decodeValue(vec4 texel) {
42286
+ float packed16 = texel.r * (255.0 * 256.0 / 65535.0) + texel.g * (255.0 / 65535.0);
42287
+ return mix(texel.r, packed16, u_valuePacked);
42288
+ }
42289
+
42232
42290
  void main() {
42233
42291
  vec4 texel = texture(u_valueTexture, st);
42234
42292
  v_st = st;
42235
- v_value = texel.r;
42293
+ v_value = decodeValue(texel);
42236
42294
  v_coverage = texel.a;
42237
42295
 
42238
- float metres = u_valueMin + texel.r * u_valueRange;
42296
+ // Exaggeration stretches the span above the archive's minimum rather than the height itself. On an
42297
+ // elevation the height is measured from the ellipsoid, tens of metres from any of the data, so
42298
+ // scaling that instead translates the whole sheet underground rather than spreading it out.
42299
+ float metres = u_valueMin + v_value * u_valueRange * u_exaggeration;
42239
42300
 
42240
42301
  // Value zero sits at the polygon's own altitude, plus the terrain underneath when the polygon
42241
42302
  // is following the ground rather than absolutely positioned.
42242
42303
  float ground = sampleGround(st) * u_groundWeight;
42243
- float displacement = u_baseHeight + ground + metres * u_exaggeration * texel.a - skirt * u_skirtDepth;
42304
+ float displacement = u_baseHeight + ground + metres * texel.a - skirt * u_skirtDepth;
42244
42305
 
42245
42306
  // Added to the LOW half of the encoded position: a metre-scale offset added to the high half
42246
42307
  // would be lost to float32 rounding at an earth radius.
@@ -42253,6 +42314,7 @@ uniform sampler2D u_valueTexture;
42253
42314
  uniform sampler2D u_rampTexture;
42254
42315
  uniform float u_coverageCutoff;
42255
42316
  uniform vec2 u_texelSize;
42317
+ uniform float u_valuePacked;
42256
42318
  uniform float u_valueRange;
42257
42319
  uniform float u_exaggeration;
42258
42320
  uniform float u_metresPerTexel;
@@ -42261,6 +42323,16 @@ in vec2 v_st;
42261
42323
  in float v_value;
42262
42324
  in float v_coverage;
42263
42325
 
42326
+ /*
42327
+ * Scaled per channel for the same reason the vertex shader's decode is: reassembling the pair reaches
42328
+ * 65535, which mediump does not have to represent, and this is the shader that may not get highp.
42329
+ */
42330
+ float valueAt(vec2 uv) {
42331
+ vec4 texel = texture(u_valueTexture, uv);
42332
+ float packed16 = texel.r * (255.0 * 256.0 / 65535.0) + texel.g * (255.0 / 65535.0);
42333
+ return mix(texel.r, packed16, u_valuePacked);
42334
+ }
42335
+
42264
42336
  void main() {
42265
42337
  if (v_coverage < u_coverageCutoff) {
42266
42338
  discard;
@@ -42275,10 +42347,10 @@ void main() {
42275
42347
 
42276
42348
  // Relief shading from the value gradient, so the displacement reads at a distance without
42277
42349
  // recomputing vertex normals every time the texture changes.
42278
- float left = texture(u_valueTexture, v_st - vec2(u_texelSize.x, 0.0)).r;
42279
- float right = texture(u_valueTexture, v_st + vec2(u_texelSize.x, 0.0)).r;
42280
- float down = texture(u_valueTexture, v_st - vec2(0.0, u_texelSize.y)).r;
42281
- float up = texture(u_valueTexture, v_st + vec2(0.0, u_texelSize.y)).r;
42350
+ float left = valueAt(v_st - vec2(u_texelSize.x, 0.0));
42351
+ float right = valueAt(v_st + vec2(u_texelSize.x, 0.0));
42352
+ float down = valueAt(v_st - vec2(0.0, u_texelSize.y));
42353
+ float up = valueAt(v_st + vec2(0.0, u_texelSize.y));
42282
42354
  float scale = u_valueRange * u_exaggeration;
42283
42355
  vec3 n = normalize(vec3((left - right) * scale, (down - up) * scale, 2.0 * u_metresPerTexel));
42284
42356
  float lambert = clamp(dot(n, normalize(vec3(-0.5, -0.6, 0.62))), 0.0, 1.0);
@@ -42488,8 +42560,9 @@ void main() {
42488
42560
  this.source = options.source || null;
42489
42561
  this.valueMin = (_a = options.valueMin) !== null && _a !== void 0 ? _a : 0;
42490
42562
  this.valueMax = (_b = options.valueMax) !== null && _b !== void 0 ? _b : 1;
42491
- this.exaggeration = (_c = options.exaggeration) !== null && _c !== void 0 ? _c : autoExaggeration(this.extent, this.valueMin, this.valueMax);
42563
+ this.exaggeration = (_c = options.exaggeration) !== null && _c !== void 0 ? _c : 1;
42492
42564
  this.baseHeight = (_d = options.baseHeight) !== null && _d !== void 0 ? _d : 0;
42565
+ this.packedValue = Boolean(options.packedValue);
42493
42566
  this.pixelPlacement = options.pixelPlacement;
42494
42567
  this.tileSkirts = Boolean(options.tileSkirts);
42495
42568
  this.rampPixels = RampLookup(options.rampStops || null, options.lowColor || DEFAULT_LOW_COLOR, options.highColor || DEFAULT_HIGH_COLOR);
@@ -42713,6 +42786,14 @@ void main() {
42713
42786
  if (this.texture) {
42714
42787
  this.texture.destroy();
42715
42788
  }
42789
+ // Nearest for a packed value, because filtering would blend the two bytes of the
42790
+ // packing rather than the values they encode, the same trap sampleGround avoids.
42791
+ const minification = this.packedValue
42792
+ ? TextureMinificationFilter.NEAREST
42793
+ : TextureMinificationFilter.LINEAR;
42794
+ const magnification = this.packedValue
42795
+ ? TextureMagnificationFilter.NEAREST
42796
+ : TextureMagnificationFilter.LINEAR;
42716
42797
  this.texture = new Texture({
42717
42798
  context,
42718
42799
  source: this.source,
@@ -42722,8 +42803,8 @@ void main() {
42722
42803
  sampler: new Sampler({
42723
42804
  wrapS: TextureWrap.CLAMP_TO_EDGE,
42724
42805
  wrapT: TextureWrap.CLAMP_TO_EDGE,
42725
- minificationFilter: TextureMinificationFilter.LINEAR,
42726
- magnificationFilter: TextureMagnificationFilter.LINEAR
42806
+ minificationFilter: minification,
42807
+ magnificationFilter: magnification
42727
42808
  })
42728
42809
  });
42729
42810
  this.textureDirty = false;
@@ -42824,6 +42905,7 @@ void main() {
42824
42905
  uniformMap: {
42825
42906
  u_valueTexture: () => self.texture,
42826
42907
  u_groundTexture: () => self.groundTexture,
42908
+ u_valuePacked: () => (self.packedValue ? 1 : 0),
42827
42909
  u_groundWeight: () => (self.followGround && self.groundPixels ? 1 : 0),
42828
42910
  u_groundRange: () => new Cartesian2(GROUND_MIN_METRES, GROUND_MAX_METRES),
42829
42911
  u_groundSize: () => new Cartesian2(self.groundPixels ? GROUND_SAMPLES_PER_SIDE : 1, self.groundPixels ? GROUND_SAMPLES_PER_SIDE : 1),
@@ -42876,31 +42958,6 @@ void main() {
42876
42958
  }
42877
42959
  return tiles;
42878
42960
  }
42879
- /**
42880
- * Exaggeration that makes the full value range stand AUTO_RELIEF_FRACTION of the extent tall.
42881
- *
42882
- * Derived from the whole extent rather than per tile: scaling each tile to its own size would
42883
- * make neighbours disagree along their shared edge and tear the surface apart.
42884
- * @param extent
42885
- * @param valueMin
42886
- * @param valueMax
42887
- */
42888
- function autoExaggeration(extent, valueMin, valueMax) {
42889
- const range = Math.abs(valueMax - valueMin);
42890
- if (!(range > 0)) {
42891
- return 1;
42892
- }
42893
- const southWest = Cartesian3.fromDegrees(extent.West, extent.South, 0);
42894
- const southEast = Cartesian3.fromDegrees(extent.East, extent.South, 0);
42895
- const northWest = Cartesian3.fromDegrees(extent.West, extent.North, 0);
42896
- const shorterSide = Math.min(Cartesian3.distance(southWest, southEast), Cartesian3.distance(southWest, northWest));
42897
- if (!(shorterSide > 0)) {
42898
- return 1;
42899
- }
42900
- const relief = Math.min(shorterSide * AUTO_RELIEF_FRACTION, AUTO_MAX_RELIEF_METRES);
42901
- return relief / range;
42902
- }
42903
- DisplacedSurfacePrimitive.autoExaggeration = autoExaggeration;
42904
42961
  function now() {
42905
42962
  return typeof performance !== "undefined" ? performance.now() : Date.now();
42906
42963
  }
@@ -43639,12 +43696,12 @@ function syncDisplacedSurface(params) {
43639
43696
  && existingAnimator.GetArchiveUrl() === extrusionArchive.url
43640
43697
  && existingSurface
43641
43698
  && !existingSurface.isDestroyed();
43642
- const placement = surfacePlacement(entity, heightRef);
43699
+ const placement = surfacePlacement(entity, heightRef, extrusionArchive && TextureFrameSeriesAnimator.IsDatumHeight(extrusionArchive.metadata));
43643
43700
  // Whether the surface follows terrain is baked into its ground sampling, so a change there has
43644
43701
  // to rebuild rather than update in place.
43645
43702
  if (reusable && existingSurface.GetFollowsGround() === placement.followGround) {
43646
43703
  existingSurface.SetBaseHeight(placement.baseHeight);
43647
- existingSurface.SetExaggeration(exaggerationFor(style, extrusionArchive.metadata, existingSurface.GetExtent()));
43704
+ existingSurface.SetExaggeration(exaggerationFor(style));
43648
43705
  return;
43649
43706
  }
43650
43707
  disposeDisplacedSurface(cEntity, viewer);
@@ -43668,8 +43725,6 @@ function syncDisplacedSurface(params) {
43668
43725
  produceValueCanvas: true,
43669
43726
  metadata: extrusionArchive.metadata,
43670
43727
  cellTexels: 1,
43671
- baselineMask: extrusionArchive.metadata.BaselineMask,
43672
- // Off-type for the same reason as the fill path: the pinned bruce-models predates the field.
43673
43728
  maskBaseline: style.maskTextureBaseline
43674
43729
  });
43675
43730
  cEntity[EXTRUSION_ANIMATOR_KEY] = animator;
@@ -43684,12 +43739,13 @@ function syncDisplacedSurface(params) {
43684
43739
  terrainProvider: viewer && viewer.terrainProvider,
43685
43740
  valueMin: extrusionArchive.metadata.ValueMin,
43686
43741
  valueMax: extrusionArchive.metadata.ValueMax,
43687
- exaggeration: exaggerationFor(style, extrusionArchive.metadata, extent),
43742
+ packedValue: TextureFrameSeriesAnimator.IsPackedValue(extrusionArchive.metadata),
43743
+ exaggeration: exaggerationFor(style),
43688
43744
  lowColor: mask ? Color$1.ColorFromStr(mask.minColor) : null,
43689
43745
  highColor: mask ? Color$1.ColorFromStr(mask.maxColor) : null,
43690
43746
  // Normalised the same way the animator normalises them, so the surface and the flat drape
43691
43747
  // agree about which values the style hides.
43692
- rampStops: (mask && mask.points || []).map((stop) => ({
43748
+ rampStops: ((mask && mask.points) || []).map((stop) => ({
43693
43749
  position: TextureFrameSeriesAnimator.NormalisePosition(extrusionArchive.metadata, stop.position),
43694
43750
  color: Color$1.ColorFromStr(stop.color)
43695
43751
  })).filter((stop) => Boolean(stop.color))
@@ -43705,7 +43761,7 @@ function syncDisplacedSurface(params) {
43705
43761
  * @param entity
43706
43762
  * @param heightRef
43707
43763
  */
43708
- function surfacePlacement(entity, heightRef) {
43764
+ function surfacePlacement(entity, heightRef, datumHeight) {
43709
43765
  const rawAltitude = Entity$1.GetValue({
43710
43766
  entity,
43711
43767
  path: ["Bruce", "Location", "altitude"]
@@ -43717,32 +43773,18 @@ function surfacePlacement(entity, heightRef) {
43717
43773
  if (heightRef === HeightReference.RELATIVE_TO_GROUND) {
43718
43774
  return { baseHeight: altitude, followGround: true };
43719
43775
  }
43720
- return { baseHeight: altitude, followGround: false };
43776
+ // Values that ARE heights against a datum already say where they belong, so adding the entity's
43777
+ // altitude on top would move a measured surface off the datum it was measured against.
43778
+ return { baseHeight: datumHeight ? 0 : altitude, followGround: false };
43721
43779
  }
43722
- /**
43723
- * The archive's own extent when it recorded one, otherwise the polygon's own bounds so archives
43724
- * generated before the extent was written still render somewhere sensible.
43725
- * @param metadata
43726
- * @param posses
43727
- */
43728
43780
  /*
43729
- * The factor a displaced surface should use, honouring an explicit style setting first.
43730
- *
43731
- * An elevation is a real height against a datum, so scaling it is not a display choice: it lifts the
43732
- * surface off the datum it belongs to. Only a thickness is safe to exaggerate, which is why an
43733
- * elevation archive defaults to 1 rather than to a derived factor.
43781
+ * The factor a displaced surface should use, which is the style's or nothing.
43734
43782
  */
43735
- function exaggerationFor(style, metadata, extent) {
43783
+ function exaggerationFor(style) {
43736
43784
  if (style.extrusionExaggeration != null) {
43737
43785
  return style.extrusionExaggeration;
43738
43786
  }
43739
- if (metadata.Quantity === TextureFrameSeriesAnimator.QUANTITY_ELEVATION) {
43740
- return 1;
43741
- }
43742
- if (!extent) {
43743
- return undefined;
43744
- }
43745
- return DisplacedSurfacePrimitive.autoExaggeration(extent, metadata.ValueMin, metadata.ValueMax);
43787
+ return 1;
43746
43788
  }
43747
43789
  /*
43748
43790
  * The lon/lat bounding rectangle of a ring, which is the frame Cesium drapes an image material in.
@@ -43843,7 +43885,6 @@ function syncTextureFrameArchive(cEntity, frameArchive, viewer, textureColorMask
43843
43885
  metadata: frameArchive.metadata,
43844
43886
  cellBorder,
43845
43887
  cellTexels,
43846
- baselineMask: frameArchive.metadata.BaselineMask,
43847
43888
  maskBaseline: maskTextureBaseline,
43848
43889
  produceValueCanvas,
43849
43890
  drapeExtent
@@ -43904,12 +43945,10 @@ function syncTextureValueLabels(params) {
43904
43945
  }
43905
43946
  const labels = new TextureValueLabels.Labels({
43906
43947
  viewer, extent, settings, metadata,
43907
- tiles: TextureFrameSeriesAnimator.IsTiledLayout(metadata)
43908
- ? metadata.Tiles.map((tile) => ({
43909
- West: tile.West, East: tile.East, South: tile.South, North: tile.North,
43910
- ResolutionX: tile.ResolutionX, ResolutionY: tile.ResolutionY
43911
- }))
43912
- : undefined,
43948
+ tiles: TextureFrameSeriesAnimator.TilesOf(metadata).map((tile) => ({
43949
+ West: tile.West, East: tile.East, South: tile.South, North: tile.North,
43950
+ ResolutionX: tile.ResolutionX, ResolutionY: tile.ResolutionY
43951
+ })),
43913
43952
  clipRing: params.clipRing
43914
43953
  });
43915
43954
  let lastVersion = -1;
@@ -44043,10 +44082,14 @@ async function resolveTextureValue(params) {
44043
44082
  url = clientFile.URL;
44044
44083
  const clientFileData = clientFile.Data;
44045
44084
  if (TextureFrameSeriesAnimator.IsFrameArchiveMetadata(clientFileData)) {
44085
+ const adapted = TextureFrameSeriesAnimator.Adapt(clientFileData.generation);
44086
+ if (!adapted) {
44087
+ return { dataUri: null, effective: textureTrace.effective };
44088
+ }
44046
44089
  return {
44047
44090
  dataUri: null,
44048
44091
  effective: textureTrace.effective,
44049
- frameArchive: { url, metadata: clientFileData.generation }
44092
+ frameArchive: { url, metadata: adapted }
44050
44093
  };
44051
44094
  }
44052
44095
  }
@@ -44075,7 +44118,11 @@ async function resolveTextureCondition(params) {
44075
44118
  const url = clientFile.URL;
44076
44119
  const clientFileData = clientFile.Data;
44077
44120
  if (TextureFrameSeriesAnimator.IsFrameArchiveMetadata(clientFileData)) {
44078
- return { dataUri: null, effective: null, frameArchive: { url, metadata: clientFileData.generation } };
44121
+ const adapted = TextureFrameSeriesAnimator.Adapt(clientFileData.generation);
44122
+ if (adapted) {
44123
+ return { dataUri: null, effective: null, frameArchive: { url, metadata: adapted } };
44124
+ }
44125
+ return { dataUri: null, effective: null };
44079
44126
  }
44080
44127
  const cacheKey = "texture-" + url + "-none";
44081
44128
  let prom = _textureCache.Get(cacheKey);
@@ -45559,7 +45606,7 @@ var StyleUtils;
45559
45606
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
45560
45607
  })(StyleUtils || (StyleUtils = {}));
45561
45608
 
45562
- const VERSION = "7.2.2";
45609
+ const VERSION = "7.2.3";
45563
45610
  /**
45564
45611
  * Updates the environment instance used by bruce-cesium to one specified.
45565
45612
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
@@ -45576,5 +45623,5 @@ const getENVIRONMENT = () => {
45576
45623
  return ENVIRONMENT;
45577
45624
  };
45578
45625
 
45579
- export { VERSION, setENVIRONMENT, getENVIRONMENT, CesiumAnimatedInOut, DisplacedSurfacePrimitive, CesiumAnimatedProperty, isStyleChanged, isOutlineChanged$1 as isOutlineChanged, StyleEffective, EntityRenderEngine, EntityRenderEngineModel3d, EntityRenderEnginePoint, EntityRenderEnginePolygon, EntityRenderEnginePolyline, TextureValueLabels, MenuItemCreator, MenuItemManager, CesiumParabola, EntityLabel, LiveCursor, SharedGetters, DataSourceStaticKmlManager, DataLabRenderManager, EntitiesIdsRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, AssemblyRenderManager, GoogleSearchRenderManager, RelationsRenderManager, RenderManager, TilesetArbRenderManager, TilesetCadRenderManager, TilesetEntitiesRenderManager, TilesetGooglePhotosRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TileRenderEngine, createTileset, TilesetRenderEngine, ViewRenderEngine, VisualRegisterCuller, VisualsRegister, XGridsRenderEngine, CesiumEntityStyler, DrawingUtils, EntityUtils, MeasureUtils, StyleUtils, CESIUM_INSPECTOR_KEY, CESIUM_TIMELINE_KEY, CESIUM_TIMELINE_LIVE_KEY, CESIUM_TIMELINE_LIVE_PADDING_KEY, CESIUM_TIMELINE_INTERVAL_KEY, CESIUM_MODEL_SPACE_KEY, DEFAULT_LIVE_PADDING_SECONDS, DEFAULT_BRIGHTNESS_SHIFT, DEFAULT_LIGHT_INTENSITY, LIGHTING_SETTINGS_VERSION, LIGHT_INTENSITY_COMPENSATION, MAX_COMPENSATED_LIGHT_INTENSITY, ViewUtils, CesiumViewMonitor, ViewGroundArea, ViewerEventTracker, ViewerUtils, Draw3dPolygon, Draw3dPolyline, MeasureCreator, Walkthrough, WidgetControlViewBar, WidgetControlViewBarSearch, WidgetLeftPanelTab, WidgetLeftPanelTabBookmarks, WidgetLeftPanelTabDashboard, EMenuItemState, WidgetLeftPanelTabMenuItems, Widget, VIEWER_BOOKMARKS_WIDGET_KEY, WidgetBookmarks, WidgetBranding, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, WidgetLeftPanel, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar };
45626
+ export { VERSION, setENVIRONMENT, getENVIRONMENT, CesiumAnimatedInOut, DisplacedSurfacePrimitive, CesiumAnimatedProperty, isStyleChanged, isOutlineChanged$1 as isOutlineChanged, StyleEffective, EntityRenderEngine, EntityRenderEngineModel3d, EntityRenderEnginePoint, EntityRenderEnginePolygon, EntityRenderEnginePolyline, TextureFrameSeriesAnimator, TextureValueLabels, MenuItemCreator, MenuItemManager, CesiumParabola, EntityLabel, LiveCursor, SharedGetters, DataSourceStaticKmlManager, DataLabRenderManager, EntitiesIdsRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, AssemblyRenderManager, GoogleSearchRenderManager, RelationsRenderManager, RenderManager, TilesetArbRenderManager, TilesetCadRenderManager, TilesetEntitiesRenderManager, TilesetGooglePhotosRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TileRenderEngine, createTileset, TilesetRenderEngine, ViewRenderEngine, VisualRegisterCuller, VisualsRegister, XGridsRenderEngine, CesiumEntityStyler, DrawingUtils, EntityUtils, MeasureUtils, StyleUtils, CESIUM_INSPECTOR_KEY, CESIUM_TIMELINE_KEY, CESIUM_TIMELINE_LIVE_KEY, CESIUM_TIMELINE_LIVE_PADDING_KEY, CESIUM_TIMELINE_INTERVAL_KEY, CESIUM_MODEL_SPACE_KEY, DEFAULT_LIVE_PADDING_SECONDS, DEFAULT_BRIGHTNESS_SHIFT, DEFAULT_LIGHT_INTENSITY, LIGHTING_SETTINGS_VERSION, LIGHT_INTENSITY_COMPENSATION, MAX_COMPENSATED_LIGHT_INTENSITY, ViewUtils, CesiumViewMonitor, ViewGroundArea, ViewerEventTracker, ViewerUtils, Draw3dPolygon, Draw3dPolyline, MeasureCreator, Walkthrough, WidgetControlViewBar, WidgetControlViewBarSearch, WidgetLeftPanelTab, WidgetLeftPanelTabBookmarks, WidgetLeftPanelTabDashboard, EMenuItemState, WidgetLeftPanelTabMenuItems, Widget, VIEWER_BOOKMARKS_WIDGET_KEY, WidgetBookmarks, WidgetBranding, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, WidgetLeftPanel, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar };
45580
45627
  //# sourceMappingURL=bruce-cesium.es5.js.map