bruce-cesium 7.1.4 → 7.1.6
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 +330 -43
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +328 -41
- 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 +42 -31
- package/dist/lib/rendering/displaced-surface-primitive.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-polygon.js +20 -4
- package/dist/lib/rendering/entity-render-engine-polygon.js.map +1 -1
- package/dist/lib/rendering/texture-frame-series-animator.js +135 -1
- package/dist/lib/rendering/texture-frame-series-animator.js.map +1 -1
- package/dist/lib/utils/simplify-geometry.js +130 -4
- package/dist/lib/utils/simplify-geometry.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/displaced-surface-primitive.d.ts +5 -0
- package/dist/types/rendering/texture-frame-series-animator.d.ts +28 -0
- package/dist/types/utils/simplify-geometry.d.ts +7 -0
- package/package.json +2 -2
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, ShaderSource,
|
|
3
|
-
import { Cartes, Entity as Entity$1, ENVIRONMENT, Calculator,
|
|
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, ClassificationType, ArcType, HeightReference, CornerType, ShadowMode, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, ColorBlendMode, Model, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Intersect, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, OrthographicFrustum, EasingFunction, PolygonPipeline, GeometryInstance, CustomDataSource, CesiumInspector, ClockRange, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
|
|
3
|
+
import { Cartes, Entity as Entity$1, ENVIRONMENT, Calculator, Carto, EntityTag, EntityType, Geometry as Geometry$1, ObjectUtils, Style, Api, ClientFile, LRUCache, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, EntityLod, Bounds, Color as Color$1, BruceEvent, EntityCoords, DataLab, DelayQueue, BruceApi, EntityHistoricData, AccountConcept, RecordChangeFeed, EntityRelation, ProgramKey, EntitySource, ProjectViewLegacyTile, ProjectViewTile, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -3587,6 +3587,7 @@ var SimplifyGeometry;
|
|
|
3587
3587
|
if (!geometry || !isTurfAvailable() || !turf.simplify) {
|
|
3588
3588
|
return geometry;
|
|
3589
3589
|
}
|
|
3590
|
+
const original = geometry;
|
|
3590
3591
|
// Convert to geojson so that we can interact with turf.
|
|
3591
3592
|
const gFeature = Geometry$1.ToGeoJsonFeature({
|
|
3592
3593
|
geometry: geometry
|
|
@@ -3607,13 +3608,97 @@ var SimplifyGeometry;
|
|
|
3607
3608
|
});
|
|
3608
3609
|
}
|
|
3609
3610
|
// Converting back to Bruce geometry.
|
|
3610
|
-
|
|
3611
|
+
const simplified = (_a = Geometry$1.FromGeoJson({
|
|
3611
3612
|
geoJson: gFeature
|
|
3612
3613
|
})) === null || _a === void 0 ? void 0 : _a.geometry;
|
|
3613
|
-
|
|
3614
|
+
// A polygon we cannot vouch for is worse than an unsimplified one, so fall back instead of shipping it.
|
|
3615
|
+
if (!simplified || !isSafeToRender(simplified)) {
|
|
3616
|
+
return original;
|
|
3617
|
+
}
|
|
3618
|
+
return simplified;
|
|
3614
3619
|
}
|
|
3615
3620
|
SimplifyGeometry.Simplify = Simplify;
|
|
3621
|
+
/**
|
|
3622
|
+
* Whether a simplified geometry still describes something a renderer can triangulate.
|
|
3623
|
+
* @param geometry the simplification result.
|
|
3624
|
+
* @returns false when any polygon has a collapsed ring, a hole outside its outer ring, or a hole
|
|
3625
|
+
* wound the same way as its outer ring.
|
|
3626
|
+
*/
|
|
3627
|
+
function IsSafeToRender(geometry) {
|
|
3628
|
+
return isSafeToRender(geometry);
|
|
3629
|
+
}
|
|
3630
|
+
SimplifyGeometry.IsSafeToRender = IsSafeToRender;
|
|
3616
3631
|
})(SimplifyGeometry || (SimplifyGeometry = {}));
|
|
3632
|
+
// A ring needs three distinct corners plus the closing repeat before it encloses any area.
|
|
3633
|
+
const MIN_RING_POSITIONS = 4;
|
|
3634
|
+
function isSafeToRender(geometry) {
|
|
3635
|
+
let safe = true;
|
|
3636
|
+
const check = (g) => {
|
|
3637
|
+
if (!safe) {
|
|
3638
|
+
return;
|
|
3639
|
+
}
|
|
3640
|
+
if (g === null || g === void 0 ? void 0 : g.MultiGeometry) {
|
|
3641
|
+
g.MultiGeometry.forEach(check);
|
|
3642
|
+
return;
|
|
3643
|
+
}
|
|
3644
|
+
if (!(g === null || g === void 0 ? void 0 : g.Polygon) || g.Polygon.length === 0) {
|
|
3645
|
+
return;
|
|
3646
|
+
}
|
|
3647
|
+
let outer = null;
|
|
3648
|
+
let outerIsClockwise = false;
|
|
3649
|
+
for (let i = 0; i < g.Polygon.length; i++) {
|
|
3650
|
+
const points = Geometry$1.ParsePoints(g.Polygon[i].LinearRing);
|
|
3651
|
+
if (!points || points.length < MIN_RING_POSITIONS) {
|
|
3652
|
+
safe = false;
|
|
3653
|
+
return;
|
|
3654
|
+
}
|
|
3655
|
+
const clockwise = signedRingArea(points) < 0;
|
|
3656
|
+
if (g.Polygon[i].Facing !== "in") {
|
|
3657
|
+
outer = points;
|
|
3658
|
+
outerIsClockwise = clockwise;
|
|
3659
|
+
continue;
|
|
3660
|
+
}
|
|
3661
|
+
// A hole with no outer ring ahead of it cannot be subtracted from anything.
|
|
3662
|
+
if (!outer) {
|
|
3663
|
+
safe = false;
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3666
|
+
if (clockwise === outerIsClockwise) {
|
|
3667
|
+
safe = false;
|
|
3668
|
+
return;
|
|
3669
|
+
}
|
|
3670
|
+
for (let j = 0; j < points.length; j++) {
|
|
3671
|
+
if (!isPointInRing(points[j], outer)) {
|
|
3672
|
+
safe = false;
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
check(geometry);
|
|
3679
|
+
return safe;
|
|
3680
|
+
}
|
|
3681
|
+
function signedRingArea(points) {
|
|
3682
|
+
let sum = 0;
|
|
3683
|
+
for (let i = 0; i < points.length; i++) {
|
|
3684
|
+
const a = points[i];
|
|
3685
|
+
const b = points[(i + 1) % points.length];
|
|
3686
|
+
sum += a.longitude * b.latitude - b.longitude * a.latitude;
|
|
3687
|
+
}
|
|
3688
|
+
return sum / 2;
|
|
3689
|
+
}
|
|
3690
|
+
function isPointInRing(point, ring) {
|
|
3691
|
+
let inside = false;
|
|
3692
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
3693
|
+
const a = ring[i];
|
|
3694
|
+
const b = ring[j];
|
|
3695
|
+
if ((a.latitude > point.latitude) !== (b.latitude > point.latitude)
|
|
3696
|
+
&& point.longitude < (b.longitude - a.longitude) * (point.latitude - a.latitude) / (b.latitude - a.latitude) + a.longitude) {
|
|
3697
|
+
inside = !inside;
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
return inside;
|
|
3701
|
+
}
|
|
3617
3702
|
/**
|
|
3618
3703
|
* Runs through all found polygons and runs unkink through turf on them.
|
|
3619
3704
|
* @param feature
|
|
@@ -3655,9 +3740,26 @@ function untangleFeature(feature) {
|
|
|
3655
3740
|
}
|
|
3656
3741
|
// Recreate the rings and reapply to the collection.
|
|
3657
3742
|
if (outer.length > 0) {
|
|
3658
|
-
|
|
3743
|
+
// Unkinking a self touching boundary splits it into pieces. Keeping whichever piece
|
|
3744
|
+
// happened to come back first can discard most of the shape, so keep the biggest one.
|
|
3745
|
+
let keep = outer[0];
|
|
3746
|
+
if (outer.length > 1) {
|
|
3747
|
+
let best = Math.abs(ringArea(keep));
|
|
3748
|
+
for (let i = 1; i < outer.length; i++) {
|
|
3749
|
+
const area = Math.abs(ringArea(outer[i]));
|
|
3750
|
+
if (area > best) {
|
|
3751
|
+
best = area;
|
|
3752
|
+
keep = outer[i];
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
const combinedCoords = [keep];
|
|
3659
3757
|
for (let i = 0; i < inner.length; i++) {
|
|
3660
|
-
|
|
3758
|
+
// A hole belonging to a piece that was just discarded is no longer inside anything,
|
|
3759
|
+
// and a hole crossing the boundary is what tears the fill.
|
|
3760
|
+
if (isRingInsideRing(inner[i], keep)) {
|
|
3761
|
+
combinedCoords.push(inner[i]);
|
|
3762
|
+
}
|
|
3661
3763
|
}
|
|
3662
3764
|
// Add the combined coordinates to the collection
|
|
3663
3765
|
const polygon = {
|
|
@@ -3805,6 +3907,30 @@ function unionFeature(feature) {
|
|
|
3805
3907
|
feature.geometry = collection;
|
|
3806
3908
|
}
|
|
3807
3909
|
}
|
|
3910
|
+
function ringArea(ring) {
|
|
3911
|
+
let sum = 0;
|
|
3912
|
+
for (let i = 0; i < ring.length; i++) {
|
|
3913
|
+
const a = ring[i];
|
|
3914
|
+
const b = ring[(i + 1) % ring.length];
|
|
3915
|
+
sum += a[0] * b[1] - b[0] * a[1];
|
|
3916
|
+
}
|
|
3917
|
+
return sum / 2;
|
|
3918
|
+
}
|
|
3919
|
+
function isRingInsideRing(inner, outer) {
|
|
3920
|
+
for (let i = 0; i < inner.length; i++) {
|
|
3921
|
+
let inside = false;
|
|
3922
|
+
for (let a = 0, b = outer.length - 1; a < outer.length; b = a++) {
|
|
3923
|
+
if ((outer[a][1] > inner[i][1]) !== (outer[b][1] > inner[i][1])
|
|
3924
|
+
&& inner[i][0] < (outer[b][0] - outer[a][0]) * (inner[i][1] - outer[a][1]) / (outer[b][1] - outer[a][1]) + outer[a][0]) {
|
|
3925
|
+
inside = !inside;
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
if (!inside) {
|
|
3929
|
+
return false;
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
return true;
|
|
3933
|
+
}
|
|
3808
3934
|
function dedupeCoordinates(inputCoords) {
|
|
3809
3935
|
return inputCoords.map(ring => {
|
|
3810
3936
|
if (ring.length < 2) {
|
|
@@ -39734,15 +39860,68 @@ var TextureFrameSeriesAnimator;
|
|
|
39734
39860
|
return Boolean(data && data.generation && Array.isArray(data.generation.Frames) && data.generation.Frames.length > 0);
|
|
39735
39861
|
}
|
|
39736
39862
|
TextureFrameSeriesAnimator.IsFrameArchiveMetadata = IsFrameArchiveMetadata;
|
|
39863
|
+
// How far covered values bleed outward into uncovered texels before the GPU samples them.
|
|
39864
|
+
const VALUE_DILATE_PASSES = 2;
|
|
39865
|
+
/*
|
|
39866
|
+
* Bleeds covered values outward into uncovered texels, leaving alpha untouched.
|
|
39867
|
+
*
|
|
39868
|
+
* The GPU samples the value texture with linear filtering, so an uncovered texel's RGB still gets
|
|
39869
|
+
* averaged into the vertices next to it even though its alpha is zero. Land sits at one end of the
|
|
39870
|
+
* ramp, so without this the coastline grows a row of spikes exactly where the data stops. Masking the
|
|
39871
|
+
* baseline creates more of these edges, which is what makes this necessary rather than cosmetic.
|
|
39872
|
+
*/
|
|
39873
|
+
function dilateValues(value, width, height, passes) {
|
|
39874
|
+
const texels = width * height;
|
|
39875
|
+
const filled = new Uint8Array(texels);
|
|
39876
|
+
for (let p = 0; p < texels; p++) {
|
|
39877
|
+
filled[p] = value[p * 4 + 3] !== 0 ? 1 : 0;
|
|
39878
|
+
}
|
|
39879
|
+
for (let pass = 0; pass < passes; pass++) {
|
|
39880
|
+
const source = value.slice();
|
|
39881
|
+
const wasFilled = filled.slice();
|
|
39882
|
+
for (let y = 0; y < height; y++) {
|
|
39883
|
+
for (let x = 0; x < width; x++) {
|
|
39884
|
+
const p = y * width + x;
|
|
39885
|
+
if (wasFilled[p]) {
|
|
39886
|
+
continue;
|
|
39887
|
+
}
|
|
39888
|
+
let sum = 0;
|
|
39889
|
+
let hits = 0;
|
|
39890
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
39891
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
39892
|
+
const nx = x + dx;
|
|
39893
|
+
const ny = y + dy;
|
|
39894
|
+
if (nx < 0 || ny < 0 || nx >= width || ny >= height || !wasFilled[ny * width + nx]) {
|
|
39895
|
+
continue;
|
|
39896
|
+
}
|
|
39897
|
+
sum += source[(ny * width + nx) * 4];
|
|
39898
|
+
hits++;
|
|
39899
|
+
}
|
|
39900
|
+
}
|
|
39901
|
+
if (hits > 0) {
|
|
39902
|
+
const v = Math.round(sum / hits);
|
|
39903
|
+
value[p * 4] = v;
|
|
39904
|
+
value[p * 4 + 1] = v;
|
|
39905
|
+
value[p * 4 + 2] = v;
|
|
39906
|
+
filled[p] = 1;
|
|
39907
|
+
}
|
|
39908
|
+
}
|
|
39909
|
+
}
|
|
39910
|
+
}
|
|
39911
|
+
}
|
|
39737
39912
|
const DEFAULT_CROSSFADE_MS = 900;
|
|
39738
39913
|
const DEFAULT_LOW_COLOR = { red: 255, green: 255, blue: 255, alpha: 0.12 };
|
|
39739
39914
|
const DEFAULT_HIGH_COLOR = { red: 21, green: 96, blue: 196, alpha: 0.92 };
|
|
39740
39915
|
class Animator {
|
|
39741
39916
|
constructor(options) {
|
|
39742
|
-
var _a;
|
|
39917
|
+
var _a, _b;
|
|
39743
39918
|
this.removeOnTick = null;
|
|
39744
39919
|
this.removeCrossfadeTick = null;
|
|
39745
39920
|
this.disposed = false;
|
|
39921
|
+
// One alpha byte per texel, 1 meaning the texel is baseline. Fetched once, the mesh does not move.
|
|
39922
|
+
this.baselineFlags = null;
|
|
39923
|
+
this.baselineDims = null;
|
|
39924
|
+
this.baselineLoad = null;
|
|
39746
39925
|
this.currentFrameIndex = -1;
|
|
39747
39926
|
// Single-in-flight fetch queue: only one Range GET outstanding at a time, and the NEXT one
|
|
39748
39927
|
// is chosen right before sending, this is what makes reprioritizing mid-scrub take effect
|
|
@@ -39782,6 +39961,8 @@ var TextureFrameSeriesAnimator;
|
|
|
39782
39961
|
this.frameDims = new Array(this.frames.length).fill(null);
|
|
39783
39962
|
this.valueCache = new Array(this.frames.length).fill(null);
|
|
39784
39963
|
this.produceValueCanvas = Boolean(options.produceValueCanvas);
|
|
39964
|
+
this.baselineMaskEntry = options.baselineMask || null;
|
|
39965
|
+
this.maskBaseline = (_b = options.maskBaseline) !== null && _b !== void 0 ? _b : Boolean(options.baselineMask);
|
|
39785
39966
|
this.valueCanvas = this.produceValueCanvas ? document.createElement("canvas") : null;
|
|
39786
39967
|
this.driveMaterial = options.driveMaterial !== false;
|
|
39787
39968
|
this.originalMaterial = options.entity.polygon.material;
|
|
@@ -39951,6 +40132,12 @@ var TextureFrameSeriesAnimator;
|
|
|
39951
40132
|
if (this.disposed) {
|
|
39952
40133
|
return;
|
|
39953
40134
|
}
|
|
40135
|
+
// Awaited before decoding rather than applied later, so no frame is ever cached unmasked and
|
|
40136
|
+
// then corrected once the mask lands.
|
|
40137
|
+
await this.ensureBaselineMask();
|
|
40138
|
+
if (this.disposed) {
|
|
40139
|
+
return;
|
|
40140
|
+
}
|
|
39954
40141
|
const decoded = await this.decodeAndTint(buffer);
|
|
39955
40142
|
if (this.disposed) {
|
|
39956
40143
|
return;
|
|
@@ -39985,8 +40172,81 @@ var TextureFrameSeriesAnimator;
|
|
|
39985
40172
|
// recovered from the tinted pixels afterwards.
|
|
39986
40173
|
const valuePixels = this.produceValueCanvas ? new Uint8ClampedArray(imageData.data) : undefined;
|
|
39987
40174
|
ApplyGrayscaleColorMask(imageData, this.lowColor, this.highColor);
|
|
40175
|
+
this.applyBaselineMask(imageData.data, valuePixels, canvas.width, canvas.height);
|
|
40176
|
+
if (valuePixels) {
|
|
40177
|
+
dilateValues(valuePixels, canvas.width, canvas.height, VALUE_DILATE_PASSES);
|
|
40178
|
+
}
|
|
39988
40179
|
return { pixels: imageData.data, width: canvas.width, height: canvas.height, valuePixels };
|
|
39989
40180
|
}
|
|
40181
|
+
/**
|
|
40182
|
+
* Fetches and decodes the archive's static baseline mask, at most once.
|
|
40183
|
+
*/
|
|
40184
|
+
ensureBaselineMask() {
|
|
40185
|
+
if (!this.maskBaseline || !this.baselineMaskEntry) {
|
|
40186
|
+
return Promise.resolve();
|
|
40187
|
+
}
|
|
40188
|
+
if (this.baselineLoad) {
|
|
40189
|
+
return this.baselineLoad;
|
|
40190
|
+
}
|
|
40191
|
+
const entry = this.baselineMaskEntry;
|
|
40192
|
+
const start = entry.ByteOffset;
|
|
40193
|
+
const end = entry.ByteOffset + entry.ByteLength - 1;
|
|
40194
|
+
this.baselineLoad = fetch(this.archiveUrl, { headers: { Range: `bytes=${start}-${end}` } })
|
|
40195
|
+
.then((response) => response.arrayBuffer())
|
|
40196
|
+
.then(async (buffer) => {
|
|
40197
|
+
if (this.disposed) {
|
|
40198
|
+
return;
|
|
40199
|
+
}
|
|
40200
|
+
const blob = new Blob([buffer], { type: "image/png" });
|
|
40201
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
40202
|
+
let image;
|
|
40203
|
+
try {
|
|
40204
|
+
image = await loadImage(objectUrl);
|
|
40205
|
+
}
|
|
40206
|
+
finally {
|
|
40207
|
+
URL.revokeObjectURL(objectUrl);
|
|
40208
|
+
}
|
|
40209
|
+
const canvas = document.createElement("canvas");
|
|
40210
|
+
canvas.width = image.width;
|
|
40211
|
+
canvas.height = image.height;
|
|
40212
|
+
const ctx = canvas.getContext("2d");
|
|
40213
|
+
ctx.drawImage(image, 0, 0);
|
|
40214
|
+
const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
|
40215
|
+
const flags = new Uint8Array(canvas.width * canvas.height);
|
|
40216
|
+
for (let p = 0; p < flags.length; p++) {
|
|
40217
|
+
flags[p] = pixels[p * 4 + 3] >= 128 ? 1 : 0;
|
|
40218
|
+
}
|
|
40219
|
+
this.baselineFlags = flags;
|
|
40220
|
+
this.baselineDims = { width: canvas.width, height: canvas.height };
|
|
40221
|
+
})
|
|
40222
|
+
.catch((e) => {
|
|
40223
|
+
// A missing or unreadable mask must not stop the animation; it just means nothing is hidden.
|
|
40224
|
+
console.warn("TextureFrameSeriesAnimator: could not load the baseline mask, drawing it instead.", e);
|
|
40225
|
+
});
|
|
40226
|
+
return this.baselineLoad;
|
|
40227
|
+
}
|
|
40228
|
+
/**
|
|
40229
|
+
* Clears alpha on baseline texels, which is what makes hiding the dry/land sentinel a render choice.
|
|
40230
|
+
*/
|
|
40231
|
+
applyBaselineMask(pixels, valuePixels, width, height) {
|
|
40232
|
+
const flags = this.baselineFlags;
|
|
40233
|
+
if (!flags || !this.baselineDims) {
|
|
40234
|
+
return;
|
|
40235
|
+
}
|
|
40236
|
+
// A mask from a different raster size cannot be indexed against this frame, and guessing a
|
|
40237
|
+
// resampling would silently hide the wrong ground.
|
|
40238
|
+
if (this.baselineDims.width !== width || this.baselineDims.height !== height) {
|
|
40239
|
+
return;
|
|
40240
|
+
}
|
|
40241
|
+
for (let p = 0; p < flags.length; p++) {
|
|
40242
|
+
if (flags[p]) {
|
|
40243
|
+
pixels[p * 4 + 3] = 0;
|
|
40244
|
+
if (valuePixels) {
|
|
40245
|
+
valuePixels[p * 4 + 3] = 0;
|
|
40246
|
+
}
|
|
40247
|
+
}
|
|
40248
|
+
}
|
|
40249
|
+
}
|
|
39990
40250
|
beginCrossfadeTo(idx) {
|
|
39991
40251
|
const to = this.frameCache[idx];
|
|
39992
40252
|
this.fadeFromValuePixels = this.displayedValuePixels === null && this.valueCache[idx]
|
|
@@ -40233,11 +40493,13 @@ void main() {
|
|
|
40233
40493
|
return _glsl300Support;
|
|
40234
40494
|
}
|
|
40235
40495
|
/*
|
|
40236
|
-
* Places grid node (fx, fy) on the ellipsoid,
|
|
40237
|
-
*
|
|
40238
|
-
* linear in a projected CRS, so stepping in degrees instead would skew the surface against the flat-textured polygon it replaces.
|
|
40496
|
+
* Places grid node (fx, fy) on the ellipsoid, stepping the way the raster was sampled.
|
|
40497
|
+
* A raster sampled at lon/lat has to be walked in degrees; one sampled linearly across a projected CRS has to be walked in tangent-plane metres.
|
|
40239
40498
|
*/
|
|
40240
|
-
function makePlacer(extent) {
|
|
40499
|
+
function makePlacer(extent, pixelPlacement) {
|
|
40500
|
+
if (pixelPlacement === "lonlat") {
|
|
40501
|
+
return (fx, fy) => Cartesian3.fromDegrees(Math$1.lerp(extent.West, extent.East, fx), Math$1.lerp(extent.North, extent.South, fy), 0);
|
|
40502
|
+
}
|
|
40241
40503
|
const ellipsoid = Ellipsoid.WGS84;
|
|
40242
40504
|
const centre = Cartesian3.fromDegrees((extent.West + extent.East) / 2, (extent.South + extent.North) / 2, 0);
|
|
40243
40505
|
const frame = Transforms.eastNorthUpToFixedFrame(centre);
|
|
@@ -40251,21 +40513,21 @@ void main() {
|
|
|
40251
40513
|
};
|
|
40252
40514
|
}
|
|
40253
40515
|
/*
|
|
40254
|
-
* Builds one tile's grid, plus a duplicated perimeter ring the shader pushes downwards to
|
|
40255
|
-
* the crack where a neighbouring tile at a different density interpolates the shared edge.
|
|
40516
|
+
* Builds one tile's grid, optionally plus a duplicated perimeter ring the shader pushes downwards to
|
|
40517
|
+
* cover the crack where a neighbouring tile at a different density interpolates the shared edge.
|
|
40256
40518
|
*/
|
|
40257
|
-
function buildGeometry(extent, resolution, patch) {
|
|
40519
|
+
function buildGeometry(extent, resolution, patch, pixelPlacement, withSkirt = false) {
|
|
40258
40520
|
const cols = resolution;
|
|
40259
40521
|
const rows = resolution;
|
|
40260
40522
|
const gridCount = (cols + 1) * (rows + 1);
|
|
40261
|
-
const perimeterCount = 2 * (cols + 1) + 2 * (rows + 1) - 4;
|
|
40523
|
+
const perimeterCount = withSkirt ? 2 * (cols + 1) + 2 * (rows + 1) - 4 : 0;
|
|
40262
40524
|
const count = gridCount + perimeterCount;
|
|
40263
40525
|
const positions = new Float64Array(count * 3);
|
|
40264
40526
|
const normals = new Float32Array(count * 3);
|
|
40265
40527
|
const sts = new Float32Array(count * 2);
|
|
40266
40528
|
const skirts = new Float32Array(count);
|
|
40267
40529
|
const ellipsoid = Ellipsoid.WGS84;
|
|
40268
|
-
const place = makePlacer(extent);
|
|
40530
|
+
const place = makePlacer(extent, pixelPlacement);
|
|
40269
40531
|
let v = 0;
|
|
40270
40532
|
for (let row = 0; row <= rows; row++) {
|
|
40271
40533
|
// Texture row 0 is the north edge, so t runs opposite to northing.
|
|
@@ -40316,26 +40578,28 @@ void main() {
|
|
|
40316
40578
|
loop.push(row * (cols + 1));
|
|
40317
40579
|
}
|
|
40318
40580
|
const skirtStart = gridCount;
|
|
40319
|
-
|
|
40320
|
-
|
|
40321
|
-
|
|
40322
|
-
|
|
40323
|
-
|
|
40324
|
-
|
|
40325
|
-
|
|
40326
|
-
|
|
40327
|
-
|
|
40328
|
-
|
|
40329
|
-
|
|
40330
|
-
|
|
40331
|
-
|
|
40332
|
-
|
|
40333
|
-
|
|
40334
|
-
|
|
40335
|
-
|
|
40336
|
-
|
|
40337
|
-
|
|
40338
|
-
|
|
40581
|
+
if (withSkirt) {
|
|
40582
|
+
loop.forEach((gridIndex, k) => {
|
|
40583
|
+
const target = skirtStart + k;
|
|
40584
|
+
positions[target * 3] = positions[gridIndex * 3];
|
|
40585
|
+
positions[target * 3 + 1] = positions[gridIndex * 3 + 1];
|
|
40586
|
+
positions[target * 3 + 2] = positions[gridIndex * 3 + 2];
|
|
40587
|
+
normals[target * 3] = normals[gridIndex * 3];
|
|
40588
|
+
normals[target * 3 + 1] = normals[gridIndex * 3 + 1];
|
|
40589
|
+
normals[target * 3 + 2] = normals[gridIndex * 3 + 2];
|
|
40590
|
+
sts[target * 2] = sts[gridIndex * 2];
|
|
40591
|
+
sts[target * 2 + 1] = sts[gridIndex * 2 + 1];
|
|
40592
|
+
skirts[target] = 1;
|
|
40593
|
+
});
|
|
40594
|
+
for (let k = 0; k < loop.length; k++) {
|
|
40595
|
+
const nextK = (k + 1) % loop.length;
|
|
40596
|
+
indices[i++] = loop[k];
|
|
40597
|
+
indices[i++] = skirtStart + k;
|
|
40598
|
+
indices[i++] = loop[nextK];
|
|
40599
|
+
indices[i++] = loop[nextK];
|
|
40600
|
+
indices[i++] = skirtStart + k;
|
|
40601
|
+
indices[i++] = skirtStart + nextK;
|
|
40602
|
+
}
|
|
40339
40603
|
}
|
|
40340
40604
|
const geometry = new Geometry({
|
|
40341
40605
|
attributes: {
|
|
@@ -40393,6 +40657,8 @@ void main() {
|
|
|
40393
40657
|
this.valueMax = (_b = options.valueMax) !== null && _b !== void 0 ? _b : 1;
|
|
40394
40658
|
this.exaggeration = (_c = options.exaggeration) !== null && _c !== void 0 ? _c : autoExaggeration(this.extent, this.valueMin, this.valueMax);
|
|
40395
40659
|
this.baseHeight = (_d = options.baseHeight) !== null && _d !== void 0 ? _d : 0;
|
|
40660
|
+
this.pixelPlacement = options.pixelPlacement;
|
|
40661
|
+
this.tileSkirts = Boolean(options.tileSkirts);
|
|
40396
40662
|
this.lowColor = toCesiumColor(options.lowColor || DEFAULT_LOW_COLOR);
|
|
40397
40663
|
this.highColor = toCesiumColor(options.highColor || DEFAULT_HIGH_COLOR);
|
|
40398
40664
|
this.tiles = buildTiles(hasCoverage);
|
|
@@ -40400,6 +40666,9 @@ void main() {
|
|
|
40400
40666
|
GetFollowsGround() {
|
|
40401
40667
|
return this.followGround;
|
|
40402
40668
|
}
|
|
40669
|
+
GetPixelPlacement() {
|
|
40670
|
+
return this.pixelPlacement;
|
|
40671
|
+
}
|
|
40403
40672
|
GetBaseHeight() {
|
|
40404
40673
|
return this.baseHeight;
|
|
40405
40674
|
}
|
|
@@ -40614,7 +40883,7 @@ void main() {
|
|
|
40614
40883
|
if (cached) {
|
|
40615
40884
|
return cached;
|
|
40616
40885
|
}
|
|
40617
|
-
const geometry = buildGeometry(this.extent, tier, tile.patch);
|
|
40886
|
+
const geometry = buildGeometry(this.extent, tier, tile.patch, this.pixelPlacement, this.tileSkirts);
|
|
40618
40887
|
const attributeLocations = GeometryPipeline.createAttributeLocations(geometry);
|
|
40619
40888
|
const mesh = {
|
|
40620
40889
|
attributeLocations,
|
|
@@ -40707,7 +40976,9 @@ void main() {
|
|
|
40707
40976
|
u_valueRange: () => self.valueMax - self.valueMin,
|
|
40708
40977
|
u_exaggeration: () => self.exaggeration,
|
|
40709
40978
|
u_baseHeight: () => self.baseHeight,
|
|
40710
|
-
u_skirtDepth: () =>
|
|
40979
|
+
u_skirtDepth: () => self.tileSkirts
|
|
40980
|
+
? Math.max(2, Math.abs(self.valueMax - self.valueMin) * self.exaggeration * SKIRT_FRACTION)
|
|
40981
|
+
: 0,
|
|
40711
40982
|
u_coverageCutoff: () => COVERAGE_CUTOFF,
|
|
40712
40983
|
u_lowColor: () => self.lowColor,
|
|
40713
40984
|
u_highColor: () => self.highColor,
|
|
@@ -40840,6 +41111,8 @@ var EntityRenderEnginePolygon;
|
|
|
40840
41111
|
}
|
|
40841
41112
|
}
|
|
40842
41113
|
const drawsDisplacedSurface = Boolean(extrusionArchive);
|
|
41114
|
+
// The displaced surface IS the entity's fill, drawn as its own primitive at the value's height.
|
|
41115
|
+
// Leaving the flat polygon filled as well shows a second copy of the parcel on the ground under it.
|
|
40843
41116
|
const hasFill = (drawsDisplacedSurface ? true
|
|
40844
41117
|
: fillType === Style.EPolygonFillType.Texture
|
|
40845
41118
|
? Boolean(textureDataUri || frameArchive || cFillColor.alpha > 0)
|
|
@@ -40928,6 +41201,7 @@ var EntityRenderEnginePolygon;
|
|
|
40928
41201
|
polygon: {
|
|
40929
41202
|
hierarchy: new PolygonHierarchy(posses, holePosses.map(x => new PolygonHierarchy(x))),
|
|
40930
41203
|
material: fillMaterial,
|
|
41204
|
+
fill: !drawsDisplacedSurface,
|
|
40931
41205
|
extrudedHeight: extrusion.value,
|
|
40932
41206
|
extrudedHeightReference: extrusion.exHeightRef,
|
|
40933
41207
|
shadows: ShadowMode.ENABLED,
|
|
@@ -40958,6 +41232,12 @@ var EntityRenderEnginePolygon;
|
|
|
40958
41232
|
if (!CompareCPolygonHierarchies(oldHierarchy, newHierarchy)) {
|
|
40959
41233
|
cEntity.polygon.hierarchy = new ConstantProperty(newHierarchy);
|
|
40960
41234
|
}
|
|
41235
|
+
// Toggling extrusion styling on an already-rendered entity flips this,
|
|
41236
|
+
// so it has to be reconciled rather than set only at creation.
|
|
41237
|
+
const oldFill = GetCValue(params.viewer, cEntity.polygon.fill);
|
|
41238
|
+
if (oldFill !== !drawsDisplacedSurface) {
|
|
41239
|
+
cEntity.polygon.fill = new ConstantProperty(!drawsDisplacedSurface);
|
|
41240
|
+
}
|
|
40961
41241
|
const oldExtrusion = GetCValue(params.viewer, cEntity.polygon.extrudedHeight);
|
|
40962
41242
|
if (oldExtrusion != extrusion.value) {
|
|
40963
41243
|
cEntity.polygon.extrudedHeight = new ConstantProperty(extrusion.value);
|
|
@@ -41011,7 +41291,7 @@ var EntityRenderEnginePolygon;
|
|
|
41011
41291
|
}
|
|
41012
41292
|
// Must run before any material is baked below: the Animator takes over polygon.material, so a bake
|
|
41013
41293
|
// has to know whether it is baking over a live animation or over a disposed one's restored material.
|
|
41014
|
-
const animator = syncTextureFrameArchive(cEntity, drawsDisplacedSurface ? null : frameArchive, params.viewer, style.textureColorMask);
|
|
41294
|
+
const animator = syncTextureFrameArchive(cEntity, drawsDisplacedSurface ? null : frameArchive, params.viewer, style.textureColorMask, style.maskTextureBaseline);
|
|
41015
41295
|
syncDisplacedSurface({
|
|
41016
41296
|
cEntity,
|
|
41017
41297
|
extrusionArchive,
|
|
@@ -41496,12 +41776,17 @@ function syncDisplacedSurface(params) {
|
|
|
41496
41776
|
frames: extrusionArchive.metadata.Frames,
|
|
41497
41777
|
textureColorMask: style.textureColorMask,
|
|
41498
41778
|
driveMaterial: false,
|
|
41499
|
-
produceValueCanvas: true
|
|
41779
|
+
produceValueCanvas: true,
|
|
41780
|
+
baselineMask: extrusionArchive.metadata.BaselineMask,
|
|
41781
|
+
// Off-type for the same reason as the fill path: the pinned bruce-models predates the field.
|
|
41782
|
+
maskBaseline: style.maskTextureBaseline
|
|
41500
41783
|
});
|
|
41501
41784
|
cEntity[EXTRUSION_ANIMATOR_KEY] = animator;
|
|
41502
41785
|
const mask = style.textureColorMask;
|
|
41503
41786
|
const surface = new DisplacedSurfacePrimitive.Surface({
|
|
41504
41787
|
extent,
|
|
41788
|
+
// The grid has to be walked the way the raster was sampled, or the surface skews across the extent.
|
|
41789
|
+
pixelPlacement: extrusionArchive.metadata.PixelPlacement,
|
|
41505
41790
|
source: null,
|
|
41506
41791
|
baseHeight: placement.baseHeight,
|
|
41507
41792
|
followGround: placement.followGround,
|
|
@@ -41593,7 +41878,7 @@ function disposeDisplacedSurface(cEntity, viewer) {
|
|
|
41593
41878
|
* @param viewer
|
|
41594
41879
|
* @param textureColorMask
|
|
41595
41880
|
*/
|
|
41596
|
-
function syncTextureFrameArchive(cEntity, frameArchive, viewer, textureColorMask) {
|
|
41881
|
+
function syncTextureFrameArchive(cEntity, frameArchive, viewer, textureColorMask, maskTextureBaseline) {
|
|
41597
41882
|
const existing = cEntity[TEXTURE_FRAME_SERIES_ANIMATOR_KEY];
|
|
41598
41883
|
if (frameArchive && existing && !existing.IsDisposed() && existing.GetArchiveUrl() === frameArchive.url) {
|
|
41599
41884
|
return existing;
|
|
@@ -41610,7 +41895,9 @@ function syncTextureFrameArchive(cEntity, frameArchive, viewer, textureColorMask
|
|
|
41610
41895
|
entity: cEntity,
|
|
41611
41896
|
archiveUrl: frameArchive.url,
|
|
41612
41897
|
frames: frameArchive.metadata.Frames,
|
|
41613
|
-
textureColorMask
|
|
41898
|
+
textureColorMask,
|
|
41899
|
+
baselineMask: frameArchive.metadata.BaselineMask,
|
|
41900
|
+
maskBaseline: maskTextureBaseline
|
|
41614
41901
|
});
|
|
41615
41902
|
cEntity[TEXTURE_FRAME_SERIES_ANIMATOR_KEY] = animator;
|
|
41616
41903
|
return animator;
|
|
@@ -43222,7 +43509,7 @@ var StyleUtils;
|
|
|
43222
43509
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
43223
43510
|
})(StyleUtils || (StyleUtils = {}));
|
|
43224
43511
|
|
|
43225
|
-
const VERSION = "7.1.
|
|
43512
|
+
const VERSION = "7.1.6";
|
|
43226
43513
|
/**
|
|
43227
43514
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
43228
43515
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|