Canvas: Как построить спираль вокруг указанной фиолетовой точки от указанной оранжевой точки до указанной зеленой точки

#javascript #canvas #html5-canvas

#javascript #холст #html5-canvas

Вопрос:

Я пытаюсь нарисовать спираль, начинающуюся от «начальной» точки до «конечной точки». Спираль также имеет заданную центральную точку, поэтому она может рисовать спирали вокруг этой центральной точки. Я не могу заставить это работать, почему-то математика совершенно неправильная. Есть какие-нибудь советы о том, как это решить?

jsfiddle кода, который я пробовал, находится здесь.

 <!DOCTYPE HTML>
<html>
<body>
  <canvas id="myCanvas" width="800" height="600" style="border:1px solid #c3c3c3;"></canvas>

  <script type="text/javascript">
    var c = document.getElementById("myCanvas");
    var cxt = c.getContext("2d");

    //center of the spiral coords:
    var centerX = 400;
    var centerY = 300;

    //draw the center of spiral point:
    drawCirc(centerX, centerY, 10, '#6f0c4f');

    var gap = 8;
    var STEPS_PER_ROTATION = 50;
    var rotations = 4;
    var increment = rotations * Math.PI / STEPS_PER_ROTATION;
    var theta = increment;

    //start point:
    var startX = 500;
    var startY = 380;

    //end point:
    var endX = 600
    var endY = 300;

    //draw the start and end points as small circles:
    drawCirc(startX, startY, 6, '#FF0000');
    drawCirc(endX, endY, 6, '#00FF00');

    //trying to calculate theta start position:
    theta = Math.abs(((centerX - startX) / Math.cos(theta)) / gap);

    var ind = 0;
    while (theta < rotations * Math.PI * 2) {
      var newX = centerX   theta * Math.cos(theta) * gap;
      var newY = centerY   theta * Math.sin(theta) * gap;
      var ukwObj = { x: newX, y: newY };
      if (ind == 0) {
        //draw start point with differnt color to differentiate
        drawCirc(newX, newY, 2, 'orange');
      } else {
        drawCirc(newX, newY);
      }
      ind  ;
      theta = theta   increment;
    }

    function drawCirc(x, y, radius = 2, stroke = '#000000') {
      cxt.beginPath();
      cxt.arc(x, y, radius, 0, 2 * Math.PI);
      cxt.strokeStyle = stroke;
      cxt.stroke();
      cxt.fillStyle = stroke;
      cxt.fill();
    }

    cxt.stroke(); // draw the spiral
  </script>
</body>
</html>  

Комментарии:

1. Можете ли вы добавить изображение того, чего вы хотели бы достичь?

Ответ №1:

Принцип построения окружности таков:
Учитывая центр x,y , радиус r , мы можем построить точки, принадлежащие окружности, вычисляя их координаты следующим образом: px = x r * Math.cos(angle) и py = y r * Math.sin(angle) при изменении угла от 0 до 2* Math.PI .
Если r увеличивается при изменении угла, то мы получаем направленную наружу спираль (от угла 0 до угла 2 * PI, что эквивалентно 0).

Для рассматриваемой задачи нам нужно вычислить начальное и конечное положение спирали в полярных координатах (расстояние, угол).
Итак, нам нужно вычислить начальный угол, начальное расстояние, конечный угол и конечное расстояние и построить каждую точку, постепенно увеличивая как угол, так и расстояние.

Первоначальное вычисление тета было неправильным, я изменил его.

Затем мне нужно было вычислить начальное расстояние между центром и начальной точкой и конечное расстояние между центром и конечной точкой.

Во время вращения вы постепенно переходите от начального расстояния к конечному.

Общее угловое расстояние должно быть totalTheta = numberOfRotation * 2 * Math.PI (endAngle - startAngle) , я заменил rotations * Math.PI * 2 на totalTheta )

Просто для развлечения и чтобы продемонстрировать, что это работает при любых начальных условиях, я немного изменил начальную позицию, конечную позицию и количество оборотов.

Я также уменьшал приращение угла на каждой итерации, чтобы расстояние между каждой точкой выглядело более равномерным, но вы можете прокомментировать, чтобы сохранить постоянную угловую скорость.

