itowns 2.42.1-next.5 → 2.42.1-next.7

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.
@@ -64,10 +64,17 @@
64
64
  }
65
65
 
66
66
  function readEPTURL() {
67
- var url = document.getElementById('ept_url').value || new URL(location.href).searchParams.get('ept');
67
+ const urlParams = new URL(location.href).searchParams
68
+ var url = document.getElementById('ept_url').value || urlParams.get('ept');
68
69
 
69
70
  if (url) {
70
- loadEPT(url);
71
+ const options = {};
72
+ urlParams.keys().forEach(key => {
73
+ if (key !== 'ept') {
74
+ options[key] = parseInt(urlParams.get(key), 10);
75
+ }
76
+ });
77
+ loadEPT(url, options);
71
78
 
72
79
  document.getElementById('share').innerHTML = '<a href="' +
73
80
  location.href.replace(location.search, '') +
@@ -77,7 +84,7 @@
77
84
  }
78
85
  }
79
86
 
80
- function loadEPT(url) {
87
+ function loadEPT(url, options) {
81
88
  eptSource = new itowns.EntwinePointTileSource({ url });
82
89
 
83
90
  if (eptLayer) {
@@ -87,14 +94,17 @@
87
94
  eptLayer.delete();
88
95
  }
89
96
 
90
- eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', {
97
+ const config = {
91
98
  source: eptSource,
92
99
  crs: view.referenceCrs,
93
- });
100
+ ...options,
101
+ }
102
+ eptLayer = new itowns.EntwinePointTileLayer('Entwine Point Tile', config);
94
103
 
95
104
  view.addLayer(eptLayer).then(onLayerReady);
96
105
 
97
- debug.PotreeDebug.initTools(view, eptLayer, debugGui);
106
+ eptLayer.whenReady
107
+ .then(() => debug.PotreeDebug.initTools(view, eptLayer, debugGui));
98
108
 
99
109
  function dblClickHandler(event) {
100
110
  var pick = view.pickObjectsAt(event, 5, eptLayer);
@@ -60,6 +60,8 @@ class EntwinePointTileLayer extends _PointCloudLayer.default {
60
60
  this.root = new _EntwinePointTileNode.default(0, 0, 0, 0, this, -1);
61
61
  this.root.bbox.min.fromArray(this.source.boundsConforming, 0);
62
62
  this.root.bbox.max.fromArray(this.source.boundsConforming, 3);
63
+ this.minElevationRange = this.source.boundsConforming[2];
64
+ this.maxElevationRange = this.source.boundsConforming[5];
63
65
  this.extent = _Extent.default.fromBox3(config.crs || 'EPSG:4326', this.root.bbox);
64
66
  return this.root.loadOctree().then(resolve);
65
67
  });
@@ -82,9 +82,16 @@ function markForDeletion(elt) {
82
82
  }
83
83
  }
84
84
  function changeIntensityRange(layer) {
85
- if (layer.material.intensityRange) {
86
- layer.material.intensityRange.set(layer.minIntensityRange, layer.maxIntensityRange);
87
- }
85
+ var _layer$material$inten;
86
+ (_layer$material$inten = layer.material.intensityRange) === null || _layer$material$inten === void 0 ? void 0 : _layer$material$inten.set(layer.minIntensityRange, layer.maxIntensityRange);
87
+ }
88
+ function changeElevationRange(layer) {
89
+ var _layer$material$eleva;
90
+ (_layer$material$eleva = layer.material.elevationRange) === null || _layer$material$eleva === void 0 ? void 0 : _layer$material$eleva.set(layer.minElevationRange, layer.maxElevationRange);
91
+ }
92
+ function changeAngleRange(layer) {
93
+ var _layer$material$angle;
94
+ (_layer$material$angle = layer.material.angleRange) === null || _layer$material$angle === void 0 ? void 0 : _layer$material$angle.set(layer.minAngleRange, layer.maxAngleRange);
88
95
  }
89
96
 
