@anov/3d 0.0.1 → 0.0.2

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 (570) hide show
  1. package/README.md +142 -1
  2. package/dist/core/camera.d.ts +31 -4
  3. package/dist/core/camera.js +62 -52
  4. package/dist/core/control/transformControls.d.ts +12 -0
  5. package/dist/core/control/transformControls.js +72 -0
  6. package/dist/core/cssRenderer.d.ts +17 -0
  7. package/dist/core/cssRenderer.js +36 -0
  8. package/dist/core/global/global.d.ts +27 -0
  9. package/dist/core/global/global.js +72 -0
  10. package/dist/core/global/globalControl.d.ts +17 -0
  11. package/dist/core/global/globalControl.js +62 -0
  12. package/dist/core/group.d.ts +51 -6
  13. package/dist/core/group.js +124 -16
  14. package/dist/core/line.d.ts +13 -0
  15. package/dist/core/line.js +83 -0
  16. package/dist/core/mesh.d.ts +12 -7
  17. package/dist/core/mesh.js +57 -56
  18. package/dist/core/model.d.ts +11 -3
  19. package/dist/core/model.js +34 -7
  20. package/dist/core/scene.d.ts +84 -25
  21. package/dist/core/scene.js +207 -53
  22. package/dist/core/use/useScene.d.ts +10 -0
  23. package/dist/core/use/useScene.js +14 -0
  24. package/dist/core/use/useframe.d.ts +6 -0
  25. package/dist/core/use/useframe.js +11 -0
  26. package/dist/export.d.ts +41 -0
  27. package/dist/export.js +37 -0
  28. package/dist/index.d.ts +3 -6
  29. package/dist/index.js +5 -6
  30. package/dist/threeCell.d.ts +8 -0
  31. package/dist/threeCell.js +16 -0
  32. package/dist/type.d.ts +4 -3
  33. package/dist/utils/createElement.d.ts +103 -0
  34. package/dist/utils/createElement.js +145 -0
  35. package/dist/utils/createLabel.d.ts +2 -0
  36. package/dist/utils/createLabel.js +4 -0
  37. package/dist/utils/index.d.ts +36 -0
  38. package/dist/utils/index.js +76 -0
  39. package/dist/utils/line.d.ts +0 -0
  40. package/dist/utils/line.js +0 -0
  41. package/dist/utils/move.d.ts +48 -0
  42. package/dist/utils/move.js +149 -0
  43. package/examples/fonts/LICENSE +13 -0
  44. package/examples/fonts/README.md +11 -0
  45. package/examples/fonts/droid/NOTICE +190 -0
  46. package/examples/fonts/droid/README.txt +18 -0
  47. package/examples/fonts/droid/droid_sans_bold.typeface.json +1 -0
  48. package/examples/fonts/droid/droid_sans_mono_regular.typeface.json +1 -0
  49. package/examples/fonts/droid/droid_sans_regular.typeface.json +1 -0
  50. package/examples/fonts/droid/droid_serif_bold.typeface.json +1 -0
  51. package/examples/fonts/droid/droid_serif_regular.typeface.json +1 -0
  52. package/examples/fonts/gentilis_bold.typeface.json +1 -0
  53. package/examples/fonts/gentilis_regular.typeface.json +1 -0
  54. package/examples/fonts/helvetiker_bold.typeface.json +1 -0
  55. package/examples/fonts/helvetiker_regular.typeface.json +1 -0
  56. package/examples/fonts/optimer_bold.typeface.json +1 -0
  57. package/examples/fonts/optimer_regular.typeface.json +1 -0
  58. package/examples/fonts/ttf/README.md +9 -0
  59. package/examples/fonts/ttf/kenpixel.ttf +0 -0
  60. package/examples/jsm/animation/AnimationClipCreator.js +116 -0
  61. package/examples/jsm/animation/CCDIKSolver.js +482 -0
  62. package/examples/jsm/animation/MMDAnimationHelper.js +1207 -0
  63. package/examples/jsm/animation/MMDPhysics.js +1406 -0
  64. package/examples/jsm/cameras/CinematicCamera.js +208 -0
  65. package/examples/jsm/capabilities/WebGL.js +91 -0
  66. package/examples/jsm/capabilities/WebGPU.js +53 -0
  67. package/examples/jsm/controls/ArcballControls.js +3224 -0
  68. package/examples/jsm/controls/DragControls.js +220 -0
  69. package/examples/jsm/controls/FirstPersonControls.js +325 -0
  70. package/examples/jsm/controls/FlyControls.js +300 -0
  71. package/examples/jsm/controls/MapControls.js +28 -0
  72. package/examples/jsm/controls/OrbitControls.js +1388 -0
  73. package/examples/jsm/controls/PointerLockControls.js +162 -0
  74. package/examples/jsm/controls/TrackballControls.js +828 -0
  75. package/examples/jsm/controls/TransformControls.js +1557 -0
  76. package/examples/jsm/csm/CSM.js +384 -0
  77. package/examples/jsm/csm/CSMFrustum.js +152 -0
  78. package/examples/jsm/csm/CSMHelper.js +193 -0
  79. package/examples/jsm/csm/CSMShader.js +252 -0
  80. package/examples/jsm/curves/CurveExtras.js +422 -0
  81. package/examples/jsm/curves/NURBSCurve.js +80 -0
  82. package/examples/jsm/curves/NURBSSurface.js +52 -0
  83. package/examples/jsm/curves/NURBSUtils.js +487 -0
  84. package/examples/jsm/effects/AnaglyphEffect.js +154 -0
  85. package/examples/jsm/effects/AsciiEffect.js +263 -0
  86. package/examples/jsm/effects/OutlineEffect.js +539 -0
  87. package/examples/jsm/effects/ParallaxBarrierEffect.js +119 -0
  88. package/examples/jsm/effects/PeppersGhostEffect.js +153 -0
  89. package/examples/jsm/effects/StereoEffect.js +55 -0
  90. package/examples/jsm/environments/DebugEnvironment.js +52 -0
  91. package/examples/jsm/environments/RoomEnvironment.js +148 -0
  92. package/examples/jsm/exporters/DRACOExporter.js +267 -0
  93. package/examples/jsm/exporters/EXRExporter.js +501 -0
  94. package/examples/jsm/exporters/GLTFExporter.js +3161 -0
  95. package/examples/jsm/exporters/KTX2Exporter.js +292 -0
  96. package/examples/jsm/exporters/MMDExporter.js +217 -0
  97. package/examples/jsm/exporters/OBJExporter.js +284 -0
  98. package/examples/jsm/exporters/PLYExporter.js +528 -0
  99. package/examples/jsm/exporters/STLExporter.js +199 -0
  100. package/examples/jsm/exporters/USDZExporter.js +711 -0
  101. package/examples/jsm/geometries/BoxLineGeometry.js +69 -0
  102. package/examples/jsm/geometries/ConvexGeometry.js +53 -0
  103. package/examples/jsm/geometries/DecalGeometry.js +356 -0
  104. package/examples/jsm/geometries/ParametricGeometries.js +254 -0
  105. package/examples/jsm/geometries/ParametricGeometry.js +139 -0
  106. package/examples/jsm/geometries/RoundedBoxGeometry.js +155 -0
  107. package/examples/jsm/geometries/TeapotGeometry.js +704 -0
  108. package/examples/jsm/geometries/TextGeometry.js +57 -0
  109. package/examples/jsm/helpers/LightProbeHelper.js +130 -0
  110. package/examples/jsm/helpers/OctreeHelper.js +73 -0
  111. package/examples/jsm/helpers/PositionalAudioHelper.js +109 -0
  112. package/examples/jsm/helpers/RectAreaLightHelper.js +85 -0
  113. package/examples/jsm/helpers/VertexNormalsHelper.js +96 -0
  114. package/examples/jsm/helpers/VertexTangentsHelper.js +88 -0
  115. package/examples/jsm/helpers/ViewHelper.js +333 -0
  116. package/examples/jsm/interactive/HTMLMesh.js +565 -0
  117. package/examples/jsm/interactive/InteractiveGroup.js +116 -0
  118. package/examples/jsm/interactive/SelectionBox.js +227 -0
  119. package/examples/jsm/interactive/SelectionHelper.js +104 -0
  120. package/examples/jsm/libs/ammo.wasm.js +822 -0
  121. package/examples/jsm/libs/ammo.wasm.wasm +0 -0
  122. package/examples/jsm/libs/basis/README.md +46 -0
  123. package/examples/jsm/libs/basis/basis_transcoder.js +21 -0
  124. package/examples/jsm/libs/basis/basis_transcoder.wasm +0 -0
  125. package/examples/jsm/libs/chevrotain.module.min.js +141 -0
  126. package/examples/jsm/libs/draco/README.md +32 -0
  127. package/examples/jsm/libs/draco/draco_decoder.js +34 -0
  128. package/examples/jsm/libs/draco/draco_decoder.wasm +0 -0
  129. package/examples/jsm/libs/draco/draco_encoder.js +33 -0
  130. package/examples/jsm/libs/draco/draco_wasm_wrapper.js +117 -0
  131. package/examples/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  132. package/examples/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  133. package/examples/jsm/libs/draco/gltf/draco_encoder.js +33 -0
  134. package/examples/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  135. package/examples/jsm/libs/ecsy.module.js +1792 -0
  136. package/examples/jsm/libs/fflate.module.js +2474 -0
  137. package/examples/jsm/libs/ktx-parse.module.js +1 -0
  138. package/examples/jsm/libs/lil-gui.module.min.js +8 -0
  139. package/examples/jsm/libs/lottie_canvas.module.js +14844 -0
  140. package/examples/jsm/libs/meshopt_decoder.module.js +178 -0
  141. package/examples/jsm/libs/mikktspace.module.js +128 -0
  142. package/examples/jsm/libs/mmdparser.module.js +11530 -0
  143. package/examples/jsm/libs/motion-controllers.module.js +397 -0
  144. package/examples/jsm/libs/opentype.module.js +14568 -0
  145. package/examples/jsm/libs/potpack.module.js +125 -0
  146. package/examples/jsm/libs/rhino3dm/rhino3dm.js +21 -0
  147. package/examples/jsm/libs/rhino3dm/rhino3dm.module.js +16 -0
  148. package/examples/jsm/libs/rhino3dm/rhino3dm.wasm +0 -0
  149. package/examples/jsm/libs/stats.module.js +167 -0
  150. package/examples/jsm/libs/tween.module.js +803 -0
  151. package/examples/jsm/libs/utif.module.js +1579 -0
  152. package/examples/jsm/libs/zstddec.module.js +1 -0
  153. package/examples/jsm/lights/IESSpotLight.js +25 -0
  154. package/examples/jsm/lights/LightProbeGenerator.js +252 -0
  155. package/examples/jsm/lights/RectAreaLightUniformsLib.js +79 -0
  156. package/examples/jsm/lines/Line2.js +19 -0
  157. package/examples/jsm/lines/LineGeometry.js +79 -0
  158. package/examples/jsm/lines/LineMaterial.js +702 -0
  159. package/examples/jsm/lines/LineSegments2.js +361 -0
  160. package/examples/jsm/lines/LineSegmentsGeometry.js +241 -0
  161. package/examples/jsm/lines/Wireframe.js +56 -0
  162. package/examples/jsm/lines/WireframeGeometry2.js +24 -0
  163. package/examples/jsm/loaders/3DMLoader.js +1497 -0
  164. package/examples/jsm/loaders/3MFLoader.js +1478 -0
  165. package/examples/jsm/loaders/AMFLoader.js +521 -0
  166. package/examples/jsm/loaders/BVHLoader.js +437 -0
  167. package/examples/jsm/loaders/ColladaLoader.js +4122 -0
  168. package/examples/jsm/loaders/DDSLoader.js +274 -0
  169. package/examples/jsm/loaders/DRACOLoader.js +612 -0
  170. package/examples/jsm/loaders/EXRLoader.js +2309 -0
  171. package/examples/jsm/loaders/FBXLoader.js +4142 -0
  172. package/examples/jsm/loaders/FontLoader.js +183 -0
  173. package/examples/jsm/loaders/GCodeLoader.js +261 -0
  174. package/examples/jsm/loaders/GLTFLoader.js +4576 -0
  175. package/examples/jsm/loaders/HDRCubeTextureLoader.js +115 -0
  176. package/examples/jsm/loaders/IESLoader.js +337 -0
  177. package/examples/jsm/loaders/KMZLoader.js +130 -0
  178. package/examples/jsm/loaders/KTX2Loader.js +868 -0
  179. package/examples/jsm/loaders/KTXLoader.js +176 -0
  180. package/examples/jsm/loaders/LDrawLoader.js +2464 -0
  181. package/examples/jsm/loaders/LUT3dlLoader.js +151 -0
  182. package/examples/jsm/loaders/LUTCubeLoader.js +153 -0
  183. package/examples/jsm/loaders/LWOLoader.js +1052 -0
  184. package/examples/jsm/loaders/LogLuvLoader.js +606 -0
  185. package/examples/jsm/loaders/LottieLoader.js +77 -0
  186. package/examples/jsm/loaders/MD2Loader.js +399 -0
  187. package/examples/jsm/loaders/MDDLoader.js +102 -0
  188. package/examples/jsm/loaders/MMDLoader.js +2273 -0
  189. package/examples/jsm/loaders/MTLLoader.js +567 -0
  190. package/examples/jsm/loaders/MaterialXLoader.js +734 -0
  191. package/examples/jsm/loaders/NRRDLoader.js +699 -0
  192. package/examples/jsm/loaders/OBJLoader.js +905 -0
  193. package/examples/jsm/loaders/PCDLoader.js +467 -0
  194. package/examples/jsm/loaders/PDBLoader.js +232 -0
  195. package/examples/jsm/loaders/PLYLoader.js +771 -0
  196. package/examples/jsm/loaders/PVRLoader.js +251 -0
  197. package/examples/jsm/loaders/RGBELoader.js +468 -0
  198. package/examples/jsm/loaders/RGBMLoader.js +1065 -0
  199. package/examples/jsm/loaders/STLLoader.js +403 -0
  200. package/examples/jsm/loaders/SVGLoader.js +3172 -0
  201. package/examples/jsm/loaders/TDSLoader.js +1124 -0
  202. package/examples/jsm/loaders/TGALoader.js +517 -0
  203. package/examples/jsm/loaders/TIFFLoader.js +36 -0
  204. package/examples/jsm/loaders/TTFLoader.js +214 -0
  205. package/examples/jsm/loaders/TiltLoader.js +520 -0
  206. package/examples/jsm/loaders/USDZLoader.js +633 -0
  207. package/examples/jsm/loaders/VOXLoader.js +311 -0
  208. package/examples/jsm/loaders/VRMLLoader.js +3533 -0
  209. package/examples/jsm/loaders/VTKLoader.js +1163 -0
  210. package/examples/jsm/loaders/XYZLoader.js +106 -0
  211. package/examples/jsm/loaders/lwo/IFFParser.js +1218 -0
  212. package/examples/jsm/loaders/lwo/LWO2Parser.js +414 -0
  213. package/examples/jsm/loaders/lwo/LWO3Parser.js +373 -0
  214. package/examples/jsm/materials/MeshGouraudMaterial.js +420 -0
  215. package/examples/jsm/math/Capsule.js +137 -0
  216. package/examples/jsm/math/ColorConverter.js +36 -0
  217. package/examples/jsm/math/ConvexHull.js +1271 -0
  218. package/examples/jsm/math/ImprovedNoise.js +71 -0
  219. package/examples/jsm/math/Lut.js +204 -0
  220. package/examples/jsm/math/MeshSurfaceSampler.js +250 -0
  221. package/examples/jsm/math/OBB.js +423 -0
  222. package/examples/jsm/math/Octree.js +462 -0
  223. package/examples/jsm/math/SimplexNoise.js +444 -0
  224. package/examples/jsm/misc/ConvexObjectBreaker.js +519 -0
  225. package/examples/jsm/misc/GPUComputationRenderer.js +446 -0
  226. package/examples/jsm/misc/Gyroscope.js +66 -0
  227. package/examples/jsm/misc/MD2Character.js +276 -0
  228. package/examples/jsm/misc/MD2CharacterComplex.js +576 -0
  229. package/examples/jsm/misc/MorphAnimMesh.js +75 -0
  230. package/examples/jsm/misc/MorphBlendMesh.js +322 -0
  231. package/examples/jsm/misc/ProgressiveLightMap.js +323 -0
  232. package/examples/jsm/misc/RollerCoaster.js +566 -0
  233. package/examples/jsm/misc/TubePainter.js +205 -0
  234. package/examples/jsm/misc/Volume.js +473 -0
  235. package/examples/jsm/misc/VolumeSlice.js +229 -0
  236. package/examples/jsm/modifiers/CurveModifier.js +326 -0
  237. package/examples/jsm/modifiers/EdgeSplitModifier.js +279 -0
  238. package/examples/jsm/modifiers/SimplifyModifier.js +525 -0
  239. package/examples/jsm/modifiers/TessellateModifier.js +307 -0
  240. package/examples/jsm/nodes/Nodes.js +171 -0
  241. package/examples/jsm/nodes/accessors/BitangentNode.js +89 -0
  242. package/examples/jsm/nodes/accessors/BufferAttributeNode.js +99 -0
  243. package/examples/jsm/nodes/accessors/BufferNode.js +30 -0
  244. package/examples/jsm/nodes/accessors/CameraNode.js +98 -0
  245. package/examples/jsm/nodes/accessors/CubeTextureNode.js +103 -0
  246. package/examples/jsm/nodes/accessors/ExtendedMaterialNode.js +77 -0
  247. package/examples/jsm/nodes/accessors/InstanceNode.js +71 -0
  248. package/examples/jsm/nodes/accessors/MaterialNode.js +267 -0
  249. package/examples/jsm/nodes/accessors/MaterialReferenceNode.js +39 -0
  250. package/examples/jsm/nodes/accessors/ModelNode.js +34 -0
  251. package/examples/jsm/nodes/accessors/ModelViewProjectionNode.js +29 -0
  252. package/examples/jsm/nodes/accessors/MorphNode.js +70 -0
  253. package/examples/jsm/nodes/accessors/NormalNode.js +96 -0
  254. package/examples/jsm/nodes/accessors/Object3DNode.js +150 -0
  255. package/examples/jsm/nodes/accessors/PointUVNode.js +26 -0
  256. package/examples/jsm/nodes/accessors/PositionNode.js +104 -0
  257. package/examples/jsm/nodes/accessors/ReferenceNode.js +72 -0
  258. package/examples/jsm/nodes/accessors/ReflectVectorNode.js +35 -0
  259. package/examples/jsm/nodes/accessors/SceneNode.js +52 -0
  260. package/examples/jsm/nodes/accessors/SkinningNode.js +93 -0
  261. package/examples/jsm/nodes/accessors/StorageBufferNode.js +27 -0
  262. package/examples/jsm/nodes/accessors/TangentNode.js +103 -0
  263. package/examples/jsm/nodes/accessors/TextureBicubicNode.js +94 -0
  264. package/examples/jsm/nodes/accessors/TextureNode.js +271 -0
  265. package/examples/jsm/nodes/accessors/TextureSizeNode.js +35 -0
  266. package/examples/jsm/nodes/accessors/UVNode.js +47 -0
  267. package/examples/jsm/nodes/accessors/UserDataNode.js +29 -0
  268. package/examples/jsm/nodes/code/CodeNode.js +78 -0
  269. package/examples/jsm/nodes/code/ExpressionNode.js +37 -0
  270. package/examples/jsm/nodes/code/FunctionCallNode.js +96 -0
  271. package/examples/jsm/nodes/code/FunctionNode.js +127 -0
  272. package/examples/jsm/nodes/code/ScriptableNode.js +488 -0
  273. package/examples/jsm/nodes/code/ScriptableValueNode.js +167 -0
  274. package/examples/jsm/nodes/core/ArrayUniformNode.js +26 -0
  275. package/examples/jsm/nodes/core/AttributeNode.js +102 -0
  276. package/examples/jsm/nodes/core/BypassNode.js +45 -0
  277. package/examples/jsm/nodes/core/CacheNode.js +46 -0
  278. package/examples/jsm/nodes/core/ConstNode.js +32 -0
  279. package/examples/jsm/nodes/core/ContextNode.js +61 -0
  280. package/examples/jsm/nodes/core/IndexNode.js +66 -0
  281. package/examples/jsm/nodes/core/InputNode.js +83 -0
  282. package/examples/jsm/nodes/core/LightingModel.js +15 -0
  283. package/examples/jsm/nodes/core/Node.js +454 -0
  284. package/examples/jsm/nodes/core/NodeAttribute.js +15 -0
  285. package/examples/jsm/nodes/core/NodeBuilder.js +1016 -0
  286. package/examples/jsm/nodes/core/NodeCache.js +26 -0
  287. package/examples/jsm/nodes/core/NodeCode.js +15 -0
  288. package/examples/jsm/nodes/core/NodeFrame.js +110 -0
  289. package/examples/jsm/nodes/core/NodeFunction.js +22 -0
  290. package/examples/jsm/nodes/core/NodeFunctionInput.js +17 -0
  291. package/examples/jsm/nodes/core/NodeKeywords.js +80 -0
  292. package/examples/jsm/nodes/core/NodeParser.js +11 -0
  293. package/examples/jsm/nodes/core/NodeUniform.js +28 -0
  294. package/examples/jsm/nodes/core/NodeUtils.js +212 -0
  295. package/examples/jsm/nodes/core/NodeVar.js +14 -0
  296. package/examples/jsm/nodes/core/NodeVarying.js +17 -0
  297. package/examples/jsm/nodes/core/PropertyNode.js +61 -0
  298. package/examples/jsm/nodes/core/StackNode.js +99 -0
  299. package/examples/jsm/nodes/core/TempNode.js +58 -0
  300. package/examples/jsm/nodes/core/UniformNode.js +61 -0
  301. package/examples/jsm/nodes/core/VarNode.js +87 -0
  302. package/examples/jsm/nodes/core/VaryingNode.js +69 -0
  303. package/examples/jsm/nodes/core/constants.js +27 -0
  304. package/examples/jsm/nodes/display/BlendModeNode.js +99 -0
  305. package/examples/jsm/nodes/display/BumpMapNode.js +77 -0
  306. package/examples/jsm/nodes/display/ColorAdjustmentNode.js +100 -0
  307. package/examples/jsm/nodes/display/ColorSpaceNode.js +108 -0
  308. package/examples/jsm/nodes/display/FrontFacingNode.js +27 -0
  309. package/examples/jsm/nodes/display/NormalMapNode.js +106 -0
  310. package/examples/jsm/nodes/display/PosterizeNode.js +32 -0
  311. package/examples/jsm/nodes/display/ToneMappingNode.js +141 -0
  312. package/examples/jsm/nodes/display/ViewportDepthNode.js +69 -0
  313. package/examples/jsm/nodes/display/ViewportDepthTextureNode.js +34 -0
  314. package/examples/jsm/nodes/display/ViewportNode.js +115 -0
  315. package/examples/jsm/nodes/display/ViewportSharedTextureNode.js +31 -0
  316. package/examples/jsm/nodes/display/ViewportTextureNode.js +75 -0
  317. package/examples/jsm/nodes/fog/FogExp2Node.js +35 -0
  318. package/examples/jsm/nodes/fog/FogNode.js +37 -0
  319. package/examples/jsm/nodes/fog/FogRangeNode.js +34 -0
  320. package/examples/jsm/nodes/functions/BSDF/BRDF_GGX.js +40 -0
  321. package/examples/jsm/nodes/functions/BSDF/BRDF_Lambert.js +9 -0
  322. package/examples/jsm/nodes/functions/BSDF/BRDF_Sheen.js +43 -0
  323. package/examples/jsm/nodes/functions/BSDF/DFGApprox.js +29 -0
  324. package/examples/jsm/nodes/functions/BSDF/D_GGX.js +18 -0
  325. package/examples/jsm/nodes/functions/BSDF/EnvironmentBRDF.js +13 -0
  326. package/examples/jsm/nodes/functions/BSDF/F_Schlick.js +16 -0
  327. package/examples/jsm/nodes/functions/BSDF/Schlick_to_F0.js +13 -0
  328. package/examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +20 -0
  329. package/examples/jsm/nodes/functions/PhongLightingModel.js +67 -0
  330. package/examples/jsm/nodes/functions/PhysicalLightingModel.js +343 -0
  331. package/examples/jsm/nodes/functions/material/getGeometryRoughness.js +13 -0
  332. package/examples/jsm/nodes/functions/material/getRoughness.js +18 -0
  333. package/examples/jsm/nodes/geometry/RangeNode.js +104 -0
  334. package/examples/jsm/nodes/gpgpu/ComputeNode.js +85 -0
  335. package/examples/jsm/nodes/lighting/AONode.js +27 -0
  336. package/examples/jsm/nodes/lighting/AmbientLightNode.js +27 -0
  337. package/examples/jsm/nodes/lighting/AnalyticLightNode.js +184 -0
  338. package/examples/jsm/nodes/lighting/DirectionalLightNode.js +40 -0
  339. package/examples/jsm/nodes/lighting/EnvironmentNode.js +191 -0
  340. package/examples/jsm/nodes/lighting/HemisphereLightNode.js +55 -0
  341. package/examples/jsm/nodes/lighting/IESSpotLightNode.js +39 -0
  342. package/examples/jsm/nodes/lighting/LightNode.js +57 -0
  343. package/examples/jsm/nodes/lighting/LightUtils.js +17 -0
  344. package/examples/jsm/nodes/lighting/LightingContextNode.js +102 -0
  345. package/examples/jsm/nodes/lighting/LightingNode.js +21 -0
  346. package/examples/jsm/nodes/lighting/LightsNode.js +128 -0
  347. package/examples/jsm/nodes/lighting/PointLightNode.js +68 -0
  348. package/examples/jsm/nodes/lighting/SpotLightNode.js +89 -0
  349. package/examples/jsm/nodes/loaders/NodeLoader.js +108 -0
  350. package/examples/jsm/nodes/loaders/NodeMaterialLoader.js +59 -0
  351. package/examples/jsm/nodes/loaders/NodeObjectLoader.js +70 -0
  352. package/examples/jsm/nodes/materials/LineBasicNodeMaterial.js +28 -0
  353. package/examples/jsm/nodes/materials/Materials.js +12 -0
  354. package/examples/jsm/nodes/materials/MeshBasicNodeMaterial.js +27 -0
  355. package/examples/jsm/nodes/materials/MeshLambertNodeMaterial.js +34 -0
  356. package/examples/jsm/nodes/materials/MeshNormalNodeMaterial.js +40 -0
  357. package/examples/jsm/nodes/materials/MeshPhongNodeMaterial.js +65 -0
  358. package/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +128 -0
  359. package/examples/jsm/nodes/materials/MeshStandardNodeMaterial.js +80 -0
  360. package/examples/jsm/nodes/materials/NodeMaterial.js +536 -0
  361. package/examples/jsm/nodes/materials/PointsNodeMaterial.js +49 -0
  362. package/examples/jsm/nodes/materials/SpriteNodeMaterial.js +103 -0
  363. package/examples/jsm/nodes/materialx/DISCLAIMER.md +199 -0
  364. package/examples/jsm/nodes/materialx/MaterialXNodes.js +68 -0
  365. package/examples/jsm/nodes/materialx/lib/mx_hsv.js +56 -0
  366. package/examples/jsm/nodes/materialx/lib/mx_noise.js +618 -0
  367. package/examples/jsm/nodes/materialx/lib/mx_transform_color.js +19 -0
  368. package/examples/jsm/nodes/math/CondNode.js +86 -0
  369. package/examples/jsm/nodes/math/MathNode.js +359 -0
  370. package/examples/jsm/nodes/math/OperatorNode.js +269 -0
  371. package/examples/jsm/nodes/parsers/GLSLNodeFunction.js +152 -0
  372. package/examples/jsm/nodes/parsers/GLSLNodeParser.js +14 -0
  373. package/examples/jsm/nodes/procedural/CheckerNode.js +42 -0
  374. package/examples/jsm/nodes/shadernode/ShaderNode.js +420 -0
  375. package/examples/jsm/nodes/utils/ArrayElementNode.js +33 -0
  376. package/examples/jsm/nodes/utils/ConvertNode.js +65 -0
  377. package/examples/jsm/nodes/utils/DiscardNode.js +26 -0
  378. package/examples/jsm/nodes/utils/EquirectUVNode.js +33 -0
  379. package/examples/jsm/nodes/utils/JoinNode.js +51 -0
  380. package/examples/jsm/nodes/utils/LoopNode.js +186 -0
  381. package/examples/jsm/nodes/utils/MatcapUVNode.js +30 -0
  382. package/examples/jsm/nodes/utils/MaxMipLevelNode.js +46 -0
  383. package/examples/jsm/nodes/utils/OscNode.js +81 -0
  384. package/examples/jsm/nodes/utils/PackingNode.js +55 -0
  385. package/examples/jsm/nodes/utils/RemapNode.js +42 -0
  386. package/examples/jsm/nodes/utils/RotateUVNode.js +43 -0
  387. package/examples/jsm/nodes/utils/SpecularMIPLevelNode.js +37 -0
  388. package/examples/jsm/nodes/utils/SplitNode.js +104 -0
  389. package/examples/jsm/nodes/utils/SpriteSheetUVNode.js +41 -0
  390. package/examples/jsm/nodes/utils/TimerNode.js +94 -0
  391. package/examples/jsm/nodes/utils/TriplanarTexturesNode.js +62 -0
  392. package/examples/jsm/objects/GroundProjectedSkybox.js +172 -0
  393. package/examples/jsm/objects/Lensflare.js +377 -0
  394. package/examples/jsm/objects/MarchingCubes.js +1176 -0
  395. package/examples/jsm/objects/Reflector.js +264 -0
  396. package/examples/jsm/objects/ReflectorForSSRPass.js +349 -0
  397. package/examples/jsm/objects/Refractor.js +324 -0
  398. package/examples/jsm/objects/ShadowMesh.js +80 -0
  399. package/examples/jsm/objects/Sky.js +219 -0
  400. package/examples/jsm/objects/Water.js +330 -0
  401. package/examples/jsm/objects/Water2.js +358 -0
  402. package/examples/jsm/offscreen/jank.js +45 -0
  403. package/examples/jsm/offscreen/offscreen.js +8 -0
  404. package/examples/jsm/offscreen/scene.js +86 -0
  405. package/examples/jsm/physics/AmmoPhysics.js +285 -0
  406. package/examples/jsm/physics/RapierPhysics.js +199 -0
  407. package/examples/jsm/postprocessing/AfterimagePass.js +104 -0
  408. package/examples/jsm/postprocessing/BloomPass.js +172 -0
  409. package/examples/jsm/postprocessing/BokehPass.js +140 -0
  410. package/examples/jsm/postprocessing/ClearPass.js +46 -0
  411. package/examples/jsm/postprocessing/CubeTexturePass.js +85 -0
  412. package/examples/jsm/postprocessing/DotScreenPass.js +65 -0
  413. package/examples/jsm/postprocessing/EffectComposer.js +231 -0
  414. package/examples/jsm/postprocessing/FilmPass.js +66 -0
  415. package/examples/jsm/postprocessing/GlitchPass.js +128 -0
  416. package/examples/jsm/postprocessing/HalftonePass.js +79 -0
  417. package/examples/jsm/postprocessing/LUTPass.js +173 -0
  418. package/examples/jsm/postprocessing/MaskPass.js +104 -0
  419. package/examples/jsm/postprocessing/OutlinePass.js +654 -0
  420. package/examples/jsm/postprocessing/OutputPass.js +91 -0
  421. package/examples/jsm/postprocessing/Pass.js +84 -0
  422. package/examples/jsm/postprocessing/RenderPass.js +81 -0
  423. package/examples/jsm/postprocessing/RenderPixelatedPass.js +235 -0
  424. package/examples/jsm/postprocessing/SAOPass.js +411 -0
  425. package/examples/jsm/postprocessing/SMAAPass.js +201 -0
  426. package/examples/jsm/postprocessing/SSAARenderPass.js +228 -0
  427. package/examples/jsm/postprocessing/SSAOPass.js +440 -0
  428. package/examples/jsm/postprocessing/SSRPass.js +641 -0
  429. package/examples/jsm/postprocessing/SavePass.js +79 -0
  430. package/examples/jsm/postprocessing/ShaderPass.js +77 -0
  431. package/examples/jsm/postprocessing/TAARenderPass.js +189 -0
  432. package/examples/jsm/postprocessing/TexturePass.js +67 -0
  433. package/examples/jsm/postprocessing/UnrealBloomPass.js +415 -0
  434. package/examples/jsm/renderers/CSS2DRenderer.js +215 -0
  435. package/examples/jsm/renderers/CSS3DRenderer.js +335 -0
  436. package/examples/jsm/renderers/Projector.js +918 -0
  437. package/examples/jsm/renderers/SVGRenderer.js +553 -0
  438. package/examples/jsm/renderers/common/Animation.js +58 -0
  439. package/examples/jsm/renderers/common/Attributes.js +75 -0
  440. package/examples/jsm/renderers/common/Backend.js +162 -0
  441. package/examples/jsm/renderers/common/Background.js +136 -0
  442. package/examples/jsm/renderers/common/Binding.js +19 -0
  443. package/examples/jsm/renderers/common/Bindings.js +165 -0
  444. package/examples/jsm/renderers/common/Buffer.js +38 -0
  445. package/examples/jsm/renderers/common/BufferUtils.js +33 -0
  446. package/examples/jsm/renderers/common/ChainMap.js +89 -0
  447. package/examples/jsm/renderers/common/ComputePipeline.js +17 -0
  448. package/examples/jsm/renderers/common/Constants.js +14 -0
  449. package/examples/jsm/renderers/common/CubeRenderTarget.js +65 -0
  450. package/examples/jsm/renderers/common/DataMap.js +54 -0
  451. package/examples/jsm/renderers/common/Geometries.js +215 -0
  452. package/examples/jsm/renderers/common/Info.js +73 -0
  453. package/examples/jsm/renderers/common/Pipeline.js +13 -0
  454. package/examples/jsm/renderers/common/Pipelines.js +370 -0
  455. package/examples/jsm/renderers/common/ProgrammableStage.js +18 -0
  456. package/examples/jsm/renderers/common/RenderContext.js +38 -0
  457. package/examples/jsm/renderers/common/RenderContexts.js +49 -0
  458. package/examples/jsm/renderers/common/RenderList.js +178 -0
  459. package/examples/jsm/renderers/common/RenderLists.js +38 -0
  460. package/examples/jsm/renderers/common/RenderObject.js +129 -0
  461. package/examples/jsm/renderers/common/RenderObjects.js +95 -0
  462. package/examples/jsm/renderers/common/RenderPipeline.js +16 -0
  463. package/examples/jsm/renderers/common/Renderer.js +895 -0
  464. package/examples/jsm/renderers/common/SampledTexture.js +80 -0
  465. package/examples/jsm/renderers/common/Sampler.js +18 -0
  466. package/examples/jsm/renderers/common/StorageBuffer.js +17 -0
  467. package/examples/jsm/renderers/common/Textures.js +218 -0
  468. package/examples/jsm/renderers/common/Uniform.js +140 -0
  469. package/examples/jsm/renderers/common/UniformBuffer.js +15 -0
  470. package/examples/jsm/renderers/common/UniformsGroup.js +299 -0
  471. package/examples/jsm/renderers/common/nodes/NodeSampledTexture.js +39 -0
  472. package/examples/jsm/renderers/common/nodes/NodeSampler.js +21 -0
  473. package/examples/jsm/renderers/common/nodes/NodeUniform.js +135 -0
  474. package/examples/jsm/renderers/common/nodes/Nodes.js +330 -0
  475. package/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +340 -0
  476. package/examples/jsm/renderers/webgl/nodes/SlotNode.js +26 -0
  477. package/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +764 -0
  478. package/examples/jsm/renderers/webgl/nodes/WebGLNodes.js +49 -0
  479. package/examples/jsm/renderers/webgpu/WebGPUBackend.js +844 -0
  480. package/examples/jsm/renderers/webgpu/WebGPURenderer.js +32 -0
  481. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +902 -0
  482. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js +104 -0
  483. package/examples/jsm/renderers/webgpu/nodes/WGSLNodeParser.js +14 -0
  484. package/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js +274 -0
  485. package/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +223 -0
  486. package/examples/jsm/renderers/webgpu/utils/WebGPUConstants.js +324 -0
  487. package/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js +533 -0
  488. package/examples/jsm/renderers/webgpu/utils/WebGPUTextureMipmapUtils.js +163 -0
  489. package/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +964 -0
  490. package/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js +92 -0
  491. package/examples/jsm/shaders/ACESFilmicToneMappingShader.js +87 -0
  492. package/examples/jsm/shaders/AfterimageShader.js +56 -0
  493. package/examples/jsm/shaders/BasicShader.js +27 -0
  494. package/examples/jsm/shaders/BleachBypassShader.js +62 -0
  495. package/examples/jsm/shaders/BlendShader.js +47 -0
  496. package/examples/jsm/shaders/BokehShader.js +143 -0
  497. package/examples/jsm/shaders/BokehShader2.js +393 -0
  498. package/examples/jsm/shaders/BrightnessContrastShader.js +54 -0
  499. package/examples/jsm/shaders/ColorCorrectionShader.js +50 -0
  500. package/examples/jsm/shaders/ColorifyShader.js +51 -0
  501. package/examples/jsm/shaders/ConvolutionShader.js +103 -0
  502. package/examples/jsm/shaders/CopyShader.js +45 -0
  503. package/examples/jsm/shaders/DOFMipMapShader.js +54 -0
  504. package/examples/jsm/shaders/DepthLimitedBlurShader.js +166 -0
  505. package/examples/jsm/shaders/DigitalGlitch.js +101 -0
  506. package/examples/jsm/shaders/DotScreenShader.js +70 -0
  507. package/examples/jsm/shaders/ExposureShader.js +44 -0
  508. package/examples/jsm/shaders/FXAAShader.js +286 -0
  509. package/examples/jsm/shaders/FilmShader.js +102 -0
  510. package/examples/jsm/shaders/FocusShader.js +87 -0
  511. package/examples/jsm/shaders/FreiChenShader.js +94 -0
  512. package/examples/jsm/shaders/GammaCorrectionShader.js +43 -0
  513. package/examples/jsm/shaders/GodRaysShader.js +313 -0
  514. package/examples/jsm/shaders/HalftoneShader.js +310 -0
  515. package/examples/jsm/shaders/HorizontalBlurShader.js +59 -0
  516. package/examples/jsm/shaders/HorizontalTiltShiftShader.js +61 -0
  517. package/examples/jsm/shaders/HueSaturationShader.js +65 -0
  518. package/examples/jsm/shaders/KaleidoShader.js +56 -0
  519. package/examples/jsm/shaders/LuminosityHighPassShader.js +64 -0
  520. package/examples/jsm/shaders/LuminosityShader.js +46 -0
  521. package/examples/jsm/shaders/MMDToonShader.js +132 -0
  522. package/examples/jsm/shaders/MirrorShader.js +54 -0
  523. package/examples/jsm/shaders/NormalMapShader.js +53 -0
  524. package/examples/jsm/shaders/OutputShader.js +78 -0
  525. package/examples/jsm/shaders/RGBShiftShader.js +54 -0
  526. package/examples/jsm/shaders/SAOShader.js +188 -0
  527. package/examples/jsm/shaders/SMAAShader.js +460 -0
  528. package/examples/jsm/shaders/SSAOShader.js +288 -0
  529. package/examples/jsm/shaders/SSRShader.js +364 -0
  530. package/examples/jsm/shaders/SepiaShader.js +52 -0
  531. package/examples/jsm/shaders/SobelOperatorShader.js +90 -0
  532. package/examples/jsm/shaders/SubsurfaceScatteringShader.js +88 -0
  533. package/examples/jsm/shaders/TechnicolorShader.js +43 -0
  534. package/examples/jsm/shaders/ToonShader.js +326 -0
  535. package/examples/jsm/shaders/TriangleBlurShader.js +72 -0
  536. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +45 -0
  537. package/examples/jsm/shaders/VelocityShader.js +128 -0
  538. package/examples/jsm/shaders/VerticalBlurShader.js +59 -0
  539. package/examples/jsm/shaders/VerticalTiltShiftShader.js +61 -0
  540. package/examples/jsm/shaders/VignetteShader.js +51 -0
  541. package/examples/jsm/shaders/VolumeShader.js +289 -0
  542. package/examples/jsm/shaders/WaterRefractionShader.js +93 -0
  543. package/examples/jsm/textures/FlakesTexture.js +40 -0
  544. package/examples/jsm/utils/BufferGeometryUtils.js +1373 -0
  545. package/examples/jsm/utils/CameraUtils.js +73 -0
  546. package/examples/jsm/utils/GPUStatsPanel.js +128 -0
  547. package/examples/jsm/utils/GeometryCompressionUtils.js +639 -0
  548. package/examples/jsm/utils/GeometryUtils.js +221 -0
  549. package/examples/jsm/utils/LDrawUtils.js +202 -0
  550. package/examples/jsm/utils/PackedPhongMaterial.js +178 -0
  551. package/examples/jsm/utils/SceneUtils.js +254 -0
  552. package/examples/jsm/utils/ShadowMapViewer.js +210 -0
  553. package/examples/jsm/utils/SkeletonUtils.js +413 -0
  554. package/examples/jsm/utils/TextureUtils.js +86 -0
  555. package/examples/jsm/utils/UVsDebug.js +165 -0
  556. package/examples/jsm/utils/WorkerPool.js +102 -0
  557. package/examples/jsm/webxr/ARButton.js +208 -0
  558. package/examples/jsm/webxr/OculusHandModel.js +109 -0
  559. package/examples/jsm/webxr/OculusHandPointerModel.js +413 -0
  560. package/examples/jsm/webxr/Text2D.js +38 -0
  561. package/examples/jsm/webxr/VRButton.js +200 -0
  562. package/examples/jsm/webxr/XRButton.js +198 -0
  563. package/examples/jsm/webxr/XRControllerModelFactory.js +299 -0
  564. package/examples/jsm/webxr/XREstimatedLight.js +223 -0
  565. package/examples/jsm/webxr/XRHandMeshModel.js +112 -0
  566. package/examples/jsm/webxr/XRHandModelFactory.js +105 -0
  567. package/examples/jsm/webxr/XRHandPrimitiveModel.js +103 -0
  568. package/examples/jsm/webxr/XRPlanes.js +100 -0
  569. package/lib/3d.min.js +1 -0
  570. package/package.json +25 -12
@@ -0,0 +1,3224 @@
1
+ import {
2
+ GridHelper,
3
+ EllipseCurve,
4
+ BufferGeometry,
5
+ Line,
6
+ LineBasicMaterial,
7
+ Raycaster,
8
+ Group,
9
+ Box3,
10
+ Sphere,
11
+ Quaternion,
12
+ Vector2,
13
+ Vector3,
14
+ Matrix4,
15
+ MathUtils,
16
+ EventDispatcher
17
+ } from 'three';
18
+
19
+ //trackball state
20
+ const STATE = {
21
+
22
+ IDLE: Symbol(),
23
+ ROTATE: Symbol(),
24
+ PAN: Symbol(),
25
+ SCALE: Symbol(),
26
+ FOV: Symbol(),
27
+ FOCUS: Symbol(),
28
+ ZROTATE: Symbol(),
29
+ TOUCH_MULTI: Symbol(),
30
+ ANIMATION_FOCUS: Symbol(),
31
+ ANIMATION_ROTATE: Symbol()
32
+
33
+ };
34
+
35
+ const INPUT = {
36
+
37
+ NONE: Symbol(),
38
+ ONE_FINGER: Symbol(),
39
+ ONE_FINGER_SWITCHED: Symbol(),
40
+ TWO_FINGER: Symbol(),
41
+ MULT_FINGER: Symbol(),
42
+ CURSOR: Symbol()
43
+
44
+ };
45
+
46
+ //cursor center coordinates
47
+ const _center = {
48
+
49
+ x: 0,
50
+ y: 0
51
+
52
+ };
53
+
54
+ //transformation matrices for gizmos and camera
55
+ const _transformation = {
56
+
57
+ camera: new Matrix4(),
58
+ gizmos: new Matrix4()
59
+
60
+ };
61
+
62
+ //events
63
+ const _changeEvent = { type: 'change' };
64
+ const _startEvent = { type: 'start' };
65
+ const _endEvent = { type: 'end' };
66
+
67
+ const _raycaster = new Raycaster();
68
+ const _offset = new Vector3();
69
+
70
+ const _gizmoMatrixStateTemp = new Matrix4();
71
+ const _cameraMatrixStateTemp = new Matrix4();
72
+ const _scalePointTemp = new Vector3();
73
+ /**
74
+ *
75
+ * @param {Camera} camera Virtual camera used in the scene
76
+ * @param {HTMLElement} domElement Renderer's dom element
77
+ * @param {Scene} scene The scene to be rendered
78
+ */
79
+ class ArcballControls extends EventDispatcher {
80
+
81
+ constructor( camera, domElement, scene = null ) {
82
+
83
+ super();
84
+ this.camera = null;
85
+ this.domElement = domElement;
86
+ this.scene = scene;
87
+ this.target = new Vector3();
88
+ this._currentTarget = new Vector3();
89
+ this.radiusFactor = 0.67;
90
+
91
+ this.mouseActions = [];
92
+ this._mouseOp = null;
93
+
94
+
95
+ //global vectors and matrices that are used in some operations to avoid creating new objects every time (e.g. every time cursor moves)
96
+ this._v2_1 = new Vector2();
97
+ this._v3_1 = new Vector3();
98
+ this._v3_2 = new Vector3();
99
+
100
+ this._m4_1 = new Matrix4();
101
+ this._m4_2 = new Matrix4();
102
+
103
+ this._quat = new Quaternion();
104
+
105
+ //transformation matrices
106
+ this._translationMatrix = new Matrix4(); //matrix for translation operation
107
+ this._rotationMatrix = new Matrix4(); //matrix for rotation operation
108
+ this._scaleMatrix = new Matrix4(); //matrix for scaling operation
109
+
110
+ this._rotationAxis = new Vector3(); //axis for rotate operation
111
+
112
+
113
+ //camera state
114
+ this._cameraMatrixState = new Matrix4();
115
+ this._cameraProjectionState = new Matrix4();
116
+
117
+ this._fovState = 1;
118
+ this._upState = new Vector3();
119
+ this._zoomState = 1;
120
+ this._nearPos = 0;
121
+ this._farPos = 0;
122
+
123
+ this._gizmoMatrixState = new Matrix4();
124
+
125
+ //initial values
126
+ this._up0 = new Vector3();
127
+ this._zoom0 = 1;
128
+ this._fov0 = 0;
129
+ this._initialNear = 0;
130
+ this._nearPos0 = 0;
131
+ this._initialFar = 0;
132
+ this._farPos0 = 0;
133
+ this._cameraMatrixState0 = new Matrix4();
134
+ this._gizmoMatrixState0 = new Matrix4();
135
+
136
+ //pointers array
137
+ this._button = - 1;
138
+ this._touchStart = [];
139
+ this._touchCurrent = [];
140
+ this._input = INPUT.NONE;
141
+
142
+ //two fingers touch interaction
143
+ this._switchSensibility = 32; //minimum movement to be performed to fire single pan start after the second finger has been released
144
+ this._startFingerDistance = 0; //distance between two fingers
145
+ this._currentFingerDistance = 0;
146
+ this._startFingerRotation = 0; //amount of rotation performed with two fingers
147
+ this._currentFingerRotation = 0;
148
+
149
+ //double tap
150
+ this._devPxRatio = 0;
151
+ this._downValid = true;
152
+ this._nclicks = 0;
153
+ this._downEvents = [];
154
+ this._downStart = 0; //pointerDown time
155
+ this._clickStart = 0; //first click time
156
+ this._maxDownTime = 250;
157
+ this._maxInterval = 300;
158
+ this._posThreshold = 24;
159
+ this._movementThreshold = 24;
160
+
161
+ //cursor positions
162
+ this._currentCursorPosition = new Vector3();
163
+ this._startCursorPosition = new Vector3();
164
+
165
+ //grid
166
+ this._grid = null; //grid to be visualized during pan operation
167
+ this._gridPosition = new Vector3();
168
+
169
+ //gizmos
170
+ this._gizmos = new Group();
171
+ this._curvePts = 128;
172
+
173
+
174
+ //animations
175
+ this._timeStart = - 1; //initial time
176
+ this._animationId = - 1;
177
+
178
+ //focus animation
179
+ this.focusAnimationTime = 500; //duration of focus animation in ms
180
+
181
+ //rotate animation
182
+ this._timePrev = 0; //time at which previous rotate operation has been detected
183
+ this._timeCurrent = 0; //time at which current rotate operation has been detected
184
+ this._anglePrev = 0; //angle of previous rotation
185
+ this._angleCurrent = 0; //angle of current rotation
186
+ this._cursorPosPrev = new Vector3(); //cursor position when previous rotate operation has been detected
187
+ this._cursorPosCurr = new Vector3();//cursor position when current rotate operation has been detected
188
+ this._wPrev = 0; //angular velocity of the previous rotate operation
189
+ this._wCurr = 0; //angular velocity of the current rotate operation
190
+
191
+
192
+ //parameters
193
+ this.adjustNearFar = false;
194
+ this.scaleFactor = 1.1; //zoom/distance multiplier
195
+ this.dampingFactor = 25;
196
+ this.wMax = 20; //maximum angular velocity allowed
197
+ this.enableAnimations = true; //if animations should be performed
198
+ this.enableGrid = false; //if grid should be showed during pan operation
199
+ this.cursorZoom = false; //if wheel zoom should be cursor centered
200
+ this.minFov = 5;
201
+ this.maxFov = 90;
202
+ this.rotateSpeed = 1;
203
+
204
+ this.enabled = true;
205
+ this.enablePan = true;
206
+ this.enableRotate = true;
207
+ this.enableZoom = true;
208
+ this.enableGizmos = true;
209
+
210
+ this.minDistance = 0;
211
+ this.maxDistance = Infinity;
212
+ this.minZoom = 0;
213
+ this.maxZoom = Infinity;
214
+
215
+ //trackball parameters
216
+ this._tbRadius = 1;
217
+
218
+ //FSA
219
+ this._state = STATE.IDLE;
220
+
221
+ this.setCamera( camera );
222
+
223
+ if ( this.scene != null ) {
224
+
225
+ this.scene.add( this._gizmos );
226
+
227
+ }
228
+
229
+ this.domElement.style.touchAction = 'none';
230
+ this._devPxRatio = window.devicePixelRatio;
231
+
232
+ this.initializeMouseActions();
233
+
234
+ this._onContextMenu = onContextMenu.bind( this );
235
+ this._onWheel = onWheel.bind( this );
236
+ this._onPointerUp = onPointerUp.bind( this );
237
+ this._onPointerMove = onPointerMove.bind( this );
238
+ this._onPointerDown = onPointerDown.bind( this );
239
+ this._onPointerCancel = onPointerCancel.bind( this );
240
+ this._onWindowResize = onWindowResize.bind( this );
241
+
242
+ this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
243
+ this.domElement.addEventListener( 'wheel', this._onWheel );
244
+ this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
245
+ this.domElement.addEventListener( 'pointercancel', this._onPointerCancel );
246
+
247
+ window.addEventListener( 'resize', this._onWindowResize );
248
+
249
+ }
250
+
251
+ onSinglePanStart( event, operation ) {
252
+
253
+ if ( this.enabled ) {
254
+
255
+ this.dispatchEvent( _startEvent );
256
+
257
+ this.setCenter( event.clientX, event.clientY );
258
+
259
+ switch ( operation ) {
260
+
261
+ case 'PAN':
262
+
263
+ if ( ! this.enablePan ) {
264
+
265
+ return;
266
+
267
+ }
268
+
269
+ if ( this._animationId != - 1 ) {
270
+
271
+ cancelAnimationFrame( this._animationId );
272
+ this._animationId = - 1;
273
+ this._timeStart = - 1;
274
+
275
+ this.activateGizmos( false );
276
+ this.dispatchEvent( _changeEvent );
277
+
278
+ }
279
+
280
+ this.updateTbState( STATE.PAN, true );
281
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
282
+ if ( this.enableGrid ) {
283
+
284
+ this.drawGrid();
285
+ this.dispatchEvent( _changeEvent );
286
+
287
+ }
288
+
289
+ break;
290
+
291
+ case 'ROTATE':
292
+
293
+ if ( ! this.enableRotate ) {
294
+
295
+ return;
296
+
297
+ }
298
+
299
+ if ( this._animationId != - 1 ) {
300
+
301
+ cancelAnimationFrame( this._animationId );
302
+ this._animationId = - 1;
303
+ this._timeStart = - 1;
304
+
305
+ }
306
+
307
+ this.updateTbState( STATE.ROTATE, true );
308
+ this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
309
+ this.activateGizmos( true );
310
+ if ( this.enableAnimations ) {
311
+
312
+ this._timePrev = this._timeCurrent = performance.now();
313
+ this._angleCurrent = this._anglePrev = 0;
314
+ this._cursorPosPrev.copy( this._startCursorPosition );
315
+ this._cursorPosCurr.copy( this._cursorPosPrev );
316
+ this._wCurr = 0;
317
+ this._wPrev = this._wCurr;
318
+
319
+ }
320
+
321
+ this.dispatchEvent( _changeEvent );
322
+ break;
323
+
324
+ case 'FOV':
325
+
326
+ if ( ! this.camera.isPerspectiveCamera || ! this.enableZoom ) {
327
+
328
+ return;
329
+
330
+ }
331
+
332
+ if ( this._animationId != - 1 ) {
333
+
334
+ cancelAnimationFrame( this._animationId );
335
+ this._animationId = - 1;
336
+ this._timeStart = - 1;
337
+
338
+ this.activateGizmos( false );
339
+ this.dispatchEvent( _changeEvent );
340
+
341
+ }
342
+
343
+ this.updateTbState( STATE.FOV, true );
344
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
345
+ this._currentCursorPosition.copy( this._startCursorPosition );
346
+ break;
347
+
348
+ case 'ZOOM':
349
+
350
+ if ( ! this.enableZoom ) {
351
+
352
+ return;
353
+
354
+ }
355
+
356
+ if ( this._animationId != - 1 ) {
357
+
358
+ cancelAnimationFrame( this._animationId );
359
+ this._animationId = - 1;
360
+ this._timeStart = - 1;
361
+
362
+ this.activateGizmos( false );
363
+ this.dispatchEvent( _changeEvent );
364
+
365
+ }
366
+
367
+ this.updateTbState( STATE.SCALE, true );
368
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
369
+ this._currentCursorPosition.copy( this._startCursorPosition );
370
+ break;
371
+
372
+ }
373
+
374
+ }
375
+
376
+ }
377
+
378
+ onSinglePanMove( event, opState ) {
379
+
380
+ if ( this.enabled ) {
381
+
382
+ const restart = opState != this._state;
383
+ this.setCenter( event.clientX, event.clientY );
384
+
385
+ switch ( opState ) {
386
+
387
+ case STATE.PAN:
388
+
389
+ if ( this.enablePan ) {
390
+
391
+ if ( restart ) {
392
+
393
+ //switch to pan operation
394
+
395
+ this.dispatchEvent( _endEvent );
396
+ this.dispatchEvent( _startEvent );
397
+
398
+ this.updateTbState( opState, true );
399
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
400
+ if ( this.enableGrid ) {
401
+
402
+ this.drawGrid();
403
+
404
+ }
405
+
406
+ this.activateGizmos( false );
407
+
408
+ } else {
409
+
410
+ //continue with pan operation
411
+ this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ) );
412
+ this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition ) );
413
+
414
+ }
415
+
416
+ }
417
+
418
+ break;
419
+
420
+ case STATE.ROTATE:
421
+
422
+ if ( this.enableRotate ) {
423
+
424
+ if ( restart ) {
425
+
426
+ //switch to rotate operation
427
+
428
+ this.dispatchEvent( _endEvent );
429
+ this.dispatchEvent( _startEvent );
430
+
431
+ this.updateTbState( opState, true );
432
+ this._startCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
433
+
434
+ if ( this.enableGrid ) {
435
+
436
+ this.disposeGrid();
437
+
438
+ }
439
+
440
+ this.activateGizmos( true );
441
+
442
+ } else {
443
+
444
+ //continue with rotate operation
445
+ this._currentCursorPosition.copy( this.unprojectOnTbSurface( this.camera, _center.x, _center.y, this.domElement, this._tbRadius ) );
446
+
447
+ const distance = this._startCursorPosition.distanceTo( this._currentCursorPosition );
448
+ const angle = this._startCursorPosition.angleTo( this._currentCursorPosition );
449
+ const amount = Math.max( distance / this._tbRadius, angle ) * this.rotateSpeed; //effective rotation angle
450
+
451
+ this.applyTransformMatrix( this.rotate( this.calculateRotationAxis( this._startCursorPosition, this._currentCursorPosition ), amount ) );
452
+
453
+ if ( this.enableAnimations ) {
454
+
455
+ this._timePrev = this._timeCurrent;
456
+ this._timeCurrent = performance.now();
457
+ this._anglePrev = this._angleCurrent;
458
+ this._angleCurrent = amount;
459
+ this._cursorPosPrev.copy( this._cursorPosCurr );
460
+ this._cursorPosCurr.copy( this._currentCursorPosition );
461
+ this._wPrev = this._wCurr;
462
+ this._wCurr = this.calculateAngularSpeed( this._anglePrev, this._angleCurrent, this._timePrev, this._timeCurrent );
463
+
464
+ }
465
+
466
+ }
467
+
468
+ }
469
+
470
+ break;
471
+
472
+ case STATE.SCALE:
473
+
474
+ if ( this.enableZoom ) {
475
+
476
+ if ( restart ) {
477
+
478
+ //switch to zoom operation
479
+
480
+ this.dispatchEvent( _endEvent );
481
+ this.dispatchEvent( _startEvent );
482
+
483
+ this.updateTbState( opState, true );
484
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
485
+ this._currentCursorPosition.copy( this._startCursorPosition );
486
+
487
+ if ( this.enableGrid ) {
488
+
489
+ this.disposeGrid();
490
+
491
+ }
492
+
493
+ this.activateGizmos( false );
494
+
495
+ } else {
496
+
497
+ //continue with zoom operation
498
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
499
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
500
+
501
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
502
+
503
+ let size = 1;
504
+
505
+ if ( movement < 0 ) {
506
+
507
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
508
+
509
+ } else if ( movement > 0 ) {
510
+
511
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
512
+
513
+ }
514
+
515
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState );
516
+
517
+ this.applyTransformMatrix( this.scale( size, this._v3_1 ) );
518
+
519
+ }
520
+
521
+ }
522
+
523
+ break;
524
+
525
+ case STATE.FOV:
526
+
527
+ if ( this.enableZoom && this.camera.isPerspectiveCamera ) {
528
+
529
+ if ( restart ) {
530
+
531
+ //switch to fov operation
532
+
533
+ this.dispatchEvent( _endEvent );
534
+ this.dispatchEvent( _startEvent );
535
+
536
+ this.updateTbState( opState, true );
537
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
538
+ this._currentCursorPosition.copy( this._startCursorPosition );
539
+
540
+ if ( this.enableGrid ) {
541
+
542
+ this.disposeGrid();
543
+
544
+ }
545
+
546
+ this.activateGizmos( false );
547
+
548
+ } else {
549
+
550
+ //continue with fov operation
551
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
552
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
553
+
554
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
555
+
556
+ let size = 1;
557
+
558
+ if ( movement < 0 ) {
559
+
560
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
561
+
562
+ } else if ( movement > 0 ) {
563
+
564
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
565
+
566
+ }
567
+
568
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
569
+ const x = this._v3_1.distanceTo( this._gizmos.position );
570
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
571
+
572
+ //check min and max distance
573
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
574
+
575
+ const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
576
+
577
+ //calculate new fov
578
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
579
+
580
+ //check min and max fov
581
+ newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
582
+
583
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
584
+ size = x / newDistance;
585
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
586
+
587
+ this.setFov( newFov );
588
+ this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
589
+
590
+ //adjusting distance
591
+ _offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
592
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
593
+
594
+ }
595
+
596
+ }
597
+
598
+ break;
599
+
600
+ }
601
+
602
+ this.dispatchEvent( _changeEvent );
603
+
604
+ }
605
+
606
+ }
607
+
608
+ onSinglePanEnd() {
609
+
610
+ if ( this._state == STATE.ROTATE ) {
611
+
612
+
613
+ if ( ! this.enableRotate ) {
614
+
615
+ return;
616
+
617
+ }
618
+
619
+ if ( this.enableAnimations ) {
620
+
621
+ //perform rotation animation
622
+ const deltaTime = ( performance.now() - this._timeCurrent );
623
+ if ( deltaTime < 120 ) {
624
+
625
+ const w = Math.abs( ( this._wPrev + this._wCurr ) / 2 );
626
+
627
+ const self = this;
628
+ this._animationId = window.requestAnimationFrame( function ( t ) {
629
+
630
+ self.updateTbState( STATE.ANIMATION_ROTATE, true );
631
+ const rotationAxis = self.calculateRotationAxis( self._cursorPosPrev, self._cursorPosCurr );
632
+
633
+ self.onRotationAnim( t, rotationAxis, Math.min( w, self.wMax ) );
634
+
635
+ } );
636
+
637
+ } else {
638
+
639
+ //cursor has been standing still for over 120 ms since last movement
640
+ this.updateTbState( STATE.IDLE, false );
641
+ this.activateGizmos( false );
642
+ this.dispatchEvent( _changeEvent );
643
+
644
+ }
645
+
646
+ } else {
647
+
648
+ this.updateTbState( STATE.IDLE, false );
649
+ this.activateGizmos( false );
650
+ this.dispatchEvent( _changeEvent );
651
+
652
+ }
653
+
654
+ } else if ( this._state == STATE.PAN || this._state == STATE.IDLE ) {
655
+
656
+ this.updateTbState( STATE.IDLE, false );
657
+
658
+ if ( this.enableGrid ) {
659
+
660
+ this.disposeGrid();
661
+
662
+ }
663
+
664
+ this.activateGizmos( false );
665
+ this.dispatchEvent( _changeEvent );
666
+
667
+
668
+ }
669
+
670
+ this.dispatchEvent( _endEvent );
671
+
672
+ }
673
+
674
+ onDoubleTap( event ) {
675
+
676
+ if ( this.enabled && this.enablePan && this.scene != null ) {
677
+
678
+ this.dispatchEvent( _startEvent );
679
+
680
+ this.setCenter( event.clientX, event.clientY );
681
+ const hitP = this.unprojectOnObj( this.getCursorNDC( _center.x, _center.y, this.domElement ), this.camera );
682
+
683
+ if ( hitP != null && this.enableAnimations ) {
684
+
685
+ const self = this;
686
+ if ( this._animationId != - 1 ) {
687
+
688
+ window.cancelAnimationFrame( this._animationId );
689
+
690
+ }
691
+
692
+ this._timeStart = - 1;
693
+ this._animationId = window.requestAnimationFrame( function ( t ) {
694
+
695
+ self.updateTbState( STATE.ANIMATION_FOCUS, true );
696
+ self.onFocusAnim( t, hitP, self._cameraMatrixState, self._gizmoMatrixState );
697
+
698
+ } );
699
+
700
+ } else if ( hitP != null && ! this.enableAnimations ) {
701
+
702
+ this.updateTbState( STATE.FOCUS, true );
703
+ this.focus( hitP, this.scaleFactor );
704
+ this.updateTbState( STATE.IDLE, false );
705
+ this.dispatchEvent( _changeEvent );
706
+
707
+ }
708
+
709
+ }
710
+
711
+ this.dispatchEvent( _endEvent );
712
+
713
+ }
714
+
715
+ onDoublePanStart() {
716
+
717
+ if ( this.enabled && this.enablePan ) {
718
+
719
+ this.dispatchEvent( _startEvent );
720
+
721
+ this.updateTbState( STATE.PAN, true );
722
+
723
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
724
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement, true ) );
725
+ this._currentCursorPosition.copy( this._startCursorPosition );
726
+
727
+ this.activateGizmos( false );
728
+
729
+ }
730
+
731
+ }
732
+
733
+ onDoublePanMove() {
734
+
735
+ if ( this.enabled && this.enablePan ) {
736
+
737
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
738
+
739
+ if ( this._state != STATE.PAN ) {
740
+
741
+ this.updateTbState( STATE.PAN, true );
742
+ this._startCursorPosition.copy( this._currentCursorPosition );
743
+
744
+ }
745
+
746
+ this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement, true ) );
747
+ this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition, true ) );
748
+ this.dispatchEvent( _changeEvent );
749
+
750
+ }
751
+
752
+ }
753
+
754
+ onDoublePanEnd() {
755
+
756
+ this.updateTbState( STATE.IDLE, false );
757
+ this.dispatchEvent( _endEvent );
758
+
759
+ }
760
+
761
+ onRotateStart() {
762
+
763
+ if ( this.enabled && this.enableRotate ) {
764
+
765
+ this.dispatchEvent( _startEvent );
766
+
767
+ this.updateTbState( STATE.ZROTATE, true );
768
+
769
+ //this._startFingerRotation = event.rotation;
770
+
771
+ this._startFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
772
+ this._currentFingerRotation = this._startFingerRotation;
773
+
774
+ this.camera.getWorldDirection( this._rotationAxis ); //rotation axis
775
+
776
+ if ( ! this.enablePan && ! this.enableZoom ) {
777
+
778
+ this.activateGizmos( true );
779
+
780
+ }
781
+
782
+ }
783
+
784
+ }
785
+
786
+ onRotateMove() {
787
+
788
+ if ( this.enabled && this.enableRotate ) {
789
+
790
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
791
+ let rotationPoint;
792
+
793
+ if ( this._state != STATE.ZROTATE ) {
794
+
795
+ this.updateTbState( STATE.ZROTATE, true );
796
+ this._startFingerRotation = this._currentFingerRotation;
797
+
798
+ }
799
+
800
+ //this._currentFingerRotation = event.rotation;
801
+ this._currentFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
802
+
803
+ if ( ! this.enablePan ) {
804
+
805
+ rotationPoint = new Vector3().setFromMatrixPosition( this._gizmoMatrixState );
806
+
807
+ } else {
808
+
809
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
810
+ rotationPoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement ).applyQuaternion( this.camera.quaternion ).multiplyScalar( 1 / this.camera.zoom ).add( this._v3_2 );
811
+
812
+ }
813
+
814
+ const amount = MathUtils.DEG2RAD * ( this._startFingerRotation - this._currentFingerRotation );
815
+
816
+ this.applyTransformMatrix( this.zRotate( rotationPoint, amount ) );
817
+ this.dispatchEvent( _changeEvent );
818
+
819
+ }
820
+
821
+ }
822
+
823
+ onRotateEnd() {
824
+
825
+ this.updateTbState( STATE.IDLE, false );
826
+ this.activateGizmos( false );
827
+ this.dispatchEvent( _endEvent );
828
+
829
+ }
830
+
831
+ onPinchStart() {
832
+
833
+ if ( this.enabled && this.enableZoom ) {
834
+
835
+ this.dispatchEvent( _startEvent );
836
+ this.updateTbState( STATE.SCALE, true );
837
+
838
+ this._startFingerDistance = this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] );
839
+ this._currentFingerDistance = this._startFingerDistance;
840
+
841
+ this.activateGizmos( false );
842
+
843
+ }
844
+
845
+ }
846
+
847
+ onPinchMove() {
848
+
849
+ if ( this.enabled && this.enableZoom ) {
850
+
851
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
852
+ const minDistance = 12; //minimum distance between fingers (in css pixels)
853
+
854
+ if ( this._state != STATE.SCALE ) {
855
+
856
+ this._startFingerDistance = this._currentFingerDistance;
857
+ this.updateTbState( STATE.SCALE, true );
858
+
859
+ }
860
+
861
+ this._currentFingerDistance = Math.max( this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] ), minDistance * this._devPxRatio );
862
+ const amount = this._currentFingerDistance / this._startFingerDistance;
863
+
864
+ let scalePoint;
865
+
866
+ if ( ! this.enablePan ) {
867
+
868
+ scalePoint = this._gizmos.position;
869
+
870
+ } else {
871
+
872
+ if ( this.camera.isOrthographicCamera ) {
873
+
874
+ scalePoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement )
875
+ .applyQuaternion( this.camera.quaternion )
876
+ .multiplyScalar( 1 / this.camera.zoom )
877
+ .add( this._gizmos.position );
878
+
879
+ } else if ( this.camera.isPerspectiveCamera ) {
880
+
881
+ scalePoint = this.unprojectOnTbPlane( this.camera, _center.x, _center.y, this.domElement )
882
+ .applyQuaternion( this.camera.quaternion )
883
+ .add( this._gizmos.position );
884
+
885
+ }
886
+
887
+ }
888
+
889
+ this.applyTransformMatrix( this.scale( amount, scalePoint ) );
890
+ this.dispatchEvent( _changeEvent );
891
+
892
+ }
893
+
894
+ }
895
+
896
+ onPinchEnd() {
897
+
898
+ this.updateTbState( STATE.IDLE, false );
899
+ this.dispatchEvent( _endEvent );
900
+
901
+ }
902
+
903
+ onTriplePanStart() {
904
+
905
+ if ( this.enabled && this.enableZoom ) {
906
+
907
+ this.dispatchEvent( _startEvent );
908
+
909
+ this.updateTbState( STATE.SCALE, true );
910
+
911
+ //const center = event.center;
912
+ let clientX = 0;
913
+ let clientY = 0;
914
+ const nFingers = this._touchCurrent.length;
915
+
916
+ for ( let i = 0; i < nFingers; i ++ ) {
917
+
918
+ clientX += this._touchCurrent[ i ].clientX;
919
+ clientY += this._touchCurrent[ i ].clientY;
920
+
921
+ }
922
+
923
+ this.setCenter( clientX / nFingers, clientY / nFingers );
924
+
925
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
926
+ this._currentCursorPosition.copy( this._startCursorPosition );
927
+
928
+ }
929
+
930
+ }
931
+
932
+ onTriplePanMove() {
933
+
934
+ if ( this.enabled && this.enableZoom ) {
935
+
936
+ // fov / 2
937
+ // |\
938
+ // | \
939
+ // | \
940
+ // x | \
941
+ // | \
942
+ // | \
943
+ // | _ _ _\
944
+ // y
945
+
946
+ //const center = event.center;
947
+ let clientX = 0;
948
+ let clientY = 0;
949
+ const nFingers = this._touchCurrent.length;
950
+
951
+ for ( let i = 0; i < nFingers; i ++ ) {
952
+
953
+ clientX += this._touchCurrent[ i ].clientX;
954
+ clientY += this._touchCurrent[ i ].clientY;
955
+
956
+ }
957
+
958
+ this.setCenter( clientX / nFingers, clientY / nFingers );
959
+
960
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
961
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
962
+
963
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
964
+
965
+ let size = 1;
966
+
967
+ if ( movement < 0 ) {
968
+
969
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
970
+
971
+ } else if ( movement > 0 ) {
972
+
973
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
974
+
975
+ }
976
+
977
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
978
+ const x = this._v3_1.distanceTo( this._gizmos.position );
979
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
980
+
981
+ //check min and max distance
982
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
983
+
984
+ const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
985
+
986
+ //calculate new fov
987
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
988
+
989
+ //check min and max fov
990
+ newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
991
+
992
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
993
+ size = x / newDistance;
994
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
995
+
996
+ this.setFov( newFov );
997
+ this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
998
+
999
+ //adjusting distance
1000
+ _offset.copy( this._gizmos.position ).sub( this.camera.position ).normalize().multiplyScalar( newDistance / x );
1001
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
1002
+
1003
+ this.dispatchEvent( _changeEvent );
1004
+
1005
+ }
1006
+
1007
+ }
1008
+
1009
+ onTriplePanEnd() {
1010
+
1011
+ this.updateTbState( STATE.IDLE, false );
1012
+ this.dispatchEvent( _endEvent );
1013
+ //this.dispatchEvent( _changeEvent );
1014
+
1015
+ }
1016
+
1017
+ /**
1018
+ * Set _center's x/y coordinates
1019
+ * @param {Number} clientX
1020
+ * @param {Number} clientY
1021
+ */
1022
+ setCenter( clientX, clientY ) {
1023
+
1024
+ _center.x = clientX;
1025
+ _center.y = clientY;
1026
+
1027
+ }
1028
+
1029
+ /**
1030
+ * Set default mouse actions
1031
+ */
1032
+ initializeMouseActions() {
1033
+
1034
+ this.setMouseAction( 'PAN', 0, 'CTRL' );
1035
+ this.setMouseAction( 'PAN', 2 );
1036
+
1037
+ this.setMouseAction( 'ROTATE', 0 );
1038
+
1039
+ this.setMouseAction( 'ZOOM', 'WHEEL' );
1040
+ this.setMouseAction( 'ZOOM', 1 );
1041
+
1042
+ this.setMouseAction( 'FOV', 'WHEEL', 'SHIFT' );
1043
+ this.setMouseAction( 'FOV', 1, 'SHIFT' );
1044
+
1045
+
1046
+ }
1047
+
1048
+ /**
1049
+ * Compare two mouse actions
1050
+ * @param {Object} action1
1051
+ * @param {Object} action2
1052
+ * @returns {Boolean} True if action1 and action 2 are the same mouse action, false otherwise
1053
+ */
1054
+ compareMouseAction( action1, action2 ) {
1055
+
1056
+ if ( action1.operation == action2.operation ) {
1057
+
1058
+ if ( action1.mouse == action2.mouse && action1.key == action2.key ) {
1059
+
1060
+ return true;
1061
+
1062
+ } else {
1063
+
1064
+ return false;
1065
+
1066
+ }
1067
+
1068
+ } else {
1069
+
1070
+ return false;
1071
+
1072
+ }
1073
+
1074
+ }
1075
+
1076
+ /**
1077
+ * Set a new mouse action by specifying the operation to be performed and a mouse/key combination. In case of conflict, replaces the existing one
1078
+ * @param {String} operation The operation to be performed ('PAN', 'ROTATE', 'ZOOM', 'FOV)
1079
+ * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
1080
+ * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
1081
+ * @returns {Boolean} True if the mouse action has been successfully added, false otherwise
1082
+ */
1083
+ setMouseAction( operation, mouse, key = null ) {
1084
+
1085
+ const operationInput = [ 'PAN', 'ROTATE', 'ZOOM', 'FOV' ];
1086
+ const mouseInput = [ 0, 1, 2, 'WHEEL' ];
1087
+ const keyInput = [ 'CTRL', 'SHIFT', null ];
1088
+ let state;
1089
+
1090
+ if ( ! operationInput.includes( operation ) || ! mouseInput.includes( mouse ) || ! keyInput.includes( key ) ) {
1091
+
1092
+ //invalid parameters
1093
+ return false;
1094
+
1095
+ }
1096
+
1097
+ if ( mouse == 'WHEEL' ) {
1098
+
1099
+ if ( operation != 'ZOOM' && operation != 'FOV' ) {
1100
+
1101
+ //cannot associate 2D operation to 1D input
1102
+ return false;
1103
+
1104
+ }
1105
+
1106
+ }
1107
+
1108
+ switch ( operation ) {
1109
+
1110
+ case 'PAN':
1111
+
1112
+ state = STATE.PAN;
1113
+ break;
1114
+
1115
+ case 'ROTATE':
1116
+
1117
+ state = STATE.ROTATE;
1118
+ break;
1119
+
1120
+ case 'ZOOM':
1121
+
1122
+ state = STATE.SCALE;
1123
+ break;
1124
+
1125
+ case 'FOV':
1126
+
1127
+ state = STATE.FOV;
1128
+ break;
1129
+
1130
+ }
1131
+
1132
+ const action = {
1133
+
1134
+ operation: operation,
1135
+ mouse: mouse,
1136
+ key: key,
1137
+ state: state
1138
+
1139
+ };
1140
+
1141
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1142
+
1143
+ if ( this.mouseActions[ i ].mouse == action.mouse && this.mouseActions[ i ].key == action.key ) {
1144
+
1145
+ this.mouseActions.splice( i, 1, action );
1146
+ return true;
1147
+
1148
+ }
1149
+
1150
+ }
1151
+
1152
+ this.mouseActions.push( action );
1153
+ return true;
1154
+
1155
+ }
1156
+
1157
+ /**
1158
+ * Remove a mouse action by specifying its mouse/key combination
1159
+ * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
1160
+ * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
1161
+ * @returns {Boolean} True if the operation has been succesfully removed, false otherwise
1162
+ */
1163
+ unsetMouseAction( mouse, key = null ) {
1164
+
1165
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1166
+
1167
+ if ( this.mouseActions[ i ].mouse == mouse && this.mouseActions[ i ].key == key ) {
1168
+
1169
+ this.mouseActions.splice( i, 1 );
1170
+ return true;
1171
+
1172
+ }
1173
+
1174
+ }
1175
+
1176
+ return false;
1177
+
1178
+ }
1179
+
1180
+ /**
1181
+ * Return the operation associated to a mouse/keyboard combination
1182
+ * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
1183
+ * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
1184
+ * @returns The operation if it has been found, null otherwise
1185
+ */
1186
+ getOpFromAction( mouse, key ) {
1187
+
1188
+ let action;
1189
+
1190
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1191
+
1192
+ action = this.mouseActions[ i ];
1193
+ if ( action.mouse == mouse && action.key == key ) {
1194
+
1195
+ return action.operation;
1196
+
1197
+ }
1198
+
1199
+ }
1200
+
1201
+ if ( key != null ) {
1202
+
1203
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1204
+
1205
+ action = this.mouseActions[ i ];
1206
+ if ( action.mouse == mouse && action.key == null ) {
1207
+
1208
+ return action.operation;
1209
+
1210
+ }
1211
+
1212
+ }
1213
+
1214
+ }
1215
+
1216
+ return null;
1217
+
1218
+ }
1219
+
1220
+ /**
1221
+ * Get the operation associated to mouse and key combination and returns the corresponding FSA state
1222
+ * @param {Number} mouse Mouse button
1223
+ * @param {String} key Keyboard modifier
1224
+ * @returns The FSA state obtained from the operation associated to mouse/keyboard combination
1225
+ */
1226
+ getOpStateFromAction( mouse, key ) {
1227
+
1228
+ let action;
1229
+
1230
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1231
+
1232
+ action = this.mouseActions[ i ];
1233
+ if ( action.mouse == mouse && action.key == key ) {
1234
+
1235
+ return action.state;
1236
+
1237
+ }
1238
+
1239
+ }
1240
+
1241
+ if ( key != null ) {
1242
+
1243
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1244
+
1245
+ action = this.mouseActions[ i ];
1246
+ if ( action.mouse == mouse && action.key == null ) {
1247
+
1248
+ return action.state;
1249
+
1250
+ }
1251
+
1252
+ }
1253
+
1254
+ }
1255
+
1256
+ return null;
1257
+
1258
+ }
1259
+
1260
+ /**
1261
+ * Calculate the angle between two pointers
1262
+ * @param {PointerEvent} p1
1263
+ * @param {PointerEvent} p2
1264
+ * @returns {Number} The angle between two pointers in degrees
1265
+ */
1266
+ getAngle( p1, p2 ) {
1267
+
1268
+ return Math.atan2( p2.clientY - p1.clientY, p2.clientX - p1.clientX ) * 180 / Math.PI;
1269
+
1270
+ }
1271
+
1272
+ /**
1273
+ * Update a PointerEvent inside current pointerevents array
1274
+ * @param {PointerEvent} event
1275
+ */
1276
+ updateTouchEvent( event ) {
1277
+
1278
+ for ( let i = 0; i < this._touchCurrent.length; i ++ ) {
1279
+
1280
+ if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
1281
+
1282
+ this._touchCurrent.splice( i, 1, event );
1283
+ break;
1284
+
1285
+ }
1286
+
1287
+ }
1288
+
1289
+ }
1290
+
1291
+ /**
1292
+ * Apply a transformation matrix, to the camera and gizmos
1293
+ * @param {Object} transformation Object containing matrices to apply to camera and gizmos
1294
+ */
1295
+ applyTransformMatrix( transformation ) {
1296
+
1297
+ if ( transformation.camera != null ) {
1298
+
1299
+ this._m4_1.copy( this._cameraMatrixState ).premultiply( transformation.camera );
1300
+ this._m4_1.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
1301
+ this.camera.updateMatrix();
1302
+
1303
+ //update camera up vector
1304
+ if ( this._state == STATE.ROTATE || this._state == STATE.ZROTATE || this._state == STATE.ANIMATION_ROTATE ) {
1305
+
1306
+ this.camera.up.copy( this._upState ).applyQuaternion( this.camera.quaternion );
1307
+
1308
+ }
1309
+
1310
+ }
1311
+
1312
+ if ( transformation.gizmos != null ) {
1313
+
1314
+ this._m4_1.copy( this._gizmoMatrixState ).premultiply( transformation.gizmos );
1315
+ this._m4_1.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1316
+ this._gizmos.updateMatrix();
1317
+
1318
+ }
1319
+
1320
+ if ( this._state == STATE.SCALE || this._state == STATE.FOCUS || this._state == STATE.ANIMATION_FOCUS ) {
1321
+
1322
+ this._tbRadius = this.calculateTbRadius( this.camera );
1323
+
1324
+ if ( this.adjustNearFar ) {
1325
+
1326
+ const cameraDistance = this.camera.position.distanceTo( this._gizmos.position );
1327
+
1328
+ const bb = new Box3();
1329
+ bb.setFromObject( this._gizmos );
1330
+ const sphere = new Sphere();
1331
+ bb.getBoundingSphere( sphere );
1332
+
1333
+ const adjustedNearPosition = Math.max( this._nearPos0, sphere.radius + sphere.center.length() );
1334
+ const regularNearPosition = cameraDistance - this._initialNear;
1335
+
1336
+ const minNearPos = Math.min( adjustedNearPosition, regularNearPosition );
1337
+ this.camera.near = cameraDistance - minNearPos;
1338
+
1339
+
1340
+ const adjustedFarPosition = Math.min( this._farPos0, - sphere.radius + sphere.center.length() );
1341
+ const regularFarPosition = cameraDistance - this._initialFar;
1342
+
1343
+ const minFarPos = Math.min( adjustedFarPosition, regularFarPosition );
1344
+ this.camera.far = cameraDistance - minFarPos;
1345
+
1346
+ this.camera.updateProjectionMatrix();
1347
+
1348
+ } else {
1349
+
1350
+ let update = false;
1351
+
1352
+ if ( this.camera.near != this._initialNear ) {
1353
+
1354
+ this.camera.near = this._initialNear;
1355
+ update = true;
1356
+
1357
+ }
1358
+
1359
+ if ( this.camera.far != this._initialFar ) {
1360
+
1361
+ this.camera.far = this._initialFar;
1362
+ update = true;
1363
+
1364
+ }
1365
+
1366
+ if ( update ) {
1367
+
1368
+ this.camera.updateProjectionMatrix();
1369
+
1370
+ }
1371
+
1372
+ }
1373
+
1374
+ }
1375
+
1376
+ }
1377
+
1378
+ /**
1379
+ * Calculate the angular speed
1380
+ * @param {Number} p0 Position at t0
1381
+ * @param {Number} p1 Position at t1
1382
+ * @param {Number} t0 Initial time in milliseconds
1383
+ * @param {Number} t1 Ending time in milliseconds
1384
+ */
1385
+ calculateAngularSpeed( p0, p1, t0, t1 ) {
1386
+
1387
+ const s = p1 - p0;
1388
+ const t = ( t1 - t0 ) / 1000;
1389
+ if ( t == 0 ) {
1390
+
1391
+ return 0;
1392
+
1393
+ }
1394
+
1395
+ return s / t;
1396
+
1397
+ }
1398
+
1399
+ /**
1400
+ * Calculate the distance between two pointers
1401
+ * @param {PointerEvent} p0 The first pointer
1402
+ * @param {PointerEvent} p1 The second pointer
1403
+ * @returns {number} The distance between the two pointers
1404
+ */
1405
+ calculatePointersDistance( p0, p1 ) {
1406
+
1407
+ return Math.sqrt( Math.pow( p1.clientX - p0.clientX, 2 ) + Math.pow( p1.clientY - p0.clientY, 2 ) );
1408
+
1409
+ }
1410
+
1411
+ /**
1412
+ * Calculate the rotation axis as the vector perpendicular between two vectors
1413
+ * @param {Vector3} vec1 The first vector
1414
+ * @param {Vector3} vec2 The second vector
1415
+ * @returns {Vector3} The normalized rotation axis
1416
+ */
1417
+ calculateRotationAxis( vec1, vec2 ) {
1418
+
1419
+ this._rotationMatrix.extractRotation( this._cameraMatrixState );
1420
+ this._quat.setFromRotationMatrix( this._rotationMatrix );
1421
+
1422
+ this._rotationAxis.crossVectors( vec1, vec2 ).applyQuaternion( this._quat );
1423
+ return this._rotationAxis.normalize().clone();
1424
+
1425
+ }
1426
+
1427
+ /**
1428
+ * Calculate the trackball radius so that gizmo's diamater will be 2/3 of the minimum side of the camera frustum
1429
+ * @param {Camera} camera
1430
+ * @returns {Number} The trackball radius
1431
+ */
1432
+ calculateTbRadius( camera ) {
1433
+
1434
+ const distance = camera.position.distanceTo( this._gizmos.position );
1435
+
1436
+ if ( camera.type == 'PerspectiveCamera' ) {
1437
+
1438
+ const halfFovV = MathUtils.DEG2RAD * camera.fov * 0.5; //vertical fov/2 in radians
1439
+ const halfFovH = Math.atan( ( camera.aspect ) * Math.tan( halfFovV ) ); //horizontal fov/2 in radians
1440
+ return Math.tan( Math.min( halfFovV, halfFovH ) ) * distance * this.radiusFactor;
1441
+
1442
+ } else if ( camera.type == 'OrthographicCamera' ) {
1443
+
1444
+ return Math.min( camera.top, camera.right ) * this.radiusFactor;
1445
+
1446
+ }
1447
+
1448
+ }
1449
+
1450
+ /**
1451
+ * Focus operation consist of positioning the point of interest in front of the camera and a slightly zoom in
1452
+ * @param {Vector3} point The point of interest
1453
+ * @param {Number} size Scale factor
1454
+ * @param {Number} amount Amount of operation to be completed (used for focus animations, default is complete full operation)
1455
+ */
1456
+ focus( point, size, amount = 1 ) {
1457
+
1458
+ //move center of camera (along with gizmos) towards point of interest
1459
+ _offset.copy( point ).sub( this._gizmos.position ).multiplyScalar( amount );
1460
+ this._translationMatrix.makeTranslation( _offset.x, _offset.y, _offset.z );
1461
+
1462
+ _gizmoMatrixStateTemp.copy( this._gizmoMatrixState );
1463
+ this._gizmoMatrixState.premultiply( this._translationMatrix );
1464
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1465
+
1466
+ _cameraMatrixStateTemp.copy( this._cameraMatrixState );
1467
+ this._cameraMatrixState.premultiply( this._translationMatrix );
1468
+ this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
1469
+
1470
+ //apply zoom
1471
+ if ( this.enableZoom ) {
1472
+
1473
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
1474
+
1475
+ }
1476
+
1477
+ this._gizmoMatrixState.copy( _gizmoMatrixStateTemp );
1478
+ this._cameraMatrixState.copy( _cameraMatrixStateTemp );
1479
+
1480
+ }
1481
+
1482
+ /**
1483
+ * Draw a grid and add it to the scene
1484
+ */
1485
+ drawGrid() {
1486
+
1487
+ if ( this.scene != null ) {
1488
+
1489
+ const color = 0x888888;
1490
+ const multiplier = 3;
1491
+ let size, divisions, maxLength, tick;
1492
+
1493
+ if ( this.camera.isOrthographicCamera ) {
1494
+
1495
+ const width = this.camera.right - this.camera.left;
1496
+ const height = this.camera.bottom - this.camera.top;
1497
+
1498
+ maxLength = Math.max( width, height );
1499
+ tick = maxLength / 20;
1500
+
1501
+ size = maxLength / this.camera.zoom * multiplier;
1502
+ divisions = size / tick * this.camera.zoom;
1503
+
1504
+ } else if ( this.camera.isPerspectiveCamera ) {
1505
+
1506
+ const distance = this.camera.position.distanceTo( this._gizmos.position );
1507
+ const halfFovV = MathUtils.DEG2RAD * this.camera.fov * 0.5;
1508
+ const halfFovH = Math.atan( ( this.camera.aspect ) * Math.tan( halfFovV ) );
1509
+
1510
+ maxLength = Math.tan( Math.max( halfFovV, halfFovH ) ) * distance * 2;
1511
+ tick = maxLength / 20;
1512
+
1513
+ size = maxLength * multiplier;
1514
+ divisions = size / tick;
1515
+
1516
+ }
1517
+
1518
+ if ( this._grid == null ) {
1519
+
1520
+ this._grid = new GridHelper( size, divisions, color, color );
1521
+ this._grid.position.copy( this._gizmos.position );
1522
+ this._gridPosition.copy( this._grid.position );
1523
+ this._grid.quaternion.copy( this.camera.quaternion );
1524
+ this._grid.rotateX( Math.PI * 0.5 );
1525
+
1526
+ this.scene.add( this._grid );
1527
+
1528
+ }
1529
+
1530
+ }
1531
+
1532
+ }
1533
+
1534
+ /**
1535
+ * Remove all listeners, stop animations and clean scene
1536
+ */
1537
+ dispose() {
1538
+
1539
+ if ( this._animationId != - 1 ) {
1540
+
1541
+ window.cancelAnimationFrame( this._animationId );
1542
+
1543
+ }
1544
+
1545
+ this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
1546
+ this.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );
1547
+ this.domElement.removeEventListener( 'wheel', this._onWheel );
1548
+ this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
1549
+
1550
+ window.removeEventListener( 'pointermove', this._onPointerMove );
1551
+ window.removeEventListener( 'pointerup', this._onPointerUp );
1552
+
1553
+ window.removeEventListener( 'resize', this._onWindowResize );
1554
+
1555
+ if ( this.scene !== null ) this.scene.remove( this._gizmos );
1556
+ this.disposeGrid();
1557
+
1558
+ }
1559
+
1560
+ /**
1561
+ * remove the grid from the scene
1562
+ */
1563
+ disposeGrid() {
1564
+
1565
+ if ( this._grid != null && this.scene != null ) {
1566
+
1567
+ this.scene.remove( this._grid );
1568
+ this._grid = null;
1569
+
1570
+ }
1571
+
1572
+ }
1573
+
1574
+ /**
1575
+ * Compute the easing out cubic function for ease out effect in animation
1576
+ * @param {Number} t The absolute progress of the animation in the bound of 0 (beginning of the) and 1 (ending of animation)
1577
+ * @returns {Number} Result of easing out cubic at time t
1578
+ */
1579
+ easeOutCubic( t ) {
1580
+
1581
+ return 1 - Math.pow( 1 - t, 3 );
1582
+
1583
+ }
1584
+
1585
+ /**
1586
+ * Make rotation gizmos more or less visible
1587
+ * @param {Boolean} isActive If true, make gizmos more visible
1588
+ */
1589
+ activateGizmos( isActive ) {
1590
+
1591
+ const gizmoX = this._gizmos.children[ 0 ];
1592
+ const gizmoY = this._gizmos.children[ 1 ];
1593
+ const gizmoZ = this._gizmos.children[ 2 ];
1594
+
1595
+ if ( isActive ) {
1596
+
1597
+ gizmoX.material.setValues( { opacity: 1 } );
1598
+ gizmoY.material.setValues( { opacity: 1 } );
1599
+ gizmoZ.material.setValues( { opacity: 1 } );
1600
+
1601
+ } else {
1602
+
1603
+ gizmoX.material.setValues( { opacity: 0.6 } );
1604
+ gizmoY.material.setValues( { opacity: 0.6 } );
1605
+ gizmoZ.material.setValues( { opacity: 0.6 } );
1606
+
1607
+ }
1608
+
1609
+ }
1610
+
1611
+ /**
1612
+ * Calculate the cursor position in NDC
1613
+ * @param {number} x Cursor horizontal coordinate within the canvas
1614
+ * @param {number} y Cursor vertical coordinate within the canvas
1615
+ * @param {HTMLElement} canvas The canvas where the renderer draws its output
1616
+ * @returns {Vector2} Cursor normalized position inside the canvas
1617
+ */
1618
+ getCursorNDC( cursorX, cursorY, canvas ) {
1619
+
1620
+ const canvasRect = canvas.getBoundingClientRect();
1621
+ this._v2_1.setX( ( ( cursorX - canvasRect.left ) / canvasRect.width ) * 2 - 1 );
1622
+ this._v2_1.setY( ( ( canvasRect.bottom - cursorY ) / canvasRect.height ) * 2 - 1 );
1623
+ return this._v2_1.clone();
1624
+
1625
+ }
1626
+
1627
+ /**
1628
+ * Calculate the cursor position inside the canvas x/y coordinates with the origin being in the center of the canvas
1629
+ * @param {Number} x Cursor horizontal coordinate within the canvas
1630
+ * @param {Number} y Cursor vertical coordinate within the canvas
1631
+ * @param {HTMLElement} canvas The canvas where the renderer draws its output
1632
+ * @returns {Vector2} Cursor position inside the canvas
1633
+ */
1634
+ getCursorPosition( cursorX, cursorY, canvas ) {
1635
+
1636
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
1637
+ this._v2_1.x *= ( this.camera.right - this.camera.left ) * 0.5;
1638
+ this._v2_1.y *= ( this.camera.top - this.camera.bottom ) * 0.5;
1639
+ return this._v2_1.clone();
1640
+
1641
+ }
1642
+
1643
+ /**
1644
+ * Set the camera to be controlled
1645
+ * @param {Camera} camera The virtual camera to be controlled
1646
+ */
1647
+ setCamera( camera ) {
1648
+
1649
+ camera.lookAt( this.target );
1650
+ camera.updateMatrix();
1651
+
1652
+ //setting state
1653
+ if ( camera.type == 'PerspectiveCamera' ) {
1654
+
1655
+ this._fov0 = camera.fov;
1656
+ this._fovState = camera.fov;
1657
+
1658
+ }
1659
+
1660
+ this._cameraMatrixState0.copy( camera.matrix );
1661
+ this._cameraMatrixState.copy( this._cameraMatrixState0 );
1662
+ this._cameraProjectionState.copy( camera.projectionMatrix );
1663
+ this._zoom0 = camera.zoom;
1664
+ this._zoomState = this._zoom0;
1665
+
1666
+ this._initialNear = camera.near;
1667
+ this._nearPos0 = camera.position.distanceTo( this.target ) - camera.near;
1668
+ this._nearPos = this._initialNear;
1669
+
1670
+ this._initialFar = camera.far;
1671
+ this._farPos0 = camera.position.distanceTo( this.target ) - camera.far;
1672
+ this._farPos = this._initialFar;
1673
+
1674
+ this._up0.copy( camera.up );
1675
+ this._upState.copy( camera.up );
1676
+
1677
+ this.camera = camera;
1678
+ this.camera.updateProjectionMatrix();
1679
+
1680
+ //making gizmos
1681
+ this._tbRadius = this.calculateTbRadius( camera );
1682
+ this.makeGizmos( this.target, this._tbRadius );
1683
+
1684
+ }
1685
+
1686
+ /**
1687
+ * Set gizmos visibility
1688
+ * @param {Boolean} value Value of gizmos visibility
1689
+ */
1690
+ setGizmosVisible( value ) {
1691
+
1692
+ this._gizmos.visible = value;
1693
+ this.dispatchEvent( _changeEvent );
1694
+
1695
+ }
1696
+
1697
+ /**
1698
+ * Set gizmos radius factor and redraws gizmos
1699
+ * @param {Float} value Value of radius factor
1700
+ */
1701
+ setTbRadius( value ) {
1702
+
1703
+ this.radiusFactor = value;
1704
+ this._tbRadius = this.calculateTbRadius( this.camera );
1705
+
1706
+ const curve = new EllipseCurve( 0, 0, this._tbRadius, this._tbRadius );
1707
+ const points = curve.getPoints( this._curvePts );
1708
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
1709
+
1710
+
1711
+ for ( const gizmo in this._gizmos.children ) {
1712
+
1713
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
1714
+
1715
+ }
1716
+
1717
+ this.dispatchEvent( _changeEvent );
1718
+
1719
+ }
1720
+
1721
+ /**
1722
+ * Creates the rotation gizmos matching trackball center and radius
1723
+ * @param {Vector3} tbCenter The trackball center
1724
+ * @param {number} tbRadius The trackball radius
1725
+ */
1726
+ makeGizmos( tbCenter, tbRadius ) {
1727
+
1728
+ const curve = new EllipseCurve( 0, 0, tbRadius, tbRadius );
1729
+ const points = curve.getPoints( this._curvePts );
1730
+
1731
+ //geometry
1732
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
1733
+
1734
+ //material
1735
+ const curveMaterialX = new LineBasicMaterial( { color: 0xff8080, fog: false, transparent: true, opacity: 0.6 } );
1736
+ const curveMaterialY = new LineBasicMaterial( { color: 0x80ff80, fog: false, transparent: true, opacity: 0.6 } );
1737
+ const curveMaterialZ = new LineBasicMaterial( { color: 0x8080ff, fog: false, transparent: true, opacity: 0.6 } );
1738
+
1739
+ //line
1740
+ const gizmoX = new Line( curveGeometry, curveMaterialX );
1741
+ const gizmoY = new Line( curveGeometry, curveMaterialY );
1742
+ const gizmoZ = new Line( curveGeometry, curveMaterialZ );
1743
+
1744
+ const rotation = Math.PI * 0.5;
1745
+ gizmoX.rotation.x = rotation;
1746
+ gizmoY.rotation.y = rotation;
1747
+
1748
+
1749
+ //setting state
1750
+ this._gizmoMatrixState0.identity().setPosition( tbCenter );
1751
+ this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
1752
+
1753
+ if ( this.camera.zoom !== 1 ) {
1754
+
1755
+ //adapt gizmos size to camera zoom
1756
+ const size = 1 / this.camera.zoom;
1757
+ this._scaleMatrix.makeScale( size, size, size );
1758
+ this._translationMatrix.makeTranslation( - tbCenter.x, - tbCenter.y, - tbCenter.z );
1759
+
1760
+ this._gizmoMatrixState.premultiply( this._translationMatrix ).premultiply( this._scaleMatrix );
1761
+ this._translationMatrix.makeTranslation( tbCenter.x, tbCenter.y, tbCenter.z );
1762
+ this._gizmoMatrixState.premultiply( this._translationMatrix );
1763
+
1764
+ }
1765
+
1766
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1767
+
1768
+ //
1769
+
1770
+ this._gizmos.traverse( function ( object ) {
1771
+
1772
+ if ( object.isLine ) {
1773
+
1774
+ object.geometry.dispose();
1775
+ object.material.dispose();
1776
+
1777
+ }
1778
+
1779
+ } );
1780
+
1781
+ this._gizmos.clear();
1782
+
1783
+ //
1784
+
1785
+ this._gizmos.add( gizmoX );
1786
+ this._gizmos.add( gizmoY );
1787
+ this._gizmos.add( gizmoZ );
1788
+
1789
+ }
1790
+
1791
+ /**
1792
+ * Perform animation for focus operation
1793
+ * @param {Number} time Instant in which this function is called as performance.now()
1794
+ * @param {Vector3} point Point of interest for focus operation
1795
+ * @param {Matrix4} cameraMatrix Camera matrix
1796
+ * @param {Matrix4} gizmoMatrix Gizmos matrix
1797
+ */
1798
+ onFocusAnim( time, point, cameraMatrix, gizmoMatrix ) {
1799
+
1800
+ if ( this._timeStart == - 1 ) {
1801
+
1802
+ //animation start
1803
+ this._timeStart = time;
1804
+
1805
+ }
1806
+
1807
+ if ( this._state == STATE.ANIMATION_FOCUS ) {
1808
+
1809
+ const deltaTime = time - this._timeStart;
1810
+ const animTime = deltaTime / this.focusAnimationTime;
1811
+
1812
+ this._gizmoMatrixState.copy( gizmoMatrix );
1813
+
1814
+ if ( animTime >= 1 ) {
1815
+
1816
+ //animation end
1817
+
1818
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1819
+
1820
+ this.focus( point, this.scaleFactor );
1821
+
1822
+ this._timeStart = - 1;
1823
+ this.updateTbState( STATE.IDLE, false );
1824
+ this.activateGizmos( false );
1825
+
1826
+ this.dispatchEvent( _changeEvent );
1827
+
1828
+ } else {
1829
+
1830
+ const amount = this.easeOutCubic( animTime );
1831
+ const size = ( ( 1 - amount ) + ( this.scaleFactor * amount ) );
1832
+
1833
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1834
+ this.focus( point, size, amount );
1835
+
1836
+ this.dispatchEvent( _changeEvent );
1837
+ const self = this;
1838
+ this._animationId = window.requestAnimationFrame( function ( t ) {
1839
+
1840
+ self.onFocusAnim( t, point, cameraMatrix, gizmoMatrix.clone() );
1841
+
1842
+ } );
1843
+
1844
+ }
1845
+
1846
+ } else {
1847
+
1848
+ //interrupt animation
1849
+
1850
+ this._animationId = - 1;
1851
+ this._timeStart = - 1;
1852
+
1853
+ }
1854
+
1855
+ }
1856
+
1857
+ /**
1858
+ * Perform animation for rotation operation
1859
+ * @param {Number} time Instant in which this function is called as performance.now()
1860
+ * @param {Vector3} rotationAxis Rotation axis
1861
+ * @param {number} w0 Initial angular velocity
1862
+ */
1863
+ onRotationAnim( time, rotationAxis, w0 ) {
1864
+
1865
+ if ( this._timeStart == - 1 ) {
1866
+
1867
+ //animation start
1868
+ this._anglePrev = 0;
1869
+ this._angleCurrent = 0;
1870
+ this._timeStart = time;
1871
+
1872
+ }
1873
+
1874
+ if ( this._state == STATE.ANIMATION_ROTATE ) {
1875
+
1876
+ //w = w0 + alpha * t
1877
+ const deltaTime = ( time - this._timeStart ) / 1000;
1878
+ const w = w0 + ( ( - this.dampingFactor ) * deltaTime );
1879
+
1880
+ if ( w > 0 ) {
1881
+
1882
+ //tetha = 0.5 * alpha * t^2 + w0 * t + tetha0
1883
+ this._angleCurrent = 0.5 * ( - this.dampingFactor ) * Math.pow( deltaTime, 2 ) + w0 * deltaTime + 0;
1884
+ this.applyTransformMatrix( this.rotate( rotationAxis, this._angleCurrent ) );
1885
+ this.dispatchEvent( _changeEvent );
1886
+ const self = this;
1887
+ this._animationId = window.requestAnimationFrame( function ( t ) {
1888
+
1889
+ self.onRotationAnim( t, rotationAxis, w0 );
1890
+
1891
+ } );
1892
+
1893
+ } else {
1894
+
1895
+ this._animationId = - 1;
1896
+ this._timeStart = - 1;
1897
+
1898
+ this.updateTbState( STATE.IDLE, false );
1899
+ this.activateGizmos( false );
1900
+
1901
+ this.dispatchEvent( _changeEvent );
1902
+
1903
+ }
1904
+
1905
+ } else {
1906
+
1907
+ //interrupt animation
1908
+
1909
+ this._animationId = - 1;
1910
+ this._timeStart = - 1;
1911
+
1912
+ if ( this._state != STATE.ROTATE ) {
1913
+
1914
+ this.activateGizmos( false );
1915
+ this.dispatchEvent( _changeEvent );
1916
+
1917
+ }
1918
+
1919
+ }
1920
+
1921
+ }
1922
+
1923
+
1924
+ /**
1925
+ * Perform pan operation moving camera between two points
1926
+ * @param {Vector3} p0 Initial point
1927
+ * @param {Vector3} p1 Ending point
1928
+ * @param {Boolean} adjust If movement should be adjusted considering camera distance (Perspective only)
1929
+ */
1930
+ pan( p0, p1, adjust = false ) {
1931
+
1932
+ const movement = p0.clone().sub( p1 );
1933
+
1934
+ if ( this.camera.isOrthographicCamera ) {
1935
+
1936
+ //adjust movement amount
1937
+ movement.multiplyScalar( 1 / this.camera.zoom );
1938
+
1939
+ } else if ( this.camera.isPerspectiveCamera && adjust ) {
1940
+
1941
+ //adjust movement amount
1942
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ); //camera's initial position
1943
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ); //gizmo's initial position
1944
+ const distanceFactor = this._v3_1.distanceTo( this._v3_2 ) / this.camera.position.distanceTo( this._gizmos.position );
1945
+ movement.multiplyScalar( 1 / distanceFactor );
1946
+
1947
+ }
1948
+
1949
+ this._v3_1.set( movement.x, movement.y, 0 ).applyQuaternion( this.camera.quaternion );
1950
+
1951
+ this._m4_1.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z );
1952
+
1953
+ this.setTransformationMatrices( this._m4_1, this._m4_1 );
1954
+ return _transformation;
1955
+
1956
+ }
1957
+
1958
+ /**
1959
+ * Reset trackball
1960
+ */
1961
+ reset() {
1962
+
1963
+ this.camera.zoom = this._zoom0;
1964
+
1965
+ if ( this.camera.isPerspectiveCamera ) {
1966
+
1967
+ this.camera.fov = this._fov0;
1968
+
1969
+ }
1970
+
1971
+ this.camera.near = this._nearPos;
1972
+ this.camera.far = this._farPos;
1973
+ this._cameraMatrixState.copy( this._cameraMatrixState0 );
1974
+ this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
1975
+ this.camera.up.copy( this._up0 );
1976
+
1977
+ this.camera.updateMatrix();
1978
+ this.camera.updateProjectionMatrix();
1979
+
1980
+ this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
1981
+ this._gizmoMatrixState0.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1982
+ this._gizmos.updateMatrix();
1983
+
1984
+ this._tbRadius = this.calculateTbRadius( this.camera );
1985
+ this.makeGizmos( this._gizmos.position, this._tbRadius );
1986
+
1987
+ this.camera.lookAt( this._gizmos.position );
1988
+
1989
+ this.updateTbState( STATE.IDLE, false );
1990
+
1991
+ this.dispatchEvent( _changeEvent );
1992
+
1993
+ }
1994
+
1995
+ /**
1996
+ * Rotate the camera around an axis passing by trackball's center
1997
+ * @param {Vector3} axis Rotation axis
1998
+ * @param {number} angle Angle in radians
1999
+ * @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera
2000
+ */
2001
+ rotate( axis, angle ) {
2002
+
2003
+ const point = this._gizmos.position; //rotation center
2004
+ this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
2005
+ this._rotationMatrix.makeRotationAxis( axis, - angle );
2006
+
2007
+ //rotate camera
2008
+ this._m4_1.makeTranslation( point.x, point.y, point.z );
2009
+ this._m4_1.multiply( this._rotationMatrix );
2010
+ this._m4_1.multiply( this._translationMatrix );
2011
+
2012
+ this.setTransformationMatrices( this._m4_1 );
2013
+
2014
+ return _transformation;
2015
+
2016
+ }
2017
+
2018
+ copyState() {
2019
+
2020
+ let state;
2021
+ if ( this.camera.isOrthographicCamera ) {
2022
+
2023
+ state = JSON.stringify( { arcballState: {
2024
+
2025
+ cameraFar: this.camera.far,
2026
+ cameraMatrix: this.camera.matrix,
2027
+ cameraNear: this.camera.near,
2028
+ cameraUp: this.camera.up,
2029
+ cameraZoom: this.camera.zoom,
2030
+ gizmoMatrix: this._gizmos.matrix
2031
+
2032
+ } } );
2033
+
2034
+ } else if ( this.camera.isPerspectiveCamera ) {
2035
+
2036
+ state = JSON.stringify( { arcballState: {
2037
+ cameraFar: this.camera.far,
2038
+ cameraFov: this.camera.fov,
2039
+ cameraMatrix: this.camera.matrix,
2040
+ cameraNear: this.camera.near,
2041
+ cameraUp: this.camera.up,
2042
+ cameraZoom: this.camera.zoom,
2043
+ gizmoMatrix: this._gizmos.matrix
2044
+
2045
+ } } );
2046
+
2047
+ }
2048
+
2049
+ navigator.clipboard.writeText( state );
2050
+
2051
+ }
2052
+
2053
+ pasteState() {
2054
+
2055
+ const self = this;
2056
+ navigator.clipboard.readText().then( function resolved( value ) {
2057
+
2058
+ self.setStateFromJSON( value );
2059
+
2060
+ } );
2061
+
2062
+ }
2063
+
2064
+ /**
2065
+ * Save the current state of the control. This can later be recover with .reset
2066
+ */
2067
+ saveState() {
2068
+
2069
+ this._cameraMatrixState0.copy( this.camera.matrix );
2070
+ this._gizmoMatrixState0.copy( this._gizmos.matrix );
2071
+ this._nearPos = this.camera.near;
2072
+ this._farPos = this.camera.far;
2073
+ this._zoom0 = this.camera.zoom;
2074
+ this._up0.copy( this.camera.up );
2075
+
2076
+ if ( this.camera.isPerspectiveCamera ) {
2077
+
2078
+ this._fov0 = this.camera.fov;
2079
+
2080
+ }
2081
+
2082
+ }
2083
+
2084
+ /**
2085
+ * Perform uniform scale operation around a given point
2086
+ * @param {Number} size Scale factor
2087
+ * @param {Vector3} point Point around which scale
2088
+ * @param {Boolean} scaleGizmos If gizmos should be scaled (Perspective only)
2089
+ * @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos
2090
+ */
2091
+ scale( size, point, scaleGizmos = true ) {
2092
+
2093
+ _scalePointTemp.copy( point );
2094
+ let sizeInverse = 1 / size;
2095
+
2096
+ if ( this.camera.isOrthographicCamera ) {
2097
+
2098
+ //camera zoom
2099
+ this.camera.zoom = this._zoomState;
2100
+ this.camera.zoom *= size;
2101
+
2102
+ //check min and max zoom
2103
+ if ( this.camera.zoom > this.maxZoom ) {
2104
+
2105
+ this.camera.zoom = this.maxZoom;
2106
+ sizeInverse = this._zoomState / this.maxZoom;
2107
+
2108
+ } else if ( this.camera.zoom < this.minZoom ) {
2109
+
2110
+ this.camera.zoom = this.minZoom;
2111
+ sizeInverse = this._zoomState / this.minZoom;
2112
+
2113
+ }
2114
+
2115
+ this.camera.updateProjectionMatrix();
2116
+
2117
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ); //gizmos position
2118
+
2119
+ //scale gizmos so they appear in the same spot having the same dimension
2120
+ this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
2121
+ this._translationMatrix.makeTranslation( - this._v3_1.x, - this._v3_1.y, - this._v3_1.z );
2122
+
2123
+ this._m4_2.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z ).multiply( this._scaleMatrix );
2124
+ this._m4_2.multiply( this._translationMatrix );
2125
+
2126
+
2127
+ //move camera and gizmos to obtain pinch effect
2128
+ _scalePointTemp.sub( this._v3_1 );
2129
+
2130
+ const amount = _scalePointTemp.clone().multiplyScalar( sizeInverse );
2131
+ _scalePointTemp.sub( amount );
2132
+
2133
+ this._m4_1.makeTranslation( _scalePointTemp.x, _scalePointTemp.y, _scalePointTemp.z );
2134
+ this._m4_2.premultiply( this._m4_1 );
2135
+
2136
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2137
+ return _transformation;
2138
+
2139
+ } else if ( this.camera.isPerspectiveCamera ) {
2140
+
2141
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
2142
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
2143
+
2144
+ //move camera
2145
+ let distance = this._v3_1.distanceTo( _scalePointTemp );
2146
+ let amount = distance - ( distance * sizeInverse );
2147
+
2148
+ //check min and max distance
2149
+ const newDistance = distance - amount;
2150
+ if ( newDistance < this.minDistance ) {
2151
+
2152
+ sizeInverse = this.minDistance / distance;
2153
+ amount = distance - ( distance * sizeInverse );
2154
+
2155
+ } else if ( newDistance > this.maxDistance ) {
2156
+
2157
+ sizeInverse = this.maxDistance / distance;
2158
+ amount = distance - ( distance * sizeInverse );
2159
+
2160
+ }
2161
+
2162
+ _offset.copy( _scalePointTemp ).sub( this._v3_1 ).normalize().multiplyScalar( amount );
2163
+
2164
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
2165
+
2166
+
2167
+ if ( scaleGizmos ) {
2168
+
2169
+ //scale gizmos so they appear in the same spot having the same dimension
2170
+ const pos = this._v3_2;
2171
+
2172
+ distance = pos.distanceTo( _scalePointTemp );
2173
+ amount = distance - ( distance * sizeInverse );
2174
+ _offset.copy( _scalePointTemp ).sub( this._v3_2 ).normalize().multiplyScalar( amount );
2175
+
2176
+ this._translationMatrix.makeTranslation( pos.x, pos.y, pos.z );
2177
+ this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
2178
+
2179
+ this._m4_2.makeTranslation( _offset.x, _offset.y, _offset.z ).multiply( this._translationMatrix );
2180
+ this._m4_2.multiply( this._scaleMatrix );
2181
+
2182
+ this._translationMatrix.makeTranslation( - pos.x, - pos.y, - pos.z );
2183
+
2184
+ this._m4_2.multiply( this._translationMatrix );
2185
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2186
+
2187
+
2188
+ } else {
2189
+
2190
+ this.setTransformationMatrices( this._m4_1 );
2191
+
2192
+ }
2193
+
2194
+ return _transformation;
2195
+
2196
+ }
2197
+
2198
+ }
2199
+
2200
+ /**
2201
+ * Set camera fov
2202
+ * @param {Number} value fov to be setted
2203
+ */
2204
+ setFov( value ) {
2205
+
2206
+ if ( this.camera.isPerspectiveCamera ) {
2207
+
2208
+ this.camera.fov = MathUtils.clamp( value, this.minFov, this.maxFov );
2209
+ this.camera.updateProjectionMatrix();
2210
+
2211
+ }
2212
+
2213
+ }
2214
+
2215
+ /**
2216
+ * Set values in transformation object
2217
+ * @param {Matrix4} camera Transformation to be applied to the camera
2218
+ * @param {Matrix4} gizmos Transformation to be applied to gizmos
2219
+ */
2220
+ setTransformationMatrices( camera = null, gizmos = null ) {
2221
+
2222
+ if ( camera != null ) {
2223
+
2224
+ if ( _transformation.camera != null ) {
2225
+
2226
+ _transformation.camera.copy( camera );
2227
+
2228
+ } else {
2229
+
2230
+ _transformation.camera = camera.clone();
2231
+
2232
+ }
2233
+
2234
+ } else {
2235
+
2236
+ _transformation.camera = null;
2237
+
2238
+ }
2239
+
2240
+ if ( gizmos != null ) {
2241
+
2242
+ if ( _transformation.gizmos != null ) {
2243
+
2244
+ _transformation.gizmos.copy( gizmos );
2245
+
2246
+ } else {
2247
+
2248
+ _transformation.gizmos = gizmos.clone();
2249
+
2250
+ }
2251
+
2252
+ } else {
2253
+
2254
+ _transformation.gizmos = null;
2255
+
2256
+ }
2257
+
2258
+ }
2259
+
2260
+ /**
2261
+ * Rotate camera around its direction axis passing by a given point by a given angle
2262
+ * @param {Vector3} point The point where the rotation axis is passing trough
2263
+ * @param {Number} angle Angle in radians
2264
+ * @returns The computed transormation matix
2265
+ */
2266
+ zRotate( point, angle ) {
2267
+
2268
+ this._rotationMatrix.makeRotationAxis( this._rotationAxis, angle );
2269
+ this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
2270
+
2271
+ this._m4_1.makeTranslation( point.x, point.y, point.z );
2272
+ this._m4_1.multiply( this._rotationMatrix );
2273
+ this._m4_1.multiply( this._translationMatrix );
2274
+
2275
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ).sub( point ); //vector from rotation center to gizmos position
2276
+ this._v3_2.copy( this._v3_1 ).applyAxisAngle( this._rotationAxis, angle ); //apply rotation
2277
+ this._v3_2.sub( this._v3_1 );
2278
+
2279
+ this._m4_2.makeTranslation( this._v3_2.x, this._v3_2.y, this._v3_2.z );
2280
+
2281
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2282
+ return _transformation;
2283
+
2284
+ }
2285
+
2286
+
2287
+ getRaycaster() {
2288
+
2289
+ return _raycaster;
2290
+
2291
+ }
2292
+
2293
+
2294
+ /**
2295
+ * Unproject the cursor on the 3D object surface
2296
+ * @param {Vector2} cursor Cursor coordinates in NDC
2297
+ * @param {Camera} camera Virtual camera
2298
+ * @returns {Vector3} The point of intersection with the model, if exist, null otherwise
2299
+ */
2300
+ unprojectOnObj( cursor, camera ) {
2301
+
2302
+ const raycaster = this.getRaycaster();
2303
+ raycaster.near = camera.near;
2304
+ raycaster.far = camera.far;
2305
+ raycaster.setFromCamera( cursor, camera );
2306
+
2307
+ const intersect = raycaster.intersectObjects( this.scene.children, true );
2308
+
2309
+ for ( let i = 0; i < intersect.length; i ++ ) {
2310
+
2311
+ if ( intersect[ i ].object.uuid != this._gizmos.uuid && intersect[ i ].face != null ) {
2312
+
2313
+ return intersect[ i ].point.clone();
2314
+
2315
+ }
2316
+
2317
+ }
2318
+
2319
+ return null;
2320
+
2321
+ }
2322
+
2323
+ /**
2324
+ * Unproject the cursor on the trackball surface
2325
+ * @param {Camera} camera The virtual camera
2326
+ * @param {Number} cursorX Cursor horizontal coordinate on screen
2327
+ * @param {Number} cursorY Cursor vertical coordinate on screen
2328
+ * @param {HTMLElement} canvas The canvas where the renderer draws its output
2329
+ * @param {number} tbRadius The trackball radius
2330
+ * @returns {Vector3} The unprojected point on the trackball surface
2331
+ */
2332
+ unprojectOnTbSurface( camera, cursorX, cursorY, canvas, tbRadius ) {
2333
+
2334
+ if ( camera.type == 'OrthographicCamera' ) {
2335
+
2336
+ this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
2337
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
2338
+
2339
+ const x2 = Math.pow( this._v2_1.x, 2 );
2340
+ const y2 = Math.pow( this._v2_1.y, 2 );
2341
+ const r2 = Math.pow( this._tbRadius, 2 );
2342
+
2343
+ if ( x2 + y2 <= r2 * 0.5 ) {
2344
+
2345
+ //intersection with sphere
2346
+ this._v3_1.setZ( Math.sqrt( r2 - ( x2 + y2 ) ) );
2347
+
2348
+ } else {
2349
+
2350
+ //intersection with hyperboloid
2351
+ this._v3_1.setZ( ( r2 * 0.5 ) / ( Math.sqrt( x2 + y2 ) ) );
2352
+
2353
+ }
2354
+
2355
+ return this._v3_1;
2356
+
2357
+ } else if ( camera.type == 'PerspectiveCamera' ) {
2358
+
2359
+ //unproject cursor on the near plane
2360
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
2361
+
2362
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
2363
+ this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
2364
+
2365
+ const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
2366
+ const cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
2367
+ const radius2 = Math.pow( tbRadius, 2 );
2368
+
2369
+ // camera
2370
+ // |\
2371
+ // | \
2372
+ // | \
2373
+ // h | \
2374
+ // | \
2375
+ // | \
2376
+ // _ _ | _ _ _\ _ _ near plane
2377
+ // l
2378
+
2379
+ const h = this._v3_1.z;
2380
+ const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
2381
+
2382
+ if ( l == 0 ) {
2383
+
2384
+ //ray aligned with camera
2385
+ rayDir.set( this._v3_1.x, this._v3_1.y, tbRadius );
2386
+ return rayDir;
2387
+
2388
+ }
2389
+
2390
+ const m = h / l;
2391
+ const q = cameraGizmoDistance;
2392
+
2393
+ /*
2394
+ * calculate intersection point between unprojected ray and trackball surface
2395
+ *|y = m * x + q
2396
+ *|x^2 + y^2 = r^2
2397
+ *
2398
+ * (m^2 + 1) * x^2 + (2 * m * q) * x + q^2 - r^2 = 0
2399
+ */
2400
+ let a = Math.pow( m, 2 ) + 1;
2401
+ let b = 2 * m * q;
2402
+ let c = Math.pow( q, 2 ) - radius2;
2403
+ let delta = Math.pow( b, 2 ) - ( 4 * a * c );
2404
+
2405
+ if ( delta >= 0 ) {
2406
+
2407
+ //intersection with sphere
2408
+ this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
2409
+ this._v2_1.setY( m * this._v2_1.x + q );
2410
+
2411
+ const angle = MathUtils.RAD2DEG * this._v2_1.angle();
2412
+
2413
+ if ( angle >= 45 ) {
2414
+
2415
+ //if angle between intersection point and X' axis is >= 45°, return that point
2416
+ //otherwise, calculate intersection point with hyperboloid
2417
+
2418
+ const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
2419
+ rayDir.multiplyScalar( rayLength );
2420
+ rayDir.z += cameraGizmoDistance;
2421
+ return rayDir;
2422
+
2423
+ }
2424
+
2425
+ }
2426
+
2427
+ //intersection with hyperboloid
2428
+ /*
2429
+ *|y = m * x + q
2430
+ *|y = (1 / x) * (r^2 / 2)
2431
+ *
2432
+ * m * x^2 + q * x - r^2 / 2 = 0
2433
+ */
2434
+
2435
+ a = m;
2436
+ b = q;
2437
+ c = - radius2 * 0.5;
2438
+ delta = Math.pow( b, 2 ) - ( 4 * a * c );
2439
+ this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
2440
+ this._v2_1.setY( m * this._v2_1.x + q );
2441
+
2442
+ const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
2443
+
2444
+ rayDir.multiplyScalar( rayLength );
2445
+ rayDir.z += cameraGizmoDistance;
2446
+ return rayDir;
2447
+
2448
+ }
2449
+
2450
+ }
2451
+
2452
+
2453
+ /**
2454
+ * Unproject the cursor on the plane passing through the center of the trackball orthogonal to the camera
2455
+ * @param {Camera} camera The virtual camera
2456
+ * @param {Number} cursorX Cursor horizontal coordinate on screen
2457
+ * @param {Number} cursorY Cursor vertical coordinate on screen
2458
+ * @param {HTMLElement} canvas The canvas where the renderer draws its output
2459
+ * @param {Boolean} initialDistance If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only)
2460
+ * @returns {Vector3} The unprojected point on the trackball plane
2461
+ */
2462
+ unprojectOnTbPlane( camera, cursorX, cursorY, canvas, initialDistance = false ) {
2463
+
2464
+ if ( camera.type == 'OrthographicCamera' ) {
2465
+
2466
+ this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
2467
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
2468
+
2469
+ return this._v3_1.clone();
2470
+
2471
+ } else if ( camera.type == 'PerspectiveCamera' ) {
2472
+
2473
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
2474
+
2475
+ //unproject cursor on the near plane
2476
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
2477
+ this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
2478
+
2479
+ const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
2480
+
2481
+ // camera
2482
+ // |\
2483
+ // | \
2484
+ // | \
2485
+ // h | \
2486
+ // | \
2487
+ // | \
2488
+ // _ _ | _ _ _\ _ _ near plane
2489
+ // l
2490
+
2491
+ const h = this._v3_1.z;
2492
+ const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
2493
+ let cameraGizmoDistance;
2494
+
2495
+ if ( initialDistance ) {
2496
+
2497
+ cameraGizmoDistance = this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ).distanceTo( this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ) );
2498
+
2499
+ } else {
2500
+
2501
+ cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
2502
+
2503
+ }
2504
+
2505
+ /*
2506
+ * calculate intersection point between unprojected ray and the plane
2507
+ *|y = mx + q
2508
+ *|y = 0
2509
+ *
2510
+ * x = -q/m
2511
+ */
2512
+ if ( l == 0 ) {
2513
+
2514
+ //ray aligned with camera
2515
+ rayDir.set( 0, 0, 0 );
2516
+ return rayDir;
2517
+
2518
+ }
2519
+
2520
+ const m = h / l;
2521
+ const q = cameraGizmoDistance;
2522
+ const x = - q / m;
2523
+
2524
+ const rayLength = Math.sqrt( Math.pow( q, 2 ) + Math.pow( x, 2 ) );
2525
+ rayDir.multiplyScalar( rayLength );
2526
+ rayDir.z = 0;
2527
+ return rayDir;
2528
+
2529
+ }
2530
+
2531
+ }
2532
+
2533
+ /**
2534
+ * Update camera and gizmos state
2535
+ */
2536
+ updateMatrixState() {
2537
+
2538
+ //update camera and gizmos state
2539
+ this._cameraMatrixState.copy( this.camera.matrix );
2540
+ this._gizmoMatrixState.copy( this._gizmos.matrix );
2541
+
2542
+ if ( this.camera.isOrthographicCamera ) {
2543
+
2544
+ this._cameraProjectionState.copy( this.camera.projectionMatrix );
2545
+ this.camera.updateProjectionMatrix();
2546
+ this._zoomState = this.camera.zoom;
2547
+
2548
+ } else if ( this.camera.isPerspectiveCamera ) {
2549
+
2550
+ this._fovState = this.camera.fov;
2551
+
2552
+ }
2553
+
2554
+ }
2555
+
2556
+ /**
2557
+ * Update the trackball FSA
2558
+ * @param {STATE} newState New state of the FSA
2559
+ * @param {Boolean} updateMatrices If matriices state should be updated
2560
+ */
2561
+ updateTbState( newState, updateMatrices ) {
2562
+
2563
+ this._state = newState;
2564
+ if ( updateMatrices ) {
2565
+
2566
+ this.updateMatrixState();
2567
+
2568
+ }
2569
+
2570
+ }
2571
+
2572
+ update() {
2573
+
2574
+ const EPS = 0.000001;
2575
+
2576
+ if ( this.target.equals( this._currentTarget ) === false ) {
2577
+
2578
+ this._gizmos.position.copy( this.target ); //for correct radius calculation
2579
+ this._tbRadius = this.calculateTbRadius( this.camera );
2580
+ this.makeGizmos( this.target, this._tbRadius );
2581
+ this._currentTarget.copy( this.target );
2582
+
2583
+ }
2584
+
2585
+ //check min/max parameters
2586
+ if ( this.camera.isOrthographicCamera ) {
2587
+
2588
+ //check zoom
2589
+ if ( this.camera.zoom > this.maxZoom || this.camera.zoom < this.minZoom ) {
2590
+
2591
+ const newZoom = MathUtils.clamp( this.camera.zoom, this.minZoom, this.maxZoom );
2592
+ this.applyTransformMatrix( this.scale( newZoom / this.camera.zoom, this._gizmos.position, true ) );
2593
+
2594
+ }
2595
+
2596
+ } else if ( this.camera.isPerspectiveCamera ) {
2597
+
2598
+ //check distance
2599
+ const distance = this.camera.position.distanceTo( this._gizmos.position );
2600
+
2601
+ if ( distance > this.maxDistance + EPS || distance < this.minDistance - EPS ) {
2602
+
2603
+ const newDistance = MathUtils.clamp( distance, this.minDistance, this.maxDistance );
2604
+ this.applyTransformMatrix( this.scale( newDistance / distance, this._gizmos.position ) );
2605
+ this.updateMatrixState();
2606
+
2607
+ }
2608
+
2609
+ //check fov
2610
+ if ( this.camera.fov < this.minFov || this.camera.fov > this.maxFov ) {
2611
+
2612
+ this.camera.fov = MathUtils.clamp( this.camera.fov, this.minFov, this.maxFov );
2613
+ this.camera.updateProjectionMatrix();
2614
+
2615
+ }
2616
+
2617
+ const oldRadius = this._tbRadius;
2618
+ this._tbRadius = this.calculateTbRadius( this.camera );
2619
+
2620
+ if ( oldRadius < this._tbRadius - EPS || oldRadius > this._tbRadius + EPS ) {
2621
+
2622
+ const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
2623
+ const newRadius = this._tbRadius / scale;
2624
+ const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
2625
+ const points = curve.getPoints( this._curvePts );
2626
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
2627
+
2628
+ for ( const gizmo in this._gizmos.children ) {
2629
+
2630
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
2631
+
2632
+ }
2633
+
2634
+ }
2635
+
2636
+ }
2637
+
2638
+ this.camera.lookAt( this._gizmos.position );
2639
+
2640
+ }
2641
+
2642
+ setStateFromJSON( json ) {
2643
+
2644
+ const state = JSON.parse( json );
2645
+
2646
+ if ( state.arcballState != undefined ) {
2647
+
2648
+ this._cameraMatrixState.fromArray( state.arcballState.cameraMatrix.elements );
2649
+ this._cameraMatrixState.decompose( this.camera.position, this.camera.quaternion, this.camera.scale );
2650
+
2651
+ this.camera.up.copy( state.arcballState.cameraUp );
2652
+ this.camera.near = state.arcballState.cameraNear;
2653
+ this.camera.far = state.arcballState.cameraFar;
2654
+
2655
+ this.camera.zoom = state.arcballState.cameraZoom;
2656
+
2657
+ if ( this.camera.isPerspectiveCamera ) {
2658
+
2659
+ this.camera.fov = state.arcballState.cameraFov;
2660
+
2661
+ }
2662
+
2663
+ this._gizmoMatrixState.fromArray( state.arcballState.gizmoMatrix.elements );
2664
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2665
+
2666
+ this.camera.updateMatrix();
2667
+ this.camera.updateProjectionMatrix();
2668
+
2669
+ this._gizmos.updateMatrix();
2670
+
2671
+ this._tbRadius = this.calculateTbRadius( this.camera );
2672
+ const gizmoTmp = new Matrix4().copy( this._gizmoMatrixState0 );
2673
+ this.makeGizmos( this._gizmos.position, this._tbRadius );
2674
+ this._gizmoMatrixState0.copy( gizmoTmp );
2675
+
2676
+ this.camera.lookAt( this._gizmos.position );
2677
+ this.updateTbState( STATE.IDLE, false );
2678
+
2679
+ this.dispatchEvent( _changeEvent );
2680
+
2681
+ }
2682
+
2683
+ }
2684
+
2685
+ }
2686
+
2687
+ //listeners
2688
+
2689
+ function onWindowResize() {
2690
+
2691
+ const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
2692
+ this._tbRadius = this.calculateTbRadius( this.camera );
2693
+
2694
+ const newRadius = this._tbRadius / scale;
2695
+ const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
2696
+ const points = curve.getPoints( this._curvePts );
2697
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
2698
+
2699
+
2700
+ for ( const gizmo in this._gizmos.children ) {
2701
+
2702
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
2703
+
2704
+ }
2705
+
2706
+ this.dispatchEvent( _changeEvent );
2707
+
2708
+ }
2709
+
2710
+ function onContextMenu( event ) {
2711
+
2712
+ if ( ! this.enabled ) {
2713
+
2714
+ return;
2715
+
2716
+ }
2717
+
2718
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
2719
+
2720
+ if ( this.mouseActions[ i ].mouse == 2 ) {
2721
+
2722
+ //prevent only if button 2 is actually used
2723
+ event.preventDefault();
2724
+ break;
2725
+
2726
+ }
2727
+
2728
+ }
2729
+
2730
+ }
2731
+
2732
+ function onPointerCancel() {
2733
+
2734
+ this._touchStart.splice( 0, this._touchStart.length );
2735
+ this._touchCurrent.splice( 0, this._touchCurrent.length );
2736
+ this._input = INPUT.NONE;
2737
+
2738
+ }
2739
+
2740
+ function onPointerDown( event ) {
2741
+
2742
+ if ( event.button == 0 && event.isPrimary ) {
2743
+
2744
+ this._downValid = true;
2745
+ this._downEvents.push( event );
2746
+ this._downStart = performance.now();
2747
+
2748
+ } else {
2749
+
2750
+ this._downValid = false;
2751
+
2752
+ }
2753
+
2754
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
2755
+
2756
+ this._touchStart.push( event );
2757
+ this._touchCurrent.push( event );
2758
+
2759
+ switch ( this._input ) {
2760
+
2761
+ case INPUT.NONE:
2762
+
2763
+ //singleStart
2764
+ this._input = INPUT.ONE_FINGER;
2765
+ this.onSinglePanStart( event, 'ROTATE' );
2766
+
2767
+ window.addEventListener( 'pointermove', this._onPointerMove );
2768
+ window.addEventListener( 'pointerup', this._onPointerUp );
2769
+
2770
+ break;
2771
+
2772
+ case INPUT.ONE_FINGER:
2773
+ case INPUT.ONE_FINGER_SWITCHED:
2774
+
2775
+ //doubleStart
2776
+ this._input = INPUT.TWO_FINGER;
2777
+
2778
+ this.onRotateStart();
2779
+ this.onPinchStart();
2780
+ this.onDoublePanStart();
2781
+
2782
+ break;
2783
+
2784
+ case INPUT.TWO_FINGER:
2785
+
2786
+ //multipleStart
2787
+ this._input = INPUT.MULT_FINGER;
2788
+ this.onTriplePanStart( event );
2789
+ break;
2790
+
2791
+ }
2792
+
2793
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.NONE ) {
2794
+
2795
+ let modifier = null;
2796
+
2797
+ if ( event.ctrlKey || event.metaKey ) {
2798
+
2799
+ modifier = 'CTRL';
2800
+
2801
+ } else if ( event.shiftKey ) {
2802
+
2803
+ modifier = 'SHIFT';
2804
+
2805
+ }
2806
+
2807
+ this._mouseOp = this.getOpFromAction( event.button, modifier );
2808
+ if ( this._mouseOp != null ) {
2809
+
2810
+ window.addEventListener( 'pointermove', this._onPointerMove );
2811
+ window.addEventListener( 'pointerup', this._onPointerUp );
2812
+
2813
+ //singleStart
2814
+ this._input = INPUT.CURSOR;
2815
+ this._button = event.button;
2816
+ this.onSinglePanStart( event, this._mouseOp );
2817
+
2818
+ }
2819
+
2820
+ }
2821
+
2822
+ }
2823
+
2824
+ function onPointerMove( event ) {
2825
+
2826
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
2827
+
2828
+ switch ( this._input ) {
2829
+
2830
+ case INPUT.ONE_FINGER:
2831
+
2832
+ //singleMove
2833
+ this.updateTouchEvent( event );
2834
+
2835
+ this.onSinglePanMove( event, STATE.ROTATE );
2836
+ break;
2837
+
2838
+ case INPUT.ONE_FINGER_SWITCHED:
2839
+
2840
+ const movement = this.calculatePointersDistance( this._touchCurrent[ 0 ], event ) * this._devPxRatio;
2841
+
2842
+ if ( movement >= this._switchSensibility ) {
2843
+
2844
+ //singleMove
2845
+ this._input = INPUT.ONE_FINGER;
2846
+ this.updateTouchEvent( event );
2847
+
2848
+ this.onSinglePanStart( event, 'ROTATE' );
2849
+ break;
2850
+
2851
+ }
2852
+
2853
+ break;
2854
+
2855
+ case INPUT.TWO_FINGER:
2856
+
2857
+ //rotate/pan/pinchMove
2858
+ this.updateTouchEvent( event );
2859
+
2860
+ this.onRotateMove();
2861
+ this.onPinchMove();
2862
+ this.onDoublePanMove();
2863
+
2864
+ break;
2865
+
2866
+ case INPUT.MULT_FINGER:
2867
+
2868
+ //multMove
2869
+ this.updateTouchEvent( event );
2870
+
2871
+ this.onTriplePanMove( event );
2872
+ break;
2873
+
2874
+ }
2875
+
2876
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
2877
+
2878
+ let modifier = null;
2879
+
2880
+ if ( event.ctrlKey || event.metaKey ) {
2881
+
2882
+ modifier = 'CTRL';
2883
+
2884
+ } else if ( event.shiftKey ) {
2885
+
2886
+ modifier = 'SHIFT';
2887
+
2888
+ }
2889
+
2890
+ const mouseOpState = this.getOpStateFromAction( this._button, modifier );
2891
+
2892
+ if ( mouseOpState != null ) {
2893
+
2894
+ this.onSinglePanMove( event, mouseOpState );
2895
+
2896
+ }
2897
+
2898
+ }
2899
+
2900
+ //checkDistance
2901
+ if ( this._downValid ) {
2902
+
2903
+ const movement = this.calculatePointersDistance( this._downEvents[ this._downEvents.length - 1 ], event ) * this._devPxRatio;
2904
+ if ( movement > this._movementThreshold ) {
2905
+
2906
+ this._downValid = false;
2907
+
2908
+ }
2909
+
2910
+ }
2911
+
2912
+ }
2913
+
2914
+ function onPointerUp( event ) {
2915
+
2916
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
2917
+
2918
+ const nTouch = this._touchCurrent.length;
2919
+
2920
+ for ( let i = 0; i < nTouch; i ++ ) {
2921
+
2922
+ if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
2923
+
2924
+ this._touchCurrent.splice( i, 1 );
2925
+ this._touchStart.splice( i, 1 );
2926
+ break;
2927
+
2928
+ }
2929
+
2930
+ }
2931
+
2932
+ switch ( this._input ) {
2933
+
2934
+ case INPUT.ONE_FINGER:
2935
+ case INPUT.ONE_FINGER_SWITCHED:
2936
+
2937
+ //singleEnd
2938
+ window.removeEventListener( 'pointermove', this._onPointerMove );
2939
+ window.removeEventListener( 'pointerup', this._onPointerUp );
2940
+
2941
+ this._input = INPUT.NONE;
2942
+ this.onSinglePanEnd();
2943
+
2944
+ break;
2945
+
2946
+ case INPUT.TWO_FINGER:
2947
+
2948
+ //doubleEnd
2949
+ this.onDoublePanEnd( event );
2950
+ this.onPinchEnd( event );
2951
+ this.onRotateEnd( event );
2952
+
2953
+ //switching to singleStart
2954
+ this._input = INPUT.ONE_FINGER_SWITCHED;
2955
+
2956
+ break;
2957
+
2958
+ case INPUT.MULT_FINGER:
2959
+
2960
+ if ( this._touchCurrent.length == 0 ) {
2961
+
2962
+ window.removeEventListener( 'pointermove', this._onPointerMove );
2963
+ window.removeEventListener( 'pointerup', this._onPointerUp );
2964
+
2965
+ //multCancel
2966
+ this._input = INPUT.NONE;
2967
+ this.onTriplePanEnd();
2968
+
2969
+ }
2970
+
2971
+ break;
2972
+
2973
+ }
2974
+
2975
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
2976
+
2977
+ window.removeEventListener( 'pointermove', this._onPointerMove );
2978
+ window.removeEventListener( 'pointerup', this._onPointerUp );
2979
+
2980
+ this._input = INPUT.NONE;
2981
+ this.onSinglePanEnd();
2982
+ this._button = - 1;
2983
+
2984
+ }
2985
+
2986
+ if ( event.isPrimary ) {
2987
+
2988
+ if ( this._downValid ) {
2989
+
2990
+ const downTime = event.timeStamp - this._downEvents[ this._downEvents.length - 1 ].timeStamp;
2991
+
2992
+ if ( downTime <= this._maxDownTime ) {
2993
+
2994
+ if ( this._nclicks == 0 ) {
2995
+
2996
+ //first valid click detected
2997
+ this._nclicks = 1;
2998
+ this._clickStart = performance.now();
2999
+
3000
+ } else {
3001
+
3002
+ const clickInterval = event.timeStamp - this._clickStart;
3003
+ const movement = this.calculatePointersDistance( this._downEvents[ 1 ], this._downEvents[ 0 ] ) * this._devPxRatio;
3004
+
3005
+ if ( clickInterval <= this._maxInterval && movement <= this._posThreshold ) {
3006
+
3007
+ //second valid click detected
3008
+ //fire double tap and reset values
3009
+ this._nclicks = 0;
3010
+ this._downEvents.splice( 0, this._downEvents.length );
3011
+ this.onDoubleTap( event );
3012
+
3013
+ } else {
3014
+
3015
+ //new 'first click'
3016
+ this._nclicks = 1;
3017
+ this._downEvents.shift();
3018
+ this._clickStart = performance.now();
3019
+
3020
+ }
3021
+
3022
+ }
3023
+
3024
+ } else {
3025
+
3026
+ this._downValid = false;
3027
+ this._nclicks = 0;
3028
+ this._downEvents.splice( 0, this._downEvents.length );
3029
+
3030
+ }
3031
+
3032
+ } else {
3033
+
3034
+ this._nclicks = 0;
3035
+ this._downEvents.splice( 0, this._downEvents.length );
3036
+
3037
+ }
3038
+
3039
+ }
3040
+
3041
+ }
3042
+
3043
+ function onWheel( event ) {
3044
+
3045
+ if ( this.enabled && this.enableZoom ) {
3046
+
3047
+ let modifier = null;
3048
+
3049
+ if ( event.ctrlKey || event.metaKey ) {
3050
+
3051
+ modifier = 'CTRL';
3052
+
3053
+ } else if ( event.shiftKey ) {
3054
+
3055
+ modifier = 'SHIFT';
3056
+
3057
+ }
3058
+
3059
+ const mouseOp = this.getOpFromAction( 'WHEEL', modifier );
3060
+
3061
+ if ( mouseOp != null ) {
3062
+
3063
+ event.preventDefault();
3064
+ this.dispatchEvent( _startEvent );
3065
+
3066
+ const notchDeltaY = 125; //distance of one notch of mouse wheel
3067
+ let sgn = event.deltaY / notchDeltaY;
3068
+
3069
+ let size = 1;
3070
+
3071
+ if ( sgn > 0 ) {
3072
+
3073
+ size = 1 / this.scaleFactor;
3074
+
3075
+ } else if ( sgn < 0 ) {
3076
+
3077
+ size = this.scaleFactor;
3078
+
3079
+ }
3080
+
3081
+ switch ( mouseOp ) {
3082
+
3083
+ case 'ZOOM':
3084
+
3085
+ this.updateTbState( STATE.SCALE, true );
3086
+
3087
+ if ( sgn > 0 ) {
3088
+
3089
+ size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
3090
+
3091
+ } else if ( sgn < 0 ) {
3092
+
3093
+ size = Math.pow( this.scaleFactor, - sgn );
3094
+
3095
+ }
3096
+
3097
+ if ( this.cursorZoom && this.enablePan ) {
3098
+
3099
+ let scalePoint;
3100
+
3101
+ if ( this.camera.isOrthographicCamera ) {
3102
+
3103
+ scalePoint = this.unprojectOnTbPlane( this.camera, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.camera.quaternion ).multiplyScalar( 1 / this.camera.zoom ).add( this._gizmos.position );
3104
+
3105
+ } else if ( this.camera.isPerspectiveCamera ) {
3106
+
3107
+ scalePoint = this.unprojectOnTbPlane( this.camera, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.camera.quaternion ).add( this._gizmos.position );
3108
+
3109
+ }
3110
+
3111
+ this.applyTransformMatrix( this.scale( size, scalePoint ) );
3112
+
3113
+ } else {
3114
+
3115
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
3116
+
3117
+ }
3118
+
3119
+ if ( this._grid != null ) {
3120
+
3121
+ this.disposeGrid();
3122
+ this.drawGrid();
3123
+
3124
+ }
3125
+
3126
+ this.updateTbState( STATE.IDLE, false );
3127
+
3128
+ this.dispatchEvent( _changeEvent );
3129
+ this.dispatchEvent( _endEvent );
3130
+
3131
+ break;
3132
+
3133
+ case 'FOV':
3134
+
3135
+ if ( this.camera.isPerspectiveCamera ) {
3136
+
3137
+ this.updateTbState( STATE.FOV, true );
3138
+
3139
+
3140
+ //Vertigo effect
3141
+
3142
+ // fov / 2
3143
+ // |\
3144
+ // | \
3145
+ // | \
3146
+ // x | \
3147
+ // | \
3148
+ // | \
3149
+ // | _ _ _\
3150
+ // y
3151
+
3152
+ //check for iOs shift shortcut
3153
+ if ( event.deltaX != 0 ) {
3154
+
3155
+ sgn = event.deltaX / notchDeltaY;
3156
+
3157
+ size = 1;
3158
+
3159
+ if ( sgn > 0 ) {
3160
+
3161
+ size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
3162
+
3163
+ } else if ( sgn < 0 ) {
3164
+
3165
+ size = Math.pow( this.scaleFactor, - sgn );
3166
+
3167
+ }
3168
+
3169
+ }
3170
+
3171
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
3172
+ const x = this._v3_1.distanceTo( this._gizmos.position );
3173
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
3174
+
3175
+ //check min and max distance
3176
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
3177
+
3178
+ const y = x * Math.tan( MathUtils.DEG2RAD * this.camera.fov * 0.5 );
3179
+
3180
+ //calculate new fov
3181
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
3182
+
3183
+ //check min and max fov
3184
+ if ( newFov > this.maxFov ) {
3185
+
3186
+ newFov = this.maxFov;
3187
+
3188
+ } else if ( newFov < this.minFov ) {
3189
+
3190
+ newFov = this.minFov;
3191
+
3192
+ }
3193
+
3194
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
3195
+ size = x / newDistance;
3196
+
3197
+ this.setFov( newFov );
3198
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position, false ) );
3199
+
3200
+ }
3201
+
3202
+ if ( this._grid != null ) {
3203
+
3204
+ this.disposeGrid();
3205
+ this.drawGrid();
3206
+
3207
+ }
3208
+
3209
+ this.updateTbState( STATE.IDLE, false );
3210
+
3211
+ this.dispatchEvent( _changeEvent );
3212
+ this.dispatchEvent( _endEvent );
3213
+
3214
+ break;
3215
+
3216
+ }
3217
+
3218
+ }
3219
+
3220
+ }
3221
+
3222
+ }
3223
+
3224
+ export { ArcballControls };