简体   繁体   中英

How to draw triangle pointers inside of circle

I realize this is a simple Trigonometry question, but my high school is failing me right now.

Given an angle, that I have converted into radians to get the first point. How do I figure the next two points of the triangle to draw on the canvas, so as to make a small triangle always point outwards to the circle. So lets say Ive drawn a circle of a given radius already. Now I want a function to plot a triangle that sits on the edge of the circle inside of it, that points outwards no matter the angle. (follows the edge, so to speak)

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);


}

Example在此处输入图像描述

reduce the radius, change the angle and call again 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);
}

the resulting triangle's size is proportional to the size of the circle.


in case you need an equilateral, fixed size triangle, use this:

在此处输入图像描述

//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;
...

You don't say what type of triangle you want to draw so I suppose that it is an equilateral triangle.

Take a look at this image (credit here )

在此处输入图像描述

I will call 3 points p1, p2, p3 from top right to bottom right, counterclockwise.

You can easily calculate the coordinate of three points of the triangle in the coordinate system with the origin is coincident with the triangle's centroid.

Given a point belongs to the edge of the circle and the point p1 that we just calculated, we can calculate parameters of the translation from our main coordinate system to the triangle's coordinate system. Then, we just have to translate the coordinate of two other points back to our main coordinate system. That is (x1,y1) and (x2,y2).

You can take a look at the demo below that is based on your code.

 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM