I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

Sierpinski curve

From Rosetta Code
Sierpinski curve is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.


Task

Produce a graphical or ASCII-art representation of a Sierpinski curve of at least order 3.

AutoHotkey[edit]

Translation of: Go

Requires Gdip Library

SierpinskiW	:= 500
SierpinskiH := 500
level := 5
cx := SierpinskiW/2
cy := SierpinskiH
h := cx / (2**(level+1))
Arr := []
squareCurve(level)
xmin := xmax := ymin := ymax := 0
for i, point in Arr
{
xmin := A_Index = 1 ? point.x : xmin < point.x ? xmin : point.x
xmax := point.x > xmax ? point.x : xmax
ymin := A_Index = 1 ? point.y : ymin < point.y ? ymin : point.y
ymax := point.y > ymax ? point.y : ymax
}
SierpinskiX := A_ScreenWidth/2 - (xmax-xmin)/2 , SierpinskiY := A_ScreenHeight/2 - (ymax-ymin)/2
for i, point in Arr
points .= point.x - xmin + SierpinskiX "," point.y - ymin + SierpinskiY "|"
points := Trim(points, "|")
gdip1()
Gdip_DrawLines(G, pPen, Points)
UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
return
 
; ---------------------------------------------------------------
lineTo(newX, newY) {
global
Arr[Arr.count()+1, "x"] := newX-SierpinskiW/2+h
Arr[Arr.count() , "y"] := SierpinskiH-newY+2*h
cx := newX
cy := newY
}
; ---------------------------------------------------------------
sierN(level) {
global
if (level = 1) {
lineTo(cx+h, cy-h) ; lineNE()
lineTo(cx, cy-2*h) ; lineN()
lineTo(cx-h, cy-h) ; lineNW()
}
else{
sierN(level - 1)
lineTo(cx+h, cy-h) ; lineNE()
sierE(level - 1)
lineTo(cx, cy-2*h) ; lineN()
sierW(level - 1)
lineTo(cx-h, cy-h) ; lineNW()
sierN(level - 1)
}
}
; ---------------------------------------------------------------
sierE(level) {
global
if (level = 1) {
lineTo(cx+h, cy+h) ; lineSE()
lineTo(cx+2*h, cy) ; lineE()
lineTo(cx+h, cy-h) ; lineNE()
}
else {
sierE(level - 1)
lineTo(cx+h, cy+h) ; lineSE()
sierS(level - 1)
lineTo(cx+2*h, cy) ; lineE()
sierN(level - 1)
lineTo(cx+h, cy-h) ; lineNE()
sierE(level - 1)
}
}
; ---------------------------------------------------------------
sierS(level) {
global
if (level = 1) {
lineTo(cx-h, cy+h) ; lineSW()
lineTo(cx, cy+2*h) ; lineS()
lineTo(cx+h, cy+h) ; lineSE()
}
else {
sierS(level - 1)
lineTo(cx-h, cy+h) ; lineSW()
sierW(level - 1)
lineTo(cx, cy+2*h) ; lineS()
sierE(level - 1)
lineTo(cx+h, cy+h) ; lineSE()
sierS(level - 1)
}
}
; ---------------------------------------------------------------
sierW(level) {
global
if (level = 1) {
lineTo(cx-h, cy-h) ; lineNW()
lineTo(cx-2*h, cy) ; lineW()
lineTo(cx-h, cy+h) ; lineSW()
}
else {
sierW(level - 1)
lineTo(cx-h, cy-h) ; lineNW()
sierN(level - 1)
lineTo(cx-2*h, cy) ; lineW()
sierS(level - 1)
lineTo(cx-h, cy+h) ; lineSW()
sierW(level - 1)
}
}
; ---------------------------------------------------------------
squareCurve(level) {
global
sierN(level)
lineTo(cx+h, cy-h) ; lineNE()
sierE(level)
lineTo(cx+h, cy+h) ; lineSE()
sierS(level)
lineTo(cx-h, cy+h) ; lineSW()
sierW(level)
lineTo(cx-h, cy-h) ; lineNW()
lineTo(cx+h, cy-h) ; lineNE()
}
 
