Java program to generate Sierpinski Triangle (Fractal) of specified resolution using Random algorithm, even in high resolutions ? tested for 40000x40000px with increased Java VM heap size ? -Xmx8g option.

Note that the more steps, the more acurate triangle is represented.
Main.java
import javax.imageio.ImageIO; import java.io.File; // 2018 TheFlyingKeyboard and released under MIT License // theflyingkeyboard.net public class Main { public static void main(String[] args) { SierpinskiTriangle sierpinskiTriangle = new SierpinskiTriangle(); try { ImageIO.write(sierpinskiTriangle.generate(40000, 10000000), "png", new File("SierpinskiTriangle.png")); } catch (Exception e) { e.printStackTrace(); } } }
Point2D.java
// 2018 TheFlyingKeyboard and released under MIT License // theflyingkeyboard.net public class Point2D { private final double x; private final double y; public Point2D(double x, double y) { this.x = x; this.y = y; } public Point2D(Point2D point) { this.x = point.getX(); this.y = point.getY(); } public double getX() { return x; } public double getY() { return y; } }
SierpinskiTriangle.java
import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.util.concurrent.ThreadLocalRandom; // 2018 TheFlyingKeyboard and released under MIT License // theflyingkeyboard.net public class SierpinskiTriangle { private final int foregroundColor; private final int backgroundColor; private int[] imagePixelData; public SierpinskiTriangle() { this.foregroundColor = Color.BLACK.getRGB(); this.backgroundColor = Color.WHITE.getRGB(); } public SierpinskiTriangle(final Color foregroundColor, final Color backgroundColor) { this.foregroundColor = foregroundColor.getRGB(); this.backgroundColor = backgroundColor.getRGB(); } public BufferedImage generate(final int triangleSize, final int steps) { BufferedImage bufferedImage = new BufferedImage(triangleSize, triangleSize, BufferedImage.TYPE_INT_RGB); imagePixelData = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData(); setBackground(triangleSize); int triangleHeight = (int) Math.round(triangleSize * Math.sqrt(3.0d) / 2.0d); Point2D pointA = new Point2D(0, triangleHeight); Point2D pointB = new Point2D(triangleSize / 2, 0); Point2D pointC = new Point2D(triangleSize, triangleHeight); Point2D newPoint = new Point2D(pointA); for (int i = 0; i < steps; ++i) { imagePixelData[(int) (newPoint.getY()) * triangleSize + (int) (newPoint.getX())] = foregroundColor; switch (ThreadLocalRandom.current().nextInt(3)) { case 0: newPoint = middlePoint(newPoint, pointA); break; case 1: newPoint = middlePoint(newPoint, pointB); break; case 2: newPoint = middlePoint(newPoint, pointC); break; } System.out.println(((double) i / steps) * 100.0d + "%"); } return bufferedImage; } private void setBackground(final int triangleSize) { for (int x = 0; x < triangleSize; ++x) { for (int y = 0; y < triangleSize; ++y) { imagePixelData[y * triangleSize + x] = backgroundColor; } } } private Point2D middlePoint(Point2D pointA, Point2D pointB) { return new Point2D((pointA.getX() + pointB.getX()) / 2, (pointA.getY() + pointB.getY()) / 2); } }