Task: Sierpinski pentagon


C++: #include <iomanip>
#include <iostream>

#define _USE_MATH_DEFINES
#include <math.h>

constexpr double degrees(double deg) {
    const double tau = 2.0 * M_PI;
    return deg * tau / 360.0;
}

const double part_ratio = 2.0 * cos(degrees(72));
const double side_ratio = 1.0 / (part_ratio + 2.0);


struct Point {
    double x, y;

    friend std::ostream& operator<<(std::ostream& os, const Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    auto f(std::cout.flags());
    os << std::setprecision(3) << std::fixed << p.x << ',' << p.y << ' ';
    std::cout.flags(f);
    return os;
}


struct Turtle {
private:
    Point pos;
    double theta;
    bool tracing;

public:
    Turtle() : theta(0.0), tracing(false) {
        pos.x = 0.0;
        pos.y = 0.0;
    }

    Turtle(double x, double y) : theta(0.0), tracing(false) {
        pos.x = x;
        pos.y = y;
    }

    Point position() {
        return pos;
    }
    void position(const Point& p) {
        pos = p;
    }

    double heading() {
        return theta;
    }
    void heading(double angle) {
        theta = angle;
    }

    
    void forward(double dist) {
        auto dx = dist * cos(theta);
        auto dy = dist * sin(theta);

        pos.x += dx;
        pos.y += dy;

        if (tracing) {
            std::cout << pos;
        }
    }

    
    void right(double angle) {
        theta -= angle;
    }

    
    void begin_fill() {
        if (!tracing) {
            std::cout << "<polygon points=\"";
            tracing = true;
        }
    }
    void end_fill() {
        if (tracing) {
            std::cout << "\"/>\n";
            tracing = false;
        }
    }
};


void pentagon(Turtle& turtle, double size) {
    turtle.right(degrees(36));
    turtle.begin_fill();
    for (size_t i = 0; i < 5; i++) {
        turtle.forward(size);
        turtle.right(degrees(72));
    }
    turtle.end_fill();
}


void sierpinski(int order, Turtle& turtle, double size) {
    turtle.heading(0.0);
    auto new_size = size * side_ratio;

    if (order-- > 1) {
        
        for (size_t j = 0; j < 4; j++) {
            turtle.right(degrees(36));

            double small = size * side_ratio / part_ratio;
            auto distList = { small, size, size, small };
            auto dist = *(distList.begin() + j);

            Turtle spawn{ turtle.position().x, turtle.position().y };
            spawn.heading(turtle.heading());
            spawn.forward(dist);

            
            sierpinski(order, spawn, new_size);
        }

        
        sierpinski(order, turtle, new_size);
    } else {
        
        pentagon(turtle, size);
    }
    if (order > 0) {
        std::cout << '\n';
    }
}


int main() {
    const int order = 5;
    double size = 500;

    Turtle turtle{ size / 2.0, size };

    std::cout << "<?xml version=\"1.0\" standalone=\"no\"?>\n";
    std::cout << "<!DOCTYPE svg PUBLIC \" -
    std::cout << "    \"http:
    std::cout << "<svg height=\"" << size << "\" width=\"" << size << "\" style=\"fill:blue\" transform=\"translate(" << size / 2 << ", " << size / 2 << ") rotate(-36)\"\n";
    std::cout << "    version=\"1.1\" xmlns=\"http:

    size *= part_ratio;
    sierpinski(order, turtle, size);

    std::cout << "</svg>";
}