跳蚤分形任务的递归解决方案



我正在尝试解决"Eric S. Roberts (1986)递归思考"一书中的任务 9.3。让我们考虑我们有简单的三角形:

              .
             / 
            /   
           /     
          /       
         /         
        /           
       /             
      /               
     /                 
    /                   
   /                     
  /_______________________

较小的跳蚤放在形成大跳蚤背面的两个部分中的每个部分上,可以进行下一阶段:

              .
             / 
            /   
           /     
 _________/       _________
        /                /
       /                /
      /                /
     /                /
     /                 
    /                   
   /                     
  /_______________________

这两种新跳蚤中的每一个都容纳了两只较小的跳蚤,它们为我们提供了以下动物园:

              .
             / 
            /   
     .     /          .
 ___/____/       ___/____
        /                /
  :     /                :
 /_   /                /_
     /                /
     /                 
    /                   
   /                     
  /_______________________

问题是我无法弄清楚这里的递归模式。我什至不知道我应该如何开始考虑这项任务以找到解决方案。

对于绘图,我使用3个函数:

  1. setPointer(x, y) -- 将笔设置为坐标 x,y
  2. vector(dx,dy) -- 从 x, y 到 dx, dy 画线
  3. polarVec(l, angle) 从 x, y 绘制线,长度 l 按角度(以度为单位)

我在画布上绘画的课程:

        var X_CENTER = 400;
        var Y_CENTER = 400;
        function DrawLib() {
            var canvas = document.getElementById("myCanvas");
            var ctx = canvas.getContext("2d");
            var inverted_y = 800; 
            var _dx = 0, _dy = 800;
            this.setPoint = function (x, y) {
                inverted_y = 800;
                inverted_y -= y;
                _dx = x;
                _dy = inverted_y;
                ctx.moveTo(x, inverted_y);
            };
            this.vector = function(dx, dy) {
                _dx += dx;
                _dy -= dy;
                ctx.lineTo(_dx, _dy); 
            };
            this.polarVec = function(lengthPx, angle) {
                var radians = angle * Math.PI / 180;
                this.vector(lengthPx * Math.cos(radians), lengthPx * Math.sin(radians));
            }
            this.stroke = function () {
                ctx.stroke();
            }
        }
        var drawLib = new DrawLib();

我的解决方案(仅适用于订单 0 和 1):

        function fractLine(order, l, theta) {
            if (order == 0) return drawLib.polarVec(l, theta);
            fractLine(order - 1, 2 * l/3,theta);
            fractLine(order - 1, l/3,theta - 120);
            fractLine(order - 1, l/3,theta + 120);
            fractLine(order - 1,  2* l/3,theta);
        }
        function triangleWithFleas(order, l) {
            //left side of triangle
            drawLib.setPoint(X_CENTER - l/2, Y_CENTER - Math.sqrt(3)* l/4);
            //start drawing
            drawLib.vector(l,0);
            fractLine(order, l, 120);
            fractLine(order, l, 240);
            drawLib.stroke();
        }
        triangleWithFleas(1, 400);

根据@jxh评论,我需要一个函数,从特定起点以特定方向绘制三角形。然后,它应该递归调用自己两次,调整每次调用的方向和起点。

我已经更新了我的代码。 triangle绘制三角形,showFlake调用triangle后递归绘制跳蚤三角形。

现在它完美运行。

var X_CENTER = 400;
    var Y_CENTER = 400;
    function DrawLib() {
        var canvas = document.getElementById("myCanvas");
        var ctx = canvas.getContext("2d");
        var inverted_y = 800; 
        var _dx = 0, _dy = 800;
        this.setPoint = function (x, y) {
            inverted_y = 800;
            inverted_y -= y;
            _dx = x;
            _dy = inverted_y;
            ctx.moveTo(x, inverted_y);
        };
        this.vector = function(dx, dy) {
            _dx += dx;
            _dy -= dy;
            ctx.lineTo(_dx, _dy);
            return {
                x: _dx,
                y: 800 - _dy // coord inversion
            };
        };
        this.polarVec = function(lengthPx, angle, color) {
            var radians = angle * Math.PI / 180;
            return this.vector(lengthPx * Math.cos(radians), lengthPx * Math.sin(radians));
        }
        this.stroke = function () {
            ctx.stroke();
        }
    }
    var drawLib = new DrawLib();

    function triangle(x, y, l, theta) {
        drawLib.setPoint(x, y);
        drawLib.polarVec(l, theta);
        var firstAngle = theta + 120;
        var secondAngle = theta + 240;
        var firstTrianleStartPoint = drawLib.polarVec(2 * l / 3, firstAngle);
        drawLib.polarVec( l / 3, firstAngle);
        var secondTrianleStartPoint = drawLib.polarVec(2 * l / 3, secondAngle);
        drawLib.polarVec(l / 3, secondAngle);
         return {
            x1: firstTrianleStartPoint.x,
            y1: firstTrianleStartPoint.y,
            x2: secondTrianleStartPoint.x,
            y2: secondTrianleStartPoint.y,
        }
    }
    function showFlake(order, x, y, l, theta) {
        if(order === 0) return;
        var coords = triangle(x, y, l, theta);
        showFlake(order - 1, coords.x1, coords.y1, l / 3, theta + -60);
        showFlake(order - 1, coords.x2, coords.y2, l / 3, theta + 60);
    }
    var len = 600
    var x = X_CENTER - len / 2;
    var y = Y_CENTER - Math.sqrt(3) * len / 4;
    showFlake(5, x, y, len, 0);
    drawLib.stroke();

最新更新