@vcmap/core 5.0.0-rc.2 → 5.0.0-rc.3

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/index.d.ts CHANGED
@@ -3124,7 +3124,7 @@ export function sampleCesiumTerrain(terrainProvider: import("@vcmap/cesium").Ces
3124
3124
  * changes input coordinate Array in place, new height can also be accessed by coordinates[x][2]
3125
3125
  * @param [optSourceProjection] - if input is not WGS84
3126
3126
  */
3127
- export function getHeightFromTerrainProvider(terrainProvider: import("@vcmap/cesium").CesiumTerrainProvider, coordinates: import("ol/coordinate").Coordinate[], optSourceProjection?: Projection | import("ol/proj/Projection").default, result?: import("ol/coordinate").Coordinate[]): Promise<import("ol/coordinate").Coordinate[]>;
3127
+ export function getHeightFromTerrainProvider(terrainProvider: import("@vcmap/cesium").CesiumTerrainProvider, coordinates: import("ol/coordinate").Coordinate[], optSourceProjection?: Projection, result?: import("ol/coordinate").Coordinate[]): Promise<import("ol/coordinate").Coordinate[]>;
3128
3128
 
3129
3129
  /**
3130
3130
  * checks, whether a terrain tile is available at given position or not
@@ -5158,7 +5158,7 @@ export class Oblique extends BaseOLMap {
5158
5158
  switchThreshold: any;
5159
5159
  mapChangeEvent: any;
5160
5160
  readonly collection: ObliqueCollection;
5161
- readonly imageChanged: import("@vcmap/cesium").Event;
5161
+ readonly imageChanged: VcsEvent<ObliqueImage>;
5162
5162
  readonly currentImage: ObliqueImage | null;
5163
5163
  getExtentOfCurrentImage(): Extent;
5164
5164
  getCurrentImage(): ObliqueImage;
@@ -5365,9 +5365,14 @@ export interface ObliqueVersion {
5365
5365
  buildNumber: number;
5366
5366
  }
5367
5367
 
5368
- export interface ObliqueCollectionOptions {
5369
- name?: string | undefined;
5370
- dataSets: ObliqueDataSet[];
5368
+ export interface ObliqueDataSetOptions {
5369
+ url: string;
5370
+ projection?: ProjectionOptions;
5371
+ terrainProvider?: TerrainProviderOptions;
5372
+ }
5373
+
5374
+ export interface ObliqueCollectionOptions extends VcsObjectOptions {
5375
+ dataSets?: (ObliqueDataSet | ObliqueDataSetOptions)[];
5371
5376
  maxZoom?: number | undefined;
5372
5377
  minZoom?: number | undefined;
5373
5378
  scaleFactor?: number | undefined;
@@ -5376,16 +5381,13 @@ export interface ObliqueCollectionOptions {
5376
5381
 
5377
5382
  export class ObliqueCollection {
5378
5383
  constructor(options: ObliqueCollectionOptions);
5379
- /**
5380
- * The unique name of the collection
5381
- */
5382
- name: string;
5384
+ static getDefaultOptions(): ObliqueCollectionOptions;
5383
5385
  viewOptions: ObliqueViewOptions;
5384
5386
 
5385
5387
  /**
5386
5388
  * Event raised when images are loaded. Is passed an Array of ObliqueImages as its only argument.
5387
5389
  */
5388
- imagesLoaded: import("@vcmap/cesium").Event;
5390
+ imagesLoaded: VcsEvent<ObliqueImage[]>;
5389
5391
  readonly dataSets: ObliqueDataSet[];
5390
5392
  /**
5391
5393
  * Indicates, that this collection has been loaded
@@ -5476,6 +5478,20 @@ export class ObliqueCollection {
5476
5478
  * Destroys all data sets and all images and any image/tile features for this collection
5477
5479
  */
5478
5480
  destroy(): void;
5481
+ toJSON(): ObliqueCollectionOptions;
5482
+ }
5483
+
5484
+ /**
5485
+ */
5486
+ export interface ObliqueDataSetImagesLoaded {
5487
+ /**
5488
+ * the loaded images
5489
+ */
5490
+ images: ObliqueImage[];
5491
+ /**
5492
+ * an optional tile coordinate
5493
+ */
5494
+ tileCoordinate?: string;
5479
5495
  }
5480
5496
 
5481
5497
  /**
@@ -5490,16 +5506,14 @@ export const enum DataState {
5490
5506
  export function getStateFromStatesArray(states: DataState[]): DataState;
5491
5507
 
5492
5508
  export class ObliqueDataSet {
5493
- constructor(url: string, projection: import("ol/proj/Projection").default, terrainProvider?: import("@vcmap/cesium").CesiumTerrainProvider);
5509
+ constructor(url: string, projection: Projection | ProjectionOptions, terrainProviderOptions?: TerrainProviderOptions);
5494
5510
  url: string;
5495
5511
  baseUrl: string;
5496
- projection: import("ol/proj/Projection").default;
5497
- terrainProvider: import("@vcmap/cesium").CesiumTerrainProvider | undefined;
5512
+ projection: Projection;
5498
5513
  /**
5499
- * Event raised when images are loaded. Is passed an Array of ObliqueImages as the first argument and optionally
5500
- * a string representing the tile coordinate ("z/x/y"), if the images where loaded for a tile.
5514
+ * Event raised when images are loaded.
5501
5515
  */
5502
- imagesLoaded: import("@vcmap/cesium").Event;
5516
+ imagesLoaded: VcsEvent<ObliqueDataSetImagesLoaded>;
5503
5517
 
5504
5518
 
5505
5519
 
