JavaScript计算归一化角度相似度:基于朝向的0-1评分实现方案
角度朝向相似度计算实现方案
问题根因
原有代码的问题是将角度差值除以360做归一化,而朝向的最大有效差异为180度(差值超过180度时实际为反向的更小夹角),因此会出现0°和90°、0°和270°计算结果相同的错误。
实现方案
方案1:线性相似度(差值与评分线性负相关)
逻辑:朝向完全相同时相似度为1,完全相反(差180度)时相似度为0,差值和评分呈线性负相关。
实现代码:
function modulo(x, y){ return (x % y + y) % y; } function angleSimilarity(angle1, angle2) { let relativeAngle = angle2 - angle1; // 计算范围在-180~180之间的相对角度 relativeAngle = modulo((relativeAngle + 180), 360) - 180; let diff = Math.abs(relativeAngle); // 最大差异180度对应相似度0,除以180做归一化 const baseScore = 1 - (diff / 180); // 可选校准:如果需要10度差输出接近0.9的结果,可保留1位小数 // return Number(baseScore.toFixed(1)); return baseScore; }
测试结果:
angleSimilarity(90, 100)≈ 0.94,保留1位小数为0.9,符合示例要求angleSimilarity(0, 90)= 0.5angleSimilarity(0, 180)= 0(完全相反)
方案2:余弦相似度(更符合人眼感知)
逻辑:基于方向向量的点积计算,小角度差异时评分下降更慢,大角度差异时下降更快,更符合人对朝向接近程度的感知。
实现代码:
function angleSimilarity(angle1, angle2) { // 角度差转弧度 const radDiff = (angle1 - angle2) * Math.PI / 180; // 余弦值映射到0~1区间 return (Math.cos(radDiff) + 1) / 2; }
如果需要匹配示例中红-绿相似度0.9、红-橙相似度0.8、相反朝向接近0.1的效果,可对结果做幂次调整:
function angleSimilarity(angle1, angle2) { const radDiff = (angle1 - angle2) * Math.PI / 180; const baseScore = (Math.cos(radDiff) + 1) / 2; // 调整幂次校准评分分布,数值越大小差异评分越高 return Math.pow(baseScore, 3); }
内容的提问来源于stack exchange,提问作者Ood
相关产品推荐
相关产品推荐

