bruce-cesium 7.6.3 → 7.6.5
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/README.md +2 -27
- package/dist/bruce-cesium.es5.js +684 -43
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +682 -41
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-render-engine-point-orientation.js +422 -0
- package/dist/lib/rendering/entity-render-engine-point-orientation.js.map +1 -0
- package/dist/lib/rendering/entity-render-engine-point.js +43 -3
- package/dist/lib/rendering/entity-render-engine-point.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label-group.js +53 -17
- package/dist/lib/rendering/render-managers/common/entity-label-group.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label.js +51 -3
- package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js +3 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js.map +1 -1
- package/dist/lib/rendering/view-render-engine.js +2 -2
- package/dist/lib/rendering/view-render-engine.js.map +1 -1
- package/dist/lib/utils/entity-utils.js +96 -0
- package/dist/lib/utils/entity-utils.js.map +1 -1
- package/dist/lib/viewer/viewer-utils.js +23 -15
- package/dist/lib/viewer/viewer-utils.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/entity-render-engine-point-orientation.d.ts +59 -0
- package/dist/types/rendering/render-managers/common/entity-label-group.d.ts +2 -0
- package/dist/types/rendering/render-managers/common/entity-label.d.ts +3 -0
- package/dist/types/utils/entity-utils.d.ts +29 -0
- package/package.json +4 -3
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, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, HeightReference, Matrix4,
|
|
3
|
-
import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, UrlUtils, Carto, Geometry as Geometry$1, Bounds, ClientFileValueMap, Color as Color$1, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords,
|
|
2
|
+
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, HeightReference, Matrix4, ColorBlendMode, ShadowMode, ClassificationType, Model, ShaderSource, Ellipsoid, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, PixelDatatype, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, ArcType, CornerType, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, DistanceDisplayCondition, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneMode, IntersectionTests, Ray, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, FeatureDetection, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileColorBlendMode, Cesium3DTileset, Intersect, OrthographicFrustum, EasingFunction, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, PolygonPipeline, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, CustomDataSource, ScreenSpaceEventHandler, ScreenSpaceEventType, GeometryInstance, Fullscreen, CzmlDataSource } from 'cesium';
|
|
3
|
+
import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, UrlUtils, Carto, Geometry as Geometry$1, Api, Bounds, ClientFileValueMap, Color as Color$1, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DataLab, DelayQueue, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, ProgramKey, ProjectViewLegacyTile, EntitySource, Camera, Account, AccountLimits, Session, ProjectViewBookmarkGroup, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType, EntityHistoricData } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -7688,6 +7688,8 @@ var EntityLabel;
|
|
|
7688
7688
|
this.modelBox = null;
|
|
7689
7689
|
this.boxMorph = { value: 0, from: 0, target: 0, start: 0, anchor: undefined, group: undefined,
|
|
7690
7690
|
shift: { x: 0, y: 0, start: 0 } };
|
|
7691
|
+
// A CAD part's record and its tileset, so the label stays on the part wherever the tileset is drawn now.
|
|
7692
|
+
this.tilesetPart = null;
|
|
7691
7693
|
// Counter to help differentiate between createLabel calls.
|
|
7692
7694
|
this.counter = 0;
|
|
7693
7695
|
// Whether this label has asked its group for a default image, which it does once on screen.
|
|
@@ -7997,6 +7999,9 @@ var EntityLabel;
|
|
|
7997
7999
|
return;
|
|
7998
8000
|
}
|
|
7999
8001
|
this._pos3d = pos3d;
|
|
8002
|
+
if (!this.prePositioned && visual instanceof Cesium3DTileFeature) {
|
|
8003
|
+
this.followTilesetPart(visual, counter);
|
|
8004
|
+
}
|
|
8000
8005
|
let text = "Unknown Entity";
|
|
8001
8006
|
const additionalTexts = this.additionalTexts ? this.additionalTexts : [];
|
|
8002
8007
|
if (this.rego) {
|
|
@@ -8458,13 +8463,12 @@ var EntityLabel;
|
|
|
8458
8463
|
// Past the wait a slow record no longer holds the label back; a box that comes later eases in.
|
|
8459
8464
|
setTimeout(settle, MODEL_BOX_WAIT);
|
|
8460
8465
|
this.modelBox.load.then(corners => {
|
|
8461
|
-
var _a, _b;
|
|
8462
8466
|
if (!corners || this.disposed || this.counter !== counter) {
|
|
8463
8467
|
return;
|
|
8464
8468
|
}
|
|
8465
8469
|
// A record that disagrees with where the model was found describes another placement, such as a moved tileset.
|
|
8466
8470
|
// A part known to have moved from its record, eg. a joint turning, is judged where it has moved to.
|
|
8467
|
-
const motion =
|
|
8471
|
+
const motion = this.motionAt(this.viewer.clock.currentTime);
|
|
8468
8472
|
const centre = Cartesian3.midpoint(corners[0], corners[7], new Cartesian3());
|
|
8469
8473
|
if (motion) {
|
|
8470
8474
|
Matrix4.multiplyByPoint(motion, centre, centre);
|
|
@@ -8476,7 +8480,8 @@ var EntityLabel;
|
|
|
8476
8480
|
// Let go a little further out than it is taken, so a camera resting at the limit does not flip it.
|
|
8477
8481
|
let near = false;
|
|
8478
8482
|
layer.modelBoxes.Set(this.id, corners, rego.entityId, {
|
|
8479
|
-
|
|
8483
|
+
// Asked each frame, since a CAD part's tileset may only be known once its record is read.
|
|
8484
|
+
motion: () => this.motionAt(this.viewer.clock.currentTime),
|
|
8480
8485
|
selected: () => { var _a, _b; return Boolean((_b = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.GetState({ entityId: rego.entityId, menuItemId: rego.menuItemId })) === null || _b === void 0 ? void 0 : _b.selected); },
|
|
8481
8486
|
hovered: () => { var _a, _b; return Boolean((_b = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.IsLabelHovered) === null || _b === void 0 ? void 0 : _b.call(_a, rego.entityId, rego.menuItemId)); },
|
|
8482
8487
|
near: () => {
|
|
@@ -8510,6 +8515,12 @@ var EntityLabel;
|
|
|
8510
8515
|
desiredHeightRef: HeightReference.NONE, heightRef, pos3d: position, viewer: this.viewer
|
|
8511
8516
|
});
|
|
8512
8517
|
}
|
|
8518
|
+
// A CAD part sits where its tileset is drawn this frame.
|
|
8519
|
+
else if (!this.prePositioned && this.tilesetPart) {
|
|
8520
|
+
const { tileset, entity } = this.tilesetPart;
|
|
8521
|
+
const rootFrame = EntityUtils.GetTilesetRootFrame(tileset);
|
|
8522
|
+
this._pos3d = (rootFrame && EntityUtils.GetAssemblyPartPos3d({ viewer: this.viewer, entity, rootFrame })) || this._pos3d;
|
|
8523
|
+
}
|
|
8513
8524
|
if (!Number.isFinite((_b = this._pos3d) === null || _b === void 0 ? void 0 : _b.x)) {
|
|
8514
8525
|
return null;
|
|
8515
8526
|
}
|
|
@@ -9243,6 +9254,43 @@ var EntityLabel;
|
|
|
9243
9254
|
};
|
|
9244
9255
|
step();
|
|
9245
9256
|
}
|
|
9257
|
+
/*
|
|
9258
|
+
* Keeps a label on a CAD Assembly part where its tileset is drawn, which a record cannot know as it moves.
|
|
9259
|
+
*/
|
|
9260
|
+
async followTilesetPart(feature, counter) {
|
|
9261
|
+
var _a, _b, _c;
|
|
9262
|
+
const known = (_c = (_b = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.GetLabelGroupFor(this.rego.entityId, this.rego.menuItemId)) === null || _b === void 0 ? void 0 : _b.item) === null || _c === void 0 ? void 0 : _c.entity;
|
|
9263
|
+
let entity = EntityUtils.IsAssemblyPart(known) ? known : null;
|
|
9264
|
+
if (!entity && this.api) {
|
|
9265
|
+
try {
|
|
9266
|
+
entity = (await Entity$1.Get({ api: this.api, entityId: this.rego.entityId, expandLocation: true, migrated: true })).entity;
|
|
9267
|
+
}
|
|
9268
|
+
// Expanding location fails for entities outside an assembly, which keep the position already found.
|
|
9269
|
+
catch {
|
|
9270
|
+
return;
|
|
9271
|
+
}
|
|
9272
|
+
}
|
|
9273
|
+
const record = EntityUtils.GetAssemblyRecordFrame(entity);
|
|
9274
|
+
if (!record || this.disposed || this.counter !== counter || !feature.tileset) {
|
|
9275
|
+
return;
|
|
9276
|
+
}
|
|
9277
|
+
this.tilesetPart = { tileset: feature.tileset, entity, record };
|
|
9278
|
+
this.viewer.scene.requestRender();
|
|
9279
|
+
}
|
|
9280
|
+
/*
|
|
9281
|
+
* Rigid motion from where the record places this Entity to where it is drawn, see IVisualRego.motion.
|
|
9282
|
+
* A CAD part has none of its own, so it moves with its tileset.
|
|
9283
|
+
*/
|
|
9284
|
+
motionAt(time) {
|
|
9285
|
+
var _a, _b;
|
|
9286
|
+
const own = (_b = (_a = this.rego) === null || _a === void 0 ? void 0 : _a.motion) === null || _b === void 0 ? void 0 : _b.call(_a, time);
|
|
9287
|
+
if (own || !this.tilesetPart) {
|
|
9288
|
+
return own !== null && own !== void 0 ? own : null;
|
|
9289
|
+
}
|
|
9290
|
+
const drawn = EntityUtils.GetTilesetRootFrame(this.tilesetPart.tileset);
|
|
9291
|
+
const inverse = Matrix4.inverseTransformation(this.tilesetPart.record, new Matrix4());
|
|
9292
|
+
return drawn ? Matrix4.multiply(drawn, inverse, inverse) : null;
|
|
9293
|
+
}
|
|
9246
9294
|
/*
|
|
9247
9295
|
* Reads the record's geometry box, preferring an entity a label group already hydrated.
|
|
9248
9296
|
*/
|
|
@@ -9416,21 +9464,17 @@ var EntityLabelGroup;
|
|
|
9416
9464
|
(function (EntityLabelGroup) {
|
|
9417
9465
|
/*
|
|
9418
9466
|
* Keeps the query response useful even when the Entity has no loaded visual yet.
|
|
9467
|
+
* An Assembly part is placed from its record when shown (Manager.RefreshEntity); Location is its fallback.
|
|
9419
9468
|
*/
|
|
9420
9469
|
function FromEntity(entity) {
|
|
9421
|
-
var _a, _b, _c
|
|
9470
|
+
var _a, _b, _c;
|
|
9422
9471
|
const location = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.Location;
|
|
9423
|
-
const pivot = (_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.GeometryWorldPivot;
|
|
9424
|
-
let cartographic;
|
|
9425
|
-
if ((pivot === null || pivot === void 0 ? void 0 : pivot.length) >= 3 && pivot.every(Number.isFinite)) {
|
|
9426
|
-
cartographic = Cartographic.fromCartesian(Cartesian3.fromArray(pivot));
|
|
9427
|
-
}
|
|
9428
9472
|
return {
|
|
9429
|
-
entityId: (
|
|
9430
|
-
text: (
|
|
9431
|
-
longitude:
|
|
9432
|
-
latitude:
|
|
9433
|
-
altitude:
|
|
9473
|
+
entityId: (_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.ID,
|
|
9474
|
+
text: (_c = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _c === void 0 ? void 0 : _c.Name,
|
|
9475
|
+
longitude: location === null || location === void 0 ? void 0 : location.longitude,
|
|
9476
|
+
latitude: location === null || location === void 0 ? void 0 : location.latitude,
|
|
9477
|
+
altitude: location === null || location === void 0 ? void 0 : location.altitude,
|
|
9434
9478
|
entity
|
|
9435
9479
|
};
|
|
9436
9480
|
}
|
|
@@ -9543,7 +9587,8 @@ var EntityLabelGroup;
|
|
|
9543
9587
|
const response = await DataLab.Run({ api, query, skip: offset, load: limit, migrated: true, req: { noCache: true, abortSignal: signal } });
|
|
9544
9588
|
const entities = response.entities || response.items || [];
|
|
9545
9589
|
return {
|
|
9546
|
-
|
|
9590
|
+
// A simulated stand-in or patch wins over what the query read, as it does for hand-picked groups.
|
|
9591
|
+
items: entities.map(entity => { var _a, _b; return FromEntity((_b = simulation === null || simulation === void 0 ? void 0 : simulation.Resolve((_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID, entity)) !== null && _b !== void 0 ? _b : entity); }),
|
|
9547
9592
|
hasMore: response.totalCount != null ? offset + entities.length < response.totalCount : entities.length === limit
|
|
9548
9593
|
};
|
|
9549
9594
|
};
|
|
@@ -9896,7 +9941,7 @@ var EntityLabelGroup;
|
|
|
9896
9941
|
}
|
|
9897
9942
|
}
|
|
9898
9943
|
RefreshEntity(entityId) {
|
|
9899
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
9944
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
9900
9945
|
const match = this.Resolve(entityId);
|
|
9901
9946
|
const registered = this.register.GetRego({ entityId });
|
|
9902
9947
|
if (!registered && match && this.standalone.has(entityId) && this.standaloneItems.get(entityId) === match.item) {
|
|
@@ -9913,19 +9958,22 @@ var EntityLabelGroup;
|
|
|
9913
9958
|
return;
|
|
9914
9959
|
}
|
|
9915
9960
|
const item = match.item;
|
|
9916
|
-
|
|
9961
|
+
const position = (_d = this.assemblyPosition(item.entity)) !== null && _d !== void 0 ? _d : ([item.longitude, item.latitude, (_e = item.altitude) !== null && _e !== void 0 ? _e : 0].every(Number.isFinite) && Math.abs(item.latitude) <= 90
|
|
9962
|
+
? Cartesian3.fromDegrees(item.longitude, item.latitude, item.altitude || 0)
|
|
9963
|
+
: null);
|
|
9964
|
+
if (!position) {
|
|
9917
9965
|
return;
|
|
9918
9966
|
}
|
|
9919
9967
|
const visual = new Entity({
|
|
9920
|
-
position:
|
|
9968
|
+
position: position,
|
|
9921
9969
|
point: { heightReference: HeightReference.NONE, pixelSize: 0 }
|
|
9922
9970
|
});
|
|
9923
9971
|
this.standalone.set(entityId, new EntityLabel.Label({
|
|
9924
9972
|
viewer: this.register.Viewer,
|
|
9925
9973
|
visualRegister: this.register,
|
|
9926
|
-
api: (
|
|
9974
|
+
api: (_f = this.register.ApiGetters) === null || _f === void 0 ? void 0 : _f.GetBruceApi(),
|
|
9927
9975
|
rego: { entityId, visual, name: item.text || entityId, priority: 0 },
|
|
9928
|
-
options: { ...match.options, text: (
|
|
9976
|
+
options: { ...match.options, text: (_h = (_g = match.options.text) !== null && _g !== void 0 ? _g : item.text) !== null && _h !== void 0 ? _h : entityId },
|
|
9929
9977
|
groupId: match.groupId,
|
|
9930
9978
|
visible: () => {
|
|
9931
9979
|
const state = this.register.GetState({ entityId });
|
|
@@ -9934,6 +9982,41 @@ var EntityLabelGroup;
|
|
|
9934
9982
|
}));
|
|
9935
9983
|
this.standaloneItems.set(entityId, item);
|
|
9936
9984
|
}
|
|
9985
|
+
/*
|
|
9986
|
+
* Places an undrawn Assembly part where its Assembly is now: model-space, history and simulation included.
|
|
9987
|
+
* Returns null for anything else, which keeps its record's Location.
|
|
9988
|
+
*/
|
|
9989
|
+
assemblyPosition(entity) {
|
|
9990
|
+
const viewer = this.register.Viewer;
|
|
9991
|
+
if (!EntityUtils.GetAssemblyPartPos3d({ viewer, entity })) {
|
|
9992
|
+
return null;
|
|
9993
|
+
}
|
|
9994
|
+
let last = null;
|
|
9995
|
+
return new CallbackProperty((time) => {
|
|
9996
|
+
var _a, _b, _c;
|
|
9997
|
+
const at = JulianDate.toDate(time !== null && time !== void 0 ? time : viewer.clock.currentTime).getTime();
|
|
9998
|
+
const simulated = (_b = (_a = EntitySimulation.Get(viewer)) === null || _a === void 0 ? void 0 : _a.ApplyAt(entity, at)) !== null && _b !== void 0 ? _b : entity;
|
|
9999
|
+
last = (_c = EntityUtils.GetAssemblyPartPos3d({ viewer, entity: simulated, rootFrame: this.drawnFrame(entity) })) !== null && _c !== void 0 ? _c : last;
|
|
10000
|
+
return last;
|
|
10001
|
+
}, false);
|
|
10002
|
+
}
|
|
10003
|
+
/*
|
|
10004
|
+
* The frame of a CAD tileset drawn at this Assembly's root, which moves with its history and simulation.
|
|
10005
|
+
*/
|
|
10006
|
+
drawnFrame(entity) {
|
|
10007
|
+
var _a, _b;
|
|
10008
|
+
const root = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.AssemblyRootLocation;
|
|
10009
|
+
for (const { tileset } of this.register.GetTilesets()) {
|
|
10010
|
+
const at = (_b = tileset._bruceCoords) === null || _b === void 0 ? void 0 : _b.location;
|
|
10011
|
+
if (at && root &&
|
|
10012
|
+
Math.abs(+at.latitude - +root.latitude) < 1e-7 &&
|
|
10013
|
+
Math.abs(+at.longitude - +root.longitude) < 1e-7 &&
|
|
10014
|
+
Math.abs((+at.altitude || 0) - (+root.altitude || 0)) < 0.01) {
|
|
10015
|
+
return EntityUtils.GetTilesetRootFrame(tileset);
|
|
10016
|
+
}
|
|
10017
|
+
}
|
|
10018
|
+
return null;
|
|
10019
|
+
}
|
|
9937
10020
|
Remove(id) {
|
|
9938
10021
|
var _a;
|
|
9939
10022
|
const known = this.definitions.delete(id);
|
|
@@ -23523,7 +23606,9 @@ var TilesetCadRenderManager;
|
|
|
23523
23606
|
ucs: coords === null || coords === void 0 ? void 0 : coords.ucs,
|
|
23524
23607
|
location: (coords === null || coords === void 0 ? void 0 : coords.location) == null ? settings.location : coords.location,
|
|
23525
23608
|
transform: (coords === null || coords === void 0 ? void 0 : coords.transform) == null ? settings.transform : coords.transform
|
|
23526
|
-
}
|
|
23609
|
+
},
|
|
23610
|
+
// Placed as first drawn, or a model-space tileset jumps to its site on a history or simulation update.
|
|
23611
|
+
modelSpace: this.modelSpace
|
|
23527
23612
|
});
|
|
23528
23613
|
this.viewer.scene.requestRender();
|
|
23529
23614
|
}
|
|
@@ -38270,7 +38355,7 @@ var ViewRenderEngine;
|
|
|
38270
38355
|
if (!bookmark) {
|
|
38271
38356
|
let bookmarkId = params.bookmarkId;
|
|
38272
38357
|
if (!bookmarkId) {
|
|
38273
|
-
bookmarkId = view.
|
|
38358
|
+
bookmarkId = view["Default.UISlide.ID"];
|
|
38274
38359
|
}
|
|
38275
38360
|
bookmark = bookmarkId ? (await ProjectViewBookmark.Get({
|
|
38276
38361
|
api,
|
|
@@ -38331,7 +38416,7 @@ var ViewRenderEngine;
|
|
|
38331
38416
|
if (!bookmark) {
|
|
38332
38417
|
let bookmarkId = params.bookmarkId;
|
|
38333
38418
|
if (!bookmarkId) {
|
|
38334
|
-
bookmarkId = view.
|
|
38419
|
+
bookmarkId = view["Default.UISlide.ID"];
|
|
38335
38420
|
}
|
|
38336
38421
|
bookmark = bookmarkId ? (await ProjectViewBookmark.Get({
|
|
38337
38422
|
api,
|
|
@@ -44112,37 +44197,46 @@ class WidgetNavCompass$$1 extends Widget.AWidget {
|
|
|
44112
44197
|
|
|
44113
44198
|
const CESIUM_VIEWER_MANAGER_KEY = "_cesiumViewerManager";
|
|
44114
44199
|
const CESIUM_VIEWER_EVENT_TRACKER_KEY = "_cesiumViewerEventTracker";
|
|
44115
|
-
/**
|
|
44116
|
-
* Bug related to entities not being visible after they were added then a render was requested.
|
|
44117
|
-
* It was 4 point entities in York. They would not appear until a request render was recalled.
|
|
44118
|
-
* Adding this slow render loop as a band-aid fix.
|
|
44119
|
-
*/
|
|
44120
44200
|
const BACKGROUND_RENDERING_KEY = "_backgroundRendering";
|
|
44201
|
+
// How long after the scene last drew it is drawn once more.
|
|
44202
|
+
const FOLLOW_UP_RENDER_MS = 3000;
|
|
44203
|
+
/*
|
|
44204
|
+
* Draws once more a few seconds after the scene last drew, for graphics not ready by the render that asked for them.
|
|
44205
|
+
*/
|
|
44121
44206
|
function backgroundRendering(viewer) {
|
|
44122
44207
|
if (viewer[BACKGROUND_RENDERING_KEY]) {
|
|
44123
44208
|
return;
|
|
44124
44209
|
}
|
|
44125
44210
|
viewer[BACKGROUND_RENDERING_KEY] = true;
|
|
44211
|
+
// Wall time, since scene.lastRenderTime is the scene clock's and stands still while the clock is paused.
|
|
44212
|
+
let lastRenderAt = performance.now();
|
|
44213
|
+
// Whether the last render was the follow up, so a still scene is drawn once more rather than forever.
|
|
44214
|
+
let followedUp = false;
|
|
44215
|
+
let requested = false;
|
|
44216
|
+
const removeListener = viewer.scene.postRender.addEventListener(() => {
|
|
44217
|
+
lastRenderAt = performance.now();
|
|
44218
|
+
followedUp = requested;
|
|
44219
|
+
requested = false;
|
|
44220
|
+
});
|
|
44126
44221
|
const interval = setInterval(() => {
|
|
44127
44222
|
var _a;
|
|
44128
44223
|
if (!(viewer === null || viewer === void 0 ? void 0 : viewer.cesiumWidget) || !(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
|
|
44129
44224
|
clearInterval(interval);
|
|
44225
|
+
removeListener();
|
|
44130
44226
|
return;
|
|
44131
44227
|
}
|
|
44132
44228
|
// We'll ignore the call if the viewer container is not visible.
|
|
44133
44229
|
if (!viewer.container || ((_a = viewer.container.style) === null || _a === void 0 ? void 0 : _a.display) == "none") {
|
|
44134
44230
|
return;
|
|
44135
44231
|
}
|
|
44232
|
+
if (followedUp || requested || performance.now() - lastRenderAt < FOLLOW_UP_RENDER_MS) {
|
|
44233
|
+
return;
|
|
44234
|
+
}
|
|
44136
44235
|
try {
|
|
44137
|
-
//
|
|
44138
|
-
|
|
44139
|
-
|
|
44140
|
-
|
|
44141
|
-
// Check if window is active/in focus.
|
|
44142
|
-
// TODO: Should render the moment it is in focus as well.
|
|
44143
|
-
if (document.hasFocus()) {
|
|
44144
|
-
viewer.scene.requestRender();
|
|
44145
|
-
}
|
|
44236
|
+
// Only while the window has focus. TODO: should render the moment it regains focus as well.
|
|
44237
|
+
if (document.hasFocus()) {
|
|
44238
|
+
requested = true;
|
|
44239
|
+
viewer.scene.requestRender();
|
|
44146
44240
|
}
|
|
44147
44241
|
}
|
|
44148
44242
|
catch (e) {
|
|
@@ -44543,6 +44637,47 @@ function calcEntityLocation(entity, modelSpace) {
|
|
|
44543
44637
|
}
|
|
44544
44638
|
return Matrix4.multiplyByPoint(enuFrame, new Cartesian3(tx, ty, tz), new Cartesian3());
|
|
44545
44639
|
}
|
|
44640
|
+
/*
|
|
44641
|
+
* Reads a row-major 4x4 from a record, or null when it is missing or malformed.
|
|
44642
|
+
*/
|
|
44643
|
+
function matrixFromRows(rows) {
|
|
44644
|
+
if (!Array.isArray(rows) || rows.length !== 4) {
|
|
44645
|
+
return null;
|
|
44646
|
+
}
|
|
44647
|
+
const values = [].concat(...rows).map(Number);
|
|
44648
|
+
return values.length === 16 && values.every(Number.isFinite) ? Matrix4.fromRowMajorArray(values) : null;
|
|
44649
|
+
}
|
|
44650
|
+
/*
|
|
44651
|
+
* An Assembly part's geometry centre in its root's frame, via its parent so a simulated AssemblyPosition counts.
|
|
44652
|
+
*/
|
|
44653
|
+
function calcAssemblyPartOffset(entity) {
|
|
44654
|
+
const bruce = entity === null || entity === void 0 ? void 0 : entity.Bruce;
|
|
44655
|
+
const pivot = Array.isArray(bruce === null || bruce === void 0 ? void 0 : bruce.GeometryPivot) && bruce.GeometryPivot.length >= 3 ? bruce.GeometryPivot.slice(0, 3).map(Number) : null;
|
|
44656
|
+
const parent = matrixFromRows(bruce === null || bruce === void 0 ? void 0 : bruce.AssemblyParentWorldPosition);
|
|
44657
|
+
const local = matrixFromRows(bruce === null || bruce === void 0 ? void 0 : bruce.AssemblyPosition);
|
|
44658
|
+
const world = parent && local ? Matrix4.multiply(parent, local, new Matrix4()) : matrixFromRows(bruce === null || bruce === void 0 ? void 0 : bruce.AssemblyWorldPosition);
|
|
44659
|
+
if (world && (!pivot || pivot.every(Number.isFinite))) {
|
|
44660
|
+
return Matrix4.multiplyByPoint(world, pivot ? Cartesian3.fromArray(pivot) : Cartesian3.ZERO, new Cartesian3());
|
|
44661
|
+
}
|
|
44662
|
+
const worldPivot = Array.isArray(bruce === null || bruce === void 0 ? void 0 : bruce.GeometryWorldPivot) ? bruce.GeometryWorldPivot.slice(0, 3).map(Number) : [];
|
|
44663
|
+
return worldPivot.length === 3 && worldPivot.every(Number.isFinite) ? Cartesian3.fromArray(worldPivot) : null;
|
|
44664
|
+
}
|
|
44665
|
+
/*
|
|
44666
|
+
* The frame a part's record places it in, as the API's Location: the root (0,0 in model-space), then its transform.
|
|
44667
|
+
*/
|
|
44668
|
+
function calcAssemblyRootFrame(entity, modelSpace) {
|
|
44669
|
+
var _a, _b, _c;
|
|
44670
|
+
const root = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.AssemblyRootLocation;
|
|
44671
|
+
if (!root && !modelSpace) {
|
|
44672
|
+
return null;
|
|
44673
|
+
}
|
|
44674
|
+
const origin = modelSpace ? Cartesian3.fromDegrees(0, 0, 0) : Cartesian3.fromDegrees(EnsureNumber(root.longitude), EnsureNumber(root.latitude), EnsureNumber(root.altitude));
|
|
44675
|
+
const transform = (_c = (_b = entity.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyWorldTransform) !== null && _c !== void 0 ? _c : {};
|
|
44676
|
+
const frame = Transforms.eastNorthUpToFixedFrame(origin);
|
|
44677
|
+
Matrix4.multiply(frame, Matrix4.fromTranslation(new Cartesian3(EnsureNumber(transform.x), EnsureNumber(transform.y), EnsureNumber(transform.z))), frame);
|
|
44678
|
+
const hpr = HeadingPitchRoll.fromDegrees(EnsureNumber(transform.heading), EnsureNumber(transform.pitch), EnsureNumber(transform.roll));
|
|
44679
|
+
return Matrix4.multiply(frame, Matrix4.fromRotation(Matrix3.fromHeadingPitchRoll(hpr)), frame);
|
|
44680
|
+
}
|
|
44546
44681
|
// Records created within about this long ago are the ones the oversized GeometryRadius bug could have written.
|
|
44547
44682
|
const GEOMETRY_RADIUS_SUSPECT_AGE_MS = 1000 * 60 * 60 * 24 * 183;
|
|
44548
44683
|
// Above this a recent record's radius is treated as that bug rather than a real size.
|
|
@@ -44588,6 +44723,61 @@ function getModelBoundsCenter(viewer, part, pos3d, bounds) {
|
|
|
44588
44723
|
const _assemblyAxisShift = new Quaternion(0, 0, -Math.SQRT1_2, Math.SQRT1_2);
|
|
44589
44724
|
var EntityUtils;
|
|
44590
44725
|
(function (EntityUtils) {
|
|
44726
|
+
/**
|
|
44727
|
+
* Returns where an Assembly part's geometry centre is, without asking the API or the scene.
|
|
44728
|
+
* Bruce.Location only holds where the API last placed it, so this composes from the root's frame instead.
|
|
44729
|
+
* @param params.rootFrame the frame its Assembly is drawn in now, eg. GetTilesetRootFrame of its CAD tileset.
|
|
44730
|
+
* Default: the frame its record describes, at 0,0 in model-space.
|
|
44731
|
+
* @returns null when the record is not an Assembly part or lacks its matrices.
|
|
44732
|
+
*/
|
|
44733
|
+
function GetAssemblyPartPos3d(params) {
|
|
44734
|
+
var _a;
|
|
44735
|
+
const { viewer, entity } = params;
|
|
44736
|
+
if (!IsAssemblyPart(entity)) {
|
|
44737
|
+
return null;
|
|
44738
|
+
}
|
|
44739
|
+
const offset = calcAssemblyPartOffset(entity);
|
|
44740
|
+
const frame = (_a = params.rootFrame) !== null && _a !== void 0 ? _a : calcAssemblyRootFrame(entity, ViewUtils.GetModelSpace(viewer));
|
|
44741
|
+
return offset && frame ? Matrix4.multiplyByPoint(frame, offset, new Cartesian3()) : null;
|
|
44742
|
+
}
|
|
44743
|
+
EntityUtils.GetAssemblyPartPos3d = GetAssemblyPartPos3d;
|
|
44744
|
+
/**
|
|
44745
|
+
* Returns the geospatial frame a part's record assumes for its root, the one the API works Location out in.
|
|
44746
|
+
* Comparing it with where the Assembly is drawn gives how far the drawing has moved from the record.
|
|
44747
|
+
* @param entity
|
|
44748
|
+
*/
|
|
44749
|
+
function GetAssemblyRecordFrame(entity) {
|
|
44750
|
+
return IsAssemblyPart(entity) ? calcAssemblyRootFrame(entity, false) : null;
|
|
44751
|
+
}
|
|
44752
|
+
EntityUtils.GetAssemblyRecordFrame = GetAssemblyRecordFrame;
|
|
44753
|
+
/**
|
|
44754
|
+
* Returns whether a record is an Assembly part, ie. placed through its root rather than its own Location.
|
|
44755
|
+
* @param entity
|
|
44756
|
+
*/
|
|
44757
|
+
function IsAssemblyPart(entity) {
|
|
44758
|
+
const bruce = entity === null || entity === void 0 ? void 0 : entity.Bruce;
|
|
44759
|
+
return ((bruce === null || bruce === void 0 ? void 0 : bruce.AssemblyRootLocation) != null &&
|
|
44760
|
+
(bruce.AssemblyWorldPosition != null || bruce.AssemblyPosition != null || bruce.GeometryWorldPivot != null));
|
|
44761
|
+
}
|
|
44762
|
+
EntityUtils.IsAssemblyPart = IsAssemblyPart;
|
|
44763
|
+
/**
|
|
44764
|
+
* Returns the frame a tileset is drawn in now, without its scale, so Assembly offsets in metres apply to it.
|
|
44765
|
+
* It follows whatever moved the tileset: history, a simulated root, or model-space.
|
|
44766
|
+
* @param tileset
|
|
44767
|
+
*/
|
|
44768
|
+
function GetTilesetRootFrame(tileset) {
|
|
44769
|
+
var _a, _b;
|
|
44770
|
+
const transform = (_a = tileset === null || tileset === void 0 ? void 0 : tileset.root) === null || _a === void 0 ? void 0 : _a.transform;
|
|
44771
|
+
if (!transform || ((_b = tileset.isDestroyed) === null || _b === void 0 ? void 0 : _b.call(tileset))) {
|
|
44772
|
+
return null;
|
|
44773
|
+
}
|
|
44774
|
+
const scale = Matrix4.getScale(transform, new Cartesian3());
|
|
44775
|
+
if (!(scale.x > 0)) {
|
|
44776
|
+
return null;
|
|
44777
|
+
}
|
|
44778
|
+
return Matrix4.multiplyByUniformScale(transform, 1 / scale.x, new Matrix4());
|
|
44779
|
+
}
|
|
44780
|
+
EntityUtils.GetTilesetRootFrame = GetTilesetRootFrame;
|
|
44591
44781
|
/**
|
|
44592
44782
|
* Returns the location for given entity or entities.
|
|
44593
44783
|
* If available it will also compute a rectangle.
|
|
@@ -46450,6 +46640,418 @@ function OneTimeError(key, message) {
|
|
|
46450
46640
|
}
|
|
46451
46641
|
}
|
|
46452
46642
|
|
|
46643
|
+
/**
|
|
46644
|
+
* Draws the orientation effect a point style can ask for, an open ring whose pointer shows which way the Entity faces.
|
|
46645
|
+
*/
|
|
46646
|
+
var EntityRenderEnginePointOrientation;
|
|
46647
|
+
(function (EntityRenderEnginePointOrientation) {
|
|
46648
|
+
// Compared as the wire string, since an older bruce-models in the host has no EPointEffectType at runtime.
|
|
46649
|
+
EntityRenderEnginePointOrientation.ORIENTATION_EFFECT = "ORIENTATION";
|
|
46650
|
+
// Clearance between the glyph and the ring, and the smallest ring, matching entity-label.ts's icon ring.
|
|
46651
|
+
EntityRenderEnginePointOrientation.RING_PADDING = 4;
|
|
46652
|
+
EntityRenderEnginePointOrientation.RING_MIN = 10;
|
|
46653
|
+
const RING_STROKE = 2;
|
|
46654
|
+
const RING_CSS = "rgba(255, 255, 255, 0.8)";
|
|
46655
|
+
const RING_GLOW_CSS = "rgba(0, 0, 0, 0.3)";
|
|
46656
|
+
const RING_GLOW_BLUR = 5;
|
|
46657
|
+
// The pointer reaches TIP_BASE + TIP_GROWTH * sqrt(radius) px past the ring, so it grows slower than the ring.
|
|
46658
|
+
const TIP_BASE = 3;
|
|
46659
|
+
const TIP_GROWTH = 2.2;
|
|
46660
|
+
// Share of the circle kept around the heading. Label rings keep 0.35, but the pointer uses most of it.
|
|
46661
|
+
const ARC_FRACTION = 0.5;
|
|
46662
|
+
// The arc always runs at least this far past where the pointer leaves it, so it still reads as a ring.
|
|
46663
|
+
const ARC_TAIL = Math.PI / 30;
|
|
46664
|
+
const ARC_STEPS = 12;
|
|
46665
|
+
// Copies of the cap outline nested toward its centre, enough for 2 px strokes to read as a fill.
|
|
46666
|
+
const CAP_FILL_LOOPS = 4;
|
|
46667
|
+
// Canvas oversampling so the stroke stays crisp on high density screens.
|
|
46668
|
+
const RING_DPR = 2;
|
|
46669
|
+
const _ringCache = new LRUCache(50);
|
|
46670
|
+
/*
|
|
46671
|
+
* Whether a point style asks for the orientation effect.
|
|
46672
|
+
*/
|
|
46673
|
+
function IsEnabled(style) {
|
|
46674
|
+
var _a;
|
|
46675
|
+
return ((_a = style === null || style === void 0 ? void 0 : style.effect) === null || _a === void 0 ? void 0 : _a.type) === EntityRenderEnginePointOrientation.ORIENTATION_EFFECT;
|
|
46676
|
+
}
|
|
46677
|
+
EntityRenderEnginePointOrientation.IsEnabled = IsEnabled;
|
|
46678
|
+
/*
|
|
46679
|
+
* The Entity's orientation from Bruce.Transform, or null when it has no usable heading to show.
|
|
46680
|
+
*/
|
|
46681
|
+
function GetOrientation(entity) {
|
|
46682
|
+
var _a;
|
|
46683
|
+
const transform = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.Transform;
|
|
46684
|
+
const raw = transform === null || transform === void 0 ? void 0 : transform.heading;
|
|
46685
|
+
if (raw == null ||
|
|
46686
|
+
(typeof raw == "string" && !raw.trim())) {
|
|
46687
|
+
return null;
|
|
46688
|
+
}
|
|
46689
|
+
const heading = Number(raw);
|
|
46690
|
+
if (!isFinite(heading)) {
|
|
46691
|
+
return null;
|
|
46692
|
+
}
|
|
46693
|
+
const pitch = Number(transform.pitch);
|
|
46694
|
+
const roll = Number(transform.roll);
|
|
46695
|
+
return {
|
|
46696
|
+
heading,
|
|
46697
|
+
pitch: isFinite(pitch) ? pitch : 0,
|
|
46698
|
+
roll: isFinite(roll) ? roll : 0
|
|
46699
|
+
};
|
|
46700
|
+
}
|
|
46701
|
+
EntityRenderEnginePointOrientation.GetOrientation = GetOrientation;
|
|
46702
|
+
/*
|
|
46703
|
+
* Ring radius in px for a glyph of the given radius.
|
|
46704
|
+
*/
|
|
46705
|
+
function GetRingRadius(glyphRadius) {
|
|
46706
|
+
const radius = Number(glyphRadius);
|
|
46707
|
+
return Math.max(EntityRenderEnginePointOrientation.RING_MIN, (isFinite(radius) ? radius : 0) + EntityRenderEnginePointOrientation.RING_PADDING);
|
|
46708
|
+
}
|
|
46709
|
+
EntityRenderEnginePointOrientation.GetRingRadius = GetRingRadius;
|
|
46710
|
+
/*
|
|
46711
|
+
* How far the pointer's tip sits from the centre, as a multiple of the ring radius.
|
|
46712
|
+
*/
|
|
46713
|
+
function GetTipRatio(ringRadius) {
|
|
46714
|
+
return 1 + (TIP_BASE + TIP_GROWTH * Math.sqrt(ringRadius)) / ringRadius;
|
|
46715
|
+
}
|
|
46716
|
+
EntityRenderEnginePointOrientation.GetTipRatio = GetTipRatio;
|
|
46717
|
+
/*
|
|
46718
|
+
* The open ring in a unit frame, u forward and v right: arc tail, tangent to the tip, tangent back, arc tail.
|
|
46719
|
+
* The pointer's sides are tangents to the circle, so the arc runs into the tip with no visible joint.
|
|
46720
|
+
*/
|
|
46721
|
+
function GetOutline(tipRatio) {
|
|
46722
|
+
const touch = Math.acos(1 / tipRatio);
|
|
46723
|
+
const half = Math.max(Math.PI * ARC_FRACTION, touch + ARC_TAIL);
|
|
46724
|
+
const points = [];
|
|
46725
|
+
for (let i = 0; i <= ARC_STEPS; i++) {
|
|
46726
|
+
const phi = -half + (half - touch) * i / ARC_STEPS;
|
|
46727
|
+
points.push([Math.cos(phi), Math.sin(phi)]);
|
|
46728
|
+
}
|
|
46729
|
+
points.push([tipRatio, 0]);
|
|
46730
|
+
for (let i = 0; i <= ARC_STEPS; i++) {
|
|
46731
|
+
const phi = touch + (half - touch) * i / ARC_STEPS;
|
|
46732
|
+
points.push([Math.cos(phi), Math.sin(phi)]);
|
|
46733
|
+
}
|
|
46734
|
+
return points;
|
|
46735
|
+
}
|
|
46736
|
+
EntityRenderEnginePointOrientation.GetOutline = GetOutline;
|
|
46737
|
+
/*
|
|
46738
|
+
* The filled cap between the pointer's sides and the circle, in the same unit frame as GetOutline.
|
|
46739
|
+
*/
|
|
46740
|
+
function GetCap(tipRatio) {
|
|
46741
|
+
const touch = Math.acos(1 / tipRatio);
|
|
46742
|
+
const points = [[tipRatio, 0]];
|
|
46743
|
+
for (let i = 0; i <= ARC_STEPS; i++) {
|
|
46744
|
+
const phi = touch - 2 * touch * i / ARC_STEPS;
|
|
46745
|
+
points.push([Math.cos(phi), Math.sin(phi)]);
|
|
46746
|
+
}
|
|
46747
|
+
return points;
|
|
46748
|
+
}
|
|
46749
|
+
EntityRenderEnginePointOrientation.GetCap = GetCap;
|
|
46750
|
+
/*
|
|
46751
|
+
* The outline as one path with its cap filled by nested copies of the cap's outline, for a polyline that cannot fill.
|
|
46752
|
+
* Back and forth strokes would need sharp reversals, which Cesium mitres into spikes; nested loops only turn at the
|
|
46753
|
+
* cap's own corners. Like GetOutline it starts and ends on the arc tails.
|
|
46754
|
+
*/
|
|
46755
|
+
function GetFilledOutline(tipRatio) {
|
|
46756
|
+
const outline = GetOutline(tipRatio);
|
|
46757
|
+
const tipIndex = outline.findIndex(([u, v]) => u === tipRatio && v === 0);
|
|
46758
|
+
const cap = GetCap(tipRatio);
|
|
46759
|
+
const cu = cap.reduce((sum, [u]) => sum + u, 0) / cap.length;
|
|
46760
|
+
const cv = cap.reduce((sum, [, v]) => sum + v, 0) / cap.length;
|
|
46761
|
+
const loops = [];
|
|
46762
|
+
for (let i = 0; i < CAP_FILL_LOOPS; i++) {
|
|
46763
|
+
const k = 1 - i / CAP_FILL_LOOPS;
|
|
46764
|
+
for (const [u, v] of cap) {
|
|
46765
|
+
loops.push([cu + (u - cu) * k, cv + (v - cv) * k]);
|
|
46766
|
+
}
|
|
46767
|
+
}
|
|
46768
|
+
loops.push([tipRatio, 0]);
|
|
46769
|
+
return [...outline.slice(0, tipIndex + 1), ...loops, ...outline.slice(tipIndex + 1)];
|
|
46770
|
+
}
|
|
46771
|
+
EntityRenderEnginePointOrientation.GetFilledOutline = GetFilledOutline;
|
|
46772
|
+
/*
|
|
46773
|
+
* Draws the ring for a glyph as a billboard image pointing up, or null where there is no canvas to draw on.
|
|
46774
|
+
*/
|
|
46775
|
+
function CreateRingBillboard(glyphRadius) {
|
|
46776
|
+
var _a;
|
|
46777
|
+
const radius = GetRingRadius(glyphRadius);
|
|
46778
|
+
const key = radius.toFixed(1);
|
|
46779
|
+
const cached = _ringCache.Get(key);
|
|
46780
|
+
if (cached) {
|
|
46781
|
+
return cached;
|
|
46782
|
+
}
|
|
46783
|
+
const tipRatio = GetTipRatio(radius);
|
|
46784
|
+
const size = Math.ceil((radius * tipRatio + RING_STROKE + RING_GLOW_BLUR) * 2);
|
|
46785
|
+
const canvas = document.createElement("canvas");
|
|
46786
|
+
canvas.width = size * RING_DPR;
|
|
46787
|
+
canvas.height = size * RING_DPR;
|
|
46788
|
+
const context = (_a = canvas.getContext) === null || _a === void 0 ? void 0 : _a.call(canvas, "2d");
|
|
46789
|
+
if (!context) {
|
|
46790
|
+
return null;
|
|
46791
|
+
}
|
|
46792
|
+
context.scale(RING_DPR, RING_DPR);
|
|
46793
|
+
// Forward is up the image, right is to the right.
|
|
46794
|
+
const toCanvas = ([u, v]) => [size / 2 + v * radius, size / 2 - u * radius];
|
|
46795
|
+
const trace = (points, close) => {
|
|
46796
|
+
context.beginPath();
|
|
46797
|
+
points.map(toCanvas).forEach(([x, y], i) => i ? context.lineTo(x, y) : context.moveTo(x, y));
|
|
46798
|
+
if (close) {
|
|
46799
|
+
context.closePath();
|
|
46800
|
+
}
|
|
46801
|
+
};
|
|
46802
|
+
context.shadowColor = RING_GLOW_CSS;
|
|
46803
|
+
context.shadowBlur = RING_GLOW_BLUR;
|
|
46804
|
+
context.fillStyle = RING_CSS;
|
|
46805
|
+
trace(GetCap(tipRatio), true);
|
|
46806
|
+
context.fill();
|
|
46807
|
+
context.strokeStyle = RING_CSS;
|
|
46808
|
+
context.lineWidth = RING_STROKE;
|
|
46809
|
+
context.lineJoin = "round";
|
|
46810
|
+
context.lineCap = "round";
|
|
46811
|
+
trace(GetOutline(tipRatio), false);
|
|
46812
|
+
context.stroke();
|
|
46813
|
+
const ring = {
|
|
46814
|
+
canvasDataUri: canvas.toDataURL("image/png"),
|
|
46815
|
+
size
|
|
46816
|
+
};
|
|
46817
|
+
_ringCache.Set(key, ring);
|
|
46818
|
+
return ring;
|
|
46819
|
+
}
|
|
46820
|
+
EntityRenderEnginePointOrientation.CreateRingBillboard = CreateRingBillboard;
|
|
46821
|
+
/*
|
|
46822
|
+
* World space unit vector along the local horizon at a heading in degrees clockwise from north.
|
|
46823
|
+
*/
|
|
46824
|
+
function GetHeadingAxis(pos3d, heading) {
|
|
46825
|
+
const enu = Transforms.eastNorthUpToFixedFrame(pos3d);
|
|
46826
|
+
const rad = Math$1.toRadians(heading);
|
|
46827
|
+
const local = new Cartesian3(Math.sin(rad), Math.cos(rad), 0);
|
|
46828
|
+
const world = Matrix4.multiplyByPointAsVector(enu, local, new Cartesian3());
|
|
46829
|
+
return Cartesian3.normalize(world, world);
|
|
46830
|
+
}
|
|
46831
|
+
EntityRenderEnginePointOrientation.GetHeadingAxis = GetHeadingAxis;
|
|
46832
|
+
/*
|
|
46833
|
+
* World space forward and right unit vectors for a full orientation, which span the plane the 3D ring lies in.
|
|
46834
|
+
*/
|
|
46835
|
+
function GetBasis(pos3d, orientation) {
|
|
46836
|
+
const h = Math$1.toRadians(orientation.heading);
|
|
46837
|
+
const p = Math$1.toRadians(orientation.pitch);
|
|
46838
|
+
const r = Math$1.toRadians(orientation.roll);
|
|
46839
|
+
const forward = new Cartesian3(Math.sin(h) * Math.cos(p), Math.cos(h) * Math.cos(p), Math.sin(p));
|
|
46840
|
+
const level = new Cartesian3(Math.cos(h), -Math.sin(h), 0);
|
|
46841
|
+
const up = Cartesian3.cross(level, forward, new Cartesian3());
|
|
46842
|
+
// Positive roll lowers the right side.
|
|
46843
|
+
const right = Cartesian3.add(Cartesian3.multiplyByScalar(level, Math.cos(r), new Cartesian3()), Cartesian3.multiplyByScalar(up, -Math.sin(r), new Cartesian3()), new Cartesian3());
|
|
46844
|
+
const enu = Transforms.eastNorthUpToFixedFrame(pos3d);
|
|
46845
|
+
const toWorld = (local) => {
|
|
46846
|
+
const world = Matrix4.multiplyByPointAsVector(enu, local, new Cartesian3());
|
|
46847
|
+
return Cartesian3.normalize(world, world);
|
|
46848
|
+
};
|
|
46849
|
+
return { forward: toWorld(forward), right: toWorld(right) };
|
|
46850
|
+
}
|
|
46851
|
+
EntityRenderEnginePointOrientation.GetBasis = GetBasis;
|
|
46852
|
+
/*
|
|
46853
|
+
* Counter-clockwise billboard rotation that turns its up edge along a world direction as the camera sees it.
|
|
46854
|
+
* Cesium's alignedAxis squares its angle and drops perspective, up to 160 degrees out when side on.
|
|
46855
|
+
*/
|
|
46856
|
+
function GetScreenRotation(viewer, pos3d, axis) {
|
|
46857
|
+
const transforms = SceneTransforms;
|
|
46858
|
+
const project = transforms.wgs84ToWindowCoordinates || transforms.worldToWindowCoordinates;
|
|
46859
|
+
const camera = viewer.camera.positionWC || viewer.camera.position;
|
|
46860
|
+
// A step proportional to distance keeps the two projections a few pixels apart at any zoom.
|
|
46861
|
+
const step = Math.max(0.01, Cartesian3.distance(camera, pos3d) * 0.01);
|
|
46862
|
+
const ahead = Cartesian3.add(pos3d, Cartesian3.multiplyByScalar(axis, step, new Cartesian3()), new Cartesian3());
|
|
46863
|
+
const from = project(viewer.scene, pos3d, new Cartesian2());
|
|
46864
|
+
const to = project(viewer.scene, ahead, new Cartesian2());
|
|
46865
|
+
if (!from || !to) {
|
|
46866
|
+
return null;
|
|
46867
|
+
}
|
|
46868
|
+
const dx = to.x - from.x;
|
|
46869
|
+
const dy = to.y - from.y;
|
|
46870
|
+
if (Math.abs(dx) + Math.abs(dy) < 1e-6) {
|
|
46871
|
+
return null;
|
|
46872
|
+
}
|
|
46873
|
+
return Math.atan2(-dx, -dy);
|
|
46874
|
+
}
|
|
46875
|
+
EntityRenderEnginePointOrientation.GetScreenRotation = GetScreenRotation;
|
|
46876
|
+
/*
|
|
46877
|
+
* Metres one CSS pixel covers at a position, since billboard sizes and polyline widths are CSS pixels.
|
|
46878
|
+
*/
|
|
46879
|
+
function getMetresPerPixel(viewer, pos3d) {
|
|
46880
|
+
const scene = viewer.scene;
|
|
46881
|
+
const sphere = new BoundingSphere(pos3d, 0);
|
|
46882
|
+
const perBufferPixel = viewer.camera.getPixelSize(sphere, scene.drawingBufferWidth, scene.drawingBufferHeight);
|
|
46883
|
+
return perBufferPixel * (scene.pixelRatio || 1);
|
|
46884
|
+
}
|
|
46885
|
+
/*
|
|
46886
|
+
* Where the parent is drawn this frame, as an absolute position, or null while its ground is not known yet.
|
|
46887
|
+
*/
|
|
46888
|
+
function getDrawnPos3d(viewer, parent, heightRef) {
|
|
46889
|
+
const pos3d = GetCValue(viewer, parent.position);
|
|
46890
|
+
if (!pos3d) {
|
|
46891
|
+
return null;
|
|
46892
|
+
}
|
|
46893
|
+
return DrawingUtils.GetDrawnPos3d({
|
|
46894
|
+
viewer,
|
|
46895
|
+
heightRef,
|
|
46896
|
+
pos3d,
|
|
46897
|
+
terrainId: ViewUtils.GetTerrainCacheId(viewer)
|
|
46898
|
+
});
|
|
46899
|
+
}
|
|
46900
|
+
/*
|
|
46901
|
+
* Creates or updates the ring for a point, or returns null when it cannot be drawn.
|
|
46902
|
+
* Clamped to ground it shows only the heading as a billboard, otherwise the full 3D orientation.
|
|
46903
|
+
*/
|
|
46904
|
+
function Render(params) {
|
|
46905
|
+
const { viewer, parent, orientation, heightRef } = params;
|
|
46906
|
+
if (!viewer || !parent || !orientation) {
|
|
46907
|
+
return null;
|
|
46908
|
+
}
|
|
46909
|
+
const clamped = heightRef == HeightReference.CLAMP_TO_GROUND;
|
|
46910
|
+
const ring = clamped ? renderBillboard(params) : renderPolyline(params);
|
|
46911
|
+
if (ring) {
|
|
46912
|
+
ring._orientationRing = true;
|
|
46913
|
+
ring._noEdit = true;
|
|
46914
|
+
ring._parentEntity = parent;
|
|
46915
|
+
}
|
|
46916
|
+
return ring;
|
|
46917
|
+
}
|
|
46918
|
+
EntityRenderEnginePointOrientation.Render = Render;
|
|
46919
|
+
/*
|
|
46920
|
+
* The ring among a point's sibling graphics, if it has one.
|
|
46921
|
+
*/
|
|
46922
|
+
function FindRing(siblings) {
|
|
46923
|
+
return (siblings === null || siblings === void 0 ? void 0 : siblings.find(x => x === null || x === void 0 ? void 0 : x._orientationRing)) || null;
|
|
46924
|
+
}
|
|
46925
|
+
EntityRenderEnginePointOrientation.FindRing = FindRing;
|
|
46926
|
+
/*
|
|
46927
|
+
* The heading only ring, a billboard turned every frame to point along the ground.
|
|
46928
|
+
*/
|
|
46929
|
+
function renderBillboard(params) {
|
|
46930
|
+
var _a;
|
|
46931
|
+
const { viewer, parent, orientation, heightRef } = params;
|
|
46932
|
+
const image = CreateRingBillboard(params.glyphRadius);
|
|
46933
|
+
if (!image) {
|
|
46934
|
+
return null;
|
|
46935
|
+
}
|
|
46936
|
+
let rotation = 0;
|
|
46937
|
+
const rotationProp = new CallbackProperty(() => {
|
|
46938
|
+
const drawn = getDrawnPos3d(viewer, parent, heightRef);
|
|
46939
|
+
if (drawn) {
|
|
46940
|
+
const next = GetScreenRotation(viewer, drawn, GetHeadingAxis(drawn, orientation.heading));
|
|
46941
|
+
if (next != null) {
|
|
46942
|
+
rotation = next;
|
|
46943
|
+
}
|
|
46944
|
+
}
|
|
46945
|
+
return rotation;
|
|
46946
|
+
}, false);
|
|
46947
|
+
const position = new CallbackProperty(() => GetCValue(viewer, parent.position), false);
|
|
46948
|
+
const displayCondition = EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance);
|
|
46949
|
+
const pixelOffset = new Cartesian2(0, -(params.glyphOffsetY || 0));
|
|
46950
|
+
let ring = ((_a = params.existing) === null || _a === void 0 ? void 0 : _a.billboard) ? params.existing : null;
|
|
46951
|
+
if (!ring) {
|
|
46952
|
+
ring = new Entity({
|
|
46953
|
+
id: ObjectUtils.UId(15),
|
|
46954
|
+
billboard: {
|
|
46955
|
+
image: image.canvasDataUri,
|
|
46956
|
+
width: image.size,
|
|
46957
|
+
height: image.size,
|
|
46958
|
+
rotation: rotationProp,
|
|
46959
|
+
heightReference: heightRef,
|
|
46960
|
+
pixelOffset,
|
|
46961
|
+
distanceDisplayCondition: displayCondition
|
|
46962
|
+
},
|
|
46963
|
+
position,
|
|
46964
|
+
show: true
|
|
46965
|
+
});
|
|
46966
|
+
}
|
|
46967
|
+
else {
|
|
46968
|
+
ring.billboard.image = new ConstantProperty(image.canvasDataUri);
|
|
46969
|
+
ring.billboard.width = new ConstantProperty(image.size);
|
|
46970
|
+
ring.billboard.height = new ConstantProperty(image.size);
|
|
46971
|
+
ring.billboard.rotation = rotationProp;
|
|
46972
|
+
ring.billboard.heightReference = new ConstantProperty(heightRef);
|
|
46973
|
+
ring.billboard.pixelOffset = new ConstantProperty(pixelOffset);
|
|
46974
|
+
ring.billboard.distanceDisplayCondition = new ConstantProperty(displayCondition);
|
|
46975
|
+
ring.position = position;
|
|
46976
|
+
ring.show = true;
|
|
46977
|
+
}
|
|
46978
|
+
CesiumEntityStyler.BakeDefaultColor({
|
|
46979
|
+
entity: ring,
|
|
46980
|
+
viewer,
|
|
46981
|
+
colors: {
|
|
46982
|
+
"billboard": Color.WHITE
|
|
46983
|
+
},
|
|
46984
|
+
refresh: false
|
|
46985
|
+
});
|
|
46986
|
+
return ring;
|
|
46987
|
+
}
|
|
46988
|
+
/*
|
|
46989
|
+
* The full orientation ring, a polyline in the orientation's plane, resized each frame to hold its screen size.
|
|
46990
|
+
*/
|
|
46991
|
+
function renderPolyline(params) {
|
|
46992
|
+
var _a;
|
|
46993
|
+
const { viewer, parent, orientation, heightRef } = params;
|
|
46994
|
+
const radiusPx = GetRingRadius(params.glyphRadius);
|
|
46995
|
+
const outline = GetFilledOutline(GetTipRatio(radiusPx));
|
|
46996
|
+
const color = Color.fromCssColorString(RING_CSS);
|
|
46997
|
+
let last = [];
|
|
46998
|
+
let basisAt = null;
|
|
46999
|
+
let basis = null;
|
|
47000
|
+
const positions = new CallbackProperty(() => {
|
|
47001
|
+
const drawn = getDrawnPos3d(viewer, parent, heightRef);
|
|
47002
|
+
if (!drawn) {
|
|
47003
|
+
return last;
|
|
47004
|
+
}
|
|
47005
|
+
// The local frame only changes when the point moves.
|
|
47006
|
+
if (!basisAt || !Cartesian3.equals(basisAt, drawn)) {
|
|
47007
|
+
basis = GetBasis(drawn, orientation);
|
|
47008
|
+
basisAt = Cartesian3.clone(drawn);
|
|
47009
|
+
}
|
|
47010
|
+
const scale = radiusPx * getMetresPerPixel(viewer, drawn);
|
|
47011
|
+
if (!isFinite(scale) || scale <= 0) {
|
|
47012
|
+
return last;
|
|
47013
|
+
}
|
|
47014
|
+
last = outline.map(([u, v]) => {
|
|
47015
|
+
const point = Cartesian3.multiplyByScalar(basis.forward, u * scale, new Cartesian3());
|
|
47016
|
+
Cartesian3.add(point, Cartesian3.multiplyByScalar(basis.right, v * scale, new Cartesian3()), point);
|
|
47017
|
+
return Cartesian3.add(point, drawn, point);
|
|
47018
|
+
});
|
|
47019
|
+
return last;
|
|
47020
|
+
}, false);
|
|
47021
|
+
const displayCondition = EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance);
|
|
47022
|
+
let ring = ((_a = params.existing) === null || _a === void 0 ? void 0 : _a.polyline) ? params.existing : null;
|
|
47023
|
+
if (!ring) {
|
|
47024
|
+
ring = new Entity({
|
|
47025
|
+
id: ObjectUtils.UId(15),
|
|
47026
|
+
polyline: {
|
|
47027
|
+
positions,
|
|
47028
|
+
width: RING_STROKE,
|
|
47029
|
+
material: color,
|
|
47030
|
+
arcType: ArcType.NONE,
|
|
47031
|
+
// The positions are already absolute. Unset reads as clamped to the culler, which then grounds the ring.
|
|
47032
|
+
clampToGround: false,
|
|
47033
|
+
distanceDisplayCondition: displayCondition
|
|
47034
|
+
},
|
|
47035
|
+
position: new CallbackProperty(() => GetCValue(viewer, parent.position), false),
|
|
47036
|
+
show: true
|
|
47037
|
+
});
|
|
47038
|
+
}
|
|
47039
|
+
else {
|
|
47040
|
+
ring.polyline.positions = positions;
|
|
47041
|
+
ring.polyline.distanceDisplayCondition = new ConstantProperty(displayCondition);
|
|
47042
|
+
ring.show = true;
|
|
47043
|
+
}
|
|
47044
|
+
CesiumEntityStyler.SetDefaultColor({
|
|
47045
|
+
color,
|
|
47046
|
+
entity: ring,
|
|
47047
|
+
viewer,
|
|
47048
|
+
override: true,
|
|
47049
|
+
requestRender: false
|
|
47050
|
+
});
|
|
47051
|
+
return ring;
|
|
47052
|
+
}
|
|
47053
|
+
})(EntityRenderEnginePointOrientation || (EntityRenderEnginePointOrientation = {}));
|
|
47054
|
+
|
|
46453
47055
|
/**
|
|
46454
47056
|
* Handles point rendering.
|
|
46455
47057
|
*/
|
|
@@ -46491,14 +47093,21 @@ var EntityRenderEnginePoint;
|
|
|
46491
47093
|
let animatePosition = null;
|
|
46492
47094
|
let shouldShowTrack = false;
|
|
46493
47095
|
let trackStyle = null;
|
|
47096
|
+
// The drawn glyph's half size and how far its centre sits above the anchor, for sizing the orientation ring.
|
|
47097
|
+
let glyph = null;
|
|
47098
|
+
// The orientation ring a previous render left, which the effect decides to keep or remove at the end.
|
|
47099
|
+
let existingRing = null;
|
|
46494
47100
|
const prepareExistingGraphic = (cEntity, maxSiblings = 0) => {
|
|
46495
47101
|
// Gather entity in case previous version had sibling graphics we no longer need.
|
|
46496
47102
|
const parts = EntityUtils.GatherEntity({
|
|
46497
47103
|
entity: cEntity,
|
|
46498
47104
|
});
|
|
46499
47105
|
if (parts.length > 1) {
|
|
47106
|
+
// The ring is held apart so the sibling count below only ever trims the track.
|
|
47107
|
+
existingRing = EntityRenderEnginePointOrientation.FindRing(cEntity._siblingGraphics);
|
|
47108
|
+
const others = (cEntity._siblingGraphics || []).filter(x => x !== existingRing);
|
|
46500
47109
|
// We'll cull all except the allowed number of siblings.
|
|
46501
|
-
cEntity._siblingGraphics =
|
|
47110
|
+
cEntity._siblingGraphics = others.slice(0, maxSiblings).concat(existingRing ? [existingRing] : []);
|
|
46502
47111
|
// We'll remove all that aren't in the allowed (direct) list.
|
|
46503
47112
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
46504
47113
|
const part = parts[i];
|
|
@@ -46510,7 +47119,7 @@ var EntityRenderEnginePoint;
|
|
|
46510
47119
|
console.warn("Point.Render: Parent entity was not null. This should not happen.");
|
|
46511
47120
|
}
|
|
46512
47121
|
}
|
|
46513
|
-
siblings = cEntity._siblingGraphics;
|
|
47122
|
+
siblings = (cEntity._siblingGraphics || []).filter(x => x !== existingRing);
|
|
46514
47123
|
cEntity._siblingGraphics = [];
|
|
46515
47124
|
};
|
|
46516
47125
|
const updateShouldShowTrack = () => {
|
|
@@ -46763,6 +47372,11 @@ var EntityRenderEnginePoint;
|
|
|
46763
47372
|
}
|
|
46764
47373
|
cEntity.billboard._billboardSize = image.height;
|
|
46765
47374
|
cEntity.billboard._billboardImgKey = imageKey;
|
|
47375
|
+
// Icons hang from their bottom edge, so the glyph's centre sits half its height up.
|
|
47376
|
+
glyph = {
|
|
47377
|
+
radius: Math.max(image.width || image.height, image.height) * iconScale / 2,
|
|
47378
|
+
offsetY: image.height * iconScale / 2
|
|
47379
|
+
};
|
|
46766
47380
|
}
|
|
46767
47381
|
}
|
|
46768
47382
|
}
|
|
@@ -47136,6 +47750,7 @@ var EntityRenderEnginePoint;
|
|
|
47136
47750
|
cEntity.billboard._billboardImgKey = imgKey;
|
|
47137
47751
|
}
|
|
47138
47752
|
cEntity.billboard._billboardSize = Math.ceil(circleBillboard.height / 2);
|
|
47753
|
+
glyph = { radius: size / 2, offsetY: 0 };
|
|
47139
47754
|
}
|
|
47140
47755
|
// Generate a polyline 'track' for the historic data.
|
|
47141
47756
|
// We do this for historic data that exists and is moving.
|
|
@@ -47185,6 +47800,31 @@ var EntityRenderEnginePoint;
|
|
|
47185
47800
|
}
|
|
47186
47801
|
trackEntity._parentEntity = cEntity;
|
|
47187
47802
|
}
|
|
47803
|
+
// Cylinders set no glyph, so a style switching to one drops its ring.
|
|
47804
|
+
const orientation = glyph && cEntity && EntityRenderEnginePointOrientation.IsEnabled(style)
|
|
47805
|
+
? EntityRenderEnginePointOrientation.GetOrientation(entity)
|
|
47806
|
+
: null;
|
|
47807
|
+
const ring = orientation ? EntityRenderEnginePointOrientation.Render({
|
|
47808
|
+
viewer: params.viewer,
|
|
47809
|
+
parent: cEntity,
|
|
47810
|
+
existing: existingRing,
|
|
47811
|
+
orientation,
|
|
47812
|
+
heightRef,
|
|
47813
|
+
glyphRadius: glyph.radius,
|
|
47814
|
+
glyphOffsetY: glyph.offsetY,
|
|
47815
|
+
minDistance: params.minDistance,
|
|
47816
|
+
maxDistance: params.maxDistance
|
|
47817
|
+
}) : null;
|
|
47818
|
+
if (existingRing && existingRing !== ring) {
|
|
47819
|
+
RemoveCEntityFromScene(params.viewer, existingRing);
|
|
47820
|
+
}
|
|
47821
|
+
if (ring) {
|
|
47822
|
+
siblings.push(ring);
|
|
47823
|
+
// A new graphic on an existing visual needs a full refresh to be added, as the track does.
|
|
47824
|
+
if (ring !== existingRing && params.rego) {
|
|
47825
|
+
params.rego.stale = true;
|
|
47826
|
+
}
|
|
47827
|
+
}
|
|
47188
47828
|
cEntity._siblingGraphics = siblings;
|
|
47189
47829
|
cEntity.styleEffective = StyleEffective.Combine(styleTraceParts);
|
|
47190
47830
|
return cEntity;
|
|
@@ -47319,7 +47959,8 @@ const createImageBillboard = (url) => {
|
|
|
47319
47959
|
canvas.getContext("2d").drawImage(image, 0, 0);
|
|
47320
47960
|
return {
|
|
47321
47961
|
canvasDataUri: canvas.toDataURL("image/png"),
|
|
47322
|
-
height: image.height
|
|
47962
|
+
height: image.height,
|
|
47963
|
+
width: image.width
|
|
47323
47964
|
};
|
|
47324
47965
|
});
|
|
47325
47966
|
_billboardCache$1.Set(cacheKey, prom);
|
|
@@ -55584,7 +56225,7 @@ var StyleUtils;
|
|
|
55584
56225
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
55585
56226
|
})(StyleUtils || (StyleUtils = {}));
|
|
55586
56227
|
|
|
55587
|
-
const VERSION = "7.6.
|
|
56228
|
+
const VERSION = "7.6.5";
|
|
55588
56229
|
/**
|
|
55589
56230
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
55590
56231
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|