; ---------------------------------------------------------------
gdip1(){
global
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
OnExit, Exit
Width := A_ScreenWidth, Height := A_ScreenHeight
Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
Gui, 1: Show, NA
hwnd1 := WinExist()
hbm := CreateDIBSection(Width, Height)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_SetSmoothingMode(G, 4)
pPen := Gdip_CreatePen(0xFFFF0000, 2)
}
; ---------------------------------------------------------------
gdip2(){
global
Gdip_DeleteBrush(pBrush)
Gdip_DeletePen(pPen)
SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(G)
}
; ---------------------------------------------------------------
Exit:
gdip2()
Gdip_Shutdown(pToken)
ExitApp
Return
 

C++[edit]

Output is a file in SVG format. The curve is generated using the Lindenmayer system method.

// See https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve#Representation_as_Lindenmayer_system
#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
 
std::string rewrite(const std::string& s) {
std::string t;
for (char c : s) {
if (c == 'X')
t += "XF+G+XF--F--XF+G+X";
else
t += c;
}
return t;
}
 
void line(std::ostream& out, double& x, double& y, double length, int angle) {
constexpr double pi = 3.14159265359;
double theta = (pi * angle)/180.0;
x += length * std::cos(theta);
y -= length * std::sin(theta);
out << 'L' << x << ',' << y << '\n';
}
 
void execute(std::ostream& out, const std::string& s, double x, double y,
double length, int angle) {
out << 'M' << x << ',' << y << '\n';
for (char c : s) {
if (c == 'F' || c == 'G')
line(out, x, y, length, angle);
else if (c == '+')
angle = (angle + 45) % 360;
else if (c == '-')
angle = (angle - 45) % 360;
}
}
 
int main() {
const int size = 545;
const int order = 5;
const double x = 5, y = 10, length = 7;
std::ofstream out("sierpinski_curve.svg");
if (!out) {
std::cerr << "Cannot open output file\n";
return 1;
}
out << "<svg xmlns='http://www.w3.org/2000/svg' width='"
<< size << "' height='" << size << "'>\n";
out << "<rect width='100%' height='100%' fill='white'/>\n";
out << "<path stroke-width='1' stroke='black' fill='none' d='";
std::string s = "F--XF--F--XF";
for (int i = 0; i < order; ++i)
s = rewrite(s);
execute(out, s, x, y, length, 45);
out << "'/>\n</svg>\n";
return 0;
}
Output:

See: sierpinski_curve.svg (offsite SVG image)

Factor[edit]

Works with: Factor version 0.99 2020-08-14
USING: accessors kernel L-system sequences ui ;
 
: curve ( L-system -- L-system )
L-parser-dialect
{ "G" [ dup length>> draw-forward ] } suffix >>commands
[ 45 >>angle ] >>turtle-values
"F--XF--F--XF" >>axiom
{
{ "X" "XF+G+XF--F--XF+G+X" }
} >>rules ;
 
[ <L-system> curve "Sierpinski curve" open-window ] with-ui


When using the L-system visualizer, the following controls apply:

Camera controls
Button Command
a zoom in
z zoom out
left arrow turn left
right arrow turn right
up arrow pitch down
down arrow pitch up
q roll left
w roll right
Other controls
Button Command
x iterate L-system

Go[edit]

Library: Go Graphics
Translation of: Phix

A partial translation anyway which produces a static image of a SC of level 5, yellow on blue, which can be viewed with a utility such as EOG.

package main
 
import (
"github.com/fogleman/gg"
"math"
)
 
var (
width = 770.0
height = 770.0
dc = gg.NewContext(int(width), int(height))
)
 
var cx, cy, h float64
 
func lineTo(newX, newY float64) {
dc.LineTo(newX-width/2+h, height-newY+2*h)
cx, cy = newX, newY
}
 
func lineN() { lineTo(cx, cy-2*h) }
func lineS() { lineTo(cx, cy+2*h) }
func lineE() { lineTo(cx+2*h, cy) }
func lineW() { lineTo(cx-2*h, cy) }
 
func lineNW() { lineTo(cx-h, cy-h) }
func lineNE() { lineTo(cx+h, cy-h) }
func lineSE() { lineTo(cx+h, cy+h) }
func lineSW() { lineTo(cx-h, cy+h) }
 
func sierN(level int) {
if level == 1 {
lineNE()
lineN()
lineNW()
} else {
sierN(level - 1)
lineNE()
sierE(level - 1)
lineN()
sierW(level - 1)
lineNW()
sierN(level - 1)
}
}
 
