Как нарисовать треугольные указатели внутри круга - PullRequest
0 голосов
/ 04 апреля 2020

Я понимаю, что это простой вопрос тригонометрии, но моя средняя школа подводит меня прямо сейчас.

Учитывая угол, который я преобразовал в радианы, чтобы получить первую точку. Как изобразить следующие две точки треугольника для рисования на холсте, чтобы маленький треугольник всегда указывал наружу на круг. Допустим, я уже нарисовал круг заданного радиуса. Теперь я хочу, чтобы функция построила треугольник, который находится на краю круга внутри него, который указывает наружу, независимо от угла. (следует за краем, так сказать)

function drawPointerTriangle(ctx, angle){
    var radians = angle * (Math.PI/180)
    var startX = this.radius + this.radius/1.34 * Math.cos(radians)
    var startY = this.radius - this.radius/1.34 * Math.sin(radians)
    // This gives me my starting point on the outer edge of the circle, plotted at the angle I need    
    ctx.moveTo(startX, startY);

   // HOW DO I THEN CALCULATE x1,y1 and x2, y2.  So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);


}

Пример enter image description here

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

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

Посмотрите на это изображение (кредит здесь )

enter image description here

Я назову 3 точки p1, p2, p3 сверху вниз справа налево против часовой стрелки.

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

Учитывая, что точка принадлежит краю окружности и точке p1, которую мы только что рассчитали, мы можем вычислить параметры перевод из нашей основной системы координат в систему координат треугольника. Затем нам просто нужно перевести координаты двух других точек обратно в нашу основную систему координат. Это (x1, y1) и (x2, y2).

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

const w = 300;
const h = 300;

function calculateTrianglePoints(angle, width) {
  let r = width / Math.sqrt(3);
  let firstPoint = [
    r * Math.cos(angle),
    r * Math.sin(angle),
  ]

  let secondPoint = [
    r * Math.cos(angle + 2 * Math.PI / 3),
    r * Math.sin(angle + 2 * Math.PI / 3),
  ]

  let thirdPoint = [
    r * Math.cos(angle + 4 * Math.PI / 3),
    r * Math.sin(angle + 4 * Math.PI / 3),
  ]

  return [firstPoint, secondPoint, thirdPoint]
}

const radius = 100
const triangleWidth = 20;

function drawPointerTriangle(ctx, angle) {
  var radians = angle * (Math.PI / 180)
  var startX = radius * Math.cos(radians)
  var startY = radius * Math.sin(radians)
  var [pt0, pt1, pt2] = calculateTrianglePoints(radians, triangleWidth);
  var delta = [
    startX - pt0[0],
    startY - pt0[1],
  ]

  pt1[0] = pt1[0] + delta[0]
  pt1[1] = pt1[1] + delta[1]
  pt2[0] = pt2[0] + delta[0]
  pt2[1] = pt2[1] + delta[1]
  ctx.beginPath();
  // This gives me my starting point on the outer edge of the circle, plotted at the angle I need    
  ctx.moveTo(startX, startY);

  [x1, y1] = pt1;
  [x2, y2] = pt2;
  // HOW DO I THEN CALCULATE x1,y1 and x2, y2.  So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
  ctx.lineTo(x1, y1);
  ctx.lineTo(x2, y2);
  ctx.closePath();
  ctx.fillStyle = '#FF0000';
  ctx.fill();
}

function drawCircle(ctx, radius) {
  ctx.beginPath();
  ctx.arc(0, 0, radius, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.fillStyle = '#000';
  ctx.fill();
}

function clear(ctx) {
  ctx.fillStyle = '#fff';
  ctx.fillRect(-w / 2, -h / 2, w, h);
}

function normalizeAngle(pointCoordinate, angle) {
  const [x, y] = pointCoordinate;
  if (x > 0 && y > 0) return angle;
  else if (x > 0 && y < 0) return 360 + angle;
  else if (x < 0 && y < 0) return 180 - angle;
  else if (x < 0 && y > 0) return 180 - angle;
}

function getAngleFromPoint(point) {
  const [x, y] = point;
  if (x == 0 && y == 0) return 0;
  else if (x == 0) return 90 * (y > 0 ? 1 : -1);
  else if (y == 0) return 180 * (x >= 0 ? 0: 1);
  const radians = Math.asin(y / Math.sqrt(
    x ** 2 + y ** 2
  ))

  return normalizeAngle(point, radians / (Math.PI / 180))
}

document.addEventListener('DOMContentLoaded', function() {
  const canvas = document.querySelector('canvas');
  const angleText = document.querySelector('.angle');
  const ctx = canvas.getContext('2d');
  ctx.translate(w / 2, h / 2);
  drawCircle(ctx, radius);
  drawPointerTriangle(ctx, 0);
  canvas.addEventListener('mousemove', _.throttle(function(ev) {
    let mouseCoordinate = [
      ev.clientX - w / 2,
      ev.clientY - h / 2
    ]
    
    let degAngle = getAngleFromPoint(mouseCoordinate)

    clear(ctx);
    drawCircle(ctx, radius);
    drawPointerTriangle(ctx, degAngle)
    angleText.innerText = Math.floor((360 - degAngle)*100)/100;
  }, 15))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
<canvas width=300 height=300></canvas>
<div class="angle">0</div>
1 голос
/ 04 апреля 2020

уменьшить радиус, изменить угол и снова вызвать cos / sin:

function drawPointerTriangle(ctx, angle)
{
    var radians = angle * (Math.PI/180);
    var radius = this.radius/1.34;
    var startX = this.center.x + radius * Math.cos(radians);
    var startY = this.center.y + radius * Math.sin(radians);

    ctx.moveTo(startX, startY);

    radius  *= 0.9;
    radians += 0.1;
    var x1  = this.center.x + radius * Math.cos(radians);
    var y1  = this.center.y + radius * Math.sin(radians);

    radians -= 0.2;
    var x1  = this.center.x + radius * Math.cos(radians);
    var y1  = this.center.y + radius * Math.sin(radians);

    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.lineTo(startX, startY);
}

размер полученного треугольника пропорционален размеру круга.


в случае вам нужен равносторонний треугольник фиксированного размера, используйте это:

enter image description here

//get h by pythagoras
h = sqrt( a^2 - (a/2)^2 );)
//get phi using arcustangens:
phi = atan( a/2, radius-h );
//reduced radius h by pythagoras:
radius = sqrt( (radius-h)^2 + (a/2)^2 );

radians += phi;
...
radians -= 2*phi;
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...