@aibee/owlly 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/README.external.md +75 -0
  2. package/README.md +28 -0
  3. package/lib/src/external/lines/line-geometry.d.ts +9 -0
  4. package/lib/src/external/lines/line-geometry.js +52 -0
  5. package/lib/src/external/lines/line-geometry.js.map +1 -0
  6. package/lib/src/external/lines/line-material.d.ts +10 -0
  7. package/lib/src/external/lines/line-material.js +377 -0
  8. package/lib/src/external/lines/line-material.js.map +1 -0
  9. package/lib/src/external/lines/line-segments-2.d.ts +7 -0
  10. package/lib/src/external/lines/line-segments-2.js +144 -0
  11. package/lib/src/external/lines/line-segments-2.js.map +1 -0
  12. package/lib/src/external/lines/line-segments-geometry.d.ts +15 -0
  13. package/lib/src/external/lines/line-segments-geometry.js +141 -0
  14. package/lib/src/external/lines/line-segments-geometry.js.map +1 -0
  15. package/lib/src/external/loaders/gltf-loader.d.ts +77 -0
  16. package/lib/src/external/loaders/gltf-loader.js +2319 -0
  17. package/lib/src/external/loaders/gltf-loader.js.map +1 -0
  18. package/lib/src/external/orbit-controls.d.ts +44 -0
  19. package/lib/src/external/orbit-controls.js +746 -0
  20. package/lib/src/external/orbit-controls.js.map +1 -0
  21. package/lib/src/external/renderers/css-2d-renderer.d.ts +16 -0
  22. package/lib/src/external/renderers/css-2d-renderer.js +122 -0
  23. package/lib/src/external/renderers/css-2d-renderer.js.map +1 -0
  24. package/lib/src/external/renderers/css-3d-renderer.d.ts +18 -0
  25. package/lib/src/external/renderers/css-3d-renderer.js +139 -0
  26. package/lib/src/external/renderers/css-3d-renderer.js.map +1 -0
  27. package/lib/src/external/transform-controls.d.ts +106 -0
  28. package/lib/src/external/transform-controls.js +1113 -0
  29. package/lib/src/external/transform-controls.js.map +1 -0
  30. package/lib/src/external/util/buffer-geometry-utils.d.ts +45 -0
  31. package/lib/src/external/util/buffer-geometry-utils.js +569 -0
  32. package/lib/src/external/util/buffer-geometry-utils.js.map +1 -0
  33. package/lib/src/owlly/controller/aerial-element-controller.d.ts +65 -0
  34. package/lib/src/owlly/controller/aerial-element-controller.js +236 -0
  35. package/lib/src/owlly/controller/aerial-element-controller.js.map +1 -0
  36. package/lib/src/owlly/controller/basic-controller.d.ts +324 -0
  37. package/lib/src/owlly/controller/basic-controller.js +1239 -0
  38. package/lib/src/owlly/controller/basic-controller.js.map +1 -0
  39. package/lib/src/owlly/controller/camera-controller.d.ts +37 -0
  40. package/lib/src/owlly/controller/camera-controller.js +138 -0
  41. package/lib/src/owlly/controller/camera-controller.js.map +1 -0
  42. package/lib/src/owlly/controller/controller.d.ts +61 -0
  43. package/lib/src/owlly/controller/controller.js +24 -0
  44. package/lib/src/owlly/controller/controller.js.map +1 -0
  45. package/lib/src/owlly/controller/index.d.ts +2 -0
  46. package/lib/src/owlly/controller/index.js +14 -0
  47. package/lib/src/owlly/controller/index.js.map +1 -0
  48. package/lib/src/owlly/controller/mouse-indicator-controller.d.ts +34 -0
  49. package/lib/src/owlly/controller/mouse-indicator-controller.js +119 -0
  50. package/lib/src/owlly/controller/mouse-indicator-controller.js.map +1 -0
  51. package/lib/src/owlly/controller/orbit-control.d.ts +147 -0
  52. package/lib/src/owlly/controller/orbit-control.js +265 -0
  53. package/lib/src/owlly/controller/orbit-control.js.map +1 -0
  54. package/lib/src/owlly/controller/panorama-adjust-controller.d.ts +45 -0
  55. package/lib/src/owlly/controller/panorama-adjust-controller.js +158 -0
  56. package/lib/src/owlly/controller/panorama-adjust-controller.js.map +1 -0
  57. package/lib/src/owlly/controller/panorama-controller.d.ts +441 -0
  58. package/lib/src/owlly/controller/panorama-controller.js +1944 -0
  59. package/lib/src/owlly/controller/panorama-controller.js.map +1 -0
  60. package/lib/src/owlly/controller/panorama-transform-controller.d.ts +66 -0
  61. package/lib/src/owlly/controller/panorama-transform-controller.js +137 -0
  62. package/lib/src/owlly/controller/panorama-transform-controller.js.map +1 -0
  63. package/lib/src/owlly/controller/plane-controller.d.ts +43 -0
  64. package/lib/src/owlly/controller/plane-controller.js +174 -0
  65. package/lib/src/owlly/controller/plane-controller.js.map +1 -0
  66. package/lib/src/owlly/controller/texture-controller.d.ts +181 -0
  67. package/lib/src/owlly/controller/texture-controller.js +876 -0
  68. package/lib/src/owlly/controller/texture-controller.js.map +1 -0
  69. package/lib/src/owlly/controller/tile-panorama-controller.d.ts +308 -0
  70. package/lib/src/owlly/controller/tile-panorama-controller.js +1354 -0
  71. package/lib/src/owlly/controller/tile-panorama-controller.js.map +1 -0
  72. package/lib/src/owlly/controller/transform-controller.d.ts +106 -0
  73. package/lib/src/owlly/controller/transform-controller.js +546 -0
  74. package/lib/src/owlly/controller/transform-controller.js.map +1 -0
  75. package/lib/src/owlly/element/bottom-nav-element.d.ts +65 -0
  76. package/lib/src/owlly/element/bottom-nav-element.js +258 -0
  77. package/lib/src/owlly/element/bottom-nav-element.js.map +1 -0
  78. package/lib/src/owlly/element/camera.d.ts +82 -0
  79. package/lib/src/owlly/element/camera.js +284 -0
  80. package/lib/src/owlly/element/camera.js.map +1 -0
  81. package/lib/src/owlly/element/dom-2d-element.d.ts +35 -0
  82. package/lib/src/owlly/element/dom-2d-element.js +49 -0
  83. package/lib/src/owlly/element/dom-2d-element.js.map +1 -0
  84. package/lib/src/owlly/element/dom-3d-element.d.ts +27 -0
  85. package/lib/src/owlly/element/dom-3d-element.js +34 -0
  86. package/lib/src/owlly/element/dom-3d-element.js.map +1 -0
  87. package/lib/src/owlly/element/dom-label-2d.d.ts +116 -0
  88. package/lib/src/owlly/element/dom-label-2d.js +383 -0
  89. package/lib/src/owlly/element/dom-label-2d.js.map +1 -0
  90. package/lib/src/owlly/element/element.d.ts +53 -0
  91. package/lib/src/owlly/element/element.js +76 -0
  92. package/lib/src/owlly/element/element.js.map +1 -0
  93. package/lib/src/owlly/element/floor-model.d.ts +83 -0
  94. package/lib/src/owlly/element/floor-model.js +228 -0
  95. package/lib/src/owlly/element/floor-model.js.map +1 -0
  96. package/lib/src/owlly/element/gif-kit/Gif.d.ts +96 -0
  97. package/lib/src/owlly/element/gif-kit/Gif.js +433 -0
  98. package/lib/src/owlly/element/gif-kit/Gif.js.map +1 -0
  99. package/lib/src/owlly/element/gif-kit/GifColor.d.ts +21 -0
  100. package/lib/src/owlly/element/gif-kit/GifColor.js +38 -0
  101. package/lib/src/owlly/element/gif-kit/GifColor.js.map +1 -0
  102. package/lib/src/owlly/element/gif-kit/GifCompressedCodesToByteArrayConverter.d.ts +20 -0
  103. package/lib/src/owlly/element/gif-kit/GifCompressedCodesToByteArrayConverter.js +51 -0
  104. package/lib/src/owlly/element/gif-kit/GifCompressedCodesToByteArrayConverter.js.map +1 -0
  105. package/lib/src/owlly/element/gif-kit/GifFrame.d.ts +31 -0
  106. package/lib/src/owlly/element/gif-kit/GifFrame.js +97 -0
  107. package/lib/src/owlly/element/gif-kit/GifFrame.js.map +1 -0
  108. package/lib/src/owlly/element/gif-kit/GifImage.d.ts +23 -0
  109. package/lib/src/owlly/element/gif-kit/GifImage.js +8 -0
  110. package/lib/src/owlly/element/gif-kit/GifImage.js.map +1 -0
  111. package/lib/src/owlly/element/gif-kit/GifParser.d.ts +17 -0
  112. package/lib/src/owlly/element/gif-kit/GifParser.js +197 -0
  113. package/lib/src/owlly/element/gif-kit/GifParser.js.map +1 -0
  114. package/lib/src/owlly/element/gif-kit/GifPresenter.d.ts +20 -0
  115. package/lib/src/owlly/element/gif-kit/GifPresenter.js +44 -0
  116. package/lib/src/owlly/element/gif-kit/GifPresenter.js.map +1 -0
  117. package/lib/src/owlly/element/gif-kit/GifVersion.d.ts +10 -0
  118. package/lib/src/owlly/element/gif-kit/GifVersion.js +13 -0
  119. package/lib/src/owlly/element/gif-kit/GifVersion.js.map +1 -0
  120. package/lib/src/owlly/element/gltf-mesh-element.d.ts +31 -0
  121. package/lib/src/owlly/element/gltf-mesh-element.js +137 -0
  122. package/lib/src/owlly/element/gltf-mesh-element.js.map +1 -0
  123. package/lib/src/owlly/element/index.d.ts +20 -0
  124. package/lib/src/owlly/element/index.js +25 -0
  125. package/lib/src/owlly/element/index.js.map +1 -0
  126. package/lib/src/owlly/element/map-kit/area.d.ts +24 -0
  127. package/lib/src/owlly/element/map-kit/area.js +218 -0
  128. package/lib/src/owlly/element/map-kit/area.js.map +1 -0
  129. package/lib/src/owlly/element/map-kit/block-set.d.ts +39 -0
  130. package/lib/src/owlly/element/map-kit/block-set.js +91 -0
  131. package/lib/src/owlly/element/map-kit/block-set.js.map +1 -0
  132. package/lib/src/owlly/element/map-kit/block.d.ts +77 -0
  133. package/lib/src/owlly/element/map-kit/block.js +339 -0
  134. package/lib/src/owlly/element/map-kit/block.js.map +1 -0
  135. package/lib/src/owlly/element/map-kit/index.d.ts +4 -0
  136. package/lib/src/owlly/element/map-kit/index.js +7 -0
  137. package/lib/src/owlly/element/map-kit/index.js.map +1 -0
  138. package/lib/src/owlly/element/map-kit/shape.d.ts +131 -0
  139. package/lib/src/owlly/element/map-kit/shape.js +190 -0
  140. package/lib/src/owlly/element/map-kit/shape.js.map +1 -0
  141. package/lib/src/owlly/element/mesh-element.d.ts +22 -0
  142. package/lib/src/owlly/element/mesh-element.js +64 -0
  143. package/lib/src/owlly/element/mesh-element.js.map +1 -0
  144. package/lib/src/owlly/element/mesh-line-2d.d.ts +82 -0
  145. package/lib/src/owlly/element/mesh-line-2d.js +888 -0
  146. package/lib/src/owlly/element/mesh-line-2d.js.map +1 -0
  147. package/lib/src/owlly/element/meshline-o.d.ts +64 -0
  148. package/lib/src/owlly/element/meshline-o.js +679 -0
  149. package/lib/src/owlly/element/meshline-o.js.map +1 -0
  150. package/lib/src/owlly/element/panorama-group.d.ts +241 -0
  151. package/lib/src/owlly/element/panorama-group.js +967 -0
  152. package/lib/src/owlly/element/panorama-group.js.map +1 -0
  153. package/lib/src/owlly/element/panorama.d.ts +132 -0
  154. package/lib/src/owlly/element/panorama.js +813 -0
  155. package/lib/src/owlly/element/panorama.js.map +1 -0
  156. package/lib/src/owlly/element/path-group.d.ts +69 -0
  157. package/lib/src/owlly/element/path-group.js +172 -0
  158. package/lib/src/owlly/element/path-group.js.map +1 -0
  159. package/lib/src/owlly/element/path.d.ts +99 -0
  160. package/lib/src/owlly/element/path.js +532 -0
  161. package/lib/src/owlly/element/path.js.map +1 -0
  162. package/lib/src/owlly/element/placeable-2d.d.ts +158 -0
  163. package/lib/src/owlly/element/placeable-2d.js +471 -0
  164. package/lib/src/owlly/element/placeable-2d.js.map +1 -0
  165. package/lib/src/owlly/element/polygon-mesh.d.ts +107 -0
  166. package/lib/src/owlly/element/polygon-mesh.js +308 -0
  167. package/lib/src/owlly/element/polygon-mesh.js.map +1 -0
  168. package/lib/src/owlly/element/ring-element.d.ts +79 -0
  169. package/lib/src/owlly/element/ring-element.js +384 -0
  170. package/lib/src/owlly/element/ring-element.js.map +1 -0
  171. package/lib/src/owlly/element/sphere-mesh.d.ts +28 -0
  172. package/lib/src/owlly/element/sphere-mesh.js +70 -0
  173. package/lib/src/owlly/element/sphere-mesh.js.map +1 -0
  174. package/lib/src/owlly/element/svg-floor-model.d.ts +22 -0
  175. package/lib/src/owlly/element/svg-floor-model.js +185 -0
  176. package/lib/src/owlly/element/svg-floor-model.js.map +1 -0
  177. package/lib/src/owlly/element/svg-floors.d.ts +27 -0
  178. package/lib/src/owlly/element/svg-floors.js +110 -0
  179. package/lib/src/owlly/element/svg-floors.js.map +1 -0
  180. package/lib/src/owlly/element/tile-panorama-group.d.ts +335 -0
  181. package/lib/src/owlly/element/tile-panorama-group.js +1007 -0
  182. package/lib/src/owlly/element/tile-panorama-group.js.map +1 -0
  183. package/lib/src/owlly/element/tile-panorama.d.ts +161 -0
  184. package/lib/src/owlly/element/tile-panorama.js +511 -0
  185. package/lib/src/owlly/element/tile-panorama.js.map +1 -0
  186. package/lib/src/owlly/element/tile-plane.d.ts +105 -0
  187. package/lib/src/owlly/element/tile-plane.js +361 -0
  188. package/lib/src/owlly/element/tile-plane.js.map +1 -0
  189. package/lib/src/owlly/element/video-element.d.ts +33 -0
  190. package/lib/src/owlly/element/video-element.js +160 -0
  191. package/lib/src/owlly/element/video-element.js.map +1 -0
  192. package/lib/src/owlly/geometries/ExtrudeGeometry2.d.ts +15 -0
  193. package/lib/src/owlly/geometries/ExtrudeGeometry2.js +211 -0
  194. package/lib/src/owlly/geometries/ExtrudeGeometry2.js.map +1 -0
  195. package/lib/src/owlly/index.d.ts +13 -0
  196. package/lib/src/owlly/index.js +17 -0
  197. package/lib/src/owlly/index.js.map +1 -0
  198. package/lib/src/owlly/overlay/canvas-overlay.d.ts +96 -0
  199. package/lib/src/owlly/overlay/canvas-overlay.js +511 -0
  200. package/lib/src/owlly/overlay/canvas-overlay.js.map +1 -0
  201. package/lib/src/owlly/overlay/css-2d-overlay.d.ts +14 -0
  202. package/lib/src/owlly/overlay/css-2d-overlay.js +36 -0
  203. package/lib/src/owlly/overlay/css-2d-overlay.js.map +1 -0
  204. package/lib/src/owlly/overlay/css-3d-overlay.d.ts +16 -0
  205. package/lib/src/owlly/overlay/css-3d-overlay.js +37 -0
  206. package/lib/src/owlly/overlay/css-3d-overlay.js.map +1 -0
  207. package/lib/src/owlly/overlay/index.d.ts +6 -0
  208. package/lib/src/owlly/overlay/index.js +12 -0
  209. package/lib/src/owlly/overlay/index.js.map +1 -0
  210. package/lib/src/owlly/overlay/label-overlay.d.ts +62 -0
  211. package/lib/src/owlly/overlay/label-overlay.js +329 -0
  212. package/lib/src/owlly/overlay/label-overlay.js.map +1 -0
  213. package/lib/src/owlly/overlay/overlay.d.ts +14 -0
  214. package/lib/src/owlly/overlay/overlay.js +5 -0
  215. package/lib/src/owlly/overlay/overlay.js.map +1 -0
  216. package/lib/src/owlly/overlay/path-overlay.d.ts +39 -0
  217. package/lib/src/owlly/overlay/path-overlay.js +125 -0
  218. package/lib/src/owlly/overlay/path-overlay.js.map +1 -0
  219. package/lib/src/owlly/overlay/path-overlay2.d.ts +35 -0
  220. package/lib/src/owlly/overlay/path-overlay2.js +119 -0
  221. package/lib/src/owlly/overlay/path-overlay2.js.map +1 -0
  222. package/lib/src/owlly/overlay/poi-overlay-3d.d.ts +278 -0
  223. package/lib/src/owlly/overlay/poi-overlay-3d.js +1433 -0
  224. package/lib/src/owlly/overlay/poi-overlay-3d.js.map +1 -0
  225. package/lib/src/owlly/overlay/poi-overlay.d.ts +277 -0
  226. package/lib/src/owlly/overlay/poi-overlay.js +1412 -0
  227. package/lib/src/owlly/overlay/poi-overlay.js.map +1 -0
  228. package/lib/src/owlly/owlly-2d/index.d.ts +28 -0
  229. package/lib/src/owlly/owlly-2d/index.js +93 -0
  230. package/lib/src/owlly/owlly-2d/index.js.map +1 -0
  231. package/lib/src/owlly/screen/index.d.ts +1 -0
  232. package/lib/src/owlly/screen/index.js +2 -0
  233. package/lib/src/owlly/screen/index.js.map +1 -0
  234. package/lib/src/owlly/screen/screen.d.ts +73 -0
  235. package/lib/src/owlly/screen/screen.js +237 -0
  236. package/lib/src/owlly/screen/screen.js.map +1 -0
  237. package/lib/src/owlly/stage/__test__/stage.spec.d.ts +1 -0
  238. package/lib/src/owlly/stage/__test__/stage.spec.js +15 -0
  239. package/lib/src/owlly/stage/__test__/stage.spec.js.map +1 -0
  240. package/lib/src/owlly/stage/externals.d.ts +19 -0
  241. package/lib/src/owlly/stage/externals.js +25 -0
  242. package/lib/src/owlly/stage/externals.js.map +1 -0
  243. package/lib/src/owlly/stage/index.d.ts +4 -0
  244. package/lib/src/owlly/stage/index.js +7 -0
  245. package/lib/src/owlly/stage/index.js.map +1 -0
  246. package/lib/src/owlly/stage/owlly.d.ts +38 -0
  247. package/lib/src/owlly/stage/owlly.js +168 -0
  248. package/lib/src/owlly/stage/owlly.js.map +1 -0
  249. package/lib/src/owlly/stage/stage.d.ts +108 -0
  250. package/lib/src/owlly/stage/stage.js +235 -0
  251. package/lib/src/owlly/stage/stage.js.map +1 -0
  252. package/lib/src/owlly/utils/alignment-utils.d.ts +20 -0
  253. package/lib/src/owlly/utils/alignment-utils.js +64 -0
  254. package/lib/src/owlly/utils/alignment-utils.js.map +1 -0
  255. package/lib/src/owlly/utils/basic-calc.d.ts +18 -0
  256. package/lib/src/owlly/utils/basic-calc.js +130 -0
  257. package/lib/src/owlly/utils/basic-calc.js.map +1 -0
  258. package/lib/src/owlly/utils/basic-tools.d.ts +71 -0
  259. package/lib/src/owlly/utils/basic-tools.js +236 -0
  260. package/lib/src/owlly/utils/basic-tools.js.map +1 -0
  261. package/lib/src/owlly/utils/bvh-tree.d.ts +105 -0
  262. package/lib/src/owlly/utils/bvh-tree.js +540 -0
  263. package/lib/src/owlly/utils/bvh-tree.js.map +1 -0
  264. package/lib/src/owlly/utils/camera.d.ts +37 -0
  265. package/lib/src/owlly/utils/camera.js +51 -0
  266. package/lib/src/owlly/utils/camera.js.map +1 -0
  267. package/lib/src/owlly/utils/cube-texture-cache.d.ts +25 -0
  268. package/lib/src/owlly/utils/cube-texture-cache.js +144 -0
  269. package/lib/src/owlly/utils/cube-texture-cache.js.map +1 -0
  270. package/lib/src/owlly/utils/device-utils.d.ts +18 -0
  271. package/lib/src/owlly/utils/device-utils.js +42 -0
  272. package/lib/src/owlly/utils/device-utils.js.map +1 -0
  273. package/lib/src/owlly/utils/environment-utils.d.ts +37 -0
  274. package/lib/src/owlly/utils/environment-utils.js +74 -0
  275. package/lib/src/owlly/utils/environment-utils.js.map +1 -0
  276. package/lib/src/owlly/utils/event-hub.d.ts +50 -0
  277. package/lib/src/owlly/utils/event-hub.js +107 -0
  278. package/lib/src/owlly/utils/event-hub.js.map +1 -0
  279. package/lib/src/owlly/utils/events.d.ts +219 -0
  280. package/lib/src/owlly/utils/events.js +220 -0
  281. package/lib/src/owlly/utils/events.js.map +1 -0
  282. package/lib/src/owlly/utils/geometry-utils.d.ts +119 -0
  283. package/lib/src/owlly/utils/geometry-utils.js +623 -0
  284. package/lib/src/owlly/utils/geometry-utils.js.map +1 -0
  285. package/lib/src/owlly/utils/helper.d.ts +6 -0
  286. package/lib/src/owlly/utils/helper.js +25 -0
  287. package/lib/src/owlly/utils/helper.js.map +1 -0
  288. package/lib/src/owlly/utils/index.d.ts +14 -0
  289. package/lib/src/owlly/utils/index.js +18 -0
  290. package/lib/src/owlly/utils/index.js.map +1 -0
  291. package/lib/src/owlly/utils/lru-cache.d.ts +26 -0
  292. package/lib/src/owlly/utils/lru-cache.js +110 -0
  293. package/lib/src/owlly/utils/lru-cache.js.map +1 -0
  294. package/lib/src/owlly/utils/map-utils.d.ts +7 -0
  295. package/lib/src/owlly/utils/map-utils.js +53 -0
  296. package/lib/src/owlly/utils/map-utils.js.map +1 -0
  297. package/lib/src/owlly/utils/number-utils.d.ts +8 -0
  298. package/lib/src/owlly/utils/number-utils.js +73 -0
  299. package/lib/src/owlly/utils/number-utils.js.map +1 -0
  300. package/lib/src/owlly/utils/panorama-model-util.d.ts +46 -0
  301. package/lib/src/owlly/utils/panorama-model-util.js +246 -0
  302. package/lib/src/owlly/utils/panorama-model-util.js.map +1 -0
  303. package/lib/src/owlly/utils/path-utils.d.ts +80 -0
  304. package/lib/src/owlly/utils/path-utils.js +729 -0
  305. package/lib/src/owlly/utils/path-utils.js.map +1 -0
  306. package/lib/src/owlly/utils/svgutils.d.ts +138 -0
  307. package/lib/src/owlly/utils/svgutils.js +562 -0
  308. package/lib/src/owlly/utils/svgutils.js.map +1 -0
  309. package/lib/src/owlly/utils/texture-cache.d.ts +29 -0
  310. package/lib/src/owlly/utils/texture-cache.js +116 -0
  311. package/lib/src/owlly/utils/texture-cache.js.map +1 -0
  312. package/lib/src/owlly/utils/tile-util.d.ts +187 -0
  313. package/lib/src/owlly/utils/tile-util.js +457 -0
  314. package/lib/src/owlly/utils/tile-util.js.map +1 -0
  315. package/lib/src/owlly/utils/time-profiler.d.ts +21 -0
  316. package/lib/src/owlly/utils/time-profiler.js +49 -0
  317. package/lib/src/owlly/utils/time-profiler.js.map +1 -0
  318. package/lib/src/owlly/view/__test__/perspective-view.spec.d.ts +0 -0
  319. package/lib/src/owlly/view/__test__/perspective-view.spec.js +22 -0
  320. package/lib/src/owlly/view/__test__/perspective-view.spec.js.map +1 -0
  321. package/lib/src/owlly/view/camera-view.d.ts +35 -0
  322. package/lib/src/owlly/view/camera-view.js +102 -0
  323. package/lib/src/owlly/view/camera-view.js.map +1 -0
  324. package/lib/src/owlly/view/index.d.ts +3 -0
  325. package/lib/src/owlly/view/index.js +6 -0
  326. package/lib/src/owlly/view/index.js.map +1 -0
  327. package/lib/src/owlly/view/orthographic-view.d.ts +40 -0
  328. package/lib/src/owlly/view/orthographic-view.js +95 -0
  329. package/lib/src/owlly/view/orthographic-view.js.map +1 -0
  330. package/lib/src/owlly/view/perspective-view.d.ts +40 -0
  331. package/lib/src/owlly/view/perspective-view.js +96 -0
  332. package/lib/src/owlly/view/perspective-view.js.map +1 -0
  333. package/lib/src/owlly/view/svg-map-view.d.ts +46 -0
  334. package/lib/src/owlly/view/svg-map-view.js +145 -0
  335. package/lib/src/owlly/view/svg-map-view.js.map +1 -0
  336. package/lib/src/owlly/view/view.d.ts +146 -0
  337. package/lib/src/owlly/view/view.js +318 -0
  338. package/lib/src/owlly/view/view.js.map +1 -0
  339. package/lib/src/web/main.centroid.d.ts +0 -0
  340. package/lib/src/web/main.centroid.js +74 -0
  341. package/lib/src/web/main.centroid.js.map +1 -0
  342. package/lib/src/web/main.hyma.meshline2d.d.ts +1 -0
  343. package/lib/src/web/main.hyma.meshline2d.js +76 -0
  344. package/lib/src/web/main.hyma.meshline2d.js.map +1 -0
  345. package/lib/src/web/main.jyfang.sample.d.ts +0 -0
  346. package/lib/src/web/main.jyfang.sample.js +122 -0
  347. package/lib/src/web/main.jyfang.sample.js.map +1 -0
  348. package/lib/src/web/main.rpeng.extrude.d.ts +1 -0
  349. package/lib/src/web/main.rpeng.extrude.js +180 -0
  350. package/lib/src/web/main.rpeng.extrude.js.map +1 -0
  351. package/lib/src/web/main.rpeng.mes.plane.d.ts +1 -0
  352. package/lib/src/web/main.rpeng.mes.plane.js +135 -0
  353. package/lib/src/web/main.rpeng.mes.plane.js.map +1 -0
  354. package/lib/src/web/main.rpeng.sample.d.ts +0 -0
  355. package/lib/src/web/main.rpeng.sample.js +318 -0
  356. package/lib/src/web/main.rpeng.sample.js.map +1 -0
  357. package/lib/src/web/main.rpeng.vr.d.ts +1 -0
  358. package/lib/src/web/main.rpeng.vr.js +141 -0
  359. package/lib/src/web/main.rpeng.vr.js.map +1 -0
  360. package/lib/src/web/main.sample.d.ts +1 -0
  361. package/lib/src/web/main.sample.js +52 -0
  362. package/lib/src/web/main.sample.js.map +1 -0
  363. package/lib/src/web/quattree.hyma.d.ts +0 -0
  364. package/lib/src/web/quattree.hyma.js +150 -0
  365. package/lib/src/web/quattree.hyma.js.map +1 -0
  366. package/lib/src/web/sensor-vr-plugin.d.ts +0 -0
  367. package/lib/src/web/sensor-vr-plugin.js +166 -0
  368. package/lib/src/web/sensor-vr-plugin.js.map +1 -0
  369. package/package.json +142 -0
  370. package/src/@types/SceneUtils.d.ts +9 -0
  371. package/src/@types/chaikin-smooth.d.ts +5 -0
  372. package/src/@types/global.d.ts +3 -0
  373. package/src/@types/snapsvg.d.ts +11 -0
  374. package/src/@types/svgson.d.ts +30 -0
  375. package/src/assets/favicon.ico +0 -0
  376. package/src/external/lines/line-geometry.ts +70 -0
  377. package/src/external/lines/line-material.ts +453 -0
  378. package/src/external/lines/line-segments-2.ts +194 -0
  379. package/src/external/lines/line-segments-geometry.ts +197 -0
  380. package/src/external/loaders/gltf-loader.ts +3004 -0
  381. package/src/external/orbit-controls.ts +1070 -0
  382. package/src/external/renderers/css-2d-renderer.ts +185 -0
  383. package/src/external/renderers/css-3d-renderer.ts +245 -0
  384. package/src/external/transform-controls.ts +1532 -0
  385. package/src/external/util/buffer-geometry-utils.ts +783 -0
  386. package/src/owlly/controller/aerial-element-controller.ts +277 -0
  387. package/src/owlly/controller/basic-controller.ts +1509 -0
  388. package/src/owlly/controller/camera-controller.ts +155 -0
  389. package/src/owlly/controller/controller.ts +76 -0
  390. package/src/owlly/controller/index.ts +15 -0
  391. package/src/owlly/controller/mouse-indicator-controller.ts +157 -0
  392. package/src/owlly/controller/orbit-control.ts +310 -0
  393. package/src/owlly/controller/panorama-adjust-controller.ts +183 -0
  394. package/src/owlly/controller/panorama-controller.ts +2234 -0
  395. package/src/owlly/controller/panorama-transform-controller.ts +151 -0
  396. package/src/owlly/controller/plane-controller.ts +222 -0
  397. package/src/owlly/controller/texture-controller.ts +949 -0
  398. package/src/owlly/controller/tile-panorama-controller.ts +1633 -0
  399. package/src/owlly/controller/transform-controller.ts +684 -0
  400. package/src/owlly/element/bottom-nav-element.ts +352 -0
  401. package/src/owlly/element/camera.ts +389 -0
  402. package/src/owlly/element/dom-2d-element.ts +88 -0
  403. package/src/owlly/element/dom-3d-element.ts +87 -0
  404. package/src/owlly/element/dom-label-2d.ts +497 -0
  405. package/src/owlly/element/element.ts +117 -0
  406. package/src/owlly/element/floor-model.ts +290 -0
  407. package/src/owlly/element/gif-kit/Gif.ts +509 -0
  408. package/src/owlly/element/gif-kit/GifColor.ts +44 -0
  409. package/src/owlly/element/gif-kit/GifCompressedCodesToByteArrayConverter.ts +56 -0
  410. package/src/owlly/element/gif-kit/GifFrame.ts +207 -0
  411. package/src/owlly/element/gif-kit/GifImage.ts +26 -0
  412. package/src/owlly/element/gif-kit/GifParser.ts +254 -0
  413. package/src/owlly/element/gif-kit/GifPresenter.ts +46 -0
  414. package/src/owlly/element/gif-kit/GifVersion.ts +12 -0
  415. package/src/owlly/element/gltf-mesh-element.ts +184 -0
  416. package/src/owlly/element/index.ts +25 -0
  417. package/src/owlly/element/map-kit/area.ts +232 -0
  418. package/src/owlly/element/map-kit/block-set.ts +102 -0
  419. package/src/owlly/element/map-kit/block.ts +417 -0
  420. package/src/owlly/element/map-kit/index.ts +6 -0
  421. package/src/owlly/element/map-kit/shape.ts +285 -0
  422. package/src/owlly/element/mesh-element.ts +94 -0
  423. package/src/owlly/element/mesh-line-2d.ts +1032 -0
  424. package/src/owlly/element/meshline-o.ts +802 -0
  425. package/src/owlly/element/panorama-group.ts +1250 -0
  426. package/src/owlly/element/panorama.ts +1044 -0
  427. package/src/owlly/element/path-group.ts +212 -0
  428. package/src/owlly/element/path.ts +727 -0
  429. package/src/owlly/element/placeable-2d.ts +627 -0
  430. package/src/owlly/element/polygon-mesh.ts +344 -0
  431. package/src/owlly/element/ring-element.ts +517 -0
  432. package/src/owlly/element/sphere-mesh.ts +96 -0
  433. package/src/owlly/element/svg-floor-model.ts +200 -0
  434. package/src/owlly/element/svg-floors.ts +121 -0
  435. package/src/owlly/element/tile-panorama-group.ts +1314 -0
  436. package/src/owlly/element/tile-panorama.ts +636 -0
  437. package/src/owlly/element/tile-plane.ts +430 -0
  438. package/src/owlly/element/video-element.ts +190 -0
  439. package/src/owlly/geometries/ExtrudeGeometry2.ts +255 -0
  440. package/src/owlly/index.ts +19 -0
  441. package/src/owlly/overlay/canvas-overlay.ts +642 -0
  442. package/src/owlly/overlay/css-2d-overlay.ts +48 -0
  443. package/src/owlly/overlay/css-3d-overlay.ts +50 -0
  444. package/src/owlly/overlay/index.ts +11 -0
  445. package/src/owlly/overlay/label-overlay.ts +419 -0
  446. package/src/owlly/overlay/overlay.ts +17 -0
  447. package/src/owlly/overlay/path-overlay.ts +170 -0
  448. package/src/owlly/overlay/path-overlay2.ts +149 -0
  449. package/src/owlly/overlay/poi-overlay-3d.ts +1759 -0
  450. package/src/owlly/overlay/poi-overlay.ts +1739 -0
  451. package/src/owlly/owlly-2d/index.ts +108 -0
  452. package/src/owlly/screen/index.ts +1 -0
  453. package/src/owlly/screen/screen.ts +323 -0
  454. package/src/owlly/stage/__test__/stage.spec.ts +15 -0
  455. package/src/owlly/stage/externals.ts +45 -0
  456. package/src/owlly/stage/index.ts +12 -0
  457. package/src/owlly/stage/owlly.ts +223 -0
  458. package/src/owlly/stage/stage.ts +274 -0
  459. package/src/owlly/utils/alignment-utils.ts +84 -0
  460. package/src/owlly/utils/basic-calc.ts +141 -0
  461. package/src/owlly/utils/basic-tools.ts +286 -0
  462. package/src/owlly/utils/bvh-tree.ts +695 -0
  463. package/src/owlly/utils/camera.ts +72 -0
  464. package/src/owlly/utils/cube-texture-cache.ts +155 -0
  465. package/src/owlly/utils/device-utils.ts +53 -0
  466. package/src/owlly/utils/environment-utils.ts +81 -0
  467. package/src/owlly/utils/event-hub.ts +120 -0
  468. package/src/owlly/utils/events.ts +266 -0
  469. package/src/owlly/utils/geometry-utils.ts +749 -0
  470. package/src/owlly/utils/helper.ts +33 -0
  471. package/src/owlly/utils/index.ts +17 -0
  472. package/src/owlly/utils/lru-cache.ts +126 -0
  473. package/src/owlly/utils/map-utils.ts +55 -0
  474. package/src/owlly/utils/number-utils.ts +75 -0
  475. package/src/owlly/utils/panorama-model-util.ts +255 -0
  476. package/src/owlly/utils/path-utils.ts +837 -0
  477. package/src/owlly/utils/svgutils.ts +732 -0
  478. package/src/owlly/utils/texture-cache.ts +132 -0
  479. package/src/owlly/utils/tile-util.ts +563 -0
  480. package/src/owlly/utils/time-profiler.ts +57 -0
  481. package/src/owlly/view/__test__/perspective-view.spec.ts +23 -0
  482. package/src/owlly/view/camera-view.ts +114 -0
  483. package/src/owlly/view/index.ts +5 -0
  484. package/src/owlly/view/orthographic-view.ts +124 -0
  485. package/src/owlly/view/perspective-view.ts +125 -0
  486. package/src/owlly/view/svg-map-view.ts +187 -0
  487. package/src/owlly/view/view.ts +409 -0
  488. package/src/public/js/jsmpeg.min.js +3129 -0
  489. package/src/web/index.html +52 -0
  490. package/src/web/main.centroid.ts +85 -0
  491. package/src/web/main.hyma.meshline2d.ts +84 -0
  492. package/src/web/main.jyfang.sample.ts +139 -0
  493. package/src/web/main.rpeng.extrude.ts +194 -0
  494. package/src/web/main.rpeng.mes.plane.ts +161 -0
  495. package/src/web/main.rpeng.sample.ts +345 -0
  496. package/src/web/main.rpeng.vr.ts +159 -0
  497. package/src/web/main.sample.ts +59 -0
  498. package/src/web/quattree.hyma.ts +163 -0
  499. package/src/web/sensor-vr-plugin.ts +201 -0
  500. package/src/web/testPixel.png +0 -0
