Types/Turtle/Morph.ps1

<#
.SYNOPSIS
    Morphs a Turtle
.DESCRIPTION
    Morphs a Turtle by animating its path.

    Any two paths with the same number of points can be morphed into each other.
.EXAMPLE
    $sierpinskiTriangle = turtle SierpinskiTriangle 42 4
    $SierpinskiTriangleFlipped = turtle rotate 180 SierpinskiTriangle 42 4
    turtle SierpinskiTriangle 42 4 morph (
        $SierpinskiTriangle,
        $SierpinskiTriangleFlipped,
        $sierpinskiTriangle
    ) save ./SierpinskiTriangleFlip.svg
.EXAMPLE
    $sideCount = (3..24 | Get-Random )
    $stepCount = 36
    
    $flower = turtle rotate ((Get-Random -Max 180) * -1) flower 42 10 $sideCount $stepCount
    $flower2 = turtle rotate ((Get-Random -Max 180)) flower 42 50 $sideCount $stepCount
    $flower3 = turtle rotate ((Get-Random -Max 90)) flower 42 20 $sideCount $stepCount
    turtle flower 42 10 $sideCount $stepCount duration ($sideCount * 3) morph ($flower, $flower2,$flower) |
        save-turtle ./flowerMorph.svg Pattern
.EXAMPLE
    $flowerAngle = (40..60 | Get-Random )
    $stepCount = 36
    $radius = 23..42 | Get-Random
    
    $flowerPetals = turtle rotate ((Get-Random -Max 180) * -1) flowerPetal $radius 10 $flowerAngle $stepCount
    $flowerPetals3 = turtle rotate ((Get-Random -Max 180)) flowerPetal $radius 40 $flowerAngle $stepCount
    turtle flowerPetal $radius 10 $flowerAngle $stepCount duration $radius morph (
        $flowerPetals,
        $flowerPetals3,
        $flowerPetals
    ) | Save-Turtle ./flowerPetalMorph.svg Pattern
#>

param(
[Parameter(ValueFromRemainingArguments)]
$Arguments
)

$durationArgument = $null

$newPaths = @(foreach ($arg in $Arguments) {
    if ($arg -is [string]) {
        if ($arg -match '^\s{0,}m') {
            $arg
        }
    } elseif ($arg.PathData) {
        $arg.PathData
    } elseif ($arg.D) {
        $arg.D
    } elseif ($arg -is [TimeSpan]) {
        $durationArgument = $arg
    }
    elseif ($arg -is [double] -or $arg -is [int]) {
        $durationArgument = [TimeSpan]::FromSeconds($arg)
    }
})

if (-not $newPaths) {
    return $this
    <#$pathSegments = @($this.PathData -split '(?=\p{L})')
    $newPaths = @(for ($segmentNumber = 0; $segmentNumber -lt $pathSegments.Count; $segmentNumber++) {
        $pathSegments[0..$segmentNumber] -join ' '
    }) -join ';'#>

}

if ($this.PathAnimation) {
    $updatedAnimations = 
        @(foreach ($animationXML in $this.PathAnimation -split '(?<=/>)') {
            $animationXML = $animationXML -as [xml]
            if (-not $animationXML) { continue }
            if ($animationXML.attributeName -eq 'd') {
                $animationXML.values = "$($newPaths -join ';')"
            }
            $animationXML.OuterXml
        })
    $this.PathAnimation = $updatedAnimations
} else {
    $this.PathAnimation += [Ordered]@{
        attributeName = 'd'   ; values = "$($newPaths -join ';')" ; repeatCount = 'indefinite'; dur = $(
            if ($durationArgument) {
                "$($durationArgument.TotalSeconds)s"
            } elseif ($this.Duration) {
                "$($this.Duration.TotalSeconds)s"
            } else {
                "4.2s"
            }
            
        )
    }
}

return $this