【问题标题】:Fractal Tree - branches not drawn分形树 - 未绘制分支
【发布时间】:2019-01-09 05:26:59
【问题描述】:

目前,我正在尝试通过 IFS(迭代函数系统)绘制对称二叉树:

但结果总是只有分支提示:

我无法弄清楚我做错了什么或错过了什么。

这是 IFS:

这是我的代码:

RenderWindow window(VideoMode(480, 640), "fractals everywhere");
CircleShape point(1);
int chance;
float x, y, w, h, nx, ny, px, py;

void SymmetricBinaryTrees()
{
    float r = 0.57f;
    float o = 0.785f;

    chance = rand() % 3;

    switch (chance)
    {
    case 0:
        nx = r * cos(o) * x + (-1 * r * sin(o) * y);
        ny = r * sin(o) * x + r * cos(o) * y + 1;
        break;
    case 1:
        nx = r * cos(o) * x + r * sin(o) * y;
        ny = -1 * r * sin(o) * x + r * cos(o) * y + 1;
        break;
    case 2:
        nx = x;
        ny = y;
        break;
    }
}

void nextPoint()
{
    SymmetricBinaryTrees();

    x = nx; y = ny;
}

void drawPoint()
{
    px = _map(x, -1.078, 1.078f, 0, w); py = _map(y, 0.f, 2.078f, h, 0); // maps the position accordingly
    point.setPosition(px, py);

    window.draw(point);
}

int main()
{
    srand(time(NULL));

    w = window.getSize().x * 1.f;
    h = window.getSize().y * 1.f;

    x = 0.f; y = 0.f;

    window.setFramerateLimit(60);

    while (window.isOpen())
    {
        Event e;

        while (window.pollEvent(e))
            if (e.type == Event::Closed) window.close();

        for (int i = 1; i <= 500; i++)
        {
            drawPoint();
            nextPoint();
        }

        window.display();
    }
    return 0;
}

This 是我用于编写代码的网站。

如果有人可以帮助我或有任何想法,我将非常感激,谢谢。

【问题讨论】:

  • 代码不应该在x, ynx, ny之间画一条线吗?

标签: c++ graphics iteration sfml fractals


【解决方案1】:

我同意@beyond 的观点,我认为你把事情复杂化了。使用不同的方法会更容易。让我们让事情变得更简单。

使用递归函数,我们可以很容易地理解每一步应该做什么。 假设我们从一个初始点开始,然后在给定长度角度上追踪一条直线,所以我们需要这样的功能:

void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght)

tree 将是我们的行集,它组成了树本身。

我们可以做的第一件事是设置第一个点,这是已知的:

// Add first point
tree.append(sf::Vertex(point, treeColor));

现在我们需要计算下一个点,形成一条线。通过简单的三角函数,我们可以确定这一点:

float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght);  // Caution here! Minus(-) sign because we're drawing upwards

所以我们添加第二个点,然后将树分成 2 个新分支,每个分支都旋转了一定度数:

// Add second point
tree.append(sf::Vertex(nextPoint, treeColor));

// Create sub-tree from 2nd point, rotating +45 degrees (i.e. counterclockwise), reducing lenght of the new branch by 0.6 factor
createTreeRecursive(tree, nextPoint, angle + O, lenght * R);

// Same with the other sub-tree, but rotating -45 (i.e. clockwise)
createTreeRecursive(tree, nextPoint, angle - O, lenght * R);

我们需要递归函数的基本情况,在这种情况下,我选择 3 作为最小长度:

if (lenght < 3)
    // End condition, can be modified
    return;

这必须先检查出来。

所以我们完成了,我们只需要初始调用:

sf::VertexArray createTree(){
    // Our tree will be made out of lines
    sf::VertexArray ret(sf::PrimitiveType::Lines);
    // Initial point at botton-center(250, 450), with a 90 degrees rotation, first branch lenght 200 
    createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
    return ret;
}

结果是:

完整代码

#include <SFML/Graphics.hpp>

const double PI = 3.141592;
const double R = 0.57;  // Reduction factor
const double O = 45;    // Degree rotation each time
sf::Color treeColor = sf::Color::Blue;

void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght){
    if (lenght < 3)
        // End condition, can be modified
        return;

    // Add first point
    tree.append(sf::Vertex(point, treeColor));
    float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
    float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght);  // Caution here! Minus(-) sign because we're drawing upwards
    sf::Vector2f nextPoint(newX, newY);
    // Add second point
    tree.append(sf::Vertex(nextPoint, treeColor));

    // Create sub-tree from 2nd point, rotating +45 degrees (i.e. counterclockwise), reducing lenght of the new branch by 0.6 factor
    createTreeRecursive(tree, nextPoint, angle + O, lenght * R);

    // Same with the other sub-tree, but rotating -45 (i.e. clockwise)
    createTreeRecursive(tree, nextPoint, angle - O, lenght * R);
}

sf::VertexArray createTree(){
    // Our tree will be made out of lines
    sf::VertexArray ret(sf::PrimitiveType::Lines);
    // Initial point at bottom-center(250, 450), with a 90 degrees rotation, first branch lenght 200 
    createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
    return ret;
}

int main()
{
    RenderWindow window({ 500, 500 }, "SFML Tree", Style::Close);

    auto tree = createTree();

    while (window.isOpen())
    {
        for (Event event; window.pollEvent(event);){
            if (event.type == Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(tree);
        window.display();
    }
    return EXIT_SUCCESS;
}

【讨论】:

    【解决方案2】:

    我建议您使用递归函数,该函数 1) 绘制当前分支(作为一条线),然后 2) 从当前分支创建两个新分支。使用全局变量也无济于事。看起来你应该重新考虑你的方法。

    【讨论】:

      【解决方案3】:

      对于 Linux 是:

      #include <SFML/Graphics.hpp>
      #include <cmath>
      
      const double PI = 3.141592;
      const double R = 0.57;
      const double O = 45;
      sf::Color treeColor = sf::Color::Blue;
      
      void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght){
          if (lenght < 3)
      
              return;
      
      
          tree.append(sf::Vertex(point, treeColor));
          float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
          float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght);
          sf::Vector2f nextPoint(newX, newY);
      
          tree.append(sf::Vertex(nextPoint, treeColor));
      
      
          createTreeRecursive(tree, nextPoint, angle + O, lenght * R);
      
      
          createTreeRecursive(tree, nextPoint, angle - O, lenght * R);
      }
      
      sf::VertexArray createTree(){
      
          sf::VertexArray ret(sf::PrimitiveType::Lines);
      
          createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
          return ret;
      }
      
      int main()
      {
          sf::RenderWindow window({ 500, 500 }, "SFML Tree", sf::Style::Close);
      
          auto tree = createTree();
      
          while (window.isOpen())
          {
              for (sf::Event event; window.pollEvent(event);){
                  if (event.type == sf::Event::Closed)
                      window.close();
              }
      
              window.clear();
              window.draw(tree);
              window.display();
          }
          return EXIT_SUCCESS;
      }
      
      

      【讨论】:

        猜你喜欢
        • 2015-06-06
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 2010-11-10
        • 1970-01-01
        • 2021-06-17
        • 1970-01-01
        • 2017-02-12
        相关资源
        最近更新 更多