@@ -0,0 +1,2234 @@
1
+ import TWEEN from '@tweenjs/tween.js';
2
+ import { Externals, NS_THREE } from '../stage/externals';
3
+ import { OrbitControls } from '../../external/orbit-controls';
4
+ import { Controller } from './controller';
5
+ import { PanoramaGroup } from '../element/panorama-group';
6
+ import { View } from '../view/view';
7
+ import { Element } from '../element/element';
8
+ import { Panorama } from '../element/panorama';
9
+ import { Events } from '../utils/events';
10
+ import { FloorModel } from '../element/floor-model';
11
+ import { CubeTextureCache } from '../utils/cube-texture-cache';
12
+ import { TextureCache } from '../utils/texture-cache';
13
+ // import { OwllyEvents } from '../utils/events';
14
+
15
+ const ROTATION_LOCK_BOUNDARY = 3 / 180 * Math.PI;
16
+
17
+ /**
18
+ * 在升级至瓦片后, 停止使用该控制器
19
+ */
20
+ class PanoramaController extends Controller {
21
+ private orbitControl: OrbitControls;
22
+
23
+ private mouseDownHandler: {(event: PointerEvent): void};
24
+
25
+ private mouseMoveHandler: {(event: PointerEvent): void};
26
+
27
+ private mouseUpHandler: {(event: PointerEvent): void};
28
+
29
+ private mouseWheelHandler: {(event: WheelEvent): void};
30
+
31
+ // private mouseMovement: number;
32
+
33
+ private touchStartHandler: {(event: TouchEvent): void};
34
+
35
+ private touchMoveHandler: {(event: TouchEvent): void};
36
+
37
+ private touchEndHandler: {(event: TouchEvent): void};
38
+
39
+ private touches: {
40
+ c: [NS_THREE.Vector2, NS_THREE.Vector2];
41
+ s: [NS_THREE.Vector2, NS_THREE.Vector2];
42
+ state: 'down'|'move'|'idle'|'zoom';
43
+ dist: number;
44
+ fov: number;
45
+ }
46
+
47
+ private isAnimating: boolean;
48
+
49
+ private translatePromise: Promise<unknown>|undefined;
50
+
51
+ private panoramaGroups: PanoramaGroup[];
52
+
53
+ private currentPanoramaGroup: PanoramaGroup|undefined;
54
+
55
+ private pid2GroupMap: Map<number, PanoramaGroup>;
56
+
57
+ // private modelElement: Element;
58
+
59
+ // private modelMesh: Mesh|null;
60
+
61
+ private modelMaterial: NS_THREE.ShaderMaterial;
62
+
63
+ private instantTranslationMaterial: NS_THREE.ShaderMaterial;
64
+
65
+ private raycaster: NS_THREE.Raycaster;
66
+
67
+ private elements: Set<Element>;
68
+
69
+ private view: View;
70
+
71
+ private renderFrame: boolean | undefined;
72
+
73
+ private static RotateSpeed = -1;
74
+
75
+ private static DirectionVectorScalar = -0.0001;
76
+
77
+ private moveOnClick: boolean;
78
+
79
+ private hidePanoramas: boolean;
80
+
81
+ private showModel: boolean;
82
+
83
+ private fovRange: { min: number; max: number };
84
+
85
+ private onScreenDetectRadius: number;
86
+
87
+ private rotationLocks: {
88
+ lockAzimuth: boolean;
89
+ lockPolar: boolean;
90
+ centralAzimuth: number;
91
+ centralPolar: number;
92
+ azimuthRange: number;
93
+ polarRange: number;
94
+ };
95
+
96
+ private captureMove: boolean;
97
+
98
+ public rotateSpeed: number;
99
+
100
+ private panoramaGroupChanged: boolean;
101
+
102
+ // private tween: TWEEN.Tween;
103
+
104
+ private cancelAnimation: boolean;
105
+
106
+ /**
107
+ * 获得模型顶点着色器
108
+ * @ignore
109
+ * @returns {string} 顶点着色器代码
110
+ */
111
+ static getModelVS(): string {
112
+ const vertexShader = `
113
+ uniform vec3 pano0Position;
114
+ uniform mat4 pano0Matrix;
115
+ uniform vec3 pano1Position;
116
+ uniform mat4 pano1Matrix;
117
+
118
+ varying vec3 vWorldPosition0;
119
+ varying vec3 vWorldPosition1;
120
+
121
+ void main() {
122
+
123
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
124
+
125
+ vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position;
126
+ vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
127
+ vWorldPosition0.y *= -1.0;
128
+
129
+ vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
130
+ vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
131
+ vWorldPosition1.y *= -1.0;
132
+
133
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
134
+ }`;
135
+ return vertexShader;
136
+ }
137
+
138
+ static getInstantTranslationVS(): string {
139
+ // L == lookAt = Inv(R) * Inv(T)
140
+ // L1 * p1 = L0 * p0 => p0 = Inv(L0) * L1 * p1
141
+ // Let T = Inv(L0) * L1
142
+ const vertexShader = `
143
+ uniform mat4 matrixT;
144
+
145
+ uniform vec3 pano0Position;
146
+ uniform mat4 pano0Matrix;
147
+ uniform vec3 pano1Position;
148
+ uniform mat4 pano1Matrix;
149
+
150
+ varying vec3 vWorldPosition0;
151
+ varying vec3 vWorldPosition1;
152
+
153
+ void main() {
154
+
155
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
156
+ vec4 worldPosition0 = matrixT * worldPosition;
157
+
158
+ vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
159
+ vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
160
+ vWorldPosition1.y *= -1.0;
161
+
162
+ vec3 positionLocalToPanoCenter0 = worldPosition0.xyz - pano0Position;
163
+ vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
164
+ vWorldPosition0.y *= -1.0;
165
+
166
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
167
+ }`;
168
+ return vertexShader;
169
+ }
170
+
171
+ /**
172
+ * 获得模型片源着色器
173
+ * @ignore
174
+ * @returns {string} 片源着色器代码
175
+ */
176
+ static getModelFS(): string {
177
+ const fragmentShader = `
178
+ uniform float weight0;
179
+ uniform float weight1;
180
+
181
+ uniform samplerCube pano0Map;
182
+
183
+ uniform samplerCube pano1Map;
184
+
185
+ varying vec3 vWorldPosition0;
186
+ varying vec3 vWorldPosition1;
187
+
188
+ void main() {
189
+ vec3 cp0 = vWorldPosition0.xyz;
190
+ vec3 cp1 = vWorldPosition1.xyz;
191
+ vec4 colorFromPano0 = textureCube( pano0Map, cp0);
192
+ vec4 colorFromPano1 = textureCube( pano1Map, cp1);
193
+
194
+ vec4 colorFromPanos;
195
+ // 'colorFromPanos = mix(colorFromPano0, colorFromPano1, progress);
196
+ colorFromPanos = colorFromPano0 * weight0 + colorFromPano1 * weight1;
197
+ gl_FragColor = vec4(colorFromPanos.rgb, 1.0);
198
+ }`;
199
+ return fragmentShader;
200
+ }
201
+
202
+ static debugModelVS(): string {
203
+ const vertexShader = `
204
+ uniform vec2 xRange;
205
+ uniform vec2 yRange;
206
+ uniform vec2 zRange;
207
+ varying vec4 vColor;
208
+
209
+ void main() {
210
+ vColor = vec4((position.x - xRange.x) / xRange.y, (position.y - yRange.x) / yRange.y, (position.z - zRange.x) / zRange.y, 1.0);
211
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
212
+ }`;
213
+ return vertexShader;
214
+ }
215
+
216
+ static debugModelFS(): string {
217
+ const fragmentShader = `
218
+ varying vec4 vColor;
219
+
220
+ void main() {
221
+ gl_FragColor = vColor;
222
+ }`;
223
+ return fragmentShader;
224
+ }
225
+
226
+ async dispose(): Promise<void> {
227
+ if (this.modelMaterial) {
228
+ this.modelMaterial.dispose();
229
+ }
230
+ if (this.instantTranslationMaterial) {
231
+ this.instantTranslationMaterial.dispose();
232
+ }
233
+ this.setTouchEnabled(false);
234
+ this.setMouseClickEnabled(false);
235
+
236
+ TextureCache.disposeAll();
237
+ CubeTextureCache.disposeAll();
238
+
239
+ if (this.translatePromise) {
240
+ await this.translatePromise;
241
+ }
242
+ }
243
+
244
+ /**
245
+ *
246
+ * @param view 绑定的View
247
+ * @param panoramaGroups 全景图组数组,至少需要有一个元素
248
+ * @param showModel 可选,是否一开始就显示模型
249
+ * @example
250
+ * ``` typescript
251
+ * panoCtl = new PanoramaController(view, panoMgr);
252
+ * panoCtl.setMouseClickEnabled(true);
253
+ * stage.bindController(panoCtl);
254
+ * panoCtl.lookFromPanorama(0, new Vector3(-1, 0, 0));
255
+ */
256
+ constructor(view: View, panoramaGroups?: PanoramaGroup|PanoramaGroup[], showModel?: boolean) {
257
+ super();
258
+ const { THREE } = Externals.getInstance();
259
+ this.hidePanoramas = false;
260
+ this.showModel = showModel === undefined || showModel;
261
+ this.panoramaGroupChanged = true;
262
+
263
+ this.touches = {
264
+ s: [new THREE.Vector2(), new THREE.Vector2()],
265
+ c: [new THREE.Vector2(), new THREE.Vector2()],
266
+ state: 'idle',
267
+ dist: 0,
268
+ fov: 60,
269
+ };
270
+
271
+ this.touchStartHandler = (event: TouchEvent): void => {
272
+ // event.preventDefault();
273
+ const l = event.touches.length;
274
+ const tl = event.targetTouches.length;
275
+ for (let i = 0; i < Math.min(l, 2); i++) {
276
+ const t = event.touches[i];
277
+ this.touches.s[i] = new THREE.Vector2(t.clientX, t.clientY);
278
+ }
279
+ this.touches.state = 'down';
280
+ if (tl > 1 && this.view.camera instanceof THREE.PerspectiveCamera) {
281
+ this.touches.state = 'zoom';
282
+ this.touches.dist = this.touches.s[0].distanceTo(this.touches.s[1]);
283
+ this.touches.fov = this.view.camera.fov;
284
+ }
285
+ };
286
+
287
+ this.touchMoveHandler = (event: TouchEvent): void => {
288
+ if (!this.view.camera || !(this.view.camera instanceof THREE.PerspectiveCamera)) return;
289
+ if (this.touches.state === 'idle') return;
290
+
291
+ event.preventDefault();
292
+ event.stopPropagation();
293
+
294
+ const l = event.touches.length;
295
+ for (let i = 0; i < Math.min(l, 2); i++) {
296
+ const t = event.touches[i];
297
+ this.touches.c[i] = new THREE.Vector2(t.clientX, t.clientY);
298
+ }
299
+
300
+ if (this.touches.state === 'down' && this.touches.c[0].distanceToSquared(this.touches.s[0]) > 100) {
301
+ this.touches.state = 'move';
302
+ } else if (this.touches.state === 'zoom') {
303
+ const distDiff = this.touches.c[0].distanceTo(this.touches.c[1]) - this.touches.dist;
304
+ const { innerWidth, innerHeight } = window;
305
+ const diagnalDist = Math.sqrt((innerWidth ** 2) + (innerHeight ** 2));
306
+ const distRatio = distDiff / diagnalDist;
307
+
308
+ this.view.camera.fov = Math.min(
309
+ Math.max(this.touches.fov - distRatio * 90, this.fovRange.min),
310
+ this.fovRange.max,
311
+ );
312
+ this.view.camera.updateProjectionMatrix();
313
+ this.orbitControl.rotateSpeed = -this.view.camera.fov / 360 * this.rotateSpeed;
314
+ this.renderThisFrame();
315
+ }
316
+ };
317
+
318
+ this.touchEndHandler = async (event: TouchEvent): Promise<void> => {
319
+ if (this.touches.state === 'idle') return;
320
+
321
+ if (this.touches.state === 'down' && this.view.renderer) {
322
+ const touchPoint = new THREE.Vector2(this.touches.s[0].x, this.touches.s[0].y);
323
+ const { clientWidth, clientHeight } = this.view.container;
324
+ const { left: rectX, top: rectY } = this.view.container.getBoundingClientRect();
325
+ const x = touchPoint.x - rectX;
326
+ const y = touchPoint.y - rectY;
327
+ this.raycaster.setFromCamera({ x, y }, (this.view.camera as NS_THREE.Camera));
328
+ if (this.currentPanoramaGroup) {
329
+ let toPID: number;
330
+ if (this.onScreenDetectRadius > 0 && this.view.camera) {
331
+ toPID = this.currentPanoramaGroup.intersectIndicatorsOnScreen(
332
+ new THREE.Vector2(x, y),
333
+ this.onScreenDetectRadius,
334
+ { screenWidth: clientWidth, screenHeight: clientHeight },
335
+ this.view.camera,
336
+ );
337
+ } else {
338
+ toPID = this.currentPanoramaGroup.intersectIndicators(
339
+ this.raycaster.ray.origin,
340
+ this.raycaster.ray.direction,
341
+ );
342
+ }
343
+ if (toPID !== -1) {
344
+ this.emit(Events.CLICK_PANORAMA, toPID, event);
345
+ // this.moveToPanorama(toPID, { interval: 2000, toDirection: new Vector3(-0.8, 0.6, 0.0) });
346
+ if (this.moveOnClick && this.currentPanoramaGroup.currentPanoramaID !== toPID) {
347
+ await this.moveToPanorama(toPID, { interval: 1000, showModel: true, fadeInOut: false });
348
+ }
349
+ }
350
+ }
351
+ }
352
+
353
+ this.touches.state = 'idle';
354
+ };
355
+
356
+ this.mouseDownHandler = (event: PointerEvent): void => {
357
+ if (event.pointerType !== 'mouse') return;
358
+ // this.mouseMovement = new Vector2(event.movementX, event.movementY).length();
359
+ this.touches.s[0] = new THREE.Vector2(event.clientX, event.clientY);
360
+ this.touches.state = 'down';
361
+ };
362
+ this.mouseMoveHandler = (event: PointerEvent): void => {
363
+ if (event.pointerType !== 'mouse') return;
364
+ // this.mouseMovement += new Vector2(event.movementX, event.movementY).length();
365
+ this.touches.c[0] = new THREE.Vector2(event.clientX, event.clientY);
366
+ if (this.touches.state === 'down' && this.touches.c[0].distanceToSquared(this.touches.s[0]) > 100) {
367
+ this.touches.state = 'move';
368
+ }
369
+ if (this.raycaster && this.captureMove) {
370
+ const { clientWidth, clientHeight } = this.view.container;
371
+ const { left: rectX, top: rectY } = this.view.container.getBoundingClientRect();
372
+ const x = event.clientX - rectX;
373
+ const y = event.clientY - rectY;
374
+ this.raycaster.setFromCamera({ x, y }, (this.view.camera as NS_THREE.Camera));
375
+ if (this.currentPanoramaGroup) {
376
+ let toPID: number;
377
+ if (this.onScreenDetectRadius > 0 && this.view.camera) {
378
+ toPID = this.currentPanoramaGroup.intersectIndicatorsOnScreen(
379
+ new THREE.Vector2(x, y),
380
+ this.onScreenDetectRadius,
381
+ { screenWidth: clientWidth, screenHeight: clientHeight },
382
+ this.view.camera,
383
+ );
384
+ } else {
385
+ toPID = this.currentPanoramaGroup.intersectIndicators(
386
+ this.raycaster.ray.origin,
387
+ this.raycaster.ray.direction,
388
+ );
389
+ }
390
+ if (toPID > -1) {
391
+ this.emit(
392
+ Events.PANORAMA_HOVER,
393
+ toPID,
394
+ this.currentPanoramaGroup.getIndicatorPosition(toPID),
395
+ );
396
+ }
397
+ }
398
+ }
399
+ };
400
+ this.mouseUpHandler = async (event: PointerEvent): Promise<void> => {
401
+ // console.info('## mouseup : ', event);
402
+ // if (this.touches.state === 'idle') return;
403
+ if (event.pointerType !== 'mouse') return;
404
+ if (this.touches.state === 'down') {
405
+ const { clientWidth, clientHeight } = this.view.container;
406
+ const { left: rectX, top: rectY } = this.view.container.getBoundingClientRect();
407
+ const x = event.clientX - rectX;
408
+ const y = event.clientY - rectY;
409
+ if (this.raycaster) {
410
+ this.raycaster.setFromCamera({ x, y }, (this.view.camera as NS_THREE.Camera));
411
+ if (this.onScreenDetectRadius && this.currentPanoramaGroup) {
412
+ let toPID: number;
413
+ if (this.view.camera) {
414
+ toPID = this.currentPanoramaGroup.intersectIndicatorsOnScreen(
415
+ new THREE.Vector2(x, y),
416
+ this.onScreenDetectRadius,
417
+ { screenWidth: clientWidth, screenHeight: clientHeight },
418
+ this.view.camera,
419
+ );
420
+ } else {
421
+ toPID = this.currentPanoramaGroup.intersectIndicators(
422
+ this.raycaster.ray.origin,
423
+ this.raycaster.ray.direction,
424
+ );
425
+ }
426
+ if (toPID !== -1) {
427
+ this.emit(Events.CLICK_PANORAMA, toPID, event);
428
+ // this.moveToPanorama(toPID, { interval: 2000, toDirection: new Vector3(-0.8, 0.6, 0.0) });
429
+ if (event.button === 0 && this.moveOnClick && this.currentPanoramaGroup.currentPanoramaID !== toPID) {
430
+ await this.moveToPanorama(toPID, { interval: 1000, showModel: true, fadeInOut: false });
431
+ }
432
+ }
433
+ }
434
+ }
435
+ }
436
+ this.touches.state = 'idle';
437
+ };
438
+ this.mouseWheelHandler = (event: WheelEvent): void => {
439
+ event.preventDefault();
440
+ if (!(this.view.camera instanceof THREE.PerspectiveCamera)) return;
441
+ this.view.camera.fov = Math.min(
442
+ Math.max(this.view.camera.fov - Math.sign(event.deltaY) * 1.5, this.fovRange.min),
443
+ this.fovRange.max,
444
+ );
445
+ this.view.camera.updateProjectionMatrix();
446
+ this.orbitControl.rotateSpeed = -this.view.camera.fov / 360 * this.rotateSpeed;
447
+ this.renderThisFrame();
448
+ };
449
+
450
+ this.moveOnClick = true;
451
+ this.onScreenDetectRadius = 1000;
452
+
453
+ this.rotateSpeed = 1;
454
+
455
+ if (view) {
456
+ this.bindView(view);
457
+ this.renderThisFrame();
458
+ }
459
+
460
+ if (panoramaGroups) {
461
+ if (panoramaGroups instanceof PanoramaGroup) {
462
+ this.panoramaGroups = [panoramaGroups];
463
+ } else {
464
+ this.panoramaGroups = panoramaGroups;
465
+ }
466
+ } else {
467
+ this.panoramaGroups = [];
468
+ }
469
+ if (this.panoramaGroups.length > 0) {
470
+ [this.currentPanoramaGroup] = this.panoramaGroups;
471
+ }
472
+ this.pid2GroupMap = new Map();
473
+
474
+ const modelVisible = (undefined === showModel || showModel === true || this.showModel);
475
+ this.panoramaGroups.forEach((panoGroup: PanoramaGroup) => {
476
+ const modelMesh = PanoramaController.getModelMesh(panoGroup);
477
+ this.setModelAppearance(panoGroup.modelElement!, modelVisible, undefined, modelMesh);
478
+ });
479
+
480
+ // this.mouseMovement = 0;
481
+
482
+ this.isAnimating = false;
483
+
484
+ this.rotationLocks = {
485
+ lockAzimuth: false,
486
+ lockPolar: false,
487
+ centralAzimuth: 0,
488
+ centralPolar: Math.PI / 2,
489
+ azimuthRange: Math.PI,
490
+ polarRange: Math.PI / 2,
491
+ };
492
+
493
+ this.fovRange = { min: 60, max: 90 };
494
+
495
+ this.raycaster = new THREE.Raycaster();
496
+ }
497
+
498
+ public async setViewConfiguration(hidePanoramas: boolean, showModel: boolean): Promise<void> {
499
+ this.hidePanoramas = hidePanoramas;
500
+ this.showModel = showModel;
501
+ if (this.currentPanoramaGroup) {
502
+ const pano = await this.currentPanoramaGroup.getPanoramaByPID(this.currentPanoramaGroup.currentPanoramaID);
503
+ if (pano) {
504
+ pano.addViewConfiguration({
505
+ targetView: this.view,
506
+ showSkyBox: !hidePanoramas,
507
+ });
508
+ }
509
+ this.setModelAppearance(this.currentPanoramaGroup.modelElement!, showModel);
510
+ }
511
+ }
512
+
513
+ public bindElement(element: Element | Element[]): void {
514
+ if (element instanceof Array) {
515
+ element.forEach((e) => { this.bindElement(e); });
516
+ } else {
517
+ if (!this.elements) {
518
+ this.elements = new Set();
519
+ }
520
+ this.elements.add(element);
521
+ // if (element.intersectables && element.intersectables.length) {
522
+ // element.intersectables.forEach((object) => {
523
+ // this.intersectables.push({ object, parent: element });
524
+ // });
525
+ // } else {
526
+ // element.children.filter((c) => (c as Mesh).isMesh).forEach((object) => {
527
+ // this.intersectables.push({ object, parent: element });
528
+ // });
529
+ // }
530
+ }
531
+ }
532
+
533
+ public unbindElement(element: Element | Element[]): void {
534
+ if (element instanceof Array) {
535
+ element.forEach((e) => { this.unbindElement(e); });
536
+ } else if (this.elements && this.elements.has(element)) {
537
+ this.elements.delete(element);
538
+ }
539
+ }
540
+
541
+ /**
542
+ * 添加全景图组
543
+ * @param panoramaGroups 新增加的全景图组(单个或数组)
544
+ * @parama showModel 可选,是否一开始就显示模型
545
+ */
546
+ public addPanoramaGroups(panoramaGroups: PanoramaGroup|PanoramaGroup[], showModel?: boolean): void {
547
+ let groupArray: PanoramaGroup[];
548
+ if (panoramaGroups instanceof PanoramaGroup) {
549
+ groupArray = [panoramaGroups as PanoramaGroup];
550
+ } else {
551
+ groupArray = panoramaGroups as PanoramaGroup[];
552
+ }
553
+ this.panoramaGroups.push(...groupArray);
554
+
555
+ const modelVisible = (undefined === showModel || showModel === true || this.showModel);
556
+ groupArray.forEach((panoGroup: PanoramaGroup) => {
557
+ const modelMesh = PanoramaController.getModelMesh(panoGroup);
558
+ this.setModelAppearance(panoGroup.modelElement!, modelVisible, undefined, modelMesh);
559
+ });
560
+ }
561
+
562
+ public removePanoramaGroup(panoramaGroup: PanoramaGroup): boolean {
563
+ const index = this.panoramaGroups.indexOf(panoramaGroup);
564
+ if (index >= 0) {
565
+ this.panoramaGroups = this.panoramaGroups.slice(0, index).concat(this.panoramaGroups.slice(index + 1));
566
+ if (panoramaGroup === this.currentPanoramaGroup) {
567
+ this.currentPanoramaGroup = undefined;
568
+ }
569
+ return true;
570
+ }
571
+ return false;
572
+ }
573
+
574
+ protected renderThisFrame(): void {
575
+ if (!this.renderFrame) {
576
+ this.renderFrame = true;
577
+ }
578
+ }
579
+
580
+ private static getModelMeshInElement(e: NS_THREE.Object3D): NS_THREE.Mesh|undefined {
581
+ let ret;
582
+ const { THREE } = Externals.getInstance();
583
+ if (e instanceof THREE.Mesh) return e;
584
+ if (e) {
585
+ e.traverse((obj) => {
586
+ if (obj instanceof THREE.Mesh) {
587
+ ret = obj as NS_THREE.Mesh;
588
+ }
589
+ });
590
+ }
591
+ return ret;
592
+ }
593
+
594
+ private static getModelMesh(panoGroup: PanoramaGroup): NS_THREE.Mesh|undefined {
595
+ if (panoGroup && panoGroup.modelElement) { // TODO: Multiple children mesh?
596
+ return PanoramaController.getModelMeshInElement(panoGroup.modelElement);
597
+ }
598
+ return undefined;
599
+ }
600
+
601
+ bindView(view: View): void {
602
+ if (!view.camera || !view.renderer) {
603
+ throw new Error('No Camera or Renderer found in view');
604
+ }
605
+ this.view = view;
606
+ const { THREE } = Externals.getInstance();
607
+
608
+ this.setTouchEnabled(true);
609
+
610
+ this.orbitControl = new OrbitControls(view.camera as NS_THREE.PerspectiveCamera, view.container);
611
+ this.orbitControl.addEventListener('start', () => {
612
+ this.renderThisFrame();
613
+ });
614
+ this.orbitControl.addEventListener('end', () => {
615
+ this.renderThisFrame();
616
+ });
617
+ this.orbitControl.addEventListener('change', () => {
618
+ this.emit(Events.PANORAMA_CAMERA_CHANGED, view.camera!.position, view.camera!.quaternion, this);
619
+ const { lockAzimuth, lockPolar } = this.rotationLocks;
620
+ let vFov = 0;
621
+ let hFov = 0;
622
+ if (this.orbitControl.object instanceof THREE.PerspectiveCamera) {
623
+ const { clientWidth, clientHeight } = this.view.container;
624
+ vFov = this.orbitControl.object.fov / 180 * Math.PI;
625
+ hFov = vFov * clientWidth / clientHeight;
626
+ }
627
+ if (lockAzimuth) {
628
+ const { centralAzimuth, azimuthRange } = this.rotationLocks;
629
+ const azimuth = this.orbitControl.getAzimuthalAngle();
630
+ let minAzimuth = centralAzimuth - azimuthRange / 2 + hFov / 2;
631
+ let maxAzimuth = centralAzimuth + azimuthRange / 2 - hFov / 2;
632
+ if (minAzimuth > Math.PI) minAzimuth -= 2 * Math.PI;
633
+ if (maxAzimuth < -Math.PI) maxAzimuth += 2 * Math.PI;
634
+ if (minAzimuth > maxAzimuth) {
635
+ this.orbitControl.minAzimuthAngle = centralAzimuth;
636
+ this.orbitControl.maxAzimuthAngle = centralAzimuth;
637
+ } else {
638
+ if (minAzimuth < -Math.PI) minAzimuth += 2 * Math.PI;
639
+ if (maxAzimuth > Math.PI) maxAzimuth -= 2 * Math.PI;
640
+ if (minAzimuth > maxAzimuth) {
641
+ if (Math.abs(azimuth) > Math.PI - ROTATION_LOCK_BOUNDARY) {
642
+ this.orbitControl.minAzimuthAngle = -Infinity;
643
+ this.orbitControl.maxAzimuthAngle = Infinity;
644
+ } else if (azimuth > 0) {
645
+ this.orbitControl.minAzimuthAngle = minAzimuth;
646
+ this.orbitControl.maxAzimuthAngle = Infinity;
647
+ } else if (azimuth < 0) {
648
+ this.orbitControl.minAzimuthAngle = -Infinity;
649
+ this.orbitControl.maxAzimuthAngle = maxAzimuth;
650
+ }
651
+ } else {
652
+ this.orbitControl.minAzimuthAngle = minAzimuth;
653
+ this.orbitControl.maxAzimuthAngle = maxAzimuth;
654
+ }
655
+ }
656
+ }
657
+ if (lockPolar) {
658
+ const { centralPolar, polarRange } = this.rotationLocks;
659
+ const polar = this.orbitControl.getPolarAngle();
660
+ let minPolar = centralPolar - polarRange / 2 + vFov / 2;
661
+ let maxPolar = centralPolar + polarRange / 2 - vFov / 2;
662
+ if (minPolar > Math.PI) minPolar -= Math.PI;
663
+ if (maxPolar < 0) maxPolar += Math.PI;
664
+ if (minPolar > maxPolar) {
665
+ this.orbitControl.minPolarAngle = centralPolar;
666
+ this.orbitControl.maxPolarAngle = centralPolar;
667
+ } else {
668
+ if (minPolar < 0) minPolar += Math.PI;
669
+ if (maxPolar > Math.PI) maxPolar -= Math.PI;
670
+ if (minPolar > maxPolar) {
671
+ if (Math.abs(polar - Math.PI / 2) > Math.PI / 2 - ROTATION_LOCK_BOUNDARY) {
672
+ this.orbitControl.minPolarAngle = -Infinity;
673
+ this.orbitControl.maxPolarAngle = Infinity;
674
+ } else if (polar > 0) {
675
+ this.orbitControl.minPolarAngle = minPolar;
676
+ this.orbitControl.maxPolarAngle = Infinity;
677
+ } else if (polar < 0) {
678
+ this.orbitControl.minPolarAngle = -Infinity;
679
+ this.orbitControl.maxPolarAngle = maxPolar;
680
+ }
681
+ } else {
682
+ this.orbitControl.minPolarAngle = minPolar;
683
+ this.orbitControl.maxPolarAngle = maxPolar;
684
+ }
685
+ }
686
+ }
687
+ this.renderThisFrame();
688
+ });
689
+
690
+ this.orbitControl.rotateSpeed = PanoramaController.RotateSpeed;
691
+ if (view.camera && view.camera instanceof THREE.PerspectiveCamera) {
692
+ const { fov } = view.camera as NS_THREE.PerspectiveCamera;
693
+ this.orbitControl.rotateSpeed = -fov / 360 * this.rotateSpeed;
694
+ }
695
+
696
+ this.setMouseControls(
697
+ { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN },
698
+ );
699
+ this.setTouchControls({ ONE: THREE.TOUCH.ROTATE, TWO: THREE.TOUCH.PAN });
700
+
701
+ this.setDampingEnabled(true);
702
+ this.setDampingFactor(0.25);
703
+ this.setKeysEnabled(false);
704
+ this.setRotateEnabled(true);
705
+ this.setPanEnabled(false);
706
+ this.setZoomEnabled(false);
707
+ this.orbitControl.update();
708
+
709
+ this.setEnabled(true);
710
+
711
+ this.renderThisFrame();
712
+ }
713
+
714
+ async unbind(): Promise<void> {
715
+ super.unbind();
716
+ if (this.orbitControl) this.orbitControl.dispose();
717
+ await this.dispose();
718
+ }
719
+
720
+ /**
721
+ * @ignore
722
+ */
723
+ update(): boolean {
724
+ if (this.orbitControl && this.orbitControl.enabled) this.orbitControl.update();
725
+
726
+ let result = true;
727
+ if (!this.renderFrame) result = false;
728
+ this.renderFrame = false;
729
+ return result;
730
+ }
731
+
732
+ /**
733
+ * 设置是否启用该控制器
734
+ * @param value 开关值
735
+ */
736
+ public setEnabled(value: boolean): void {
737
+ if (this.orbitControl) this.orbitControl.enabled = value;
738
+ }
739
+
740
+ /**
741
+ * 设置键盘控制启用
742
+ * @param value 是否启用键盘控制
743
+ */
744
+ public setKeysEnabled(value: boolean): void {
745
+ if (!this.orbitControl) return;
746
+ this.orbitControl.enableKeys = value;
747
+ }
748
+
749
+ /**
750
+ * 使能/禁用 鼠标点击
751
+ * @param value 使能还是禁用
752
+ */
753
+ public setMouseClickEnabled(enable: boolean): boolean {
754
+ if (!this.view.renderer) return false;
755
+ const { THREE } = Externals.getInstance();
756
+ if (this.view.camera && this.view.camera instanceof THREE.Camera) {
757
+ if (enable) {
758
+ this.view.container.addEventListener('pointerup', this.mouseUpHandler, false);
759
+ this.view.container.addEventListener('pointermove', this.mouseMoveHandler, false);
760
+ this.view.container.addEventListener('pointerdown', this.mouseDownHandler, false);
761
+ this.view.container.addEventListener('wheel', this.mouseWheelHandler, false);
762
+ } else {
763
+ this.view.container.removeEventListener('pointerup', this.mouseUpHandler, false);
764
+ this.view.container.removeEventListener('pointermove', this.mouseMoveHandler, false);
765
+ this.view.container.removeEventListener('pointerdown', this.mouseDownHandler, false);
766
+ this.view.container.removeEventListener('wheel', this.mouseWheelHandler, false);
767
+ }
768
+ }
769
+ return true;
770
+ }
771
+
772
+ public setTouchEnabled(enable: boolean): boolean {
773
+ if (!this.view.renderer) return false;
774
+ const { THREE } = Externals.getInstance();
775
+ if (this.view.camera && this.view.camera instanceof THREE.Camera) {
776
+ if (enable) {
777
+ this.view.container.addEventListener('touchstart', this.touchStartHandler, false);
778
+ this.view.container.addEventListener('touchmove', this.touchMoveHandler, false);
779
+ this.view.container.addEventListener('touchend', this.touchEndHandler, false);
780
+ this.view.container.addEventListener('touchcancel', this.touchEndHandler, false);
781
+ } else {
782
+ this.view.container.removeEventListener('touchstart', this.touchStartHandler);
783
+ this.view.container.removeEventListener('touchmove', this.touchMoveHandler);
784
+ this.view.container.removeEventListener('touchend', this.touchEndHandler);
785
+ this.view.container.removeEventListener('touchcancel', this.touchEndHandler);
786
+ }
787
+ }
788
+ return true;
789
+ }
790
+
791
+ /**
792
+ * 设置是否启用惯性
793
+ * @param value 开关值
794
+ */
795
+ public setDampingEnabled(value: boolean): void {
796
+ if (!this.orbitControl) return;
797
+ this.orbitControl.enableDamping = value;
798
+ }
799
+
800
+ /**
801
+ * 设置是否启用旋转功能
802
+ * @param value 开关值
803
+ */
804
+ public setRotateEnabled(value: boolean): void {
805
+ if (!this.orbitControl) return;
806
+ this.orbitControl.enableRotate = value;
807
+ }
808
+
809
+ /**
810
+ * 设置是否启用平移功能
811
+ * @param value 开关值
812
+ */
813
+ public setPanEnabled(value: boolean): void {
814
+ if (!this.orbitControl) return;
815
+ this.orbitControl.enablePan = value;
816
+ }
817
+
818
+ /**
819
+ * 设置是否启用缩放功能
820
+ * @param value 开关值
821
+ */
822
+ public setZoomEnabled(value: boolean): void {
823
+ if (!this.orbitControl) return;
824
+ this.orbitControl.enableZoom = value;
825
+ }
826
+
827
+ /**
828
+ * 设置缩放
829
+ * @param zoom 缩放比例值
830
+ */
831
+ public setZoom(zoom: number): void {
832
+ if (!this.orbitControl) return;
833
+ const { THREE } = Externals.getInstance();
834
+ if (
835
+ !(this.view.camera! instanceof THREE.PerspectiveCamera)
836
+ && !(this.view.camera! instanceof THREE.OrthographicCamera)
837
+ ) throw new Error('Cannot set zoom for camera');
838
+ this.view.camera.zoom = zoom;
839
+ this.view.camera.updateProjectionMatrix();
840
+ this.renderFrame = true;
841
+ }
842
+
843
+ /**
844
+ * 设置FOV, 不可以超过setFOVRange所设置的范围.
845
+ * @param fov 垂直方向视场角
846
+ */
847
+ public setFOV(fov: number): void {
848
+ const { THREE } = Externals.getInstance();
849
+ if (!this.orbitControl || !(this.view.camera! instanceof THREE.PerspectiveCamera)) return;
850
+ const targetFov = Math.min(Math.max(fov, this.fovRange.min), this.fovRange.max);
851
+ this.view.camera.fov = targetFov;
852
+ this.view.camera.updateProjectionMatrix();
853
+ this.orbitControl.rotateSpeed = -targetFov / 360 * this.rotateSpeed;
854
+ this.renderFrame = true;
855
+ }
856
+
857
+ /**
858
+ * 设置FOV范围, 默认为[60, 90]
859
+ * @param min 垂直方向视场角最小值
860
+ * @param max 垂直方向视场角最大值
861
+ */
862
+ public setFOVRange(min: number, max: number): void {
863
+ this.fovRange.min = min;
864
+ this.fovRange.max = max;
865
+ const { THREE } = Externals.getInstance();
866
+ if (!this.orbitControl || !(this.view.camera! instanceof THREE.PerspectiveCamera)) return;
867
+ this.setFOV(this.view.camera.fov);
868
+ }
869
+
870
+ /**
871
+ * 设置惯性阻尼
872
+ * @param value 衰减值
873
+ */
874
+ public setDampingFactor(value: number): void {
875
+ if (!this.orbitControl) return;
876
+ this.orbitControl.dampingFactor = value;
877
+ }
878
+
879
+ /**
880
+ * 设置位移速度
881
+ * @param value 位移速度
882
+ */
883
+ public setPanSpeed(value: number): void {
884
+ if (!this.orbitControl) return;
885
+ this.orbitControl.panSpeed = value;
886
+ }
887
+
888
+ /**
889
+ * 设置旋转速度
890
+ * @param value 旋转速度
891
+ */
892
+ // public setRotateSpeed(value: number): void {
893
+ // if (!this.orbitControl) return;
894
+ // this.orbitControl.rotateSpeed = value;
895
+ // }
896
+
897
+ /**
898
+ * 设置触摸操作模式
899
+ * @param touches 触摸配置
900
+ */
901
+ public setTouchControls(touches: { ONE: NS_THREE.TOUCH; TWO: NS_THREE.TOUCH }): void {
902
+ if (!this.orbitControl) return;
903
+ this.orbitControl.touches = touches;
904
+ }
905
+
906
+ /**
907
+ * 设置鼠标操作模式
908
+ * @param mouseButtons 鼠标按键配置
909
+ */
910
+ public setMouseControls(
911
+ mouseButtons: { LEFT: NS_THREE.MOUSE; MIDDLE: NS_THREE.MOUSE; RIGHT: NS_THREE.MOUSE },
912
+ ): void {
913
+ if (!this.orbitControl) return;
914
+ this.orbitControl.mouseButtons = mouseButtons;
915
+ }
916
+
917
+ /**
918
+ * 设置控制中心点
919
+ * @param x 世界坐标X
920
+ * @param y 世界坐标Y
921
+ * @param z 世界坐标Z
922
+ */
923
+ public setTarget(x: number, y: number, z: number): void {
924
+ if (!this.orbitControl) return;
925
+ this.orbitControl.target.set(x, y, z);
926
+ this.orbitControl.update();
927
+ }
928
+
929
+ /**
930
+ * 设置摄像机观察方向和位置
931
+ * @param position 摄像机所在位置
932
+ * @param lookAt 观察目标点,同时也是[[OrbitControls]]的旋转中心
933
+ */
934
+ public setCameraPose(position: [number, number, number], lookAt: [number, number, number], useLookAt = true): void {
935
+ if (this.view.camera) {
936
+ this.view.camera.position.set(...position);
937
+ // this.view.camera.lookAt(...lookAt);
938
+ }
939
+ if (useLookAt) this.setTarget(...lookAt);
940
+ // console.log(lookAt);
941
+ this.renderThisFrame();
942
+ }
943
+
944
+ private async getPanoramaOfPID(pid: number):
945
+ Promise<{
946
+ pano?: Panorama;
947
+ panoramaGroup?: PanoramaGroup;
948
+ }> {
949
+ const panoGroup = this.pid2GroupMap.get(pid);
950
+ if (panoGroup) {
951
+ const pano = await panoGroup.getPanoramaByPID(pid);
952
+ return { pano, panoramaGroup: panoGroup };
953
+ }
954
+ for (let i = 0; i < this.panoramaGroups.length; i += 1) {
955
+ const panoramaGroup = this.panoramaGroups[i];
956
+ // eslint-disable-next-line no-await-in-loop
957
+ const pano = await panoramaGroup.getPanoramaByPID(pid);
958
+ if (pano) {
959
+ this.pid2GroupMap.set(pid, panoramaGroup);
960
+ return { pano, panoramaGroup };
961
+ }
962
+ }
963
+ return {};
964
+ }
965
+
966
+ private async preloadCubeTexturesOfPIDs(pids: number[], waitForReadyCount: number,
967
+ recycleIntermediateTextures?: boolean[]): Promise<NS_THREE.CubeTexture[]> {
968
+ const panos = await Promise.all(pids.map((pid) => this.getPanoramaOfPID(pid)));
969
+ const textureURLsArray: (string[]|undefined)[] = panos.map(({ pano }) => {
970
+ if (pano) {
971
+ return pano.textureURLs;
972
+ }
973
+ return undefined;
974
+ });
975
+ return CubeTextureCache.sharedInstance.preloadCubeTextures(
976
+ textureURLsArray,
977
+ waitForReadyCount,
978
+ recycleIntermediateTextures,
979
+ );
980
+ }
981
+
982
+ /**
983
+ * 设置摄像机按指定视线方向看向目标位置
984
+ * @param target 目标位置
985
+ * @param sightDirection 可选,视线方向,不设置则默认以摄像机当前方向
986
+ */
987
+ public setCameraLookAt(target: NS_THREE.Vector3, sightDirection?: NS_THREE.Vector3): void {
988
+ const { x, y, z } = target;
989
+ const { THREE } = Externals.getInstance();
990
+ let direction;
991
+ if (sightDirection) {
992
+ direction = sightDirection.clone().normalize();
993
+ } else if (this.view.camera) {
994
+ direction = this.view.camera.getWorldDirection(new THREE.Vector3(0, 0, -1));
995
+ } else {
996
+ direction = new THREE.Vector3(1, 0, 0);
997
+ }
998
+ const p0 = direction
999
+ .multiplyScalar(PanoramaController.DirectionVectorScalar)
1000
+ .add(target);
1001
+ this.setCameraPose([p0.x, p0.y, p0.z], [x, y, z]);
1002
+ }
1003
+
1004
+ /**
1005
+ * 仅显示指定全景图,但不操作摄像机
1006
+ * @param pid 全景点PID
1007
+ * @parama showModel 可选,是否一开始就显示模型
1008
+ * @param preInitPanoramasStrategy 可选,预创建全景对象的顺序策略,详见[PanoramaGroup]的【initializePanoramasIfNecessary]方法说明
1009
+ */
1010
+ public async showPanorama(pid: number,
1011
+ options?: {
1012
+ lookDirection?: NS_THREE.Vector3;
1013
+ target?: NS_THREE.Vector3;
1014
+ showModel?: boolean;
1015
+ preInitPanoramasStrategy?: 'all'|number|number[];
1016
+ }): Promise<Panorama|undefined> {
1017
+ const {
1018
+ lookDirection, target, showModel, preInitPanoramasStrategy,
1019
+ } = options || {};
1020
+ const { pano, panoramaGroup } = await this.getPanoramaOfPID(pid);
1021
+ if (panoramaGroup) {
1022
+ if (this.currentPanoramaGroup !== panoramaGroup) this.panoramaGroupChanged = true;
1023
+
1024
+ this.currentPanoramaGroup = panoramaGroup;
1025
+ if (panoramaGroup.modelElement) {
1026
+ this.setModelAppearance(panoramaGroup.modelElement, false, undefined);
1027
+ }
1028
+ if (preInitPanoramasStrategy) {
1029
+ panoramaGroup.initializePanoramasIfNecessary(preInitPanoramasStrategy);
1030
+ }
1031
+ panoramaGroup.panoramaIDsAround(pid);
1032
+ // const allPanos = await panoramaGroup.allPanoramas();
1033
+ // // console.info(`#Async# showPanorama : allPanos(${allPanos!.length})=`, allPanos);
1034
+ // allPanos.forEach((panorama: Panorama) => {
1035
+ // panorama.addViewConfiguration({
1036
+ // targetView: this.view,
1037
+ // showBorder: false,
1038
+ // showSkyBox: false,
1039
+ // });
1040
+ // });
1041
+ // if (aroundPIDs) {
1042
+ // const panoramas = await Promise.all(aroundPIDs.map((panoID: number) => panoramaGroup.getPanoramaByPID(panoID)));
1043
+ // console.info('#Async# showPanorama : panoramas=', panoramas);
1044
+ // panoramas.forEach((panorama: Panorama) => {
1045
+ // panorama.addViewConfiguration({
1046
+ // targetView: this.view,
1047
+ // showBorder: false,
1048
+ // showSkyBox: false,
1049
+ // });
1050
+ // });
1051
+ // }
1052
+
1053
+ panoramaGroup.presentPanoramaIndicatorsAround(pid, this.view);
1054
+ if (pano) {
1055
+ if (lookDirection) {
1056
+ this.setCameraLookAt(pano.position, lookDirection);
1057
+ } else if (target) {
1058
+ this.setCameraLookAt(pano.position, target.clone().sub(pano.position));
1059
+ }
1060
+ if (!pano.legacyMode) {
1061
+ const tiles = pano.getIntersectedTiles(this.view.camera);
1062
+ await panoramaGroup.presentPanoramaAround(pid, tiles.hdTiles, tiles.ldTiles, this.view);
1063
+ } else {
1064
+ await panoramaGroup.presentPanoramaAround(pid, [], [], this.view);
1065
+ }
1066
+ pano.addViewConfiguration({
1067
+ targetView: this.view,
1068
+ showBorder: false,
1069
+ showSkyBox: !this.hidePanoramas, // /true,
1070
+ });
1071
+
1072
+ if (undefined === showModel || showModel === true) {
1073
+ const material = this.getModelMaterial();
1074
+ const uniforms = material.uniforms as { [uniform: string]: NS_THREE.IUniform };
1075
+ uniforms.pano0Matrix.value = pano.matrix;
1076
+ uniforms.pano0Position.value = pano.position;
1077
+ uniforms.pano1Matrix.value = pano.matrix;
1078
+ uniforms.pano1Position.value = pano.position;
1079
+ uniforms.weight0.value = 1.0;
1080
+ uniforms.weight1.value = 0.0;
1081
+
1082
+ const textures: NS_THREE.CubeTexture[] = await CubeTextureCache.sharedInstance.preloadCubeTextures(
1083
+ [pano.textureURLs], 1,
1084
+ );
1085
+ [uniforms.pano0Map.value, uniforms.pano1Map.value] = [textures[0], textures[0]];
1086
+ this.setModelAppearance(panoramaGroup.modelElement!, true, material);
1087
+ }
1088
+ }
1089
+ return pano;
1090
+ }
1091
+ return undefined;
1092
+ }
1093
+
1094
+ /**
1095
+ * 从指定全景图中心以指定视线方向观看
1096
+ * @param pid 全景图PID
1097
+ * @param lookDirection 视线方向
1098
+ * @parama showModel 可选,是否一开始就显示模型
1099
+ * @param preInitPanoramasStrategy 可选,预创建全景对象的顺序策略,详见[PanoramaGroup]的【initializePanoramasIfNecessary]方法说明
1100
+ */
1101
+ public async lookFromPanorama(pid: number,
1102
+ lookDirection?: NS_THREE.Vector3,
1103
+ showModel?: boolean,
1104
+ preInitPanoramasStrategy?: 'all'|number|number[]): Promise<void> {
1105
+ const pano = await this.showPanorama(pid, { lookDirection, showModel, preInitPanoramasStrategy });
1106
+ this.emit(Events.MOVE_TO_PANORAMA, pid, pano ? pano.position : null, this.panoramaGroupChanged);
1107
+ this.panoramaGroupChanged = false;
1108
+ }
1109
+
1110
+ /**
1111
+ * 从指定全景图中心看向指定位置
1112
+ * @param pid 全景图PID
1113
+ * @param target 目标位置
1114
+ * @parama showModel 可选,是否一开始就显示模型
1115
+ * @param preInitPanoramasStrategy 可选,预创建全景对象的顺序策略,详见[PanoramaGroup]的【initializePanoramasIfNecessary]方法说明
1116
+ */
1117
+ public async lookFromPanoramaTo(pid: number,
1118
+ target: NS_THREE.Vector3,
1119
+ showModel?: boolean,
1120
+ preInitPanoramasStrategy?: 'all'|number|number[]): Promise<void> {
1121
+ const pano = await this.showPanorama(pid, { target, showModel, preInitPanoramasStrategy });
1122
+ this.emit(Events.MOVE_TO_PANORAMA, pid, pano ? pano.position : null, this.panoramaGroupChanged);
1123
+ this.panoramaGroupChanged = false;
1124
+ }
1125
+
1126
+ public static createModelUniforms(): { [uniform: string]: NS_THREE.IUniform } {
1127
+ const { THREE } = Externals.getInstance();
1128
+ const modelUniforms = {
1129
+ weight0: {
1130
+ type: 'f',
1131
+ value: 0,
1132
+ },
1133
+ weight1: {
1134
+ type: 'f',
1135
+ value: 0,
1136
+ },
1137
+ // 源全景图立方体贴图
1138
+ pano0Map: {
1139
+ type: 't',
1140
+ value: null,
1141
+ },
1142
+ // 源全景图位置
1143
+ pano0Position: {
1144
+ type: 'v3',
1145
+ value: new THREE.Vector3(),
1146
+ },
1147
+ // 源全景图世界变换矩阵
1148
+ pano0Matrix: {
1149
+ type: 'm4',
1150
+ value: new THREE.Matrix4(),
1151
+ },
1152
+ // 目标全景图立方体贴图
1153
+ pano1Map: {
1154
+ type: 't',
1155
+ value: null,
1156
+ },
1157
+ // 目标全景图位置
1158
+ pano1Position: {
1159
+ type: 'v3',
1160
+ value: new THREE.Vector3(),
1161
+ },
1162
+ // 目标全景图世界变换矩阵
1163
+ pano1Matrix: {
1164
+ type: 'm4',
1165
+ value: new THREE.Matrix4(),
1166
+ },
1167
+ };
1168
+ return modelUniforms;
1169
+ }
1170
+
1171
+ private static createInstantTranslationUniforms(): { [uniform: string]: NS_THREE.IUniform } {
1172
+ const { THREE } = Externals.getInstance();
1173
+ const modelUniforms = {
1174
+ weight0: {
1175
+ type: 'f',
1176
+ value: 0,
1177
+ },
1178
+ weight1: {
1179
+ type: 'f',
1180
+ value: 0,
1181
+ },
1182
+ // 源全景图立方体贴图
1183
+ pano0Map: {
1184
+ type: 't',
1185
+ value: null,
1186
+ },
1187
+ pano0Position: {
1188
+ type: 'v3',
1189
+ value: new THREE.Vector3(),
1190
+ },
1191
+ // 源全景图世界变换矩阵
1192
+ pano0Matrix: {
1193
+ type: 'm4',
1194
+ value: new THREE.Matrix4(),
1195
+ },
1196
+ // 目标全景图立方体贴图
1197
+ pano1Map: {
1198
+ type: 't',
1199
+ value: null,
1200
+ },
1201
+ // 目标全景图位置
1202
+ pano1Position: {
1203
+ type: 'v3',
1204
+ value: new THREE.Vector3(),
1205
+ },
1206
+ // 目标全景图世界变换矩阵
1207
+ pano1Matrix: {
1208
+ type: 'm4',
1209
+ value: new THREE.Matrix4(),
1210
+ },
1211
+ matrixT: {
1212
+ type: 'm4',
1213
+ value: new THREE.Matrix4(),
1214
+ },
1215
+ };
1216
+ return modelUniforms;
1217
+ }
1218
+
1219
+ private getModelMaterial(): NS_THREE.ShaderMaterial {
1220
+ if (this.modelMaterial) {
1221
+ return this.modelMaterial;
1222
+ }
1223
+ const { THREE } = Externals.getInstance();
1224
+ const uniforms = PanoramaController.createModelUniforms();
1225
+ this.modelMaterial = new THREE.ShaderMaterial({
1226
+ side: THREE.DoubleSide,
1227
+ vertexShader: PanoramaController.getModelVS(),
1228
+ fragmentShader: PanoramaController.getModelFS(),
1229
+ uniforms,
1230
+ name: 'modelMaterial',
1231
+ });
1232
+ return this.modelMaterial;
1233
+ }
1234
+
1235
+ private getInstantTranslationMaterial(): NS_THREE.ShaderMaterial {
1236
+ if (this.instantTranslationMaterial) {
1237
+ return this.instantTranslationMaterial;
1238
+ }
1239
+ const { THREE } = Externals.getInstance();
1240
+ const uniforms = PanoramaController.createInstantTranslationUniforms();
1241
+ this.instantTranslationMaterial = new THREE.ShaderMaterial({
1242
+ side: THREE.DoubleSide,
1243
+ vertexShader: PanoramaController.getInstantTranslationVS(),
1244
+ fragmentShader: PanoramaController.getModelFS(),
1245
+ uniforms,
1246
+ name: 'instantTranslationMaterial',
1247
+ });
1248
+ return this.instantTranslationMaterial;
1249
+ }
1250
+
1251
+ /**
1252
+ * @ignore
1253
+ * @param visible
1254
+ */
1255
+ public setModelAppearance(
1256
+ modelElement: NS_THREE.Object3D, visible: boolean,
1257
+ meshMaterial?: NS_THREE.Material|NS_THREE.Material[],
1258
+ modelMesh?: NS_THREE.Mesh,
1259
+ ): void {
1260
+ if (modelElement) {
1261
+ if (modelElement instanceof FloorModel) {
1262
+ (modelElement as FloorModel).addViewConfiguration({
1263
+ targetView: this.view,
1264
+ visible,
1265
+ meshMaterial,
1266
+ });
1267
+ } else {
1268
+ modelElement.visible = visible;
1269
+ let mesh = modelMesh;
1270
+ if (!mesh) {
1271
+ mesh = PanoramaController.getModelMeshInElement(modelElement);
1272
+ }
1273
+ if (mesh && meshMaterial) {
1274
+ mesh.material = meshMaterial;
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+
1280
+ /**
1281
+ * 配置controller是否开启点击移动
1282
+ * @param value 是否开启点击移动
1283
+ */
1284
+ public setMoveOnClickEnabled(value: boolean): void {
1285
+ this.moveOnClick = value;
1286
+ }
1287
+
1288
+ /**
1289
+ * 移动到指定的全景点处
1290
+ * @param toPID 目标全景点ID
1291
+ * @param interval 可选,过渡所用时长
1292
+ * @param easing 可选,插值函数
1293
+ * @param fadeInOut 可选,是否使用淡出淡入变换
1294
+ * @param toDirection 可选,到达目的点时要转到的视线方向,
1295
+ * 若不设置则默认以从起始点到目的点的连线为最终视线方向
1296
+ * @param lookAtTarget 可选,到达目的点时视线看向的位置,优先于toDirection
1297
+ * @param fov 可选,视场角度数
1298
+ * @param rotateDelays 可选,旋转时的延迟时间
1299
+ */
1300
+ public async moveToPanorama(toPID: number,
1301
+ params?: {
1302
+ toDirection?: NS_THREE.Vector3;
1303
+ lookAtTarget?: NS_THREE.Vector3;
1304
+ interval?: number;
1305
+ fov?: number;
1306
+ fadeInOut?: boolean;
1307
+ easing?: {(k: number): number};
1308
+ showModel?: boolean;
1309
+ rotateDelays?: number|number[];
1310
+ }): Promise<void> {
1311
+ const p = params || {};
1312
+ return this.moveInPath([toPID], {
1313
+ queueIfBusy: false,
1314
+ lookAtTargets: p.lookAtTarget,
1315
+ toDirections: p.toDirection,
1316
+ intervals: p.interval,
1317
+ fovs: p.fov,
1318
+ fadeInOuts: p.fadeInOut,
1319
+ easings: p.easing,
1320
+ freeRotation: !p.lookAtTarget,
1321
+ showModel: p.showModel,
1322
+ rotateDelays: p.rotateDelays,
1323
+ });
1324
+ }
1325
+
1326
+ /**
1327
+ * 移动到指定的全景点处
1328
+ * 此方法与[[moveToPanorama]]的不同点在于通过Promise机制实现同步阻塞,
1329
+ * 在前一个Translation未完成时发起的Translation会自动被阻塞到前一个完成时再执行
1330
+ * @param toPID 目标全景点ID
1331
+ * @param interval 可选,过渡所用时长
1332
+ * @param easing 可选,插值函数
1333
+ * @param fadeInOut 可选,是否使用淡出淡入变换
1334
+ * @param toDirection 可选,到达目的点时要转到的视线方向,
1335
+ * 若不设置则默认以从起始点到目的点的连线为最终视线方向
1336
+ * @param lookAtTarget 可选,到达目的点时视线看向的位置,优先于toDirection
1337
+ * @param fov 可选,视场角度数
1338
+ * @param rotateDelays 可选,旋转时的延迟时间
1339
+ */
1340
+ public async moveToPanoramaSync(toPID: number,
1341
+ params?: {
1342
+ toDirection?: NS_THREE.Vector3;
1343
+ lookAtTarget?: NS_THREE.Vector3;
1344
+ interval?: number;
1345
+ fov?: number;
1346
+ fadeInOut?: boolean;
1347
+ easing?: {(k: number): number};
1348
+ showModel?: boolean;
1349
+ rotateDelays?: number|number[];
1350
+ }): Promise<void> {
1351
+ const p = params || {};
1352
+ return this.moveInPath([toPID], {
1353
+ queueIfBusy: true,
1354
+ lookAtTargets: p.lookAtTarget,
1355
+ toDirections: p.toDirection,
1356
+ intervals: p.interval,
1357
+ fovs: p.fov,
1358
+ fadeInOuts: p.fadeInOut,
1359
+ easings: p.easing,
1360
+ freeRotation: !p.lookAtTarget,
1361
+ showModel: p.showModel,
1362
+ rotateDelays: p.rotateDelays,
1363
+ });
1364
+ }
1365
+
1366
+ /**
1367
+ * 摄像机按指定路径运动,并在全景点之间产生渐入渐出效果
1368
+ * @param pathPIDs 目标全景点序列
1369
+ * @param queueIfBusy 可选,指示当当前有动画在进行中时,是把此次动作排队还是直接放弃
1370
+ * @param showModel 可选 是否在移动完成后也保持模型显示(用于遮挡路径)
1371
+ * @param intervals 可选,若为数组则依次是每一段路径所花费的时间间隔,若是一个数则全都用该时间间隔
1372
+ * @param fovs 可选,若为数组则依次是每一段路径结束时的视场角,若是一个数则全都用该视场角
1373
+ * @param toDirections 可选,若为数组则依次是每一段路径结束点的视线方向,若是单一Vector3对象则全用此视线方向
1374
+ * @param lookAtTargets 可选,若为数组则依次是每一段路径所看向的位置,若是单一Vector3对象则始终看向此位置
1375
+ * toDirections与lookAtTargets最多只能有一个,如果同时传入了则只以lookAtTargets为准
1376
+ * @param rotateDelays 可选,旋转时的延迟时间
1377
+ * @param easings 可选,若为数组则依次是每一段路径的动画插值函数,
1378
+ * 若是单一{(k: number): number}对象则全用此插值函数
1379
+ * @example
1380
+ * ``` typescript
1381
+ * panoCtl = new PanoramaController(view, panoMgr, floorModel);
1382
+ * panoCtl.setMouseClickEnabled(true);
1383
+ * stage.bindController(panoCtl);
1384
+ * panoCtl.lookFromPanorama(0, new Vector3(-1, 0, 0));
1385
+ * panoCtl.moveInPath([0, 68, 69, 68, 0], {
1386
+ * queueIfBusy: true,
1387
+ * intervals: [200, 1000, 2000, 1000, 3000],
1388
+ * toDirections: [
1389
+ * new Vector3(-1, 0, 0),
1390
+ * new Vector3(-0.8, 0.6, 0),
1391
+ * new Vector3(-0.6, 0.8, 0),
1392
+ * new Vector3(0, 0.8, 0),
1393
+ * new Vector3(0.6, 0, 0),
1394
+ * ],
1395
+ * });
1396
+ */
1397
+ public async moveInPath(path: number[],
1398
+ params?: {
1399
+ queueIfBusy?: boolean;
1400
+ showModel?: boolean;
1401
+ toDirections?: NS_THREE.Vector3|NS_THREE.Vector3[];
1402
+ lookAtTargets?: NS_THREE.Vector3|NS_THREE.Vector3[];
1403
+ intervals?: number|number[];
1404
+ fovs?: number|number[];
1405
+ fadeInOuts?: boolean|boolean[];
1406
+ easings?: {(k: number): number}|{(k: number): number}[];
1407
+ freeRotation?: boolean;
1408
+ rotateDelays?: number|number[];
1409
+ }): Promise<void> {
1410
+ if (path.length === 0) return;
1411
+ // const path: number[] = pathPIDs;
1412
+
1413
+ const pathPositions: NS_THREE.Vector3[] = [];
1414
+ const inPathPanos = await Promise.all(path.map((pid: number) => this.getPanoramaOfPID(pid)));
1415
+ inPathPanos.forEach((item) => {
1416
+ if (item.pano) {
1417
+ pathPositions.push(item.pano.position.clone());
1418
+ }
1419
+ });
1420
+
1421
+ const {
1422
+ toDirections, lookAtTargets, intervals,
1423
+ fovs, easings,
1424
+ fadeInOuts,
1425
+ queueIfBusy, showModel, freeRotation, rotateDelays,
1426
+ } = params || {};
1427
+ const modelVisible = (undefined === showModel || showModel === true || this.showModel);
1428
+
1429
+ let material: NS_THREE.ShaderMaterial;
1430
+ let uniforms: {[uniform: string]: NS_THREE.IUniform};
1431
+ let previousMaterial: NS_THREE.Material | NS_THREE.Material[] | undefined;
1432
+ let fromPID = -1;
1433
+ let toPID: number;
1434
+ let fadeInOut = false;
1435
+
1436
+ const preloadTextureCount = CubeTextureCache.sharedInstance.getCapacity();
1437
+ let from: {
1438
+ pano?: Panorama;
1439
+ panoramaGroup?: PanoramaGroup;
1440
+ modelMesh?: NS_THREE.Mesh;
1441
+ };
1442
+ let to: {
1443
+ pano?: Panorama;
1444
+ panoramaGroup?: PanoramaGroup;
1445
+ modelMesh?: NS_THREE.Mesh;
1446
+ };
1447
+
1448
+ let modelElement: NS_THREE.Object3D;
1449
+
1450
+ const trivialProgressTransform = (progress: number): number => progress;
1451
+ const fadeInOutProgressTransform = (progress: number): number => {
1452
+ if (progress < 0.25) return 0;
1453
+ if (progress > 0.75) return 1;
1454
+ return 2 * (progress - 0.25);
1455
+ };
1456
+ let progressTransforms: {(progress: number): number}|{(progress: number): number}[]|undefined;
1457
+ if (Array.isArray(fadeInOuts)) {
1458
+ progressTransforms = fadeInOuts.map((b) => (b ? fadeInOutProgressTransform : trivialProgressTransform));
1459
+ } else if (fadeInOuts === true) {
1460
+ progressTransforms = fadeInOutProgressTransform;
1461
+ }
1462
+
1463
+ await this.moveCameraInPath(pathPositions, {
1464
+ queueIfBusy,
1465
+ toDirections,
1466
+ lookAtTargets,
1467
+ intervals,
1468
+ fovs,
1469
+ easings,
1470
+ progressTransforms,
1471
+ freeRotation,
1472
+ rotateDelays,
1473
+ beforeAllMoves: async () => {
1474
+ // console.log('#PanoCtrl# beforeAllMoves');
1475
+ fromPID = this.currentPanoramaGroup ? this.currentPanoramaGroup.currentPanoramaID : -1;
1476
+
1477
+ material = this.getModelMaterial();
1478
+ uniforms = material.uniforms as { [uniform: string]: NS_THREE.IUniform };
1479
+
1480
+ // this.getModelMesh();
1481
+ // if (this.modelMesh) {
1482
+ // previousMaterial = this.modelMesh.material;
1483
+ // this.setModelAppearance(true, material);
1484
+ // }
1485
+ // this.panoramaGroup.setBoundBoxAppearance(material);
1486
+ // this.panoramaGroup.addGroupViewConfiguration({
1487
+ // targetView: this.view,
1488
+ // showBoundBox: true,
1489
+ // });// /!!! master
1490
+ if (path.length > 1) this.emit(Events.PATH_MOVEMENT_START, path);
1491
+ },
1492
+ onOneMoveStart: async (index: number,
1493
+ target0: NS_THREE.Vector3,
1494
+ eye0: NS_THREE.Vector3,
1495
+ target1: NS_THREE.Vector3,
1496
+ eye1: NS_THREE.Vector3,
1497
+ ): Promise<boolean> => {
1498
+ // console.log(`#PanoCtrl# onOneMoveStart(${index}`);
1499
+ // console.log(`#PanoCtrl# Will moveToPanorama from #${fromPID} to #${toPID}`);
1500
+ toPID = path[index];
1501
+ from = await this.getPanoramaOfPID(fromPID);
1502
+ to = await this.getPanoramaOfPID(toPID);
1503
+
1504
+ const { THREE } = Externals.getInstance();
1505
+
1506
+ // console.log(`#PanoCtrl# onOneMoveStart : from(${fromPID})=${from}, to(${toPID})=${to}`);
1507
+ if (!from.pano || !to.pano || !from.panoramaGroup || !to.panoramaGroup) return false;
1508
+ from.modelMesh = PanoramaController.getModelMesh(from.panoramaGroup);
1509
+ to.modelMesh = PanoramaController.getModelMesh(to.panoramaGroup);
1510
+
1511
+ const preloadPIDs = [fromPID];
1512
+ const preloadPIDsSet = new Set();
1513
+ preloadPIDsSet.add(fromPID);
1514
+ for (let i = index; preloadPIDs.length < preloadTextureCount && i < path.length; i += 1) {
1515
+ if (!preloadPIDsSet.has(path[i])) {
1516
+ preloadPIDsSet.add(path[i]);
1517
+ preloadPIDs.push(path[i]);
1518
+ }
1519
+ }
1520
+ await this.preloadCubeTexturesOfPIDs(
1521
+ preloadPIDs,
1522
+ preloadPIDs.length,
1523
+ preloadPIDs.map((pid: number) => (pid === fromPID)),
1524
+ );// #TiledCube# Keep LD cubeTexture
1525
+ this.emit(Events.WILL_MOVE_TO_PANORAMA, toPID, to.pano ? to.pano.position : null);
1526
+
1527
+ if (fromPID === toPID) return false;
1528
+
1529
+ if (Array.isArray(fadeInOuts)) {
1530
+ if (fadeInOuts.length > index) {
1531
+ fadeInOut = fadeInOuts[index];
1532
+ } else if (fadeInOuts.length > 0) {
1533
+ fadeInOut = fadeInOuts[fadeInOuts.length - 1];
1534
+ }
1535
+ } else if (fadeInOuts) {
1536
+ fadeInOut = fadeInOuts as boolean;
1537
+ }
1538
+
1539
+ const translateBetweenGroups = (from.panoramaGroup !== to.panoramaGroup);
1540
+ if (translateBetweenGroups) {
1541
+ material = this.getInstantTranslationMaterial();
1542
+ uniforms = material.uniforms as { [uniform: string]: NS_THREE.IUniform };
1543
+ // /!!!from.panoramaGroup.dispose(from.pano.pid);
1544
+ // TODO: Dispose useless PanoramaGroup(s) after all moves,
1545
+ // and initialize necessary PanoramaGroup(s) before all moves
1546
+ } else {
1547
+ material = this.getModelMaterial();
1548
+ uniforms = material.uniforms as { [uniform: string]: NS_THREE.IUniform };
1549
+ }
1550
+
1551
+ if (!translateBetweenGroups && !modelVisible) {
1552
+ const distance = to.pano!.position.distanceTo(from.pano!.position);
1553
+ const boxGeometry = new THREE.BoxGeometry(5, (from.pano!.position.z + 0.93) * 2, distance * 4);
1554
+ modelElement = new THREE.Mesh(
1555
+ boxGeometry,
1556
+ material,
1557
+ );
1558
+ modelElement.position.copy(from.pano.position);
1559
+ modelElement.up.set(0, 0, 1);
1560
+ modelElement.lookAt(to.pano!.position);
1561
+ to.panoramaGroup.add(modelElement);
1562
+ }
1563
+
1564
+ if (!translateBetweenGroups && !modelVisible) {
1565
+ const distance = to.pano!.position.distanceTo(from.pano!.position);
1566
+ const boxGeometry = new THREE.BoxGeometry(5, (from.pano.position.z + 0.93) * 2, distance * 4);
1567
+ modelElement = new THREE.Mesh(
1568
+ boxGeometry,
1569
+ material,
1570
+ );
1571
+ modelElement.position.copy(from.pano.position);
1572
+ modelElement.up.set(0, 0, 1);
1573
+ modelElement.lookAt(to.pano!.position);
1574
+ to.panoramaGroup.add(modelElement);
1575
+ }
1576
+
1577
+ if (!translateBetweenGroups && !modelVisible) {
1578
+ const distance = to.pano!.position.distanceTo(from.pano!.position);
1579
+ const boxGeometry = new THREE.BoxGeometry(5, (from.pano.position.z + 0.93) * 2, distance * 4);
1580
+ modelElement = new THREE.Mesh(
1581
+ boxGeometry,
1582
+ material,
1583
+ );
1584
+ modelElement.position.copy(from.pano.position);
1585
+ modelElement.up.set(0, 0, 1);
1586
+ modelElement.lookAt(to.pano!.position);
1587
+ to.panoramaGroup.add(modelElement);
1588
+ }
1589
+
1590
+ [to].forEach(({ panoramaGroup, modelMesh }) => {
1591
+ if (modelMesh && panoramaGroup) {
1592
+ previousMaterial = modelMesh.material;
1593
+ if (from.panoramaGroup === to.panoramaGroup) {
1594
+ this.setModelAppearance(panoramaGroup.modelElement!, modelVisible, material, modelMesh);
1595
+ } else {
1596
+ this.setModelAppearance(panoramaGroup.modelElement!, false, material, modelMesh);
1597
+ }
1598
+ panoramaGroup.setBoundBoxAppearance(material);
1599
+ panoramaGroup.addGroupViewConfiguration({
1600
+ targetView: this.view,
1601
+ showBoundBox: true,
1602
+ });
1603
+ }
1604
+ });
1605
+ // console.log(`#Async# moveInPath$onOneMoveStart : Hide 'from' pano#${from.pano.pid}`);
1606
+ from.pano.addViewConfiguration({
1607
+ targetView: this.view,
1608
+ showBorder: false,
1609
+ showSkyBox: false,
1610
+ });
1611
+
1612
+ if (translateBetweenGroups) {
1613
+ // Inv(L0) * L1
1614
+ let up = new THREE.Vector3(0, 1, 0);
1615
+ if (this.view.camera) {
1616
+ up = this.view.camera.up;
1617
+ }
1618
+ const invLookAt0 = new THREE.Matrix4().lookAt(eye0, target0, up);
1619
+ const invLookAt1 = new THREE.Matrix4().lookAt(eye1, target1, up);
1620
+ uniforms.matrixT.value = invLookAt0.multiply(invLookAt1.clone().invert());
1621
+ }
1622
+ uniforms.pano0Matrix.value = from.pano.matrix;
1623
+ uniforms.pano0Position.value = from.pano.position;
1624
+ uniforms.pano1Matrix.value = to.pano.matrix;
1625
+ uniforms.pano1Position.value = to.pano.position;
1626
+ uniforms.weight0.value = 1.0;
1627
+ uniforms.weight1.value = 0.0;
1628
+
1629
+ const textures: NS_THREE.CubeTexture[] = await CubeTextureCache.sharedInstance.preloadCubeTextures(
1630
+ [from.pano.textureURLs, to.pano.textureURLs], 2, [true, false],
1631
+ );
1632
+ [uniforms.pano0Map.value, uniforms.pano1Map.value] = textures;// #TiledCube# Keep LD cubeTexture
1633
+
1634
+ // console.log(`#PanoCtrl# moveToPanorama#onStart from #${fromPID} to #${toPID}`);
1635
+ // if (index === path.length - 1) {
1636
+ // const nextCamera = new PerspectiveCamera();
1637
+ // nextCamera.position.copy(eye1);
1638
+ // nextCamera.lookAt(target1);
1639
+ // const tiles = to.pano!.getIntersectedTiles(nextCamera);
1640
+ // // console.info('#TiledCube# getIntersectedTiles:', tiles.hdTiles, tiles.ldTiles);
1641
+ // to.panoramaGroup.presentPanoramaAround(toPID, tiles.hdTiles, tiles.ldTiles, this.view);
1642
+ // to.panoramaGroup.presentPanoramaIndicatorsAround(toPID, this.view);
1643
+ // }
1644
+ // console.log(`#PanoCtrl# Translate onStart:toPID=${toPID}`);
1645
+ return translateBetweenGroups;
1646
+ },
1647
+ onOneMoveUpdate: (index: number, progress: number) => {
1648
+ if (fromPID === toPID) return;
1649
+ const translateBetweenGroups = (from.panoramaGroup !== to.panoramaGroup);
1650
+ if (translateBetweenGroups) {
1651
+ if (progress < 0.5) {
1652
+ uniforms.weight0.value = 1.0 - progress * 2;
1653
+ uniforms.weight1.value = 0.0;
1654
+ } else {
1655
+ uniforms.weight1.value = progress * 2 - 1.0;
1656
+ uniforms.weight0.value = 0.0;
1657
+ }
1658
+ } else if (fadeInOut) {
1659
+ if (progress < 0.25) {
1660
+ uniforms.weight0.value = 1.0 - progress * 4;
1661
+ uniforms.weight1.value = 0.0;
1662
+ } else if (progress > 0.75) {
1663
+ uniforms.weight1.value = progress * 4 - 3.0;
1664
+ uniforms.weight0.value = 0.0;
1665
+ } else {
1666
+ uniforms.weight1.value = 0.0;
1667
+ uniforms.weight0.value = 0.0;
1668
+ }
1669
+ } else {
1670
+ uniforms.weight0.value = 1.0 - progress;
1671
+ uniforms.weight1.value = progress;
1672
+ }
1673
+ },
1674
+ onOneMoveComplete: async (index: number) => {
1675
+ // console.log(`#PanoCtrl# onOneMoveComplete : from=${from}, to=${to}`);
1676
+ // if (index === path.length - 1) {
1677
+ // const tiles = to.pano!.getIntersectedTiles(this.view.camera);
1678
+ // // console.info('#TiledCube# getIntersectedTiles:', tiles.hdTiles, tiles.ldTiles);
1679
+ // await to.panoramaGroup!.presentPanoramaAround(toPID, tiles.hdTiles, tiles.ldTiles, this.view);
1680
+ // to.panoramaGroup!.presentPanoramaIndicatorsAround(toPID, this.view);
1681
+ // to.pano!.addViewConfiguration({
1682
+ // targetView: this.view,
1683
+ // showBorder: false,
1684
+ // showSkyBox: true,
1685
+ // });
1686
+ // // const allPanos = await to.panoramaGroup!.allPanoramas();
1687
+ // // console.info('#Async# onOneMoveComplete : Set all panos invisible:', allPanos);
1688
+ // // allPanos.forEach((panorama: Panorama) => {
1689
+ // // panorama.addViewConfiguration({
1690
+ // // targetView: this.view,
1691
+ // // showBorder: false,
1692
+ // // showSkyBox: false,
1693
+ // // });
1694
+ // // });
1695
+ // }
1696
+ if (from.modelMesh && from.panoramaGroup && from.panoramaGroup !== to.panoramaGroup) {
1697
+ if (!modelVisible) {
1698
+ this.setModelAppearance(from.panoramaGroup.modelElement!, false, previousMaterial, from.modelMesh);
1699
+ }
1700
+ from.panoramaGroup.addGroupViewConfiguration({
1701
+ targetView: this.view,
1702
+ showBoundBox: false,
1703
+ });
1704
+ }
1705
+
1706
+ to.panoramaGroup!.remove(modelElement);
1707
+
1708
+ this.emit(
1709
+ Events.MOVE_TO_PANORAMA,
1710
+ toPID,
1711
+ to.pano ? to.pano.position : null,
1712
+ from.panoramaGroup !== to.panoramaGroup,
1713
+ );
1714
+ this.panoramaGroupChanged = false;
1715
+
1716
+ if (index < path.length - 1) {
1717
+ fromPID = path[index];
1718
+ }
1719
+ },
1720
+ afterAllMoves: async () => {
1721
+ const tiles = to.pano!.getIntersectedTiles(this.view.camera);
1722
+ // console.info('#TiledCube# getIntersectedTiles:', tiles.hdTiles, tiles.ldTiles);
1723
+ await to.panoramaGroup!.presentPanoramaAround(toPID, tiles.hdTiles, tiles.ldTiles, this.view);
1724
+ // console.log(`#Async# moveInPath$afterAllMoves : Show 'to' pano#${to.pano!.pid}`);
1725
+ to.pano!.addViewConfiguration({
1726
+ targetView: this.view,
1727
+ showBorder: false,
1728
+ showSkyBox: !this.hidePanoramas, // /true,
1729
+ });
1730
+ to.panoramaGroup!.presentPanoramaIndicatorsAround(toPID, this.view);
1731
+ if (fromPID !== toPID && to && from) {
1732
+ if (to.modelMesh && to.panoramaGroup) {
1733
+ if (!modelVisible) {
1734
+ this.setModelAppearance(to.panoramaGroup.modelElement!, false, previousMaterial, to.modelMesh);
1735
+ }
1736
+ to.panoramaGroup.addGroupViewConfiguration({
1737
+ targetView: this.view,
1738
+ showBoundBox: false,
1739
+ });
1740
+ }
1741
+ if (to.panoramaGroup) {
1742
+ this.currentPanoramaGroup = to.panoramaGroup;
1743
+ }
1744
+ }
1745
+ if (path.length > 1) this.emit(Events.PATH_MOVEMENT_COMPLETED, path);
1746
+ },
1747
+ });
1748
+ }
1749
+
1750
+ /**
1751
+ * 摄像机按指定路径运动
1752
+ * @param pathPoints 摄像机运动的路径上每一段目的点的Vector3坐标数组
1753
+ * @param queueIfBusy 可选,指示当当前有动画在进行中时,是把此次动作排队还是直接放弃
1754
+ * @param intervals 可选,若为数组则依次是每一段路径所花费的时间间隔,若是一个数则全都用该时间间隔
1755
+ * @param fovs 可选,若为数组则依次是每一段路径结束时的视场角,若是一个数则全都用该视场角
1756
+ * @param toDirections 可选,若为数组则依次是每一段路径结束点的视线方向,若是单一Vector3对象则全用此视线方向
1757
+ * @param lookAtTargets 可选,若为数组则依次是每一段路径所看向的位置,若是单一Vector3对象则始终看向此位置
1758
+ * toDirections与lookAtTargets最多只能有一个,如果同时传入了则只以lookAtTargets为准
1759
+ * @param easings 可选,若为数组则依次是每一段路径的动画插值函数,
1760
+ * 若是单一{(k: number): number}对象则全用此插值函数
1761
+ * @param rotateDelays 可选,旋转时的延迟时间
1762
+ * @param progressTransforms 可选,转换progress的映射函数,从0~1之间的小数映射到另一个0~1之间的小数
1763
+ * @param beforeAllMoves 整个路径移动即将开始前的回调
1764
+ * @param onOneMoveStart 每段路径移动开始时的回调
1765
+ * @param onOneMoveUpdate 每段路径移动进行中的进度回调
1766
+ * @param onOneMoveComplete 每段路径移动结束时的回调
1767
+ * @param afterAllMoves 整个路径移动结束时的回调
1768
+ * @example
1769
+ * ``` typescript
1770
+ * panoCtl.moveCameraInPath(points, {
1771
+ * queueIfBusy: false,
1772
+ * intervals: [200, 1000, 2000, 1000, 3000],
1773
+ * toDirections: [
1774
+ * new Vector3(-1, 0, 0),
1775
+ * new Vector3(-0.8, 0.6, 0),
1776
+ * new Vector3(-0.6, 0.8, 0),
1777
+ * new Vector3(0, 0.8, 0),
1778
+ * new Vector3(0.6, 0, 0),
1779
+ * ],
1780
+ * });
1781
+ */
1782
+ public async moveCameraInPath(pathPoints: NS_THREE.Vector3[],
1783
+ params?: {
1784
+ queueIfBusy?: boolean;
1785
+ toDirections?: NS_THREE.Vector3|NS_THREE.Vector3[];
1786
+ lookAtTargets?: NS_THREE.Vector3|NS_THREE.Vector3[];
1787
+ intervals?: number|number[];
1788
+ fovs?: number|number[];
1789
+ easings?: {(k: number): number}|{(k: number): number}[];
1790
+ progressTransforms?: {(progress: number): number}|{(progress: number): number}[];
1791
+ rotateDelays?: number|number[];
1792
+
1793
+ beforeAllMoves?: {(): Promise<void>};
1794
+ onOneMoveStart?: {(index: number,
1795
+ target0: NS_THREE.Vector3,
1796
+ eye0: NS_THREE.Vector3,
1797
+ target1: NS_THREE.Vector3,
1798
+ eye1: NS_THREE.Vector3): Promise<boolean>;};
1799
+ onOneMoveUpdate?: {(index: number, progress0: number, progress: number): void};
1800
+ onOneMoveComplete?: {(index: number): void};
1801
+ afterAllMoves?: {(): Promise<void>};
1802
+ freeRotation?: boolean;
1803
+ }): Promise<void> {
1804
+ if (!pathPoints || pathPoints.length === 0) return;
1805
+ const { THREE } = Externals.getInstance();
1806
+ const { queueIfBusy = false } = params || {};
1807
+ if (!queueIfBusy) {
1808
+ if (this.isAnimating) return;
1809
+ this.isAnimating = true;
1810
+ }
1811
+ while (this.translatePromise) {
1812
+ // eslint-disable-next-line no-await-in-loop
1813
+ await this.translatePromise;
1814
+ }
1815
+ // eslint-disable-next-line no-async-promise-executor
1816
+ const translatePromise = new Promise<void>(async (resolve0) => {
1817
+ const {
1818
+ beforeAllMoves,
1819
+ onOneMoveStart,
1820
+ onOneMoveUpdate,
1821
+ onOneMoveComplete,
1822
+ afterAllMoves,
1823
+ } = params || {};
1824
+ let iPath = 0;
1825
+ // eslint-disable-next-line no-async-promise-executor
1826
+ const createTask = (): Promise<void> => new Promise(async (resolve, reject) => {
1827
+ if (!this.view.camera || this.cancelAnimation) {
1828
+ reject();
1829
+ this.cancelAnimation = false;
1830
+ return;
1831
+ }
1832
+
1833
+ const {
1834
+ toDirections,
1835
+ lookAtTargets,
1836
+ intervals,
1837
+ fovs,
1838
+ easings,
1839
+ progressTransforms,
1840
+ freeRotation,
1841
+ rotateDelays,
1842
+ } = params || {};
1843
+
1844
+ const fromPosition = this.orbitControl.target.clone();
1845
+ const toPosition = pathPoints[iPath];
1846
+
1847
+ const diff = toPosition.clone().sub(fromPosition);
1848
+
1849
+ let toDirection = toPosition.clone();
1850
+ // let directionFrom = toPosition;
1851
+ if (Array.isArray(lookAtTargets)) {
1852
+ if (lookAtTargets.length > iPath) {
1853
+ toDirection = lookAtTargets[iPath].clone();
1854
+ } else if (lookAtTargets.length > 0) {
1855
+ toDirection = lookAtTargets[lookAtTargets.length - 1].clone();
1856
+ }
1857
+ } else if (lookAtTargets instanceof THREE.Vector3) {
1858
+ toDirection = (lookAtTargets as NS_THREE.Vector3).clone();
1859
+ } // else {
1860
+ // directionFrom = fromPosition;
1861
+ // }
1862
+
1863
+ let rotateDelay = 0;
1864
+ if (rotateDelays) {
1865
+ if (Array.isArray(rotateDelays)) {
1866
+ if (rotateDelays.length > iPath) {
1867
+ rotateDelay = rotateDelays[iPath];
1868
+ } else if (rotateDelays.length > 0) {
1869
+ rotateDelay = rotateDelays[rotateDelays.length - 1];
1870
+ }
1871
+ } else {
1872
+ rotateDelay = rotateDelays || 0;
1873
+ }
1874
+ }
1875
+
1876
+ if (lookAtTargets || !toDirections) {
1877
+ if (toDirection.distanceToSquared(toPosition) < 0.000001) {
1878
+ toDirection = this.orbitControl.target.clone().sub(this.view.camera.position);
1879
+ } else {
1880
+ toDirection.sub(toPosition);
1881
+ }
1882
+ } else if (Array.isArray(toDirections)) {
1883
+ if (toDirections.length > iPath) {
1884
+ toDirection = toDirections[iPath];
1885
+ } else if (toDirections.length > 0) {
1886
+ toDirection = toDirections[toDirections.length - 1];
1887
+ }
1888
+ } else if (toDirections instanceof THREE.Vector3) {
1889
+ toDirection = toDirections as NS_THREE.Vector3;
1890
+ }
1891
+
1892
+ toDirection.normalize();
1893
+ // toDirection = this.view.camera.up.clone().cross(toDirection.cross(this.view.camera.up));
1894
+ // toDirection.normalize();
1895
+
1896
+ const fromDirection = this.orbitControl.target.clone().sub(this.view.camera.position).normalize();
1897
+ // const diffQuaternion = new Quaternion().setFromUnitVectors(fromDirection, toDirection);
1898
+
1899
+ const quat = new THREE.Quaternion().setFromUnitVectors(this.view.camera.up, new THREE.Vector3(0, 1, 0));
1900
+ const quatInverse = quat.clone().invert();
1901
+
1902
+ fromDirection.applyQuaternion(quat);
1903
+ toDirection.applyQuaternion(quat);
1904
+ const fromSpherical = new THREE.Spherical().setFromVector3(fromDirection);
1905
+ const toSpherical = new THREE.Spherical().setFromVector3(toDirection);
1906
+ const thetaDiff = fromSpherical.theta - toSpherical.theta;
1907
+ fromDirection.applyQuaternion(quatInverse);
1908
+ toDirection.applyQuaternion(quatInverse);
1909
+
1910
+ let toFOV = 60;
1911
+ let fromFOV = 60;
1912
+ if (this.view.camera instanceof THREE.PerspectiveCamera) {
1913
+ const camera = this.view.camera as NS_THREE.PerspectiveCamera;
1914
+ fromFOV = camera.fov;
1915
+ toFOV = camera.fov;
1916
+ if (Array.isArray(fovs)) {
1917
+ if (fovs.length > iPath) {
1918
+ toFOV = fovs[iPath];
1919
+ } else if (fovs.length > 0) {
1920
+ toFOV = fovs[fovs.length - 1];
1921
+ }
1922
+ } else if (fovs) {
1923
+ toFOV = fovs as number;
1924
+ }
1925
+ }
1926
+
1927
+ let interval = 1000;
1928
+ if (Array.isArray(intervals)) {
1929
+ if (intervals.length > iPath) {
1930
+ interval = intervals[iPath];
1931
+ } else if (intervals.length > 0) {
1932
+ interval = intervals[intervals.length - 1];
1933
+ }
1934
+ } else if (intervals) {
1935
+ interval = intervals as number;
1936
+ }
1937
+
1938
+ let easing = TWEEN.Easing.Linear.None;
1939
+ if (Array.isArray(easings)) {
1940
+ if (easings.length > iPath) {
1941
+ easing = easings[iPath];
1942
+ } else if (easings.length > 0) {
1943
+ easing = easings[easings.length - 1];
1944
+ }
1945
+ } else if (typeof easings === 'function') {
1946
+ easing = easings as {(k: number): number};
1947
+ } else if (iPath === 0) {
1948
+ easing = TWEEN.Easing.Quadratic.Out;
1949
+ if ((iPath === pathPoints.length - 1)) easing = TWEEN.Easing.Quadratic.InOut;
1950
+ } else if (iPath === pathPoints.length - 1) {
1951
+ easing = TWEEN.Easing.Quadratic.In;
1952
+ }
1953
+
1954
+ let progressTransform: {(progress: number): number}|undefined;
1955
+ if (Array.isArray(progressTransforms)) {
1956
+ if (progressTransforms.length > iPath) {
1957
+ progressTransform = progressTransforms[iPath];
1958
+ } else if (progressTransforms.length > 0) {
1959
+ progressTransform = progressTransforms[progressTransforms.length - 1];
1960
+ }
1961
+ } else if (progressTransforms) {
1962
+ progressTransform = progressTransforms as {(progress: number): number};
1963
+ }
1964
+
1965
+ const target1 = toPosition;
1966
+ const eye1 = toDirection.clone()
1967
+ .multiplyScalar(PanoramaController.DirectionVectorScalar)
1968
+ .add(target1);
1969
+ const target0 = fromPosition;
1970
+ const eye0 = fromDirection.clone()
1971
+ .multiplyScalar(PanoramaController.DirectionVectorScalar)
1972
+ .add(target0);
1973
+
1974
+ let skipPositionTranslate = false;
1975
+ if (onOneMoveStart) {
1976
+ skipPositionTranslate = await onOneMoveStart(iPath, target0, eye0, target1, eye1);
1977
+ }
1978
+
1979
+ const fromTheta = fromSpherical.theta;
1980
+ const toTheta = Math.abs(thetaDiff) > Math.PI
1981
+ ? toSpherical.theta + Math.sign(thetaDiff) * Math.PI * 2 : toSpherical.theta;
1982
+ const fromPhi = fromSpherical.phi;
1983
+ const toPhi = toSpherical.phi;
1984
+
1985
+ new TWEEN.Tween({ timer: 0 })
1986
+ .to({
1987
+ timer: interval,
1988
+ }, interval)
1989
+ .easing(easing)
1990
+ .onStart(() => {
1991
+ let eye = skipPositionTranslate ? eye1 : eye0;
1992
+ const target = skipPositionTranslate ? target1 : target0;
1993
+
1994
+ if (freeRotation) {
1995
+ this.orbitControl.update();
1996
+ const orbitControlTarget = this.orbitControl.target.clone();
1997
+ const cameraPosition = this.orbitControl.object.position.clone();
1998
+ const originDiff = orbitControlTarget.sub(cameraPosition).normalize();
1999
+ eye = originDiff.multiplyScalar(PanoramaController.DirectionVectorScalar).add(target);
2000
+ }
2001
+
2002
+ this.setCameraPose([eye.x, eye.y, eye.z], [target.x, target.y, target.z]);
2003
+
2004
+ this.renderThisFrame();
2005
+ })
2006
+ .onUpdate(({ timer }) => {
2007
+ const progress = timer / interval;
2008
+ let rotateProgress = (timer - rotateDelay) / (interval - rotateDelay);
2009
+ rotateProgress = easing(Math.max(Math.min(rotateProgress, 1), 0));
2010
+ const theta = fromTheta + (toTheta - fromTheta) * rotateProgress;
2011
+ const phi = fromPhi + (toPhi - fromPhi) * rotateProgress;
2012
+
2013
+ const transformedProgress = progressTransform ? progressTransform(progress) : progress;
2014
+ // const progress = progress0;
2015
+ if (!skipPositionTranslate) {
2016
+ // if (freeRotation) lookAt = this.orbitControl.target.clone();
2017
+ const spherical = new THREE.Spherical(
2018
+ 1,
2019
+ phi,
2020
+ Math.abs(theta) > Math.PI ? theta - Math.sign(theta) * Math.PI * 2 : theta,
2021
+ );
2022
+ spherical.makeSafe();
2023
+ const direction = new THREE.Vector3().setFromSpherical(spherical).applyQuaternion(quatInverse);
2024
+ // console.log(`#PanoCtrl# onUpdate: direction=(${direction.x}, ${direction.y}, ${direction.z})`);
2025
+ const lookAt: NS_THREE.Vector3 = fromPosition.clone().addScaledVector(diff, transformedProgress);
2026
+ this.orbitControl.update();
2027
+ const orbitControlTarget = this.orbitControl.target.clone();
2028
+ const cameraPosition = this.orbitControl.object.position.clone();
2029
+ const originDiff = orbitControlTarget.sub(cameraPosition).normalize();
2030
+ const fromNormalized = fromDirection.clone().normalize();
2031
+ const dist = originDiff.distanceToSquared(fromNormalized);
2032
+ const cameraPos = (freeRotation && dist > 0.0001 ? originDiff : direction)
2033
+ .multiplyScalar(PanoramaController.DirectionVectorScalar)
2034
+ .add(lookAt);
2035
+ this.setCameraPose([cameraPos.x, cameraPos.y, cameraPos.z], [lookAt.x, lookAt.y, lookAt.z]);
2036
+ }
2037
+
2038
+ const currentFOV = fromFOV + transformedProgress * (toFOV - fromFOV);
2039
+ this.setFOV(currentFOV);
2040
+
2041
+ if (onOneMoveUpdate) {
2042
+ onOneMoveUpdate(iPath, progress, transformedProgress);
2043
+ }
2044
+
2045
+ this.renderThisFrame();
2046
+ })
2047
+ .onComplete(async () => {
2048
+ if (!skipPositionTranslate) {
2049
+ const toLookAt = toPosition;
2050
+ this.orbitControl.update();
2051
+ const orbitControlTarget = this.orbitControl.target.clone();
2052
+ const cameraPosition = this.orbitControl.object.position.clone();
2053
+ const originDiff = orbitControlTarget.sub(cameraPosition).normalize();
2054
+ // const toLookAt = freeRotation ? this.orbitControl.target.clone() : toPosition;
2055
+ // console.log(`#PanoCtrl# onComplete: direction=(${toDirection.x}, ${toDirection.y}, ${toDirection.z})`);
2056
+ const cameraPos = (freeRotation ? originDiff : toDirection).clone()
2057
+ .multiplyScalar(PanoramaController.DirectionVectorScalar)
2058
+ .add(toLookAt);
2059
+ this.setCameraPose(
2060
+ [cameraPos.x, cameraPos.y, cameraPos.z],
2061
+ [toLookAt.x, toLookAt.y, toLookAt.z],
2062
+ );
2063
+ }
2064
+
2065
+ this.renderThisFrame();
2066
+
2067
+ if (onOneMoveComplete) {
2068
+ await onOneMoveComplete(iPath);
2069
+ }
2070
+ resolve();
2071
+ })
2072
+ .start();
2073
+ });
2074
+
2075
+ if (beforeAllMoves) {
2076
+ await beforeAllMoves();
2077
+ }
2078
+
2079
+ while (iPath < pathPoints.length) {
2080
+ if (this.cancelAnimation) break;
2081
+ const task = createTask();
2082
+ // eslint-disable-next-line no-await-in-loop
2083
+ await task;
2084
+ iPath += 1;
2085
+ }
2086
+
2087
+ if (!this.cancelAnimation) {
2088
+ if (afterAllMoves) {
2089
+ await afterAllMoves();
2090
+ }
2091
+ }
2092
+
2093
+ this.cancelAnimation = false;
2094
+
2095
+ this.translatePromise = undefined;
2096
+
2097
+ if (!queueIfBusy) {
2098
+ this.isAnimating = false;
2099
+ }
2100
+
2101
+ resolve0();
2102
+ });
2103
+ this.translatePromise = translatePromise;
2104
+ // eslint-disable-next-line consistent-return
2105
+ await translatePromise;
2106
+ }
2107
+
2108
+ public unlockRotation(): void {
2109
+ this.rotationLocks = {
2110
+ lockAzimuth: false,
2111
+ lockPolar: false,
2112
+ centralAzimuth: 0,
2113
+ centralPolar: Math.PI / 2,
2114
+ azimuthRange: Math.PI,
2115
+ polarRange: Math.PI / 2,
2116
+ };
2117
+ this.orbitControl.maxAzimuthAngle = Infinity;
2118
+ this.orbitControl.minAzimuthAngle = -Infinity;
2119
+ this.orbitControl.maxPolarAngle = Infinity;
2120
+ this.orbitControl.minPolarAngle = -Infinity;
2121
+ }
2122
+
2123
+ public unlockPolarAngle(): void {
2124
+ Object.assign(this.rotationLocks, {
2125
+ lockPolar: false,
2126
+ centralPolar: Math.PI / 2,
2127
+ polarRange: Math.PI / 2,
2128
+ });
2129
+ this.orbitControl.maxPolarAngle = Infinity;
2130
+ this.orbitControl.minPolarAngle = -Infinity;
2131
+ }
2132
+
2133
+ public lockPolarAngle(range: number): void {
2134
+ if (range < ROTATION_LOCK_BOUNDARY) throw new Error(`Cannot set polar range smaller than ${ROTATION_LOCK_BOUNDARY}`);
2135
+ Object.assign(this.rotationLocks, {
2136
+ lockPolar: true,
2137
+ polarRange: range,
2138
+ centralPolar: this.orbitControl.getPolarAngle(),
2139
+ });
2140
+ }
2141
+
2142
+ public unlockAzimuthalAngle(): void {
2143
+ Object.assign(this.rotationLocks, {
2144
+ lockAzimuth: false,
2145
+ centralAzimuth: 0,
2146
+ azimuthRange: Math.PI,
2147
+ });
2148
+ this.orbitControl.maxAzimuthAngle = Infinity;
2149
+ this.orbitControl.minAzimuthAngle = -Infinity;
2150
+ }
2151
+
2152
+ public lockAzimuthalAngle(range: number): void {
2153
+ if (range < ROTATION_LOCK_BOUNDARY) throw new Error(`Cannot set azimuth range smaller than ${ROTATION_LOCK_BOUNDARY}`);
2154
+ Object.assign(this.rotationLocks, {
2155
+ lockAzimuth: true,
2156
+ azimuthRange: range,
2157
+ centralAzimuth: this.orbitControl.getAzimuthalAngle(),
2158
+ });
2159
+ }
2160
+
2161
+ /**
2162
+ * 获取当前纵向转动角度
2163
+ */
2164
+ public getPolarAngle(): number {
2165
+ return this.orbitControl.getPolarAngle();
2166
+ }
2167
+
2168
+ /**
2169
+ * 获取当前横向转动角度
2170
+ */
2171
+ public getAzimuthalAngle(): number {
2172
+ return this.orbitControl.getAzimuthalAngle();
2173
+ }
2174
+
2175
+ public setCaptureMove(capture: boolean): void {
2176
+ this.captureMove = capture;
2177
+ }
2178
+
2179
+ public setOnScreenDetectRadius(radius: number): void {
2180
+ this.onScreenDetectRadius = radius;
2181
+ }
2182
+
2183
+ /**
2184
+ * 设置纵向转动范围, 最低为0, 最高为Math.PI
2185
+ * @param min 纵向转动范围最小值
2186
+ * @param max 纵向转动范围最大值
2187
+ */
2188
+ public setPolarAngleRange(min: number, max: number): void {
2189
+ this.orbitControl.minPolarAngle = min;
2190
+ this.orbitControl.maxPolarAngle = max;
2191
+ }
2192
+
2193
+ /**
2194
+ * 设置横向转动范围, 最低为-Math.PI, 最高为Math.PI
2195
+ * @param min 横向转动范围最小值
2196
+ * @param max 横向转动范围最大值
2197
+ */
2198
+ public setAzimuthAngleRange(min: number, max: number): void {
2199
+ this.orbitControl.minAzimuthAngle = min;
2200
+ this.orbitControl.maxAzimuthAngle = max;
2201
+ }
2202
+
2203
+ /**
2204
+ * 设置相机的横向旋转
2205
+ * @param radius 目标弧度
2206
+ */
2207
+ public setAzimuthAngle(radius: number): void {
2208
+ const { minAzimuthAngle, maxAzimuthAngle } = this.orbitControl;
2209
+ this.setAzimuthAngleRange(radius, radius + 0.000001);
2210
+ this.orbitControl.update();
2211
+ this.setAzimuthAngleRange(minAzimuthAngle, maxAzimuthAngle);
2212
+ this.orbitControl.update();
2213
+ this.renderThisFrame();
2214
+ }
2215
+
2216
+ /**
2217
+ * 设置相机的纵向旋转
2218
+ * @param radius 目标弧度
2219
+ */
2220
+ public setPolarAngle(radius: number): void {
2221
+ const { minPolarAngle, maxPolarAngle } = this.orbitControl;
2222
+ this.setPolarAngleRange(radius, radius + 0.000001);
2223
+ this.orbitControl.update();
2224
+ this.setPolarAngleRange(minPolarAngle, maxPolarAngle);
2225
+ this.orbitControl.update();
2226
+ this.renderThisFrame();
2227
+ }
2228
+
2229
+ public stopMoving(): void {
2230
+ this.cancelAnimation = false;
2231
+ }
2232
+ }
2233
+
2234
+ export { PanoramaController };