Common.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import math from './math.js'
  3. //THREE.Vector2.name2 = 'Common'
  4. var Common = {
  5. sortByScore: function(list, request, rank){
  6. var i = request ? Common.filterAll(list, request) : list
  7. return 0 === i.length ? [] : i = i.map(function(e) {
  8. let results = rank.map(function(f){return f(e)})
  9. let scores = results.map(e=>e.score != void 0 ? e.score : e)
  10. let logs = results.map(e=>e.log)
  11. return {
  12. item: e,
  13. scores,
  14. logs,
  15. score: scores.reduce(function(t, i) {//总分
  16. return t + i
  17. }, 0)
  18. }
  19. }).sort(function(e, t) {
  20. return t.score - e.score;
  21. })
  22. }
  23. ,
  24. filterAll: function(e, t) {
  25. return e.filter(function (e) {
  26. return t.every(function (t) {
  27. return t(e)
  28. })
  29. })
  30. },
  31. //---------------
  32. find : function(list, request, rank, sortByScore ) {
  33. if(sortByScore){
  34. var r = this.sortByScore(list, request, rank)
  35. return r[0] && r[0].item
  36. }else{
  37. var i = request ? Common.filterAll(list, request) : list
  38. return 0 === i.length ? null : (rank && rank.forEach(function(e) {
  39. i = Common.stableSort(i, e)
  40. }),
  41. i[0])
  42. }
  43. }
  44. ,
  45. stableSort: function(e, f) {//用到排序函数,涉及到两个item相减
  46. return e.map(function(e, i) {
  47. return {
  48. value: e,
  49. index: i
  50. }
  51. }).sort(function(e, u) {
  52. var n = f(e.value, u.value);
  53. return 0 !== n ? n : e.index - u.index //似乎就是加多了这一步:若差距为0,按照原顺序
  54. }).map(function(e) {
  55. return e.value
  56. })
  57. },
  58. average: function (e, t) {
  59. if (0 === e.length)
  60. return null;
  61. for (var i = 0, n = 0, r = 0; r < e.length; r++) {
  62. var o = t ? e[r][t] : e[r];
  63. i += o,
  64. n++
  65. }
  66. return i / n
  67. },
  68. //---------------------------
  69. getMixedSet : function(arr1, arr2){//交集
  70. return arr1.filter(item=>arr2.includes(item));
  71. },
  72. getUnionSet : function(arr1, arr2){//并集
  73. return arr1.concat(arr2.filter(item=>!arr1.includes(item)))
  74. },
  75. getDifferenceSet : function(arr1, arr2){//差集 不能识别重复的,如getDifferenceSet([1,2,2],[1,1,2]) 为空
  76. var arr11 = arr1.filter(item=>!arr2.includes(item));
  77. var arr22 = arr2.filter(item=>!arr1.includes(item));
  78. return arr11.concat(arr22)
  79. },
  80. getDifferenceSetMuti : function(arr){//收集绝对没有重复的元素,也就是判断出现次数=1的
  81. var set = [];
  82. arr.forEach(arr1=>{
  83. arr1.forEach(item=>{
  84. var index = set.indexOf(item)
  85. if(index>-1){
  86. set.splice(index, 1)
  87. }else{
  88. set.push(item)
  89. }
  90. })
  91. })
  92. return set;
  93. }
  94. ,
  95. CloneJson : function(data){
  96. var str = JSON.stringify(data)
  97. return JSON.parse(str)
  98. }
  99. ,
  100. CloneObject : function (copyObj, isSimpleCopy, simpleCopyList = [], judgeSimpleCopyFun) {
  101. //isSimpleCopy 只复制最外层
  102. //复制json result的可能:普通数字或字符串、普通数组、复杂对象
  103. judgeSimpleCopyFun || (judgeSimpleCopyFun=()=>{})
  104. if (!copyObj || typeof copyObj == 'number' || typeof copyObj == 'string' ||copyObj.isObject3D || copyObj instanceof Function || simpleCopyList.some(className => copyObj instanceof className) || judgeSimpleCopyFun(copyObj)) {
  105. return copyObj
  106. }
  107. if (copyObj instanceof Array) {
  108. return copyObj.map(e => {
  109. return this.CloneObject(e, isSimpleCopy, simpleCopyList, judgeSimpleCopyFun)
  110. })
  111. } else {
  112. if (copyObj.clone instanceof Function) {
  113. //解决一部分
  114. return copyObj.clone()
  115. }
  116. }
  117. let result = {}
  118. for (var key in copyObj) {
  119. if (copyObj[key] instanceof Object && !isSimpleCopy ) result[key] = this.CloneObject(copyObj[key], isSimpleCopy, simpleCopyList, judgeSimpleCopyFun)
  120. else result[key] = copyObj[key]
  121. //如果是函数类同基本数据,即复制引用
  122. }
  123. return result
  124. }
  125. ,
  126. CloneClassObject :function(copyObj, {ignoreList=[],simpleCopyList=[]}={}){//复杂类对象
  127. var newobj = new copyObj.constructor();
  128. this.CopyClassObject(newobj, copyObj, {ignoreList,simpleCopyList})
  129. return newobj
  130. }
  131. ,
  132. CopyClassObject :function(targetObj, copyObj, {ignoreList=[],simpleCopyList=[]}={}){//复杂类对象
  133. for(let i in copyObj){
  134. if(i in copyObj.__proto__)break; //到函数了跳出
  135. if(ignoreList.includes(i)){
  136. continue;
  137. }else if(simpleCopyList.includes(i)){
  138. targetObj[i] = copyObj[i]
  139. }else{
  140. targetObj[i] = this.CloneObject(copyObj[i], false, simpleCopyList )
  141. }
  142. /* else if(copyObj[i].clone instanceof Function ){
  143. targetObj[i] = copyObj[i].clone()
  144. }else{
  145. targetObj[i] = copyObj[i];
  146. } */
  147. }
  148. }
  149. ,
  150. ifSame : function(object1, object2, simpleEqualClass=[]){ //对于复杂的类对象,若能简单判断就直接写进simpleEqualClass
  151. if(object1 == object2 )return true // 0 != undefined , 0 == ''
  152. else if(!object1 || !object2) return false
  153. else if(object1.constructor != object2.constructor){
  154. return false
  155. }else if(simpleEqualClass.some(className => object1 instanceof className)){
  156. return object1 == object2
  157. }else if(object1 instanceof Array ) {
  158. if(object1.length != object2.length)return false;
  159. var _object2 = object2.slice(0);
  160. for(let i=0;i<object1.length;i++){
  161. var u = _object2.find(e=>Common.ifSame(object1[i], e, simpleEqualClass));
  162. if(u == void 0 && !_object2.includes(u) && !object1.includes(u))return false;
  163. else{
  164. let index = _object2.indexOf(u);
  165. _object2.splice(index,1);
  166. }
  167. }
  168. return true
  169. }else if(object1.equals instanceof Function ){//复杂数据仅支持这种,其他的可能卡住?
  170. return object1.equals(object2)
  171. }else if(typeof object1 == 'number' || typeof object1 == 'string'){
  172. if(isNaN(object1) && isNaN(object2))return true
  173. else return object1 == object2
  174. }else if(typeof object1 == "object"){
  175. var keys1 = Object.keys(object1)
  176. var keys2 = Object.keys(object2)
  177. if(!Common.ifSame(keys1,keys2,simpleEqualClass))return false;
  178. for(let i in object1){
  179. var same = Common.ifSame(object1[i], object2[i],simpleEqualClass);
  180. if(!same)return false
  181. }
  182. return true
  183. }else{
  184. console.log('isSame出现例外')
  185. }
  186. }
  187. ,
  188. downloadFile : function(data, filename, cb) {
  189. var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
  190. save_link.href = data;
  191. save_link.download = filename;
  192. var event = document.createEvent('MouseEvents');
  193. event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  194. save_link.dispatchEvent(event);
  195. cb && cb();
  196. },
  197. replaceAll : function (str, f, e) {
  198. //f全部替换成e
  199. var reg = new RegExp(f, "g"); //创建正则RegExp对象
  200. return str.replace(reg, e);
  201. },
  202. dealURL(url){
  203. let urlNew = this.replaceAll(url, "\\+", "%2B");// 浏览器似乎不支持访问带+的地址
  204. urlNew = this.replaceAll(urlNew, "/.//", "/") //去除双斜杠(/.//)
  205. return urlNew
  206. },
  207. getNameFromURL(url){
  208. if(!url)return ''
  209. let get = (e)=>{
  210. return e.split('/').pop()
  211. }
  212. if(url instanceof Array){
  213. return url.map(e=>get(e))
  214. }
  215. return get(url)
  216. },
  217. //---------------------------
  218. intervalTool:{ //延时update,防止卡顿
  219. list:[],
  220. /* isWaiting:function(name, func, delayTime){
  221. if(!this.list.includes(name)){ //如果没有该项, 则开始判断
  222. var needWait = func(); //触发了改变,则等待一段时间后再自动判断
  223. if(needWait){
  224. this.list.push(name);
  225. setTimeout(()=>{
  226. var a = this.list.indexOf(name);
  227. this.list.splice(a,1);
  228. this.isWaiting(name, func, delayTime) //循环
  229. },delayTime)
  230. }
  231. }
  232. }, */
  233. isWaiting:function(name, func, delayTime/* , autoCycle */){
  234. let item = this.list.find(e=>e.name == name)
  235. if(!item){ //如果没有该项, 则加入循环
  236. let ifContinue = func()
  237. item = {name, func, delayTime}
  238. this.list.push(item);
  239. setTimeout(()=>{
  240. var a = this.list.indexOf(item);
  241. this.list.splice(a,1);
  242. let {func, delayTime} = item
  243. if(item.requestUpdate || ifContinue ) this.isWaiting(name, func, delayTime) //循环
  244. },delayTime)
  245. }else{//如果有该项,说明现在请求下一次继续更新
  246. //if(delayTime == 0){//想立刻更新一次
  247. // func()
  248. //}else{
  249. //更新属性
  250. item.func = func
  251. item.delayTime = delayTime
  252. item.requestUpdate = true
  253. //}
  254. }
  255. },
  256. }
  257. ,
  258. pushToGroupAuto : function(items, groups, recognizeFunction, recognizeGroup){//自动分组。 items是将分到一起的组合。items.length = 1 or 2.
  259. recognizeFunction = recognizeFunction || function(){}
  260. if(recognizeGroup){ //有更复杂的识别处理,直接传递整个组
  261. var atGroups = groups.filter(group=>recognizeGroup(group, items))
  262. }else{
  263. var atGroups = groups.filter(group=>group.find(
  264. item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
  265. ))
  266. }
  267. if(atGroups.length){//在不同组
  268. //因为items是一组的,所以先都放入组1
  269. items.forEach(item=> {if(!atGroups[0].includes(item)) atGroups[0].push(item);})
  270. if(atGroups.length>1){//如果在不同组,说明这两个组需要合并
  271. var combineGroup = []
  272. atGroups.forEach(group=>{
  273. combineGroup = Common.getUnionSet(combineGroup, group)
  274. groups.splice(groups.indexOf(group),1)
  275. })
  276. groups.push(combineGroup)
  277. }
  278. }else{//直接加入为一组
  279. groups.push(items)
  280. }
  281. },
  282. getBestCount : (function(){
  283. let lastCount = {}
  284. return function(name, minCount=1,maxCount=6, durBound1 = 1.2, durBound2 = 10, ifLog, maxHistory){
  285. let timeStamp = performance.getEntriesByName("loop-start");
  286. let count
  287. if(timeStamp.length){
  288. let dur = performance.now() - timeStamp[timeStamp.length-1].startTime; //dur在iphoneX中静止有7,pc是2
  289. count = Math.round(math.linearClamp(dur, [durBound1,durBound2], [maxCount, minCount]))
  290. if (maxHistory) {
  291. if (!lastCount[name]) lastCount[name] = []
  292. if (count == 0 && lastCount[name].length > maxHistory - 1 && !lastCount[name].some(e => e > 0)) {
  293. count = 1
  294. }
  295. lastCount[name].push(count)
  296. if (lastCount[name].length > maxHistory) lastCount[name].splice(0, 1)
  297. }
  298. if(ifLog){//注意,console.log本身用时挺高, 降4倍时可能占用0.5毫秒
  299. name && count && console.log(name, count , ' ,dur:', dur.toFixed(3))
  300. }
  301. }else{
  302. count = maxCount // ?
  303. }
  304. //主要在手机端有效果。
  305. return count
  306. }
  307. })(),
  308. batchHandling : {//分批处理
  309. lists:[],
  310. getSlice : function(name, items , {stopWhenAllUsed, min=5,max=100, durBound1 , durBound2, useEquals , maxUseCount}){
  311. if(items.length == 0 ||
  312. ((maxUseCount = maxUseCount == void 0 ? Common.getBestCount(name, min,max , durBound1, durBound2 /* , true */ ) : maxUseCount), !maxUseCount) //本次最多可以使用的个数
  313. ){
  314. return {list:[]}
  315. }
  316. if(!this.lists[name]) this.lists[name] = {list:[] }
  317. //更新列表项目,但不变原来的顺序
  318. let list = this.lists[name].list.filter(a=>items.some(item=> useEquals ? a.item.equals(item) : a.item == item))//去掉已经不在items里的项目
  319. this.lists[name].list = list
  320. items.forEach(item=>{//增加新的项目。
  321. if(!list.some(a=>useEquals ? a.item.equals(item) : a.item == item )){
  322. list.push({item, count:0})
  323. }
  324. })
  325. //至此,在后排的都是未使用的
  326. let unUsed = list.filter(e=>e.count == 0)//未使用的项目(count为0)优先
  327. let result = []
  328. unUsed.slice(0,maxUseCount).forEach(e=>{
  329. result.push(e.item);
  330. e.count ++;
  331. })
  332. if(unUsed.length > maxUseCount){
  333. //还是剩有未使用的项目,等待下一次
  334. }else{
  335. //所有项目都能使用一次
  336. if(!stopWhenAllUsed){ //若不是全部使用就停止
  337. let wholeCount = Math.min(items.length, maxUseCount);
  338. let restCount = wholeCount - result.length; //补齐
  339. list.slice(0,restCount).forEach(e=>{
  340. result.push(e.item);
  341. e.count ++;
  342. })
  343. }
  344. list.forEach(e=>e.count--) //复原,等待新的循环
  345. }
  346. /* result.forEach((e,i)=>{//有重复的
  347. if( result.slice(0,i).some(a=>a.equals(e)) || result.slice(i+1).some(a=>a.equals(e)) ) {
  348. console.log(e)
  349. }
  350. }) */
  351. return {list:result }
  352. }
  353. },
  354. getRootWindow(){//获取包含Potree的根window
  355. let win = window
  356. try{
  357. while(win.parent!=win && win.parent.Potree){
  358. win = win.parent
  359. }
  360. if(window != win)return win
  361. }catch(e){
  362. //console.log(e) //可能跨域,从而win.parent.Potree报错
  363. console.log('getRootWindow 跨域')
  364. return
  365. }
  366. },
  367. watch: function(object, propName, initialValue){ //监听某个属性的变化
  368. let v = initialValue
  369. Object.defineProperty(object, propName, {
  370. get: function() {
  371. return v
  372. },
  373. set: function(e) {
  374. console.warn('watch:',propName, e)
  375. v = e
  376. }
  377. })
  378. },
  379. imgAddLabel : function (img, labelImg, labelInfo = {}) {
  380. //图上加另一张小图,用于添加水印
  381. let canvas = document.createElement('canvas')
  382. let context = canvas.getContext('2d')
  383. context.canvas.width = img.width
  384. context.canvas.height = img.height
  385. context.drawImage(img, 0, 0, img.width, img.height)
  386. let labelWidth = labelInfo.widthRatioToImg ? img.width * labelInfo.widthRatioToImg : labelImg.width //widthRatioToImg:label的width占img的width的比例
  387. let labelHeight = (labelWidth * labelImg.height) / labelImg.width
  388. if (!labelInfo.leftRatioToImg && labelInfo.rightRatioToImg) {
  389. labelInfo.leftRatioToImg = 1 - labelInfo.rightRatioToImg - (labelInfo.widthRatioToImg || labelImg.width / img.width)
  390. }
  391. if (!labelInfo.topRatioToImg && labelInfo.bottomRatioToImg) {
  392. labelInfo.topRatioToImg = 1 - labelInfo.bottomRatioToImg - labelHeight / img.height
  393. }
  394. let labelLeft = img.width * labelInfo.leftRatioToImg //leftRatioToImg:label的left占img的width的比例
  395. let labelTop = img.height * labelInfo.topRatioToImg //topRatioToImg:label的top占img的height的比例
  396. context.globalAlpha = labelInfo.opacity != void 0 ? labelInfo.opacity : 1
  397. context.drawImage(labelImg, labelLeft, labelTop, labelWidth, labelHeight)
  398. var dataUrl = canvas.toDataURL('image/png', labelInfo.compressRatio)
  399. //Common.downloadFile(dataUrl, 'screenshot.png')
  400. context.clearRect(0,0,img.width,img.height)
  401. return dataUrl
  402. }
  403. }
  404. Potree.Common = Common
  405. export default Common