Sierpinski square curve: Difference between revisions
(Added Rust solution) |
(→{{header|Quackery}}: added link to description of method) |
||
(38 intermediate revisions by 17 users not shown) | |||
Line 1: | Line 1: | ||
{{ |
{{task|Fractals}} |
||
<br/> |
<br/> |
||
;Task |
;Task |
||
Produce a graphical or ASCII-art representation of a [[wp:Sierpiński_curve|Sierpinski square curve]] of at least order 3. |
Produce a graphical or ASCII-art representation of a [[wp:Sierpiński_curve|Sierpinski square curve]] of at least order 3. |
||
=={{header|11l}}== |
|||
{{trans|C++}} |
|||
<syntaxhighlight lang="11l">F sierpinski_square(fname, size, length, order) |
|||
V x = (size - length) / 2 |
|||
V y = Float(length) |
|||
V angle = 0.0 |
|||
V outfile = File(fname, WRITE) |
|||
outfile.write(‘<svg xmlns='http://www.w3.org/2000/svg' width='’size‘' height='’size"'>\n") |
|||
outfile.write("<rect width='100%' height='100%' fill='white'/>\n") |
|||
outfile.write(‘<path stroke-width='1' stroke='black' fill='none' d='’) |
|||
V s = ‘F+XF+F+XF’ |
|||
L 0 .< order |
|||
s = s.replace(‘X’, ‘XF-F+F-XF+F+XF-F+F-X’) |
|||
outfile.write(‘M’x‘,’y) |
|||
L(c) s |
|||
S c |
|||
‘F’ |
|||
x += length * cos(radians(angle)) |
|||
y += length * sin(radians(angle)) |
|||
outfile.write(‘ L’x‘,’y) |
|||
‘+’ |
|||
angle = (angle + 90) % 360 |
|||
‘-’ |
|||
angle = (angle - 90 + 360) % 360 |
|||
outfile.write("'/>\n</svg>\n") |
|||
sierpinski_square(‘sierpinski_square.svg’, 635, 5, 5)</syntaxhighlight> |
|||
{{out}} |
|||
Output is similar to C++. |
|||
=={{header|ALGOL 68}}== |
|||
Generates an SVG file. The SVG generating code is translated from the FreeBASIC sample (which is a translation of the 11l sample which is translated from the C++). Uses the Algol 68 library for L-System related Tasks on Rosetta Code. |
|||
{{libheader|ALGOL 68-l-system}} |
|||
Note: The source of the Algol 68 L-System library is available on a separate page on Rosetta Code - see the above link and follow the link to the Talk (Discussion) page. |
|||
<syntaxhighlight lang="algol68"> |
|||
BEGIN # Sierpinski Square Curve in SVG - SVG generation translated from the # |
|||
# FreeBASIC sample (which is a translation of C++) # |
|||
# uses the RC Algol 68 L-System library for the L-System evaluation & # |
|||
# interpretation # |
|||
PR read "lsystem.incl.a68" PR # include L-System utilities # |
|||
PROC sierpinski square curve = ( STRING fname, INT size, length, order )VOID: |
|||
IF FILE svg file; |
|||
BOOL open error := IF open( svg file, fname, stand out channel ) = 0 |
|||
THEN |
|||
# opened OK - file already exists and # |
|||
# will be overwritten # |
|||
FALSE |
|||
ELSE |
|||
# failed to open the file # |
|||
# - try creating a new file # |
|||
establish( svg file, fname, stand out channel ) /= 0 |
|||
FI; |
|||
open error |
|||
THEN # failed to open the file # |
|||
print( ( "Unable to open ", fname, newline ) ); |
|||
stop |
|||
ELSE # file opened OK # |
|||
REAL x := ( size - length ) / 2; |
|||
REAL y := length; |
|||
INT angle := 0; |
|||
put( svg file, ( "<svg xmlns='http://www.w3.org/2000/svg' width='" |
|||
, whole( size, 0 ), "' height='", whole( size, 0 ), "'>" |
|||
, newline, "<rect width='100%' height='100%' fill='white'/>" |
|||
, newline, "<path stroke-width='1' stroke='black' fill='none' d='" |
|||
, newline, "M", whole( x, 0 ), ",", whole( y, 0 ), newline |
|||
) |
|||
); |
|||
LSYSTEM ssc = ( "F+XF+F+XF" |
|||
, ( "X" -> "XF-F+F-XF+F+XF-F+F-X" |
|||
) |
|||
); |
|||
STRING curve = ssc EVAL order; |
|||
curve INTERPRET ( ( CHAR c )VOID: |
|||
IF c = "F" THEN |
|||
x +:= length * cos( angle * pi / 180 ); |
|||
y +:= length * sin( angle * pi / 180 ); |
|||
put( svg file, ( " L", whole( x, 0 ), ",", whole( y, 0 ), newline ) ) |
|||
ELIF c = "+" THEN |
|||
angle +:= 90 MODAB 360 |
|||
ELIF c = "-" THEN |
|||
angle +:= 270 MODAB 360 |
|||
FI |
|||
); |
|||
put( svg file, ( "'/>", newline, "</svg>", newline ) ); |
|||
close( svg file ) |
|||
FI # sierpinski square # ; |
|||
sierpinski square curve( "sierpinski_square.svg", 635, 5, 5 ) |
|||
END |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
Similar to FreeBasic, 11l, C++, etc. |
|||
=={{header|ALGOL W}}== |
|||
Draws an ASCII art Sierpinski square curve. For orders greater than 6, the value of CANVAS_WIDTH must be increased.<br> |
|||
The resolution of the canvas is, of course fairly small, so for orders > 4, to avoid the curve overwriting itself, the connecting lines between the segments of the curve are made longer. |
|||
<syntaxhighlight lang="algolw"> |
|||
begin % draw a Sierpinski curve using ascii art % |
|||
integer CANVAS_WIDTH; |
|||
CANVAS_WIDTH := 200; |
|||
begin |
|||
% the ascii art canvas and related items % |
|||
string(1) array canvas ( 1 :: CANVAS_WIDTH, 1 :: CANVAS_WIDTH ); |
|||
integer heading, asciiX, asciiY, width, maxX, maxY, minX, minY; |
|||
% draw a line using ascii art - the length is ignored and the heading determines the % |
|||
% character to use % |
|||
% the position is updated % |
|||
procedure drawLine( real value length ) ; |
|||
begin |
|||
% stores the min and max coordinates % |
|||
procedure updateCoordinateRange ; |
|||
begin |
|||
if asciiX > maxX then maxX := asciiX; |
|||
if asciiY > maxY then maxY := asciiY; |
|||
if asciiX < minX then minX := asciiX; |
|||
if asciiY < minY then minY := asciiY |
|||
end updateCoordinateRange ; |
|||
if heading = 0 then begin |
|||
asciiX := asciiX + 1; |
|||
canvas( asciiX, asciiY ) := "_"; |
|||
updateCoordinateRange; |
|||
end |
|||
else if heading = 90 then begin |
|||
updateCoordinateRange; |
|||
canvas( asciiX, asciiY ) := "|"; |
|||
asciiY := asciiY - 1; |
|||
end |
|||
else if heading = 180 then begin |
|||
asciiX := asciiX - 1; |
|||
canvas( asciiX, asciiY ) := "_"; |
|||
updateCoordinateRange; |
|||
end |
|||
else if heading = 270 then begin |
|||
asciiY := asciiY + 1; |
|||
updateCoordinateRange; |
|||
canvas( asciiX - 1, asciiY ) := "|"; |
|||
end if_various_headings |
|||
end drawLine ; |
|||
% changes the heading by the specified angle ( in degrees ) - angle must be +/- 90 % |
|||
% the position is updated, if necessary as the horizontal lines are at the bottom % |
|||
% of a character but the vertical lines are in the middle pf a character % |
|||
procedure turn( integer value angle ) ; |
|||
begin |
|||
integer prevHeading; |
|||
prevHeading := heading; |
|||
heading := heading + angle; |
|||
while heading < 0 do heading := heading + 360; |
|||
heading := heading rem 360; |
|||
if heading = 0 and prevHeading = 270 then asciiX := asciiX - 1 |
|||
else if heading = 90 then begin |
|||
if prevHeading = 180 then asciiX := asciiX - 1 |
|||
else if prevHeading = 0 then asciiX := asciiX + 1 |
|||
end |
|||
else if heading = 180 and prevHeading = 270 then asciiX := asciiX - 1 |
|||
else if heading = 270 and prevHeading = 0 then asciiX := asciiX + 2 |
|||
end turn ; |
|||
% initialises the ascii art canvas % |
|||
procedure initArt ( integer value initHeading ) ; |
|||
begin |
|||
heading := initHeading;; |
|||
asciiX := CANVAS_WIDTH div 2; |
|||
asciiY := asciiX; |
|||
maxX := asciiX; |
|||
maxY := asciiY; |
|||
minX := asciiX; |
|||
minY := asciiY; |
|||
for x := 1 until CANVAS_WIDTH do for y := 1 until CANVAS_WIDTH do canvas( x, y ) := " " |
|||
end initArt ; |
|||
% shows the used parts of the canvas % |
|||
procedure drawArt ; |
|||
begin |
|||
for y := minY until maxY do begin |
|||
write(); |
|||
for x := minX until maxX do writeon( canvas( x, y ) ) |
|||
end for_y ; |
|||
write() |
|||
end drawIArt ; |
|||
% draws a sierpinski square curve of the specified order % |
|||
procedure sierpinskiSquareCurve( integer value order ) ; |
|||
begin |
|||
% draw a line connecting segments % |
|||
procedure extendedLine ; |
|||
if actualOrder > 4 then begin |
|||
% for higher orders, the segments can touch % |
|||
% so space the segments further apart % |
|||
if heading rem 180 = 0 then drawline( 1 ); |
|||
drawline( 1 ); |
|||
drawline( 1 ) |
|||
end extendedLine ; |
|||
% draw a corner of an element of the curve % |
|||
procedure corner ; |
|||
begin |
|||
drawline( 1 ); |
|||
turn( - 90 ); |
|||
drawline( 1 ) |
|||
end corner ; |
|||
% recursively draws a part of a sierpinski square curve % |
|||
procedure subCurve( integer value order; logical value threeSubCurves ) ; |
|||
begin |
|||
corner; |
|||
turn( + 90 ); |
|||
drawline( 1 ); |
|||
if order < 1 then begin |
|||
turn( - 90 ); |
|||
drawline( 1 ); |
|||
turn( - 90 ) |
|||
end |
|||
else begin |
|||
extendedLine;; |
|||
turn( + 90 ); |
|||
curve( order, threeSubCurves ); |
|||
turn( + 90 ); |
|||
extendedLine |
|||
end if_order_lt_1 ; |
|||
drawline( 1 ); |
|||
turn( + 90 ) |
|||
end subCurve; |
|||
% recursively draws a segment of the sierpinski curve % |
|||
procedure curve( integer value order; logical value threeSubCurves ) ; |
|||
begin |
|||
subCurve( if threeSubCurves then order - 1 else 0, not threeSubCurves ); |
|||
subCurve( order - 1, not threeSubCurves ); |
|||
subCurve( if threeSubCurves then order - 1 else 0, not threeSubCurves ); |
|||
corner |
|||
end curve ; |
|||
integer actualOrder; |
|||
actualOrder := order; |
|||
if order = 1 then begin |
|||
for c := 1 until 4 do corner |
|||
end |
|||
else if order = 2 then begin |
|||
for c := 1 until 4 do subCurve( 0, false ) |
|||
end |
|||
else begin |
|||
for c := 1 until 4 do subCurve( ( 2 * order ) - 5, false ) |
|||
end if_order_eq_1__2__ |
|||
end sierpinskiSquareCurve ; |
|||
% draw curves % |
|||
begin |
|||
integer order; |
|||
i_w := 1; s_w := 0; % set output formatting % |
|||
write( "order> " ); |
|||
read( order ); |
|||
write( "Sierpinski curve of order ", order ); |
|||
write( "===========================" ); |
|||
write(); |
|||
initArt( 0 ); |
|||
sierpinskiSquareCurve( order ); |
|||
drawArt |
|||
end |
|||
end |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
order> 4 |
|||
Sierpinski square curve of order 4 |
|||
================================== |
|||
_ |
|||
_| |_ |
|||
_| |_ |
|||
|_ _| |
|||
_ |_ _| _ |
|||
_| |_ _| |_ _| |_ |
|||
_| |_| |_| |_ |
|||
|_ _ _ _| |
|||
_ |_ _| |_ _| |_ _| _ |
|||
_| |_ |_| _| |_ |_| _| |_ |
|||
_| |_ _| |_ _| |_ |
|||
|_ _| |_ _| |_ _| |
|||
_ |_ _| _ |_ _| _ |_ _| _ |
|||
_| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ |
|||
_| |_| |_| |_| |_| |_| |_| |_ |
|||
|_ _ _ _ _ _ _ _| |
|||
|_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |
|||
|_| _| |_ |_| _| |_ |_| _| |_ |_| |
|||
_| |_ _| |_ _| |_ |
|||
|_ _| |_ _| |_ _| |
|||
|_ _| _ |_ _| _ |_ _| |
|||
|_| _| |_ _| |_ _| |_ |_| |
|||
_| |_| |_| |_ |
|||
|_ _ _ _| |
|||
|_ _| |_ _| |_ _| |
|||
|_| _| |_ |_| |
|||
_| |_ |
|||
|_ _| |
|||
|_ _| |
|||
|_| |
|||
</pre> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
Output is a file in SVG format. |
Output is a file in SVG format. |
||
< |
<syntaxhighlight lang="cpp">// See https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve#Representation_as_Lindenmayer_system |
||
#include <cmath> |
#include <cmath> |
||
#include <fstream> |
#include <fstream> |
||
Line 13: | Line 316: | ||
#include <string> |
#include <string> |
||
class sierpinski_square { |
|||
std::string rewrite(const std::string& s) { |
|||
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_square::write(std::ostream& out, int size, int length, int order) { |
|||
length_ = length; |
|||
x_ = (size - length)/2; |
|||
y_ = length; |
|||
angle_ = 0; |
|||
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_square::rewrite(const std::string& s) { |
|||
std::string t; |
std::string t; |
||
for (char c : s) { |
for (char c : s) { |
||
Line 24: | Line 356: | ||
} |
} |
||
void line(std::ostream& out |
void sierpinski_square::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_; |
|||
out << 'L' << x << ',' << y << '\n'; |
|||
} |
} |
||
void execute(std::ostream& out, const std::string& s |
void sierpinski_square::execute(std::ostream& out, const std::string& s) { |
||
out << 'M' << x_ << ',' << y_; |
|||
out << 'M' << x << ',' << y << '\n'; |
|||
for (char c : s) { |
for (char c : s) { |
||
switch (c) { |
|||
case 'F': |
|||
line(out, x, y, length, angle); |
|||
line(out); |
|||
break; |
|||
case '+': |
|||
angle_ = (angle_ + 90) % 360; |
|||
break; |
|||
case '-': |
|||
angle_ = (angle_ - 90) % 360; |
|||
break; |
|||
} |
|||
} |
} |
||
} |
} |
||
int main() { |
int main() { |
||
const int size = 635; |
|||
const int order = 5; |
|||
const double x = 315, y = 630, length = 5; |
|||
std::ofstream out("sierpinski_square.svg"); |
std::ofstream out("sierpinski_square.svg"); |
||
if (!out) { |
if (!out) { |
||
Line 54: | Line 386: | ||
return 1; |
return 1; |
||
} |
} |
||
sierpinski_square s; |
|||
out << "<svg xmlns='http://www.w3.org/2000/svg' width='" |
|||
s.write(out, 635, 5, 5); |
|||
<< 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, 0); |
|||
out << "'/>\n</svg>\n"; |
|||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
|||
[[Media:Sierpinski_square_cpp.svg]] |
|||
=={{header|EasyLang}}== |
|||
[https://easylang.online/show/#cod=jZK9bsMgFIV3nuIIWR2KjOw2HTKw+hkiRR6oQxJUgi1wE+ftq1sbJ3EzdEFwz8f9ObpdaBu4eI1m6ODM2ThI6MG2pwzh25mYbWtIBmDfBjj07UhRBID2GRQ4n57ENBmsR+xDc9QhTrkmfUIsFErE3nR4GzP6udiNBGD3KW5rKDTZgwpQMTUjECjrJfEZjP5C+RCW7NmVZnm5K5KkeNFdskT7X1Uyybrk3C7oS9IHXKH9Ac4fIMcMznpzsbv+iEK+U+DUng2B7B+G2f04Iq/4rdEBQqFpI3Y24JVq3bQradH6Zxp1kgoDMG7Ont9lp4+5oin+cmLBiXtOJmcmL6hrsakEHZzNy6SwBd9w8E2VV6LKJ2K8c9QsbeNquYds6fZHgbLAukApV4z9AA== Run it] |
|||
<syntaxhighlight> |
|||
proc lsysexp level . axiom$ rules$[] . |
|||
for l to level |
|||
an$ = "" |
|||
for c$ in strchars axiom$ |
|||
for i = 1 step 2 to len rules$[] |
|||
if rules$[i] = c$ |
|||
c$ = rules$[i + 1] |
|||
break 1 |
|||
. |
|||
. |
|||
an$ &= c$ |
|||
. |
|||
swap axiom$ an$ |
|||
. |
|||
. |
|||
proc lsysdraw axiom$ x y ang lng . . |
|||
linewidth 0.3 |
|||
move x y |
|||
for c$ in strchars axiom$ |
|||
if c$ = "F" |
|||
x += cos dir * lng |
|||
y += sin dir * lng |
|||
line x y |
|||
elif c$ = "-" |
|||
dir -= ang |
|||
elif c$ = "+" |
|||
dir += ang |
|||
. |
|||
. |
|||
. |
|||
axiom$ = "F+XF+F+XF" |
|||
rules$[] = [ "X" "XF-F+F-XF+F+XF-F+F-X" ] |
|||
lsysexp 4 axiom$ rules$[] |
|||
lsysdraw axiom$ 50 10 90 1.4 |
|||
</syntaxhighlight> |
|||
=={{header|Factor}}== |
|||
{{works with|Factor|0.99 2020-08-14}} |
|||
<syntaxhighlight lang="factor">USING: accessors kernel L-system sequences ui ; |
|||
: square-curve ( L-system -- L-system ) |
|||
L-parser-dialect >>commands |
|||
[ 90 >>angle ] >>turtle-values |
|||
"F+XF+F+XF" >>axiom |
|||
{ |
|||
{ "X" "XF-F+F-XF+F+XF-F+F-X" } |
|||
} >>rules ; |
|||
[ |
|||
<L-system> square-curve |
|||
"Sierpinski square curve" open-window |
|||
] with-ui</syntaxhighlight> |
|||
When using the L-system visualizer, the following controls apply: |
|||
{| class="wikitable" |
|||
|+ 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 |
|||
|} |
|||
{| class="wikitable" |
|||
|+ Other controls |
|||
|- |
|||
! Button !! Command |
|||
|- |
|||
| x || iterate L-system |
|||
|} |
|||
=={{header|FreeBASIC}}== |
|||
{{trans|11l}} |
|||
Output is a file in SVG format. |
|||
<syntaxhighlight lang="vbnet">#define pi 4 * Atn(1) |
|||
Sub sierpinski_square(fname As String, size As Integer, length As Integer, order As Integer) |
|||
Dim As Single x = (size - length) / 2 |
|||
Dim As Single y = length |
|||
Dim As Single angle = 0.0 |
|||
Dim As Integer i, j |
|||
Dim As String t, s = "F+XF+F+XF" |
|||
For i = 1 To order |
|||
t = "" |
|||
For j = 1 To Len(s) |
|||
Select Case Mid(s, j, 1) |
|||
Case "X" |
|||
t += "XF-F+F-XF+F+XF-F+F-X" |
|||
Case Else |
|||
t += Mid(s, j, 1) |
|||
End Select |
|||
Next j |
|||
s = t |
|||
Next i |
|||
Open fname For Output As #1 |
|||
Print #1, "<svg xmlns='http://www.w3.org/2000/svg' width='" ; size ; "' height='" ; size ; "'>" |
|||
Print #1, "<rect width='100%' height='100%' fill='white'/>" |
|||
Print #1, "<path stroke-width='1' stroke='black' fill='none' d='"; |
|||
Print #1, "M" ; x ; "," ; y; |
|||
For i = 1 To Len(s) |
|||
Select Case Mid(s, i, 1) |
|||
Case "F" |
|||
x += length * Cos(angle * pi / 180) |
|||
y += length * Sin(angle * pi / 180) |
|||
Print #1, " L" ; x ; "," ; y; |
|||
Case "+" |
|||
angle = (angle + 90) Mod 360 |
|||
Case "-" |
|||
angle = (angle - 90 + 360) Mod 360 |
|||
End Select |
|||
Next i |
|||
Print #1, "'/>" |
|||
Print #1, "</svg>" |
|||
Close #1 |
|||
End Sub |
|||
sierpinski_square("sierpinski_square.svg", 635, 5, 5) |
|||
Windowtitle "Hit any key to end program"</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Output is similar to C++.</pre> |
|||
=={{header|Fōrmulæ}}== |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/L-system}} |
|||
'''Solution''' |
|||
It can be done using an [[wp:L-system|L-system]]. There are generic functions written in Fōrmulæ to compute an L-system in the page [[L-system#Fōrmulæ | L-system]]. |
|||
The program that creates a Sierpiński's square curve is: |
|||
[[File:Fōrmulæ - L-system - Sierpiński's square curve 01.png]] |
|||
[[File:Fōrmulæ - L-system - Sierpiński's square curve 02.png]] |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
Line 70: | Line 555: | ||
{{libheader|go-lindenmayer}} |
{{libheader|go-lindenmayer}} |
||
The following uses the Lindenmayer system with the appropriate parameters from the Wikipedia article and produces a similar image (apart from the colors, yellow on blue) to the Sidef and zkl entries. |
The following uses the Lindenmayer system with the appropriate parameters from the Wikipedia article and produces a similar image (apart from the colors, yellow on blue) to the Sidef and zkl entries. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 129: | Line 614: | ||
dc.Stroke() |
dc.Stroke() |
||
dc.SavePNG("sierpinski_square_curve.png") |
dc.SavePNG("sierpinski_square_curve.png") |
||
}</ |
}</syntaxhighlight> |
||
=={{header|J}}== |
|||
It looks like there's two different (though similar) concepts implemented here, of what a "Sierpinski square curve" looks like (the wikipedia writeup shows 45 degree angles -- like [[j:File:Sierpinski_curve.png]] but many of the implementations here show only right angles). And, the wikipedia writeup is obtuse about some of the details of the structure. And, we've got some dead links here. So, for now, a quickie ascii art implementation:<syntaxhighlight lang="j"> 1j1#"1' #'{~{{l,(1,~0{.~#y),l=.y,.0,.y}}^:3,.1 |
|||
# # # # # # # # |
|||
# # # # |
|||
# # # # # # # # |
|||
# # |
|||
# # # # # # # # |
|||
# # # # |
|||
# # # # # # # # |
|||
# |
|||
# # # # # # # # |
|||
# # # # |
|||
# # # # # # # # |
|||
# # |
|||
# # # # # # # # |
|||
# # # # |
|||
# # # # # # # # </syntaxhighlight> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
{{trans|C++}} |
{{trans|C++}} |
||
< |
<syntaxhighlight lang="java">import java.io.*; |
||
public class SierpinskiSquareCurve { |
public class SierpinskiSquareCurve { |
||
Line 139: | Line 642: | ||
try (Writer writer = new BufferedWriter(new FileWriter("sierpinski_square.svg"))) { |
try (Writer writer = new BufferedWriter(new FileWriter("sierpinski_square.svg"))) { |
||
SierpinskiSquareCurve s = new SierpinskiSquareCurve(writer); |
SierpinskiSquareCurve s = new SierpinskiSquareCurve(writer); |
||
int size = 635, length = 5; |
|||
s.currentAngle = 0; |
s.currentAngle = 0; |
||
s.currentX = |
s.currentX = (size - length)/2; |
||
s.currentY = |
s.currentY = length; |
||
s.lineLength = |
s.lineLength = length; |
||
s.begin( |
s.begin(size); |
||
s.execute(rewrite(5)); |
s.execute(rewrite(5)); |
||
s.end(); |
s.end(); |
||
Line 173: | Line 677: | ||
break; |
break; |
||
case '+': |
case '+': |
||
turn( |
turn(ANGLE); |
||
break; |
break; |
||
case '-': |
case '-': |
||
turn(ANGLE); |
turn(-ANGLE); |
||
break; |
break; |
||
} |
} |
||
Line 222: | Line 726: | ||
private static final String PRODUCTION = "XF-F+F-XF+F+XF-F+F-X"; |
private static final String PRODUCTION = "XF-F+F-XF+F+XF-F+F-X"; |
||
private static final int ANGLE = 90; |
private static final int ANGLE = 90; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
|||
[[Media:Sierpinski_square_java.svg]] |
|||
=={{header|jq}}== |
|||
{{works with|jq}} |
|||
'''Works with gojq, the Go implementation of jq''' |
|||
The program given here generates SVG code that can be |
|||
viewed directly in a browser, at least if the file suffix is .svg. |
|||
See [[Peano_curve#Simple_Turtle_Graphics | Simple Turtle Graphics]] |
|||
for the simple-turtle.jq module used in this entry. The `include` |
|||
statement assumes the file is in the pwd. |
|||
<syntaxhighlight lang="jq">include "simple-turtle" {search: "."}; |
|||
def rules: {"X": "XF-F+F-XF+F+XF-F+F-X"}; |
|||
def sierpinski($count): |
|||
rules as $rules |
|||
| def p($count): |
|||
if $count <= 0 then . |
|||
else gsub("X"; $rules["X"]) | p($count-1) |
|||
end; |
|||
"F+XF+F+XF" | p($count) ; |
|||
def interpret($x): |
|||
if $x == "+" then turtleRotate(90) |
|||
elif $x == "-" then turtleRotate(-90) |
|||
elif $x == "F" then turtleForward(5) |
|||
else . |
|||
end; |
|||
def sierpinski_curve($n): |
|||
sierpinski($n) |
|||
| split("") |
|||
| reduce .[] as $action (turtle([200,650]) | turtleDown; |
|||
interpret($action) ) ; |
|||
sierpinski_curve(5) |
|||
| path("none"; "red"; 1) | svg(1000) |
|||
</syntaxhighlight> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia">using Lindenmayer # https://github.com/cormullion/Lindenmayer.jl |
||
scurve = LSystem(Dict("X" => "XF-F+F-XF+F+XF-F+F-X"), "F+XF+F+XF") |
scurve = LSystem(Dict("X" => "XF-F+F-XF+F+XF-F+F-X"), "F+XF+F+XF") |
||
Line 237: | Line 784: | ||
showpreview = true |
showpreview = true |
||
) |
) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">Graphics[SierpinskiCurve[3]]</syntaxhighlight> |
|||
{{out}} |
|||
Outputs a graphical version of a 3rd order Sierpinski curve. |
|||
=={{header|Nim}}== |
|||
{{trans|C++}} |
|||
We produce a SVG file. |
|||
<syntaxhighlight lang="nim">import math |
|||
type |
|||
SierpinskiCurve = object |
|||
x, y: float |
|||
angle: float |
|||
length: int |
|||
file: File |
|||
proc line(sc: var SierpinskiCurve) = |
|||
let theta = degToRad(sc.angle) |
|||
sc.x += sc.length.toFloat * cos(theta) |
|||
sc.y += sc.length.toFloat * sin(theta) |
|||
sc.file.write " L", sc.x, ',', sc.y |
|||
proc execute(sc: var SierpinskiCurve; s: string) = |
|||
sc.file.write 'M', sc.x, ',', sc.y |
|||
for c in s: |
|||
case c |
|||
of 'F': sc.line() |
|||
of '+': sc.angle = floorMod(sc.angle + 90, 360) |
|||
of '-': sc.angle = floorMod(sc.angle - 90, 360) |
|||
else: discard |
|||
func rewrite(s: string): string = |
|||
for c in s: |
|||
if c == 'X': |
|||
result.add "XF-F+F-XF+F+XF-F+F-X" |
|||
else: |
|||
result.add c |
|||
proc write(sc: var SierpinskiCurve; size, length, order: int) = |
|||
sc.length = length |
|||
sc.x = (size - length) / 2 |
|||
sc.y = length.toFloat |
|||
sc.angle = 0 |
|||
sc.file.write "<svg xmlns='http://www.w3.org/2000/svg' width='", size, "' height='", size, "'>\n" |
|||
sc.file.write "<rect width='100%' height='100%' fill='white'/>\n" |
|||
sc.file.write "<path stroke-width='1' stroke='black' fill='none' d='" |
|||
var s = "F+XF+F+XF" |
|||
for _ in 1..order: s = s.rewrite() |
|||
sc.execute(s) |
|||
sc.file.write "'/>\n</svg>\n" |
|||
let outfile = open("sierpinski_square.svg", fmWrite) |
|||
var sc = SierpinskiCurve(file: outfile) |
|||
sc.write(635, 5, 5) |
|||
outfile.close()</syntaxhighlight> |
|||
{{out}} |
|||
Same as C++ output. |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">use strict; |
||
use warnings; |
use warnings; |
||
use SVG; |
use SVG; |
||
Line 276: | Line 889: | ||
open my $fh, '>', 'sierpinski-square-curve.svg'; |
open my $fh, '>', 'sierpinski-square-curve.svg'; |
||
print $fh $svg->xmlify(-namespace=>'svg'); |
print $fh $svg->xmlify(-namespace=>'svg'); |
||
close $fh;</ |
close $fh;</syntaxhighlight> |
||
See: [https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/sierpinski-square-curve.svg sierpinski-square-curve.svg] (offsite SVG image) |
See: [https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/sierpinski-square-curve.svg sierpinski-square-curve.svg] (offsite SVG image) |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
{{libheader|Phix/pGUI}} |
|||
<lang Phix>constant rule = "XF-F+F-XF+F+XF-F+F-X" |
|||
{{libheader|Phix/online}} |
|||
string s = "F+F+XF+F+XF" |
|||
You can run this online [http://phix.x10.mx/p2js/Sierpinski_square_curve.htm here]. |
|||
for n=1 to 4 do |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
string next = "" |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
for i=1 to length(s) do |
|||
-- demo\rosetta\Sierpinski_square_curve.exw |
|||
integer ch = s[i] |
|||
-- ======================================== |
|||
next &= iff(ch='X'?rule:ch) |
|||
-- |
|||
end for |
|||
-- My second atempt at a Lindenmayer system. The first |
|||
s = next |
|||
-- is now saved in demo\rosetta\Penrose_tiling.exw |
|||
end for |
|||
--</span> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span> |
|||
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*canvas*/</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"F+F+XF+F+XF"</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">next</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">next</span> <span style="color: #0000FF;">&=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"XF-F+F-XF+F+XF-F+F-X"</span><span style="color: #0000FF;">:</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">next</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasBegin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_CLOSED_LINES</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">theta</span><span style="color: #0000FF;">=</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">6</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">switch</span> <span style="color: #000000;">ch</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'F'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">theta</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">y</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">theta</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasVertex</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">270</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">270</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'+'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">theta</span> <span style="color: #0000FF;">+=</span> <span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'-'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">theta</span> <span style="color: #0000FF;">-=</span> <span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">cdCanvasEnd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_WHITE</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BLUE</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=290x295"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">)})</span> |
|||
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="Sierpinski square curve"`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`DIALOGFRAME`</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`YES`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<!--</syntaxhighlight>--> |
|||
and an svg-creating version: |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o)</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">rule</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"XF-F+F-XF+F+XF-F+F-X"</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"F+F+XF+F+XF"</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">next</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">next</span> <span style="color: #0000FF;">&=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">?</span><span style="color: #000000;">rule</span><span style="color: #0000FF;">:</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">next</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">X</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000000;">Y</span><span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">theta</span><span style="color: #0000FF;">=</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">6</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">svg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">switch</span> <span style="color: #000000;">ch</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'F'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">X</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">theta</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">Y</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">y</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">theta</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'+'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">theta</span> <span style="color: #0000FF;">+=</span> <span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">case</span> <span style="color: #008000;">'-'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">theta</span> <span style="color: #0000FF;">-=</span> <span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">svgfmt</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""" |
|||
<svg xmlns="http://www.w3.org/2000/svg" height="%d" width="%d"> |
|||
<rect height="100%%" width="100%%" style="fill:black" /> |
|||
<polyline points="%s" style="stroke: orange; stroke-width: 1" transform="translate(%d,%d)" /> |
|||
</svg>"""</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">X</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">points</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%.2f,%.2f "</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">X</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"sierpinski_square_curve.svg"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"w"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">xt</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">X</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">yt</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">10</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">svgfmt</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">X</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">xt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">yt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">yt</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|Python}}== |
|||
sequence X = {}, Y= {} |
|||
<syntaxhighlight lang="python">import matplotlib.pyplot as plt |
|||
atom x=0, y=0, theta=PI/4, r = 6 |
|||
import math |
|||
string svg = "" |
|||
for i=1 to length(s) do |
|||
integer ch = s[i] |
|||
def nextPoint(x, y, angle): |
|||
switch ch do |
|||
a = math.pi * angle / 180 |
|||
case 'F': X &= x; x += r*cos(theta) |
|||
x2 = (int)(round(x + (1 * math.cos(a)))) |
|||
y2 = (int)(round(y + (1 * math.sin(a)))) |
|||
return x2, y2 |
|||
case '-': theta -= PI/2 |
|||
end switch |
|||
end for |
|||
def expand(axiom, rules, level): |
|||
constant svgfmt = """ |
|||
for l in range(0, level): |
|||
<svg xmlns="http://www.w3.org/2000/svg" height="%d" width="%d"> |
|||
a2 = "" |
|||
<rect height="100%%" width="100%%" style="fill:black" /> |
|||
for c in axiom: |
|||
<polyline points="%s" style="stroke: orange; stroke-width: 1" transform="translate(%d,%d)" /> |
|||
if c in rules: |
|||
</svg>""" |
|||
a2 += rules[c] |
|||
string points = "" |
|||
else: |
|||
for i=1 to length(X) do |
|||
a2 += c |
|||
points &= sprintf("%.2f,%.2f ",{X[i],Y[i]}) |
|||
axiom = a2 |
|||
end for |
|||
return axiom |
|||
integer fn = open("sierpinski_square_curve.svg","w") |
|||
atom xt = -min(X)+10, |
|||
yt = -min(Y)+10 |
|||
def draw_lsystem(axiom, rules, angle, iterations): |
|||
printf(fn,svgfmt,{max(X)+xt+10,max(Y)+yt+10,points,xt,yt}) |
|||
xp = [1] |
|||
close(fn)</lang> |
|||
yp = [1] |
|||
direction = 0 |
|||
for c in expand(axiom, rules, iterations): |
|||
if c == "F": |
|||
xn, yn = nextPoint(xp[-1], yp[-1], direction) |
|||
xp.append(xn) |
|||
yp.append(yn) |
|||
elif c == "-": |
|||
direction = direction - angle |
|||
if direction < 0: |
|||
direction = 360 + direction |
|||
elif c == "+": |
|||
direction = (direction + angle) % 360 |
|||
plt.plot(xp, yp) |
|||
plt.show() |
|||
if __name__ == '__main__': |
|||
# Sierpinski Square L-System Definition |
|||
s_axiom = "F+XF+F+XF" |
|||
s_rules = {"X": "XF-F+F-XF+F+XF-F+F-X"} |
|||
s_angle = 90 |
|||
draw_lsystem(s_axiom, s_rules, s_angle, 3)</syntaxhighlight> |
|||
=={{header|Quackery}}== |
|||
Method is described at [[L-system#Quackery]]. |
|||
<syntaxhighlight lang="quackery"> [ $ "turtleduck.qky" loadfile ] now! |
|||
[ stack ] is switch.arg ( --> [ ) |
|||
[ switch.arg put ] is switch ( x --> ) |
|||
[ switch.arg release ] is otherwise ( --> ) |
|||
[ switch.arg share |
|||
!= iff ]else[ done |
|||
otherwise ]'[ do ]done[ ] is case ( x --> ) |
|||
[ $ "" swap witheach |
|||
[ nested quackery join ] ] is expand ( $ --> $ ) |
|||
[ $ "L" ] is L ( $ --> $ ) |
|||
[ $ "R" ] is R ( $ --> $ ) |
|||
[ $ "F" ] is F ( $ --> $ ) |
|||
[ $ "AFRFLFRAFLFLAFRFLFRA" ] is A ( $ --> $ ) |
|||
$ "FLAFLFLAF" |
|||
4 times expand |
|||
turtle |
|||
10 frames |
|||
witheach |
|||
[ switch |
|||
[ char L case [ -1 4 turn ] |
|||
char R case [ 1 4 turn ] |
|||
char F case [ 5 1 walk ] |
|||
otherwise ( ignore ) ] ] |
|||
1 frames</syntaxhighlight> |
|||
{{output}} |
|||
[[File:Quackery sierpinski square.png]] |
|||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
Line 322: | Line 1,102: | ||
{{works with|Rakudo|2020.02}} |
{{works with|Rakudo|2020.02}} |
||
<lang |
<syntaxhighlight lang="raku" line>use SVG; |
||
role Lindenmayer { |
role Lindenmayer { |
||
Line 365: | Line 1,145: | ||
], |
], |
||
], |
], |
||
);</ |
);</syntaxhighlight> |
||
See: [https://github.com/thundergnat/rc/blob/master/img/sierpinski-square-curve-perl6.svg Sierpinski-square-curve-perl6.svg] (offsite SVG image) |
See: [https://github.com/thundergnat/rc/blob/master/img/sierpinski-square-curve-perl6.svg Sierpinski-square-curve-perl6.svg] (offsite SVG image) |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
Program output is a file in SVG format. |
Program output is a file in SVG format. |
||
< |
<syntaxhighlight lang="rust">// [dependencies] |
||
// svg = "0.8.0" |
// svg = "0.8.0" |
||
Line 377: | Line 1,157: | ||
struct SierpinskiSquareCurve { |
struct SierpinskiSquareCurve { |
||
current_x |
current_x: f64, |
||
current_y |
current_y: f64, |
||
current_angle |
current_angle: i32, |
||
line_length |
line_length: f64, |
||
} |
} |
||
impl SierpinskiSquareCurve { |
impl SierpinskiSquareCurve { |
||
fn new(x |
fn new(x: f64, y: f64, length: f64, angle: i32) -> SierpinskiSquareCurve { |
||
SierpinskiSquareCurve { |
SierpinskiSquareCurve { |
||
current_x |
current_x: x, |
||
current_y |
current_y: y, |
||
current_angle |
current_angle: angle, |
||
line_length |
line_length: length, |
||
} |
} |
||
} |
} |
||
fn rewrite(order |
fn rewrite(order: usize) -> String { |
||
let mut str = String::from("F+XF+F+XF"); |
let mut str = String::from("F+XF+F+XF"); |
||
for _ in 0..order { |
for _ in 0..order { |
||
Line 399: | Line 1,179: | ||
match ch { |
match ch { |
||
'X' => tmp.push_str("XF-F+F-XF+F+XF-F+F-X"), |
'X' => tmp.push_str("XF-F+F-XF+F+XF-F+F-X"), |
||
_ => tmp.push(ch) |
_ => tmp.push(ch), |
||
} |
} |
||
} |
} |
||
Line 406: | Line 1,186: | ||
str |
str |
||
} |
} |
||
fn execute(&mut self, order |
fn execute(&mut self, order: usize) -> Path { |
||
let mut data = Data::new().move_to((self.current_x, self.current_y)); |
let mut data = Data::new().move_to((self.current_x, self.current_y)); |
||
for ch in SierpinskiSquareCurve::rewrite(order).chars() { |
for ch in SierpinskiSquareCurve::rewrite(order).chars() { |
||
Line 422: | Line 1,202: | ||
.set("d", data) |
.set("d", data) |
||
} |
} |
||
fn draw_line(&mut self, data |
fn draw_line(&mut self, data: Data) -> Data { |
||
let theta = (self.current_angle as f64).to_radians(); |
|||
use std::f64::consts::PI; |
|||
let theta = (PI * self.current_angle as f64) / 180.0; |
|||
self.current_x += self.line_length * theta.cos(); |
self.current_x += self.line_length * theta.cos(); |
||
self.current_y |
self.current_y += self.line_length * theta.sin(); |
||
data.line_to((self.current_x, self.current_y)) |
data.line_to((self.current_x, self.current_y)) |
||
} |
} |
||
fn turn(&mut self, angle |
fn turn(&mut self, angle: i32) { |
||
self.current_angle = (self.current_angle + angle) % 360; |
self.current_angle = (self.current_angle + angle) % 360; |
||
} |
} |
||
fn save(file |
fn save(file: &str, size: usize, length: f64, order: usize) -> std::io::Result<()> { |
||
use svg::node::element::Rectangle; |
use svg::node::element::Rectangle; |
||
let x = |
let x = (size as f64 - length) / 2.0; |
||
let y = |
let y = length; |
||
let rect = Rectangle::new() |
let rect = Rectangle::new() |
||
.set("width", "100%") |
.set("width", "100%") |
||
.set("height", "100%") |
.set("height", "100%") |
||
.set("fill", "white"); |
.set("fill", "white"); |
||
let mut |
let mut s = SierpinskiSquareCurve::new(x, y, length, 0); |
||
let document = svg::Document::new() |
let document = svg::Document::new() |
||
.set("width", size) |
.set("width", size) |
||
.set("height", size) |
.set("height", size) |
||
.add(rect) |
.add(rect) |
||
.add( |
.add(s.execute(order)); |
||
svg::save(file, &document) |
svg::save(file, &document) |
||
} |
} |
||
Line 451: | Line 1,230: | ||
fn main() { |
fn main() { |
||
SierpinskiSquareCurve::save("sierpinski_square_curve.svg", 635, 5).unwrap(); |
SierpinskiSquareCurve::save("sierpinski_square_curve.svg", 635, 5.0, 5).unwrap(); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
|||
[[Media:Sierpinski_square_curve_rust.svg]] |
|||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
Uses the '''LSystem()''' class from [https://rosettacode.org/wiki/Hilbert_curve#Sidef Hilbert curve]. |
Uses the '''LSystem()''' class from [https://rosettacode.org/wiki/Hilbert_curve#Sidef Hilbert curve]. |
||
< |
<syntaxhighlight lang="ruby">var rules = Hash( |
||
x => 'xF-F+F-xF+F+xF-F+F-x', |
x => 'xF-F+F-xF+F+xF-F+F-x', |
||
) |
) |
||
Line 472: | Line 1,254: | ||
) |
) |
||
lsys.execute('F+xF+F+xF', 5, "sierpiński_square_curve.png", rules)</ |
lsys.execute('F+xF+F+xF', 5, "sierpiński_square_curve.png", rules)</syntaxhighlight> |
||
Output image: [https://github.com/trizen/rc/blob/master/img/sierpi%C5%84ski_square_curve-sidef.png Sierpiński square curve] |
Output image: [https://github.com/trizen/rc/blob/master/img/sierpi%C5%84ski_square_curve-sidef.png Sierpiński square curve] |
||
=={{header|VBScript}}== |
|||
Output to html (svg) displayed in the default browser. A turtle graphics class helps to keep the curve definition simple |
|||
<syntaxhighlight lang="vb"> |
|||
option explicit |
|||
'outputs turtle graphics to svg file and opens it |
|||
const pi180= 0.01745329251994329576923690768489 ' pi/180 |
|||
const pi=3.1415926535897932384626433832795 'pi |
|||
class turtle |
|||
dim fso |
|||
dim fn |
|||
dim svg |
|||
dim iang 'radians |
|||
dim ori 'radians |
|||
dim incr |
|||
dim pdown |
|||
dim clr |
|||
dim x |
|||
dim y |
|||
public property let orient(n):ori = n*pi180 :end property |
|||
public property let iangle(n):iang= n*pi180 :end property |
|||
public sub pd() : pdown=true: end sub |
|||
public sub pu() :pdown=FALSE :end sub |
|||
public sub rt(i) |
|||
ori=ori - i*iang: |
|||
'if ori<0 then ori = ori+pi*2 |
|||
end sub |
|||
public sub lt(i): |
|||
ori=(ori + i*iang) |
|||
'if ori>(pi*2) then ori=ori-pi*2 |
|||
end sub |
|||
public sub bw(l) |
|||
x= x+ cos(ori+pi)*l*incr |
|||
y= y+ sin(ori+pi)*l*incr |
|||
' ori=ori+pi '????? |
|||
end sub |
|||
public sub fw(l) |
|||
dim x1,y1 |
|||
x1=x + cos(ori)*l*incr |
|||
y1=y + sin(ori)*l*incr |
|||
if pdown then line x,y,x1,y1 |
|||
x=x1:y=y1 |
|||
end sub |
|||
Private Sub Class_Initialize() |
|||
setlocale "us" |
|||
initsvg |
|||
x=400:y=400:incr=100 |
|||
ori=90*pi180 |
|||
iang=90*pi180 |
|||
clr=0 |
|||
pdown=true |
|||
end sub |
|||
Private Sub Class_Terminate() |
|||
disply |
|||
end sub |
|||
private sub line (x,y,x1,y1) |
|||
svg.WriteLine "<line x1=""" & x & """ y1= """& y & """ x2=""" & x1& """ y2=""" & y1 & """/>" |
|||
end sub |
|||
private sub disply() |
|||
dim shell |
|||
svg.WriteLine "</svg></body></html>" |
|||
svg.close |
|||
Set shell = CreateObject("Shell.Application") |
|||
shell.ShellExecute fn,1,False |
|||
end sub |
|||
private sub initsvg() |
|||
dim scriptpath |
|||
Set fso = CreateObject ("Scripting.Filesystemobject") |
|||
ScriptPath= Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName, "\")) |
|||
fn=Scriptpath & "SIERP.HTML" |
|||
Set svg = fso.CreateTextFile(fn,True) |
|||
if SVG IS nothing then wscript.echo "Can't create svg file" :vscript.quit |
|||
svg.WriteLine "<!DOCTYPE html>" &vbcrlf & "<html>" &vbcrlf & "<head>" |
|||
svg.writeline "<style>" & vbcrlf & "line {stroke:rgb(255,0,0);stroke-width:.5}" &vbcrlf &"</style>" |
|||
svg.writeline "</head>"&vbcrlf & "<body>" |
|||
svg.WriteLine "<svg xmlns=""http://www.w3.org/2000/svg"" width=""800"" height=""800"" viewBox=""0 0 800 800"">" |
|||
end sub |
|||
end class |
|||
'to half.sierpinski :size :level |
|||
' if :level = 0 [forward :size stop] |
|||
' half.sierpinski :size :level - 1 |
|||
' left 45 |
|||
' forward :size * sqrt 2 |
|||
' left 45 |
|||
' half.sierpinski :size :level - 1 |
|||
' right 90 |
|||
' forward :size |
|||
' right 90 |
|||
' half.sierpinski :size :level - 1 |
|||
' left 45 |
|||
' forward :size * sqrt 2 |
|||
' left 45 |
|||
' half.sierpinski :size :level - 1 |
|||
'end |
|||
const raiz2=1.4142135623730950488016887242097 |
|||
sub media_sierp (niv,sz) |
|||
if niv=0 then x.fw sz: exit sub |
|||
media_sierp niv-1,sz |
|||
x.lt 1 |
|||
x.fw sz*raiz2 |
|||
x.lt 1 |
|||
media_sierp niv-1,sz |
|||
x.rt 2 |
|||
x.fw sz |
|||
x.rt 2 |
|||
media_sierp niv-1,sz |
|||
x.lt 1 |
|||
x.fw sz*raiz2 |
|||
x.lt 1 |
|||
media_sierp niv-1,sz |
|||
end sub |
|||
'to sierpinski :size :level |
|||
' half.sierpinski :size :level |
|||
' right 90 |
|||
' forward :size |
|||
' right 90 |
|||
' half.sierpinski :size :level |
|||
' right 90 |
|||
' forward :size |
|||
' right 90 |
|||
'end |
|||
sub sierp(niv,sz) |
|||
media_sierp niv,sz |
|||
x.rt 2 |
|||
x.fw sz |
|||
x.rt 2 |
|||
media_sierp niv,sz |
|||
x.rt 2 |
|||
x.fw sz |
|||
x.rt 2 |
|||
end sub |
|||
dim x |
|||
set x=new turtle |
|||
x.iangle=45 |
|||
x.orient=0 |
|||
x.incr=1 |
|||
x.x=100:x.y=270 |
|||
'star5 |
|||
sierp 5,4 |
|||
set x=nothing |
|||
</syntaxhighlight> |
|||
=={{header|Wren}}== |
|||
{{trans|Go}} |
|||
{{libheader|DOME}} |
|||
{{libheader|Wren-lsystem}} |
|||
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color |
|||
import "dome" for Window |
|||
import "math" for Math |
|||
import "./lsystem" for LSystem, Rule |
|||
var TwoPi = Num.pi * 2 |
|||
class SierpinskiSquareCurve { |
|||
construct new(width, height, back, fore) { |
|||
Window.title = "Sierpinski Square Curve" |
|||
Window.resize(width, height) |
|||
Canvas.resize(width, height) |
|||
_w = width |
|||
_h = height |
|||
_bc = back |
|||
_fc = fore |
|||
} |
|||
init() { |
|||
Canvas.cls(_bc) |
|||
var cx = 10 |
|||
var cy = (_h/2).floor + 5 |
|||
var theta = 0 |
|||
var h = 6 |
|||
var lsys = LSystem.new( |
|||
["X"], // variables |
|||
["F", "+", "-"], // constants |
|||
"F+XF+F+XF", // axiom |
|||
[Rule.new("X", "XF-F+F-XF+F+XF-F+F-X")], // rules |
|||
Num.pi / 2 // angle (90 degrees in radians) |
|||
) |
|||
var result = lsys.iterate(5) |
|||
var operations = { |
|||
"F": Fn.new { |
|||
var newX = cx + h*Math.sin(theta) |
|||
var newY = cy - h*Math.cos(theta) |
|||
Canvas.line(cx, cy, newX, newY, _fc, 2) |
|||
cx = newX |
|||
cy = newY |
|||
}, |
|||
"+": Fn.new { |
|||
theta = (theta + lsys.angle) % TwoPi |
|||
}, |
|||
"-": Fn.new { |
|||
theta = (theta - lsys.angle) % TwoPi |
|||
} |
|||
} |
|||
LSystem.execute(result, operations) |
|||
} |
|||
update() {} |
|||
draw(alpha) {} |
|||
} |
|||
var Game = SierpinskiSquareCurve.new(770, 770, Color.blue, Color.yellow)</syntaxhighlight> |
|||
{{out}} |
|||
[[File:Wren-Sierpinski_square_curve.png|400px]] |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Uses Image Magick and |
Uses Image Magick and |
||
the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl |
the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl |
||
< |
<syntaxhighlight lang="zkl">sierpinskiSquareCurve(4) : turtle(_); |
||
fcn sierpinskiSquareCurve(n){ // Lindenmayer system --> Data of As |
fcn sierpinskiSquareCurve(n){ // Lindenmayer system --> Data of As |
||
Line 506: | Line 1,509: | ||
} |
} |
||
img.writeJPGFile("sierpinskiSquareCurve.zkl.jpg"); |
img.writeJPGFile("sierpinskiSquareCurve.zkl.jpg"); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Offsite image at [http://www.zenkinetic.com/Images/RosettaCode/sierpinskiSquareCurve.zkl.jpg Sierpinski square curve of order 4] |
Offsite image at [http://www.zenkinetic.com/Images/RosettaCode/sierpinskiSquareCurve.zkl.jpg Sierpinski square curve of order 4] |
Latest revision as of 13:55, 14 May 2024
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Produce a graphical or ASCII-art representation of a Sierpinski square curve of at least order 3.
11l
F sierpinski_square(fname, size, length, order)
V x = (size - length) / 2
V y = Float(length)
V angle = 0.0
V outfile = File(fname, WRITE)
outfile.write(‘<svg xmlns='http://www.w3.org/2000/svg' width='’size‘' height='’size"'>\n")
outfile.write("<rect width='100%' height='100%' fill='white'/>\n")
outfile.write(‘<path stroke-width='1' stroke='black' fill='none' d='’)
V s = ‘F+XF+F+XF’
L 0 .< order
s = s.replace(‘X’, ‘XF-F+F-XF+F+XF-F+F-X’)
outfile.write(‘M’x‘,’y)
L(c) s
S c
‘F’
x += length * cos(radians(angle))
y += length * sin(radians(angle))
outfile.write(‘ L’x‘,’y)
‘+’
angle = (angle + 90) % 360
‘-’
angle = (angle - 90 + 360) % 360
outfile.write("'/>\n</svg>\n")
sierpinski_square(‘sierpinski_square.svg’, 635, 5, 5)
- Output:
Output is similar to C++.
ALGOL 68
Generates an SVG file. The SVG generating code is translated from the FreeBASIC sample (which is a translation of the 11l sample which is translated from the C++). Uses the Algol 68 library for L-System related Tasks on Rosetta Code.
Note: The source of the Algol 68 L-System library is available on a separate page on Rosetta Code - see the above link and follow the link to the Talk (Discussion) page.
BEGIN # Sierpinski Square Curve in SVG - SVG generation translated from the #
# FreeBASIC sample (which is a translation of C++) #
# uses the RC Algol 68 L-System library for the L-System evaluation & #
# interpretation #
PR read "lsystem.incl.a68" PR # include L-System utilities #
PROC sierpinski square curve = ( STRING fname, INT size, length, order )VOID:
IF FILE svg file;
BOOL open error := IF open( svg file, fname, stand out channel ) = 0
THEN
# opened OK - file already exists and #
# will be overwritten #
FALSE
ELSE
# failed to open the file #
# - try creating a new file #
establish( svg file, fname, stand out channel ) /= 0
FI;
open error
THEN # failed to open the file #
print( ( "Unable to open ", fname, newline ) );
stop
ELSE # file opened OK #
REAL x := ( size - length ) / 2;
REAL y := length;
INT angle := 0;
put( svg file, ( "<svg xmlns='http://www.w3.org/2000/svg' width='"
, whole( size, 0 ), "' height='", whole( size, 0 ), "'>"
, newline, "<rect width='100%' height='100%' fill='white'/>"
, newline, "<path stroke-width='1' stroke='black' fill='none' d='"
, newline, "M", whole( x, 0 ), ",", whole( y, 0 ), newline
)
);
LSYSTEM ssc = ( "F+XF+F+XF"
, ( "X" -> "XF-F+F-XF+F+XF-F+F-X"
)
);
STRING curve = ssc EVAL order;
curve INTERPRET ( ( CHAR c )VOID:
IF c = "F" THEN
x +:= length * cos( angle * pi / 180 );
y +:= length * sin( angle * pi / 180 );
put( svg file, ( " L", whole( x, 0 ), ",", whole( y, 0 ), newline ) )
ELIF c = "+" THEN
angle +:= 90 MODAB 360
ELIF c = "-" THEN
angle +:= 270 MODAB 360
FI
);
put( svg file, ( "'/>", newline, "</svg>", newline ) );
close( svg file )
FI # sierpinski square # ;
sierpinski square curve( "sierpinski_square.svg", 635, 5, 5 )
END
- Output:
Similar to FreeBasic, 11l, C++, etc.
ALGOL W
Draws an ASCII art Sierpinski square curve. For orders greater than 6, the value of CANVAS_WIDTH must be increased.
The resolution of the canvas is, of course fairly small, so for orders > 4, to avoid the curve overwriting itself, the connecting lines between the segments of the curve are made longer.
begin % draw a Sierpinski curve using ascii art %
integer CANVAS_WIDTH;
CANVAS_WIDTH := 200;
begin
% the ascii art canvas and related items %
string(1) array canvas ( 1 :: CANVAS_WIDTH, 1 :: CANVAS_WIDTH );
integer heading, asciiX, asciiY, width, maxX, maxY, minX, minY;
% draw a line using ascii art - the length is ignored and the heading determines the %
% character to use %
% the position is updated %
procedure drawLine( real value length ) ;
begin
% stores the min and max coordinates %
procedure updateCoordinateRange ;
begin
if asciiX > maxX then maxX := asciiX;
if asciiY > maxY then maxY := asciiY;
if asciiX < minX then minX := asciiX;
if asciiY < minY then minY := asciiY
end updateCoordinateRange ;
if heading = 0 then begin
asciiX := asciiX + 1;
canvas( asciiX, asciiY ) := "_";
updateCoordinateRange;
end
else if heading = 90 then begin
updateCoordinateRange;
canvas( asciiX, asciiY ) := "|";
asciiY := asciiY - 1;
end
else if heading = 180 then begin
asciiX := asciiX - 1;
canvas( asciiX, asciiY ) := "_";
updateCoordinateRange;
end
else if heading = 270 then begin
asciiY := asciiY + 1;
updateCoordinateRange;
canvas( asciiX - 1, asciiY ) := "|";
end if_various_headings
end drawLine ;
% changes the heading by the specified angle ( in degrees ) - angle must be +/- 90 %
% the position is updated, if necessary as the horizontal lines are at the bottom %
% of a character but the vertical lines are in the middle pf a character %
procedure turn( integer value angle ) ;
begin
integer prevHeading;
prevHeading := heading;
heading := heading + angle;
while heading < 0 do heading := heading + 360;
heading := heading rem 360;
if heading = 0 and prevHeading = 270 then asciiX := asciiX - 1
else if heading = 90 then begin
if prevHeading = 180 then asciiX := asciiX - 1
else if prevHeading = 0 then asciiX := asciiX + 1
end
else if heading = 180 and prevHeading = 270 then asciiX := asciiX - 1
else if heading = 270 and prevHeading = 0 then asciiX := asciiX + 2
end turn ;
% initialises the ascii art canvas %
procedure initArt ( integer value initHeading ) ;
begin
heading := initHeading;;
asciiX := CANVAS_WIDTH div 2;
asciiY := asciiX;
maxX := asciiX;
maxY := asciiY;
minX := asciiX;
minY := asciiY;
for x := 1 until CANVAS_WIDTH do for y := 1 until CANVAS_WIDTH do canvas( x, y ) := " "
end initArt ;
% shows the used parts of the canvas %
procedure drawArt ;
begin
for y := minY until maxY do begin
write();
for x := minX until maxX do writeon( canvas( x, y ) )
end for_y ;
write()
end drawIArt ;
% draws a sierpinski square curve of the specified order %
procedure sierpinskiSquareCurve( integer value order ) ;
begin
% draw a line connecting segments %
procedure extendedLine ;
if actualOrder > 4 then begin
% for higher orders, the segments can touch %
% so space the segments further apart %
if heading rem 180 = 0 then drawline( 1 );
drawline( 1 );
drawline( 1 )
end extendedLine ;
% draw a corner of an element of the curve %
procedure corner ;
begin
drawline( 1 );
turn( - 90 );
drawline( 1 )
end corner ;
% recursively draws a part of a sierpinski square curve %
procedure subCurve( integer value order; logical value threeSubCurves ) ;
begin
corner;
turn( + 90 );
drawline( 1 );
if order < 1 then begin
turn( - 90 );
drawline( 1 );
turn( - 90 )
end
else begin
extendedLine;;
turn( + 90 );
curve( order, threeSubCurves );
turn( + 90 );
extendedLine
end if_order_lt_1 ;
drawline( 1 );
turn( + 90 )
end subCurve;
% recursively draws a segment of the sierpinski curve %
procedure curve( integer value order; logical value threeSubCurves ) ;
begin
subCurve( if threeSubCurves then order - 1 else 0, not threeSubCurves );
subCurve( order - 1, not threeSubCurves );
subCurve( if threeSubCurves then order - 1 else 0, not threeSubCurves );
corner
end curve ;
integer actualOrder;
actualOrder := order;
if order = 1 then begin
for c := 1 until 4 do corner
end
else if order = 2 then begin
for c := 1 until 4 do subCurve( 0, false )
end
else begin
for c := 1 until 4 do subCurve( ( 2 * order ) - 5, false )
end if_order_eq_1__2__
end sierpinskiSquareCurve ;
% draw curves %
begin
integer order;
i_w := 1; s_w := 0; % set output formatting %
write( "order> " );
read( order );
write( "Sierpinski curve of order ", order );
write( "===========================" );
write();
initArt( 0 );
sierpinskiSquareCurve( order );
drawArt
end
end
end.
- Output:
order> 4 Sierpinski square curve of order 4 ================================== _ _| |_ _| |_ |_ _| _ |_ _| _ _| |_ _| |_ _| |_ _| |_| |_| |_ |_ _ _ _| _ |_ _| |_ _| |_ _| _ _| |_ |_| _| |_ |_| _| |_ _| |_ _| |_ _| |_ |_ _| |_ _| |_ _| _ |_ _| _ |_ _| _ |_ _| _ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_| |_| |_| |_| |_| |_| |_ |_ _ _ _ _ _ _ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_| _| |_ |_| _| |_ |_| _| |_ |_| _| |_ _| |_ _| |_ |_ _| |_ _| |_ _| |_ _| _ |_ _| _ |_ _| |_| _| |_ _| |_ _| |_ |_| _| |_| |_| |_ |_ _ _ _| |_ _| |_ _| |_ _| |_| _| |_ |_| _| |_ |_ _| |_ _| |_|
C++
Output is a file in SVG format.
// See https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve#Representation_as_Lindenmayer_system
#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
class sierpinski_square {
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_square::write(std::ostream& out, int size, int length, int order) {
length_ = length;
x_ = (size - length)/2;
y_ = length;
angle_ = 0;
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_square::rewrite(const std::string& s) {
std::string t;
for (char c : s) {
if (c == 'X')
t += "XF-F+F-XF+F+XF-F+F-X";
else
t += c;
}
return t;
}
void sierpinski_square::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_square::execute(std::ostream& out, const std::string& s) {
out << 'M' << x_ << ',' << y_;
for (char c : s) {
switch (c) {
case 'F':
line(out);
break;
case '+':
angle_ = (angle_ + 90) % 360;
break;
case '-':
angle_ = (angle_ - 90) % 360;
break;
}
}
}
int main() {
std::ofstream out("sierpinski_square.svg");
if (!out) {
std::cerr << "Cannot open output file\n";
return 1;
}
sierpinski_square s;
s.write(out, 635, 5, 5);
return 0;
}
- Output:
Media:Sierpinski_square_cpp.svg
EasyLang
proc lsysexp level . axiom$ rules$[] .
for l to level
an$ = ""
for c$ in strchars axiom$
for i = 1 step 2 to len rules$[]
if rules$[i] = c$
c$ = rules$[i + 1]
break 1
.
.
an$ &= c$
.
swap axiom$ an$
.
.
proc lsysdraw axiom$ x y ang lng . .
linewidth 0.3
move x y
for c$ in strchars axiom$
if c$ = "F"
x += cos dir * lng
y += sin dir * lng
line x y
elif c$ = "-"
dir -= ang
elif c$ = "+"
dir += ang
.
.
.
axiom$ = "F+XF+F+XF"
rules$[] = [ "X" "XF-F+F-XF+F+XF-F+F-X" ]
lsysexp 4 axiom$ rules$[]
lsysdraw axiom$ 50 10 90 1.4
Factor
USING: accessors kernel L-system sequences ui ;
: square-curve ( L-system -- L-system )
L-parser-dialect >>commands
[ 90 >>angle ] >>turtle-values
"F+XF+F+XF" >>axiom
{
{ "X" "XF-F+F-XF+F+XF-F+F-X" }
} >>rules ;
[
<L-system> square-curve
"Sierpinski square curve" open-window
] with-ui
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 |
FreeBASIC
Output is a file in SVG format.
#define pi 4 * Atn(1)
Sub sierpinski_square(fname As String, size As Integer, length As Integer, order As Integer)
Dim As Single x = (size - length) / 2
Dim As Single y = length
Dim As Single angle = 0.0
Dim As Integer i, j
Dim As String t, s = "F+XF+F+XF"
For i = 1 To order
t = ""
For j = 1 To Len(s)
Select Case Mid(s, j, 1)
Case "X"
t += "XF-F+F-XF+F+XF-F+F-X"
Case Else
t += Mid(s, j, 1)
End Select
Next j
s = t
Next i
Open fname For Output As #1
Print #1, "<svg xmlns='http://www.w3.org/2000/svg' width='" ; size ; "' height='" ; size ; "'>"
Print #1, "<rect width='100%' height='100%' fill='white'/>"
Print #1, "<path stroke-width='1' stroke='black' fill='none' d='";
Print #1, "M" ; x ; "," ; y;
For i = 1 To Len(s)
Select Case Mid(s, i, 1)
Case "F"
x += length * Cos(angle * pi / 180)
y += length * Sin(angle * pi / 180)
Print #1, " L" ; x ; "," ; y;
Case "+"
angle = (angle + 90) Mod 360
Case "-"
angle = (angle - 90 + 360) Mod 360
End Select
Next i
Print #1, "'/>"
Print #1, "</svg>"
Close #1
End Sub
sierpinski_square("sierpinski_square.svg", 635, 5, 5)
Windowtitle "Hit any key to end program"
- Output:
Output is similar to C++.
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
It can be done using an L-system. There are generic functions written in Fōrmulæ to compute an L-system in the page L-system.
The program that creates a Sierpiński's square curve is:
Go
The following uses the Lindenmayer system with the appropriate parameters from the Wikipedia article and produces a similar image (apart from the colors, yellow on blue) to the Sidef and zkl entries.
package main
import (
"github.com/fogleman/gg"
"github.com/trubitsyn/go-lindenmayer"
"log"
"math"
)
const twoPi = 2 * math.Pi
var (
width = 770.0
height = 770.0
dc = gg.NewContext(int(width), int(height))
)
var cx, cy, h, theta float64
func main() {
dc.SetRGB(0, 0, 1) // blue background
dc.Clear()
cx, cy = 10, height/2+5
h = 6
sys := lindenmayer.Lsystem{
Variables: []rune{'X'},
Constants: []rune{'F', '+', '-'},
Axiom: "F+XF+F+XF",
Rules: []lindenmayer.Rule{
{"X", "XF-F+F-XF+F+XF-F+F-X"},
},
Angle: math.Pi / 2, // 90 degrees in radians
}
result := lindenmayer.Iterate(&sys, 5)
operations := map[rune]func(){
'F': func() {
newX, newY := cx+h*math.Sin(theta), cy-h*math.Cos(theta)
dc.LineTo(newX, newY)
cx, cy = newX, newY
},
'+': func() {
theta = math.Mod(theta+sys.Angle, twoPi)
},
'-': func() {
theta = math.Mod(theta-sys.Angle, twoPi)
},
}
if err := lindenmayer.Process(result, operations); err != nil {
log.Fatal(err)
}
// needed to close the square at the extreme left
operations['+']()
operations['F']()
// create the image and save it
dc.SetRGB255(255, 255, 0) // yellow curve
dc.SetLineWidth(2)
dc.Stroke()
dc.SavePNG("sierpinski_square_curve.png")
}
J
It looks like there's two different (though similar) concepts implemented here, of what a "Sierpinski square curve" looks like (the wikipedia writeup shows 45 degree angles -- like j:File:Sierpinski_curve.png but many of the implementations here show only right angles). And, the wikipedia writeup is obtuse about some of the details of the structure. And, we've got some dead links here. So, for now, a quickie ascii art implementation:
1j1#"1' #'{~{{l,(1,~0{.~#y),l=.y,.0,.y}}^:3,.1
# # # # # # # #
# # # #
# # # # # # # #
# #
# # # # # # # #
# # # #
# # # # # # # #
#
# # # # # # # #
# # # #
# # # # # # # #
# #
# # # # # # # #
# # # #
# # # # # # # #
Java
import java.io.*;
public class SierpinskiSquareCurve {
public static void main(final String[] args) {
try (Writer writer = new BufferedWriter(new FileWriter("sierpinski_square.svg"))) {
SierpinskiSquareCurve s = new SierpinskiSquareCurve(writer);
int size = 635, length = 5;
s.currentAngle = 0;
s.currentX = (size - length)/2;
s.currentY = length;
s.lineLength = length;
s.begin(size);
s.execute(rewrite(5));
s.end();
} catch (final Exception ex) {
ex.printStackTrace();
}
}
private SierpinskiSquareCurve(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':
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-F+F-XF+F+XF-F+F-X";
private static final int ANGLE = 90;
}
- Output:
Media:Sierpinski_square_java.svg
jq
Works with gojq, the Go implementation of jq
The program given here generates SVG code that can be viewed directly in a browser, at least if the file suffix is .svg.
See Simple Turtle Graphics for the simple-turtle.jq module used in this entry. The `include` statement assumes the file is in the pwd.
include "simple-turtle" {search: "."};
def rules: {"X": "XF-F+F-XF+F+XF-F+F-X"};
def sierpinski($count):
rules as $rules
| def p($count):
if $count <= 0 then .
else gsub("X"; $rules["X"]) | p($count-1)
end;
"F+XF+F+XF" | p($count) ;
def interpret($x):
if $x == "+" then turtleRotate(90)
elif $x == "-" then turtleRotate(-90)
elif $x == "F" then turtleForward(5)
else .
end;
def sierpinski_curve($n):
sierpinski($n)
| split("")
| reduce .[] as $action (turtle([200,650]) | turtleDown;
interpret($action) ) ;
sierpinski_curve(5)
| path("none"; "red"; 1) | svg(1000)
Julia
using Lindenmayer # https://github.com/cormullion/Lindenmayer.jl
scurve = LSystem(Dict("X" => "XF-F+F-XF+F+XF-F+F-X"), "F+XF+F+XF")
drawLSystem(scurve,
forward = 3,
turn = 90,
startingy = -400,
iterations = 6,
filename = "sierpinski_square_curve.png",
showpreview = true
)
Mathematica/Wolfram Language
Graphics[SierpinskiCurve[3]]
- Output:
Outputs a graphical version of a 3rd order Sierpinski curve.
Nim
We produce a SVG file.
import math
type
SierpinskiCurve = object
x, y: float
angle: float
length: int
file: File
proc line(sc: var SierpinskiCurve) =
let theta = degToRad(sc.angle)
sc.x += sc.length.toFloat * cos(theta)
sc.y += sc.length.toFloat * sin(theta)
sc.file.write " L", sc.x, ',', sc.y
proc execute(sc: var SierpinskiCurve; s: string) =
sc.file.write 'M', sc.x, ',', sc.y
for c in s:
case c
of 'F': sc.line()
of '+': sc.angle = floorMod(sc.angle + 90, 360)
of '-': sc.angle = floorMod(sc.angle - 90, 360)
else: discard
func rewrite(s: string): string =
for c in s:
if c == 'X':
result.add "XF-F+F-XF+F+XF-F+F-X"
else:
result.add c
proc write(sc: var SierpinskiCurve; size, length, order: int) =
sc.length = length
sc.x = (size - length) / 2
sc.y = length.toFloat
sc.angle = 0
sc.file.write "<svg xmlns='http://www.w3.org/2000/svg' width='", size, "' height='", size, "'>\n"
sc.file.write "<rect width='100%' height='100%' fill='white'/>\n"
sc.file.write "<path stroke-width='1' stroke='black' fill='none' d='"
var s = "F+XF+F+XF"
for _ in 1..order: s = s.rewrite()
sc.execute(s)
sc.file.write "'/>\n</svg>\n"
let outfile = open("sierpinski_square.svg", fmWrite)
var sc = SierpinskiCurve(file: outfile)
sc.write(635, 5, 5)
outfile.close()
- Output:
Same as C++ output.
Perl
use strict;
use warnings;
use SVG;
use List::Util qw(max min);
use constant pi => 2 * atan2(1, 0);
my $rule = 'XF-F+F-XF+F+XF-F+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/2; }
elsif (/\-/) { $theta -= pi/2; }
}
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-square-curve.svg';
print $fh $svg->xmlify(-namespace=>'svg');
close $fh;
See: sierpinski-square-curve.svg (offsite SVG image)
Phix
You can run this online here.
-- -- demo\rosetta\Sierpinski_square_curve.exw -- ======================================== -- -- My second atempt at a Lindenmayer system. The first -- is now saved in demo\rosetta\Penrose_tiling.exw -- with javascript_semantics include pGUI.e Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas function redraw_cb(Ihandle /*canvas*/) string s = "F+F+XF+F+XF" for n=1 to 4 do string next = "" for i=1 to length(s) do integer ch = s[i] next &= iff(ch='X'?"XF-F+F-XF+F+XF-F+F-X":ch) end for s = next end for cdCanvasActivate(cddbuffer) cdCanvasBegin(cddbuffer, CD_CLOSED_LINES) atom x=0, y=0, theta=PI/4, r = 6 for i=1 to length(s) do integer ch = s[i] switch ch do case 'F': x += r*cos(theta) y += r*sin(theta) cdCanvasVertex(cddbuffer, x+270, y+270) case '+': theta += PI/2 case '-': theta -= PI/2 end switch end for cdCanvasEnd(cddbuffer) cdCanvasFlush(cddbuffer) return IUP_DEFAULT end function function map_cb(Ihandle canvas) cdcanvas = cdCreateCanvas(CD_IUP, canvas) cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) cdCanvasSetBackground(cddbuffer, CD_WHITE) cdCanvasSetForeground(cddbuffer, CD_BLUE) return IUP_DEFAULT end function IupOpen() canvas = IupCanvas("RASTERSIZE=290x295") IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"), "ACTION", Icallback("redraw_cb")}) dlg = IupDialog(canvas,`TITLE="Sierpinski square curve"`) IupSetAttribute(dlg,`DIALOGFRAME`,`YES`) IupShow(dlg) if platform()!=JS then IupMainLoop() IupClose() end if
and an svg-creating version:
without js -- (file i/o) constant rule = "XF-F+F-XF+F+XF-F+F-X" string s = "F+F+XF+F+XF" for n=1 to 4 do string next = "" for i=1 to length(s) do integer ch = s[i] next &= iff(ch='X'?rule:ch) end for s = next end for sequence X = {}, Y= {} atom x=0, y=0, theta=PI/4, r = 6 string svg = "" for i=1 to length(s) do integer ch = s[i] switch ch do case 'F': X &= x; x += r*cos(theta) Y &= y; y += r*sin(theta) case '+': theta += PI/2 case '-': theta -= PI/2 end switch end for constant svgfmt = """ <svg xmlns="http://www.w3.org/2000/svg" height="%d" width="%d"> <rect height="100%%" width="100%%" style="fill:black" /> <polyline points="%s" style="stroke: orange; stroke-width: 1" transform="translate(%d,%d)" /> </svg>""" string points = "" for i=1 to length(X) do points &= sprintf("%.2f,%.2f ",{X[i],Y[i]}) end for integer fn = open("sierpinski_square_curve.svg","w") atom xt = -min(X)+10, yt = -min(Y)+10 printf(fn,svgfmt,{max(X)+xt+10,max(Y)+yt+10,points,xt,yt}) close(fn)
Python
import matplotlib.pyplot as plt
import math
def nextPoint(x, y, angle):
a = math.pi * angle / 180
x2 = (int)(round(x + (1 * math.cos(a))))
y2 = (int)(round(y + (1 * math.sin(a))))
return x2, y2
def expand(axiom, rules, level):
for l in range(0, level):
a2 = ""
for c in axiom:
if c in rules:
a2 += rules[c]
else:
a2 += c
axiom = a2
return axiom
def draw_lsystem(axiom, rules, angle, iterations):
xp = [1]
yp = [1]
direction = 0
for c in expand(axiom, rules, iterations):
if c == "F":
xn, yn = nextPoint(xp[-1], yp[-1], direction)
xp.append(xn)
yp.append(yn)
elif c == "-":
direction = direction - angle
if direction < 0:
direction = 360 + direction
elif c == "+":
direction = (direction + angle) % 360
plt.plot(xp, yp)
plt.show()
if __name__ == '__main__':
# Sierpinski Square L-System Definition
s_axiom = "F+XF+F+XF"
s_rules = {"X": "XF-F+F-XF+F+XF-F+F-X"}
s_angle = 90
draw_lsystem(s_axiom, s_rules, s_angle, 3)
Quackery
Method is described at L-system#Quackery.
[ $ "turtleduck.qky" loadfile ] now!
[ stack ] is switch.arg ( --> [ )
[ switch.arg put ] is switch ( x --> )
[ switch.arg release ] is otherwise ( --> )
[ switch.arg share
!= iff ]else[ done
otherwise ]'[ do ]done[ ] is case ( x --> )
[ $ "" swap witheach
[ nested quackery join ] ] is expand ( $ --> $ )
[ $ "L" ] is L ( $ --> $ )
[ $ "R" ] is R ( $ --> $ )
[ $ "F" ] is F ( $ --> $ )
[ $ "AFRFLFRAFLFLAFRFLFRA" ] is A ( $ --> $ )
$ "FLAFLFLAF"
4 times expand
turtle
10 frames
witheach
[ switch
[ char L case [ -1 4 turn ]
char R case [ 1 4 turn ]
char F case [ 5 1 walk ]
otherwise ( ignore ) ] ]
1 frames
- Output:
Raku
(formerly Perl 6)
use SVG;
role Lindenmayer {
has %.rules;
method succ {
self.comb.map( { %!rules{$^c} // $c } ).join but Lindenmayer(%!rules)
}
}
my $sierpinski = 'X' but Lindenmayer( { X => 'XF-F+F-XF+F+XF-F+F-X' } );
$sierpinski++ xx 5;
my $dim = 600;
my $scale = 6;
my @points = (-80, 298);
for $sierpinski.comb {
state ($x, $y) = @points[0,1];
state $d = $scale + 0i;
when 'F' { @points.append: ($x += $d.re).round(1), ($y += $d.im).round(1) }
when /< + - >/ { $d *= "{$_}1i" }
default { }
}
my @t = @points.tail(2).clone;
my $out = './sierpinski-square-curve-perl6.svg'.IO;
$out.spurt: SVG.serialize(
svg => [
:width($dim), :height($dim),
:rect[:width<100%>, :height<100%>, :fill<black>],
:polyline[
:points((@points, map {(@t »+=» $_).clone}, ($scale,0), (0,$scale), (-$scale,0)).join: ','),
:fill<black>, :transform("rotate(45, 300, 300)"), :style<stroke:#61D4FF>,
],
:polyline[
:points(@points.map( -> $x,$y { $x, $dim - $y + 1 }).join: ','),
:fill<black>, :transform("rotate(45, 300, 300)"), :style<stroke:#61D4FF>,
],
],
);
See: Sierpinski-square-curve-perl6.svg (offsite SVG image)
Rust
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 SierpinskiSquareCurve {
current_x: f64,
current_y: f64,
current_angle: i32,
line_length: f64,
}
impl SierpinskiSquareCurve {
fn new(x: f64, y: f64, length: f64, angle: i32) -> SierpinskiSquareCurve {
SierpinskiSquareCurve {
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-F+F-XF+F+XF-F+F-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 SierpinskiSquareCurve::rewrite(order).chars() {
match ch {
'F' => data = self.draw_line(data),
'+' => self.turn(90),
'-' => self.turn(-90),
_ => {}
}
}
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, length: f64, order: usize) -> std::io::Result<()> {
use svg::node::element::Rectangle;
let x = (size as f64 - length) / 2.0;
let y = length;
let rect = Rectangle::new()
.set("width", "100%")
.set("height", "100%")
.set("fill", "white");
let mut s = SierpinskiSquareCurve::new(x, y, length, 0);
let document = svg::Document::new()
.set("width", size)
.set("height", size)
.add(rect)
.add(s.execute(order));
svg::save(file, &document)
}
}
fn main() {
SierpinskiSquareCurve::save("sierpinski_square_curve.svg", 635, 5.0, 5).unwrap();
}
- Output:
Media:Sierpinski_square_curve_rust.svg
Sidef
Uses the LSystem() class from Hilbert curve.
var rules = Hash(
x => 'xF-F+F-xF+F+xF-F+F-x',
)
var lsys = LSystem(
width: 510,
height: 510,
xoff: -505,
yoff: -254,
len: 4,
angle: 90,
color: 'dark green',
)
lsys.execute('F+xF+F+xF', 5, "sierpiński_square_curve.png", rules)
Output image: Sierpiński square curve
VBScript
Output to html (svg) displayed in the default browser. A turtle graphics class helps to keep the curve definition simple
option explicit
'outputs turtle graphics to svg file and opens it
const pi180= 0.01745329251994329576923690768489 ' pi/180
const pi=3.1415926535897932384626433832795 'pi
class turtle
dim fso
dim fn
dim svg
dim iang 'radians
dim ori 'radians
dim incr
dim pdown
dim clr
dim x
dim y
public property let orient(n):ori = n*pi180 :end property
public property let iangle(n):iang= n*pi180 :end property
public sub pd() : pdown=true: end sub
public sub pu() :pdown=FALSE :end sub
public sub rt(i)
ori=ori - i*iang:
'if ori<0 then ori = ori+pi*2
end sub
public sub lt(i):
ori=(ori + i*iang)
'if ori>(pi*2) then ori=ori-pi*2
end sub
public sub bw(l)
x= x+ cos(ori+pi)*l*incr
y= y+ sin(ori+pi)*l*incr
' ori=ori+pi '?????
end sub
public sub fw(l)
dim x1,y1
x1=x + cos(ori)*l*incr
y1=y + sin(ori)*l*incr
if pdown then line x,y,x1,y1
x=x1:y=y1
end sub
Private Sub Class_Initialize()
setlocale "us"
initsvg
x=400:y=400:incr=100
ori=90*pi180
iang=90*pi180
clr=0
pdown=true
end sub
Private Sub Class_Terminate()
disply
end sub
private sub line (x,y,x1,y1)
svg.WriteLine "<line x1=""" & x & """ y1= """& y & """ x2=""" & x1& """ y2=""" & y1 & """/>"
end sub
private sub disply()
dim shell
svg.WriteLine "</svg></body></html>"
svg.close
Set shell = CreateObject("Shell.Application")
shell.ShellExecute fn,1,False
end sub
private sub initsvg()
dim scriptpath
Set fso = CreateObject ("Scripting.Filesystemobject")
ScriptPath= Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName, "\"))
fn=Scriptpath & "SIERP.HTML"
Set svg = fso.CreateTextFile(fn,True)
if SVG IS nothing then wscript.echo "Can't create svg file" :vscript.quit
svg.WriteLine "<!DOCTYPE html>" &vbcrlf & "<html>" &vbcrlf & "<head>"
svg.writeline "<style>" & vbcrlf & "line {stroke:rgb(255,0,0);stroke-width:.5}" &vbcrlf &"</style>"
svg.writeline "</head>"&vbcrlf & "<body>"
svg.WriteLine "<svg xmlns=""http://www.w3.org/2000/svg"" width=""800"" height=""800"" viewBox=""0 0 800 800"">"
end sub
end class
'to half.sierpinski :size :level
' if :level = 0 [forward :size stop]
' half.sierpinski :size :level - 1
' left 45
' forward :size * sqrt 2
' left 45
' half.sierpinski :size :level - 1
' right 90
' forward :size
' right 90
' half.sierpinski :size :level - 1
' left 45
' forward :size * sqrt 2
' left 45
' half.sierpinski :size :level - 1
'end
const raiz2=1.4142135623730950488016887242097
sub media_sierp (niv,sz)
if niv=0 then x.fw sz: exit sub
media_sierp niv-1,sz
x.lt 1
x.fw sz*raiz2
x.lt 1
media_sierp niv-1,sz
x.rt 2
x.fw sz
x.rt 2
media_sierp niv-1,sz
x.lt 1
x.fw sz*raiz2
x.lt 1
media_sierp niv-1,sz
end sub
'to sierpinski :size :level
' half.sierpinski :size :level
' right 90
' forward :size
' right 90
' half.sierpinski :size :level
' right 90
' forward :size
' right 90
'end
sub sierp(niv,sz)
media_sierp niv,sz
x.rt 2
x.fw sz
x.rt 2
media_sierp niv,sz
x.rt 2
x.fw sz
x.rt 2
end sub
dim x
set x=new turtle
x.iangle=45
x.orient=0
x.incr=1
x.x=100:x.y=270
'star5
sierp 5,4
set x=nothing
Wren
import "graphics" for Canvas, Color
import "dome" for Window
import "math" for Math
import "./lsystem" for LSystem, Rule
var TwoPi = Num.pi * 2
class SierpinskiSquareCurve {
construct new(width, height, back, fore) {
Window.title = "Sierpinski Square Curve"
Window.resize(width, height)
Canvas.resize(width, height)
_w = width
_h = height
_bc = back
_fc = fore
}
init() {
Canvas.cls(_bc)
var cx = 10
var cy = (_h/2).floor + 5
var theta = 0
var h = 6
var lsys = LSystem.new(
["X"], // variables
["F", "+", "-"], // constants
"F+XF+F+XF", // axiom
[Rule.new("X", "XF-F+F-XF+F+XF-F+F-X")], // rules
Num.pi / 2 // angle (90 degrees in radians)
)
var result = lsys.iterate(5)
var operations = {
"F": Fn.new {
var newX = cx + h*Math.sin(theta)
var newY = cy - h*Math.cos(theta)
Canvas.line(cx, cy, newX, newY, _fc, 2)
cx = newX
cy = newY
},
"+": Fn.new {
theta = (theta + lsys.angle) % TwoPi
},
"-": Fn.new {
theta = (theta - lsys.angle) % TwoPi
}
}
LSystem.execute(result, operations)
}
update() {}
draw(alpha) {}
}
var Game = SierpinskiSquareCurve.new(770, 770, Color.blue, Color.yellow)
- Output:
zkl
Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
sierpinskiSquareCurve(4) : turtle(_);
fcn sierpinskiSquareCurve(n){ // Lindenmayer system --> Data of As
var [const] A="AF-F+F-AF+F+AF-F+F-A", B=""; // Production rules
var [const] Axiom="F+AF+F+AF";
buf1,buf2 := Data(Void,Axiom).howza(3), Data().howza(3); // characters
do(n){
buf1.pump(buf2.clear(),fcn(c){ if(c=="A") A else if(c=="B") B else c });
t:=buf1; buf1=buf2; buf2=t; // swap buffers
}
buf1 // n=4 --> 3,239 characters
}
fcn turtle(curve){ // a "square" turtle, directions are +-90*
const D=10;
ds,dir := T( T(D,0), T(0,-D), T(-D,0), T(0,D) ), 2; // turtle offsets
dx,dy := ds[dir];
img,color := PPM(650,650), 0x00ff00; // green on black
x,y := img.w/2, 10;
curve.replace("A","").replace("B",""); // A & B are no-op during drawing
foreach c in (curve){
switch(c){
case("F"){ img.line(x,y, (x+=dx),(y+=dy), color) } // draw forward
case("+"){ dir=(dir+1)%4; dx,dy = ds[dir] } // turn right 90*
case("-"){ dir=(dir-1)%4; dx,dy = ds[dir] } // turn left 90*
}
}
img.writeJPGFile("sierpinskiSquareCurve.zkl.jpg");
}
- Output:
Offsite image at Sierpinski square curve of order 4