@inweb/viewer-three 26.6.0 → 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.
- package/dist/plugins/components/LightHelperComponent.js +9 -3
- package/dist/plugins/components/LightHelperComponent.js.map +1 -1
- package/dist/plugins/components/LightHelperComponent.min.js +1 -1
- package/dist/plugins/components/LightHelperComponent.module.js +5 -4
- package/dist/plugins/components/LightHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js +178 -0
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +1 -0
- package/dist/plugins/components/RoomEnvironmentComponent.min.js +1 -0
- package/dist/plugins/components/RoomEnvironmentComponent.module.js +21 -0
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +1 -0
- package/dist/plugins/loaders/IFCXLoader.js +21 -27
- package/dist/plugins/loaders/IFCXLoader.js.map +1 -1
- package/dist/plugins/loaders/IFCXLoader.min.js +1 -1
- package/dist/plugins/loaders/IFCXLoader.module.js +7 -18
- package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -1
- package/dist/viewer-three.js +1162 -231
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +2 -2
- package/dist/viewer-three.module.js +180 -39
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/Viewer.d.ts +1 -1
- package/lib/Viewer/components/HighlighterComponent.d.ts +18 -0
- package/lib/Viewer/components/HighlighterUtils.d.ts +6 -0
- package/lib/Viewer/components/LightComponent.d.ts +3 -1
- package/lib/Viewer/components/SelectionComponent.d.ts +5 -4
- package/package.json +5 -5
- package/plugins/components/LightHelperComponent.ts +10 -5
- package/{src/Viewer → plugins}/components/RoomEnvironmentComponent.ts +4 -4
- package/plugins/loaders/IFCX/render.js +26 -21
- package/src/Viewer/Viewer.ts +4 -4
- package/src/Viewer/components/HighlighterComponent.ts +159 -0
- package/src/Viewer/components/HighlighterUtils.ts +116 -0
- package/src/Viewer/components/LightComponent.ts +33 -4
- package/src/Viewer/components/SelectionComponent.ts +10 -22
- package/src/Viewer/components/index.ts +2 -2
- package/lib/Viewer/components/RoomEnvironmentComponent.d.ts +0 -7
package/lib/Viewer/Viewer.d.ts
CHANGED
|
@@ -151,6 +151,7 @@ export declare class Viewer extends EventEmitter2<ViewerEventMap & CanvasEventMa
|
|
|
151
151
|
activeDragger(): IDragger | null;
|
|
152
152
|
setActiveDragger(name?: string): IDragger | null;
|
|
153
153
|
resetActiveDragger(): void;
|
|
154
|
+
getComponent(name: string): IComponent;
|
|
154
155
|
is3D(): boolean;
|
|
155
156
|
screenToWorld(position: {
|
|
156
157
|
x: number;
|
|
@@ -174,7 +175,6 @@ export declare class Viewer extends EventEmitter2<ViewerEventMap & CanvasEventMa
|
|
|
174
175
|
z: number;
|
|
175
176
|
};
|
|
176
177
|
executeCommand(id: string, ...args: any[]): any;
|
|
177
|
-
getComponent(name: string): IComponent;
|
|
178
178
|
drawViewpoint(viewpoint: IViewpoint): void;
|
|
179
179
|
createViewpoint(): IViewpoint;
|
|
180
180
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { LineBasicMaterial, MeshBasicMaterial } from "three";
|
|
2
|
+
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
|
|
3
|
+
import { IComponent, ResizeEvent } from "@inweb/viewer-core";
|
|
4
|
+
import { Viewer } from "../Viewer";
|
|
5
|
+
export declare class HighlighterComponent implements IComponent {
|
|
6
|
+
protected viewer: Viewer;
|
|
7
|
+
highlightMaterial: MeshBasicMaterial;
|
|
8
|
+
outlineMaterial: LineMaterial;
|
|
9
|
+
highlightLineMaterial: LineBasicMaterial;
|
|
10
|
+
highlightLineGlowMaterial: LineMaterial;
|
|
11
|
+
constructor(viewer: Viewer);
|
|
12
|
+
dispose(): void;
|
|
13
|
+
highlight(object: any): void;
|
|
14
|
+
unhighlight(object: any): void;
|
|
15
|
+
geometryEnd: () => void;
|
|
16
|
+
optionsChange: () => void;
|
|
17
|
+
viewerResize(event: ResizeEvent): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
|
|
2
|
+
export declare class HighlighterUtils {
|
|
3
|
+
static isBreak(positions: Float32Array, i: number): boolean;
|
|
4
|
+
static fromIndexedLine(positions: Float32Array, indices: number[]): LineSegmentsGeometry;
|
|
5
|
+
static fromNonIndexedLine(positions: Float32Array, isLineSegments: boolean): LineSegmentsGeometry;
|
|
6
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { AmbientLight, DirectionalLight } from "three";
|
|
1
|
+
import { AmbientLight, DirectionalLight, HemisphereLight } from "three";
|
|
2
2
|
import { IComponent } from "@inweb/viewer-core";
|
|
3
3
|
import type { Viewer } from "../Viewer";
|
|
4
4
|
export declare class LightComponent implements IComponent {
|
|
5
5
|
protected viewer: Viewer;
|
|
6
6
|
protected ambientLight: AmbientLight;
|
|
7
7
|
protected directionalLight: DirectionalLight;
|
|
8
|
+
protected frontLight: DirectionalLight;
|
|
9
|
+
protected hemisphereLight: HemisphereLight;
|
|
8
10
|
constructor(viewer: Viewer);
|
|
9
11
|
dispose(): void;
|
|
10
12
|
geometryEnd: () => void;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Intersection,
|
|
1
|
+
import { Intersection, Object3D, Raycaster, Vector2 } from "three";
|
|
2
2
|
import { IComponent } from "@inweb/viewer-core";
|
|
3
|
-
import
|
|
3
|
+
import { Viewer } from "../Viewer";
|
|
4
|
+
import { HighlighterComponent } from "./HighlighterComponent";
|
|
4
5
|
export declare class SelectionComponent implements IComponent {
|
|
5
6
|
protected viewer: Viewer;
|
|
6
7
|
protected raycaster: Raycaster;
|
|
7
8
|
protected downPosition: Vector2;
|
|
8
|
-
protected
|
|
9
|
+
protected highlighter: HighlighterComponent;
|
|
9
10
|
constructor(viewer: Viewer);
|
|
10
11
|
dispose(): void;
|
|
11
12
|
onPointerDown: (event: PointerEvent) => void;
|
|
@@ -15,5 +16,5 @@ export declare class SelectionComponent implements IComponent {
|
|
|
15
16
|
getPointerIntersects(mouse: Vector2): Array<Intersection<Object3D>>;
|
|
16
17
|
select(object: any): void;
|
|
17
18
|
clearSelection(): void;
|
|
18
|
-
|
|
19
|
+
initHighlighter: () => void;
|
|
19
20
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inweb/viewer-three",
|
|
3
|
-
"version": "26.6.
|
|
3
|
+
"version": "26.6.2",
|
|
4
4
|
"description": "JavaScript library for rendering CAD and BIM files in a browser using Three.js",
|
|
5
5
|
"homepage": "https://cloud.opendesign.com/docs/index.html",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"docs": "typedoc"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@inweb/client": "~26.6.
|
|
35
|
-
"@inweb/eventemitter2": "~26.6.
|
|
36
|
-
"@inweb/markup": "~26.6.
|
|
37
|
-
"@inweb/viewer-core": "~26.6.
|
|
34
|
+
"@inweb/client": "~26.6.2",
|
|
35
|
+
"@inweb/eventemitter2": "~26.6.2",
|
|
36
|
+
"@inweb/markup": "~26.6.2",
|
|
37
|
+
"@inweb/viewer-core": "~26.6.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/three": "^0.173.0",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import { DirectionalLightHelper, Sphere } from "three";
|
|
24
|
+
import { DirectionalLightHelper, HemisphereLightHelper, PointLightHelper, Sphere } from "three";
|
|
25
25
|
import { IComponent, components, Viewer } from "@inweb/viewer-three";
|
|
26
26
|
|
|
27
27
|
class LightHelperComponent implements IComponent {
|
|
28
28
|
private viewer: Viewer;
|
|
29
|
-
private lightHelpers: DirectionalLightHelper[];
|
|
29
|
+
private lightHelpers: (DirectionalLightHelper | HemisphereLightHelper | PointLightHelper)[];
|
|
30
30
|
|
|
31
31
|
constructor(viewer: Viewer) {
|
|
32
32
|
this.lightHelpers = [];
|
|
@@ -54,11 +54,16 @@ class LightHelperComponent implements IComponent {
|
|
|
54
54
|
this.lightHelpers.length = 0;
|
|
55
55
|
|
|
56
56
|
const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2;
|
|
57
|
-
const size = extentsSize /
|
|
57
|
+
const size = extentsSize / 20;
|
|
58
58
|
|
|
59
59
|
this.viewer.scene.traverse((object: any) => {
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
let helper: DirectionalLightHelper | HemisphereLightHelper | PointLightHelper;
|
|
61
|
+
|
|
62
|
+
if (object.isDirectionalLight) helper = new DirectionalLightHelper(object, size, "#aa0000");
|
|
63
|
+
else if (object.isHemisphereLight) helper = new HemisphereLightHelper(object, size, "#ff9800");
|
|
64
|
+
else if (object.isPointLight) helper = new PointLightHelper(object, size, "#ff9800");
|
|
65
|
+
|
|
66
|
+
if (helper) {
|
|
62
67
|
this.lightHelpers.push(helper);
|
|
63
68
|
this.viewer.helpers.add(helper);
|
|
64
69
|
}
|
|
@@ -23,11 +23,9 @@
|
|
|
23
23
|
|
|
24
24
|
import { PMREMGenerator } from "three";
|
|
25
25
|
import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
|
|
26
|
+
import { IComponent, components, Viewer } from "@inweb/viewer-three";
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
import type { Viewer } from "../Viewer";
|
|
29
|
-
|
|
30
|
-
export class RoomEnvironmentComponent implements IComponent {
|
|
28
|
+
class RoomEnvironmentComponent implements IComponent {
|
|
31
29
|
protected viewer: Viewer;
|
|
32
30
|
|
|
33
31
|
constructor(viewer: Viewer) {
|
|
@@ -45,3 +43,5 @@ export class RoomEnvironmentComponent implements IComponent {
|
|
|
45
43
|
this.viewer.scene.environment = undefined;
|
|
46
44
|
}
|
|
47
45
|
}
|
|
46
|
+
|
|
47
|
+
components.registerComponent("LightComponent", (viewer) => new RoomEnvironmentComponent(viewer));
|
|
@@ -21,13 +21,15 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
// https://github.com/buildingSMART/IFC5-development
|
|
25
|
-
//
|
|
26
|
-
// Commit SHA-1:
|
|
24
|
+
// Repository: https://github.com/buildingSMART/IFC5-development
|
|
25
|
+
// Original File: docs/viewer/render.mjs
|
|
26
|
+
// Commit SHA-1: 83a7ae862232c90065d1bd03fcd538315e7d2563
|
|
27
|
+
// Commit Date: 20.05.2025 21:00:52
|
|
27
28
|
|
|
28
29
|
// (C) buildingSMART International
|
|
29
30
|
// published under MIT license
|
|
30
31
|
|
|
32
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
31
33
|
/* eslint-disable prefer-const */
|
|
32
34
|
/* eslint-disable no-useless-catch */
|
|
33
35
|
|
|
@@ -175,7 +177,7 @@ function FindRootsOrCycles(nodes) {
|
|
|
175
177
|
}
|
|
176
178
|
visit(path);
|
|
177
179
|
});
|
|
178
|
-
} catch {
|
|
180
|
+
} catch (e) {
|
|
179
181
|
return null;
|
|
180
182
|
}
|
|
181
183
|
return roots;
|
|
@@ -262,7 +264,7 @@ function ToInputNodes(data) {
|
|
|
262
264
|
let inputNodes = /* @__PURE__ */ new Map();
|
|
263
265
|
data.forEach((ifcxNode) => {
|
|
264
266
|
let node = {
|
|
265
|
-
path: ifcxNode.
|
|
267
|
+
path: ifcxNode.path,
|
|
266
268
|
children: ifcxNode.children ? ifcxNode.children : {},
|
|
267
269
|
inherits: ifcxNode.inherits ? ifcxNode.inherits : {},
|
|
268
270
|
attributes: ifcxNode.attributes ? ifcxNode.attributes : {},
|
|
@@ -431,7 +433,7 @@ function Prune(file, deleteEmpty = false) {
|
|
|
431
433
|
let collapsed = Collapse(nodes, deleteEmpty);
|
|
432
434
|
if (collapsed)
|
|
433
435
|
result.data.push({
|
|
434
|
-
|
|
436
|
+
path: collapsed.path,
|
|
435
437
|
children: collapsed.children,
|
|
436
438
|
inherits: collapsed.inherits,
|
|
437
439
|
attributes: collapsed.attributes,
|
|
@@ -496,8 +498,8 @@ function init() {
|
|
|
496
498
|
camera.lookAt(0, 0, 0);
|
|
497
499
|
// const nd = document.querySelector(".viewport");
|
|
498
500
|
// renderer = new THREE.WebGLRenderer({
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
+
// alpha: true,
|
|
502
|
+
// logarithmicDepthBuffer: true,
|
|
501
503
|
// });
|
|
502
504
|
// renderer.setSize(nd.offsetWidth, nd.offsetHeight);
|
|
503
505
|
// controls = new THREE.OrbitControls(camera, renderer.domElement);
|
|
@@ -529,13 +531,12 @@ function createMaterialFromParent(parent, root) {
|
|
|
529
531
|
};
|
|
530
532
|
if (reference) {
|
|
531
533
|
const materialNode = getChildByName(root, reference.ref);
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
let color = shader?.attributes["usd::materials::inputs::diffuseColor"];
|
|
534
|
+
if (materialNode) {
|
|
535
|
+
let color = materialNode?.attributes["bsi::presentation::diffuseColor"];
|
|
535
536
|
material.color = new THREE.Color(...color);
|
|
536
|
-
if (
|
|
537
|
+
if (materialNode?.attributes["bsi::presentation::opacity"]) {
|
|
537
538
|
material.transparent = true;
|
|
538
|
-
material.opacity =
|
|
539
|
+
material.opacity = materialNode.attributes["bsi::presentation::opacity"];
|
|
539
540
|
}
|
|
540
541
|
}
|
|
541
542
|
}
|
|
@@ -596,17 +597,23 @@ function traverseTree(node, parent, root, parentNode = void 0) {
|
|
|
596
597
|
// var icons = {
|
|
597
598
|
// "usd::usdgeom::mesh::points": "deployed_code",
|
|
598
599
|
// "usd::usdgeom::basiscurves::points": "line_curve",
|
|
599
|
-
// "usd::usdshade::material::outputs::surface.connect": "line_style"
|
|
600
|
+
// "usd::usdshade::material::outputs::surface.connect": "line_style",
|
|
600
601
|
// };
|
|
601
602
|
// function buildDomTree(prim, node) {
|
|
602
603
|
// const elem = document.createElement("div");
|
|
603
604
|
// let span;
|
|
604
605
|
// elem.appendChild(document.createTextNode(prim.name ? prim.name.split("/").reverse()[0] : "root"));
|
|
605
|
-
// elem.appendChild(span = document.createElement("span"));
|
|
606
|
-
// Object.entries(icons).forEach(([k, v]) => span.innerText += (prim.attributes || {})[k] ? v : " ");
|
|
606
|
+
// elem.appendChild((span = document.createElement("span")));
|
|
607
|
+
// Object.entries(icons).forEach(([k, v]) => (span.innerText += (prim.attributes || {})[k] ? v : " "));
|
|
607
608
|
// span.className = "material-symbols-outlined";
|
|
608
609
|
// elem.onclick = (evt) => {
|
|
609
|
-
// let rows = [["name", prim.name]]
|
|
610
|
+
// let rows = [["name", prim.name]]
|
|
611
|
+
// .concat(Object.entries(prim.attributes))
|
|
612
|
+
// .map(
|
|
613
|
+
// ([k, v]) =>
|
|
614
|
+
// `<tr><td>${encodeHtmlEntities(k)}</td><td>${encodeHtmlEntities(typeof v === "object" ? JSON.stringify(v) : v)}</td>`
|
|
615
|
+
// )
|
|
616
|
+
// .join("");
|
|
610
617
|
// document.querySelector(".attributes .table").innerHTML = `<table border="0">${rows}</table>`;
|
|
611
618
|
// evt.stopPropagation();
|
|
612
619
|
// };
|
|
@@ -685,10 +692,8 @@ function composeAndRender() {
|
|
|
685
692
|
// controls.update();
|
|
686
693
|
// renderer.render(scene, camera);
|
|
687
694
|
// }
|
|
688
|
-
// export {
|
|
689
|
-
|
|
690
|
-
// addModel as default
|
|
691
|
-
// };
|
|
695
|
+
// export { composeAndRender, addModel as default };
|
|
696
|
+
|
|
692
697
|
export function parse(m, name) {
|
|
693
698
|
datas.push([name, m]);
|
|
694
699
|
composeAndRender();
|
package/src/Viewer/Viewer.ts
CHANGED
|
@@ -535,6 +535,10 @@ export class Viewer
|
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
getComponent(name: string): IComponent {
|
|
539
|
+
return this._components.find((component) => component.name === name);
|
|
540
|
+
}
|
|
541
|
+
|
|
538
542
|
is3D(): boolean {
|
|
539
543
|
return true;
|
|
540
544
|
}
|
|
@@ -573,10 +577,6 @@ export class Viewer
|
|
|
573
577
|
return commands.executeCommand(id, this, ...args);
|
|
574
578
|
}
|
|
575
579
|
|
|
576
|
-
getComponent(name: string): IComponent {
|
|
577
|
-
return this._components.find((component) => component.name === name);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
580
|
drawViewpoint(viewpoint: IViewpoint): void {
|
|
581
581
|
if (!this.renderer) return;
|
|
582
582
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
24
|
+
import { Color, EdgesGeometry, LineBasicMaterial, MeshBasicMaterial, Vector2 } from "three";
|
|
25
|
+
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
|
|
26
|
+
import { Wireframe } from "three/examples/jsm/lines/Wireframe.js";
|
|
27
|
+
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
|
|
28
|
+
|
|
29
|
+
import { IComponent, ResizeEvent } from "@inweb/viewer-core";
|
|
30
|
+
import { Viewer } from "../Viewer";
|
|
31
|
+
import { HighlighterUtils } from "./HighlighterUtils";
|
|
32
|
+
|
|
33
|
+
export class HighlighterComponent implements IComponent {
|
|
34
|
+
protected viewer: Viewer;
|
|
35
|
+
public highlightMaterial: MeshBasicMaterial;
|
|
36
|
+
public outlineMaterial: LineMaterial;
|
|
37
|
+
public highlightLineMaterial: LineBasicMaterial;
|
|
38
|
+
public highlightLineGlowMaterial: LineMaterial;
|
|
39
|
+
|
|
40
|
+
constructor(viewer: Viewer) {
|
|
41
|
+
this.viewer = viewer;
|
|
42
|
+
|
|
43
|
+
this.viewer.addEventListener("databasechunk", this.geometryEnd);
|
|
44
|
+
this.viewer.addEventListener("optionschange", this.optionsChange);
|
|
45
|
+
this.viewer.addEventListener("resize", this.viewerResize);
|
|
46
|
+
|
|
47
|
+
this.geometryEnd();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
dispose() {
|
|
51
|
+
this.viewer.removeEventListener("databasechunk", this.geometryEnd);
|
|
52
|
+
this.viewer.removeEventListener("optionschange", this.optionsChange);
|
|
53
|
+
this.viewer.removeEventListener("resize", this.viewerResize);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
highlight(object: any) {
|
|
57
|
+
if (object.isHighlighted) return;
|
|
58
|
+
|
|
59
|
+
if (object.isLine || object.isLineSegments) {
|
|
60
|
+
const positions = object.geometry.attributes.position.array;
|
|
61
|
+
const indices = object.geometry.index ? object.geometry.index.array : null;
|
|
62
|
+
const lineGeometry = indices
|
|
63
|
+
? HighlighterUtils.fromIndexedLine(positions, indices)
|
|
64
|
+
: HighlighterUtils.fromNonIndexedLine(positions, object.isLineSegments);
|
|
65
|
+
|
|
66
|
+
const wireframe = new Wireframe(lineGeometry, this.highlightLineGlowMaterial);
|
|
67
|
+
wireframe.position.copy(object.position);
|
|
68
|
+
wireframe.rotation.copy(object.rotation);
|
|
69
|
+
wireframe.scale.copy(object.scale);
|
|
70
|
+
|
|
71
|
+
object.parent.add(wireframe);
|
|
72
|
+
|
|
73
|
+
object.userData.highlightwireframe = wireframe;
|
|
74
|
+
object.userData.originalMaterial = object.material;
|
|
75
|
+
object.material = this.highlightLineMaterial;
|
|
76
|
+
object.isHighlighted = true;
|
|
77
|
+
} else if (object.isMesh) {
|
|
78
|
+
const edgesGeometry = new EdgesGeometry(object.geometry, 30);
|
|
79
|
+
const lineGeometry = new LineSegmentsGeometry().fromEdgesGeometry(edgesGeometry);
|
|
80
|
+
|
|
81
|
+
const wireframe = new Wireframe(lineGeometry, this.outlineMaterial);
|
|
82
|
+
wireframe.position.copy(object.position);
|
|
83
|
+
wireframe.rotation.copy(object.rotation);
|
|
84
|
+
wireframe.scale.copy(object.scale);
|
|
85
|
+
|
|
86
|
+
object.parent.add(wireframe);
|
|
87
|
+
|
|
88
|
+
object.userData.highlightwireframe = wireframe;
|
|
89
|
+
object.userData.originalMaterial = object.material;
|
|
90
|
+
object.material = this.highlightMaterial;
|
|
91
|
+
object.isHighlighted = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
unhighlight(object: any) {
|
|
96
|
+
if (!object.isHighlighted) return;
|
|
97
|
+
|
|
98
|
+
object.isHighlighted = false;
|
|
99
|
+
object.material = object.userData.originalMaterial;
|
|
100
|
+
object.userData.highlightwireframe.removeFromParent();
|
|
101
|
+
|
|
102
|
+
delete object.userData.originalMaterial;
|
|
103
|
+
delete object.userData.highlightwireframe;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
geometryEnd = () => {
|
|
107
|
+
const { facesColor, facesTransparancy, edgesColor } = this.viewer.options;
|
|
108
|
+
|
|
109
|
+
this.highlightMaterial = new MeshBasicMaterial({
|
|
110
|
+
color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
|
|
111
|
+
transparent: true,
|
|
112
|
+
opacity: (255 - facesTransparancy) / 255,
|
|
113
|
+
depthTest: false,
|
|
114
|
+
depthWrite: false,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
this.outlineMaterial = new LineMaterial({
|
|
118
|
+
color: new Color(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255),
|
|
119
|
+
linewidth: 1.5,
|
|
120
|
+
depthTest: false,
|
|
121
|
+
depthWrite: false,
|
|
122
|
+
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
this.highlightLineMaterial = new LineBasicMaterial({
|
|
126
|
+
color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
|
|
127
|
+
depthTest: false,
|
|
128
|
+
depthWrite: false,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
this.highlightLineGlowMaterial = new LineMaterial({
|
|
132
|
+
color: new Color(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255),
|
|
133
|
+
linewidth: 5,
|
|
134
|
+
transparent: true,
|
|
135
|
+
opacity: 0.8,
|
|
136
|
+
depthTest: true,
|
|
137
|
+
depthWrite: true,
|
|
138
|
+
resolution: new Vector2(window.innerWidth, window.innerHeight),
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
optionsChange = () => {
|
|
143
|
+
const { facesColor, facesTransparancy, edgesColor } = this.viewer.options;
|
|
144
|
+
|
|
145
|
+
this.highlightMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
|
|
146
|
+
this.highlightMaterial.opacity = (255 - facesTransparancy) / 255;
|
|
147
|
+
this.outlineMaterial.color.setRGB(edgesColor.r / 255, edgesColor.g / 255, edgesColor.b / 255);
|
|
148
|
+
this.highlightLineMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
|
|
149
|
+
this.highlightLineGlowMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
|
|
150
|
+
|
|
151
|
+
this.viewer.update();
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
viewerResize(event: ResizeEvent) {
|
|
155
|
+
if (!this.outlineMaterial) return;
|
|
156
|
+
|
|
157
|
+
this.outlineMaterial.resolution.set(event.width, event.height);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
24
|
+
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
|
|
25
|
+
|
|
26
|
+
export class HighlighterUtils {
|
|
27
|
+
static isBreak(positions: Float32Array, i: number) {
|
|
28
|
+
return (
|
|
29
|
+
isNaN(positions[i]) ||
|
|
30
|
+
isNaN(positions[i + 1]) ||
|
|
31
|
+
isNaN(positions[i + 2]) ||
|
|
32
|
+
positions[i] === Infinity ||
|
|
33
|
+
positions[i] === -Infinity ||
|
|
34
|
+
positions[i + 1] === Infinity ||
|
|
35
|
+
positions[i + 1] === -Infinity ||
|
|
36
|
+
positions[i + 2] === Infinity ||
|
|
37
|
+
positions[i + 2] === -Infinity
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static fromIndexedLine(positions: Float32Array, indices: number[]) {
|
|
42
|
+
const lineGeometry = new LineSegmentsGeometry();
|
|
43
|
+
const segments = [];
|
|
44
|
+
|
|
45
|
+
for (let i = 0; i < indices.length; i += 2) {
|
|
46
|
+
const idx1 = indices[i] * 3;
|
|
47
|
+
const idx2 = indices[i + 1] * 3;
|
|
48
|
+
|
|
49
|
+
if (indices[i] === -1 || indices[i + 1] === -1) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
segments.push(
|
|
54
|
+
positions[idx1],
|
|
55
|
+
positions[idx1 + 1],
|
|
56
|
+
positions[idx1 + 2],
|
|
57
|
+
positions[idx2],
|
|
58
|
+
positions[idx2 + 1],
|
|
59
|
+
positions[idx2 + 2]
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (segments.length === 0) return null;
|
|
64
|
+
|
|
65
|
+
lineGeometry.setPositions(segments);
|
|
66
|
+
return lineGeometry;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static fromNonIndexedLine(positions: Float32Array, isLineSegments: boolean) {
|
|
70
|
+
const lineGeometry = new LineSegmentsGeometry();
|
|
71
|
+
const segments = [];
|
|
72
|
+
|
|
73
|
+
if (isLineSegments) {
|
|
74
|
+
for (let i = 0; i < positions.length; i += 6) {
|
|
75
|
+
if (i + 5 >= positions.length) break;
|
|
76
|
+
|
|
77
|
+
if (HighlighterUtils.isBreak(positions, i) || HighlighterUtils.isBreak(positions, i + 3)) continue;
|
|
78
|
+
|
|
79
|
+
segments.push(
|
|
80
|
+
positions[i],
|
|
81
|
+
positions[i + 1],
|
|
82
|
+
positions[i + 2],
|
|
83
|
+
positions[i + 3],
|
|
84
|
+
positions[i + 4],
|
|
85
|
+
positions[i + 5]
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
let lastValidIndex = -1;
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
92
|
+
if (HighlighterUtils.isBreak(positions, i)) {
|
|
93
|
+
lastValidIndex = -1;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (lastValidIndex !== -1) {
|
|
98
|
+
segments.push(
|
|
99
|
+
positions[lastValidIndex],
|
|
100
|
+
positions[lastValidIndex + 1],
|
|
101
|
+
positions[lastValidIndex + 2],
|
|
102
|
+
positions[i],
|
|
103
|
+
positions[i + 1],
|
|
104
|
+
positions[i + 2]
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
lastValidIndex = i;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (segments.length === 0) return null;
|
|
112
|
+
|
|
113
|
+
lineGeometry.setPositions(segments);
|
|
114
|
+
return lineGeometry;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import { AmbientLight, DirectionalLight, Sphere, Vector3 } from "three";
|
|
24
|
+
import { AmbientLight, DirectionalLight, HemisphereLight, Sphere, Vector3 } from "three";
|
|
25
25
|
|
|
26
26
|
import { IComponent } from "@inweb/viewer-core";
|
|
27
27
|
import type { Viewer } from "../Viewer";
|
|
@@ -30,17 +30,27 @@ export class LightComponent implements IComponent {
|
|
|
30
30
|
protected viewer: Viewer;
|
|
31
31
|
protected ambientLight: AmbientLight;
|
|
32
32
|
protected directionalLight: DirectionalLight;
|
|
33
|
+
protected frontLight: DirectionalLight;
|
|
34
|
+
protected hemisphereLight: HemisphereLight;
|
|
33
35
|
|
|
34
36
|
constructor(viewer: Viewer) {
|
|
35
37
|
this.viewer = viewer;
|
|
36
38
|
|
|
37
|
-
this.ambientLight = new AmbientLight(0xffffff,
|
|
39
|
+
this.ambientLight = new AmbientLight(0xffffff, 1);
|
|
38
40
|
this.viewer.scene.add(this.ambientLight);
|
|
39
41
|
|
|
40
42
|
this.directionalLight = new DirectionalLight(0xffffff, 1);
|
|
41
43
|
this.directionalLight.position.set(0.5, 0, 0.866); // ~60º
|
|
42
44
|
this.viewer.scene.add(this.directionalLight);
|
|
43
45
|
|
|
46
|
+
this.frontLight = new DirectionalLight(0xffffff, 1.25);
|
|
47
|
+
this.frontLight.position.set(0, 1, 0);
|
|
48
|
+
this.viewer.scene.add(this.frontLight);
|
|
49
|
+
|
|
50
|
+
this.hemisphereLight = new HemisphereLight(0xffffff, 0x444444, 1.25);
|
|
51
|
+
this.hemisphereLight.position.set(0, 0, 1);
|
|
52
|
+
this.viewer.scene.add(this.hemisphereLight);
|
|
53
|
+
|
|
44
54
|
this.viewer.addEventListener("databasechunk", this.geometryEnd);
|
|
45
55
|
this.viewer.addEventListener("clear", this.geometryEnd);
|
|
46
56
|
}
|
|
@@ -52,6 +62,12 @@ export class LightComponent implements IComponent {
|
|
|
52
62
|
this.directionalLight.removeFromParent();
|
|
53
63
|
this.directionalLight.dispose();
|
|
54
64
|
|
|
65
|
+
this.frontLight.removeFromParent();
|
|
66
|
+
this.frontLight.dispose();
|
|
67
|
+
|
|
68
|
+
this.hemisphereLight.removeFromParent();
|
|
69
|
+
this.hemisphereLight.dispose();
|
|
70
|
+
|
|
55
71
|
this.viewer.removeEventListener("databasechunk", this.geometryEnd);
|
|
56
72
|
this.viewer.removeEventListener("clear", this.geometryEnd);
|
|
57
73
|
}
|
|
@@ -59,15 +75,28 @@ export class LightComponent implements IComponent {
|
|
|
59
75
|
geometryEnd = () => {
|
|
60
76
|
this.ambientLight.removeFromParent();
|
|
61
77
|
this.directionalLight.removeFromParent();
|
|
78
|
+
this.frontLight.removeFromParent();
|
|
79
|
+
this.hemisphereLight.removeFromParent();
|
|
62
80
|
|
|
63
81
|
if (this.viewer.extents.isEmpty()) return;
|
|
64
82
|
|
|
65
83
|
const extentsCenter = this.viewer.extents.getCenter(new Vector3());
|
|
66
|
-
const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius
|
|
67
|
-
|
|
84
|
+
const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius;
|
|
85
|
+
|
|
86
|
+
this.directionalLight.position
|
|
87
|
+
.set(0.5, 0, 0.866)
|
|
88
|
+
.multiplyScalar(extentsSize * 2)
|
|
89
|
+
.add(extentsCenter);
|
|
68
90
|
this.directionalLight.target.position.copy(extentsCenter);
|
|
69
91
|
|
|
92
|
+
this.frontLight.position.set(0, extentsSize * 2, 0).add(extentsCenter);
|
|
93
|
+
this.frontLight.target.position.copy(extentsCenter);
|
|
94
|
+
|
|
95
|
+
this.hemisphereLight.position.set(0, extentsSize * 3, 0).add(extentsCenter);
|
|
96
|
+
|
|
70
97
|
this.viewer.scene.add(this.ambientLight);
|
|
71
98
|
this.viewer.scene.add(this.directionalLight);
|
|
99
|
+
this.viewer.scene.add(this.frontLight);
|
|
100
|
+
this.viewer.scene.add(this.hemisphereLight);
|
|
72
101
|
};
|
|
73
102
|
}
|