90
97
  /**
@@ -154,12 +161,18 @@ class PointCloudLayer extends _GeometryLayer.default {
154
161
  this.pointBudget = config.pointBudget || 2000000;
155
162
  this.pointSize = config.pointSize === 0 || !isNaN(config.pointSize) ? config.pointSize : 4;
156
163
  this.sseThreshold = config.sseThreshold || 2;
157
- this.defineLayerProperty('minIntensityRange', config.minIntensityRange || 0, changeIntensityRange);
158
- this.defineLayerProperty('maxIntensityRange', config.maxIntensityRange || 1, changeIntensityRange);
164
+ this.defineLayerProperty('minIntensityRange', config.minIntensityRange || 1, changeIntensityRange);
165
+ this.defineLayerProperty('maxIntensityRange', config.maxIntensityRange || 65536, changeIntensityRange);
166
+ this.defineLayerProperty('minElevationRange', config.minElevationRange || 0, changeElevationRange);
167
+ this.defineLayerProperty('maxElevationRange', config.maxElevationRange || 1000, changeElevationRange);
168
+ this.defineLayerProperty('minAngleRange', config.minAngleRange || -90, changeAngleRange);
169
+ this.defineLayerProperty('maxAngleRange', config.maxAngleRange || 90, changeAngleRange);
159
170
  this.material = config.material || {};
160
171
  if (!this.material.isMaterial) {
161
172
  config.material = config.material || {};
162
173
  config.material.intensityRange = new THREE.Vector2(this.minIntensityRange, this.maxIntensityRange);
174
+ config.material.elevationRange = new THREE.Vector2(this.minElevationRange, this.maxElevationRange);
175
+ config.material.angleRange = new THREE.Vector2(this.minAngleRange, this.maxAngleRange);
163
176
  this.material = new _PointsMaterial.default(config.material);
164
177
  }
165
178
  this.material.defines = this.material.defines || {};
@@ -51,6 +51,7 @@ class LASLoader {
51
51
  const getClassification = view.getter('Classification');
52
52
  const getPointSourceID = view.getter('PointSourceId');
53
53
  const getColor = view.dimensions.Red ? ['Red', 'Green', 'Blue'].map(view.getter) : undefined;
54
+ const getScanAngle = view.getter('ScanAngle');
54
55
  const positions = new Float32Array(view.pointCount * 3);
55
56
  const intensities = new Uint16Array(view.pointCount);
56
57
  const returnNumbers = new Uint8Array(view.pointCount);
@@ -58,6 +59,14 @@ class LASLoader {
58
59
  const classifications = new Uint8Array(view.pointCount);
59
60
  const pointSourceIDs = new Uint16Array(view.pointCount);
60
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);
61
70
  for (let i = 0; i < view.pointCount; i++) {
62
71
  // `getPosition` apply scale and offset transform to the X, Y, Z
63
72
  // values. See https://github.com/connormanning/copc.js/blob/master/src/las/extractor.ts.
@@ -85,6 +94,7 @@ class LASLoader {
85
94
  }
86
95
  classifications[i] = getClassification(i);
87
96
  pointSourceIDs[i] = getPointSourceID(i);
97
+ scanAngles[i] = getScanAngle(i);
88
98
  }
89
99
  return {
90
100
  position: positions,
@@ -93,7 +103,8 @@ class LASLoader {
93
103
  numberOfReturns,
94
104
  classification: classifications,
95
105
  pointSourceID: pointSourceIDs,
96
- color: colors
106
+ color: colors,
107
+ scanAngle: scanAngles
97
108
  };
98
109
  }
99
110
 
@@ -58,13 +58,13 @@ var _default = {
58
58
  geometry.userData = parsedData.header;
59
59
  const positionBuffer = new THREE.BufferAttribute(attributes.position, 3);
60
60
  geometry.setAttribute('position', positionBuffer);
61
- const intensityBuffer = new THREE.BufferAttribute(attributes.intensity, 1, true);
61
+ const intensityBuffer = new THREE.BufferAttribute(attributes.intensity, 1);
62
62
  geometry.setAttribute('intensity', intensityBuffer);
63
63
  const returnNumber = new THREE.BufferAttribute(attributes.returnNumber, 1);
64
64
  geometry.setAttribute('returnNumber', returnNumber);
65
65
  const numberOfReturns = new THREE.BufferAttribute(attributes.numberOfReturns, 1);
66
66
  geometry.setAttribute('numberOfReturns', numberOfReturns);
67
- const classBuffer = new THREE.BufferAttribute(attributes.classification, 1, true);
67
+ const classBuffer = new THREE.BufferAttribute(attributes.classification, 1);
68
68
  geometry.setAttribute('classification', classBuffer);
69
69
  const pointSourceID = new THREE.BufferAttribute(attributes.pointSourceID, 1);
70
70
  geometry.setAttribute('pointSourceID', pointSourceID);
@@ -72,6 +72,8 @@ var _default = {
72
72
  const colorBuffer = new THREE.BufferAttribute(attributes.color, 4, true);
73
73
  geometry.setAttribute('color', colorBuffer);
74
74
  }
75
+ const scanAngle = new THREE.BufferAttribute(attributes.scanAngle, 1);
76
+ geometry.setAttribute('scanAngle', scanAngle);
75
77
  geometry.computeBoundingBox();
76
78
  return geometry;
77
79
  });
@@ -218,16 +218,19 @@ function updateLayeredMaterialNodeElevation(context, layer, node, parent) {
218
218
  }, err => (0, _handlerNodeError.default)(err, node, layer, targetLevel, context.view));
219
219
  }
220
220
  function removeLayeredMaterialNodeLayer(layerId) {
221
+ /**
222
+ * @param {TileMesh} node - The node to udpate.
223
+ */
221
224
  return function (node) {
222
225
  var _node$material;
223
226
  if ((_node$material = node.material) !== null && _node$material !== void 0 && _node$material.removeLayer) {
224
- node.material.removeLayer(layerId);
225
- if (node.material.elevationLayerIds[0] == layerId) {
227
+ if (node.material.elevationLayerIds.indexOf(layerId) > -1) {
226
228
  node.setBBoxZ({
227
229
  min: 0,
228
230
  max: 0
229
231
  });
230
232
  }
233
+ node.material.removeLayer(layerId);
231
234
  }
232
235
  if (node.layerUpdateState && node.layerUpdateState[layerId]) {
233
236
  delete node.layerUpdateState[layerId];
@@ -9,17 +9,24 @@ var THREE = _interopRequireWildcard(require("three"));
9
9
  var _Capabilities = _interopRequireDefault(require("../Core/System/Capabilities"));
10
10
  var _ShaderUtils = _interopRequireDefault(require("./Shader/ShaderUtils"));
11
11
  var _CommonMaterial = _interopRequireDefault(require("./CommonMaterial"));
12
+ var _Gradients = _interopRequireDefault(require("../Utils/Gradients"));
12
13
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
14
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
14
15
  /* babel-plugin-inline-import './Shader/PointsVS.glsl' */
15
- const PointsVS = "#include <itowns/WebGL2_pars_vertex>\n#include <itowns/precision_qualifier>\n#include <itowns/project_pars_vertex>\n#if defined(USE_TEXTURES_PROJECTIVE)\n#include <itowns/projective_texturing_pars_vertex>\n#endif\n#include <common>\n#include <logdepthbuf_pars_vertex>\n\nuniform float size;\nuniform float scale;\n\nuniform bool picking;\nuniform int mode;\nuniform float opacity;\nuniform vec4 overlayColor;\nuniform vec2 intensityRange;\nuniform bool applyOpacityClassication;\nattribute vec3 color;\nattribute vec4 unique_id;\nattribute float intensity;\nattribute float classification;\nuniform sampler2D classificationLUT;\nuniform int sizeMode;\nuniform float minAttenuatedSize;\nuniform float maxAttenuatedSize;\n\n#if defined(NORMAL_OCT16)\nattribute vec2 oct16Normal;\n#elif defined(NORMAL_SPHEREMAPPED)\nattribute vec2 sphereMappedNormal;\n#else\nattribute vec3 normal;\n#endif\n\nvarying vec4 vColor;\n\n// see https://web.archive.org/web/20150303053317/http://lgdv.cs.fau.de/get/1602\n// and implementation in PotreeConverter (BINPointReader.cpp) and potree (BinaryDecoderWorker.js)\n#if defined(NORMAL_OCT16)\nvec3 decodeOct16Normal(vec2 encodedNormal) {\n vec2 nNorm = 2. * (encodedNormal / 255.) - 1.;\n vec3 n;\n n.z = 1. - abs(nNorm.x) - abs(nNorm.y);\n if (n.z >= 0.) {\n n.x = nNorm.x;\n n.y = nNorm.y;\n } else {\n n.x = sign(nNorm.x) - sign(nNorm.x) * sign(nNorm.y) * nNorm.y;\n n.y = sign(nNorm.y) - sign(nNorm.y) * sign(nNorm.x) * nNorm.x;\n }\n return normalize(n);\n}\n#elif defined(NORMAL_SPHEREMAPPED)\n// see http://aras-p.info/texts/CompactNormalStorage.html method #4\n// or see potree's implementation in BINPointReader.cpp\nvec3 decodeSphereMappedNormal(vec2 encodedNormal) {\n vec2 fenc = 2. * encodedNormal / 255. - 1.;\n float f = dot(fenc,fenc);\n float g = 2. * sqrt(1. - f);\n vec3 n;\n n.xy = fenc * g;\n n.z = 1. - 2. * f;\n return n;\n}\n#endif\n\nvoid main() {\n\n#if defined(NORMAL_OCT16)\n vec3 normal = decodeOct16Normal(oct16Normal);\n#elif defined(NORMAL_SPHEREMAPPED)\n vec3 normal = decodeSphereMappedNormal(sphereMappedNormal);\n#elif defined(NORMAL)\n // nothing to do\n#else\n // default to color\n vec3 normal = color;\n#endif\n\n if (picking) {\n vColor = unique_id;\n } else {\n vColor.a = opacity;\n if (applyOpacityClassication || mode == PNTS_MODE_CLASSIFICATION) {\n vec2 uv = vec2(classification, 0.5);\n vColor = texture2D(classificationLUT, uv);\n vColor.a *= opacity;\n }\n\n if (mode == PNTS_MODE_INTENSITY) {\n // adapt the grayscale knowing the range\n float i = (intensity - intensityRange.x) / (intensityRange.y - intensityRange.x);\n vColor.rgb = vec3(i, i, i);\n } else if (mode == PNTS_MODE_NORMAL) {\n vColor.rgb = abs(normal);\n } else if (mode == PNTS_MODE_COLOR) {\n // default to color mode\n vColor.rgb = mix(color, overlayColor.rgb, overlayColor.a);\n }\n }\n\n #include <begin_vertex>\n #include <project_vertex>\n\n gl_PointSize = size;\n\n if (sizeMode == PNTS_SIZE_MODE_ATTENUATED) {\n bool isPerspective = isPerspectiveMatrix(projectionMatrix);\n\n if (isPerspective) {\n gl_PointSize *= scale / -mvPosition.z;\n gl_PointSize = clamp(gl_PointSize, minAttenuatedSize, maxAttenuatedSize);\n }\n }\n\n#if defined(USE_TEXTURES_PROJECTIVE)\n #include <itowns/projective_texturing_vertex>\n#endif\n #include <logdepthbuf_vertex>\n}\n";
16
+ const PointsVS = "#include <itowns/WebGL2_pars_vertex>\n#include <itowns/precision_qualifier>\n#include <itowns/project_pars_vertex>\n#if defined(USE_TEXTURES_PROJECTIVE)\n#include <itowns/projective_texturing_pars_vertex>\n#endif\n#include <common>\n#include <logdepthbuf_pars_vertex>\n\n#define NB_CLASS 8.\n\nuniform float size;\nuniform float scale;\n\nuniform bool picking;\nuniform int mode;\nuniform float opacity;\nuniform vec4 overlayColor;\n\nuniform vec2 elevationRange;\nuniform vec2 intensityRange;\nuniform vec2 angleRange;\n\nuniform bool applyOpacityClassication;\n\nuniform sampler2D classificationTexture;\nuniform sampler2D discreteTexture;\nuniform sampler2D gradientTexture;\nuniform int sizeMode;\nuniform float minAttenuatedSize;\nuniform float maxAttenuatedSize;\n\nattribute vec3 color;\nattribute vec2 range;\nattribute vec4 unique_id;\nattribute float intensity;\nattribute float classification;\nattribute float pointSourceID;\n\nattribute float returnNumber;\nattribute float numberOfReturns;\nattribute float scanAngle;\n\n#if defined(NORMAL_OCT16)\nattribute vec2 oct16Normal;\n#elif defined(NORMAL_SPHEREMAPPED)\nattribute vec2 sphereMappedNormal;\n#else\nattribute vec3 normal;\n#endif\n\nvarying vec4 vColor;\n\n// see https://web.archive.org/web/20150303053317/http://lgdv.cs.fau.de/get/1602\n// and implementation in PotreeConverter (BINPointReader.cpp) and potree (BinaryDecoderWorker.js)\n#if defined(NORMAL_OCT16)\nvec3 decodeOct16Normal(vec2 encodedNormal) {\n vec2 nNorm = 2. * (encodedNormal / 255.) - 1.;\n vec3 n;\n n.z = 1. - abs(nNorm.x) - abs(nNorm.y);\n if (n.z >= 0.) {\n n.x = nNorm.x;\n n.y = nNorm.y;\n } else {\n n.x = sign(nNorm.x) - sign(nNorm.x) * sign(nNorm.y) * nNorm.y;\n n.y = sign(nNorm.y) - sign(nNorm.y) * sign(nNorm.x) * nNorm.x;\n }\n return normalize(n);\n}\n#elif defined(NORMAL_SPHEREMAPPED)\n// see http://aras-p.info/texts/CompactNormalStorage.html method #4\n// or see potree's implementation in BINPointReader.cpp\nvec3 decodeSphereMappedNormal(vec2 encodedNormal) {\n vec2 fenc = 2. * encodedNormal / 255. - 1.;\n float f = dot(fenc,fenc);\n float g = 2. * sqrt(1. - f);\n vec3 n;\n n.xy = fenc * g;\n n.z = 1. - 2. * f;\n return n;\n}\n#endif\n\nvoid main() {\n\n#if defined(NORMAL_OCT16)\n vec3 normal = decodeOct16Normal(oct16Normal);\n#elif defined(NORMAL_SPHEREMAPPED)\n vec3 normal = decodeSphereMappedNormal(sphereMappedNormal);\n#elif defined(NORMAL)\n // nothing to do\n#else\n // default to color\n vec3 normal = color;\n#endif\n\n if (picking) {\n vColor = unique_id;\n } else {\n vColor.a = opacity;\n if (applyOpacityClassication || mode == PNTS_MODE_CLASSIFICATION) {\n vec2 uv = vec2(classification/255., 0.5);\n vColor = texture2D(classificationTexture, uv);\n vColor.a *= opacity;\n }\n\n if (mode == PNTS_MODE_NORMAL) {\n vColor.rgb = abs(normal);\n } else if (mode == PNTS_MODE_COLOR) {\n // default to color mode\n vColor.rgb = mix(color, overlayColor.rgb, overlayColor.a);\n } else if (mode == PNTS_MODE_RETURN_NUMBER) {\n vec2 uv = vec2(returnNumber/255., 0.5);\n vColor = texture2D(discreteTexture, uv);\n } else if (mode == PNTS_MODE_RETURN_TYPE) {\n float returnType;\n if (returnNumber > numberOfReturns) {\n returnType = 4.;\n } else if (returnNumber == 1.) {\n if (numberOfReturns == 1.) {\n // single\n returnType = 0.;\n } else {\n // first\n returnType = 1.;\n }\n } else {\n if (returnNumber == numberOfReturns) {\n // last\n returnType = 3.;\n } else {\n // intermediate\n returnType = 2.;\n }\n }\n vec2 uv = vec2(returnType/255., 0.5);\n vColor = texture2D(discreteTexture, uv);\n } else if (mode == PNTS_MODE_RETURN_COUNT) {\n vec2 uv = vec2(numberOfReturns/255., 0.5);\n vColor = texture2D(discreteTexture, uv);\n } else if (mode == PNTS_MODE_POINT_SOURCE_ID) {\n vec2 uv = vec2(mod(pointSourceID, NB_CLASS)/255., 0.5);\n vColor = texture2D(discreteTexture, uv);\n } else if (mode == PNTS_MODE_SCAN_ANGLE) {\n float i = (scanAngle - angleRange.x) / (angleRange.y - angleRange.x);\n vec2 uv = vec2(i, (1. - i));\n vColor = texture2D(gradientTexture, uv);\n } else if (mode == PNTS_MODE_INTENSITY) {\n float i = (intensity - intensityRange.x) / (intensityRange.y - intensityRange.x);\n vec2 uv = vec2(i, (1. - i));\n vColor = texture2D(gradientTexture, uv);\n } else if (mode == PNTS_MODE_ELEVATION) {\n float i = (position.z - elevationRange.x) / (elevationRange.y - elevationRange.x);\n vec2 uv = vec2(i, (1. - i));\n vColor = texture2D(gradientTexture, uv);\n }\n }\n\n #include <begin_vertex>\n #include <project_vertex>\n\n gl_PointSize = size;\n\n if (sizeMode == PNTS_SIZE_MODE_ATTENUATED) {\n bool isPerspective = isPerspectiveMatrix(projectionMatrix);\n\n if (isPerspective) {\n gl_PointSize *= scale / -mvPosition.z;\n gl_PointSize = clamp(gl_PointSize, minAttenuatedSize, maxAttenuatedSize);\n }\n }\n\n#if defined(USE_TEXTURES_PROJECTIVE)\n #include <itowns/projective_texturing_vertex>\n#endif\n #include <logdepthbuf_vertex>\n}\n";
16
17
  /* babel-plugin-inline-import './Shader/PointsFS.glsl' */
17
18
  const PointsFS = "#include <itowns/WebGL2_pars_fragment>\n#include <itowns/precision_qualifier>\n#include <logdepthbuf_pars_fragment>\n#if defined(USE_TEXTURES_PROJECTIVE)\n#include <itowns/projective_texturing_pars_fragment>\n#endif\n\nvarying vec4 vColor;\nuniform bool picking;\nuniform int shape;\n\nvoid main() {\n #include <logdepthbuf_fragment>\n //square shape does not require any change.\n if (shape == PNTS_SHAPE_CIRCLE) {\n //circular rendering in glsl\n if ((length(gl_PointCoord - 0.5) > 0.5) || (vColor.a == 0.0)) {\n discard;\n }\n }\n\n#if defined(USE_TEXTURES_PROJECTIVE)\n vec4 color = vColor;\n if (!picking) {\n #pragma unroll_loop\n for (int i = 0; i < ORIENTED_IMAGES_COUNT; i++) {\n color = projectiveTextureColor(projectiveTextureCoords[ ORIENTED_IMAGES_COUNT - 1 - i ], projectiveTextureDistortion[ ORIENTED_IMAGES_COUNT - 1 - i ], projectiveTexture[ ORIENTED_IMAGES_COUNT - 1 - i ], mask[ORIENTED_IMAGES_COUNT - 1 - i], color);\n }\n gl_FragColor = vec4(color.rgb, color.a * opacity);\n } else {\n gl_FragColor = color;\n }\n#else\n gl_FragColor = vColor;\n#endif\n}\n";
18
19
  const PNTS_MODE = {
19
20
  COLOR: 0,
20
21
  INTENSITY: 1,
21
22
  CLASSIFICATION: 2,
22
- NORMAL: 3
23
+ ELEVATION: 3,
24
+ RETURN_NUMBER: 4,
25
+ RETURN_TYPE: 5,
26
+ RETURN_COUNT: 6,
27
+ POINT_SOURCE_ID: 7,
28
+ SCAN_ANGLE: 8,
29
+ NORMAL: 9
23
30
  };
24
31
  exports.PNTS_MODE = PNTS_MODE;
25
32
  const PNTS_SHAPE = {
@@ -138,6 +145,128 @@ const ClassificationScheme = {
138
145
  }
139
146
  };
140
147
  exports.ClassificationScheme = ClassificationScheme;
148
+ const DiscreteScheme = {
149
+ DEFAULT: {
150
+ 0: {
151
+ visible: true,
152
+ name: '0',
153
+ color: new THREE.Color('rgb(67, 99, 216)'),
154
+ opacity: 1.0
155
+ },
156
+ 1: {
157
+ visible: true,
158
+ name: '1',
159
+ color: new THREE.Color('rgb(60, 180, 75);'),
160
+ opacity: 1.0
161
+ },
162
+ 2: {
163
+ visible: true,
164
+ name: '2',
165
+ color: new THREE.Color('rgb(255, 255, 25)'),
166
+ opacity: 1.0
167
+ },
168
+ 3: {
169
+ visible: true,
170
+ name: '3',
171
+ color: new THREE.Color('rgb(145, 30, 180)'),
172
+ opacity: 1.0
173
+ },
174
+ 4: {
175
+ visible: true,
176
+ name: '4',
177
+ color: new THREE.Color('rgb(245, 130, 49)'),
178
+ opacity: 1.0
179
+ },
180
+ 5: {
181
+ visible: true,
182
+ name: '5',
183
+ color: new THREE.Color('rgb(230, 25, 75)'),
184
+ opacity: 1.0
185
+ },
186
+ 6: {
187
+ visible: true,
188
+ name: '6',
189
+ color: new THREE.Color('rgb(66, 212, 244)'),
190
+ opacity: 1.0
191
+ },
192
+ 7: {
193
+ visible: true,
194
+ name: '7',
195
+ color: new THREE.Color('rgb(240, 50, 230)'),
196
+ opacity: 1.0
197
+ },
198
+ DEFAULT: {
199
+ visible: true,
200
+ name: 'default',
201
+ color: white,
202
+ opacity: 0.5
203
+ }
204
+ }
205
+ };
206
+
207
+ // Taken from Potree. Copyright (c) 2011-2020, Markus Schütz All rights reserved.
208
+ // https://github.com/potree/potree/blob/develop/src/materials/PointCloudMaterial.js
209
+ function generateGradientTexture(gradient) {
210
+ const size = 64;
211
+
212
+ // create canvas
213
+ const canvas = document.createElement('canvas');
214
+ canvas.width = size;
215
+ canvas.height = size;
216
+
217
+ // get context
218
+ const context = canvas.getContext('2d');
219
+
220
+ // draw gradient
221
+ context.rect(0, 0, size, size);
222
+ const ctxGradient = context.createLinearGradient(0, 0, size, size);
223
+ for (let i = 0; i < gradient.length; i++) {
224
+ const step = gradient[i];
225
+ ctxGradient.addColorStop(step[0], `#${step[1].getHexString()}`);
226
+ }
227
+ context.fillStyle = ctxGradient;
228
+ context.fill();
229
+ const texture = new THREE.CanvasTexture(canvas);
230
+ texture.needsUpdate = true;
231
+ texture.minFilter = THREE.LinearFilter;
232
+ texture.wrap = THREE.RepeatWrapping;
233
+ texture.repeat = 2;
234
+ return texture;
235
+ }
236
+ function recomputeTexture(scheme, texture, nbClass) {
237
+ const data = texture.image.data;
238
+ const width = texture.image.width;
239
+ if (!nbClass) {
240
+ nbClass = Object.keys(scheme).length;
241
+ }
242
+ for (let i = 0; i < width; i++) {
243
+ let color;
244
+ let opacity;
245
+ let visible = true;
246
+ if (scheme[i]) {
247
+ color = scheme[i].color;
248
+ visible = scheme[i].visible;
249
+ opacity = scheme[i].opacity;
250
+ } else if (scheme[i % nbClass]) {
251
+ color = scheme[i % nbClass].color;
252
+ visible = scheme[i % nbClass].visible;
253
+ opacity = scheme[i % nbClass].opacity;
254
+ } else if (scheme.DEFAULT) {
255
+ color = scheme.DEFAULT.color;
256
+ visible = scheme.DEFAULT.visible;
257
+ opacity = scheme.DEFAULT.opacity;
258
+ } else {
259
+ color = white;
260
+ opacity = 1.0;
261
+ }
262
+ const j = 4 * i;
263
+ data[j + 0] = parseInt(255 * color.r, 10);
264
+ data[j + 1] = parseInt(255 * color.g, 10);
265
+ data[j + 2] = parseInt(255 * color.b, 10);
266
+ data[j + 3] = visible ? parseInt(255 * opacity, 10) : 0;
267
+ }
268
+ texture.needsUpdate = true;
269
+ }
141
270
  class PointsMaterial extends THREE.RawShaderMaterial {
142
271
  /**
143
272
  * @class PointsMaterial
@@ -146,13 +275,23 @@ class PointsMaterial extends THREE.RawShaderMaterial {
146
275
  * @param {number} [options.mode=PNTS_MODE.COLOR] display mode.
147
276
  * @param {number} [options.mode=PNTS_SHAPE.CIRCLE] rendered points shape.
148
277
  * @param {THREE.Vector4} [options.overlayColor=new THREE.Vector4(0, 0, 0, 0)] overlay color.
149
- * @param {THREE.Vector2} [options.intensityRange=new THREE.Vector2(0, 1)] intensity range.
278
+ * @param {THREE.Vector2} [options.intensityRange=new THREE.Vector2(1, 65536)] intensity range.
279
+ * @param {THREE.Vector2} [options.elevationRange=new THREE.Vector2(0, 1000)] elevation range.
280
+ * @param {THREE.Vector2} [options.angleRange=new THREE.Vector2(-90, 90)] scan angle range.
150
281
  * @param {boolean} [options.applyOpacityClassication=false] apply opacity classification on all display mode.
151
- * @param {Classification} [options.classification] - define points classification.
282
+ * @param {Scheme} [options.classification] LUT for point classification colorization.
283
+ * @param {Scheme} [options.discreteScheme] LUT for other discret point values colorization.
284
+ * @param {string} [options.gradient] Descrition of the gradient to use for continuous point values.
285
+ * (Default value will be the 'SPECTRAL' gradient from Utils/Gradients)
152
286
  * @param {number} [options.sizeMode=PNTS_SIZE_MODE.VALUE] point cloud size mode. Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance from point to camera.
153
287
  * @param {number} [options.minAttenuatedSize=3] minimum scale used by 'ATTENUATED' size mode
154
288
  * @param {number} [options.maxAttenuatedSize=10] maximum scale used by 'ATTENUATED' size mode
155
- * @property {Classification} classification - points classification.
289
+ *
290
+ * @property {Scheme} classificationScheme - Color scheme for point classification values.
291
+ * @property {Scheme} discreteScheme - Color scheme for all other discrete values.
292
+ * @property {object} gradients - Descriptions of all available gradients.
293
+ * @property {object} gradient - Description of the gradient to use for display.
294
+ * @property {THREE.CanvasTexture} gradientTexture - The texture generate from the choosen gradient.
156
295
  *
157
296
  * @example
158
297
  * // change color category classification
@@ -162,9 +301,12 @@ class PointsMaterial extends THREE.RawShaderMaterial {
162
301
  */
163
302
  constructor() {
164
303
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
165
- const intensityRange = options.intensityRange || new THREE.Vector2(0, 1);
304
+ const intensityRange = options.intensityRange || new THREE.Vector2(1, 65536);
305
+ const elevationRange = options.elevationRange || new THREE.Vector2(0, 1000);
306
+ const angleRange = options.angleRange || new THREE.Vector2(-90, 90);
166
307
  const oiMaterial = options.orientedImageMaterial;
167
- const classification = options.classification || ClassificationScheme.DEFAULT;
308
+ const classificationScheme = options.classification || ClassificationScheme.DEFAULT;
309
+ const discreteScheme = options.discreteScheme || DiscreteScheme.DEFAULT;
168
310
  const applyOpacityClassication = options.applyOpacityClassication == undefined ? false : options.applyOpacityClassication;
169
311
  const size = options.size || 0;
170
312
  const mode = options.mode || PNTS_MODE.COLOR;
@@ -172,9 +314,19 @@ class PointsMaterial extends THREE.RawShaderMaterial {
172
314
  const sizeMode = size === 0 ? PNTS_SIZE_MODE.ATTENUATED : options.sizeMode || PNTS_SIZE_MODE.VALUE;
173
315
  const minAttenuatedSize = options.minAttenuatedSize || 3;
174
316
  const maxAttenuatedSize = options.maxAttenuatedSize || 10;
175
- delete options.orientedImageMaterial;
317
+ let gradients = _Gradients.default;
318
+ if (options.gradient) {
319
+ gradients = {
320
+ ...options.gradient,
321
+ ..._Gradients.default
322
+ };
323
+ }
176
324
  delete options.intensityRange;
177
- delete options.classification;
325
+ delete options.elevationRange;
326
+ delete options.angleRange;
327
+ delete options.orientedImageMaterial;
328
+ delete options.classificationScheme;
329
+ delete options.discreteScheme;
178
330
  delete options.applyOpacityClassication;
179
331
  delete options.size;
180
332
  delete options.mode;
@@ -182,7 +334,10 @@ class PointsMaterial extends THREE.RawShaderMaterial {
182
334
  delete options.sizeMode;
183
335
  delete options.minAttenuatedSize;
184
336
  delete options.maxAttenuatedSize;
337
+ delete options.gradient;
185
338
  super(options);
339
+ this.gradients = gradients;
340
+ this.gradientTexture = new THREE.CanvasTexture();
186
341
  this.vertexShader = PointsVS;
187
342
  const scale = options.scale || 0.05 * 0.5 / Math.tan(1.0 / 2.0); // autosizing scale
188
343
 
@@ -196,6 +351,8 @@ class PointsMaterial extends THREE.RawShaderMaterial {
196
351
  _CommonMaterial.default.setUniformProperty(this, 'opacity', this.opacity);
197
352
  _CommonMaterial.default.setUniformProperty(this, 'overlayColor', options.overlayColor || new THREE.Vector4(0, 0, 0, 0));
198
353
  _CommonMaterial.default.setUniformProperty(this, 'intensityRange', intensityRange);
354
+ _CommonMaterial.default.setUniformProperty(this, 'elevationRange', elevationRange);
355
+ _CommonMaterial.default.setUniformProperty(this, 'angleRange', angleRange);
199
356
  _CommonMaterial.default.setUniformProperty(this, 'applyOpacityClassication', applyOpacityClassication);
200
357
  _CommonMaterial.default.setUniformProperty(this, 'sizeMode', sizeMode);
201
358
  _CommonMaterial.default.setUniformProperty(this, 'scale', scale);
@@ -207,13 +364,26 @@ class PointsMaterial extends THREE.RawShaderMaterial {
207
364
  const texture = new THREE.DataTexture(data, 256, 1, THREE.RGBAFormat);
208
365
  texture.needsUpdate = true;
209
366
  texture.magFilter = THREE.NearestFilter;
210
- _CommonMaterial.default.setUniformProperty(this, 'classificationLUT', texture);
367
+ _CommonMaterial.default.setUniformProperty(this, 'classificationTexture', texture);
368
+
369
+ // add texture to applying the discrete lut.
370
+ const dataLUT = new Uint8Array(256 * 4);
371
+ const textureLUT = new THREE.DataTexture(dataLUT, 256, 1, THREE.RGBAFormat);
372
+ textureLUT.needsUpdate = true;
373
+ textureLUT.magFilter = THREE.NearestFilter;
374
+ _CommonMaterial.default.setUniformProperty(this, 'discreteTexture', textureLUT);
211
375
 
212
- // Classification scheme
213
- this.classification = classification;
376
+ // Classification and other discrete values scheme
377
+ this.classificationScheme = classificationScheme;
378
+ this.discreteScheme = discreteScheme;
214
379
 
215
- // Update classification
380
+ // Update classification and discrete Texture
216
381
  this.recomputeClassification();
382
+ this.recomputeDiscreteTexture();
383
+
384
+ // Gradient texture for continuous values
385
+ this.gradient = Object.values(gradients)[0];
386
+ _CommonMaterial.default.setUniformProperty(this, 'gradientTexture', this.gradientTexture);
217
387
  if (oiMaterial) {
218
388
  this.uniforms.projectiveTextureAlphaBorder = oiMaterial.uniforms.projectiveTextureAlphaBorder;
219
389
  this.uniforms.projectiveTextureDistortion = oiMaterial.uniforms.projectiveTextureDistortion;
@@ -236,39 +406,17 @@ class PointsMaterial extends THREE.RawShaderMaterial {
236
406
  }
237
407
  }
238
408
  recomputeClassification() {
239
- const classification = this.classification;
240
- const data = this.classificationLUT.image.data;
241
- const width = this.classificationLUT.image.width;
242
- for (let i = 0; i < width; i++) {
243
- let color;
244
- let opacity;
245
- let visible = true;
246
- if (classification[i]) {
247
- color = classification[i].color;
248
- visible = classification[i].visible;
249
- opacity = classification[i].opacity;
250
- } else if (classification[i % 32]) {
251
- color = classification[i % 32].color;
252
- visible = classification[i % 32].visible;
253
- opacity = classification[i % 32].opacity;
254
- } else if (classification.DEFAULT) {
255
- color = classification.DEFAULT.color;
256
- visible = classification.DEFAULT.visible;
257
- opacity = classification.DEFAULT.opacity;
258
- } else {
259
- color = white;
260
- opacity = 1.0;
261
- }
262
- const j = 4 * i;
263
- data[j + 0] = parseInt(255 * color.r, 10);
264
- data[j + 1] = parseInt(255 * color.g, 10);
265
- data[j + 2] = parseInt(255 * color.b, 10);
266
- data[j + 3] = visible ? parseInt(255 * opacity, 10) : 0;
267
- }
268
- this.classificationLUT.needsUpdate = true;
409
+ recomputeTexture(this.classificationScheme, this.classificationTexture, 32);
269
410
  this.dispatchEvent({
270
411
  type: 'material_property_changed',
271
- target: this
412
+ target: this.uniforms
413
+ });
414
+ }
415
+ recomputeDiscreteTexture() {
416
+ recomputeTexture(this.discreteScheme, this.discreteTexture);
417
+ this.dispatchEvent({
418
+ type: 'material_property_changed',
419
+ target: this.uniforms
272
420
  });
273
421
  }
274
422
  onBeforeCompile(shader, renderer) {
@@ -309,9 +457,14 @@ class PointsMaterial extends THREE.RawShaderMaterial {
309
457
  this.scale = source.scale;
310
458
  this.overlayColor.copy(source.overlayColor);
311
459
  this.intensityRange.copy(source.intensityRange);
460
+ this.elevationRange.copy(source.elevationRange);
461
+ this.angleRange.copy(source.angleRange);
312
462
  Object.assign(this.defines, source.defines);
313
463
  return this;
314
464
  }
465
+ set gradient(value) {
466
+ this.gradientTexture = generateGradientTexture(value);
467
+ }
315
468
  }
316
469
  var _default = PointsMaterial;
317
470
  exports.default = _default;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var THREE = _interopRequireWildcard(require("three"));
8
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
9
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
10
+ var _default = {
11
+ // From chroma spectral http://gka.github.io/chroma.js/
12
+ SPECTRAL: [[0, new THREE.Color(0.3686, 0.3098, 0.6353)], [0.1, new THREE.Color(0.1961, 0.5333, 0.7412)], [0.2, new THREE.Color(0.4000, 0.7608, 0.6471)], [0.3, new THREE.Color(0.6706, 0.8667, 0.6431)], [0.4, new THREE.Color(0.9020, 0.9608, 0.5961)], [0.5, new THREE.Color(1.0000, 1.0000, 0.7490)], [0.6, new THREE.Color(0.9961, 0.8784, 0.5451)], [0.7, new THREE.Color(0.9922, 0.6824, 0.3804)], [0.8, new THREE.Color(0.9569, 0.4275, 0.2627)], [0.9, new THREE.Color(0.8353, 0.2431, 0.3098)], [1, new THREE.Color(0.6196, 0.0039, 0.2588)]],
13
+ PLASMA: [[0.0, new THREE.Color(0.241, 0.015, 0.610)], [0.1, new THREE.Color(0.387, 0.001, 0.654)], [0.2, new THREE.Color(0.524, 0.025, 0.653)], [0.3, new THREE.Color(0.651, 0.125, 0.596)], [0.4, new THREE.Color(0.752, 0.227, 0.513)], [0.5, new THREE.Color(0.837, 0.329, 0.431)], [0.6, new THREE.Color(0.907, 0.435, 0.353)], [0.7, new THREE.Color(0.963, 0.554, 0.272)], [0.8, new THREE.Color(0.992, 0.681, 0.195)], [0.9, new THREE.Color(0.987, 0.822, 0.144)], [1.0, new THREE.Color(0.940, 0.975, 0.131)]],
14
+ YELLOW_GREEN: [[0, new THREE.Color(0.1647, 0.2824, 0.3451)], [0.1, new THREE.Color(0.1338, 0.3555, 0.4227)], [0.2, new THREE.Color(0.0610, 0.4319, 0.4864)], [0.3, new THREE.Color(0.0000, 0.5099, 0.5319)], [0.4, new THREE.Color(0.0000, 0.5881, 0.5569)], [0.5, new THREE.Color(0.1370, 0.6650, 0.5614)], [0.6, new THREE.Color(0.2906, 0.7395, 0.5477)], [0.7, new THREE.Color(0.4453, 0.8099, 0.5201)], [0.8, new THREE.Color(0.6102, 0.8748, 0.4850)], [0.9, new THREE.Color(0.7883, 0.9323, 0.4514)], [1, new THREE.Color(0.9804, 0.9804, 0.4314)]],
15
+ VIRIDIS: [[0.0, new THREE.Color(0.267, 0.005, 0.329)], [0.1, new THREE.Color(0.283, 0.141, 0.458)], [0.2, new THREE.Color(0.254, 0.265, 0.530)], [0.3, new THREE.Color(0.207, 0.372, 0.553)], [0.4, new THREE.Color(0.164, 0.471, 0.558)], [0.5, new THREE.Color(0.128, 0.567, 0.551)], [0.6, new THREE.Color(0.135, 0.659, 0.518)], [0.7, new THREE.Color(0.267, 0.749, 0.441)], [0.8, new THREE.Color(0.478, 0.821, 0.318)], [0.9, new THREE.Color(0.741, 0.873, 0.150)], [1.0, new THREE.Color(0.993, 0.906, 0.144)]],
16
+ INFERNO: [[0.0, new THREE.Color(0.077, 0.042, 0.206)], [0.1, new THREE.Color(0.225, 0.036, 0.388)], [0.2, new THREE.Color(0.373, 0.074, 0.432)], [0.3, new THREE.Color(0.522, 0.128, 0.420)], [0.4, new THREE.Color(0.665, 0.182, 0.370)], [0.5, new THREE.Color(0.797, 0.255, 0.287)], [0.6, new THREE.Color(0.902, 0.364, 0.184)], [0.7, new THREE.Color(0.969, 0.516, 0.063)], [0.8, new THREE.Color(0.988, 0.683, 0.072)], [0.9, new THREE.Color(0.961, 0.859, 0.298)], [1.0, new THREE.Color(0.988, 0.998, 0.645)]],
17
+ GRAYSCALE: [[0, new THREE.Color(0, 0, 0)], [1, new THREE.Color(1, 1, 1)]],
18
+ // 16 samples of the TURBU color scheme
19
+ // values taken from: https://gist.github.com/mikhailov-work/ee72ba4191942acecc03fe6da94fc73f
20
+ // original file licensed under Apache-2.0
21
+ TURBO: [[0.00, new THREE.Color(0.18995, 0.07176, 0.23217)], [0.07, new THREE.Color(0.25107, 0.25237, 0.63374)], [0.13, new THREE.Color(0.27628, 0.42118, 0.89123)], [0.20, new THREE.Color(0.25862, 0.57958, 0.99876)], [0.27, new THREE.Color(0.15844, 0.73551, 0.92305)], [0.33, new THREE.Color(0.09267, 0.86554, 0.7623)], [0.40, new THREE.Color(0.19659, 0.94901, 0.59466)], [0.47, new THREE.Color(0.42778, 0.99419, 0.38575)], [0.53, new THREE.Color(0.64362, 0.98999, 0.23356)], [0.60, new THREE.Color(0.80473, 0.92452, 0.20459)], [0.67, new THREE.Color(0.93301, 0.81236, 0.22667)], [0.73, new THREE.Color(0.99314, 0.67408, 0.20348)], [0.80, new THREE.Color(0.9836, 0.49291, 0.12849)], [0.87, new THREE.Color(0.92105, 0.31489, 0.05475)], [0.93, new THREE.Color(0.81608, 0.18462, 0.01809)], [1.00, new THREE.Color(0.66449, 0.08436, 0.00424)]],
22
+ RAINBOW: [[0, new THREE.Color(0.278, 0, 0.714)], [1 / 6, new THREE.Color(0, 0, 1)], [2 / 6, new THREE.Color(0, 1, 1)], [3 / 6, new THREE.Color(0, 1, 0)], [4 / 6, new THREE.Color(1, 1, 0)], [5 / 6, new THREE.Color(1, 0.64, 0)], [1, new THREE.Color(1, 0, 0)]],
23
+ CONTOUR: [[0.00, new THREE.Color(0, 0, 0)], [0.03, new THREE.Color(0, 0, 0)], [0.04, new THREE.Color(1, 1, 1)], [1.00, new THREE.Color(1, 1, 1)]]
24
+ };
25
+ exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itowns",
3
- "version": "2.42.1-next.5",
3
+ "version": "2.42.1-next.7",
4
4
  "description": "A JS/WebGL framework for 3D geospatial data visualization",
5
5
  "main": "lib/Main.js",
6
6
  "exports": {