TransformationTool.js 30 KB

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