使用数组创建蝴蝶曲线

时间:2015-06-28 06:20:55

标签: javascript

我有两个问题,第一个是如何分别访问我的数组中的索引,因为我的[n] [0]的console.log会产生两个值 - x和y。其次,对于蝴蝶曲线https://en.wikipedia.org/wiki/Butterfly_curve_%28transcendental%29,我如何确定t的值?并通过一定的最小值和最大值重申。需要逻辑支持。

到目前为止,这是我的进展。

/*function drawButterFly(n){
    c.beginPath();
    console.log(n[2])
    for (var i = 0; i < n.length; i++){
        if (i === 0) {
            c.moveTo();
        } else {
            c.lineTo();
        }
        c.stroke();

    }

}*/

function butterFly() {
    var r = 5;
    var N = 3;
    var value = [];
    for (var a = 0.2; a < 2*Math.PI; a = a + 0.1){
        value.push(a);
    }

    var t = value[Math.floor(Math.random()*value.length)];
    var cos = r*Math.cos(t)*( (Math.exp(Math.cos(t))) - (2*Math.cos(4*t)) - (Math.sin(t/12)^5) );
    var sin = r*Math.sin(t)*( (Math.exp(Math.cos(t))) - (2*Math.cos(4*t)) - (Math.sin(t/12)^5) );

    var n = [];
    for (var u = 0; u < N; u++){
        var x = sin * -u;
        var y = cos * -u;
        n.push([x,y]);
    }
    drawButterFly(n);
}

4 个答案:

答案 0 :(得分:2)

由于您在array推送n.push([x,y]),因此您可以使用n[0][0]访问第一个元素的x组件,并使用{{1}访问同一元素的y组件}

示例:

n[0][1]

至于var n = []; n.push( ["x", "y"] ); console.log( n[0][0] ); console.log( n[0][1] ); 的有用值 - 在您显示的图像中,您会注意到相同的蝴蝶以不同的大小绘制了几次。要绘制完整的蝴蝶,您需要使用[0..2pi]的t范围。如果要绘制两只蝴蝶,则需要使用范围[0..4pi]。这就是圆圈在同一时期的循环。然而,与圆形不同,每个循环都不会覆盖前一个循环。

这是一个快速而令人讨厌的例子:

t
function byId(id) {
  return document.getElementById(id);
}
window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt) {
  butterFly();
}

function butterFly() {
  var pointArray = [];
  var stepSize = 0.05; // ~125 steps for every 360°
  var upperLimit = 4 * Math.PI;
  var scale = 20;
  for (var t = 0.0; t < upperLimit; t += stepSize) {
    var xVal = Math.sin(t) * ((Math.exp(Math.cos(t))) - (2 * Math.cos(4 * t)) - (Math.pow(Math.sin(t / 12), 5)));
    var yVal = Math.cos(t) * ((Math.exp(Math.cos(t))) - (2 * Math.cos(4 * t)) - (Math.pow(Math.sin(t / 12), 5)));
    pointArray.push([scale * xVal, -scale * yVal]); // -1 value since screen-y direction is opposite direction to cartesian coords y
  }
  drawButterFly(pointArray);
}

function drawButterFly(pointArray) {
  var can = byId('myCan');
  var ctx = can.getContext('2d');
  var originX, originY;
  originX = can.width / 2;
  originY = can.height / 2;

  ctx.beginPath();
  for (var i = 0; i < pointArray.length; i++) {
    if (i === 0) {
      ctx.moveTo(originX + pointArray[i][0], originX + pointArray[i][1]);
    } else {
      ctx.lineTo(originX + pointArray[i][0], originY + pointArray[i][1]);
    }
  }
  ctx.closePath();
  ctx.stroke();
}
canvas {
  border: solid 1px red;
}

答案 1 :(得分:2)

如果我没有弄错的话,蝴蝶曲线是作为一对参数方程给出的,这意味着你增加import pytest exit_code = pytest.main("smoke_test_suite.py") test_failures = bool(exit_code) 以获得曲线上的下一个t点。换句话说,您的代码中(x, y)应该代替t使用u,而t的值范围应为0 .. 24*pi,因为sin(t / 12)的范围是function getPoint(t, S, O) { var cos_t = Math.cos(t); var factor = Math.exp(cos_t) - 2 * Math.cos(4*t) - Math.pow(Math.sin(t/12), 5); return { x: S * Math.sin(t) * factor + O.x, y: S * cos_t * factor + O.y }; } var canvas = document.getElementById("c"); canvas.width = 300; canvas.height = 300; var ctx = canvas.getContext("2d"); // First path ctx.beginPath(); ctx.strokeStyle = 'blue'; var offset = {x:150, y:120}; var scale = 40; var maxT = 24 * Math.PI; var p = getPoint(0, scale, offset); ctx.moveTo(p.x, canvas.height - p.y); for (var t = 0.01; t <= maxT; t += 0.01) { p = getPoint(t, scale, offset); ctx.lineTo(p.x, canvas.height - p.y); } ctx.stroke(); 1}}有其独特的价值观。)

