itowns 2.44.3-next.21 → 2.44.3-next.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/itowns.js +1 -1
- package/dist/itowns.js.map +1 -1
- package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
- package/examples/source_file_geojson_3d.html +0 -1
- package/examples/source_stream_wfs_raster.html +0 -7
- package/lib/Converter/Feature2Mesh.js +1 -2
- package/lib/Converter/Feature2Texture.js +3 -1
- package/lib/Converter/convertToTile.js +3 -3
- package/lib/Converter/textureConverter.js +1 -2
- package/lib/Core/Feature.js +1 -2
- package/lib/Core/Geographic/Coordinates.js +1 -1
- package/lib/Core/Geographic/Crs.js +114 -144
- package/lib/Core/Geographic/Extent.js +2 -5
- package/lib/Core/Geographic/GeoidGrid.js +1 -1
- package/lib/Core/Prefab/Globe/Atmosphere.js +4 -2
- package/lib/Core/Prefab/Globe/GlobeLayer.js +21 -14
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
- package/lib/Core/Prefab/GlobeView.js +2 -3
- package/lib/Core/Prefab/Planar/PlanarLayer.js +16 -10
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
- package/lib/Core/Prefab/TileBuilder.js +27 -32
- package/lib/Core/Prefab/computeBufferTileGeometry.js +189 -130
- package/lib/Core/Tile/Tile.js +4 -4
- package/lib/Core/Tile/TileGrid.js +7 -10
- package/lib/Core/TileGeometry.js +112 -28
- package/lib/Core/TileMesh.js +1 -2
- package/lib/Core/View.js +2 -2
- package/lib/Layer/C3DTilesLayer.js +7 -4
- package/lib/Layer/ColorLayer.js +35 -9
- package/lib/Layer/CopcLayer.js +5 -0
- package/lib/Layer/ElevationLayer.js +39 -7
- package/lib/Layer/EntwinePointTileLayer.js +12 -5
- package/lib/Layer/FeatureGeometryLayer.js +20 -6
- package/lib/Layer/GeometryLayer.js +42 -11
- package/lib/Layer/LabelLayer.js +11 -5
- package/lib/Layer/Layer.js +83 -57
- package/lib/Layer/OGC3DTilesLayer.js +3 -2
- package/lib/Layer/OrientedImageLayer.js +12 -4
- package/lib/Layer/PointCloudLayer.js +69 -23
- package/lib/Layer/Potree2Layer.js +7 -2
- package/lib/Layer/PotreeLayer.js +8 -3
- package/lib/Layer/RasterLayer.js +12 -2
- package/lib/Layer/TiledGeometryLayer.js +69 -13
- package/lib/Main.js +1 -1
- package/lib/Provider/Fetcher.js +5 -1
- package/lib/Renderer/OBB.js +11 -13
- package/lib/Renderer/RasterTile.js +1 -2
- package/lib/Source/FileSource.js +1 -2
- package/lib/Source/Source.js +1 -1
- package/lib/Source/TMSSource.js +2 -3
- package/lib/Source/WFSSource.js +1 -2
- package/package.json +3 -3
- package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
"updateStrategy": {
|
|
5
5
|
"type": 0
|
|
6
6
|
},
|
|
7
|
-
"
|
|
7
|
+
"clampValues": {
|
|
8
|
+
"min": -12000
|
|
9
|
+
},
|
|
8
10
|
"source": {
|
|
9
11
|
"url": "https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/geoid/geoid/bil/%TILEMATRIX/geoid_%COL_%ROW.bil",
|
|
10
12
|
"format": "image/x-bil;bits=32",
|
|
@@ -53,12 +53,6 @@
|
|
|
53
53
|
itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig);
|
|
54
54
|
itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig);
|
|
55
55
|
|
|
56
|
-
function isValidData(data) {
|
|
57
|
-
if(data.features[0].geometries.length < 1000) {
|
|
58
|
-
return data;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
56
|
var wfsBuildingSource = new itowns.WFSSource({
|
|
63
57
|
url: 'https://data.geopf.fr/wfs/ows?',
|
|
64
58
|
version: '2.0.0',
|
|
@@ -102,7 +96,6 @@
|
|
|
102
96
|
width: 2.0,
|
|
103
97
|
},
|
|
104
98
|
},
|
|
105
|
-
isValidData: isValidData,
|
|
106
99
|
source: wfsBuildingSource,
|
|
107
100
|
zoom: { max: 20, min: 13 },
|
|
108
101
|
});
|
|
@@ -4,7 +4,6 @@ import { FEATURE_TYPES } from "../Core/Feature.js";
|
|
|
4
4
|
import ReferLayerProperties from "../Layer/ReferencingLayerProperties.js";
|
|
5
5
|
import { deprecatedFeature2MeshOptions } from "../Core/Deprecated/Undeprecator.js";
|
|
6
6
|
import Extent from "../Core/Geographic/Extent.js";
|
|
7
|
-
import Crs from "../Core/Geographic/Crs.js";
|
|
8
7
|
import OrientationUtils from "../Utils/OrientationUtils.js";
|
|
9
8
|
import Coordinates from "../Core/Geographic/Coordinates.js";
|
|
10
9
|
import Style, { StyleContext } from "../Core/Style.js";
|
|
@@ -54,7 +53,7 @@ class FeatureMesh extends THREE.Group {
|
|
|
54
53
|
} else {
|
|
55
54
|
// calculate the scale transformation to transform the feature.extent
|
|
56
55
|
// to feature.extent.as(crs)
|
|
57
|
-
coord.crs =
|
|
56
|
+
coord.crs = this.#originalCrs;
|
|
58
57
|
// TODO: An extent here could be either a geographic extent (for
|
|
59
58
|
// features from WFS) or a tiled extent (for features from MVT).
|
|
60
59
|
// Unify both behavior.
|
|
@@ -114,7 +114,9 @@ export default {
|
|
|
114
114
|
coord.crs = extent.crs;
|
|
115
115
|
c.width = sizeTexture;
|
|
116
116
|
c.height = sizeTexture;
|
|
117
|
-
const ctx = c.getContext('2d'
|
|
117
|
+
const ctx = c.getContext('2d', {
|
|
118
|
+
willReadFrequently: true
|
|
119
|
+
});
|
|
118
120
|
if (backgroundColor) {
|
|
119
121
|
ctx.fillStyle = backgroundColor.getStyle();
|
|
120
122
|
ctx.fillRect(0, 0, sizeTexture, sizeTexture);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import * as THREE from 'three';
|
|
7
7
|
import TileMesh from "../Core/TileMesh.js";
|
|
8
8
|
import LayeredMaterial from "../Renderer/LayeredMaterial.js";
|
|
9
|
-
import newTileGeometry from "../Core/Prefab/TileBuilder.js";
|
|
9
|
+
import { newTileGeometry } from "../Core/Prefab/TileBuilder.js";
|
|
10
10
|
import ReferLayerProperties from "../Layer/ReferencingLayerProperties.js";
|
|
11
11
|
import { geoidLayerIsVisible } from "../Layer/GeoidLayer.js";
|
|
12
12
|
const dimensions = new THREE.Vector2();
|
|
@@ -42,14 +42,14 @@ export default {
|
|
|
42
42
|
};
|
|
43
43
|
return newTileGeometry(builder, paramsGeometry).then(result => {
|
|
44
44
|
// build tile mesh
|
|
45
|
-
result.geometry.
|
|
45
|
+
result.geometry.increaseRefCount();
|
|
46
46
|
const crsCount = layer.tileMatrixSets.length;
|
|
47
47
|
const material = new LayeredMaterial(layer.materialOptions, crsCount);
|
|
48
48
|
ReferLayerProperties(material, layer);
|
|
49
49
|
const tile = new TileMesh(result.geometry, material, layer, extent, level);
|
|
50
50
|
if (parent && parent.isTileMesh) {
|
|
51
51
|
// get parent extent transformation
|
|
52
|
-
const pTrans = builder.
|
|
52
|
+
const pTrans = builder.computeShareableExtent(parent.extent);
|
|
53
53
|
// place relative to his parent
|
|
54
54
|
result.position.sub(pTrans.position).applyQuaternion(pTrans.quaternion.invert());
|
|
55
55
|
result.quaternion.premultiply(pTrans.quaternion);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import Feature2Texture from "./Feature2Texture.js";
|
|
3
3
|
import Extent from "../Core/Geographic/Extent.js";
|
|
4
|
-
import CRS from "../Core/Geographic/Crs.js";
|
|
5
4
|
const extentTexture = new Extent('EPSG:4326', [0, 0, 0, 0]);
|
|
6
5
|
const textureLayer = (texture, layer) => {
|
|
7
6
|
texture.generateMipmaps = false;
|
|
@@ -20,7 +19,7 @@ export default {
|
|
|
20
19
|
if (data.isFeatureCollection) {
|
|
21
20
|
const backgroundLayer = layer.source.backgroundLayer;
|
|
22
21
|
const backgroundColor = backgroundLayer && backgroundLayer.paint ? new THREE.Color(backgroundLayer.paint['background-color']) : undefined;
|
|
23
|
-
destinationTile.toExtent(
|
|
22
|
+
destinationTile.toExtent(layer.crs, extentTexture);
|
|
24
23
|
texture = Feature2Texture.createTextureFromFeature(data, extentTexture, layer.subdivisionThreshold, layer.style, backgroundColor);
|
|
25
24
|
texture.features = data;
|
|
26
25
|
texture.extent = destinationTile;
|
package/lib/Core/Feature.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import Extent from "./Geographic/Extent.js";
|
|
3
3
|
import Coordinates from "./Geographic/Coordinates.js";
|
|
4
|
-
import CRS from "./Geographic/Crs.js";
|
|
5
4
|
import Style from "./Style.js";
|
|
6
5
|
function defaultExtent(crs) {
|
|
7
6
|
return new Extent(crs, Infinity, -Infinity, Infinity, -Infinity);
|
|
@@ -340,7 +339,7 @@ export class FeatureCollection extends THREE.Object3D {
|
|
|
340
339
|
constructor(options) {
|
|
341
340
|
super();
|
|
342
341
|
this.isFeatureCollection = true;
|
|
343
|
-
this.crs =
|
|
342
|
+
this.crs = options.accurate || !options.source?.crs ? options.crs : options.source.crs;
|
|
344
343
|
this.features = [];
|
|
345
344
|
this.mergeFeatures = options.mergeFeatures === undefined ? true : options.mergeFeatures;
|
|
346
345
|
this.size = options.structure == '3d' ? 3 : 2;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import proj4 from 'proj4';
|
|
3
|
-
import CRS from "./Crs.js";
|
|
3
|
+
import * as CRS from "./Crs.js";
|
|
4
4
|
import Ellipsoid from "../Math/Ellipsoid.js";
|
|
5
5
|
proj4.defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs');
|
|
6
6
|
const ellipsoid = new Ellipsoid();
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import proj4 from 'proj4';
|
|
2
2
|
proj4.defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A projection as a CRS identifier string. This identifier references a
|
|
6
|
+
* projection definition previously defined with
|
|
7
|
+
* [`proj4.defs`](https://github.com/proj4js/proj4js#named-projections).
|
|
8
|
+
*/
|
|
9
|
+
|
|
3
10
|
function isString(s) {
|
|
4
11
|
return typeof s === 'string' || s instanceof String;
|
|
5
12
|
}
|
|
@@ -8,168 +15,131 @@ function mustBeString(crs) {
|
|
|
8
15
|
throw new Error(`Crs parameter value must be a string: '${crs}'`);
|
|
9
16
|
}
|
|
10
17
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function formatToEPSG(crs) {
|
|
22
|
-
mustBeString(crs);
|
|
23
|
-
return isEpsg(crs) ? crs : `EPSG:${crs.match(/\d+/)[0]}`;
|
|
24
|
-
}
|
|
25
|
-
const UNIT = {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* System units supported for a coordinate system. See
|
|
21
|
+
* [proj](https://proj4.org/en/9.5/operations/conversions/unitconvert.html#angular-units).
|
|
22
|
+
* Note that only degree and meters units are supported for now.
|
|
23
|
+
*/
|
|
24
|
+
export const UNIT = {
|
|
25
|
+
/**
|
|
26
|
+
* Angular unit in degree.
|
|
27
|
+
*/
|
|
26
28
|
DEGREE: 1,
|
|
29
|
+
/**
|
|
30
|
+
* Distance unit in meter.
|
|
31
|
+
*/
|
|
27
32
|
METER: 2
|
|
28
33
|
};
|
|
29
|
-
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks that the CRS is EPSG:4326.
|
|
37
|
+
* @internal
|
|
38
|
+
*
|
|
39
|
+
* @param crs - The CRS to test.
|
|
40
|
+
*/
|
|
41
|
+
export function is4326(crs) {
|
|
30
42
|
return crs === 'EPSG:4326';
|
|
31
43
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
const projection = proj4.defs(crs);
|
|
35
|
-
return !projection ? false : projection.projName == 'geocent';
|
|
36
|
-
}
|
|
37
|
-
function _unitFromProj4Unit(projunit) {
|
|
38
|
-
if (projunit === 'degrees') {
|
|
44
|
+
function unitFromProj4Unit(proj) {
|
|
45
|
+
if (proj.units === 'degrees') {
|
|
39
46
|
return UNIT.DEGREE;
|
|
40
|
-
} else if (
|
|
47
|
+
} else if (proj.units === 'm') {
|
|
48
|
+
return UNIT.METER;
|
|
49
|
+
} else if (proj.units === undefined && proj.to_meter === undefined) {
|
|
50
|
+
// See https://proj.org/en/9.4/usage/projections.html [17/10/2024]
|
|
51
|
+
// > The default unit for projected coordinates is the meter.
|
|
41
52
|
return UNIT.METER;
|
|
42
53
|
} else {
|
|
43
54
|
return undefined;
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
|
-
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns the horizontal coordinates system units associated with this CRS.
|
|
60
|
+
*
|
|
61
|
+
* @param crs - The CRS to extract the unit from.
|
|
62
|
+
* @returns Either `UNIT.METER`, `UNIT.DEGREE` or `undefined`.
|
|
63
|
+
*/
|
|
64
|
+
export function getUnit(crs) {
|
|
47
65
|
mustBeString(crs);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
case 'EPSG:4978':
|
|
52
|
-
return UNIT.METER;
|
|
53
|
-
default:
|
|
54
|
-
{
|
|
55
|
-
const p = proj4.defs(formatToEPSG(crs));
|
|
56
|
-
if (!p) {
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
return _unitFromProj4Unit(p.units);
|
|
60
|
-
}
|
|
66
|
+
const p = proj4.defs(crs);
|
|
67
|
+
if (!p) {
|
|
68
|
+
return undefined;
|
|
61
69
|
}
|
|
70
|
+
return unitFromProj4Unit(p);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Asserts that the CRS is using metric units.
|
|
75
|
+
*
|
|
76
|
+
* @param crs - The CRS to check.
|
|
77
|
+
* @throws {@link Error} if the CRS is not valid.
|
|
78
|
+
*/
|
|
79
|
+
export function isMetricUnit(crs) {
|
|
80
|
+
return getUnit(crs) === UNIT.METER;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Asserts that the CRS is geographic.
|
|
85
|
+
*
|
|
86
|
+
* @param crs - The CRS to check.
|
|
87
|
+
* @throws {@link Error} if the CRS is not valid.
|
|
88
|
+
*/
|
|
89
|
+
export function isGeographic(crs) {
|
|
90
|
+
return getUnit(crs) === UNIT.DEGREE;
|
|
62
91
|
}
|
|
63
|
-
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Asserts that the CRS is geocentric.
|
|
95
|
+
*
|
|
96
|
+
* @param crs - The CRS to test.
|
|
97
|
+
* @returns false if the crs isn't defined.
|
|
98
|
+
*/
|
|
99
|
+
export function isGeocentric(crs) {
|
|
64
100
|
mustBeString(crs);
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
const projection = proj4.defs(crs);
|
|
102
|
+
return !projection ? false : projection.projName == 'geocent';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Asserts that the CRS is valid, meaning it has been previously defined and
|
|
107
|
+
* includes an unit.
|
|
108
|
+
*
|
|
109
|
+
* @param crs - The CRS to test.
|
|
110
|
+
* @throws {@link Error} if the crs is not valid.
|
|
111
|
+
*/
|
|
112
|
+
export function isValid(crs) {
|
|
113
|
+
const proj = proj4.defs(crs);
|
|
114
|
+
if (!proj) {
|
|
115
|
+
throw new Error(`Undefined crs '${crs}'. Add it with proj4.defs('${crs}', string)`);
|
|
116
|
+
}
|
|
117
|
+
if (!unitFromProj4Unit(proj)) {
|
|
118
|
+
throw new Error(`No valid unit found for crs '${crs}', found ${proj.units}`);
|
|
68
119
|
}
|
|
69
|
-
return u;
|
|
70
120
|
}
|
|
71
121
|
|
|
72
122
|
/**
|
|
73
|
-
*
|
|
123
|
+
* Gives a reasonable epsilon for this CRS.
|
|
74
124
|
*
|
|
75
|
-
* @
|
|
125
|
+
* @param crs - The CRS to use.
|
|
126
|
+
* @returns 0.01 if the CRS is EPSG:4326, 0.001 otherwise.
|
|
76
127
|
*/
|
|
77
|
-
export
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* Assert that the CRS is geographic.
|
|
96
|
-
*
|
|
97
|
-
* @param {string} crs - The CRS to validate.
|
|
98
|
-
* @return {boolean}
|
|
99
|
-
* @throws {Error} if the CRS is not valid.
|
|
100
|
-
*/
|
|
101
|
-
isGeographic(crs) {
|
|
102
|
-
return toUnitWithError(crs) == UNIT.DEGREE;
|
|
103
|
-
},
|
|
104
|
-
/**
|
|
105
|
-
* Assert that the CRS is using metric units.
|
|
106
|
-
*
|
|
107
|
-
* @param {string} crs - The CRS to validate.
|
|
108
|
-
* @return {boolean}
|
|
109
|
-
* @throws {Error} if the CRS is not valid.
|
|
110
|
-
*/
|
|
111
|
-
isMetricUnit(crs) {
|
|
112
|
-
return toUnit(crs) == UNIT.METER;
|
|
113
|
-
},
|
|
114
|
-
/**
|
|
115
|
-
* Get the unit to use with the CRS.
|
|
116
|
-
*
|
|
117
|
-
* @param {string} crs - The CRS to get the unit from.
|
|
118
|
-
* @return {number} Either `UNIT.METER`, `UNIT.DEGREE` or `undefined`.
|
|
119
|
-
*/
|
|
120
|
-
toUnit,
|
|
121
|
-
/**
|
|
122
|
-
* Is the CRS EPSG:4326 ?
|
|
123
|
-
*
|
|
124
|
-
* @param {string} crs - The CRS to test.
|
|
125
|
-
* @return {boolean}
|
|
126
|
-
*/
|
|
127
|
-
is4326,
|
|
128
|
-
/**
|
|
129
|
-
* Is the CRS geocentric ?
|
|
130
|
-
* if crs isn't defined the method returns false.
|
|
131
|
-
*
|
|
132
|
-
* @param {string} crs - The CRS to test.
|
|
133
|
-
* @return {boolean}
|
|
134
|
-
*/
|
|
135
|
-
isGeocentric,
|
|
136
|
-
/**
|
|
137
|
-
* Give a reasonnable epsilon to use with this CRS.
|
|
138
|
-
*
|
|
139
|
-
* @param {string} crs - The CRS to use.
|
|
140
|
-
* @return {number} 0.01 if the CRS is EPSG:4326, 0.001 otherwise.
|
|
141
|
-
*/
|
|
142
|
-
reasonnableEpsilon(crs) {
|
|
143
|
-
if (is4326(crs)) {
|
|
144
|
-
return 0.01;
|
|
145
|
-
} else {
|
|
146
|
-
return 0.001;
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
/**
|
|
150
|
-
* format crs to European Petroleum Survey Group notation : EPSG:XXXX.
|
|
151
|
-
*
|
|
152
|
-
* @param {string} crs The crs to format
|
|
153
|
-
* @return {string} formated crs
|
|
154
|
-
*/
|
|
155
|
-
formatToEPSG,
|
|
156
|
-
/**
|
|
157
|
-
* format crs to tile matrix set notation : TMS:XXXX.
|
|
158
|
-
*
|
|
159
|
-
* @param {string} crs The crs to format
|
|
160
|
-
* @return {string} formated crs
|
|
161
|
-
*/
|
|
162
|
-
formatToTms,
|
|
163
|
-
isTms,
|
|
164
|
-
isEpsg,
|
|
165
|
-
tms_3857: 'TMS:3857',
|
|
166
|
-
tms_4326: 'TMS:4326',
|
|
167
|
-
/**
|
|
168
|
-
* Define a proj4 projection as a string and reference.
|
|
169
|
-
*
|
|
170
|
-
* @param {string} code code is the projection's SRS code (only used internally by the Proj4js library)
|
|
171
|
-
* @param {string} proj4def is the Proj4 definition string for the projection to use
|
|
172
|
-
* @return {undefined}
|
|
173
|
-
*/
|
|
174
|
-
defs: (code, proj4def) => proj4.defs(code, proj4def)
|
|
175
|
-
};
|
|
128
|
+
export function reasonableEpsilon(crs) {
|
|
129
|
+
if (is4326(crs)) {
|
|
130
|
+
return 0.01;
|
|
131
|
+
} else {
|
|
132
|
+
return 0.001;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Defines a proj4 projection as a named alias.
|
|
138
|
+
* This function is a specialized wrapper over the
|
|
139
|
+
* [`proj4.defs`](https://github.com/proj4js/proj4js#named-projections)
|
|
140
|
+
* function.
|
|
141
|
+
*
|
|
142
|
+
* @param code - Named alias of the currently defined projection.
|
|
143
|
+
* @param proj4def - Proj4 or WKT string of the defined projection.
|
|
144
|
+
*/
|
|
145
|
+
export const defs = (code, proj4def) => proj4.defs(code, proj4def);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import * as CRS from "./Crs.js";
|
|
2
3
|
import Coordinates from "./Coordinates.js";
|
|
3
|
-
import CRS from "./Crs.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Extent is a SIG-area (so 2D)
|
|
@@ -43,9 +43,6 @@ class Extent {
|
|
|
43
43
|
if (CRS.isGeocentric(crs)) {
|
|
44
44
|
throw new Error(`${crs} is a geocentric projection, it doesn't make sense with a geographical extent`);
|
|
45
45
|
}
|
|
46
|
-
if (CRS.isTms(crs)) {
|
|
47
|
-
throw new Error(`${crs} is a tiled projection, use Tile instead`);
|
|
48
|
-
}
|
|
49
46
|
this.isExtent = true;
|
|
50
47
|
this.crs = crs;
|
|
51
48
|
this.west = 0;
|
|
@@ -220,7 +217,7 @@ class Extent {
|
|
|
220
217
|
*/
|
|
221
218
|
isInside(extent, epsilon) {
|
|
222
219
|
extent.as(this.crs, _extent);
|
|
223
|
-
epsilon = epsilon
|
|
220
|
+
epsilon = epsilon ?? CRS.reasonableEpsilon(this.crs);
|
|
224
221
|
return this.east - _extent.east <= epsilon && _extent.west - this.west <= epsilon && this.north - _extent.north <= epsilon && _extent.south - this.south <= epsilon;
|
|
225
222
|
}
|
|
226
223
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import * as CRS from "./Crs.js";
|
|
2
3
|
import Coordinates from "./Coordinates.js";
|
|
3
|
-
import CRS from "./Crs.js";
|
|
4
4
|
const coord = new Coordinates('EPSG:4326');
|
|
5
5
|
const indexes = new THREE.Vector2();
|
|
6
6
|
function biLinearInterpolation(indexes, getData) {
|
|
@@ -31,6 +31,10 @@ const colorSky = new THREE.Color();
|
|
|
31
31
|
const spaceColor = new THREE.Color(0x030508);
|
|
32
32
|
const limitAlti = 600000;
|
|
33
33
|
const mfogDistance = ellipsoidSizes.x * 160.0;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @extends GeometryLayer
|
|
37
|
+
*/
|
|
34
38
|
class Atmosphere extends GeometryLayer {
|
|
35
39
|
/**
|
|
36
40
|
* It's layer to simulate Globe atmosphere.
|
|
@@ -40,8 +44,6 @@ class Atmosphere extends GeometryLayer {
|
|
|
40
44
|
* * [Atmosphere Shader From Space (Atmospheric scattering)](http://stainlessbeer.weebly.com/planets-9-atmospheric-scattering.html)
|
|
41
45
|
* * [Accurate Atmospheric Scattering (NVIDIA GPU Gems 2)](https://developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-16-accurate-atmospheric-scattering).
|
|
42
46
|
*
|
|
43
|
-
* @extends GeometryLayer
|
|
44
|
-
*
|
|
45
47
|
* @param {string} id - The id of the layer Atmosphere.
|
|
46
48
|
* @param {Object} [options] - options layer.
|
|
47
49
|
* @param {number} [options.Kr] - `Kr` is the rayleigh scattering constant.
|
|
@@ -2,8 +2,7 @@ import * as THREE from 'three';
|
|
|
2
2
|
import TiledGeometryLayer from "../../../Layer/TiledGeometryLayer.js";
|
|
3
3
|
import { ellipsoidSizes } from "../../Math/Ellipsoid.js";
|
|
4
4
|
import { globalExtentTMS, schemeTiles } from "../../Tile/TileGrid.js";
|
|
5
|
-
import
|
|
6
|
-
import CRS from "../../Geographic/Crs.js";
|
|
5
|
+
import { GlobeTileBuilder } from "./GlobeTileBuilder.js";
|
|
7
6
|
|
|
8
7
|
// matrix to convert sphere to ellipsoid
|
|
9
8
|
const worldToScaledEllipsoid = new THREE.Matrix4();
|
|
@@ -18,18 +17,18 @@ const scaledHorizonCullingPoint = new THREE.Vector3();
|
|
|
18
17
|
* @property {boolean} isGlobeLayer - Used to checkout whether this layer is a
|
|
19
18
|
* GlobeLayer. Default is true. You should not change this, as it is used
|
|
20
19
|
* internally for optimisation.
|
|
20
|
+
*
|
|
21
|
+
* @extends TiledGeometryLayer
|
|
21
22
|
*/
|
|
22
23
|
class GlobeLayer extends TiledGeometryLayer {
|
|
23
24
|
/**
|
|
24
25
|
* A {@link TiledGeometryLayer} to use with a {@link GlobeView}. It has
|
|
25
26
|
* specific method for updating and subdivising its grid.
|
|
26
27
|
*
|
|
27
|
-
* @extends TiledGeometryLayer
|
|
28
|
-
*
|
|
29
28
|
* @param {string} id - The id of the layer, that should be unique. It is
|
|
30
29
|
* not mandatory, but an error will be emitted if this layer is added a
|
|
31
30
|
* {@link View} that already has a layer going by that id.
|
|
32
|
-
* @param {THREE.
|
|
31
|
+
* @param {THREE.Object3D} [object3d=THREE.Group] - The object3d used to
|
|
33
32
|
* contain the geometry of the TiledGeometryLayer. It is usually a
|
|
34
33
|
* `THREE.Group`, but it can be anything inheriting from a `THREE.Object3d`.
|
|
35
34
|
* @param {Object} [config] - Optional configuration, all elements in it
|
|
@@ -48,22 +47,30 @@ class GlobeLayer extends TiledGeometryLayer {
|
|
|
48
47
|
*/
|
|
49
48
|
constructor(id, object3d) {
|
|
50
49
|
let config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
50
|
+
const {
|
|
51
|
+
minSubdivisionLevel = 2,
|
|
52
|
+
maxSubdivisionLevel = 19,
|
|
53
|
+
...tiledConfig
|
|
54
|
+
} = config;
|
|
55
|
+
|
|
51
56
|
// Configure tiles
|
|
52
|
-
const scheme = schemeTiles.get(
|
|
57
|
+
const scheme = schemeTiles.get('EPSG:4326');
|
|
53
58
|
const schemeTile = globalExtentTMS.get('EPSG:4326').subdivisionByScheme(scheme);
|
|
54
59
|
|
|
55
60
|
// Supported tile matrix set for color/elevation layer
|
|
56
|
-
|
|
57
|
-
const uvCount =
|
|
58
|
-
const builder = new
|
|
59
|
-
crs: 'EPSG:4978',
|
|
61
|
+
const tileMatrixSets = ['EPSG:4326', 'EPSG:3857'];
|
|
62
|
+
const uvCount = tileMatrixSets.length;
|
|
63
|
+
const builder = new GlobeTileBuilder({
|
|
60
64
|
uvCount
|
|
61
65
|
});
|
|
62
|
-
super(id, object3d || new THREE.Group(), schemeTile, builder,
|
|
66
|
+
super(id, object3d || new THREE.Group(), schemeTile, builder, {
|
|
67
|
+
tileMatrixSets,
|
|
68
|
+
...tiledConfig
|
|
69
|
+
});
|
|
63
70
|
this.isGlobeLayer = true;
|
|
64
71
|
this.options.defaultPickingRadius = 5;
|
|
65
|
-
this.minSubdivisionLevel =
|
|
66
|
-
this.maxSubdivisionLevel =
|
|
72
|
+
this.minSubdivisionLevel = minSubdivisionLevel;
|
|
73
|
+
this.maxSubdivisionLevel = maxSubdivisionLevel;
|
|
67
74
|
this.extent = this.schemeTile[0].clone();
|
|
68
75
|
for (let i = 1; i < this.schemeTile.length; i++) {
|
|
69
76
|
this.extent.union(this.schemeTile[i]);
|
|
@@ -97,7 +104,7 @@ class GlobeLayer extends TiledGeometryLayer {
|
|
|
97
104
|
}
|
|
98
105
|
subdivision(context, layer, node) {
|
|
99
106
|
if (node.level == 5) {
|
|
100
|
-
const row = node.getExtentsByProjection(
|
|
107
|
+
const row = node.getExtentsByProjection('EPSG:4326')[0].row;
|
|
101
108
|
if (row == 31 || row == 0) {
|
|
102
109
|
// doesn't subdivise the pole
|
|
103
110
|
return false;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Coordinates from "../../Geographic/Coordinates.js";
|
|
3
|
+
import Extent from "../../Geographic/Extent.js";
|
|
4
|
+
const PI_OV_FOUR = Math.PI / 4;
|
|
5
|
+
const INV_TWO_PI = 1.0 / (Math.PI * 2);
|
|
6
|
+
const axisZ = new THREE.Vector3(0, 0, 1);
|
|
7
|
+
const axisY = new THREE.Vector3(0, 1, 0);
|
|
8
|
+
const quatToAlignLongitude = new THREE.Quaternion();
|
|
9
|
+
const quatToAlignLatitude = new THREE.Quaternion();
|
|
10
|
+
const quatNormalToZ = new THREE.Quaternion();
|
|
11
|
+
|
|
12
|
+
/** Transforms a WGS84 latitude into a usable texture offset. */
|
|
13
|
+
function WGS84ToOneSubY(latitude) {
|
|
14
|
+
return 1.0 - (0.5 - Math.log(Math.tan(PI_OV_FOUR + THREE.MathUtils.degToRad(latitude) * 0.5)) * INV_TWO_PI);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Specialized parameters for the [GlobeTileBuilder]. */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* TileBuilder implementation for the purpose of generating globe (or more
|
|
21
|
+
* precisely ellipsoidal) tile arrangements.
|
|
22
|
+
*/
|
|
23
|
+
export class GlobeTileBuilder {
|
|
24
|
+
static _crs = 'EPSG:4978';
|
|
25
|
+
static _computeExtraOffset(params) {
|
|
26
|
+
const t = WGS84ToOneSubY(params.coordinates.latitude) * params.nbRow;
|
|
27
|
+
return (!isFinite(t) ? 0 : t) - params.deltaUV1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Buffer holding information about the tile/vertex currently being
|
|
32
|
+
* processed.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
get crs() {
|
|
36
|
+
return GlobeTileBuilder._crs;
|
|
37
|
+
}
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this._transform = {
|
|
40
|
+
coords: [new Coordinates('EPSG:4326', 0, 0), new Coordinates('EPSG:4326', 0, 0)],
|
|
41
|
+
position: new THREE.Vector3(),
|
|
42
|
+
dimension: new THREE.Vector2()
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// UV: Normalized coordinates (from degree) on the entire tile
|
|
46
|
+
// EPSG:4326
|
|
47
|
+
// Offset: Float row coordinate from Pseudo mercator coordinates
|
|
48
|
+
// EPSG:3857
|
|
49
|
+
if (options.uvCount > 1) {
|
|
50
|
+
this.computeExtraOffset = GlobeTileBuilder._computeExtraOffset;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
prepare(params) {
|
|
54
|
+
const nbRow = 2 ** (params.level + 1.0);
|
|
55
|
+
let st1 = WGS84ToOneSubY(params.extent.south);
|
|
56
|
+
if (!isFinite(st1)) {
|
|
57
|
+
st1 = 0;
|
|
58
|
+
}
|
|
59
|
+
const start = st1 % (1.0 / nbRow);
|
|
60
|
+
const newParams = {
|
|
61
|
+
nbRow,
|
|
62
|
+
deltaUV1: (st1 - start) * nbRow,
|
|
63
|
+
// transformation to align tile's normal to z axis
|
|
64
|
+
quatNormalToZ: quatNormalToZ.setFromAxisAngle(axisY, -(Math.PI * 0.5 - THREE.MathUtils.degToRad(params.extent.center().latitude))),
|
|
65
|
+
// let's avoid building too much temp objects
|
|
66
|
+
coordinates: new Coordinates(this.crs)
|
|
67
|
+
};
|
|
68
|
+
params.extent.planarDimensions(this._transform.dimension);
|
|
69
|
+
return {
|
|
70
|
+
...params,
|
|
71
|
+
...newParams
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
center(extent) {
|
|
75
|
+
return extent.center(this._transform.coords[0]).as(this.crs, this._transform.coords[1]).toVector3();
|
|
76
|
+
}
|
|
77
|
+
vertexPosition(coordinates) {
|
|
78
|
+
return this._transform.coords[0].setFromValues(coordinates.x, coordinates.y).as(this.crs, this._transform.coords[1]).toVector3(this._transform.position);
|
|
79
|
+
}
|
|
80
|
+
vertexNormal() {
|
|
81
|
+
return this._transform.coords[1].geodesicNormal;
|
|
82
|
+
}
|
|
83
|
+
uProject(u, extent) {
|
|
84
|
+
return extent.west + u * this._transform.dimension.x;
|
|
85
|
+
}
|
|
86
|
+
vProject(v, extent) {
|
|
87
|
+
return extent.south + v * this._transform.dimension.y;
|
|
88
|
+
}
|
|
89
|
+
computeShareableExtent(extent) {
|
|
90
|
+
// NOTE: It should be possible to take advantage of equatorial plane
|
|
91
|
+
// symmetry, for which we'd have to reverse the tile's UVs.
|
|
92
|
+
// This would halve the memory requirement when viewing a full globe,
|
|
93
|
+
// but that case is not that relevant for iTowns' usual use cases and
|
|
94
|
+
// the globe mesh memory usage is already inconsequential.
|
|
95
|
+
const sizeLongitude = Math.abs(extent.west - extent.east) / 2;
|
|
96
|
+
const shareableExtent = new Extent(extent.crs, -sizeLongitude, sizeLongitude, extent.south, extent.north);
|
|
97
|
+
|
|
98
|
+
// Compute rotation to transform the tile to position on the ellispoid.
|
|
99
|
+
// This transformation takes the parents' transformation into account.
|
|
100
|
+
const rotLon = THREE.MathUtils.degToRad(extent.west - shareableExtent.west);
|
|
101
|
+
const rotLat = THREE.MathUtils.degToRad(90 - extent.center(this._transform.coords[0]).latitude);
|
|
102
|
+
quatToAlignLongitude.setFromAxisAngle(axisZ, rotLon);
|
|
103
|
+
quatToAlignLatitude.setFromAxisAngle(axisY, rotLat);
|
|
104
|
+
quatToAlignLongitude.multiply(quatToAlignLatitude);
|
|
105
|
+
return {
|
|
106
|
+
shareableExtent,
|
|
107
|
+
quaternion: quatToAlignLongitude.clone(),
|
|
108
|
+
position: this.center(extent)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|