itowns 2.43.2-next.0 → 2.43.2-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- 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/dist/itowns_widgets.js +1 -1
- package/dist/itowns_widgets.js.map +1 -1
- package/examples/3dtiles_25d.html +1 -1
- package/examples/3dtiles_basic.html +2 -2
- package/examples/3dtiles_batch_table.html +1 -3
- package/examples/3dtiles_pointcloud.html +9 -15
- package/examples/config.json +2 -1
- package/examples/copc_simple_loader.html +128 -0
- package/examples/entwine_3d_loader.html +1 -1
- package/examples/entwine_simple_loader.html +1 -1
- package/examples/js/plugins/COGParser.js +84 -50
- package/examples/js/plugins/COGSource.js +7 -4
- package/examples/layers/JSONLayers/OPENSM.json +1 -1
- package/examples/potree_25d_map.html +1 -1
- package/examples/potree_3d_map.html +1 -1
- package/examples/source_file_cog.html +22 -5
- package/lib/Controls/FirstPersonControls.js +0 -1
- package/lib/Controls/FlyControls.js +0 -1
- package/lib/Converter/Feature2Mesh.js +2 -4
- package/lib/Converter/textureConverter.js +1 -1
- package/lib/Core/3DTiles/C3DTBatchTable.js +1 -1
- package/lib/Core/3DTiles/C3DTFeature.js +0 -1
- package/lib/Core/CopcNode.js +174 -0
- package/lib/Core/Feature.js +1 -2
- package/lib/Core/Geographic/CoordStars.js +0 -1
- package/lib/Core/Label.js +0 -1
- package/lib/Core/MainLoop.js +0 -1
- package/lib/Core/Prefab/Globe/Atmosphere.js +0 -4
- package/lib/Core/Prefab/Globe/GlobeLayer.js +3 -3
- package/lib/Core/Style.js +2 -4
- package/lib/Core/View.js +2 -4
- package/lib/Layer/C3DTilesLayer.js +3 -1
- package/lib/Layer/CopcLayer.js +59 -0
- package/lib/Layer/ElevationLayer.js +2 -3
- package/lib/Layer/GeoidLayer.js +1 -2
- package/lib/Layer/LabelLayer.js +8 -17
- package/lib/Layer/Layer.js +4 -2
- package/lib/Layer/PointCloudLayer.js +4 -7
- package/lib/Layer/ReferencingLayerProperties.js +3 -3
- package/lib/Layer/TiledGeometryLayer.js +2 -3
- package/lib/Main.js +2 -0
- package/lib/Parser/GeoJsonParser.js +2 -3
- package/lib/Parser/LASLoader.js +45 -1
- package/lib/Parser/LASParser.js +57 -25
- package/lib/Parser/deprecated/LegacyGLTFLoader.js +1 -2
- package/lib/Process/FeatureProcessing.js +1 -2
- package/lib/Process/LayeredMaterialNodeProcessing.js +3 -9
- package/lib/Process/ObjectRemovalHelper.js +1 -2
- package/lib/Provider/3dTilesProvider.js +1 -0
- package/lib/Renderer/ColorLayersOrdering.js +1 -2
- package/lib/Renderer/Label2DRenderer.js +1 -4
- package/lib/Renderer/PointsMaterial.js +14 -9
- package/lib/Renderer/RenderMode.js +0 -1
- package/lib/Source/CopcSource.js +118 -0
- package/lib/Source/Source.js +3 -1
- package/lib/ThreeExtended/loaders/DDSLoader.js +11 -1
- package/lib/ThreeExtended/loaders/DRACOLoader.js +0 -1
- package/lib/ThreeExtended/loaders/GLTFLoader.js +1 -0
- package/lib/Utils/DEMUtils.js +2 -2
- package/lib/Utils/OrientationUtils.js +0 -1
- package/lib/Utils/gui/Searchbar.js +1 -2
- package/package.json +8 -7
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Hierarchy } from 'copc';
|
|
3
|
+
import PointCloudNode from "./PointCloudNode.js";
|
|
4
|
+
const size = new THREE.Vector3();
|
|
5
|
+
const position = new THREE.Vector3();
|
|
6
|
+
const translation = new THREE.Vector3();
|
|
7
|
+
function buildId(depth, x, y, z) {
|
|
8
|
+
return `${depth}-${x}-${y}-${z}`;
|
|
9
|
+
}
|
|
10
|
+
class CopcNode extends PointCloudNode {
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new instance of a COPC Octree node
|
|
13
|
+
*
|
|
14
|
+
* @param {number} depth - Depth within the octree
|
|
15
|
+
* @param {number} x - X position within the octree
|
|
16
|
+
* @param {number} y - Y position within the octree
|
|
17
|
+
* @param {number} z - Z position with the octree
|
|
18
|
+
* @param {number} entryOffset - Offset from the beginning of the file of
|
|
19
|
+
* the node entry
|
|
20
|
+
* @param {number} entryLength - Size of the node entry
|
|
21
|
+
* @param {CopcLayer} layer - Parent COPC layer
|
|
22
|
+
* @param {number} [numPoints=0] - Number of points given by this entry
|
|
23
|
+
*/
|
|
24
|
+
constructor(depth, x, y, z, entryOffset, entryLength, layer) {
|
|
25
|
+
let numPoints = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 0;
|
|
26
|
+
super(numPoints, layer);
|
|
27
|
+
this.isCopcNode = true;
|
|
28
|
+
this.entryOffset = entryOffset;
|
|
29
|
+
this.entryLength = entryLength;
|
|
30
|
+
this.layer = layer;
|
|
31
|
+
this.depth = depth;
|
|
32
|
+
this.x = x;
|
|
33
|
+
this.y = y;
|
|
34
|
+
this.z = z;
|
|
35
|
+
}
|
|
36
|
+
get id() {
|
|
37
|
+
return buildId(this.depth, this.x, this.y, this.z);
|
|
38
|
+
}
|
|
39
|
+
get octreeIsLoaded() {
|
|
40
|
+
return this.numPoints >= 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {number} offset
|
|
45
|
+
* @param {number} size
|
|
46
|
+
*/
|
|
47
|
+
async _fetch(offset, size) {
|
|
48
|
+
return this.layer.source.fetcher(this.layer.source.url, {
|
|
49
|
+
...this.layer.source.networkOptions,
|
|
50
|
+
headers: {
|
|
51
|
+
...this.layer.source.networkOptions.headers,
|
|
52
|
+
range: `bytes=${offset}-${offset + size - 1}`
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create an (A)xis (A)ligned (B)ounding (B)ox for the given node given
|
|
59
|
+
* `this` is its parent.
|
|
60
|
+
* @param {CopcNode} node - The child node
|
|
61
|
+
*/
|
|
62
|
+
createChildAABB(node) {
|
|
63
|
+
// factor to apply, based on the depth difference (can be > 1)
|
|
64
|
+
const f = 2 ** (node.depth - this.depth);
|
|
65
|
+
|
|
66
|
+
// size of the child node bbox (Vector3), based on the size of the
|
|
67
|
+
// parent node, and divided by the factor
|
|
68
|
+
this.bbox.getSize(size).divideScalar(f);
|
|
69
|
+
|
|
70
|
+
// initialize the child node bbox at the location of the parent node bbox
|
|
71
|
+
node.bbox.min.copy(this.bbox.min);
|
|
72
|
+
|
|
73
|
+
// position of the parent node, if it was at the same depth as the
|
|
74
|
+
// child, found by multiplying the tree position by the factor
|
|
75
|
+
position.copy(this).multiplyScalar(f);
|
|
76
|
+
|
|
77
|
+
// difference in position between the two nodes, at child depth, and
|
|
78
|
+
// scale it using the size
|
|
79
|
+
translation.subVectors(node, position).multiply(size);
|
|
80
|
+
|
|
81
|
+
// apply the translation to the child node bbox
|
|
82
|
+
node.bbox.min.add(translation);
|
|
83
|
+
|
|
84
|
+
// use the size computed above to set the max
|
|
85
|
+
node.bbox.max.copy(node.bbox.min).add(size);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create a CopcNode from the provided subtree and add it as child
|
|
90
|
+
* of the current node.
|
|
91
|
+
* @param {number} depth - Child node depth in the octree
|
|
92
|
+
* @param {number} x - Child node x position in the octree
|
|
93
|
+
* @param {number} y - Child node y position in the octree
|
|
94
|
+
* @param {number} z - Child node z position in the octree
|
|
95
|
+
* @param {Hierarchy.Subtree} hierarchy - Octree's subtree
|
|
96
|
+
* @param {CopcNode[]} stack - Stack of node candidates for traversal
|
|
97
|
+
*/
|
|
98
|
+
findAndCreateChild(depth, x, y, z, hierarchy, stack) {
|
|
99
|
+
const id = buildId(depth, x, y, z);
|
|
100
|
+
let pointCount;
|
|
101
|
+
let offset;
|
|
102
|
+
let byteSize;
|
|
103
|
+
const node = hierarchy.nodes[id];
|
|
104
|
+
if (node) {
|
|
105
|
+
pointCount = node.pointCount;
|
|
106
|
+
offset = node.pointDataOffset;
|
|
107
|
+
byteSize = node.pointDataLength;
|
|
108
|
+
} else {
|
|
109
|
+
const page = hierarchy.pages[id];
|
|
110
|
+
if (!page) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
pointCount = -1;
|
|
114
|
+
offset = page.pageOffset;
|
|
115
|
+
byteSize = page.pageLength;
|
|
116
|
+
}
|
|
117
|
+
const child = new CopcNode(depth, x, y, z, offset, byteSize, this.layer, pointCount);
|
|
118
|
+
this.add(child);
|
|
119
|
+
stack.push(child);
|
|
120
|
+
}
|
|
121
|
+
async loadOctree() {
|
|
122
|
+
// Load hierarchy
|
|
123
|
+
const buffer = await this._fetch(this.entryOffset, this.entryLength);
|
|
124
|
+
const hierarchy = await Hierarchy.parse(new Uint8Array(buffer));
|
|
125
|
+
|
|
126
|
+
// Update current node entry from loaded subtree
|
|
127
|
+
const node = hierarchy.nodes[this.id];
|
|
128
|
+
if (!node) {
|
|
129
|
+
return Promise.reject('[CopcNode]: Ill-formed data, entry not found in hierarchy.');
|
|
130
|
+
}
|
|
131
|
+
this.numPoints = node.pointCount;
|
|
132
|
+
this.entryOffset = node.pointDataOffset;
|
|
133
|
+
this.entryLength = node.pointDataLength;
|
|
134
|
+
|
|
135
|
+
// Load subtree entries
|
|
136
|
+
const stack = [];
|
|
137
|
+
stack.push(this);
|
|
138
|
+
while (stack.length) {
|
|
139
|
+
const node = stack.shift();
|
|
140
|
+
const depth = node.depth + 1;
|
|
141
|
+
const x = node.x * 2;
|
|
142
|
+
const y = node.y * 2;
|
|
143
|
+
const z = node.z * 2;
|
|
144
|
+
node.findAndCreateChild(depth, x, y, z, hierarchy, stack);
|
|
145
|
+
node.findAndCreateChild(depth, x + 1, y, z, hierarchy, stack);
|
|
146
|
+
node.findAndCreateChild(depth, x, y + 1, z, hierarchy, stack);
|
|
147
|
+
node.findAndCreateChild(depth, x + 1, y + 1, z, hierarchy, stack);
|
|
148
|
+
node.findAndCreateChild(depth, x, y, z + 1, hierarchy, stack);
|
|
149
|
+
node.findAndCreateChild(depth, x + 1, y, z + 1, hierarchy, stack);
|
|
150
|
+
node.findAndCreateChild(depth, x, y + 1, z + 1, hierarchy, stack);
|
|
151
|
+
node.findAndCreateChild(depth, x + 1, y + 1, z + 1, hierarchy, stack);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Load the COPC Buffer geometry for this node.
|
|
157
|
+
* @returns {Promise<THREE.BufferGeometry>}
|
|
158
|
+
*/
|
|
159
|
+
async load() {
|
|
160
|
+
if (!this.octreeIsLoaded) {
|
|
161
|
+
await this.loadOctree();
|
|
162
|
+
}
|
|
163
|
+
const buffer = await this._fetch(this.entryOffset, this.entryLength);
|
|
164
|
+
const geometry = await this.layer.source.parser(buffer, {
|
|
165
|
+
in: {
|
|
166
|
+
...this.layer.source,
|
|
167
|
+
pointCount: this.numPoints
|
|
168
|
+
},
|
|
169
|
+
out: this.layer
|
|
170
|
+
});
|
|
171
|
+
return geometry;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export default CopcNode;
|
package/lib/Core/Feature.js
CHANGED
|
@@ -338,10 +338,9 @@ export class FeatureCollection extends THREE.Object3D {
|
|
|
338
338
|
* @param {FeatureBuildingOptions|Layer} options The building options .
|
|
339
339
|
*/
|
|
340
340
|
constructor(options) {
|
|
341
|
-
var _options$source;
|
|
342
341
|
super();
|
|
343
342
|
this.isFeatureCollection = true;
|
|
344
|
-
this.crs = CRS.formatToEPSG(options.accurate || !
|
|
343
|
+
this.crs = CRS.formatToEPSG(options.accurate || !options.source?.crs ? options.crs : options.source.crs);
|
|
345
344
|
this.features = [];
|
|
346
345
|
this.mergeFeatures = options.mergeFeatures === undefined ? true : options.mergeFeatures;
|
|
347
346
|
this.size = options.structure == '3d' ? 3 : 2;
|
package/lib/Core/Label.js
CHANGED
package/lib/Core/MainLoop.js
CHANGED
|
@@ -72,7 +72,6 @@ class Atmosphere extends GeometryLayer {
|
|
|
72
72
|
value: new THREE.Vector2(window.innerWidth, window.innerHeight)
|
|
73
73
|
} // Should be updated on screen resize...
|
|
74
74
|
},
|
|
75
|
-
|
|
76
75
|
vertexShader: GlowVS,
|
|
77
76
|
fragmentShader: GlowFS,
|
|
78
77
|
side: THREE.BackSide,
|
|
@@ -100,7 +99,6 @@ class Atmosphere extends GeometryLayer {
|
|
|
100
99
|
value: new THREE.Vector2(window.innerWidth, window.innerHeight)
|
|
101
100
|
} // Should be updated on screen resize...
|
|
102
101
|
},
|
|
103
|
-
|
|
104
102
|
vertexShader: GlowVS,
|
|
105
103
|
fragmentShader: GlowFS,
|
|
106
104
|
side: THREE.FrontSide,
|
|
@@ -135,7 +133,6 @@ class Atmosphere extends GeometryLayer {
|
|
|
135
133
|
scaleDepth: 0.25
|
|
136
134
|
// mieScaleDepth: 0.1,
|
|
137
135
|
};
|
|
138
|
-
|
|
139
136
|
this.object3d.updateMatrixWorld();
|
|
140
137
|
}
|
|
141
138
|
update(context, layer, node) {
|
|
@@ -288,7 +285,6 @@ class Atmosphere extends GeometryLayer {
|
|
|
288
285
|
skyDome.material.uniforms.mieDirectionalG.value = effectController.mieDirectionalG;
|
|
289
286
|
skyDome.material.uniforms.up.value = new THREE.Vector3(); // no more necessary, estimate normal from cam..
|
|
290
287
|
}
|
|
291
|
-
|
|
292
288
|
setRealisticOn(bool) {
|
|
293
289
|
if (bool) {
|
|
294
290
|
if (!this.realisticAtmosphere.children.length) {
|
|
@@ -3,7 +3,6 @@ import TiledGeometryLayer from "../../../Layer/TiledGeometryLayer.js";
|
|
|
3
3
|
import { ellipsoidSizes } from "../../Math/Ellipsoid.js";
|
|
4
4
|
import { globalExtentTMS, schemeTiles } from "../../Geographic/Extent.js";
|
|
5
5
|
import BuilderEllipsoidTile from "./BuilderEllipsoidTile.js";
|
|
6
|
-
import { SIZE_DIAGONAL_TEXTURE } from "../../../Process/LayeredMaterialNodeProcessing.js";
|
|
7
6
|
import CRS from "../../Geographic/Crs.js";
|
|
8
7
|
|
|
9
8
|
// matrix to convert sphere to ellipsoid
|
|
@@ -129,7 +128,7 @@ class GlobeLayer extends TiledGeometryLayer {
|
|
|
129
128
|
return isOccluded;
|
|
130
129
|
}
|
|
131
130
|
computeTileZoomFromDistanceCamera(distance, camera) {
|
|
132
|
-
const preSinus =
|
|
131
|
+
const preSinus = this.sizeDiagonalTexture * (this.sseSubdivisionThreshold * 0.5) / camera._preSSE / ellipsoidSizes.x;
|
|
133
132
|
let sinus = distance * preSinus;
|
|
134
133
|
let zoom = Math.log(Math.PI / (2.0 * Math.asin(sinus))) / Math.log(2);
|
|
135
134
|
const delta = Math.PI / 2 ** zoom;
|
|
@@ -143,7 +142,8 @@ class GlobeLayer extends TiledGeometryLayer {
|
|
|
143
142
|
const delta = Math.PI / 2 ** zoom;
|
|
144
143
|
const circleChord = 2.0 * ellipsoidSizes.x * Math.sin(delta * 0.5);
|
|
145
144
|
const radius = circleChord * 0.5;
|
|
146
|
-
|
|
145
|
+
const error = radius / this.sizeDiagonalTexture;
|
|
146
|
+
return camera._preSSE * error / (this.sseSubdivisionThreshold * 0.5) + radius;
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
export default GlobeLayer;
|
package/lib/Core/Style.js
CHANGED
|
@@ -12,8 +12,7 @@ const matrix = document.createElementNS('http://www.w3.org/2000/svg', 'svg').cre
|
|
|
12
12
|
const canvas = document.createElement('canvas');
|
|
13
13
|
const inv255 = 1 / 255;
|
|
14
14
|
function baseAltitudeDefault(properties, ctx) {
|
|
15
|
-
|
|
16
|
-
return (ctx === null || ctx === void 0 ? void 0 : (_ctx$coordinates = ctx.coordinates) === null || _ctx$coordinates === void 0 ? void 0 : _ctx$coordinates.z) || 0;
|
|
15
|
+
return ctx?.coordinates?.z || 0;
|
|
17
16
|
}
|
|
18
17
|
export function readExpression(property, ctx) {
|
|
19
18
|
if (property != undefined) {
|
|
@@ -154,7 +153,6 @@ function defineStyleProperty(style, category, parameter, userValue, defaultValue
|
|
|
154
153
|
Object.defineProperty(style[category], parameter, {
|
|
155
154
|
enumerable: true,
|
|
156
155
|
get: () => {
|
|
157
|
-
var _style$context$featur, _style$context$featur2;
|
|
158
156
|
// != to check for 'undefined' and 'null' value)
|
|
159
157
|
if (property != undefined) {
|
|
160
158
|
return property;
|
|
@@ -162,7 +160,7 @@ function defineStyleProperty(style, category, parameter, userValue, defaultValue
|
|
|
162
160
|
if (userValue != undefined) {
|
|
163
161
|
return readExpression(userValue, style.context);
|
|
164
162
|
}
|
|
165
|
-
const dataValue =
|
|
163
|
+
const dataValue = style.context.featureStyle?.[category]?.[parameter];
|
|
166
164
|
if (dataValue != undefined) {
|
|
167
165
|
return readExpression(dataValue, style.context);
|
|
168
166
|
}
|
package/lib/Core/View.js
CHANGED
|
@@ -232,8 +232,7 @@ class View extends THREE.EventDispatcher {
|
|
|
232
232
|
* @returns {THREE.WebGLRenderer} the WebGLRenderer used to render this view.
|
|
233
233
|
*/
|
|
234
234
|
get renderer() {
|
|
235
|
-
|
|
236
|
-
return (_this$mainLoop = this.mainLoop) === null || _this$mainLoop === void 0 ? void 0 : (_this$mainLoop$gfxEng = _this$mainLoop.gfxEngine) === null || _this$mainLoop$gfxEng === void 0 ? void 0 : _this$mainLoop$gfxEng.getRenderer();
|
|
235
|
+
return this.mainLoop?.gfxEngine?.getRenderer();
|
|
237
236
|
}
|
|
238
237
|
|
|
239
238
|
/**
|
|
@@ -241,8 +240,7 @@ class View extends THREE.EventDispatcher {
|
|
|
241
240
|
* @returns {THREE.Camera} the threejs camera of this view
|
|
242
241
|
*/
|
|
243
242
|
get camera3D() {
|
|
244
|
-
|
|
245
|
-
return (_this$camera = this.camera) === null || _this$camera === void 0 ? void 0 : _this$camera.camera3D;
|
|
243
|
+
return this.camera?.camera3D;
|
|
246
244
|
}
|
|
247
245
|
|
|
248
246
|
/**
|
|
@@ -92,7 +92,9 @@ class C3DTilesLayer extends GeometryLayer {
|
|
|
92
92
|
* @param {Number} [config.cleanupDelay=1000] The time (in ms) after which a tile content (and its children) are
|
|
93
93
|
* removed from the scene.
|
|
94
94
|
* @param {C3DTExtensions} [config.registeredExtensions] 3D Tiles extensions managers registered for this tileset.
|
|
95
|
-
* @param {String} [config.pntsMode= PNTS_MODE.COLOR] {@link PointsMaterials} Point cloud coloring mode.
|
|
95
|
+
* @param {String} [config.pntsMode= PNTS_MODE.COLOR] {@link PointsMaterials} Point cloud coloring mode.
|
|
96
|
+
* Only 'COLOR' or 'CLASSIFICATION' are possible. COLOR uses RGB colors of the points,
|
|
97
|
+
* CLASSIFICATION uses a classification property of the batch table to color points.
|
|
96
98
|
* @param {String} [config.pntsShape= PNTS_SHAPE.CIRCLE] Point cloud point shape. Only 'CIRCLE' or 'SQUARE' are possible.
|
|
97
99
|
* @param {String} [config.pntsSizeMode= PNTS_SIZE_MODE.VALUE] {@link PointsMaterials} Point cloud size mode. Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance from point to camera.
|
|
98
100
|
* @param {Number} [config.pntsMinAttenuatedSize=3] Minimum scale used by 'ATTENUATED' size mode
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import CopcNode from "../Core/CopcNode.js";
|
|
3
|
+
import PointCloudLayer from "./PointCloudLayer.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @classdesc
|
|
7
|
+
* A layer for [Cloud Optimised Point Cloud](https://copc.io) (COPC) datasets.
|
|
8
|
+
* See {@link PointCloudLayer} class for documentation on base properties.
|
|
9
|
+
*
|
|
10
|
+
* @extends {PointCloudLayer}
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Create a new COPC layer
|
|
14
|
+
* const copcSource = new CopcSource({
|
|
15
|
+
* url: 'https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz',
|
|
16
|
+
* crs: 'EPSG:4978',
|
|
17
|
+
* colorDepth: 16, // bit-depth of 'color' attribute (either 8 or 16 bits)
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const copcLayer = new CopcLayer('COPC', {
|
|
21
|
+
* source: copcSource,
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* View.prototype.addLayer.call(view, copcLayer);
|
|
25
|
+
*/
|
|
26
|
+
class CopcLayer extends PointCloudLayer {
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} id - Unique id of the layer.
|
|
29
|
+
* @param {Object} config - See {@link PointCloudLayer} for base pointcloud
|
|
30
|
+
* options.
|
|
31
|
+
*/
|
|
32
|
+
constructor(id, config) {
|
|
33
|
+
super(id, config);
|
|
34
|
+
this.isCopcLayer = true;
|
|
35
|
+
const resolve = () => this;
|
|
36
|
+
this.whenReady = this.source.whenReady.then(( /** @type {CopcSource} */source) => {
|
|
37
|
+
const {
|
|
38
|
+
cube,
|
|
39
|
+
rootHierarchyPage
|
|
40
|
+
} = source.info;
|
|
41
|
+
const {
|
|
42
|
+
pageOffset,
|
|
43
|
+
pageLength
|
|
44
|
+
} = rootHierarchyPage;
|
|
45
|
+
this.root = new CopcNode(0, 0, 0, 0, pageOffset, pageLength, this, -1);
|
|
46
|
+
this.root.bbox.min.fromArray(cube, 0);
|
|
47
|
+
this.root.bbox.max.fromArray(cube, 3);
|
|
48
|
+
this.minElevationRange = source.header.min[2];
|
|
49
|
+
this.maxElevationRange = source.header.max[2];
|
|
50
|
+
this.scale = new THREE.Vector3(1.0, 1.0, 1.0);
|
|
51
|
+
this.offset = new THREE.Vector3(0.0, 0.0, 0.0);
|
|
52
|
+
return this.root.loadOctree().then(resolve);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
get spacing() {
|
|
56
|
+
return this.source.info.spacing;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export default CopcLayer;
|
|
@@ -60,14 +60,13 @@ class ElevationLayer extends RasterLayer {
|
|
|
60
60
|
* view.addLayer(elevation);
|
|
61
61
|
*/
|
|
62
62
|
constructor(id) {
|
|
63
|
-
var _config$clampValues, _config$clampValues2;
|
|
64
63
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
65
64
|
super(id, config);
|
|
66
65
|
if (config.zmin || config.zmax) {
|
|
67
66
|
console.warn('Config using zmin and zmax are deprecated, use {clampValues: {min, max}} structure.');
|
|
68
67
|
}
|
|
69
|
-
this.zmin =
|
|
70
|
-
this.zmax =
|
|
68
|
+
this.zmin = config.clampValues?.min ?? config.zmin;
|
|
69
|
+
this.zmax = config.clampValues?.max ?? config.zmax;
|
|
71
70
|
this.isElevationLayer = true;
|
|
72
71
|
this.defineLayerProperty('scale', this.scale || 1.0);
|
|
73
72
|
}
|
package/lib/Layer/GeoidLayer.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import Layer from "./Layer.js";
|
|
2
2
|
import LayerUpdateState from "./LayerUpdateState.js";
|
|
3
3
|
export function geoidLayerIsVisible(tilelayer) {
|
|
4
|
-
|
|
5
|
-
return tilelayer === null || tilelayer === void 0 ? void 0 : (_tilelayer$attachedLa = tilelayer.attachedLayers.filter(l => l.isGeoidLayer)[0]) === null || _tilelayer$attachedLa === void 0 ? void 0 : _tilelayer$attachedLa.visible;
|
|
4
|
+
return tilelayer?.attachedLayers.filter(l => l.isGeoidLayer)[0]?.visible;
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
/**
|
package/lib/Layer/LabelLayer.js
CHANGED
|
@@ -195,11 +195,9 @@ class LabelLayer extends GeometryLayer {
|
|
|
195
195
|
set visible(value) {
|
|
196
196
|
super.visible = value;
|
|
197
197
|
if (value) {
|
|
198
|
-
|
|
199
|
-
(_this$domElement = this.domElement) === null || _this$domElement === void 0 ? void 0 : _this$domElement.show();
|
|
198
|
+
this.domElement?.show();
|
|
200
199
|
} else {
|
|
201
|
-
|
|
202
|
-
(_this$domElement2 = this.domElement) === null || _this$domElement2 === void 0 ? void 0 : _this$domElement2.hide();
|
|
200
|
+
this.domElement?.hide();
|
|
203
201
|
}
|
|
204
202
|
}
|
|
205
203
|
get submittedLabelNodes() {
|
|
@@ -231,16 +229,15 @@ class LabelLayer extends GeometryLayer {
|
|
|
231
229
|
coord.crs = data.crs;
|
|
232
230
|
context.setZoom(extent.zoom);
|
|
233
231
|
data.features.forEach(f => {
|
|
234
|
-
var _f$style, _f$style$text, _f$style2, _f$style2$point;
|
|
235
232
|
// TODO: add support for LINE and POLYGON
|
|
236
233
|
if (f.type !== FEATURE_TYPES.POINT) {
|
|
237
234
|
return;
|
|
238
235
|
}
|
|
239
236
|
context.setFeature(f);
|
|
240
|
-
const featureField =
|
|
237
|
+
const featureField = f.style?.text?.field;
|
|
241
238
|
|
|
242
239
|
// determine if altitude style is specified by the user
|
|
243
|
-
const altitudeStyle =
|
|
240
|
+
const altitudeStyle = f.style?.point?.base_altitude;
|
|
244
241
|
const isDefaultElevationStyle = altitudeStyle instanceof Function && altitudeStyle.name == 'baseAltitudeDefault';
|
|
245
242
|
|
|
246
243
|
// determine if the altitude needs update with ElevationLayer
|
|
@@ -292,19 +289,14 @@ class LabelLayer extends GeometryLayer {
|
|
|
292
289
|
this.toHide.add(labelsNode);
|
|
293
290
|
}
|
|
294
291
|
#findClosestDomElement(node) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
var _node$parent$link$thi;
|
|
298
|
-
return ((_node$parent$link$thi = node.parent.link[this.id]) === null || _node$parent$link$thi === void 0 ? void 0 : _node$parent$link$thi.domElements) || this.#findClosestDomElement(node.parent);
|
|
292
|
+
if (node.parent?.isTileMesh) {
|
|
293
|
+
return node.parent.link[this.id]?.domElements || this.#findClosestDomElement(node.parent);
|
|
299
294
|
} else {
|
|
300
295
|
return this.domElement;
|
|
301
296
|
}
|
|
302
297
|
}
|
|
303
298
|
#hasLabelChildren(object) {
|
|
304
|
-
return object.children.every(c =>
|
|
305
|
-
var _c$layerUpdateState$t;
|
|
306
|
-
return c.layerUpdateState && ((_c$layerUpdateState$t = c.layerUpdateState[this.id]) === null || _c$layerUpdateState$t === void 0 ? void 0 : _c$layerUpdateState$t.hasFinished());
|
|
307
|
-
});
|
|
299
|
+
return object.children.every(c => c.layerUpdateState && c.layerUpdateState[this.id]?.hasFinished());
|
|
308
300
|
}
|
|
309
301
|
|
|
310
302
|
// Remove all labels invisible with pre-culling with screen grid
|
|
@@ -439,8 +431,7 @@ class LabelLayer extends GeometryLayer {
|
|
|
439
431
|
this.removeNodeDomElement(node);
|
|
440
432
|
}
|
|
441
433
|
removeNodeDomElement(node) {
|
|
442
|
-
|
|
443
|
-
if ((_node$link$this$id = node.link[this.id]) !== null && _node$link$this$id !== void 0 && _node$link$this$id.domElements) {
|
|
434
|
+
if (node.link[this.id]?.domElements) {
|
|
444
435
|
const child = node.link[this.id].domElements.dom;
|
|
445
436
|
child.parentElement.removeChild(child);
|
|
446
437
|
delete node.link[this.id].domElements;
|
package/lib/Layer/Layer.js
CHANGED
|
@@ -66,6 +66,7 @@ class Layer extends THREE.EventDispatcher {
|
|
|
66
66
|
* @param {boolean} [config.addLabelLayer.performance=false] - In case label layer adding, so remove labels that have no chance of being visible.
|
|
67
67
|
* Indeed, even in the best case, labels will never be displayed. By example, if there's many labels.
|
|
68
68
|
* @param {boolean} [config.addLabelLayer.forceClampToTerrain=false] - use elevation layer to clamp label on terrain.
|
|
69
|
+
* @param {number} [config.subdivisionThreshold=256] - set the texture size and, if applied to the globe, affects the tile subdivision.
|
|
69
70
|
*
|
|
70
71
|
* @example
|
|
71
72
|
* // Add and create a new Layer
|
|
@@ -100,8 +101,7 @@ class Layer extends THREE.EventDispatcher {
|
|
|
100
101
|
super();
|
|
101
102
|
this.isLayer = true;
|
|
102
103
|
if (config.style && !(config.style instanceof Style)) {
|
|
103
|
-
|
|
104
|
-
if (typeof ((_config$style$fill = config.style.fill) === null || _config$style$fill === void 0 ? void 0 : _config$style$fill.pattern) === 'string') {
|
|
104
|
+
if (typeof config.style.fill?.pattern === 'string') {
|
|
105
105
|
console.warn('Using style.fill.pattern = { source: Img|url } is adviced');
|
|
106
106
|
config.style.fill.pattern = {
|
|
107
107
|
source: config.style.fill.pattern
|
|
@@ -110,6 +110,8 @@ class Layer extends THREE.EventDispatcher {
|
|
|
110
110
|
config.style = new Style(config.style);
|
|
111
111
|
}
|
|
112
112
|
this.style = config.style || new Style();
|
|
113
|
+
this.subdivisionThreshold = config.subdivisionThreshold || 256;
|
|
114
|
+
this.sizeDiagonalTexture = (2 * (this.subdivisionThreshold * this.subdivisionThreshold)) ** 0.5;
|
|
113
115
|
Object.assign(this, config);
|
|
114
116
|
Object.defineProperty(this, 'id', {
|
|
115
117
|
value: id,
|
|
@@ -73,16 +73,13 @@ function markForDeletion(elt) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
function changeIntensityRange(layer) {
|
|
76
|
-
|
|
77
|
-
(_layer$material$inten = layer.material.intensityRange) === null || _layer$material$inten === void 0 ? void 0 : _layer$material$inten.set(layer.minIntensityRange, layer.maxIntensityRange);
|
|
76
|
+
layer.material.intensityRange?.set(layer.minIntensityRange, layer.maxIntensityRange);
|
|
78
77
|
}
|
|
79
78
|
function changeElevationRange(layer) {
|
|
80
|
-
|
|
81
|
-
(_layer$material$eleva = layer.material.elevationRange) === null || _layer$material$eleva === void 0 ? void 0 : _layer$material$eleva.set(layer.minElevationRange, layer.maxElevationRange);
|
|
79
|
+
layer.material.elevationRange?.set(layer.minElevationRange, layer.maxElevationRange);
|
|
82
80
|
}
|
|
83
81
|
function changeAngleRange(layer) {
|
|
84
|
-
|
|
85
|
-
(_layer$material$angle = layer.material.angleRange) === null || _layer$material$angle === void 0 ? void 0 : _layer$material$angle.set(layer.minAngleRange, layer.maxAngleRange);
|
|
82
|
+
layer.material.angleRange?.set(layer.minAngleRange, layer.maxAngleRange);
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
/**
|
|
@@ -176,7 +173,7 @@ class PointCloudLayer extends GeometryLayer {
|
|
|
176
173
|
if (this.material) {
|
|
177
174
|
this.material.visible = this.visible;
|
|
178
175
|
this.material.opacity = this.opacity;
|
|
179
|
-
this.material.transparent = this.opacity < 1;
|
|
176
|
+
this.material.transparent = this.opacity < 1 || this.material.userData.needTransparency[this.material.mode];
|
|
180
177
|
this.material.size = this.pointSize;
|
|
181
178
|
this.material.scale = context.camera.preSSE;
|
|
182
179
|
if (this.material.updateUniforms) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// next step is move these properties to Style class
|
|
2
2
|
// and hide transparent mechanism
|
|
3
|
-
|
|
4
3
|
function ReferLayerProperties(material, layer) {
|
|
5
4
|
if (layer && layer.isGeometryLayer) {
|
|
6
5
|
let transparent = material.transparent;
|
|
@@ -44,9 +43,10 @@ function ReferLayerProperties(material, layer) {
|
|
|
44
43
|
});
|
|
45
44
|
Object.defineProperty(material, 'transparent', {
|
|
46
45
|
get: () => {
|
|
47
|
-
|
|
46
|
+
const needTransparency = material.userData.needTransparency?.[material.mode] || material.layer.opacity < 1.0;
|
|
47
|
+
if (transparent != needTransparency) {
|
|
48
48
|
material.needsUpdate = true;
|
|
49
|
-
transparent =
|
|
49
|
+
transparent = needTransparency;
|
|
50
50
|
}
|
|
51
51
|
return transparent;
|
|
52
52
|
}
|
|
@@ -4,7 +4,6 @@ import { InfoTiledGeometryLayer } from "./InfoLayer.js";
|
|
|
4
4
|
import Picking from "../Core/Picking.js";
|
|
5
5
|
import convertToTile from "../Converter/convertToTile.js";
|
|
6
6
|
import ObjectRemovalHelper from "../Process/ObjectRemovalHelper.js";
|
|
7
|
-
import { SIZE_DIAGONAL_TEXTURE } from "../Process/LayeredMaterialNodeProcessing.js";
|
|
8
7
|
import { ImageryLayers } from "./Layer.js";
|
|
9
8
|
import { CACHE_POLICIES } from "../Core/Scheduler/Cache.js";
|
|
10
9
|
const subdivisionVector = new THREE.Vector3();
|
|
@@ -89,7 +88,7 @@ class TiledGeometryLayer extends GeometryLayer {
|
|
|
89
88
|
this.object3d.add(...level0s);
|
|
90
89
|
this.object3d.updateMatrixWorld();
|
|
91
90
|
}));
|
|
92
|
-
this.maxScreenSizeNode = this.sseSubdivisionThreshold * (
|
|
91
|
+
this.maxScreenSizeNode = this.sseSubdivisionThreshold * (this.sizeDiagonalTexture * 2);
|
|
93
92
|
}
|
|
94
93
|
get hideSkirt() {
|
|
95
94
|
return this._hideSkirt;
|
|
@@ -408,7 +407,7 @@ class TiledGeometryLayer extends GeometryLayer {
|
|
|
408
407
|
|
|
409
408
|
// The screen space error is calculated to have a correct texture display.
|
|
410
409
|
// For the projection of a texture's texel to be less than or equal to one pixel
|
|
411
|
-
const sse = node.screenSize / (
|
|
410
|
+
const sse = node.screenSize / (this.sizeDiagonalTexture * 2);
|
|
412
411
|
return this.sseSubdivisionThreshold < sse;
|
|
413
412
|
}
|
|
414
413
|
}
|
package/lib/Main.js
CHANGED
|
@@ -60,6 +60,7 @@ export { default as GlobeLayer } from "./Core/Prefab/Globe/GlobeLayer.js";
|
|
|
60
60
|
export { default as PlanarLayer } from "./Core/Prefab/Planar/PlanarLayer.js";
|
|
61
61
|
export { default as LabelLayer } from "./Layer/LabelLayer.js";
|
|
62
62
|
export { default as EntwinePointTileLayer } from "./Layer/EntwinePointTileLayer.js";
|
|
63
|
+
export { default as CopcLayer } from "./Layer/CopcLayer.js";
|
|
63
64
|
export { default as GeoidLayer } from "./Layer/GeoidLayer.js";
|
|
64
65
|
|
|
65
66
|
// Sources provided by default in iTowns
|
|
@@ -78,6 +79,7 @@ export { default as C3DTilesSource } from "./Source/C3DTilesSource.js";
|
|
|
78
79
|
export { default as C3DTilesIonSource } from "./Source/C3DTilesIonSource.js";
|
|
79
80
|
export { default as C3DTilesGoogleSource } from "./Source/C3DTilesGoogleSource.js";
|
|
80
81
|
export { default as EntwinePointTileSource } from "./Source/EntwinePointTileSource.js";
|
|
82
|
+
export { default as CopcSource } from "./Source/CopcSource.js";
|
|
81
83
|
|
|
82
84
|
// Parsers provided by default in iTowns
|
|
83
85
|
// Custom parser can be implemented as wanted, as long as the main function
|
|
@@ -132,8 +132,7 @@ function toFeatureType(jsonType) {
|
|
|
132
132
|
const keyProperties = ['type', 'geometry', 'properties'];
|
|
133
133
|
const firstCoordinates = a => a === undefined || Array.isArray(a) && !isNaN(a[0]) ? a : firstCoordinates(a[0]);
|
|
134
134
|
function jsonFeatureToFeature(crsIn, json, collection) {
|
|
135
|
-
|
|
136
|
-
if (!((_json$geometry = json.geometry) !== null && _json$geometry !== void 0 && _json$geometry.type)) {
|
|
135
|
+
if (!json.geometry?.type) {
|
|
137
136
|
console.warn('No geometry provided');
|
|
138
137
|
return null;
|
|
139
138
|
}
|
|
@@ -142,7 +141,7 @@ function jsonFeatureToFeature(crsIn, json, collection) {
|
|
|
142
141
|
const feature = collection.requestFeatureByType(featureType);
|
|
143
142
|
const coordinates = jsonType != 'point' ? json.geometry.coordinates : [json.geometry.coordinates];
|
|
144
143
|
const properties = json.properties || {};
|
|
145
|
-
feature.hasRawElevationData =
|
|
144
|
+
feature.hasRawElevationData = firstCoordinates(coordinates)?.length === 3;
|
|
146
145
|
|
|
147
146
|
// copy other properties
|
|
148
147
|
for (const key of Object.keys(json)) {
|