Приведенное ниже решение случайным образом выберет оранжевую точку, зеленую точку, количество витков для завершения спирали и построит спираль вокруг фиксированной фиолетовой точки.

     var c = document.getElementById("myCanvas");
    var cxt = c.getContext("2d");

    //center of the spiral coords:
    var centerX = 200;
    var centerY = 150;

    //draw the center of spiral point:
    drawCirc(centerX, centerY, 10, '#6f0c4f');

    var gap = 8;
    var STEPS_PER_ROTATION = 50;
    var rotations = 1   parseInt(Math.random() * 5, 10);
    var increment = rotations * Math.PI / STEPS_PER_ROTATION;
    var theta = increment;
    var dist = 0;

    //start point:
    var startX = centerX   (Math.random() * 150 - 75);
    var startY = centerY   (Math.random() * 150 - 75);
    var startAngleOffset = startX > centerX ? (startY > centerY ? 0 : 0) : (startY > centerY ? Math.PI : Math.PI);
    var startAngleSign = startX > centerX ? (startY > centerY ? 1 : -1) : (startY > centerY ? -1 : 1);

    //end point:
    var endX = centerX   (Math.random() * 150 - 75);
    var endY = centerY   (Math.random() * 150 - 75);
    var endAngleOffset = endX > centerX ? (endY > centerY ? 0 : 0) : (endY > centerY ? Math.PI : Math.PI);
    var endAngleSign = endX > centerX ? (endY > centerY ? 1 : -1) : (endY > centerY ? -1 : 1);

    //draw the start and end points as small circles:
    drawCirc(startX, startY, 6, '#FF0000');
    drawCirc(endX, endY, 6, '#00FF00');

    var startTheta = theta = startAngleOffset   startAngleSign * Math.atan(Math.abs(startY - centerY)/Math.abs(startX - centerX));

    var endTheta = endAngleOffset   endAngleSign * Math.atan(Math.abs(endY - centerY)/Math.abs(endX - centerX));

    var totalTheta = rotations * 2 * Math.PI   (endTheta - startTheta)
    dist = Math.sqrt(Math.pow(startY - centerY, 2)   Math.pow(startX - centerX, 2));

    finalDist = Math.sqrt(Math.pow(endY - centerY, 2)   Math.pow(endX - centerX, 2));
    var ind = 0;
    while (theta -startTheta < totalTheta) {
      var currentDist = (dist   ((finalDist - dist)* ((theta - startTheta) / (totalTheta))));
      var newX = centerX   currentDist * Math.cos(theta);
      var newY = centerY   currentDist * Math.sin(theta);
      var ukwObj = { x: newX, y: newY };
      if (ind == 0) {
        //draw start point with differnt color to differentiate
        drawCirc(newX, newY, 2, 'orange');
      } else {
        drawCirc(newX, newY);
      }
      ind  ;
      theta = theta   increment;
      // decrement increment to make the space between points look more regular
      increment = Math.max(0.01, increment - 0.00096);
    }

    function drawCirc(x, y, radius = 2, stroke = '#000000') {
      cxt.beginPath();
      cxt.arc(x, y, radius, 0, 2 * Math.PI);
      cxt.strokeStyle = stroke;
      cxt.stroke();
      cxt.fillStyle = stroke;
      cxt.fill();
    }

    cxt.stroke(); // draw the spiral  
 <!DOCTYPE HTML>
<html>
<body>
  <canvas id="myCanvas" width="800" height="600" style="border:1px solid #c3c3c3;"></canvas>
</body>
</html>  

Комментарии:

1. Это потрясающе! Большое вам спасибо!

2. Иногда происходит сбой кода (блокируется браузер). Возможно, я внес математическую нестабильность, слишком много играя с кодом. Но вы должны быть в состоянии разобраться в этом…

3. Я думаю, что, поскольку начальное значение может стать отрицательным, угол никогда не достигнет конца. измените increment -= 0.00096; на increment = Math.max(0.01, increment - 0.00096) или прокомментируйте эту строку, чтобы исправить.

4. Это была проблема, я добавил исправление к ответу.

5. Изменен ответ, чтобы он работал для ЛЮБОЙ начальной и конечной позиции.