math.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. import * as THREE from '../lib/three.module.js'
  2. var math = {
  3. getBaseLog(x, y) {
  4. //返回以 x 为底 y 的对数(即 logx y) . Math.log 返回一个数的自然对数
  5. return Math.log(y) / Math.log(x)
  6. },
  7. convertVector: {
  8. ZupToYup: function(e) {
  9. //navvis -> 4dkk
  10. return new THREE.Vector3(e.x, e.z, -e.y)
  11. },
  12. YupToZup: function(e) {
  13. //4dkk -> navvis
  14. return new THREE.Vector3(e.x, -e.z, e.y)
  15. }
  16. },
  17. convertQuaternion: {
  18. ZupToYup: function(e) {
  19. //navvis -> 4dkk //不同于convertVisionQuaternion
  20. let rotation = new THREE.Euler(-Math.PI / 2, 0, 0)
  21. let quaternion = new THREE.Quaternion().setFromEuler(rotation)
  22. return e.clone().premultiply(quaternion)
  23. //return new THREE.Quaternion(e.x,e.z,-e.y,e.w).multiply((new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(1,0,0), THREE.Math.degToRad(90)))
  24. },
  25. YupToZup: function(e) {
  26. //4dkk -> navvis
  27. let rotation = new THREE.Euler(Math.PI / 2, 0, 0)
  28. let quaternion = new THREE.Quaternion().setFromEuler(rotation)
  29. return e.clone().premultiply(quaternion)
  30. }
  31. },
  32. convertVisionQuaternion: function(e) {
  33. return new THREE.Quaternion(e.x, e.z, -e.y, e.w).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), THREE.Math.degToRad(90)))
  34. },
  35. invertVisionQuaternion: function(e) {
  36. //反转给算法部
  37. var a = e.clone().multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), THREE.Math.degToRad(-90)))
  38. return new THREE.Quaternion(a.x, -a.z, a.y, a.w)
  39. },
  40. //------------
  41. getVec2Angle: function(dir1, dir2) {
  42. return Math.acos(THREE.Math.clamp(this.getVec2Cos(dir1, dir2), -1, 1))
  43. },
  44. getVec2Cos: function(dir1, dir2) {
  45. return dir1.dot(dir2) / dir1.length() / dir2.length()
  46. },
  47. getAngle: function(vec1, vec2, axis) {
  48. //带方向的角度 vector3
  49. var angle = vec1.angleTo(vec2)
  50. var axis_ = vec1.clone().cross(vec2)
  51. if (axis_[axis] < 0) {
  52. angle *= -1
  53. }
  54. return angle
  55. },
  56. closeTo: function(a, b, precision = 1e-6) {
  57. let f = (a, b) => {
  58. return Math.abs(a - b) < precision
  59. }
  60. if (typeof a == 'number') {
  61. return f(a, b)
  62. } else {
  63. let judge = name => {
  64. if (a[name] == void 0) return true
  65. //有值就判断,没值就不判断
  66. else return f(a[name], b[name])
  67. }
  68. return judge('x') && judge('y') && judge('z') && judge('w')
  69. }
  70. },
  71. toPrecision: function(e, t) {
  72. //xzw change 保留小数
  73. var f = function(e, t) {
  74. var i = Math.pow(10, t)
  75. return Math.round(e * i) / i
  76. }
  77. if (e instanceof Array) {
  78. for (var s = 0; s < e.length; s++) {
  79. e[s] = f(e[s], t)
  80. }
  81. return e
  82. } else if (e instanceof Object) {
  83. for (var s in e) {
  84. e[s] = f(e[s], t)
  85. }
  86. return e
  87. } else return f(e, t)
  88. },
  89. isEmptyQuaternion: function(e) {
  90. return 0 === Math.abs(e.x) && 0 === Math.abs(e.y) && 0 === Math.abs(e.z) && 0 === Math.abs(e.w)
  91. },
  92. projectPositionToCanvas: function(e, t, i) {
  93. ;(i = i || new THREE.Vector3()), i.copy(e)
  94. var r = 0.5 * $('#player').width(),
  95. o = 0.5 * $('#player').height()
  96. return i.project(t), (i.x = i.x * r + r), (i.y = -(i.y * o) + o), i
  97. },
  98. handelPadResize: false,
  99. /* handelPadding : function () { //去除player左边和上面的宽高,因为pc的player左上有其他element 许钟文
  100. var pads = [];//记录下来避免反复计算
  101. var index = [];
  102. var resetPad = function(){
  103. pads = [];
  104. index = [];
  105. math.handelPadResize = false; //switchview时resized为true
  106. }
  107. if(config.isEdit && !config.isMobile){
  108. window.addEventListener('resize',resetPad);
  109. }
  110. return function(x, y, domE){
  111. if(!config.isEdit || config.isMobile) {
  112. return {
  113. x: x,
  114. y: y
  115. }
  116. }
  117. if(this.handelPadResize)resetPad();
  118. domE = domE || $('#player')[0];
  119. var pad;
  120. var i = index.indexOf(domE);
  121. if (i == -1){
  122. index.push(domE);
  123. pad = {
  124. x: this.getOffset("left", domE),
  125. y: this.getOffset("top", domE)
  126. }
  127. pads.push(pad)
  128. }
  129. else pad = pads[i];
  130. return {
  131. x: x - pad.x,
  132. y: y - pad.y
  133. }
  134. }
  135. }(), */
  136. getOffset: function(type, element, parent) {
  137. //获取元素的边距 许钟文
  138. var offset = type == 'left' ? element.offsetLeft : element.offsetTop
  139. if (!parent) parent = $('body')[0]
  140. while ((element = element.offsetParent)) {
  141. if (element == parent) break
  142. offset += type == 'left' ? element.offsetLeft : element.offsetTop
  143. }
  144. return offset
  145. },
  146. constrainedTurn: function(e) {
  147. var t = e % (2 * Math.PI)
  148. return (t = t > Math.PI ? (t -= 2 * Math.PI) : t < -Math.PI ? (t += 2 * Math.PI) : t)
  149. },
  150. getFOVDotThreshold: function(e) {
  151. return Math.cos(THREE.Math.degToRad(e / 2))
  152. },
  153. transform2DForwardVectorByCubeFace: function(e, t, i, n) {
  154. switch (e) {
  155. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  156. i.set(1, t.y, t.x)
  157. break
  158. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  159. i.set(-1, t.y, -t.x)
  160. break
  161. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
  162. i.set(-t.x, 1, -t.y)
  163. break
  164. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  165. i.set(-t.x, -1, t.y)
  166. break
  167. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  168. i.set(-t.x, t.y, 1)
  169. break
  170. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  171. i.set(t.x, t.y, -1)
  172. }
  173. n && i.normalize()
  174. },
  175. getFootPoint: function(oldPos, p1, p2, restricInline) {
  176. //找oldPos在线段p1, p2上的垂足
  177. /* if(isWorld){//输出全局坐标 需要考虑meshGroup.position
  178. p1 = p1.clone();
  179. p2 = p2.clone();
  180. p1.y += mainDesign.meshGroup.position.y;
  181. p2.y += mainDesign.meshGroup.position.y;
  182. } */
  183. if (p1.equals(p2)) return p1.clone()
  184. var op1 = oldPos.clone().sub(p1)
  185. var p1p2 = p1.clone().sub(p2)
  186. var p1p2Len = p1p2.length()
  187. var leftLen = op1.dot(p1p2) / p1p2Len
  188. var pos = p1.clone().add(p1p2.multiplyScalar(leftLen / p1p2Len))
  189. if (
  190. restricInline &&
  191. pos
  192. .clone()
  193. .sub(p1)
  194. .dot(pos.clone().sub(p2)) > 0
  195. ) {
  196. //foot不在线段上
  197. if (pos.distanceTo(p1) < pos.distanceTo(p2)) pos = p1.clone()
  198. else pos = p2.clone()
  199. }
  200. return pos
  201. },
  202. /**
  203. * 计算多边形的重心
  204. * @param {*} points
  205. */
  206. getCenterOfGravityPoint: function(mPoints) {
  207. var area = 0.0 //多边形面积
  208. var Gx = 0.0,
  209. Gy = 0.0 // 重心的x、y
  210. for (var i = 1; i <= mPoints.length; i++) {
  211. var ix = mPoints[i % mPoints.length].x
  212. var iy = mPoints[i % mPoints.length].y
  213. var nx = mPoints[i - 1].x
  214. var ny = mPoints[i - 1].y
  215. var temp = (ix * ny - iy * nx) / 2.0
  216. area += temp
  217. Gx += (temp * (ix + nx)) / 3.0
  218. Gy += (temp * (iy + ny)) / 3.0
  219. }
  220. Gx = Gx / area
  221. Gy = Gy / area
  222. return { x: Gx, y: Gy }
  223. },
  224. getBound: function(ring) {
  225. var bound = new THREE.Box2()
  226. for (var j = 0, len = ring.length; j < len; j++) {
  227. bound.expandByPoint(ring[j])
  228. }
  229. return bound
  230. },
  231. isPointInArea: function(ring, holes, point, ifAtLine) {
  232. //判断点是否在某个环内, 若传递了holes代表还要不能在内环内
  233. var bound = this.getBound(ring)
  234. if (point.x < bound.min.x || point.x > bound.max.x || point.y < bound.min.y || point.y > bound.max.y) return false
  235. var inside = false
  236. var x = point.x,
  237. y = point.y
  238. for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
  239. var xi = ring[i].x,
  240. yi = ring[i].y
  241. var xj = ring[j].x,
  242. yj = ring[j].y
  243. if (
  244. (xi - x) * (yj - y) == (xi - x) * (yi - y) &&
  245. x >= Math.min(xi, xj) &&
  246. x <= Math.max(xi, xj) && //xzw add
  247. y >= Math.min(yi, yj) &&
  248. y <= Math.max(yi, yj)
  249. ) {
  250. //return !!ifAtLine;//在线段上,则判断为…… (默认在外)
  251. return { atLine: true }
  252. }
  253. if (yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
  254. inside = !inside
  255. }
  256. }
  257. if (inside && holes) {
  258. return !holes.some(ring => this.isPointInArea(ring, null, point, ifAtLine)) //不能存在于任何一个二级内环内
  259. } else {
  260. return inside
  261. }
  262. },
  263. getArea: function(ring) {
  264. //求面积 顺时针为正 来自three shape
  265. for (var t = ring.length, i = 0, n = t - 1, r = 0; r < t; n = r++) i += ring[n].x * ring[r].y - ring[r].x * ring[n].y
  266. return -0.5 * i
  267. },
  268. isInBetween: function(a, b, c, precision) {
  269. // 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
  270. /* if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
  271. return false;
  272. }
  273. return (a <= b && b <= c) || (c <= b && b <= a);*/
  274. //更改:如果b和a或c中一个接近 就算在a和c之间
  275. return (a <= b && b <= c) || (c <= b && b <= a) || this.closeTo(a, b, precision) || this.closeTo(b, c, precision)
  276. },
  277. ifPointAtLineBound: function(point, linePoints, precision) {
  278. //待验证 横线和竖线比较特殊
  279. return math.isInBetween(linePoints[0].x, point.x, linePoints[1].x, precision) && math.isInBetween(linePoints[0].y, point.y, linePoints[1].y, precision)
  280. },
  281. isLineIntersect: function(line1, line2, notSegment, precision) {
  282. //线段和线段是否有交点. notSegment代表是直线而不是线段
  283. var a1 = line1[1].y - line1[0].y
  284. var b1 = line1[0].x - line1[1].x
  285. var c1 = a1 * line1[0].x + b1 * line1[0].y
  286. //转换成一般式: Ax+By = C
  287. var a2 = line2[1].y - line2[0].y
  288. var b2 = line2[0].x - line2[1].x
  289. var c2 = a2 * line2[0].x + b2 * line2[0].y
  290. // 计算交点
  291. var d = a1 * b2 - a2 * b1
  292. // 当d==0时,两线平行
  293. if (d == 0) {
  294. return false
  295. } else {
  296. var x = (b2 * c1 - b1 * c2) / d
  297. var y = (a1 * c2 - a2 * c1) / d
  298. // 检测交点是否在两条线段上
  299. /* if (notSegment || (isInBetween(line1[0].x, x, line1[1].x) || isInBetween(line1[0].y, y, line1[1].y)) &&
  300. (isInBetween(line2[0].x, x, line2[1].x) || isInBetween(line2[0].y, y, line2[1].y))) {
  301. return {x,y};
  302. } */
  303. if (notSegment || (math.ifPointAtLineBound({ x, y }, line1, precision) && math.ifPointAtLineBound({ x, y }, line2, precision))) {
  304. return { x, y }
  305. }
  306. }
  307. },
  308. getNormal2d: function(o = {}) {
  309. //获取二维法向量 方向向内
  310. var x, y, x1, y1
  311. //line2d的向量
  312. if (o.vec) {
  313. x1 = o.vec.x
  314. y1 = o.vec.y
  315. } else {
  316. x1 = o.p1.x - o.p2.x
  317. y1 = o.p1.y - o.p2.y
  318. }
  319. //假设法向量的x或y固定为1或-1
  320. if (y1 != 0) {
  321. x = 1
  322. y = -(x1 * x) / y1
  323. } else if (x1 != 0) {
  324. //y如果为0,正常情况x不会是0
  325. y = 1
  326. x = -(y1 * y) / x1
  327. } else {
  328. console.log('两个点一样')
  329. return null
  330. }
  331. //判断方向里或者外:
  332. var vNormal = new THREE.Vector3(x, 0, y)
  333. var vLine = new THREE.Vector3(x1, 0, y1)
  334. var vDir = vNormal.cross(vLine)
  335. if (vDir.y > 0) {
  336. x *= -1
  337. y *= -1
  338. }
  339. return new THREE.Vector2(x, y).normalize()
  340. },
  341. getQuaBetween2Vector: function(oriVec, newVec, upVec) {
  342. //获取从oriVec旋转到newVec可以应用的quaternion
  343. var angle = oriVec.angleTo(newVec)
  344. var axis = oriVec
  345. .clone()
  346. .cross(newVec)
  347. .normalize() //两个up之间
  348. if (axis.length() == 0) {
  349. //当夹角为180 或 0 度时,得到的axis为(0,0,0),故使用备用的指定upVec
  350. return new THREE.Quaternion().setFromAxisAngle(upVec, angle)
  351. }
  352. return new THREE.Quaternion().setFromAxisAngle(axis, angle)
  353. },
  354. /* ,
  355. getQuaBetween2Vector2 : function(oriVec, newVec ){//not camera
  356. var _ = (new THREE.Matrix4).lookAt( oriVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
  357. var aimQua = (new THREE.Quaternion).setFromRotationMatrix(_)
  358. var _2 = (new THREE.Matrix4).lookAt( newVec, new THREE.Vector3, new THREE.Vector3(0,1,0))
  359. var aimQua2 = (new THREE.Quaternion).setFromRotationMatrix(_2)
  360. return aimQua2.multiply(aimQua.clone().inverse())
  361. } */
  362. getScaleForConstantSize: (function() {
  363. //获得规定二维大小的mesh的scale值。可以避免因camera的projection造成的mesh视觉大小改变。 来源:tag.updateDisc
  364. var w
  365. var i = new THREE.Vector3(),
  366. o = new THREE.Vector3(),
  367. l = new THREE.Vector3(),
  368. c = new THREE.Vector3(),
  369. h = new THREE.Vector3()
  370. return function(op = {}) {
  371. if (op.width2d) w = op.width2d
  372. //如果恒定二维宽度
  373. else {
  374. //否则考虑上距离,加一丢丢近大远小的效果
  375. var currentDis, nearBound, farBound
  376. if (op.camera.type == 'OrthographicCamera') {
  377. currentDis = 200 / op.camera.zoom //(op.camera.right - op.camera.left) / op.camera.zoom
  378. } else {
  379. currentDis = op.position.distanceTo(op.camera.position)
  380. }
  381. w = op.maxSize - (op.maxSize - op.minSize) * THREE.Math.smoothstep(currentDis, op.nearBound, op.farBound)
  382. //maxSize : mesh要表现的最大像素宽度; nearBound: 最近距离,若比nearBound近,则使用maxSize
  383. }
  384. i.copy(op.position).project(op.camera), //tag中心在屏幕上的二维坐标
  385. o.set(op.resolution.x / 2, op.resolution.y / 2, 1).multiply(i), //转化成px -w/2 到 w/2的范围
  386. l.set(w / 2, 0, 0).add(o), //加上tag宽度的一半
  387. c.set(2 / op.resolution.x, 2 / op.resolution.y, 1).multiply(l), //再转回 -1 到 1的范围
  388. h.copy(c).unproject(op.camera) //再转成三维坐标,求得tag边缘的位置
  389. var g = h.distanceTo(op.position) //就能得到tag的三维半径
  390. //这里使用的都是resolution2, 好处是手机端不会太小, 坏处是pc更改网页显示百分比时显示的大小会变(或许可以自己算出设备真实的deviceRatio, 因window.screen是不会改变的),但考虑到用户可以自行调节字大小也许是好的
  391. return g //可能NAN 当相机和position重叠时
  392. }
  393. })(),
  394. //W , H, left, top分别是rect的宽、高、左、上
  395. getCrossPointAtRect: function(p1, aim, W, H, left, top) {
  396. //求射线p1-aim在rect边界上的交点,其中aim在rect范围内,p1则不一定(交点在aim这边的延长线上)
  397. var x, y, borderX
  398. var r = (aim.x - p1.x) / (aim.y - p1.y) //根据相似三角形原理先求出这个比值
  399. var getX = function(y) {
  400. return r * (y - p1.y) + p1.x
  401. }
  402. var getY = function(x) {
  403. return (1 / r) * (x - p1.x) + p1.y
  404. }
  405. if (aim.x >= p1.x) {
  406. borderX = W + left
  407. } else {
  408. borderX = left
  409. }
  410. x = borderX
  411. y = getY(x)
  412. if (y < top || y > top + H) {
  413. if (y < top) {
  414. y = top
  415. } else {
  416. y = top + H
  417. }
  418. x = getX(y)
  419. }
  420. return new THREE.Vector2(x, y)
  421. },
  422. getDirFromUV: function(uv) {
  423. //获取dir 反向计算 - - 二维转三维比较麻烦
  424. var dirB //所求 单位向量
  425. var y = Math.cos(uv.y * Math.PI) //uv中纵向可以直接确定y, 根据上面getUVfromDir的反向计算
  426. // 故 uv.y * Math.PI 就是到垂直线(向上)的夹角
  427. var angle = 2 * Math.PI * uv.x - Math.PI //x/z代表的是角度
  428. var axisX, axisZ //axis为1代表是正,-1是负数
  429. if (-Math.PI <= angle && angle < 0) {
  430. axisX = -1 //下半圆
  431. } else {
  432. axisX = 1 //上半圆
  433. }
  434. if (-Math.PI / 2 <= angle && angle < Math.PI / 2) {
  435. axisZ = 1 //右半圆
  436. } else {
  437. axisZ = -1 //左半圆
  438. }
  439. var XDivideZ = Math.tan(angle)
  440. var z = Math.sqrt((1 - y * y) / (1 + XDivideZ * XDivideZ))
  441. var x = XDivideZ * z
  442. if (z * axisZ < 0) {
  443. //异号
  444. z *= -1
  445. x *= -1
  446. if (x * axisX < 0) {
  447. // console.log("wrong!!!!!??????????")
  448. }
  449. }
  450. x *= -1 //计算完成后这里不能漏掉 *= -1
  451. dirB = this.convertVector.YupToZup(new THREE.Vector3(x, y, z))
  452. //理想状态下x和z和anotherDir相同
  453. return dirB
  454. },
  455. getUVfromDir: function(dir) {
  456. //获取UV 同shader里的计算
  457. var dir = this.convertVector.ZupToYup(dir)
  458. dir.x *= -1 //计算前这里不能漏掉 *= -1 见shader
  459. var tx = Math.atan2(dir.x, dir.z) / (Math.PI * 2.0) + 0.5 //atan2(y,x) 返回从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。区间是-PI 到 PI 之间的值
  460. var ty = Math.acos(dir.y) / Math.PI
  461. return new THREE.Vector2(tx, ty)
  462. //理想状态下tx相同
  463. },
  464. getDirByLonLat: function(lon, lat) {
  465. var dir = new THREE.Vector3()
  466. var phi = THREE.Math.degToRad(90 - lat)
  467. var theta = THREE.Math.degToRad(lon)
  468. dir.x = Math.sin(phi) * Math.cos(theta)
  469. dir.y = Math.cos(phi)
  470. dir.z = Math.sin(phi) * Math.sin(theta)
  471. return dir
  472. }, //0,0 => (1,0,0) 270=>(0,0,-1)
  473. projectPointAtPlane: function(o = {}) {
  474. //获取一个点在一个面上的投影 {facePoints:[a,b,c], point:}
  475. var plane = new THREE.Plane().setFromCoplanarPoints(...o.facePoints)
  476. return plane.projectPoint(o.point, new THREE.Vector3())
  477. },
  478. getPolygonsMixedRings: function(polygons, onlyGetOutRing) {
  479. //{points:[vector2,...],holes:[[],[]]}
  480. let points = []
  481. let lines = []
  482. let i = 0
  483. polygons.forEach(e => points.push(...e.map(a => new THREE.Vector2().copy(a))))
  484. polygons.forEach((ps, j) => {
  485. let length = ps.length
  486. let index = 0
  487. while (index < length) {
  488. lines.push({ p1: index + i, p2: ((index + 1) % length) + i })
  489. index++
  490. }
  491. i += length
  492. })
  493. points.forEach((p, j) => {
  494. p.id = j
  495. })
  496. let rings = searchRings({
  497. points,
  498. lines,
  499. onlyGetOutRing
  500. })
  501. //console.log(rings)
  502. rings = rings.filter(e => e.closetParent == void 0) // 子环不加,被外环包含了
  503. return rings
  504. },
  505. getQuaFromPosAim(position, target) {
  506. let matrix = new THREE.Matrix4().lookAt(position, target, new THREE.Vector3(0, 0, 1))
  507. return new THREE.Quaternion().setFromRotationMatrix(matrix)
  508. },
  509. getBoundByPoints(points, minSize) {
  510. var bound = new THREE.Box3()
  511. points.forEach(point => {
  512. bound.expandByPoint(point)
  513. })
  514. let center = bound.getCenter(new THREE.Vector3())
  515. if (minSize) {
  516. let minBound = new THREE.Box3().setFromCenterAndSize(center, minSize)
  517. bound.union(minBound)
  518. }
  519. return {
  520. bounding: bound,
  521. size: bound.getSize(new THREE.Vector3()),
  522. center
  523. }
  524. },
  525. convertScreenPositionToNDC(pointer, mouse, width, height) {
  526. return (pointer = pointer || new THREE.Vector2()), (pointer.x = (mouse.x / width) * 2 - 1), (pointer.y = 2 * -(mouse.y / height) + 1), pointer
  527. },
  528. convertNDCToScreenPosition(pointer, mouse, width, height) {
  529. return (mouse = mouse || new THREE.Vector2()), (mouse.x = Math.round(((pointer.x + 1) / 2) * width)), (mouse.y = Math.round((-(pointer.y - 1) / 2) * height)), mouse
  530. },
  531. averageVectors(e, t) {
  532. var i = new THREE.Vector3()
  533. if (0 === e.length) return i
  534. for (var r = 0, o = 0; o < e.length; o++) {
  535. var a = t ? e[o][t] : e[o]
  536. i.add(a), r++
  537. }
  538. return i.divideScalar(r)
  539. }
  540. }
  541. export default math