Sierpinski pentagon

From Rosetta Code
Task
Sierpinski pentagon
You are encouraged to solve this task according to the task description, using any language you may know.

Produce a graphical or ASCII-art representation of a Sierpinski pentagon (aka a Pentaflake) of order 5. Your code should also be able to correctly generate representations of lower orders: 1 to 4.

See also



C[edit]

The Sierpinski fractals can be generated via the Chaos Game. This implementation thus generalizes the Chaos game C implementation on Rosettacode. As the number of sides increases, the number of iterations must increase dramatically for a well pronounced fractal ( 30000 for a pentagon). This is in keeping with the requirements that the implementation should work for polygons with sides 1 to 4 as well. Requires the WinBGIm library.

 
/*Abhishek Ghosh, 24th September 2017*/
 
#include<graphics.h>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<time.h>
 
#define pi M_PI
 
int main(){
 
time_t t;
double side, **vertices,seedX,seedY,windowSide = 500,sumX=0,sumY=0;
int i,iter,choice,numSides;
 
printf("Enter number of sides : ");
scanf("%d",&numSides);
 
printf("Enter polygon side length : ");
scanf("%lf",&side);
 
printf("Enter number of iterations : ");
scanf("%d",&iter);
 
initwindow(windowSide,windowSide,"Polygon Chaos");
 
vertices = (double**)malloc(numSides*sizeof(double*));
 
for(i=0;i<numSides;i++){
vertices[i] = (double*)malloc(2 * sizeof(double));
 
vertices[i][0] = windowSide/2 + side*cos(i*2*pi/numSides);
vertices[i][1] = windowSide/2 + side*sin(i*2*pi/numSides);
sumX+= vertices[i][0];
sumY+= vertices[i][1];
putpixel(vertices[i][0],vertices[i][1],15);
}
 
srand((unsigned)time(&t));
 
seedX = sumX/numSides;
seedY = sumY/numSides;
 
putpixel(seedX,seedY,15);
 
for(i=0;i<iter;i++){
choice = rand()%numSides;
 
seedX = (seedX + (numSides-2)*vertices[choice][0])/(numSides-1);
seedY = (seedY + (numSides-2)*vertices[choice][1])/(numSides-1);
 
putpixel(seedX,seedY,15);
}
 
free(vertices);
 
getch();
 
closegraph();
 
return 0;
}
 

D[edit]

Translation of: Perl 6
Translation of: Python

This solution combines the turtle graphics concept used in Python, with the SVG output format of the Perl 6 solution. This runs very quickly compared to the Python version.

import std.math;
import std.stdio;
 
/// Convert degrees into radians, as that is the accepted unit for sin/cos etc...
real degrees(real deg) {
immutable tau = 2.0 * PI;
return deg * tau / 360.0;
}
 
immutable part_ratio = 2.0 * cos(72.degrees);
immutable side_ratio = 1.0 / (part_ratio + 2.0);
 
/// Use the provided turtle to draw a pentagon of the specified size
void pentagon(Turtle turtle, real size) {
turtle.right(36.degrees);
turtle.begin_fill();
foreach(i; 0..5) {
turtle.forward(size);
turtle.right(72.degrees);
}
turtle.end_fill();
}
 
/// Draw a sierpinski pentagon of the desired order
void sierpinski(int order, Turtle turtle, real size) {
turtle.setheading(0.0);
auto new_size = size * side_ratio;
 
if (order-- > 1) {
// create four more turtles
foreach(j; 0..4) {
turtle.right(36.degrees);
real small = size * side_ratio / part_ratio;
auto dist = [small, size, size, small][j];
 
auto spawn = new Turtle();
spawn.setposition(turtle.position);
spawn.setheading(turtle.heading);
spawn.forward(dist);
 
// recurse for each spawned turtle
sierpinski(order, spawn, new_size);
}
 
// recurse for the original turtle
sierpinski(order, turtle, new_size);
} else {
// The bottom has been reached for this turtle
pentagon(turtle, size);
}
}
 
/// Run the generation of a P(5) sierpinksi pentagon
void main() {
int order = 5;
real size = 500;
 
auto turtle = new Turtle(size/2, size);
 
// Write the header to an SVG file for the image
writeln(`<?xml version="1.0" standalone="no"?>`);
writeln(`<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"`);
writeln(` "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">`);
writefln(`<svg height="%s" width="%s" style="fill:blue" transform="translate(%s,%s) rotate(-36)"`, size, size, size/2, size/2);
writeln(` version="1.1" xmlns="http://www.w3.org/2000/svg">`);
// Write the close tag when the interior points have been written
scope(success) writeln("</svg>");
 
// Scale the initial turtle so that it stays in the inner pentagon
size *= part_ratio;
 
// Begin rendering
sierpinski(order, turtle, size);
}
 
/// Define a position
struct Point {
real x;
real y;
 
/// When a point is written, do it in the form "x,y " to three decimal places
void toString(scope void delegate(const(char)[]) sink) const {
import std.format;
 
formattedWrite(sink, "%0.3f", x);
sink(",");
formattedWrite(sink, "%0.3f", y);
sink(" ");
}
}
 
/// Mock turtle implementation sufficiant to handle "drawing" the pentagons
class Turtle {
/////////////////////////////////
private:
 
Point pos;
real theta;
bool tracing;
 
/////////////////////////////////
public:
this() {
// empty
}
 
this(real x, real y) {
pos.x = x;
pos.y = y;
}
 
// Get/Set the turtle position
Point position() {
return pos;
}
void setposition(Point pos) {
this.pos = pos;
}
 
// Get/Set the turtle's heading
real heading() {
return theta;
}
void setheading(real angle) {
theta = angle;
}
 
// Move the turtle through space
void forward(real dist) {
// Calculate both components at once for the specified angle
auto delta = dist * expi(theta);
 
pos.x += delta.re;
pos.y += delta.im;
 
if (tracing) {
write(pos);
}
}
 
// Turn the turle
void right(real angle) {
theta = theta - angle;
}
 
// Start/Stop exporting the points of the polygon
void begin_fill() {
write(`<polygon points="`);
tracing = true;
}
void end_fill() {
writeln(`"/>`);
tracing = false;
}
}

Haskell[edit]

For universal solution see Fractal tree#Haskell

import Graphics.Gloss 
 
pentaflake :: Int -> Picture
pentaflake order = iterate transformation pentagon !! order
where
transformation = Scale s s . foldMap copy [0,72..288]
copy a = Rotate a . Translate 0 x
pentagon = Polygon [ (sin a, cos a) | a <- [0,2*pi/5..2*pi] ]
x = 2*cos(pi/5)
s = 1/(1+x)
 
main = display dc white (Color blue $ Scale 300 300 $ pentaflake 5)
where dc = InWindow "Pentaflake" (400, 400) (0, 0)

Explanation: Since Picture forms a monoid with image overlaying as multiplication, so do functions having type Picture -> Picture:

f,g :: Picture -> Picture
f <> g = \p -> f p <> g p 

Function copy for an angle returns transformation, which shifts and rotates given picture, therefore foldMap copy for a list of angles returns a transformation, which shifts and rotates initial image five times. After that the resulting image is scaled to fit the inital size, so that it is ready for next iteration.

If one wants to get all intermediate pentaflakes transformation shoud be changed as follows:

transformation = Scale s s . (Rotate 36 <> foldMap copy [0,72..288])

See also the implementation using Diagrams

Java[edit]

Sierpinski pentagon java.png
Works with: Java version 8
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 {
// exterior angle
final double degrees072 = toRadians(72);
 
/* After scaling we'll have 2 sides plus a gap occupying the length
of a side before scaling. The gap is the base of an isosceles triangle
with a base angle of 72 degrees. */

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; // starting angle
 
if (depth == 0) {
 
Path2D p = new Path2D.Double();
p.moveTo(x, y);
 
// draw from the top
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;
 
/* Starting at the top of the highest pentagon, calculate
the top vertices of the other pentagons by taking the
length of the scaled side plus the length of the gap. */

double distance = side + side * cos(degrees072) * 2;
 
/* The top positions form a virtual pentagon of their own,
so simply move from one to the other by changing direction. */

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 {
/* Try to avoid random color values clumping together */
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);
}
}

