@inweb/viewer-three 26.6.1 → 26.6.2

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.
@@ -2,10 +2,16 @@ import { draggersRegistry, commandsRegistry, componentsRegistry, Loader, loaders
2
2
 
3
3
  export * from "@inweb/viewer-core";
4
4
 
5
- import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Matrix4, Vector4, Raycaster, Controls, Clock, Box3, Sphere, MathUtils, Color, AmbientLight, DirectionalLight, HemisphereLight, OrthographicCamera, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, LoadingManager, LoaderUtils, Scene, PerspectiveCamera, WebGLRenderer, LinearToneMapping } from "three";
5
+ import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Matrix4, Vector4, Raycaster, Controls, Clock, Box3, Sphere, MathUtils, Color, AmbientLight, DirectionalLight, HemisphereLight, EdgesGeometry, OrthographicCamera, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, LoadingManager, LoaderUtils, Scene, PerspectiveCamera, WebGLRenderer, LinearToneMapping } from "three";
6
6
 
7
7
  import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
8
8
 
9
+ import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
10
+
11
+ import { Wireframe } from "three/examples/jsm/lines/Wireframe.js";
12
+
13
+ import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
14
+
9
15
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
10
16
 
11
17
  import { EventEmitter2 } from "@inweb/eventemitter2";
@@ -1660,31 +1666,22 @@ class SelectionComponent {
1660
1666
  if (event.button !== 0) return;
1661
1667
  this.viewer.executeCommand("zoomToSelected");
1662
1668
  };
1663
- this.optionsChange = () => {
1664
- const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
1665
- this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
1666
- this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
1667
- this.viewer.update();
1669
+ this.initHighlighter = () => {
1670
+ this.highlighter = this.viewer.getComponent("HighlighterComponent");
1668
1671
  };
1669
1672
  this.viewer = viewer;
1670
1673
  this.raycaster = new Raycaster;
1671
1674
  this.downPosition = new Vector2;
1672
- const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
1673
- this.facesMaterial = new MeshBasicMaterial;
1674
- this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
1675
- this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
1676
- this.facesMaterial.transparent = true;
1677
1675
  this.viewer.addEventListener("pointerdown", this.onPointerDown);
1678
1676
  this.viewer.addEventListener("pointerup", this.onPointerUp);
1679
1677
  this.viewer.addEventListener("dblclick", this.onDoubleClick);
1680
- this.viewer.addEventListener("optionschange", this.optionsChange);
1678
+ this.viewer.addEventListener("initialize", this.initHighlighter);
1681
1679
  }
1682
1680
  dispose() {
1683
- this.facesMaterial.dispose();
1684
1681
  this.viewer.removeEventListener("pointerdown", this.onPointerDown);
1685
1682
  this.viewer.removeEventListener("pointerup", this.onPointerUp);
1686
1683
  this.viewer.removeEventListener("dblclick", this.onDoubleClick);
1687
- this.viewer.removeEventListener("optionschange", this.optionsChange);
1684
+ this.viewer.removeEventListener("initialize", this.initHighlighter);
1688
1685
  }
