Javascript 绘制5点星的算法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14580033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 17:17:08  来源:igfitidea点击:

Algorithm for drawing a 5 point star

javascriptmathcanvas

提问by Luke Haas

I'm currently working on a solution for drawing a standard 5-point star on the canvas using JavaScript. I'm part way there but can't figure it out entirely. I'd appreciate any tips or pointers anyone might have.

我目前正在研究使用 JavaScript 在画布上绘制标准 5 点星的解决方案。我在那里,但无法完全弄清楚。我很感激任何人可能有的任何提示或指示。

回答by Nycholas Weissberg

I made some changes to the code that Chris posted so it would work for me:

我对 Chris 发布的代码进行了一些更改,以便它对我有用:

var alpha = (2 * Math.PI) / 10; 
var radius = 12;
var starXY = [100,100]

canvasCtx.beginPath();

for(var i = 11; i != 0; i--)
{
    var r = radius*(i % 2 + 1)/2;
    var omega = alpha * i;
    canvasCtx.lineTo((r * Math.sin(omega)) + starXY[0], (r * Math.cos(omega)) + starXY[1]);
}
canvasCtx.closePath();
canvasCtx.fillStyle = "#000";
canvasCtx.fill();

Hope it helps...

希望能帮助到你...

回答by Phil H

n point star, points are distributed evenly around a circle. Assume the first point is at 0,r (top), with the circle centred on 0,0, and that we can construct it from a series of triangles rotated by 2π/(2n+1):

n 点星,点均匀分布在一个圆上。假设第一个点在 0,r(顶部),圆以 0,0 为中心,我们可以用旋转 2π/(2n+1) 的一系列三角形来构造它:

5 point star

5分星

Define a rotation function:

定义一个旋转函数:

function rotate2D(vecArr, byRads) {
    var mat = [ [Math.cos(byRads), -Math.sin(byRads)], 
                [Math.sin(byRads), Math.cos(byRads)] ];
    var result = [];
    for(var i=0; i < vecArr.length; ++i) {
        result[i] = [ mat[0][0]*vecArr[i][0] + mat[0][1]*vecArr[i][1],
                      mat[1][0]*vecArr[i][0] + mat[1][1]*vecArr[i][1] ];
    }
    return result;
}

Construct a star by rotating n triangles:

通过旋转 n 个三角形构造一颗星:

function generateStarTriangles(numPoints, r) {
    var triangleBase = r * Math.tan(Math.PI/numPoints);
    var triangle = [ [0,r], [triangleBase/2,0], [-triangleBase/2,0], [0,r] ];
    var result = [];
    for(var i = 0; i < numPoints; ++i) {
       result[i] = rotate2D(triangle, i*(2*Math.PI/numPoints));
    }
    return result;
}

Define a function to draw any given array of polygons:

定义一个函数来绘制任何给定的多边形数组:

function drawObj(ctx, obj, offset, flipVert) {
   var sign=flipVert ? -1 : 1;
   for(var objIdx=0; objIdx < obj.length; ++objIdx) {
      var elem = obj[objIdx];
      ctx.moveTo(elem[0][0] + offset[0], sign*elem[0][1] + offset[1]);
      ctx.beginPath();
      for(var vert=1; vert < elem.length; ++vert) {
        ctx.lineTo(elem[vert][0] + offset[0], sign*elem[vert][1] + offset[1]);
      }
      ctx.fill();
   }
}

Use the above to draw a 5 point star:

使用上面的方法绘制一个 5 点星:

var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
var offset = [canvas.width/2, canvas.height/2];
ctx.fillStyle="#000000";
var penta = generateStarTriangles(5, 200);
drawObj(ctx, penta, offset, true);

See it here http://jsbin.com/oyonos/2/

看这里 http://jsbin.com/oyonos/2/

回答by pbierre

This is a problem where Turtle Geometry makes things simple:

这是 Turtle Geometry 使事情变得简单的问题:

5-point star:

5分星:

repeat 5 times:

重复5次:

fwd 100, right 144, fwd 100, left 72,

前进 100,右 144,前进 100,左 72,

回答by ChrisIPowell

You need to draw the inner bits and a complete circle is 2 * PI radians. In the example below r is the radius of the encompassing circle. Code below is from an open source project (http://github.com/CIPowell/PhyloCanvas)

您需要绘制内部位,一个完整的圆是 2 * PI 弧度。在下面的例子中,r 是包围圆的半径。下面的代码来自一个开源项目(http://github.com/CIPowell/PhyloCanvas

var alpha = (2 * Math.PI) / 10; 
// works out the angle between each vertex (5 external + 5 internal = 10)
var r_point = r * 1.75; // r_point is the radius to the external point

for(var i = 11; i != 0; i--) // or i could = 10 and you could use closePath at the end
{
var ra = i % 2 == 1 ? rb: r;

var omega = alpha * i; //omega is the angle of the current point
    //cx and cy are the center point of the star.
node.canvas.lineTo(cx + (ra * Math.sin(omega)), cy + (ra * Math.cos(omega)));

}

//Store or fill.

NB: This is one of those many ways to skin a cat things, I'm sure someone else has another way of doing it. Also, the reason for the decremental loop rather than the incremental is preformance. i != 0 is more efficient than i < 10 and i-- is more efficient than i++. But performance matters a lot for my code, it might not be so crucial for yours.

注意:这是给猫剥皮的众多方法之一,我相信其他人有另一种方法。此外,递减循环而不是递增循环的原因是性能。i != 0 比 i < 10 更有效,而 i-- 比 i++ 更有效。但是性能对我的代码很重要,对你来说可能不是那么重要。

回答by Fab

I was looking for such an algorithm myself and wondered if I could invent one myself. Turned out not to be too hard. So here is a small function to create stars and polygons, with options to set the number of point, outer radius, and inner radius (the latter does only apply to stars).

我自己也在寻找这样的算法,并想知道我是否可以自己发明一个。原来不是太难。所以这里有一个创建星星和多边形的小函数,有设置点数、外半径和内半径的选项(后者只适用于星星)。

function makeStar(c, s, x, y , p, o, i) {
    var ct = c.getContext('2d');
    var points =  p || 5;
    var outer_radius = o || 100;
    var inner_radius = i || 40;
    var start_x = x || 100;
    var start_y = y || 100;
    var new_outer_RAD, half_new_outer_RAD;
    var RAD_distance = ( 2 * Math.PI / points);  
    var RAD_half_PI = Math.PI /2; 
    var i;
    ct.moveTo(start_x, start_y);
    ct.beginPath();

    for (i=0; i <= points; i++) {
        new_outer_RAD = (i + 1) * RAD_distance;     
        half_new_outer_RAD = new_outer_RAD - (RAD_distance / 2); 

        if (s) {
            ct.lineTo(start_x + Math.round(Math.cos(half_new_outer_RAD - RAD_half_PI) * inner_radius), start_y + Math.round(Math.sin(half_new_outer_RAD - RAD_half_PI) * inner_radius));
        }

        ct.lineTo(start_x + Math.round(Math.cos(new_outer_RAD - RAD_half_PI) * outer_radius), start_y + Math.round(Math.sin(new_outer_RAD - RAD_half_PI) * outer_radius));   

    }

    ct.stroke();
}

var canvas = document.getElementById('canvas');

makeStar(canvas);
makeStar(canvas, true, 120,200, 7, 110, 40);