diff --git a/CHANGELOG.md b/CHANGELOG.md index e30fbf5..7aaa9ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## Turtle 0.1.10: + +* Updated Methods + * `Turtle.Star` even point fix (#190) + * `Turtle.Polygon` partial polygon support (#194) +* New Shapes + * `Turtle.Rectangle` (#192) + * `Turtle.StarFlower` (#191) + * `Turtle.GoldenFlower` (#193) + * `Turtle.HatMonotile` (#196) + * `Turtle.TurtleMonotile` (#195) + * `Turtle.BarGraph` (#173) +* Added Demos + * Intro To Turtles (#197) + +--- + ## Turtle 0.1.9: * Turtle Text Path Support diff --git a/Commands/Get-Turtle.ps1 b/Commands/Get-Turtle.ps1 index 9cc58ed..916a7df 100644 --- a/Commands/Get-Turtle.ps1 +++ b/Commands/Get-Turtle.ps1 @@ -188,6 +188,54 @@ function Get-Turtle { $flowerPetals2, $flowerPetals ) + .EXAMPLE + # We can create a Star with N points + turtle star 42 5 + + turtle star 42 6 + + turtle star 42 7 + + turtle star 42 8 + .EXAMPLE + # Stars look spectacular when we rotate and repeat them + turtle @('star',42,5,'rotate',72 * 5) + + turtle @('star',42,6,'rotate',60 * 6) + + turtle @('star',42,7,'rotate',(360/7) * 7) + + turtle @('star',42,8,'rotate',45 * 8) + .EXAMPLE + # When we do this, we call it a Star Flower + turtle StarFlower 42 + .EXAMPLE + turtle StarFlower 42 45 8 8 + .EXAMPLE + turtle StarFlower 42 45 8 8 + .EXAMPLE + # StarFlowers look spectacular when morphed + turtle StarFlower 42 45 8 24 morph @( + turtle StarFlower 42 45 8 24 + turtle StarFlower 42 15 8 24 + turtle StarFlower 42 45 8 24 + ) + .EXAMPLE + # We can rotate the points we morph into. + turtle StarFlower 42 45 8 24 morph @( + turtle StarFlower 42 45 8 24 + turtle rotate (Get-Random -Max 360) StarFlower 42 15 8 24 + turtle StarFlower 42 45 8 24 + ) + .EXAMPLE + # We can mix the number of points in a star flower morph + # + # (as long as we're drawing the same number of points) + turtle StarFlower 42 12 5 30 morph @( + turtle StarFlower 42 12 5 30 + turtle rotate (Get-Random -Max 360) StarFlower 42 14.4 6 25 + turtle StarFlower 42 12 5 30 + ) .EXAMPLE # We can construct a 'scissor' by drawing two lines at an angle turtle Scissor 42 60 diff --git a/Demos/Turtle_101-Intro-To-Turtles.demo.ps1 b/Demos/Turtle_101-Intro-To-Turtles.demo.ps1 new file mode 100644 index 0000000..3e53b7f --- /dev/null +++ b/Demos/Turtle_101-Intro-To-Turtles.demo.ps1 @@ -0,0 +1,37 @@ +# Turtle 101 - Intro to Turtles + +# Turtle is a groovy graphics system that dates back to 1966. + +# Imagine you are a turtle holding a pen. + +# You can: +# * Turn +# * Move Forward +# * Pick up the pen + +# Using these fundamental basics, we can theoretically draw any shape. + +# Let's start simple, by drawing a line +turtle forward 42 save ./line.svg + +# Let's draw a line and take a few turns +turtle forward 42 rotate 120 forward 42 rotate 120 forward 42 rotate 120 stroke '#4488ff' save ./triangle.svg + +# Let's make a square +turtle forward 42 rotate 90 forward 42 rotate 90 forward 42 rotate 90 forward 42 rotate 90 stroke '#4488ff' save ./square.svg + +# Now let's do it the easier way, with square +turtle square 42 stroke '#4488ff' save ./square2.svg + +# Now let's do it the general way, with polygon +turtle polygon 42 4 stroke '#4488ff' save ./square4.svg + +# Our turtle is pretty smart, and so it can draw a lot of shapes for us. + +# A classic example is a 'flower', which repeats many polygons +turtle flower stroke '#4488ff' save ./flower.svg + + + + + diff --git a/Turtle.psd1 b/Turtle.psd1 index aa98f0e..903f643 100644 --- a/Turtle.psd1 +++ b/Turtle.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. - ModuleVersion = '0.1.9' + ModuleVersion = '0.1.10' # Description of the module Description = "Turtles in a PowerShell" # Script module or binary module file associated with this manifest. @@ -37,15 +37,21 @@ # A URL to the license for this module. LicenseURI = 'https://github.com/PowerShellWeb/Turtle/blob/main/LICENSE' ReleaseNotes = @' -## Turtle 0.1.9: - -* Turtle Text Path Support - * `Turtle.get/set_Text` controls the text (#167) - * `Turtle.get/set_TextAttribute` sets text attributes (#168) - * `Turtle.get/set_TextAnimation` animates text attributes (#171) -* `Get-Turtle` parameter improvements (#169, #170) -* `Get-Turtle` tracks invocation info (#157) +## Turtle 0.1.10: +* Updated Methods + * `Turtle.Star` even point fix (#190) + * `Turtle.Polygon` partial polygon support (#194) +* New Shapes + * `Turtle.Rectangle` (#192) + * `Turtle.StarFlower` (#191) + * `Turtle.GoldenFlower` (#193) + * `Turtle.HatMonotile` (#196) + * `Turtle.TurtleMonotile` (#195) + * `Turtle.BarGraph` (#173) +* Added Demos + * Intro To Turtles (#197) + --- Additional details available in the [CHANGELOG](https://github.com/PowerShellWeb/Turtle/blob/main/CHANGELOG.md) diff --git a/Turtle.types.ps1xml b/Turtle.types.ps1xml index d6d1d95..7fd0c7b 100644 --- a/Turtle.types.ps1xml +++ b/Turtle.types.ps1xml @@ -39,6 +39,14 @@ fd Forward + + FlowerGolden + GoldenFlower + + + FlowerStar + StarFlower + HLineBy HorizontalLine @@ -204,6 +212,106 @@ $Distance = 10 $this.Forward($Distance * -1) + + + + BarGraph + @@ -465,22 +573,31 @@ return $this Draws a flower pattern in turtle graphics. This pattern consists of a series of polygons and rotations to create a flower-like design. +.EXAMPLE + turtle Flower 42 .EXAMPLE - $turtle = New-Turtle - $turtle.Flower(100, 10, 5, 36) - $turtle.Pattern.Save("$pwd/FlowerPattern.svg") + turtle Flower 42 20 6 18 .EXAMPLE - Move-Turtle Flower | - Save-Turtle ./FlowerSymbol.svg + turtle Flower 42 20 6 18 +.EXAMPLE + # We can make Flowers with partial polygons + turtle Flower 42 20 6.6 18 +.EXAMPLE + # They are surprisingly beautiful + turtle Flower 42 30 7.7 12 #> param( + # The size of the base shape [double]$Size = 100, + # The rotation after each step [double]$Rotation = 10, + # The number of sides in each shape [double]$SideCount = 4, - [double]$StepCount = 36 + # The number of steps in the flower. + [int]$StepCount = 36 ) -$null = foreach ($n in 1..$StepCount) { +$null = foreach ($n in 1..([Math]::Abs($StepCount))) { $this.Polygon($Size, $SideCount) $this.Rotate($Rotation) } @@ -569,6 +686,42 @@ return $this.Rotate(-90).LSystem('-X', [Ordered]@{ + + GoldenFlower + + GosperCurve + + HatMonotile + + HilbertCurve @@ -1388,6 +1640,40 @@ $this.'.Stack'.Push(@{ return $this + + Rectangle + + Right + + + StarFlower + @@ -2134,6 +2481,66 @@ return $this.LSystem('F++F++F', [Ordered]@{ 'F' = { $this.Forward($Size) } }) + + + + TurtleMonotile + diff --git a/Types/Turtle/Alias.psd1 b/Types/Turtle/Alias.psd1 index e4b0432..64785d2 100644 --- a/Types/Turtle/Alias.psd1 +++ b/Types/Turtle/Alias.psd1 @@ -20,4 +20,6 @@ ArcL = 'ArcLeft' HLineBy = 'HorizontalLine' VLineBy = 'VerticalLine' + FlowerStar = 'StarFlower' + FlowerGolden = 'GoldenFlower' } \ No newline at end of file diff --git a/Types/Turtle/BarGraph.ps1 b/Types/Turtle/BarGraph.ps1 new file mode 100644 index 0000000..30e975a --- /dev/null +++ b/Types/Turtle/BarGraph.ps1 @@ -0,0 +1,94 @@ +<# +.SYNOPSIS + Draws a bar graph using turtle graphics. +.DESCRIPTION + This script uses turtle graphics to draw a bar graph based on the provided data. +.EXAMPLE + turtle barGraph 100 100 5 10 15 20 15 10 5 +.EXAMPLE + turtle barGraph 200 200 ( + @(1..50;-1..-50) | + Get-Random -Count (Get-Random -Minimum 5 -Maximum 20) + ) save ./RandomBarGraph.svg +.EXAMPLE + turtle rotate 90 barGraph 200 200 ( + @(1..50;-1..-50) | + Get-Random -Count (Get-Random -Minimum 5 -Maximum 20) + ) save ./RandomVerticalBarGraph.svg +.EXAMPLE + turtle rotate 45 barGraph 200 200 ( + @(1..50;-1..-50) | + Get-Random -Count (Get-Random -Minimum 5 -Maximum 20) + ) save ./RandomDiagonalBarGraph.svg +.EXAMPLE + $sourceData = @(1..50;-1..-50) + $itemCount = (Get-Random -Minimum 5 -Maximum 20) + $points = $sourceData | Get-Random -Count $itemCount + turtle bargraph 200 200 $points morph @( + turtle bargraph 200 200 $points + turtle bargraph 200 200 ( $sourceData | Get-Random -Count $itemCount ) + turtle bargraph 200 200 $points + ) save ./RandomBarGraphMorph.svg +#> +param( +# The width of the bar graph +[double]$Width, +# The height of the bar graph. +# Please note that in the case of negative values, the effective height is twice this number. +[double]$Height, + +# The points in the bar graph. +# Each point will be turned into a relative number and turned into an equal-width bar. +[Parameter(ValueFromRemainingArguments)] +[double[]]$Points +) + + +# If there were no points, we are drawing nothing, so return ourself. +if (-not $points) { return $this} + +# Divide the width by the number of points to get a very snug bar graph +$barWidth = $width / $points.Length + +# Find the maximum and minimum values in the points +$min, $max = 0, 0 +foreach ($point in $points) { + if ($point -gt $max) { $max = $point} + if ($point -lt $min) { $min = $point} +} + +# This gives us the range. +$range = $max - $min + +# If the range is zero, we're drawing a flatline. +if ($range -eq 0) { + # so just draw that line and return. + return $this.Forward($width) +} + +# Now that we've normalized the range, we can draw the bars. +for ($pointIndex =0 ; $pointIndex -lt $points.Length; $pointIndex++) { + # Each point is essentially telling us the height + $point = $points[$pointIndex] + # which we can turn into a relative value + $relativeHeight = ( + # by subtracting the minimum and dividing by the range + (($point - $min) / $range) + ) * $height + # If the point was negative, we need to flip the height + if ($point -lt 0) { $relativeHeight *= -1} + # Now we can draw the bar + $this = $this. + # Turn outward and draw the side + Rotate(-90).Forward($relativeHeight). + # Turn and draw the top + Rotate(90).Forward($barWidth). + # Turn and draw the other side + Rotate(90).Forward($relativeHeight). + # Turn back to the original direction + Rotate(-90) +} +return $this + + + diff --git a/Types/Turtle/Flower.ps1 b/Types/Turtle/Flower.ps1 index 9e96382..b54eff1 100644 --- a/Types/Turtle/Flower.ps1 +++ b/Types/Turtle/Flower.ps1 @@ -5,22 +5,31 @@ Draws a flower pattern in turtle graphics. This pattern consists of a series of polygons and rotations to create a flower-like design. +.EXAMPLE + turtle Flower 42 .EXAMPLE - $turtle = New-Turtle - $turtle.Flower(100, 10, 5, 36) - $turtle.Pattern.Save("$pwd/FlowerPattern.svg") + turtle Flower 42 20 6 18 .EXAMPLE - Move-Turtle Flower | - Save-Turtle ./FlowerSymbol.svg + turtle Flower 42 20 6 18 +.EXAMPLE + # We can make Flowers with partial polygons + turtle Flower 42 20 6.6 18 +.EXAMPLE + # They are surprisingly beautiful + turtle Flower 42 30 7.7 12 #> param( + # The size of the base shape [double]$Size = 100, + # The rotation after each step [double]$Rotation = 10, + # The number of sides in each shape [double]$SideCount = 4, - [double]$StepCount = 36 + # The number of steps in the flower. + [int]$StepCount = 36 ) -$null = foreach ($n in 1..$StepCount) { +$null = foreach ($n in 1..([Math]::Abs($StepCount))) { $this.Polygon($Size, $SideCount) $this.Rotate($Rotation) } diff --git a/Types/Turtle/GoldenFlower.ps1 b/Types/Turtle/GoldenFlower.ps1 new file mode 100644 index 0000000..5bbc163 --- /dev/null +++ b/Types/Turtle/GoldenFlower.ps1 @@ -0,0 +1,31 @@ +<# +.SYNOPSIS + Draws a golden rectangle flower pattern. +.DESCRIPTION + Draws a flower made out of golden rectangles. + + This pattern consists of a series of rectangles and rotations to create a flower-like design. +.EXAMPLE + Turtle GoldenFlower +.EXAMPLE + Turtle GoldenFlower 42 10 36 +.EXAMPLE + Turtle GoldenFlower 42 5 72 +.EXAMPLE + Turtle GoldenFlower 84 30 12 | Save-Turtle ./GoldenFlowerPattern.svg Pattern +#> +param( + # The width of each rectangle + [double]$Size = 42, + # The rotation after each rectangle + [double]$Rotation = 20, + # The number of steps. + [int]$StepCount = 18 +) + +$null = foreach ($n in 1..([Math]::Abs($StepCount))) { + $this.Rectangle($Size) + $this.Rotate($Rotation) +} + +return $this \ No newline at end of file diff --git a/Types/Turtle/HatMonotile.ps1 b/Types/Turtle/HatMonotile.ps1 new file mode 100644 index 0000000..54cc068 --- /dev/null +++ b/Types/Turtle/HatMonotile.ps1 @@ -0,0 +1,51 @@ +<# +.SYNOPSIS + Draws a hat aperiodic monotile. +.DESCRIPTION + This function uses turtle graphics to draw an aperiodic monotile called a "Hat" +.EXAMPLE + turtle rotate -90 hatMonotile 100 save ./hatMonotile.svg +.LINK + https://github.com/christianp/aperiodic-monotile/blob/main/hat-monotile.logo +#> +param( +[double] +$A = 100, + +[double] +$B = 0 +) + +if (-not $B) { + $B = [Math]::Tan(60 * [Math]::PI / 180) * $A +} + + +return $this. + Forward($b). + Rotate(90). + Forward($a). + Left(60). + Forward($a). + Rotate(90). + Forward($b). + Rotate(60). + Forward($b). + Left(90). + Forward($a). + Rotate(60). + Forward($a). + Rotate(90). + Forward($b). + Rotate(60). + Forward($b). + Left(90). + Forward($a). + Rotate(60). + Forward($a). + Forward($a). + Rotate(60). + Forward($a). + Rotate(90). + Forward($b). + Left(60) diff --git a/Types/Turtle/Polygon.ps1 b/Types/Turtle/Polygon.ps1 index afff6fe..64efe60 100644 --- a/Types/Turtle/Polygon.ps1 +++ b/Types/Turtle/Polygon.ps1 @@ -1,10 +1,51 @@ +<# +.SYNOPSIS + Draws a polygon +.DESCRIPTION + Draws a regular polygon with N sides. + + To draw a closed polygon, provide a whole number of sides. + + To draw an open polygon, provide a fractial number of sides. +.EXAMPLE + turtle polygon 42 3 +.EXAMPLE + turtle polygon 42 4 +.EXAMPLE + turtle polygon 42 6 +.EXAMPLE + turtle polygon 42 8 +.EXAMPLE + turtle polygon 42 3.75 +.EXAMPLE + turtle polygon 42 3.001 morph @( + turtle polygon 42 3.001 + turtle polygon 42 4 + turtle polygon 42 3.001 + ) save ./TriangleToSquare.svg + +#> param( - $Size = 100, - $SideCount = 6 +# The default size of each segment of the polygon +[double]$Size = 42, +# The number of sides in the polygon. +# If this is not a whole number, the polygon will not be closed. +[double]$SideCount = 6 ) -$null = foreach ($n in 1..$SideCount) { - $this.Forward($Size) - $this.Rotate(360 / $SideCount) +# Determine the absolute side count +$absSideCount = [Math]::Abs($SideCount) +# and, for each whole number between 1 and that side count +$null = foreach ($n in 1..([Math]::Floor($absSideCount))) { + # Rotate and move forward + $this.Rotate(360 / $SideCount).Forward($Size) } -return $this \ No newline at end of file +# Determine if there was a remainder +$remainder = $SideCount - [Math]::Floor($SideCount) +# If there was not, return this polygon +if (-not $remainder) { return $this } +# Otherwise, we do one more partial rotation (multiplied by the remainder) +# and draw one more line segment (multiplied by the remainder) +# (the effect will be like watching a polygon close) +return $this.Rotate((360 / $SideCount) * $remainder).Forward($remainder * $Size) + diff --git a/Types/Turtle/Rectangle.ps1 b/Types/Turtle/Rectangle.ps1 new file mode 100644 index 0000000..ec48886 --- /dev/null +++ b/Types/Turtle/Rectangle.ps1 @@ -0,0 +1,29 @@ +<# +.SYNOPSIS + Draws a Rectangle +.DESCRIPTION + Draws a Rectangle. + + If only one dimension is specified, will draw a golden rectangle. +.EXAMPLE + turtle rectangle 42 save ./goldenRectangle.svg +#> +param( +# The width of the rectangle +[double] +$Width = 42, + +# The height of the rectangle. If not provided, will be the width divided by the golden ratio. +[double] +$Height +) + +if (-not $Height) { + $Height = $width/((1 + [Math]::Sqrt(5))/2) +} + +$this. + Forward($width).Rotate(90). + Forward($Height).Rotate(90). + Forward($Width).Rotate(90). + Forward($height).Rotate(90) \ No newline at end of file diff --git a/Types/Turtle/Star.ps1 b/Types/Turtle/Star.ps1 index 84b929a..a4d03a9 100644 --- a/Types/Turtle/Star.ps1 +++ b/Types/Turtle/Star.ps1 @@ -4,17 +4,40 @@ .DESCRIPTION Draws a star pattern with turtle graphics. .EXAMPLE - $turtle = New-Turtle - $turtle.Star().Pattern.Save("$pwd/Star.svg") + turtle star 42 .EXAMPLE - Move-Turtle Star | Save-Turtle "./Star.svg" + turtle star 42 20 +.EXAMPLE + turtle star 42 20 @('rotate', (360/20*2), 'star', 42, 20 * 10) save ./StarFlower20.svg +.EXAMPLE + turtle star 42 20 @('rotate', (360/20*2), 'star', 42, 20 * 10) morph @( + turtle star 42 20 @('rotate', (360/20*2), 'star', 42, 20 * 10) + turtle star 42 20 @('rotate', (360/20*26), 'star', 42, 20 * 10) + turtle star 42 20 @('rotate', (360/20*2), 'star', 42, 20 * 10) + ) save ./StarFlower20Morph.svg +.EXAMPLE + turtle star 42 20 @('rotate', (360/20*18), 'star', 42, 20 * 10) save ./StarFlower-20-18.svg #> param( + # The approximate size of the star [double]$Size = 50, - [int]$Points = 5 + # The number of points in the star + [int]$Points = 6 ) -$Angle = 180 - (180 / $Points) -foreach ($n in 1..$Points) { - $this.Forward($Size) - $this.Rotate($Angle) -} + +# To determine the angle, divide 360 by the number of points +$angle = 360 / $Points + +$SegmentLength = ($Size*2)/$Points +# Each 'point' in the star actually consists of two points, an inward and outward point. +# Imagine we start an an outward point +$null = foreach ($n in 1..([Math]::Abs($Points))) { + $this. # We rotate by the angle and move forward one segment + Rotate($Angle).Forward($SegmentLength). + # The rotate back and move forward another segment + Rotate(-$angle).Forward($SegmentLength). + # then rotate once more so we continue moving around the circle + Rotate($angle) +} # we repeat this up to the number of points in order to draw a star with no crossings. + +return $this diff --git a/Types/Turtle/StarFlower.ps1 b/Types/Turtle/StarFlower.ps1 new file mode 100644 index 0000000..a248a5c --- /dev/null +++ b/Types/Turtle/StarFlower.ps1 @@ -0,0 +1,33 @@ +<# +.SYNOPSIS + Draws a star flower pattern. +.DESCRIPTION + Draws a flower made out of stars. + + This pattern consists of a series of stars and rotations to create a flower-like design. +.EXAMPLE + Turtle StarFlower +.EXAMPLE + Turtle StarFlower 42 20 10 +.EXAMPLE + Turtle StarFlower 42 40 13 9 +.EXAMPLE + Turtle StarFlower 84 40 6 9 | Save-Turtle ./StarFlowerPattern.svg Pattern +#> +param( + # The size of each star + [double]$Size = 42, + # The rotation after each star + [double]$Rotation = 20, + # The number of points in the star + [double]$PointCount = 6, + # The number of steps. + [int]$StepCount = 18 +) + +$null = foreach ($n in 1..([Math]::Abs($StepCount))) { + $this.Star($Size, $PointCount) + $this.Rotate($Rotation) +} + +return $this \ No newline at end of file diff --git a/Types/Turtle/TurtleMonotile.ps1 b/Types/Turtle/TurtleMonotile.ps1 new file mode 100644 index 0000000..f3c7f0d --- /dev/null +++ b/Types/Turtle/TurtleMonotile.ps1 @@ -0,0 +1,54 @@ +<# +.SYNOPSIS + Draws a turtle aperiodic monotile. +.DESCRIPTION + This function uses turtle graphics to draw an aperiodic monotile called a "Turtle" +.EXAMPLE + turtle rotate -90 turtleMonotile 100 save ./turtleMonotile.svg +.LINK + https://github.com/christianp/aperiodic-monotile/blob/main/turtle-monotile.logo +#> +param( +[double] +$A = 100, + +[double] +$B = 0 +) + +if (-not $B) { + $B = [Math]::Tan(60 * [Math]::PI / 180) * $A +} + +return $this. + Rotate(90). + Forward($a). + Rotate(60). + Forward($a). + Rotate(-90). + Forward($b). + Rotate(60). + Forward($b). + Forward($b). + Rotate(60). + Forward($b). + Rotate(90). + Forward($a). + Rotate(-60). + Forward($a). + Rotate(90). + Forward($b). + Rotate(-60). + Forward($b). + Rotate(90). + Forward($a). + Rotate(60). + Forward($a). + Rotate(-90). + Forward($b). + Rotate(60). + Forward($b) + +return + +