1. 程式人生 > 實用技巧 >多點位置配對-相似度-形狀配對 (元件)

多點位置配對-相似度-形狀配對 (元件)

改寫成了uniapp通用元件

名稱 型別 必填 說明
@success Events 成功回撥
@fail Events 失敗回撥
data Array 用來匹配。
  • 事件回撥 返回一個物件

    obj

名稱 型別 內容 說明
msg String seal:ok或seal:no 訊息
likeness Number 相似度
location Array 觸發的位置

注意-

  1. location並不會大於傳入data的長度

  2. 當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>

專案地址:Dome