func sierE(level int) {
if level == 1 {
lineSE()
lineE()
lineNE()
} else {
sierE(level - 1)
lineSE()
sierS(level - 1)
lineE()
sierN(level - 1)
lineNE()
sierE(level - 1)
}
}
 
func sierS(level int) {
if level == 1 {
lineSW()
lineS()
lineSE()
} else {
sierS(level - 1)
lineSW()
sierW(level - 1)
lineS()
sierE(level - 1)
lineSE()
sierS(level - 1)
}
}
 
func sierW(level int) {
if level == 1 {
lineNW()
lineW()
lineSW()
} else {
sierW(level - 1)
lineNW()
sierN(level - 1)
lineW()
sierS(level - 1)
lineSW()
sierW(level - 1)
}
}
 
func squareCurve(level int) {
sierN(level)
lineNE()
sierE(level)
lineSE()
sierS(level)
lineSW()
sierW(level)
lineNW()
lineNE() // needed to close the square in the top left hand corner
}
 
func main() {
dc.SetRGB(0, 0, 1) // blue background
dc.Clear()
level := 5
cx, cy = width/2, height
h = cx / math.Pow(2, float64(level+1))
squareCurve(level)
dc.SetRGB255(255, 255, 0) // yellow curve
dc.SetLineWidth(2)
dc.Stroke()
dc.SavePNG("sierpinski_curve.png")
}

Java[edit]

Translation of: C++
import java.io.*;
 
public class SierpinskiCurve {
public static void main(final String[] args) {
try (Writer writer = new BufferedWriter(new FileWriter("sierpinski_curve.svg"))) {
SierpinskiCurve s = new SierpinskiCurve(writer);
s.currentAngle = 45;
s.currentX = 5;
s.currentY = 10;
s.lineLength = 7;
s.begin(545);
s.execute(rewrite(5));
s.end();
} catch (final Exception ex) {
ex.printStackTrace();
}
}
 
private SierpinskiCurve(final Writer writer) {
this.writer = writer;
}
 
private void begin(final int size) throws IOException {
write("<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>\n", size, size);
write("<rect width='100%%' height='100%%' fill='white'/>\n");
write("<path stroke-width='1' stroke='black' fill='none' d='");
}
 
private void end() throws IOException {
write("'/>\n</svg>\n");
}
 
private void execute(final String s) throws IOException {
write("M%g,%g\n", currentX, currentY);
for (int i = 0, n = s.length(); i < n; ++i) {
switch (s.charAt(i)) {
case 'F':
case 'G':
line(lineLength);
break;
case '+':
turn(ANGLE);
break;
case '-':
turn(-ANGLE);
break;
}
}
}
 
private void line(final double length) throws IOException {
final double theta = (Math.PI * currentAngle) / 180.0;
currentX += length * Math.cos(theta);
currentY -= length * Math.sin(theta);
write("L%g,%g\n", currentX, currentY);
}
 
private void turn(final int angle) {
currentAngle = (currentAngle + angle) % 360;
}
 
private void write(final String format, final Object... args) throws IOException {
writer.write(String.format(format, args));
}
 
private static String rewrite(final int order) {
String s = AXIOM;
for (int i = 0; i < order; ++i) {
final StringBuilder sb = new StringBuilder();
for (int j = 0, n = s.length(); j < n; ++j) {
final char ch = s.charAt(j);
if (ch == 'X')
sb.append(PRODUCTION);
else
sb.append(ch);
}
s = sb.toString();
}
return s;
}
 
private final Writer writer;
private double lineLength;
private double currentX;
private double currentY;
private int currentAngle;
 
private static final String AXIOM = "F--XF--F--XF";
private static final String PRODUCTION = "XF+G+XF--F--XF+G+X";
private static final int ANGLE = 45;
}
Output:

See: sierpinski_curve.svg (offsite SVG image)

Julia[edit]

Turtle procedural (lineto) version[edit]

Modified from Craft of Coding blog, Processing version

using Luxor
 
function sierpinski_curve(x0, y0, h, level)
x1, y1 = x0, y0
lineto(x, y) = begin line(Point(x1, y1), Point(x, y), :stroke); x1, y1 = x, y end
lineN() = lineto(x1,y1-2*h)
lineS() = lineto(x1,y1+2*h)
lineE() = lineto(x1+2*h,y1)
lineW() = lineto(x1-2*h,y1)
lineNW() = lineto(x1-h,y1-h)
lineNE() = lineto(x1+h,y1-h)
lineSE() = lineto(x1+h,y1+h)
lineSW() = lineto(x1-h,y1+h)
function drawN(i)
if i == 1
lineNE(); lineN(); lineNW()
else
drawN(i-1); lineNE(); drawE(i-1); lineN(); drawW(i-1); lineNW(); drawN(i-1)
end
end
function drawE(i)
if i == 1
lineSE(); lineE(); lineNE()
else
drawE(i-1); lineSE(); drawS(i-1); lineE(); drawN(i-1); lineNE(); drawE(i-1)
end
end
function drawS(i)
if i == 1
lineSW(); lineS(); lineSE()
else
drawS(i-1); lineSW(); drawW(i-1); lineS(); drawE(i-1); lineSE(); drawS(i-1)
end
end
function drawW(i)
if i == 1
lineNW(); lineW(); lineSW()
else
drawW(i-1); lineNW(); drawN(i-1); lineW(); drawS(i-1); lineSW(); drawW(i-1)
end
end
function draw_curve(levl)
drawN(levl); lineNE(); drawE(levl); lineSE()
drawS(levl); lineSW(); drawW(levl); lineNW()
end
draw_curve(level)
end
 
Drawing(800, 800)
sierpinski_curve(10, 790, 3, 6)
finish()
preview()
 

LSystem version[edit]

using Lindenmayer # https://github.com/cormullion/Lindenmayer.jl
 
sierpcurve = LSystem(Dict("X" => "XF+G+XF--F--XF+G+X"), "F--XF--F--XF")
 
drawLSystem(sierpcurve,
forward = 10,
turn = 45,
startingpen= (0.2, 0.8, 0.8),
startingx = -380,
startingy = 380,
startingorientation = π/4,
iterations = 5,
filename = "sierpinski_curve.png",
showpreview = true
)
 

Perl[edit]

use strict;
use warnings;
use SVG;
use List::Util qw(max min);
 
use constant pi => 2 * atan2(1, 0);
 
my $rule = 'XF+F+XF--F--XF+F+X';
my $S = 'F--F--XF--F--XF';
$S =~ s/X/$rule/g for 1..5;
 
my (@X, @Y);
my ($x, $y) = (0, 0);
my $theta = pi/4;
my $r = 6;
 
for (split //, $S) {
if (/F/) {
push @X, sprintf "%.0f", $x;
push @Y, sprintf "%.0f", $y;
$x += $r * cos($theta);
$y += $r * sin($theta);
}
elsif (/\+/) { $theta += pi/4; }
elsif (/\-/) { $theta -= pi/4; }
}
 
my ($xrng, $yrng) = ( max(@X) - min(@X), max(@Y) - min(@Y));
my ($xt, $yt) = (-min(@X) + 10, -min(@Y) + 10);
 
my $svg = SVG->new(width=>$xrng+20, height=>$yrng+20);
my $points = $svg->get_path(x=>\@X, y=>\@Y, -type=>'polyline');
$svg->rect(width=>"100%", height=>"100%", style=>{'fill'=>'black'});
$svg->polyline(%$points, style=>{'stroke'=>'orange', 'stroke-width'=>1}, transform=>"translate($xt,$yt)");
 
open my $fh, '>', 'sierpinski-curve.svg';
print $fh $svg->xmlify(-namespace=>'svg');
close $fh;

See: sierpinski-curve.svg (offsite SVG image)

Phix[edit]

Library: Phix/pGUI
-- demo\rosetta\Sierpinski_curve.exw
--
-- Draws curves lo to hi (simultaneously), initially {1,1}, max {8,8}
-- Press +/- to change hi, shift +/- to change lo.
-- ("=_" are also mapped to "+-", for the non-numpad +/-)
--
include pGUI.e
 
Ihandle dlg, canvas
cdCanvas cddbuffer, cdcanvas
 
integer width, height,
lo = 1, hi = 1
atom cx, cy, h
 
procedure lineTo(atom newX, newY)
cdCanvasVertex(cddbuffer, newX-width/2+h, height-newY+2*h)
cx = newX
cy = newY
end procedure
 
procedure lineN() lineTo(cx,cy-2*h) end procedure
procedure lineS() lineTo(cx,cy+2*h) end procedure
procedure lineE() lineTo(cx+2*h,cy) end procedure
procedure lineW() lineTo(cx-2*h,cy) end procedure
 
