Pythagoras tree

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

The Pythagoras tree is a fractal tree constructed from squares. It is named after Pythagoras because each triple of touching squares encloses a right triangle, in a configuration traditionally used to represent the Pythagorean theorem.

Task

Construct a Pythagoras tree of order 7 using only vectors (no rotation or trigonometric functions).

Related tasks



C[edit]

A Pythagoras tree constructed from an initial square of side length L, fits exactly in a bounding box of length 6L and width 4L(Proof). That's why the window dimensions are set to 6L x 4L, where L is entered by the user. The squares increase rapidly, an iteration value of 30 takes 'forever' for a single branch to complete. The colours are picked randomly thus producing the effect of a Pythagorean Christmas Tree. :)

Requires the WinBGIm library.

 
/*Abhishek Ghosh, 24th September 2017*/
 
#include<graphics.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
 
typedef struct{
double x,y;
}point;
 
void pythagorasTree(point a,point b,int times){
 
point c,d,e;
 
c.x = b.x - (a.y - b.y);
c.y = b.y - (b.x - a.x);
 
d.x = a.x - (a.y - b.y);
d.y = a.y - (b.x - a.x);
 
e.x = d.x + ( b.x - a.x - (a.y - b.y) ) / 2;
e.y = d.y - ( b.x - a.x + a.y - b.y ) / 2;
 
if(times>0){
setcolor(rand()%15 + 1);
 
line(a.x,a.y,b.x,b.y);
line(c.x,c.y,b.x,b.y);
line(c.x,c.y,d.x,d.y);
line(a.x,a.y,d.x,d.y);
 
pythagorasTree(d,e,times-1);
pythagorasTree(e,c,times-1);
}
}
 
int main(){
 
point a,b;
double side;
int iter;
 
time_t t;
 
printf("Enter initial side length : ");
scanf("%lf",&side);
 
printf("Enter number of iterations : ");
scanf("%d",&iter);
 
a.x = 6*side/2 - side/2;
a.y = 4*side;
b.x = 6*side/2 + side/2;
b.y = 4*side;
 
initwindow(6*side,4*side,"Pythagoras Tree ?");
 
srand((unsigned)time(&t));
 
pythagorasTree(a,b,iter);
 
getch();
 
closegraph();
 
return 0;
 
}
 
 

C++[edit]

Pythagoras treeCpp.png

Windows version

Translation of: Java
 
#include <windows.h>
#include <string>
#include <iostream>
 
const int BMP_SIZE = 720, LINE_LEN = 120, BORDER = 100;
 
class myBitmap {
public:
myBitmap() : pen( NULL ), brush( NULL ), clr( 0 ), wid( 1 ) {}
~myBitmap() {
DeleteObject( pen ); DeleteObject( brush );
DeleteDC( hdc ); DeleteObject( bmp );
}
bool create( int w, int h ) {
BITMAPINFO bi;
ZeroMemory( &bi, sizeof( bi ) );
bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biWidth = w;
bi.bmiHeader.biHeight = -h;
HDC dc = GetDC( GetConsoleWindow() );
bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
if( !bmp ) return false;
hdc = CreateCompatibleDC( dc );
SelectObject( hdc, bmp );
ReleaseDC( GetConsoleWindow(), dc );
width = w; height = h;
return true;
}
void clear( BYTE clr = 0 ) {
memset( pBits, clr, width * height * sizeof( DWORD ) );
}
void setBrushColor( DWORD bClr ) {
if( brush ) DeleteObject( brush );
brush = CreateSolidBrush( bClr );
SelectObject( hdc, brush );
}
void setPenColor( DWORD c ) {
clr = c; createPen();
}
void setPenWidth( int w ) {
wid = w; createPen();
}
void saveBitmap( std::string path ) {
BITMAPFILEHEADER fileheader;
BITMAPINFO infoheader;
BITMAP bitmap;
DWORD wb;
GetObject( bmp, sizeof( bitmap ), &bitmap );
DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
infoheader.bmiHeader.biCompression = BI_RGB;
infoheader.bmiHeader.biPlanes = 1;
infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
infoheader.bmiHeader.biHeight = bitmap.bmHeight;
infoheader.bmiHeader.biWidth = bitmap.bmWidth;
infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
fileheader.bfType = 0x4D42;
fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL );
WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
CloseHandle( file );
delete [] dwpBits;
}
HDC getDC() const { return hdc; }
int getWidth() const { return width; }
int getHeight() const { return height; }
private:
void createPen() {
if( pen ) DeleteObject( pen );
pen = CreatePen( PS_SOLID, wid, clr );
SelectObject( hdc, pen );
}
HBITMAP bmp; HDC hdc;
HPEN pen; HBRUSH brush;
void *pBits; int width, height, wid;
DWORD clr;
};
class tree {
public:
tree() {
bmp.create( BMP_SIZE, BMP_SIZE ); bmp.clear();
clr[0] = RGB( 90, 30, 0 ); clr[1] = RGB( 255, 255, 0 );
clr[2] = RGB( 0, 255, 255 ); clr[3] = RGB( 255, 255, 255 );
clr[4] = RGB( 255, 0, 0 ); clr[5] = RGB( 0, 100, 190 );
}
void draw( int it, POINT a, POINT b ) {
if( !it ) return;
bmp.setPenColor( clr[it % 6] );
POINT df = { b.x - a.x, a.y - b.y }; POINT c = { b.x - df.y, b.y - df.x };
POINT d = { a.x - df.y, a.y - df.x };
POINT e = { d.x + ( ( df.x - df.y ) / 2 ), d.y - ( ( df.x + df.y ) / 2 )};
drawSqr( a, b, c, d ); draw( it - 1, d, e ); draw( it - 1, e, c );
}
void save( std::string p ) { bmp.saveBitmap( p ); }
private:
void drawSqr( POINT a, POINT b, POINT c, POINT d ) {
HDC dc = bmp.getDC();
MoveToEx( dc, a.x, a.y, NULL );
LineTo( dc, b.x, b.y );
LineTo( dc, c.x, c.y );
LineTo( dc, d.x, d.y );
LineTo( dc, a.x, a.y );
}
myBitmap bmp;
DWORD clr[6];
};
int main( int argc, char* argv[] ) {
POINT ptA = { ( BMP_SIZE >> 1 ) - ( LINE_LEN >> 1 ), BMP_SIZE - BORDER },
ptB = { ptA.x + LINE_LEN, ptA.y };
tree t; t.draw( 12, ptA, ptB );
// change this path
t.save( "?:/pt.bmp" );
return 0;
}
 