JavaScript[edit]

Notes
  • I didn't try to, but got the first of 2 possible versions according to WP N-flake article. Mine has central pentagon. All others here got second version.
  • This one looks a little bit differently from the 1st version on WP. Almost like 2nd version, but with central pentagon.
  • Not a Durer's pentagon either.
File:Pentaflakejs.png
Output Pentaflakejs.png


 
<html>
<head>
<script type="application/x-javascript">
// Globals
var cvs, ctx, scale=500, p0, ord=0, clr='blue', jc=0;
var clrs=['blue','navy','green','darkgreen','red','brown','yellow','cyan'];
 
function p5f() {
cvs = document.getElementById("cvsid");
ctx = cvs.getContext("2d");
cvs.onclick=iter;
pInit(); //init plot
}
 
function iter() {
if(ord>5) {resetf(0)};
ctx.clearRect(0,0,cvs.width,cvs.height);
p0.forEach(iter5);
p0.forEach(pIter5);
ord++; document.getElementById("p1id").innerHTML=ord;
}
 
function iter5(v, i, a) {
if(typeof(v[0][0]) == "object") {a[i].forEach(iter5)}
else {a[i] = meta5(v)}
}
 
function pIter5(v, i, a) {
if(typeof(v[0][0]) == "object") {v.forEach(pIter5)}
else {pPoly(v)}
}
 
function pInit() {
p0 = [make5([.5,.5], .5)];
pPoly(p0[0]);
}
 
function meta5(h) {
c=h[0]; p1=c; p2=h[1]; z1=p1[0]-p2[0]; z2=p1[1]-p2[1];
dist = Math.sqrt(z1*z1 + z2*z2)/2.65;
nP=[];
for(k=1; k<h.length; k++) {
p1=h[k]; p2=c; a=Math.atan2(p2[1]-p1[1], p2[0]-p1[0]);
nP[k] = make5(ppad(a, dist, h[k]), dist)
}
nP[0]=make5(c, dist);
return nP;
}
 
function make5(c, r) {
vs=[]; j = 1;
for(i=1/10; i<2; i+=2/5) {
vs[j]=ppad(i*Math.PI, r, c); j++;
}
vs[0] = c; return vs;
}
 
function pPoly(s) {
ctx.beginPath();
ctx.moveTo(s[1][0]*scale, s[1][1]*-scale+scale);
for(i=2; i<s.length; i++)
ctx.lineTo(s[i][0]*scale, s[i][1]*-scale+scale);
ctx.fillStyle=clr; ctx.fill()
}
 
// a - angle, d - distance, p - point
function ppad(a, d, p) {
x=p[0]; y=p[1];
x2=d*Math.cos(a)+x; y2=d*Math.sin(a)+y;
return [x2,y2]
}
 
function resetf(rord) {
ctx.clearRect(0,0,cvs.width,cvs.height);
ord=rord; jc++; if(jc>7){jc=0}; clr=clrs[jc];
document.getElementById("p1id").innerHTML=ord;
p5f();
}
</script>
</head>
<body onload="p5f()" style="font-family: arial, helvatica, sans-serif;">
<b>Click Pentaflake to iterate.</b>&nbsp; Order: <label id='p1id'>0</label>&nbsp;&nbsp;
<input type="submit" value="RESET" onclick="resetf(0);">&nbsp;&nbsp;
(Reset anytime: to start new Pentaflake and change color.)
<br /><br />
<canvas id="cvsid" width=640 height=640></canvas>
</body>
</html>
 
Output:
Page with Pentaflakejs.png
Clicking Pentaflake you can see orders 1-6 of it in different colors.

Kotlin[edit]

Translation of: Java
// version 1.1.2
 
import java.awt.*
import java.awt.geom.Path2D
import java.util.Random
import javax.swing.*
 
class SierpinskiPentagon : JPanel() {
// exterior angle
private val degrees072 = Math.toRadians(72.0)
 
/* After scaling we'll have 2 sides plus a gap occupying the length
of a side before scaling. The gap is the base of an isosceles triangle
with a base angle of 72 degrees. */

private val scaleFactor = 1.0 / (2.0 + Math.cos(degrees072) * 2.0)
 
private val margin = 20
private var limit = 0
private val r = Random()
 
init {
preferredSize = Dimension(640, 640)
background = Color.white
Timer(3000) {
limit++
if (limit >= 5) limit = 0
repaint()
}.start()
}
 
private fun drawPentagon(g: Graphics2D, x: Double, y: Double, s: Double, depth: Int) {
var angle = 3.0 * degrees072 // starting angle
var xx = x
var yy = y
var side = s
if (depth == 0) {
val p = Path2D.Double()
p.moveTo(xx, yy)
 
// draw from the top
for (i in 0 until 5) {
xx += Math.cos(angle) * side
yy -= Math.sin(angle) * side
p.lineTo(xx, yy)
angle += degrees072
}
 
g.color = RandomHue.next()
g.fill(p)
}
else {
side *= scaleFactor
/* Starting at the top of the highest pentagon, calculate
the top vertices of the other pentagons by taking the
length of the scaled side plus the length of the gap. */

val distance = side + side * Math.cos(degrees072) * 2.0
 
/* The top positions form a virtual pentagon of their own,
so simply move from one to the other by changing direction. */

for (i in 0 until 5) {
xx += Math.cos(angle) * distance
yy -= Math.sin(angle) * distance
drawPentagon(g, xx, yy, side, depth - 1)
angle += degrees072
}
}
}
 
override fun paintComponent(gg: Graphics) {
super.paintComponent(gg)
val g = gg as Graphics2D
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
val hw = width / 2
val radius = hw - 2.0 * margin
val side = radius * Math.sin(Math.PI / 5.0) * 2.0
drawPentagon(g, hw.toDouble(), 3.0 * margin, side, limit)
}
 
private class RandomHue {
/* Try to avoid random color values clumping together */
companion object {
val goldenRatioConjugate = (Math.sqrt(5.0) - 1.0) / 2.0
var hue = Math.random()
 
fun next(): Color {
hue = (hue + goldenRatioConjugate) % 1
return Color.getHSBColor(hue.toFloat(), 1.0f, 1.0f)
}
}
}
}
 
fun main(args: Array<String>) {
SwingUtilities.invokeLater {
val f = JFrame()
f.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
f.title = "Sierpinski Pentagon"
f.isResizable = true
f.add(SierpinskiPentagon(), BorderLayout.CENTER)
f.pack()
f.setLocationRelativeTo(null)
f.isVisible = true
}
}

Mathematica[edit]

pentaFlake[0] = RegularPolygon[5];
pentaFlake[n_] :=
GeometricTransformation[pentaFlake[n - 1],
TranslationTransform /@
CirclePoints[{GoldenRatio^(2 n - 1), Pi/10}, 5]]
 
[email protected][4]
Output:

https://i.imgur.com/rvXvQc0.png

MATLAB[edit]