1689
1686
  getMousePosition(event, target) {
1690
1687
  return target.set(event.clientX, event.clientY);
@@ -1716,14 +1713,13 @@ class SelectionComponent {
1716
1713
  select(object) {
1717
1714
  if (object.isSelected) return;
1718
1715
  object.isSelected = true;
1719
- object.originalMaterial = object.material;
1720
- object.material = this.facesMaterial;
1716
+ this.highlighter.highlight(object);
1721
1717
  this.viewer.selected.push(object);
1722
1718
  }
1723
1719
  clearSelection() {
1724
1720
  this.viewer.selected.forEach((object => {
1725
1721
  object.isSelected = false;
1726
- object.material = object.originalMaterial;
1722
+ this.highlighter.unhighlight(object);
1727
1723
  }));
1728
1724
  this.viewer.selected.length = 0;
1729
1725
  }
@@ -2119,6 +2115,149 @@ class ResizeCanvasComponent {
2119
2115
  }
2120
2116
  }
2121
2117
 
2118
+ class HighlighterUtils {
2119
+ static isBreak(positions, i) {
2120
+ return isNaN(positions[i]) || isNaN(positions[i + 1]) || isNaN(positions[i + 2]) || positions[i] === Infinity || positions[i] === -Infinity || positions[i + 1] === Infinity || positions[i + 1] === -Infinity || positions[i + 2] === Infinity || positions[i + 2] === -Infinity;
2121
+ }
2122
+ static fromIndexedLine(positions, indices) {
2123
+ const lineGeometry = new LineSegmentsGeometry;
2124
+ const segments = [];
2125
+ for (let i = 0; i < indices.length; i += 2) {
2126
+ const idx1 = indices[i] * 3;
2127
+ const idx2 = indices[i + 1] * 3;
2128
+ if (indices[i] === -1 || indices[i + 1] === -1) {
2129
+ continue;
2130
+ }
2131
+ segments.push(positions[idx1], positions[idx1 + 1], positions[idx1 + 2], positions[idx2], positions[idx2 + 1], positions[idx2 + 2]);
2132
+ }
2133
+ if (segments.length === 0) return null;
2134
+ lineGeometry.setPositions(segments);
2135
+ return lineGeometry;
2136
+ }
2137
+ static fromNonIndexedLine(positions, isLineSegments) {
2138
+ const lineGeometry = new LineSegmentsGeometry;
2139
+ const segments = [];
2140
+ if (isLineSegments) {
2141
+ for (let i = 0; i < positions.length; i += 6) {
2142
+ if (i + 5 >= positions.length) break;
2143
+ if (HighlighterUtils.isBreak(positions, i) || HighlighterUtils.isBreak(positions, i + 3)) continue;
2144
+ segments.push(positions[i], positions[i + 1], positions[i + 2], positions[i + 3], positions[i + 4], positions[i + 5]);
2145
+ }
2146
+ } else {
2147
+ let lastValidIndex = -1;
2148
+ for (let i = 0; i < positions.length; i += 3) {
2149
+ if (HighlighterUtils.isBreak(positions, i)) {
2150
+ lastValidIndex = -1;
2151
+ continue;
2152
+ }
2153
+ if (lastValidIndex !== -1) {
2154
+ segments.push(positions[lastValidIndex], positions[lastValidIndex + 1], positions[lastValidIndex + 2], positions[i], positions[i + 1], positions[i + 2]);
2155
+ }
2156
+ lastValidIndex = i;
2157
+ }
2158
+ }
2159
+ if (segments.length === 0) return null;
2160
+ lineGeometry.setPositions(segments);
2161
+ return lineGeometry;
2162
+ }
2163
+ }
2164
+
2165
+ class HighlighterComponent {
2166
+ constructor(viewer) {
2167
+ this.geometryEnd = () => {
2168
+ const {facesColor: facesColor, facesTransparancy: facesTransparancy, edgesColor: edgesColor} = this.viewer.options;
2169
+ this.highlightMaterial = new MeshBasicMaterial({
2170
+ color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
2171
+ transparent: true,
2172
+ opacity: (255 - facesTransparancy) / 255,
2173
+ depthTest: false,
2174
+ depthWrite: false
2175
+ });
2176
+ this.outlineMaterial = new LineMaterial({
2177
+ color: new Color(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255),
2178
+ linewidth: 1.5,
2179
+ depthTest: false,
2180
+ depthWrite: false,
2181
+ resolution: new Vector2(window.innerWidth, window.innerHeight)
2182
+ });
2183
+ this.highlightLineMaterial = new LineBasicMaterial({
2184
+ color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
2185
+ depthTest: false,
2186
+ depthWrite: false
2187
+ });
2188
+ this.highlightLineGlowMaterial = new LineMaterial({
2189
+ color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
2190
+ linewidth: 5,
2191
+ transparent: true,
2192
+ opacity: .8,
2193
+ depthTest: true,
2194
+ depthWrite: true,
2195
+ resolution: new Vector2(window.innerWidth, window.innerHeight)
2196
+ });
2197
+ };
2198
+ this.optionsChange = () => {
2199
+ const {facesColor: facesColor, facesTransparancy: facesTransparancy, edgesColor: edgesColor} = this.viewer.options;
2200
+ this.highlightMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
2201
+ this.highlightMaterial.opacity = (255 - facesTransparancy) / 255;
2202
+ this.outlineMaterial.color.setRGB(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255);
2203
+ this.highlightLineMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
2204
+ this.highlightLineGlowMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
2205
+ this.viewer.update();
2206
+ };
2207
+ this.viewer = viewer;
2208
+ this.viewer.addEventListener("databasechunk", this.geometryEnd);
2209
+ this.viewer.addEventListener("optionschange", this.optionsChange);
2210
+ this.viewer.addEventListener("resize", this.viewerResize);
2211
+ this.geometryEnd();
2212
+ }
2213
+ dispose() {
2214
+ this.viewer.removeEventListener("databasechunk", this.geometryEnd);
2215
+ this.viewer.removeEventListener("optionschange", this.optionsChange);
2216
+ this.viewer.removeEventListener("resize", this.viewerResize);
2217
+ }
2218
+ highlight(object) {
2219
+ if (object.isHighlighted) return;
2220
+ if (object.isLine || object.isLineSegments) {
2221
+ const positions = object.geometry.attributes.position.array;
2222
+ const indices = object.geometry.index ? object.geometry.index.array : null;
2223
+ const lineGeometry = indices ? HighlighterUtils.fromIndexedLine(positions, indices) : HighlighterUtils.fromNonIndexedLine(positions, object.isLineSegments);
2224
+ const wireframe = new Wireframe(lineGeometry, this.highlightLineGlowMaterial);
2225
+ wireframe.position.copy(object.position);
2226
+ wireframe.rotation.copy(object.rotation);
2227
+ wireframe.scale.copy(object.scale);
2228
+ object.parent.add(wireframe);
2229
+ object.userData.highlightwireframe = wireframe;
2230
+ object.userData.originalMaterial = object.material;
2231
+ object.material = this.highlightLineMaterial;
2232
+ object.isHighlighted = true;
2233
+ } else if (object.isMesh) {
2234
+ const edgesGeometry = new EdgesGeometry(object.geometry, 30);
2235
+ const lineGeometry = (new LineSegmentsGeometry).fromEdgesGeometry(edgesGeometry);
2236
+ const wireframe = new Wireframe(lineGeometry, this.outlineMaterial);
2237
+ wireframe.position.copy(object.position);
2238
+ wireframe.rotation.copy(object.rotation);
2239
+ wireframe.scale.copy(object.scale);
2240
+ object.parent.add(wireframe);
2241
+ object.userData.highlightwireframe = wireframe;
2242
+ object.userData.originalMaterial = object.material;
2243
+ object.material = this.highlightMaterial;
2244
+ object.isHighlighted = true;
2245
+ }
2246
+ }
2247
+ unhighlight(object) {
2248
+ if (!object.isHighlighted) return;
2249
+ object.isHighlighted = false;
2250
+ object.material = object.userData.originalMaterial;
2251
+ object.userData.highlightwireframe.removeFromParent();
2252
+ delete object.userData.originalMaterial;
2253
+ delete object.userData.highlightwireframe;
2254
+ }
2255
+ viewerResize(event) {
2256
+ if (!this.outlineMaterial) return;
2257
+ this.outlineMaterial.resolution.set(event.width, event.height);
2258
+ }
2259
+ }
2260
+
2122
2261
  class WCSHelper extends Object3D {
2123
2262
  constructor(camera) {
2124
2263
  super();
@@ -2238,6 +2377,8 @@ components.registerComponent("ResizeCanvasComponent", (viewer => new ResizeCanva
2238
2377
 
2239
2378
  components.registerComponent("RenderLoopComponent", (viewer => new RenderLoopComponent(viewer)));
2240
2379
 
2380
+ components.registerComponent("HighlighterComponent", (viewer => new HighlighterComponent(viewer)));
2381
+
2241
2382
  components.registerComponent("SelectionComponent", (viewer => new SelectionComponent(viewer)));
2242
2383
 
2243
2384
  components.registerComponent("WCSHelperComponent", (viewer => new WCSHelperComponent(viewer)));
@@ -2670,6 +2811,9 @@ class Viewer extends EventEmitter2 {
2670
2811
  this.setActiveDragger(dragger.name);
2671
2812
  }
2672
2813
  }
2814
+ getComponent(name) {
2815
+ return this._components.find((component => component.name === name));
2816
+ }
2673
2817
  is3D() {
2674
2818
  return true;
2675
2819
  }
@@ -2715,9 +2859,6 @@ class Viewer extends EventEmitter2 {
2715
2859
  executeCommand(id, ...args) {
2716
2860
  return commands.executeCommand(id, this, ...args);
2717
2861
  }
2718
- getComponent(name) {
2719
- return this._components.find((component => component.name === name));
2720
- }
2721
2862
  drawViewpoint(viewpoint) {
2722
2863
  var _a, _b, _c;
2723
2864
  if (!this.renderer) return;