F#[edit]

Creating an HTML file with an inline SVG. The generation of the tree is done breadth first.

type Point = { x:float; y:float }
type Line = { left : Point; right : Point }
 
let draw_start_html = """<!DOCTYPE html>
<html><head><title>Phytagoras tree</title>
<style type="
text/css">polygon{fill:none;stroke:black;stroke-width:1}</style>
</head><body>
<svg width="
640" height="640">"""
 
let draw_end_html = """Sorry, your browser does not support inline SVG.
</svg></body></html>"
""
 
let svg_square x1 y1 x2 y2 x3 y3 x4 y4 =
sprintf """<polygon points="%i %i %i %i %i %i %i %i" />"""
(int x1) (int y1) (int x2) (int y2) (int x3) (int y3) (int x4) (int y4)
 
let out (x : string) = System.Console.WriteLine(x)
 
let sprout line =
let dx = line.right.x - line.left.x
let dy = line.left.y - line.right.y
let line2 = {
left = { x = line.left.x - dy; y = line.left.y - dx };
right = { x = line.right.x - dy ; y = line.right.y - dx }
}
let triangleTop = {
x = line2.left.x + (dx - dy) / 2.;
y = line2.left.y - (dx + dy) / 2.
}
[
{ left = line2.left; right = triangleTop }
{ left = triangleTop; right = line2.right }
]
 
let draw_square line =
let dx = line.right.x - line.left.x
let dy = line.left.y - line.right.y
svg_square line.left.x line.left.y line.right.x line.right.y
(line.right.x - dy) (line.right.y - dx) (line.left.x - dy) (line.left.y - dx)
 
let rec generate lines = function
| 0 -> ()
| n ->
let next =
lines
|> List.collect (fun line ->
(draw_square >> out) line
sprout line
)
generate next (n-1)
 
 
[<EntryPoint>]
let main argv =
let depth = 1 + if argv.Length > 0 then (System.UInt32.Parse >> int) argv.[0] else 2
out draw_start_html
generate [{ left = { x = 275.; y = 500. }; right = { x = 375.; y = 500. } }] depth
out draw_end_html
0

FreeBASIC[edit]

Translation of: zkl
' version 03-12-2016
' compile with: fbc -s gui
' or fbc -s console
 
Sub pythagoras_tree(x1 As Double, y1 As Double, x2 As Double, y2 As Double, depth As ULong)
 
If depth > 10 Then Return
 
Dim As Double dx = x2 - x1, dy = y1 - y2
Dim As Double x3 = x2 - dy, y3 = y2 - dx
Dim As Double x4 = x1 - dy, y4 = y1 - dx
Dim As Double x5 = x4 + (dx - dy) / 2
Dim As Double y5 = y4 - (dx + dy) / 2
'draw the box
Line (x1, y1) - (x2, y2) : Line - (x3, y3)
Line - (x4, y4) : Line - (x1, y1)
 
pythagoras_tree(x4, y4, x5, y5, depth +1)
pythagoras_tree(x5, y5, x3, y3, depth +1)
 
End Sub
 
' ------=< MAIN >=------
' max for w is about max screensize - 500
Dim As ULong w = 800, h = w * 11 \ 16
Dim As ULong w2 = w \ 2, diff = w \ 12
 
ScreenRes w, h, 8
pythagoras_tree(w2 - diff, h -10 , w2 + diff , h -10 , 0)
' BSave "pythagoras_tree.bmp",0
 
 
 
' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End

Go[edit]

package main
 
import (
"image"
"image/color"
"image/draw"
"image/png"
"log"
"os"
)
 
const (
width, height = 800, 600
maxDepth = 11 // how far to recurse, between 1 and 20 is reasonable
colFactor = uint8(255 / maxDepth) // adjusts the colour so leaves get greener further out
fileName = "pythagorasTree.png"
)
 
func main() {
img := image.NewNRGBA(image.Rect(0, 0, width, height)) // create new image
bg := image.NewUniform(color.RGBA{255, 255, 255, 255}) // prepare white for background
draw.Draw(img, img.Bounds(), bg, image.ZP, draw.Src) // fill the background
 
drawSquares(340, 550, 460, 550, img, 0) // start off near the bottom of the image
 
imgFile, err := os.Create(fileName)
if err != nil {
log.Fatal(err)
}
defer imgFile.Close()
if err := png.Encode(imgFile, img); err != nil {
imgFile.Close()
log.Fatal(err)
}
}
 
func drawSquares(ax, ay, bx, by int, img *image.NRGBA, depth int) {
if depth > maxDepth {
return
}
dx, dy := bx-ax, ay-by
x3, y3 := bx-dy, by-dx
x4, y4 := ax-dy, ay-dx
x5, y5 := x4+(dx-dy)/2, y4-(dx+dy)/2
col := color.RGBA{0, uint8(depth) * colFactor, 0, 255}
drawLine(ax, ay, bx, by, img, col)
drawLine(bx, by, x3, y3, img, col)
drawLine(x3, y3, x4, y4, img, col)
drawLine(x4, y4, ax, ay, img, col)
drawSquares(x4, y4, x5, y5, img, depth+1)
drawSquares(x5, y5, x3, y3, img, depth+1)
}
 
func drawLine(x0, y0, x1, y1 int, img *image.NRGBA, col color.RGBA) {
dx := abs(x1 - x0)
dy := abs(y1 - y0)
var sx, sy int = -1, -1
if x0 < x1 {
sx = 1
}
if y0 < y1 {
sy = 1
}
err := dx - dy
for {
img.Set(x0, y0, col)
if x0 == x1 && y0 == y1 {
break
}
e2 := 2 * err
if e2 > -dy {
err -= dy
x0 += sx
}
if e2 < dx {
err += dx
y0 += sy
}
}
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}

Haskell[edit]

Haskell allows us to make highly modular solution.

Firstly, we define a function mkBranches that produces a pair of minor squares based on a given square. Each square is represented as a list of points.

mkBranches :: [(Float,Float)] -> [[(Float,Float)]]
mkBranches [a, b, c, d] = let d = 0.5 <*> (b <+> (-1 <*> a))
l1 = d <+> orth d
l2 = orth l1
in
[ [a <+> l2, b <+> (2 <*> l2), a <+> l1, a]
, [a <+> (2 <*> l1), b <+> l1, b, b <+> l2] ]
where
(a, b) <+> (c, d) = (a+c, b+d)
n <*> (a, b) = (a*n, b*n)
orth (a, b) = (-b, a)

We then create squares using mkBranches to build a list representing the set of squares. In order to apply this function iteratively to form a 10-generation tree, we also have to define the monadic iteration iterateM within squares.

squares = concat $ take 10 $ iterateM mkBranches start
where start = [(0,100),(100,100),(100,0),(0,0)]
iterateM f x = iterate (>>= f) (pure x)

The raw result returned by squares should be used in the main function in order to be displayed in a new window, saved directly to a SVG file, or printed to a bitmap file.

Window output

Library: Gloss
--import should go to the top of the code
import Graphics.Gloss
 
main = display (InWindow "Pithagoras tree" (400, 400) (0, 0)) white tree
where tree = foldMap lineLoop squares

SVG file

main = writeFile "pith.svg" svg
where svg = "<svg " ++ attrs ++ foldMap (mkLine . close) squares ++ "</svg>"
attrs = "fill='none' stroke='black' height='400' width='600'>"
mkLine path = "<polyline points ='" ++ foldMap mkPoint path ++ "'/>"
mkPoint (x,y) = show (250+x) ++ "," ++ show (400-y) ++ " "
close lst = lst ++ [head lst]

Bitmap image

Library: easyplot
--import should go to the top of the code
import Graphics.EasyPlot
 
--change PNG by the desired format
main = plot (PNG "pith.png") $ map (mkLine . close) squares
where mkLine = Data2D [Style Lines, Color Black,Title ""] []
close lst = lst ++ [head lst]

Java[edit]

Pythagoras tree java.png
Works with: Java version 8
import java.awt.*;
import java.awt.geom.Path2D;
import javax.swing.*;
 
public class PythagorasTree extends JPanel {
final int depthLimit = 7;
float hue = 0.15f;
 
public PythagorasTree() {
setPreferredSize(new Dimension(640, 640));
setBackground(Color.white);
}
 
private void drawTree(Graphics2D g, float x1, float y1, float x2, float y2,
int depth) {
 
if (depth == depthLimit)
return;
 
float dx = x2 - x1;
float dy = y1 - y2;
 
float x3 = x2 - dy;
float y3 = y2 - dx;
float x4 = x1 - dy;
float y4 = y1 - dx;
float x5 = x4 + 0.5F * (dx - dy);
float y5 = y4 - 0.5F * (dx + dy);
 
Path2D square = new Path2D.Float();
square.moveTo(x1, y1);
square.lineTo(x2, y2);
square.lineTo(x3, y3);
square.lineTo(x4, y4);
square.closePath();
 
g.setColor(Color.getHSBColor(hue + depth * 0.02f, 1, 1));
g.fill(square);
g.setColor(Color.lightGray);
g.draw(square);
 
Path2D triangle = new Path2D.Float();
triangle.moveTo(x3, y3);
triangle.lineTo(x4, y4);
triangle.lineTo(x5, y5);
triangle.closePath();
 
g.setColor(Color.getHSBColor(hue + depth * 0.035f, 1, 1));
g.fill(triangle);
g.setColor(Color.lightGray);
g.draw(triangle);
 
drawTree(g, x4, y4, x5, y5, depth + 1);
drawTree(g, x5, y5, x3, y3, depth + 1);
}
 
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawTree((Graphics2D) g, 275, 500, 375, 500, 0);
}
 
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Pythagoras Tree");
f.setResizable(false);
f.add(new PythagorasTree(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

JavaScript[edit]

Translation of: Java
<!DOCTYPE html>
<html lang="en">
 
<head>
<meta charset="UTF-8">
<style>
canvas {
position: absolute;
top: 45%;
left: 50%;
width: 640px;
height: 640px;
margin: -320px 0 0 -320px;
}
</style>
</head>
 
<body>
<canvas></canvas>
<script>
'use strict';
var canvas = document.querySelector('canvas');
canvas.width = 640;
canvas.height = 640;
 
var g = canvas.getContext('2d');
 
var depthLimit = 7;
var hue = 0.15;
 
function drawTree(x1, y1, x2, y2, depth) {
 
if (depth == depthLimit)
return;
 
var dx = x2 - x1;
var dy = y1 - y2;
 
var x3 = x2 - dy;
var y3 = y2 - dx;
var x4 = x1 - dy;
var y4 = y1 - dx;
var x5 = x4 + 0.5 * (dx - dy);
var y5 = y4 - 0.5 * (dx + dy);
 
g.beginPath();
g.moveTo(x1, y1);
g.lineTo(x2, y2);
g.lineTo(x3, y3);
g.lineTo(x4, y4);
g.closePath();
 
g.fillStyle = HSVtoRGB(hue + depth * 0.02, 1, 1);
g.fill();
g.strokeStyle = "lightGray";
g.stroke();
 
g.beginPath();
g.moveTo(x3, y3);
g.lineTo(x4, y4);
g.lineTo(x5, y5);
g.closePath();
 
g.fillStyle = HSVtoRGB(hue + depth * 0.035, 1, 1);
g.fill();
g.strokeStyle = "lightGray";
g.stroke();
 
drawTree(x4, y4, x5, y5, depth + 1);
drawTree(x5, y5, x3, y3, depth + 1);
}
 
/* copied from stackoverflow */
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
 
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return "rgb("
+ Math.round(r * 255) + ","
+ Math.round(g * 255) + ","
+ Math.round(b * 255) + ")";
}
 
function draw() {
g.clearRect(0, 0, canvas.width, canvas.height);
drawTree(275, 500, 375, 500, 0);
}
draw();
</script>
 
</body>
 
</html>

Kotlin[edit]

Translation of: Java
// version 1.1.2
 
import java.awt.*
import java.awt.geom.Path2D
import javax.swing.*
 
class PythagorasTree : JPanel() {
val depthLimit = 7
val hue = 0.15f
 
init {
preferredSize = Dimension(640, 640)
background = Color.white
}
 
private fun drawTree(g: Graphics2D, x1: Float, y1: Float,
x2: Float, y2: Float, depth: Int) {
if (depth == depthLimit) return
 
val dx = x2 - x1
val dy = y1 - y2
 
val x3 = x2 - dy
val y3 = y2 - dx
val x4 = x1 - dy
val y4 = y1 - dx
val x5 = x4 + 0.5f * (dx - dy)
val y5 = y4 - 0.5f * (dx + dy)
 
val square = Path2D.Float()
with (square) {
moveTo(x1, y1)
lineTo(x2, y2)
lineTo(x3, y3)
lineTo(x4, y4)
closePath()
}
 
g.color = Color.getHSBColor(hue + depth * 0.02f, 1.0f, 1.0f)
g.fill(square)
g.color = Color.lightGray
g.draw(square)
 
val triangle = Path2D.Float()
with (triangle) {
moveTo(x3, y3)
lineTo(x4, y4)
lineTo(x5, y5)
closePath()
}
 
g.color = Color.getHSBColor(hue + depth * 0.035f, 1.0f, 1.0f)
g.fill(triangle)
g.color = Color.lightGray
g.draw(triangle)
 
drawTree(g, x4, y4, x5, y5, depth + 1)
drawTree(g, x5, y5, x3, y3, depth + 1)
}
 
override fun paintComponent(g: Graphics) {
super.paintComponent(g)
drawTree(g as Graphics2D, 275.0f, 500.0f, 375.0f, 500.0f, 0)
}
}
 
fun main(args: Array<String>) {
SwingUtilities.invokeLater {
val f = JFrame()
with (f) {
defaultCloseOperation = JFrame.EXIT_ON_CLOSE
title = "Pythagoras Tree"
isResizable = false
add(PythagorasTree(), BorderLayout.CENTER)
pack()
setLocationRelativeTo(null);
setVisible(true)
}
}
}

PARI/GP[edit]

Output PythTree1.png

This version with recursion, in general, is a translation of zkl version. Almost "as is", so, outputting upside-down tree.

Translation of: zkl
Works with: PARI/GP version 2.7.4 and above
 
\\ Pythagoras Tree (w/recursion)
\\ 4/11/16 aev
plotline(x1,y1,x2,y2)={plotmove(0, x1,y1);plotrline(0,x2-x1,y2-y1);}
 
pythtree(ax,ay,bx,by,d=0)={
my(dx,dy,x3,y3,x4,y4,x5,y5);
if(d>10, return());
dx=bx-ax; dy=ay-by;
x3=bx-dy; y3=by-dx;
x4=ax-dy; y4=ay-dx;
x5=x4+(dx-dy)\2; y5=y4-(dx+dy)\2;
plotline(ax,ay,bx,by);
plotline(bx,by,x3,y3);
plotline(x3,y3,x4,y4);
plotline(x4,y4,ax,ay);
pythtree(x4,y4,x5,y5,d+1);
pythtree(x5,y5,x3,y3,d+1);
}
 
PythagorTree(x1,y1,x2,y2,depth=9,size)={
my(dx=1,dy=0,ttlb="Pythagoras Tree, depth ",ttl=Str(ttlb,depth));
print1(" *** ",ttl); print(", size ",size);
print(" *** Start: ",x1,",",y1,",",x2,",",y2);
plotinit(0);
plotcolor(0,6); \\green
plotscale(0, -size,size, size,0 );
plotmove(0, 0,0);
pythtree(x1,y1, x2,y2);
plotdraw([0,size,size]);
}
 
{\\ Executing:
PythagorTree(275,500,375,500,9,640); \\PythTree1.png
}
 
Output:
 *** Pythagoras Tree, depth 9, size 640
 *** Start: 275,500,375,500

Perl[edit]

Translation of: Sidef
use Imager;
 
sub tree {
my ($img, $x1, $y1, $x2, $y2, $depth) = @_;
 
return () if $depth <= 0;
 
my $dx = ($x2 - $x1);
my $dy = ($y1 - $y2);
 
my $x3 = ($x2 - $dy);
my $y3 = ($y2 - $dx);
my $x4 = ($x1 - $dy);
my $y4 = ($y1 - $dx);
my $x5 = ($x4 + 0.5 * ($dx - $dy));
my $y5 = ($y4 - 0.5 * ($dx + $dy));
 
# Square
$img->polygon(
points => [
[$x1, $y1],
[$x2, $y2],
[$x3, $y3],
[$x4, $y4],
],
color => [0, 255 / $depth, 0],
);
 
# Triangle
$img->polygon(
points => [
[$x3, $y3],
[$x4, $y4],
[$x5, $y5],
],
color => [0, 255 / $depth, 0],
);
 
tree($img, $x4, $y4, $x5, $y5, $depth - 1);
tree($img, $x5, $y5, $x3, $y3, $depth - 1);
}
 
my ($width, $height) = (1920, 1080);
my $img = Imager->new(xsize => $width, ysize => $height);
$img->box(filled => 1, color => 'white');
tree($img, $width/2.3, $height, $width/1.8, $height, 10);
$img->write(file => 'pythagoras_tree.png');

Perl 6[edit]

We'll generate a SVG image.

 
class Square {
has Complex ($.position, $.edge);
method size { $!edge.abs }
method svg-polygon {
qq[<polygon points="{join ' ', map
{ ($!position + $_ * $!edge).reals.join(',') },
0, 1, 1+1i, 1i}"
style="fill:lime;stroke=black" />]
}
method left-child {
self.new:
position => $!position + i*$!edge,
edge => sqrt(2)/2*cis(pi/4)*$!edge;
}
method right-child {
self.new:
position => $!position + i*$!edge + self.left-child.edge,
edge => sqrt(2)/2*cis(-pi/4)*$!edge;
}
}
 
BEGIN say '<svg width="500" height="500">';
END say '</svg>';
 
sub tree(Square $s, $level = 0) {
return if $level > 8;
say $s.svg-polygon;
tree($s.left-child, $level+1);
tree($s.right-child, $level+1);
}
 
tree Square.new: :position(250+0i), :edge(60+0i);

Phix[edit]

Translation of: Java
Library: pGUI
--
-- demo\rosetta\PythagorasTree.exw
--
include pGUI.e
 
Ihandle dlg, canvas
cdCanvas cddbuffer, cdcanvas
 
function rgb(integer r, integer g, integer b)
return r*#10000 + g*#100 + b
end function
 
procedure drawTree(atom x1, atom y1, atom x2, atom y2, integer depth)
atom dx = x2 - x1
atom dy = y1 - y2
 
atom x3 = x2 - dy
atom y3 = y2 - dx
atom x4 = x1 - dy
atom y4 = y1 - dx
atom x5 = x4 + 0.5 * (dx - dy)
atom y5 = y4 - 0.5 * (dx + dy)
 
integer r = 250-depth*20
 
cdCanvasSetForeground(cddbuffer, rgb(r,#FF,0))
cdCanvasBegin(cddbuffer,CD_FILL)
cdCanvasVertex(cddbuffer, x1, 640-y1)
cdCanvasVertex(cddbuffer, x2, 640-y2)
cdCanvasVertex(cddbuffer, x3, 640-y3)
cdCanvasVertex(cddbuffer, x4, 640-y4)
cdCanvasEnd(cddbuffer)
 
cdCanvasSetForeground(cddbuffer, CD_GRAY)
cdCanvasBegin(cddbuffer,CD_CLOSED_LINES)
cdCanvasVertex(cddbuffer, x1, 640-y1)
cdCanvasVertex(cddbuffer, x2, 640-y2)
cdCanvasVertex(cddbuffer, x3, 640-y3)
cdCanvasVertex(cddbuffer, x4, 640-y4)
cdCanvasEnd(cddbuffer)
 
cdCanvasSetForeground(cddbuffer, rgb(r-depth*10,#FF,0))
cdCanvasBegin(cddbuffer,CD_FILL)
cdCanvasVertex(cddbuffer, x3, 640-y3)
cdCanvasVertex(cddbuffer, x4, 640-y4)
cdCanvasVertex(cddbuffer, x5, 640-y5)
cdCanvasEnd(cddbuffer)
 
cdCanvasSetForeground(cddbuffer, CD_GRAY)
cdCanvasBegin(cddbuffer,CD_CLOSED_LINES)
cdCanvasVertex(cddbuffer, x3, 640-y3)
cdCanvasVertex(cddbuffer, x4, 640-y4)
cdCanvasVertex(cddbuffer, x5, 640-y5)
cdCanvasEnd(cddbuffer)
 
if depth<8 then
drawTree(x4, y4, x5, y5, depth + 1)
drawTree(x5, y5, x3, y3, depth + 1)
end if
end procedure
 
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
cdCanvasActivate(cddbuffer)
drawTree(275, 500, 375, 500, 0)
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function
 
function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih)
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
cdCanvasSetBackground(cddbuffer, CD_WHITE)
cdCanvasSetForeground(cddbuffer, CD_RED)
return IUP_DEFAULT
end function
 
function esc_close(Ihandle /*ih*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
return IUP_CONTINUE
end function
 
procedure main()
IupOpen()
 
canvas = IupCanvas(NULL)
IupSetAttribute(canvas, "RASTERSIZE", "640x640")
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
 
dlg = IupDialog(canvas,"RESIZE=NO")
IupSetAttribute(dlg, "TITLE", "Pythagoras Tree")
IupSetCallback(dlg, "K_ANY", Icallback("esc_close"))
 
IupShow(dlg)
IupMainLoop()
IupClose()
end procedure
 
main()

Processing[edit]

Translation of: Sidef
void tree(float x1, float y1, float x2, float y2, int depth) {
 
if (depth <= 0) {
return;
}
 
float dx = (x2 - x1);
float dy = (y1 - y2);
 
float x3 = (x2 - dy);
float y3 = (y2 - dx);
float x4 = (x1 - dy);
float y4 = (y1 - dx);
float x5 = (x4 + 0.5*(dx - dy));
float y5 = (y4 - 0.5*(dx + dy));
 
// square
beginShape();
fill(0.0, 255.0/depth, 0.0);
vertex(x1, y1);
vertex(x2, y2);
vertex(x3, y3);
vertex(x4, y4);
vertex(x1, y1);
endShape();
 
// triangle
beginShape();
fill(0.0, 255.0/depth, 0.0);
vertex(x3, y3);
vertex(x4, y4);
vertex(x5, y5);
vertex(x3, y3);
endShape();
 
tree(x4, y4, x5, y5, depth-1);
tree(x5, y5, x3, y3, depth-1);
}
 
void setup() {
size(1920, 1080);
background(255);
stroke(0, 255, 0);
tree(width/2.3, height, width/1.8, height, 10);
}

PurePasic[edit]

Translation of: FreeBasic
EnableExplicit
DisableDebugger
 
Procedure.d maxXY(a.d,b.d,c.d,d.d)
If a<b : Swap a,b : EndIf
If a<c : Swap a,c : EndIf
If a<d : Swap a,d : EndIf
ProcedureReturn a
EndProcedure
 
Procedure.d minXY(a.d,b.d,c.d,d.d)
If a>b : Swap a,b : EndIf
If a>c : Swap a,c : EndIf
If a>d : Swap a,d : EndIf
ProcedureReturn a
EndProcedure
 
Procedure Ptree(x1.d, y1.d, x2.d, y2.d, d.i=0)
If d>10 : ProcedureReturn : EndIf
 
Define dx.d=x2-x1,
dy.d=y1-y2,
x3.d=x2-dy,
y3.d=y2-dx,
x4.d=x1-dy,
y4.d=y1-dx,
x5.d=x4+(dx-dy)/2.0,
y5.d=y4-(dx+dy)/2.0,
p1.d=(maxXY(x1,x2,x3,x4)+minXY(x1,x2,x3,x4))/2.0,
p2.d=(maxXY(y1,y2,y3,y4)+minXY(y1,y2,y3,y4))/2.0,
p3.d=(maxXY(x1,x2,x3,x4)-minXY(x1,x2,x3,x4))
 
FrontColor(RGB(Random(125,1),Random(255,125),Random(125,1)))
LineXY(x1,y1,x2,y2)
LineXY(x2,y2,x3,y3)
LineXY(x3,y3,x4,y4)
LineXY(x4,y4,x1,y1)
BoxedGradient(minXY(x1,x2,x3,x4),minXY(y1,y2,y3,y4),p3,p3)
FillArea(p1,p2,-1)
 
Ptree(x4,y4,x5,y5,d+1)
Ptree(x5,y5,x3,y3,d+1)
 
EndProcedure
 
Define w1.i=800,
h1.i=w1*11/16,
w2.i=w1/2,
di.i=w1/12
 
If OpenWindow(0,#PB_Ignore,#PB_Ignore,w1,h1,"Pythagoras tree")
If CreateImage(0,w1,h1,24,0) And StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_Gradient)
BackColor($000000)
Ptree(w2-di,h1-10,w2+di,h1-10)
StopDrawing()
EndIf
ImageGadget(0,0,0,0,0,ImageID(0))
Repeat : Until WaitWindowEvent(50)=#PB_Event_CloseWindow
EndIf
End

R[edit]

Translation of: PARI/GP
Works with: R version 3.3.3 and above
File:PYTHTR9.png
Output PYTHTR9.png
File:PYTHTR7.png
Output PYTHTR7.png
 
## Recursive PT plotting
pythtree <- function(ax,ay,bx,by,d) {
if(d<0) {return()}; clr="darkgreen";
dx=bx-ax; dy=ay-by;
x3=bx-dy; y3=by-dx;
x4=ax-dy; y4=ay-dx;
x5=x4+(dx-dy)/2; y5=y4-(dx+dy)/2;
segments(ax,-ay,bx,-by, col=clr);
segments(bx,-by,x3,-y3, col=clr);
segments(x3,-y3,x4,-y4, col=clr);
segments(x4,-y4,ax,-ay, col=clr);
pythtree(x4,y4,x5,y5,d-1);
pythtree(x5,y5,x3,y3,d-1);
}
## Plotting Pythagoras Tree. aev 3/27/17
## x1,y1,x2,y2 - starting position
## ord - order/depth, fn - file name, ttl - plot title.
pPythagorasT <- function(x1, y1,x2, y2, ord, fn="", ttl="") {
cat(" *** START PYTHT:", date(), "\n");
m=640; i=j=k=m1=m-2; x=y=d=dm=0;
if(fn=="") {pf=paste0("PYTHTR", ord, ".png")} else {pf=paste0(fn, ".png")};
if(ttl=="") {ttl=paste0("Pythagoras tree, order - ", ord)};
cat(" *** Plot file -", pf, "title:", ttl, "\n");
plot(NA, xlim=c(0,m), ylim=c(-m,0), xlab="", ylab="", main=ttl);
pythtree(x1,y1, x2,y2, ord);
dev.copy(png, filename=pf, width=m, height=m);
dev.off(); graphics.off();
cat(" *** END PYTHT:",date(),"\n");
}
## Executing:
pPythagorasT(275,500,375,500,9)
pPythagorasT(275,500,375,500,7)
 
Output:
> pPythagorasT(275,500,375,500,9) 
 *** START PYTHT: Tue Mar 28 15:57:19 2017 
 *** Plot file - PYTHTR9.png title: Pythagoras tree, order - 9 
 *** END PYTHT: Tue Mar 28 15:57:20 2017 
> pPythagorasT(275,500,375,500,7) 
 *** START PYTHT: Tue Mar 28 15:59:25 2017 
 *** Plot file - PYTHTR7.png title: Pythagoras tree, order - 7 
 *** END PYTHT: Tue Mar 28 15:59:25 2017 

Racket[edit]

#lang racket
(require racket/draw pict)
 
(define (draw-pythagoras-tree order x0 y0 x1 y1)
(λ (the-dc dx dy)
(define (inr order x0 y0 x1 y1)
(when (positive? order)
(let* ((y0-1 (- y0 y1))
(x1-0 (- x1 x0))
(x2 (+ x1 y0-1))
(y2 (+ y1 x1-0))
(x3 (+ x0 y0-1))
(y3 (+ y0 x1-0))
(x4 (+ x2 x3 (/ (+ x0 x2) -2)))
(y4 (+ y2 y3 (/ (+ y0 y2) -2)))
(path (new dc-path%)))
(send* path [move-to x0 y0]
[line-to x1 y1] [line-to x2 y2] [line-to x3 y3]
[close])
(send the-dc draw-path path dx dy)
(inr (sub1 order) x3 y3 x4 y4)
(inr (sub1 order) x4 y4 x2 y2))))
 
(define old-brush (send the-dc get-brush))
(define old-pen (send the-dc get-pen))
(send the-dc set-pen (new pen% [width 1] [color "black"]))
(inr (add1 order) x0 y0 x1 y1)
(send the-dc set-brush old-brush)
(send the-dc set-pen old-pen)))
 
(dc (draw-pythagoras-tree 7 (+ 200 32) 255 (- 200 32) 255) 400 256)

Scilab[edit]

L-System approach[edit]

This solution uses complex numbers to represent vectors, and it draws the contour of the tree. By "uncommenting" the six commented lines inside the select structure, it will also draw the triangles between the squares. The output is a new graphic window.

side = 1;       //side length of the square
depth = 8; //final number of branch levels
 
//L-system definition:
//Alphabet: UTDB+-[]
//U: go upwards T: top of the square
//D: go downwards B: bottom of the square
//[: start new branch ]: end current branch
//+: branch to the right -: branch to the left
//Axiom: UTDB
//Rule: T -> [+UTD-UTD]
 
//L-system sentence generation
sentence = 'UTDB'
rule = '[+UTD-UTD]';
for i=1:depth
sentence = strsubst(sentence,'T',rule);
end
sentence = strsplit(sentence)';
 
//Empty tree
tree_size = 1.0...
+ length(find(sentence == "U" | sentence == "T" |...
sentence == "D" | sentence == "B"))...
+ 2 * length(find(sentence == "]" | sentence == "-" |...
sentence == "+"));
tree=zeros(tree_size,1);
 
//Vectorial operation to calculate a new point in the tree
deff('z = new_point(origin,rho,theta)',...
'z = origin + rho * exp(%i*theta)');
 
//Drawing the tree
curr_angle = %pi/2;
curr_pos = 1;
ratio = 1/sqrt(2);
for ind = 1:size(sentence,'c')
charac = sentence(ind);
 
select charac
case 'U' then //Draw line upwards
tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
curr_pos = curr_pos + 1;
 
case 'T' then //Draw top of the square
curr_angle = curr_angle - %pi/2;
tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
curr_pos = curr_pos + 1;
 
case 'D' then //Draw line downwards
curr_angle = curr_angle - %pi/2;
tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
curr_pos = curr_pos + 1;
 
case 'B' then //Draw the bottom
curr_angle = curr_angle - %pi/2;
tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
curr_pos = curr_pos + 1;
 
case '[' then //Start branch
side = side * ratio;
 
case '+' then //Start going to the left
curr_angle = curr_angle - %pi/4;
// tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
// tree(curr_pos+2) = new_point(tree(curr_pos+1),side,%pi+curr_angle);
// curr_pos = curr_pos + 2;
curr_angle = curr_angle + %pi/2;
 
case '-' then //Start going to the left
// tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
// tree(curr_pos+2) = new_point(tree(curr_pos+1),side,%pi+curr_angle);
// curr_pos = curr_pos + 2;
curr_angle = curr_angle + %pi/2;
case ']' then
side = side / ratio;
curr_angle = curr_angle - %pi/4;
// tree(curr_pos+1) = new_point(tree(curr_pos),side,curr_angle);
// tree(curr_pos+2) = new_point(tree(curr_pos+1),side,%pi+curr_angle);
// curr_pos = curr_pos + 2;
curr_angle = curr_angle + %pi;
 
else
error('L-system sentence error');
end
end
 
scf(); clf();
xname('Pythagoras tree: '+string(depth)+' levels')
plot2d(real(tree),imag(tree),14);
set(gca(),'isoview','on');
set(gca(),'axes_visible',['off','off','off']);

Recursive approach[edit]

A minor change was made so that the final depth of the tree is an argument of fcn, and not a condition set within itself.

Translation of: zkl
function []=fcn(bitmap,ax,ay,bx,by,depth)
if depth < 0 then
return
end
 
dx = bx - ax; dy = ay - by;
x3 = bx + dy; y3 = by + dx;
x4 = ax + dy; y4 = ay + dx;
x5 = x4 + (dx + dy)/2; y5 = y4 + (dx - dy)/2;
 
scf(bitmap);
plot2d([x3 x4 x5],[y3 y4 y5],-2)
plot2d([ax bx],[ay by]); plot2d([bx x3],[by y3]);
plot2d([x3 x4],[y3 y4]); plot2d([x4 ax],[y4 ay]);
 
fcn(bitmap,x4,y4,x5,y5,depth-1);
fcn(bitmap,x5,y5,x3,y3,depth-1);
endfunction
 
plot_win = scf();
final_depth = 8;
clf();
 
fcn(plot_win,275,500,375,500,final_depth)
 
scf(plot_win);
xname('Pythagoras tree: '+string(final_depth)+' levels');
set(gca(),'isoview','on');
set(gca(),'axes_visible',['off','off','off']);

Sidef[edit]

Translation of: Java
require('Imager')
 
func tree(img, x1, y1, x2, y2, depth) {
 
depth <= 0 && return()
 
var dx = (x2 - x1)
var dy = (y1 - y2)
 
var x3 = (x2 - dy)
var y3 = (y2 - dx)
var x4 = (x1 - dy)
var y4 = (y1 - dx)
var x5 = (x4 + 0.5*(dx - dy))
var y5 = (y4 - 0.5*(dx + dy))
 
# square
img.polygon(
points => [
[x1, y1],
[x2, y2],
[x3, y3],
[x4, y4],
],
color => [0, 255/depth, 0],
)
 
# triangle
img.polygon(
points => [
[x3, y3],
[x4, y4],
[x5, y5],
],
color => [0, 255/depth, 0],
)
 
tree(img, x4, y4, x5, y5, depth - 1)
tree(img, x5, y5, x3, y3, depth - 1)
}
 
var (width=1920, height=1080)
var img = %s<Imager>.new(xsize => width, ysize => height)
img.box(filled => 1, color => 'white')
tree(img, width/2.3, height, width/1.8, height, 10)
img.write(file => 'pythagoras_tree.png')

zkl[edit]

I added green crosses at three of the vertexes of the new square to simulate leaves on the tree.

Translation of: Java

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

PythagorasTreeWithLeafs.zkl.jpg
fcn pythagorasTree{
bitmap:=PPM(640,640,0xFF|FF|FF); // White background
 
fcn(bitmap, ax,ay, bx,by, depth=0){
if(depth>10) return();
dx,dy:=bx-ax, ay-by;
x3,y3:=bx-dy, by-dx;
x4,y4:=ax-dy, ay-dx;
x5,y5:=x4 + (dx - dy)/2, y4 - (dx + dy)/2;
bitmap.cross(x3,y3);bitmap.cross(x4,y4);bitmap.cross(x5,y5);
bitmap.line(ax,ay, bx,by, 0); bitmap.line(bx,by, x3,y3, 0);
bitmap.line(x3,y3, x4,y4, 0); bitmap.line(x4,y4, ax,ay, 0);
 
self.fcn(bitmap,x4,y4, x5,y5, depth+1);
self.fcn(bitmap,x5,y5, x3,y3, depth+1);
}(bitmap,275,500, 375,500);
 
bitmap.writeJPGFile("pythagorasTree.jpg",True);
}();