[x, x0] = deal(exp(1i*(0.5:.4:2.1)*pi));
for k = 1 : 4
x = x(:) + x0 * (1 + sqrt(5)) * (3 + sqrt(5)) ^(k - 1) / 2 ^ k;
end
patch('Faces', reshape(1 : 5 * 5 ^ k, 5, '')', 'Vertices', [real(x(:)) imag(x(:))])
axis image off
Output:

http://i.imgur.com/8ht6HqG.png

Perl 6[edit]

Works with: rakudo version 2016-01

Generate an SVG file to STDOUT. Redirect to a file to capture and display it.

constant order  = 5;
constant $dim = 250;
constant $sides = 5;
constant scaling-factor = ( 3 - 5**.5 ) / 2;
my @orders = ((1 - scaling-factor) * $dim) «*» scaling-factor «**» (^order);
 
INIT say qq:to/STOP/;
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="{$dim*2}" width="{$dim*2}" style="fill:blue" transform="translate($dim,$dim) rotate(-18)"
version="1.1" xmlns="http://www.w3.org/2000/svg">
STOP
END say '</svg>';
 
my @vertices = map { cis( $_ * τ / $sides ) }, ^$sides;
 
for 0 ..^ $sides ** order -> $i {
my $vector = [+] @vertices[$i.base($sides).fmt("%{order}d").comb] «*» @orders;
say pgon ((@orders[*-1] * (1 - scaling-factor)) «*» @vertices «+» $vector)».reals».fmt("%0.3f");
};
 
sub pgon (@q) { qq|<polygon points="{@q}"/>| }
 

See 5th order pentaflake

Python[edit]

Draws the result on a canvas. Runs pretty slowly.

from turtle import *
import math
speed(0) # 0 is the fastest speed. Otherwise, 1 (slow) to 10 (fast)
hideturtle() # hide the default turtle
 
part_ratio = 2 * math.cos(math.radians(72))
side_ratio = 1 / (part_ratio + 2)
 
hide_turtles = True # show/hide turtles as they draw
path_color = "black" # path color
fill_color = "black" # fill color
 
# turtle, size
def pentagon(t, s):
t.color(path_color, fill_color)
t.pendown()
t.right(36)
t.begin_fill()
for i in range(5):
t.forward(s)
t.right(72)
t.end_fill()
 
# iteration, turtle, size
def sierpinski(i, t, s):
t.setheading(0)
new_size = s * side_ratio
 
if i > 1:
i -= 1
 
# create four more turtles
for j in range(4):
t.right(36)
short = s * side_ratio / part_ratio
dist = [short, s, s, short][j]
 
# spawn a turtle
spawn = Turtle()
if hide_turtles:spawn.hideturtle()
spawn.penup()
spawn.setposition(t.position())
spawn.setheading(t.heading())
spawn.forward(dist)
 
# recurse for spawned turtles
sierpinski(i, spawn, new_size)
 
# recurse for parent turtle
sierpinski(i, t, new_size)
 
else:
# draw a pentagon
pentagon(t, s)
# delete turtle
del t
 
def main():
t = Turtle()
t.hideturtle()
t.penup()
screen = t.getscreen()
y = screen.window_height()
t.goto(0, y/2-20)
 
i = 5 # depth. i >= 1
size = 300 # side length
 
# so the spawned turtles move only the distance to an inner pentagon
size *= part_ratio
 
# begin recursion
sierpinski(i, t, size)
 
main()

See online implementation. See completed output.

Racket[edit]

Translation of: Java
#lang racket/base
(require racket/draw pict racket/math racket/class)
 
;; exterior angle
(define 72-degrees (degrees->radians 72))
;; After scaling we'll have 2 sides plus a gap occupying the length
;; of a side before scaling. The gap is the base of an isosceles triangle
;; with a base angle of 72 degrees.
(define scale-factor (/ (+ 2 (* (cos 72-degrees) 2))))
;; Starting at the top of the highest pentagon, calculate
;; the top vertices of the other pentagons by taking the
;; length of the scaled side plus the length of the gap.
(define dist-factor (+ 1 (* (cos 72-degrees) 2)))
 
;; don't use scale, since it scales brushes too (making lines all tiny)
(define (draw-pentagon x y side depth dc)
(let recur ((x x) (y y) (side side) (depth depth))
(cond
[(zero? depth)
(define p (new dc-path%))
(send p move-to x y)
(for/fold ((x x) (y y) (α (* 3 72-degrees))) ((i 5))
(send p line-to x y)
(values (+ x (* side (cos α)))
(- y (* side (sin α)))
(+ α 72-degrees)))
(send p close)
(send dc draw-path p)]
[else
(define side/ (* side scale-factor))
(define dist (* side/ dist-factor))
 ;; The top positions form a virtual pentagon of their own,
 ;; so simply move from one to the other by changing direction.
(for/fold ((x x) (y y) (α (* 3 72-degrees))) ((i 5))
(recur x y side/ (sub1 depth))
(values (+ x (* dist (cos α)))
(- y (* dist (sin α)))
(+ α 72-degrees)))])))
 
(define (dc-draw-pentagon depth w h #:margin (margin 4))
(dc (lambda (dc dx dy)
(define old-brush (send dc get-brush))
(send dc set-brush (make-brush #:style 'transparent))
(draw-pentagon (/ w 2)
(* 3 margin)
(* (- (/ w 2) (* 2 margin))
(sin (/ pi 5)) 2)
depth
dc)
(send dc set-brush old-brush))
w h))
 
(dc-draw-pentagon 1 120 120)
(dc-draw-pentagon 2 120 120)
(dc-draw-pentagon 3 120 120)
(dc-draw-pentagon 4 120 120)
(dc-draw-pentagon 5 640 640)

Sidef[edit]

Translation of: Perl 6

Generates a SVG image to STDOUT. Redirect to a file to capture and display it.

define order = 5
define sides = 5
define dim = 500
define scaling_factor = ((3 - 5**0.5) / 2)
var orders = order.of {|i| ((1-scaling_factor) * dim) * scaling_factor**i }
 
say <<"STOP";
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="#{dim*2}" width="#{dim*2}"
style="fill:blue" transform="translate(#{dim},#{dim}) rotate(-18)"
version="1.1" xmlns="http://www.w3.org/2000/svg">
STOP
 
var vertices = sides.of {|i| Complex(0, i * Number.tau / sides).exp }
 
for i in ^(sides**order) {
var vector = ([vertices["%#{order}d" % i.base(sides) -> chars]] »*« orders «+»)
var points = (vertices »*» orders[-1]*(1-scaling_factor) »+» vector »reals()» «%« '%0.3f')
say ('<polygon points="' + points.join(' ') + '"/>')
}
 
say '</svg>'

zkl[edit]

Translation of: Perl 6
const order=5, sides=5, dim=250, scaleFactor=((3.0 - (5.0).pow(0.5))/2);
const tau=(0.0).pi*2; // 2*pi*r
orders:=order.pump(List,fcn(n){ (1.0 - scaleFactor)*dim*scaleFactor.pow(n) });
 
println(
#<<<
0'|<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="%d" width="%d" style="fill:blue" transform="translate(%d,%d) rotate(-18)"
version="1.1" xmlns="http://www.w3.org/2000/svg">|
#<<<
.fmt(dim*2,dim*2,dim,dim));
 
vertices:=sides.pump(List,fcn(s){ (1.0).toRectangular(tau*s/sides) }); // points on unit circle
vx:=vertices.apply('wrap([(a,b)]v,x){ return(a*x,b*x) }, // scaled points
orders[-1]*(1.0 - scaleFactor));
fmt:="%%0%d.%dB".fmt(sides,order).fmt; //-->%05.5B (leading zeros, 5 places, base 5)
sides.pow(order).pump(Console.println,'wrap(i){
vector:=fmt(i).pump(List,vertices.get) // "00012"-->(vertices[0],..,vertices[2])
.zipWith(fcn([(a,b)]v,x){ return(a*x,b*x) },orders) // ((a,b)...)*x -->((ax,bx)...)
.reduce(fcn(vsum,v){ vsum[0]+=v[0]; vsum[1]+=v[1]; vsum },L(0.0, 0.0)); //-->(x,y)
pgon(vx.apply(fcn([(a,b)]v,c,d){ return(a+c,b+d) },vector.xplode()));
});
println("</svg>"); // 3,131 lines
 
fcn pgon(vertices){ // eg ( ((250,0),(248.595,1.93317),...), len 5
0'|<polygon points="%s"/>|.fmt(
vertices.pump(String,fcn(v){ "%.3f %.3f ".fmt(v.xplode()) }) )
}
Output:

See this image. Displays fine in FireFox, in Chrome, it doesn't appear to be transformed so you only see part of the image.

zkl bbb > sierpinskiPentagon.zkl.svg
$ wc sierpinskiPentagon.zkl.svg 
  3131  37519 314183 sierpinskiPentagon.zkl.svg