@vcmap/core 5.0.0-rc.0
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/LICENSE.md +21 -0
- package/README.md +44 -0
- package/build/postinstall.js +44 -0
- package/index.js +139 -0
- package/package.json +92 -0
- package/src/cesium/cesium3DTileFeature.js +9 -0
- package/src/cesium/cesium3DTilePointFeature.js +9 -0
- package/src/cesium/cesiumVcsCameraPrimitive.js +146 -0
- package/src/cesium/wallpaperMaterial.js +64 -0
- package/src/ol/feature.js +47 -0
- package/src/ol/geom/circle.js +24 -0
- package/src/ol/geom/geometryCollection.js +33 -0
- package/src/ol/render/canvas/canvasTileRenderer.js +179 -0
- package/src/ol/source/ClusterEnhancedVectorSource.js +39 -0
- package/src/ol/source/VcsCluster.js +37 -0
- package/src/vcs/vcm/classRegistry.js +106 -0
- package/src/vcs/vcm/event/vcsEvent.js +89 -0
- package/src/vcs/vcm/globalCollections.js +11 -0
- package/src/vcs/vcm/interaction/abstractInteraction.js +149 -0
- package/src/vcs/vcm/interaction/coordinateAtPixel.js +102 -0
- package/src/vcs/vcm/interaction/eventHandler.js +425 -0
- package/src/vcs/vcm/interaction/featureAtPixelInteraction.js +286 -0
- package/src/vcs/vcm/interaction/featureProviderInteraction.js +54 -0
- package/src/vcs/vcm/interaction/interactionChain.js +124 -0
- package/src/vcs/vcm/interaction/interactionType.js +114 -0
- package/src/vcs/vcm/layer/buildings.js +17 -0
- package/src/vcs/vcm/layer/cesium/cesiumTilesetCesium.js +359 -0
- package/src/vcs/vcm/layer/cesium/clusterContext.js +95 -0
- package/src/vcs/vcm/layer/cesium/dataSourceCesium.js +171 -0
- package/src/vcs/vcm/layer/cesium/openStreetMapCesium.js +29 -0
- package/src/vcs/vcm/layer/cesium/pointCloudCesium.js +58 -0
- package/src/vcs/vcm/layer/cesium/rasterLayerCesium.js +110 -0
- package/src/vcs/vcm/layer/cesium/singleImageCesium.js +49 -0
- package/src/vcs/vcm/layer/cesium/terrainCesium.js +80 -0
- package/src/vcs/vcm/layer/cesium/tmsCesium.js +54 -0
- package/src/vcs/vcm/layer/cesium/vectorCesium.js +255 -0
- package/src/vcs/vcm/layer/cesium/vectorContext.js +167 -0
- package/src/vcs/vcm/layer/cesium/vectorRasterTileCesium.js +116 -0
- package/src/vcs/vcm/layer/cesium/vectorTileImageryProvider.js +246 -0
- package/src/vcs/vcm/layer/cesium/wmsCesium.js +71 -0
- package/src/vcs/vcm/layer/cesium/wmtsCesium.js +101 -0
- package/src/vcs/vcm/layer/cesium/x3dmHelper.js +22 -0
- package/src/vcs/vcm/layer/cesiumTileset.js +376 -0
- package/src/vcs/vcm/layer/czml.js +141 -0
- package/src/vcs/vcm/layer/dataSource.js +259 -0
- package/src/vcs/vcm/layer/featureLayer.js +261 -0
- package/src/vcs/vcm/layer/featureStore.js +647 -0
- package/src/vcs/vcm/layer/featureStoreChanges.js +360 -0
- package/src/vcs/vcm/layer/featureStoreState.js +19 -0
- package/src/vcs/vcm/layer/featureVisibility.js +435 -0
- package/src/vcs/vcm/layer/geojson.js +185 -0
- package/src/vcs/vcm/layer/geojsonHelpers.js +450 -0
- package/src/vcs/vcm/layer/globalHider.js +157 -0
- package/src/vcs/vcm/layer/layer.js +752 -0
- package/src/vcs/vcm/layer/layerImplementation.js +102 -0
- package/src/vcs/vcm/layer/layerState.js +17 -0
- package/src/vcs/vcm/layer/layerSymbols.js +6 -0
- package/src/vcs/vcm/layer/oblique/layerOblique.js +76 -0
- package/src/vcs/vcm/layer/oblique/obliqueHelpers.js +175 -0
- package/src/vcs/vcm/layer/oblique/vectorOblique.js +469 -0
- package/src/vcs/vcm/layer/openStreetMap.js +194 -0
- package/src/vcs/vcm/layer/openlayers/layerOpenlayers.js +79 -0
- package/src/vcs/vcm/layer/openlayers/openStreetMapOpenlayers.js +27 -0
- package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +121 -0
- package/src/vcs/vcm/layer/openlayers/singleImageOpenlayers.js +49 -0
- package/src/vcs/vcm/layer/openlayers/tileDebugOpenlayers.js +39 -0
- package/src/vcs/vcm/layer/openlayers/tmsOpenlayers.js +62 -0
- package/src/vcs/vcm/layer/openlayers/vectorOpenlayers.js +118 -0
- package/src/vcs/vcm/layer/openlayers/vectorTileOpenlayers.js +177 -0
- package/src/vcs/vcm/layer/openlayers/wmsOpenlayers.js +55 -0
- package/src/vcs/vcm/layer/openlayers/wmtsOpenlayers.js +141 -0
- package/src/vcs/vcm/layer/pointCloud.js +162 -0
- package/src/vcs/vcm/layer/rasterLayer.js +294 -0
- package/src/vcs/vcm/layer/singleImage.js +119 -0
- package/src/vcs/vcm/layer/terrain.js +122 -0
- package/src/vcs/vcm/layer/terrainHelpers.js +123 -0
- package/src/vcs/vcm/layer/tileLoadedHelper.js +72 -0
- package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +104 -0
- package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +67 -0
- package/src/vcs/vcm/layer/tileProvider/tileProvider.js +584 -0
- package/src/vcs/vcm/layer/tileProvider/tileProviderFactory.js +28 -0
- package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +106 -0
- package/src/vcs/vcm/layer/tms.js +121 -0
- package/src/vcs/vcm/layer/vector.js +632 -0
- package/src/vcs/vcm/layer/vectorHelpers.js +206 -0
- package/src/vcs/vcm/layer/vectorProperties.js +1391 -0
- package/src/vcs/vcm/layer/vectorSymbols.js +40 -0
- package/src/vcs/vcm/layer/vectorTile.js +480 -0
- package/src/vcs/vcm/layer/wfs.js +165 -0
- package/src/vcs/vcm/layer/wms.js +270 -0
- package/src/vcs/vcm/layer/wmsHelpers.js +65 -0
- package/src/vcs/vcm/layer/wmts.js +235 -0
- package/src/vcs/vcm/maps/baseOLMap.js +257 -0
- package/src/vcs/vcm/maps/cameraLimiter.js +219 -0
- package/src/vcs/vcm/maps/cesium.js +1192 -0
- package/src/vcs/vcm/maps/map.js +511 -0
- package/src/vcs/vcm/maps/mapState.js +17 -0
- package/src/vcs/vcm/maps/oblique.js +536 -0
- package/src/vcs/vcm/maps/openlayers.js +205 -0
- package/src/vcs/vcm/object.js +92 -0
- package/src/vcs/vcm/oblique/ObliqueCollection.js +572 -0
- package/src/vcs/vcm/oblique/ObliqueDataSet.js +357 -0
- package/src/vcs/vcm/oblique/ObliqueImage.js +247 -0
- package/src/vcs/vcm/oblique/ObliqueImageMeta.js +126 -0
- package/src/vcs/vcm/oblique/ObliqueProvider.js +433 -0
- package/src/vcs/vcm/oblique/ObliqueView.js +130 -0
- package/src/vcs/vcm/oblique/ObliqueViewDirection.js +40 -0
- package/src/vcs/vcm/oblique/helpers.js +483 -0
- package/src/vcs/vcm/oblique/parseImageJson.js +248 -0
- package/src/vcs/vcm/util/clipping/clippingObject.js +386 -0
- package/src/vcs/vcm/util/clipping/clippingObjectManager.js +312 -0
- package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +413 -0
- package/src/vcs/vcm/util/collection.js +193 -0
- package/src/vcs/vcm/util/dateTime.js +60 -0
- package/src/vcs/vcm/util/exclusiveManager.js +135 -0
- package/src/vcs/vcm/util/extent.js +124 -0
- package/src/vcs/vcm/util/featureProvider/abstractFeatureProvider.js +196 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +51 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderSymbols.js +11 -0
- package/src/vcs/vcm/util/featureProvider/tileProviderFeatureProvider.js +62 -0
- package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +280 -0
- package/src/vcs/vcm/util/featureconverter/circleToCesium.js +215 -0
- package/src/vcs/vcm/util/featureconverter/convert.js +83 -0
- package/src/vcs/vcm/util/featureconverter/extent3d.js +154 -0
- package/src/vcs/vcm/util/featureconverter/featureconverterHelper.js +591 -0
- package/src/vcs/vcm/util/featureconverter/lineStringToCesium.js +171 -0
- package/src/vcs/vcm/util/featureconverter/pointToCesium.js +359 -0
- package/src/vcs/vcm/util/featureconverter/polygonToCesium.js +229 -0
- package/src/vcs/vcm/util/geometryHelpers.js +172 -0
- package/src/vcs/vcm/util/indexedCollection.js +158 -0
- package/src/vcs/vcm/util/isMobile.js +12 -0
- package/src/vcs/vcm/util/layerCollection.js +216 -0
- package/src/vcs/vcm/util/locale.js +53 -0
- package/src/vcs/vcm/util/mapCollection.js +363 -0
- package/src/vcs/vcm/util/math.js +71 -0
- package/src/vcs/vcm/util/projection.js +348 -0
- package/src/vcs/vcm/util/splitScreen.js +233 -0
- package/src/vcs/vcm/util/style/declarativeStyleItem.js +631 -0
- package/src/vcs/vcm/util/style/shapesCategory.js +67 -0
- package/src/vcs/vcm/util/style/styleFactory.js +48 -0
- package/src/vcs/vcm/util/style/styleHelpers.js +555 -0
- package/src/vcs/vcm/util/style/styleItem.js +226 -0
- package/src/vcs/vcm/util/style/vectorStyleItem.js +927 -0
- package/src/vcs/vcm/util/style/writeStyle.js +48 -0
- package/src/vcs/vcm/util/urlHelpers.js +16 -0
- package/src/vcs/vcm/util/viewpoint.js +333 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumeration of view directions.
|
|
3
|
+
* @enum {number}
|
|
4
|
+
* @property {number} NORTH
|
|
5
|
+
* @property {number} EAST
|
|
6
|
+
* @property {number} SOUTH
|
|
7
|
+
* @property {number} WEST
|
|
8
|
+
* @property {number} NADIR
|
|
9
|
+
* @export
|
|
10
|
+
* @api
|
|
11
|
+
*/
|
|
12
|
+
export const ObliqueViewDirection = {
|
|
13
|
+
NORTH: 1,
|
|
14
|
+
EAST: 2,
|
|
15
|
+
SOUTH: 3,
|
|
16
|
+
WEST: 4,
|
|
17
|
+
NADIR: 5,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @type {Object<string, ObliqueViewDirection>}
|
|
22
|
+
* @export
|
|
23
|
+
*/
|
|
24
|
+
export const obliqueViewDirectionNames = {
|
|
25
|
+
north: ObliqueViewDirection.NORTH,
|
|
26
|
+
east: ObliqueViewDirection.EAST,
|
|
27
|
+
south: ObliqueViewDirection.SOUTH,
|
|
28
|
+
west: ObliqueViewDirection.WEST,
|
|
29
|
+
nadir: ObliqueViewDirection.NADIR,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {number} direction
|
|
34
|
+
* @returns {string|undefined}
|
|
35
|
+
* @export
|
|
36
|
+
*/
|
|
37
|
+
export function getDirectionName(direction) {
|
|
38
|
+
return Object.keys(obliqueViewDirectionNames)
|
|
39
|
+
.find((name => obliqueViewDirectionNames[name] === direction));
|
|
40
|
+
}
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/* eslint no-underscore-dangle: ["error", { "allow": ["_listeners", "_scopes", "_toRemove"] }] */
|
|
2
|
+
/* eslint-disable no-continue */
|
|
3
|
+
import { boundingExtent, getBottomLeft, getBottomRight, getTopLeft, getTopRight } from 'ol/extent.js';
|
|
4
|
+
import { get as getProjection, transform } from 'ol/proj.js';
|
|
5
|
+
import { Cartesian2 } from '@vcmap/cesium';
|
|
6
|
+
import { ObliqueViewDirection } from './ObliqueViewDirection.js';
|
|
7
|
+
import { getHeightFromTerrainProvider } from '../layer/terrainHelpers.js';
|
|
8
|
+
import { cartesian2DDistance } from '../util/math.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @type {import("@vcmap/cesium").Cartesian2}
|
|
12
|
+
*/
|
|
13
|
+
let scratchCartesian2A = new Cartesian2();
|
|
14
|
+
/**
|
|
15
|
+
* @type {import("@vcmap/cesium").Cartesian2}
|
|
16
|
+
*/
|
|
17
|
+
let scratchCartesian2B = new Cartesian2();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {Object} PickTerrainReturn
|
|
21
|
+
* @property {boolean} estimate
|
|
22
|
+
* @property {import("ol/coordinate").Coordinate} coords
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* sorts the corner points of the json after [lower left, lower right, upper right, upper left]
|
|
27
|
+
* 3----2 ^
|
|
28
|
+
* | | |
|
|
29
|
+
* 0----1 north
|
|
30
|
+
* @param {Array<import("ol/coordinate").Coordinate>} inputCornerPoints
|
|
31
|
+
* @param {(ObliqueViewDirection|boolean)=} [sortDirection=false]
|
|
32
|
+
* @returns {Array<import("ol/coordinate").Coordinate>}
|
|
33
|
+
*/
|
|
34
|
+
export function sortRealWordEdgeCoordinates(inputCornerPoints, sortDirection = false) {
|
|
35
|
+
const cornerPoints = inputCornerPoints.slice();
|
|
36
|
+
const extent = boundingExtent(cornerPoints);
|
|
37
|
+
const extentPoints = [
|
|
38
|
+
getBottomLeft(extent),
|
|
39
|
+
getBottomRight(extent),
|
|
40
|
+
getTopRight(extent),
|
|
41
|
+
getTopLeft(extent),
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
let sorted = extentPoints.map((extentPoint) => {
|
|
45
|
+
let closest = 0;
|
|
46
|
+
let distance = Infinity;
|
|
47
|
+
cornerPoints.forEach((cornerPoint, cornerIndex) => {
|
|
48
|
+
const currentDistance = cartesian2DDistance(extentPoint, cornerPoint);
|
|
49
|
+
if (currentDistance < distance) {
|
|
50
|
+
distance = currentDistance;
|
|
51
|
+
closest = cornerIndex;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return cornerPoints.splice(closest, 1)[0];
|
|
55
|
+
});
|
|
56
|
+
if (sortDirection === ObliqueViewDirection.EAST) {
|
|
57
|
+
sorted = [sorted[3], sorted[0], sorted[1], sorted[2]];
|
|
58
|
+
} else if (sortDirection === ObliqueViewDirection.SOUTH) {
|
|
59
|
+
sorted = [sorted[2], sorted[3], sorted[0], sorted[1]];
|
|
60
|
+
} else if (sortDirection === ObliqueViewDirection.WEST) {
|
|
61
|
+
sorted = [sorted[1], sorted[2], sorted[3], sorted[0]];
|
|
62
|
+
}
|
|
63
|
+
return sorted;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {import("ol/coordinate").Coordinate} v1
|
|
68
|
+
* @param {import("ol/coordinate").Coordinate} v2
|
|
69
|
+
* @returns {number|null}
|
|
70
|
+
*/
|
|
71
|
+
function angleBetweenTwo2DVectors(v1, v2) {
|
|
72
|
+
scratchCartesian2A = Cartesian2.fromElements(v1[0], v1[1], scratchCartesian2A);
|
|
73
|
+
scratchCartesian2B = Cartesian2.fromElements(v2[0], v2[1], scratchCartesian2B);
|
|
74
|
+
return Cartesian2.angleBetween(scratchCartesian2A, scratchCartesian2B);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* taken from http://jsfiddle.net/justin_c_rounds/Gd2S2/
|
|
79
|
+
* @param {Array<import("ol/coordinate").Coordinate>} segment1
|
|
80
|
+
* @param {Array<import("ol/coordinate").Coordinate>} segment2
|
|
81
|
+
* @returns {{x: (number|null), y:(number|null), onLine1: boolean, onLine2: boolean}}
|
|
82
|
+
* @export
|
|
83
|
+
*/
|
|
84
|
+
export function checkLineIntersection(segment1, segment2) {
|
|
85
|
+
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
|
|
86
|
+
const [[line1StartX, line1StartY], [line1EndX, line1EndY]] = segment1;
|
|
87
|
+
const [[line2StartX, line2StartY], [line2EndX, line2EndY]] = segment2;
|
|
88
|
+
let a;
|
|
89
|
+
let b;
|
|
90
|
+
|
|
91
|
+
const result = {
|
|
92
|
+
x: null,
|
|
93
|
+
y: null,
|
|
94
|
+
onLine1: false,
|
|
95
|
+
onLine2: false,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const denominator =
|
|
99
|
+
((line2EndY - line2StartY) * (line1EndX - line1StartX)) -
|
|
100
|
+
((line2EndX - line2StartX) * (line1EndY - line1StartY));
|
|
101
|
+
|
|
102
|
+
if (denominator === 0) {
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
a = line1StartY - line2StartY;
|
|
106
|
+
b = line1StartX - line2StartX;
|
|
107
|
+
const numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
|
|
108
|
+
const numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
|
|
109
|
+
a = numerator1 / denominator;
|
|
110
|
+
b = numerator2 / denominator;
|
|
111
|
+
|
|
112
|
+
// if we cast these lines infinitely in both directions, they intersect here:
|
|
113
|
+
result.x = line1StartX + (a * (line1EndX - line1StartX));
|
|
114
|
+
result.y = line1StartY + (a * (line1EndY - line1StartY));
|
|
115
|
+
/*
|
|
116
|
+
// it is worth noting that this should be the same as:
|
|
117
|
+
x = line2StartX + (b * (line2EndX - line2StartX));
|
|
118
|
+
y = line2StartX + (b * (line2EndY - line2StartY));
|
|
119
|
+
*/
|
|
120
|
+
// if line1 is a segment and line2 is infinite, they intersect if:
|
|
121
|
+
if (a > 0 && a < 1) {
|
|
122
|
+
result.onLine1 = true;
|
|
123
|
+
}
|
|
124
|
+
// if line2 is a segment and line1 is infinite, they intersect if:
|
|
125
|
+
if (b > 0 && b < 1) {
|
|
126
|
+
result.onLine2 = true;
|
|
127
|
+
}
|
|
128
|
+
// if line1 and line2 are segments, they intersect if both of the above are true
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* transforms coordinate with intersection from corner
|
|
134
|
+
* @param {Array<import("ol/coordinate").Coordinate>} inputOrigin
|
|
135
|
+
* @param {Array<import("ol/coordinate").Coordinate>} inputTarget
|
|
136
|
+
* @param {boolean} originIsImage
|
|
137
|
+
* @param {import("ol/coordinate").Coordinate} coordinate2Transform
|
|
138
|
+
* @param {ObliqueViewDirection} viewDirection
|
|
139
|
+
* @returns {{x: (number|null), y:(number|null), onLine1: boolean, onLine2: boolean}|null}
|
|
140
|
+
*/
|
|
141
|
+
export function transformCWIFC(inputOrigin, inputTarget, originIsImage, coordinate2Transform, viewDirection) {
|
|
142
|
+
const origin = sortRealWordEdgeCoordinates(inputOrigin, originIsImage ? false : viewDirection);
|
|
143
|
+
const target = sortRealWordEdgeCoordinates(inputTarget, originIsImage ? viewDirection : false);
|
|
144
|
+
|
|
145
|
+
// test intersections from all corner points over coordinate to all non neighbouring borders
|
|
146
|
+
// and non side borders too - so actually remains only upper and lower border
|
|
147
|
+
// and store:
|
|
148
|
+
// - from which corner point,
|
|
149
|
+
// - intersection,
|
|
150
|
+
// - angle of intersection
|
|
151
|
+
// - as well as edge (ccw) and
|
|
152
|
+
// - distance ratio while negative means negative direction
|
|
153
|
+
// to be able to recreate the situation in the target system
|
|
154
|
+
const intersections = [];
|
|
155
|
+
for (let cp = 0; cp < origin.length; ++cp) { // TODO write into a proper map and function
|
|
156
|
+
const intrCurrCP = [];
|
|
157
|
+
|
|
158
|
+
for (let sp = 0; sp < origin.length; ++sp) {
|
|
159
|
+
const ep = sp === origin.length - 1 ? 0 : sp + 1; // end point of edge
|
|
160
|
+
|
|
161
|
+
// skip if cp is sp or ep - neighbouring edge
|
|
162
|
+
if (cp === sp || cp === ep) { continue; }
|
|
163
|
+
|
|
164
|
+
// skip also if sp is 3 and ep is 0 and also skip sp is 1 and ep is 2 since does only work over the upper and lower boundary
|
|
165
|
+
if ((sp === 3 && ep === 0) || (sp === 1 && ep === 2)) { continue; }
|
|
166
|
+
|
|
167
|
+
// get intersection from cp over coordinate2Transform to current border edge
|
|
168
|
+
const currIntr = checkLineIntersection([origin[cp], coordinate2Transform], [origin[sp], origin[ep]]);
|
|
169
|
+
if (currIntr.x == null || currIntr.y == null) { continue; }
|
|
170
|
+
|
|
171
|
+
// get vector from current cp to coordinate2Transform to be able to determine if the intersection is in same direction
|
|
172
|
+
// might be in different direction when point is outside - then we dont need this data
|
|
173
|
+
const vectorCP2Coordinate = [coordinate2Transform[0] - origin[cp][0], coordinate2Transform[1] - origin[cp][1]];
|
|
174
|
+
const vectorCP2Intr = [currIntr.x - origin[cp][0], currIntr.y - origin[cp][1]];
|
|
175
|
+
const angleDirectionCheck = angleBetweenTwo2DVectors(vectorCP2Coordinate, vectorCP2Intr);
|
|
176
|
+
if (angleDirectionCheck == null) { continue; }
|
|
177
|
+
|
|
178
|
+
if (angleDirectionCheck / (Math.PI * 180.0) > 5) { continue; }
|
|
179
|
+
|
|
180
|
+
const sp2ep = [origin[sp][0] - origin[ep][0], origin[sp][1] - origin[ep][1]];
|
|
181
|
+
const ep2sp = [origin[ep][0] - origin[sp][0], origin[ep][1] - origin[sp][1]];
|
|
182
|
+
// regarding the angle find the smallest
|
|
183
|
+
const angleStart2End = angleBetweenTwo2DVectors(vectorCP2Coordinate, sp2ep);
|
|
184
|
+
if (angleStart2End == null) { continue; }
|
|
185
|
+
|
|
186
|
+
const angleEnd2Start = angleBetweenTwo2DVectors(vectorCP2Coordinate, ep2sp);
|
|
187
|
+
if (angleEnd2Start == null) { continue; }
|
|
188
|
+
|
|
189
|
+
// regarding ratioStart2End get ratio and then direction
|
|
190
|
+
const distStartEnd = cartesian2DDistance(origin[sp], origin[ep]);
|
|
191
|
+
if (distStartEnd === 0) { continue; }
|
|
192
|
+
const tempRatioStartEnd = cartesian2DDistance(origin[sp], [currIntr.x, currIntr.y]) / distStartEnd;
|
|
193
|
+
let angleEdge2Intr = 0;
|
|
194
|
+
if (tempRatioStartEnd !== 0) {
|
|
195
|
+
angleEdge2Intr = angleBetweenTwo2DVectors(ep2sp, [currIntr.x - origin[sp][0], currIntr.y - origin[sp][1]]);
|
|
196
|
+
if (angleEdge2Intr == null) { continue; }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
intrCurrCP.push({
|
|
200
|
+
cornerPoint: cp,
|
|
201
|
+
intrX: currIntr.x,
|
|
202
|
+
intrY: currIntr.y,
|
|
203
|
+
angle: angleStart2End <= angleEnd2Start ? angleStart2End : angleEnd2Start,
|
|
204
|
+
edgeStart: sp,
|
|
205
|
+
edgeEnd: ep,
|
|
206
|
+
ratioStart2End: (angleEdge2Intr / Math.PI) * 180.0 > 5 ? tempRatioStartEnd * (-1) : tempRatioStartEnd,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// after getting the data find the intersection with largest of smallest angles
|
|
211
|
+
let largestAngle = -1;
|
|
212
|
+
let indLargestAngle = -1;
|
|
213
|
+
for (let i = 0; i < intrCurrCP.length; ++i) {
|
|
214
|
+
if (intrCurrCP[i].angle > largestAngle) {
|
|
215
|
+
largestAngle = intrCurrCP[i].angle;
|
|
216
|
+
indLargestAngle = i;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (indLargestAngle !== -1) { intersections.push(intrCurrCP[indLargestAngle]); }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// if we don not have enough data to recreate the situation in target system stop
|
|
223
|
+
if (intersections.length < 2) { return null; }
|
|
224
|
+
|
|
225
|
+
// make list with intersection combinations and sort after strength (add angles together)
|
|
226
|
+
const intrCombis = []; // will contain [addedAngle, intersectionsIndex_i, intersectionsIndex_j]
|
|
227
|
+
for (let i = 0; i < intersections.length; ++i) {
|
|
228
|
+
for (let j = i + 1; j < intersections.length; ++j) {
|
|
229
|
+
intrCombis.push([intersections[i].angle + intersections[j].angle, i, j]);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
let intrCross = null;
|
|
234
|
+
intrCombis
|
|
235
|
+
.sort()
|
|
236
|
+
.reverse()
|
|
237
|
+
.find((intersection) => {
|
|
238
|
+
const intersectionsSorted = [intersections[intersection[1]], intersections[intersection[2]]];
|
|
239
|
+
|
|
240
|
+
const targetEdgeEnd0 = target[intersectionsSorted[0].edgeEnd];
|
|
241
|
+
const targetEdgeStart0 = target[intersectionsSorted[0].edgeStart];
|
|
242
|
+
// test angle of lines with that the intersection will be calculated - if two small skip
|
|
243
|
+
const targetEdgeVectorFor0 = [
|
|
244
|
+
targetEdgeEnd0[0] - targetEdgeStart0[0],
|
|
245
|
+
targetEdgeEnd0[1] - targetEdgeStart0[1],
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
const intrFor0InTarget = [
|
|
249
|
+
targetEdgeStart0[0] + (targetEdgeVectorFor0[0] * intersectionsSorted[0].ratioStart2End),
|
|
250
|
+
targetEdgeStart0[1] + (targetEdgeVectorFor0[1] * intersectionsSorted[0].ratioStart2End),
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
const targetEdgeEnd1 = target[intersectionsSorted[1].edgeEnd];
|
|
254
|
+
const targetEdgeStart1 = target[intersectionsSorted[1].edgeStart];
|
|
255
|
+
|
|
256
|
+
const targetEdgeVectorFor1 = [targetEdgeEnd1[0] - targetEdgeStart1[0], targetEdgeEnd1[1] - targetEdgeStart1[1]];
|
|
257
|
+
const intrFor1InTarget = [
|
|
258
|
+
targetEdgeStart1[0] + (targetEdgeVectorFor1[0] * intersectionsSorted[1].ratioStart2End),
|
|
259
|
+
targetEdgeStart1[1] + (targetEdgeVectorFor1[1] * intersectionsSorted[1].ratioStart2End),
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const vecCP0ToIntr0 = [
|
|
263
|
+
intrFor0InTarget[0] - target[intersectionsSorted[0].cornerPoint][0],
|
|
264
|
+
intrFor0InTarget[1] - target[intersectionsSorted[0].cornerPoint][1],
|
|
265
|
+
];
|
|
266
|
+
const vecCP1ToIntr1 = [
|
|
267
|
+
intrFor1InTarget[0] - target[intersectionsSorted[1].cornerPoint][0],
|
|
268
|
+
intrFor1InTarget[1] - target[intersectionsSorted[1].cornerPoint][1],
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
const angleCross = angleBetweenTwo2DVectors(vecCP0ToIntr0, vecCP1ToIntr1);
|
|
272
|
+
if (angleCross == null) { return false; }
|
|
273
|
+
/* var thresholdInDegree = 3;
|
|
274
|
+
if (angleCross/Math.PI*180.0 < thresholdInDegree || angleCross/Math.PI*180.0 > 180-thresholdInDegree)
|
|
275
|
+
continue; */
|
|
276
|
+
|
|
277
|
+
// get point in target
|
|
278
|
+
intrCross = checkLineIntersection(
|
|
279
|
+
[target[intersectionsSorted[0].cornerPoint], intrFor0InTarget],
|
|
280
|
+
[target[intersectionsSorted[1].cornerPoint], intrFor1InTarget],
|
|
281
|
+
);
|
|
282
|
+
if (intrCross.x == null || intrCross.y == null) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return true;
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return intrCross;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @typedef {Object} ImageTransformationOptions
|
|
294
|
+
* @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 {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
|
+
* @property {number|undefined} [terrainErrorCountThreshold=3] - how often the transformToWorld process iterativly calculates a new Height Value from the terrainProvider
|
|
298
|
+
* @api
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Always returns a Promise. When the input coordinates contain a height, it will use this height to compute the image coordinates
|
|
303
|
+
* When not, it will try to get the terrainHeight in case a terrain is defined and use the height from there, to compute the image coordinates
|
|
304
|
+
* @param {import("@vcmap/core").ObliqueImage} image
|
|
305
|
+
* @param {import("ol/coordinate").Coordinate} worldCoordinate if not in web mercatpr, specify data-projection in options
|
|
306
|
+
* @param {ImageTransformationOptions=} options
|
|
307
|
+
* @returns {Promise<{coords: import("ol/coordinate").Coordinate, height: number, estimate: (boolean|undefined)}>}
|
|
308
|
+
* @export
|
|
309
|
+
*/
|
|
310
|
+
export function transformToImage(image, worldCoordinate, options = {}) {
|
|
311
|
+
let gpInternalCoordinates;
|
|
312
|
+
if (options.dataProjection && options.dataProjection === image.meta.projection) {
|
|
313
|
+
gpInternalCoordinates = worldCoordinate;
|
|
314
|
+
} else {
|
|
315
|
+
gpInternalCoordinates = options.dataProjection ?
|
|
316
|
+
transform(worldCoordinate, options.dataProjection, image.meta.projection) :
|
|
317
|
+
transform(worldCoordinate, 'EPSG:3857', image.meta.projection);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function useAverageHeight() {
|
|
321
|
+
const coords = image.transformRealWorld2Image(gpInternalCoordinates);
|
|
322
|
+
return { coords, height: image.averageHeight, estimate: true };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (worldCoordinate[2]) {
|
|
326
|
+
const coords = image.transformRealWorld2Image(gpInternalCoordinates, worldCoordinate[2]);
|
|
327
|
+
return Promise.resolve({ coords, height: worldCoordinate[2], estimate: false });
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (!options.dontUseTerrain && image.meta.terrainProvider) {
|
|
331
|
+
return getHeightFromTerrainProvider(image.meta.terrainProvider, [gpInternalCoordinates], image.meta.projection)
|
|
332
|
+
.then(([gpWithHeight]) => {
|
|
333
|
+
if (gpWithHeight[2]) {
|
|
334
|
+
const imageCoordinates = image.transformRealWorld2Image(gpInternalCoordinates, gpWithHeight[2]);
|
|
335
|
+
return { coords: imageCoordinates, height: gpInternalCoordinates[2], estimate: false };
|
|
336
|
+
}
|
|
337
|
+
// eslint-disable-next-line no-console
|
|
338
|
+
console.warn('The configured terrain on the oblique layer could not be queried, position might be inaccurate');
|
|
339
|
+
return useAverageHeight();
|
|
340
|
+
})
|
|
341
|
+
.catch(() => useAverageHeight());
|
|
342
|
+
}
|
|
343
|
+
return Promise.resolve(useAverageHeight());
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @typedef {Object} PickTerrainOptions
|
|
348
|
+
* @property {import("@vcmap/core").ObliqueImage} image
|
|
349
|
+
* @property {import("ol/coordinate").Coordinate} worldCoordinate
|
|
350
|
+
* @property {import("ol/coordinate").Coordinate} imageCoordinate
|
|
351
|
+
* @property {number} height
|
|
352
|
+
* @property {number} terrainErrorThreshold
|
|
353
|
+
* @property {number} terrainErrorCountThreshold
|
|
354
|
+
* @property {number} count
|
|
355
|
+
*/
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* @param {PickTerrainOptions} pickTerrainOptions
|
|
359
|
+
* @returns {Promise<PickTerrainReturn>}
|
|
360
|
+
*/
|
|
361
|
+
function pickTerrain(pickTerrainOptions) {
|
|
362
|
+
pickTerrainOptions.count += 1;
|
|
363
|
+
const {
|
|
364
|
+
image,
|
|
365
|
+
worldCoordinate,
|
|
366
|
+
imageCoordinate,
|
|
367
|
+
terrainErrorThreshold,
|
|
368
|
+
terrainErrorCountThreshold,
|
|
369
|
+
count,
|
|
370
|
+
height,
|
|
371
|
+
} = pickTerrainOptions;
|
|
372
|
+
const wgs84Projection = getProjection('EPSG:4326');
|
|
373
|
+
return getHeightFromTerrainProvider(image.meta.terrainProvider, [worldCoordinate])
|
|
374
|
+
.then(([worldCoordinateWithHeights]) => {
|
|
375
|
+
if (worldCoordinateWithHeights[2] != null) {
|
|
376
|
+
const newWorldCoords = transform(
|
|
377
|
+
image.transformImage2RealWorld(imageCoordinate, worldCoordinateWithHeights[2]),
|
|
378
|
+
image.meta.projection,
|
|
379
|
+
wgs84Projection,
|
|
380
|
+
);
|
|
381
|
+
newWorldCoords[2] = worldCoordinateWithHeights[2];
|
|
382
|
+
if (
|
|
383
|
+
Math.abs(height - worldCoordinateWithHeights[2]) < terrainErrorThreshold ||
|
|
384
|
+
(count > terrainErrorCountThreshold)
|
|
385
|
+
) {
|
|
386
|
+
return { coords: newWorldCoords, estimate: false };
|
|
387
|
+
}
|
|
388
|
+
pickTerrainOptions.height = newWorldCoords[2];
|
|
389
|
+
pickTerrainOptions.worldCoordinate = worldCoordinateWithHeights;
|
|
390
|
+
return pickTerrain(pickTerrainOptions);
|
|
391
|
+
}
|
|
392
|
+
// eslint-disable-next-line no-console
|
|
393
|
+
console.log('The configured terrain on the oblique layer could not be queried, position might be inaccurate');
|
|
394
|
+
return { coords: worldCoordinateWithHeights, estimate: true };
|
|
395
|
+
})
|
|
396
|
+
.catch(() => ({ coords: worldCoordinate, estimate: true }));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Always returns a deferred.
|
|
401
|
+
* it will try to get the terrainHeight in case a terrain is defined.
|
|
402
|
+
* @param {import("@vcmap/core").ObliqueImage} image
|
|
403
|
+
* @param {import("ol/coordinate").Coordinate} imageCoordinate
|
|
404
|
+
* @param {ImageTransformationOptions=} options
|
|
405
|
+
* @returns {Promise<PickTerrainReturn>} return coordinates are in mercator if not specified in options
|
|
406
|
+
* @export
|
|
407
|
+
*/
|
|
408
|
+
export async function transformFromImage(image, imageCoordinate, options = {}) {
|
|
409
|
+
const wgs84Projection = getProjection('EPSG:4326');
|
|
410
|
+
const initialWorldCoords = transform(
|
|
411
|
+
image.transformImage2RealWorld(imageCoordinate, image.averageHeight),
|
|
412
|
+
image.meta.projection,
|
|
413
|
+
wgs84Projection,
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const terrainErrorThreshold = options.terrainErrorThreshold || 1;
|
|
417
|
+
const terrainErrorCountThreshold = options.terrainErrorCountThreshold || 3;
|
|
418
|
+
|
|
419
|
+
let coordsObj = { coords: initialWorldCoords, estimate: true };
|
|
420
|
+
if (!options.dontUseTerrain && image.meta.terrainProvider) {
|
|
421
|
+
coordsObj = await pickTerrain({
|
|
422
|
+
worldCoordinate: initialWorldCoords,
|
|
423
|
+
imageCoordinate,
|
|
424
|
+
image,
|
|
425
|
+
count: 0,
|
|
426
|
+
height: image.averageHeight,
|
|
427
|
+
terrainErrorThreshold,
|
|
428
|
+
terrainErrorCountThreshold,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
coordsObj.coords = options.dataProjection ?
|
|
433
|
+
transform(coordsObj.coords, wgs84Projection, options.dataProjection) :
|
|
434
|
+
transform(coordsObj.coords, wgs84Projection, getProjection('EPSG:3857'));
|
|
435
|
+
return coordsObj;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @param {string} url
|
|
440
|
+
* @returns {boolean}
|
|
441
|
+
*/
|
|
442
|
+
export function hasSameOrigin(url) {
|
|
443
|
+
// relative Url, return true;
|
|
444
|
+
if (!/^[a-z][a-z0-9+.-]*:/.test(url)) {
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
// data uri, return true
|
|
448
|
+
if (/^data:/.test(url)) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const currentUri = new URL(window.location.href);
|
|
453
|
+
const uri = new URL(url);
|
|
454
|
+
return currentUri.host.toLowerCase() === uri.host.toLocaleLowerCase();
|
|
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
|
+
}
|