提问人:smpa01 提问时间:10/19/2023 最后编辑:smpa01 更新时间:10/19/2023 访问量:59
确保计算返回的坐标完全相同
Ensuring exact same coordinate returned by calculation
问:
我在一个大圆圈上以度角放置了 4 个小圆圈。我希望 javascript 返回完全相同的红色和蓝色圆圈(因为移位是水平的,y 是相同的,但 x 会改变)和绿色和粉红色圆圈的返回完全相同(因为移位是垂直的,x 是相同的,但 y 会改变)。0, 90, 180, 270
y
x
而下面的 javascript 返回相同的 x,但返回不同的 y(红色 = 237.76900370542438,蓝色 = 237.7690037054244)。展望未来,它搞砸了所有的计算,因为它们不一样。
我不知道这是什么根本原因,但有没有办法解决它?我需要它们完全相同。
const angle = [0, 90, 180, 270];
const angleCoord = [];
angle.forEach(
(a, i) => {
const element = d3.select('.circ1').node();
const cx = parseFloat(element.getAttribute('cx'));
const cy = parseFloat(element.getAttribute('cy'));
const r = parseFloat(element.getAttribute('r'));
const x = cx + Math.cos(a * Math.PI / 180) * r;
const y = cy + Math.sin(a * Math.PI / 180) * r;
angleCoord.push({
angle: a,
x: x,
y: y
})
}
);
const color = ['red', 'green', 'blue', 'pink'];
d3.select('svg').append('g')
.attr('class', 'circles')
.selectAll('circle')
.data(angleCoord)
.join('circle')
.attr('class', (_, i) => color[i])
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', '4')
.attr('fill', (_, i) => color[i]);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<script type="text/javascript" src='https://cdn.jsdelivr.net/npm/[email protected]/bignumber.min.js'></script>
<body>
<div id="container" class="svg-container"></div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1536 720">
<circle class="circ1" cx="384" cy="237.76900370542438" r="122.23099629457562" fill="none" stroke="black"></circle>
</svg>
<script src="prod3.js"></script>
</body>
</html>
答:
0赞
Wyck
10/19/2023
#1
sin 180 的精度与 PI/2 的精度加上或减去一些无穷小误差的精度差不多。
如果您想要“精确”值,请考虑使用以度为单位的 90° 角倍数的 sin 和 cos 的“精确”值。例如:
const lookupTable = {
0: { sin: 0, cos: 1 },
90: { sin: 1, cos: 0 },
180: { sin: 0, cos: -1 },
270: { sin: -1, cos: 0 }
};
const exactSin = degrees => lookupTable[degrees].sin;
const exactCos = degrees => lookupTable[degrees].cos;
const angle = [0, 90, 180, 270];
const angleCoord = [];
const lookupTable = {
0: { sin: 0, cos: 1 },
90: { sin: 1, cos: 0 },
180: { sin: 0, cos: -1 },
270: { sin: -1, cos: 0 }
};
const exactSin = (degrees) => lookupTable[degrees].sin;
const exactCos = (degrees) => lookupTable[degrees].cos;
angle.forEach(
(a, i) => {
const element = d3.select('.circ1').node();
const cx = parseFloat(element.getAttribute('cx'));
const cy = parseFloat(element.getAttribute('cy'));
const r = parseFloat(element.getAttribute('r'));
const x = cx + exactCos(a) * r;
const y = cy + exactSin(a) * r;
console.log({x, y});
angleCoord.push({
angle: a,
x: x,
y: y
})
}
);
const color = ['red', 'green', 'blue', 'pink'];
d3.select('svg').append('g')
.attr('class', 'circles')
.selectAll('circle')
.data(angleCoord)
.join('circle')
.attr('class', (_, i) => color[i])
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', '4')
.attr('fill', (_, i) => color[i]);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<script type="text/javascript" src='https://cdn.jsdelivr.net/npm/[email protected]/bignumber.min.js'></script>
<body>
<div id="container" class="svg-container"></div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1536 720">
<circle class="circ1" cx="384" cy="237.76900370542438" r="122.23099629457562" fill="none" stroke="black"></circle>
</svg>
<script src="prod3.js"></script>
</body>
</html>
评论
0赞
smpa01
10/19/2023
在代码中是否有任何其他方法可以处理此问题?除了使用硬编码查找表之外。因为,对于产品,我不会事先知道所有的角度(因为它们都是动态的),因此不可能构建这样的表。
0赞
Wyck
10/19/2023
其他角度将不准确。您正在寻找的轴对称性吗?只需计算一个象限中的所有角度,然后使用上面的查找表将它们旋转到其他象限中。
0赞
Wyck
10/19/2023
@smpa01请更新您的问题,以更清楚地定义您的要求,即当所有角度都是动态的时,您希望结果是什么。
0赞
smpa01
10/19/2023
#2
感谢@Wyck分享指向另一个链接的链接。
我能够调整此链接中的建议,并在上述情况下使用它来通过让 js 在代码中处理它来解决问题。
const angle = [0, 90, 180, 270];
const angleCoord = [];
const color = ['red', 'green', 'blue', 'pink'];
function round(value, precision) {
const power = Math.pow(10, precision)
return Math.round((value*power)+(Number.EPSILON*power)) / power
}
angle.forEach(
(a, i) => {
const element = d3.select('.circ1').node();
const cx = round(parseFloat(element.getAttribute('cx')),15);
const cy = round(parseFloat(element.getAttribute('cy')),15);
const r = round(parseFloat(element.getAttribute('r')),15);
const _sin = round(Math.sin(a * Math.PI / 180),15);
const _cos = round(Math.cos(a * Math.PI / 180),15);
const x = cx + _cos * r;
const y = cy + _sin * r;
console.log(`${color[i]}`,cx,cy,r,_sin,_cos,x,y,);
angleCoord.push({
angle: a,
x: x,
y: y
})
}
);
d3.select('svg').append('g')
.attr('class', 'circles')
.selectAll('circle')
.data(angleCoord)
.join('circle')
.attr('class', (_, i) => color[i])
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', '4')
.attr('fill', (_, i) => color[i]);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<script type="text/javascript" src='https://cdn.jsdelivr.net/npm/[email protected]/bignumber.min.js'></script>
<body>
<div id="container" class="svg-container"></div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1536 720">
<circle class="circ1" cx="384" cy="237.76900370542438" r="122.23099629457562" fill="none" stroke="black"></circle>
</svg>
<script src="prod3.js"></script>
</body>
</html>
评论
console.log( 0.1 + 0.2 )