Sierpinski curve: Difference between revisions
m (C++ - calculate initial x and y from length) |
(Added Wren) |
||
Line 942:
lsys.execute('F--xF--F--xF', 5, "sierpiński_curve.png", rules)</lang>
Output image: [https://github.com/trizen/rc/blob/master/img/sierpi%C5%84ski_curve-sidef.png Sierpiński curve]
=={{header|Wren}}==
{{trans|Go}}
{{libheader|DOME}}
<lang ecmascript>import "graphics" for Canvas, Color
import "dome" for Window
var PX = 0
var PY = 0
var CX = 0
var CY = 0
var H = 0
class SierpinskiCurve {
construct new(width, height, level, back, fore) {
Window.title = "Sierpinski Curve"
Window.resize(width, height)
Canvas.resize(width, height)
_w = width
_h = height
_l = level
_bc = back
_fc = fore
}
init() {
Canvas.cls(Color.blue)
CX = _w /2
CY = _h
H = CX / 2.pow(_l + 1)
PX = CX - _w/2 + 2*H
PY = _h - CY + 3*H
squareCurve(_l)
}
lineTo(newX, newY) {
Canvas.line(PX, PY, PX = newX - _w/2 + H, PY = _h - newY + 2*H, _fc, 2)
CX = newX
CY = newY
}
lineN() { lineTo(CX, CY - 2*H) }
lineS() { lineTo(CX, CY + 2*H) }
lineE() { lineTo(CX + 2*H, CY) }
lineW() { lineTo(CX - 2*H, CY) }
lineNW() { lineTo(CX - H, CY - H) }
lineNE() { lineTo(CX + H, CY - H) }
lineSE() { lineTo(CX + H, CY + H) }
lineSW() { lineTo(CX - H, CY + H) }
sierN(level) {
if (level == 1) {
lineNE()
lineN()
lineNW()
} else {
sierN(level - 1)
lineNE()
sierE(level - 1)
lineN()
sierW(level - 1)
lineNW()
sierN(level - 1)
}
}
sierE(level) {
if (level == 1) {
lineSE()
lineE()
lineNE()
} else {
sierE(level - 1)
lineSE()
sierS(level - 1)
lineE()
sierN(level - 1)
lineNE()
sierE(level - 1)
}
}
sierS(level) {
if (level == 1) {
lineSW()
lineS()
lineSE()
} else {
sierS(level - 1)
lineSW()
sierW(level - 1)
lineS()
sierE(level - 1)
lineSE()
sierS(level - 1)
}
}
sierW(level) {
if (level == 1) {
lineNW()
lineW()
lineSW()
} else {
sierW(level - 1)
lineNW()
sierN(level - 1)
lineW()
sierS(level - 1)
lineSW()
sierW(level - 1)
}
}
squareCurve(level) {
sierN(level)
lineNE()
sierE(level)
lineSE()
sierS(level)
lineSW()
sierW(level)
lineNW()
lineNE() // needed to close the square in the top left hand corner
}
update() {}
draw(alpha) {}
}
var Game = SierpinskiCurve.new(770, 770, 5, Color.blue, Color.yellow)</lang>
=={{header|zkl}}==
|
Revision as of 16:07, 2 June 2021
- Task
Produce a graphical or ASCII-art representation of a Sierpinski curve of at least order 3.
AutoHotkey
Requires Gdip Library <lang AutoHotkey>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 </lang>
C++
Output is a file in SVG format. The curve is generated using the Lindenmayer system method. <lang cpp>// See https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve#Representation_as_Lindenmayer_system
- include <cmath>
- include <fstream>
- include <iostream>
- include <string>
class sierpinski_curve { public:
void write(std::ostream& out, int size, int length, int order);
private:
static std::string rewrite(const std::string& s); void line(std::ostream& out); void execute(std::ostream& out, const std::string& s); double x_; double y_; int angle_; int length_;
};
void sierpinski_curve::write(std::ostream& out, int size, int length, int order) {
length_ = length; x_ = length/std::sqrt(2.0); y_ = 2 * x_; angle_ = 45; 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); out << "'/>\n</svg>\n";
}
std::string sierpinski_curve::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 sierpinski_curve::line(std::ostream& out) {
double theta = (3.14159265359 * angle_)/180.0; x_ += length_ * std::cos(theta); y_ -= length_ * std::sin(theta); out << " L" << x_ << ',' << y_;
}
void sierpinski_curve::execute(std::ostream& out, const std::string& s) {
out << 'M' << x_ << ',' << y_; for (char c : s) { switch (c) { case 'F': case 'G': line(out); break; case '+': angle_ = (angle_ + 45) % 360; break; case '-': angle_ = (angle_ - 45) % 360; break; } }
}
int main() {
std::ofstream out("sierpinski_curve.svg"); if (!out) { std::cerr << "Cannot open output file\n"; return 1; } sierpinski_curve s; s.write(out, 545, 7, 5); return 0;
}</lang>
- Output:
See: sierpinski_curve.svg (offsite SVG image)
Factor
<lang factor>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</lang>
When using the L-system visualizer, the following controls apply:
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 |
Button | Command |
---|---|
x | iterate L-system |
Go
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. <lang go>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")
}</lang>
Java
<lang java>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;
}</lang>
- Output:
See: sierpinski_curve.svg (offsite SVG image)
Julia
Turtle procedural (lineto) version
Modified from Craft of Coding blog, Processing version <lang Julia>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() </lang>
LSystem version
<lang julia>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
) </lang>
Perl
<lang perl>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;</lang> See: sierpinski-curve.svg (offsite SVG image)
Phix
<lang Phix>-- 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()</lang>
Raku
(formerly Perl 6)
<lang perl6>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>, ], ],
);</lang> See: Sierpinski-curve-perl6.svg (offsite SVG image)
Rust
Program output is a file in SVG format. <lang rust>// [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();
}</lang>
- Output:
See: sierpinski_curve.svg (offsite SVG image)
Sidef
Uses the LSystem() class from Hilbert curve. <lang ruby>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)</lang> Output image: Sierpiński curve
Wren
<lang ecmascript>import "graphics" for Canvas, Color import "dome" for Window
var PX = 0 var PY = 0 var CX = 0 var CY = 0 var H = 0
class SierpinskiCurve {
construct new(width, height, level, back, fore) { Window.title = "Sierpinski Curve" Window.resize(width, height) Canvas.resize(width, height) _w = width _h = height _l = level _bc = back _fc = fore }
init() { Canvas.cls(Color.blue) CX = _w /2 CY = _h H = CX / 2.pow(_l + 1) PX = CX - _w/2 + 2*H PY = _h - CY + 3*H squareCurve(_l) }
lineTo(newX, newY) { Canvas.line(PX, PY, PX = newX - _w/2 + H, PY = _h - newY + 2*H, _fc, 2) CX = newX CY = newY }
lineN() { lineTo(CX, CY - 2*H) } lineS() { lineTo(CX, CY + 2*H) } lineE() { lineTo(CX + 2*H, CY) } lineW() { lineTo(CX - 2*H, CY) }
lineNW() { lineTo(CX - H, CY - H) } lineNE() { lineTo(CX + H, CY - H) } lineSE() { lineTo(CX + H, CY + H) } lineSW() { lineTo(CX - H, CY + H) }
sierN(level) { if (level == 1) { lineNE() lineN() lineNW() } else { sierN(level - 1) lineNE() sierE(level - 1) lineN() sierW(level - 1) lineNW() sierN(level - 1) } } sierE(level) { if (level == 1) { lineSE() lineE() lineNE() } else { sierE(level - 1) lineSE() sierS(level - 1) lineE() sierN(level - 1) lineNE() sierE(level - 1) } } sierS(level) { if (level == 1) { lineSW() lineS() lineSE() } else { sierS(level - 1) lineSW() sierW(level - 1) lineS() sierE(level - 1) lineSE() sierS(level - 1) } } sierW(level) { if (level == 1) { lineNW() lineW() lineSW() } else { sierW(level - 1) lineNW() sierN(level - 1) lineW() sierS(level - 1) lineSW() sierW(level - 1) } }
squareCurve(level) { sierN(level) lineNE() sierE(level) lineSE() sierS(level) lineSW() sierW(level) lineNW() lineNE() // needed to close the square in the top left hand corner }
update() {}
draw(alpha) {}
}
var Game = SierpinskiCurve.new(770, 770, 5, Color.blue, Color.yellow)</lang>
zkl
Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl <lang 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");
}</lang>
- Output:
Offsite image at Sierpinski curve order 5