相关的 live-javascript/jsbin:http://jsbin.com/ekuyam/2/edit
我基本上只是在相对于 Canvas 中心的六边形中生成点,然后在六边形中的每个点绘制圆圈,但仔细检查圆圈没有正确对齐,它实际上是不可见的,除非你使用大圈子。
当我使用小圆圈时,它们似乎非常准确地放置在 Canvas 上,如下所示:
但是通过使用更大的圆圈进行仔细检查(有点像放大),发现数学中存在一些不准确的地方,从这里不需要的空间/区域可以看出:
线条应该完美对齐,但我得到了一些不需要的空间。为什么会这样,我该如何修改?
代码:
function hexagon(w, h, p) {
var points = 6;
var width = w;
var height = h;
var angle = ((2 * Math.PI) / points);
var hexagon = [];
for (i = 0; i < points; i++) {
hexagon.push({
x: width * Math.sin(angle * i) + p.x,
y: height * Math.cos(angle * i) + p.y
})
}
return hexagon
}
var stage = new Kinetic.Stage({
container: "container",
width: 600,
height: 600
});
var layer = new Kinetic.Layer();
var group = new Kinetic.Group({x: 600/2, y: 600/2, draggable: false});
var radius = 1000;
var s = new Kinetic.Circle({
radius: radius,
stroke: 'black',
strokeWidth: 1,
draggable: true
});
group.add(s);
var hex_points = hexagon(radius, radius, {x: 600/2, y: 600/2});
for (p in hex_points) {
var s = new Kinetic.Circle({
radius: radius,
stroke: 'black',
strokeWidth: 1,
draggable: true
});
s.setPosition({x: hex_points[p].x - 600/2, y: hex_points[p].y - 600/2})
group.add(s);
}
layer.add(group);
stage.add(layer);
最佳答案
这是因为 sin(2 * Math.PI)/6 = sqrt(3)/2 是一个无理数。然而, float 只能表示有理数(实际上只有分母是 2 的幂)。因此,您总会有一些舍入误差。如果将圆圈放大到足够大,则可以看到此舍入误差。为了防止这种情况,您需要限制放大倍率。
如果您绝对必须绕过它,最简单的方法就是追求更高的算术精度。
另一种方法是使用公式 (x-x_0)^2 + (y-y_0)^2 = R^2 并在不使用三 Angular 函数的情况下围绕已知交点局部求解。更具体地说,函数 f(x,y):= (x-x_0)^2+(y-y_0)^2 满足 inverse function theorem 的条件。除 x=x_0 和 y=y_0 之外的任何地方。请注意,圆示例包含在另一篇关于 implicit function theorem 的维基百科文章中。 .手头的例子是一个全纯函数,因此局部逆也将是全纯的。特别是它有一个很好的局部近似 Taylor series expansion. .这种方法的要点是您不要围绕中心绘制圆圈,而是“通过所需的交点”绘制它。因此,您可以强制它“与”这一点“相交”。但请记住,他的“交点”只是一个近似值,因为 float 永远无法正确表示 sqrt(3) 或其有理倍数。
现在怎么办?我会做什么:一旦放大倍数使得屏幕上只有一个交点,我会通过替换 R 作弊,使得 R^2 = (x_i-x_0)^2+(y_i-y_0)^2 其中 (x_i , y_i) 是所需的交点,“(x_0,y_0)”是圆心。然后我会继续使用标准圆公式。
一个非常简单的方法是确保圆线也得到缩放。因此,对于高倍率,不精确性将隐藏在圆的“厚”周长下。
关于javascript - 想要将 6 个圆圈放置在数学上精确的几何形状中,但它们没有正确对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16052630/