这是一个演示将曲线绘制到画布的版本:

#c {
  border: solid 1px black;
}
<canvas id="c"></canvas>
y = 0

有一点需要注意:画布的顶部是canvas.height - y,因此您需要反转y(即function getPoint(t, S, O) { var cos_t = Math.cos(t); var factor = Math.exp(cos_t) - 2 * Math.cos(4*t) - Math.pow(Math.sin(t/12), 5); return { x: S * Math.sin(t) * factor + O.x, y: S * cos_t * factor + O.y }; } var canvas = document.getElementById("c"); canvas.width = 300; canvas.height = 300; var ctx = canvas.getContext("2d"); var offset = {x:150, y:120}; var scale = 40; var maxT = 24 * Math.PI; var animationID; var started = false; var t = 0; document.getElementById('start').addEventListener('click', function(e) { e.preventDefault(); if (!started) { animationID = requestAnimationFrame(animate); started = true; } }); document.getElementById('pause').addEventListener('click', function(e) { e.preventDefault(); if (started) { cancelAnimationFrame(animationID); started = false; } }); function animate() { animationID = requestAnimationFrame(animate); var p = getPoint(t, scale, offset); if (t === 0) { ctx.beginPath(); ctx.strokeStyle = 'blue'; ctx.moveTo(p.x, canvas.height - p.y); t += 0.01; } else if (t < maxT) { ctx.lineTo(p.x, canvas.height - p.y); ctx.stroke(); t += 0.01; } else { cancelAnimationFrame(animationID); } })以使曲线正确定位。

更新:添加了动画版

根据royhowie的要求,这是一个使用requestAnimationFrame的动画版本:

#c {
  border: solid 1px black;
}
<div>
  <button id="start">Start</button>
  <button id="pause">Pause</button>
</div>
<canvas id="c"></canvas>
public class Draw extends JPanel {

    private static final long serialVersionUID = 1L;

    public Draw(int rx, int ry)
    {

        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            this.setBackground(Color.WHITE);
            g.setColor(Color.BLUE);
            try{
                g.fillRect(rx, ry, 5, 5);
                Thread.sleep(1000);
            }
            catch(InterruptedException ex)
            {
                Thread.currentThread().interrupt();
            }

        }
    }

    public static void main(String[] args) {
        JFrame f = new JFrame("Title");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        for (int i = 1; i < 40; i++) {
            Random r = new Random();
            int rx = r.nextInt(40);
            int ry = r.nextInt(40);

            Draw d = new Draw(rx, ry);
            f.add(d);
            f.setSize(400, 400);
            f.setVisible(true);
        }
    }
}

答案 2 :(得分:1)

问题1

对于任意整数i,请n[i] = [xi, yi]。然后可以通过xin[i][0]通过yi

访问n[i][1]

问题2

对于t的值,我确定您要使用子整数值,因此我建议使用代表图表“分辨率”的常量增量值。

我们称之为dt。另外,我建议您将变量名称从单个字母更改为更具描述性的内容,例如min_tmax_t,而不是n我将调用您的数组{{1 }}

points.

我不确定该函数内部的其他循环是什么,但是如果你需要它,你可以适应上面的模式。

用法示例:function drawButterFly(points){ for (var i = 0, n = points.count; i < n; ++i) { var x = points[i][0]; var y = points[i][1]; ... } } function butterFly(min_t, max_t, dt, r) { var points = []; for (var t = min_t; t < max_t; t+=dt){ var x = r*Math.sin(t)*... var y = r*Math.cos(t)*... points.push([x,y]); } drawButterFly(points, dt); } - &gt; butterFly(0, 10, 0.01, 3)t升级到0,增量为{​​{1}},10

答案 3 :(得分:0)

关于你的第一个问题,用一个对象替换包含xy坐标的多维数组是一个更好的选择。然后,当迭代数组时,您可以检查对象值。

所以而不是:

n.push([x,y]);

你应该这样做:

m.push({
    'xPos' : x,
    'yPos' : y
})

稍后您可以m.xPosm.yPos访问此内容 然后,您可以按对象文字名称访问x和y值。

关于第二个问题:对于蝴蝶曲线的良好伪代码实现,您可以查看Paul Burke网站:http://paulbourke.net/geometry/butterfly/。因此,t就是:

t = i * 24.0 * PI / N;

如您所见t是一个参数值,当迭代数组时,每个步骤都会递增。