diff --git a/CHANGELOG.md b/CHANGELOG.md index 38164b1..07b53c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## Turtle 0.1.4 + +* `Turtle` Upgrades + * `turtle` will return an empty turtle (#112) + * `turtle` now splats to script methods, enabling more complex input binding (#121) + * `LSystem` is faster and more flexible (#116) +* New Properties: + * `get/set_Opacity` (#115) + * `get/set_PathAnimation` (#117) + * `get/set_Width/Height` (#125) +* New Methods: + * `HorizontalLine/VerticalLine` (#126) + * `Petal` (#119) + * `FlowerPetal` (#124) + * `Spirolateral` (#120) + * `StepSpiral` (#122) +* Fixes: + * `Turtle.Towards()` returns a relative angle (#123) + +--- + ## Turtle 0.1.3 * Fixing `Get-Turtle` inline sets (#108, #107) diff --git a/Commands/Get-Turtle.ps1 b/Commands/Get-Turtle.ps1 index 7fc7f74..e9fd1dd 100644 --- a/Commands/Get-Turtle.ps1 +++ b/Commands/Get-Turtle.ps1 @@ -88,7 +88,8 @@ function Get-Turtle { # We want to keep track of the current member, # and continue to the next word until we find a member name. $currentMember = $null - $outputTurtle = $false + # We want to output the turtle by default, in case we were called with no parameters. + $outputTurtle = $true # To do this in one pass, we will iterate through the words and arguments. # We use an indexed loop so we can skip past claimed arguments. @@ -116,15 +117,13 @@ function Get-Turtle { } # Now we know how long it took to get to the next member name. - # And we can determine if we have any parameters + # And we can determine if we have any parameters. + # (it is important that we always force any parameters into an array) $argList = - if ($methodArgIndex -eq ($argIndex + 1)) { - @() - } - else { + @(if ($methodArgIndex -ne ($argIndex + 1)) { $wordsAndArguments[($argIndex + 1)..($methodArgIndex - 1)] $argIndex = $methodArgIndex - 1 - } + }) # Look up the member information for the current member. $memberInfo = $turtleType.Members[$currentMember] @@ -145,8 +144,18 @@ function Get-Turtle { ) { # If we have arguments, if ($argList) { - # pass them to the method. - $currentTurtle.$currentMember.Invoke($argList) + # and we have a script method + if ($memberInfo -is [Management.Automation.Runspaces.ScriptMethodData]) { + # set this to the current turtle + $this = $currentTurtle + # and call the script, splatting positional parameters + # (this allows more complex binding, like ValueFromRemainingArguments) + . $currentTurtle.$currentMember.Script @argList + } else { + # Otherwise, we pass the parameters directly to the method + $currentTurtle.$currentMember.Invoke($argList) + } + } else { # otherwise, just invoke the method with no arguments. $currentTurtle.$currentMember.Invoke() diff --git a/Examples/BoxFractal.svg b/Examples/BoxFractal.svg index 0c6a946..e745d7c 100644 --- a/Examples/BoxFractal.svg +++ b/Examples/BoxFractal.svg @@ -1,6 +1,7 @@ - + + \ No newline at end of file diff --git a/Examples/EndlessBoxFractal.svg b/Examples/EndlessBoxFractal.svg index a0f3f41..b31525d 100644 --- a/Examples/EndlessBoxFractal.svg +++ b/Examples/EndlessBoxFractal.svg @@ -6,7 +6,8 @@ - + + diff --git a/Examples/EndlessHilbert.svg b/Examples/EndlessHilbert.svg index c130204..996cd0e 100644 --- a/Examples/EndlessHilbert.svg +++ b/Examples/EndlessHilbert.svg @@ -6,7 +6,8 @@ - + + diff --git a/Examples/EndlessSierpinskiTrianglePattern.svg b/Examples/EndlessSierpinskiTrianglePattern.svg index 0f93759..01fdacc 100644 --- a/Examples/EndlessSierpinskiTrianglePattern.svg +++ b/Examples/EndlessSierpinskiTrianglePattern.svg @@ -6,7 +6,8 @@ - + + diff --git a/Examples/EndlessSnowflake.svg b/Examples/EndlessSnowflake.svg index 17575f2..5e944d6 100644 --- a/Examples/EndlessSnowflake.svg +++ b/Examples/EndlessSnowflake.svg @@ -6,7 +6,8 @@ - + + diff --git a/Examples/EndlessSpirolateral.svg b/Examples/EndlessSpirolateral.svg new file mode 100644 index 0000000..2552f07 --- /dev/null +++ b/Examples/EndlessSpirolateral.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/EndlessSpirolateral.turtle.ps1 b/Examples/EndlessSpirolateral.turtle.ps1 new file mode 100644 index 0000000..7c9e0f1 --- /dev/null +++ b/Examples/EndlessSpirolateral.turtle.ps1 @@ -0,0 +1,20 @@ +Push-Location $PSScriptRoot +$myName = $MyInvocation.MyCommand.Name -replace '\.turtle\.ps1$' +$turtle = turtle rotate -30 @('spirolateral',42,60,6,@(1,3),'rotate', 60 * 6 )| + Set-Turtle -Property PatternTransform -Value @{scale=0.33} | + set-turtle -property Fill -value '#4488ff' | + set-turtle -property FillRule -value 'evenodd' | + Set-Turtle -Property PatternAnimation -Value ([Ordered]@{ + type = 'scale' ; values = 0.66,0.33, 0.66 ; repeatCount = 'indefinite' ;dur = "23s"; additive = 'sum' + }, [Ordered]@{ + type = 'rotate' ; values = 0, 360 ;repeatCount = 'indefinite'; dur = "41s"; additive = 'sum' + }, [Ordered]@{ + type = 'skewX' ; values = -30,30,-30;repeatCount = 'indefinite';dur = "83s";additive = 'sum' + }, [Ordered]@{ + type = 'skewY' ; values = 30,-30, 30;repeatCount = 'indefinite';additive = 'sum';dur = "103s" + }, [Ordered]@{ + type = 'translate';values = "0 0","42 42", "0 0";repeatCount = 'indefinite';additive = 'sum';dur = "117s" + }) + +$turtle | save-turtle -Path "./$myName.svg" -Property Pattern +Pop-Location \ No newline at end of file diff --git a/Examples/EndlessStepSpiral.svg b/Examples/EndlessStepSpiral.svg new file mode 100644 index 0000000..4b6330d --- /dev/null +++ b/Examples/EndlessStepSpiral.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/EndlessStepSpiral.turtle.ps1 b/Examples/EndlessStepSpiral.turtle.ps1 new file mode 100644 index 0000000..e0550c3 --- /dev/null +++ b/Examples/EndlessStepSpiral.turtle.ps1 @@ -0,0 +1,16 @@ +Push-Location $PSScriptRoot +$myName = $MyInvocation.MyCommand.Name -replace '\.turtle\.ps1$' +$turtle = turtle @('StepSpiral',16, 90, 16, 20, 'rotate',90 * 4) | + Set-Turtle -Property PatternTransform -Value @{scale=1} | + # set-turtle -property Fill -value 'currentColor' | + # set-turtle -property FillRule -value 'evenodd' | + Set-Turtle -Property PatternAnimation -Value ([Ordered]@{ + type = 'scale' ; values = 0.66,0.33, 0.66 ; repeatCount = 'indefinite' ;dur = "23s"; additive = 'sum' + }, [Ordered]@{ + type = 'rotate' ; values = 0, 360 ;repeatCount = 'indefinite'; dur = "41s"; additive = 'sum' + }, [Ordered]@{ + type = 'translate';values = "0 0","42 42", "0 0";repeatCount = 'indefinite';additive = 'sum';dur = "117s" + }) + +$turtle | save-turtle -Path "./$myName.svg" -Property Pattern +Pop-Location \ No newline at end of file diff --git a/Examples/SierpinskiTriangle.svg b/Examples/SierpinskiTriangle.svg index 30b944f..8d733a4 100644 --- a/Examples/SierpinskiTriangle.svg +++ b/Examples/SierpinskiTriangle.svg @@ -1,6 +1,7 @@ - + + \ No newline at end of file diff --git a/Turtle.psd1 b/Turtle.psd1 index 1d9bd46..68c522e 100644 --- a/Turtle.psd1 +++ b/Turtle.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. - ModuleVersion = '0.1.3' + ModuleVersion = '0.1.4' # Description of the module Description = "Turtles in a PowerShell" # Script module or binary module file associated with this manifest. @@ -37,95 +37,28 @@ # A URL to the license for this module. LicenseURI = 'https://github.com/PowerShellWeb/Turtle/blob/main/LICENSE' ReleaseNotes = @' -## Turtle 0.1.3 - -* Fixing `Get-Turtle` inline sets (#108, #107) -* Fixing `.PNG/JPEG/WEBP` to no longer try to use msedge (#110) -* Adding `Turtle.get/set_FillRule` to get or set the fill rule for the turtle. (#109) - ---- - -## Turtle 0.1.2 - -* `Get-Turtle/Turtle` can now get or set properties or methods +## Turtle 0.1.4 + +* `Turtle` Upgrades + * `turtle` will return an empty turtle (#112) + * `turtle` now splats to script methods, enabling more complex input binding (#121) + * `LSystem` is faster and more flexible (#116) +* New Properties: + * `get/set_Opacity` (#115) + * `get/set_PathAnimation` (#117) + * `get/set_Width/Height` (#125) * New Methods: - * `Turtle.Distance()` determines the distance to a point - * `Turtle.Towards()` determines the angle to a point - * `Turtle.Home()` sends the turtle to 0,0 - * `Turtle.lt/rt` aliases help original Logo compatibility - * `Turtle.Save()` calls Save-Turtle -* Explicitly exporting commands from module - ---- - -## Turtle 0.1.1 - -* Updates: - * `Turtle.get/set_ID` allows for turtle identifiers - * `Turtle.ToString()` stringifies the SVG + * `HorizontalLine/VerticalLine` (#126) + * `Petal` (#119) + * `FlowerPetal` (#124) + * `Spirolateral` (#120) + * `StepSpiral` (#122) * Fixes: - * Fixing GoTo/Teleport (#90) - * Fixing Position default (#85) (thanks @ninmonkey !) - * Fixing Turtle Action ID (#89) -* New: - * `Turtle.Push()` pushes position/heading to a stack (#91) - * `Turtle.Pop()` pops position/heading from a stack (#92) - * `Turtle.get_Stack` gets the position stack (#93) -* New Fractals: - * `BinaryTree()` (#94) - * `FractalPlant()` (#95) + * `Turtle.Towards()` returns a relative angle (#123) --- -## Turtle 0.1 - -* Initial Release -* Builds a Turtle Graphics engine in PowerShell -* Core commands - * `Get-Turtle` (alias `turtle`) runs multiple moves - * `New-Turtle` create a turtle - * `Move-Turtle` performas a single move - * `Set-Turtle` changes a turtle - * `Save-Turtle` saves a turtle - -~~~PowerShell -turtle Forward 10 Rotate 120 Forward 10 Roate 120 Forward 10 Rotate 120 | - Set-Turtle Stroke '#4488ff' | - Save-Turtle ./Triangle.svg -~~~ - -* Core Object - * `.Heading` controls the turtle heading - * `.Steps` stores a list of moves as an SVG path - * `.IsPenDown` controls the pen - * `.Forward()` moves forward at heading - * `.Rotate()` rotates the heading - * `.Square()` draws a square - * `.Polygon()` draws a polygon - * `.Circle()` draws a circle (or partial circle) -* LSystems - * Turtle can draw a L system. Several are included: - * `BoxFractal` - * `GosperCurve` - * `HilbertCurve` - * `KochCurve` - * `KochIsland` - * `KochSnowflake` - * `MooreCurve` - * `PeanoCurve` - * `SierpinskiTriangle` - * `SierpinskiCurve` - * `SierpinskiSquareCurve` - * `SierpinskiArrowheadCurve` - * `TerdragonCurve` - * `TwinDragonCurve` - -~~~PowerShell -turtle SierpinskiTriangle 10 4 | - Set-Turtle Stroke '#4488ff' | - Save-Turtle ./SierpinskiTriangle.svg -~~~ - +Additional details available in the [CHANGELOG](https://github.com/PowerShellWeb/Turtle/blob/main/CHANGELOG.md) '@ } } diff --git a/Turtle.tests.ps1 b/Turtle.tests.ps1 index ec2d3d9..62306f8 100644 --- a/Turtle.tests.ps1 +++ b/Turtle.tests.ps1 @@ -18,4 +18,33 @@ describe Turtle { $png = New-Turtle | Move-Turtle SierpinskiTriangle 15 5 | Select-Object -ExpandProperty PNG $png[1..3] -as 'char[]' -as 'string[]' -join '' | Should -Be PNG } + + + context 'Turtle Directions' { + it 'Can tell you the way towards a point' { + $turtle = turtle + $turtle.Towards(0,1) | should -be 90 + $turtle.Towards(1,1) | Should -be 45 + $turtle.Towards(1,0) | should -be 0 + $turtle.Towards(-1,1) | Should -be 135 + $turtle.Towards(-1,0) | Should -be 180 + $turtle.Towards(0,-1) | Should -be -90 + } + + it 'Will return a relative heading' { + $turtle = turtle + $turtle = $turtle.Rotate($turtle.Towards(1,1)) + $turtle = $turtle.Forward($turtle.Distance(1,1)) + $turtle.Heading | Should -be 45 + [Math]::Round($turtle.Position.X,10) | Should -be 1 + [Math]::Round($turtle.Position.Y,10) | Should -be 1 + $turtle = $turtle.Rotate($turtle.Towards(2,2)) + $turtle = $turtle.Forward($turtle.Distance(2,2)) + $turtle.Heading | Should -be 45 + [Math]::Round($turtle.Position.Y,10) | Should -be 2 + [Math]::Round($turtle.Position.Y,10) | Should -be 2 + } + } + + } diff --git a/Turtle.types.ps1xml b/Turtle.types.ps1xml index 90d669a..4a2a1bc 100644 --- a/Turtle.types.ps1xml +++ b/Turtle.types.ps1xml @@ -15,6 +15,14 @@ + + ArcL + ArcLeft + + + ArcR + ArcRight + Back Backward @@ -31,6 +39,10 @@ fd Forward + + HLineBy + HorizontalLine + l Left @@ -75,6 +87,10 @@ up PenUp + + VLineBy + VerticalLine + xPos xcor @@ -83,6 +99,74 @@ yPos ycor + + ArcLeft + + + + ArcRight + + Backward @@ -315,6 +399,45 @@ $null = foreach ($n in 1..$StepCount) { $this.Rotate($Rotation) } +return $this + + + + FlowerPetal + @@ -457,6 +580,27 @@ return $this.Teleport(0,0) + + HorizontalLine + + Jump @@ -873,6 +1049,40 @@ return $this + + Petal + + Polygon + + Spirolateral + + Square + + + StepSpiral + @@ -1266,7 +1606,7 @@ return "$($this.SVG.OuterXml)" .SYNOPSIS Determines the angle towards a point .DESCRIPTION - Determines the angle from the turtle's current position towards a point. + Determines the angle from the turtle's current heading towards a point. #> param( # The X-coordinate @@ -1276,12 +1616,12 @@ param( ) # Determine the delta from the turtle's current position to the specified point -$deltaX = $this.Position.X - $X -$deltaY = $this.Position.Y - $Y +$deltaX = $X - $this.Position.X +$deltaY = $Y - $this.Position.Y # Calculate the angle in radians and convert to degrees $angle = [Math]::Atan2($deltaY, $deltaX) * 180 / [Math]::PI -# Return the angle rotate by 90 to account for the turtle's coordinate system -return $angle + 90 +# Return the angle minus the current heading (modulo 360) +return $angle - ($this.Heading % 360) @@ -1329,6 +1669,26 @@ return $this.LSystem('FX+FX+', [Ordered]@{ + + VerticalLine + + xcor