|
@@ -1,910 +0,0 @@
|
|
|
-
|
|
|
-import * as THREE from "../../../libs/three.js/build/three.module.js";
|
|
|
-import {Utils} from "../../utils.js";
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-//add-------------------------------------
|
|
|
-const OpaWhenNotSelect = 0.75
|
|
|
-const ScaleRatio = 4
|
|
|
-const OutlineColor = 0x666666
|
|
|
-//----------------------------------------
|
|
|
-const hideFocusHandles = true//add
|
|
|
-
|
|
|
-
|
|
|
-export class TransformationTool {
|
|
|
- constructor(viewer) {
|
|
|
- this.viewer = viewer;
|
|
|
-
|
|
|
- this.scene = new THREE.Scene();
|
|
|
-
|
|
|
- this.selection = [];
|
|
|
- this.pivot = new THREE.Vector3();
|
|
|
- this.dragging = false;
|
|
|
- this.showPickVolumes = false;
|
|
|
-
|
|
|
- this.viewer.inputHandler.registerInteractiveScene(this.scene);
|
|
|
- this.viewer.inputHandler.addEventListener('selection_changed', (e) => {
|
|
|
- for(let selected of this.selection){
|
|
|
- this.viewer.inputHandler.blacklist.delete(selected);
|
|
|
- }
|
|
|
-
|
|
|
- this.selection = e.selection;
|
|
|
-
|
|
|
- for(let selected of this.selection){
|
|
|
- this.viewer.inputHandler.blacklist.add(selected);
|
|
|
- }
|
|
|
-
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- this.viewer.addEventListener('global_touchstart',(e)=>{ //add
|
|
|
- this.update()
|
|
|
- })
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- let red = Potree.config.axis.x.color
|
|
|
- let green = Potree.config.axis.y.color
|
|
|
- let blue = Potree.config.axis.z.color
|
|
|
-
|
|
|
- this.activeHandle = null;
|
|
|
- this.scaleHandles = {
|
|
|
- "scale.x+": {name: "scale.x+", node: new THREE.Object3D(), color: red, alignment: [+1, +0, +0]},
|
|
|
- "scale.x-": {name: "scale.x-", node: new THREE.Object3D(), color: red, alignment: [-1, +0, +0]},
|
|
|
- "scale.y+": {name: "scale.y+", node: new THREE.Object3D(), color: green, alignment: [+0, +1, +0]},
|
|
|
- "scale.y-": {name: "scale.y-", node: new THREE.Object3D(), color: green, alignment: [+0, -1, +0]},
|
|
|
- "scale.z+": {name: "scale.z+", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, +1]},
|
|
|
- "scale.z-": {name: "scale.z-", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, -1]},
|
|
|
- };
|
|
|
- this.focusHandles = {
|
|
|
- "focus.x+": {name: "focus.x+", node: new THREE.Object3D(), color: red, alignment: [+1, +0, +0]},
|
|
|
- "focus.x-": {name: "focus.x-", node: new THREE.Object3D(), color: red, alignment: [-1, +0, +0]},
|
|
|
- "focus.y+": {name: "focus.y+", node: new THREE.Object3D(), color: green, alignment: [+0, +1, +0]},
|
|
|
- "focus.y-": {name: "focus.y-", node: new THREE.Object3D(), color: green, alignment: [+0, -1, +0]},
|
|
|
- "focus.z+": {name: "focus.z+", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, +1]},
|
|
|
- "focus.z-": {name: "focus.z-", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, -1]},
|
|
|
- };
|
|
|
- this.translationHandles = {
|
|
|
- "translation.x": {name: "translation.x", node: new THREE.Object3D(), color: red, alignment: [1, 0, 0]},
|
|
|
- "translation.y": {name: "translation.y", node: new THREE.Object3D(), color: green, alignment: [0, 1, 0]},
|
|
|
- "translation.z": {name: "translation.z", node: new THREE.Object3D(), color: blue, alignment: [0, 0, 1]},
|
|
|
- };
|
|
|
- this.rotationHandles = {
|
|
|
- "rotation.x": {name: "rotation.x", node: new THREE.Object3D(), color: red, alignment: [1, 0, 0]},
|
|
|
- "rotation.y": {name: "rotation.y", node: new THREE.Object3D(), color: green, alignment: [0, 1, 0]},
|
|
|
- "rotation.z": {name: "rotation.z", node: new THREE.Object3D(), color: blue, alignment: [0, 0, 1]},
|
|
|
- };
|
|
|
- this.handles = Object.assign({}, this.scaleHandles, hideFocusHandles?{}:this.focusHandles, this.translationHandles, this.rotationHandles);
|
|
|
- this.pickVolumes = [];
|
|
|
-
|
|
|
- this.initializeScaleHandles();
|
|
|
- this.initializeFocusHandles();
|
|
|
- this.initializeTranslationHandles();
|
|
|
- this.initializeRotationHandles();
|
|
|
-
|
|
|
-
|
|
|
- let boxFrameGeometry = new THREE.Geometry();
|
|
|
- {
|
|
|
- // bottom
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
|
|
|
- // top
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
|
|
|
- // sides
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
|
|
|
- boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
|
|
|
- }
|
|
|
- this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: 0xffff00}));
|
|
|
- this.scene.add(this.frame);
|
|
|
- viewer.setObjectLayers(this.scene, 'transformationTool' )
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- initializeScaleHandles(){
|
|
|
- let sgSphere = new THREE.SphereGeometry(1, 32, 32);
|
|
|
- let sgLowPolySphere = new THREE.SphereGeometry(1, 16, 16);
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.scaleHandles)){
|
|
|
- let handle = this.scaleHandles[handleName];
|
|
|
- let node = handle.node;
|
|
|
- this.scene.add(node);
|
|
|
- node.position.set(...handle.alignment).multiplyScalar(0.5);
|
|
|
-
|
|
|
- let material = new THREE.MeshBasicMaterial({
|
|
|
- color: handle.color,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true
|
|
|
- });
|
|
|
-
|
|
|
- let outlineMaterial = new THREE.MeshBasicMaterial({
|
|
|
- color: OutlineColor,
|
|
|
- side: THREE.BackSide,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true});
|
|
|
-
|
|
|
- let pickMaterial = new THREE.MeshNormalMaterial({
|
|
|
- opacity: 0.2,
|
|
|
- transparent: true,
|
|
|
- visible: this.showPickVolumes});
|
|
|
-
|
|
|
- let sphere = new THREE.Mesh(sgSphere, material);
|
|
|
- sphere.scale.set(2, 2, 2 );
|
|
|
- sphere.name = `${handleName}.handle`;
|
|
|
- node.add(sphere);
|
|
|
-
|
|
|
- let outline = new THREE.Mesh(sgSphere, outlineMaterial);
|
|
|
- outline.scale.set(1.1, 1.1, 1.1);
|
|
|
- outline.name = `${handleName}.outline`;
|
|
|
- sphere.add(outline);
|
|
|
-
|
|
|
- let pickSphere = new THREE.Mesh(sgLowPolySphere, pickMaterial);
|
|
|
- pickSphere.name = `${handleName}.pick_volume`;
|
|
|
- pickSphere.scale.set(2, 2, 2);
|
|
|
- sphere.add(pickSphere);
|
|
|
- pickSphere.handle = handleName;
|
|
|
- this.pickVolumes.push(pickSphere);
|
|
|
-
|
|
|
- node.setOpacity = (target) => {
|
|
|
- let opacity = {x: material.opacity};
|
|
|
- let t = new TWEEN.Tween(opacity).to({x: target}, 100);
|
|
|
- t.onUpdate(() => {
|
|
|
- sphere.visible = opacity.x > 0;
|
|
|
- pickSphere.visible = opacity.x > 0;
|
|
|
- material.opacity = opacity.x;
|
|
|
- outlineMaterial.opacity = opacity.x;
|
|
|
- pickSphere.material.opacity = opacity.x * 0.5;
|
|
|
- });
|
|
|
- t.start();
|
|
|
- };
|
|
|
-
|
|
|
- pickSphere.addEventListener("drag", (e) => this.dragScaleHandle(e));
|
|
|
- pickSphere.addEventListener("drop", (e) => this.dropScaleHandle(e));
|
|
|
-
|
|
|
- pickSphere.addEventListener("mouseover", e => {
|
|
|
- //node.setOpacity(1);
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("click", e => {
|
|
|
- e.consume();
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("mouseleave", e => {
|
|
|
- //node.setOpacity(OpaWhenNotSelect);
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- initializeFocusHandles(){
|
|
|
- if(hideFocusHandles)return//add
|
|
|
- //let sgBox = new THREE.BoxGeometry(1, 1, 1);
|
|
|
- let sgPlane = new THREE.PlaneGeometry(4, 4, 1, 1);
|
|
|
- let sgLowPolySphere = new THREE.SphereGeometry(1, 16, 16);
|
|
|
-
|
|
|
- let texture = new THREE.TextureLoader().load(`${exports.resourcePath}/icons/eye_2.png`);
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.focusHandles)){
|
|
|
- let handle = this.focusHandles[handleName];
|
|
|
- let node = handle.node;
|
|
|
- this.scene.add(node);
|
|
|
- let align = handle.alignment;
|
|
|
-
|
|
|
- //node.lookAt(new THREE.Vector3().addVectors(node.position, new THREE.Vector3(...align)));
|
|
|
- node.lookAt(new THREE.Vector3(...align));
|
|
|
-
|
|
|
- let off = 0.8;
|
|
|
- if(align[0] === 1){
|
|
|
- node.position.set(1, off, -off).multiplyScalar(0.5);
|
|
|
- node.rotation.z = Math.PI / 2;
|
|
|
- }else if(align[0] === -1){
|
|
|
- node.position.set(-1, -off, -off).multiplyScalar(0.5);
|
|
|
- node.rotation.z = Math.PI / 2;
|
|
|
- }else if(align[1] === 1){
|
|
|
- node.position.set(-off, 1, -off).multiplyScalar(0.5);
|
|
|
- node.rotation.set(Math.PI / 2, Math.PI, 0.0);
|
|
|
- }else if(align[1] === -1){
|
|
|
- node.position.set(off, -1, -off).multiplyScalar(0.5);
|
|
|
- node.rotation.set(Math.PI / 2, 0.0, 0.0);
|
|
|
- }else if(align[2] === 1){
|
|
|
- node.position.set(off, off, 1).multiplyScalar(0.5);
|
|
|
- }else if(align[2] === -1){
|
|
|
- node.position.set(-off, off, -1).multiplyScalar(0.5);
|
|
|
- }
|
|
|
-
|
|
|
- let material = new THREE.MeshBasicMaterial({
|
|
|
- color: handle.color,
|
|
|
- opacity: 0,
|
|
|
- transparent: true,
|
|
|
- map: texture
|
|
|
- });
|
|
|
-
|
|
|
- //let outlineMaterial = new THREE.MeshBasicMaterial({
|
|
|
- // color: 0x000000,
|
|
|
- // side: THREE.BackSide,
|
|
|
- // opacity: 0,
|
|
|
- // transparent: true});
|
|
|
-
|
|
|
- let pickMaterial = new THREE.MeshNormalMaterial({
|
|
|
- //opacity: 0,
|
|
|
- transparent: true,
|
|
|
- visible: this.showPickVolumes});
|
|
|
-
|
|
|
- let box = new THREE.Mesh(sgPlane, material);
|
|
|
- box.name = `${handleName}.handle`;
|
|
|
- box.scale.set(1.5, 1.5, 1.5);
|
|
|
- box.position.set(0, 0, 0);
|
|
|
- box.visible = false;
|
|
|
- node.add(box);
|
|
|
- //handle.focusNode = box;
|
|
|
-
|
|
|
- //let outline = new THREE.Mesh(sgPlane, outlineMaterial);
|
|
|
- //outline.scale.set(1.4, 1.4, 1.4);
|
|
|
- //outline.name = `${handleName}.outline`;
|
|
|
- //box.add(outline);
|
|
|
-
|
|
|
- let pickSphere = new THREE.Mesh(sgLowPolySphere, pickMaterial);
|
|
|
- pickSphere.name = `${handleName}.pick_volume`;
|
|
|
- pickSphere.scale.set(2, 2, 2);
|
|
|
- box.add(pickSphere);
|
|
|
- pickSphere.handle = handleName;
|
|
|
- this.pickVolumes.push(pickSphere);
|
|
|
-
|
|
|
- node.setOpacity = (target) => {
|
|
|
- let opacity = {x: material.opacity};
|
|
|
- let t = new TWEEN.Tween(opacity).to({x: target}, 100);
|
|
|
- t.onUpdate(() => {
|
|
|
- pickSphere.visible = opacity.x > 0;
|
|
|
- box.visible = opacity.x > 0;
|
|
|
- material.opacity = opacity.x;
|
|
|
- //outlineMaterial.opacity = opacity.x;
|
|
|
- pickSphere.material.opacity = opacity.x * 0.5;
|
|
|
- });
|
|
|
- t.start();
|
|
|
- };
|
|
|
-
|
|
|
- //pickSphere.addEventListener("drag", e => {});
|
|
|
-
|
|
|
- pickSphere.addEventListener("mouseup", e => {
|
|
|
- e.consume();
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("mousedown", e => {
|
|
|
- e.consume();
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("click", e => {
|
|
|
- e.consume();
|
|
|
-
|
|
|
- let selected = this.selection[0];
|
|
|
- let maxScale = Math.max(...selected.scale.toArray());
|
|
|
- let minScale = Math.min(...selected.scale.toArray());
|
|
|
- let handleLength = Math.abs(selected.scale.dot(new THREE.Vector3(...handle.alignment)));
|
|
|
- let alignment = new THREE.Vector3(...handle.alignment).multiplyScalar(2 * maxScale / handleLength);
|
|
|
- alignment.applyMatrix4(selected.matrixWorld);
|
|
|
- let newCamPos = alignment;
|
|
|
- let newCamTarget = selected.getWorldPosition(new THREE.Vector3());
|
|
|
-
|
|
|
- Utils.moveTo(this.viewer.scene, newCamPos, newCamTarget);
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("mouseover", e => {
|
|
|
- //box.setOpacity(1);
|
|
|
- });
|
|
|
-
|
|
|
- pickSphere.addEventListener("mouseleave", e => {
|
|
|
- //box.setOpacity(OpaWhenNotSelect);
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- initializeTranslationHandles(){
|
|
|
-
|
|
|
- let boxGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.translationHandles)){
|
|
|
- let handle = this.handles[handleName];
|
|
|
- let node = handle.node;
|
|
|
- this.scene.add(node);
|
|
|
-
|
|
|
- let material = new THREE.MeshBasicMaterial({
|
|
|
- color: handle.color,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true});
|
|
|
-
|
|
|
- let outlineMaterial = new THREE.MeshBasicMaterial({
|
|
|
- color: OutlineColor,
|
|
|
- side: THREE.BackSide,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true});
|
|
|
-
|
|
|
- let pickMaterial = new THREE.MeshNormalMaterial({
|
|
|
- opacity: 0.2,
|
|
|
- transparent: true,
|
|
|
- visible: this.showPickVolumes
|
|
|
- });
|
|
|
-
|
|
|
- let box = new THREE.Mesh(boxGeometry, material);
|
|
|
- box.name = `${handleName}.handle`;
|
|
|
- box.scale.set(1, 1, 36);
|
|
|
- box.lookAt(new THREE.Vector3(...handle.alignment));
|
|
|
- box.renderOrder = 10;
|
|
|
- node.add(box);
|
|
|
- handle.translateNode = box;
|
|
|
-
|
|
|
- let outline = new THREE.Mesh(boxGeometry, outlineMaterial);
|
|
|
- outline.name = `${handleName}.outline`;
|
|
|
- outline.scale.set(1.3, 1.3, 1.01);
|
|
|
- outline.renderOrder = 0;
|
|
|
- box.add(outline);
|
|
|
-
|
|
|
- let pickVolume = new THREE.Mesh(boxGeometry, pickMaterial);
|
|
|
- pickVolume.name = `${handleName}.pick_volume`;
|
|
|
- pickVolume.scale.set(4, 4, 1.1);
|
|
|
- pickVolume.handle = handleName;
|
|
|
- box.add(pickVolume);
|
|
|
- this.pickVolumes.push(pickVolume);
|
|
|
-
|
|
|
- node.setOpacity = (target) => {
|
|
|
- let opacity = {x: material.opacity};
|
|
|
- let t = new TWEEN.Tween(opacity).to({x: target}, 100);
|
|
|
- t.onUpdate(() => {
|
|
|
- box.visible = opacity.x > 0;
|
|
|
- pickVolume.visible = opacity.x > 0;
|
|
|
- material.opacity = opacity.x;
|
|
|
- outlineMaterial.opacity = opacity.x;
|
|
|
- pickMaterial.opacity = opacity.x * 0.5;
|
|
|
- });
|
|
|
- t.start();
|
|
|
- };
|
|
|
-
|
|
|
- pickVolume.addEventListener("drag", (e) => {this.dragTranslationHandle(e)});
|
|
|
- pickVolume.addEventListener("drop", (e) => {this.dropTranslationHandle(e)});
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- initializeRotationHandles(){
|
|
|
- let adjust = 1.5;
|
|
|
- let torusGeometry = new THREE.TorusGeometry(1, adjust * 0.015, 8, 64, Math.PI / 2);
|
|
|
- let outlineGeometry = new THREE.TorusGeometry(1, adjust * 0.018, 8, 64, Math.PI / 2);
|
|
|
- let pickGeometry = new THREE.TorusGeometry(1, adjust * 0.04, 6, 4, Math.PI / 2);
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.rotationHandles)){
|
|
|
- let handle = this.handles[handleName];
|
|
|
- let node = handle.node;
|
|
|
- this.scene.add(node);
|
|
|
-
|
|
|
- let material = new THREE.MeshBasicMaterial({
|
|
|
- color: handle.color,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true
|
|
|
- });
|
|
|
-
|
|
|
- let outlineMaterial = new THREE.MeshBasicMaterial({
|
|
|
- color: OutlineColor,
|
|
|
- side: THREE.BackSide,
|
|
|
- opacity: OpaWhenNotSelect,
|
|
|
- transparent: true
|
|
|
- });
|
|
|
-
|
|
|
- let pickMaterial = new THREE.MeshNormalMaterial({
|
|
|
- opacity: 0.2,
|
|
|
- transparent: true,
|
|
|
- visible: this.showPickVolumes
|
|
|
- });
|
|
|
-
|
|
|
- let box = new THREE.Mesh(torusGeometry, material);
|
|
|
- box.name = `${handleName}.handle`;
|
|
|
- box.scale.set(30, 30, 30);
|
|
|
- box.lookAt(new THREE.Vector3(...handle.alignment));
|
|
|
- node.add(box);
|
|
|
- handle.translateNode = box;
|
|
|
-
|
|
|
- let outline = new THREE.Mesh(outlineGeometry, outlineMaterial);
|
|
|
- outline.name = `${handleName}.outline`;
|
|
|
- outline.scale.set(1, 1, 1);
|
|
|
- outline.renderOrder = 0;
|
|
|
- box.add(outline);
|
|
|
-
|
|
|
- let pickVolume = new THREE.Mesh(pickGeometry, pickMaterial);
|
|
|
- pickVolume.name = `${handleName}.pick_volume`;
|
|
|
- pickVolume.scale.set(1, 1, 1);
|
|
|
- pickVolume.handle = handleName;
|
|
|
- box.add(pickVolume);
|
|
|
- this.pickVolumes.push(pickVolume);
|
|
|
-
|
|
|
- node.setOpacity = (target) => {
|
|
|
- let opacity = {x: material.opacity};
|
|
|
- let t = new TWEEN.Tween(opacity).to({x: target}, 100);
|
|
|
- t.onUpdate(() => {
|
|
|
- box.visible = opacity.x > 0;
|
|
|
- pickVolume.visible = opacity.x > 0;
|
|
|
- material.opacity = opacity.x;
|
|
|
- outlineMaterial.opacity = opacity.x;
|
|
|
- pickMaterial.opacity = opacity.x * 0.5;
|
|
|
- });
|
|
|
- t.start();
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
- //pickVolume.addEventListener("mouseover", (e) => {
|
|
|
- // //let a = this.viewer.scene.getActiveCamera().getWorldDirection(new THREE.Vector3()).dot(pickVolume.getWorldDirection(new THREE.Vector3()));
|
|
|
- // console.log(pickVolume.getWorldDirection(new THREE.Vector3()));
|
|
|
- //});
|
|
|
-
|
|
|
- pickVolume.addEventListener("drag", (e) => {this.dragRotationHandle(e)});
|
|
|
- pickVolume.addEventListener("drop", (e) => {this.dropRotationHandle(e)});
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dragRotationHandle(e){
|
|
|
- let drag = e.drag;
|
|
|
- let handle = this.activeHandle;
|
|
|
- let camera = this.viewer.scene.getActiveCamera();
|
|
|
-
|
|
|
- if(!handle){
|
|
|
- return
|
|
|
- };
|
|
|
-
|
|
|
- let localNormal = new THREE.Vector3(...handle.alignment);
|
|
|
- let n = new THREE.Vector3();
|
|
|
- n.copy(new THREE.Vector4(...localNormal.toArray(), 0).applyMatrix4(handle.node.matrixWorld));
|
|
|
- n.normalize();
|
|
|
-
|
|
|
- if (!drag.intersectionStart){
|
|
|
-
|
|
|
- //this.viewer.scene.scene.remove(this.debug);
|
|
|
- //this.debug = new THREE.Object3D();
|
|
|
- //this.viewer.scene.scene.add(this.debug);
|
|
|
- //Utils.debugSphere(this.debug, drag.location, 3, 0xaaaaaa);
|
|
|
- //let debugEnd = drag.location.clone().add(n.clone().multiplyScalar(20));
|
|
|
- //Utils.debugLine(this.debug, drag.location, debugEnd, 0xff0000);
|
|
|
-
|
|
|
- drag.intersectionStart = drag.location;
|
|
|
- drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
|
|
|
- drag.handle = handle;
|
|
|
-
|
|
|
- let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(n, drag.intersectionStart);
|
|
|
-
|
|
|
- drag.dragPlane = plane;
|
|
|
- drag.pivot = drag.intersectionStart;
|
|
|
- }else{
|
|
|
- handle = drag.handle;
|
|
|
- }
|
|
|
-
|
|
|
- this.dragging = true;
|
|
|
-
|
|
|
- let pointer = this.viewer.inputHandler.pointer
|
|
|
- let domElement = this.viewer.renderer.domElement;
|
|
|
- let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
|
|
|
-
|
|
|
- let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
|
|
|
-
|
|
|
- if (I) {
|
|
|
- let center = this.scene.getWorldPosition(new THREE.Vector3());
|
|
|
- let from = drag.pivot;
|
|
|
- let to = I;
|
|
|
-
|
|
|
- let v1 = from.clone().sub(center).normalize();
|
|
|
- let v2 = to.clone().sub(center).normalize();
|
|
|
-
|
|
|
- let angle = Math.acos(v1.dot(v2));
|
|
|
- let sign = Math.sign(v1.cross(v2).dot(n));
|
|
|
- angle = angle * sign;
|
|
|
- if (Number.isNaN(angle)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let normal = new THREE.Vector3(...handle.alignment);
|
|
|
- for (let selection of this.selection) {
|
|
|
- selection.rotateOnAxis(normal, angle);
|
|
|
- selection.dispatchEvent({
|
|
|
- type: "orientation_changed",
|
|
|
- object: selection
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- drag.pivot = I;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dropRotationHandle(e){
|
|
|
- this.dragging = false;
|
|
|
- this.setActiveHandle(null);
|
|
|
- }
|
|
|
-
|
|
|
- dragTranslationHandle(e){
|
|
|
- let drag = e.drag;
|
|
|
- let handle = this.activeHandle;
|
|
|
- let camera = this.viewer.scene.getActiveCamera();
|
|
|
-
|
|
|
- if(!drag.intersectionStart && handle){
|
|
|
- drag.intersectionStart = drag.location;
|
|
|
- drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
|
|
|
-
|
|
|
- let start = drag.intersectionStart;
|
|
|
- let dir = new THREE.Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
|
|
|
- let end = new THREE.Vector3().addVectors(start, dir);
|
|
|
- let line = new THREE.Line3(start.clone(), end.clone());
|
|
|
- drag.line = line;
|
|
|
-
|
|
|
- let camOnLine = line.closestPointToPoint(camera.position, false, new THREE.Vector3());
|
|
|
- let normal = new THREE.Vector3().subVectors(camera.position, camOnLine);
|
|
|
- let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
|
|
|
- drag.dragPlane = plane;
|
|
|
- drag.pivot = drag.intersectionStart;
|
|
|
- }else{
|
|
|
- handle = drag.handle;
|
|
|
- }
|
|
|
-
|
|
|
- this.dragging = true;
|
|
|
-
|
|
|
- {
|
|
|
- let pointer = this.viewer.inputHandler.pointer
|
|
|
- let domElement = this.viewer.renderer.domElement;
|
|
|
- let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
|
|
|
- let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
|
|
|
-
|
|
|
- if (I) {
|
|
|
- let iOnLine = drag.line.closestPointToPoint(I, false, new THREE.Vector3());
|
|
|
-
|
|
|
- let diff = new THREE.Vector3().subVectors(iOnLine, drag.pivot);
|
|
|
-
|
|
|
- for (let selection of this.selection) {
|
|
|
- selection.position.add(diff);
|
|
|
- selection.dispatchEvent({
|
|
|
- type: "position_changed",
|
|
|
- object: selection
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- drag.pivot = drag.pivot.add(diff);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dropTranslationHandle(e){
|
|
|
- this.dragging = false;
|
|
|
- this.setActiveHandle(null);
|
|
|
- }
|
|
|
-
|
|
|
- dropScaleHandle(e){
|
|
|
- this.dragging = false;
|
|
|
- this.setActiveHandle(null);
|
|
|
- }
|
|
|
-
|
|
|
- dragScaleHandle(e){
|
|
|
- let drag = e.drag;
|
|
|
- let handle = this.activeHandle;
|
|
|
- let camera = this.viewer.scene.getActiveCamera();
|
|
|
-
|
|
|
- if(!drag.intersectionStart){
|
|
|
- drag.intersectionStart = drag.location;
|
|
|
- drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
|
|
|
- drag.handle = handle;
|
|
|
-
|
|
|
- let start = drag.intersectionStart;
|
|
|
- let dir = new THREE.Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
|
|
|
- let end = new THREE.Vector3().addVectors(start, dir);
|
|
|
- let line = new THREE.Line3(start.clone(), end.clone());
|
|
|
- drag.line = line;
|
|
|
-
|
|
|
- let camOnLine = line.closestPointToPoint(camera.position, false, new THREE.Vector3());
|
|
|
- let normal = new THREE.Vector3().subVectors(camera.position, camOnLine);
|
|
|
- let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
|
|
|
- drag.dragPlane = plane;
|
|
|
- drag.pivot = drag.intersectionStart;
|
|
|
-
|
|
|
- //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
|
|
|
- }else{
|
|
|
- handle = drag.handle;
|
|
|
- }
|
|
|
-
|
|
|
- this.dragging = true;
|
|
|
-
|
|
|
- {
|
|
|
- let pointer = this.viewer.inputHandler.pointer
|
|
|
- let domElement = this.viewer.renderer.domElement;
|
|
|
- let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
|
|
|
- let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
|
|
|
-
|
|
|
- if (I) {
|
|
|
- let iOnLine = drag.line.closestPointToPoint(I, false, new THREE.Vector3());
|
|
|
- let direction = handle.alignment.reduce( (a, v) => a + v, 0);
|
|
|
-
|
|
|
- let toObjectSpace = this.selection[0].matrixWorld.clone().invert();
|
|
|
- let iOnLineOS = iOnLine.clone().applyMatrix4(toObjectSpace);
|
|
|
- let pivotOS = drag.pivot.clone().applyMatrix4(toObjectSpace);
|
|
|
- let diffOS = new THREE.Vector3().subVectors(iOnLineOS, pivotOS);
|
|
|
- let dragDirectionOS = diffOS.clone().normalize();
|
|
|
- if(iOnLine.distanceTo(drag.pivot) === 0){
|
|
|
- dragDirectionOS.set(0, 0, 0);
|
|
|
- }
|
|
|
- let dragDirection = dragDirectionOS.dot(new THREE.Vector3(...handle.alignment));
|
|
|
-
|
|
|
- let diff = new THREE.Vector3().subVectors(iOnLine, drag.pivot);
|
|
|
- let diffScale = new THREE.Vector3(...handle.alignment).multiplyScalar(diff.length() * direction * dragDirection);
|
|
|
- let diffPosition = diff.clone().multiplyScalar(0.5);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- for (let selection of this.selection) {
|
|
|
- //xzw 改:否则不跟手
|
|
|
- let diffScale_ = diffScale.clone().divide(selection.boundingBox.getSize(new THREE.Vector3))
|
|
|
- selection.scale.add(diffScale_);
|
|
|
- //selection.scale.add(diffScale);
|
|
|
- selection.scale.x = Math.max(0.1, selection.scale.x);
|
|
|
- selection.scale.y = Math.max(0.1, selection.scale.y);
|
|
|
- selection.scale.z = Math.max(0.1, selection.scale.z);
|
|
|
- selection.position.add(diffPosition);
|
|
|
-
|
|
|
-
|
|
|
- selection.dispatchEvent({
|
|
|
- type: "position_changed",
|
|
|
- object: selection
|
|
|
- });
|
|
|
- selection.dispatchEvent({
|
|
|
- type: "scale_changed",
|
|
|
- object: selection
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- drag.pivot.copy(iOnLine);
|
|
|
- //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- setActiveHandle(handle){
|
|
|
- if(this.dragging){
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if(this.activeHandle === handle){
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this.activeHandle = handle;
|
|
|
-
|
|
|
- if(handle === null){
|
|
|
- for(let handleName of Object.keys(this.handles)){
|
|
|
- let handle = this.handles[handleName];
|
|
|
- handle.node.setOpacity(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(!hideFocusHandles){
|
|
|
- for(let handleName of Object.keys(this.focusHandles)){
|
|
|
- let handle = this.focusHandles[handleName];
|
|
|
-
|
|
|
- if(this.activeHandle === handle){
|
|
|
- handle.node.setOpacity(1.0);
|
|
|
- }else{
|
|
|
- handle.node.setOpacity(OpaWhenNotSelect)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.translationHandles)){
|
|
|
- let handle = this.translationHandles[handleName];
|
|
|
-
|
|
|
- if(this.activeHandle === handle){
|
|
|
- handle.node.setOpacity(1.0);
|
|
|
- }else{
|
|
|
- handle.node.setOpacity(OpaWhenNotSelect)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.rotationHandles)){
|
|
|
- let handle = this.rotationHandles[handleName];
|
|
|
-
|
|
|
- //if(this.activeHandle === handle){
|
|
|
- // handle.node.setOpacity(1.0);
|
|
|
- //}else{
|
|
|
- // handle.node.setOpacity(OpaWhenNotSelect)
|
|
|
- //}
|
|
|
-
|
|
|
- handle.node.setOpacity(OpaWhenNotSelect);
|
|
|
- }
|
|
|
-
|
|
|
- for(let handleName of Object.keys(this.scaleHandles)){
|
|
|
- let handle = this.scaleHandles[handleName];
|
|
|
-
|
|
|
- if(this.activeHandle === handle){
|
|
|
- handle.node.setOpacity(1.0);
|
|
|
- if(!hideFocusHandles){
|
|
|
- let relatedFocusHandle = this.focusHandles[handle.name.replace("scale", "focus")];
|
|
|
- let relatedFocusNode = relatedFocusHandle.node;
|
|
|
- relatedFocusNode.setOpacity(OpaWhenNotSelect);
|
|
|
- }
|
|
|
- for(let translationHandleName of Object.keys(this.translationHandles)){
|
|
|
- let translationHandle = this.translationHandles[translationHandleName];
|
|
|
- translationHandle.node.setOpacity(OpaWhenNotSelect);
|
|
|
- }
|
|
|
-
|
|
|
- //let relatedTranslationHandle = this.translationHandles[
|
|
|
- // handle.name.replace("scale", "translation").replace(/[+-]/g, "")];
|
|
|
- //let relatedTranslationNode = relatedTranslationHandle.node;
|
|
|
- //relatedTranslationNode.setOpacity(OpaWhenNotSelect);
|
|
|
-
|
|
|
-
|
|
|
- }else{
|
|
|
- handle.node.setOpacity(OpaWhenNotSelect)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(handle){
|
|
|
- handle.node.setOpacity(1.0);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- update () {
|
|
|
-
|
|
|
- if(this.selection.length === 1){
|
|
|
- this.scene.visible = true;
|
|
|
-
|
|
|
- this.scene.updateMatrix();
|
|
|
- this.scene.updateMatrixWorld();
|
|
|
-
|
|
|
- let selected = this.selection[0];
|
|
|
- let world = selected.matrixWorld;
|
|
|
- let camera = this.viewer.scene.getActiveCamera();
|
|
|
- let domElement = this.viewer.renderer.domElement;
|
|
|
- let pointer = this.viewer.inputHandler.pointer;
|
|
|
-
|
|
|
- let center = selected.boundingBox.getCenter(new THREE.Vector3()).clone().applyMatrix4(selected.matrixWorld);
|
|
|
-
|
|
|
- this.scene.scale.copy(selected.boundingBox.getSize(new THREE.Vector3()).multiply(selected.scale));
|
|
|
- this.scene.position.copy(center);
|
|
|
- this.scene.rotation.copy(selected.rotation);
|
|
|
-
|
|
|
- this.scene.updateMatrixWorld();
|
|
|
-
|
|
|
- {
|
|
|
- // adjust rotation handles
|
|
|
- if(!this.dragging){
|
|
|
- let tWorld = this.scene.matrixWorld;
|
|
|
- let tObject = tWorld.clone().invert();
|
|
|
- let camObjectPos = camera.getWorldPosition(new THREE.Vector3()).applyMatrix4(tObject);
|
|
|
-
|
|
|
- let x = this.rotationHandles["rotation.x"].node.rotation;
|
|
|
- let y = this.rotationHandles["rotation.y"].node.rotation;
|
|
|
- let z = this.rotationHandles["rotation.z"].node.rotation;
|
|
|
-
|
|
|
- x.order = "ZYX";
|
|
|
- y.order = "ZYX";
|
|
|
-
|
|
|
- let above = camObjectPos.z > 0;
|
|
|
- let below = !above;
|
|
|
- let PI_HALF = Math.PI / 2;
|
|
|
-
|
|
|
- if(above){
|
|
|
- if(camObjectPos.x > 0 && camObjectPos.y > 0){
|
|
|
- x.x = 1 * PI_HALF;
|
|
|
- y.y = 3 * PI_HALF;
|
|
|
- z.z = 0 * PI_HALF;
|
|
|
- }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
|
|
|
- x.x = 1 * PI_HALF;
|
|
|
- y.y = 2 * PI_HALF;
|
|
|
- z.z = 1 * PI_HALF;
|
|
|
- }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
|
|
|
- x.x = 2 * PI_HALF;
|
|
|
- y.y = 2 * PI_HALF;
|
|
|
- z.z = 2 * PI_HALF;
|
|
|
- }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
|
|
|
- x.x = 2 * PI_HALF;
|
|
|
- y.y = 3 * PI_HALF;
|
|
|
- z.z = 3 * PI_HALF;
|
|
|
- }
|
|
|
- }else if(below){
|
|
|
- if(camObjectPos.x > 0 && camObjectPos.y > 0){
|
|
|
- x.x = 0 * PI_HALF;
|
|
|
- y.y = 0 * PI_HALF;
|
|
|
- z.z = 0 * PI_HALF;
|
|
|
- }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
|
|
|
- x.x = 0 * PI_HALF;
|
|
|
- y.y = 1 * PI_HALF;
|
|
|
- z.z = 1 * PI_HALF;
|
|
|
- }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
|
|
|
- x.x = 3 * PI_HALF;
|
|
|
- y.y = 1 * PI_HALF;
|
|
|
- z.z = 2 * PI_HALF;
|
|
|
- }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
|
|
|
- x.x = 3 * PI_HALF;
|
|
|
- y.y = 0 * PI_HALF;
|
|
|
- z.z = 3 * PI_HALF;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // adjust scale of components
|
|
|
- for(let handleName of Object.keys(this.handles)){
|
|
|
- let handle = this.handles[handleName];
|
|
|
- let node = handle.node;
|
|
|
-
|
|
|
- let handlePos = node.getWorldPosition(new THREE.Vector3());
|
|
|
- let distance = handlePos.distanceTo(camera.position);
|
|
|
- let pr = Utils.projectedRadius(1, camera, distance, domElement.clientWidth, domElement.clientHeight);
|
|
|
-
|
|
|
- let ws = node.parent.getWorldScale(new THREE.Vector3());
|
|
|
-
|
|
|
- let s = (ScaleRatio / pr);
|
|
|
- let scale = new THREE.Vector3(s, s, s).divide(ws);
|
|
|
-
|
|
|
- let rot = new THREE.Matrix4().makeRotationFromEuler(node.rotation); //需要使用到旋转,所以我把设置scale的移到旋转后了,否则在视图上下旋转的分界线处rotateHandel会被拉长从而闪烁。
|
|
|
- let rotInv = rot.clone().invert();
|
|
|
-
|
|
|
- scale.applyMatrix4(rotInv);
|
|
|
- scale.x = Math.abs(scale.x);
|
|
|
- scale.y = Math.abs(scale.y);
|
|
|
- scale.z = Math.abs(scale.z);
|
|
|
-
|
|
|
- node.scale.copy(scale);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- {
|
|
|
- let ray = Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
|
|
|
- let raycaster = new THREE.Raycaster(ray.origin, ray.direction);
|
|
|
- raycaster.layers.enableAll()//add
|
|
|
-
|
|
|
- let intersects = raycaster.intersectObjects(this.pickVolumes.filter(v => v.visible), true);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(intersects.length > 0){
|
|
|
- let I = intersects[0];
|
|
|
- let handleName = I.object.handle;
|
|
|
- this.setActiveHandle(this.handles[handleName]);
|
|
|
- }else{
|
|
|
- this.setActiveHandle(null);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //
|
|
|
- for(let handleName of Object.keys(this.scaleHandles)){
|
|
|
- let handle = this.handles[handleName];
|
|
|
- let node = handle.node;
|
|
|
- let alignment = handle.alignment;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }else{
|
|
|
- this.scene.visible = false;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-};
|