Какова математика создания звезды в p5js - PullRequest
2 голосов
/ 14 июля 2020

Я делал один из примеров кода с сайта p5 js .org - https://p5js.org/examples/form-star.html. Я понял весь код, кроме следующих строк.

function star(x, y, radius1, radius2, npoints) {
  let angle = TWO_PI / npoints;
  let halfAngle = angle / 2.0;
  beginShape();
  for (let a = 0; a < TWO_PI; a += angle) {
    let sx = x + cos(a) * radius2;
    let sy = y + sin(a) * radius2;
    vertex(sx, sy);
    sx = x + cos(a + halfAngle) * radius1;
    sy = y + sin(a + halfAngle) * radius1;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}

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

Ответы [ 2 ]

3 голосов
/ 14 июля 2020

Мой ответ - это просто дополнительное визуальное объяснение превосходного ответа Лаанселота (+1):

Взгляните на эту диаграмму:

polar-cartesian coordinate conversion

You're probably used to the cartesian coordinates system, where the X axis is the horizontal axis and Y is the vertial axis perpendicular on it, both centering at 0,0.

There's another way to look at the same x,y cartesian location from another point of view.

Imagine line from the centre to a point x,y without the square grid.

If the point was on a clock you could describe that point using the time where let's say the hour points to x,y (is angle towards it) and the clock handle is the distance to x,y.

That's an illustration of viewing the same coordinates in the polar coordinate system, where the coordinates are not x,y but angle and radius (distance from centre to x,y).

On the diagram you can see AB as the point from centre to the cursor. Recall the old trigonometry mnemonic: SOH-CAH-TOA (sin = opposite / hypothenuse, cos = adjacent / hypothenuse).

If we know the angle and radius of a point, we can solve for x,y.

sin(angle) = BC (y) / AB (radius) 

which is the same as

sin(angle) / 1 = y / radius

from which we can extract:

y = sin(angle) * radius

and similarly

cos(angle) = AC (x) / AB (radius) 

which is the same as

cos(angle) / 1 = x / radius

from which we can extract:

x = cos(angle) * radius

hence the polar(angle, radius) to cartesian(x,y) conversion formula:

x = cos(angle) * radius
y = sin(angle) * radius

Bonus points: now you visually get how the dist () функция работает под капотом.

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

AC = mouseX - centerX
BC = mouseY - centerY
dist = sqrt( (AB * AB) + (BC * BC) )

иллюстрация здесь:

let showCartesian = true;
let showPolar = true;

let explanation = "cos(angle) = AC (x) / AB (radius)\n" +
                  "cos(angle) / 1 = x / radius\n" + 
                  "x = cos(angle) * radius\n\n" + 
                  "sin(angle) = BC (y) / AB (radius)\n" + 
                  "sin(angle) / 1 = y / radius\n" +
                  "y = sin(angle) * radius\n\n";
                  
function setup() {
  createCanvas(600, 600);
}

function draw() {
  
  background(255);
  if(showCartesian) drawCartesianGrid(20,20,30);
  if(showPolar) drawPolarGrid(300, 300, 30);
  stroke(0);
  // instructions
  text("press 'c' to toggle cartesian grid\n" + 
       "press 'p' to toggle polar grid\n\n" + explanation, 10, 15);
  
  stroke(0);
  
  // center
  let cx = width * 0.5;
  let cy = height * 0.5;
  // mouse
  let x = mouseX;
  let y = mouseY;
  
  // cartesian to polar conversion (e.g. x,y to angle, radius )
  let angle = atan2(y - cy, x - cx);
  let radius = dist(cx, cy, x, y);
  // polar to cartesian conversion
  let px = cos(angle) * radius;
  let py = sin(angle) * radius;
  
  // visualise triangle
  strokeWeight(3);
  line(cx, cy, x, y);
  strokeWeight(1);
  line(cx, cy, x, cx);
  line(x, cy, x, y);
  text("x = " + nfc(x, 0) + ", y = " + nfc(y, 0), x, y - 12);
  // visualise angle
  noFill();
  arc(cx, cy, radius * 0.25, radius * 0.25, angle < 0 ? angle : 0, angle < 0 ? 0 : angle);
  text("angle: " + nfc(degrees(angle),2), cx + 12, cy - 12);
  // visualise radius / hypothenuse / AB
  push();
    translate(cx, cy);
    rotate(angle);
    text("radius / AB / hypo.: " + nfc(radius, 2), radius * 0.25, -12);
  pop();
  // triangle corner labels
  text("A", cx - 12, cy);
  text("B", x + 12, y);
  text("C", x + 12, cy);
  // visualise cartesian coordinate point (offset from centre = same as x,y)
  stroke(0,192,0);
  ellipse(cx + px, cy + py, 30, 30);
}

function drawCartesianGrid(segsW, segsH, spacing){
  stroke(198);
  for(let y = 0; y < segsH; y++){
    for(let x = 0; x < segsW; x++){
      line(x * spacing, y * spacing,
           (x+1) * spacing, y * spacing);
      line(x * spacing, y * spacing,
           x * spacing, (y+1) * spacing);
    }
  }
}

function drawPolarGrid(x,y,spacing){
  let count = width / spacing;
  let cx = width * 0.5;
  let cy = height * 0.5;
  stroke(192);
  for(let i = 1 ; i <= count; i++){
    ellipse(x, y, (spacing * 2) * i);
  }
  stroke(127);
  line(cx, 0, cx, height);
  line(0, cy, width, cy);
  line(0, 0, width, height);
  line(0, height, width, 0);
}

function keyPressed(){
  if(key == 'c'){
    showCartesian = !showCartesian;
  }
  if(key == 'p'){
    showPolar = !showPolar;
  }
} 

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>

( Примечание в отличие от математического класса, где начало декартовой системы находится в центре с положительной осью Y вверх, в p5. js 0,0 - это верхний левый угол, где y увеличивается вниз. Точно так же обратите внимание на угол от -180 (-PI) до 180 (PI), с направлением вправо, в отличие от диапазона 0, 360 (0 - TWO_PI))

Для удовольствия вы можете закомментировать вершины, нарисованные в функции star(), чтобы понять, какая точка есть какая, как изменяется angle / halfAngle, а также radius1, radius2

Для тщательного изучения вы можете использовать JS Debugger , чтобы установить точку останова на каждом vertex(sx, sy); и посмотреть, как изменится angle/halfAngle.

2 голосов
/ 14 июля 2020

Автор рисует линии. Для этого ему нужны 2 точки.

Чтобы получить координаты этих точек, он «воображает» круг, потому что, если звезда правильная, каждая точка должна находиться на одинаковом расстоянии от середины (отсюда и рисование воображаемый круг вокруг средней точки звезды). Как это:

Imaginary circle

Now, a circle is 360 degrees, or, in radians, 2 * PI. Like this:

Radians

Note that: zero radians is on the right. If you read counter clockwise, you get to 1/2 PI when you're on "top" of the circle, 1 * PI when you're on the left, 1,5 * PI on the bottom and 2 * PI once back on the right side.

By dividing the circle by the amount of points the star has, the author can now use trigonometry to get the coordinates he needs to draw the star:

Тригонометрия!

Это идея. Удачи!

...