procedure lineNW() lineTo(cx-h,cy-h) end procedure
procedure lineNE() lineTo(cx+h,cy-h) end procedure
procedure lineSE() lineTo(cx+h,cy+h) end procedure
procedure lineSW() lineTo(cx-h,cy+h) end procedure
 
procedure sierN(integer level)
if level=1 then
lineNE() lineN()
lineNW()
else
sierN(level-1) lineNE()
sierE(level-1) lineN()
sierW(level-1) lineNW()
sierN(level-1)
end if
end procedure
 
procedure sierE(integer level)
if level=1 then
lineSE() lineE()
lineNE()
else
sierE(level-1) lineSE()
sierS(level-1) lineE()
sierN(level-1) lineNE()
sierE(level-1)
end if
end procedure
 
procedure sierS(integer level)
if level=1 then
lineSW() lineS()
lineSE()
else
sierS(level-1) lineSW()
sierW(level-1) lineS()
sierE(level-1) lineSE()
sierS(level-1)
end if
end procedure
 
procedure sierW(integer level)
if level=1 then
lineNW() lineW()
lineSW()
else
sierW(level-1) lineNW()
sierN(level-1) lineW()
sierS(level-1) lineSW()
sierW(level-1)
end if
end procedure
 
procedure sierpinskiCurve(integer level)
sierN(level) lineNE()
sierE(level) lineSE()
sierS(level) lineSW()
sierW(level) lineNW()
end procedure
 
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
{width, height} = IupGetIntInt(canvas, "DRAWSIZE")
cdCanvasActivate(cddbuffer)
for level=lo to hi do
cx = width/2
cy = height
h = cx/power(2,level+1)
cdCanvasBegin(cddbuffer, CD_CLOSED_LINES)
sierpinskiCurve(level)
cdCanvasEnd(cddbuffer)
end for
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function
 
function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih)
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
cdCanvasSetBackground(cddbuffer, CD_WHITE)
cdCanvasSetForeground(cddbuffer, CD_BLUE)
return IUP_DEFAULT
end function
 
