VolumeNew.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import {TextSprite} from "../TextSprite.js";
  3. import DepthBasicMaterial from "../custom/materials/DepthBasicMaterial.js";
  4. import {LineDraw} from "../custom/utils/DrawUtil.js";
  5. const boxOpacity = {
  6. hovered : 0.1,
  7. selected : 0.2
  8. }
  9. const LineOpacity = {
  10. default : 0.6,
  11. selected: 1,
  12. }
  13. const colors = {
  14. 2: 0x2ee4ce,//0x00ff80, //可见
  15. 3: 0xffc23b,//0xff3158, //不可见
  16. 4: 0xffffff, //
  17. }
  18. export class Volume extends THREE.Object3D {
  19. constructor (args = {}) {
  20. super();
  21. if(this.constructor.name === "Volume"){
  22. console.warn("Can't create object of class Volume directly. Use classes BoxVolume or SphereVolume instead.");
  23. }
  24. this._clip = args.clip || false;
  25. this._visible = true;
  26. //this.showVolumeLabel = true;
  27. this._modifiable = args.modifiable || true;
  28. { // event listeners
  29. this.addEventListener('select', e => {
  30. //console.log('select')
  31. this.setSelected(true)
  32. });
  33. this.addEventListener('deselect', e => {
  34. //console.log('deselect')
  35. this.setSelected(false)
  36. });
  37. this.addEventListener('mouseover', e => {
  38. this.hovered = true
  39. this.update()
  40. })
  41. this.addEventListener('mouseleave', e => {
  42. this.hovered = false
  43. this.update()
  44. });
  45. }
  46. }
  47. setSelected(state){//add
  48. this.selected = !!state
  49. this.update()
  50. }
  51. get visible(){
  52. return this._visible;
  53. }
  54. set visible(value){
  55. if(this._visible !== value){
  56. this._visible = value;
  57. this.dispatchEvent({type: "visibility_changed", object: this});
  58. }
  59. }
  60. getVolume () {
  61. console.warn("override this in subclass");
  62. }
  63. update () {
  64. };
  65. raycast (raycaster, intersects) {
  66. }
  67. get clip () {
  68. return this._clip;
  69. }
  70. set clip (value) {
  71. if(this._clip !== value){
  72. this._clip = value;
  73. this.update();
  74. this.dispatchEvent({
  75. type: "clip_changed",
  76. object: this
  77. });
  78. }
  79. }
  80. get modifieable () {
  81. return this._modifiable;
  82. }
  83. set modifieable (value) {
  84. this._modifiable = value;
  85. this.update();
  86. }
  87. };
  88. export class BoxVolume extends Volume{
  89. constructor(args = {}){
  90. super(args);
  91. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  92. this.name = 'box_' + this.constructor.counter;
  93. this.clipTask = args.clipTask || Potree.ClipTask.SHOW_INSIDE //add
  94. this.showBox = true
  95. let boxGeometry = new THREE.BoxGeometry(1, 1, 1);
  96. boxGeometry.computeBoundingBox();
  97. let boxFrameGeometry = new THREE.Geometry();
  98. let Vector3 = THREE.Vector3;
  99. {
  100. boxFrameGeometry.vertices.push(
  101. // bottom
  102. new Vector3(-0.5, -0.5, 0.5),
  103. new Vector3(0.5, -0.5, 0.5),
  104. new Vector3(0.5, -0.5, 0.5),
  105. new Vector3(0.5, -0.5, -0.5),
  106. new Vector3(0.5, -0.5, -0.5),
  107. new Vector3(-0.5, -0.5, -0.5),
  108. new Vector3(-0.5, -0.5, -0.5),
  109. new Vector3(-0.5, -0.5, 0.5),
  110. // top
  111. new Vector3(-0.5, 0.5, 0.5),
  112. new Vector3(0.5, 0.5, 0.5),
  113. new Vector3(0.5, 0.5, 0.5),
  114. new Vector3(0.5, 0.5, -0.5),
  115. new Vector3(0.5, 0.5, -0.5),
  116. new Vector3(-0.5, 0.5, -0.5),
  117. new Vector3(-0.5, 0.5, -0.5),
  118. new Vector3(-0.5, 0.5, 0.5),
  119. // sides
  120. new Vector3(-0.5, -0.5, 0.5),
  121. new Vector3(-0.5, 0.5, 0.5),
  122. new Vector3(0.5, -0.5, 0.5),
  123. new Vector3(0.5, 0.5, 0.5),
  124. new Vector3(0.5, -0.5, -0.5),
  125. new Vector3(0.5, 0.5, -0.5),
  126. new Vector3(-0.5, -0.5, -0.5),
  127. new Vector3(-0.5, 0.5, -0.5),
  128. );
  129. }
  130. this.material = new DepthBasicMaterial({
  131. color: colors[this.clipTask],
  132. side:THREE.DoubleSide,
  133. transparent: true,
  134. opacity: boxOpacity.hovered,
  135. depthTest: true,
  136. depthWrite: false,
  137. useDepth:true,
  138. clipDistance : 2,//消失距离
  139. occlusionDistance: 0.1,//变为backColor距离
  140. maxClipFactor: 0.9,
  141. });
  142. this.box = new THREE.Mesh(boxGeometry, this.material);
  143. this.box.geometry.computeBoundingBox();
  144. this.boundingBox = this.box.geometry.boundingBox;
  145. this.add(this.box);
  146. //this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: colors[this.clipTask], opacity:LineOpacity.default/* 0xff2050 */}));
  147. this.frame = LineDraw.createFatLine(
  148. boxFrameGeometry.vertices,
  149. { color: colors[this.clipTask], opacity:LineOpacity.default, lineWidth:1, dontAlwaysSeen:true} )
  150. // this.frame.mode = THREE.Lines;
  151. this.add(this.frame);
  152. this.update();
  153. }
  154. update(){
  155. this.boundingBox = this.box.geometry.boundingBox;
  156. this.boundingSphere = this.boundingBox.getBoundingSphere(new THREE.Sphere());
  157. Potree.Utils.updateVisible(this.box, 'selected', (this.selected || this.hovered) && this.showBox)
  158. this.box.material.opacity = this.selected ? boxOpacity.selected : boxOpacity.hovered
  159. this.box.material.color.set(colors[this.clipTask])
  160. this.frame.material.color.set(colors[this.clipTask])
  161. this.frame.material.opacity = this.selected ? LineOpacity.selected : LineOpacity.default
  162. this.frame.material.lineWidth = this.selected ? 2 : 1
  163. }
  164. raycast (raycaster, intersects) {
  165. let is = [];
  166. this.box.raycast(raycaster, is);
  167. if (is.length > 0) {
  168. let I = is[0];
  169. intersects.push({
  170. distance: I.distance,
  171. object: this,
  172. point: I.point.clone()
  173. });
  174. }
  175. }
  176. getVolume(){
  177. return Math.abs(this.scale.x * this.scale.y * this.scale.z);
  178. }
  179. };
  180. export class SphereVolume extends Volume{
  181. constructor(args = {}){
  182. super(args);
  183. this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
  184. this.name = 'sphere_' + this.constructor.counter;
  185. let sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
  186. sphereGeometry.computeBoundingBox();
  187. this.material = new THREE.MeshBasicMaterial({
  188. color: 0x00ff00,
  189. transparent: true,
  190. opacity: 0.3,
  191. depthTest: true,
  192. depthWrite: false});
  193. this.sphere = new THREE.Mesh(sphereGeometry, this.material);
  194. this.sphere.visible = false;
  195. this.sphere.geometry.computeBoundingBox();
  196. this.boundingBox = this.sphere.geometry.boundingBox;
  197. this.add(this.sphere);
  198. this.label.visible = false;
  199. let frameGeometry = new THREE.Geometry();
  200. {
  201. let steps = 64;
  202. let uSegments = 8;
  203. let vSegments = 5;
  204. let r = 1;
  205. for(let uSegment = 0; uSegment < uSegments; uSegment++){
  206. let alpha = (uSegment / uSegments) * Math.PI * 2;
  207. let dirx = Math.cos(alpha);
  208. let diry = Math.sin(alpha);
  209. for(let i = 0; i <= steps; i++){
  210. let v = (i / steps) * Math.PI * 2;
  211. let vNext = v + 2 * Math.PI / steps;
  212. let height = Math.sin(v);
  213. let xyAmount = Math.cos(v);
  214. let heightNext = Math.sin(vNext);
  215. let xyAmountNext = Math.cos(vNext);
  216. let vertex = new THREE.Vector3(dirx * xyAmount, diry * xyAmount, height);
  217. frameGeometry.vertices.push(vertex);
  218. let vertexNext = new THREE.Vector3(dirx * xyAmountNext, diry * xyAmountNext, heightNext);
  219. frameGeometry.vertices.push(vertexNext);
  220. }
  221. }
  222. // creates rings at poles, just because it's easier to implement
  223. for(let vSegment = 0; vSegment <= vSegments + 1; vSegment++){
  224. //let height = (vSegment / (vSegments + 1)) * 2 - 1; // -1 to 1
  225. let uh = (vSegment / (vSegments + 1)); // -1 to 1
  226. uh = (1 - uh) * (-Math.PI / 2) + uh *(Math.PI / 2);
  227. let height = Math.sin(uh);
  228. console.log(uh, height);
  229. for(let i = 0; i <= steps; i++){
  230. let u = (i / steps) * Math.PI * 2;
  231. let uNext = u + 2 * Math.PI / steps;
  232. let dirx = Math.cos(u);
  233. let diry = Math.sin(u);
  234. let dirxNext = Math.cos(uNext);
  235. let diryNext = Math.sin(uNext);
  236. let xyAmount = Math.sqrt(1 - height * height);
  237. let vertex = new THREE.Vector3(dirx * xyAmount, diry * xyAmount, height);
  238. frameGeometry.vertices.push(vertex);
  239. let vertexNext = new THREE.Vector3(dirxNext * xyAmount, diryNext * xyAmount, height);
  240. frameGeometry.vertices.push(vertexNext);
  241. }
  242. }
  243. }
  244. this.frame = new THREE.LineSegments(frameGeometry, new THREE.LineBasicMaterial({color: 0x000000}));
  245. this.add(this.frame);
  246. let frameMaterial = new THREE.MeshBasicMaterial({wireframe: true, color: 0x000000});
  247. this.frame = new THREE.Mesh(sphereGeometry, frameMaterial);
  248. //this.add(this.frame);
  249. //this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: 0x000000}));
  250. // this.frame.mode = THREE.Lines;
  251. //this.add(this.frame);
  252. this.update();
  253. }
  254. update(){
  255. this.boundingBox = this.sphere.geometry.boundingBox;
  256. this.boundingSphere = this.boundingBox.getBoundingSphere(new THREE.Sphere());
  257. //if (this._clip) {
  258. // this.sphere.visible = false;
  259. // this.label.visible = false;
  260. //} else {
  261. // this.sphere.visible = true;
  262. // this.label.visible = this.showVolumeLabel;
  263. //}
  264. }
  265. raycast (raycaster, intersects) {
  266. let is = [];
  267. this.sphere.raycast(raycaster, is);
  268. if (is.length > 0) {
  269. let I = is[0];
  270. intersects.push({
  271. distance: I.distance,
  272. object: this,
  273. point: I.point.clone()
  274. });
  275. }
  276. }
  277. // see https://en.wikipedia.org/wiki/Ellipsoid#Volume
  278. getVolume(){
  279. return (4 / 3) * Math.PI * this.scale.x * this.scale.y * this.scale.z;
  280. }
  281. };