TransformationTool.js 29 KB

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