Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Graphics 非常大的HTML5画布圆圈不精确_Graphics_Drawing_Html5 Canvas - Fatal编程技术网

Graphics 非常大的HTML5画布圆圈不精确

Graphics 非常大的HTML5画布圆圈不精确,graphics,drawing,html5-canvas,Graphics,Drawing,Html5 Canvas,我正在开发一个应用程序,用户可以在HTML5画布上绘制欧几里得结构。因此,我不能真正限制某些形状的大小。当检查屏幕上绘制的非常大的圆时,我注意到非常大的圆没有恒定的半径 更具体地说,由两个点(一个中心点和一个指定半径的点)定义的圆不再通过半径点 逐渐变大的圆圈。这些都应该通过E点 在45度=PI/4的倍数上不会出现错误。在这些倍数之间误差最大(例如PI/8) 以下是包含上述第一个示例的JSFIDLE: 我的问题:为什么会发生这种情况?有什么办法(有效地)解决这个问题吗?在谷歌chrome中

我正在开发一个应用程序,用户可以在HTML5画布上绘制欧几里得结构。因此,我不能真正限制某些形状的大小。当检查屏幕上绘制的非常大的圆时,我注意到非常大的圆没有恒定的半径

更具体地说,由两个点(一个中心点和一个指定半径的点)定义的圆不再通过半径点

逐渐变大的圆圈。这些都应该通过E点

在45度=PI/4的倍数上不会出现错误。在这些倍数之间误差最大(例如PI/8)

以下是包含上述第一个示例的JSFIDLE:


我的问题:为什么会发生这种情况?有什么办法(有效地)解决这个问题吗?

在谷歌chrome中,我可以重复这个问题,但在IE 9和IE 10中,一切都很好

所以我猜Chrome的实现是错误的。这可能是一个舍入误差,或者他们使用插值方法来避免不太准确的正弦和余弦

请看这里:


我能想象的唯一解决办法是用自己的代码或使用(jQuery?)插件来绘制圆。

这可能是一个浮点截断错误。可能是因为正弦和余弦没有给出完全准确的值。你可以通过旋转画布而不是旋转弧线来绕过它(至少是镀铬的)

ctx.save();          // Save the canvas so we can rotate back.
ctx.translate(x, y); // Translate to the origin point.
ctx.rotate(alpha);   // Rotate the proper angle.

ctx.arc(0, 0, 3, 0, Math.PI*2); // Draw the small circle at the origin.
ctx.fill();

ctx.arc(r, 0, r, 0, Math.PI*2); // Create a big with the origin 1 radius away.
ctx.restore();                  // Restore the canvas to the original orientation
                                // before drawing.  Otherwise the circle looks bad.
ctx.strokeStyle = "black";
ctx.stroke();                   // Draw!

我非常喜欢操纵画布而不是形状。它为您提供了一个更符合逻辑的工作领域。请参见

我完全解决这个问题的方法是使用贝塞尔曲线实现圆绘制近似。在这里可以找到一篇详细介绍实现的文章


仅使用这四个分段,我就能够比内置的google chrome canvas实现更好地逼近一个圆。

只是将其抛在一边,但如果没有指定足够的圆周率数字,这会是一个问题吗?每当我做这样的事情时,我往往会有点过火,使用大约10位数的圆周率。

在MacOS X 10.7.2上的Chrome 16.0.912.63上,小提琴中的圆圈会接触,但不会通过所需的点。有趣的是,我在Chrome 16.0.912.63 Windows 7上。这个问题也发生在Linux上的Chrome上。在FirefoxWindows7上,同样的错误也会发生,但要小一个数量级(只有当r=100000时才明显)。在IE 9上,误差更小(在r=1 000 000时明显)。所有这些测试都是用alpha=PI/8Wow进行的,真是太酷了!然而,这并不能完全解决我的问题。我需要圆在任何地方都“完美”,而不仅仅是某个任意点。圆应该在任何地方都完美。问题可能不是圆的半径,而是
Math.sin
Math.cos
的数学不精确性在乘以一个大常数时被夸大了。也就是说,使用原始方法放置任何点都会有问题,因此如果在x+2*cos(a),y+2*sin(a)处放置第二个点,它将不会对齐。对于真正精确的图形,您需要在旋转的画布上绘制所有图形。问题是,
Math.cos
Math.sin
由V8中的一些泰勒级数实现。出于优化目的,这些泰勒级数的阶数不是很高,因此在绘制非常大的圆时会出现错误。这比仅绘制圆的默认arc()方法要好得多。我用这个替换了CanvasRenderingContext2D.prototype.arc,它修复了各种奇怪的瑕疵和故障。
function magic_circle(ctx, x, y, r){
  m = 0.551784

  ctx.save()
  ctx.translate(x, y)
  ctx.scale(r, r)

  ctx.beginPath()
  ctx.moveTo(1, 0)
  ctx.bezierCurveTo(1,  -m,  m, -1,  0, -1)
  ctx.bezierCurveTo(-m, -1, -1, -m, -1,  0)
  ctx.bezierCurveTo(-1,  m, -m,  1,  0,  1)
  ctx.bezierCurveTo( m,  1,  1,  m,  1,  0)
  ctx.closePath()
  ctx.restore()
}