utils.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. // 归一化
  2. function normalize(xyz) {
  3. var _mo_ = Math.sqrt(xyz[0] * xyz[0] + xyz[1] * xyz[1] + xyz[2] * xyz[2]);
  4. var x = xyz[0] / _mo_;
  5. var y = xyz[1] / _mo_;
  6. var z = xyz[2] / _mo_;
  7. return [x, y, z];
  8. }
  9. // 向量归一化
  10. function normalizeV(xy) {
  11. var _mo_ = Math.sqrt(xy[0] * xy[0] + xy[1] * xy[1]);
  12. var x = xy[0] / _mo_;
  13. var y = xy[1] / _mo_;
  14. // var z = xyz[2] / _mo_;
  15. return [x, y];
  16. }
  17. /**
  18. * 画线
  19. * @param {*} arr
  20. * @param {*} context
  21. * @param {*} color
  22. * @param {*} w
  23. * @param {*} h
  24. * @param {*} isClear
  25. */
  26. function circularLine(arr, context, color,cam_pos, w, h, isClear) {
  27. if (isClear) {
  28. context.clearRect(0, 0, w, h);
  29. // context.translate(w/2, h/2);
  30. }
  31. if (cam_pos.length>0) {
  32. for (let i = 0; i < cam_pos.length; i++) {
  33. const element = cam_pos[i];
  34. draw_point(context,element,w,h)
  35. }
  36. }
  37. context.strokeStyle = color;
  38. context.lineWidth = 4;
  39. context.beginPath();
  40. context.moveTo(arr[0][0] * w/2, arr[0][1] * h/2);
  41. for (let i = 0; i < arr.length; i++) {
  42. context.lineTo(arr[i][0] * w/2, arr[i][1] * h/2);
  43. }
  44. context.closePath();
  45. context.stroke();
  46. }
  47. /**
  48. * 选择线
  49. * @param {*} current
  50. * @param {*} cubeLine
  51. * @param {*} w
  52. * @param {*} h
  53. */
  54. function selectLine(current, cubeLine, w, h) {
  55. for (let i = 0; i < cubeLine.length; i++) {
  56. for (let j = 0; j < cubeLine[i].line.length; j++) {
  57. if (isInLine(current, cubeLine[i].line[j], w, h)) {
  58. // return current,arr[i]
  59. return [cubeLine[i].line[j],cubeLine[i]['room']];
  60. }
  61. }
  62. }
  63. return [];
  64. }
  65. function _getWhichPoint(line, current, verticalLine, cubeLine, cube,w,h) {
  66. current = [current[0]/w*2,current[1]/h*2]
  67. var direction=0;
  68. if (verticalLine[0]) {
  69. direction = 0
  70. }
  71. if (verticalLine[1]) {
  72. direction = 1
  73. }
  74. for (let i = 0; i < cube.length; i++) {
  75. for (let j = 0; j < cube[i].points.length; j++) {
  76. if (
  77. cube[i].points[j]["id"] === line["_3d_point1"]["point_id"] ||
  78. cube[i].points[j]["id"] === line["_3d_point2"]["point_id"]
  79. ) {
  80. // cube[i].points[j]['data'][0] = current[0]
  81. cube[i].points[j]["data"][direction] = current[direction];
  82. }
  83. }
  84. }
  85. // for (let i = 0; i < cubeLine.length; i++) {
  86. // for (let j = 0; j < cubeLine[i].line.length; j++) {
  87. // if (
  88. // cubeLine[i].line[j]["_3d_point1"]["point_id"] ===
  89. // line["_3d_point1"]["point_id"] ||
  90. // cubeLine[i].line[j]["_3d_point1"]["point_id"] ===
  91. // line["_3d_point2"]["point_id"]
  92. // ) {
  93. // cubeLine[i].line[j]["_3d_point1"]["data"][direction] = current[direction];
  94. // }
  95. // if (
  96. // cubeLine[i].line[j]["_3d_point2"]["point_id"] ===
  97. // line["_3d_point1"]["point_id"] ||
  98. // cubeLine[i].line[j]["_3d_point2"]["point_id"] ===
  99. // line["_3d_point2"]["point_id"]
  100. // ) {
  101. // cubeLine[i].line[j]["_3d_point2"]["data"][direction] = current[direction];
  102. // }
  103. // }
  104. // }
  105. return [cubeLine, cube];
  106. }
  107. /**
  108. * 判断是否在线上
  109. * @param {*} current
  110. * @param {*} arr
  111. * @param {*} w
  112. * @param {*} h
  113. */
  114. function isInLine(current, arr, w, h) {
  115. var accuay = 2;
  116. var minX = arr["_3d_point1"]["data"][0],
  117. minY = arr["_3d_point1"]["data"][1],
  118. maxX = arr["_3d_point1"]["data"][0],
  119. maxY = arr["_3d_point1"]["data"][1];
  120. minX = Math.min(minX, arr["_3d_point1"]["data"][0]);
  121. maxX = Math.max(maxX, arr["_3d_point1"]["data"][0]);
  122. minY = Math.min(minY, arr["_3d_point1"]["data"][1]);
  123. maxY = Math.max(maxY, arr["_3d_point1"]["data"][1]);
  124. minX = Math.min(minX, arr["_3d_point2"]["data"][0]);
  125. maxX = Math.max(maxX, arr["_3d_point2"]["data"][0]);
  126. minY = Math.min(minY, arr["_3d_point2"]["data"][1]);
  127. maxY = Math.max(maxY, arr["_3d_point2"]["data"][1]);
  128. return (
  129. current[0] >= minX * w/2 - accuay &&
  130. current[0] <= maxX * w/2 + accuay &&
  131. current[1] >= minY * h/2 - accuay &&
  132. current[1] <= maxY * h/2 + accuay
  133. );
  134. }
  135. /**
  136. * 计算向量的垂直向量
  137. * @param {向量} arr
  138. */
  139. function verticalLine(arr) {
  140. if (arr.length !== 0) {
  141. var x, y;
  142. y = Math.sqrt(1 / ((arr[1] * arr[1]) / (arr[0] * arr[0]) + 1));
  143. x = Math.sqrt(1 - y * y);
  144. return [x, y];
  145. }
  146. return [];
  147. }
  148. function getPointFromLine(line) {
  149. var ret = []
  150. var temp
  151. for (let i = 0; i < line.length; i++) {
  152. temp = []
  153. for (let j = 0; j < line[i].line.length; j++) {
  154. temp.push(line[i].line[j]['_3d_point2']['data'])
  155. }
  156. ret.push(temp)
  157. }
  158. }
  159. /**
  160. * 根据顶点数据获取向量数据
  161. * @param {顶点数据} cube
  162. */
  163. function changeData(cube) {
  164. let ret = []
  165. let item = [] ;
  166. for (let i = 0; i < cube.length; i++) {
  167. item = []
  168. for (let j = 0; j < cube[i].points.length; j++) {
  169. if (j+1<cube[i].points.length) {
  170. item.push(
  171. {
  172. '_3d_id':j,
  173. '_3d_point1':{
  174. 'point_id':cube[i].points[j]['id'],
  175. 'data':cube[i].points[j]['data']
  176. },
  177. '_3d_point2':{
  178. 'point_id':cube[i].points[j+1]['id'],
  179. 'data':cube[i].points[j+1]['data']
  180. },
  181. '_vector':[cube[i].points[j+1]['data'][0]-cube[i].points[j]['data'][0],cube[i].points[j+1]['data'][1]-cube[i].points[j]['data'][1]]
  182. }
  183. )
  184. }
  185. if (j+1==cube[i].points.length) {
  186. item.push(
  187. {
  188. '_3d_id':j,
  189. '_3d_point1':{
  190. 'point_id':cube[i].points[j]['id'],
  191. 'data':cube[i].points[j]['data']
  192. },
  193. '_3d_point2':{
  194. 'point_id':cube[i].points[0]['id'],
  195. 'data':cube[i].points[0]['data']
  196. },
  197. '_vector':[cube[i].points[0]['data'][0]-cube[i].points[j]['data'][0],cube[i].points[0]['data'][1]-cube[i].points[j]['data'][1]]
  198. }
  199. )
  200. }
  201. }
  202. ret.push({
  203. room:i,
  204. line:item
  205. })
  206. }
  207. return ret
  208. }
  209. /**
  210. * 判断点是否在墙体上
  211. * @param {鼠标当前坐标点} current
  212. * @param {墙体线段} lineArr
  213. * @param {水平缩放倍数} scaleTime
  214. * @param {垂直缩放倍数} scaleTimeH
  215. */
  216. function isInFace(current, test, scaleTime, scaleTimeH) {
  217. var fixArr = [];
  218. var selectYArr = [];
  219. var minX = 1,
  220. minY = 1,
  221. maxX = 0,
  222. maxY = 0;
  223. for (var i = 0; i < test.length; i++) {
  224. for (var j = 0; j < test[i].line.length; j++) {
  225. minX = Math.min(minX, test[i].line[j][0]);
  226. // minY = Math.min(minY, test[i].line[j][1]);
  227. maxX = Math.max(maxX, test[i].line[j][0]);
  228. // maxY = Math.max(maxY, test[i].line[j][1]);
  229. fixArr.push({
  230. id: parseFloat(test[i].line[j][0]).toFixed(1),
  231. y: test[i].line[j][1]
  232. });
  233. }
  234. }
  235. for (var i = 0; i < fixArr.length; i++) {
  236. if (fixArr[i].id == parseFloat(current[0] / scaleTime).toFixed(1)) {
  237. selectYArr.push(fixArr[i].y);
  238. }
  239. }
  240. for (var i = 0; i < selectYArr.length; i++) {
  241. minY = Math.min(minY, selectYArr[i]);
  242. maxY = Math.max(maxY, selectYArr[i]);
  243. }
  244. return (
  245. current[0] > minX * scaleTime &&
  246. current[0] < maxX * scaleTime &&
  247. current[1] > minY * scaleTimeH &&
  248. current[1] < maxY * scaleTimeH
  249. );
  250. }
  251. /**
  252. * 计算两线段的交点
  253. * @param {线段一端点} a
  254. * @param {线段一端点} b
  255. * @param {线段二端点} c
  256. * @param {线段二端点} d
  257. */
  258. function segmentsIntr(a, b, c, d){
  259. // 三角形abc 面积的2倍
  260. var area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
  261. // 三角形abd 面积的2倍
  262. var area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x);
  263. // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);
  264. if ( area_abc*area_abd>=0 ) {
  265. return false;
  266. }
  267. // 三角形cda 面积的2倍
  268. var area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x);
  269. // 三角形cdb 面积的2倍
  270. // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
  271. var area_cdb = area_cda + area_abc - area_abd ;
  272. if ( area_cda * area_cdb >= 0 ) {
  273. return false;
  274. }
  275. //计算交点坐标
  276. var t = area_cda / ( area_abd- area_abc );
  277. var dx= t*(b.x - a.x),
  278. dy= t*(b.y - a.y);
  279. return toDecimal({ x: a.x + dx , y: a.y + dy });
  280. }
  281. /**
  282. * 判断一个点是否在面上
  283. * @param {点} point
  284. * @param {面} vs
  285. */
  286. function pointInside(point, vs) {
  287. // ray-casting algorithm based on
  288. // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
  289. let temp = []
  290. for (let i = 0; i < vs.points.length; i++) {
  291. temp.push(vs.points[i]['data'])
  292. }
  293. var x = point[0], y = point[1];
  294. var inside = false;
  295. for (var i = 0, j = temp.length - 1; i < temp.length; j = i++) {
  296. var xi = temp[i][0], yi = temp[i][1];
  297. var xj = temp[j][0], yj = temp[j][1];
  298. var intersect = ((yi > y) != (yj > y))
  299. && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  300. if (intersect) inside = !inside;
  301. }
  302. return inside;
  303. };
  304. function cubePointInFace(selectRoomId,cube,cubeLine) {
  305. let selectCube
  306. let ret = []
  307. for (let i = 0; i < cube.length; i++) {
  308. if (cube[i]['roomId']==selectRoomId) {
  309. selectCube = cube[i]
  310. for (let j = 0; j < cube[i].points.length; j++) {
  311. pointInside(cube[i].points[j]['data'],f_cube[0])
  312. }
  313. }
  314. }
  315. for (let i = 0; i < cube.length; i++) {
  316. if (cube[i]['roomId']!==selectRoomId) {
  317. for (let j = 0; j < selectCube.points.length; j++) {
  318. if (pointInside(selectCube.points[j]['data'],cube[i])) {
  319. ret.push(selectCube.points[j]['data'])
  320. }
  321. }
  322. }
  323. }
  324. return ret
  325. }
  326. /**
  327. * 找出相交线的交点
  328. * @param {线段数组} cubeLine
  329. */
  330. function intersect(selectRoomId,cubeLine) {
  331. //获取选中面的每条线段
  332. let selectCubeVector = [];
  333. let ret = []
  334. for (let i = 0; i < cubeLine.length; i++) {
  335. if (cubeLine[i]['room']===selectRoomId) {
  336. for (let j = 0; j < cubeLine[i].line.length; j++) {
  337. // segmentsIntr(cubeLine[i].line)
  338. // cubeLine[i].line[j]['_vector']
  339. selectCubeVector.push([{
  340. x:cubeLine[i].line[j]['_3d_point1']['data'][0],
  341. y:cubeLine[i].line[j]['_3d_point1']['data'][1],
  342. },{
  343. x:cubeLine[i].line[j]['_3d_point2']['data'][0],
  344. y:cubeLine[i].line[j]['_3d_point2']['data'][1],
  345. }])
  346. }
  347. }
  348. }
  349. for (let i = 0; i < cubeLine.length; i++) {
  350. //未选中的房间
  351. if (cubeLine[i]['room']!==selectRoomId) {
  352. for (let k = 0; k < selectCubeVector.length; k++) {
  353. for (let l = 0; l < cubeLine[i].line.length; l++) {
  354. let item = [{
  355. x:cubeLine[i].line[l]['_3d_point1']['data'][0],
  356. y:cubeLine[i].line[l]['_3d_point1']['data'][1],
  357. },{
  358. x:cubeLine[i].line[l]['_3d_point2']['data'][0],
  359. y:cubeLine[i].line[l]['_3d_point2']['data'][1],
  360. }]
  361. if ((segmentsIntr(selectCubeVector[k][0],selectCubeVector[k][1],item[0],item[1]))) {
  362. let tempItem = segmentsIntr(selectCubeVector[k][0],selectCubeVector[k][1],item[0],item[1])
  363. //判断该交点不是面的顶点
  364. if ((selectCubeVector[k][0]['x']==tempItem['x'] && selectCubeVector[k][0]['y']==tempItem['y'])
  365. || (selectCubeVector[k][1]['x']==tempItem['x'] && selectCubeVector[k][1]['y']==tempItem['y'])
  366. || (item[0]['x']==tempItem['x']&&item[0]['y']==tempItem['y'])
  367. || (item[1]['x']==tempItem['x']&&item[1]['y']==tempItem['y'])) {
  368. }
  369. else{
  370. ret.push(segmentsIntr(selectCubeVector[k][0],selectCubeVector[k][1],item[0],item[1]))
  371. }
  372. }
  373. }
  374. }
  375. }
  376. }
  377. return ret
  378. }
  379. function pushInNewCube(inFaceArr,intersectArr,cube) {
  380. let count = 0;
  381. let temp = []
  382. let item
  383. for (let i = 0; i < cube.length; i++) {
  384. item = []
  385. for (let j = 0; j < cube[i].points.length; j++) {
  386. let ele = cube[i].points[j];
  387. item.push(ele['data'])
  388. }
  389. for (let l = 0; l < intersectArr.length; l++) {
  390. let el = intersectArr[l];
  391. item.push([el.x,el.y])
  392. }
  393. for (let k = 0; k < inFaceArr.length; k++) {
  394. let element = inFaceArr[k];
  395. item.push(element)
  396. }
  397. temp.push(item)
  398. }
  399. return changeCube(temp)
  400. }
  401. function changeCube(arr) {
  402. let item;
  403. let ret = [];
  404. let count = 0
  405. for (let i = 0; i < arr.length; i++) {
  406. const element = arr[i];
  407. item = []
  408. for (let j = 0; j < arr[i].length; j++) {
  409. count++
  410. item.push({
  411. id:count,
  412. data:arr[i][j],
  413. })
  414. }
  415. ret.push({
  416. roomId:i,
  417. points:item
  418. })
  419. }
  420. return ret
  421. }
  422. function draw_point(ctx, point,w,h) {
  423. ctx.fillStyle="#00cc00";
  424. ctx.fillRect(point.x*w-4,point.y*h-4,4,4);
  425. }
  426. /**
  427. * 判断选择的cube相机位置是否在面内
  428. * @param {选择的面id} selectFaceId
  429. * @param {*} cube
  430. */
  431. function pointInSelectFace(selectFaceId,cube) {
  432. for (let i = 0; i < cube.length; i++) {
  433. const element = cube[i];
  434. if (element['roomId'] ===selectFaceId) {
  435. for (let j = 0; j < element['campos'].length; j++) {
  436. if (!pointInside([element['campos'][j].x,element['campos'][j].y],element)) {
  437. return false
  438. }
  439. }
  440. }
  441. }
  442. return true
  443. }
  444. /**
  445. * 判断交点是否为顶点
  446. * @param {交点坐标} intersectArr
  447. * @param {顶点数组} cube
  448. */
  449. function interectNotInPoint(intersectArr,cube) {
  450. if (intersectArr.length>0) {
  451. for (let k = 0; k < intersectArr.length; k++) {
  452. for (let i = 0; i < cube.length; i++) {
  453. let element = cube[i];
  454. for (let j = 0; j < element['points'].length; j++) {
  455. let ele = element['points'][j]['data'];
  456. if (intersectArr[k].x==ele[0]&&intersectArr[k].y==ele[1]) {
  457. return true
  458. }
  459. }
  460. }
  461. }
  462. return false
  463. }
  464. return false
  465. }
  466. /**
  467. *
  468. * @param {原生数据} raw_cube
  469. */
  470. function rawToCube(raw_cube,w,h) {
  471. let item;
  472. let count = 0
  473. let ret = [];
  474. for (let i = 0; i < raw_cube.length; i++) {
  475. item = {
  476. roomId:i,
  477. campos:[
  478. {
  479. x:-0.1,
  480. y:0.25
  481. }
  482. ],
  483. points:[]
  484. }
  485. for (let j = 0; j < raw_cube[i].point.length; j++) {
  486. count++
  487. let element = raw_cube[i].point[j];
  488. let norV = fixRawData([element['x'],element['y']],w,h)
  489. item.points.push({
  490. id:count,
  491. data:norV
  492. })
  493. }
  494. ret.push(item)
  495. }
  496. return ret
  497. }
  498. /**
  499. * 将鼠标点击起始点移到中心
  500. * @param {鼠标点} xy
  501. */
  502. function calculateXY(xy,w,h) {
  503. return [xy[0]-w/2,xy[1]-h/2]
  504. }
  505. function fixRawData(xy,w,h) {
  506. return [xy[0]*50 / w,xy[1]*50 / h]
  507. }
  508. /**
  509. * 四舍五入保留7位小数
  510. * @param {数组} arr
  511. */
  512. function toDecimal(arr) {
  513. var xf = parseFloat(arr.x);
  514. var yf = parseFloat(arr.y);
  515. if (isNaN(xf) || isNaN(yf)) {
  516. return;
  517. }
  518. tx = Math.round(xf * 10e6) / 10e6;
  519. ty = Math.round(yf * 10e6) / 10e6;
  520. return {x:tx,y:ty};
  521. }
  522. function calculateRawData(data) {
  523. let {vertex,room} = data
  524. let item
  525. let ret = []
  526. for (let i = 0; i < room.length; i++) {
  527. let element = room[i];
  528. item = {
  529. point:[]
  530. }
  531. for (let j = 0; j < element.length; j++) {
  532. let ele = element[j];
  533. for (let a = 0; a < vertex.length; a++) {
  534. if (a === ele) {
  535. item.point.push(vertex[a])
  536. }
  537. }
  538. }
  539. ret.push(item)
  540. }
  541. return ret
  542. }