bruce-cesium 7.2.8 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bruce-cesium.es5.js +539 -27
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +537 -25
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/displaced-surface-primitive.js +508 -24
- package/dist/lib/rendering/displaced-surface-primitive.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-polygon.js +28 -0
- package/dist/lib/rendering/entity-render-engine-polygon.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/displaced-surface-primitive.d.ts +44 -1
- package/dist/types/rendering/entity-render-engine-polygon.d.ts +15 -0
- package/package.json +1 -1
package/dist/bruce-cesium.es5.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Cesium from 'cesium';
|
|
2
|
-
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature,
|
|
3
|
-
import { Cartes, Entity as Entity$1, ProjectViewTile, ENVIRONMENT,
|
|
2
|
+
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, DistanceDisplayCondition, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, Matrix4, HeightReference, ColorBlendMode, ShadowMode, ClassificationType, Model, ShaderSource, Ellipsoid, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, Cartesian2, Cartesian4, ArcType, CornerType, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, SceneMode, GeoJsonDataSource, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Intersect, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, 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, Api, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, ClientFileValueMap, Color as Color$1, BruceEvent, EntityCoords, Bounds, DelayQueue, DataLab, BruceApi, EntityRelation, EntitySource, AccountConcept, RecordChangeFeed, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, ProjectViewBookmarkGroup, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType, EntityHistoricData } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -42468,7 +42468,7 @@ var TextureValueLabels;
|
|
|
42468
42468
|
var DisplacedSurfacePrimitive;
|
|
42469
42469
|
(function (DisplacedSurfacePrimitive) {
|
|
42470
42470
|
// Grid densities a tile can draw at, coarsest first.
|
|
42471
|
-
const TIERS = [32, 64, 128, 192];
|
|
42471
|
+
const TIERS = [32, 64, 128, 192, 256, 384];
|
|
42472
42472
|
// Tiles per side the extent is cut into.
|
|
42473
42473
|
const TILES_PER_SIDE = 6;
|
|
42474
42474
|
// Screen pixels one grid cell should cover. Lower means finer meshes sooner.
|
|
@@ -42488,6 +42488,17 @@ var DisplacedSurfacePrimitive;
|
|
|
42488
42488
|
// Most-detailed would fetch every tile under a parcel that can be a hundred kilometres across.
|
|
42489
42489
|
const GROUND_SAMPLE_LEVEL = 11;
|
|
42490
42490
|
// Height window the packed ground texture covers, wide enough for any terrain on Earth.
|
|
42491
|
+
// Ground samples across the clearance regions rather than the whole extent.
|
|
42492
|
+
const MASK_GROUND_SAMPLES_PER_SIDE = 128;
|
|
42493
|
+
// Finest and coarsest terrain level a clearance raster is sampled at, and how many terrain tiles it is allowed to pull.
|
|
42494
|
+
const MASK_GROUND_LEVEL_MAX = 13;
|
|
42495
|
+
const MASK_GROUND_LEVEL_MIN = 8;
|
|
42496
|
+
const MASK_GROUND_TILE_BUDGET = 64;
|
|
42497
|
+
// Longest side of the rasterised region mask. The mask decides whether a texel is held up, so it
|
|
42498
|
+
// wants to be finer than the value raster it is compared against.
|
|
42499
|
+
const MASK_TEXTURE_MAX_SIDE = 1024;
|
|
42500
|
+
// Stands in for "no floor" and "no clearance", far below anything the sheet can reach.
|
|
42501
|
+
const NO_LIMIT_METRES = -1e6;
|
|
42491
42502
|
const GROUND_MIN_METRES = -1000;
|
|
42492
42503
|
const GROUND_MAX_METRES = 9000;
|
|
42493
42504
|
const DEFAULT_LOW_COLOR = { red: 255, green: 255, blue: 255, alpha: 0.12 };
|
|
@@ -42510,6 +42521,19 @@ uniform float u_skirtDepth;
|
|
|
42510
42521
|
uniform float u_groundWeight;
|
|
42511
42522
|
uniform vec2 u_groundRange;
|
|
42512
42523
|
uniform vec2 u_groundSize;
|
|
42524
|
+
uniform sampler2D u_maskTexture;
|
|
42525
|
+
uniform sampler2D u_maskGroundTexture;
|
|
42526
|
+
uniform float u_maskWeight;
|
|
42527
|
+
uniform float u_maskGroundWeight;
|
|
42528
|
+
uniform float u_maskFill;
|
|
42529
|
+
uniform float u_maskFillValue;
|
|
42530
|
+
uniform float u_maskClearance;
|
|
42531
|
+
uniform float u_maskFloor;
|
|
42532
|
+
uniform vec2 u_maskGroundSize;
|
|
42533
|
+
// West, East, North, South in degrees, for the surface and for the sampled region box.
|
|
42534
|
+
uniform vec4 u_extentDegrees;
|
|
42535
|
+
uniform vec4 u_maskGroundDegrees;
|
|
42536
|
+
uniform float u_coverageCutoffVertex;
|
|
42513
42537
|
|
|
42514
42538
|
out vec2 v_st;
|
|
42515
42539
|
out float v_value;
|
|
@@ -42539,6 +42563,46 @@ float sampleGround(vec2 uv) {
|
|
|
42539
42563
|
return mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y);
|
|
42540
42564
|
}
|
|
42541
42565
|
|
|
42566
|
+
/*
|
|
42567
|
+
* Height of the terrain under a point of the surface, read from the region's own ground raster.
|
|
42568
|
+
*
|
|
42569
|
+
* Sampled over the regions rather than over the whole extent, so the raster is fine enough for a
|
|
42570
|
+
* clearance test to mean something.
|
|
42571
|
+
*/
|
|
42572
|
+
float sampleMaskGround(vec2 uv) {
|
|
42573
|
+
float longitude = mix(u_extentDegrees.x, u_extentDegrees.y, uv.x);
|
|
42574
|
+
float latitude = mix(u_extentDegrees.z, u_extentDegrees.w, uv.y);
|
|
42575
|
+
vec2 inBox = vec2(
|
|
42576
|
+
(longitude - u_maskGroundDegrees.x) / max(u_maskGroundDegrees.y - u_maskGroundDegrees.x, 1e-9),
|
|
42577
|
+
(u_maskGroundDegrees.z - latitude) / max(u_maskGroundDegrees.z - u_maskGroundDegrees.w, 1e-9));
|
|
42578
|
+
vec2 clamped = clamp(inBox, vec2(0.0), vec2(1.0));
|
|
42579
|
+
vec2 texel = 1.0 / u_maskGroundSize;
|
|
42580
|
+
vec2 coord = clamped * u_maskGroundSize - 0.5;
|
|
42581
|
+
vec2 base = floor(coord);
|
|
42582
|
+
vec2 f = coord - base;
|
|
42583
|
+
vec2 origin = (base + 0.5) * texel;
|
|
42584
|
+
vec4 t00 = texture(u_maskGroundTexture, origin);
|
|
42585
|
+
vec4 t10 = texture(u_maskGroundTexture, origin + vec2(texel.x, 0.0));
|
|
42586
|
+
vec4 t01 = texture(u_maskGroundTexture, origin + vec2(0.0, texel.y));
|
|
42587
|
+
vec4 t11 = texture(u_maskGroundTexture, origin + texel);
|
|
42588
|
+
// One unknown corner makes the interpolation meaningless, so the whole point is treated as
|
|
42589
|
+
// unsampled and answers low enough that no clearance built on it can win.
|
|
42590
|
+
float known = min(min(t00.a, t10.a), min(t01.a, t11.a));
|
|
42591
|
+
if (known < 0.5) {
|
|
42592
|
+
return u_groundRange.x;
|
|
42593
|
+
}
|
|
42594
|
+
vec3 p00 = t00.rgb * 255.0;
|
|
42595
|
+
vec3 p10 = t10.rgb * 255.0;
|
|
42596
|
+
vec3 p01 = t01.rgb * 255.0;
|
|
42597
|
+
vec3 p11 = t11.rgb * 255.0;
|
|
42598
|
+
vec3 weights = vec3(65536.0, 256.0, 1.0);
|
|
42599
|
+
float h00 = u_groundRange.x + dot(p00, weights) / 16777215.0 * (u_groundRange.y - u_groundRange.x);
|
|
42600
|
+
float h10 = u_groundRange.x + dot(p10, weights) / 16777215.0 * (u_groundRange.y - u_groundRange.x);
|
|
42601
|
+
float h01 = u_groundRange.x + dot(p01, weights) / 16777215.0 * (u_groundRange.y - u_groundRange.x);
|
|
42602
|
+
float h11 = u_groundRange.x + dot(p11, weights) / 16777215.0 * (u_groundRange.y - u_groundRange.x);
|
|
42603
|
+
return mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y);
|
|
42604
|
+
}
|
|
42605
|
+
|
|
42542
42606
|
/*
|
|
42543
42607
|
* The texel's normalised value, whichever way the archive packed it.
|
|
42544
42608
|
*
|
|
@@ -42558,8 +42622,16 @@ float decodeValue(vec4 texel) {
|
|
|
42558
42622
|
void main() {
|
|
42559
42623
|
vec4 texel = texture(u_valueTexture, st);
|
|
42560
42624
|
v_st = st;
|
|
42561
|
-
|
|
42562
|
-
|
|
42625
|
+
|
|
42626
|
+
// Inside a region the scene knows is water, a texel with no value still has to paint, or the
|
|
42627
|
+
// hole the region exists to close is still a hole.
|
|
42628
|
+
// The value it paints is the shallowest the ramp is not transparent at.
|
|
42629
|
+
float inMask = u_maskWeight * texture(u_maskTexture, st).a;
|
|
42630
|
+
float hasData = step(u_coverageCutoffVertex, texel.a);
|
|
42631
|
+
float raw = decodeValue(texel);
|
|
42632
|
+
float filled = mix(u_maskFillValue, max(raw, u_maskFillValue), hasData);
|
|
42633
|
+
v_value = mix(raw, filled, inMask * u_maskFill);
|
|
42634
|
+
v_coverage = max(texel.a, inMask * u_maskFill);
|
|
42563
42635
|
|
|
42564
42636
|
// Exaggeration stretches the span above the archive's minimum rather than the height itself. On an
|
|
42565
42637
|
// elevation the height is measured from the ellipsoid, tens of metres from any of the data, so
|
|
@@ -42572,8 +42644,14 @@ void main() {
|
|
|
42572
42644
|
|
|
42573
42645
|
// Coverage scales the displacement only where it is measured from the terrain, because there a
|
|
42574
42646
|
// zero means the surface sits on the ground.
|
|
42575
|
-
float coverageScale = mix(1.0,
|
|
42576
|
-
float
|
|
42647
|
+
float coverageScale = mix(1.0, v_coverage, u_groundWeight);
|
|
42648
|
+
float placed = u_baseHeight + ground + metres * coverageScale;
|
|
42649
|
+
|
|
42650
|
+
// Held above whichever is higher, the region's own floor or the terrain under it plus a margin.
|
|
42651
|
+
// Only inside the region: lifting the whole sheet would raise it over dry land as well.
|
|
42652
|
+
float held = max(u_maskFloor, sampleMaskGround(st) * u_maskGroundWeight + u_maskClearance);
|
|
42653
|
+
float lifted = mix(placed, max(placed, held), step(0.5, inMask));
|
|
42654
|
+
float displacement = lifted - skirt * u_skirtDepth;
|
|
42577
42655
|
|
|
42578
42656
|
// Added to the LOW half of the encoded position: a metre-scale offset added to the high half
|
|
42579
42657
|
// would be lost to float32 rounding at an earth radius.
|
|
@@ -42808,6 +42886,147 @@ void main() {
|
|
|
42808
42886
|
GeometryPipeline.encodeAttribute(geometry, "position", "position3DHigh", "position3DLow");
|
|
42809
42887
|
return geometry;
|
|
42810
42888
|
}
|
|
42889
|
+
/*
|
|
42890
|
+
* Where the ramp first paints something, as a normalised value.
|
|
42891
|
+
*
|
|
42892
|
+
* A style with a hidden floor is transparent over its lowest band, so filling a gap at zero would
|
|
42893
|
+
* fill it with nothing. This is the lowest value that actually shows.
|
|
42894
|
+
*/
|
|
42895
|
+
function firstOpaqueStop(ramp) {
|
|
42896
|
+
const stops = ramp.length / 4;
|
|
42897
|
+
for (let i = 0; i < stops; i++) {
|
|
42898
|
+
if (ramp[i * 4 + 3] > 0) {
|
|
42899
|
+
return stops > 1 ? i / (stops - 1) : 0;
|
|
42900
|
+
}
|
|
42901
|
+
}
|
|
42902
|
+
return 0;
|
|
42903
|
+
}
|
|
42904
|
+
/*
|
|
42905
|
+
* Rasterises the clearance regions into a mask over the surface's extent, alpha inside.
|
|
42906
|
+
*
|
|
42907
|
+
* Drawn north row first, matching the value raster's own row order, so one set of texture
|
|
42908
|
+
* coordinates indexes both.
|
|
42909
|
+
*/
|
|
42910
|
+
function rasteriseMask(extent, regions) {
|
|
42911
|
+
const spanX = extent.East - extent.West;
|
|
42912
|
+
const spanY = extent.North - extent.South;
|
|
42913
|
+
if (!(spanX > 0) || !(spanY > 0) || !regions.length) {
|
|
42914
|
+
return null;
|
|
42915
|
+
}
|
|
42916
|
+
// No document at all off the page, and the regions are still worth holding: the mask can be
|
|
42917
|
+
// rasterised the next time they are set, and until then the surface simply lifts nothing.
|
|
42918
|
+
if (typeof document === "undefined") {
|
|
42919
|
+
return null;
|
|
42920
|
+
}
|
|
42921
|
+
const wide = spanX >= spanY;
|
|
42922
|
+
const width = wide ? MASK_TEXTURE_MAX_SIDE : Math.max(1, Math.round(MASK_TEXTURE_MAX_SIDE * spanX / spanY));
|
|
42923
|
+
const height = wide ? Math.max(1, Math.round(MASK_TEXTURE_MAX_SIDE * spanY / spanX)) : MASK_TEXTURE_MAX_SIDE;
|
|
42924
|
+
const canvas = document.createElement("canvas");
|
|
42925
|
+
canvas.width = width;
|
|
42926
|
+
canvas.height = height;
|
|
42927
|
+
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
42928
|
+
if (!ctx) {
|
|
42929
|
+
return null;
|
|
42930
|
+
}
|
|
42931
|
+
ctx.clearRect(0, 0, width, height);
|
|
42932
|
+
ctx.fillStyle = "#ffffff";
|
|
42933
|
+
for (const region of regions) {
|
|
42934
|
+
const rings = region.rings || [];
|
|
42935
|
+
if (!rings.length) {
|
|
42936
|
+
continue;
|
|
42937
|
+
}
|
|
42938
|
+
ctx.beginPath();
|
|
42939
|
+
for (const ring of rings) {
|
|
42940
|
+
for (let i = 0; i + 1 < ring.length; i += 2) {
|
|
42941
|
+
const x = (ring[i] - extent.West) / spanX * width;
|
|
42942
|
+
const y = (extent.North - ring[i + 1]) / spanY * height;
|
|
42943
|
+
if (i === 0) {
|
|
42944
|
+
ctx.moveTo(x, y);
|
|
42945
|
+
}
|
|
42946
|
+
else {
|
|
42947
|
+
ctx.lineTo(x, y);
|
|
42948
|
+
}
|
|
42949
|
+
}
|
|
42950
|
+
ctx.closePath();
|
|
42951
|
+
}
|
|
42952
|
+
// Even odd, so a ring inside a ring is a hole without the caller having to wind them.
|
|
42953
|
+
ctx.fill("evenodd");
|
|
42954
|
+
}
|
|
42955
|
+
return { width, height, data: new Uint8Array(ctx.getImageData(0, 0, width, height).data.buffer.slice(0)) };
|
|
42956
|
+
}
|
|
42957
|
+
/*
|
|
42958
|
+
* The box every region fits inside, clipped to the surface, so the ground under them can be
|
|
42959
|
+
* sampled without sampling the whole extent.
|
|
42960
|
+
*/
|
|
42961
|
+
function boxOf(extent, regions) {
|
|
42962
|
+
let west = Infinity;
|
|
42963
|
+
let east = -Infinity;
|
|
42964
|
+
let south = Infinity;
|
|
42965
|
+
let north = -Infinity;
|
|
42966
|
+
for (const region of regions) {
|
|
42967
|
+
for (const ring of region.rings || []) {
|
|
42968
|
+
for (let i = 0; i + 1 < ring.length; i += 2) {
|
|
42969
|
+
west = Math.min(west, ring[i]);
|
|
42970
|
+
east = Math.max(east, ring[i]);
|
|
42971
|
+
south = Math.min(south, ring[i + 1]);
|
|
42972
|
+
north = Math.max(north, ring[i + 1]);
|
|
42973
|
+
}
|
|
42974
|
+
}
|
|
42975
|
+
}
|
|
42976
|
+
if (!isFinite(west) || !isFinite(south)) {
|
|
42977
|
+
return null;
|
|
42978
|
+
}
|
|
42979
|
+
return {
|
|
42980
|
+
West: Math.max(west, extent.West),
|
|
42981
|
+
East: Math.min(east, extent.East),
|
|
42982
|
+
South: Math.max(south, extent.South),
|
|
42983
|
+
North: Math.min(north, extent.North)
|
|
42984
|
+
};
|
|
42985
|
+
}
|
|
42986
|
+
/*
|
|
42987
|
+
* Packs sampled terrain heights into a texture's RGB, three bytes a height.
|
|
42988
|
+
*
|
|
42989
|
+
* A height needs more than eight bits to be useful and the surface reads it in the vertex shader,
|
|
42990
|
+
* where float textures are not guaranteed, so it goes in as a fixed point integer.
|
|
42991
|
+
*/
|
|
42992
|
+
function packHeights(sampled) {
|
|
42993
|
+
const pixels = new Uint8Array(sampled.length * 4);
|
|
42994
|
+
const span = GROUND_MAX_METRES - GROUND_MIN_METRES;
|
|
42995
|
+
for (let i = 0; i < sampled.length; i++) {
|
|
42996
|
+
const height = sampled[i] ? sampled[i].height : undefined;
|
|
42997
|
+
const known = typeof height === "number" && isFinite(height);
|
|
42998
|
+
const clamped = Math.min(GROUND_MAX_METRES, Math.max(GROUND_MIN_METRES, known ? height : 0));
|
|
42999
|
+
const packed = Math.round(((clamped - GROUND_MIN_METRES) / span) * 16777215);
|
|
43000
|
+
pixels[i * 4] = (packed >> 16) & 255;
|
|
43001
|
+
pixels[i * 4 + 1] = (packed >> 8) & 255;
|
|
43002
|
+
pixels[i * 4 + 2] = packed & 255;
|
|
43003
|
+
pixels[i * 4 + 3] = known ? 255 : 0;
|
|
43004
|
+
}
|
|
43005
|
+
return pixels;
|
|
43006
|
+
}
|
|
43007
|
+
/*
|
|
43008
|
+
* The finest terrain level a box can be sampled at inside the tile budget.
|
|
43009
|
+
*
|
|
43010
|
+
* Asked of the provider's own tiling scheme where it offers one, since a terrain set is free to
|
|
43011
|
+
* tile the world differently from the default two by one.
|
|
43012
|
+
*/
|
|
43013
|
+
function groundLevelFor(box, provider) {
|
|
43014
|
+
const scheme = provider && provider.tilingScheme;
|
|
43015
|
+
for (let level = MASK_GROUND_LEVEL_MAX; level > MASK_GROUND_LEVEL_MIN; level--) {
|
|
43016
|
+
const across = scheme && typeof scheme.getNumberOfXTilesAtLevel === "function"
|
|
43017
|
+
? scheme.getNumberOfXTilesAtLevel(level)
|
|
43018
|
+
: Math.pow(2, level + 1);
|
|
43019
|
+
const down = scheme && typeof scheme.getNumberOfYTilesAtLevel === "function"
|
|
43020
|
+
? scheme.getNumberOfYTilesAtLevel(level)
|
|
43021
|
+
: Math.pow(2, level);
|
|
43022
|
+
const tiles = Math.ceil((box.East - box.West) / (360 / across) + 1)
|
|
43023
|
+
* Math.ceil((box.North - box.South) / (180 / down) + 1);
|
|
43024
|
+
if (tiles <= MASK_GROUND_TILE_BUDGET) {
|
|
43025
|
+
return level;
|
|
43026
|
+
}
|
|
43027
|
+
}
|
|
43028
|
+
return MASK_GROUND_LEVEL_MIN;
|
|
43029
|
+
}
|
|
42811
43030
|
class Surface {
|
|
42812
43031
|
constructor(options, hasCoverage) {
|
|
42813
43032
|
var _a, _b, _c, _d;
|
|
@@ -42826,6 +43045,14 @@ void main() {
|
|
|
42826
43045
|
this.groundTexture = null;
|
|
42827
43046
|
this.groundPixels = null;
|
|
42828
43047
|
this.groundRequested = false;
|
|
43048
|
+
this.groundClearance = null;
|
|
43049
|
+
this.maskTexture = null;
|
|
43050
|
+
this.maskPixels = null;
|
|
43051
|
+
this.maskGroundTexture = null;
|
|
43052
|
+
this.maskGroundPixels = null;
|
|
43053
|
+
this.maskGroundBox = null;
|
|
43054
|
+
this.maskGroundRequested = false;
|
|
43055
|
+
this.maskGroundLevel = 0;
|
|
42829
43056
|
this.followGround = Boolean(options.followGround);
|
|
42830
43057
|
this.terrainProvider = options.terrainProvider || null;
|
|
42831
43058
|
this.extent = options.extent;
|
|
@@ -42838,7 +43065,9 @@ void main() {
|
|
|
42838
43065
|
this.pixelPlacement = options.pixelPlacement;
|
|
42839
43066
|
this.tileSkirts = Boolean(options.tileSkirts);
|
|
42840
43067
|
this.rampPixels = RampLookup(options.rampStops || null, options.lowColor || DEFAULT_LOW_COLOR, options.highColor || DEFAULT_HIGH_COLOR);
|
|
43068
|
+
this.maskFillValue = firstOpaqueStop(this.rampPixels);
|
|
42841
43069
|
this.tiles = buildTiles(hasCoverage);
|
|
43070
|
+
this.SetGroundClearance(options.groundClearance || null);
|
|
42842
43071
|
}
|
|
42843
43072
|
GetFollowsGround() {
|
|
42844
43073
|
return this.followGround;
|
|
@@ -42861,6 +43090,97 @@ void main() {
|
|
|
42861
43090
|
SetBaseHeight(baseHeight) {
|
|
42862
43091
|
this.baseHeight = baseHeight;
|
|
42863
43092
|
}
|
|
43093
|
+
GetGroundClearance() {
|
|
43094
|
+
return this.groundClearance;
|
|
43095
|
+
}
|
|
43096
|
+
/*
|
|
43097
|
+
* The terrain level the clearance regions were sampled at, once they have been.
|
|
43098
|
+
*
|
|
43099
|
+
* Worth reading rather than assuming: the level is chosen from how big the regions are, so a
|
|
43100
|
+
* region covering a whole sound gets a coarser test than a hand drawn harbour does.
|
|
43101
|
+
*/
|
|
43102
|
+
GetGroundClearanceLevel() {
|
|
43103
|
+
return this.maskGroundLevel;
|
|
43104
|
+
}
|
|
43105
|
+
/*
|
|
43106
|
+
* What the clearance regions were measured against, once they have been.
|
|
43107
|
+
* The heights are read out of whatever the terrain stores, and a terrain referenced to sea
|
|
43108
|
+
* level reads a geoid apart from an archive delivering ellipsoidal metres.
|
|
43109
|
+
*/
|
|
43110
|
+
GetGroundClearanceStats() {
|
|
43111
|
+
if (!this.maskGroundPixels) {
|
|
43112
|
+
return null;
|
|
43113
|
+
}
|
|
43114
|
+
const span = GROUND_MAX_METRES - GROUND_MIN_METRES;
|
|
43115
|
+
let min = Infinity;
|
|
43116
|
+
let max = -Infinity;
|
|
43117
|
+
let samples = 0;
|
|
43118
|
+
for (let i = 0; i < this.maskGroundPixels.length / 4; i++) {
|
|
43119
|
+
if (!this.maskGroundPixels[i * 4 + 3]) {
|
|
43120
|
+
continue;
|
|
43121
|
+
}
|
|
43122
|
+
const packed = (this.maskGroundPixels[i * 4] << 16)
|
|
43123
|
+
+ (this.maskGroundPixels[i * 4 + 1] << 8) + this.maskGroundPixels[i * 4 + 2];
|
|
43124
|
+
const height = GROUND_MIN_METRES + (packed / 16777215) * span;
|
|
43125
|
+
min = Math.min(min, height);
|
|
43126
|
+
max = Math.max(max, height);
|
|
43127
|
+
samples++;
|
|
43128
|
+
}
|
|
43129
|
+
if (!samples) {
|
|
43130
|
+
return null;
|
|
43131
|
+
}
|
|
43132
|
+
return { level: this.maskGroundLevel, min, max, samples };
|
|
43133
|
+
}
|
|
43134
|
+
/*
|
|
43135
|
+
* The real world range the texture's 0 to 1 maps onto, so a caller can compare it against what
|
|
43136
|
+
* the terrain says without having kept its own copy.
|
|
43137
|
+
*/
|
|
43138
|
+
GetValueRange() {
|
|
43139
|
+
return { min: this.valueMin, max: this.valueMax };
|
|
43140
|
+
}
|
|
43141
|
+
/*
|
|
43142
|
+
* Takes a different terrain to measure against.
|
|
43143
|
+
* The clearance raster is sampled once and cached, so a scene that swaps its terrain would
|
|
43144
|
+
* otherwise keep holding the sheet above heights read from the terrain it used to have.
|
|
43145
|
+
*/
|
|
43146
|
+
SetTerrainProvider(provider) {
|
|
43147
|
+
if (provider === this.terrainProvider) {
|
|
43148
|
+
return;
|
|
43149
|
+
}
|
|
43150
|
+
this.terrainProvider = provider;
|
|
43151
|
+
this.groundPixels = null;
|
|
43152
|
+
this.groundRequested = false;
|
|
43153
|
+
this.maskGroundPixels = null;
|
|
43154
|
+
this.maskGroundRequested = false;
|
|
43155
|
+
this.maskGroundLevel = 0;
|
|
43156
|
+
}
|
|
43157
|
+
/*
|
|
43158
|
+
* Takes a new set of clearance regions, or drops them.
|
|
43159
|
+
* The mask is rasterised here rather than on the render thread, and the ground under the
|
|
43160
|
+
* regions is re-requested, so a plugin can hand over regions the moment it has them.
|
|
43161
|
+
*/
|
|
43162
|
+
SetGroundClearance(clearance) {
|
|
43163
|
+
this.groundClearance = clearance && clearance.regions && clearance.regions.length
|
|
43164
|
+
? clearance
|
|
43165
|
+
: null;
|
|
43166
|
+
this.maskPixels = this.groundClearance
|
|
43167
|
+
? rasteriseMask(this.extent, this.groundClearance.regions)
|
|
43168
|
+
: null;
|
|
43169
|
+
if (this.maskTexture) {
|
|
43170
|
+
this.maskTexture.destroy();
|
|
43171
|
+
this.maskTexture = null;
|
|
43172
|
+
}
|
|
43173
|
+
this.maskGroundPixels = null;
|
|
43174
|
+
this.maskGroundRequested = false;
|
|
43175
|
+
this.maskGroundLevel = 0;
|
|
43176
|
+
this.maskGroundBox = this.groundClearance
|
|
43177
|
+
? boxOf(this.extent, this.groundClearance.regions)
|
|
43178
|
+
: null;
|
|
43179
|
+
if (this.maskGroundTexture) {
|
|
43180
|
+
this.maskGroundTexture.destroy();
|
|
43181
|
+
this.maskGroundTexture = null;
|
|
43182
|
+
}
|
|
43183
|
+
}
|
|
42864
43184
|
/**
|
|
42865
43185
|
* Feeds the surface from an animated frame series.
|
|
42866
43186
|
* Height and colour advance with the clock without the caller having to push each frame in.
|
|
@@ -42899,6 +43219,8 @@ void main() {
|
|
|
42899
43219
|
this.syncRampTexture(context);
|
|
42900
43220
|
this.requestGround();
|
|
42901
43221
|
this.syncGroundTexture(context);
|
|
43222
|
+
this.requestMaskGround();
|
|
43223
|
+
this.syncMaskTextures(context);
|
|
42902
43224
|
// A tile needs one mesh before it has a bounding sphere to measure against.
|
|
42903
43225
|
for (const tile of this.tiles) {
|
|
42904
43226
|
if (!tile.centre) {
|
|
@@ -42943,6 +43265,14 @@ void main() {
|
|
|
42943
43265
|
this.groundTexture.destroy();
|
|
42944
43266
|
this.groundTexture = null;
|
|
42945
43267
|
}
|
|
43268
|
+
if (this.maskTexture) {
|
|
43269
|
+
this.maskTexture.destroy();
|
|
43270
|
+
this.maskTexture = null;
|
|
43271
|
+
}
|
|
43272
|
+
if (this.maskGroundTexture) {
|
|
43273
|
+
this.maskGroundTexture.destroy();
|
|
43274
|
+
this.maskGroundTexture = null;
|
|
43275
|
+
}
|
|
42946
43276
|
return undefined;
|
|
42947
43277
|
}
|
|
42948
43278
|
/*
|
|
@@ -42975,24 +43305,123 @@ void main() {
|
|
|
42975
43305
|
if (this.destroyed || !sampled) {
|
|
42976
43306
|
return;
|
|
42977
43307
|
}
|
|
42978
|
-
|
|
42979
|
-
const span = GROUND_MAX_METRES - GROUND_MIN_METRES;
|
|
42980
|
-
for (let i = 0; i < sampled.length; i++) {
|
|
42981
|
-
const height = sampled[i] && isFinite(sampled[i].height) ? sampled[i].height : 0;
|
|
42982
|
-
const clamped = Math.min(GROUND_MAX_METRES, Math.max(GROUND_MIN_METRES, height));
|
|
42983
|
-
const packed = Math.round(((clamped - GROUND_MIN_METRES) / span) * 16777215);
|
|
42984
|
-
pixels[i * 4] = (packed >> 16) & 255;
|
|
42985
|
-
pixels[i * 4 + 1] = (packed >> 8) & 255;
|
|
42986
|
-
pixels[i * 4 + 2] = packed & 255;
|
|
42987
|
-
pixels[i * 4 + 3] = 255;
|
|
42988
|
-
}
|
|
42989
|
-
this.groundPixels = pixels;
|
|
43308
|
+
this.groundPixels = packHeights(sampled);
|
|
42990
43309
|
})
|
|
42991
43310
|
.catch(() => {
|
|
42992
43311
|
// Terrain that cannot be sampled leaves the surface on the ellipsoid, which is
|
|
42993
43312
|
// where a clamped polygon sat before this existed.
|
|
42994
43313
|
});
|
|
42995
43314
|
}
|
|
43315
|
+
/*
|
|
43316
|
+
* Samples the terrain under the clearance regions.
|
|
43317
|
+
*
|
|
43318
|
+
* Its own raster rather than the surface's, because the surface extent here is two degrees
|
|
43319
|
+
* wide and the region is a few kilometres, and a clearance test needs the finer one.
|
|
43320
|
+
*/
|
|
43321
|
+
requestMaskGround() {
|
|
43322
|
+
if (this.maskGroundRequested || !this.groundClearance || !this.maskGroundBox) {
|
|
43323
|
+
return;
|
|
43324
|
+
}
|
|
43325
|
+
if (!(this.groundClearance.clearance > NO_LIMIT_METRES / 2)) {
|
|
43326
|
+
return;
|
|
43327
|
+
}
|
|
43328
|
+
this.maskGroundRequested = true;
|
|
43329
|
+
const sampler = sampleTerrain;
|
|
43330
|
+
if (!this.terrainProvider || typeof sampler !== "function") {
|
|
43331
|
+
return;
|
|
43332
|
+
}
|
|
43333
|
+
const box = this.maskGroundBox;
|
|
43334
|
+
const level = groundLevelFor(box, this.terrainProvider);
|
|
43335
|
+
this.maskGroundLevel = level;
|
|
43336
|
+
const total = MASK_GROUND_SAMPLES_PER_SIDE * MASK_GROUND_SAMPLES_PER_SIDE;
|
|
43337
|
+
const scheme = this.terrainProvider.tilingScheme;
|
|
43338
|
+
const asked = [];
|
|
43339
|
+
// Which slot in the raster each asked-for position belongs to, since the ones the terrain
|
|
43340
|
+
// does not cover are never asked for at all.
|
|
43341
|
+
const slots = [];
|
|
43342
|
+
for (let row = 0; row < MASK_GROUND_SAMPLES_PER_SIDE; row++) {
|
|
43343
|
+
const fy = row / (MASK_GROUND_SAMPLES_PER_SIDE - 1);
|
|
43344
|
+
const latitude = Math$1.lerp(box.North, box.South, fy);
|
|
43345
|
+
for (let col = 0; col < MASK_GROUND_SAMPLES_PER_SIDE; col++) {
|
|
43346
|
+
const fx = col / (MASK_GROUND_SAMPLES_PER_SIDE - 1);
|
|
43347
|
+
const at = Cartographic.fromDegrees(Math$1.lerp(box.West, box.East, fx), latitude);
|
|
43348
|
+
// An imported terrain covers a survey area, so asking outside it answers 404 and
|
|
43349
|
+
// fills the console with failures for points that were never going to have a height.
|
|
43350
|
+
if (scheme && typeof this.terrainProvider.getTileDataAvailable === "function") {
|
|
43351
|
+
const tile = scheme.positionToTileXY(at, level);
|
|
43352
|
+
if (!tile || this.terrainProvider.getTileDataAvailable(tile.x, tile.y, level) === false) {
|
|
43353
|
+
continue;
|
|
43354
|
+
}
|
|
43355
|
+
}
|
|
43356
|
+
asked.push(at);
|
|
43357
|
+
slots.push(row * MASK_GROUND_SAMPLES_PER_SIDE + col);
|
|
43358
|
+
}
|
|
43359
|
+
}
|
|
43360
|
+
if (!asked.length) {
|
|
43361
|
+
return;
|
|
43362
|
+
}
|
|
43363
|
+
Promise.resolve(sampler(this.terrainProvider, level, asked))
|
|
43364
|
+
.then((sampled) => {
|
|
43365
|
+
if (this.destroyed || !sampled) {
|
|
43366
|
+
return;
|
|
43367
|
+
}
|
|
43368
|
+
const spread = new Array(total).fill(undefined);
|
|
43369
|
+
for (let i = 0; i < slots.length; i++) {
|
|
43370
|
+
spread[slots[i]] = sampled[i];
|
|
43371
|
+
}
|
|
43372
|
+
this.maskGroundPixels = packHeights(spread);
|
|
43373
|
+
})
|
|
43374
|
+
.catch(() => {
|
|
43375
|
+
// Unsampled terrain leaves only the region's own floor to hold the sheet up,
|
|
43376
|
+
// which is the behaviour a region with no clearance already has.
|
|
43377
|
+
});
|
|
43378
|
+
}
|
|
43379
|
+
/*
|
|
43380
|
+
* Uploads the region mask and the ground under it, with a one texel stand-in until they land
|
|
43381
|
+
* so the shader always has something bound.
|
|
43382
|
+
*/
|
|
43383
|
+
syncMaskTextures(context) {
|
|
43384
|
+
if (!this.maskTexture) {
|
|
43385
|
+
const held = this.maskPixels;
|
|
43386
|
+
this.maskTexture = new Texture({
|
|
43387
|
+
context,
|
|
43388
|
+
pixelFormat: PixelFormat.RGBA,
|
|
43389
|
+
source: held
|
|
43390
|
+
? { width: held.width, height: held.height, arrayBufferView: held.data }
|
|
43391
|
+
: { width: 1, height: 1, arrayBufferView: new Uint8Array([0, 0, 0, 0]) },
|
|
43392
|
+
flipY: false,
|
|
43393
|
+
sampler: new Sampler({
|
|
43394
|
+
wrapS: TextureWrap.CLAMP_TO_EDGE,
|
|
43395
|
+
wrapT: TextureWrap.CLAMP_TO_EDGE
|
|
43396
|
+
})
|
|
43397
|
+
});
|
|
43398
|
+
}
|
|
43399
|
+
if (this.maskGroundTexture && (!this.maskGroundPixels
|
|
43400
|
+
|| this.maskGroundTexture.width === MASK_GROUND_SAMPLES_PER_SIDE)) {
|
|
43401
|
+
return;
|
|
43402
|
+
}
|
|
43403
|
+
if (this.maskGroundTexture) {
|
|
43404
|
+
this.maskGroundTexture.destroy();
|
|
43405
|
+
}
|
|
43406
|
+
const size = this.maskGroundPixels ? MASK_GROUND_SAMPLES_PER_SIDE : 1;
|
|
43407
|
+
this.maskGroundTexture = new Texture({
|
|
43408
|
+
context,
|
|
43409
|
+
pixelFormat: PixelFormat.RGBA,
|
|
43410
|
+
source: {
|
|
43411
|
+
width: size,
|
|
43412
|
+
height: size,
|
|
43413
|
+
arrayBufferView: this.maskGroundPixels || packHeights([{ height: 0 }])
|
|
43414
|
+
},
|
|
43415
|
+
flipY: false,
|
|
43416
|
+
sampler: new Sampler({
|
|
43417
|
+
wrapS: TextureWrap.CLAMP_TO_EDGE,
|
|
43418
|
+
wrapT: TextureWrap.CLAMP_TO_EDGE,
|
|
43419
|
+
// Nearest, because the shader interpolates decoded heights itself.
|
|
43420
|
+
minificationFilter: TextureMinificationFilter.NEAREST,
|
|
43421
|
+
magnificationFilter: TextureMagnificationFilter.NEAREST
|
|
43422
|
+
})
|
|
43423
|
+
});
|
|
43424
|
+
}
|
|
42996
43425
|
/*
|
|
42997
43426
|
* Uploads whatever ground samples exist, and a flat stand-in until they arrive, so the
|
|
42998
43427
|
* shader always has a texture bound whether or not this surface follows the ground.
|
|
@@ -43004,10 +43433,8 @@ void main() {
|
|
|
43004
43433
|
if (this.groundTexture) {
|
|
43005
43434
|
this.groundTexture.destroy();
|
|
43006
43435
|
}
|
|
43007
|
-
const zero = Math.round(((0 - GROUND_MIN_METRES) / (GROUND_MAX_METRES - GROUND_MIN_METRES)) * 16777215);
|
|
43008
43436
|
const size = this.groundPixels ? GROUND_SAMPLES_PER_SIDE : 1;
|
|
43009
|
-
const arrayBufferView = this.groundPixels
|
|
43010
|
-
|| new Uint8Array([(zero >> 16) & 255, (zero >> 8) & 255, zero & 255, 255]);
|
|
43437
|
+
const arrayBufferView = this.groundPixels || packHeights([{ height: 0 }]);
|
|
43011
43438
|
this.groundTexture = new Texture({
|
|
43012
43439
|
context,
|
|
43013
43440
|
pixelFormat: PixelFormat.RGBA,
|
|
@@ -43116,6 +43543,7 @@ void main() {
|
|
|
43116
43543
|
const camera = frameState.camera;
|
|
43117
43544
|
const fovy = camera.frustum && camera.frustum.fovy ? camera.frustum.fovy : Math$1.PI_OVER_THREE;
|
|
43118
43545
|
const pixelsPerRadian = frameState.context.drawingBufferHeight / fovy;
|
|
43546
|
+
const ceiling = this.tierCeiling();
|
|
43119
43547
|
for (const tile of this.tiles) {
|
|
43120
43548
|
if (!tile.centre) {
|
|
43121
43549
|
tile.tier = TIERS[0];
|
|
@@ -43126,13 +43554,33 @@ void main() {
|
|
|
43126
43554
|
const wanted = screenPixels / TARGET_CELL_PIXELS;
|
|
43127
43555
|
let tier = TIERS[0];
|
|
43128
43556
|
for (const candidate of TIERS) {
|
|
43129
|
-
if (candidate <= wanted) {
|
|
43557
|
+
if (candidate <= wanted && candidate <= ceiling) {
|
|
43130
43558
|
tier = candidate;
|
|
43131
43559
|
}
|
|
43132
43560
|
}
|
|
43133
43561
|
tile.tier = tier;
|
|
43134
43562
|
}
|
|
43135
43563
|
}
|
|
43564
|
+
/*
|
|
43565
|
+
* The finest tier worth drawing for this surface, from the texture behind it.
|
|
43566
|
+
*
|
|
43567
|
+
* Subdividing past one vertex per texel spends vertices resolving detail the source does not
|
|
43568
|
+
* carry, so the ladder is capped one step above the texel count rather than run to its top.
|
|
43569
|
+
*/
|
|
43570
|
+
tierCeiling() {
|
|
43571
|
+
const source = this.source;
|
|
43572
|
+
if (!source || !source.width || !source.height) {
|
|
43573
|
+
return TIERS[TIERS.length - 1];
|
|
43574
|
+
}
|
|
43575
|
+
const perSide = Math.sqrt(this.tiles.length) || TILES_PER_SIDE;
|
|
43576
|
+
const texelsPerTile = Math.max(source.width, source.height) / perSide;
|
|
43577
|
+
for (const candidate of TIERS) {
|
|
43578
|
+
if (candidate >= texelsPerTile) {
|
|
43579
|
+
return candidate;
|
|
43580
|
+
}
|
|
43581
|
+
}
|
|
43582
|
+
return TIERS[TIERS.length - 1];
|
|
43583
|
+
}
|
|
43136
43584
|
shouldReselect(frameState, nowMs) {
|
|
43137
43585
|
if (this.selectionDirty) {
|
|
43138
43586
|
return true;
|
|
@@ -43145,9 +43593,23 @@ void main() {
|
|
|
43145
43593
|
return true;
|
|
43146
43594
|
}
|
|
43147
43595
|
const moved = Cartesian3.distance(eye, this.lastEyePosition);
|
|
43148
|
-
|
|
43149
|
-
|
|
43150
|
-
|
|
43596
|
+
return moved / this.nearestTileDistance(eye) > MOVEMENT_THRESHOLD;
|
|
43597
|
+
}
|
|
43598
|
+
/*
|
|
43599
|
+
* Distance to the closest tile, measured the way selectTiers measures each one.
|
|
43600
|
+
*/
|
|
43601
|
+
nearestTileDistance(eye) {
|
|
43602
|
+
let nearest = Number.POSITIVE_INFINITY;
|
|
43603
|
+
for (const tile of this.tiles) {
|
|
43604
|
+
if (!tile.centre) {
|
|
43605
|
+
continue;
|
|
43606
|
+
}
|
|
43607
|
+
const distance = Cartesian3.distance(eye, tile.centre) - tile.radius;
|
|
43608
|
+
if (distance < nearest) {
|
|
43609
|
+
nearest = distance;
|
|
43610
|
+
}
|
|
43611
|
+
}
|
|
43612
|
+
return isFinite(nearest) ? Math.max(1, nearest) : 1;
|
|
43151
43613
|
}
|
|
43152
43614
|
commandFor(context, tile, mesh) {
|
|
43153
43615
|
if (!this.shaderProgram) {
|
|
@@ -43181,6 +43643,28 @@ void main() {
|
|
|
43181
43643
|
u_groundWeight: () => (self.followGround && self.groundPixels ? 1 : 0),
|
|
43182
43644
|
u_groundRange: () => new Cartesian2(GROUND_MIN_METRES, GROUND_MAX_METRES),
|
|
43183
43645
|
u_groundSize: () => new Cartesian2(self.groundPixels ? GROUND_SAMPLES_PER_SIDE : 1, self.groundPixels ? GROUND_SAMPLES_PER_SIDE : 1),
|
|
43646
|
+
u_maskTexture: () => self.maskTexture,
|
|
43647
|
+
u_maskGroundTexture: () => self.maskGroundTexture,
|
|
43648
|
+
u_maskWeight: () => (self.groundClearance && self.maskPixels ? 1 : 0),
|
|
43649
|
+
u_maskGroundWeight: () => (self.maskGroundPixels ? 1 : 0),
|
|
43650
|
+
u_maskFill: () => (self.groundClearance && self.groundClearance.fillGaps ? 1 : 0),
|
|
43651
|
+
u_maskFillValue: () => self.maskFillValue,
|
|
43652
|
+
u_maskClearance: () => (self.groundClearance
|
|
43653
|
+
&& typeof self.groundClearance.clearance === "number"
|
|
43654
|
+
&& self.maskGroundPixels
|
|
43655
|
+
? self.groundClearance.clearance
|
|
43656
|
+
: NO_LIMIT_METRES),
|
|
43657
|
+
u_maskFloor: () => (self.groundClearance
|
|
43658
|
+
&& typeof self.groundClearance.floor === "number"
|
|
43659
|
+
? self.groundClearance.floor
|
|
43660
|
+
: NO_LIMIT_METRES),
|
|
43661
|
+
u_maskGroundSize: () => new Cartesian2(self.maskGroundPixels ? MASK_GROUND_SAMPLES_PER_SIDE : 1, self.maskGroundPixels ? MASK_GROUND_SAMPLES_PER_SIDE : 1),
|
|
43662
|
+
u_extentDegrees: () => new Cartesian4(self.extent.West, self.extent.East, self.extent.North, self.extent.South),
|
|
43663
|
+
u_maskGroundDegrees: () => {
|
|
43664
|
+
const box = self.maskGroundBox || self.extent;
|
|
43665
|
+
return new Cartesian4(box.West, box.East, box.North, box.South);
|
|
43666
|
+
},
|
|
43667
|
+
u_coverageCutoffVertex: () => COVERAGE_CUTOFF,
|
|
43184
43668
|
u_metresPerTexel: () => self.metresPerTexel(),
|
|
43185
43669
|
u_valueMin: () => self.valueMin,
|
|
43186
43670
|
u_valueRange: () => self.valueMax - self.valueMin,
|
|
@@ -43817,6 +44301,34 @@ var EntityRenderEnginePolygon;
|
|
|
43817
44301
|
return cEntities;
|
|
43818
44302
|
}
|
|
43819
44303
|
EntityRenderEnginePolygon.RenderGroup = RenderGroup;
|
|
44304
|
+
/**
|
|
44305
|
+
* The displaced surface a cEntity is drawing, if it is drawing one.
|
|
44306
|
+
*
|
|
44307
|
+
* Exposed so a background plugin can hand a rendered polygon the water regions it is supposed to
|
|
44308
|
+
* stay above without having to know where the surface is kept.
|
|
44309
|
+
* @param cEntity
|
|
44310
|
+
*/
|
|
44311
|
+
function GetDisplacedSurface(cEntity) {
|
|
44312
|
+
return (cEntity === null || cEntity === void 0 ? void 0 : cEntity[DISPLACED_SURFACE_KEY]) || null;
|
|
44313
|
+
}
|
|
44314
|
+
EntityRenderEnginePolygon.GetDisplacedSurface = GetDisplacedSurface;
|
|
44315
|
+
/**
|
|
44316
|
+
* Hands every rendered polygon in a set the regions its sheet must stay above.
|
|
44317
|
+
* @param cEntities
|
|
44318
|
+
* @param clearance Pass null to drop the regions again.
|
|
44319
|
+
*/
|
|
44320
|
+
function SetGroundClearance(cEntities, clearance) {
|
|
44321
|
+
let touched = 0;
|
|
44322
|
+
for (const cEntity of cEntities || []) {
|
|
44323
|
+
const surface = GetDisplacedSurface(cEntity);
|
|
44324
|
+
if (surface) {
|
|
44325
|
+
surface.SetGroundClearance(clearance);
|
|
44326
|
+
touched++;
|
|
44327
|
+
}
|
|
44328
|
+
}
|
|
44329
|
+
return touched;
|
|
44330
|
+
}
|
|
44331
|
+
EntityRenderEnginePolygon.SetGroundClearance = SetGroundClearance;
|
|
43820
44332
|
/**
|
|
43821
44333
|
* Disposes a cEntity's TextureFrameSeriesAnimator.Animator (if any).
|
|
43822
44334
|
*/
|
|
@@ -45879,7 +46391,7 @@ var StyleUtils;
|
|
|
45879
46391
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
45880
46392
|
})(StyleUtils || (StyleUtils = {}));
|
|
45881
46393
|
|
|
45882
|
-
const VERSION = "7.
|
|
46394
|
+
const VERSION = "7.3.0";
|
|
45883
46395
|
/**
|
|
45884
46396
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
45885
46397
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|