function key_cb(Ihandle /*ih*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
if find(c,"+=-_") then
bool bShift = IupGetInt(NULL,"SHIFTKEY")
if c='+' or c='=' then
if bShift then
lo = min(lo+1,hi)
else
hi = min(8,hi+1)
end if
elsif c='-' or c='_' then
if bShift then
lo = max(1,lo-1)
else
hi = max(lo,hi-1)
end if
end if
IupSetStrAttribute(dlg, "TITLE", "Sierpinski curve (%d..%d)",{lo,hi})
cdCanvasClear(cddbuffer)
IupUpdate(canvas)
end if
return IUP_CONTINUE
end function
 
procedure main()
IupOpen()
 
canvas = IupCanvas(NULL)
IupSetAttribute(canvas, "RASTERSIZE", "770x770")
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
 
dlg = IupDialog(canvas)
IupSetAttribute(dlg, "TITLE", "Sierpinski curve (1..1)")
IupSetCallback(dlg, "K_ANY", Icallback("key_cb"))
 
IupMap(dlg)
IupShowXY(dlg,IUP_CENTER,IUP_CENTER)
IupMainLoop()
IupClose()
end procedure
 
main()

Raku[edit]

(formerly Perl 6)

Works with: Rakudo version 2020.02
use SVG;
 
role Lindenmayer {
has %.rules;
method succ {
self.comb.map( { %!rules{$^c} // $c } ).join but Lindenmayer(%!rules)
}
}
 
my $sierpinski = 'F--XF--F--XF' but Lindenmayer( { X => 'XF+G+XF--F--XF+G+X' } );
 
$sierpinski++ xx 5;
 
my $dim = 640;
my $scale = 8;
my $dir = pi/4;
my @points = (316, -108);
 
for $sierpinski.comb {
state ($x, $y) = @points[0,1];
state $d = 0;
when 'F'|'G' { @points.append: ($x += $scale * $d.cos).round(1), ($y += $scale * $d.sin).round(1) }
when '+' { $d -= $dir }
when '-' { $d += $dir }
default { }
}
 
my $out = './sierpinski-curve-perl6.svg'.IO;
 
$out.spurt: SVG.serialize(
svg => [
:width($dim), :height($dim),
:rect[:width<100%>, :height<100%>, :fill<black>],
:polyline[
:points(@points.join: ','), :fill<black>,
:transform("rotate(45, 320, 320)"), :style<stroke:#F7DF1E>,
],
],
);

See: Sierpinski-curve-perl6.svg (offsite SVG image)

Rust[edit]

Program output is a file in SVG format.

// [dependencies]
// svg = "0.8.0"
 
use svg::node::element::path::Data;
use svg::node::element::Path;
 
struct SierpinskiCurve {
current_x: f64,
current_y: f64,
current_angle: i32,
line_length: f64,
}
 
impl SierpinskiCurve {
fn new(x: f64, y: f64, length: f64, angle: i32) -> SierpinskiCurve {
SierpinskiCurve {
current_x: x,
current_y: y,
current_angle: angle,
line_length: length,
}
}
fn rewrite(order: usize) -> String {
let mut str = String::from("F--XF--F--XF");
for _ in 0..order {
let mut tmp = String::new();
for ch in str.chars() {
match ch {
'X' => tmp.push_str("XF+G+XF--F--XF+G+X"),
_ => tmp.push(ch),
}
}
str = tmp;
}
str
}
fn execute(&mut self, order: usize) -> Path {
let mut data = Data::new().move_to((self.current_x, self.current_y));
for ch in SierpinskiCurve::rewrite(order).chars() {
match ch {
'F' => data = self.draw_line(data),
'G' => data = self.draw_line(data),
'+' => self.turn(45),
'-' => self.turn(-45),
_ => {}
}
}
Path::new()
.set("fill", "none")
.set("stroke", "black")
.set("stroke-width", "1")
.set("d", data)
}
fn draw_line(&mut self, data: Data) -> Data {
let theta = (self.current_angle as f64).to_radians();
self.current_x += self.line_length * theta.cos();
self.current_y -= self.line_length * theta.sin();
data.line_to((self.current_x, self.current_y))
}
fn turn(&mut self, angle: i32) {
self.current_angle = (self.current_angle + angle) % 360;
}
fn save(file: &str, size: usize, order: usize) -> std::io::Result<()> {
use svg::node::element::Rectangle;
let x = 5.0;
let y = 10.0;
let rect = Rectangle::new()
.set("width", "100%")
.set("height", "100%")
.set("fill", "white");
let mut s = SierpinskiCurve::new(x, y, 7.0, 45);
let document = svg::Document::new()
.set("width", size)
.set("height", size)
.add(rect)
.add(s.execute(order));
svg::save(file, &document)
}
}
 
fn main() {
SierpinskiCurve::save("sierpinski_curve.svg", 545, 5).unwrap();
}
Output:

See: sierpinski_curve.svg (offsite SVG image)

Sidef[edit]

Uses the LSystem() class from Hilbert curve.

var rules = Hash(
x => 'xF+G+xF--F--xF+G+x',
)
 
var lsys = LSystem(
width: 550,
height: 550,
 
xoff: -9,
yoff: -271,
 
len: 5,
angle: 45,
color: 'dark green',
)
 
lsys.execute('F--xF--F--xF', 5, "sierpiński_curve.png", rules)

Output image: Sierpiński curve

zkl[edit]

Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

sierpinskiCurve(5) : turtle(_,45,45);	// n=5 --> 11,606 characters
 
fcn sierpinskiCurve(order){
LSystem("F--XF--F--XF",Dictionary("X","XF+G+XF--F--XF+G+X"), order)
}
fcn LSystem(axiom,rules,order){ // Lindenmayer system
buf1,buf2 := Data(Void,axiom).howza(3), Data().howza(3); // characters
do(order){
buf1.pump(buf2.clear(),'wrap(c){ rules.find(c,c) }); // change if rule
t:=buf1; buf1=buf2; buf2=t; // swap buffers
}
buf1
}
 
fcn turtle(curve,angle,startAngle){ // angles in degrees
const D=10.0;
dir:=startAngle;
img,color := PPM(800,800), 0x00ff00; // green on black
x,y := 15, img.h - x;
foreach c in (curve){
switch(c){
case("F","G"){ // draw forward
a,b := D.toRectangular(dir.toFloat().toRad());
img.line(x,y, (x+=a.round()),(y+=b.round()), color)
}
case("+"){ dir=(dir + angle)%360; } // turn left angle
case("-"){ dir=(dir - angle)%360; } // turn right angle
}
}
img.writeJPGFile("sierpinskiCurve.zkl.jpg");
}
Output:

Offsite image at Sierpinski curve order 5