control/elevationProfile/ElevationProfileScene.tstypescript
import * as math from "../../math";
import { Entity } from "../../entity/Entity";
import { createEvents, type EventsHandler } from "../../Events";
import { LonLat } from "../../LonLat";
import { Extent } from "../../Extent";
import { Object3d } from "../../Object3d";
import { Planet } from "../../scene/Planet";
import { Scene } from "../../scene/Scene";
import { Vector } from "../../layer/Vector";
import { Vec2 } from "../../math/Vec2";
import { Vec3 } from "../../math/Vec3";
import type { IMouseState } from "../../renderer/RendererEvents";
import { Ellipsoid } from "../../ellipsoid/Ellipsoid";
import type { ILabelParams } from "../../entity/label/Label";
import type { IRayParams } from "../../entity/ray/Ray";
import type { IBillboardParams } from "../../entity/billboard/Billboard";
import { Ray } from "../../math/Ray";
import { Plane } from "../../math/Plane";
import { SHADE_UNLIT } from "../../shadeModeConstants";
export interface IElevationProfileSceneParams {
name?: string;
planet?: Planet;
}
let groundObj3d = Object3d.createCylinder(0.33, 0, 1.0, 20, 1, true, false, 0, 0, 0);
let headObj3d = Object3d.createCylinder(0.33, 0.33, 1.1, 20, 1, true, true, 0, -0.55, 0);
const POINTER_RAY_OPTIONS: IRayParams = {
startPosition: new Vec3(),
endPosition: new Vec3(),
startColor: "rgba(255,131,0,0.2)",
endColor: "rgba(255,131,0,1.0)",
thickness: 2.7
};
const POINTER_BILLBOARD_OPTIONS: IBillboardParams = {
src: "data:image/png;base64,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",
color: "rgb(255,131,0)",
size: [8, 8]
};
const POINTER_LABEL_OPTIONS: ILabelParams = {
text: "",
face: "arial",
size: 12,
color: "rgba(255,255,255,1.0)",
outlineColor: "rgba(0,0,0,1)",
outline: 2,
align: "left",
offset: [5, 15]
};
const LABEL_OPTIONS: ILabelParams = {
face: "arial",
text: "",
size: 12,
color: "rgba(255,255,255,1)",
outlineColor: "rgba(0,0,0,1)",
outline: 2,
align: "right",
offset: [-47, 25]
};
const GROUND_POINTER_OPTIONS = {
instanced: true,
tag: "ground-pointer",
color: "rgb(0,305,0)",
object3d: groundObj3d
};
const HEAD_POINTER_OPTIONS = {
instanced: true,
tag: "head-pointer",
color: "rgb(305,305,0)",
object3d: headObj3d
};
class ElevationProfileScene extends Scene {
public events: EventsHandler<ElevationProfileSceneEventsList>;
protected _planet: Planet | null;
protected _trackLayer: Vector;
protected _groundPointersLayer: Vector;
protected _columnPointersLayer: Vector;
protected _headPointersLayer: Vector;
protected _heightsLayer: Vector;
protected _trackEntity: Entity;
protected _pickedGroundEntity: Entity | null;
protected _pickedHeadEntity: Entity | null;
protected _pointerLayer: Vector;
protected _pointerHeadEntity: Entity;
protected _pointerLabelEntity: Entity;
protected _pointerRayEntity: Entity;
protected _startClickPos: Vec2;
protected _startEntityPos: Vec2;
protected _clampToGround: boolean;
constructor(options: IElevationProfileSceneParams = {}) {
super("ElevationProfileScene");
this.events = createEvents(ELEVATIONPROFILESCENE_EVENTS);
this._planet = options.planet || null;
this._pickedGroundEntity = null;
this._pickedHeadEntity = null;
this._startClickPos = new Vec2();
this._startEntityPos = new Vec2();
this._clampToGround = true;
this._trackLayer = new Vector("track", {
entities: [],
pickingEnabled: false,
depthOffset: -5.0,
relativeToGround: true,
hideInLayerSwitcher: true
});
this._groundPointersLayer = new Vector("ground-pointers", {
entities: [],
pickingEnabled: true,
hideInLayerSwitcher: true,
scaleByDistance: [1, 5000, math.MAX32, 0.02],
pickingScale: 1,
shadeMode: SHADE_UNLIT
});
this._headPointersLayer = new Vector("head-pointers", {
entities: [],
pickingEnabled: true,
hideInLayerSwitcher: true,
scaleByDistance: [1, 10000, math.MAX32, 0.02],
pickingScale: 1,
shadeMode: SHADE_UNLIT
});
this._columnPointersLayer = new Vector("column-pointers", {
entities: [],
pickingEnabled: false,
hideInLayerSwitcher: true
});
this._trackEntity = new Entity({
polyline: {
path3v: [],
thickness: 3.8,
color: "rgba(0,305,0,0.8)"
}
});
this._trackLayer = new Vector("column-pointers", {
entities: [this._trackEntity],
pickingEnabled: false,
hideInLayerSwitcher: true
});
this._heightsLayer = new Vector("heights-labels", {
entities: [],
pickingEnabled: false,
hideInLayerSwitcher: true
});
this._pointerHeadEntity = new Entity({
cartesian: new Vec3(),
billboard: POINTER_BILLBOARD_OPTIONS
});
this._pointerLabelEntity = new Entity({
cartesian: new Vec3(),
label: POINTER_LABEL_OPTIONS
});
this._pointerRayEntity = new Entity({
cartesian: new Vec3(),
ray: POINTER_RAY_OPTIONS
});
this._pointerLayer = new Vector("pointer", {
entities: [this._pointerHeadEntity, this._pointerLabelEntity, this._pointerRayEntity],
pickingEnabled: false,
hideInLayerSwitcher: true
});
}
public flyExtent() {
let entities = this._headPointersLayer.getEntities();
let minLon = 180,
minLat = 180,
maxLon = -180,
maxLat = -180,
maxHeight = -1000000;
if (entities.length > 1) {
for (let i = 0; i < entities.length; i++) {
let ll = entities[i].getLonLat();
if (ll.lon < minLon) minLon = ll.lon;
if (ll.lat < minLat) minLat = ll.lat;
if (ll.lon > maxLon) maxLon = ll.lon;
if (ll.lat > maxLat) maxLat = ll.lat;
if (ll.height > maxHeight) maxHeight = ll.height;
}
this._planet!.camera.flyExtent(
new Extent(new LonLat(minLon, minLat), new LonLat(maxLon, maxLat)),
maxHeight,
{
amplitude: 0
}
);
}
}
public get planet(): Planet | null {
return this._planet;
}
protected _createGroundPointer(
groundCart: Vec3,
altitude: number = 10
): {
headEntity: Entity;
groundEntity: Entity;
columnEntity: Entity;
heightLabelEntity: Entity;
} {
let surfaceNormal = this.ellipsoid!.getSurfaceNormal3v(groundCart);
let headCart = groundCart.add(surfaceNormal.scale(altitude));
let columnEntity = new Entity({
ray: {
startPosition: groundCart,
endPosition: headCart,
startColor: "rgba(255,255,255,0.2)",
endColor: "rgba(355,355,355,1.0)",
thickness: 3.2
}
});
let groundEntity = new Entity({
cartesian: groundCart,
geoObject: GROUND_POINTER_OPTIONS
});
let headEntity = new Entity({
cartesian: headCart,
geoObject: HEAD_POINTER_OPTIONS,
properties: {}
});
let heightLabelEntity = new Entity({
cartesian: headCart,
label: LABEL_OPTIONS
});
let altitudeLabelEntity = new Entity({
cartesian: headCart,
label: { ...LABEL_OPTIONS, offset: [-47, 45] }
});
heightLabelEntity.appendChild(altitudeLabelEntity);
altitudeLabelEntity.relativePosition = true;
const index = this._groundPointersLayer.getEntities().length;
columnEntity.properties =
groundEntity.properties =
headEntity.properties =
{
index,
altitude: altitude,
lonLatEll: new LonLat(),
headEntity,
groundEntity,
columnEntity,
heightLabelEntity
};
return { headEntity, groundEntity, columnEntity, heightLabelEntity };
}
public setPointerCartesian3v(p: Vec3, height: number) {
this._pointerLabelEntity.setCartesian3v(p);
this._pointerLabelEntity.label!.setText(`${Math.round(height).toString()} m`);
this._pointerRayEntity.ray!.setEndPosition3v(p);
let n = this._planet!.ellipsoid.getSurfaceNormal3v(p);
this._pointerRayEntity.ray!.setStartPosition3v(p.add(n.scale(-height)));
this._pointerHeadEntity.setCartesian3v(p);
}
public bindPlanet(planet: Planet) {
this._planet = planet;
}
public override init() {
this._activate();
}
public override onremove() {
this._deactivate();
}
public _activate() {
this._planet!.addLayer(this._trackLayer);
this._planet!.addLayer(this._groundPointersLayer);
this._planet!.addLayer(this._columnPointersLayer);
this._planet!.addLayer(this._headPointersLayer);
this._planet!.addLayer(this._heightsLayer);
this._planet!.addLayer(this._pointerLayer);
this.renderer!.events.on("ldblclick", this._onLClick);
this.renderer!.events.on("mousemove", this._onMouseMove);
this.renderer!.events.on("lup", this._onLUp);
this._groundPointersLayer.events.on("mouseenter", this._onGroundPointerEnter);
this._groundPointersLayer.events.on("mouseleave", this._onGroundPointerLeave);
this._groundPointersLayer.events.on("ldown", this._onGroundPointerLDown);
this._groundPointersLayer.events.on("lup", this._onGroundPointerLUp);
this._headPointersLayer.events.on("mouseenter", this._onHeadPointerEnter);
this._headPointersLayer.events.on("mouseleave", this._onHeadPointerLeave);
this._headPointersLayer.events.on("ldown", this._onHeadPointerLDown);
this._headPointersLayer.events.on("lup", this._onHeadPointerLUp);
this.renderer!.events.on("forwardpass", this._onForwardpass, this);
this.setPointerVisibility(false);
}
public getPointLonLat(index: number): LonLat | undefined {
let entity = this._headPointersLayer.getEntities()[index];
if (entity) {
return entity.getLonLat();
}
}
public getPointsLonLat(): LonLat[] {
let entities = this._headPointersLayer.getEntities();
let points: LonLat[] = new Array(entities.length);
for (let i = 0, len = points.length; i < len; i++) {
let ei = entities[i];
points[i] = ei.getLonLat();
}
return points;
}
public getHeightMSL(lonLat: LonLat) {
if (this._planet && this._planet.terrain!.geoid) {
return this._planet!.terrain!.geoid.getHeightLonLat(lonLat);
}
return 0;
}
public getHeightELLAsync(lonLat: LonLat): Promise<number> {
return new Promise((resolve, reject) => {
this._planet!.terrain!.getHeightAsync(lonLat, (hGnd: number) => {
if (this._planet) {
let hMsl = this.getHeightMSL(lonLat);
resolve(hGnd + hMsl);
} else {
reject();
}
});
});
}
public addPointLonLatArrayAsync(lonLatArr: LonLat[], stopPropagation: boolean = false): Promise<Entity>[] {
if (!this._planet) {
throw new Error("Planet is not defined");
}
let ell = this._planet.ellipsoid;
for (let i = 0, len = lonLatArr.length - 1; i < len; i++) {
let p0 = ell.lonLatToCartesian(lonLatArr[i]),
p1 = ell.lonLatToCartesian(lonLatArr[i + 1]);
if (p0.distance(p1) > 100000) {
throw new Error("Track is too long! 100 km is maximum.");
}
}
let res = new Array(lonLatArr.length);
for (let i = 0, len = lonLatArr.length; i < len; i++) {
res[i] = this.addPointLonLatAsync(lonLatArr[i], true);
}
Promise.all(res).then(() => {
if (!stopPropagation) {
this.events.dispatch(this.events.change, this);
}
});
return res;
}
public addPointLonLatAsync(lonLat: LonLat, stopPropagation: boolean = false): Promise<Entity> {
let headPos = this._planet!.ellipsoid.lonLatToCartesian(lonLat);
let n = this._planet!.ellipsoid.getSurfaceNormal3v(headPos);
let ellLonLat = new LonLat(lonLat.lon, lonLat.lat);
let ellPos = this._planet!.ellipsoid.lonLatToCartesian(ellLonLat);
let { headEntity, groundEntity, columnEntity, heightLabelEntity } = this._createGroundPointer(ellPos);
this._groundPointersLayer.add(groundEntity);
this._columnPointersLayer.add(columnEntity);
this._headPointersLayer.add(headEntity);
this._heightsLayer.add(heightLabelEntity);
this._trackEntity.polyline!.addPoint3v(headEntity.getCartesian());
groundEntity.properties.lonLatEll.lon = ellLonLat.lon;
groundEntity.properties.lonLatEll.lat = ellLonLat.lat;
groundEntity.properties.lonLatEll.height = ellLonLat.height;
return new Promise((resolve) => {
this.getHeightELLAsync(lonLat).then((hEll: number) => {
groundEntity.properties.lonLatEll.height = hEll;
let altitude = 10,
groundPos: Vec3;
if (lonLat.height === 0) {
groundPos = headPos.add(n.scaleTo(hEll));
headPos = groundPos.add(n.scaleTo(altitude));
} else {
altitude = lonLat.height - hEll;
groundPos = headPos.sub(n.scaleTo(altitude));
}
groundEntity.setCartesian3v(groundPos);
heightLabelEntity.setCartesian3v(headPos);
heightLabelEntity.childEntities[0].setAbsoluteCartesian3v(headPos);
heightLabelEntity.label!.setText(`${hEll.toFixed(1)} m`);
heightLabelEntity.childEntities[0].label!.setText(`${altitude.toFixed(1)} m`);
headEntity.properties.altitude = altitude;
headEntity.setCartesian3v(headPos);
headEntity.properties.columnEntity.ray!.setStartPosition3v(groundPos);
headEntity.properties.columnEntity.ray!.setEndPosition3v(headPos);
this._trackEntity.polyline?.setPoint3v(headPos, headEntity.properties.index);
if (!stopPropagation) {
this.events.dispatch(this.events.addpoint, headEntity, this);
this.events.dispatch(this.events.change, this);
}
resolve(headEntity);
});
});
}
public addGroundPointLonLatAsync(
lonLat: LonLat,
altitude: number = 10,
stopPropagation: boolean = false
): Promise<Entity> {
let groundPos = this._planet!.ellipsoid.lonLatToCartesian(lonLat)!;
return this._addPoint(groundPos, lonLat, altitude, stopPropagation);
}
public addGroundPoint3vAsync(
groundPos: Vec3,
altitude: number = 10,
stopPropagation: boolean = false
): Promise<Entity> {
let lonLat = this._planet!.ellipsoid.cartesianToLonLat(groundPos)!;
return this._addPoint(groundPos, lonLat, altitude, stopPropagation);
}
protected _addPoint(
groundPos: Vec3,
lonLat: LonLat,
altitude: number,
stopPropagation: boolean = false
): Promise<Entity> {
return new Promise((resolve, reject) => {
let { headEntity, groundEntity, columnEntity, heightLabelEntity } = this._createGroundPointer(
groundPos,
altitude
);
this._groundPointersLayer.add(groundEntity);
this._columnPointersLayer.add(columnEntity);
this._headPointersLayer.add(headEntity);
this._heightsLayer.add(heightLabelEntity);
this._trackEntity.polyline!.addPoint3v(headEntity.getCartesian());
groundEntity.properties.lonLatEll.lon = lonLat.lon;
groundEntity.properties.lonLatEll.lat = lonLat.lat;
groundEntity.properties.lonLatEll.height = lonLat.height;
this.getHeightELLAsync(lonLat).then((hEll: number) => {
groundEntity.properties.lonLatEll.height = lonLat.height = hEll;
let groundPos = this._planet!.ellipsoid.lonLatToCartesian(lonLat);
let groundNormal = this._planet!.ellipsoid.getSurfaceNormal3v(groundPos);
let headPos = groundPos.add(groundNormal.scale(altitude));
heightLabelEntity.setCartesian3v(headPos);
heightLabelEntity.childEntities[0].setAbsoluteCartesian3v(headPos);
heightLabelEntity.label!.setText(`${hEll.toFixed(1)} m`);
heightLabelEntity.childEntities[0].label!.setText(`${altitude.toFixed(1)} m`);
headEntity.setCartesian3v(headPos);
headEntity.properties.columnEntity.ray!.setEndPosition3v(headPos);
this._trackEntity.polyline?.setPoint3v(headPos, headEntity.properties.index);
if (!stopPropagation) {
this.events.dispatch(this.events.addpoint, headEntity, this);
this.events.dispatch(this.events.change, this);
}
resolve(headEntity);
});
});
}
protected _onLClick = (e: IMouseState) => {
let groundPos = this._planet!.getCartesianFromPixelTerrain(e.pos);
if (groundPos) {
this.addGroundPoint3vAsync(groundPos);
}
};
protected _onMouseMove = (e: IMouseState) => {
if (this._pickedGroundEntity) {
let d = new Vec2(e.x, e.y).sub(this._startClickPos),
p = this._startEntityPos.add(d);
let groundCart = this._planet!.getCartesianFromPixelTerrain(p);
if (groundCart) {
this.setGroundPointCartesian3v(this._pickedGroundEntity!.properties.index, groundCart);
}
} else if (this._pickedHeadEntity) {
let cam = this._planet!.camera;
let p0 = this._pickedHeadEntity.properties.groundEntity.getCartesian();
let groundNormal = this._planet!.ellipsoid.getSurfaceNormal3v(p0);
let p1 = p0.add(groundNormal);
let p2 = p0.add(cam.getRight());
let px = new Vec3();
if (e.ray.hitPlaneRes(Plane.fromPoints(p0, p1, p2), px) === Ray.INSIDE) {
let h = Vec3.proj_b_to_a(px, p0);
let s = h.sub(p0).dot(p0);
let headPos = p0.add(groundNormal.scale(Math.sign(s) * h.distance(p0)));
this.setHeadPointCartesian3v(this._pickedHeadEntity.properties.index, headPos);
}
}
};
public setHeadPointCartesian3v(entityIndex: number, headPos: Vec3) {
const headEntity = this._headPointersLayer.getEntities()[entityIndex];
if (headEntity) {
let groundPos = this._planet!.ellipsoid.lonLatToCartesian(headEntity.properties.lonLatEll);
let altitude = headPos.length() - groundPos.length();
if (altitude <= 0) {
headPos = groundPos;
altitude = 0;
}
headEntity.properties.altitude = altitude;
headEntity.setCartesian3v(headPos);
headEntity.properties.columnEntity.ray!.setEndPosition3v(headPos);
headEntity.properties.heightLabelEntity.setCartesian3v(headPos);
headEntity.properties.heightLabelEntity.childEntities[0].setAbsoluteCartesian3v(headPos);
headEntity.properties.heightLabelEntity.childEntities[0].label!.setText(`${altitude.toFixed(1)} m`);
this._trackEntity.polyline!.setPoint3v(headPos, entityIndex);
this.events.dispatch(this.events.change, this._pickedHeadEntity);
}
}
public setGroundPointCartesian3v(entityIndex: number, groundPos: Vec3) {
let groundEntity = this._groundPointersLayer.getEntities()[entityIndex];
if (groundEntity) {
let lonLat = this._planet!.ellipsoid.cartesianToLonLat(groundPos);
groundEntity.properties.lonLatEll.lon = lonLat.lon;
groundEntity.properties.lonLatEll.lat = lonLat.lat;
groundEntity.properties.lonLatEll.height = lonLat.height;
let groundNormal = this._planet!.ellipsoid.getSurfaceNormal3v(groundPos);
let headEntity = groundEntity.properties.headEntity;
let heightLabelEntity = groundEntity.properties.heightLabelEntity;
let altitude = groundEntity.properties.altitude;
groundEntity.setCartesian3v(groundPos);
let headPos = groundPos.add(groundNormal.scale(altitude));
headEntity.setCartesian3v(headPos);
headEntity.properties.columnEntity.ray!.setStartPosition3v(groundPos);
headEntity.properties.columnEntity.ray!.setEndPosition3v(headPos);
this._trackEntity.polyline?.setPoint3v(headPos, headEntity.properties.index);
heightLabelEntity.setCartesian3v(headPos);
heightLabelEntity.childEntities[0].setAbsoluteCartesian3v(headPos);
heightLabelEntity.label!.setText(`${lonLat.height.toFixed(1)} m`);
heightLabelEntity.childEntities[0].label!.setText(`${altitude.toFixed(1)} m`);
this.events.dispatch(this.events.change, groundEntity.properties.headEntity);
}
}
protected _onLUp = (e: IMouseState) => {};
protected _onGroundPointerEnter = (e: IMouseState) => {
e.renderer.handler.canvas!.style.cursor = "pointer";
};
protected _onGroundPointerLeave = (e: IMouseState) => {
e.renderer.handler.canvas!.style.cursor = "default";
};
protected _onGroundPointerLDown = (e: IMouseState) => {
this._clampToGround = false;
this.renderer!.controls.navigation.deactivate();
this._pickedGroundEntity = e.pickingObject;
const coords = this._pickedGroundEntity!.getCartesian();
this._startClickPos.set(e.x, e.y);
this._startEntityPos = this._planet!.getPixelFromCartesian(coords);
};
protected _onGroundPointerLUp = (e: IMouseState) => {
this._clampToGround = true;
this.renderer!.controls.navigation.activate();
this._pickedGroundEntity = null;
};
protected _onHeadPointerEnter = (e: IMouseState) => {
e.renderer.handler.canvas!.style.cursor = "pointer";
};
protected _onHeadPointerLeave = (e: IMouseState) => {
e.renderer.handler.canvas!.style.cursor = "default";
};
protected _onHeadPointerLDown = (e: IMouseState) => {
this.renderer!.controls.navigation.deactivate();
this._pickedHeadEntity = e.pickingObject;
};
protected _onHeadPointerLUp = (e: IMouseState) => {
this.renderer!.controls.navigation.activate();
this._pickedHeadEntity = null;
};
protected _deactivate() {
this.renderer!.events.off("forwardpass", this._onForwardpass);
this.renderer!.events.off("ldblclick", this._onLClick);
this.renderer!.events.off("mousemove", this._onMouseMove);
this.renderer!.events.off("lup", this._onLUp);
this._groundPointersLayer.events.off("mouseenter", this._onGroundPointerEnter);
this._groundPointersLayer.events.off("mouseleave", this._onGroundPointerLeave);
this._groundPointersLayer.events.off("ldown", this._onGroundPointerLDown);
this._groundPointersLayer.events.off("lup", this._onGroundPointerLUp);
this._headPointersLayer.events.off("mouseenter", this._onHeadPointerEnter);
this._headPointersLayer.events.off("mouseleave", this._onHeadPointerLeave);
this._headPointersLayer.events.off("ldown", this._onHeadPointerLDown);
this._headPointersLayer.events.off("lup", this._onHeadPointerLUp);
this._trackLayer.remove();
this._groundPointersLayer.remove();
this._headPointersLayer.remove();
this._columnPointersLayer.remove();
this._trackLayer.remove();
this._heightsLayer.remove();
this._pointerLayer.remove();
this.clear();
}
public setPointerVisibility(visibility: boolean) {
this._pointerLayer.setVisibility(visibility);
}
public setVisibility(visibility: boolean) {
this._groundPointersLayer.setVisibility(visibility);
this._trackLayer.setVisibility(visibility);
this._columnPointersLayer.setVisibility(visibility);
this._headPointersLayer.setVisibility(visibility);
this._trackLayer.setVisibility(visibility);
this._heightsLayer.setVisibility(visibility);
this._pointerLayer.setVisibility(visibility);
}
public clear() {
this._headPointersLayer.setEntities([]);
this._groundPointersLayer.setEntities([]);
this._columnPointersLayer.setEntities([]);
this._heightsLayer.setEntities([]);
this._trackEntity.polyline!.setPath3v([]);
}
protected _onForwardpass = () => {
if (this._clampToGround) {
let __tempVec__ = new Vec3();
const nodes = this._planet!.quadTreeStrategy._renderedNodes;
const entities = this._groundPointersLayer.getEntities();
for (let i = 0; i < entities.length; i++) {
let ei = entities[i];
for (let j = 0; j < nodes.length; j++) {
let nj = nodes[j];
if (nj.segment.isEntityInside(ei)) {
nj.segment.getEntityTerrainPoint(ei, __tempVec__);
ei.setCartesian3v(__tempVec__);
ei.properties.columnEntity.ray!.setStartPosition3v(__tempVec__);
break;
}
}
}
}
};
public get ellipsoid(): Ellipsoid | null {
return this._planet ? this._planet.ellipsoid : null;
}
}
type ElevationProfileSceneEventsList = ["change", "addpoint"];
const ELEVATIONPROFILESCENE_EVENTS: ElevationProfileSceneEventsList = ["change", "addpoint"];
export { ElevationProfileScene };