Подтвердить что ты не робот

Как рисовать круг на холсте?

Я использую javascript и холст, чтобы нарисовать математически разработанную шкалу (для измерения крутящего момента, он включает в себя Ньютон-метры и фунты). Естественно, я позиционировал свои тики, используя тригонометрию, и рисование линий дуги с использованием arc. Проблема возникла, когда им нужно было выстраиваться в линию, но было странное искажение. Затем я рисовал очень большой круг и сравнивал его с круговым выбором в GIMP, и было искажение. Круги согласуются каждые 45 градусов вокруг кругов, но между этими узлами холст, нарисованный кругом, отклоняется наружу, подобно восьмиугольнику, который может быть закруглен слишком далеко наружу, чтобы приблизить круг.

Почему происходят эти искажения? Как я могу нарисовать по кругу круг по кругу?

Это код, который я использовал для генерации искаженного круга.

<!DOCTYPE html>
<html>
  <body>
    <canvas width=8000 height=8000 id='myCanvas'></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      context.beginPath();
      context.arc(4000, 4000, 3200, 0, Math.PI*2, false);
      context.lineWidth = 1;
      context.strokeStyle = '#ff0000';
      context.lineCap = 'square';
      context.stroke();
    </script>
  </body>
</html>

Это может быть не минимально, я не знаю о релевантности context.lineCap, но это остаток кода, на котором он основан. На следующем скриншоте показана разница между кружком, нарисованным GIMP, и кругом, нарисованным в Chrome screenshot

4b9b3361

Ответ 1

Это Chromium Bug # 164241 (объявлено исправлено, хотя исправление еще не показало его). Короткий ответ: Chrome приближает круги с композитными кривыми Безье.

Мне не удалось воспроизвести это на Chromium (43.0.2357.130, Ubuntu), но это происходит на Firefox 39, хотя я не смог найти подобный отчет об ошибках для Firefox. Тот факт, что он исправляет каждые 90 градусов (не 45, по крайней мере, не для меня), указывает на то, что круги аппроксимируются 4 кривыми, так как конечные точки кривой гарантированно будут правильными.

К счастью, существует простой способ: создать путь, состоящий из более чем 4 кривых. 8 или даже 6 должно быть достаточно для радиусов, которые вы используете, но вы можете использовать больше, если хотите играть в безопасное место. Или вы можете увеличить число кривых в зависимости от радиуса, хотя вычисление оптимальной функции (минимальное n, которое будет производить точный круг для заданного радиуса r), нетривиально.

context.beginPath();
var n=8; // 4 is the default behaviour. higher is better, also slower
for (var i=0; i<n; i++) {
    context.arc(4000, 4000, 3200, Math.PI*2*i/n, Math.PI*2*(i+1)/n, false);
}
context.stroke();

См. также этот вопрос.

(И да, lineCap - красная селедка.)