Application.js 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520
  1. /**
  2. * Application.js
  3. *
  4. * @author realor
  5. */
  6. import { Panel, PanelManager } from '../ui/Panel.js'
  7. import { ProgressBar } from '../ui/ProgressBar.js'
  8. import { MenuBar } from '../ui/Menu.js'
  9. import { Tool } from '../tools/Tool.js'
  10. import { ToolBar } from '../ui/ToolBar.js'
  11. import { MessageDialog } from '../ui/MessageDialog.js'
  12. import { Cord } from '../core/Cord.js'
  13. import { Profile } from '../core/Profile.js'
  14. import { Solid } from '../core/Solid.js'
  15. import { Cloner } from '../builders/Cloner.js'
  16. import { ObjectBuilder } from '../builders/ObjectBuilder.js'
  17. import { SolidGeometry } from '../core/SolidGeometry.js'
  18. import { ServiceManager } from '../io/ServiceManager.js'
  19. import { IOManager } from '../io/IOManager.js'
  20. import { Selection } from '../utils/Selection.js'
  21. import { ObjectUtils } from '../utils/ObjectUtils.js'
  22. import { WebUtils } from '../utils/WebUtils.js'
  23. import { ModuleLoader } from '../utils/ModuleLoader.js'
  24. import { WEBGL } from '../utils/WebGL.js'
  25. import { PointSelector } from '../utils/PointSelector.js'
  26. import { LineDashedShaderMaterial } from '../materials/LineDashedShaderMaterial.js'
  27. import { Inspector } from '../ui/Inspector.js'
  28. import { FakeRenderer } from '../renderers/FakeRenderer.js'
  29. import { Formula } from '../formula/Formula.js'
  30. import { LoginDialog } from './LoginDialog.js'
  31. import { ScriptDialog } from './ScriptDialog.js'
  32. import { I18N } from '../i18n/I18N.js'
  33. import * as THREE from '../lib/three.module.js'
  34. import { transitions, easing, lerp } from '../utils/transitions.js'
  35. class Application {
  36. static NAME = 'BIMROCKET'
  37. static VERSION = '$VERSION$'
  38. static EDGES_SELECTION = 'edges'
  39. static FACES_SELECTION = 'faces'
  40. static UNITS = [
  41. ['km', 'units.km'],
  42. ['m', 'units.m'],
  43. ['cm', 'units.cm'],
  44. ['mm', 'units.mm'],
  45. ['in', 'units.in'],
  46. ]
  47. static SET_SELECTION_MODE = 'set'
  48. static ADD_SELECTION_MODE = 'add'
  49. static REMOVE_SELECTION_MODE = 'remove'
  50. constructor(element = document.body) {
  51. this.element = element
  52. this.i18n = new I18N()
  53. this.scene = null
  54. this.camera = null
  55. this.perspectiveCamera = null
  56. this.orthographicCamera = null
  57. this.baseObject = null
  58. this.clippingPlane = null
  59. this.clippingGroup = null
  60. this.overlays = null
  61. this.tools = {}
  62. this.tool = null
  63. this._units = null
  64. this._decimals = null
  65. this._backgroundColor1 = null
  66. this._backgroundColor2 = null
  67. this._panelOpacity = null
  68. this._frameRateDivisor = null
  69. this._shadowsEnabled = null
  70. /* services */
  71. this.services = {} // Service instances
  72. /* selection */
  73. this.selection = new Selection(this, true)
  74. this.selectionMode = Application.SET_SELECTION_MODE
  75. this.selectionPaintMode = Application.EDGES_SELECTION
  76. this._showDeepSelection = null
  77. this._showLocalAxes = null
  78. this._selectionLines = null
  79. this._axisLines = null
  80. this.clock = new THREE.Clock()
  81. this.autoRepaint = false
  82. this.needsRepaint = true
  83. /* internal properties */
  84. this._cutObjects = []
  85. this._eventListeners = {
  86. scene: [],
  87. selection: [],
  88. animation: [],
  89. tool: [],
  90. }
  91. this.loadingManager = new THREE.LoadingManager()
  92. const loadingManager = this.loadingManager
  93. loadingManager.onStart = (url, itemsLoaded, itemsTotal) => {
  94. if (!url.startsWith('data:')) {
  95. console.info(url, itemsLoaded, itemsTotal)
  96. }
  97. }
  98. loadingManager.onLoad = () => {
  99. console.info('Load completed.')
  100. setTimeout(() => {
  101. document.querySelector('button.tool_button.orbit').click()
  102. }, 2000)
  103. this.repaint()
  104. }
  105. THREE.Object3D.DefaultMatrixAutoUpdate = false
  106. THREE.Object3D.DefaultUp = new THREE.Vector3(0, 0, 1)
  107. THREE.Object3D.HIDDEN_PREFIX = '.'
  108. /* create sub elements */
  109. const logoPanelElem = document.createElement('div')
  110. logoPanelElem.className = 'logo_panel'
  111. logoPanelElem.addEventListener('click', () => this.hideLogo())
  112. this.logoPanel = logoPanelElem
  113. element.appendChild(logoPanelElem)
  114. const bigLogoImage = document.createElement('img')
  115. bigLogoImage.src = 'css/images/grey-logo.png'
  116. bigLogoImage.title = Application.NAME
  117. bigLogoImage.alt = Application.NAME
  118. logoPanelElem.appendChild(bigLogoImage)
  119. const headerElem = document.createElement('header')
  120. element.appendChild(headerElem)
  121. // const logoLink = document.createElement('a')
  122. // logoLink.className = 'logo_link'
  123. // logoLink.addEventListener('click', event => this.showLogo())
  124. // headerElem.appendChild(logoLink)
  125. // const logoImage = document.createElement('img')
  126. // logoImage.src = 'css/images/bimrocket.svg'
  127. // logoImage.title = Application.NAME
  128. // logoImage.alt = Application.NAME
  129. // logoLink.appendChild(logoImage)
  130. const toolBarElem = document.createElement('div')
  131. toolBarElem.className = 'toolbar'
  132. element.appendChild(toolBarElem)
  133. const container = document.createElement('div')
  134. container.className = 'container'
  135. container.style.touchAction = 'none'
  136. this.container = container
  137. element.appendChild(container)
  138. const progressBarElem = document.createElement('div')
  139. progressBarElem.className = 'progress_bar'
  140. element.appendChild(progressBarElem)
  141. this.restoreBackground()
  142. this.updateBackground()
  143. // renderer
  144. let renderer
  145. if (WEBGL.isWebGLAvailable()) {
  146. // WebGL renderer
  147. renderer = new THREE.WebGLRenderer({
  148. antialias: true,
  149. alpha: true,
  150. preserveDrawingBuffer: true,
  151. })
  152. renderer.shadowMap.enabled = this.shadowsEnabled
  153. renderer.shadowMap.type = THREE.PCFSoftShadowMap
  154. } else {
  155. // fake renderer
  156. renderer = new FakeRenderer()
  157. }
  158. this.renderer = renderer
  159. renderer.alpha = true
  160. renderer.setClearColor(0x000000, 0)
  161. renderer.sortObjects = true
  162. renderer.setPixelRatio(window.devicePixelRatio)
  163. renderer.setSize(container.clientWidth, container.clientHeight)
  164. container.appendChild(renderer.domElement)
  165. // panelManager
  166. this.panelManager = new PanelManager(container)
  167. // general tabbed panel
  168. this.progressBar = new ProgressBar(progressBarElem)
  169. // menuBar
  170. this.menuBar = new MenuBar(this, headerElem)
  171. // toolBar
  172. this.toolBar = new ToolBar(this, toolBarElem)
  173. /* selection materials */
  174. const selectionColor = new THREE.Color(0, 0, 1)
  175. this.selectionMaterial = new THREE.LineBasicMaterial({ color: selectionColor, linewidth: 1.5, depthTest: true, depthWrite: true, transparent: true })
  176. this.deepSelectionMaterial = new THREE.LineBasicMaterial({ color: selectionColor, linewidth: 1.5, depthTest: false, depthWrite: false, transparent: true })
  177. this.boxSelectionMaterial = new THREE.LineBasicMaterial({ color: selectionColor, linewidth: 1.5, depthTest: true, depthWrite: true })
  178. this.invisibleSelectionMaterial = new LineDashedShaderMaterial({ color: selectionColor, dashSize: 4, gapSize: 4, depthTest: true, depthWrite: true })
  179. this.deepInvisibleSelectionMaterial = new LineDashedShaderMaterial({ color: selectionColor, dashSize: 4, gapSize: 4, depthTest: false, depthWrite: false, transparent: true })
  180. this.pointSelector = new PointSelector(this)
  181. // set language
  182. this.i18n.userLanguages = window.localStorage.getItem('bimrocket.language') || navigator.language
  183. // init scene
  184. this.initScene()
  185. // listeners
  186. this.addEventListener('scene', event => {
  187. if (event.type === 'cameraActivated') {
  188. this.repaint()
  189. } else if (event.type !== 'cut') {
  190. if (event.type === 'nodeChanged') {
  191. let updateSelection = false
  192. for (let object of event.objects) {
  193. if (event.source !== ObjectBuilder) {
  194. object.needsRebuild = true
  195. }
  196. if (object instanceof THREE.Camera && event.source instanceof Inspector) {
  197. // inspector has changed a camera
  198. const camera = object
  199. camera.updateProjectionMatrix()
  200. } else if (this.selection.contains(object)) {
  201. updateSelection = true
  202. }
  203. }
  204. if (updateSelection) this.updateSelection()
  205. } else if (event.type === 'added' || event.type === 'removed') {
  206. event.parent.needsRebuild = true
  207. }
  208. this.repaint()
  209. }
  210. })
  211. this.addEventListener('selection', event => {
  212. if (event.type === 'changed') {
  213. this.updateSelection()
  214. }
  215. })
  216. window.addEventListener('resize', this.onResize.bind(this), false)
  217. // window.addEventListener('beforeunload', event => {
  218. // if (this.baseObject.children.length > 0) {
  219. // event.preventDefault()
  220. // event.returnValue = ''
  221. // }
  222. // })
  223. // animation
  224. let __animationEvent = { delta: 0 }
  225. let __animationCounter = 0
  226. let animate = () => {
  227. requestAnimationFrame(animate)
  228. __animationEvent.delta = this.clock.getDelta()
  229. if (this._eventListeners.animation.length > 0) {
  230. this.notifyEventListeners('animation', __animationEvent)
  231. }
  232. transitions.update(__animationEvent.delta) //add
  233. __animationCounter++
  234. if (__animationCounter >= this.frameRateDivisor) {
  235. __animationCounter = 0
  236. if (this.autoRepaint || this.needsRepaint) {
  237. this.render()
  238. }
  239. }
  240. }
  241. animate()
  242. }
  243. initScene() {
  244. const container = this.container
  245. if (this.scene) {
  246. ObjectUtils.dispose(this.scene)
  247. this.stopControllers()
  248. }
  249. this.scene = new THREE.Scene()
  250. const scene = this.scene
  251. scene.userData.selection = { type: 'none' }
  252. scene.name = 'Scene'
  253. // Add lights
  254. const hemisphereLight = new THREE.HemisphereLight(0xf0f0f0, 0x808080, 1)
  255. hemisphereLight.name = 'HemisphereLight'
  256. hemisphereLight.updateMatrix()
  257. scene.add(hemisphereLight)
  258. const sunLight = new THREE.DirectionalLight(0xffffff, 1)
  259. sunLight.position.x = 20
  260. sunLight.position.y = 20
  261. sunLight.position.z = 80
  262. sunLight.name = 'SunLight'
  263. sunLight.castShadow = true
  264. sunLight.shadow.mapSize.width = 4096
  265. sunLight.shadow.mapSize.height = 4096
  266. sunLight.shadow.camera.left = -40
  267. sunLight.shadow.camera.right = 40
  268. sunLight.shadow.camera.top = 40
  269. sunLight.shadow.camera.bottom = -40
  270. sunLight.shadow.camera.far = 3000
  271. sunLight.shadow.camera.near = 0.01
  272. sunLight.shadow.camera.matrixAutoUpdate = true
  273. sunLight.shadow.bias = -0.0001
  274. sunLight.target = scene
  275. scene.add(sunLight)
  276. sunLight.updateMatrix()
  277. // initial camera
  278. let camera = new THREE.OrthographicCamera(-10, 10, 10, -10, -2000, 2000)
  279. camera.position.set(0, -30, 2)
  280. camera.name = 'Orthographic'
  281. camera.updateProjectionMatrix()
  282. camera.updateMatrix()
  283. camera.lookAt(new THREE.Vector3(0, 0, 0))
  284. camera.updateMatrix()
  285. scene.add(camera)
  286. this.orthographicCamera = camera
  287. camera = new THREE.PerspectiveCamera(60, container.clientWidth / container.clientHeight, 0.1, 4000)
  288. camera.position.set(0, -10, 0.2)
  289. camera.name = 'Perspective'
  290. camera.aspect = container.clientWidth / container.clientHeight
  291. camera.updateProjectionMatrix()
  292. camera.updateMatrix()
  293. camera.lookAt(new THREE.Vector3(0, 0, 0))
  294. camera.updateMatrix()
  295. scene.add(camera)
  296. this.perspectiveCamera = camera
  297. this.camera = camera
  298. // Add base group
  299. this.baseObject = new THREE.Group()
  300. const baseObject = this.baseObject
  301. baseObject.name = 'Base'
  302. baseObject.userData.selection = { type: 'none' }
  303. baseObject.updateMatrix()
  304. scene.add(baseObject)
  305. // Add clipping group
  306. this.clippingGroup = new THREE.Group()
  307. this.clippingGroup.name = THREE.Object3D.HIDDEN_PREFIX + 'clipping'
  308. this.scene.add(this.clippingGroup)
  309. // Add overlays group
  310. this.overlays = new THREE.Group()
  311. this.overlays.name = THREE.Object3D.HIDDEN_PREFIX + 'overlays'
  312. this.scene.add(this.overlays)
  313. let sceneEvent = { type: 'structureChanged', objects: [this.scene], source: this }
  314. this.notifyEventListeners('scene', sceneEvent)
  315. this.selection.set(baseObject)
  316. }
  317. render() {
  318. this.renderer.render(this.scene, this.camera)
  319. this.needsRepaint = false
  320. }
  321. repaint() {
  322. this.needsRepaint = true
  323. }
  324. /* gets the model root depending on selection */
  325. getModelRoot(lowestRoot = false) {
  326. let root
  327. const roots = this.selection.roots
  328. const baseObject = this.baseObject
  329. if (roots.length === 0) {
  330. // nothing selected
  331. if (baseObject.children.length === 1) {
  332. root = baseObject.children[0]
  333. } else {
  334. root = baseObject
  335. }
  336. } else if (roots.length === 1) {
  337. root = roots[0]
  338. if (!lowestRoot) {
  339. // find top root (under baseObject)
  340. while (root.parent !== baseObject && root !== this.scene && root !== baseObject) {
  341. root = root.parent
  342. }
  343. }
  344. } // multiple roots
  345. else {
  346. root = baseObject
  347. }
  348. return root
  349. }
  350. get units() {
  351. if (this._units === null) {
  352. this._units = window.localStorage.getItem('bimrocket.units') || 'm'
  353. }
  354. return this._units
  355. }
  356. set units(units) {
  357. this._units = units
  358. window.localStorage.setItem('bimrocket.units', units)
  359. }
  360. get decimals() {
  361. if (this._decimals === null) {
  362. this._decimals = parseInt(window.localStorage.getItem('bimrocket.decimals') || '2')
  363. }
  364. return this._decimals
  365. }
  366. set decimals(decimals) {
  367. this._decimals = decimals
  368. window.localStorage.setItem('bimrocket.decimals', String(decimals))
  369. }
  370. get backgroundColor() {
  371. return this._backgroundColor1
  372. }
  373. set backgroundColor(color) {
  374. this._backgroundColor1 = color
  375. this._backgroundColor2 = color
  376. this.updateBackground()
  377. this.saveBackground()
  378. }
  379. get backgroundColor1() {
  380. return this._backgroundColor1
  381. }
  382. set backgroundColor1(color) {
  383. this._backgroundColor1 = color
  384. this.updateBackground()
  385. this.saveBackground()
  386. }
  387. get backgroundColor2() {
  388. return this._backgroundColor2
  389. }
  390. set backgroundColor2(color) {
  391. this._backgroundColor2 = color
  392. this.updateBackground()
  393. this.saveBackground()
  394. }
  395. get panelOpacity() {
  396. if (this._panelOpacity === null) {
  397. let opacityValue = window.localStorage.getItem('bimrocket.panelOpacity')
  398. this._panelOpacity = opacityValue ? parseFloat(opacityValue) : 0.8
  399. }
  400. return this._panelOpacity
  401. }
  402. set panelOpacity(opacity) {
  403. this._panelOpacity = opacity
  404. window.localStorage.setItem('bimrocket.panelOpacity', String(opacity))
  405. let panels = this.panelManager.getPanels()
  406. for (let panel of panels) {
  407. panel.opacity = opacity
  408. }
  409. }
  410. get frameRateDivisor() {
  411. if (this._frameRateDivisor === null) {
  412. let value = window.localStorage.getItem('bimrocket.frameRateDivisor')
  413. this._frameRateDivisor = value ? parseInt(value) : 1
  414. }
  415. return this._frameRateDivisor
  416. }
  417. set frameRateDivisor(frd) {
  418. this._frameRateDivisor = frd
  419. window.localStorage.setItem('bimrocket.frameRateDivisor', String(frd))
  420. }
  421. get showDeepSelection() {
  422. if (this._showDeepSelection === null) {
  423. this._showDeepSelection = window.localStorage.getItem('bimrocket.showDeepSelection') !== 'false'
  424. }
  425. return this._showDeepSelection
  426. }
  427. set showDeepSelection(enabled) {
  428. this._showDeepSelection = enabled
  429. window.localStorage.setItem('bimrocket.showDeepSelection', enabled)
  430. this.updateSelection()
  431. }
  432. get showLocalAxes() {
  433. if (this._showLocalAxes === null) {
  434. this._showLocalAxes = window.localStorage.getItem('bimrocket.showLocalAxes') !== 'false'
  435. }
  436. return this._showLocalAxes
  437. }
  438. set showLocalAxes(enabled) {
  439. this._showLocalAxes = enabled
  440. window.localStorage.setItem('bimrocket.showLocalAxes', enabled)
  441. this.updateSelection()
  442. }
  443. get shadowsEnabled() {
  444. if (this._shadowsEnabled === null) {
  445. this._shadowsEnabled = window.localStorage.getItem('bimrocket.shadowsEnabled') === 'true'
  446. }
  447. return this._shadowsEnabled
  448. }
  449. set shadowsEnabled(enabled) {
  450. this._shadowsEnabled = enabled
  451. window.localStorage.setItem('bimrocket.shadowsEnabled', enabled)
  452. if (this.renderer.shadowMap) {
  453. if (this.renderer.shadowMap.enabled !== enabled) {
  454. this.renderer.shadowMap.enabled = enabled
  455. this.scene.traverse(object => {
  456. if (object.material) object.material.needsUpdate = true
  457. })
  458. this.repaint()
  459. }
  460. }
  461. }
  462. updateBackground() {
  463. if (this._backgroundColor1 === this._backgroundColor2) {
  464. this.container.style.background = this._backgroundColor1
  465. } else {
  466. this.container.style.background = 'linear-gradient(' + this._backgroundColor1 + ',' + this._backgroundColor2 + ')'
  467. }
  468. }
  469. restoreBackground() {
  470. this._backgroundColor1 = window.localStorage.getItem('bimrocket.backgroundColor1')
  471. if (this._backgroundColor1 === null) this._backgroundColor1 = '#E0E0FF'
  472. this._backgroundColor2 = window.localStorage.getItem('bimrocket.backgroundColor2')
  473. if (this._backgroundColor2 === null) this._backgroundColor2 = '#E0F0E0'
  474. }
  475. saveBackground() {
  476. window.localStorage.setItem('bimrocket.backgroundColor1', this._backgroundColor1)
  477. window.localStorage.setItem('bimrocket.backgroundColor2', this._backgroundColor2)
  478. }
  479. updateSelection() {
  480. this.hideSelectionLines()
  481. this.showSelectionLines()
  482. this.hideAxisLines()
  483. if (this.showLocalAxes) {
  484. this.showAxisLines()
  485. }
  486. }
  487. hideSelectionLines() {
  488. if (this._selectionLines !== null) {
  489. this.overlays.remove(this._selectionLines)
  490. ObjectUtils.dispose(this._selectionLines)
  491. this._selectionLines = null
  492. this.repaint()
  493. }
  494. }
  495. showSelectionLines() {
  496. if (this._selectionLines === null && !this.selection.isEmpty()) {
  497. const linesGroup = new THREE.Group()
  498. linesGroup.renderOrder = 1
  499. linesGroup.name = 'SelectionLines'
  500. const iterator = this.selection.iterator
  501. let item = iterator.next()
  502. while (!item.done) {
  503. let object = item.value
  504. this.collectLines(object, linesGroup)
  505. item = iterator.next()
  506. }
  507. this._selectionLines = linesGroup
  508. this.overlays.add(this._selectionLines)
  509. this.repaint()
  510. }
  511. }
  512. transformSelectionLines(matrix) {
  513. if (this._selectionLines !== null) {
  514. const lines = this._selectionLines
  515. matrix.decompose(lines.position, lines.quaternion, lines.scale)
  516. lines.updateMatrix()
  517. this.repaint()
  518. }
  519. }
  520. collectLines(object, linesGroup) {
  521. let material = this.getSelectionMaterial(object)
  522. if (object instanceof Solid) {
  523. let solid = object
  524. if (this.selectionPaintMode === Application.EDGES_SELECTION) {
  525. let edgesGeometry = solid.edgesGeometry
  526. if (edgesGeometry) {
  527. let lines = new THREE.LineSegments(edgesGeometry, material)
  528. lines.name = 'SelectionLines'
  529. lines.raycast = function () {}
  530. solid.updateMatrixWorld()
  531. solid.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  532. lines.updateMatrix()
  533. linesGroup.add(lines)
  534. }
  535. } // show faces (triangles)
  536. else {
  537. let geometry = solid.geometry
  538. if (geometry) {
  539. let edgesGeometry = geometry.getTrianglesGeometry()
  540. let lines = new THREE.LineSegments(edgesGeometry, material)
  541. lines.name = 'SelectionLines'
  542. lines.raycast = function () {}
  543. solid.updateMatrixWorld()
  544. solid.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  545. lines.updateMatrix()
  546. linesGroup.add(lines)
  547. }
  548. }
  549. } else if (object instanceof THREE.Camera) {
  550. let camera = object
  551. if (camera !== this.camera) {
  552. camera.updateMatrixWorld()
  553. let lines = new THREE.CameraHelper(camera)
  554. lines.updateMatrix()
  555. lines.name = 'SelectionLines'
  556. lines.raycast = function () {}
  557. linesGroup.add(lines)
  558. }
  559. } else if (object instanceof THREE.DirectionalLight) {
  560. let light = object
  561. let lines = new THREE.DirectionalLightHelper(light, 1, 0x0)
  562. lines.name = 'SelectionLines'
  563. lines.raycast = function () {}
  564. lines.lightPlane.updateMatrix()
  565. lines.targetLine.updateMatrix()
  566. linesGroup.add(lines)
  567. } else if (object instanceof THREE.Mesh) {
  568. object.updateMatrixWorld()
  569. let edgesGeometry = new THREE.EdgesGeometry(object.geometry)
  570. let lines = new THREE.LineSegments(edgesGeometry, material)
  571. lines.raycast = function () {}
  572. lines.name = 'OuterLines'
  573. object.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  574. lines.updateMatrix()
  575. linesGroup.add(lines)
  576. } else if (object instanceof Cord) {
  577. object.updateMatrixWorld()
  578. let lines = new THREE.LineSegments(object.geometry, material)
  579. lines.raycast = function () {}
  580. lines.name = 'Lines'
  581. object.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  582. lines.updateMatrix()
  583. linesGroup.add(lines)
  584. } else if (object instanceof Profile) {
  585. object.updateMatrixWorld()
  586. let lines = new THREE.LineSegments(object.geometry, material)
  587. lines.raycast = function () {}
  588. lines.name = 'Lines'
  589. object.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  590. lines.updateMatrix()
  591. linesGroup.add(lines)
  592. } else if (object instanceof THREE.Group || object instanceof THREE.Object3D) {
  593. object.updateMatrixWorld()
  594. let selectionProperties = object.userData.selection
  595. let selectionType = selectionProperties && selectionProperties.type ? selectionProperties.type : 'edges'
  596. if (selectionType === 'edges') {
  597. let children = object.children
  598. for (let i = 0; i < children.length; i++) {
  599. var child = children[i]
  600. this.collectLines(child, linesGroup)
  601. }
  602. } else if (selectionType === 'box') {
  603. let box = ObjectUtils.getLocalBoundingBox(object, true)
  604. if (!box.isEmpty()) {
  605. let geometry = ObjectUtils.getBoxGeometry(box)
  606. let lines = new THREE.LineSegments(geometry, object.visible ? this.boxSelectionMaterial : material)
  607. lines.raycast = function () {}
  608. object.updateMatrixWorld()
  609. object.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  610. lines.updateMatrix()
  611. linesGroup.add(lines)
  612. }
  613. }
  614. }
  615. }
  616. getSelectionMaterial(object) {
  617. if (object.visible) {
  618. return this.showDeepSelection ? this.deepSelectionMaterial : this.selectionMaterial
  619. } else {
  620. return this.showDeepSelection ? this.deepInvisibleSelectionMaterial : this.invisibleSelectionMaterial
  621. }
  622. }
  623. hideAxisLines() {
  624. if (this._axisLines !== null) {
  625. this.overlays.remove(this._axisLines)
  626. ObjectUtils.dispose(this._axisLines)
  627. this._axisLines = null
  628. this.repaint()
  629. }
  630. }
  631. showAxisLines() {
  632. if (this._axisLines === null) {
  633. var object = this.selection.object
  634. if (object) {
  635. this._axisLines = new THREE.AxesHelper(1)
  636. var lines = this._axisLines
  637. lines.name = 'AxisLines'
  638. object.updateMatrixWorld(true)
  639. object.matrixWorld.decompose(lines.position, lines.rotation, lines.scale)
  640. lines.updateMatrix()
  641. lines.raycast = function () {}
  642. lines.material.depthTest = false
  643. lines.material.depthWrite = false
  644. this.overlays.add(lines)
  645. this.repaint()
  646. }
  647. }
  648. }
  649. addEventListener(type, eventListener) {
  650. var eventListeners = this._eventListeners[type]
  651. if (eventListeners) {
  652. eventListeners.push(eventListener)
  653. }
  654. }
  655. removeEventListener(type, eventListener) {
  656. var eventListeners = this._eventListeners[type]
  657. if (eventListeners) {
  658. var index = eventListeners.indexOf(eventListener)
  659. if (index !== -1) {
  660. eventListeners.splice(index, 1)
  661. }
  662. }
  663. }
  664. notifyEventListeners(type, event) {
  665. const eventListeners = this._eventListeners[type]
  666. for (let listener of eventListeners) {
  667. listener(event)
  668. }
  669. }
  670. addService(service, group, save = true) {
  671. if (group === undefined) {
  672. console.warn('group is mandatory.')
  673. return
  674. }
  675. if (this.services[group] === undefined) {
  676. this.services[group] = {}
  677. }
  678. this.services[group][service.name] = service
  679. if (save) this.saveServices(group)
  680. }
  681. removeService(service, group, save = true) {
  682. if (this.services[group]) {
  683. delete this.services[group][service.name]
  684. if (save) this.saveServices(group)
  685. }
  686. }
  687. saveServices(group) {
  688. let data = []
  689. let serviceGroup = this.services[group]
  690. for (let name in serviceGroup) {
  691. let service = serviceGroup[name]
  692. data.push({
  693. className: service.constructor.name,
  694. parameters: service.getParameters(),
  695. })
  696. }
  697. let json = JSON.stringify(data)
  698. window.localStorage.setItem('bimrocket.services.' + group, json)
  699. console.info('save services.' + group + ': ', data)
  700. }
  701. restoreServices(group) {
  702. let json = window.localStorage.getItem('bimrocket.services.' + group)
  703. if (json) {
  704. let array = JSON.parse(json)
  705. for (let i = 0; i < array.length; i++) {
  706. let entry = array[i]
  707. let className = entry.className
  708. let parameters = entry.parameters
  709. let serviceClass = ServiceManager.classes[className]
  710. if (serviceClass) {
  711. let service = new serviceClass()
  712. service.setParameters(parameters)
  713. this.addService(service, group, false)
  714. } else console.warn('Service ' + className + ' not restored.')
  715. }
  716. }
  717. }
  718. addTool(tool) {
  719. if (!this.tools[tool.name]) {
  720. this.tools[tool.name] = tool
  721. var toolEvent = { type: 'added', tool: tool }
  722. this.notifyEventListeners('tool', toolEvent)
  723. }
  724. }
  725. removeTool(tool) {
  726. if (this.tool === tool) return
  727. if (this.tools[tool.name]) {
  728. delete this.tools[tool.name]
  729. var toolEvent = { type: 'removed', tool: tool }
  730. this.notifyEventListeners('tool', toolEvent)
  731. }
  732. }
  733. useTool(tool) {
  734. if (typeof tool === 'string') {
  735. tool = this.tools[tool]
  736. }
  737. if (tool === undefined) tool = null
  738. let toolEvent
  739. if (tool && tool.immediate) {
  740. tool.execute()
  741. toolEvent = { type: 'executed', tool: tool }
  742. this.notifyEventListeners('tool', toolEvent)
  743. } else {
  744. if (this.tool === tool) return // already active
  745. if (this.tool !== null) {
  746. this.tool.deactivate()
  747. toolEvent = { type: 'deactivated', tool: this.tool }
  748. this.notifyEventListeners('tool', toolEvent)
  749. }
  750. this.tool = tool
  751. if (tool) {
  752. tool.activate()
  753. toolEvent = { type: 'activated', tool: tool }
  754. this.notifyEventListeners('tool', toolEvent)
  755. }
  756. }
  757. }
  758. addObject(object, parent = null, attach = false, select = false, source = this) {
  759. if (!(object instanceof THREE.Object3D)) return
  760. const scene = this.scene
  761. if (parent === null) {
  762. parent = this.selection.object || this.baseObject
  763. while (parent !== scene) {
  764. if (parent.type === 'Object3D' || parent.type === 'Group') {
  765. break
  766. } else {
  767. parent = parent.parent
  768. }
  769. }
  770. }
  771. if (parent === scene) {
  772. parent = this.baseObject
  773. }
  774. if (attach) {
  775. parent.attach(object)
  776. } else {
  777. parent.add(object)
  778. }
  779. object.updateMatrix()
  780. let addEvent = {
  781. type: 'added',
  782. object: object,
  783. parent: parent,
  784. source: source,
  785. }
  786. this.notifyEventListeners('scene', addEvent)
  787. if (select) {
  788. this.selection.set(object)
  789. }
  790. return object
  791. }
  792. removeObject(object, source = this) {
  793. if (!(object instanceof THREE.Object3D)) {
  794. object = this.selection.object
  795. }
  796. if (object && object !== this.baseObject && object !== this.scene) {
  797. this.stopControllers(object)
  798. let parent = object.parent
  799. if (parent) {
  800. parent.remove(object)
  801. ObjectUtils.dispose(object)
  802. }
  803. let removeEvent = {
  804. type: 'removed',
  805. object: object,
  806. parent: parent,
  807. source: source,
  808. }
  809. this.notifyEventListeners('scene', removeEvent)
  810. this.selection.remove(object) // TODO: unselect child objects
  811. }
  812. }
  813. cloneObject(object, dynamic = false) {
  814. if (object === undefined) {
  815. object = this.selection.object
  816. }
  817. if (object && object !== this.baseObject) {
  818. let clone
  819. if (dynamic) {
  820. clone = new THREE.Object3D()
  821. clone.name = object.name + '_cloner'
  822. clone.builder = new Cloner(object)
  823. clone.userData.selection = { group: true }
  824. ObjectBuilder.build(clone)
  825. } else {
  826. clone = object.clone(true)
  827. clone.name = object.name + '_clone'
  828. }
  829. this.addObject(clone, object.parent)
  830. }
  831. }
  832. cutObjects() {
  833. let cutObjects = this.selection.roots
  834. cutObjects = cutObjects.filter(root => root !== this.scene && root.parent !== this.scene)
  835. this._cutObjects = cutObjects
  836. if (cutObjects.length > 0) {
  837. let cutEvent = {
  838. type: 'cut',
  839. objects: cutObjects,
  840. source: this,
  841. }
  842. this.notifyEventListeners('scene', cutEvent)
  843. }
  844. }
  845. pasteObjects(parent) {
  846. let cutObjects = this._cutObjects
  847. if (cutObjects.length > 0) {
  848. if (parent === undefined) {
  849. parent = this.selection.object
  850. }
  851. if (parent instanceof THREE.Object3D) {
  852. let object = parent
  853. while (object && object !== this.baseObject && cutObjects.indexOf(object) === -1) {
  854. object = object.parent
  855. }
  856. if (object === this.baseObject) {
  857. // paste only under baseObject
  858. for (let cutObject of cutObjects) {
  859. let removeEvent = {
  860. type: 'removed',
  861. object: cutObject,
  862. parent: cutObject.parent,
  863. source: this,
  864. }
  865. let addEvent = {
  866. type: 'added',
  867. object: cutObject,
  868. parent: parent,
  869. source: this,
  870. }
  871. parent.attach(cutObject)
  872. cutObject.updateMatrix()
  873. cutObject.updateMatrixWorld()
  874. this.notifyEventListeners('scene', removeEvent)
  875. this.notifyEventListeners('scene', addEvent)
  876. }
  877. let pasteEvent = {
  878. type: 'pasted',
  879. objects: cutObjects,
  880. source: this,
  881. }
  882. this.notifyEventListeners('scene', pasteEvent)
  883. this._cutObjects = []
  884. }
  885. }
  886. this.selection.set(parent)
  887. }
  888. }
  889. notifyObjectsChanged(
  890. objects,
  891. source = this,
  892. type = 'nodeChanged',
  893. properties = null // properties: array of property names or null
  894. ) {
  895. if (objects instanceof THREE.Object3D) {
  896. objects = [objects]
  897. }
  898. let sceneEvent = {
  899. type: type,
  900. source: source,
  901. objects: objects,
  902. properties: properties,
  903. }
  904. this.notifyEventListeners('scene', sceneEvent)
  905. }
  906. selectParentObject() {
  907. if (!this.selection.isEmpty()) {
  908. let parent = this.selection.object.parent
  909. if (parent) {
  910. this.selection.set(parent)
  911. }
  912. }
  913. }
  914. findObjects(objectExpression, baseObject = this.baseObject, nested = false) {
  915. let objects
  916. if (objectExpression === null) {
  917. objects = this.selection.roots
  918. } else if (objectExpression instanceof THREE.Object3D) {
  919. objects = [objectExpression]
  920. } else if (objectExpression instanceof Array) {
  921. // assume objectExpression is an Object3D array
  922. objects = objectExpression
  923. } else if (typeof objectExpression === 'string' || typeof objectExpression === 'function') {
  924. const condition = ObjectUtils.createEvalFunction(objectExpression)
  925. objects = ObjectUtils.findObjects(condition, baseObject, nested)
  926. } else {
  927. objects = []
  928. }
  929. return objects
  930. }
  931. selectObjects(objectExpression, selectionMode) {
  932. const objects = this.findObjects(objectExpression)
  933. const selection = this.selection
  934. if (selectionMode === Application.ADD_SELECTION_MODE) {
  935. selection.add(...objects)
  936. } else if (selectionMode === Application.REMOVE_SELECTION_MODE) {
  937. selection.remove(...objects)
  938. } else {
  939. selection.set(...objects)
  940. }
  941. }
  942. updateVisibility(objectExpression, visible) {
  943. let objects = this.findObjects(objectExpression)
  944. const changed = ObjectUtils.updateVisibility(objects, visible)
  945. this.notifyObjectsChanged(Array.from(changed))
  946. return changed
  947. }
  948. updateStyle(objectExpression, edgesVisible, facesVisible) {
  949. let objects = this.findObjects(objectExpression)
  950. const changed = ObjectUtils.updateStyle(objects, edgesVisible, facesVisible)
  951. this.notifyObjectsChanged(Array.from(changed))
  952. return changed
  953. }
  954. updateAppearance(objectExpression, appearance) {
  955. let objects = this.findObjects(objectExpression)
  956. const changed = ObjectUtils.updateAppearance(objects, appearance)
  957. this.notifyObjectsChanged(Array.from(changed))
  958. return changed
  959. }
  960. updateObjects(objectExpression, updateFunction, recursive = false) {
  961. let objects = this.findObjects(objectExpression)
  962. const changed = ObjectUtils.updateObjects(objects, updateFunction, recursive)
  963. this.notifyObjectsChanged(Array.from(changed))
  964. return changed
  965. }
  966. userSelectObjects(objects, event) {
  967. event.preventDefault()
  968. const selection = this.selection
  969. if (event.shiftKey) {
  970. selection.add(...objects)
  971. } else if (event.ctrlKey) {
  972. selection.remove(...objects)
  973. } else {
  974. if (this.selectionMode === Application.ADD_SELECTION_MODE) {
  975. selection.add(...objects)
  976. } else if (this.selectionMode === Application.REMOVE_SELECTION_MODE) {
  977. selection.remove(...objects)
  978. } else {
  979. selection.set(...objects)
  980. }
  981. }
  982. }
  983. initControllers(object) {
  984. this.handleControllers(controller => controller.init(this), object)
  985. }
  986. startControllers(object) {
  987. const set = new Set()
  988. this.handleControllers(controller => {
  989. controller.start()
  990. set.add(controller.object)
  991. }, object)
  992. const objects = Array.from(set)
  993. this.notifyObjectsChanged(objects, this)
  994. }
  995. stopControllers(object) {
  996. const set = new Set()
  997. this.handleControllers(controller => {
  998. controller.stop()
  999. set.add(controller.object)
  1000. }, object)
  1001. const objects = Array.from(set)
  1002. this.notifyObjectsChanged(objects, this)
  1003. }
  1004. handleControllers(handler, object) {
  1005. if (object === undefined) object = this.scene
  1006. object.traverse(obj => {
  1007. let objectControllers = obj.controllers
  1008. if (objectControllers) {
  1009. for (let name in objectControllers) {
  1010. let controller = objectControllers[name]
  1011. handler(controller)
  1012. }
  1013. }
  1014. })
  1015. }
  1016. createController(controllerClass = null, object = null, name = null) {
  1017. if (controllerClass === null) return
  1018. if (object === null) {
  1019. object = this.baseObject
  1020. }
  1021. if (name === null || name.trim().length === 0) {
  1022. let count = object.controllers ? Object.keys(object.controllers).length : 0
  1023. name = 'ctr_' + count
  1024. }
  1025. let controller = new controllerClass(object, name)
  1026. if (object.controllers === undefined) {
  1027. object.controllers = {}
  1028. }
  1029. object.controllers[name] = controller
  1030. controller.init(this)
  1031. this.notifyObjectsChanged(object)
  1032. return controller
  1033. }
  1034. evaluateFormulas() {
  1035. const updatedObjects = Formula.updateTree(this.scene)
  1036. console.info('Objects updated by formulas', updatedObjects)
  1037. if (updatedObjects.length > 0) {
  1038. this.notifyObjectsChanged(updatedObjects)
  1039. }
  1040. }
  1041. rebuild() {
  1042. const baseObject = this.baseObject
  1043. const built = []
  1044. ObjectBuilder.markAndBuild(baseObject, built)
  1045. console.info('Objects rebuilt', built)
  1046. if (built.length > 0) {
  1047. let sceneEvent = { type: 'structureChanged', objects: built, source: ObjectBuilder }
  1048. this.notifyEventListeners('scene', sceneEvent)
  1049. this.updateSelection()
  1050. }
  1051. }
  1052. updateCameraAspectRatio() {
  1053. var camera = this.camera
  1054. var container = this.container
  1055. var aspect = container.clientWidth / container.clientHeight
  1056. ObjectUtils.updateCameraAspectRatio(camera, aspect)
  1057. }
  1058. activateCamera(camera) {
  1059. this.camera = camera
  1060. this.updateCameraAspectRatio()
  1061. const changeEvent = { type: 'cameraActivated', object: camera, source: this }
  1062. this.notifyEventListeners('scene', changeEvent)
  1063. }
  1064. onResize() {
  1065. this.updateCameraAspectRatio()
  1066. const container = this.container
  1067. const renderer = this.renderer
  1068. renderer.setSize(container.clientWidth, container.clientHeight)
  1069. this.repaint()
  1070. }
  1071. createPanel(title, position, className) {
  1072. const panel = new Panel(this)
  1073. if (title) panel.title = title
  1074. if (position) panel.position = position
  1075. if (className) panel.setClassName(className)
  1076. this.panelManager.addPanel(panel)
  1077. return panel
  1078. }
  1079. loadModules(...modulePaths) {
  1080. const pendent = []
  1081. const loadNextModule = () => {
  1082. if (pendent.length > 0) {
  1083. let modulePath = pendent.pop()
  1084. ModuleLoader.load(modulePath)
  1085. .then(
  1086. module => {
  1087. console.info('module ' + modulePath + ' completed.')
  1088. module.load(this)
  1089. },
  1090. error => {
  1091. console.info(`module " + modulePath + " failed: ${error}`)
  1092. }
  1093. )
  1094. .finally(() => loadNextModule())
  1095. } else {
  1096. setTimeout(() => {
  1097. this.hideLogo()
  1098. this.loadModelFromUrl()
  1099. }, 1000)
  1100. }
  1101. }
  1102. for (let i = modulePaths.length - 1; i >= 0; i--) {
  1103. pendent.push(modulePaths[i])
  1104. }
  1105. loadNextModule()
  1106. }
  1107. showLogo() {
  1108. this.logoPanel.classList.add('visible')
  1109. this.logoPanel.classList.remove('hidden')
  1110. }
  1111. hideLogo() {
  1112. this.logoPanel.classList.add('hidden')
  1113. this.logoPanel.classList.remove('visible')
  1114. }
  1115. fullscreen() {
  1116. if (document.body.requestFullscreen) {
  1117. // chrome & firefox
  1118. document.body.requestFullscreen()
  1119. } else if (document.body.webkitRequestFullscreen) {
  1120. // safari
  1121. document.body.webkitRequestFullscreen()
  1122. }
  1123. }
  1124. loadModelFromUrl() {
  1125. const params = WebUtils.getQueryParams()
  1126. const url = params['url']
  1127. if (url === undefined) return
  1128. const application = this
  1129. const intent = {
  1130. url: url,
  1131. onProgress: data => {
  1132. application.progressBar.progress = data.progress
  1133. application.progressBar.message = data.message
  1134. },
  1135. onCompleted: object => {
  1136. //模型加载完毕
  1137. application.addObject(object)
  1138. application.progressBar.visible = false
  1139. application.initTasks(params)
  1140. console.log('loaded', object)
  1141. let boundingBox = new THREE.Box3()
  1142. object.traverse(child => {
  1143. if (child instanceof THREE.Mesh) {
  1144. child.geometry.computeBoundingBox()
  1145. boundingBox.union(child.geometry.boundingBox.clone().applyMatrix4(child.matrixWorld)) //但感觉如果最外层object大小不为1,要还原下scale再乘
  1146. //获取在scale为1时,表现出的大小
  1147. }
  1148. })
  1149. object.boundingBox = boundingBox //未乘上matrixWorld的本地boundingBox
  1150. object.matrixAutoUpdate = true //原先为什么是false
  1151. this.getBoundCenter(object)
  1152. this.moveBoundCenterTo(object, new THREE.Vector3(0, 0, 0))
  1153. this.tools.zoom_all.execute()
  1154. //this.tools.orbit.deactivate()
  1155. //this.tools.panorama.activate()
  1156. },
  1157. onError: error => {
  1158. application.progressBar.visible = false
  1159. MessageDialog.create('ERROR', error).setClassName('error').setI18N(application.i18n).show()
  1160. },
  1161. options: { units: application.units },
  1162. }
  1163. application.progressBar.message = 'Loading file...'
  1164. application.progressBar.progress = undefined
  1165. application.progressBar.visible = true
  1166. const auth = params['auth']
  1167. if (auth === 'Basic') {
  1168. let dialog = new LoginDialog(application)
  1169. dialog.login = (username, password) => {
  1170. intent.basicAuthCredentials = { username: username, password: password }
  1171. IOManager.load(intent)
  1172. }
  1173. dialog.onCancel = () => {
  1174. dialog.hide()
  1175. application.progressBar.visible = false
  1176. }
  1177. dialog.show()
  1178. } else {
  1179. IOManager.load(intent) // async load
  1180. }
  1181. }
  1182. initTasks(params) {
  1183. const toolName = params['tool']
  1184. if (toolName) {
  1185. let tool = this.tools[toolName]
  1186. if (tool) {
  1187. this.useTool(tool)
  1188. }
  1189. } else {
  1190. const scriptPath = params['script']
  1191. if (scriptPath) {
  1192. const request = new XMLHttpRequest()
  1193. request.open('GET', scriptPath, true)
  1194. request.onload = () => {
  1195. console.info(request.status)
  1196. if (request.status === 200) {
  1197. const scriptCode = request.responseText
  1198. const dialog = new ScriptDialog(this)
  1199. dialog.scriptName = 'init_script'
  1200. dialog.scriptCode = scriptCode
  1201. let error = dialog.run()
  1202. if (error) {
  1203. dialog.show()
  1204. }
  1205. } else {
  1206. let message = WebUtils.getHttpStatusMessage(request.status)
  1207. MessageDialog.create('ERROR', "Can't open script: " + message + ' (HTTP ' + request.status + ')')
  1208. .setClassName('error')
  1209. .setI18N(this.i18n)
  1210. .show()
  1211. }
  1212. }
  1213. request.send()
  1214. }
  1215. }
  1216. }
  1217. //=============================
  1218. moveBoundCenterTo(model, pos) {
  1219. //使boundCenter在所要的位置
  1220. let diff = new THREE.Vector3().subVectors(pos, model.boundCenter)
  1221. model.position.add(diff)
  1222. }
  1223. getBoundCenter(model) {
  1224. if (!model.boundCenter) model.boundCenter = new THREE.Vector3()
  1225. model.boundingBox.getCenter(model.boundCenter).applyMatrix4(model.matrixWorld)
  1226. }
  1227. moveCamera() {}
  1228. setView(info = {}) {
  1229. let camera = this.camera // this.perspectiveCamera
  1230. //this.cancelFlying()
  1231. let done = () => {
  1232. /* if(endTarget){
  1233. this.lookAt(endTarget); //compute radius for orbitcontrol
  1234. }else if(endQuaternion){
  1235. this.rotation = new THREE.Euler().setFromQuaternion(endQuaternion)
  1236. }*/
  1237. let f = () => {
  1238. info.callback && info.callback()
  1239. //this.dispatchEvent('flyingDone')
  1240. }
  1241. if (info.duration) {
  1242. setTimeout(f, 1) //延迟是为了使isFlying先为false
  1243. } else {
  1244. f() //有的需要迅速执行回调
  1245. }
  1246. }
  1247. let endPosition = new THREE.Vector3().copy(info.position)
  1248. let startPosition = camera.position.clone()
  1249. let startQuaternion,
  1250. endQuaternion,
  1251. endTarget = null
  1252. if (info.target) {
  1253. endTarget = new THREE.Vector3().copy(info.target)
  1254. endQuaternion = math.getQuaFromPosAim(endPosition, endTarget)
  1255. } else if (info.quaternion) {
  1256. endQuaternion = info.quaternion.clone()
  1257. }
  1258. if (endQuaternion) {
  1259. startQuaternion = new THREE.Quaternion().copy(camera.quaternion)
  1260. }
  1261. if (!info.duration) {
  1262. this.position.copy(endPosition)
  1263. this.restrictPos()
  1264. info.onUpdate && info.onUpdate(1)
  1265. done()
  1266. } else {
  1267. transitions.start(
  1268. lerp.vector(camera.position, endPosition, (pos, progress) => {
  1269. let t = progress
  1270. if (endQuaternion) {
  1271. let quaternion = new THREE.Quaternion().copy(startQuaternion)
  1272. lerp.quaternion(quaternion, endQuaternion)(progress)
  1273. camera.quaternion.copy(quaternion)
  1274. }
  1275. camera.updateMatrix()
  1276. this.notifyObjectsChanged(camera) //才会生效
  1277. info.onUpdate && info.onUpdate(t)
  1278. }),
  1279. info.duration,
  1280. done,
  1281. 0,
  1282. info.Easing ? easing[info.Easing] : easing.easeInOutSine /*easeInOutQuad */,
  1283. null,
  1284. this.LookTransition,
  1285. info.cancelFun
  1286. )
  1287. }
  1288. } //app.setView({duration:1000, position:{x:10,y:0,z:0}})
  1289. //=============================
  1290. }
  1291. export { Application }