多點位置配對-相似度-形狀配對 (元件)
阿新 • • 發佈:2020-11-02
改寫成了uniapp通用元件
名稱 | 型別 | 必填 | 說明 |
---|---|---|---|
@success | Events | 否 | 成功回撥 |
@fail | Events | 否 | 失敗回撥 |
data | Array | 是 | 用來匹配。 |
-
事件回撥 返回一個物件
obj
名稱 | 型別 | 內容 | 說明 |
---|---|---|---|
msg | String | seal:ok或seal:no | 訊息 |
likeness | Number | 相似度 | |
location | Array | 觸發的位置 |
注意-
-
location並不會大於傳入
data
的長度 -
當likeness大於或等於
90
才觸發success
js另寫了一個檔案
<template> <view class="seal" @touchstart="touchstart" @touchend="touchEnd" /> </template> <script src="./seal.js" /> <style lang="scss" scoped> .seal{ width: 100%; height: 100%; } </style>
- script
let log=console.log; export default { props:{ data:Array }, data() { let Old=JSON.parse(JSON.stringify(this.data)); let Dot=this.data.length; //點的個數 return { array:{ New:[], Old, Dot, }, } }, methods: { touchstart(e){ // 手機按下 獲取位置 let data=[Math.floor(e.changedTouches[0].pageX),Math.floor(e.changedTouches[0].pageY)]; this.array.New.push(data); if(this.array.New.length==this.array.Dot){ this.get_similarity(this.array.New); this.array.New=[]; } }, touchEnd(e){ // 當手機每次抬起都會被清空 this.array.New=[]; }, // 計算相似度 get_similarity(array_new){ // 計算兩點間距離 const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); // 生成指定範圍的二維點位 const randomPosInRange = (min, max) => Array.from({length: 2}, () => Math.floor(Math.random() * (max - min + 1)) + min); // 計算各點的相互距離 const pointsDistance = (points) => { let array = []; for (let i = 0; i < points.length; i++) { for (let j = i + 1; j < points.length; j++) { const p1 = points[i]; const p2 = points[j]; array.push(distance(p1[0], p1[1], p2[0], p2[1])); } } return array }; // 計算陣列中的最小值 const minInArray = (array) => array.sort((a, b) => a - b)[0]; // 計算各點距離與最小距離的倍數 const distanceMultiple = (points) => { const distances = pointsDistance(points); const minDistance = minInArray(distances); const code = distances.map(distance => round(distance / minDistance, 5)); code.shift(); return code }; // 四捨五入到指定位數 const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`); // 差異相關性 const approximateMatchArray = (arr1, arr2) => { let scope = 0; arr1 = arr1.sort(); arr2 = arr2.sort(); const part = 100 / arr1.length; for (let i = 0; i < arr1.length; i++) { const reduce = Math.abs(arr1[i] - arr2[i]); const partScope = part * (1 - reduce / 10); scope = scope + partScope } let damping = 105; if (scope < 90) damping = 125; scope = scope * (scope / damping); if (scope > 100) scope = 0; return scope }; // 直接獲取相似度 const getSimilarity = (points) => { const code = distanceMultiple(this.array.Old); const ity = distanceMultiple(points) const scope = approximateMatchArray(code, ity); const data={ likeness:Math.floor(scope), location:this.array.New } if(Math.floor(scope)>=90){ data.msg="seal:ok"; this.$emit('success',data); }else{ data.msg="seal:no"; this.$emit('fail',data); } }; // 執行 getSimilarity(array_new) } } }
接下來就是在頁面裡呼叫了
<template> <view class="content"> <seal @success="success" @fail="fail" :data="data" /> </view> </template> <script> import seal from '@/components/seal/seal.vue'; export default{ components:{seal}, data(){ return{ data:[[126, 76], [78, 132], [60, 44]] } }, methods:{ success(data){ uni.showLoading({title:"匹配成功",mask:true}); setTimeout(()=>{ uni.hideLoading(); },3000) console.log(data) }, fail(data){ console.log(data) } } } </script> <style lang="scss" scoped> .content{ width: 100vw; height: 100vh; background-color: pink; } </style>