itowns 2.45.1-next.0 → 2.45.1-next.1
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/455.js +2 -0
- package/dist/455.js.map +1 -0
- package/dist/debug.js +3 -0
- package/dist/debug.js.LICENSE.txt +13 -0
- package/dist/debug.js.map +1 -0
- package/dist/itowns.js +3 -0
- package/dist/itowns.js.LICENSE.txt +5 -0
- package/dist/itowns.js.map +1 -0
- 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 +2 -0
- package/dist/itowns_widgets.js.map +1 -0
- package/lib/Controls/FirstPersonControls.js +308 -0
- package/lib/Controls/FlyControls.js +175 -0
- package/lib/Controls/GlobeControls.js +1178 -0
- package/lib/Controls/PlanarControls.js +1025 -0
- package/lib/Controls/StateControl.js +432 -0
- package/lib/Controls/StreetControls.js +392 -0
- package/lib/Converter/Feature2Mesh.js +612 -0
- package/lib/Converter/Feature2Texture.js +174 -0
- package/lib/Converter/convertToTile.js +70 -0
- package/lib/Converter/textureConverter.js +43 -0
- package/lib/Core/3DTiles/C3DTBatchTable.js +131 -0
- package/lib/Core/3DTiles/C3DTBatchTableHierarchyExtension.js +96 -0
- package/lib/Core/3DTiles/C3DTBoundingVolume.js +156 -0
- package/lib/Core/3DTiles/C3DTExtensions.js +97 -0
- package/lib/Core/3DTiles/C3DTFeature.js +110 -0
- package/lib/Core/3DTiles/C3DTilesEnums.js +20 -0
- package/lib/Core/3DTiles/C3DTileset.js +99 -0
- package/lib/Core/3DTiles/utils/BinaryPropertyAccessor.js +100 -0
- package/lib/Core/AnimationPlayer.js +142 -0
- package/lib/Core/CopcNode.js +174 -0
- package/lib/Core/Deprecated/Undeprecator.js +74 -0
- package/lib/Core/EntwinePointTileNode.js +126 -0
- package/lib/Core/Feature.js +488 -0
- package/lib/Core/Geographic/GeoidGrid.js +108 -0
- package/lib/Core/Label.js +222 -0
- package/lib/Core/MainLoop.js +209 -0
- package/lib/Core/Picking.js +255 -0
- package/lib/Core/PointCloudNode.js +42 -0
- package/lib/Core/Potree2Node.js +206 -0
- package/lib/Core/Potree2PointAttributes.js +139 -0
- package/lib/Core/PotreeNode.js +101 -0
- package/lib/Core/Prefab/Globe/Atmosphere.js +293 -0
- package/lib/Core/Prefab/Globe/GlobeLayer.js +152 -0
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +110 -0
- package/lib/Core/Prefab/Globe/SkyShader.js +78 -0
- package/lib/Core/Prefab/GlobeView.js +155 -0
- package/lib/Core/Prefab/Planar/PlanarLayer.js +59 -0
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +71 -0
- package/lib/Core/Prefab/PlanarView.js +62 -0
- package/lib/Core/Prefab/TileBuilder.js +82 -0
- package/lib/Core/Prefab/computeBufferTileGeometry.js +248 -0
- package/lib/Core/Scheduler/Cache.js +17 -0
- package/lib/Core/Scheduler/CancelledCommandException.js +15 -0
- package/lib/Core/Scheduler/Scheduler.js +294 -0
- package/lib/Core/Style.js +660 -0
- package/lib/Core/StyleOptions.js +486 -0
- package/lib/Core/System/Capabilities.js +63 -0
- package/lib/Core/Tile/Tile.js +205 -0
- package/lib/Core/Tile/TileGrid.js +49 -0
- package/lib/Core/TileGeometry.js +124 -0
- package/lib/Core/TileMesh.js +108 -0
- package/lib/Core/View.js +1115 -0
- package/lib/Layer/C3DTilesLayer.js +459 -0
- package/lib/Layer/ColorLayer.js +154 -0
- package/lib/Layer/CopcLayer.js +63 -0
- package/lib/Layer/ElevationLayer.js +139 -0
- package/lib/Layer/EntwinePointTileLayer.js +71 -0
- package/lib/Layer/FeatureGeometryLayer.js +77 -0
- package/lib/Layer/GeoidLayer.js +80 -0
- package/lib/Layer/GeometryLayer.js +233 -0
- package/lib/Layer/InfoLayer.js +64 -0
- package/lib/Layer/LabelLayer.js +469 -0
- package/lib/Layer/Layer.js +335 -0
- package/lib/Layer/LayerUpdateState.js +89 -0
- package/lib/Layer/LayerUpdateStrategy.js +80 -0
- package/lib/Layer/OGC3DTilesLayer.js +543 -0
- package/lib/Layer/OrientedImageLayer.js +227 -0
- package/lib/Layer/PointCloudLayer.js +405 -0
- package/lib/Layer/Potree2Layer.js +171 -0
- package/lib/Layer/PotreeLayer.js +72 -0
- package/lib/Layer/RasterLayer.js +37 -0
- package/lib/Layer/ReferencingLayerProperties.js +62 -0
- package/lib/Layer/TiledGeometryLayer.js +459 -0
- package/lib/Loader/LASLoader.js +193 -0
- package/lib/Loader/Potree2BrotliLoader.js +261 -0
- package/lib/Loader/Potree2Loader.js +207 -0
- package/lib/Main.js +113 -0
- package/lib/MainBundle.js +4 -0
- package/lib/Parser/B3dmParser.js +174 -0
- package/lib/Parser/CameraCalibrationParser.js +94 -0
- package/lib/Parser/GDFParser.js +72 -0
- package/lib/Parser/GTXParser.js +75 -0
- package/lib/Parser/GeoJsonParser.js +212 -0
- package/lib/Parser/GpxParser.js +25 -0
- package/lib/Parser/ISGParser.js +71 -0
- package/lib/Parser/KMLParser.js +25 -0
- package/lib/Parser/LASParser.js +137 -0
- package/lib/Parser/MapBoxUrlParser.js +83 -0
- package/lib/Parser/PntsParser.js +131 -0
- package/lib/Parser/Potree2BinParser.js +92 -0
- package/lib/Parser/PotreeBinParser.js +106 -0
- package/lib/Parser/PotreeCinParser.js +29 -0
- package/lib/Parser/ShapefileParser.js +78 -0
- package/lib/Parser/VectorTileParser.js +215 -0
- package/lib/Parser/XbilParser.js +120 -0
- package/lib/Parser/deprecated/LegacyGLTFLoader.js +1386 -0
- package/lib/Parser/iGLTFLoader.js +168 -0
- package/lib/Process/3dTilesProcessing.js +304 -0
- package/lib/Process/FeatureProcessing.js +76 -0
- package/lib/Process/LayeredMaterialNodeProcessing.js +229 -0
- package/lib/Process/ObjectRemovalHelper.js +97 -0
- package/lib/Process/handlerNodeError.js +23 -0
- package/lib/Provider/3dTilesProvider.js +149 -0
- package/lib/Provider/DataSourceProvider.js +24 -0
- package/lib/Provider/Fetcher.js +233 -0
- package/lib/Provider/PointCloudProvider.js +45 -0
- package/lib/Provider/TileProvider.js +16 -0
- package/lib/Provider/URLBuilder.js +116 -0
- package/lib/Renderer/Camera.js +281 -0
- package/lib/Renderer/Color.js +56 -0
- package/lib/Renderer/ColorLayersOrdering.js +115 -0
- package/lib/Renderer/CommonMaterial.js +31 -0
- package/lib/Renderer/Label2DRenderer.js +192 -0
- package/lib/Renderer/LayeredMaterial.js +243 -0
- package/lib/Renderer/OBB.js +150 -0
- package/lib/Renderer/OrientedImageCamera.js +118 -0
- package/lib/Renderer/OrientedImageMaterial.js +167 -0
- package/lib/Renderer/PointsMaterial.js +485 -0
- package/lib/Renderer/RasterTile.js +243 -0
- package/lib/Renderer/RenderMode.js +31 -0
- package/lib/Renderer/Shader/ShaderChunk.js +160 -0
- package/lib/Renderer/Shader/ShaderUtils.js +47 -0
- package/lib/Renderer/SphereHelper.js +17 -0
- package/lib/Renderer/WebXR.js +51 -0
- package/lib/Renderer/c3DEngine.js +214 -0
- package/lib/Source/C3DTilesGoogleSource.js +74 -0
- package/lib/Source/C3DTilesIonSource.js +54 -0
- package/lib/Source/C3DTilesSource.js +30 -0
- package/lib/Source/CopcSource.js +126 -0
- package/lib/Source/EntwinePointTileSource.js +72 -0
- package/lib/Source/FileSource.js +188 -0
- package/lib/Source/OGC3DTilesGoogleSource.js +29 -0
- package/lib/Source/OGC3DTilesIonSource.js +34 -0
- package/lib/Source/OGC3DTilesSource.js +21 -0
- package/lib/Source/OrientedImageSource.js +59 -0
- package/lib/Source/Potree2Source.js +167 -0
- package/lib/Source/PotreeSource.js +82 -0
- package/lib/Source/Source.js +202 -0
- package/lib/Source/TMSSource.js +144 -0
- package/lib/Source/VectorTilesSource.js +182 -0
- package/lib/Source/WFSSource.js +170 -0
- package/lib/Source/WMSSource.js +167 -0
- package/lib/Source/WMTSSource.js +92 -0
- package/lib/ThreeExtended/capabilities/WebGL.js +69 -0
- package/lib/ThreeExtended/libs/ktx-parse.module.js +506 -0
- package/lib/ThreeExtended/libs/zstddec.module.js +29 -0
- package/lib/ThreeExtended/loaders/DDSLoader.js +200 -0
- package/lib/ThreeExtended/loaders/DRACOLoader.js +400 -0
- package/lib/ThreeExtended/loaders/GLTFLoader.js +2879 -0
- package/lib/ThreeExtended/loaders/KTX2Loader.js +709 -0
- package/lib/ThreeExtended/math/ColorSpaces.js +59 -0
- package/lib/ThreeExtended/utils/BufferGeometryUtils.js +846 -0
- package/lib/ThreeExtended/utils/WorkerPool.js +70 -0
- package/lib/Utils/CameraUtils.js +554 -0
- package/lib/Utils/DEMUtils.js +350 -0
- package/lib/Utils/FeaturesUtils.js +156 -0
- package/lib/Utils/Gradients.js +16 -0
- package/lib/Utils/ThreeUtils.js +115 -0
- package/lib/Utils/gui/C3DTilesStyle.js +218 -0
- package/lib/Utils/gui/Main.js +7 -0
- package/lib/Utils/gui/Minimap.js +152 -0
- package/lib/Utils/gui/Navigation.js +245 -0
- package/lib/Utils/gui/Scale.js +104 -0
- package/lib/Utils/gui/Searchbar.js +234 -0
- package/lib/Utils/gui/Widget.js +80 -0
- package/lib/Utils/placeObjectOnGround.js +136 -0
- package/lib/Worker/LASLoaderWorker.js +19 -0
- package/lib/Worker/Potree2Worker.js +21 -0
- package/package.json +2 -2
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import GeometryLayer from "./GeometryLayer.js";
|
|
3
|
+
import { InfoTiledGeometryLayer } from "./InfoLayer.js";
|
|
4
|
+
import Picking from "../Core/Picking.js";
|
|
5
|
+
import convertToTile from "../Converter/convertToTile.js";
|
|
6
|
+
import ObjectRemovalHelper from "../Process/ObjectRemovalHelper.js";
|
|
7
|
+
import { ImageryLayers } from "./Layer.js";
|
|
8
|
+
import { CACHE_POLICIES } from "../Core/Scheduler/Cache.js";
|
|
9
|
+
const subdivisionVector = new THREE.Vector3();
|
|
10
|
+
const boundingSphereCenter = new THREE.Vector3();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @property {InfoTiledGeometryLayer} info - Status information of layer
|
|
14
|
+
* @property {boolean} isTiledGeometryLayer - Used to checkout whether this
|
|
15
|
+
* layer is a TiledGeometryLayer. Default is true. You should not change this,
|
|
16
|
+
* as it is used internally for optimisation.
|
|
17
|
+
* @property {boolean} hideSkirt (default false) - Used to hide the skirt (tile borders).
|
|
18
|
+
* Useful when the layer opacity < 1
|
|
19
|
+
*
|
|
20
|
+
* @extends GeometryLayer
|
|
21
|
+
*/
|
|
22
|
+
class TiledGeometryLayer extends GeometryLayer {
|
|
23
|
+
/**
|
|
24
|
+
* A layer extending the {@link GeometryLayer}, but with a tiling notion.
|
|
25
|
+
*
|
|
26
|
+
* `TiledGeometryLayer` is the ground where `ColorLayer` and `ElevationLayer` are attached.
|
|
27
|
+
* `TiledGeometryLayer` is a quadtree data structure. At zoom 0,
|
|
28
|
+
* there is a single tile for the whole earth. At zoom level 1,
|
|
29
|
+
* the single tile splits into 4 tiles (2x2 tile square).
|
|
30
|
+
* Each zoom level quadtree divides the geometry tiles of the one before it.
|
|
31
|
+
* The camera distance determines how the tiles are subdivided for optimal data display.
|
|
32
|
+
*
|
|
33
|
+
* Some `GeometryLayer` can also be attached to the `TiledGeometryLayer` if they want to take advantage of the quadtree.
|
|
34
|
+
*
|
|
35
|
+
* 
|
|
36
|
+
* _In `GlobeView`, **red lines** represents the **WGS84 grid** and **orange lines** the **Pseudo-mercator grid**._
|
|
37
|
+
* _In this picture, there are tiles with 3 different zoom/levels._
|
|
38
|
+
*
|
|
39
|
+
* The zoom/level is based on [tiled web map](https://en.wikipedia.org/wiki/Tiled_web_map).
|
|
40
|
+
* It corresponds at meters by pixel. If the projection tile exceeds a certain pixel size (on screen)
|
|
41
|
+
* then it is subdivided into 4 tiles with a zoom greater than 1.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} id - The id of the layer, that should be unique. It is
|
|
44
|
+
* not mandatory, but an error will be emitted if this layer is added a
|
|
45
|
+
* {@link View} that already has a layer going by that id.
|
|
46
|
+
* @param {THREE.Object3D} object3d - The object3d used to contain the
|
|
47
|
+
* geometry of the TiledGeometryLayer. It is usually a `THREE.Group`, but it
|
|
48
|
+
* can be anything inheriting from a `THREE.Object3d`.
|
|
49
|
+
* @param {Array} schemeTile - extents Array of root tiles
|
|
50
|
+
* @param {Object} builder - builder geometry object
|
|
51
|
+
* @param {Object} [config] - Optional configuration, all elements in it
|
|
52
|
+
* will be merged as is in the layer. For example, if the configuration
|
|
53
|
+
* contains three elements `name, protocol, extent`, these elements will be
|
|
54
|
+
* available using `layer.name` or something else depending on the property
|
|
55
|
+
* name.
|
|
56
|
+
* @param {Source} [config.source] - Description and options of the source.
|
|
57
|
+
*
|
|
58
|
+
* @throws {Error} `object3d` must be a valid `THREE.Object3d`.
|
|
59
|
+
*/
|
|
60
|
+
constructor(id, object3d, schemeTile, builder, config) {
|
|
61
|
+
const {
|
|
62
|
+
sseSubdivisionThreshold = 1.0,
|
|
63
|
+
minSubdivisionLevel,
|
|
64
|
+
maxSubdivisionLevel,
|
|
65
|
+
maxDeltaElevationLevel,
|
|
66
|
+
tileMatrixSets,
|
|
67
|
+
diffuse,
|
|
68
|
+
showOutline = false,
|
|
69
|
+
segments,
|
|
70
|
+
disableSkirt = false,
|
|
71
|
+
materialOptions,
|
|
72
|
+
...configGeometryLayer
|
|
73
|
+
} = config;
|
|
74
|
+
super(id, object3d, {
|
|
75
|
+
...configGeometryLayer,
|
|
76
|
+
// cacheLifeTime = CACHE_POLICIES.INFINITE because the cache is handled by the builder
|
|
77
|
+
cacheLifeTime: CACHE_POLICIES.INFINITE,
|
|
78
|
+
source: false
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @type {boolean}
|
|
83
|
+
* @readonly
|
|
84
|
+
*/
|
|
85
|
+
this.isTiledGeometryLayer = true;
|
|
86
|
+
this.protocol = 'tile';
|
|
87
|
+
|
|
88
|
+
// TODO : this should be add in a preprocess method specific to GeoidLayer.
|
|
89
|
+
this.object3d.geoidHeight = 0;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @type {boolean}
|
|
93
|
+
*/
|
|
94
|
+
this.disableSkirt = disableSkirt;
|
|
95
|
+
this._hideSkirt = !!config.hideSkirt;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @type {number}
|
|
99
|
+
*/
|
|
100
|
+
this.sseSubdivisionThreshold = sseSubdivisionThreshold;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @type {number}
|
|
104
|
+
*/
|
|
105
|
+
this.minSubdivisionLevel = minSubdivisionLevel;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @type {number}
|
|
109
|
+
*/
|
|
110
|
+
this.maxSubdivisionLevel = maxSubdivisionLevel;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @type {number}
|
|
114
|
+
* @deprecated
|
|
115
|
+
*/
|
|
116
|
+
this.maxDeltaElevationLevel = maxDeltaElevationLevel;
|
|
117
|
+
this.segments = segments;
|
|
118
|
+
this.schemeTile = schemeTile;
|
|
119
|
+
this.builder = builder;
|
|
120
|
+
this.info = new InfoTiledGeometryLayer(this);
|
|
121
|
+
if (!this.schemeTile) {
|
|
122
|
+
throw new Error(`Cannot init tiled layer without schemeTile for layer ${this.id}`);
|
|
123
|
+
}
|
|
124
|
+
if (!this.builder) {
|
|
125
|
+
throw new Error(`Cannot init tiled layer without builder for layer ${this.id}`);
|
|
126
|
+
}
|
|
127
|
+
this.maxScreenSizeNode = this.sseSubdivisionThreshold * (this.sizeDiagonalTexture * 2);
|
|
128
|
+
this.tileMatrixSets = tileMatrixSets;
|
|
129
|
+
this.materialOptions = materialOptions;
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* @type {boolean}
|
|
133
|
+
*/
|
|
134
|
+
this.showOutline = showOutline;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @type {THREE.Vector3 | undefined}
|
|
138
|
+
*/
|
|
139
|
+
this.diffuse = diffuse;
|
|
140
|
+
this.level0Nodes = [];
|
|
141
|
+
const promises = [];
|
|
142
|
+
for (const root of this.schemeTile) {
|
|
143
|
+
promises.push(this.convert(undefined, root));
|
|
144
|
+
}
|
|
145
|
+
this._promises.push(Promise.all(promises).then(level0s => {
|
|
146
|
+
this.level0Nodes = level0s;
|
|
147
|
+
this.object3d.add(...level0s);
|
|
148
|
+
this.object3d.updateMatrixWorld();
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
get hideSkirt() {
|
|
152
|
+
return this._hideSkirt;
|
|
153
|
+
}
|
|
154
|
+
set hideSkirt(value) {
|
|
155
|
+
if (!this.level0Nodes) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this._hideSkirt = value;
|
|
159
|
+
for (const node of this.level0Nodes) {
|
|
160
|
+
node.traverse(obj => {
|
|
161
|
+
if (obj.isTileMesh) {
|
|
162
|
+
obj.geometry.hideSkirt = value;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Picking method for this layer. It uses the {@link Picking#pickTilesAt}
|
|
169
|
+
* method.
|
|
170
|
+
*
|
|
171
|
+
* @param {View} view - The view instance.
|
|
172
|
+
* @param {Object} coordinates - The coordinates to pick in the view. It
|
|
173
|
+
* should have at least `x` and `y` properties.
|
|
174
|
+
* @param {number} radius - Radius of the picking circle.
|
|
175
|
+
* @param {Array} target - Array to push picking result.
|
|
176
|
+
*
|
|
177
|
+
* @return {Array} An array containing all targets picked under the
|
|
178
|
+
* specified coordinates.
|
|
179
|
+
*/
|
|
180
|
+
pickObjectsAt(view, coordinates) {
|
|
181
|
+
let radius = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.options.defaultPickingRadius;
|
|
182
|
+
let target = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
|
|
183
|
+
return Picking.pickTilesAt(view, coordinates, radius, this, target);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Does pre-update work on the context:
|
|
188
|
+
* <ul>
|
|
189
|
+
* <li>update the `colorLayers` and `elevationLayers`</li>
|
|
190
|
+
* <li>update the `maxElevationLevel`</li>
|
|
191
|
+
* </ul>
|
|
192
|
+
*
|
|
193
|
+
* Once this work is done, it returns a list of nodes to update. Depending
|
|
194
|
+
* on the origin of `sources`, it can return a few things:
|
|
195
|
+
* <ul>
|
|
196
|
+
* <li>if `sources` is empty, it returns the first node of the layer
|
|
197
|
+
* (stored as `level0Nodes`), which will trigger the update of the whole
|
|
198
|
+
* tree</li>
|
|
199
|
+
* <li>if the update is triggered by a camera move, the whole tree is
|
|
200
|
+
* returned too</li>
|
|
201
|
+
* <li>if `source.layer` is this layer, it means that `source` is a node; a
|
|
202
|
+
* common ancestor will be found if there are multiple sources, with the
|
|
203
|
+
* default common ancestor being the first source itself</li>
|
|
204
|
+
* <li>else it returns the whole tree</li>
|
|
205
|
+
* </ul>
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} context - The context of the update; see the {@link
|
|
208
|
+
* MainLoop} for more informations.
|
|
209
|
+
* @param {Set<GeometryLayer|TileMesh>} sources - A list of sources to
|
|
210
|
+
* generate a list of nodes to update.
|
|
211
|
+
*
|
|
212
|
+
* @return {TileMesh[]} The array of nodes to update.
|
|
213
|
+
*/
|
|
214
|
+
preUpdate(context, sources) {
|
|
215
|
+
if (sources.has(undefined) || sources.size == 0) {
|
|
216
|
+
return this.level0Nodes;
|
|
217
|
+
}
|
|
218
|
+
context.colorLayers = context.view.getLayers((l, a) => a && a.id == this.id && l.isColorLayer);
|
|
219
|
+
context.elevationLayers = context.view.getLayers((l, a) => a && a.id == this.id && l.isElevationLayer);
|
|
220
|
+
context.maxElevationLevel = -1;
|
|
221
|
+
for (const e of context.elevationLayers) {
|
|
222
|
+
context.maxElevationLevel = Math.max(e.source.zoom.max, context.maxElevationLevel);
|
|
223
|
+
}
|
|
224
|
+
if (context.maxElevationLevel == -1) {
|
|
225
|
+
context.maxElevationLevel = Infinity;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Prepare ColorLayer sequence order
|
|
229
|
+
// In this moment, there is only one color layers sequence, because they are attached to tileLayer.
|
|
230
|
+
// In future, the sequence must be returned by parent geometry layer.
|
|
231
|
+
this.colorLayersOrder = ImageryLayers.getColorLayersIdOrderedBySequence(context.colorLayers);
|
|
232
|
+
let commonAncestor;
|
|
233
|
+
for (const source of sources.values()) {
|
|
234
|
+
if (source.isCamera) {
|
|
235
|
+
// if the change is caused by a camera move, no need to bother
|
|
236
|
+
// to find common ancestor: we need to update the whole tree:
|
|
237
|
+
// some invisible tiles may now be visible
|
|
238
|
+
return this.level0Nodes;
|
|
239
|
+
}
|
|
240
|
+
if (source.layer === this) {
|
|
241
|
+
if (!commonAncestor) {
|
|
242
|
+
commonAncestor = source;
|
|
243
|
+
} else {
|
|
244
|
+
commonAncestor = source.findCommonAncestor(commonAncestor);
|
|
245
|
+
if (!commonAncestor) {
|
|
246
|
+
return this.level0Nodes;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (commonAncestor.material == null) {
|
|
250
|
+
commonAncestor = undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (commonAncestor) {
|
|
255
|
+
return [commonAncestor];
|
|
256
|
+
} else {
|
|
257
|
+
return this.level0Nodes;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Update a node of this layer. The node will not be updated if:
|
|
263
|
+
* <ul>
|
|
264
|
+
* <li>it does not have a parent, then it is removed</li>
|
|
265
|
+
* <li>its parent is being subdivided</li>
|
|
266
|
+
* <li>is not visible in the camera</li>
|
|
267
|
+
* </ul>
|
|
268
|
+
*
|
|
269
|
+
* @param {Object} context - The context of the update; see the {@link
|
|
270
|
+
* MainLoop} for more informations.
|
|
271
|
+
* @param {Layer} layer - Parameter to be removed once all update methods
|
|
272
|
+
* have been aligned.
|
|
273
|
+
* @param {TileMesh} node - The node to update.
|
|
274
|
+
*
|
|
275
|
+
* @returns {Object}
|
|
276
|
+
*/
|
|
277
|
+
update(context, layer, node) {
|
|
278
|
+
if (!node.parent) {
|
|
279
|
+
return ObjectRemovalHelper.removeChildrenAndCleanup(this, node);
|
|
280
|
+
}
|
|
281
|
+
// early exit if parent' subdivision is in progress
|
|
282
|
+
if (node.parent.pendingSubdivision) {
|
|
283
|
+
node.visible = false;
|
|
284
|
+
node.material.visible = false;
|
|
285
|
+
this.info.update(node);
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// do proper culling
|
|
290
|
+
node.visible = !this.culling(node, context.camera);
|
|
291
|
+
if (node.visible) {
|
|
292
|
+
let requestChildrenUpdate = false;
|
|
293
|
+
node.material.visible = true;
|
|
294
|
+
this.info.update(node);
|
|
295
|
+
if (node.pendingSubdivision || TiledGeometryLayer.hasEnoughTexturesToSubdivide(context, node) && this.subdivision(context, this, node)) {
|
|
296
|
+
this.subdivideNode(context, node);
|
|
297
|
+
// display iff children aren't ready
|
|
298
|
+
node.material.visible = node.pendingSubdivision;
|
|
299
|
+
this.info.update(node);
|
|
300
|
+
requestChildrenUpdate = true;
|
|
301
|
+
}
|
|
302
|
+
if (node.material.visible) {
|
|
303
|
+
if (!requestChildrenUpdate) {
|
|
304
|
+
return ObjectRemovalHelper.removeChildren(this, node);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return requestChildrenUpdate ? node.children.filter(n => n.layer == this) : undefined;
|
|
308
|
+
}
|
|
309
|
+
node.material.visible = false;
|
|
310
|
+
this.info.update(node);
|
|
311
|
+
return ObjectRemovalHelper.removeChildren(this, node);
|
|
312
|
+
}
|
|
313
|
+
convert(requester, extent) {
|
|
314
|
+
return convertToTile.convert(requester, extent, this);
|
|
315
|
+
}
|
|
316
|
+
countColorLayersTextures() {
|
|
317
|
+
return arguments.length;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// eslint-disable-next-line
|
|
321
|
+
culling(node, camera) {
|
|
322
|
+
return !camera.isBox3Visible(node.obb.box3D, node.matrixWorld);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Tell if a node has enough elevation or color textures to subdivide.
|
|
327
|
+
* Subdivision is prevented if:
|
|
328
|
+
* <ul>
|
|
329
|
+
* <li>the node is covered by at least one elevation layer and if the node
|
|
330
|
+
* doesn't have an elevation texture yet</li>
|
|
331
|
+
* <li>a color texture is missing</li>
|
|
332
|
+
* </ul>
|
|
333
|
+
*
|
|
334
|
+
* @param {Object} context - The context of the update; see the {@link
|
|
335
|
+
* MainLoop} for more informations.
|
|
336
|
+
* @param {TileMesh} node - The node to subdivide.
|
|
337
|
+
*
|
|
338
|
+
* @returns {boolean} False if the node can not be subdivided, true
|
|
339
|
+
* otherwise.
|
|
340
|
+
*/
|
|
341
|
+
static hasEnoughTexturesToSubdivide(context, node) {
|
|
342
|
+
const layerUpdateState = node.layerUpdateState || {};
|
|
343
|
+
let nodeLayer = node.material.getElevationLayer();
|
|
344
|
+
for (const e of context.elevationLayers) {
|
|
345
|
+
const extents = node.getExtentsByProjection(e.crs);
|
|
346
|
+
const zoom = extents[0].zoom;
|
|
347
|
+
if (zoom > e.zoom.max || zoom < e.zoom.min) {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (!e.frozen && e.ready && e.source.extentInsideLimit(node.extent, zoom) && (!nodeLayer || nodeLayer.level < 0)) {
|
|
351
|
+
// no stop subdivision in the case of a loading error
|
|
352
|
+
if (layerUpdateState[e.id] && layerUpdateState[e.id].inError()) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (const c of context.colorLayers) {
|
|
359
|
+
if (c.frozen || !c.visible || !c.ready) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const extents = node.getExtentsByProjection(c.crs);
|
|
363
|
+
const zoom = extents[0].zoom;
|
|
364
|
+
if (zoom > c.zoom.max || zoom < c.zoom.min) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
// no stop subdivision in the case of a loading error
|
|
368
|
+
if (layerUpdateState[c.id] && layerUpdateState[c.id].inError()) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
nodeLayer = node.material.getLayer(c.id);
|
|
372
|
+
if (c.source.extentInsideLimit(node.extent, zoom) && (!nodeLayer || nodeLayer.level < 0)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Subdivides a node of this layer. If the node is currently in the process
|
|
381
|
+
* of subdivision, it will not do anything here. The subdivision of a node
|
|
382
|
+
* will occur in four part, to create a quadtree. The extent of the node
|
|
383
|
+
* will be divided in four parts: north-west, north-east, south-west and
|
|
384
|
+
* south-east. Once all four nodes are created, they will be added to the
|
|
385
|
+
* current node and the view of the context will be notified of this change.
|
|
386
|
+
*
|
|
387
|
+
* @param {Object} context - The context of the update; see the {@link
|
|
388
|
+
* MainLoop} for more informations.
|
|
389
|
+
* @param {TileMesh} node - The node to subdivide.
|
|
390
|
+
* @return {Promise} { description_of_the_return_value }
|
|
391
|
+
*/
|
|
392
|
+
subdivideNode(context, node) {
|
|
393
|
+
if (!node.pendingSubdivision && !node.children.some(n => n.layer == this)) {
|
|
394
|
+
const extents = node.extent.subdivision();
|
|
395
|
+
// TODO: pendingSubdivision mechanism is fragile, get rid of it
|
|
396
|
+
node.pendingSubdivision = true;
|
|
397
|
+
const command = {
|
|
398
|
+
/* mandatory */
|
|
399
|
+
view: context.view,
|
|
400
|
+
requester: node,
|
|
401
|
+
layer: this,
|
|
402
|
+
priority: 10000,
|
|
403
|
+
/* specific params */
|
|
404
|
+
extentsSource: extents,
|
|
405
|
+
redraw: false
|
|
406
|
+
};
|
|
407
|
+
return context.scheduler.execute(command).then(children => {
|
|
408
|
+
for (const child of children) {
|
|
409
|
+
node.add(child);
|
|
410
|
+
child.updateMatrixWorld(true);
|
|
411
|
+
}
|
|
412
|
+
node.pendingSubdivision = false;
|
|
413
|
+
context.view.notifyChange(node, false);
|
|
414
|
+
}, err => {
|
|
415
|
+
node.pendingSubdivision = false;
|
|
416
|
+
if (!err.isCancelledCommandException) {
|
|
417
|
+
throw new Error(err);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Test the subdvision of a node, compared to this layer.
|
|
425
|
+
*
|
|
426
|
+
* @param {Object} context - The context of the update; see the {@link
|
|
427
|
+
* MainLoop} for more informations.
|
|
428
|
+
* @param {PlanarLayer} layer - This layer, parameter to be removed.
|
|
429
|
+
* @param {TileMesh} node - The node to test.
|
|
430
|
+
*
|
|
431
|
+
* @return {boolean} - True if the node is subdivisable, otherwise false.
|
|
432
|
+
*/
|
|
433
|
+
subdivision(context, layer, node) {
|
|
434
|
+
if (node.level < this.minSubdivisionLevel) {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
if (this.maxSubdivisionLevel <= node.level) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
subdivisionVector.setFromMatrixScale(node.matrixWorld);
|
|
441
|
+
boundingSphereCenter.copy(node.boundingSphere.center).applyMatrix4(node.matrixWorld);
|
|
442
|
+
const distance = Math.max(0.0, context.camera.camera3D.position.distanceTo(boundingSphereCenter) - node.boundingSphere.radius * subdivisionVector.x);
|
|
443
|
+
|
|
444
|
+
// Size projection on pixel of bounding
|
|
445
|
+
if (context.camera.camera3D.isOrthographicCamera) {
|
|
446
|
+
const camera3D = context.camera.camera3D;
|
|
447
|
+
const preSSE = context.camera._preSSE * 2 * camera3D.zoom / (camera3D.top - camera3D.bottom);
|
|
448
|
+
node.screenSize = preSSE * node.boundingSphere.radius * subdivisionVector.x;
|
|
449
|
+
} else {
|
|
450
|
+
node.screenSize = context.camera._preSSE * (2 * node.boundingSphere.radius * subdivisionVector.x) / distance;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// The screen space error is calculated to have a correct texture display.
|
|
454
|
+
// For the projection of a texture's texel to be less than or equal to one pixel
|
|
455
|
+
const sse = node.screenSize / (this.sizeDiagonalTexture * 2);
|
|
456
|
+
return this.sseSubdivisionThreshold < sse;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
export default TiledGeometryLayer;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { LazPerf } from 'laz-perf';
|
|
2
|
+
import { Las } from 'copc';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} Header - Partial LAS header.
|
|
6
|
+
* @property {number} header.pointDataRecordFormat - Type of point data
|
|
7
|
+
* records contained by the buffer.
|
|
8
|
+
* @property {number} header.pointDataRecordLength - Size (in bytes) of the
|
|
9
|
+
* point data records. If the specified size is larger than implied by the
|
|
10
|
+
* point data record format (see above) the remaining bytes are user-specfic
|
|
11
|
+
* "extra bytes". Those are described by an Extra Bytes VLR.
|
|
12
|
+
* @property {number[]} header.scale - Scale factors (an array `[xScale,
|
|
13
|
+
* yScale, zScale]`) multiplied to the X, Y, Z point record values.
|
|
14
|
+
* @property {number[]} header.offset - Offsets (an array `[xOffset,
|
|
15
|
+
* xOffset, zOffset]`) added to the scaled X, Y, Z point record values.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
function defaultColorEncoding(header) {
|
|
19
|
+
return header.majorVersion === 1 && header.minorVersion <= 2 ? 8 : 16;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @classdesc
|
|
24
|
+
* Loader for LAS and LAZ (LASZip) point clouds. It uses the copc.js library and
|
|
25
|
+
* the laz-perf decoder under the hood.
|
|
26
|
+
*
|
|
27
|
+
* The laz-perf web assembly module is lazily fetched at runtime when a parsing
|
|
28
|
+
* request is initiated. Location of laz-perf wasm defaults to the unpkg
|
|
29
|
+
* repository.
|
|
30
|
+
*/
|
|
31
|
+
class LASLoader {
|
|
32
|
+
constructor() {
|
|
33
|
+
this._wasmPath = 'https://cdn.jsdelivr.net/npm/laz-perf@0.0.6/lib';
|
|
34
|
+
this._wasmPromise = null;
|
|
35
|
+
}
|
|
36
|
+
_initDecoder() {
|
|
37
|
+
if (this._wasmPromise) {
|
|
38
|
+
return this._wasmPromise;
|
|
39
|
+
}
|
|
40
|
+
this._wasmPromise = LazPerf.create({
|
|
41
|
+
locateFile: file => `${this._wasmPath}/${file}`
|
|
42
|
+
});
|
|
43
|
+
return this._wasmPromise;
|
|
44
|
+
}
|
|
45
|
+
_parseView(view, options) {
|
|
46
|
+
const colorDepth = options.colorDepth ?? 16;
|
|
47
|
+
const getPosition = ['X', 'Y', 'Z'].map(view.getter);
|
|
48
|
+
const getIntensity = view.getter('Intensity');
|
|
49
|
+
const getReturnNumber = view.getter('ReturnNumber');
|
|
50
|
+
const getNumberOfReturns = view.getter('NumberOfReturns');
|
|
51
|
+
const getClassification = view.getter('Classification');
|
|
52
|
+
const getPointSourceID = view.getter('PointSourceId');
|
|
53
|
+
const getColor = view.dimensions.Red ? ['Red', 'Green', 'Blue'].map(view.getter) : undefined;
|
|
54
|
+
const getScanAngle = view.getter('ScanAngle');
|
|
55
|
+
const positions = new Float32Array(view.pointCount * 3);
|
|
56
|
+
const intensities = new Uint16Array(view.pointCount);
|
|
57
|
+
const returnNumbers = new Uint8Array(view.pointCount);
|
|
58
|
+
const numberOfReturns = new Uint8Array(view.pointCount);
|
|
59
|
+
const classifications = new Uint8Array(view.pointCount);
|
|
60
|
+
const pointSourceIDs = new Uint16Array(view.pointCount);
|
|
61
|
+
const colors = getColor ? new Uint8Array(view.pointCount * 4) : undefined;
|
|
62
|
+
/*
|
|
63
|
+
As described by the LAS spec, Scan Angle is encoded:
|
|
64
|
+
- as signed char in a valid range from -90 to +90 (degrees) prior to the LAS 1.4 Point Data Record Formats (PDRF) 6
|
|
65
|
+
- as a signed short in a valid range from -30 000 to +30 000. Those values represents scan angles from -180 to +180
|
|
66
|
+
degrees with an increment of 0.006 for PDRF >= 6.
|
|
67
|
+
The copc.js library does the degree convertion and stores it as a `Float32`.
|
|
68
|
+
*/
|
|
69
|
+
const scanAngles = new Float32Array(view.pointCount);
|
|
70
|
+
|
|
71
|
+
// For precision we take the first point that will be use as origin for a local referentiel.
|
|
72
|
+
const origin = getPosition.map(f => f(0)).map(val => Math.floor(val));
|
|
73
|
+
for (let i = 0; i < view.pointCount; i++) {
|
|
74
|
+
// `getPosition` apply scale and offset transform to the X, Y, Z
|
|
75
|
+
// values. See https://github.com/connormanning/copc.js/blob/master/src/las/extractor.ts.
|
|
76
|
+
const [x, y, z] = getPosition.map(f => f(i));
|
|
77
|
+
positions[i * 3] = x - origin[0];
|
|
78
|
+
positions[i * 3 + 1] = y - origin[1];
|
|
79
|
+
positions[i * 3 + 2] = z - origin[2];
|
|
80
|
+
intensities[i] = getIntensity(i);
|
|
81
|
+
returnNumbers[i] = getReturnNumber(i);
|
|
82
|
+
numberOfReturns[i] = getNumberOfReturns(i);
|
|
83
|
+
if (getColor) {
|
|
84
|
+
// Note that we do not infer color depth as it is expensive
|
|
85
|
+
// (i.e. traverse the whole view to check if there exists a red,
|
|
86
|
+
// green or blue value > 255).
|
|
87
|
+
let [r, g, b] = getColor.map(f => f(i));
|
|
88
|
+
if (colorDepth === 16) {
|
|
89
|
+
r /= 256;
|
|
90
|
+
g /= 256;
|
|
91
|
+
b /= 256;
|
|
92
|
+
}
|
|
93
|
+
colors[i * 4] = r;
|
|
94
|
+
colors[i * 4 + 1] = g;
|
|
95
|
+
colors[i * 4 + 2] = b;
|
|
96
|
+
colors[i * 4 + 3] = 255;
|
|
97
|
+
}
|
|
98
|
+
classifications[i] = getClassification(i);
|
|
99
|
+
pointSourceIDs[i] = getPointSourceID(i);
|
|
100
|
+
scanAngles[i] = getScanAngle(i);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
position: positions,
|
|
104
|
+
intensity: intensities,
|
|
105
|
+
returnNumber: returnNumbers,
|
|
106
|
+
numberOfReturns,
|
|
107
|
+
classification: classifications,
|
|
108
|
+
pointSourceID: pointSourceIDs,
|
|
109
|
+
color: colors,
|
|
110
|
+
scanAngle: scanAngles,
|
|
111
|
+
origin
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Set LazPerf decoder path.
|
|
117
|
+
* @param {string} path - path to `laz-perf.wasm` folder.
|
|
118
|
+
*/
|
|
119
|
+
set lazPerf(path) {
|
|
120
|
+
this._wasmPath = path;
|
|
121
|
+
this._wasmPromise = null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Parses a LAS or LAZ (LASZip) chunk. Note that this function is
|
|
126
|
+
* **CPU-bound** and shall be parallelised in a dedicated worker.
|
|
127
|
+
* @param {Uint8Array} data - File chunk data.
|
|
128
|
+
* @param {Object} options - Parsing options.
|
|
129
|
+
* @param {Header} options.header - Partial LAS header.
|
|
130
|
+
* @param {number} options.pointCount - Number of points encoded in this
|
|
131
|
+
* data chunk.
|
|
132
|
+
* @param {Las.ExtraBytes[]} [options.eb] - Extra bytes LAS VLRs
|
|
133
|
+
* headers.
|
|
134
|
+
* @param {8 | 16} [options.colorDepth] - Color depth encoding (in bits).
|
|
135
|
+
* Either 8 or 16 bits. Defaults to 8 bits for LAS 1.2 and 16 bits for later
|
|
136
|
+
* versions (as mandatory by the specification).
|
|
137
|
+
*/
|
|
138
|
+
async parseChunk(data, options) {
|
|
139
|
+
const {
|
|
140
|
+
header,
|
|
141
|
+
eb,
|
|
142
|
+
pointCount
|
|
143
|
+
} = options;
|
|
144
|
+
const {
|
|
145
|
+
pointDataRecordFormat,
|
|
146
|
+
pointDataRecordLength
|
|
147
|
+
} = header;
|
|
148
|
+
const colorDepth = options.colorDepth ?? defaultColorEncoding(header);
|
|
149
|
+
const bytes = new Uint8Array(data);
|
|
150
|
+
const pointData = await Las.PointData.decompressChunk(bytes, {
|
|
151
|
+
pointCount,
|
|
152
|
+
pointDataRecordFormat,
|
|
153
|
+
pointDataRecordLength
|
|
154
|
+
}, this._initDecoder());
|
|
155
|
+
const view = Las.View.create(pointData, header, eb);
|
|
156
|
+
const attributes = this._parseView(view, {
|
|
157
|
+
colorDepth
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
attributes
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Parses a LAS or LAZ (LASZip) file. Note that this function is
|
|
166
|
+
* **CPU-bound** and shall be parallelised in a dedicated worker.
|
|
167
|
+
* @param {ArrayBuffer} data - Binary data to parse.
|
|
168
|
+
* @param {Object} [options] - Parsing options.
|
|
169
|
+
* @param {8 | 16} [options.colorDepth] - Color depth encoding (in bits).
|
|
170
|
+
* Either 8 or 16 bits. Defaults to 8 bits for LAS 1.2 and 16 bits for later
|
|
171
|
+
* versions (as mandatory by the specification)
|
|
172
|
+
*/
|
|
173
|
+
async parseFile(data) {
|
|
174
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
175
|
+
const bytes = new Uint8Array(data);
|
|
176
|
+
const pointData = await Las.PointData.decompressFile(bytes, this._initDecoder());
|
|
177
|
+
const header = Las.Header.parse(bytes);
|
|
178
|
+
const colorDepth = options.colorDepth ?? defaultColorEncoding(header);
|
|
179
|
+
const getter = async (begin, end) => bytes.slice(begin, end);
|
|
180
|
+
const vlrs = await Las.Vlr.walk(getter, header);
|
|
181
|
+
const ebVlr = Las.Vlr.find(vlrs, 'LASF_Spec', 4);
|
|
182
|
+
const eb = ebVlr && Las.ExtraBytes.parse(await Las.Vlr.fetch(getter, ebVlr));
|
|
183
|
+
const view = Las.View.create(pointData, header, eb);
|
|
184
|
+
const attributes = this._parseView(view, {
|
|
185
|
+
colorDepth
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
header,
|
|
189
|
+
attributes
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export default LASLoader;
|