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>";
}




Java: import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.Path2D;
import static java.lang.Math.*;
import java.util.Random;
import javax.swing.*;

public class SierpinskiPentagon extends JPanel {
    
    final double degrees072 = toRadians(72);

    
    final double scaleFactor = 1 / (2 + cos(degrees072) * 2);

    final int margin = 20;
    int limit = 0;
    Random r = new Random();

    public SierpinskiPentagon() {
        setPreferredSize(new Dimension(640, 640));
        setBackground(Color.white);

        new Timer(3000, (ActionEvent e) -> {
            limit++;
            if (limit >= 5)
                limit = 0;
            repaint();
        }).start();
    }

    void drawPentagon(Graphics2D g, double x, double y, double side, int depth) {
        double angle = 3 * degrees072; 

        if (depth == 0) {

            Path2D p = new Path2D.Double();
            p.moveTo(x, y);

            
            for (int i = 0; i < 5; i++) {
                x = x + cos(angle) * side;
                y = y - sin(angle) * side;
                p.lineTo(x, y);
                angle += degrees072;
            }

            g.setColor(RandomHue.next());
            g.fill(p);

        } else {

            side *= scaleFactor;

            
            double distance = side + side * cos(degrees072) * 2;

            
            for (int i = 0; i < 5; i++) {
                x = x + cos(angle) * distance;
                y = y - sin(angle) * distance;
                drawPentagon(g, x, y, side, depth - 1);
                angle += degrees072;
            }
        }
    }

    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        int w = getWidth();
        double radius = w / 2 - 2 * margin;
        double side = radius * sin(PI / 5) * 2;

        drawPentagon(g, w / 2, 3 * margin, side, limit);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("Sierpinski Pentagon");
            f.setResizable(true);
            f.add(new SierpinskiPentagon(), BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}

class RandomHue {
    
    final static double goldenRatioConjugate = (sqrt(5) - 1) / 2;
    private static double hue = Math.random();

    static Color next() {
        hue = (hue + goldenRatioConjugate) % 1;
        return Color.getHSBColor((float) hue, 1, 1);
    }
}