@@ -5513,6 +5527,7 @@ export class ObliqueDataSet {
5513
5527
  * reflect the state of loaded tiles.
5514
5528
  */
5515
5529
  readonly state: DataState;
5530
+ readonly terrainProvider: import("@vcmap/cesium").CesiumTerrainProvider | undefined;
5516
5531
  /**
5517
5532
  * Loads the data set.
5518
5533
  */
@@ -5546,6 +5561,7 @@ export class ObliqueDataSet {
5546
5561
  * Loads all the tiles for a given extent.
5547
5562
  */
5548
5563
  loadDataForExtent(extent: import("ol/extent").Extent): Promise<void>;
5564
+ toJSON(): ObliqueDataSetOptions;
5549
5565
  }
5550
5566
 
5551
5567
  export interface ObliqueImageOptions {
@@ -5558,7 +5574,7 @@ export interface ObliqueImageOptions {
5558
5574
  projectionCenter?: import("@vcmap/cesium").Cartesian3 | undefined;
5559
5575
  pToRealworld?: import("@vcmap/cesium").Matrix3 | undefined;
5560
5576
  pToImage?: import("@vcmap/cesium").Matrix4 | undefined;
5561
- projection?: import("ol/proj/Projection").default | undefined;
5577
+ projection?: Projection | undefined;
5562
5578
  terrainProvider?: import("@vcmap/cesium").CesiumTerrainProvider | undefined;
5563
5579
  }
5564
5580
 
@@ -5624,7 +5640,7 @@ export interface ObliqueImageMetaOptions {
5624
5640
  size: import("ol/size").Size;
5625
5641
  tileSize: import("ol/size").Size;
5626
5642
  tileResolution: number[];
5627
- projection: import("ol/proj/Projection").default;
5643
+ projection: Projection;
5628
5644
  url: string;
5629
5645
  terrainProvider: import("@vcmap/cesium").CesiumTerrainProvider;
5630
5646
  name: string;
@@ -5657,7 +5673,7 @@ export class ObliqueImageMeta {
5657
5673
  /**
5658
5674
  * The world projection of the images associated with this meta
5659
5675
  */
5660
- projection: import("ol/proj/Projection").default;
5676
+ projection: Projection;
5661
5677
  url: string;
5662
5678
  /**
5663
5679
  * An optional terrain provider
@@ -5692,7 +5708,7 @@ export class ObliqueProvider {
5692
5708
  /**
5693
5709
  * Event raised once a new image is set on the provider. Will be passed the new image as the only argument.
5694
5710
  */
5695
- imageChanged: import("@vcmap/cesium").Event;
5711
+ imageChanged: VcsEvent<ObliqueImage>;
5696
5712
  /**
5697
5713
  * Whether the post render handler should switch on image edge. Setting
5698
5714
  * this to false will suspend all post render handler switches.
@@ -5821,7 +5837,7 @@ export interface ImageTransformationOptions {
5821
5837
  /**
5822
5838
  * the projection of the input/output coordinates, assumes image source projection
5823
5839
  */
5824
- dataProjection?: import("ol/proj/Projection").default | undefined;
5840
+ dataProjection?: Projection | undefined;
5825
5841
  /**
5826
5842
  * the transformToWorld process iterativly calculates a new Height Value from the terrainProvider until the difference to the new height value is smaller
5827
5843
  */
@@ -5858,17 +5874,12 @@ export function transformFromImage(image: ObliqueImage, imageCoordinate: import(
5858
5874
 
5859
5875
  export function hasSameOrigin(url: string): boolean;
5860
5876
 
5861
- /**
5862
- * destroys a cesium Event Emitter, (removes all listeners)
5863
- */
5864
- export function destroyCesiumEvent(cesiumEvent: import("@vcmap/cesium").Event): void;
5865
-
5866
5877
  /**
5867
5878
  * @returns version
5868
5879
  */
5869
5880
  export function getVersionFromImageJson(json: any): ObliqueVersion;
5870
5881
 
5871
- export function parseImageMeta(json: ObliqueImageJson, url: string, projection?: import("ol/proj/Projection").default | null, terrainProvider?: import("@vcmap/cesium").CesiumTerrainProvider): ObliqueImageMeta[];
5882
+ export function parseImageMeta(json: ObliqueImageJson, url: string, projection?: Projection, terrainProvider?: import("@vcmap/cesium").CesiumTerrainProvider): ObliqueImageMeta[];
5872
5883
 
5873
5884
  export function parseImageData(json: ObliqueImageJson, imageMetas: ObliqueImageMeta[]): ObliqueImage[];
5874
5885
 
@@ -6181,6 +6192,7 @@ export interface ExtentOptions extends ProjectionOptions {
6181
6192
  */
6182
6193
  export class Extent {
6183
6194
  constructor(options?: ExtentOptions);
6195
+ static className: string;
6184
6196
  projection: Projection;
6185
6197
  extent: import("ol/extent").Extent | null;
6186
6198
  getCoordinatesInProjection(destination: Projection, result?: import("ol/extent").Extent): import("ol/extent").Extent;
@@ -6578,6 +6590,11 @@ export class IndexedCollection<T extends any> extends Collection<T> {
6578
6590
  * Event raised if an item is relocated within the collection. Is passed the moved item.
6579
6591
  */
6580
6592
  moved: VcsEvent<T>;
6593
+ /**
6594
+ * Get the symbol which is attached to an item prior to its removal. If an item is removed, the current index of the item
6595
+ * is set on the item with this symbol.
6596
+ */
6597
+ readonly previousIndexSymbol: symbol;
6581
6598
  /**
6582
6599
  * Returns an item at index.
6583
6600
  */
@@ -6589,6 +6606,7 @@ export class IndexedCollection<T extends any> extends Collection<T> {
6589
6606
  * @returns the index at which the item was inserted
6590
6607
  */
6591
6608
  add(item: T, index?: number): number | null;
6609
+ remove(item: T): void;
6592
6610
  protected _move(item: T, itemIndex: number, targetIndex: number): number;
6593
6611
  /**
6594
6612
  * Lowers an item within the array
@@ -6626,6 +6644,12 @@ export class LayerCollection extends IndexedCollection<Layer> {
6626
6644
  * The exclusive manager for this collection. Layers within this collection are automatically added and tracked.
6627
6645
  */
6628
6646
  exclusiveManager: ExclusiveManager;
6647
+ /**
6648
+ * A symbol to describe the local z index of a layer. The local z index must not equal the layers z index, but is
6649
+ * always consistent in comparison to the neighbouring layers. If a layer is moved other then by z index, the collection
6650
+ * ensures consistency by setting a new local z index if needed.
6651
+ */
6652
+ readonly zIndexSymbol: symbol;
6629
6653
  /**
6630
6654
  * Adds a layer to the collection. Can optionally be passed an index at which to insert the layer.
6631
6655
  * @returns returns the layer index or null, if the layers name is not unique
@@ -6745,6 +6769,7 @@ export function cartesian3DDistance(p1: import("ol/coordinate").Coordinate, p2:
6745
6769
  /**
6746
6770
  */
6747
6771
  export interface ProjectionOptions {
6772
+ type?: string;
6748
6773
  /**
6749
6774
  * EPSG of the projection, for example: "EPSG:4326" if not specified, uses the framework projection
6750
6775
  */
@@ -6757,6 +6782,10 @@ export interface ProjectionOptions {
6757
6782
  * aliases to define
6758
6783
  */
6759
6784
  alias?: string[] | undefined | null;
6785
+ /**
6786
+ * an alternate prefix to use for custom projection
6787
+ */
6788
+ prefix?: string | undefined;
6760
6789
  }
6761
6790
 
6762
6791
  /**
@@ -6770,6 +6799,7 @@ export function setDefaultProjectionOptions(options: ProjectionOptions): void;
6770
6799
  */
6771
6800
  export class Projection {
6772
6801
  constructor(options: ProjectionOptions);
6802
+ static className: any;
6773
6803
  /**
6774
6804
  * epsg code in the format "EPSG:25832"
6775
6805
  */
package/index.js CHANGED
@@ -98,7 +98,7 @@ export { default as ObliqueImageMeta } from './src/vcs/vcm/oblique/ObliqueImageM
98
98
  export { default as ObliqueProvider } from './src/vcs/vcm/oblique/ObliqueProvider.js';
99
99
  export { default as ObliqueView } from './src/vcs/vcm/oblique/ObliqueView.js';
100
100
  export { ObliqueViewDirection, obliqueViewDirectionNames, getDirectionName } from './src/vcs/vcm/oblique/ObliqueViewDirection.js';
101
- export { sortRealWordEdgeCoordinates, checkLineIntersection, transformCWIFC, transformToImage, transformFromImage, hasSameOrigin, destroyCesiumEvent } from './src/vcs/vcm/oblique/helpers.js';
101
+ export { sortRealWordEdgeCoordinates, checkLineIntersection, transformCWIFC, transformToImage, transformFromImage, hasSameOrigin } from './src/vcs/vcm/oblique/helpers.js';
102
102
  export { getVersionFromImageJson, parseImageMeta, parseImageData, parseLegacyImageData } from './src/vcs/vcm/oblique/parseImageJson.js';
103
103
  export { default as ClippingObject } from './src/vcs/vcm/util/clipping/clippingObject.js';
104
104
  export { default as ClippingObjectManager } from './src/vcs/vcm/util/clipping/clippingObjectManager.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/core",
3
- "version": "5.0.0-rc.2",
3
+ "version": "5.0.0-rc.3",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -85,7 +85,7 @@ class CoordinateAtPixel extends AbstractInteraction {
85
85
  if (Number.isFinite(pixel[0]) && Number.isFinite(pixel[1])) {
86
86
  return transformFromImage(image, pixel, {
87
87
  dontUseTerrain: !!move,
88
- dataProjection: mercatorProjection.proj,
88
+ dataProjection: mercatorProjection,
89
89
  }).then((coordinates) => {
90
90
  event.obliqueParameters = { pixel };
91
91
  event.position = coordinates.coords;
@@ -91,7 +91,7 @@ export async function mercatorGeometryToImageGeometry(inputSourceGeometry, desti
91
91
  const coordinates = sourceGeometry.getCoordinates();
92
92
  /** type {Array.<import("ol/coordinate").Coordinate>} */
93
93
  const flattenCoordinates = getFlatCoordinatesFromGeometry(sourceGeometry, coordinates);
94
- let transformer = getTransform(mercatorProjection.proj, image.meta.projection);
94
+ let transformer = getTransform(mercatorProjection.proj, image.meta.projection.proj);
95
95
 
96
96
  let updatedPositions = [];
97
97
  if (image.meta.terrainProvider) {
@@ -99,7 +99,7 @@ export async function mercatorGeometryToImageGeometry(inputSourceGeometry, desti
99
99
  Projection.mercatorToWgs84(coord, true);
100
100
  return Cartographic.fromDegrees(coord[0], coord[1]);
101
101
  });
102
- transformer = getTransform(wgs84Projection.proj, image.meta.projection);
102
+ transformer = getTransform(wgs84Projection.proj, image.meta.projection.proj);
103
103
  updatedPositions = await sampleTerrainMostDetailed(image.meta.terrainProvider, cartographicCoordinates);
104
104
  }
105
105
 
@@ -1,6 +1,6 @@
1
1
  import { CesiumTerrainProvider, Cartographic, Cartesian2, sampleTerrainMostDetailed, sampleTerrain } from '@vcmap/cesium';
2
2
  import { getTransform } from 'ol/proj.js';
3
- import Projection, { wgs84Projection } from '../util/projection.js';
3
+ import { wgs84Projection } from '../util/projection.js';
4
4
 
5
5
  /**
6
6
  * @typedef {Object} TerrainProviderOptions
@@ -69,18 +69,14 @@ export function sampleCesiumTerrain(terrainProvider, level, positions) {
69
69
  * changes input coordinate Array in place, new height can also be accessed by coordinates[x][2]
70
70
  * @param {import("@vcmap/cesium").CesiumTerrainProvider} terrainProvider
71
71
  * @param {Array<import("ol/coordinate").Coordinate>} coordinates
72
- * @param {(import("@vcmap/core").Projection|import("ol/proj/Projection").default)=} optSourceProjection - if input is not WGS84
72
+ * @param {import("@vcmap/core").Projection=} optSourceProjection - if input is not WGS84
73
73
  * @param {Array<import("ol/coordinate").Coordinate>=} result
74
74
  * @returns {Promise<Array<import("ol/coordinate").Coordinate>>}
75
75
  */
76
76
  export function getHeightFromTerrainProvider(terrainProvider, coordinates, optSourceProjection, result) {
77
- const usedProj = optSourceProjection instanceof Projection ?
78
- optSourceProjection.proj :
79
- optSourceProjection;
80
-
81
- const sourceTransformer = usedProj ?
77
+ const sourceTransformer = optSourceProjection ?
82
78
  getTransform(
83
- usedProj,
79
+ optSourceProjection.proj,
84
80
  wgs84Projection.proj,
85
81
  ) :
86
82
  null;
@@ -1,5 +1,5 @@
1
1
  import { boundingExtent, containsXY } from 'ol/extent.js';
2
- import { get as getProjection, getTransform, transform, transformExtent } from 'ol/proj.js';
2
+ import { getTransform, transform, transformExtent } from 'ol/proj.js';
3
3
  import { check } from '@vcsuite/check';
4
4
  import { parseBoolean, parseNumber } from '@vcsuite/parsers';
5
5
  import Extent from '../util/extent.js';
@@ -243,7 +243,7 @@ class Oblique extends BaseOLMap {
243
243
  get collection() { return this._obliqueProvider.collection; }
244
244
 
245
245
  /**
246
- * @type {import("@vcmap/cesium").Event}
246
+ * @type {import("@vcmap/core").VcsEvent<import("@vcmap/core").ObliqueImage>}
247
247
  * @readonly
248
248
  * @api
249
249
  */
@@ -294,7 +294,7 @@ class Oblique extends BaseOLMap {
294
294
  if (image) {
295
295
  const coords = boundingExtent(image.groundCoordinates);
296
296
  return new Extent({
297
- coordinates: transformExtent(coords, image.meta.projection, mercatorProjection.proj),
297
+ coordinates: transformExtent(coords, image.meta.projection.proj, mercatorProjection.proj),
298
298
  epsg: 'EPSG:3857',
299
299
  });
300
300
  }
@@ -399,7 +399,7 @@ class Oblique extends BaseOLMap {
399
399
  return null;
400
400
  }
401
401
 
402
- const transformationOptions = { dataProjection: getProjection('EPSG:4326') };
402
+ const transformationOptions = { dataProjection: wgs84Projection };
403
403
  const { coords } = await transformFromImage(image, viewCenter, transformationOptions);
404
404
  return this._computeViewpointInternal(coords);
405
405
  }
@@ -421,7 +421,7 @@ class Oblique extends BaseOLMap {
421
421
 
422
422
  const gpInternalProjection = image.transformImage2RealWorld(gpImageCoordinates, image.averageHeight);
423
423
 
424
- const transfrom = getTransform(image.meta.projection, wgs84Projection.proj);
424
+ const transfrom = getTransform(image.meta.projection.proj, wgs84Projection.proj);
425
425
  const gpWGS84 = transfrom(gpInternalProjection.slice(0, 2));
426
426
  return this._computeViewpointInternal(gpWGS84);
427
427
  }
@@ -489,7 +489,7 @@ class Oblique extends BaseOLMap {
489
489
  const bl = image.transformImage2RealWorld([extent[0], extent[1]]);
490
490
  const ur = image.transformImage2RealWorld([extent[2], extent[3]]);
491
491
  const bbox = [bl[0], bl[1], ur[0], ur[1]];
492
- const transformedBbox = transformExtent(bbox, image.meta.projection, wgs84Projection.proj);
492
+ const transformedBbox = transformExtent(bbox, image.meta.projection.proj, wgs84Projection.proj);
493
493
  return containsXY(transformedBbox, coords[0], coords[1]);
494
494
  }
495
495
 
@@ -1,15 +1,17 @@
1
+ import { parseInteger, parseNumber } from '@vcsuite/parsers';
1
2
  import RBush from 'rbush';
2
3
  import knn from 'rbush-knn';
3
- import { v4 as uuidv4 } from 'uuid';
4
4
  import { getTransform } from 'ol/proj.js';
5
5
  import { createXYZ } from 'ol/tilegrid.js';
6
6
  import Feature from 'ol/Feature.js';
7
7
  import Polygon, { fromExtent } from 'ol/geom/Polygon.js';
8
8
  import Vector from 'ol/source/Vector.js';
9
9
  import { boundingExtent, buffer, containsCoordinate, getCenter } from 'ol/extent.js';
10
- import { Event as CesiumEvent } from '@vcmap/cesium';
11
- import { DataState, getStateFromStatesArray } from './ObliqueDataSet.js';
10
+ import VcsEvent from '../event/vcsEvent.js';
11
+ import ObliqueDataSet, { DataState, getStateFromStatesArray } from './ObliqueDataSet.js';
12
12
  import { ObliqueViewDirection } from './ObliqueViewDirection.js';
13
+ import { mercatorProjection } from '../util/projection.js';
14
+ import VcsObject from '../object.js';
13
15
 
14
16
  /**
15
17
  * @typedef {Object} ObliqueCameraOptions
@@ -52,13 +54,19 @@ import { ObliqueViewDirection } from './ObliqueViewDirection.js';
52
54
  */
53
55
 
54
56
  /**
55
- * @typedef {Object} ObliqueCollectionOptions
56
- * @property {string|undefined} name
57
- * @property {Array<import("@vcmap/core").ObliqueDataSet>} dataSets
58
- * @property {number|undefined} maxZoom
59
- * @property {number|undefined} minZoom
57
+ * @typedef {Object} ObliqueDataSetOptions
58
+ * @property {string} url
59
+ * @property {ProjectionOptions} [projection]
60
+ * @property {TerrainProviderOptions} [terrainProvider]
61
+ */
62
+
63
+ /**
64
+ * @typedef {VcsObjectOptions} ObliqueCollectionOptions
65
+ * @property {Array<import("@vcmap/core").ObliqueDataSet|ObliqueDataSetOptions>} [dataSets]
66
+ * @property {number|undefined} [maxZoom]
67
+ * @property {number|undefined} [minZoom]
60
68
  * @property {number|undefined} [scaleFactor=4]
61
- * @property {number|undefined} hideLevels
69
+ * @property {number|undefined} [hideLevels]
62
70
  * @api
63
71
  */
64
72
 
@@ -68,7 +76,7 @@ import { ObliqueViewDirection } from './ObliqueViewDirection.js';
68
76
  */
69
77
  function getImageFeatures(images) {
70
78
  return images.map((image) => {
71
- const transform = getTransform(image.meta.projection, 'EPSG:3857');
79
+ const transform = getTransform(image.meta.projection.proj, mercatorProjection.proj);
72
80
  const feature = new Feature({
73
81
  geometry: new Polygon([image.groundCoordinates.map(c => transform(c.slice(0, 2)))]),
74
82
  viewDirection: image.viewDirection,
@@ -103,18 +111,28 @@ function getTileFeatures(tiles) {
103
111
  * @class
104
112
  * @export
105
113
  */
106
- class ObliqueCollection {
114
+ class ObliqueCollection extends VcsObject {
115
+ static get className() { return 'oblique.ObliqueCollection'; }
116
+
117
+ /**
118
+ * @returns {ObliqueCollectionOptions}
119
+ */
120
+ static getDefaultOptions() {
121
+ return {
122
+ maxZoom: 0,
123
+ minZoom: 0,
124
+ scaleFactor: 4,
125
+ dataSets: undefined,
126
+ hideLevels: 0,
127
+ };
128
+ }
129
+
107
130
  /**
108
131
  * @param {ObliqueCollectionOptions} options
109
132
  */
110
133
  constructor(options) {
111
- /**
112
- * The unique name of the collection
113
- * @type {string}
114
- * @api
115
- */
116
- this.name = options.name || uuidv4();
117
-
134
+ super(options);
135
+ const defaultOptions = ObliqueCollection.getDefaultOptions();
118
136
  /**
119
137
  * Maps each direction to an RTree
120
138
  * @type {Map<import("@vcmap/core").ObliqueViewDirection, RBush>}
@@ -136,10 +154,10 @@ class ObliqueCollection {
136
154
 
137
155
  /** @type {ObliqueViewOptions} */
138
156
  this.viewOptions = {
139
- maxZoom: options.maxZoom || 0,
140
- minZoom: options.minZoom || 0,
141
- scaleFactor: options.scaleFactor || 4,
142
- hideLevels: options.hideLevels || 0,
157
+ maxZoom: parseInteger(options.maxZoom, defaultOptions.maxZoom),
158
+ minZoom: parseInteger(options.minZoom, defaultOptions.minZoom),
159
+ scaleFactor: parseNumber(options.scaleFactor, defaultOptions.scaleFactor),
160
+ hideLevels: parseInteger(options.hideLevels, defaultOptions.hideLevels),
143
161
  };
144
162
 
145
163
  /** @type {boolean} */
@@ -147,10 +165,10 @@ class ObliqueCollection {
147
165
 
148
166
  /**
149
167
  * Event raised when images are loaded. Is passed an Array of ObliqueImages as its only argument.
150
- * @type {import("@vcmap/cesium").Event}
168
+ * @type {import("@vcmap/core").VcsEvent<Array<import("@vcmap/core").ObliqueImage>>}
151
169
  * @api
152
170
  */
153
- this.imagesLoaded = new CesiumEvent();
171
+ this.imagesLoaded = new VcsEvent();
154
172
 
155
173
  /**
156
174
  * @type {import("ol/source").Vector<import("ol/geom/Geometry").default>|null}
@@ -262,11 +280,18 @@ class ObliqueCollection {
262
280
 
263
281
  /**
264
282
  * Adds an oblique data set to this collection.
265
- * @param {import("@vcmap/core").ObliqueDataSet} dataSet
283
+ * @param {import("@vcmap/core").ObliqueDataSet|ObliqueDataSetOptions} dataSetOptions
266
284
  * @private
267
285
  */
268
- _addDataSet(dataSet) {
269
- dataSet.imagesLoaded.addEventListener((images, tileCoordinate) => {
286
+ _addDataSet(dataSetOptions) {
287
+ /** @type {import("@vcmap/core").ObliqueDataSet} */
288
+ let dataSet;
289
+ if (dataSetOptions instanceof ObliqueDataSet) {
290
+ dataSet = dataSetOptions;
291
+ } else {
292
+ dataSet = new ObliqueDataSet(dataSetOptions.url, dataSetOptions.projection, dataSetOptions.terrainProvider);
293
+ }
294
+ dataSet.imagesLoaded.addEventListener(({ images, tileCoordinate }) => {
270
295
  this._loadImages(images, tileCoordinate);
271
296
  });
272
297
  this._loadImages(dataSet.images);
@@ -279,7 +304,7 @@ class ObliqueCollection {
279
304
  * @returns {Promise<void>}
280
305
  * @api
281
306
  */
282
- async addDataSet(dataSet) {
307
+ async addDataSet(dataSet) { // XXX check for dataset here?
283
308
  if (this._loadingPromise) {
284
309
  await this._loadingPromise;
285
310
  await this._loadDataSet(dataSet);
@@ -322,7 +347,7 @@ class ObliqueCollection {
322
347
  directions.set(image.viewDirection, []);
323
348
  }
324
349
 
325
- const transform = getTransform(image.meta.projection, 'EPSG:3857');
350
+ const transform = getTransform(image.meta.projection.proj, mercatorProjection.proj);
326
351
  const coord = image.centerPointOnGround.slice(0, 2);
327
352
  transform(coord, coord);
328
353
  directions.get(image.viewDirection).push({
@@ -491,7 +516,7 @@ class ObliqueCollection {
491
516
  async hasImageAtCoordinate(mercatorCoordinate, direction) {
492
517
  const image = await this.loadImageForCoordinate(mercatorCoordinate, direction);
493
518
  if (image) {
494
- const transform = getTransform('EPSG:3857', image.meta.projection);
519
+ const transform = getTransform(mercatorProjection.proj, image.meta.projection.proj);
495
520
  const internalCoordinates = mercatorCoordinate.slice(0, 2);
496
521
  transform(internalCoordinates, internalCoordinates);
497
522
  const extent = boundingExtent(image.groundCoordinates);
@@ -513,7 +538,7 @@ class ObliqueCollection {
513
538
  async loadAdjacentImage(image, heading, deviation = Math.PI / 4) {
514
539
  const tree = this._directionTrees.get(image.viewDirection);
515
540
  if (tree) {
516
- const transform = getTransform(image.meta.projection, 'EPSG:3857');
541
+ const transform = getTransform(image.meta.projection.proj, mercatorProjection.proj);
517
542
  const coords = image.groundCoordinates.map(c => transform(c.slice(0, 2)));
518
543
  const extent = boundingExtent(coords);
519
544
  await this.loadDataForExtent(buffer(extent, 200));
@@ -566,6 +591,33 @@ class ObliqueCollection {
566
591
  this._imageFeatureSource.clear(true);
567
592
  this._imageFeatureSource = null;
568
593
  }
594
+ this.imagesLoaded.destroy();
595
+ }
596
+
597
+ /**
598
+ * @returns {ObliqueCollectionOptions}
599
+ */
600
+ toJSON() {
601
+ /** @type {ObliqueCollectionOptions} */
602
+ const config = super.toJSON();
603
+ const defaultOptions = ObliqueCollection.getDefaultOptions();
604
+ if (this.viewOptions.maxZoom !== defaultOptions.maxZoom) {
605
+ config.maxZoom = this.viewOptions.maxZoom;
606
+ }
607
+ if (this.viewOptions.minZoom !== defaultOptions.minZoom) {
608
+ config.minZoom = this.viewOptions.minZoom;
609
+ }
610
+ if (this.viewOptions.scaleFactor !== defaultOptions.scaleFactor) {
611
+ config.scaleFactor = this.viewOptions.scaleFactor;
612
+ }
613
+ if (this.viewOptions.hideLevels !== defaultOptions.hideLevels) {
614
+ config.hideLevels = this.viewOptions.hideLevels;
615
+ }
616
+
617
+ if (this.dataSets.length > 0) {
618
+ config.dataSets = this.dataSets.map(d => d.toJSON());
619
+ }
620
+ return config;
569
621
  }
570
622
  }
571
623
 
@@ -1,9 +1,16 @@
1
- import { Event as CesiumEvent } from '@vcmap/cesium';
2
1
  import axios from 'axios';
3
2
  import { createXYZ } from 'ol/tilegrid.js';
4
- import { destroyCesiumEvent } from './helpers.js';
5
3
  import { cartesian2DDistance } from '../util/math.js';
6
4
  import { parseImageData, parseImageMeta, parseLegacyImageData, getVersionFromImageJson } from './parseImageJson.js';
5
+ import VcsEvent from '../event/vcsEvent.js';
6
+ import { getTerrainProviderForUrl } from '../layer/terrainHelpers.js';
7
+ import Projection from '../util/projection.js';
8
+
9
+ /**
10
+ * @typedef {Object} ObliqueDataSetImagesLoaded
11
+ * @property {Array<import("@vcmap/core").ObliqueImage>} images - the loaded images
12
+ * @property {string} [tileCoordinate] - an optional tile coordinate
13
+ */
7
14
 
8
15
  /**
9
16
  * Enumeration of data set states
@@ -43,10 +50,10 @@ export function getStateFromStatesArray(states) {
43
50
  class ObliqueDataSet {
44
51
  /**
45
52
  * @param {string} url
46
- * @param {import("ol/proj/Projection").default} projection
47
- * @param {import("@vcmap/cesium").CesiumTerrainProvider=} terrainProvider
53
+ * @param {import("@vcmap/core").Projection|ProjectionOptions=} projection
54
+ * @param {TerrainProviderOptions=} terrainProviderOptions
48
55
  */
49
- constructor(url, projection, terrainProvider) {
56
+ constructor(url, projection, terrainProviderOptions) {
50
57
  /** @type {string} */
51
58
  this.url = url;
52
59
  if (!/\.json$/.test(this.url)) {
@@ -55,22 +62,36 @@ class ObliqueDataSet {
55
62
 
56
63
  /** @type {string} */
57
64
  this.baseUrl = this.url.replace(/\/?([^/]+\.json)?$/, '');
58
- /** @type {import("ol/proj/Projection").default} */
59
- this.projection = projection;
60
- /** @type {import("@vcmap/cesium").CesiumTerrainProvider|undefined} */
61
- this.terrainProvider = terrainProvider;
65
+
66
+ let projectionObject = projection;
67
+ if (projectionObject && !(projectionObject instanceof Projection)) {
68
+ projectionObject = new Projection(projectionObject);
69
+ }
70
+ /** @type {import("@vcmap/core").Projection} */
71
+ this.projection = /** @type {import("@vcmap/core").Projection} */ (projectionObject);
72
+ /**
73
+ * @type {TerrainProviderOptions}
74
+ * @private
75
+ */
76
+ this._terrainProviderOptions = terrainProviderOptions ? { ...terrainProviderOptions } : undefined;
77
+ /**
78
+ * @type {import("@vcmap/cesium").CesiumTerrainProvider|undefined}
79
+ * @private
80
+ */
81
+ this._terrainProvider = this._terrainProviderOptions ?
82
+ getTerrainProviderForUrl(this._terrainProviderOptions) :
83
+ undefined;
62
84
  /**
63
85
  * @type {Array<import("@vcmap/core").ObliqueImageMeta>}
64
86
  * @private
65
87
  */
66
88
  this._imageMetas = [];
67
89
  /**
68
- * Event raised when images are loaded. Is passed an Array of ObliqueImages as the first argument and optionally
69
- * a string representing the tile coordinate ("z/x/y"), if the images where loaded for a tile.
70
- * @type {import("@vcmap/cesium").Event}
90
+ * Event raised when images are loaded.
91
+ * @type {import("@vcmap/core").VcsEvent<ObliqueDataSetImagesLoaded>}
71
92
  * @api
72
93
  */
73
- this.imagesLoaded = new CesiumEvent();
94
+ this.imagesLoaded = new VcsEvent();
74
95
  /** @type {Map<string, DataState>} */
75
96
  this._tiles = new Map();
76
97
  /** @type {Map<string, Promise<void>>} */
@@ -118,6 +139,14 @@ class ObliqueDataSet {
118
139
  return this._state;
119
140
  }
120
141
 
142
+ /**
143
+ * @type {import("@vcmap/cesium").CesiumTerrainProvider|undefined}
144
+ * @readonly
145
+ */
146
+ get terrainProvider() {
147
+ return this._terrainProvider;
148
+ }
149
+
121
150
  /**
122
151
  * Loads the data set.
123
152
  * @returns {Promise<void>}
@@ -194,7 +223,7 @@ class ObliqueDataSet {
194
223
  }
195
224
  if (images.length > 0) {
196
225
  this._images = images;
197
- this.imagesLoaded.raiseEvent(images);
226
+ this.imagesLoaded.raiseEvent({ images });
198
227
  }
199
228
  }
200
229
  }
@@ -303,7 +332,7 @@ class ObliqueDataSet {
303
332
  const images = parseImageData(data, this._imageMetas);
304
333
  if (images.length > 0) {
305
334
  this._images = this._images.concat(images);
306
- this.imagesLoaded.raiseEvent(images, stringTileCoordinates);
335
+ this.imagesLoaded.raiseEvent({ images, tileCoordinate: stringTileCoordinates });
307
336
  }
308
337
  })
309
338
  .catch((err) => {
@@ -344,13 +373,27 @@ class ObliqueDataSet {
344
373
  }
345
374
 
346
375
  destroy() {
347
- destroyCesiumEvent(this.imagesLoaded);
376
+ this.imagesLoaded.destroy();
348
377
  this._images = [];
349
378
  this._imageMetas = [];
350
379
  this._tiles.clear();
351
380
  this._loadingPromises.clear();
352
381
  this._tileGrid = null;
353
- this.terrainProvider = null;
382
+ this._terrainProvider = null;
383
+ }
384
+
385
+ /**
386
+ * @returns {ObliqueDataSetOptions}
387
+ */
388
+ toJSON() {
389
+ const config = { url: this.url };
390
+ if (this.projection) {
391
+ config.projection = this.projection.toJSON();
392
+ }
393
+ if (this._terrainProviderOptions) {
394
+ config.terrainProvider = { ...this._terrainProviderOptions };
395
+ }
396
+ return config;
354
397
  }
355
398
  }
356
399
 
@@ -13,7 +13,7 @@ import { getHeightFromTerrainProvider } from '../layer/terrainHelpers.js';
13
13
  * @property {import("@vcmap/cesium").Cartesian3|undefined} projectionCenter
14
14
  * @property {import("@vcmap/cesium").Matrix3|undefined} pToRealworld
15
15
  * @property {import("@vcmap/cesium").Matrix4|undefined} pToImage
16
- * @property {import("ol/proj/Projection").default|undefined} [projection]
16
+ * @property {import("@vcmap/core").Projection|undefined} [projection]
17
17
  * @property {import("@vcmap/cesium").CesiumTerrainProvider|undefined} terrainProvider
18
18
  * @api
19
19
  */
@@ -9,7 +9,7 @@ import { cartesian2DDistance } from '../util/math.js';
9
9
  * @property {import("ol/size").Size} size
10
10
  * @property {import("ol/size").Size} tileSize
11
11
  * @property {Array<number>} tileResolution
12
- * @property {import("ol/proj/Projection").default} projection
12
+ * @property {import("@vcmap/core").Projection} projection
13
13
  * @property {string} url
14
14
  * @property {import("@vcmap/cesium").CesiumTerrainProvider} terrainProvider
15
15
  * @property {string} name
@@ -64,7 +64,7 @@ class ObliqueImageMeta {
64
64
  this.tileResolution = options.tileResolution;
65
65
  /**
66
66
  * The world projection of the images associated with this meta
67
- * @type {import("ol/proj/Projection").default}
67
+ * @type {import("@vcmap/core").Projection}
68
68
  * @api
69
69
  */
70
70
  this.projection = options.projection;
@@ -1,12 +1,12 @@
1
- import { Event as CesiumEvent } from '@vcmap/cesium';
2
1
  import { getTransform } from 'ol/proj.js';
3
2
  import View from 'ol/View.js';
4
3
  import { unByKey } from 'ol/Observable.js';
5
4
  import { DataState } from './ObliqueDataSet.js';
6
5
  import OLView from './ObliqueView.js';
7
- import { destroyCesiumEvent, transformFromImage } from './helpers.js';
6
+ import { transformFromImage } from './helpers.js';
8
7
  import { getHeightFromTerrainProvider } from '../layer/terrainHelpers.js';
9
8
  import { mercatorProjection } from '../util/projection.js';
9
+ import VcsEvent from '../event/vcsEvent.js';
10
10
 
11
11
  /**
12
12
  * @typedef {Object} ObliqueViewPoint
@@ -63,10 +63,10 @@ class ObliqueProvider {
63
63
 
64
64
  /**
65
65
  * Event raised once a new image is set on the provider. Will be passed the new image as the only argument.
66
- * @type {import("@vcmap/cesium").Event}
66
+ * @type {import("@vcmap/core").VcsEvent<import("@vcmap/core").ObliqueImage>}
67
67
  * @api
68
68
  */
69
- this.imageChanged = new CesiumEvent();
69
+ this.imageChanged = new VcsEvent();
70
70
  /**
71
71
  * Whether the post render handler should switch on image edge. Setting
72
72
  * this to false will suspend all post render handler switches.
@@ -232,7 +232,7 @@ class ObliqueProvider {
232
232
  }
233
233
  const pulledCenter = this._pullCoordinateToImageCenter(imageCoordinates.slice());
234
234
  const worldCoords = this._currentImage.transformImage2RealWorld(pulledCenter).slice(0, 2);
235
- const transform = getTransform(this._currentImage.meta.projection, 'EPSG:3857');
235
+ const transform = getTransform(this._currentImage.meta.projection.proj, mercatorProjection.proj);
236
236
  const mercatorCoords = transform(worldCoords);
237
237
  const buffer = 200; // XXX make configurable?
238
238
  const extent = [
@@ -299,7 +299,10 @@ class ObliqueProvider {
299
299
  const [width, height] = this._currentImage.meta.size;
300
300
  let center = [width / 2, height / 2];
301
301
  if (optCenter) {
302
- const worldCenter = getTransform('EPSG:3857', this._currentImage.meta.projection)(optCenter.slice(0, 2));
302
+ const worldCenter = getTransform(
303
+ mercatorProjection.proj,
304
+ this._currentImage.meta.projection.proj,
305
+ )(optCenter.slice(0, 2));
303
306
  const imageCenter = this._currentImage.transformRealWorld2Image(worldCenter, optCenter[2]);
304
307
  imageCenter[0] = withinBounds(imageCenter[0], width);
305
308
  imageCenter[1] = withinBounds(imageCenter[1], height);
@@ -424,7 +427,7 @@ class ObliqueProvider {
424
427
  this._postRenderListener = null;
425
428
  }
426
429
 
427
- destroyCesiumEvent(this.imageChanged);
430
+ this.imageChanged.destroy();
428
431
  this._collection = null;
429
432
  this._olMap = null;
430
433
  }
@@ -1,11 +1,12 @@
1
1
  /* eslint no-underscore-dangle: ["error", { "allow": ["_listeners", "_scopes", "_toRemove"] }] */
2
2
  /* eslint-disable no-continue */
3
3
  import { boundingExtent, getBottomLeft, getBottomRight, getTopLeft, getTopRight } from 'ol/extent.js';
4
- import { get as getProjection, transform } from 'ol/proj.js';
4
+ import { transform } from 'ol/proj.js';
5
5
  import { Cartesian2 } from '@vcmap/cesium';
6
6
  import { ObliqueViewDirection } from './ObliqueViewDirection.js';
7
7
  import { getHeightFromTerrainProvider } from '../layer/terrainHelpers.js';
8
8
  import { cartesian2DDistance } from '../util/math.js';
9
+ import { mercatorProjection, wgs84Projection } from '../util/projection.js';
9
10
 
10
11
  /**
11
12
  * @type {import("@vcmap/cesium").Cartesian2}
@@ -292,7 +293,7 @@ export function transformCWIFC(inputOrigin, inputTarget, originIsImage, coordina
292
293
  /**
293
294
  * @typedef {Object} ImageTransformationOptions
294
295
  * @property {boolean|undefined} [dontUseTerrain]
295
- * @property {import("ol/proj/Projection").default|undefined} [dataProjection] - the projection of the input/output coordinates, assumes image source projection
296
+ * @property {import("@vcmap/core").Projection|undefined} [dataProjection] - the projection of the input/output coordinates, assumes image source projection
296
297
  * @property {number|undefined} [terrainErrorThreshold=1] - the transformToWorld process iterativly calculates a new Height Value from the terrainProvider until the difference to the new height value is smaller
297
298
  * @property {number|undefined} [terrainErrorCountThreshold=3] - how often the transformToWorld process iterativly calculates a new Height Value from the terrainProvider
298
299
  * @api
@@ -313,8 +314,8 @@ export function transformToImage(image, worldCoordinate, options = {}) {
313
314
  gpInternalCoordinates = worldCoordinate;
314
315
  } else {
315
316
  gpInternalCoordinates = options.dataProjection ?
316
- transform(worldCoordinate, options.dataProjection, image.meta.projection) :
317
- transform(worldCoordinate, 'EPSG:3857', image.meta.projection);
317
+ transform(worldCoordinate, options.dataProjection.proj, image.meta.projection.proj) :
318
+ transform(worldCoordinate, mercatorProjection.proj, image.meta.projection.proj);
318
319
  }
319
320
 
320
321
  function useAverageHeight() {
@@ -369,14 +370,14 @@ function pickTerrain(pickTerrainOptions) {
369
370
  count,
370
371
  height,
371
372
  } = pickTerrainOptions;
372
- const wgs84Projection = getProjection('EPSG:4326');
373
+
373
374
  return getHeightFromTerrainProvider(image.meta.terrainProvider, [worldCoordinate])
374
375
  .then(([worldCoordinateWithHeights]) => {
375
376
  if (worldCoordinateWithHeights[2] != null) {
376
377
  const newWorldCoords = transform(
377
378
  image.transformImage2RealWorld(imageCoordinate, worldCoordinateWithHeights[2]),
378
- image.meta.projection,
379
- wgs84Projection,
379
+ image.meta.projection.proj,
380
+ wgs84Projection.proj,
380
381
  );
381
382
  newWorldCoords[2] = worldCoordinateWithHeights[2];
382
383
  if (
@@ -406,11 +407,10 @@ function pickTerrain(pickTerrainOptions) {
406
407
  * @export
407
408
  */
408
409
  export async function transformFromImage(image, imageCoordinate, options = {}) {
409
- const wgs84Projection = getProjection('EPSG:4326');
410
410
  const initialWorldCoords = transform(
411
411
  image.transformImage2RealWorld(imageCoordinate, image.averageHeight),
412
- image.meta.projection,
413
- wgs84Projection,
412
+ image.meta.projection.proj,
413
+ wgs84Projection.proj,
414
414
  );
415
415
 
416
416
  const terrainErrorThreshold = options.terrainErrorThreshold || 1;
@@ -430,8 +430,8 @@ export async function transformFromImage(image, imageCoordinate, options = {}) {
430
430
  }
431
431
 
432
432
  coordsObj.coords = options.dataProjection ?
433
- transform(coordsObj.coords, wgs84Projection, options.dataProjection) :
434
- transform(coordsObj.coords, wgs84Projection, getProjection('EPSG:3857'));
433
+ transform(coordsObj.coords, wgs84Projection.proj, options.dataProjection.proj) :
434
+ transform(coordsObj.coords, wgs84Projection.proj, mercatorProjection.proj);
435
435
  return coordsObj;
436
436
  }
437
437
 
@@ -453,31 +453,3 @@ export function hasSameOrigin(url) {
453
453
  const uri = new URL(url);
454
454
  return currentUri.host.toLowerCase() === uri.host.toLocaleLowerCase();
455
455
  }
456
-
457
- /**
458
- * destroys a cesium Event Emitter, (removes all listeners)
459
- * @param {import("@vcmap/cesium").Event} cesiumEvent
460
- */
461
- export function destroyCesiumEvent(cesiumEvent) {
462
- // @ts-ignore
463
- for (let i = 0; i < cesiumEvent._listeners.length; i++) {
464
- // @ts-ignore
465
- cesiumEvent._listeners[i] = undefined;
466
- }
467
- // @ts-ignore
468
- for (let i = 0; i < cesiumEvent._scopes.length; i++) {
469
- // @ts-ignore
470
- cesiumEvent._scopes[i] = undefined;
471
- }
472
- // @ts-ignore
473
- for (let i = 0; i < cesiumEvent._toRemove.length; i++) {
474
- // @ts-ignore
475
- cesiumEvent._toRemove[i] = undefined;
476
- }
477
- // @ts-ignore
478
- cesiumEvent._listeners.length = 0;
479
- // @ts-ignore
480
- cesiumEvent._scopes.length = 0;
481
- // @ts-ignore
482
- cesiumEvent._toRemove.length = 0;
483
- }
@@ -1,11 +1,18 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import proj4 from 'proj4';
3
- import { register } from 'ol/proj/proj4.js';
4
- import { get as getProjection } from 'ol/proj.js';
5
1
  import { Matrix3, Cartesian3, Matrix4 } from '@vcmap/cesium';
6
2
  import ObliqueImage from './ObliqueImage.js';
7
3
  import { obliqueViewDirectionNames } from './ObliqueViewDirection.js';
8
4
  import ImageMeta from './ObliqueImageMeta.js';
5
+ import Projection from '../util/projection.js';
6
+
7
+ let customObliqueProjectionId = 0;
8
+
9
+ /**
10
+ * @returns {number}
11
+ */
12
+ function getNextObliqueProjectionId() {
13
+ customObliqueProjectionId += 1;
14
+ return customObliqueProjectionId;
15
+ }
9
16
 
10
17
  /**
11
18
  * @param {Object} json
@@ -33,7 +40,7 @@ export function getVersionFromImageJson(json) {
33
40
  /**
34
41
  * @param {ObliqueImageJson} json
35
42
  * @param {string} url
36
- * @param {(import("ol/proj/Projection").default|null)=} projection
43
+ * @param {import("@vcmap/core").Projection=} projection
37
44
  * @param {import("@vcmap/cesium").CesiumTerrainProvider=} terrainProvider
38
45
  * @returns {Array<import("@vcmap/core").ObliqueImageMeta>}
39
46
  */
@@ -47,10 +54,11 @@ export function parseImageMeta(json, url, projection, terrainProvider) {
47
54
  let imageProjection = projection;
48
55
  const imageMetas = [];
49
56
  if (!imageProjection && json.generalImageInfo.crs) {
50
- const crsUuid = uuidv4();
51
- proj4.defs(crsUuid, json.generalImageInfo.crs);
52
- register(proj4);
53
- imageProjection = getProjection(crsUuid);
57
+ imageProjection = new Projection({
58
+ epsg: getNextObliqueProjectionId(),
59
+ prefix: 'OBLIQUE:',
60
+ proj4: json.generalImageInfo.crs,
61
+ });
54
62
  }
55
63
 
56
64
  const defaultOptions = {
@@ -35,6 +35,11 @@ function checkExtentValidity(extent) {
35
35
  * @api
36
36
  */
37
37
  class Extent {
38
+ /**
39
+ * @type {string}
40
+ */
41
+ static get className() { return 'vcs.vcm.util.Extent'; }
42
+
38
43
  /**
39
44
  * @param {ExtentOptions=} options object
40
45
  */
@@ -44,6 +49,7 @@ class Extent {
44
49
  epsg: options.epsg,
45
50
  proj4: options.proj4,
46
51
  alias: options.alias,
52
+ prefix: options.prefix,
47
53
  });
48
54
 
49
55
  /** @type {import("ol/extent").Extent|null} */
@@ -79,7 +85,11 @@ class Extent {
79
85
  * @returns {ExtentOptions}
80
86
  */
81
87
  toJSON() {
82
- return { coordinates: this.extent.slice(), ...this.projection.toJSON() };
88
+ return {
89
+ coordinates: this.extent.slice(),
90
+ ...this.projection.toJSON(),
91
+ type: Extent.className,
92
+ };
83
93
  }
84
94
 
85
95
  /**
@@ -42,8 +42,22 @@ class IndexedCollection extends Collection {
42
42
  * @api
43
43
  */
44
44
  this.moved = new VcsEvent();
45
+
46
+ /**
47
+ * @type {symbol}
48
+ * @private
49
+ */
50
+ this._previousIndexSymbol = Symbol('previousIndex');
45
51
  }
46
52
 
53
+ /**
54
+ * Get the symbol which is attached to an item prior to its removal. If an item is removed, the current index of the item
55
+ * is set on the item with this symbol.
56
+ * @type {symbol}
57
+ * @readonly
58
+ */
59
+ get previousIndexSymbol() { return this._previousIndexSymbol; }
60
+
47
61
  /**
48
62
  * Returns an item at index.
49
63
  * @param {number} index
@@ -76,6 +90,15 @@ class IndexedCollection extends Collection {
76
90
  return null;
77
91
  }
78
92
 
93
+ /**
94
+ * @inheritDoc
95
+ * @param {T} item
96
+ */
97
+ remove(item) {
98
+ item[this._previousIndexSymbol] = this._array.indexOf(item);
99
+ super.remove(item);
100
+ }
101
+
79
102
  /**
80
103
  * @param {T} item
81
104
  * @param {number} itemIndex
@@ -44,9 +44,6 @@ class LayerCollection extends IndexedCollection {
44
44
  this._layerEventListeners = {};
45
45
 
46
46
  /**
47
- * A symbol to describe the local z index of a layer. The local z index must not equal the layers z index, but is
48
- * always consistent in comparison to the neighbouring layers. If a layer is moved other then by z index, the collection
49
- * ensures consistency by setting a new local z index if needed.
50
47
  * @type {symbol}
51
48
  * @private
52
49
  */
@@ -67,6 +64,15 @@ class LayerCollection extends IndexedCollection {
67
64
  this.exclusiveManager = new ExclusiveManager();
68
65
  }
69
66
 
67
+ /**
68
+ * A symbol to describe the local z index of a layer. The local z index must not equal the layers z index, but is
69
+ * always consistent in comparison to the neighbouring layers. If a layer is moved other then by z index, the collection
70
+ * ensures consistency by setting a new local z index if needed.
71
+ * @type {symbol}
72
+ * @readonly
73
+ */
74
+ get zIndexSymbol() { return this._zIndexSymbol; }
75
+
70
76
  /**
71
77
  * @param {import("@vcmap/core").Layer} layer
72
78
  * @private
@@ -116,10 +122,9 @@ class LayerCollection extends IndexedCollection {
116
122
  _zIndexChanged(layer) {
117
123
  const currentIndex = this.indexOf(layer);
118
124
  if (currentIndex > -1) {
119
- const increased = layer[this._zIndexSymbol] < layer.zIndex;
120
125
  layer[this._zIndexSymbol] = layer.zIndex;
121
126
  let zIndexPosition = this._findZIndexPosition(layer.zIndex);
122
- if (increased && zIndexPosition > 0) {
127
+ if (zIndexPosition > 0 && zIndexPosition > currentIndex) {
123
128
  zIndexPosition -= 1; // remove self from count
124
129
  }
125
130
  zIndexPosition = zIndexPosition != null ? zIndexPosition : this._array.length - 1;
@@ -3,12 +3,15 @@ import { register } from 'ol/proj/proj4.js';
3
3
  import proj4 from 'proj4';
4
4
  import { getLogger as getLoggerByName } from '@vcsuite/logger';
5
5
  import { check } from '@vcsuite/check';
6
+ import { VcsClassRegistry } from '../classRegistry.js';
6
7
 
7
8
  /**
8
9
  * @typedef {Object} ProjectionOptions
10
+ * @property {string} [type]
9
11
  * @property {string|number} [epsg] - EPSG of the projection, for example: "EPSG:4326" if not specified, uses the framework projection
10
12
  * @property {string|undefined|null} [proj4] - definition of the projection. See for example: {@link http://spatialreference.org/ref/epsg/4326/proj4/} proj4
11
13
  * @property {Array<string>|undefined|null} [alias] - aliases to define
14
+ * @property {string|undefined} [prefix='EPSG:'] - an alternate prefix to use for custom projection
12
15
  * @api stable
13
16
  */
14
17
 
@@ -36,7 +39,8 @@ let defaultProjectionOption = {
36
39
  * @returns {string}
37
40
  */
38
41
  function parseEPSGCode(value, prefix = 'EPSG:') {
39
- const matches = `${value}`.match(/^(?:epsg:)?(\d+)/i);
42
+ const regex = new RegExp(`^(?:${prefix})?(\\d+)`, 'i');
43
+ const matches = `${value}`.match(regex);
40
44
  if (matches && matches[1]) {
41
45
  return `${prefix}${matches[1]}`;
42
46
  }
@@ -73,9 +77,11 @@ function validateProjectionOptions(options) {
73
77
  * @returns {ProjectionOptions} valid options
74
78
  */
75
79
  function registerProjection(options) {
76
- const saneOptions = {};
80
+ const saneOptions = {
81
+ prefix: options.prefix,
82
+ };
77
83
  if (options.epsg) {
78
- saneOptions.epsg = parseEPSGCode(options.epsg);
84
+ saneOptions.epsg = parseEPSGCode(options.epsg, options.prefix);
79
85
  if (saneOptions.epsg) {
80
86
  if (options.proj4) {
81
87
  saneOptions.proj4 = options.proj4;
@@ -123,6 +129,11 @@ export function setDefaultProjectionOptions(options) {
123
129
  * @api stable
124
130
  */
125
131
  class Projection {
132
+ /**
133
+ * @returns {string}
134
+ */
135
+ static get className() { return 'vcs.vcm.util.Projection'; }
136
+
126
137
  /**
127
138
  * @param {ProjectionOptions} options
128
139
  */
@@ -143,6 +154,20 @@ class Projection {
143
154
  if (!this.proj) {
144
155
  this._epsg = Projection.parseEPSGCode(defaultProjectionOption.epsg);
145
156
  }
157
+
158
+ /**
159
+ * Cached for toJSON
160
+ * @type {Array<string>}
161
+ * @private
162
+ */
163
+ this._alias = saneOptions.alias;
164
+
165
+ /**
166
+ * Cached for toJSON
167
+ * @type {string}
168
+ * @private
169
+ */
170
+ this._prefix = saneOptions.prefix;
146
171
  }
147
172
 
148
173
  /**
@@ -264,11 +289,18 @@ class Projection {
264
289
  */
265
290
  toJSON() {
266
291
  const configObject = {
292
+ type: Projection.className,
267
293
  epsg: this.epsg,
268
294
  };
269
295
  if (this.proj4) {
270
296
  configObject.proj4 = this.proj4;
271
297
  }
298
+ if (Array.isArray(this._alias) && this._alias.length > 0) {
299
+ configObject.alias = this._alias.slice();
300
+ }
301
+ if (this._prefix) {
302
+ configObject.prefix = this._prefix;
303
+ }
272
304
  return configObject;
273
305
  }
274
306
 
@@ -346,3 +378,5 @@ export const wgs84Projection = new Projection({ epsg: 4326 });
346
378
  * @export
347
379
  */
348
380
  export const mercatorProjection = new Projection({ epsg: 3857 });
381
+
382
+ VcsClassRegistry.registerClass(Projection.className, Projection);
@@ -3,6 +3,7 @@ import { parseBoolean, parseNumber } from '@vcsuite/parsers';
3
3
  import Projection, { wgs84Projection } from './projection.js';
4
4
  import VcsObject from '../object.js';
5
5
  import Extent from './extent.js';
6
+ import { VcsClassRegistry } from '../classRegistry.js';
6
7
 
7
8
  /**
8
9
  * compares two numeric properties
@@ -331,3 +332,5 @@ class ViewPoint extends VcsObject {
331
332
  }
332
333
 
333
334
  export default ViewPoint;
335
+
336
+ VcsClassRegistry.registerClass(ViewPoint.className, ViewPoint);