TransformationTool.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {Utils} from "../utils.js";
  3. export class TransformationTool {//old
  4. constructor(viewer) {
  5. this.viewer = viewer;
  6. this.scene = new THREE.Scene();
  7. this.selection = [];
  8. this.pivot = new THREE.Vector3();
  9. this.dragging = false;
  10. this.showPickVolumes = false;
  11. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  12. this.viewer.inputHandler.addEventListener('selection_changed', (e) => {
  13. for(let selected of this.selection){
  14. this.viewer.inputHandler.blacklist.delete(selected);
  15. }
  16. this.selection = e.selection;
  17. for(let selected of this.selection){
  18. this.viewer.inputHandler.blacklist.add(selected);
  19. }
  20. });
  21. let red = 0xE73100;
  22. let green = 0x44A24A;
  23. let blue = 0x2669E7;
  24. this.activeHandle = null;
  25. this.scaleHandles = {
  26. "scale.x+": {name: "scale.x+", node: new THREE.Object3D(), color: red, alignment: [+1, +0, +0]},
  27. "scale.x-": {name: "scale.x-", node: new THREE.Object3D(), color: red, alignment: [-1, +0, +0]},
  28. "scale.y+": {name: "scale.y+", node: new THREE.Object3D(), color: green, alignment: [+0, +1, +0]},
  29. "scale.y-": {name: "scale.y-", node: new THREE.Object3D(), color: green, alignment: [+0, -1, +0]},
  30. "scale.z+": {name: "scale.z+", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, +1]},
  31. "scale.z-": {name: "scale.z-", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, -1]},
  32. };
  33. this.focusHandles = {
  34. "focus.x+": {name: "focus.x+", node: new THREE.Object3D(), color: red, alignment: [+1, +0, +0]},
  35. "focus.x-": {name: "focus.x-", node: new THREE.Object3D(), color: red, alignment: [-1, +0, +0]},
  36. "focus.y+": {name: "focus.y+", node: new THREE.Object3D(), color: green, alignment: [+0, +1, +0]},
  37. "focus.y-": {name: "focus.y-", node: new THREE.Object3D(), color: green, alignment: [+0, -1, +0]},
  38. "focus.z+": {name: "focus.z+", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, +1]},
  39. "focus.z-": {name: "focus.z-", node: new THREE.Object3D(), color: blue, alignment: [+0, +0, -1]},
  40. };
  41. this.translationHandles = {
  42. "translation.x": {name: "translation.x", node: new THREE.Object3D(), color: red, alignment: [1, 0, 0]},
  43. "translation.y": {name: "translation.y", node: new THREE.Object3D(), color: green, alignment: [0, 1, 0]},
  44. "translation.z": {name: "translation.z", node: new THREE.Object3D(), color: blue, alignment: [0, 0, 1]},
  45. };
  46. this.rotationHandles = {
  47. "rotation.x": {name: "rotation.x", node: new THREE.Object3D(), color: red, alignment: [1, 0, 0]},
  48. "rotation.y": {name: "rotation.y", node: new THREE.Object3D(), color: green, alignment: [0, 1, 0]},
  49. "rotation.z": {name: "rotation.z", node: new THREE.Object3D(), color: blue, alignment: [0, 0, 1]},
  50. };
  51. this.handles = Object.assign({}, this.scaleHandles, this.focusHandles, this.translationHandles, this.rotationHandles);
  52. this.pickVolumes = [];
  53. this.initializeScaleHandles();
  54. this.initializeFocusHandles();
  55. this.initializeTranslationHandles();
  56. this.initializeRotationHandles();
  57. let boxFrameGeometry = new THREE.Geometry();
  58. {
  59. // bottom
  60. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
  61. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
  62. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
  63. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
  64. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
  65. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
  66. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
  67. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
  68. // top
  69. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
  70. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
  71. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
  72. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
  73. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
  74. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
  75. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
  76. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
  77. // sides
  78. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, 0.5));
  79. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, 0.5));
  80. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, 0.5));
  81. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, 0.5));
  82. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, -0.5, -0.5));
  83. boxFrameGeometry.vertices.push(new THREE.Vector3(0.5, 0.5, -0.5));
  84. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, -0.5, -0.5));
  85. boxFrameGeometry.vertices.push(new THREE.Vector3(-0.5, 0.5, -0.5));
  86. }
  87. this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: 0xffff00}));
  88. this.scene.add(this.frame);
  89. }
  90. initializeScaleHandles(){
  91. let sgSphere = new THREE.SphereGeometry(1, 32, 32);
  92. let sgLowPolySphere = new THREE.SphereGeometry(1, 16, 16);
  93. for(let handleName of Object.keys(this.scaleHandles)){
  94. let handle = this.scaleHandles[handleName];
  95. let node = handle.node;
  96. this.scene.add(node);
  97. node.position.set(...handle.alignment).multiplyScalar(0.5);
  98. let material = new THREE.MeshBasicMaterial({
  99. color: handle.color,
  100. opacity: 0.4,
  101. transparent: true
  102. });
  103. let outlineMaterial = new THREE.MeshBasicMaterial({
  104. color: 0x000000,
  105. side: THREE.BackSide,
  106. opacity: 0.4,
  107. transparent: true});
  108. let pickMaterial = new THREE.MeshNormalMaterial({
  109. opacity: 0.2,
  110. transparent: true,
  111. visible: this.showPickVolumes});
  112. let sphere = new THREE.Mesh(sgSphere, material);
  113. sphere.scale.set(1.3, 1.3, 1.3);
  114. sphere.name = `${handleName}.handle`;
  115. node.add(sphere);
  116. let outline = new THREE.Mesh(sgSphere, outlineMaterial);
  117. outline.scale.set(1.4, 1.4, 1.4);
  118. outline.name = `${handleName}.outline`;
  119. sphere.add(outline);
  120. let pickSphere = new THREE.Mesh(sgLowPolySphere, pickMaterial);
  121. pickSphere.name = `${handleName}.pick_volume`;
  122. pickSphere.scale.set(3, 3, 3);
  123. sphere.add(pickSphere);
  124. pickSphere.handle = handleName;
  125. this.pickVolumes.push(pickSphere);
  126. node.setOpacity = (target) => {
  127. let opacity = {x: material.opacity};
  128. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  129. t.onUpdate(() => {
  130. sphere.visible = opacity.x > 0;
  131. pickSphere.visible = opacity.x > 0;
  132. material.opacity = opacity.x;
  133. outlineMaterial.opacity = opacity.x;
  134. pickSphere.material.opacity = opacity.x * 0.5;
  135. });
  136. t.start();
  137. };
  138. pickSphere.addEventListener("drag", (e) => this.dragScaleHandle(e));
  139. pickSphere.addEventListener("drop", (e) => this.dropScaleHandle(e));
  140. pickSphere.addEventListener("mouseover", e => {
  141. //node.setOpacity(1);
  142. });
  143. pickSphere.addEventListener("click", e => {
  144. e.consume();
  145. });
  146. pickSphere.addEventListener("mouseleave", e => {
  147. //node.setOpacity(0.4);
  148. });
  149. }
  150. }
  151. initializeFocusHandles(){
  152. //let sgBox = new THREE.BoxGeometry(1, 1, 1);
  153. let sgPlane = new THREE.PlaneGeometry(4, 4, 1, 1);
  154. let sgLowPolySphere = new THREE.SphereGeometry(1, 16, 16);
  155. let texture = new THREE.TextureLoader().load(`${exports.resourcePath}/icons/eye_2.png`);
  156. for(let handleName of Object.keys(this.focusHandles)){
  157. let handle = this.focusHandles[handleName];
  158. let node = handle.node;
  159. this.scene.add(node);
  160. let align = handle.alignment;
  161. //node.lookAt(new THREE.Vector3().addVectors(node.position, new THREE.Vector3(...align)));
  162. node.lookAt(new THREE.Vector3(...align));
  163. let off = 0.8;
  164. if(align[0] === 1){
  165. node.position.set(1, off, -off).multiplyScalar(0.5);
  166. node.rotation.z = Math.PI / 2;
  167. }else if(align[0] === -1){
  168. node.position.set(-1, -off, -off).multiplyScalar(0.5);
  169. node.rotation.z = Math.PI / 2;
  170. }else if(align[1] === 1){
  171. node.position.set(-off, 1, -off).multiplyScalar(0.5);
  172. node.rotation.set(Math.PI / 2, Math.PI, 0.0);
  173. }else if(align[1] === -1){
  174. node.position.set(off, -1, -off).multiplyScalar(0.5);
  175. node.rotation.set(Math.PI / 2, 0.0, 0.0);
  176. }else if(align[2] === 1){
  177. node.position.set(off, off, 1).multiplyScalar(0.5);
  178. }else if(align[2] === -1){
  179. node.position.set(-off, off, -1).multiplyScalar(0.5);
  180. }
  181. let material = new THREE.MeshBasicMaterial({
  182. color: handle.color,
  183. opacity: 0,
  184. transparent: true,
  185. map: texture
  186. });
  187. //let outlineMaterial = new THREE.MeshBasicMaterial({
  188. // color: 0x000000,
  189. // side: THREE.BackSide,
  190. // opacity: 0,
  191. // transparent: true});
  192. let pickMaterial = new THREE.MeshNormalMaterial({
  193. //opacity: 0,
  194. transparent: true,
  195. visible: this.showPickVolumes});
  196. let box = new THREE.Mesh(sgPlane, material);
  197. box.name = `${handleName}.handle`;
  198. box.scale.set(1.5, 1.5, 1.5);
  199. box.position.set(0, 0, 0);
  200. box.visible = false;
  201. node.add(box);
  202. //handle.focusNode = box;
  203. //let outline = new THREE.Mesh(sgPlane, outlineMaterial);
  204. //outline.scale.set(1.4, 1.4, 1.4);
  205. //outline.name = `${handleName}.outline`;
  206. //box.add(outline);
  207. let pickSphere = new THREE.Mesh(sgLowPolySphere, pickMaterial);
  208. pickSphere.name = `${handleName}.pick_volume`;
  209. pickSphere.scale.set(3, 3, 3);
  210. box.add(pickSphere);
  211. pickSphere.handle = handleName;
  212. this.pickVolumes.push(pickSphere);
  213. node.setOpacity = (target) => {
  214. let opacity = {x: material.opacity};
  215. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  216. t.onUpdate(() => {
  217. pickSphere.visible = opacity.x > 0;
  218. box.visible = opacity.x > 0;
  219. material.opacity = opacity.x;
  220. //outlineMaterial.opacity = opacity.x;
  221. pickSphere.material.opacity = opacity.x * 0.5;
  222. });
  223. t.start();
  224. };
  225. pickSphere.addEventListener("drag", e => {});
  226. pickSphere.addEventListener("mouseup", e => {
  227. e.consume();
  228. });
  229. pickSphere.addEventListener("mousedown", e => {
  230. e.consume();
  231. });
  232. pickSphere.addEventListener("click", e => {
  233. e.consume();
  234. let selected = this.selection[0];
  235. let maxScale = Math.max(...selected.scale.toArray());
  236. let minScale = Math.min(...selected.scale.toArray());
  237. let handleLength = Math.abs(selected.scale.dot(new THREE.Vector3(...handle.alignment)));
  238. let alignment = new THREE.Vector3(...handle.alignment).multiplyScalar(2 * maxScale / handleLength);
  239. alignment.applyMatrix4(selected.matrixWorld);
  240. let newCamPos = alignment;
  241. let newCamTarget = selected.getWorldPosition(new THREE.Vector3());
  242. Utils.moveTo(this.viewer.scene, newCamPos, newCamTarget);
  243. });
  244. pickSphere.addEventListener("mouseover", e => {
  245. //box.setOpacity(1);
  246. });
  247. pickSphere.addEventListener("mouseleave", e => {
  248. //box.setOpacity(0.4);
  249. });
  250. }
  251. }
  252. initializeTranslationHandles(){
  253. let boxGeometry = new THREE.BoxGeometry(1, 1, 1);
  254. for(let handleName of Object.keys(this.translationHandles)){
  255. let handle = this.handles[handleName];
  256. let node = handle.node;
  257. this.scene.add(node);
  258. let material = new THREE.MeshBasicMaterial({
  259. color: handle.color,
  260. opacity: 0.4,
  261. transparent: true});
  262. let outlineMaterial = new THREE.MeshBasicMaterial({
  263. color: 0x000000,
  264. side: THREE.BackSide,
  265. opacity: 0.4,
  266. transparent: true});
  267. let pickMaterial = new THREE.MeshNormalMaterial({
  268. opacity: 0.2,
  269. transparent: true,
  270. visible: this.showPickVolumes
  271. });
  272. let box = new THREE.Mesh(boxGeometry, material);
  273. box.name = `${handleName}.handle`;
  274. box.scale.set(0.2, 0.2, 40);
  275. box.lookAt(new THREE.Vector3(...handle.alignment));
  276. box.renderOrder = 10;
  277. node.add(box);
  278. handle.translateNode = box;
  279. let outline = new THREE.Mesh(boxGeometry, outlineMaterial);
  280. outline.name = `${handleName}.outline`;
  281. outline.scale.set(3, 3, 1.03);
  282. outline.renderOrder = 0;
  283. box.add(outline);
  284. let pickVolume = new THREE.Mesh(boxGeometry, pickMaterial);
  285. pickVolume.name = `${handleName}.pick_volume`;
  286. pickVolume.scale.set(12, 12, 1.1);
  287. pickVolume.handle = handleName;
  288. box.add(pickVolume);
  289. this.pickVolumes.push(pickVolume);
  290. node.setOpacity = (target) => {
  291. let opacity = {x: material.opacity};
  292. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  293. t.onUpdate(() => {
  294. box.visible = opacity.x > 0;
  295. pickVolume.visible = opacity.x > 0;
  296. material.opacity = opacity.x;
  297. outlineMaterial.opacity = opacity.x;
  298. pickMaterial.opacity = opacity.x * 0.5;
  299. });
  300. t.start();
  301. };
  302. pickVolume.addEventListener("drag", (e) => {this.dragTranslationHandle(e)});
  303. pickVolume.addEventListener("drop", (e) => {this.dropTranslationHandle(e)});
  304. }
  305. }
  306. initializeRotationHandles(){
  307. let adjust = 0.5;
  308. let torusGeometry = new THREE.TorusGeometry(1, adjust * 0.015, 8, 64, Math.PI / 2);
  309. let outlineGeometry = new THREE.TorusGeometry(1, adjust * 0.04, 8, 64, Math.PI / 2);
  310. let pickGeometry = new THREE.TorusGeometry(1, adjust * 0.1, 6, 4, Math.PI / 2);
  311. for(let handleName of Object.keys(this.rotationHandles)){
  312. let handle = this.handles[handleName];
  313. let node = handle.node;
  314. this.scene.add(node);
  315. let material = new THREE.MeshBasicMaterial({
  316. color: handle.color,
  317. opacity: 0.4,
  318. transparent: true});
  319. let outlineMaterial = new THREE.MeshBasicMaterial({
  320. color: 0x000000,
  321. side: THREE.BackSide,
  322. opacity: 0.4,
  323. transparent: true});
  324. let pickMaterial = new THREE.MeshNormalMaterial({
  325. opacity: 0.2,
  326. transparent: true,
  327. visible: this.showPickVolumes
  328. });
  329. let box = new THREE.Mesh(torusGeometry, material);
  330. box.name = `${handleName}.handle`;
  331. box.scale.set(20, 20, 20);
  332. box.lookAt(new THREE.Vector3(...handle.alignment));
  333. node.add(box);
  334. handle.translateNode = box;
  335. let outline = new THREE.Mesh(outlineGeometry, outlineMaterial);
  336. outline.name = `${handleName}.outline`;
  337. outline.scale.set(1, 1, 1);
  338. outline.renderOrder = 0;
  339. box.add(outline);
  340. let pickVolume = new THREE.Mesh(pickGeometry, pickMaterial);
  341. pickVolume.name = `${handleName}.pick_volume`;
  342. pickVolume.scale.set(1, 1, 1);
  343. pickVolume.handle = handleName;
  344. box.add(pickVolume);
  345. this.pickVolumes.push(pickVolume);
  346. node.setOpacity = (target) => {
  347. let opacity = {x: material.opacity};
  348. let t = new TWEEN.Tween(opacity).to({x: target}, 100);
  349. t.onUpdate(() => {
  350. box.visible = opacity.x > 0;
  351. pickVolume.visible = opacity.x > 0;
  352. material.opacity = opacity.x;
  353. outlineMaterial.opacity = opacity.x;
  354. pickMaterial.opacity = opacity.x * 0.5;
  355. });
  356. t.start();
  357. };
  358. //pickVolume.addEventListener("mouseover", (e) => {
  359. // //let a = this.viewer.scene.getActiveCamera().getWorldDirection(new THREE.Vector3()).dot(pickVolume.getWorldDirection(new THREE.Vector3()));
  360. // console.log(pickVolume.getWorldDirection(new THREE.Vector3()));
  361. //});
  362. pickVolume.addEventListener("drag", (e) => {this.dragRotationHandle(e)});
  363. pickVolume.addEventListener("drop", (e) => {this.dropRotationHandle(e)});
  364. }
  365. }
  366. dragRotationHandle(e){
  367. let drag = e.drag;
  368. let handle = this.activeHandle;
  369. let camera = this.viewer.scene.getActiveCamera();
  370. if(!handle){
  371. return
  372. };
  373. let localNormal = new THREE.Vector3(...handle.alignment);
  374. let n = new THREE.Vector3();
  375. n.copy(new THREE.Vector4(...localNormal.toArray(), 0).applyMatrix4(handle.node.matrixWorld));
  376. n.normalize();
  377. if (!drag.intersectionStart){
  378. //this.viewer.scene.scene.remove(this.debug);
  379. //this.debug = new THREE.Object3D();
  380. //this.viewer.scene.scene.add(this.debug);
  381. //Utils.debugSphere(this.debug, drag.location, 3, 0xaaaaaa);
  382. //let debugEnd = drag.location.clone().add(n.clone().multiplyScalar(20));
  383. //Utils.debugLine(this.debug, drag.location, debugEnd, 0xff0000);
  384. drag.intersectionStart = drag.location;
  385. drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
  386. drag.handle = handle;
  387. let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(n, drag.intersectionStart);
  388. drag.dragPlane = plane;
  389. drag.pivot = drag.intersectionStart;
  390. }else{
  391. handle = drag.handle;
  392. }
  393. this.dragging = true;
  394. let mouse = drag.end;
  395. let domElement = this.viewer.renderer.domElement;
  396. let ray = Utils.mouseToRay(mouse, camera, domElement.clientWidth, domElement.clientHeight);
  397. let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
  398. if (I) {
  399. let center = this.scene.getWorldPosition(new THREE.Vector3());
  400. let from = drag.pivot;
  401. let to = I;
  402. let v1 = from.clone().sub(center).normalize();
  403. let v2 = to.clone().sub(center).normalize();
  404. let angle = Math.acos(v1.dot(v2));
  405. let sign = Math.sign(v1.cross(v2).dot(n));
  406. angle = angle * sign;
  407. if (Number.isNaN(angle)) {
  408. return;
  409. }
  410. let normal = new THREE.Vector3(...handle.alignment);
  411. for (let selection of this.selection) {
  412. selection.rotateOnAxis(normal, angle);
  413. selection.dispatchEvent({
  414. type: "orientation_changed",
  415. object: selection
  416. });
  417. }
  418. drag.pivot = I;
  419. }
  420. }
  421. dropRotationHandle(e){
  422. this.dragging = false;
  423. this.setActiveHandle(null);
  424. }
  425. dragTranslationHandle(e){
  426. let drag = e.drag;
  427. let handle = this.activeHandle;
  428. let camera = this.viewer.scene.getActiveCamera();
  429. if(!drag.intersectionStart && handle){
  430. drag.intersectionStart = drag.location;
  431. drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
  432. let start = drag.intersectionStart;
  433. let dir = new THREE.Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
  434. let end = new THREE.Vector3().addVectors(start, dir);
  435. let line = new THREE.Line3(start.clone(), end.clone());
  436. drag.line = line;
  437. let camOnLine = line.closestPointToPoint(camera.position, false, new THREE.Vector3());
  438. let normal = new THREE.Vector3().subVectors(camera.position, camOnLine);
  439. let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
  440. drag.dragPlane = plane;
  441. drag.pivot = drag.intersectionStart;
  442. }else{
  443. handle = drag.handle;
  444. }
  445. this.dragging = true;
  446. {
  447. let mouse = drag.end;
  448. let domElement = this.viewer.renderer.domElement;
  449. let ray = Utils.mouseToRay(mouse, camera, domElement.clientWidth, domElement.clientHeight);
  450. let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
  451. if (I) {
  452. let iOnLine = drag.line.closestPointToPoint(I, false, new THREE.Vector3());
  453. let diff = new THREE.Vector3().subVectors(iOnLine, drag.pivot);
  454. for (let selection of this.selection) {
  455. selection.position.add(diff);
  456. selection.dispatchEvent({
  457. type: "position_changed",
  458. object: selection
  459. });
  460. }
  461. drag.pivot = drag.pivot.add(diff);
  462. }
  463. }
  464. }
  465. dropTranslationHandle(e){
  466. this.dragging = false;
  467. this.setActiveHandle(null);
  468. }
  469. dropScaleHandle(e){
  470. this.dragging = false;
  471. this.setActiveHandle(null);
  472. }
  473. dragScaleHandle(e){
  474. let drag = e.drag;
  475. let handle = this.activeHandle;
  476. let camera = this.viewer.scene.getActiveCamera();
  477. if(!drag.intersectionStart){
  478. drag.intersectionStart = drag.location;
  479. drag.objectStart = drag.object.getWorldPosition(new THREE.Vector3());
  480. drag.handle = handle;
  481. let start = drag.intersectionStart;
  482. let dir = new THREE.Vector4(...handle.alignment, 0).applyMatrix4(this.scene.matrixWorld);
  483. let end = new THREE.Vector3().addVectors(start, dir);
  484. let line = new THREE.Line3(start.clone(), end.clone());
  485. drag.line = line;
  486. let camOnLine = line.closestPointToPoint(camera.position, false, new THREE.Vector3());
  487. let normal = new THREE.Vector3().subVectors(camera.position, camOnLine);
  488. let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, drag.intersectionStart);
  489. drag.dragPlane = plane;
  490. drag.pivot = drag.intersectionStart;
  491. //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
  492. }else{
  493. handle = drag.handle;
  494. }
  495. this.dragging = true;
  496. {
  497. let mouse = drag.end;
  498. let domElement = this.viewer.renderer.domElement;
  499. let ray = Utils.mouseToRay(mouse, camera, domElement.clientWidth, domElement.clientHeight);
  500. let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
  501. if (I) {
  502. let iOnLine = drag.line.closestPointToPoint(I, false, new THREE.Vector3());
  503. let direction = handle.alignment.reduce( (a, v) => a + v, 0);
  504. let toObjectSpace = this.selection[0].matrixWorld.clone().invert();
  505. let iOnLineOS = iOnLine.clone().applyMatrix4(toObjectSpace);
  506. let pivotOS = drag.pivot.clone().applyMatrix4(toObjectSpace);
  507. let diffOS = new THREE.Vector3().subVectors(iOnLineOS, pivotOS);
  508. let dragDirectionOS = diffOS.clone().normalize();
  509. if(iOnLine.distanceTo(drag.pivot) === 0){
  510. dragDirectionOS.set(0, 0, 0);
  511. }
  512. let dragDirection = dragDirectionOS.dot(new THREE.Vector3(...handle.alignment));
  513. let diff = new THREE.Vector3().subVectors(iOnLine, drag.pivot);
  514. let diffScale = new THREE.Vector3(...handle.alignment).multiplyScalar(diff.length() * direction * dragDirection);
  515. let diffPosition = diff.clone().multiplyScalar(0.5);
  516. for (let selection of this.selection) {
  517. selection.scale.add(diffScale);
  518. selection.scale.x = Math.max(0.1, selection.scale.x);
  519. selection.scale.y = Math.max(0.1, selection.scale.y);
  520. selection.scale.z = Math.max(0.1, selection.scale.z);
  521. selection.position.add(diffPosition);
  522. selection.dispatchEvent({
  523. type: "position_changed",
  524. object: selection
  525. });
  526. selection.dispatchEvent({
  527. type: "scale_changed",
  528. object: selection
  529. });
  530. }
  531. drag.pivot.copy(iOnLine);
  532. //Utils.debugSphere(viewer.scene.scene, drag.pivot, 0.05);
  533. }
  534. }
  535. }
  536. setActiveHandle(handle){
  537. if(this.dragging){
  538. return;
  539. }
  540. if(this.activeHandle === handle){
  541. return;
  542. }
  543. this.activeHandle = handle;
  544. if(handle === null){
  545. for(let handleName of Object.keys(this.handles)){
  546. let handle = this.handles[handleName];
  547. handle.node.setOpacity(0);
  548. }
  549. }
  550. for(let handleName of Object.keys(this.focusHandles)){
  551. let handle = this.focusHandles[handleName];
  552. if(this.activeHandle === handle){
  553. handle.node.setOpacity(1.0);
  554. }else{
  555. handle.node.setOpacity(0.4)
  556. }
  557. }
  558. for(let handleName of Object.keys(this.translationHandles)){
  559. let handle = this.translationHandles[handleName];
  560. if(this.activeHandle === handle){
  561. handle.node.setOpacity(1.0);
  562. }else{
  563. handle.node.setOpacity(0.4)
  564. }
  565. }
  566. for(let handleName of Object.keys(this.rotationHandles)){
  567. let handle = this.rotationHandles[handleName];
  568. //if(this.activeHandle === handle){
  569. // handle.node.setOpacity(1.0);
  570. //}else{
  571. // handle.node.setOpacity(0.4)
  572. //}
  573. handle.node.setOpacity(0.4);
  574. }
  575. for(let handleName of Object.keys(this.scaleHandles)){
  576. let handle = this.scaleHandles[handleName];
  577. if(this.activeHandle === handle){
  578. handle.node.setOpacity(1.0);
  579. let relatedFocusHandle = this.focusHandles[handle.name.replace("scale", "focus")];
  580. let relatedFocusNode = relatedFocusHandle.node;
  581. relatedFocusNode.setOpacity(0.4);
  582. for(let translationHandleName of Object.keys(this.translationHandles)){
  583. let translationHandle = this.translationHandles[translationHandleName];
  584. translationHandle.node.setOpacity(0.4);
  585. }
  586. //let relatedTranslationHandle = this.translationHandles[
  587. // handle.name.replace("scale", "translation").replace(/[+-]/g, "")];
  588. //let relatedTranslationNode = relatedTranslationHandle.node;
  589. //relatedTranslationNode.setOpacity(0.4);
  590. }else{
  591. handle.node.setOpacity(0.4)
  592. }
  593. }
  594. if(handle){
  595. handle.node.setOpacity(1.0);
  596. }
  597. }
  598. update () {
  599. if(this.selection.length === 1){
  600. this.scene.visible = true;
  601. this.scene.updateMatrix();
  602. this.scene.updateMatrixWorld();
  603. let selected = this.selection[0];
  604. let world = selected.matrixWorld;
  605. let camera = this.viewer.scene.getActiveCamera();
  606. let domElement = this.viewer.renderer.domElement;
  607. let mouse = this.viewer.inputHandler.mouse;
  608. let center = selected.boundingBox.getCenter(new THREE.Vector3()).clone().applyMatrix4(selected.matrixWorld);
  609. this.scene.scale.copy(selected.boundingBox.getSize(new THREE.Vector3()).multiply(selected.scale));
  610. this.scene.position.copy(center);
  611. this.scene.rotation.copy(selected.rotation);
  612. this.scene.updateMatrixWorld();
  613. {
  614. // adjust scale of components
  615. for(let handleName of Object.keys(this.handles)){
  616. let handle = this.handles[handleName];
  617. let node = handle.node;
  618. let handlePos = node.getWorldPosition(new THREE.Vector3());
  619. let distance = handlePos.distanceTo(camera.position);
  620. let pr = Utils.projectedRadius(1, camera, distance, domElement.clientWidth, domElement.clientHeight);
  621. let ws = node.parent.getWorldScale(new THREE.Vector3());
  622. let s = (7 / pr);
  623. let scale = new THREE.Vector3(s, s, s).divide(ws);
  624. let rot = new THREE.Matrix4().makeRotationFromEuler(node.rotation);
  625. let rotInv = rot.clone().invert();
  626. scale.applyMatrix4(rotInv);
  627. scale.x = Math.abs(scale.x);
  628. scale.y = Math.abs(scale.y);
  629. scale.z = Math.abs(scale.z);
  630. node.scale.copy(scale);
  631. }
  632. // adjust rotation handles
  633. if(!this.dragging){
  634. let tWorld = this.scene.matrixWorld;
  635. let tObject = tWorld.clone().invert();
  636. let camObjectPos = camera.getWorldPosition(new THREE.Vector3()).applyMatrix4(tObject);
  637. let x = this.rotationHandles["rotation.x"].node.rotation;
  638. let y = this.rotationHandles["rotation.y"].node.rotation;
  639. let z = this.rotationHandles["rotation.z"].node.rotation;
  640. x.order = "ZYX";
  641. y.order = "ZYX";
  642. let above = camObjectPos.z > 0;
  643. let below = !above;
  644. let PI_HALF = Math.PI / 2;
  645. if(above){
  646. if(camObjectPos.x > 0 && camObjectPos.y > 0){
  647. x.x = 1 * PI_HALF;
  648. y.y = 3 * PI_HALF;
  649. z.z = 0 * PI_HALF;
  650. }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
  651. x.x = 1 * PI_HALF;
  652. y.y = 2 * PI_HALF;
  653. z.z = 1 * PI_HALF;
  654. }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
  655. x.x = 2 * PI_HALF;
  656. y.y = 2 * PI_HALF;
  657. z.z = 2 * PI_HALF;
  658. }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
  659. x.x = 2 * PI_HALF;
  660. y.y = 3 * PI_HALF;
  661. z.z = 3 * PI_HALF;
  662. }
  663. }else if(below){
  664. if(camObjectPos.x > 0 && camObjectPos.y > 0){
  665. x.x = 0 * PI_HALF;
  666. y.y = 0 * PI_HALF;
  667. z.z = 0 * PI_HALF;
  668. }else if(camObjectPos.x < 0 && camObjectPos.y > 0){
  669. x.x = 0 * PI_HALF;
  670. y.y = 1 * PI_HALF;
  671. z.z = 1 * PI_HALF;
  672. }else if(camObjectPos.x < 0 && camObjectPos.y < 0){
  673. x.x = 3 * PI_HALF;
  674. y.y = 1 * PI_HALF;
  675. z.z = 2 * PI_HALF;
  676. }else if(camObjectPos.x > 0 && camObjectPos.y < 0){
  677. x.x = 3 * PI_HALF;
  678. y.y = 0 * PI_HALF;
  679. z.z = 3 * PI_HALF;
  680. }
  681. }
  682. }
  683. {
  684. let ray = Utils.mouseToRay(mouse, camera, domElement.clientWidth, domElement.clientHeight);
  685. let raycaster = new THREE.Raycaster(ray.origin, ray.direction);
  686. let intersects = raycaster.intersectObjects(this.pickVolumes.filter(v => v.visible), true);
  687. if(intersects.length > 0){
  688. let I = intersects[0];
  689. let handleName = I.object.handle;
  690. this.setActiveHandle(this.handles[handleName]);
  691. }else{
  692. this.setActiveHandle(null);
  693. }
  694. }
  695. //
  696. for(let handleName of Object.keys(this.scaleHandles)){
  697. let handle = this.handles[handleName];
  698. let node = handle.node;
  699. let alignment = handle.alignment;
  700. }
  701. }
  702. }else{
  703. this.scene.visible = false;
  704. }
  705. }
  706. };