itowns 2.43.2-next.2 → 2.43.2-next.20
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/558.js +2 -0
- package/dist/558.js.map +1 -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_lasparser.js +2 -0
- package/dist/itowns_lasparser.js.map +1 -0
- package/dist/itowns_lasworker.js +2 -0
- package/dist/itowns_lasworker.js.map +1 -0
- package/dist/itowns_potree2worker.js +2 -0
- package/dist/itowns_potree2worker.js.map +1 -0
- 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 +1 -0
- package/examples/copc_simple_loader.html +1 -1
- 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/potree2_25d_map.html +127 -0
- 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 +6 -7
- 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/Potree2Node.js +206 -0
- package/lib/Core/Potree2PointAttributes.js +139 -0
- package/lib/Core/Prefab/Globe/Atmosphere.js +0 -4
- package/lib/Core/Prefab/Globe/GlobeLayer.js +3 -3
- package/lib/Core/Scheduler/Scheduler.js +1 -1
- package/lib/Core/Style.js +54 -53
- package/lib/Core/View.js +2 -4
- package/lib/Layer/C3DTilesLayer.js +8 -6
- 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 +5 -8
- package/lib/Layer/Potree2Layer.js +165 -0
- package/lib/Layer/ReferencingLayerProperties.js +8 -3
- package/lib/Layer/TiledGeometryLayer.js +6 -4
- package/lib/Loader/Potree2BrotliLoader.js +261 -0
- package/lib/Loader/Potree2Loader.js +207 -0
- package/lib/Main.js +2 -0
- package/lib/Parser/GeoJsonParser.js +2 -3
- package/lib/Parser/LASParser.js +49 -18
- package/lib/Parser/Potree2BinParser.js +92 -0
- package/lib/Parser/deprecated/LegacyGLTFLoader.js +1 -2
- package/lib/Process/3dTilesProcessing.js +2 -1
- 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 +3 -2
- package/lib/Renderer/ColorLayersOrdering.js +1 -2
- package/lib/Renderer/Label2DRenderer.js +1 -4
- package/lib/Renderer/PointsMaterial.js +135 -100
- package/lib/Renderer/RenderMode.js +0 -1
- package/lib/Source/FileSource.js +1 -1
- package/lib/Source/Potree2Source.js +172 -0
- 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/lib/Worker/LASLoaderWorker.js +19 -0
- package/lib/Worker/Potree2Worker.js +21 -0
- package/package.json +11 -8
- /package/lib/{Parser → Loader}/LASLoader.js +0 -0
|
@@ -22,10 +22,8 @@
|
|
|
22
22
|
* @returns {GeoTIFFLevel} The selected zoom level.
|
|
23
23
|
*/
|
|
24
24
|
function selectLevel(source, requestExtent, requestWidth, requestHeight) {
|
|
25
|
-
// Number of images = original + overviews if any
|
|
26
|
-
const cropped = requestExtent.clone().intersect(source.extent);
|
|
27
25
|
// Dimensions of the requested extent
|
|
28
|
-
const extentDimension =
|
|
26
|
+
const extentDimension = requestExtent.clone().planarDimensions();
|
|
29
27
|
|
|
30
28
|
const targetResolution = Math.min(
|
|
31
29
|
extentDimension.x / requestWidth,
|
|
@@ -87,70 +85,112 @@ function makeWindowFromExtent(source, extent, resolution) {
|
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
/**
|
|
90
|
-
*
|
|
88
|
+
* Reads raster data from the image as RGB.
|
|
89
|
+
* The result is always an interleaved typed array.
|
|
90
|
+
* Colorspaces other than RGB will be transformed to RGB, color maps expanded.
|
|
91
|
+
*
|
|
92
|
+
* @param {Source} source The COGSource.
|
|
93
|
+
* @param {GeoTIFFLevel} level The GeoTIFF level to read
|
|
94
|
+
* @param {number[]} viewport The image region to read.
|
|
95
|
+
* @returns {Promise<TypedArray[]>} The raster data
|
|
96
|
+
*/
|
|
97
|
+
async function readRGB(source, level, viewport) {
|
|
98
|
+
try {
|
|
99
|
+
// TODO possible optimization: instead of letting geotiff.js crop and resample
|
|
100
|
+
// the tiles into the desired region, we could use image.getTileOrStrip() to
|
|
101
|
+
// read individual tiles (aka blocks) and make a texture per block. This way,
|
|
102
|
+
// there would not be multiple concurrent reads for the same block, and we would not
|
|
103
|
+
// waste time resampling the blocks since resampling is already done in the composer.
|
|
104
|
+
// We would create more textures, but it could be worth it.
|
|
105
|
+
return await level.image.readRGB({
|
|
106
|
+
window: viewport,
|
|
107
|
+
pool: source.pool,
|
|
108
|
+
width: source.tileWidth,
|
|
109
|
+
height: source.tileHeight,
|
|
110
|
+
resampleMethod: source.resampleMethod,
|
|
111
|
+
enableAlpha: true,
|
|
112
|
+
interleave: true,
|
|
113
|
+
});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (error.toString() === 'AggregateError: Request failed') {
|
|
116
|
+
// Problem with the source that is blocked by another fetch
|
|
117
|
+
// (request failed in readRasters). See the conversations in
|
|
118
|
+
// https://github.com/geotiffjs/geotiff.js/issues/218
|
|
119
|
+
// https://github.com/geotiffjs/geotiff.js/issues/221
|
|
120
|
+
// https://github.com/geotiffjs/geotiff.js/pull/224
|
|
121
|
+
// Retry until it is not blocked.
|
|
122
|
+
// TODO retry counter
|
|
123
|
+
await new Promise((resolve) => {
|
|
124
|
+
setTimeout(resolve, 100);
|
|
125
|
+
});
|
|
126
|
+
return readRGB(level, viewport, source);
|
|
127
|
+
}
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Creates a texture from the pixel buffer
|
|
91
134
|
*
|
|
92
135
|
* @param {Object} source The COGSource
|
|
93
|
-
* @param {THREE.TypedArray
|
|
94
|
-
* @param {number}
|
|
95
|
-
* @param {number}
|
|
96
|
-
* @param {number}
|
|
136
|
+
* @param {THREE.TypedArray[]} buffer The pixel buffer
|
|
137
|
+
* @param {number} buffer.width
|
|
138
|
+
* @param {number} buffer.height
|
|
139
|
+
* @param {number} buffer.byteLength
|
|
97
140
|
* @returns {THREE.DataTexture} The generated texture.
|
|
98
141
|
*/
|
|
99
|
-
function createTexture(source,
|
|
100
|
-
const {
|
|
142
|
+
function createTexture(source, buffer) {
|
|
143
|
+
const { byteLength } = buffer;
|
|
144
|
+
const width = source.tileWidth;
|
|
145
|
+
const height = source.tileHeight;
|
|
101
146
|
const pixelCount = width * height;
|
|
102
147
|
const targetDataType = source.dataType;
|
|
103
148
|
const format = THREE.RGBAFormat;
|
|
104
149
|
const channelCount = 4;
|
|
105
|
-
|
|
106
|
-
let
|
|
107
|
-
|
|
108
|
-
// Check if it's a RGBA buffer
|
|
109
|
-
if (pixelCount * channelCount === byteLength) {
|
|
110
|
-
data = buffers;
|
|
111
|
-
}
|
|
150
|
+
const isRGBA = pixelCount * channelCount === byteLength;
|
|
151
|
+
let tmpBuffer = buffer;
|
|
112
152
|
|
|
113
153
|
switch (targetDataType) {
|
|
114
154
|
case THREE.UnsignedByteType: {
|
|
115
|
-
if (!
|
|
116
|
-
|
|
117
|
-
const newBuffers = new Uint8ClampedArray(pixelCount * channelCount);
|
|
118
|
-
data = convertToRGBA(buffers, newBuffers, source.defaultAlpha);
|
|
155
|
+
if (!isRGBA) {
|
|
156
|
+
tmpBuffer = convertToRGBA(tmpBuffer, new Uint8ClampedArray(pixelCount * channelCount), source.defaultAlpha);
|
|
119
157
|
}
|
|
120
|
-
|
|
121
|
-
break;
|
|
158
|
+
return new THREE.DataTexture(tmpBuffer, width, height, format, THREE.UnsignedByteType);
|
|
122
159
|
}
|
|
123
160
|
case THREE.FloatType: {
|
|
124
|
-
if (!
|
|
125
|
-
|
|
126
|
-
const newBuffers = new Float32Array(pixelCount * channelCount);
|
|
127
|
-
data = convertToRGBA(buffers, newBuffers, source.defaultAlpha / 255);
|
|
161
|
+
if (!isRGBA) {
|
|
162
|
+
tmpBuffer = convertToRGBA(tmpBuffer, new Float32Array(pixelCount * channelCount), source.defaultAlpha / 255);
|
|
128
163
|
}
|
|
129
|
-
|
|
130
|
-
break;
|
|
164
|
+
return new THREE.DataTexture(tmpBuffer, width, height, format, THREE.FloatType);
|
|
131
165
|
}
|
|
132
166
|
default:
|
|
133
167
|
throw new Error('unsupported data type');
|
|
134
168
|
}
|
|
135
|
-
|
|
136
|
-
return texture;
|
|
137
169
|
}
|
|
138
170
|
|
|
139
|
-
|
|
140
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Convert RGB pixel buffer to RGBA pixel buffer
|
|
173
|
+
*
|
|
174
|
+
* @param {THREE.TypedArray[]} buffer The RGB pixel buffer
|
|
175
|
+
* @param {THREE.TypedArray[]} newBuffer The empty RGBA pixel buffer
|
|
176
|
+
* @param {number} defaultAlpha Default alpha value
|
|
177
|
+
* @returns {THREE.DataTexture} The generated texture.
|
|
178
|
+
*/
|
|
179
|
+
function convertToRGBA(buffer, newBuffer, defaultAlpha) {
|
|
180
|
+
const { width, height } = buffer;
|
|
141
181
|
|
|
142
182
|
for (let i = 0; i < width * height; i++) {
|
|
143
183
|
const oldIndex = i * 3;
|
|
144
184
|
const index = i * 4;
|
|
145
185
|
// Copy RGB from original buffer
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
186
|
+
newBuffer[index + 0] = buffer[oldIndex + 0]; // R
|
|
187
|
+
newBuffer[index + 1] = buffer[oldIndex + 1]; // G
|
|
188
|
+
newBuffer[index + 2] = buffer[oldIndex + 2]; // B
|
|
149
189
|
// Add alpha to new buffer
|
|
150
|
-
|
|
190
|
+
newBuffer[index + 3] = defaultAlpha; // A
|
|
151
191
|
}
|
|
152
192
|
|
|
153
|
-
return
|
|
193
|
+
return newBuffer;
|
|
154
194
|
}
|
|
155
195
|
|
|
156
196
|
/**
|
|
@@ -195,20 +235,14 @@ const COGParser = (function _() {
|
|
|
195
235
|
*/
|
|
196
236
|
parse: async function _(data, options) {
|
|
197
237
|
const source = options.in;
|
|
198
|
-
const
|
|
199
|
-
const level = selectLevel(source, nodeExtent, source.tileWidth, source.tileHeight);
|
|
200
|
-
const viewport = makeWindowFromExtent(source, nodeExtent, level.resolution);
|
|
201
|
-
|
|
202
|
-
const buffers = await level.image.readRGB({
|
|
203
|
-
window: viewport,
|
|
204
|
-
pool: source.pool,
|
|
205
|
-
enableAlpha: true,
|
|
206
|
-
interleave: true,
|
|
207
|
-
});
|
|
238
|
+
const tileExtent = options.extent.as(source.crs);
|
|
208
239
|
|
|
209
|
-
const
|
|
240
|
+
const level = selectLevel(source, tileExtent, source.tileWidth, source.tileHeight);
|
|
241
|
+
const viewport = makeWindowFromExtent(source, tileExtent, level.resolution);
|
|
242
|
+
const rgbBuffer = await readRGB(source, level, viewport);
|
|
243
|
+
const texture = createTexture(source, rgbBuffer);
|
|
210
244
|
texture.flipY = true;
|
|
211
|
-
texture.extent =
|
|
245
|
+
texture.extent = options.extent;
|
|
212
246
|
texture.needsUpdate = true;
|
|
213
247
|
texture.magFilter = THREE.LinearFilter;
|
|
214
248
|
texture.minFilter = THREE.LinearFilter;
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
* @property {string} url - The URL of the COG.
|
|
16
16
|
* @property {GeoTIFF.Pool} pool - Pool use to decode GeoTiff.
|
|
17
17
|
* @property {number} defaultAlpha - Alpha byte value used if no alpha is present in COG. Default value is 255.
|
|
18
|
+
* @property {number} tileWidth - Tile width in pixels. Default value use 'geotiff.getTileWidth()'.
|
|
19
|
+
* @property {number} tileHeight - Tile height in pixels. Default value use 'geotiff.getTileHeight()'.
|
|
20
|
+
* @property {number} resampleMethod - The desired resampling method. Default is 'nearest'.
|
|
18
21
|
*
|
|
19
22
|
* @example
|
|
20
23
|
* // Create the source
|
|
@@ -59,9 +62,9 @@ class COGSource extends itowns.Source {
|
|
|
59
62
|
this.firstImage = await geotiff.getImage();
|
|
60
63
|
this.origin = this.firstImage.getOrigin();
|
|
61
64
|
this.dataType = this.selectDataType(this.firstImage.getSampleFormat(), this.firstImage.getBitsPerSample());
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
+
this.tileWidth = source.tileWidth || this.firstImage.getTileWidth();
|
|
66
|
+
this.tileHeight = source.tileHeight || this.firstImage.getTileHeight();
|
|
67
|
+
this.resampleMethod = source.resampleMethod || 'nearest';
|
|
65
68
|
|
|
66
69
|
// Compute extent
|
|
67
70
|
const [minX, minY, maxX, maxY] = this.firstImage.getBoundingBox();
|
|
@@ -80,7 +83,7 @@ class COGSource extends itowns.Source {
|
|
|
80
83
|
.then(image => this.makeLevel(image, image.getResolution(this.firstImage)));
|
|
81
84
|
promises.push(promise);
|
|
82
85
|
}
|
|
83
|
-
this.levels.
|
|
86
|
+
this.levels = this.levels.concat(await Promise.all(promises));
|
|
84
87
|
});
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"crs": "EPSG:3857",
|
|
5
5
|
"isInverted": true,
|
|
6
6
|
"format": "image/png",
|
|
7
|
-
"url": "
|
|
7
|
+
"url": "https://maps.pole-emploi.fr/styles/klokantech-basic/${z}/${x}/${y}.png",
|
|
8
8
|
"attribution": {
|
|
9
9
|
"name":"OpenStreetMap",
|
|
10
10
|
"url": "http://www.openstreetmap.org/"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Point Cloud Viewer</title>
|
|
5
|
+
|
|
6
|
+
<style type="text/css">
|
|
7
|
+
#info {
|
|
8
|
+
color: #7ad7ff;
|
|
9
|
+
font-family: 'Open Sans', sans-serif;
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 0;
|
|
12
|
+
left: 0;
|
|
13
|
+
padding: 0.3rem;
|
|
14
|
+
background-color: #404040;
|
|
15
|
+
z-index: 1;
|
|
16
|
+
}
|
|
17
|
+
@media (max-width: 600px) {
|
|
18
|
+
#info,
|
|
19
|
+
.dg {
|
|
20
|
+
display: none;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
|
|
25
|
+
<meta charset="UTF-8">
|
|
26
|
+
<link rel="stylesheet" type="text/css" href="css/example.css">
|
|
27
|
+
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">
|
|
28
|
+
|
|
29
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
30
|
+
</head>
|
|
31
|
+
<body>
|
|
32
|
+
<div id="viewerDiv">
|
|
33
|
+
<div id="info"></div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div>
|
|
37
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
|
|
38
|
+
<script src="../dist/itowns.js"></script>
|
|
39
|
+
<script src="js/GUI/LoadingScreen.js"></script>
|
|
40
|
+
<script src="../dist/debug.js"></script>
|
|
41
|
+
<script type="text/javascript">
|
|
42
|
+
var potreeLayer;
|
|
43
|
+
var oldPostUpdate;
|
|
44
|
+
var viewerDiv;
|
|
45
|
+
var debugGui;
|
|
46
|
+
var view;
|
|
47
|
+
var controls;
|
|
48
|
+
|
|
49
|
+
// Define crs projection that we will use (taken from https://epsg.io/3946, Proj4js section)
|
|
50
|
+
itowns.proj4.defs('EPSG:3946', '+proj=lcc +lat_1=45.25 +lat_2=46.75 +lat_0=46 +lon_0=3 +x_0=1700000 +y_0=5200000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs');
|
|
51
|
+
|
|
52
|
+
viewerDiv = document.getElementById('viewerDiv');
|
|
53
|
+
viewerDiv.style.display = 'block';
|
|
54
|
+
|
|
55
|
+
debugGui = new dat.GUI();
|
|
56
|
+
|
|
57
|
+
// TODO: do we really need to disable logarithmicDepthBuffer ?
|
|
58
|
+
view = new itowns.View('EPSG:3946', viewerDiv);
|
|
59
|
+
setupLoadingScreen(viewerDiv, view);
|
|
60
|
+
view.mainLoop.gfxEngine.renderer.setClearColor(0xcccccc);
|
|
61
|
+
|
|
62
|
+
// Configure Point Cloud layer
|
|
63
|
+
potreeLayer = new itowns.Potree2Layer('Lion', {
|
|
64
|
+
source: new itowns.Potree2Source({
|
|
65
|
+
file: 'metadata.json',
|
|
66
|
+
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/potree2.0/lion',
|
|
67
|
+
crs: view.referenceCrs,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// point selection on double-click
|
|
72
|
+
function dblClickHandler(event) {
|
|
73
|
+
var pick = view.pickObjectsAt(event, 5, potreeLayer);
|
|
74
|
+
|
|
75
|
+
for (const p of pick) {
|
|
76
|
+
console.info('Selected point #' + p.index + ' in position (' +
|
|
77
|
+
p.object.position.x + ', ' +
|
|
78
|
+
p.object.position.y + ', ' +
|
|
79
|
+
p.object.position.z +
|
|
80
|
+
') in Points ' + p.object.layer.id);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
view.domElement.addEventListener('dblclick', dblClickHandler);
|
|
84
|
+
|
|
85
|
+
function placeCamera(position, lookAt) {
|
|
86
|
+
view.camera.camera3D.position.copy(position);
|
|
87
|
+
view.camera.camera3D.lookAt(lookAt);
|
|
88
|
+
// create controls
|
|
89
|
+
controls = new itowns.FirstPersonControls(view, { focusOnClick: true });
|
|
90
|
+
debugGui.add(controls.options, 'moveSpeed', 1, 100).name('Movement speed');
|
|
91
|
+
|
|
92
|
+
view.notifyChange(view.camera.camera3D);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// add potreeLayer to scene
|
|
96
|
+
function onLayerReady() {
|
|
97
|
+
var ratio;
|
|
98
|
+
var position;
|
|
99
|
+
var lookAt = new itowns.THREE.Vector3();
|
|
100
|
+
var size = new itowns.THREE.Vector3();
|
|
101
|
+
|
|
102
|
+
potreeLayer.root.bbox.getSize(size);
|
|
103
|
+
potreeLayer.root.bbox.getCenter(lookAt);
|
|
104
|
+
|
|
105
|
+
debug.PointCloudDebug.initTools(view, potreeLayer, debugGui);
|
|
106
|
+
|
|
107
|
+
view.camera.camera3D.far = 2.0 * size.length();
|
|
108
|
+
|
|
109
|
+
ratio = size.x / size.z;
|
|
110
|
+
position = potreeLayer.root.bbox.min.clone().add(
|
|
111
|
+
size.multiply({ x: 0, y: 0, z: ratio * 0.5 }));
|
|
112
|
+
lookAt.z = potreeLayer.root.bbox.min.z;
|
|
113
|
+
placeCamera(position, lookAt);
|
|
114
|
+
controls.moveSpeed = size.length() / 3;
|
|
115
|
+
|
|
116
|
+
// update stats window
|
|
117
|
+
var info = document.getElementById('info');
|
|
118
|
+
view.addFrameRequester(itowns.MAIN_LOOP_EVENTS.AFTER_RENDER, () => {
|
|
119
|
+
info.textContent = potreeLayer.displayedCount.toLocaleString() + ' points';
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
window.view = view;
|
|
123
|
+
view.addLayer(potreeLayer).then(onLayerReady);
|
|
124
|
+
</script>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
127
|
+
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
potreeLayer.root.bbox.getSize(size);
|
|
103
103
|
potreeLayer.root.bbox.getCenter(lookAt);
|
|
104
104
|
|
|
105
|
-
debug.
|
|
105
|
+
debug.PointCloudDebug.initTools(view, potreeLayer, debugGui);
|
|
106
106
|
|
|
107
107
|
view.camera3D.far = 2.0 * size.length();
|
|
108
108
|
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
|
|
72
72
|
// add potreeLayer to scene
|
|
73
73
|
function onLayerReady() {
|
|
74
|
-
debug.
|
|
74
|
+
debug.PointCloudDebug.initTools(view, potreeLayer, debugGui);
|
|
75
75
|
|
|
76
76
|
// update stats window
|
|
77
77
|
var info = document.getElementById('info');
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
itowns.proj4.defs('EPSG:2154', '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs');
|
|
37
37
|
|
|
38
38
|
var viewerDiv = document.getElementById('viewerDiv');
|
|
39
|
+
var view;
|
|
39
40
|
|
|
40
41
|
function readCOGURL() {
|
|
41
42
|
var url = document.getElementById('cog_url').value || new URLSearchParams(window.location.search).get('geotiff');
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
function loadRGBSample() {
|
|
50
|
-
document.getElementById('cog_url').value = 'https://cdn.jsdelivr.net/gh/
|
|
51
|
+
document.getElementById('cog_url').value = 'https://cdn.jsdelivr.net/gh/iTowns/iTowns2-sample-data/cog/nantes/nantes.tif';
|
|
51
52
|
readCOGURL();
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -56,17 +57,33 @@
|
|
|
56
57
|
readCOGURL();
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
function
|
|
60
|
+
function removeAllChildNodes(parent) {
|
|
61
|
+
while (parent.firstChild) {
|
|
62
|
+
parent.removeChild(parent.firstChild);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function loadCOG(url) {
|
|
60
67
|
// create a source from a Cloud Optimized GeoTiff
|
|
61
68
|
var cogSource = new COGSource({
|
|
62
69
|
url: url,
|
|
63
|
-
crs: "EPSG:2154"
|
|
70
|
+
crs: "EPSG:2154",
|
|
71
|
+
// Default resample method is 'nearest', 'bilinear' looks better when zoomed
|
|
72
|
+
resampleMethod: 'bilinear'
|
|
64
73
|
});
|
|
65
74
|
|
|
66
75
|
cogSource.whenReady.then(() => {
|
|
67
|
-
|
|
76
|
+
if (view !== undefined) {
|
|
77
|
+
view.dispose(true);
|
|
78
|
+
removeAllChildNodes(viewerDiv);
|
|
79
|
+
}
|
|
80
|
+
view = new itowns.PlanarView(viewerDiv, cogSource.extent, {
|
|
81
|
+
// Default maxSubdivisionLevel is 5, so with huge geotiff it's not enough to see details when zoomed
|
|
82
|
+
maxSubdivisionLevel: 10,
|
|
83
|
+
disableSkirt: true,
|
|
84
|
+
placement: { tilt: 90 }
|
|
85
|
+
});
|
|
68
86
|
setupLoadingScreen(viewerDiv, view);
|
|
69
|
-
new itowns.PlanarControls(view, {});
|
|
70
87
|
var cogLayer = new itowns.ColorLayer('cog', {
|
|
71
88
|
source: cogSource,
|
|
72
89
|
});
|
|
@@ -416,7 +416,6 @@ function featureToExtrudedPolygon(feature, options) {
|
|
|
416
416
|
meshColor.toArray(colors, t); // top
|
|
417
417
|
meshColor.multiplyScalar(0.5).toArray(colors, i); // base is half dark
|
|
418
418
|
}
|
|
419
|
-
|
|
420
419
|
featureId++;
|
|
421
420
|
const geomVertices = vertices.slice(startTop * 3, (end + totalVertices) * 3);
|
|
422
421
|
const holesOffsets = geometry.indices.map(i => i.offset - start).slice(1);
|
|
@@ -496,14 +495,13 @@ function pointsToInstancedMeshes(feature) {
|
|
|
496
495
|
* @return {THREE.Mesh} mesh or GROUP of THREE.InstancedMesh
|
|
497
496
|
*/
|
|
498
497
|
function featureToMesh(feature, options) {
|
|
499
|
-
var _style$point, _style$point$model;
|
|
500
498
|
if (!feature.vertices) {
|
|
501
499
|
return;
|
|
502
500
|
}
|
|
503
501
|
let mesh;
|
|
504
502
|
switch (feature.type) {
|
|
505
503
|
case FEATURE_TYPES.POINT:
|
|
506
|
-
if (
|
|
504
|
+
if (style.point?.model?.object) {
|
|
507
505
|
try {
|
|
508
506
|
mesh = pointsToInstancedMeshes(feature);
|
|
509
507
|
mesh.isInstancedMesh = true;
|
|
@@ -592,7 +590,7 @@ export default {
|
|
|
592
590
|
// style properties (@link StyleOptions) using options.style.
|
|
593
591
|
// This is usually done in some tests and if you want to use Feature2Mesh.convert()
|
|
594
592
|
// as in examples/source_file_gpx_3d.html.
|
|
595
|
-
style =
|
|
593
|
+
style = this?.style || (options.style ? new Style(options.style) : defaultStyle);
|
|
596
594
|
context.setCollection(collection);
|
|
597
595
|
const features = collection.features;
|
|
598
596
|
if (!features || features.length == 0) {
|
|
@@ -21,7 +21,7 @@ export default {
|
|
|
21
21
|
const backgroundLayer = layer.source.backgroundLayer;
|
|
22
22
|
const backgroundColor = backgroundLayer && backgroundLayer.paint ? new THREE.Color(backgroundLayer.paint['background-color']) : undefined;
|
|
23
23
|
extentDestination.as(CRS.formatToEPSG(layer.crs), extentTexture);
|
|
24
|
-
texture = Feature2Texture.createTextureFromFeature(data, extentTexture,
|
|
24
|
+
texture = Feature2Texture.createTextureFromFeature(data, extentTexture, layer.subdivisionThreshold, layer.style, backgroundColor);
|
|
25
25
|
texture.features = data;
|
|
26
26
|
texture.extent = extentDestination;
|
|
27
27
|
} else if (data.isTexture) {
|
|
@@ -52,7 +52,7 @@ class C3DTBatchTable {
|
|
|
52
52
|
if (Array.isArray(propVal)) {
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
55
|
-
if (typeof
|
|
55
|
+
if (typeof propVal?.byteOffset !== 'undefined' && typeof propVal?.componentType !== 'undefined' && typeof propVal?.type !== 'undefined') {
|
|
56
56
|
jsonContent[propKey] = binaryPropertyAccessor(binaryBuffer, this.batchLength, propVal.byteOffset, propVal.componentType, propVal.type);
|
|
57
57
|
} else {
|
|
58
58
|
console.error('Invalid 3D Tiles batch table property that is neither a JSON array nor a valid ' + 'accessor to a binary body');
|
|
@@ -72,12 +72,12 @@ class C3DTFeature {
|
|
|
72
72
|
target.min.y = Infinity;
|
|
73
73
|
target.min.z = Infinity;
|
|
74
74
|
this.groups.forEach(group => {
|
|
75
|
-
const positionIndexStart = group.start *
|
|
76
|
-
const positionIndexCount = (group.start + group.count) *
|
|
77
|
-
for (let index = positionIndexStart; index < positionIndexCount; index
|
|
78
|
-
const x = this.object3d.geometry.attributes.position.
|
|
79
|
-
const y = this.object3d.geometry.attributes.position.
|
|
80
|
-
const z = this.object3d.geometry.attributes.position.
|
|
75
|
+
const positionIndexStart = group.start * this.object3d.geometry.attributes.position.itemSize;
|
|
76
|
+
const positionIndexCount = (group.start + group.count) * this.object3d.geometry.attributes.position.itemSize;
|
|
77
|
+
for (let index = positionIndexStart; index < positionIndexCount; index++) {
|
|
78
|
+
const x = this.object3d.geometry.attributes.position.getX(index);
|
|
79
|
+
const y = this.object3d.geometry.attributes.position.getY(index);
|
|
80
|
+
const z = this.object3d.geometry.attributes.position.getZ(index);
|
|
81
81
|
target.max.x = Math.max(x, target.max.x);
|
|
82
82
|
target.max.y = Math.max(y, target.max.y);
|
|
83
83
|
target.max.z = Math.max(z, target.max.z);
|
|
@@ -103,7 +103,6 @@ class C3DTFeature {
|
|
|
103
103
|
console.warn(`[C3DTFeature]: No batch table found for tile ${this.tileId}.`);
|
|
104
104
|
return null; // or return undefined;
|
|
105
105
|
}
|
|
106
|
-
|
|
107
106
|
this.#info = batchTable.getInfoById(this.batchId);
|
|
108
107
|
return this.#info;
|
|
109
108
|
}
|
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