/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2023, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a // license agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2021 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// import * as THREE from "three"; export class ClippingPlaneDragger { protected viewer: any; protected start: THREE.Vector3; protected end: THREE.Vector3; protected delta: THREE.Vector3; protected planeHelper: THREE.PlaneHelper; public plane: THREE.Plane; constructor(viewer: any) { this.viewer = viewer; this.viewer.addEventListener("pointerdown", this.onPointerDown); this.viewer.addEventListener("pointerup", this.onPointerUp); this.plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); this.start = new THREE.Vector3(); this.end = new THREE.Vector3(); this.delta = new THREE.Vector3(); if (!this.viewer.renderer.clippingPlanes) this.viewer.renderer.clippingPlanes = []; this.viewer.renderer.clippingPlanes.push(this.plane); this.planeHelper = new THREE.PlaneHelper(this.plane, 150, 0xffff00); this.viewer.scene.add(this.planeHelper); } dispose() { this.viewer.removeEventListener("pointerdown", this.onPointerDown); this.viewer.removeEventListener("pointerup", this.onPointerUp); this.viewer.removeEventListener("pointermove", this.onPointerMove); this.viewer.renderer.clippingPlanes = this.viewer.renderer.clippingPlanes.filter((plane) => this.plane !== plane); this.planeHelper.removeFromParent(); } onPointerDown = (event: PointerEvent) => { this.viewer.addEventListener("pointermove", this.onPointerMove); const { offsetX, offsetY } = event; this.start.set(offsetX, offsetY, 0.5); this.start = this.screenToPlane(this.start); this.delta.set(0, 0, 0); this.end.set(0, 0, 0); }; onPointerUp = (event: PointerEvent) => { this.viewer.removeEventListener("pointermove", this.onPointerMove); if (this.end.length() === 0) { const plane: THREE.Plane = this.plane; plane.normal.multiplyScalar(-1); plane.constant *= -1; } else { const { offsetX, offsetY } = event; this.end.set(offsetX, offsetY, 0.5); this.end = this.screenToPlane(this.end); } }; onPointerMove = (event: PointerEvent) => { const { offsetX, offsetY } = event; this.end.set(offsetX, offsetY, 0.5); this.end = this.screenToPlane(this.end); this.delta.copy(this.end).sub(this.start); this.start.copy(this.end); const plane: THREE.Plane = this.plane; plane.translate(this.delta); }; update() {} screenToWorld(v: THREE.Vector3) { v.x = (2 * v.x) / this.viewer.canvas.clientWidth - 1; v.y = 1 - (2 * v.y) / this.viewer.canvas.clientHeight; return v.unproject(this.viewer.camera); } screenToPlane(v: THREE.Vector3) { v = this.screenToWorld(v); const direction = v.sub(this.viewer.camera.position).normalize(); const ray = new THREE.Ray(this.viewer.camera.position, direction); let plane: THREE.Plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); const dot = plane.normal.dot(this.plane.normal); if (Math.abs(dot) === 1) { plane = new THREE.Plane(new THREE.Vector3(1, 0, 0), 0); } const result = new THREE.Vector3(); ray.intersectPlane(plane, result); return result; } }