Create a gist now

Instantly share code, notes, and snippets.

Embed
Pythagorean Tree - draw a PTree using HTML5 canvas
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<canvas id="ptcanvas" width="400" height="400" style="border:1px dotted;float:left"></canvas>
<script>
function draw_square( ctx, x1, y1, x2, y2, x3, y3, x4, y4 )
{
ctx.beginPath( ) ;
ctx.moveTo( x1, y1 ) ;
ctx.lineTo( x2, y2 ) ;
ctx.lineTo( x3, y3 ) ;
ctx.lineTo( x4, y4 ) ;
ctx.lineTo( x1, y1 ) ;
ctx.fill( ) ;
ctx.closePath( ) ;
}
// Squares should always have vertices 1 and 4 as the base, with 1 always being the left of the base.
// The base of a child square is the one sitting on the isosceles right triangle formed with the parent.
// For example, the left child's 1 and 4 vertices match up with the 2 vertex of the parent
// and the top of the isosceles triangle. The right child's 1 and 4 are the top of the
// triangle and vertex 3 of the parent.
// /\
// / \ <-- bases of children, the rays (1-2 and 4-3) calculated below shoot up to form the diagonal of the child
// 2 -- 3
// | |
// 1 -- 4
function recurse_tree( ctx, x1, y1, x3, y3, swap, level, MAXLEVEL )
{
// TRUNK
var xc, xd, x2, y2, x4, y4 ;
xc = (x1 + x3)/2.0 ; yc = (y1 + y3)/2.0 ; // center point of square - credit to http://math.stackexchange.com/a/506853
xd = (x1 - x3)/2.0 ; yd = (y1 - y3)/2.0 ; // rays representing the half-diagonals
x2 = xc - yd ; y2 = yc + xd ; // corner 2
x4 = xc + yd ; y4 = yc - xd ; // corner 4
if( swap ) // this was the "rightward" child (base formed by top and vertex 3 above),
// meaning the 1 & 3 points passed should actually be 4 & 2 so the diagonal is the correct one:
// the "leftward" child's diagonal goes from its 1 to 3 vertex and is formed from the parent's 1->2 ray,
// so the "rightward" child must be adjusted so the diagonal runs 1->3 similarly instead of between 4->2
{
var tx = x4 ; var ty = y4 ;
x4 = x1 ; y4 = y1 ;
x1 = x2 ; y1 = y2 ;
x2 = x3 ; y2 = y3 ;
x3 = tx ; y3 = ty ;
}
draw_square( ctx, x1, y1, x2, y2, x3, y3, x4, y4 ) ;
// only draw the leaves if we need to go another level deeper
level++;
if( level >= MAXLEVEL )
return ;
// LEAVES
// draw these by shooting rays from the two base corners in the direction of the child to form their hypotenuses
// the child hypotenuses are the same length as the sides of the parent
var rayX = x2-x1 ; var rayY = y2-y1 ;
recurse_tree( ctx, x2, y2, x2+rayX, y2+rayY, false, level, MAXLEVEL ) ;
var rayX = x3-x4 ; var rayY = y3-y4 ;
// this diagonal is the wrong diagonal based on the assumption of the function, set swap to true to switch them; see if comment above
recurse_tree( ctx, x3, y3, x3+rayX, y3+rayY, true, level, MAXLEVEL) ;
}
// (x,y) is the base of the square, the BOTTOM side
function draw_pythagoras_tree( canvas, x, y, slength, maxLevel )
{
var ctx = canvas.getContext( "2d" ) ;
ctx.fillStyle = "#FF0000" ;
recurse_tree( ctx, x, y, x+slength, y-slength, false, 0, maxLevel ) ;
}
draw_pythagoras_tree( document.getElementById( "ptcanvas" ), 175, 350, 50, 12 ) ;
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment