多点位置配对-相似度-形状配对 (组件)

改写成了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{
	 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{
	 100vw;
	height: 100vh;
	background-color: pink;
}
</style>

项目地址:Dome

原文地址:https://www.cnblogs.com/1748sb/p/13913745.html