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,128 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<meta charset="UTF-8">
|
|
4
|
+
|
|
5
|
+
<title>Itowns - COPC loader</title>
|
|
6
|
+
|
|
7
|
+
<link rel="stylesheet" type="text/css" href="css/example.css">
|
|
8
|
+
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
#description {
|
|
12
|
+
z-index: 2;
|
|
13
|
+
left: 10px;
|
|
14
|
+
}
|
|
15
|
+
</style>
|
|
16
|
+
|
|
17
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
18
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div id="description">Specify the URL of a COPC file to load:
|
|
22
|
+
<input type="text" id="url" />
|
|
23
|
+
<button onclick="readURL()">Load</button>
|
|
24
|
+
<div>
|
|
25
|
+
<button onClick="loadAutzen()">Load Autzen Stadium (80mb)</button>
|
|
26
|
+
<button onClick="loadSofi()">Load SoFI Stadium (2.3gb)</button>
|
|
27
|
+
<button onClick="loadMillsite()">Load Millsite (1.9gb)</button>
|
|
28
|
+
<div id="share"></div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
<div id="viewerDiv"></div>
|
|
32
|
+
|
|
33
|
+
<script src="../dist/itowns.js"></script>
|
|
34
|
+
<script src="js/GUI/LoadingScreen.js"></script>
|
|
35
|
+
<script src="../dist/debug.js"></script>
|
|
36
|
+
<script type="text/javascript">
|
|
37
|
+
let layer; // COPCLayer
|
|
38
|
+
|
|
39
|
+
const uri = new URL(location);
|
|
40
|
+
|
|
41
|
+
const gui = new dat.GUI();
|
|
42
|
+
|
|
43
|
+
const viewerDiv = document.getElementById('viewerDiv');
|
|
44
|
+
const view = new itowns.View('EPSG:4326', viewerDiv);
|
|
45
|
+
const controls = new itowns.PlanarControls(view);
|
|
46
|
+
view.mainLoop.gfxEngine.renderer.setClearColor(0xdddddd);
|
|
47
|
+
|
|
48
|
+
setUrl(uri.searchParams.get('copc'));
|
|
49
|
+
|
|
50
|
+
function onLayerReady(layer) {
|
|
51
|
+
const camera = view.camera.camera3D;
|
|
52
|
+
|
|
53
|
+
const lookAt = new itowns.THREE.Vector3();
|
|
54
|
+
const size = new itowns.THREE.Vector3();
|
|
55
|
+
layer.root.bbox.getSize(size);
|
|
56
|
+
layer.root.bbox.getCenter(lookAt);
|
|
57
|
+
|
|
58
|
+
camera.far = 2.0 * size.length();
|
|
59
|
+
|
|
60
|
+
controls.groundLevel = layer.root.bbox.min.z;
|
|
61
|
+
const position = layer.root.bbox.min.clone().add(
|
|
62
|
+
size.multiply({ x: 1, y: 1, z: size.x / size.z }),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
camera.position.copy(position);
|
|
66
|
+
camera.lookAt(lookAt);
|
|
67
|
+
camera.updateProjectionMatrix();
|
|
68
|
+
|
|
69
|
+
view.notifyChange(camera);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
function readURL() {
|
|
74
|
+
const url = document.getElementById('url').value;
|
|
75
|
+
|
|
76
|
+
if (url) {
|
|
77
|
+
setUrl(url);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function setUrl(url) {
|
|
82
|
+
if (!url) return;
|
|
83
|
+
|
|
84
|
+
const input_url = document.getElementById('url');
|
|
85
|
+
if (!input_url) return;
|
|
86
|
+
|
|
87
|
+
uri.searchParams.set('copc', url);
|
|
88
|
+
history.replaceState(null, null, `?${uri.searchParams.toString()}`);
|
|
89
|
+
|
|
90
|
+
input_url.value = url;
|
|
91
|
+
load(url);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
function load(url) {
|
|
96
|
+
const source = new itowns.CopcSource({ url });
|
|
97
|
+
|
|
98
|
+
if (layer) {
|
|
99
|
+
gui.removeFolder(layer.debugUI);
|
|
100
|
+
view.removeLayer('COPC');
|
|
101
|
+
view.notifyChange();
|
|
102
|
+
layer.delete();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
layer = new itowns.CopcLayer('COPC', {
|
|
106
|
+
source,
|
|
107
|
+
crs: view.referenceCrs,
|
|
108
|
+
sseThreshold: 2,
|
|
109
|
+
pointBudget: 3000000,
|
|
110
|
+
});
|
|
111
|
+
view.addLayer(layer).then(onLayerReady);
|
|
112
|
+
debug.PointCloudDebug.initTools(view, layer, gui);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function loadAutzen() {
|
|
116
|
+
setUrl("https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function loadSofi() {
|
|
120
|
+
setUrl("https://s3.amazonaws.com/hobu-lidar/sofi.copc.laz");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function loadMillsite() {
|
|
124
|
+
setUrl("https://s3.amazonaws.com/data.entwine.io/millsite.copc.laz");
|
|
125
|
+
}
|
|
126
|
+
</script>
|
|
127
|
+
</body>
|
|
128
|
+
</html>
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
view.addLayer(eptLayer).then(onLayerReady);
|
|
105
105
|
|
|
106
106
|
eptLayer.whenReady
|
|
107
|
-
.then(() => debug.
|
|
107
|
+
.then(() => debug.PointCloudDebug.initTools(view, eptLayer, debugGui));
|
|
108
108
|
|
|
109
109
|
function dblClickHandler(event) {
|
|
110
110
|
var pick = view.pickObjectsAt(event, 5, eptLayer);
|
|
@@ -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/"
|
|
@@ -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');
|