bruce-cesium 7.7.6 → 7.7.8
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 +2313 -69
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +2292 -66
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +6 -1
- package/dist/lib/bruce-cesium.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-model3d.js +2 -2
- package/dist/lib/rendering/entity-render-engine-model3d.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-polygon.js +26 -4
- package/dist/lib/rendering/entity-render-engine-polygon.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-polyline.js +2 -1
- package/dist/lib/rendering/entity-render-engine-polyline.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-simulation.js +1 -1
- package/dist/lib/rendering/render-managers/common/entity-simulation.js.map +1 -1
- package/dist/lib/rendering/tileset-render-engine.js +47 -14
- package/dist/lib/rendering/tileset-render-engine.js.map +1 -1
- package/dist/lib/rendering/view-render-engine.js +30 -24
- package/dist/lib/rendering/view-render-engine.js.map +1 -1
- package/dist/lib/rendering/visuals-register.js +93 -8
- package/dist/lib/rendering/visuals-register.js.map +1 -1
- package/dist/lib/rendering/xgrids-render-engine.js +20 -3
- package/dist/lib/rendering/xgrids-render-engine.js.map +1 -1
- package/dist/lib/utils/cesium-map-grid.js +807 -0
- package/dist/lib/utils/cesium-map-grid.js.map +1 -0
- package/dist/lib/utils/device-profile.js +302 -0
- package/dist/lib/utils/device-profile.js.map +1 -0
- package/dist/lib/utils/gltf-generator.js +307 -0
- package/dist/lib/utils/gltf-generator.js.map +1 -0
- package/dist/lib/utils/gltf-gizmo.js +136 -0
- package/dist/lib/utils/gltf-gizmo.js.map +1 -0
- package/dist/lib/utils/view-utils.js +9 -0
- package/dist/lib/utils/view-utils.js.map +1 -1
- package/dist/lib/viewer/camera-controls.js +544 -0
- package/dist/lib/viewer/camera-controls.js.map +1 -0
- package/dist/lib/viewer/viewer-utils.js +9 -1
- package/dist/lib/viewer/viewer-utils.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +6 -1
- package/dist/types/rendering/tileset-render-engine.d.ts +10 -2
- package/dist/types/rendering/view-render-engine.d.ts +4 -0
- package/dist/types/rendering/visuals-register.d.ts +4 -0
- package/dist/types/rendering/xgrids-render-engine.d.ts +2 -0
- package/dist/types/utils/cesium-map-grid.d.ts +23 -0
- package/dist/types/utils/device-profile.d.ts +84 -0
- package/dist/types/utils/gltf-generator.d.ts +104 -0
- package/dist/types/utils/gltf-gizmo.d.ts +18 -0
- package/dist/types/utils/view-utils.d.ts +4 -0
- package/dist/types/viewer/camera-controls.d.ts +19 -0
- package/dist/types/viewer/viewer-utils.d.ts +1 -0
- package/package.json +3 -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,
|
|
3
|
-
import { Cartes, LRUCache, Carto, ProjectViewTile, EntityHistoricData, BruceEvent, DelayQueue, Entity as Entity$1, EntityTag, ClientFile, ENVIRONMENT, EntityAttachmentType, EntityRelationType, EntityType, Tileset, Calculator, DataLab, Style, ObjectUtils, MenuItem, AccountConcept, RecordChangeFeed, EntityLod, UrlUtils, Geometry as Geometry$1, ClientFileValueMap, Color as Color$1,
|
|
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, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, PixelDatatype, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, HeightReference, ColorBlendMode, HeadingPitchRoll, Model, ClassificationType, ConstantPositionProperty, DistanceDisplayCondition, ArcType, CornerType, JulianDate, Quaternion, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, HorizontalOrigin, VerticalOrigin, SceneMode, IntersectionTests, Ray, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, FeatureDetection, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Intersect, OrthographicFrustum, EasingFunction, WebGLConstants, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, CesiumInspector, ClockRange, ShadowMode, DynamicEnvironmentMapManager, GeometryInstance, PrimitiveCollection, PolylineCollection, LabelCollection, LabelStyle, Material, Event, CustomDataSource, CameraEventType, Plane, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
|
|
3
|
+
import { Cartes, LRUCache, Carto, ProjectViewTile, EntityHistoricData, BruceEvent, DelayQueue, Entity as Entity$1, EntityTag, PathUtils, ClientFile, ENVIRONMENT, EntityAttachmentType, EntityRelationType, EntityType, Tileset, Calculator, DataLab, Style, ObjectUtils, MenuItem, AccountConcept, RecordChangeFeed, EntityLod, UrlUtils, Geometry as Geometry$1, Bounds, ClientFileValueMap, Color as Color$1, Assembly, EntityCoords, ZoomControl, ProjectView, ProjectViewBookmark, Api, EntityRelation, BruceApi, ProgramKey, ProjectViewLegacyTile, Camera, EntitySource, Account, AccountLimits, Session, EntityAttachment, EntityAttribute, MathUtils, ProjectViewBookmarkGroup } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -907,6 +907,546 @@ function CompareCPolygonHierarchies(a, b) {
|
|
|
907
907
|
return true;
|
|
908
908
|
}
|
|
909
909
|
|
|
910
|
+
const CESIUM_CAMERA_CONTROLS_KEY = "_nextspace_camera_controls";
|
|
911
|
+
// How far a wheel notch or its drag equivalent moves the camera, as a share of the distance to what it points at.
|
|
912
|
+
const ZOOM_SHARE = 0.18;
|
|
913
|
+
// The distance a zoom step treats anything closer as, so the camera keeps moving through a surface instead of stalling.
|
|
914
|
+
const MIN_ZOOM_DISTANCE = 4;
|
|
915
|
+
// How far from the origin zooming out may take a model-space camera, beyond which the scene is a dot on a planet.
|
|
916
|
+
const MODEL_SPACE_MAX_RANGE = 250000;
|
|
917
|
+
// Above this height a geospatial scene is a planet, which CesiumJS's own controller navigates better.
|
|
918
|
+
const GEO_HANDOFF_HEIGHT = 15000;
|
|
919
|
+
// The furthest a depth pick is trusted from a camera close to the ground; further up the limit grows with height.
|
|
920
|
+
const PLAUSIBLE_PICK_FLOOR = 1000;
|
|
921
|
+
// Pixels of right drag that make one wheel notch.
|
|
922
|
+
const DRAG_PIXELS_PER_NOTCH = 40;
|
|
923
|
+
// Share of the outstanding wheel movement applied each animation frame.
|
|
924
|
+
const ZOOM_EASE = 0.35;
|
|
925
|
+
// A pan plane seen closer to edge on than this (sine of the angle) is swapped for one facing the camera.
|
|
926
|
+
const GRAZING_SINE = 0.12;
|
|
927
|
+
// Closest the view may get to straight up or down while orbiting, in radians, so the camera never flips over.
|
|
928
|
+
const ORBIT_POLE_MARGIN = Math$1.toRadians(1);
|
|
929
|
+
var EDrag;
|
|
930
|
+
(function (EDrag) {
|
|
931
|
+
EDrag["Pan"] = "pan";
|
|
932
|
+
EDrag["Orbit"] = "orbit";
|
|
933
|
+
EDrag["Zoom"] = "zoom";
|
|
934
|
+
})(EDrag || (EDrag = {}));
|
|
935
|
+
/**
|
|
936
|
+
* Mouse navigation that keeps moving near, through and below the ground, where CesiumJS's own controller stalls.
|
|
937
|
+
*/
|
|
938
|
+
var CameraControls;
|
|
939
|
+
(function (CameraControls) {
|
|
940
|
+
/**
|
|
941
|
+
* Takes over mouse drag and wheel navigation close to the ground; CesiumJS keeps planet scale, pinch and look.
|
|
942
|
+
*/
|
|
943
|
+
function Attach(viewer) {
|
|
944
|
+
var _a, _b, _c;
|
|
945
|
+
if (!viewer || viewer.isDestroyed() || viewer[CESIUM_CAMERA_CONTROLS_KEY]) {
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const scene = viewer.scene;
|
|
949
|
+
const controller = scene === null || scene === void 0 ? void 0 : scene.screenSpaceCameraController;
|
|
950
|
+
if (!controller || !scene.canvas || !scene.preUpdate) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
const state = {
|
|
954
|
+
viewer,
|
|
955
|
+
getModelSpaceFrame: null,
|
|
956
|
+
drag: null,
|
|
957
|
+
touches: new Set(),
|
|
958
|
+
pendingZoom: new Cartesian3(),
|
|
959
|
+
zoomFrame: null,
|
|
960
|
+
zoomPosition: null,
|
|
961
|
+
lastDistance: 100,
|
|
962
|
+
saved: {
|
|
963
|
+
rotateEventTypes: controller.rotateEventTypes,
|
|
964
|
+
zoomEventTypes: controller.zoomEventTypes,
|
|
965
|
+
tiltEventTypes: controller.tiltEventTypes,
|
|
966
|
+
enableCollisionDetection: controller.enableCollisionDetection,
|
|
967
|
+
backFaceAlpha: (_b = (_a = scene.globe) === null || _a === void 0 ? void 0 : _a.translucency) === null || _b === void 0 ? void 0 : _b.backFaceAlpha,
|
|
968
|
+
showSkirts: (_c = scene.globe) === null || _c === void 0 ? void 0 : _c.showSkirts
|
|
969
|
+
},
|
|
970
|
+
ours: false,
|
|
971
|
+
removals: []
|
|
972
|
+
};
|
|
973
|
+
viewer[CESIUM_CAMERA_CONTROLS_KEY] = state;
|
|
974
|
+
// The camera may go below the ground; zooming slows near a surface, so it takes a deliberate push.
|
|
975
|
+
controller.enableCollisionDetection = false;
|
|
976
|
+
const canvas = scene.canvas;
|
|
977
|
+
const listen = (target, type, handler, options) => {
|
|
978
|
+
target.addEventListener(type, handler, options);
|
|
979
|
+
state.removals.push(() => target.removeEventListener(type, handler, options));
|
|
980
|
+
};
|
|
981
|
+
listen(canvas, "pointerdown", (e) => onPointerDown(state, e));
|
|
982
|
+
listen(window, "pointermove", (e) => onPointerMove(state, e));
|
|
983
|
+
listen(window, "pointerup", (e) => onPointerUp(state, e));
|
|
984
|
+
listen(window, "pointercancel", (e) => onPointerUp(state, e));
|
|
985
|
+
listen(canvas, "wheel", (e) => onWheel(state, e), { passive: true });
|
|
986
|
+
state.removals.push(scene.preUpdate.addEventListener(() => syncController(state)));
|
|
987
|
+
syncController(state);
|
|
988
|
+
scene.requestRender();
|
|
989
|
+
}
|
|
990
|
+
CameraControls.Attach = Attach;
|
|
991
|
+
/**
|
|
992
|
+
* Hands navigation back to CesiumJS's own camera controller, as it was before Attach.
|
|
993
|
+
*/
|
|
994
|
+
function Detach(viewer) {
|
|
995
|
+
const state = viewer === null || viewer === void 0 ? void 0 : viewer[CESIUM_CAMERA_CONTROLS_KEY];
|
|
996
|
+
if (!state) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
SetModelSpace(viewer, null);
|
|
1000
|
+
viewer[CESIUM_CAMERA_CONTROLS_KEY] = null;
|
|
1001
|
+
state.removals.forEach((removal) => removal());
|
|
1002
|
+
state.removals = [];
|
|
1003
|
+
if (state.zoomFrame != null) {
|
|
1004
|
+
cancelAnimationFrame(state.zoomFrame);
|
|
1005
|
+
}
|
|
1006
|
+
if (viewer.isDestroyed()) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
restoreCesiumGestures(state);
|
|
1010
|
+
viewer.scene.screenSpaceCameraController.enableCollisionDetection = state.saved.enableCollisionDetection;
|
|
1011
|
+
viewer.scene.requestRender();
|
|
1012
|
+
}
|
|
1013
|
+
CameraControls.Detach = Detach;
|
|
1014
|
+
function IsAttached(viewer) {
|
|
1015
|
+
return Boolean(viewer === null || viewer === void 0 ? void 0 : viewer[CESIUM_CAMERA_CONTROLS_KEY]);
|
|
1016
|
+
}
|
|
1017
|
+
CameraControls.IsAttached = IsAttached;
|
|
1018
|
+
/**
|
|
1019
|
+
* Switches to navigating model-space measured from the frame getFrame returns, or back to geospatial with null.
|
|
1020
|
+
*/
|
|
1021
|
+
function SetModelSpace(viewer, getFrame) {
|
|
1022
|
+
const state = viewer === null || viewer === void 0 ? void 0 : viewer[CESIUM_CAMERA_CONTROLS_KEY];
|
|
1023
|
+
if (!state || viewer.isDestroyed()) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
const wasModelSpace = Boolean(state.getModelSpaceFrame);
|
|
1027
|
+
state.getModelSpaceFrame = getFrame !== null && getFrame !== void 0 ? getFrame : null;
|
|
1028
|
+
syncController(state);
|
|
1029
|
+
if (wasModelSpace === Boolean(getFrame)) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
const globe = viewer.scene.globe;
|
|
1033
|
+
const translucency = globe === null || globe === void 0 ? void 0 : globe.translucency;
|
|
1034
|
+
if (getFrame) {
|
|
1035
|
+
// The ground is see-through from below, so what stands on it stays in view underground.
|
|
1036
|
+
if (translucency && typeof translucency.backFaceAlpha === "number") {
|
|
1037
|
+
translucency.backFaceAlpha = 0.5;
|
|
1038
|
+
}
|
|
1039
|
+
// Skirts hide seams flat model-space ground never has, and below it they are walls.
|
|
1040
|
+
if (typeof state.saved.showSkirts === "boolean") {
|
|
1041
|
+
globe.showSkirts = false;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
if (translucency && typeof state.saved.backFaceAlpha === "number") {
|
|
1046
|
+
translucency.backFaceAlpha = state.saved.backFaceAlpha;
|
|
1047
|
+
}
|
|
1048
|
+
if (typeof state.saved.showSkirts === "boolean") {
|
|
1049
|
+
globe.showSkirts = state.saved.showSkirts;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
viewer.scene.requestRender();
|
|
1053
|
+
}
|
|
1054
|
+
CameraControls.SetModelSpace = SetModelSpace;
|
|
1055
|
+
})(CameraControls || (CameraControls = {}));
|
|
1056
|
+
function restoreCesiumGestures(state) {
|
|
1057
|
+
const controller = state.viewer.scene.screenSpaceCameraController;
|
|
1058
|
+
controller.rotateEventTypes = state.saved.rotateEventTypes;
|
|
1059
|
+
controller.zoomEventTypes = state.saved.zoomEventTypes;
|
|
1060
|
+
controller.tiltEventTypes = state.saved.tiltEventTypes;
|
|
1061
|
+
}
|
|
1062
|
+
/*
|
|
1063
|
+
* Decides each frame who has the mouse: these controls near the ground, CesiumJS for planets, orthographic and tracking.
|
|
1064
|
+
*/
|
|
1065
|
+
function syncController(state) {
|
|
1066
|
+
const viewer = state.viewer;
|
|
1067
|
+
if (viewer.isDestroyed() || state.drag) {
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
const ours = shouldControl(state);
|
|
1071
|
+
if (ours === state.ours) {
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
state.ours = ours;
|
|
1075
|
+
if (ours) {
|
|
1076
|
+
const controller = viewer.scene.screenSpaceCameraController;
|
|
1077
|
+
controller.rotateEventTypes = [];
|
|
1078
|
+
controller.zoomEventTypes = [CameraEventType.PINCH];
|
|
1079
|
+
controller.tiltEventTypes = [CameraEventType.PINCH];
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
restoreCesiumGestures(state);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
function shouldControl(state) {
|
|
1086
|
+
const viewer = state.viewer;
|
|
1087
|
+
const camera = viewer.camera;
|
|
1088
|
+
if (viewer.scene.mode !== SceneMode.SCENE3D || camera.frustum instanceof OrthographicFrustum) {
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
// A camera following something is CesiumJS's to move.
|
|
1092
|
+
if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
if (state.getModelSpaceFrame) {
|
|
1096
|
+
return true;
|
|
1097
|
+
}
|
|
1098
|
+
return heightOf(state, camera.positionWC) < GEO_HANDOFF_HEIGHT;
|
|
1099
|
+
}
|
|
1100
|
+
function ellipsoidOf(state) {
|
|
1101
|
+
var _a, _b;
|
|
1102
|
+
return (_b = (_a = state.viewer.scene.globe) === null || _a === void 0 ? void 0 : _a.ellipsoid) !== null && _b !== void 0 ? _b : Ellipsoid.WGS84;
|
|
1103
|
+
}
|
|
1104
|
+
function heightOf(state, position) {
|
|
1105
|
+
const carto = ellipsoidOf(state).cartesianToCartographic(position);
|
|
1106
|
+
return carto ? carto.height : Number.POSITIVE_INFINITY;
|
|
1107
|
+
}
|
|
1108
|
+
function canvasPosition(viewer, e) {
|
|
1109
|
+
const rect = viewer.scene.canvas.getBoundingClientRect();
|
|
1110
|
+
return new Cartesian2(e.clientX - rect.left, e.clientY - rect.top);
|
|
1111
|
+
}
|
|
1112
|
+
/*
|
|
1113
|
+
* Up at a point: the model-space frame's up in model-space, else the ellipsoid's surface normal there.
|
|
1114
|
+
*/
|
|
1115
|
+
function upAt(state, position) {
|
|
1116
|
+
if (state.getModelSpaceFrame) {
|
|
1117
|
+
const up = Matrix4.multiplyByPointAsVector(state.getModelSpaceFrame(), Cartesian3.UNIT_Z, new Cartesian3());
|
|
1118
|
+
return Cartesian3.normalize(up, up);
|
|
1119
|
+
}
|
|
1120
|
+
return ellipsoidOf(state).geodeticSurfaceNormal(position, new Cartesian3());
|
|
1121
|
+
}
|
|
1122
|
+
/*
|
|
1123
|
+
* The level plane standing in for the ground when nothing is drawn under the cursor.
|
|
1124
|
+
*/
|
|
1125
|
+
function groundPlane(state) {
|
|
1126
|
+
if (state.getModelSpaceFrame) {
|
|
1127
|
+
const frame = state.getModelSpaceFrame();
|
|
1128
|
+
return Plane.fromPointNormal(Matrix4.getTranslation(frame, new Cartesian3()), upAt(state, null));
|
|
1129
|
+
}
|
|
1130
|
+
const camera = state.viewer.camera;
|
|
1131
|
+
const ellipsoid = ellipsoidOf(state);
|
|
1132
|
+
const surface = ellipsoid.scaleToGeodeticSurface(camera.positionWC, new Cartesian3());
|
|
1133
|
+
if (!surface) {
|
|
1134
|
+
return null;
|
|
1135
|
+
}
|
|
1136
|
+
return Plane.fromPointNormal(surface, ellipsoid.geodeticSurfaceNormal(surface, new Cartesian3()));
|
|
1137
|
+
}
|
|
1138
|
+
/*
|
|
1139
|
+
* How far away a depth pick is believable, since below ground the depth buffer can hold the globe's inside.
|
|
1140
|
+
*/
|
|
1141
|
+
function plausibleDistance(state) {
|
|
1142
|
+
const camera = state.viewer.camera;
|
|
1143
|
+
if (state.getModelSpaceFrame) {
|
|
1144
|
+
const origin = Matrix4.getTranslation(state.getModelSpaceFrame(), new Cartesian3());
|
|
1145
|
+
return Math.max(PLAUSIBLE_PICK_FLOOR, Cartesian3.distance(camera.positionWC, origin) * 10);
|
|
1146
|
+
}
|
|
1147
|
+
const height = Math.abs(heightOf(state, camera.positionWC) - (Number(state.viewer.scene.globeHeight) || 0));
|
|
1148
|
+
const horizon = Math.sqrt(2 * ellipsoidOf(state).maximumRadius * Math.max(height, 0));
|
|
1149
|
+
return Math.max(PLAUSIBLE_PICK_FLOOR, height * 10, horizon * 1.5);
|
|
1150
|
+
}
|
|
1151
|
+
/*
|
|
1152
|
+
* The point under a screen position: what is drawn there, else the ground plane, else a point at the last distance.
|
|
1153
|
+
*/
|
|
1154
|
+
function pickTarget(state, position) {
|
|
1155
|
+
const viewer = state.viewer;
|
|
1156
|
+
const scene = viewer.scene;
|
|
1157
|
+
const camera = viewer.camera;
|
|
1158
|
+
const ray = camera.getPickRay(position);
|
|
1159
|
+
if (!ray) {
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1162
|
+
let picked;
|
|
1163
|
+
if (scene.pickPositionSupported) {
|
|
1164
|
+
try {
|
|
1165
|
+
picked = scene.pickPosition(position);
|
|
1166
|
+
}
|
|
1167
|
+
catch (e) {
|
|
1168
|
+
picked = null;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
const plausible = plausibleDistance(state);
|
|
1172
|
+
if (isAhead(camera, picked) && Cartesian3.distance(picked, camera.positionWC) < plausible) {
|
|
1173
|
+
return picked;
|
|
1174
|
+
}
|
|
1175
|
+
const ground = groundPlane(state);
|
|
1176
|
+
const onGround = ground ? IntersectionTests.rayPlane(ray, ground) : null;
|
|
1177
|
+
if (isAhead(camera, onGround) && Cartesian3.distance(onGround, camera.positionWC) < plausible) {
|
|
1178
|
+
return onGround;
|
|
1179
|
+
}
|
|
1180
|
+
return Ray.getPoint(ray, state.lastDistance);
|
|
1181
|
+
}
|
|
1182
|
+
function isAhead(camera, point) {
|
|
1183
|
+
if (!point || !Number.isFinite(point.x) || !Number.isFinite(point.y) || !Number.isFinite(point.z)) {
|
|
1184
|
+
return false;
|
|
1185
|
+
}
|
|
1186
|
+
const toPoint = Cartesian3.subtract(point, camera.positionWC, new Cartesian3());
|
|
1187
|
+
return Cartesian3.dot(toPoint, camera.directionWC) > 0;
|
|
1188
|
+
}
|
|
1189
|
+
/*
|
|
1190
|
+
* Picks which gesture a button and its modifiers start, matching CesiumJS's own mapping.
|
|
1191
|
+
*/
|
|
1192
|
+
function dragKind(e) {
|
|
1193
|
+
if (e.shiftKey) {
|
|
1194
|
+
// Shift drag looks around, which CesiumJS still handles.
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
1197
|
+
if (e.button === 1 || (e.ctrlKey && (e.button === 0 || e.button === 2))) {
|
|
1198
|
+
return EDrag.Orbit;
|
|
1199
|
+
}
|
|
1200
|
+
if (e.button === 0) {
|
|
1201
|
+
return EDrag.Pan;
|
|
1202
|
+
}
|
|
1203
|
+
if (e.button === 2) {
|
|
1204
|
+
return EDrag.Zoom;
|
|
1205
|
+
}
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
function allows(state, kind) {
|
|
1209
|
+
const controller = state.viewer.scene.screenSpaceCameraController;
|
|
1210
|
+
if (!controller.enableInputs) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
switch (kind) {
|
|
1214
|
+
case EDrag.Pan:
|
|
1215
|
+
return controller.enableRotate;
|
|
1216
|
+
case EDrag.Orbit:
|
|
1217
|
+
return controller.enableTilt;
|
|
1218
|
+
case EDrag.Zoom:
|
|
1219
|
+
return controller.enableZoom;
|
|
1220
|
+
}
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
function onPointerDown(state, e) {
|
|
1224
|
+
const viewer = state.viewer;
|
|
1225
|
+
if (viewer.isDestroyed() || !state.ours) {
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
if (e.pointerType === "touch") {
|
|
1229
|
+
state.touches.add(e.pointerId);
|
|
1230
|
+
// A second finger makes it a pinch, which CesiumJS handles.
|
|
1231
|
+
if (state.touches.size > 1) {
|
|
1232
|
+
endDrag(state);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
const kind = dragKind(e);
|
|
1237
|
+
if (!kind || !allows(state, kind)) {
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
const position = canvasPosition(viewer, e);
|
|
1241
|
+
const target = pickTarget(state, position);
|
|
1242
|
+
if (!target) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
const camera = viewer.camera;
|
|
1246
|
+
const distance = Cartesian3.distance(camera.positionWC, target);
|
|
1247
|
+
state.lastDistance = Math.max(distance, MIN_ZOOM_DISTANCE);
|
|
1248
|
+
const drag = { kind, pointerId: e.pointerId, last: position, target, up: upAt(state, target), distance };
|
|
1249
|
+
if (kind === EDrag.Pan) {
|
|
1250
|
+
drag.plane = panPlane(camera, target, drag.up);
|
|
1251
|
+
}
|
|
1252
|
+
else if (kind === EDrag.Zoom) {
|
|
1253
|
+
drag.direction = Cartesian3.normalize(Cartesian3.subtract(target, camera.positionWC, new Cartesian3()), new Cartesian3());
|
|
1254
|
+
}
|
|
1255
|
+
state.drag = drag;
|
|
1256
|
+
}
|
|
1257
|
+
/*
|
|
1258
|
+
* A level plane through the grabbed point, or one facing the camera when the level one is seen edge on.
|
|
1259
|
+
*/
|
|
1260
|
+
function panPlane(camera, target, up) {
|
|
1261
|
+
if (Math.abs(Cartesian3.dot(camera.directionWC, up)) > GRAZING_SINE) {
|
|
1262
|
+
return Plane.fromPointNormal(target, up);
|
|
1263
|
+
}
|
|
1264
|
+
return Plane.fromPointNormal(target, Cartesian3.negate(camera.directionWC, new Cartesian3()));
|
|
1265
|
+
}
|
|
1266
|
+
function onPointerMove(state, e) {
|
|
1267
|
+
const drag = state.drag;
|
|
1268
|
+
const viewer = state.viewer;
|
|
1269
|
+
if (!drag || drag.pointerId !== e.pointerId || viewer.isDestroyed()) {
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
if (!allows(state, drag.kind)) {
|
|
1273
|
+
endDrag(state);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
const position = canvasPosition(viewer, e);
|
|
1277
|
+
const dx = position.x - drag.last.x;
|
|
1278
|
+
const dy = position.y - drag.last.y;
|
|
1279
|
+
if (dx === 0 && dy === 0) {
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
switch (drag.kind) {
|
|
1283
|
+
case EDrag.Pan:
|
|
1284
|
+
pan(state, drag, position);
|
|
1285
|
+
break;
|
|
1286
|
+
case EDrag.Orbit:
|
|
1287
|
+
orbit(state, drag, dx, dy);
|
|
1288
|
+
break;
|
|
1289
|
+
case EDrag.Zoom:
|
|
1290
|
+
// Dragging down zooms in, as it does in CesiumJS.
|
|
1291
|
+
moveAlong(state, drag.direction, drag.target, dy / DRAG_PIXELS_PER_NOTCH);
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
drag.last = position;
|
|
1295
|
+
viewer.scene.requestRender();
|
|
1296
|
+
}
|
|
1297
|
+
function onPointerUp(state, e) {
|
|
1298
|
+
var _a;
|
|
1299
|
+
state.touches.delete(e.pointerId);
|
|
1300
|
+
if (((_a = state.drag) === null || _a === void 0 ? void 0 : _a.pointerId) === e.pointerId) {
|
|
1301
|
+
endDrag(state);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
function endDrag(state) {
|
|
1305
|
+
state.drag = null;
|
|
1306
|
+
}
|
|
1307
|
+
/*
|
|
1308
|
+
* Slides the camera so the grabbed point stays under the cursor.
|
|
1309
|
+
*/
|
|
1310
|
+
function pan(state, drag, position) {
|
|
1311
|
+
const camera = state.viewer.camera;
|
|
1312
|
+
const ray = camera.getPickRay(position);
|
|
1313
|
+
const hit = ray ? IntersectionTests.rayPlane(ray, drag.plane) : null;
|
|
1314
|
+
if (!isAhead(camera, hit)) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
const delta = Cartesian3.subtract(drag.target, hit, new Cartesian3());
|
|
1318
|
+
// Near the horizon a pixel covers kilometres, so one move is capped at a few times the grab distance.
|
|
1319
|
+
const limit = Math.max(drag.distance, MIN_ZOOM_DISTANCE) * 3;
|
|
1320
|
+
const length = Cartesian3.magnitude(delta);
|
|
1321
|
+
if (length > limit) {
|
|
1322
|
+
Cartesian3.multiplyByScalar(delta, limit / length, delta);
|
|
1323
|
+
}
|
|
1324
|
+
Cartesian3.add(camera.position, delta, camera.position);
|
|
1325
|
+
}
|
|
1326
|
+
/*
|
|
1327
|
+
* Turns the camera around the grabbed point: sideways about up there, and up or down about the camera's right.
|
|
1328
|
+
*/
|
|
1329
|
+
function orbit(state, drag, dx, dy) {
|
|
1330
|
+
const viewer = state.viewer;
|
|
1331
|
+
const camera = viewer.camera;
|
|
1332
|
+
const canvas = viewer.scene.canvas;
|
|
1333
|
+
const up = drag.up;
|
|
1334
|
+
const heading = -dx / Math.max(canvas.clientWidth, 1) * Math.PI * 2;
|
|
1335
|
+
// Dragging down looks further down, as CesiumJS's own tilt does.
|
|
1336
|
+
let pitch = -dy / Math.max(canvas.clientHeight, 1) * Math.PI;
|
|
1337
|
+
// Keeps the view from tipping past straight up or down, where it would flip over.
|
|
1338
|
+
const elevation = Math.asin(Math$1.clamp(Cartesian3.dot(camera.direction, up), -1, 1));
|
|
1339
|
+
const limit = Math.PI / 2 - ORBIT_POLE_MARGIN;
|
|
1340
|
+
pitch = Math$1.clamp(elevation + pitch, -limit, limit) - elevation;
|
|
1341
|
+
rotateAbout(camera, drag.target, up, heading);
|
|
1342
|
+
const right = Cartesian3.cross(camera.direction, up, new Cartesian3());
|
|
1343
|
+
if (Cartesian3.magnitude(right) > Math$1.EPSILON6) {
|
|
1344
|
+
Cartesian3.normalize(right, right);
|
|
1345
|
+
rotateAbout(camera, drag.target, right, pitch);
|
|
1346
|
+
}
|
|
1347
|
+
levelCamera(camera, upAt(state, camera.position));
|
|
1348
|
+
}
|
|
1349
|
+
function rotateAbout(camera, pivot, axis, angle) {
|
|
1350
|
+
if (!angle) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
const rotation = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(axis, angle));
|
|
1354
|
+
const offset = Cartesian3.subtract(camera.position, pivot, new Cartesian3());
|
|
1355
|
+
Matrix3.multiplyByVector(rotation, offset, offset);
|
|
1356
|
+
Cartesian3.add(pivot, offset, camera.position);
|
|
1357
|
+
Matrix3.multiplyByVector(rotation, camera.direction, camera.direction);
|
|
1358
|
+
Matrix3.multiplyByVector(rotation, camera.up, camera.up);
|
|
1359
|
+
Matrix3.multiplyByVector(rotation, camera.right, camera.right);
|
|
1360
|
+
}
|
|
1361
|
+
/*
|
|
1362
|
+
* Takes any roll out, so the horizon stays level however the camera has turned.
|
|
1363
|
+
*/
|
|
1364
|
+
function levelCamera(camera, up) {
|
|
1365
|
+
const direction = Cartesian3.normalize(camera.direction, camera.direction);
|
|
1366
|
+
const right = Cartesian3.cross(direction, up, new Cartesian3());
|
|
1367
|
+
if (Cartesian3.magnitude(right) < Math$1.EPSILON6) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
Cartesian3.normalize(right, camera.right);
|
|
1371
|
+
Cartesian3.cross(camera.right, direction, camera.up);
|
|
1372
|
+
Cartesian3.normalize(camera.up, camera.up);
|
|
1373
|
+
}
|
|
1374
|
+
function onWheel(state, e) {
|
|
1375
|
+
const viewer = state.viewer;
|
|
1376
|
+
if (viewer.isDestroyed() || !state.ours || !allows(state, EDrag.Zoom)) {
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
let notches = e.deltaMode === 1 ? e.deltaY / 3 : e.deltaMode === 2 ? e.deltaY : e.deltaY / 100;
|
|
1380
|
+
notches = Math$1.clamp(-notches, -3, 3);
|
|
1381
|
+
if (!notches) {
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
const position = canvasPosition(viewer, e);
|
|
1385
|
+
const camera = viewer.camera;
|
|
1386
|
+
const target = pickTarget(state, position);
|
|
1387
|
+
const ray = camera.getPickRay(position);
|
|
1388
|
+
if (!target || !ray) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
const step = zoomStep(state, ray.direction, target, notches);
|
|
1392
|
+
Cartesian3.add(state.pendingZoom, step, state.pendingZoom);
|
|
1393
|
+
state.zoomPosition = Cartesian3.clone(camera.position);
|
|
1394
|
+
if (state.zoomFrame == null) {
|
|
1395
|
+
state.zoomFrame = requestAnimationFrame(() => easeZoom(state));
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
/*
|
|
1399
|
+
* Applies part of the outstanding wheel movement each frame, so a notch glides rather than jumps.
|
|
1400
|
+
*/
|
|
1401
|
+
function easeZoom(state) {
|
|
1402
|
+
state.zoomFrame = null;
|
|
1403
|
+
const viewer = state.viewer;
|
|
1404
|
+
if (viewer.isDestroyed() || !viewer[CESIUM_CAMERA_CONTROLS_KEY]) {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
// A tool locking the camera mid glide (walkthrough, a camera lock) owns it from then on.
|
|
1408
|
+
if (!allows(state, EDrag.Zoom) ||
|
|
1409
|
+
!state.zoomPosition ||
|
|
1410
|
+
!Cartesian3.equalsEpsilon(viewer.camera.position, state.zoomPosition, 0, 1e-3)) {
|
|
1411
|
+
state.pendingZoom = new Cartesian3();
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
const remaining = Cartesian3.magnitude(state.pendingZoom);
|
|
1415
|
+
const share = remaining < 0.01 ? 1 : ZOOM_EASE;
|
|
1416
|
+
const step = Cartesian3.multiplyByScalar(state.pendingZoom, share, new Cartesian3());
|
|
1417
|
+
Cartesian3.subtract(state.pendingZoom, step, state.pendingZoom);
|
|
1418
|
+
Cartesian3.add(viewer.camera.position, step, viewer.camera.position);
|
|
1419
|
+
state.zoomPosition = Cartesian3.clone(viewer.camera.position);
|
|
1420
|
+
viewer.scene.requestRender();
|
|
1421
|
+
if (share < 1) {
|
|
1422
|
+
state.zoomFrame = requestAnimationFrame(() => easeZoom(state));
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
function moveAlong(state, direction, target, notches) {
|
|
1426
|
+
const step = zoomStep(state, direction, target, notches);
|
|
1427
|
+
Cartesian3.add(state.viewer.camera.position, step, state.viewer.camera.position);
|
|
1428
|
+
}
|
|
1429
|
+
/*
|
|
1430
|
+
* The move for some notches toward a target along a direction, a share of the distance with a floor so it never stalls.
|
|
1431
|
+
*/
|
|
1432
|
+
function zoomStep(state, direction, target, notches) {
|
|
1433
|
+
const camera = state.viewer.camera;
|
|
1434
|
+
const distance = Math.max(Cartesian3.distance(camera.positionWC, target), MIN_ZOOM_DISTANCE);
|
|
1435
|
+
state.lastDistance = distance;
|
|
1436
|
+
let length = distance * ZOOM_SHARE * notches;
|
|
1437
|
+
// A geospatial camera zooming out hands over to CesiumJS once it is high enough, so only model-space is capped.
|
|
1438
|
+
if (length < 0 && state.getModelSpaceFrame) {
|
|
1439
|
+
const origin = Matrix4.getTranslation(state.getModelSpaceFrame(), new Cartesian3());
|
|
1440
|
+
const pending = Cartesian3.add(camera.positionWC, state.pendingZoom, new Cartesian3());
|
|
1441
|
+
const range = Cartesian3.distance(pending, origin);
|
|
1442
|
+
length = Math.max(length, range - MODEL_SPACE_MAX_RANGE);
|
|
1443
|
+
if (length >= 0) {
|
|
1444
|
+
return new Cartesian3();
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
return Cartesian3.multiplyByScalar(Cartesian3.normalize(direction, new Cartesian3()), length, new Cartesian3());
|
|
1448
|
+
}
|
|
1449
|
+
|
|
910
1450
|
const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
|
|
911
1451
|
const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
|
|
912
1452
|
const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
|
|
@@ -1384,6 +1924,13 @@ var ViewUtils;
|
|
|
1384
1924
|
return overriddenImageBasedLighting || null;
|
|
1385
1925
|
}
|
|
1386
1926
|
ViewUtils.GetDefaultImageBasedLighting = GetDefaultImageBasedLighting;
|
|
1927
|
+
/**
|
|
1928
|
+
* Shadow mode for the Entity graphics this library draws, following the scene's shadow switch.
|
|
1929
|
+
*/
|
|
1930
|
+
function GetEntityShadowMode(viewer) {
|
|
1931
|
+
return (viewer === null || viewer === void 0 ? void 0 : viewer.shadows) ? ShadowMode.ENABLED : ShadowMode.DISABLED;
|
|
1932
|
+
}
|
|
1933
|
+
ViewUtils.GetEntityShadowMode = GetEntityShadowMode;
|
|
1387
1934
|
function EngineShadesModelsDarker() {
|
|
1388
1935
|
return typeof DynamicEnvironmentMapManager !== "undefined";
|
|
1389
1936
|
}
|
|
@@ -1455,6 +2002,7 @@ var ViewUtils;
|
|
|
1455
2002
|
viewer[CESIUM_MODEL_SPACE_KEY] = modelSpace;
|
|
1456
2003
|
// Reload globe since we display it differently between the two modes.
|
|
1457
2004
|
SetGlobeDetails({ viewer });
|
|
2005
|
+
CameraControls.SetModelSpace(viewer, modelSpace ? () => GetModelSpaceFrame(viewer) : null);
|
|
1458
2006
|
}
|
|
1459
2007
|
ViewUtils.SetModelSpace = SetModelSpace;
|
|
1460
2008
|
function GetModelSpace(viewer) {
|
|
@@ -6177,7 +6725,7 @@ var EntitySimulation;
|
|
|
6177
6725
|
const byTime = new Map();
|
|
6178
6726
|
for (const set of this.sets.values()) {
|
|
6179
6727
|
for (const [ms, record] of set.records.get(entityId) || []) {
|
|
6180
|
-
if (attrKey && record.attrKey && record.attrKey
|
|
6728
|
+
if (attrKey && record.attrKey && !PathUtils.Equals(record.attrKey, attrKey)) {
|
|
6181
6729
|
continue;
|
|
6182
6730
|
}
|
|
6183
6731
|
const held = byTime.get(ms);
|
|
@@ -11982,6 +12530,28 @@ function getHighestZIndex(viewer, visual) {
|
|
|
11982
12530
|
return highest;
|
|
11983
12531
|
}
|
|
11984
12532
|
const MAX_SHOW_DEPTH = 10;
|
|
12533
|
+
// Entity graphics whose shadows follow the scene's shadow switch.
|
|
12534
|
+
const SHADOWED_GRAPHICS = ["model", "polygon", "polyline", "corridor"];
|
|
12535
|
+
/*
|
|
12536
|
+
* Points a registered Entity graphic, and the graphics drawn beside it, at the given shadow mode.
|
|
12537
|
+
*/
|
|
12538
|
+
function updateCEntityShadows(viewer, visual, mode, depth = 0) {
|
|
12539
|
+
if (!visual || depth > MAX_SHOW_DEPTH) {
|
|
12540
|
+
return;
|
|
12541
|
+
}
|
|
12542
|
+
for (const key of SHADOWED_GRAPHICS) {
|
|
12543
|
+
const graphic = visual[key];
|
|
12544
|
+
// Only graphics drawn with a mode; one left at Cesium's default was never meant to shadow.
|
|
12545
|
+
if ((graphic === null || graphic === void 0 ? void 0 : graphic.shadows) != null) {
|
|
12546
|
+
SetCPropIfChanged({ viewer, graphic, property: "shadows", value: mode });
|
|
12547
|
+
}
|
|
12548
|
+
}
|
|
12549
|
+
if (visual._siblingGraphics) {
|
|
12550
|
+
for (let i = 0; i < visual._siblingGraphics.length; i++) {
|
|
12551
|
+
updateCEntityShadows(viewer, visual._siblingGraphics[i], mode, depth + 1);
|
|
12552
|
+
}
|
|
12553
|
+
}
|
|
12554
|
+
}
|
|
11985
12555
|
function updateCEntityShow(viewer, visual, rego, show, ignoreParent, depth = 0) {
|
|
11986
12556
|
if (depth > MAX_SHOW_DEPTH) {
|
|
11987
12557
|
console.warn("updateCEntityShow(): Max show depth reached. EntityId = " + rego.entityId);
|
|
@@ -12318,7 +12888,7 @@ var VisualsRegister;
|
|
|
12318
12888
|
}
|
|
12319
12889
|
get OnLabelGroupsChanged() { return this.labelGroupsChanged; }
|
|
12320
12890
|
constructor(params) {
|
|
12321
|
-
var _a, _b;
|
|
12891
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
12322
12892
|
this.id = ObjectUtils.UId();
|
|
12323
12893
|
this.disposed = false;
|
|
12324
12894
|
this.rego = {};
|
|
@@ -12368,6 +12938,7 @@ var VisualsRegister;
|
|
|
12368
12938
|
this.sourceOrderDirty = false;
|
|
12369
12939
|
// Stops following what is simulated, so labels can read it again when it changes.
|
|
12370
12940
|
this.simulationRemoval = null;
|
|
12941
|
+
this.shadowsRemoval = null;
|
|
12371
12942
|
this.labelGroupsChanged = new BruceEvent();
|
|
12372
12943
|
this.hoverRingState = {};
|
|
12373
12944
|
this.retiringHoverLabels = new Map();
|
|
@@ -12403,6 +12974,27 @@ var VisualsRegister;
|
|
|
12403
12974
|
register: this
|
|
12404
12975
|
});
|
|
12405
12976
|
this.simulationRemoval = (_b = (_a = EntitySimulation.Get(this.viewer)) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => this.reloadLabels(change.entityIds))) !== null && _b !== void 0 ? _b : null;
|
|
12977
|
+
this.entityShadows = Boolean((_c = this.viewer) === null || _c === void 0 ? void 0 : _c.shadows);
|
|
12978
|
+
this.shadowsRemoval = (_g = (_f = (_e = (_d = this.viewer) === null || _d === void 0 ? void 0 : _d.scene) === null || _e === void 0 ? void 0 : _e.preUpdate) === null || _f === void 0 ? void 0 : _f.addEventListener(() => this.syncEntityShadows())) !== null && _g !== void 0 ? _g : null;
|
|
12979
|
+
}
|
|
12980
|
+
/*
|
|
12981
|
+
* Follows the scene's shadow switch on every registered Entity, whichever app or bookmark flipped it.
|
|
12982
|
+
*/
|
|
12983
|
+
syncEntityShadows() {
|
|
12984
|
+
const viewer = this.viewer;
|
|
12985
|
+
const enabled = Boolean(viewer === null || viewer === void 0 ? void 0 : viewer.shadows);
|
|
12986
|
+
if (enabled === this.entityShadows || this.disposed || !viewer || viewer.isDestroyed()) {
|
|
12987
|
+
return;
|
|
12988
|
+
}
|
|
12989
|
+
this.entityShadows = enabled;
|
|
12990
|
+
const mode = enabled ? ShadowMode.ENABLED : ShadowMode.DISABLED;
|
|
12991
|
+
for (const regos of Object.values(this.rego)) {
|
|
12992
|
+
for (const rego of regos) {
|
|
12993
|
+
if (rego.visual instanceof Entity) {
|
|
12994
|
+
updateCEntityShadows(viewer, rego.visual, mode);
|
|
12995
|
+
}
|
|
12996
|
+
}
|
|
12997
|
+
}
|
|
12406
12998
|
}
|
|
12407
12999
|
/*
|
|
12408
13000
|
* Tells labels to read their Entity again, since they keep what they read when drawn.
|
|
@@ -13331,9 +13923,11 @@ var VisualsRegister;
|
|
|
13331
13923
|
(_b = this.viewer.scene) === null || _b === void 0 ? void 0 : _b.requestRender();
|
|
13332
13924
|
}
|
|
13333
13925
|
Dispose() {
|
|
13334
|
-
var _a, _b, _c, _d, _e, _f;
|
|
13926
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
13335
13927
|
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
13336
13928
|
this.simulationRemoval = null;
|
|
13929
|
+
(_b = this.shadowsRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
13930
|
+
this.shadowsRemoval = null;
|
|
13337
13931
|
CesiumEntityStyler.SetDimming(this.viewer, this.id, false);
|
|
13338
13932
|
this.ClearLabelHover();
|
|
13339
13933
|
clearTimeout(this.hoverRingReset);
|
|
@@ -13343,14 +13937,14 @@ var VisualsRegister;
|
|
|
13343
13937
|
EntityLabel.Detatch({ label });
|
|
13344
13938
|
}
|
|
13345
13939
|
this.retiringHoverLabels.clear();
|
|
13346
|
-
(
|
|
13940
|
+
(_c = this.labelGroups) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
13347
13941
|
this.labelGroupsChanged.Clear();
|
|
13348
13942
|
for (const regos of Object.values(this.rego)) {
|
|
13349
13943
|
for (const rego of regos)
|
|
13350
13944
|
EntityLabel.Detatch({ rego, force: true });
|
|
13351
13945
|
}
|
|
13352
13946
|
EntityLabel.SetContainer(this.viewer);
|
|
13353
|
-
(
|
|
13947
|
+
(_d = this.cameraCullerDispose) === null || _d === void 0 ? void 0 : _d.call(this, {
|
|
13354
13948
|
uncull: false
|
|
13355
13949
|
});
|
|
13356
13950
|
this.cameraCullerDispose = null;
|
|
@@ -13367,7 +13961,7 @@ var VisualsRegister;
|
|
|
13367
13961
|
this.disposed = true;
|
|
13368
13962
|
for (const record of Array.from(this.menuItemSources.values())) {
|
|
13369
13963
|
try {
|
|
13370
|
-
(
|
|
13964
|
+
(_f = (_e = this.viewer) === null || _e === void 0 ? void 0 : _e.dataSources) === null || _f === void 0 ? void 0 : _f.remove(record.source, true);
|
|
13371
13965
|
}
|
|
13372
13966
|
catch (e) {
|
|
13373
13967
|
console.error(e);
|
|
@@ -13376,7 +13970,7 @@ var VisualsRegister;
|
|
|
13376
13970
|
this.menuItemSources.clear();
|
|
13377
13971
|
// Hand every tileset's show flag back to its owner, holding whatever the owner last asked for.
|
|
13378
13972
|
for (const rego of Array.from(this.tilesets.values())) {
|
|
13379
|
-
(
|
|
13973
|
+
(_g = rego.gate) === null || _g === void 0 ? void 0 : _g.Release();
|
|
13380
13974
|
}
|
|
13381
13975
|
this.tilesets.clear();
|
|
13382
13976
|
}
|
|
@@ -14100,8 +14694,11 @@ var VisualsRegister;
|
|
|
14100
14694
|
}
|
|
14101
14695
|
}
|
|
14102
14696
|
// Add the new visual to the register.
|
|
14697
|
+
// Tileset managers add the same rego again for each tile holding more of the Entity.
|
|
14103
14698
|
const entityRegos = (_a = this.rego[entityId]) !== null && _a !== void 0 ? _a : [];
|
|
14104
|
-
entityRegos.
|
|
14699
|
+
if (!entityRegos.includes(rego)) {
|
|
14700
|
+
entityRegos.push(rego);
|
|
14701
|
+
}
|
|
14105
14702
|
this.rego[entityId] = entityRegos;
|
|
14106
14703
|
this.indexMenuItemEntity(rego.menuItemId, entityId);
|
|
14107
14704
|
// Mark the visual as part of this register so selection works.
|
|
@@ -14535,6 +15132,28 @@ var VisualsRegister;
|
|
|
14535
15132
|
}
|
|
14536
15133
|
}
|
|
14537
15134
|
}
|
|
15135
|
+
/*
|
|
15136
|
+
* Hands a tile feature rego to a sibling feature from another tile when its own tile unloads.
|
|
15137
|
+
* An Entity split across tiles keeps drawing from those, so it must stay registered for them.
|
|
15138
|
+
*/
|
|
15139
|
+
promoteTileSibling(rego, removing) {
|
|
15140
|
+
var _a;
|
|
15141
|
+
const departing = rego.visual;
|
|
15142
|
+
if (!(departing instanceof Cesium3DTileFeature) || !((_a = departing._siblingGraphics) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
15143
|
+
return false;
|
|
15144
|
+
}
|
|
15145
|
+
const remaining = departing._siblingGraphics.filter(s => !removing.has(s));
|
|
15146
|
+
if (!remaining.length) {
|
|
15147
|
+
return false;
|
|
15148
|
+
}
|
|
15149
|
+
departing._siblingGraphics = undefined;
|
|
15150
|
+
unmarkEntity(departing, true);
|
|
15151
|
+
const promoted = remaining[0];
|
|
15152
|
+
promoted._siblingGraphics = remaining.slice(1);
|
|
15153
|
+
rego.visual = promoted;
|
|
15154
|
+
markEntity(this, rego, promoted, false);
|
|
15155
|
+
return true;
|
|
15156
|
+
}
|
|
14538
15157
|
/**
|
|
14539
15158
|
* Removes regos matching given visuals.
|
|
14540
15159
|
* This is used when we cannot unpack properties from the visual any longer to determine its ID.
|
|
@@ -14545,6 +15164,7 @@ var VisualsRegister;
|
|
|
14545
15164
|
var _a, _b, _c;
|
|
14546
15165
|
const { doRemove = true, requestRender = true, source, doUpdate, menuItemId } = params;
|
|
14547
15166
|
const removedEntityIds = new Set();
|
|
15167
|
+
const removing = new Set(params.visuals);
|
|
14548
15168
|
for (const visual of params.visuals) {
|
|
14549
15169
|
const visExt = visual;
|
|
14550
15170
|
const rego = (visExt === null || visExt === void 0 ? void 0 : visExt._register) === this ? visExt._rego : null;
|
|
@@ -14556,7 +15176,20 @@ var VisualsRegister;
|
|
|
14556
15176
|
if (!entityRegos) {
|
|
14557
15177
|
continue;
|
|
14558
15178
|
}
|
|
14559
|
-
if (rego.visual === visual) {
|
|
15179
|
+
if (rego.visual === visual && this.promoteTileSibling(rego, removing)) {
|
|
15180
|
+
if (doRemove != false) {
|
|
15181
|
+
removeEntity(this.viewer, visual);
|
|
15182
|
+
}
|
|
15183
|
+
// The label was placed against the departing feature, the refresh attaches it again.
|
|
15184
|
+
EntityLabel.Detatch({
|
|
15185
|
+
rego, force: true
|
|
15186
|
+
});
|
|
15187
|
+
this.queueUpdate({
|
|
15188
|
+
entityId: entityId,
|
|
15189
|
+
refresh: true
|
|
15190
|
+
});
|
|
15191
|
+
}
|
|
15192
|
+
else if (rego.visual === visual) {
|
|
14560
15193
|
EntityLabel.Detatch({
|
|
14561
15194
|
rego, force: true
|
|
14562
15195
|
});
|
|
@@ -16212,6 +16845,304 @@ class TilesetStyler {
|
|
|
16212
16845
|
}
|
|
16213
16846
|
}
|
|
16214
16847
|
|
|
16848
|
+
// viewer[VIEWER_WATCH_KEY] is true once the viewer's canvas reports context loss to DeviceProfile.
|
|
16849
|
+
const VIEWER_WATCH_KEY = "_bruceDeviceProfileWatch";
|
|
16850
|
+
// localStorage[DEMOTION_KEY] holds an IDemotion written after this browser lost a WebGL context.
|
|
16851
|
+
const DEMOTION_KEY = "bruce-cesium-device-demotion";
|
|
16852
|
+
// A lost context demotes for this long, so one driver reset does not cap a strong device forever.
|
|
16853
|
+
// Measured on the wall clock, not the viewer's: it spans sessions, and a scene clock can be historic.
|
|
16854
|
+
const DEMOTION_MS = 14 * 24 * 60 * 60 * 1000;
|
|
16855
|
+
// Each loss demotes one more tier, up to this many.
|
|
16856
|
+
const DEMOTION_MAX = 2;
|
|
16857
|
+
/*
|
|
16858
|
+
* Reads the demotion left by earlier context losses, ignoring an expired or unreadable one.
|
|
16859
|
+
*/
|
|
16860
|
+
function readDemotion(now) {
|
|
16861
|
+
try {
|
|
16862
|
+
const value = JSON.parse(window.localStorage.getItem(DEMOTION_KEY));
|
|
16863
|
+
if (value &&
|
|
16864
|
+
Number.isFinite(value.count) &&
|
|
16865
|
+
Number.isFinite(value.at) &&
|
|
16866
|
+
now - value.at < DEMOTION_MS) {
|
|
16867
|
+
return value;
|
|
16868
|
+
}
|
|
16869
|
+
}
|
|
16870
|
+
catch (e) {
|
|
16871
|
+
// Storage is blocked (private mode, sandboxed frame) or holds junk; treat as no demotion.
|
|
16872
|
+
}
|
|
16873
|
+
return null;
|
|
16874
|
+
}
|
|
16875
|
+
/*
|
|
16876
|
+
* Stores or clears the demotion, carrying on without it where storage is blocked.
|
|
16877
|
+
*/
|
|
16878
|
+
function writeDemotion(value) {
|
|
16879
|
+
try {
|
|
16880
|
+
if (value) {
|
|
16881
|
+
window.localStorage.setItem(DEMOTION_KEY, JSON.stringify(value));
|
|
16882
|
+
}
|
|
16883
|
+
else {
|
|
16884
|
+
window.localStorage.removeItem(DEMOTION_KEY);
|
|
16885
|
+
}
|
|
16886
|
+
}
|
|
16887
|
+
catch (e) {
|
|
16888
|
+
// Without storage the demotion lasts only for this page.
|
|
16889
|
+
}
|
|
16890
|
+
}
|
|
16891
|
+
/*
|
|
16892
|
+
* Reads the GPU name, preferring the unmasked one, which browsers that hide it simply do not offer.
|
|
16893
|
+
*/
|
|
16894
|
+
function readRenderer(gl) {
|
|
16895
|
+
try {
|
|
16896
|
+
const ext = gl.getExtension("WEBGL_debug_renderer_info");
|
|
16897
|
+
const name = ext ? gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER);
|
|
16898
|
+
return typeof name === "string" && name ? name : undefined;
|
|
16899
|
+
}
|
|
16900
|
+
catch (e) {
|
|
16901
|
+
return undefined;
|
|
16902
|
+
}
|
|
16903
|
+
}
|
|
16904
|
+
/**
|
|
16905
|
+
* Picks how much the scene may hold in memory on this device, from a hardware guess and past sessions.
|
|
16906
|
+
*/
|
|
16907
|
+
var DeviceProfile;
|
|
16908
|
+
(function (DeviceProfile) {
|
|
16909
|
+
let ETier;
|
|
16910
|
+
(function (ETier) {
|
|
16911
|
+
ETier["Low"] = "LOW";
|
|
16912
|
+
ETier["Mid"] = "MID";
|
|
16913
|
+
ETier["High"] = "HIGH";
|
|
16914
|
+
})(ETier = DeviceProfile.ETier || (DeviceProfile.ETier = {}));
|
|
16915
|
+
DeviceProfile.BUDGETS = {
|
|
16916
|
+
[ETier.Low]: { tilesetMb: 384, splats: 1000000 },
|
|
16917
|
+
[ETier.Mid]: { tilesetMb: 1024, splats: 3000000 },
|
|
16918
|
+
[ETier.High]: { tilesetMb: 2048, splats: 6000000 }
|
|
16919
|
+
};
|
|
16920
|
+
const ORDER = [ETier.Low, ETier.Mid, ETier.High];
|
|
16921
|
+
/**
|
|
16922
|
+
* Raised after the override or a demotion changes the tier, so live budgets can be redistributed.
|
|
16923
|
+
*/
|
|
16924
|
+
DeviceProfile.Changed = new Event();
|
|
16925
|
+
let override = null;
|
|
16926
|
+
let detected = null;
|
|
16927
|
+
let logged = false;
|
|
16928
|
+
/*
|
|
16929
|
+
* Sorts a GPU name into a class. Order matters: Intel Arc is discrete, SwiftShader names any vendor.
|
|
16930
|
+
*/
|
|
16931
|
+
function ClassifyGpu(renderer) {
|
|
16932
|
+
const name = (renderer || "").toLowerCase();
|
|
16933
|
+
if (!name) {
|
|
16934
|
+
return "unknown";
|
|
16935
|
+
}
|
|
16936
|
+
if (/swiftshader|llvmpipe|softpipe|lavapipe|software|basic render/.test(name)) {
|
|
16937
|
+
return "software";
|
|
16938
|
+
}
|
|
16939
|
+
if (/mali|adreno|powervr|apple gpu|videocore|immortalis|xclipse|tegra/.test(name)) {
|
|
16940
|
+
return "mobile";
|
|
16941
|
+
}
|
|
16942
|
+
if (/apple m\d+ (pro|max|ultra)/.test(name)) {
|
|
16943
|
+
return "discrete";
|
|
16944
|
+
}
|
|
16945
|
+
if (/nvidia|geforce|quadro|rtx|radeon (rx|pro|r9|vii)|firepro|arc(\(tm\))? a\d/.test(name)) {
|
|
16946
|
+
return "discrete";
|
|
16947
|
+
}
|
|
16948
|
+
if (/intel|apple m\d|radeon(\(tm\))? graphics|vega \d/.test(name)) {
|
|
16949
|
+
return "integrated";
|
|
16950
|
+
}
|
|
16951
|
+
return "unknown";
|
|
16952
|
+
}
|
|
16953
|
+
DeviceProfile.ClassifyGpu = ClassifyGpu;
|
|
16954
|
+
/**
|
|
16955
|
+
* Guesses a tier from the hardware alone. Unknown hardware stays mid; only clear evidence moves it.
|
|
16956
|
+
*/
|
|
16957
|
+
function Classify(env) {
|
|
16958
|
+
const ua = (env.userAgent || "").toLowerCase();
|
|
16959
|
+
const mobile = /android|iphone|ipad|ipod|mobile/.test(ua) || (/macintosh/.test(ua) && env.maxTouchPoints > 1);
|
|
16960
|
+
const gpuClass = ClassifyGpu(env.gpuRenderer);
|
|
16961
|
+
const memory = env.deviceMemory;
|
|
16962
|
+
const reasons = [];
|
|
16963
|
+
let tier = ETier.Mid;
|
|
16964
|
+
if (gpuClass === "software") {
|
|
16965
|
+
reasons.push("software renderer");
|
|
16966
|
+
tier = ETier.Low;
|
|
16967
|
+
}
|
|
16968
|
+
if (mobile) {
|
|
16969
|
+
reasons.push("mobile device");
|
|
16970
|
+
tier = ETier.Low;
|
|
16971
|
+
}
|
|
16972
|
+
if (Number.isFinite(memory) && memory < 4) {
|
|
16973
|
+
reasons.push(`${memory} GB device memory`);
|
|
16974
|
+
tier = ETier.Low;
|
|
16975
|
+
}
|
|
16976
|
+
if (Number.isFinite(env.maxTextureSize) && env.maxTextureSize < 8192) {
|
|
16977
|
+
reasons.push(`max texture ${env.maxTextureSize}`);
|
|
16978
|
+
tier = ETier.Low;
|
|
16979
|
+
}
|
|
16980
|
+
if (tier === ETier.Mid && gpuClass === "discrete") {
|
|
16981
|
+
if (!Number.isFinite(memory) || memory >= 8) {
|
|
16982
|
+
reasons.push("discrete GPU");
|
|
16983
|
+
tier = ETier.High;
|
|
16984
|
+
}
|
|
16985
|
+
else {
|
|
16986
|
+
reasons.push(`discrete GPU held to mid by ${memory} GB device memory`);
|
|
16987
|
+
}
|
|
16988
|
+
}
|
|
16989
|
+
if (!reasons.length) {
|
|
16990
|
+
reasons.push(`${gpuClass} GPU`);
|
|
16991
|
+
}
|
|
16992
|
+
return { tier, gpuClass, mobile, reasons };
|
|
16993
|
+
}
|
|
16994
|
+
DeviceProfile.Classify = Classify;
|
|
16995
|
+
/*
|
|
16996
|
+
* Reads the browser environment, from the viewer's GL context when given rather than a spare one.
|
|
16997
|
+
*/
|
|
16998
|
+
function readEnvironment(viewer) {
|
|
16999
|
+
var _a, _b, _c;
|
|
17000
|
+
const nav = typeof navigator !== "undefined" ? navigator : {};
|
|
17001
|
+
const env = {
|
|
17002
|
+
userAgent: nav.userAgent,
|
|
17003
|
+
maxTouchPoints: nav.maxTouchPoints,
|
|
17004
|
+
deviceMemory: nav.deviceMemory,
|
|
17005
|
+
hardwareConcurrency: nav.hardwareConcurrency
|
|
17006
|
+
};
|
|
17007
|
+
let gl = (_b = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.scene) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b._gl;
|
|
17008
|
+
let spare = false;
|
|
17009
|
+
if (!gl && typeof document !== "undefined") {
|
|
17010
|
+
try {
|
|
17011
|
+
gl = document.createElement("canvas").getContext("webgl");
|
|
17012
|
+
spare = Boolean(gl);
|
|
17013
|
+
}
|
|
17014
|
+
catch (e) {
|
|
17015
|
+
gl = null;
|
|
17016
|
+
}
|
|
17017
|
+
}
|
|
17018
|
+
// Detection must never stop a scene loading, so anything odd leaves the GPU unknown.
|
|
17019
|
+
if (gl &&
|
|
17020
|
+
typeof gl.getParameter === "function" &&
|
|
17021
|
+
typeof gl.getExtension === "function") {
|
|
17022
|
+
env.gpuRenderer = readRenderer(gl);
|
|
17023
|
+
try {
|
|
17024
|
+
env.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE) || undefined;
|
|
17025
|
+
if (spare) {
|
|
17026
|
+
// Browsers cap live contexts per page; give this one back now rather than at GC.
|
|
17027
|
+
(_c = gl.getExtension("WEBGL_lose_context")) === null || _c === void 0 ? void 0 : _c.loseContext();
|
|
17028
|
+
}
|
|
17029
|
+
}
|
|
17030
|
+
catch (e) {
|
|
17031
|
+
// Leave it unknown.
|
|
17032
|
+
}
|
|
17033
|
+
}
|
|
17034
|
+
return env;
|
|
17035
|
+
}
|
|
17036
|
+
/**
|
|
17037
|
+
* Returns this device's profile, detecting it once per page. Pass the viewer to read its GL context.
|
|
17038
|
+
*/
|
|
17039
|
+
function Get(viewer) {
|
|
17040
|
+
var _a, _b;
|
|
17041
|
+
if (!detected) {
|
|
17042
|
+
const environment = readEnvironment(viewer);
|
|
17043
|
+
detected = { ...Classify(environment), environment };
|
|
17044
|
+
}
|
|
17045
|
+
const demotion = readDemotion(Date.now());
|
|
17046
|
+
const demoted = Math.min((_a = demotion === null || demotion === void 0 ? void 0 : demotion.count) !== null && _a !== void 0 ? _a : 0, DEMOTION_MAX);
|
|
17047
|
+
let tier = ORDER[Math.max(0, ORDER.indexOf(detected.tier) - demoted)];
|
|
17048
|
+
if (override) {
|
|
17049
|
+
tier = override;
|
|
17050
|
+
}
|
|
17051
|
+
const profile = {
|
|
17052
|
+
tier,
|
|
17053
|
+
detectedTier: detected.tier,
|
|
17054
|
+
gpuClass: detected.gpuClass,
|
|
17055
|
+
mobile: detected.mobile,
|
|
17056
|
+
demoted,
|
|
17057
|
+
overridden: Boolean(override),
|
|
17058
|
+
reasons: [...detected.reasons],
|
|
17059
|
+
environment: { ...detected.environment }
|
|
17060
|
+
};
|
|
17061
|
+
if (!logged) {
|
|
17062
|
+
logged = true;
|
|
17063
|
+
console.info(`[DeviceProfile] tier ${profile.tier} (${profile.reasons.join(", ")}` +
|
|
17064
|
+
`${demoted ? `, demoted ${demoted} after lost WebGL context` : ""}` +
|
|
17065
|
+
`${override ? ", overridden" : ""}). GPU: ${(_b = profile.environment.gpuRenderer) !== null && _b !== void 0 ? _b : "unknown"}.`);
|
|
17066
|
+
}
|
|
17067
|
+
return profile;
|
|
17068
|
+
}
|
|
17069
|
+
DeviceProfile.Get = Get;
|
|
17070
|
+
/**
|
|
17071
|
+
* Returns the memory budgets for this device's tier, or for a given tier.
|
|
17072
|
+
*/
|
|
17073
|
+
function GetBudget(tier) {
|
|
17074
|
+
return DeviceProfile.BUDGETS[tier !== null && tier !== void 0 ? tier : Get().tier];
|
|
17075
|
+
}
|
|
17076
|
+
DeviceProfile.GetBudget = GetBudget;
|
|
17077
|
+
/**
|
|
17078
|
+
* Forces a tier, for a user who knows better than the guess. Null returns to detection.
|
|
17079
|
+
*/
|
|
17080
|
+
function SetOverride(tier) {
|
|
17081
|
+
const next = tier && ORDER.includes(tier) ? tier : null;
|
|
17082
|
+
if (next === override) {
|
|
17083
|
+
return;
|
|
17084
|
+
}
|
|
17085
|
+
override = next;
|
|
17086
|
+
DeviceProfile.Changed.raiseEvent();
|
|
17087
|
+
}
|
|
17088
|
+
DeviceProfile.SetOverride = SetOverride;
|
|
17089
|
+
/**
|
|
17090
|
+
* Returns the forced tier, or null while detection decides.
|
|
17091
|
+
*/
|
|
17092
|
+
function GetOverride() {
|
|
17093
|
+
return override;
|
|
17094
|
+
}
|
|
17095
|
+
DeviceProfile.GetOverride = GetOverride;
|
|
17096
|
+
/**
|
|
17097
|
+
* Records that a WebGL context was lost, so this and later sessions start a tier lower.
|
|
17098
|
+
*/
|
|
17099
|
+
function RecordContextLost() {
|
|
17100
|
+
var _a, _b;
|
|
17101
|
+
const now = Date.now();
|
|
17102
|
+
const count = Math.min(((_b = (_a = readDemotion(now)) === null || _a === void 0 ? void 0 : _a.count) !== null && _b !== void 0 ? _b : 0) + 1, DEMOTION_MAX);
|
|
17103
|
+
writeDemotion({ count, at: now });
|
|
17104
|
+
console.warn(`[DeviceProfile] WebGL context lost; demoting the memory tier by ${count}.`);
|
|
17105
|
+
DeviceProfile.Changed.raiseEvent();
|
|
17106
|
+
}
|
|
17107
|
+
DeviceProfile.RecordContextLost = RecordContextLost;
|
|
17108
|
+
/**
|
|
17109
|
+
* Forgets earlier context losses, for a host that offers a reset.
|
|
17110
|
+
*/
|
|
17111
|
+
function ClearDemotion() {
|
|
17112
|
+
writeDemotion(null);
|
|
17113
|
+
DeviceProfile.Changed.raiseEvent();
|
|
17114
|
+
}
|
|
17115
|
+
DeviceProfile.ClearDemotion = ClearDemotion;
|
|
17116
|
+
/**
|
|
17117
|
+
* Reports the viewer's context losses. Safe to call repeatedly.
|
|
17118
|
+
*/
|
|
17119
|
+
function WatchViewer(viewer) {
|
|
17120
|
+
const canvas = viewer === null || viewer === void 0 ? void 0 : viewer.canvas;
|
|
17121
|
+
if (!canvas ||
|
|
17122
|
+
viewer[VIEWER_WATCH_KEY] ||
|
|
17123
|
+
typeof canvas.addEventListener !== "function") {
|
|
17124
|
+
return;
|
|
17125
|
+
}
|
|
17126
|
+
viewer[VIEWER_WATCH_KEY] = true;
|
|
17127
|
+
canvas.addEventListener("webglcontextlost", () => {
|
|
17128
|
+
// Ignore a loss caused by tearing the viewer down.
|
|
17129
|
+
if (!viewer.isDestroyed()) {
|
|
17130
|
+
RecordContextLost();
|
|
17131
|
+
}
|
|
17132
|
+
});
|
|
17133
|
+
}
|
|
17134
|
+
DeviceProfile.WatchViewer = WatchViewer;
|
|
17135
|
+
/**
|
|
17136
|
+
* Forgets the detected hardware and override, for tests.
|
|
17137
|
+
*/
|
|
17138
|
+
function Reset() {
|
|
17139
|
+
detected = null;
|
|
17140
|
+
override = null;
|
|
17141
|
+
logged = false;
|
|
17142
|
+
}
|
|
17143
|
+
DeviceProfile.Reset = Reset;
|
|
17144
|
+
})(DeviceProfile || (DeviceProfile = {}));
|
|
17145
|
+
|
|
16215
17146
|
/**
|
|
16216
17147
|
* Returns if a given tileset is alive and in the scene.
|
|
16217
17148
|
* @param viewer
|
|
@@ -16230,7 +17161,7 @@ function isAlive$2(viewer, cTileset) {
|
|
|
16230
17161
|
}
|
|
16231
17162
|
return viewer.scene.primitives.contains(cTileset);
|
|
16232
17163
|
}
|
|
16233
|
-
const VIEWER_WATCH_KEY = "bruce-viewer-watch";
|
|
17164
|
+
const VIEWER_WATCH_KEY$1 = "bruce-viewer-watch";
|
|
16234
17165
|
const WATCH_KEY = "bruce-tileset-watch";
|
|
16235
17166
|
const VIEWER_DATE_RANGE_WATCH_KEY = "bruce-viewer-date-range-watch";
|
|
16236
17167
|
const DATE_RANGE_WATCH_KEY = "bruce-tileset-date-range-watch";
|
|
@@ -16292,6 +17223,22 @@ function setDateRangeVisible(renderObject, visible) {
|
|
|
16292
17223
|
}
|
|
16293
17224
|
renderObject._bruceDateRangeVisible = visible;
|
|
16294
17225
|
}
|
|
17226
|
+
// A tileset may pass its cache share by this fraction before Cesium coarsens it to fit.
|
|
17227
|
+
const TILESET_OVERFLOW_RATIO = 0.25;
|
|
17228
|
+
/*
|
|
17229
|
+
* Returns the options capping a tileset's tile cache at the given MB, in the form the running Cesium reads.
|
|
17230
|
+
*/
|
|
17231
|
+
function getTilesetMemoryProps(mb) {
|
|
17232
|
+
const prototype = Cesium3DTileset.prototype;
|
|
17233
|
+
if ("cacheBytes" in prototype) {
|
|
17234
|
+
const props = { cacheBytes: Math.round(mb * 1024 * 1024) };
|
|
17235
|
+
if ("maximumCacheOverflowBytes" in prototype) {
|
|
17236
|
+
props.maximumCacheOverflowBytes = Math.round(mb * TILESET_OVERFLOW_RATIO * 1024 * 1024);
|
|
17237
|
+
}
|
|
17238
|
+
return props;
|
|
17239
|
+
}
|
|
17240
|
+
return { maximumMemoryUsage: mb };
|
|
17241
|
+
}
|
|
16295
17242
|
/**
|
|
16296
17243
|
* Creates and returns a tileset instance from a given url.
|
|
16297
17244
|
* This is made to handle the difference between old and new cesium versions.
|
|
@@ -16308,8 +17255,8 @@ async function createTileset(url, props, noMemoryLimit) {
|
|
|
16308
17255
|
};
|
|
16309
17256
|
Object.assign(defaultProps, ViewUtils.DefaultLightingProps());
|
|
16310
17257
|
if (noMemoryLimit != true) {
|
|
16311
|
-
//
|
|
16312
|
-
defaultProps.
|
|
17258
|
+
// The memory watcher narrows this to a share once the tileset joins it.
|
|
17259
|
+
Object.assign(defaultProps, getTilesetMemoryProps(TilesetRenderEngine.GetTilesetMemoryBudget()));
|
|
16313
17260
|
}
|
|
16314
17261
|
const C3DT = Cesium3DTileset;
|
|
16315
17262
|
if (C3DT.fromUrl) {
|
|
@@ -16861,10 +17808,23 @@ var TilesetRenderEngine;
|
|
|
16861
17808
|
}
|
|
16862
17809
|
TilesetRenderEngine.UnwatchDateRange = UnwatchDateRange;
|
|
16863
17810
|
/**
|
|
16864
|
-
*
|
|
16865
|
-
|
|
17811
|
+
* Total MB all tilesets may use, split evenly; null leaves it to the DeviceProfile tier.
|
|
17812
|
+
*/
|
|
17813
|
+
TilesetRenderEngine.MAX_TILESET_MEMORY = null;
|
|
17814
|
+
/**
|
|
17815
|
+
* Smallest MB share a tileset gets; small, since Cesium coarsens one that needs more.
|
|
16866
17816
|
*/
|
|
16867
|
-
TilesetRenderEngine.
|
|
17817
|
+
TilesetRenderEngine.MIN_TILESET_MEMORY = 32;
|
|
17818
|
+
/**
|
|
17819
|
+
* Returns the total MB all tilesets may use, from MAX_TILESET_MEMORY or else the device tier.
|
|
17820
|
+
*/
|
|
17821
|
+
function GetTilesetMemoryBudget() {
|
|
17822
|
+
if (Number.isFinite(TilesetRenderEngine.MAX_TILESET_MEMORY) && TilesetRenderEngine.MAX_TILESET_MEMORY > 0) {
|
|
17823
|
+
return TilesetRenderEngine.MAX_TILESET_MEMORY;
|
|
17824
|
+
}
|
|
17825
|
+
return DeviceProfile.GetBudget().tilesetMb;
|
|
17826
|
+
}
|
|
17827
|
+
TilesetRenderEngine.GetTilesetMemoryBudget = GetTilesetMemoryBudget;
|
|
16868
17828
|
/**
|
|
16869
17829
|
* Watches tileset date cutoffs and toggles their primitive visibility based on the viewer clock.
|
|
16870
17830
|
*/
|
|
@@ -16955,23 +17915,26 @@ var TilesetRenderEngine;
|
|
|
16955
17915
|
constructor(viewer) {
|
|
16956
17916
|
this.watched = [];
|
|
16957
17917
|
this.viewer = viewer;
|
|
17918
|
+
DeviceProfile.Get(viewer);
|
|
17919
|
+
DeviceProfile.WatchViewer(viewer);
|
|
17920
|
+
this.removeChanged = DeviceProfile.Changed.addEventListener(() => this.distributeMemory());
|
|
16958
17921
|
}
|
|
16959
17922
|
distributeMemory() {
|
|
16960
17923
|
this.clean();
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
const
|
|
16966
|
-
const totalPerTileset = Math.max(this.watched.length ? maxMemory / this.watched.length : maxMemory, minMemory);
|
|
17924
|
+
if (!this.watched.length) {
|
|
17925
|
+
return;
|
|
17926
|
+
}
|
|
17927
|
+
const share = Math.max(GetTilesetMemoryBudget() / this.watched.length, TilesetRenderEngine.MIN_TILESET_MEMORY);
|
|
17928
|
+
const props = getTilesetMemoryProps(share);
|
|
16967
17929
|
this.watched.forEach(x => {
|
|
16968
|
-
|
|
16969
|
-
// TODO: Check if it's needed then.
|
|
16970
|
-
x["maximumMemoryUsage"] = totalPerTileset;
|
|
17930
|
+
Object.assign(x, props);
|
|
16971
17931
|
});
|
|
16972
17932
|
}
|
|
16973
17933
|
destroy() {
|
|
17934
|
+
var _a;
|
|
16974
17935
|
this.watched = [];
|
|
17936
|
+
(_a = this.removeChanged) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
17937
|
+
this.removeChanged = null;
|
|
16975
17938
|
}
|
|
16976
17939
|
/**
|
|
16977
17940
|
* Remove all dead tilesets.
|
|
@@ -17020,10 +17983,10 @@ var TilesetRenderEngine;
|
|
|
17020
17983
|
if (!viewer || viewer.isDestroyed()) {
|
|
17021
17984
|
return null;
|
|
17022
17985
|
}
|
|
17023
|
-
if (!viewer[VIEWER_WATCH_KEY]) {
|
|
17024
|
-
viewer[VIEWER_WATCH_KEY] = new MemoryWatcher(viewer);
|
|
17986
|
+
if (!viewer[VIEWER_WATCH_KEY$1]) {
|
|
17987
|
+
viewer[VIEWER_WATCH_KEY$1] = new MemoryWatcher(viewer);
|
|
17025
17988
|
}
|
|
17026
|
-
return viewer[VIEWER_WATCH_KEY];
|
|
17989
|
+
return viewer[VIEWER_WATCH_KEY$1];
|
|
17027
17990
|
}
|
|
17028
17991
|
TilesetRenderEngine.GetMemoryWatcher = GetMemoryWatcher;
|
|
17029
17992
|
function GetDateRangeWatcher(viewer) {
|
|
@@ -28227,7 +29190,9 @@ var XGridsRenderEngine;
|
|
|
28227
29190
|
if (loadUrl.indexOf("?") !== -1) {
|
|
28228
29191
|
loadUrl = loadUrl.split("?")[0];
|
|
28229
29192
|
}
|
|
28230
|
-
|
|
29193
|
+
const profile = DeviceProfile.Get(viewer);
|
|
29194
|
+
DeviceProfile.WatchViewer(viewer);
|
|
29195
|
+
let maxSplats = DeviceProfile.GetBudget(profile.tier).splats;
|
|
28231
29196
|
/*
|
|
28232
29197
|
* Configures optional LOD capabilities once metadata or initial geometry is ready.
|
|
28233
29198
|
*/
|
|
@@ -28312,8 +29277,7 @@ var XGridsRenderEngine;
|
|
|
28312
29277
|
}
|
|
28313
29278
|
try {
|
|
28314
29279
|
const sdkBudget = typeof obj.getCurrentConfig === "function" ? (_d = obj.getCurrentConfig()) === null || _d === void 0 ? void 0 : _d.maxLoadSplatCount : undefined;
|
|
28315
|
-
|
|
28316
|
-
maxSplats = Number.isFinite(sdkBudget) && sdkBudget > 0 && sdkBudget <= 2000000 ? sdkBudget : 6000000;
|
|
29280
|
+
maxSplats = GetSplatBudget(sdkBudget, profile);
|
|
28317
29281
|
if (LCCRender.nextspaceMetadataReady === 1 &&
|
|
28318
29282
|
typeof obj.setNextspaceMetadataCallback === "function" &&
|
|
28319
29283
|
typeof obj.setMaxSplats === "function") {
|
|
@@ -28354,6 +29318,21 @@ var XGridsRenderEngine;
|
|
|
28354
29318
|
return obj;
|
|
28355
29319
|
}
|
|
28356
29320
|
XGridsRenderEngine.Render = Render;
|
|
29321
|
+
/*
|
|
29322
|
+
* The most splats a scan may load: the tier's, lowered by the SDK's GPU limit unless overridden.
|
|
29323
|
+
*/
|
|
29324
|
+
function GetSplatBudget(sdkBudget, profile) {
|
|
29325
|
+
const budget = DeviceProfile.GetBudget(profile.tier).splats;
|
|
29326
|
+
// Above 2M the SDK is reporting its flat default, not a limit it chose for this GPU.
|
|
29327
|
+
if (!profile.overridden &&
|
|
29328
|
+
Number.isFinite(sdkBudget) &&
|
|
29329
|
+
sdkBudget > 0 &&
|
|
29330
|
+
sdkBudget <= 2000000) {
|
|
29331
|
+
return Math.min(sdkBudget, budget);
|
|
29332
|
+
}
|
|
29333
|
+
return budget;
|
|
29334
|
+
}
|
|
29335
|
+
XGridsRenderEngine.GetSplatBudget = GetSplatBudget;
|
|
28357
29336
|
/*
|
|
28358
29337
|
* Detaches optional tuning before unloading the scan.
|
|
28359
29338
|
*/
|
|
@@ -38815,6 +39794,1238 @@ var TileRenderEngine;
|
|
|
38815
39794
|
})(Terrain = TileRenderEngine.Terrain || (TileRenderEngine.Terrain = {}));
|
|
38816
39795
|
})(TileRenderEngine || (TileRenderEngine = {}));
|
|
38817
39796
|
|
|
39797
|
+
// Builds simple meshes into binary glTF in code. Nothing here imports Cesium, so it can move to bruce-models as is.
|
|
39798
|
+
const GLB_MAGIC = 0x46546C67;
|
|
39799
|
+
const GLB_CHUNK_JSON = 0x4E4F534A;
|
|
39800
|
+
const GLB_CHUNK_BIN = 0x004E4942;
|
|
39801
|
+
const GL_ARRAY_BUFFER = 34962;
|
|
39802
|
+
const GL_ELEMENT_ARRAY_BUFFER = 34963;
|
|
39803
|
+
const GL_UNSIGNED_SHORT = 5123;
|
|
39804
|
+
const GL_UNSIGNED_INT = 5125;
|
|
39805
|
+
const GL_FLOAT = 5126;
|
|
39806
|
+
const GL_TRIANGLES = 4;
|
|
39807
|
+
/**
|
|
39808
|
+
* Writes meshes as binary glTF (GLB), for models simple enough to describe in code rather than ship as files.
|
|
39809
|
+
*/
|
|
39810
|
+
var GltfGenerator;
|
|
39811
|
+
(function (GltfGenerator) {
|
|
39812
|
+
/**
|
|
39813
|
+
* Vertices and triangles collected by the shape functions, one material's worth.
|
|
39814
|
+
*/
|
|
39815
|
+
class Mesh {
|
|
39816
|
+
constructor() {
|
|
39817
|
+
this.positions = [];
|
|
39818
|
+
this.normals = [];
|
|
39819
|
+
this.indices = [];
|
|
39820
|
+
}
|
|
39821
|
+
AddVertex(position, normal) {
|
|
39822
|
+
this.positions.push(position[0], position[1], position[2]);
|
|
39823
|
+
this.normals.push(normal[0], normal[1], normal[2]);
|
|
39824
|
+
return this.positions.length / 3 - 1;
|
|
39825
|
+
}
|
|
39826
|
+
/**
|
|
39827
|
+
* Adds a triangle wound so its front faces along normal, whichever order the corners come in.
|
|
39828
|
+
* Per corner normals smooth it; without them every corner takes the face normal.
|
|
39829
|
+
*/
|
|
39830
|
+
AddTriangle(a, b, c, normal, corners) {
|
|
39831
|
+
var _a, _b, _c;
|
|
39832
|
+
const ia = this.AddVertex(a, (_a = corners === null || corners === void 0 ? void 0 : corners[0]) !== null && _a !== void 0 ? _a : normal);
|
|
39833
|
+
const ib = this.AddVertex(b, (_b = corners === null || corners === void 0 ? void 0 : corners[1]) !== null && _b !== void 0 ? _b : normal);
|
|
39834
|
+
const ic = this.AddVertex(c, (_c = corners === null || corners === void 0 ? void 0 : corners[2]) !== null && _c !== void 0 ? _c : normal);
|
|
39835
|
+
if (Dot(Cross(Sub(b, a), Sub(c, a)), normal) >= 0) {
|
|
39836
|
+
this.indices.push(ia, ib, ic);
|
|
39837
|
+
}
|
|
39838
|
+
else {
|
|
39839
|
+
this.indices.push(ia, ic, ib);
|
|
39840
|
+
}
|
|
39841
|
+
}
|
|
39842
|
+
/**
|
|
39843
|
+
* Joins three added vertices into a triangle facing along normal, so shapes can share corners.
|
|
39844
|
+
*/
|
|
39845
|
+
AddIndexedTriangle(ia, ib, ic, normal) {
|
|
39846
|
+
const at = (i) => [this.positions[i * 3], this.positions[i * 3 + 1], this.positions[i * 3 + 2]];
|
|
39847
|
+
const a = at(ia);
|
|
39848
|
+
if (Dot(Cross(Sub(at(ib), a), Sub(at(ic), a)), normal) >= 0) {
|
|
39849
|
+
this.indices.push(ia, ib, ic);
|
|
39850
|
+
}
|
|
39851
|
+
else {
|
|
39852
|
+
this.indices.push(ia, ic, ib);
|
|
39853
|
+
}
|
|
39854
|
+
}
|
|
39855
|
+
get VertexCount() {
|
|
39856
|
+
return this.positions.length / 3;
|
|
39857
|
+
}
|
|
39858
|
+
}
|
|
39859
|
+
GltfGenerator.Mesh = Mesh;
|
|
39860
|
+
function Add(a, b) {
|
|
39861
|
+
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
39862
|
+
}
|
|
39863
|
+
GltfGenerator.Add = Add;
|
|
39864
|
+
function Sub(a, b) {
|
|
39865
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
39866
|
+
}
|
|
39867
|
+
GltfGenerator.Sub = Sub;
|
|
39868
|
+
function Scale(a, s) {
|
|
39869
|
+
return [a[0] * s, a[1] * s, a[2] * s];
|
|
39870
|
+
}
|
|
39871
|
+
GltfGenerator.Scale = Scale;
|
|
39872
|
+
function Dot(a, b) {
|
|
39873
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
39874
|
+
}
|
|
39875
|
+
GltfGenerator.Dot = Dot;
|
|
39876
|
+
function Cross(a, b) {
|
|
39877
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
39878
|
+
}
|
|
39879
|
+
GltfGenerator.Cross = Cross;
|
|
39880
|
+
function Normalize(a) {
|
|
39881
|
+
const length = Math.hypot(a[0], a[1], a[2]);
|
|
39882
|
+
return length ? Scale(a, 1 / length) : [0, 0, 0];
|
|
39883
|
+
}
|
|
39884
|
+
GltfGenerator.Normalize = Normalize;
|
|
39885
|
+
/*
|
|
39886
|
+
* Two unit vectors at right angles to an axis and each other, the first along start where one is given.
|
|
39887
|
+
*/
|
|
39888
|
+
function perpendiculars(axis, start) {
|
|
39889
|
+
const n = Normalize(axis);
|
|
39890
|
+
let u = start ? Sub(start, Scale(n, Dot(start, n))) : null;
|
|
39891
|
+
if (!u || Math.hypot(u[0], u[1], u[2]) < 1e-9) {
|
|
39892
|
+
u = Math.abs(n[0]) < 0.9 ? Cross(n, [1, 0, 0]) : Cross(n, [0, 1, 0]);
|
|
39893
|
+
}
|
|
39894
|
+
u = Normalize(u);
|
|
39895
|
+
return [u, Cross(n, u)];
|
|
39896
|
+
}
|
|
39897
|
+
/*
|
|
39898
|
+
* The point on a circle around centre at a given turn, in the plane the two perpendiculars span.
|
|
39899
|
+
*/
|
|
39900
|
+
function onCircle(centre, u, v, radius, angle) {
|
|
39901
|
+
return Add(centre, Add(Scale(u, Math.cos(angle) * radius), Scale(v, Math.sin(angle) * radius)));
|
|
39902
|
+
}
|
|
39903
|
+
/**
|
|
39904
|
+
* Adds a flat disc facing along normal.
|
|
39905
|
+
*/
|
|
39906
|
+
function AddDisc(mesh, params) {
|
|
39907
|
+
const { centre, radius, sides } = params;
|
|
39908
|
+
const normal = Normalize(params.normal);
|
|
39909
|
+
const [u, v] = perpendiculars(normal, params.start);
|
|
39910
|
+
for (let i = 0; i < sides; i++) {
|
|
39911
|
+
const a = onCircle(centre, u, v, radius, i / sides * Math.PI * 2);
|
|
39912
|
+
const b = onCircle(centre, u, v, radius, (i + 1) / sides * Math.PI * 2);
|
|
39913
|
+
mesh.AddTriangle(centre, a, b, normal);
|
|
39914
|
+
}
|
|
39915
|
+
}
|
|
39916
|
+
GltfGenerator.AddDisc = AddDisc;
|
|
39917
|
+
/**
|
|
39918
|
+
* Adds a smooth sided cylinder between two points, closed at the start by default.
|
|
39919
|
+
*/
|
|
39920
|
+
function AddCylinder(mesh, params) {
|
|
39921
|
+
const { start, end, radius, sides } = params;
|
|
39922
|
+
const axis = Normalize(Sub(end, start));
|
|
39923
|
+
const [u, v] = perpendiculars(axis);
|
|
39924
|
+
for (let i = 0; i < sides; i++) {
|
|
39925
|
+
const angleA = i / sides * Math.PI * 2;
|
|
39926
|
+
const angleB = (i + 1) / sides * Math.PI * 2;
|
|
39927
|
+
const outA = onCircle([0, 0, 0], u, v, 1, angleA);
|
|
39928
|
+
const outB = onCircle([0, 0, 0], u, v, 1, angleB);
|
|
39929
|
+
const a0 = onCircle(start, u, v, radius, angleA);
|
|
39930
|
+
const b0 = onCircle(start, u, v, radius, angleB);
|
|
39931
|
+
const a1 = onCircle(end, u, v, radius, angleA);
|
|
39932
|
+
const b1 = onCircle(end, u, v, radius, angleB);
|
|
39933
|
+
const face = Normalize(Add(outA, outB));
|
|
39934
|
+
mesh.AddTriangle(a0, b0, b1, face, [outA, outB, outB]);
|
|
39935
|
+
mesh.AddTriangle(a0, b1, a1, face, [outA, outB, outA]);
|
|
39936
|
+
}
|
|
39937
|
+
if (params.capStart != false) {
|
|
39938
|
+
AddDisc(mesh, { centre: start, normal: Scale(axis, -1), radius, sides });
|
|
39939
|
+
}
|
|
39940
|
+
if (params.capEnd) {
|
|
39941
|
+
AddDisc(mesh, { centre: end, normal: axis, radius, sides });
|
|
39942
|
+
}
|
|
39943
|
+
}
|
|
39944
|
+
GltfGenerator.AddCylinder = AddCylinder;
|
|
39945
|
+
/**
|
|
39946
|
+
* Adds a cone from a base circle to a tip, closed at the base by default.
|
|
39947
|
+
*/
|
|
39948
|
+
function AddCone(mesh, params) {
|
|
39949
|
+
const { base, tip, radius, sides } = params;
|
|
39950
|
+
const toTip = Sub(tip, base);
|
|
39951
|
+
const height = Math.hypot(toTip[0], toTip[1], toTip[2]);
|
|
39952
|
+
const axis = Normalize(toTip);
|
|
39953
|
+
const [u, v] = perpendiculars(axis, params.start);
|
|
39954
|
+
// A side normal leans toward the tip by the slope of the side.
|
|
39955
|
+
const sideNormal = (angle) => Normalize(Add(Scale(onCircle([0, 0, 0], u, v, 1, angle), height), Scale(axis, radius)));
|
|
39956
|
+
for (let i = 0; i < sides; i++) {
|
|
39957
|
+
const angleA = i / sides * Math.PI * 2;
|
|
39958
|
+
const angleB = (i + 1) / sides * Math.PI * 2;
|
|
39959
|
+
const a = onCircle(base, u, v, radius, angleA);
|
|
39960
|
+
const b = onCircle(base, u, v, radius, angleB);
|
|
39961
|
+
const face = sideNormal((angleA + angleB) / 2);
|
|
39962
|
+
mesh.AddTriangle(a, b, tip, face, params.faceted ? undefined : [sideNormal(angleA), sideNormal(angleB), face]);
|
|
39963
|
+
}
|
|
39964
|
+
if (params.cap != false) {
|
|
39965
|
+
AddDisc(mesh, { centre: base, normal: Scale(axis, -1), radius, sides, start: params.start });
|
|
39966
|
+
}
|
|
39967
|
+
}
|
|
39968
|
+
GltfGenerator.AddCone = AddCone;
|
|
39969
|
+
/**
|
|
39970
|
+
* Adds a smooth ring of tube around an axis through centre.
|
|
39971
|
+
*/
|
|
39972
|
+
function AddTorus(mesh, params) {
|
|
39973
|
+
const { centre, radius, tube, segments, sides } = params;
|
|
39974
|
+
const axis = Normalize(params.axis);
|
|
39975
|
+
const [u, v] = perpendiculars(axis);
|
|
39976
|
+
// A grid of shared corners, wrapping round both ways.
|
|
39977
|
+
const first = mesh.VertexCount;
|
|
39978
|
+
for (let i = 0; i < segments; i++) {
|
|
39979
|
+
const out = onCircle([0, 0, 0], u, v, 1, i / segments * Math.PI * 2);
|
|
39980
|
+
for (let j = 0; j < sides; j++) {
|
|
39981
|
+
const turn = j / sides * Math.PI * 2;
|
|
39982
|
+
const normal = Add(Scale(out, Math.cos(turn)), Scale(axis, Math.sin(turn)));
|
|
39983
|
+
mesh.AddVertex(Add(Add(centre, Scale(out, radius)), Scale(normal, tube)), normal);
|
|
39984
|
+
}
|
|
39985
|
+
}
|
|
39986
|
+
const at = (i, j) => first + (i % segments) * sides + (j % sides);
|
|
39987
|
+
const normalAt = (i) => [mesh.normals[i * 3], mesh.normals[i * 3 + 1], mesh.normals[i * 3 + 2]];
|
|
39988
|
+
for (let i = 0; i < segments; i++) {
|
|
39989
|
+
for (let j = 0; j < sides; j++) {
|
|
39990
|
+
const quad = [at(i, j), at(i + 1, j), at(i + 1, j + 1), at(i, j + 1)];
|
|
39991
|
+
const normal = Normalize(Add(normalAt(quad[0]), normalAt(quad[2])));
|
|
39992
|
+
mesh.AddIndexedTriangle(quad[0], quad[1], quad[2], normal);
|
|
39993
|
+
mesh.AddIndexedTriangle(quad[0], quad[2], quad[3], normal);
|
|
39994
|
+
}
|
|
39995
|
+
}
|
|
39996
|
+
}
|
|
39997
|
+
GltfGenerator.AddTorus = AddTorus;
|
|
39998
|
+
/**
|
|
39999
|
+
* Adds a flat convex outline, given in a plane's own across and up coordinates, facing along normal.
|
|
40000
|
+
*/
|
|
40001
|
+
function AddConvexOutline(mesh, params) {
|
|
40002
|
+
const { points, origin, across, up } = params;
|
|
40003
|
+
const normal = Normalize(params.normal);
|
|
40004
|
+
const at = ([x, y]) => Add(origin, Add(Scale(across, x), Scale(up, y)));
|
|
40005
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
40006
|
+
mesh.AddTriangle(at(points[0]), at(points[i]), at(points[i + 1]), normal);
|
|
40007
|
+
}
|
|
40008
|
+
}
|
|
40009
|
+
GltfGenerator.AddConvexOutline = AddConvexOutline;
|
|
40010
|
+
function align4(length) {
|
|
40011
|
+
return Math.ceil(length / 4) * 4;
|
|
40012
|
+
}
|
|
40013
|
+
function bounds(positions) {
|
|
40014
|
+
const min = [Infinity, Infinity, Infinity];
|
|
40015
|
+
const max = [-Infinity, -Infinity, -Infinity];
|
|
40016
|
+
for (let i = 0; i < positions.length; i++) {
|
|
40017
|
+
const k = i % 3;
|
|
40018
|
+
min[k] = Math.min(min[k], positions[i]);
|
|
40019
|
+
max[k] = Math.max(max[k], positions[i]);
|
|
40020
|
+
}
|
|
40021
|
+
return { min, max };
|
|
40022
|
+
}
|
|
40023
|
+
/**
|
|
40024
|
+
* Packs a mesh into GLB bytes, under a chain of node matrices (outermost first) when given.
|
|
40025
|
+
*/
|
|
40026
|
+
function ToGlb(params) {
|
|
40027
|
+
var _a, _b, _c;
|
|
40028
|
+
const { mesh, material } = params;
|
|
40029
|
+
const count = mesh.VertexCount;
|
|
40030
|
+
const wide = count > 0xFFFF;
|
|
40031
|
+
const IndexArray = wide ? Uint32Array : Uint16Array;
|
|
40032
|
+
const indexLength = mesh.indices.length * IndexArray.BYTES_PER_ELEMENT;
|
|
40033
|
+
const indexBytes = align4(indexLength);
|
|
40034
|
+
const vertexBytes = count * 12;
|
|
40035
|
+
const bin = new ArrayBuffer(indexBytes + vertexBytes * 2);
|
|
40036
|
+
new IndexArray(bin, 0, mesh.indices.length).set(mesh.indices);
|
|
40037
|
+
new Float32Array(bin, indexBytes, count * 3).set(mesh.positions);
|
|
40038
|
+
new Float32Array(bin, indexBytes + vertexBytes, count * 3).set(mesh.normals);
|
|
40039
|
+
// The mesh node is last, each matrix node holding the next.
|
|
40040
|
+
const matrices = (_a = params.matrices) !== null && _a !== void 0 ? _a : [];
|
|
40041
|
+
const nodes = matrices.map((matrix, i) => ({ matrix, children: [i + 1] }));
|
|
40042
|
+
nodes.push({ mesh: 0 });
|
|
40043
|
+
const json = {
|
|
40044
|
+
asset: { version: "2.0", generator: "bruce-cesium GltfGenerator" },
|
|
40045
|
+
scene: 0,
|
|
40046
|
+
scenes: [{ nodes: [0] }],
|
|
40047
|
+
nodes,
|
|
40048
|
+
meshes: [{ primitives: [{ attributes: { POSITION: 1, NORMAL: 2 }, indices: 0, material: 0, mode: GL_TRIANGLES }] }],
|
|
40049
|
+
materials: [{
|
|
40050
|
+
pbrMetallicRoughness: {
|
|
40051
|
+
baseColorFactor: material.color,
|
|
40052
|
+
metallicFactor: (_b = material.metallic) !== null && _b !== void 0 ? _b : 0,
|
|
40053
|
+
roughnessFactor: (_c = material.roughness) !== null && _c !== void 0 ? _c : 1
|
|
40054
|
+
},
|
|
40055
|
+
doubleSided: Boolean(material.doubleSided)
|
|
40056
|
+
}],
|
|
40057
|
+
buffers: [{ byteLength: bin.byteLength }],
|
|
40058
|
+
bufferViews: [
|
|
40059
|
+
{ buffer: 0, byteOffset: 0, byteLength: indexLength, target: GL_ELEMENT_ARRAY_BUFFER },
|
|
40060
|
+
{ buffer: 0, byteOffset: indexBytes, byteLength: vertexBytes, target: GL_ARRAY_BUFFER },
|
|
40061
|
+
{ buffer: 0, byteOffset: indexBytes + vertexBytes, byteLength: vertexBytes, target: GL_ARRAY_BUFFER }
|
|
40062
|
+
],
|
|
40063
|
+
accessors: [
|
|
40064
|
+
{ bufferView: 0, componentType: wide ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, count: mesh.indices.length, type: "SCALAR" },
|
|
40065
|
+
{ bufferView: 1, componentType: GL_FLOAT, count, type: "VEC3", ...bounds(mesh.positions) },
|
|
40066
|
+
{ bufferView: 2, componentType: GL_FLOAT, count, type: "VEC3" }
|
|
40067
|
+
]
|
|
40068
|
+
};
|
|
40069
|
+
let text = JSON.stringify(json);
|
|
40070
|
+
text += " ".repeat(align4(text.length) - text.length);
|
|
40071
|
+
const jsonBytes = new TextEncoder().encode(text);
|
|
40072
|
+
const glb = new Uint8Array(20 + jsonBytes.length + 8 + bin.byteLength);
|
|
40073
|
+
const view = new DataView(glb.buffer);
|
|
40074
|
+
view.setUint32(0, GLB_MAGIC, true);
|
|
40075
|
+
view.setUint32(4, 2, true);
|
|
40076
|
+
view.setUint32(8, glb.length, true);
|
|
40077
|
+
view.setUint32(12, jsonBytes.length, true);
|
|
40078
|
+
view.setUint32(16, GLB_CHUNK_JSON, true);
|
|
40079
|
+
glb.set(jsonBytes, 20);
|
|
40080
|
+
const binStart = 20 + jsonBytes.length;
|
|
40081
|
+
view.setUint32(binStart, bin.byteLength, true);
|
|
40082
|
+
view.setUint32(binStart + 4, GLB_CHUNK_BIN, true);
|
|
40083
|
+
glb.set(new Uint8Array(bin), binStart + 8);
|
|
40084
|
+
return glb;
|
|
40085
|
+
}
|
|
40086
|
+
GltfGenerator.ToGlb = ToGlb;
|
|
40087
|
+
/**
|
|
40088
|
+
* Packs a mesh into a GLB data URI, which loads as a model url with nothing to fetch.
|
|
40089
|
+
*/
|
|
40090
|
+
function ToDataUri(params) {
|
|
40091
|
+
const glb = ToGlb(params);
|
|
40092
|
+
let binary = "";
|
|
40093
|
+
for (let i = 0; i < glb.length; i += 0x8000) {
|
|
40094
|
+
binary += String.fromCharCode.apply(null, glb.subarray(i, i + 0x8000));
|
|
40095
|
+
}
|
|
40096
|
+
return "data:model/gltf-binary;base64," + btoa(binary);
|
|
40097
|
+
}
|
|
40098
|
+
GltfGenerator.ToDataUri = ToDataUri;
|
|
40099
|
+
})(GltfGenerator || (GltfGenerator = {}));
|
|
40100
|
+
|
|
40101
|
+
// Sides on an arrow's shaft and cone.
|
|
40102
|
+
const ARROW_SIDES = 16;
|
|
40103
|
+
const SHAFT_RADIUS = 2.4;
|
|
40104
|
+
const SHAFT_LENGTH = 265;
|
|
40105
|
+
const CONE_RADIUS = 10;
|
|
40106
|
+
const CONE_BASE = 264.6;
|
|
40107
|
+
const CONE_TIP = 306.3;
|
|
40108
|
+
const RING_RADIUS = 210;
|
|
40109
|
+
const RING_TUBE = 1;
|
|
40110
|
+
const RING_SEGMENTS = 60;
|
|
40111
|
+
const RING_SIDES = 10;
|
|
40112
|
+
// The ring's two arrowheads sit either side of its 45 degree mark, each pointing back toward it.
|
|
40113
|
+
const RING_MARK_ANGLES = [137.64, -47.64];
|
|
40114
|
+
const RING_MARK_LENGTH = 5.82;
|
|
40115
|
+
const RING_MARK_CENTRE = 209.8;
|
|
40116
|
+
const RING_MARK_RADIUS = 8.5;
|
|
40117
|
+
const RING_MARK_SIDES = 8;
|
|
40118
|
+
// Turns the original models' Y up node into the Z up frame the pieces were drawn in.
|
|
40119
|
+
const ROOT_MATRIX = [1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1];
|
|
40120
|
+
// Points a piece drawn along +Z down another axis, as the original models' mesh nodes did.
|
|
40121
|
+
const TO_X_MATRIX = [0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1];
|
|
40122
|
+
const TO_Y_ARROW_MATRIX = [0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1];
|
|
40123
|
+
const TO_Y_RING_MATRIX = [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1];
|
|
40124
|
+
const RED = { color: [1, 0, 0, 1] };
|
|
40125
|
+
const GREEN = { color: [0.2196, 0.5216, 0.1647, 1] };
|
|
40126
|
+
const BLUE = { color: [0.1608, 0.3843, 0.698, 1] };
|
|
40127
|
+
const LETTER_X = {
|
|
40128
|
+
across: [0, 1, 0],
|
|
40129
|
+
facing: [-1, 0, 0],
|
|
40130
|
+
strokes: [
|
|
40131
|
+
[[16.4, 318.6], [16.4, 324.2], [-19.4, 349.8], [-19.4, 343.9]],
|
|
40132
|
+
[[-19.4, 316.9], [-19.4, 322.6], [16.4, 348.8], [16.4, 343.6]]
|
|
40133
|
+
]
|
|
40134
|
+
};
|
|
40135
|
+
const LETTER_Y = {
|
|
40136
|
+
across: [0, 1, 0],
|
|
40137
|
+
facing: [-1, 0, 0],
|
|
40138
|
+
strokes: [
|
|
40139
|
+
[[-1.9, 320.1], [2.8, 320.1], [2.8, 337.7], [-1.9, 337.7]],
|
|
40140
|
+
[[-1.9, 335.3], [2.8, 335.3], [-10.7, 355.9], [-16.2, 355.9]],
|
|
40141
|
+
[[-1.9, 335.3], [2.8, 335.3], [16.6, 355.9], [10.9, 355.9]]
|
|
40142
|
+
]
|
|
40143
|
+
};
|
|
40144
|
+
const LETTER_Z = {
|
|
40145
|
+
across: [1, 0, 0],
|
|
40146
|
+
facing: [0, -1, 0],
|
|
40147
|
+
strokes: [
|
|
40148
|
+
[[-14.6, 319], [13.7, 319], [13.7, 323.3], [-14.6, 323.3]],
|
|
40149
|
+
[[-14.6, 323.3], [-9.1, 323.3], [13.1, 350.6], [7.5, 350.6]],
|
|
40150
|
+
[[-12.5, 350.6], [13.1, 350.6], [13.1, 354.8], [-12.5, 354.8]]
|
|
40151
|
+
]
|
|
40152
|
+
};
|
|
40153
|
+
/*
|
|
40154
|
+
* An axis arrow along +Z: shaft, cone and the axis letter past the tip.
|
|
40155
|
+
*/
|
|
40156
|
+
function arrowMesh(letter) {
|
|
40157
|
+
const mesh = new GltfGenerator.Mesh();
|
|
40158
|
+
GltfGenerator.AddCylinder(mesh, { start: [0, 0, 0], end: [0, 0, SHAFT_LENGTH], radius: SHAFT_RADIUS, sides: ARROW_SIDES });
|
|
40159
|
+
GltfGenerator.AddCone(mesh, { base: [0, 0, CONE_BASE], tip: [0, 0, CONE_TIP], radius: CONE_RADIUS, sides: ARROW_SIDES });
|
|
40160
|
+
for (const stroke of letter.strokes) {
|
|
40161
|
+
GltfGenerator.AddConvexOutline(mesh, { points: stroke, origin: [0, 0, 0], across: letter.across, up: [0, 0, 1], normal: letter.facing });
|
|
40162
|
+
}
|
|
40163
|
+
return mesh;
|
|
40164
|
+
}
|
|
40165
|
+
function onRing(degrees, radius) {
|
|
40166
|
+
const angle = degrees * Math.PI / 180;
|
|
40167
|
+
return [Math.cos(angle) * radius, Math.sin(angle) * radius, 0];
|
|
40168
|
+
}
|
|
40169
|
+
/*
|
|
40170
|
+
* A rotation ring about +Z with its two arrowheads.
|
|
40171
|
+
*/
|
|
40172
|
+
function ringMesh() {
|
|
40173
|
+
const mesh = new GltfGenerator.Mesh();
|
|
40174
|
+
GltfGenerator.AddTorus(mesh, {
|
|
40175
|
+
centre: [0, 0, 0],
|
|
40176
|
+
axis: [0, 0, 1],
|
|
40177
|
+
radius: RING_RADIUS,
|
|
40178
|
+
tube: RING_TUBE,
|
|
40179
|
+
segments: RING_SEGMENTS,
|
|
40180
|
+
sides: RING_SIDES
|
|
40181
|
+
});
|
|
40182
|
+
for (const degrees of RING_MARK_ANGLES) {
|
|
40183
|
+
const toward = degrees > 45 ? -RING_MARK_LENGTH : RING_MARK_LENGTH;
|
|
40184
|
+
GltfGenerator.AddCone(mesh, {
|
|
40185
|
+
base: onRing(degrees, RING_MARK_CENTRE),
|
|
40186
|
+
tip: onRing(degrees + toward, RING_MARK_CENTRE),
|
|
40187
|
+
radius: RING_MARK_RADIUS,
|
|
40188
|
+
sides: RING_MARK_SIDES,
|
|
40189
|
+
faceted: true,
|
|
40190
|
+
// A rim corner points at the ring's centre, as the original arrowheads' did.
|
|
40191
|
+
start: onRing(degrees, 1)
|
|
40192
|
+
});
|
|
40193
|
+
}
|
|
40194
|
+
return mesh;
|
|
40195
|
+
}
|
|
40196
|
+
/**
|
|
40197
|
+
* The transform gizmo's pieces as GLB data URIs, built on first use so there are no model files to host.
|
|
40198
|
+
* Sizes, colours and frames match the models they replaced (Navigator's public/res/gizmo), scales included.
|
|
40199
|
+
*/
|
|
40200
|
+
var GltfGizmo;
|
|
40201
|
+
(function (GltfGizmo) {
|
|
40202
|
+
let EPiece;
|
|
40203
|
+
(function (EPiece) {
|
|
40204
|
+
EPiece["X"] = "x";
|
|
40205
|
+
EPiece["Y"] = "y";
|
|
40206
|
+
EPiece["Z"] = "z";
|
|
40207
|
+
EPiece["XRotation"] = "x-rot";
|
|
40208
|
+
EPiece["YRotation"] = "y-rot";
|
|
40209
|
+
EPiece["ZRotation"] = "z-rot";
|
|
40210
|
+
})(EPiece = GltfGizmo.EPiece || (GltfGizmo.EPiece = {}));
|
|
40211
|
+
const BUILDERS = {
|
|
40212
|
+
[EPiece.X]: () => GltfGenerator.ToDataUri({ mesh: arrowMesh(LETTER_X), material: RED, matrices: [ROOT_MATRIX, TO_X_MATRIX] }),
|
|
40213
|
+
[EPiece.Y]: () => GltfGenerator.ToDataUri({ mesh: arrowMesh(LETTER_Y), material: GREEN, matrices: [ROOT_MATRIX, TO_Y_ARROW_MATRIX] }),
|
|
40214
|
+
[EPiece.Z]: () => GltfGenerator.ToDataUri({ mesh: arrowMesh(LETTER_Z), material: BLUE, matrices: [ROOT_MATRIX] }),
|
|
40215
|
+
[EPiece.XRotation]: () => GltfGenerator.ToDataUri({ mesh: ringMesh(), material: RED, matrices: [ROOT_MATRIX, TO_X_MATRIX] }),
|
|
40216
|
+
[EPiece.YRotation]: () => GltfGenerator.ToDataUri({ mesh: ringMesh(), material: GREEN, matrices: [ROOT_MATRIX, TO_Y_RING_MATRIX] }),
|
|
40217
|
+
[EPiece.ZRotation]: () => GltfGenerator.ToDataUri({ mesh: ringMesh(), material: BLUE, matrices: [ROOT_MATRIX] })
|
|
40218
|
+
};
|
|
40219
|
+
// Built pieces, so every gizmo shares one string per piece and CesiumJS's model cache sees the same url.
|
|
40220
|
+
const built = {};
|
|
40221
|
+
/**
|
|
40222
|
+
* Returns a piece's model as a data URI, to pass wherever a model url is taken.
|
|
40223
|
+
*/
|
|
40224
|
+
function GetUri(piece) {
|
|
40225
|
+
if (!built[piece]) {
|
|
40226
|
+
built[piece] = BUILDERS[piece]();
|
|
40227
|
+
}
|
|
40228
|
+
return built[piece];
|
|
40229
|
+
}
|
|
40230
|
+
GltfGizmo.GetUri = GetUri;
|
|
40231
|
+
})(GltfGizmo || (GltfGizmo = {}));
|
|
40232
|
+
|
|
40233
|
+
// viewer[CLASS_INSTANCE_KEY] will point at an instance of MapGridHandler.
|
|
40234
|
+
const CLASS_INSTANCE_KEY = "nextspace-navigator-grid-handler";
|
|
40235
|
+
// viewer[UPDATE_MARKER_KEY] will point at a number that is incremented every time the grid is updated.
|
|
40236
|
+
// This is used to determine if the grid is still valid or if it needs to be redrawn.
|
|
40237
|
+
const UPDATE_MARKER_KEY = "nextspace-marker-grid";
|
|
40238
|
+
// viewer[LAST_SETTINGS_KEY] will point at the last settings used for the grid.
|
|
40239
|
+
const LAST_SETTINGS_KEY = "nextspace-navigator-last-settings-grid";
|
|
40240
|
+
/*
|
|
40241
|
+
* The point a distance in metres along a heading in degrees from another, over a spherical earth.
|
|
40242
|
+
*/
|
|
40243
|
+
function offsetPoint$1(point, distance, heading) {
|
|
40244
|
+
// Radius of earth.
|
|
40245
|
+
const radius = 6371e3;
|
|
40246
|
+
const δ = distance / radius;
|
|
40247
|
+
const θ = Math$1.toRadians(heading);
|
|
40248
|
+
const φ1 = Math$1.toRadians(point.latitude);
|
|
40249
|
+
const λ1 = Math$1.toRadians(point.longitude);
|
|
40250
|
+
const sinφ2 = Math.sin(φ1) * Math.cos(δ) + Math.cos(φ1) * Math.sin(δ) * Math.cos(θ);
|
|
40251
|
+
const φ2 = Math.asin(sinφ2);
|
|
40252
|
+
const y = Math.sin(θ) * Math.sin(δ) * Math.cos(φ1);
|
|
40253
|
+
const x = Math.cos(δ) - Math.sin(φ1) * sinφ2;
|
|
40254
|
+
const λ2 = λ1 + Math.atan2(y, x);
|
|
40255
|
+
return {
|
|
40256
|
+
altitude: point.altitude,
|
|
40257
|
+
latitude: Math$1.toDegrees(φ2),
|
|
40258
|
+
longitude: Math$1.toDegrees(λ2)
|
|
40259
|
+
};
|
|
40260
|
+
}
|
|
40261
|
+
/**
|
|
40262
|
+
* Handler for drawing a grid of lines on the map with a specified spacing.
|
|
40263
|
+
* Initially this grid is for model-space viewing which means we start at 0,0 lat/lon and have it expand from there.
|
|
40264
|
+
* However, it should be a general-use tool for drawing a grid anywhere.
|
|
40265
|
+
*
|
|
40266
|
+
* It reacts to camera changes and draws the grid within view with padding.
|
|
40267
|
+
* This helps avoid performance issues around drawing too many lines.
|
|
40268
|
+
*/
|
|
40269
|
+
class MapGridHandler {
|
|
40270
|
+
constructor(viewer, spacingInMeters = 100, modelSpace = false) {
|
|
40271
|
+
this.gridCenterGizmoPieces = [];
|
|
40272
|
+
this.maxCacheSize = 1000;
|
|
40273
|
+
// === Thresholds for grid stability.
|
|
40274
|
+
// As a fraction of current grid extent.
|
|
40275
|
+
this.CAMERA_MOVE_THRESHOLD = 0.5;
|
|
40276
|
+
// 40% change in camera height triggers redraw.
|
|
40277
|
+
this.HEIGHT_CHANGE_THRESHOLD = 0.4;
|
|
40278
|
+
// 40% change in grid extent triggers redraw.
|
|
40279
|
+
this.GRID_EXTENT_CHANGE_THRESHOLD = 0.4;
|
|
40280
|
+
// 5km - distance that triggers origin reset.
|
|
40281
|
+
this.EXTREME_DISTANCE_THRESHOLD = 5000;
|
|
40282
|
+
// Grid limits to prevent drawing too many lines.
|
|
40283
|
+
this.MAX_LINES = 500;
|
|
40284
|
+
// 50% padding around visible area.
|
|
40285
|
+
this.VIEW_PADDING_FACTOR = 0.5;
|
|
40286
|
+
// Minimum pixels between grid lines to show them.
|
|
40287
|
+
this.MIN_GRID_PIXEL_SIZE = 20;
|
|
40288
|
+
// Base ratio - will be adjusted dynamically based on spacing size and camera height.
|
|
40289
|
+
this.BASE_MAX_VISIBILITY_RATIO = 30;
|
|
40290
|
+
// Height to spacing ratio.
|
|
40291
|
+
this.HEIGHT_TO_SPACING_RATIO = 100;
|
|
40292
|
+
// === Label settings
|
|
40293
|
+
// Label every nth intersection.
|
|
40294
|
+
this.LABEL_INTERVAL = 2;
|
|
40295
|
+
// Maximum number of labels to show.
|
|
40296
|
+
this.MAX_LABELS = 100;
|
|
40297
|
+
// Spacing levels to use for adaptive spacing.
|
|
40298
|
+
this.SPACING_LEVELS = [
|
|
40299
|
+
1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 300, 400, 500, 1000, 2000, 2500, 5000, 10000, 20000, 25000, 50000, 100000
|
|
40300
|
+
];
|
|
40301
|
+
// Minimum zoom distance to prevent precision issues.
|
|
40302
|
+
this.MINIMUM_ZOOM_DISTANCE = 40;
|
|
40303
|
+
// Base spacing to use for adaptive spacing.
|
|
40304
|
+
this.BASE_SPACING = 1;
|
|
40305
|
+
// Maximum number of attempts to find a suitable spacing.
|
|
40306
|
+
this.MAX_ADAPTIVE_ATTEMPTS = 5;
|
|
40307
|
+
this.viewer = viewer;
|
|
40308
|
+
this.spacingInMeters = spacingInMeters;
|
|
40309
|
+
this.isUpdating = false;
|
|
40310
|
+
this.modelSpace = modelSpace;
|
|
40311
|
+
this.lastCameraPosition = null;
|
|
40312
|
+
this.fixedGridOrigin = null;
|
|
40313
|
+
this.lastGridExtent = 0;
|
|
40314
|
+
this.offsetCache = new Map();
|
|
40315
|
+
this.gridPrimitives = new PrimitiveCollection();
|
|
40316
|
+
this.viewer.scene.primitives.add(this.gridPrimitives);
|
|
40317
|
+
this.currentMarker = viewer[UPDATE_MARKER_KEY] || 1;
|
|
40318
|
+
const isMac = typeof navigator !== "undefined" && (navigator.platform.toUpperCase().indexOf("MAC") !== -1 ||
|
|
40319
|
+
navigator.userAgent.toUpperCase().indexOf("MAC") !== -1);
|
|
40320
|
+
if (modelSpace && isMac) {
|
|
40321
|
+
console.log("[MAC-FIX] Applying camera distance limits for Mac");
|
|
40322
|
+
viewer.scene.screenSpaceCameraController.minimumZoomDistance = this.MINIMUM_ZOOM_DISTANCE;
|
|
40323
|
+
}
|
|
40324
|
+
const manager = ViewerUtils.GetManager({
|
|
40325
|
+
viewer: this.viewer,
|
|
40326
|
+
createIfMissing: false
|
|
40327
|
+
});
|
|
40328
|
+
if (manager) {
|
|
40329
|
+
this.cameraChangeRemoval = manager.Monitor.Updated().Subscribe(() => {
|
|
40330
|
+
this.onCameraChanged();
|
|
40331
|
+
});
|
|
40332
|
+
}
|
|
40333
|
+
// Initial grid draw.
|
|
40334
|
+
this.onCameraChanged();
|
|
40335
|
+
}
|
|
40336
|
+
Update(spacingInMeters, modelSpace) {
|
|
40337
|
+
this.currentMarker = this.viewer[UPDATE_MARKER_KEY] || 1;
|
|
40338
|
+
let needsUpdate = false;
|
|
40339
|
+
if (this.spacingInMeters !== spacingInMeters) {
|
|
40340
|
+
this.spacingInMeters = spacingInMeters;
|
|
40341
|
+
needsUpdate = true;
|
|
40342
|
+
}
|
|
40343
|
+
if (modelSpace !== undefined && this.modelSpace !== modelSpace) {
|
|
40344
|
+
this.modelSpace = modelSpace;
|
|
40345
|
+
needsUpdate = true;
|
|
40346
|
+
}
|
|
40347
|
+
if (needsUpdate) {
|
|
40348
|
+
this.clearGrid();
|
|
40349
|
+
// When spacing or model space changes, clear the cached origin to force recalculation
|
|
40350
|
+
// This ensures grid alignment at the new spacing.
|
|
40351
|
+
this.fixedGridOrigin = null;
|
|
40352
|
+
this.offsetCache.clear();
|
|
40353
|
+
this.onCameraChanged();
|
|
40354
|
+
}
|
|
40355
|
+
}
|
|
40356
|
+
Dispose() {
|
|
40357
|
+
this.clearGrid();
|
|
40358
|
+
this.clearGizmoPieces();
|
|
40359
|
+
if (this.cameraChangeRemoval) {
|
|
40360
|
+
this.cameraChangeRemoval();
|
|
40361
|
+
this.cameraChangeRemoval = null;
|
|
40362
|
+
}
|
|
40363
|
+
if (this.gridPrimitives) {
|
|
40364
|
+
this.viewer.scene.primitives.remove(this.gridPrimitives);
|
|
40365
|
+
this.gridPrimitives = null;
|
|
40366
|
+
}
|
|
40367
|
+
if (this.viewer) {
|
|
40368
|
+
this.viewer = null;
|
|
40369
|
+
}
|
|
40370
|
+
this.offsetCache.clear();
|
|
40371
|
+
this.fixedGridOrigin = null;
|
|
40372
|
+
}
|
|
40373
|
+
clearGrid() {
|
|
40374
|
+
if (this.gridPrimitives) {
|
|
40375
|
+
this.gridPrimitives.removeAll();
|
|
40376
|
+
this.gridLines = null;
|
|
40377
|
+
this.gridLabels = null;
|
|
40378
|
+
}
|
|
40379
|
+
}
|
|
40380
|
+
calculateAdaptiveSpacing(cameraHeight, baseSpacing) {
|
|
40381
|
+
// Define spacing levels that look good (powers of 2, 5, and 10)
|
|
40382
|
+
const spacingLevels = this.SPACING_LEVELS;
|
|
40383
|
+
// Ensure base spacing is at least 1m
|
|
40384
|
+
const adjustedBaseSpacing = Math.max(this.BASE_SPACING, baseSpacing);
|
|
40385
|
+
// For very close cameras, use much smaller spacing regardless of base
|
|
40386
|
+
if (cameraHeight < 10) {
|
|
40387
|
+
// Find the smallest reasonable spacing for this height
|
|
40388
|
+
// Rule: spacing should be roughly 1/20th to 1/50th of camera height, but at least 1m
|
|
40389
|
+
const targetSpacing = Math.max(this.BASE_SPACING, cameraHeight / 30);
|
|
40390
|
+
// Find the closest spacing level to our target
|
|
40391
|
+
let bestSpacing = this.BASE_SPACING; // Start with minimum
|
|
40392
|
+
let bestDifference = Math.abs(1 - targetSpacing);
|
|
40393
|
+
for (const spacing of spacingLevels) {
|
|
40394
|
+
if (spacing >= this.BASE_SPACING) { // Only consider valid spacings
|
|
40395
|
+
const difference = Math.abs(spacing - targetSpacing);
|
|
40396
|
+
if (difference < bestDifference) {
|
|
40397
|
+
bestSpacing = spacing;
|
|
40398
|
+
bestDifference = difference;
|
|
40399
|
+
}
|
|
40400
|
+
}
|
|
40401
|
+
}
|
|
40402
|
+
return bestSpacing;
|
|
40403
|
+
}
|
|
40404
|
+
// For medium distances (10m - 200m), scale more gradually
|
|
40405
|
+
if (cameraHeight < 200) {
|
|
40406
|
+
const targetSpacing = cameraHeight / 10; // More conservative scaling// Find closest spacing level, but prefer going up from base spacing
|
|
40407
|
+
let bestSpacing = adjustedBaseSpacing;
|
|
40408
|
+
let bestDifference = Math.abs(adjustedBaseSpacing - targetSpacing);
|
|
40409
|
+
for (const spacing of spacingLevels) {
|
|
40410
|
+
if (spacing >= Math.min(adjustedBaseSpacing, targetSpacing)) {
|
|
40411
|
+
const difference = Math.abs(spacing - targetSpacing);
|
|
40412
|
+
if (difference < bestDifference) {
|
|
40413
|
+
bestSpacing = spacing;
|
|
40414
|
+
bestDifference = difference;
|
|
40415
|
+
}
|
|
40416
|
+
}
|
|
40417
|
+
}
|
|
40418
|
+
return bestSpacing;
|
|
40419
|
+
}
|
|
40420
|
+
// For far distances (100m+), scale up aggressively
|
|
40421
|
+
const targetSpacing = cameraHeight / 20;
|
|
40422
|
+
// Find the spacing level that's closest to target but not smaller than base
|
|
40423
|
+
let bestSpacing = adjustedBaseSpacing;
|
|
40424
|
+
let bestDifference = Math.abs(adjustedBaseSpacing - targetSpacing);
|
|
40425
|
+
for (const spacing of spacingLevels) {
|
|
40426
|
+
if (spacing >= adjustedBaseSpacing) {
|
|
40427
|
+
const difference = Math.abs(spacing - targetSpacing);
|
|
40428
|
+
if (difference < bestDifference) {
|
|
40429
|
+
bestSpacing = spacing;
|
|
40430
|
+
bestDifference = difference;
|
|
40431
|
+
}
|
|
40432
|
+
}
|
|
40433
|
+
}
|
|
40434
|
+
return bestSpacing;
|
|
40435
|
+
}
|
|
40436
|
+
/*
|
|
40437
|
+
* The point model-space treats as 0,0,0: the UCS in UCS placement, otherwise 0,0 lat/lon at sea level.
|
|
40438
|
+
*/
|
|
40439
|
+
modelSpaceOrigin() {
|
|
40440
|
+
const origin = ViewUtils.IsModelSpaceUcs(this.viewer) ? ViewUtils.GetModelSpaceOrigin(this.viewer) : null;
|
|
40441
|
+
return origin !== null && origin !== void 0 ? origin : { latitude: 0, longitude: 0, altitude: 0 };
|
|
40442
|
+
}
|
|
40443
|
+
/*
|
|
40444
|
+
* The origin as a scene position, where the axis gizmo sits.
|
|
40445
|
+
*/
|
|
40446
|
+
modelSpaceOriginPos3d() {
|
|
40447
|
+
const origin = this.modelSpaceOrigin();
|
|
40448
|
+
return Cartesian3.fromDegrees(origin.longitude, origin.latitude, origin.altitude);
|
|
40449
|
+
}
|
|
40450
|
+
drawGizmoPieces() {
|
|
40451
|
+
if (this.gridCenterGizmoPieces.length) {
|
|
40452
|
+
return;
|
|
40453
|
+
}
|
|
40454
|
+
// X.
|
|
40455
|
+
{
|
|
40456
|
+
const pos3d = this.modelSpaceOriginPos3d();
|
|
40457
|
+
const scale = new CallbackProperty(() => Cartesian3.distance(this.viewer.camera.position, pos3d) * 0.0002, false);
|
|
40458
|
+
const orientation = Transforms.headingPitchRollQuaternion(pos3d, new HeadingPitchRoll(Math$1.toRadians(90), 0, 0));
|
|
40459
|
+
const entity = this.viewer.entities.add(new Entity({
|
|
40460
|
+
model: {
|
|
40461
|
+
uri: GltfGizmo.GetUri(GltfGizmo.EPiece.X),
|
|
40462
|
+
heightReference: HeightReference.NONE,
|
|
40463
|
+
shadows: ShadowMode.DISABLED,
|
|
40464
|
+
distanceDisplayCondition: new DistanceDisplayCondition(0, Number.MAX_VALUE),
|
|
40465
|
+
scale
|
|
40466
|
+
},
|
|
40467
|
+
position: pos3d,
|
|
40468
|
+
orientation: new ConstantProperty(orientation)
|
|
40469
|
+
}));
|
|
40470
|
+
this.gridCenterGizmoPieces.push(entity);
|
|
40471
|
+
}
|
|
40472
|
+
// Y.
|
|
40473
|
+
{
|
|
40474
|
+
const pos3d = this.modelSpaceOriginPos3d();
|
|
40475
|
+
const scale = new CallbackProperty(() => Cartesian3.distance(this.viewer.camera.position, pos3d) * 0.0002, false);
|
|
40476
|
+
const orientation = Transforms.headingPitchRollQuaternion(pos3d, new HeadingPitchRoll(Math$1.toRadians(90), 0, 0));
|
|
40477
|
+
const entity = this.viewer.entities.add(new Entity({
|
|
40478
|
+
model: {
|
|
40479
|
+
uri: GltfGizmo.GetUri(GltfGizmo.EPiece.Y),
|
|
40480
|
+
heightReference: HeightReference.NONE,
|
|
40481
|
+
shadows: ShadowMode.DISABLED,
|
|
40482
|
+
distanceDisplayCondition: new DistanceDisplayCondition(0, Number.MAX_VALUE),
|
|
40483
|
+
scale
|
|
40484
|
+
},
|
|
40485
|
+
position: pos3d,
|
|
40486
|
+
orientation: new ConstantProperty(orientation)
|
|
40487
|
+
}));
|
|
40488
|
+
this.gridCenterGizmoPieces.push(entity);
|
|
40489
|
+
}
|
|
40490
|
+
// Z.
|
|
40491
|
+
{
|
|
40492
|
+
const pos3d = this.modelSpaceOriginPos3d();
|
|
40493
|
+
const scale = new CallbackProperty(() => Cartesian3.distance(this.viewer.camera.position, pos3d) * 0.0002, false);
|
|
40494
|
+
const orientation = Transforms.headingPitchRollQuaternion(pos3d, new HeadingPitchRoll(Math$1.toRadians(90), 0, 0));
|
|
40495
|
+
const entity = this.viewer.entities.add(new Entity({
|
|
40496
|
+
model: {
|
|
40497
|
+
uri: GltfGizmo.GetUri(GltfGizmo.EPiece.Z),
|
|
40498
|
+
heightReference: HeightReference.NONE,
|
|
40499
|
+
shadows: ShadowMode.DISABLED,
|
|
40500
|
+
distanceDisplayCondition: new DistanceDisplayCondition(0, Number.MAX_VALUE),
|
|
40501
|
+
scale
|
|
40502
|
+
},
|
|
40503
|
+
position: pos3d,
|
|
40504
|
+
orientation: new ConstantProperty(orientation)
|
|
40505
|
+
}));
|
|
40506
|
+
this.gridCenterGizmoPieces.push(entity);
|
|
40507
|
+
}
|
|
40508
|
+
}
|
|
40509
|
+
clearGizmoPieces() {
|
|
40510
|
+
for (const piece of this.gridCenterGizmoPieces) {
|
|
40511
|
+
if (piece && this.viewer.entities.contains(piece)) {
|
|
40512
|
+
this.viewer.entities.remove(piece);
|
|
40513
|
+
}
|
|
40514
|
+
}
|
|
40515
|
+
this.gridCenterGizmoPieces = [];
|
|
40516
|
+
}
|
|
40517
|
+
onCameraChanged() {
|
|
40518
|
+
if (this.isUpdating) {
|
|
40519
|
+
return;
|
|
40520
|
+
}
|
|
40521
|
+
else if (this.currentMarker !== this.viewer[UPDATE_MARKER_KEY]) {
|
|
40522
|
+
return;
|
|
40523
|
+
}
|
|
40524
|
+
this.isUpdating = true;
|
|
40525
|
+
// Small delay to avoid excessive updates during camera movement.
|
|
40526
|
+
setTimeout(() => {
|
|
40527
|
+
if (this.currentMarker !== this.viewer[UPDATE_MARKER_KEY]) {
|
|
40528
|
+
this.isUpdating = false;
|
|
40529
|
+
return;
|
|
40530
|
+
}
|
|
40531
|
+
try {
|
|
40532
|
+
// The grid goes first, since it notices when the origin has moved and the gizmo has to follow.
|
|
40533
|
+
this.updateGrid();
|
|
40534
|
+
if (this.modelSpace) {
|
|
40535
|
+
this.drawGizmoPieces();
|
|
40536
|
+
}
|
|
40537
|
+
else {
|
|
40538
|
+
this.clearGizmoPieces();
|
|
40539
|
+
}
|
|
40540
|
+
}
|
|
40541
|
+
catch (e) {
|
|
40542
|
+
console.error(e);
|
|
40543
|
+
}
|
|
40544
|
+
finally {
|
|
40545
|
+
this.isUpdating = false;
|
|
40546
|
+
}
|
|
40547
|
+
}, 100);
|
|
40548
|
+
}
|
|
40549
|
+
cachedOffsetPoint(point, distance, heading) {
|
|
40550
|
+
const key = `${point.latitude.toFixed(8)},${point.longitude.toFixed(8)},${distance.toFixed(1)},${heading}`;
|
|
40551
|
+
if (this.offsetCache.has(key)) {
|
|
40552
|
+
return this.offsetCache.get(key);
|
|
40553
|
+
}
|
|
40554
|
+
const result = offsetPoint$1(point, distance, heading);
|
|
40555
|
+
this.offsetCache.set(key, result);
|
|
40556
|
+
if (this.offsetCache.size > this.maxCacheSize) {
|
|
40557
|
+
const keys = Array.from(this.offsetCache.keys());
|
|
40558
|
+
for (let i = 0; i < 100; i++) {
|
|
40559
|
+
this.offsetCache.delete(keys[i]);
|
|
40560
|
+
}
|
|
40561
|
+
}
|
|
40562
|
+
return result;
|
|
40563
|
+
}
|
|
40564
|
+
/**
|
|
40565
|
+
* Calculates a dynamic visibility ratio based on spacing size.
|
|
40566
|
+
* For small grid spacings, we can show the grid from farther away.
|
|
40567
|
+
* For large grid spacings, we need to hide it sooner to prevent performance issues.
|
|
40568
|
+
*/
|
|
40569
|
+
getMaxVisibilityRatio() {
|
|
40570
|
+
if (this.spacingInMeters <= 10) {
|
|
40571
|
+
return this.BASE_MAX_VISIBILITY_RATIO;
|
|
40572
|
+
}
|
|
40573
|
+
if (this.spacingInMeters <= 100) {
|
|
40574
|
+
const factor = 1 - ((this.spacingInMeters - 10) / 90);
|
|
40575
|
+
return this.BASE_MAX_VISIBILITY_RATIO * (0.5 + (factor * 0.5));
|
|
40576
|
+
}
|
|
40577
|
+
const largeGridFactor = Math.min(1, 100 / this.spacingInMeters);
|
|
40578
|
+
return this.BASE_MAX_VISIBILITY_RATIO * 0.5 * largeGridFactor;
|
|
40579
|
+
}
|
|
40580
|
+
updateGrid() {
|
|
40581
|
+
const cameraPosition = this.viewer.camera.position;
|
|
40582
|
+
const cameraCartographic = Cartographic.fromCartesian(cameraPosition);
|
|
40583
|
+
const cameraHeight = cameraCartographic.height;
|
|
40584
|
+
let adaptiveSpacing = this.calculateAdaptiveSpacing(cameraHeight, this.spacingInMeters);
|
|
40585
|
+
// Calculate visible area.
|
|
40586
|
+
const visibleArea = this.calculateVisibleArea();
|
|
40587
|
+
if (!visibleArea) {
|
|
40588
|
+
return;
|
|
40589
|
+
}
|
|
40590
|
+
let densityCheckPassed = false;
|
|
40591
|
+
let attempts = 0;
|
|
40592
|
+
while (!densityCheckPassed && attempts < this.MAX_ADAPTIVE_ATTEMPTS) {
|
|
40593
|
+
if (this.isGridDensityAcceptable(visibleArea, cameraHeight, adaptiveSpacing)) {
|
|
40594
|
+
densityCheckPassed = true;
|
|
40595
|
+
}
|
|
40596
|
+
else {
|
|
40597
|
+
adaptiveSpacing *= 2;
|
|
40598
|
+
attempts++;
|
|
40599
|
+
}
|
|
40600
|
+
}
|
|
40601
|
+
// The origin follows the UCS of what is shown, so the grid moves with it when that changes.
|
|
40602
|
+
if (this.modelSpace && this.fixedGridOrigin && !Carto.IsEqual(this.fixedGridOrigin, this.modelSpaceOrigin())) {
|
|
40603
|
+
this.fixedGridOrigin = null;
|
|
40604
|
+
this.lastCameraPosition = null;
|
|
40605
|
+
this.clearGizmoPieces();
|
|
40606
|
+
}
|
|
40607
|
+
// Calculate grid origin if we don't have one yet.
|
|
40608
|
+
if (!this.fixedGridOrigin) {
|
|
40609
|
+
if (this.modelSpace) {
|
|
40610
|
+
this.fixedGridOrigin = this.modelSpaceOrigin();
|
|
40611
|
+
}
|
|
40612
|
+
else {
|
|
40613
|
+
const centerCartographic = Cartographic.fromCartesian(visibleArea.centerCartesian);
|
|
40614
|
+
const centerPoint = {
|
|
40615
|
+
latitude: Math$1.toDegrees(centerCartographic.latitude),
|
|
40616
|
+
longitude: Math$1.toDegrees(centerCartographic.longitude),
|
|
40617
|
+
altitude: 0
|
|
40618
|
+
};
|
|
40619
|
+
// Simple attempt at snapping to the grid, should do something smarter.
|
|
40620
|
+
this.fixedGridOrigin = {
|
|
40621
|
+
latitude: Math.round(centerPoint.latitude * 100000) / 100000,
|
|
40622
|
+
longitude: Math.round(centerPoint.longitude * 100000) / 100000,
|
|
40623
|
+
altitude: 0
|
|
40624
|
+
};
|
|
40625
|
+
}
|
|
40626
|
+
}
|
|
40627
|
+
// Calculate appropriate grid extent based on camera height.
|
|
40628
|
+
// For larger grid spacings, we use a tighter extent to prevent performance issues.
|
|
40629
|
+
const scaledExtentFactor = Math.max(0.5, Math.min(3, 3 - Math.log10(Math.max(1, adaptiveSpacing)) * 0.5));
|
|
40630
|
+
const visibilityRadius = Math.min(cameraHeight * scaledExtentFactor, Infinity);
|
|
40631
|
+
// Check if we should redraw the grid.
|
|
40632
|
+
const shouldRedraw = this.shouldRedrawGrid(cameraPosition, cameraHeight, visibilityRadius, adaptiveSpacing);
|
|
40633
|
+
if (!shouldRedraw) {
|
|
40634
|
+
return;
|
|
40635
|
+
}
|
|
40636
|
+
// Remember current settings for next comparison.
|
|
40637
|
+
this.lastCameraHeight = cameraHeight;
|
|
40638
|
+
this.lastCameraPosition = cameraPosition.clone();
|
|
40639
|
+
this.lastGridExtent = visibilityRadius;
|
|
40640
|
+
// Clear existing grid and create a new one.
|
|
40641
|
+
this.clearGrid();
|
|
40642
|
+
this.gridLines = new PolylineCollection();
|
|
40643
|
+
this.gridLabels = new LabelCollection({
|
|
40644
|
+
scene: this.viewer.scene
|
|
40645
|
+
});
|
|
40646
|
+
this.gridPrimitives.add(this.gridLines);
|
|
40647
|
+
this.gridPrimitives.add(this.gridLabels);
|
|
40648
|
+
// Generate grid lines and labels using our fixed origin.
|
|
40649
|
+
this.generateGridLines(this.fixedGridOrigin, visibilityRadius, adaptiveSpacing);
|
|
40650
|
+
}
|
|
40651
|
+
shouldRedrawGrid(cameraPosition, cameraHeight, gridExtent, currentSpacing) {
|
|
40652
|
+
// check if the spacing has changed
|
|
40653
|
+
if (this.lastUsedSpacing && this.lastUsedSpacing !== currentSpacing) {
|
|
40654
|
+
return true;
|
|
40655
|
+
}
|
|
40656
|
+
// Always draw if we don't have a grid yet.
|
|
40657
|
+
if (!this.gridLines || !this.lastCameraPosition || !this.fixedGridOrigin) {
|
|
40658
|
+
return true;
|
|
40659
|
+
}
|
|
40660
|
+
// Check for significant height change.
|
|
40661
|
+
const heightRatio = cameraHeight / this.lastCameraHeight;
|
|
40662
|
+
if (heightRatio > (1 + this.HEIGHT_CHANGE_THRESHOLD) ||
|
|
40663
|
+
heightRatio < (1 - this.HEIGHT_CHANGE_THRESHOLD)) {
|
|
40664
|
+
return true;
|
|
40665
|
+
}
|
|
40666
|
+
// Check for significant position change relative to current grid extent.
|
|
40667
|
+
const distance = Cartesian3.distance(cameraPosition, this.lastCameraPosition);
|
|
40668
|
+
const moveThreshold = gridExtent * this.CAMERA_MOVE_THRESHOLD;
|
|
40669
|
+
if (distance > moveThreshold) {
|
|
40670
|
+
return true;
|
|
40671
|
+
}
|
|
40672
|
+
// Check for significant grid extent change.
|
|
40673
|
+
const extentRatio = gridExtent / this.lastGridExtent;
|
|
40674
|
+
if (extentRatio > (1 + this.GRID_EXTENT_CHANGE_THRESHOLD) ||
|
|
40675
|
+
extentRatio < (1 - this.GRID_EXTENT_CHANGE_THRESHOLD)) {
|
|
40676
|
+
return true;
|
|
40677
|
+
}
|
|
40678
|
+
// No significant changes, keep current grid.
|
|
40679
|
+
return false;
|
|
40680
|
+
}
|
|
40681
|
+
isGridDensityAcceptable(visibleArea, cameraHeight, spacingToCheck = this.spacingInMeters) {
|
|
40682
|
+
const lonRange = visibleArea.eastLon - visibleArea.westLon;
|
|
40683
|
+
const latRange = visibleArea.northLat - visibleArea.southLat;
|
|
40684
|
+
// Convert to approximate meters at center
|
|
40685
|
+
const centerCartographic = Cartographic.fromCartesian(visibleArea.centerCartesian);
|
|
40686
|
+
const metersPerDegreeLon = 111319.9 * Math.cos(centerCartographic.latitude);
|
|
40687
|
+
const canvas = this.viewer.scene.canvas;
|
|
40688
|
+
const spacingInDegrees = spacingToCheck / metersPerDegreeLon;
|
|
40689
|
+
const canvasWidth = canvas.clientWidth;
|
|
40690
|
+
const pixelsPerDegree = canvasWidth / lonRange;
|
|
40691
|
+
const pixelsBetweenGridLines = pixelsPerDegree * spacingInDegrees;
|
|
40692
|
+
const minPixelSize = 1;
|
|
40693
|
+
return pixelsBetweenGridLines >= minPixelSize;
|
|
40694
|
+
}
|
|
40695
|
+
calculateVisibleArea() {
|
|
40696
|
+
const scene = this.viewer.scene;
|
|
40697
|
+
const camera = scene.camera;
|
|
40698
|
+
const globe = scene.globe;
|
|
40699
|
+
// Get the corners of the view frustum
|
|
40700
|
+
const canvas = scene.canvas;
|
|
40701
|
+
const corners = [
|
|
40702
|
+
new Cartesian2(0, 0),
|
|
40703
|
+
new Cartesian2(canvas.clientWidth, 0),
|
|
40704
|
+
new Cartesian2(0, canvas.clientHeight),
|
|
40705
|
+
new Cartesian2(canvas.clientWidth, canvas.clientHeight),
|
|
40706
|
+
new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2) // Center
|
|
40707
|
+
];
|
|
40708
|
+
// Project corners to the globe
|
|
40709
|
+
const cartographicCorners = [];
|
|
40710
|
+
for (const corner of corners) {
|
|
40711
|
+
const ray = camera.getPickRay(corner);
|
|
40712
|
+
if (!ray) {
|
|
40713
|
+
continue;
|
|
40714
|
+
}
|
|
40715
|
+
const position = globe.pick(ray, scene);
|
|
40716
|
+
if (!position) {
|
|
40717
|
+
continue;
|
|
40718
|
+
}
|
|
40719
|
+
cartographicCorners.push(Cartographic.fromCartesian(position));
|
|
40720
|
+
}
|
|
40721
|
+
if (cartographicCorners.length === 0) {
|
|
40722
|
+
return null;
|
|
40723
|
+
}
|
|
40724
|
+
// Find the bounding rectangle
|
|
40725
|
+
let westLon = Number.POSITIVE_INFINITY;
|
|
40726
|
+
let eastLon = Number.NEGATIVE_INFINITY;
|
|
40727
|
+
let southLat = Number.POSITIVE_INFINITY;
|
|
40728
|
+
let northLat = Number.NEGATIVE_INFINITY;
|
|
40729
|
+
for (const corner of cartographicCorners) {
|
|
40730
|
+
westLon = Math.min(westLon, corner.longitude);
|
|
40731
|
+
eastLon = Math.max(eastLon, corner.longitude);
|
|
40732
|
+
southLat = Math.min(southLat, corner.latitude);
|
|
40733
|
+
northLat = Math.max(northLat, corner.latitude);
|
|
40734
|
+
}
|
|
40735
|
+
// Add some padding around the visible area
|
|
40736
|
+
const lonPadding = (eastLon - westLon) * this.VIEW_PADDING_FACTOR;
|
|
40737
|
+
const latPadding = (northLat - southLat) * this.VIEW_PADDING_FACTOR;
|
|
40738
|
+
westLon -= lonPadding;
|
|
40739
|
+
eastLon += lonPadding;
|
|
40740
|
+
southLat -= latPadding;
|
|
40741
|
+
northLat += latPadding;
|
|
40742
|
+
// Get center position for reference
|
|
40743
|
+
const centerCartographic = new Cartographic((westLon + eastLon) / 2, (southLat + northLat) / 2);
|
|
40744
|
+
const centerCartesian = Cartesian3.fromRadians(centerCartographic.longitude, centerCartographic.latitude, 0);
|
|
40745
|
+
return {
|
|
40746
|
+
westLon: Math$1.toDegrees(westLon),
|
|
40747
|
+
eastLon: Math$1.toDegrees(eastLon),
|
|
40748
|
+
southLat: Math$1.toDegrees(southLat),
|
|
40749
|
+
northLat: Math$1.toDegrees(northLat),
|
|
40750
|
+
centerCartesian: centerCartesian
|
|
40751
|
+
};
|
|
40752
|
+
}
|
|
40753
|
+
generateGridLines(originPoint, visibilityRadius, actualSpacing = this.spacingInMeters) {
|
|
40754
|
+
// Number of grid cells in each direction (add 1 for edge lines).
|
|
40755
|
+
const gridCellCount = Math.ceil(visibilityRadius / actualSpacing) + 1;
|
|
40756
|
+
const maxCells = Math.min(gridCellCount, Math.floor(this.MAX_LINES / 2));
|
|
40757
|
+
// Calculate interval to skip lines for density control.
|
|
40758
|
+
const spacingFactor = actualSpacing / 100;
|
|
40759
|
+
const heightFactor = this.lastCameraHeight / 500;
|
|
40760
|
+
let lineSkipInterval = Math.floor(spacingFactor * heightFactor);
|
|
40761
|
+
lineSkipInterval = Math.min(Math.max(lineSkipInterval, 1), 10); // Clamp between 1 and 10
|
|
40762
|
+
const intersections = [];
|
|
40763
|
+
// Generate north-south grid lines (longitude lines)
|
|
40764
|
+
for (let i = -maxCells; i <= maxCells; i++) {
|
|
40765
|
+
if (i % lineSkipInterval !== 0) {
|
|
40766
|
+
continue;
|
|
40767
|
+
}
|
|
40768
|
+
const positions = [];
|
|
40769
|
+
// Create a vertical line at this longitude offset.
|
|
40770
|
+
// East heading for longitude.
|
|
40771
|
+
const startPoint = this.cachedOffsetPoint(originPoint, i * actualSpacing, 90);
|
|
40772
|
+
// Draw the line from south to north
|
|
40773
|
+
for (let j = -maxCells; j <= maxCells; j++) {
|
|
40774
|
+
if (j % lineSkipInterval !== 0) {
|
|
40775
|
+
continue;
|
|
40776
|
+
}
|
|
40777
|
+
// North heading for latitude.
|
|
40778
|
+
const linePoint = this.cachedOffsetPoint(startPoint, j * actualSpacing, 0);
|
|
40779
|
+
const position = Cartesian3.fromDegrees(linePoint.longitude, linePoint.latitude, linePoint.altitude);
|
|
40780
|
+
positions.push(position);
|
|
40781
|
+
intersections.push({
|
|
40782
|
+
position: position,
|
|
40783
|
+
i: i,
|
|
40784
|
+
j: j
|
|
40785
|
+
});
|
|
40786
|
+
}
|
|
40787
|
+
if (positions.length >= 2) {
|
|
40788
|
+
// Check if this is the primary Y axis (i=0) in model space
|
|
40789
|
+
const isPrimaryYAxis = this.modelSpace && i === 0;
|
|
40790
|
+
this.addGridLine(positions, isPrimaryYAxis ? "y" : null);
|
|
40791
|
+
}
|
|
40792
|
+
}
|
|
40793
|
+
// Generate east-west grid lines (latitude lines).
|
|
40794
|
+
for (let j = -maxCells; j <= maxCells; j++) {
|
|
40795
|
+
if (j % lineSkipInterval !== 0) {
|
|
40796
|
+
continue;
|
|
40797
|
+
}
|
|
40798
|
+
const positions = [];
|
|
40799
|
+
// Create a horizontal line at this latitude offset
|
|
40800
|
+
// North heading for latitude.
|
|
40801
|
+
const startPoint = this.cachedOffsetPoint(originPoint, j * actualSpacing, 0);
|
|
40802
|
+
// Draw the line from west to east.
|
|
40803
|
+
for (let i = -maxCells; i <= maxCells; i++) {
|
|
40804
|
+
if (i % lineSkipInterval !== 0) {
|
|
40805
|
+
continue;
|
|
40806
|
+
}
|
|
40807
|
+
// East heading for longitude.
|
|
40808
|
+
const linePoint = this.cachedOffsetPoint(startPoint, i * actualSpacing, 90);
|
|
40809
|
+
const position = Cartesian3.fromDegrees(linePoint.longitude, linePoint.latitude, linePoint.altitude);
|
|
40810
|
+
positions.push(position);
|
|
40811
|
+
}
|
|
40812
|
+
if (positions.length >= 2) {
|
|
40813
|
+
// Check if this is the primary X axis (j=0) in model space
|
|
40814
|
+
const isPrimaryXAxis = this.modelSpace && j === 0;
|
|
40815
|
+
this.addGridLine(positions, isPrimaryXAxis ? "x" : null);
|
|
40816
|
+
}
|
|
40817
|
+
}
|
|
40818
|
+
this.addGridLabels(intersections, actualSpacing);
|
|
40819
|
+
}
|
|
40820
|
+
addGridLabels(intersections, actualSpacing) {
|
|
40821
|
+
if (!this.gridLabels) {
|
|
40822
|
+
return;
|
|
40823
|
+
}
|
|
40824
|
+
// Determine label interval based on number of intersections.
|
|
40825
|
+
// Use higher interval for more intersections to prevent crowding.
|
|
40826
|
+
const totalIntersections = intersections.length;
|
|
40827
|
+
let labelInterval = this.LABEL_INTERVAL;
|
|
40828
|
+
if (totalIntersections > 1000) {
|
|
40829
|
+
labelInterval = 5;
|
|
40830
|
+
}
|
|
40831
|
+
else if (totalIntersections > 500) {
|
|
40832
|
+
labelInterval = 3;
|
|
40833
|
+
}
|
|
40834
|
+
let labelCount = 0;
|
|
40835
|
+
// Filter intersections to only those at the labelInterval.
|
|
40836
|
+
const labelPoints = intersections.filter(point => {
|
|
40837
|
+
// Always label the origin (0,0).
|
|
40838
|
+
if (point.i === 0 && point.j === 0) {
|
|
40839
|
+
return true;
|
|
40840
|
+
}
|
|
40841
|
+
return (point.i % labelInterval === 0 && point.j % labelInterval === 0);
|
|
40842
|
+
});
|
|
40843
|
+
// Sort points by distance from origin.
|
|
40844
|
+
labelPoints.sort((a, b) => {
|
|
40845
|
+
const distA = Math.abs(a.i) + Math.abs(a.j);
|
|
40846
|
+
const distB = Math.abs(b.i) + Math.abs(b.j);
|
|
40847
|
+
return distA - distB;
|
|
40848
|
+
});
|
|
40849
|
+
// Add labels, prioritizing those closest to the origin.
|
|
40850
|
+
for (const point of labelPoints) {
|
|
40851
|
+
if (labelCount >= this.MAX_LABELS) {
|
|
40852
|
+
// Limit reached.
|
|
40853
|
+
break;
|
|
40854
|
+
}
|
|
40855
|
+
let labelText;
|
|
40856
|
+
// Model space coordinates (meters from origin).
|
|
40857
|
+
if (this.modelSpace) {
|
|
40858
|
+
const xMeters = point.i * actualSpacing;
|
|
40859
|
+
const yMeters = point.j * actualSpacing;
|
|
40860
|
+
if (point.i === 0 && point.j === 0) {
|
|
40861
|
+
labelText = "0,0,0";
|
|
40862
|
+
}
|
|
40863
|
+
else {
|
|
40864
|
+
labelText = `${xMeters},${yMeters}`;
|
|
40865
|
+
}
|
|
40866
|
+
}
|
|
40867
|
+
// Geographic coordinates (degrees).
|
|
40868
|
+
else {
|
|
40869
|
+
const cartographic = Cartographic.fromCartesian(point.position);
|
|
40870
|
+
const latitude = Math$1.toDegrees(cartographic.latitude);
|
|
40871
|
+
const longitude = Math$1.toDegrees(cartographic.longitude);
|
|
40872
|
+
const latFormatted = latitude.toFixed(5);
|
|
40873
|
+
const lonFormatted = longitude.toFixed(5);
|
|
40874
|
+
labelText = `${latFormatted}, ${lonFormatted}`;
|
|
40875
|
+
}
|
|
40876
|
+
this.gridLabels.add({
|
|
40877
|
+
position: point.position,
|
|
40878
|
+
text: labelText,
|
|
40879
|
+
font: this.modelSpace && point.i === 0 && point.j === 0 ? "20px sans-serif" : "14px sans-serif",
|
|
40880
|
+
fillColor: this.modelSpace && point.i === 0 && point.j === 0 ? Color.WHITE : Color.WHITE.withAlpha(0.5),
|
|
40881
|
+
style: LabelStyle.FILL,
|
|
40882
|
+
horizontalOrigin: HorizontalOrigin.CENTER,
|
|
40883
|
+
verticalOrigin: VerticalOrigin.TOP,
|
|
40884
|
+
pixelOffset: new Cartesian2(0, 10),
|
|
40885
|
+
// Fade out with distance.
|
|
40886
|
+
translucencyByDistance: new NearFarScalar(1000, 1.0, 15000, 0.4)
|
|
40887
|
+
});
|
|
40888
|
+
labelCount++;
|
|
40889
|
+
}
|
|
40890
|
+
}
|
|
40891
|
+
addGridLine(positions, primaryAxis = null) {
|
|
40892
|
+
if (!this.gridLines || positions.length < 2) {
|
|
40893
|
+
return;
|
|
40894
|
+
}
|
|
40895
|
+
let lineColor;
|
|
40896
|
+
let lineWidth = 1.0;
|
|
40897
|
+
let lineAlpha = 0.2;
|
|
40898
|
+
// Red for X axis.
|
|
40899
|
+
if (primaryAxis === "x") {
|
|
40900
|
+
lineColor = Color.RED;
|
|
40901
|
+
lineAlpha = 0.5;
|
|
40902
|
+
lineWidth = 1.5;
|
|
40903
|
+
}
|
|
40904
|
+
// Green for Y axis.
|
|
40905
|
+
else if (primaryAxis === "y") {
|
|
40906
|
+
lineColor = Color.GREEN;
|
|
40907
|
+
lineAlpha = 0.5;
|
|
40908
|
+
lineWidth = 1.5;
|
|
40909
|
+
}
|
|
40910
|
+
// Default gray for regular grid lines.
|
|
40911
|
+
else {
|
|
40912
|
+
lineColor = Color.LIGHTGRAY;
|
|
40913
|
+
}
|
|
40914
|
+
this.gridLines.add({
|
|
40915
|
+
positions: positions,
|
|
40916
|
+
width: lineWidth,
|
|
40917
|
+
material: Material.fromType("Color", {
|
|
40918
|
+
color: lineColor.withAlpha(lineAlpha)
|
|
40919
|
+
})
|
|
40920
|
+
});
|
|
40921
|
+
}
|
|
40922
|
+
}
|
|
40923
|
+
// Grid square size used when settings name none, in metres.
|
|
40924
|
+
const DEFAULT_SPACING = 50;
|
|
40925
|
+
var CesiumMapGrid;
|
|
40926
|
+
(function (CesiumMapGrid) {
|
|
40927
|
+
function GetCurrentSpacing(viewer) {
|
|
40928
|
+
if (!viewer || viewer.isDestroyed()) {
|
|
40929
|
+
return 0;
|
|
40930
|
+
}
|
|
40931
|
+
const handler = viewer[CLASS_INSTANCE_KEY];
|
|
40932
|
+
return handler ? handler.getCurrentSpacing() : 0;
|
|
40933
|
+
}
|
|
40934
|
+
CesiumMapGrid.GetCurrentSpacing = GetCurrentSpacing;
|
|
40935
|
+
function Remove(viewer) {
|
|
40936
|
+
if (!viewer || viewer.isDestroyed()) {
|
|
40937
|
+
return;
|
|
40938
|
+
}
|
|
40939
|
+
else if (!viewer[LAST_SETTINGS_KEY]) {
|
|
40940
|
+
return;
|
|
40941
|
+
}
|
|
40942
|
+
if (!viewer[UPDATE_MARKER_KEY]) {
|
|
40943
|
+
viewer[UPDATE_MARKER_KEY] = 1;
|
|
40944
|
+
}
|
|
40945
|
+
else {
|
|
40946
|
+
viewer[UPDATE_MARKER_KEY]++;
|
|
40947
|
+
}
|
|
40948
|
+
// Dispose of the handler.
|
|
40949
|
+
if (viewer[CLASS_INSTANCE_KEY]) {
|
|
40950
|
+
viewer[CLASS_INSTANCE_KEY].Dispose();
|
|
40951
|
+
viewer[CLASS_INSTANCE_KEY] = null;
|
|
40952
|
+
}
|
|
40953
|
+
viewer[LAST_SETTINGS_KEY] = {
|
|
40954
|
+
...viewer[LAST_SETTINGS_KEY],
|
|
40955
|
+
enabled: false
|
|
40956
|
+
};
|
|
40957
|
+
}
|
|
40958
|
+
CesiumMapGrid.Remove = Remove;
|
|
40959
|
+
function Draw(viewer, spacingInMeters, modelSpace = true) {
|
|
40960
|
+
if (!viewer || viewer.isDestroyed()) {
|
|
40961
|
+
return;
|
|
40962
|
+
}
|
|
40963
|
+
let settings = viewer[LAST_SETTINGS_KEY];
|
|
40964
|
+
if (settings) {
|
|
40965
|
+
// See if the settings are the same as the last time.
|
|
40966
|
+
if (settings.spacing === spacingInMeters &&
|
|
40967
|
+
settings.modelSpace === modelSpace &&
|
|
40968
|
+
settings.enabled) {
|
|
40969
|
+
return;
|
|
40970
|
+
}
|
|
40971
|
+
}
|
|
40972
|
+
if (!viewer[UPDATE_MARKER_KEY]) {
|
|
40973
|
+
viewer[UPDATE_MARKER_KEY] = 1;
|
|
40974
|
+
}
|
|
40975
|
+
else {
|
|
40976
|
+
viewer[UPDATE_MARKER_KEY]++;
|
|
40977
|
+
}
|
|
40978
|
+
settings = {
|
|
40979
|
+
...settings,
|
|
40980
|
+
enabled: true,
|
|
40981
|
+
spacing: spacingInMeters,
|
|
40982
|
+
modelSpace: modelSpace
|
|
40983
|
+
};
|
|
40984
|
+
viewer[LAST_SETTINGS_KEY] = settings;
|
|
40985
|
+
// Create or update the handler.
|
|
40986
|
+
if (viewer[CLASS_INSTANCE_KEY]) {
|
|
40987
|
+
viewer[CLASS_INSTANCE_KEY].Update(spacingInMeters, modelSpace);
|
|
40988
|
+
}
|
|
40989
|
+
else {
|
|
40990
|
+
viewer[CLASS_INSTANCE_KEY] = new MapGridHandler(viewer, spacingInMeters, modelSpace);
|
|
40991
|
+
}
|
|
40992
|
+
}
|
|
40993
|
+
CesiumMapGrid.Draw = Draw;
|
|
40994
|
+
/**
|
|
40995
|
+
* Draws a bookmark's grid, or removes the grid when it has none; only model-space draws one.
|
|
40996
|
+
*/
|
|
40997
|
+
function Apply(viewer, grid, modelSpace) {
|
|
40998
|
+
if ((grid === null || grid === void 0 ? void 0 : grid.enabled) && modelSpace) {
|
|
40999
|
+
Draw(viewer, Number(grid.spacing) || DEFAULT_SPACING, modelSpace);
|
|
41000
|
+
}
|
|
41001
|
+
else {
|
|
41002
|
+
Remove(viewer);
|
|
41003
|
+
}
|
|
41004
|
+
}
|
|
41005
|
+
CesiumMapGrid.Apply = Apply;
|
|
41006
|
+
function GetIsEnabled(viewer) {
|
|
41007
|
+
if (!viewer || viewer.isDestroyed()) {
|
|
41008
|
+
return false;
|
|
41009
|
+
}
|
|
41010
|
+
const settings = viewer[LAST_SETTINGS_KEY];
|
|
41011
|
+
if (settings) {
|
|
41012
|
+
return Boolean(settings.enabled);
|
|
41013
|
+
}
|
|
41014
|
+
return false;
|
|
41015
|
+
}
|
|
41016
|
+
CesiumMapGrid.GetIsEnabled = GetIsEnabled;
|
|
41017
|
+
/**
|
|
41018
|
+
* Returns the last applied grid settings.
|
|
41019
|
+
*/
|
|
41020
|
+
function GetSettings(viewer) {
|
|
41021
|
+
if (!viewer || viewer.isDestroyed()) {
|
|
41022
|
+
return null;
|
|
41023
|
+
}
|
|
41024
|
+
return viewer[LAST_SETTINGS_KEY];
|
|
41025
|
+
}
|
|
41026
|
+
CesiumMapGrid.GetSettings = GetSettings;
|
|
41027
|
+
})(CesiumMapGrid || (CesiumMapGrid = {}));
|
|
41028
|
+
|
|
38818
41029
|
// TODO: Move these to the data model.
|
|
38819
41030
|
const MIN_SHADOW_SIZE = 2048;
|
|
38820
41031
|
const MAX_SHADOW_SIZE = 32768;
|
|
@@ -39006,7 +41217,7 @@ async function renderLegacyNavigator(iteration, params, bookmark, view) {
|
|
|
39006
41217
|
* @param view
|
|
39007
41218
|
*/
|
|
39008
41219
|
async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
39009
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
|
|
41220
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9;
|
|
39010
41221
|
const viewer = params.manager.Viewer;
|
|
39011
41222
|
const scene = viewer.scene;
|
|
39012
41223
|
// Ion requests go through the server-side proxy (set up during viewer init or here as fallback).
|
|
@@ -39231,15 +41442,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39231
41442
|
scene.globe.translucency.frontFaceAlphaByDistance.farValue = 1;
|
|
39232
41443
|
}
|
|
39233
41444
|
scene.globe.translucency.frontFaceAlphaByDistance.nearValue = EnsureNumber(globeAlpha, 1);
|
|
39234
|
-
|
|
39235
|
-
if (shadows == null) {
|
|
39236
|
-
shadows = (_u = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _u === void 0 ? void 0 : _u.shadows;
|
|
39237
|
-
}
|
|
39238
|
-
if (shadows == null) {
|
|
39239
|
-
shadows = {
|
|
39240
|
-
enabled: false
|
|
39241
|
-
};
|
|
39242
|
-
}
|
|
41445
|
+
const shadows = ViewRenderEngine.ResolveShadows(bSettings, defaults === null || defaults === void 0 ? void 0 : defaults.settings, contentType);
|
|
39243
41446
|
viewer.shadows = Boolean(shadows.enabled);
|
|
39244
41447
|
viewer.shadowMap.enabled = Boolean(shadows.enabled);
|
|
39245
41448
|
let size = EnsureNumber(shadows.pixelSize);
|
|
@@ -39252,9 +41455,11 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39252
41455
|
viewer.shadowMap.size = size;
|
|
39253
41456
|
viewer.shadowMap.softShadows = Boolean(shadows.soften);
|
|
39254
41457
|
viewer.shadowMap.darkness = EnsureNumber(shadows.darkness, 0.3);
|
|
41458
|
+
// Drawn after the model-space origin is resolved above, since the grid starts from it.
|
|
41459
|
+
CesiumMapGrid.Apply(viewer, (_u = bSettings.grid) !== null && _u !== void 0 ? _u : (_v = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _v === void 0 ? void 0 : _v.grid, contentType == ProjectViewBookmark.EContentType.WEB_3D_MODEL_SPACE);
|
|
39255
41460
|
let ambientOcclusion = bSettings === null || bSettings === void 0 ? void 0 : bSettings.ambientOcclusion;
|
|
39256
41461
|
if (ambientOcclusion == null) {
|
|
39257
|
-
ambientOcclusion = (
|
|
41462
|
+
ambientOcclusion = (_w = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _w === void 0 ? void 0 : _w.ambientOcclusion;
|
|
39258
41463
|
}
|
|
39259
41464
|
if (ambientOcclusion == null) {
|
|
39260
41465
|
ambientOcclusion = {
|
|
@@ -39277,7 +41482,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39277
41482
|
}
|
|
39278
41483
|
let lighting = bSettings === null || bSettings === void 0 ? void 0 : bSettings.lighting;
|
|
39279
41484
|
if (lighting == null) {
|
|
39280
|
-
lighting = (
|
|
41485
|
+
lighting = (_x = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _x === void 0 ? void 0 : _x.lighting;
|
|
39281
41486
|
}
|
|
39282
41487
|
if (lighting == null) {
|
|
39283
41488
|
lighting = {
|
|
@@ -39295,7 +41500,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39295
41500
|
ViewUtils.ApplyDefaultBrightness(viewer, EnsureNumber(lighting.brightnessShift, DEFAULT_BRIGHTNESS_SHIFT));
|
|
39296
41501
|
let quality = bSettings === null || bSettings === void 0 ? void 0 : bSettings.quality;
|
|
39297
41502
|
if (quality == null) {
|
|
39298
|
-
quality = (
|
|
41503
|
+
quality = (_y = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _y === void 0 ? void 0 : _y.quality;
|
|
39299
41504
|
}
|
|
39300
41505
|
if (quality == null) {
|
|
39301
41506
|
quality = {
|
|
@@ -39306,11 +41511,11 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39306
41511
|
fxaa.enabled = Boolean(quality.fxaa);
|
|
39307
41512
|
let dateTime = bSettings === null || bSettings === void 0 ? void 0 : bSettings.dateTime;
|
|
39308
41513
|
if (dateTime == null) {
|
|
39309
|
-
dateTime = (
|
|
41514
|
+
dateTime = (_z = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _z === void 0 ? void 0 : _z.dateTime;
|
|
39310
41515
|
}
|
|
39311
41516
|
let timeline = bSettings === null || bSettings === void 0 ? void 0 : bSettings.timeline;
|
|
39312
41517
|
if (timeline == null) {
|
|
39313
|
-
timeline = (
|
|
41518
|
+
timeline = (_0 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _0 === void 0 ? void 0 : _0.timeline;
|
|
39314
41519
|
}
|
|
39315
41520
|
if (timeline == null) {
|
|
39316
41521
|
timeline = {
|
|
@@ -39334,7 +41539,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39334
41539
|
// Newer version that has states per Entity ID + Menu Item ID.
|
|
39335
41540
|
let states = bSettings === null || bSettings === void 0 ? void 0 : bSettings.states;
|
|
39336
41541
|
if (states == null) {
|
|
39337
|
-
states = (
|
|
41542
|
+
states = (_1 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _1 === void 0 ? void 0 : _1.states;
|
|
39338
41543
|
}
|
|
39339
41544
|
if (states != null) {
|
|
39340
41545
|
params.manager.VisualsRegister.OverrideStates(states);
|
|
@@ -39343,7 +41548,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39343
41548
|
else {
|
|
39344
41549
|
let selectedIds = bSettings === null || bSettings === void 0 ? void 0 : bSettings.selectedEntityIds;
|
|
39345
41550
|
if (selectedIds == null) {
|
|
39346
|
-
selectedIds = (
|
|
41551
|
+
selectedIds = (_2 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _2 === void 0 ? void 0 : _2.selectedEntityIds;
|
|
39347
41552
|
}
|
|
39348
41553
|
if (selectedIds != null) {
|
|
39349
41554
|
params.manager.VisualsRegister.ClearSelected();
|
|
@@ -39357,7 +41562,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39357
41562
|
params.manager.VisualsRegister.ClearHidden();
|
|
39358
41563
|
let hiddenIds = bSettings === null || bSettings === void 0 ? void 0 : bSettings.hiddenEntityIds;
|
|
39359
41564
|
if (hiddenIds == null) {
|
|
39360
|
-
hiddenIds = (
|
|
41565
|
+
hiddenIds = (_3 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _3 === void 0 ? void 0 : _3.hiddenEntityIds;
|
|
39361
41566
|
}
|
|
39362
41567
|
if (hiddenIds != null) {
|
|
39363
41568
|
params.manager.VisualsRegister.SetHidden({
|
|
@@ -39369,7 +41574,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39369
41574
|
params.manager.VisualsRegister.ClearIsolated();
|
|
39370
41575
|
let isolatedIds = bSettings === null || bSettings === void 0 ? void 0 : bSettings.isolatedEntityIds;
|
|
39371
41576
|
if (isolatedIds == null) {
|
|
39372
|
-
isolatedIds = (
|
|
41577
|
+
isolatedIds = (_4 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _4 === void 0 ? void 0 : _4.isolatedEntityIds;
|
|
39373
41578
|
}
|
|
39374
41579
|
if (isolatedIds != null) {
|
|
39375
41580
|
params.manager.VisualsRegister.SetIsolated({
|
|
@@ -39380,7 +41585,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39380
41585
|
}
|
|
39381
41586
|
let labelledIds = bSettings === null || bSettings === void 0 ? void 0 : bSettings.labelledEntityIds;
|
|
39382
41587
|
if (labelledIds == null) {
|
|
39383
|
-
labelledIds = (
|
|
41588
|
+
labelledIds = (_5 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _5 === void 0 ? void 0 : _5.labelledEntityIds;
|
|
39384
41589
|
}
|
|
39385
41590
|
if (!(labelledIds === null || labelledIds === void 0 ? void 0 : labelledIds.length)) {
|
|
39386
41591
|
params.manager.VisualsRegister.ClearLabelled({
|
|
@@ -39404,7 +41609,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39404
41609
|
params.manager.VisualsRegister.ClearOpacity();
|
|
39405
41610
|
let entityOpacityMap = bSettings === null || bSettings === void 0 ? void 0 : bSettings.entityOpacityMap;
|
|
39406
41611
|
if (entityOpacityMap == null) {
|
|
39407
|
-
entityOpacityMap = (
|
|
41612
|
+
entityOpacityMap = (_6 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _6 === void 0 ? void 0 : _6.entityOpacityMap;
|
|
39408
41613
|
}
|
|
39409
41614
|
if (entityOpacityMap != null) {
|
|
39410
41615
|
for (const entityId in entityOpacityMap) {
|
|
@@ -39419,7 +41624,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39419
41624
|
}
|
|
39420
41625
|
}
|
|
39421
41626
|
}
|
|
39422
|
-
let imagery = (bSettings === null || bSettings === void 0 ? void 0 : bSettings.imagery) != null ? bSettings.imagery : (
|
|
41627
|
+
let imagery = (bSettings === null || bSettings === void 0 ? void 0 : bSettings.imagery) != null ? bSettings.imagery : (_7 = defaults.settings) === null || _7 === void 0 ? void 0 : _7.imagery;
|
|
39423
41628
|
if (imagery == null) {
|
|
39424
41629
|
// TODO: Need global default.
|
|
39425
41630
|
imagery = [
|
|
@@ -39489,7 +41694,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39489
41694
|
// Otherwise we cause a flicker of rendered graphics.
|
|
39490
41695
|
// Maybe TODO to such a function for menu item manager.
|
|
39491
41696
|
const curEnabled = params.manager.GetEnabledItemIds();
|
|
39492
|
-
const newItemIds = (
|
|
41697
|
+
const newItemIds = (_8 = bSettings === null || bSettings === void 0 ? void 0 : bSettings.menuItemIds) !== null && _8 !== void 0 ? _8 : [];
|
|
39493
41698
|
for (const id of curEnabled) {
|
|
39494
41699
|
let shouldRemove;
|
|
39495
41700
|
if (id == RELATION_MENU_ITEM_ID) {
|
|
@@ -39563,7 +41768,7 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
|
|
|
39563
41768
|
}
|
|
39564
41769
|
let gOcclusion = bSettings === null || bSettings === void 0 ? void 0 : bSettings.groundOcclusion;
|
|
39565
41770
|
if (gOcclusion == null) {
|
|
39566
|
-
gOcclusion = (
|
|
41771
|
+
gOcclusion = (_9 = defaults === null || defaults === void 0 ? void 0 : defaults.settings) === null || _9 === void 0 ? void 0 : _9.groundOcclusion;
|
|
39567
41772
|
}
|
|
39568
41773
|
if (gOcclusion == null) {
|
|
39569
41774
|
// TODO: Need global default.
|
|
@@ -39581,6 +41786,17 @@ var ViewRenderEngine;
|
|
|
39581
41786
|
ProjectViewBookmark.EContentType.WEB_3D_MODEL_SPACE,
|
|
39582
41787
|
ProjectViewBookmark.EContentType.WEB_3D_SPLIT_PLUGIN
|
|
39583
41788
|
];
|
|
41789
|
+
/**
|
|
41790
|
+
* A bookmark's own shadows, else the view's defaults unless it is model-space, which reads brighter without.
|
|
41791
|
+
*/
|
|
41792
|
+
function ResolveShadows(bSettings, defaults, contentType) {
|
|
41793
|
+
let shadows = bSettings === null || bSettings === void 0 ? void 0 : bSettings.shadows;
|
|
41794
|
+
if (shadows == null && contentType != ProjectViewBookmark.EContentType.WEB_3D_MODEL_SPACE) {
|
|
41795
|
+
shadows = defaults === null || defaults === void 0 ? void 0 : defaults.shadows;
|
|
41796
|
+
}
|
|
41797
|
+
return shadows !== null && shadows !== void 0 ? shadows : { enabled: false };
|
|
41798
|
+
}
|
|
41799
|
+
ViewRenderEngine.ResolveShadows = ResolveShadows;
|
|
39584
41800
|
/**
|
|
39585
41801
|
* Returns where a model-space bookmark's camera goes, measured from the origin in effect.
|
|
39586
41802
|
* @param viewer
|
|
@@ -44312,7 +46528,7 @@ const HOLD_ACTIVATION_TIME_MS = 350;
|
|
|
44312
46528
|
const HOLD_LOADER_DELAY_MS = 150;
|
|
44313
46529
|
const CONTINUOUS_ANIMATION_SPEED = 0.02 / 3;
|
|
44314
46530
|
const ZOOM_DISTANCE = 0.85;
|
|
44315
|
-
const MIN_ZOOM_DISTANCE = 0.3;
|
|
46531
|
+
const MIN_ZOOM_DISTANCE$1 = 0.3;
|
|
44316
46532
|
const NEAR_NADIR_PITCH = -Math.PI / 2 + 0.05;
|
|
44317
46533
|
const MIN_ORBIT_OFFSET_METERS = 5;
|
|
44318
46534
|
// Caps how far a pivot may be from the camera relative to the camera's own altitude.
|
|
@@ -44518,7 +46734,7 @@ function DoZoom(params) {
|
|
|
44518
46734
|
const mag = (ZOOM_DISTANCE * 0.5) / Math.max(1, 4 - Math.log10(height));
|
|
44519
46735
|
const zoom = zoomIn ? 1 - mag : 1 + mag;
|
|
44520
46736
|
const offset = Cartesian3.multiplyByScalar(Cartesian3.subtract(p, ground, new Cartesian3()), zoom, new Cartesian3());
|
|
44521
|
-
if (zoomIn && Cartesian3.magnitude(offset) <= MIN_ZOOM_DISTANCE) {
|
|
46737
|
+
if (zoomIn && Cartesian3.magnitude(offset) <= MIN_ZOOM_DISTANCE$1) {
|
|
44522
46738
|
return Promise.resolve(null);
|
|
44523
46739
|
}
|
|
44524
46740
|
const to = Cartesian3.add(ground, offset, new Cartesian3());
|
|
@@ -44742,7 +46958,7 @@ function StartContinuousZoom(params) {
|
|
|
44742
46958
|
const mag = (ZOOM_DISTANCE * 0.5) / Math.max(1, 4 - Math.log10(height));
|
|
44743
46959
|
const zoom = zoomIn ? 1 - mag * 0.03 : 1 + mag * 0.03;
|
|
44744
46960
|
const offset = Cartesian3.multiplyByScalar(Cartesian3.subtract(p, ground, new Cartesian3()), zoom, new Cartesian3());
|
|
44745
|
-
if (zoomIn && Cartesian3.magnitude(offset) <= MIN_ZOOM_DISTANCE) {
|
|
46961
|
+
if (zoomIn && Cartesian3.magnitude(offset) <= MIN_ZOOM_DISTANCE$1) {
|
|
44746
46962
|
active = false;
|
|
44747
46963
|
return;
|
|
44748
46964
|
}
|
|
@@ -45552,7 +47768,7 @@ var ViewerUtils;
|
|
|
45552
47768
|
* @param viewer
|
|
45553
47769
|
*/
|
|
45554
47770
|
function InitViewer(params) {
|
|
45555
|
-
const { viewer, destroyWidgets, styleContainer, nextspaceWidgets, widgetParams } = params;
|
|
47771
|
+
const { viewer, destroyWidgets, styleContainer, nextspaceWidgets, widgetParams, cameraControls } = params;
|
|
45556
47772
|
const data = { widgets: {} };
|
|
45557
47773
|
if (destroyWidgets != false) {
|
|
45558
47774
|
try {
|
|
@@ -45579,6 +47795,12 @@ var ViewerUtils;
|
|
|
45579
47795
|
// Newer cesium is much dimmer by default so we shift brightness a bit.
|
|
45580
47796
|
ViewUtils.ApplyDefaultBrightness(viewer);
|
|
45581
47797
|
backgroundRendering(viewer);
|
|
47798
|
+
if (cameraControls != false) {
|
|
47799
|
+
CameraControls.Attach(viewer);
|
|
47800
|
+
if (ViewUtils.GetModelSpace(viewer)) {
|
|
47801
|
+
CameraControls.SetModelSpace(viewer, () => ViewUtils.GetModelSpaceFrame(viewer));
|
|
47802
|
+
}
|
|
47803
|
+
}
|
|
45582
47804
|
// Capturing the destroy call to destroy all widgets.
|
|
45583
47805
|
const olDestroy = viewer.destroy;
|
|
45584
47806
|
viewer.destroy = () => {
|
|
@@ -45587,6 +47809,7 @@ var ViewerUtils;
|
|
|
45587
47809
|
}
|
|
45588
47810
|
try {
|
|
45589
47811
|
ViewerUtils.DisposeNextspaceWidgets(viewer);
|
|
47812
|
+
CameraControls.Detach(viewer);
|
|
45590
47813
|
}
|
|
45591
47814
|
// We don't want the actual destroy to fail.
|
|
45592
47815
|
catch (e) {
|
|
@@ -49731,7 +51954,7 @@ var EntityRenderEngineModel3d;
|
|
|
49731
51954
|
...ViewUtils.DefaultLightingProps(),
|
|
49732
51955
|
heightReference: heightRef,
|
|
49733
51956
|
scale: new CallbackProperty(() => scale * styleScale, true),
|
|
49734
|
-
shadows:
|
|
51957
|
+
shadows: ViewUtils.GetEntityShadowMode(params.viewer),
|
|
49735
51958
|
colorBlendAmount: blendAmount,
|
|
49736
51959
|
colorBlendMode: blendMode,
|
|
49737
51960
|
color: new CallbackProperty(() => {
|
|
@@ -49766,7 +51989,7 @@ var EntityRenderEngineModel3d;
|
|
|
49766
51989
|
cEntity.model.uri = new ConstantProperty(params.lodUrl);
|
|
49767
51990
|
}
|
|
49768
51991
|
cEntity.model.heightReference = new ConstantProperty(heightRef);
|
|
49769
|
-
cEntity.model.shadows = new ConstantProperty(
|
|
51992
|
+
cEntity.model.shadows = new ConstantProperty(ViewUtils.GetEntityShadowMode(params.viewer));
|
|
49770
51993
|
cEntity.model.colorBlendAmount = new ConstantProperty(blendAmount);
|
|
49771
51994
|
cEntity.model.colorBlendMode = new ConstantProperty(blendMode);
|
|
49772
51995
|
cEntity.model.distanceDisplayCondition = new ConstantProperty(EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance));
|
|
@@ -50608,7 +52831,7 @@ var EntityRenderEnginePolyline;
|
|
|
50608
52831
|
zIndex: getZIndex(style, entity, params.tags),
|
|
50609
52832
|
distanceDisplayCondition: EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance, width),
|
|
50610
52833
|
cornerType: CornerType.MITERED,
|
|
50611
|
-
shadows:
|
|
52834
|
+
shadows: ViewUtils.GetEntityShadowMode(params.viewer),
|
|
50612
52835
|
fill: true
|
|
50613
52836
|
} : null,
|
|
50614
52837
|
position: EntityUtils.GetPos({
|
|
@@ -55007,6 +57230,12 @@ var EntityRenderEnginePolygon;
|
|
|
55007
57230
|
? Geometry$1.ParsePoints(ring.LinearRing).map((point) => point.altitude)
|
|
55008
57231
|
: [])
|
|
55009
57232
|
});
|
|
57233
|
+
const drapesOnGround = (heightRef === HeightReference.CLAMP_TO_GROUND &&
|
|
57234
|
+
extrusion.value == undefined &&
|
|
57235
|
+
!drawsDisplacedSurface);
|
|
57236
|
+
if (drapesOnGround) {
|
|
57237
|
+
posses = groundPosses(posses);
|
|
57238
|
+
}
|
|
55010
57239
|
posses = CullDuplicateCPosses(posses);
|
|
55011
57240
|
if (posses.length < 4) {
|
|
55012
57241
|
return null;
|
|
@@ -55015,6 +57244,9 @@ var EntityRenderEnginePolygon;
|
|
|
55015
57244
|
const holePosses = holeRings.map((x) => {
|
|
55016
57245
|
const points = Geometry$1.ParsePoints(x.LinearRing);
|
|
55017
57246
|
let holePosses = points.map(x => Cartesian3.fromDegrees(EnsureNumber(x.longitude), EnsureNumber(x.latitude), EnsureNumber(x.altitude)));
|
|
57247
|
+
if (drapesOnGround) {
|
|
57248
|
+
holePosses = groundPosses(holePosses);
|
|
57249
|
+
}
|
|
55018
57250
|
holePosses = CullDuplicateCPosses(holePosses);
|
|
55019
57251
|
Cartes.CloseRing3(holePosses);
|
|
55020
57252
|
return holePosses;
|
|
@@ -55065,7 +57297,7 @@ var EntityRenderEnginePolygon;
|
|
|
55065
57297
|
fill: !drawsDisplacedSurface,
|
|
55066
57298
|
extrudedHeight: extrusion.value,
|
|
55067
57299
|
extrudedHeightReference: extrusion.exHeightRef,
|
|
55068
|
-
shadows:
|
|
57300
|
+
shadows: ViewUtils.GetEntityShadowMode(params.viewer),
|
|
55069
57301
|
heightReference: heightRef,
|
|
55070
57302
|
classificationType: classification,
|
|
55071
57303
|
perPositionHeight: heightRef == HeightReference.CLAMP_TO_GROUND ? false : true,
|
|
@@ -55145,7 +57377,7 @@ var EntityRenderEnginePolygon;
|
|
|
55145
57377
|
viewer: params.viewer,
|
|
55146
57378
|
graphic: cEntity.polygon,
|
|
55147
57379
|
property: "shadows",
|
|
55148
|
-
value:
|
|
57380
|
+
value: ViewUtils.GetEntityShadowMode(params.viewer)
|
|
55149
57381
|
});
|
|
55150
57382
|
SetCPropIfChanged({
|
|
55151
57383
|
viewer: params.viewer,
|
|
@@ -55280,7 +57512,7 @@ var EntityRenderEnginePolygon;
|
|
|
55280
57512
|
cornerType: CornerType.MITERED,
|
|
55281
57513
|
classificationType: classification,
|
|
55282
57514
|
distanceDisplayCondition: EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance, width, false, size),
|
|
55283
|
-
shadows:
|
|
57515
|
+
shadows: ViewUtils.GetEntityShadowMode(params.viewer)
|
|
55284
57516
|
} : null,
|
|
55285
57517
|
show: true
|
|
55286
57518
|
});
|
|
@@ -55403,7 +57635,7 @@ var EntityRenderEnginePolygon;
|
|
|
55403
57635
|
cornerType: CornerType.MITERED,
|
|
55404
57636
|
classificationType: classification,
|
|
55405
57637
|
distanceDisplayCondition: EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance, width, false, size),
|
|
55406
|
-
shadows:
|
|
57638
|
+
shadows: ViewUtils.GetEntityShadowMode(params.viewer),
|
|
55407
57639
|
} : null,
|
|
55408
57640
|
show: true
|
|
55409
57641
|
});
|
|
@@ -55801,6 +58033,18 @@ function waterFor(style) {
|
|
|
55801
58033
|
/*
|
|
55802
58034
|
* The lon/lat bounding rectangle of a ring, which is the frame Cesium drapes an image material in.
|
|
55803
58035
|
*/
|
|
58036
|
+
/*
|
|
58037
|
+
* Moves a ring onto the ellipsoid, as Cesium fills only a strip of a ground polygon with high vertices.
|
|
58038
|
+
*/
|
|
58039
|
+
function groundPosses(posses) {
|
|
58040
|
+
return posses.map((pos) => {
|
|
58041
|
+
const carto = Cartographic.fromCartesian(pos);
|
|
58042
|
+
if (!carto) {
|
|
58043
|
+
return pos;
|
|
58044
|
+
}
|
|
58045
|
+
return Cartesian3.fromRadians(carto.longitude, carto.latitude, 0);
|
|
58046
|
+
});
|
|
58047
|
+
}
|
|
55804
58048
|
function polygonBbox(posses) {
|
|
55805
58049
|
if (!posses || posses.length === 0) {
|
|
55806
58050
|
return undefined;
|
|
@@ -57727,7 +59971,7 @@ var StyleUtils;
|
|
|
57727
59971
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
57728
59972
|
})(StyleUtils || (StyleUtils = {}));
|
|
57729
59973
|
|
|
57730
|
-
const VERSION = "7.7.
|
|
59974
|
+
const VERSION = "7.7.8";
|
|
57731
59975
|
/**
|
|
57732
59976
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
57733
59977
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|
|
@@ -57744,5 +59988,5 @@ const getENVIRONMENT = () => {
|
|
|
57744
59988
|
return ENVIRONMENT;
|
|
57745
59989
|
};
|
|
57746
59990
|
|
|
57747
|
-
export { VERSION, setENVIRONMENT, getENVIRONMENT, ClusterItems, PointClustering, PointClusterSize, CesiumAnimatedInOut, DisplacedSurfacePrimitive, CesiumAnimatedProperty, isStyleChanged, isOutlineChanged$1 as isOutlineChanged, StyleEffective, EntityRenderEngine, EntityRenderEngineModel3d, EntityRenderEnginePoint, extractMetadataFromFileUrl, EntityRenderEnginePolygon, EntityRenderEnginePolyline, TextureFrameSeriesAnimator, TextureValueLabels, MenuItemCreator, MenuItemManager, MenuItemStyles, MenuItemStyleOverlay, CesiumParabola, EntityLabel, EntityLabelGroup, LiveCursor, SharedGetters, EntitySimulation, 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, CESIUM_MODEL_SPACE_POSITIONING_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, ECursor, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, CreateTabIconSvg, WidgetLeftPanel, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar };
|
|
59991
|
+
export { VERSION, setENVIRONMENT, getENVIRONMENT, ClusterItems, PointClustering, PointClusterSize, CesiumAnimatedInOut, DisplacedSurfacePrimitive, CesiumAnimatedProperty, isStyleChanged, isOutlineChanged$1 as isOutlineChanged, StyleEffective, EntityRenderEngine, EntityRenderEngineModel3d, EntityRenderEnginePoint, extractMetadataFromFileUrl, EntityRenderEnginePolygon, EntityRenderEnginePolyline, TextureFrameSeriesAnimator, TextureValueLabels, MenuItemCreator, MenuItemManager, MenuItemStyles, MenuItemStyleOverlay, CesiumParabola, EntityLabel, EntityLabelGroup, LiveCursor, SharedGetters, EntitySimulation, 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, CESIUM_MODEL_SPACE_POSITIONING_KEY, DEFAULT_LIVE_PADDING_SECONDS, DEFAULT_BRIGHTNESS_SHIFT, DEFAULT_LIGHT_INTENSITY, LIGHTING_SETTINGS_VERSION, LIGHT_INTENSITY_COMPENSATION, MAX_COMPENSATED_LIGHT_INTENSITY, ViewUtils, CesiumMapGrid, GltfGenerator, GltfGizmo, DeviceProfile, CesiumViewMonitor, CameraControls, ViewGroundArea, ViewerEventTracker, ViewerUtils, Draw3dPolygon, Draw3dPolyline, MeasureCreator, Walkthrough, WidgetControlViewBar, WidgetControlViewBarSearch, WidgetLeftPanelTab, WidgetLeftPanelTabBookmarks, WidgetLeftPanelTabDashboard, EMenuItemState, WidgetLeftPanelTabMenuItems, Widget, VIEWER_BOOKMARKS_WIDGET_KEY, WidgetBookmarks, WidgetBranding, ECursor, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, CreateTabIconSvg, WidgetLeftPanel, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar };
|
|
57748
59992
|
//# sourceMappingURL=bruce-cesium.es5.js.map
|