From 0ee7ad4b6cbce92b50da96e122f9ce2815d6f786 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Sun, 9 Aug 2026 12:10:59 -0700 Subject: [PATCH 01/11] feat: Vector commands return type without input ( Fixes #14 ) --- Commands/Get-Vector2.ps1 | 4 ++++ Commands/Get-Vector3.ps1 | 6 ++++++ Commands/Get-Vector4.ps1 | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/Commands/Get-Vector2.ps1 b/Commands/Get-Vector2.ps1 index f3d2c6b..bd25c55 100644 --- a/Commands/Get-Vector2.ps1 +++ b/Commands/Get-Vector2.ps1 @@ -32,6 +32,10 @@ function Get-Vector2 { } ) + if (-not $allIn.Length) { + return [Numerics.Vector2] + } + # and expand them $expandAllIn = @($allIn | Vector) diff --git a/Commands/Get-Vector3.ps1 b/Commands/Get-Vector3.ps1 index 4dc1a25..a7607cb 100644 --- a/Commands/Get-Vector3.ps1 +++ b/Commands/Get-Vector3.ps1 @@ -36,6 +36,12 @@ function Get-Vector3 { } ) + # If there were no arguments + if (-not $allIn.Length) { + # return the vector type + return [Numerics.Vector3] + } + # and expand them $expandAllIn = @($allIn | Vector) diff --git a/Commands/Get-Vector4.ps1 b/Commands/Get-Vector4.ps1 index b2d0d69..c515be7 100644 --- a/Commands/Get-Vector4.ps1 +++ b/Commands/Get-Vector4.ps1 @@ -32,6 +32,12 @@ function Get-Vector4 { } ) + # If there were no arguments + if (-not $allIn.Length) { + # return the vector type + return [Numerics.Vector4] + } + # and expand them $expandAllIn = @($allIn | vector) For ($n = 0; $n -lt $expandAllIn.Length; $n+=4) { From 0749f128ed4f0e06e32836216a75149bd8d5f53f Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Sun, 9 Aug 2026 12:45:50 -0700 Subject: [PATCH 02/11] feat: Vector commands return type without input ( Fixes #14 ) --- Commands/Get-Vector2.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Commands/Get-Vector2.ps1 b/Commands/Get-Vector2.ps1 index bd25c55..8774ea2 100644 --- a/Commands/Get-Vector2.ps1 +++ b/Commands/Get-Vector2.ps1 @@ -32,7 +32,9 @@ function Get-Vector2 { } ) + # If there were no arguments if (-not $allIn.Length) { + # return the vector type return [Numerics.Vector2] } From 8851d48cd7e897ffccefd99f3b928bfbbf538f35 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:16:06 -0700 Subject: [PATCH 03/11] feat: `Get-Vector` supports v2-v4 ( Fixes #15 ) --- Commands/Get-Vector.ps1 | 115 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 4 deletions(-) diff --git a/Commands/Get-Vector.ps1 b/Commands/Get-Vector.ps1 index 8002ada..8419ff2 100644 --- a/Commands/Get-Vector.ps1 +++ b/Commands/Get-Vector.ps1 @@ -24,10 +24,62 @@ function Get-Vector * `offset.hours`, `offset.minutes`, `offset.seconds` * `[string]s` will return their bytes in the current `$outputEncoding` * Anything unknown will be stringified and the bytes will be returned + .EXAMPLE + # Create a vector out of two numbers + Vector2 1 2 + .EXAMPLE + (Vector2 1 2) + (Vector2 2 1) + .EXAMPLE + (Vector2 1 2) - (Vector2 2 1) + .EXAMPLE + # Create a thousand vectors + $vectors = Vector2 1..2kb + .EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..2kb | Get-Random -Count 2kb | Vector2 + .EXAMPLE + # Create a vector from a string + $vector = Vector2 "hi" + .EXAMPLE + # Create a vector out of two numbers + Vector3 1 2 3 + .EXAMPLE + (Vector3 1 2 3 ) + (Vector3 3 2 1) + .EXAMPLE + (Vector3 1 2 3 ) - (Vector3 3 2 1) + .EXAMPLE + # Create a thousand vectors + $vectors = Vector3 1..3kb + .EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..3kb | Get-Random -Count 3kb | Vector3 + .EXAMPLE + # Create a vector from a string + $vector = Vector3 "hi" + .EXAMPLE + # Create a vector out of four numbers + Vector4 1 2 3 4 + .EXAMPLE + (Vector4 1 2 3 4 ) + (Vector4 4 3 2 1 ) + .EXAMPLE + (Vector4 1 2 3 4 ) - (Vector4 4 3 2 1) + .EXAMPLE + # Create a thousand vectors + $vectors = Vector4 1..4kb + .EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..4kb | Get-Random -Count 4kb | Vector4 + .EXAMPLE + # Create vectors from a string + Vector4 "hi" #> - [Alias('Vector','Vector1','V1')] + [Alias('Vector', + 'Get-Vector1','Vector1','V1', + 'Get-Vector2','Vector2','V2', + 'Get-Vector3','Vector3','V3', + 'Get-Vector4','Vector4','V4' + )] param() - filter toVector { $arg = $_ # Return primitive types @@ -36,7 +88,7 @@ function Get-Vector return ($arg -as [float]) } # Return vector components - if ($arg -is [ValueType]) { + if ($arg -is [ValueType]) { if ($arg -is [Numerics.Vector2]) { return $arg.X,$arg.Y } @@ -115,5 +167,60 @@ function Get-Vector } ) - return $allIn | toVector + $myName = $MyInvocation.InvocationName + + $expandAllIn = @($allIn | toVector) + + if (-not $expandAllIn.Length) { + if ($myName -match '2$') { + return [Numerics.Vector2] + } + elseif ($myName -match '3$') { + return [Numerics.Vector3] + } + elseif ($myName -match '4$') { + return [Numerics.Vector4] + } + else { + return [Numerics.Vector2],[Numerics.Vector3],[Numerics.Vector4] + } + } + if ($myName -match '[234]$') { + $dimension = $matches.0 -as [int] + for ($n = 0; $n -lt $expandAllIn.Length; $n+=$dimension) { + $nums = $expandAllIn[$n..($n+($dimension-1))] -as [float[]] + if ($dimension -eq 2) { + if ($nums.Length -eq 1) { + [Numerics.Vector2]::new($nums[0]) + } else { + [Numerics.Vector2]::new($nums) + } + } elseif ($dimension -eq 3) { + if ($nums.Length -eq 1) { + [Numerics.Vector3]::new($nums[0]) + } + elseif ($nums.Length -eq 2) { + [Numerics.Vector3]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0) + } + elseif ($nums.Length -eq 3) { + [Numerics.Vector3]::new($nums) + } + } elseif ($dimension -eq 4) { + if ($nums.Length -eq 1) { + [Numerics.Vector4]::new($nums[0]) + } + elseif ($nums.Length -eq 2) { + [Numerics.Vector4]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0, 0) + } + elseif ($nums.Length -eq 3) { + [Numerics.Vector4]::new([Numerics.Vector3]::new($nums[0],$nums[1],$nums[2]), 0) + } + elseif ($nums.Length -eq 4) { + [Numerics.Vector4]::new($nums) + } + } + } + } else { + return $allIn | toVector + } } \ No newline at end of file From d6229ef99f91b2ec63f53d97fef2a9294b94627c Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:18:23 -0700 Subject: [PATCH 04/11] feat: `Vector` eponym ( Fixes #15 ) --- Commands/Get-Vector.ps1 | 226 --------------------------------------- Commands/Get-Vector2.ps1 | 52 --------- Commands/Get-Vector3.ps1 | 63 ----------- Commands/Get-Vector4.ps1 | 58 ---------- Vector.ps1 | 223 ++++++++++++++++++++++++++++++++++++++ Vector.psm1 | 120 +++++++++++++++------ 6 files changed, 313 insertions(+), 429 deletions(-) delete mode 100644 Commands/Get-Vector.ps1 delete mode 100644 Commands/Get-Vector2.ps1 delete mode 100644 Commands/Get-Vector3.ps1 delete mode 100644 Commands/Get-Vector4.ps1 create mode 100644 Vector.ps1 diff --git a/Commands/Get-Vector.ps1 b/Commands/Get-Vector.ps1 deleted file mode 100644 index 8419ff2..0000000 --- a/Commands/Get-Vector.ps1 +++ /dev/null @@ -1,226 +0,0 @@ -function Get-Vector -{ - <# - .SYNOPSIS - Gets a one dimensional vector - .DESCRIPTION - Gets a one dimensional vector (or, more simply, a list of numbers) - - This will convert a variety of types into numbers. - .NOTES - This attempts to convert any type into a number. - - Some types are special: - - * Primitive types will be casted to float - * `[Numerics.Vector2]`,`[Numerics.Vector3]`,`[Numerics.Vector4]` output each component - * `[string]`s that match a range (`$start..$end`) will output that range - * `[Version]`s will output each numeric component - * `[semver]`s will output each numeric component, followed by the bytes of a release type - * `[DateTime]` and `[DateTimeOffset]` will become a series of 12 numbers - * `year`,`month`,`day` - * `hour`, `minute`, `second` - * `millisecond`, `microsecond`, `nanosecond` - * `offset.hours`, `offset.minutes`, `offset.seconds` - * `[string]s` will return their bytes in the current `$outputEncoding` - * Anything unknown will be stringified and the bytes will be returned - .EXAMPLE - # Create a vector out of two numbers - Vector2 1 2 - .EXAMPLE - (Vector2 1 2) + (Vector2 2 1) - .EXAMPLE - (Vector2 1 2) - (Vector2 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector2 1..2kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..2kb | Get-Random -Count 2kb | Vector2 - .EXAMPLE - # Create a vector from a string - $vector = Vector2 "hi" - .EXAMPLE - # Create a vector out of two numbers - Vector3 1 2 3 - .EXAMPLE - (Vector3 1 2 3 ) + (Vector3 3 2 1) - .EXAMPLE - (Vector3 1 2 3 ) - (Vector3 3 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector3 1..3kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..3kb | Get-Random -Count 3kb | Vector3 - .EXAMPLE - # Create a vector from a string - $vector = Vector3 "hi" - .EXAMPLE - # Create a vector out of four numbers - Vector4 1 2 3 4 - .EXAMPLE - (Vector4 1 2 3 4 ) + (Vector4 4 3 2 1 ) - .EXAMPLE - (Vector4 1 2 3 4 ) - (Vector4 4 3 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector4 1..4kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..4kb | Get-Random -Count 4kb | Vector4 - .EXAMPLE - # Create vectors from a string - Vector4 "hi" - #> - [Alias('Vector', - 'Get-Vector1','Vector1','V1', - 'Get-Vector2','Vector2','V2', - 'Get-Vector3','Vector3','V3', - 'Get-Vector4','Vector4','V4' - )] - param() - filter toVector { - $arg = $_ - # Return primitive types - if ($arg.GetType -and $arg.GetType().IsPrimitive) { - # casted to float - return ($arg -as [float]) - } - # Return vector components - if ($arg -is [ValueType]) { - if ($arg -is [Numerics.Vector2]) { - return $arg.X,$arg.Y - } - elseif ($arg -is [Numerics.Vector3]) { - return $arg.X,$arg.Y,$arg.Z - } - elseif ($arg -is [Numerics.Vector4]) { - return $arg.X,$arg.Y,$arg.Z, $arg.W - } - } - # Look for inline ranges. - if ($arg -is [string]) { - if ($arg -match '^\d..\d') { - $start, $end = $arg -split '\..', 2 - $startInt = ($start -as [int]) - $endInt = ($end -as [int]) - if ($null -ne $startInt -and $null -ne $endInt) { - # If found, return them expanded. - return ($startInt..$endInt) - } - } - if ($arg -as [float]) { - return $arg -as [float] - } - } - - - # If the arg is a version, get each number of the version - if ($arg -is [version]) {return $arg.Major,$arg.Minor,$arg.Build,$arg.Revision} - - # If we support semver and the arg is semver - if (('semver' -as [type]) -and $arg -is [semver]) { - # Return the numeric parts of the semver - $arg.Major,$arg.Minor,$arg.Patch - # and turn any string portions to bytes - if ($arg.PreReleaseLabel) { - # make sure to include a leading dash for pre-releases - $OutputEncoding.GetBytes("-$($arg.PreReleaseLabel)") - } - - if ($arg.BuildLabel) { - # make sure to include a leading plus for build labels - $OutputEncoding.GetBytes("+$($arg.BuildLabel)") - } - return - } - - # If the arg is a datetime or datetimeoffset - if ($arg -is [DateTime] -or $arg -is [DateTimeOffset]) { - # make it an offset, and then output 12 values - $dateArg = $arg -as [DateTimeOffset] - # * `year` `month` `day` - $dateArg.Year, $dateArg.Month, $dateArg.Day, - # * `hour` `minute` `second` - $dateArg.Hour, $dateArg.Minute, $dateArg.Second, - # * `millisecond`, `microsecond`, `nanosecond` - $dateArg.Millisecond, $dateArg.Microsecond, $dateArg.Nanosecond, - # * `offset hours`, `offset minutes`, `offset seconds` - $dateArg.Offset.Hours,$dateArg.Offset.Minutes,$dateArg.Offset.Seconds - return - } - # If the arg is a string - if ($arg -is [string]) { - # return its bytes - return $OutputEncoding.GetBytes($arg) - } - # any input we have not caught, stringify and turn to bytes - return $OutputEncoding.GetBytes("$arg") - } - - - # Collect all of our input and arguments - $allIn = @($input) + @( - foreach ($arg in $args) { - $arg - } - ) - - $myName = $MyInvocation.InvocationName - - $expandAllIn = @($allIn | toVector) - - if (-not $expandAllIn.Length) { - if ($myName -match '2$') { - return [Numerics.Vector2] - } - elseif ($myName -match '3$') { - return [Numerics.Vector3] - } - elseif ($myName -match '4$') { - return [Numerics.Vector4] - } - else { - return [Numerics.Vector2],[Numerics.Vector3],[Numerics.Vector4] - } - } - if ($myName -match '[234]$') { - $dimension = $matches.0 -as [int] - for ($n = 0; $n -lt $expandAllIn.Length; $n+=$dimension) { - $nums = $expandAllIn[$n..($n+($dimension-1))] -as [float[]] - if ($dimension -eq 2) { - if ($nums.Length -eq 1) { - [Numerics.Vector2]::new($nums[0]) - } else { - [Numerics.Vector2]::new($nums) - } - } elseif ($dimension -eq 3) { - if ($nums.Length -eq 1) { - [Numerics.Vector3]::new($nums[0]) - } - elseif ($nums.Length -eq 2) { - [Numerics.Vector3]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0) - } - elseif ($nums.Length -eq 3) { - [Numerics.Vector3]::new($nums) - } - } elseif ($dimension -eq 4) { - if ($nums.Length -eq 1) { - [Numerics.Vector4]::new($nums[0]) - } - elseif ($nums.Length -eq 2) { - [Numerics.Vector4]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0, 0) - } - elseif ($nums.Length -eq 3) { - [Numerics.Vector4]::new([Numerics.Vector3]::new($nums[0],$nums[1],$nums[2]), 0) - } - elseif ($nums.Length -eq 4) { - [Numerics.Vector4]::new($nums) - } - } - } - } else { - return $allIn | toVector - } -} \ No newline at end of file diff --git a/Commands/Get-Vector2.ps1 b/Commands/Get-Vector2.ps1 deleted file mode 100644 index 8774ea2..0000000 --- a/Commands/Get-Vector2.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -function Get-Vector2 { - <# - .SYNOPSIS - Gets a Vector2 - .DESCRIPTION - Gets any input and arguments as a Vector2 - .LINK - https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2?wt.mc_id=MVP_321542 - .EXAMPLE - # Create a vector out of two numbers - Vector2 1 2 - .EXAMPLE - (Vector2 1 2) + (Vector2 2 1) - .EXAMPLE - (Vector2 1 2) - (Vector2 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector2 1..2kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..2kb | Get-Random -Count 2kb | Vector2 - .EXAMPLE - # Create a vector from a string - $vector = Vector2 "hi" - #> - [Alias('V2','Vector2')] - param() - # Collect all of our input and arguments - $allIn = @($input) + @( - foreach ($arg in $args) { - $arg - } - ) - - # If there were no arguments - if (-not $allIn.Length) { - # return the vector type - return [Numerics.Vector2] - } - - # and expand them - $expandAllIn = @($allIn | Vector) - - For ($n = 0; $n -lt $expandAllIn.Length; $n+=2) { - $argSet = $expandAllIn[$n..($n+1)] -as [float[]] - if ($argSet.Length -eq 1) { - [Numerics.Vector2]::new($argSet[0]) - } else { - [Numerics.Vector2]::new($argSet) - } - } -} diff --git a/Commands/Get-Vector3.ps1 b/Commands/Get-Vector3.ps1 deleted file mode 100644 index a7607cb..0000000 --- a/Commands/Get-Vector3.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -function Get-Vector3 { - <# - .SYNOPSIS - Gets a Vector3 - .DESCRIPTION - Gets any input and arguments as a Vector3 - .LINK - https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3?wt.mc_id=MVP_321542 - .EXAMPLE - # Create a vector out of two numbers - Vector3 1 2 3 - .EXAMPLE - (Vector3 1 2 3 ) + (Vector3 3 2 1) - .EXAMPLE - (Vector3 1 2 3 ) - (Vector3 3 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector3 1..3kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..3kb | Get-Random -Count 3kb | Vector3 - .EXAMPLE - # Create a vector from a string - $vector = Vector3 "hi" - .NOTES - This script is self contained so that it can be easily dropped into any project - #> - [Alias('Vector3','V3')] - param() - - - # Collect all of our input and arguments - $allIn = @($input) + @( - foreach ($arg in $args) { - $arg - } - ) - - # If there were no arguments - if (-not $allIn.Length) { - # return the vector type - return [Numerics.Vector3] - } - - # and expand them - $expandAllIn = @($allIn | Vector) - - # Go over our arguments three at a time - For ($n = 0; $n -lt $expandAllIn.Length; $n+=3) { - $argSet = $expandAllIn[$n..($n+2)] -as [float[]] - switch ($argSet.Length) { - 1 { - [Numerics.Vector3]::new($argSet[0]) - } - 2 { - [Numerics.Vector3]::new([Numerics.Vector2]::new($argSet[0],$argSet[1]), 1) - } - 3 { - [Numerics.Vector3]::new($argSet) - } - } - } -} diff --git a/Commands/Get-Vector4.ps1 b/Commands/Get-Vector4.ps1 deleted file mode 100644 index c515be7..0000000 --- a/Commands/Get-Vector4.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -function Get-Vector4 { - <# - .SYNOPSIS - Gets a Vector4 - .DESCRIPTION - Gets any input and arguments as a Vector4 - .LINK - https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector4?wt.mc_id=MVP_321542 - .EXAMPLE - # Create a vector out of four numbers - Vector4 1 2 3 4 - .EXAMPLE - (Vector4 1 2 3 4 ) + (Vector4 4 3 2 1 ) - .EXAMPLE - (Vector4 1 2 3 4 ) - (Vector4 4 3 2 1) - .EXAMPLE - # Create a thousand vectors - $vectors = Vector4 1..4kb - .EXAMPLE - # Create a thousand vectors in random order, using the pipeline - $vectors = 1..4kb | Get-Random -Count 4kb | Vector4 - .EXAMPLE - # Create vectors from a string - Vector4 "hi" - #> - [Alias('v4','Vector4')] - param() - # Collect all of our input and arguments - $allIn = @($input) + @( - foreach ($arg in $args) { - $arg - } - ) - - # If there were no arguments - if (-not $allIn.Length) { - # return the vector type - return [Numerics.Vector4] - } - - # and expand them - $expandAllIn = @($allIn | vector) - For ($n = 0; $n -lt $expandAllIn.Length; $n+=4) { - $argSet = $expandAllIn[$n..($n+3)] -as [float[]] - switch ($argSet.Length) { - 1 {[Numerics.Vector4]::new($argSet[0]) } - 2 { - [Numerics.Vector4]::new([Numerics.Vector2]::new($argSet[0],$argSet[1]), 1, 1) - } - 3 { - [Numerics.Vector4]::new([Numerics.Vector3]::new($argSet[0],$argSet[1],$argSet[2]), 1) - } - 4 { - [Numerics.Vector4]::new($argSet) - } - } - } -} \ No newline at end of file diff --git a/Vector.ps1 b/Vector.ps1 new file mode 100644 index 0000000..48d16ac --- /dev/null +++ b/Vector.ps1 @@ -0,0 +1,223 @@ +<# +.SYNOPSIS + Gets a one dimensional vector +.DESCRIPTION + Gets a one dimensional vector (or, more simply, a list of numbers) + + This will convert a variety of types into numbers. +.NOTES + This attempts to convert any type into a number. + + Some types are special: + + * Primitive types will be casted to float + * `[Numerics.Vector2]`,`[Numerics.Vector3]`,`[Numerics.Vector4]` output each component + * `[string]`s that match a range (`$start..$end`) will output that range + * `[Version]`s will output each numeric component + * `[semver]`s will output each numeric component, followed by the bytes of a release type + * `[DateTime]` and `[DateTimeOffset]` will become a series of 12 numbers + * `year`,`month`,`day` + * `hour`, `minute`, `second` + * `millisecond`, `microsecond`, `nanosecond` + * `offset.hours`, `offset.minutes`, `offset.seconds` + * `[string]s` will return their bytes in the current `$outputEncoding` + * Anything unknown will be stringified and the bytes will be returned +.EXAMPLE + # Create a vector out of two numbers + Vector2 1 2 +.EXAMPLE + (Vector2 1 2) + (Vector2 2 1) +.EXAMPLE + (Vector2 1 2) - (Vector2 2 1) +.EXAMPLE + # Create a thousand vectors + $vectors = Vector2 1..2kb +.EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..2kb | Get-Random -Count 2kb | Vector2 +.EXAMPLE + # Create a vector from a string + $vector = Vector2 "hi" +.EXAMPLE + # Create a vector out of two numbers + Vector3 1 2 3 +.EXAMPLE + (Vector3 1 2 3 ) + (Vector3 3 2 1) +.EXAMPLE + (Vector3 1 2 3 ) - (Vector3 3 2 1) +.EXAMPLE + # Create a thousand vectors + $vectors = Vector3 1..3kb +.EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..3kb | Get-Random -Count 3kb | Vector3 +.EXAMPLE + # Create a vector from a string + $vector = Vector3 "hi" +.EXAMPLE + # Create a vector out of four numbers + Vector4 1 2 3 4 +.EXAMPLE + (Vector4 1 2 3 4 ) + (Vector4 4 3 2 1 ) +.EXAMPLE + (Vector4 1 2 3 4 ) - (Vector4 4 3 2 1) +.EXAMPLE + # Create a thousand vectors + $vectors = Vector4 1..4kb +.EXAMPLE + # Create a thousand vectors in random order, using the pipeline + $vectors = 1..4kb | Get-Random -Count 4kb | Vector4 +.EXAMPLE + # Create vectors from a string + Vector4 "hi" +#> +[Alias('Vector', + 'Get-Vector1','Vector1','V1', + 'Get-Vector2','Vector2','V2', + 'Get-Vector3','Vector3','V3', + 'Get-Vector4','Vector4','V4' +)] +param() +filter toVector { + $arg = $_ + # Return primitive types + if ($arg.GetType -and $arg.GetType().IsPrimitive) { + # casted to float + return ($arg -as [float]) + } + # Return vector components + if ($arg -is [ValueType]) { + if ($arg -is [Numerics.Vector2]) { + return $arg.X,$arg.Y + } + elseif ($arg -is [Numerics.Vector3]) { + return $arg.X,$arg.Y,$arg.Z + } + elseif ($arg -is [Numerics.Vector4]) { + return $arg.X,$arg.Y,$arg.Z, $arg.W + } + } + # Look for inline ranges. + if ($arg -is [string]) { + if ($arg -match '^\d..\d') { + $start, $end = $arg -split '\..', 2 + $startInt = ($start -as [int]) + $endInt = ($end -as [int]) + if ($null -ne $startInt -and $null -ne $endInt) { + # If found, return them expanded. + return ($startInt..$endInt) + } + } + if ($arg -as [float]) { + return $arg -as [float] + } + } + + + # If the arg is a version, get each number of the version + if ($arg -is [version]) {return $arg.Major,$arg.Minor,$arg.Build,$arg.Revision} + + # If we support semver and the arg is semver + if (('semver' -as [type]) -and $arg -is [semver]) { + # Return the numeric parts of the semver + $arg.Major,$arg.Minor,$arg.Patch + # and turn any string portions to bytes + if ($arg.PreReleaseLabel) { + # make sure to include a leading dash for pre-releases + $OutputEncoding.GetBytes("-$($arg.PreReleaseLabel)") + } + + if ($arg.BuildLabel) { + # make sure to include a leading plus for build labels + $OutputEncoding.GetBytes("+$($arg.BuildLabel)") + } + return + } + + # If the arg is a datetime or datetimeoffset + if ($arg -is [DateTime] -or $arg -is [DateTimeOffset]) { + # make it an offset, and then output 12 values + $dateArg = $arg -as [DateTimeOffset] + # * `year` `month` `day` + $dateArg.Year, $dateArg.Month, $dateArg.Day, + # * `hour` `minute` `second` + $dateArg.Hour, $dateArg.Minute, $dateArg.Second, + # * `millisecond`, `microsecond`, `nanosecond` + $dateArg.Millisecond, $dateArg.Microsecond, $dateArg.Nanosecond, + # * `offset hours`, `offset minutes`, `offset seconds` + $dateArg.Offset.Hours,$dateArg.Offset.Minutes,$dateArg.Offset.Seconds + return + } + # If the arg is a string + if ($arg -is [string]) { + # return its bytes + return $OutputEncoding.GetBytes($arg) + } + # any input we have not caught, stringify and turn to bytes + return $OutputEncoding.GetBytes("$arg") +} + + +# Collect all of our input and arguments +$allIn = @($input) + @( + foreach ($arg in $args) { + $arg + } +) + +$myName = $MyInvocation.InvocationName + +$expandAllIn = @($allIn | toVector) + +if (-not $expandAllIn.Length) { + if ($myName -match '2$') { + return [Numerics.Vector2] + } + elseif ($myName -match '3$') { + return [Numerics.Vector3] + } + elseif ($myName -match '4$') { + return [Numerics.Vector4] + } + else { + return [Numerics.Vector2],[Numerics.Vector3],[Numerics.Vector4] + } +} +if ($myName -match '[234]$') { + $dimension = $matches.0 -as [int] + for ($n = 0; $n -lt $expandAllIn.Length; $n+=$dimension) { + $nums = $expandAllIn[$n..($n+($dimension-1))] -as [float[]] + if ($dimension -eq 2) { + if ($nums.Length -eq 1) { + [Numerics.Vector2]::new($nums[0]) + } else { + [Numerics.Vector2]::new($nums) + } + } elseif ($dimension -eq 3) { + if ($nums.Length -eq 1) { + [Numerics.Vector3]::new($nums[0]) + } + elseif ($nums.Length -eq 2) { + [Numerics.Vector3]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0) + } + elseif ($nums.Length -eq 3) { + [Numerics.Vector3]::new($nums) + } + } elseif ($dimension -eq 4) { + if ($nums.Length -eq 1) { + [Numerics.Vector4]::new($nums[0]) + } + elseif ($nums.Length -eq 2) { + [Numerics.Vector4]::new([Numerics.Vector2]::new($nums[0],$nums[1]), 0, 0) + } + elseif ($nums.Length -eq 3) { + [Numerics.Vector4]::new([Numerics.Vector3]::new($nums[0],$nums[1],$nums[2]), 0) + } + elseif ($nums.Length -eq 4) { + [Numerics.Vector4]::new($nums) + } + } + } +} else { + return $allIn | toVector +} diff --git a/Vector.psm1 b/Vector.psm1 index ebecaec..86a7438 100644 --- a/Vector.psm1 +++ b/Vector.psm1 @@ -1,39 +1,99 @@ -$commandsPath = Join-Path $PSScriptRoot Commands -:ToIncludeFiles foreach ($file in (Get-ChildItem -Path "$commandsPath" -Filter "*-*" -Recurse)) { - if ($file.Extension -ne '.ps1') { continue } # Skip if the extension is not .ps1 - foreach ($exclusion in '\.[^\.]+\.ps1$') { - if (-not $exclusion) { continue } - if ($file.Name -match $exclusion) { - continue ToIncludeFiles # Skip excluded files - } - } - . $file.FullName +#region Eponym + +# Functions and scripts are interchangeable in PowerShell +# So we can make a small module using an eponym file. +# First we need to identify the module name +$moduleName = $MyInvocation.MyCommand.Name -replace '\.psm1$' + +# Once we have done this, we can look for an eponymous script: +$eponym = + $ExecutionContext.SessionState.InvokeCommand.GetCommand(( + Join-Path $PSScriptRoot "$moduleName.ps1" + ), 'ExternalScript') + +# If we did not find one, +if (-not $eponym) { + # warn and return. + Write-Warning "Missing ./$moduleName.ps1" + return } -$myModule = $MyInvocation.MyCommand.ScriptBlock.Module -$ExecutionContext.SessionState.PSVariable.Set($myModule.Name, $myModule) -$myModule.pstypenames.insert(0, $myModule.Name) +# We want to define two functions from this script -New-PSDrive -Name $MyModule.Name -PSProvider FileSystem -Scope Global -Root $PSScriptRoot -ErrorAction Ignore +# One is the name of the script +# The other is the "verb" form of the script. -if ($home) { - $MyModuleProfileDirectory = Join-Path ([Environment]::GetFolderPath("LocalApplicationData")) $MyModule.Name - if (-not (Test-Path $MyModuleProfileDirectory)) { - $null = New-Item -ItemType Directory -Path $MyModuleProfileDirectory -Force - } - New-PSDrive -Name "My$($MyModule.Name)" -PSProvider FileSystem -Scope Global -Root $MyModuleProfileDirectory -ErrorAction Ignore +# Collect our list of verbs +$verbs = Get-Verb | + Sort-Object { $_.Verb.Length }, {$_.Verb } -Descending | + Select-Object -ExpandProperty Verb + +# and craft a regex to see if we start with the verb. +$startsWithVerb = "^(?>$( + $verbs -join '|' +))" + +# Our Exports are: +$exports = + $moduleName, # * The Eponym + $( + # The `Verb-Noun` form + if ($moduleName -match $startsWithVerb) { + "$($matches.0)-$($moduleName -replace "$startsWithVerb\p{P}?")" + } else { + "Get-$($ModuleName -replace '\p{P}')" + } + ) + +# We can use the function provider to create functions in this scope. +foreach ($functionName in $exports) { + # This allows us to dynamically set each export to by the eponym + $ExecutionContext.SessionState.PSVariable.Set( + "function:$functionName", + $eponym.ScriptBlock + ) } -# Set a script variable of this, set to the module -# (so all scripts in this scope default to the correct `$this`) -$script:this = $myModule +# We also want to export any aliases +# and add support for argument completers. +$argumentCompleter = $null +$aliasExports = @( + # walk over all of our attributes + foreach ($attribute in $eponym.ScriptBlock.Attributes) { + # and keep track of any argument completers we find. + if ($attribute -is [ArgumentCompleter]) { + $argumentCompleter = $attribute + } + # Then make our aliases + foreach ($alias in $attribute.aliasNames) { + # (unless the alias is already exported as a function) + if ($alias -in $exports) { continue } + $ExecutionContext.SessionState.PSVariable.Set( + "alias:$alias", $moduleName + ) + $alias + } + } +) + +# If we had an argument completer +if ($argumentCompleter.ScriptBlock) { + # now is the time to register it. -#region Custom -$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { - Remove-TypeData -ErrorAction Ignore -TypeName 'System.Numerics.Vector2' - Remove-TypeData -ErrorAction Ignore -TypeName 'System.Numerics.Vector3' - Remove-TypeData -ErrorAction Ignore -TypeName 'System.Numerics.Vector4' + # Argument completers need to be registered for each function + foreach ($functionExport in $exports) { + Register-ArgumentCompleter -CommandName $functionExport -ScriptBlock $argumentCompleter.ScriptBlock + } + + # and alias + foreach ($aliasExport in $aliasExports) { + Register-ArgumentCompleter -CommandName $aliasExport -ScriptBlock $argumentCompleter.ScriptBlock + } } -#endregion Custom -Export-ModuleMember -Alias * -Function * -Variable $myModule.Name +# We will also be exporting our eponym as a variable +$ExecutionContext.SessionState.PSVariable.Set($moduleName, $eponym) + +# All that's left to do is explicitly export just these functions. +Export-ModuleMember -Function $exports -Alias $aliasExports -Variable $moduleName +#endregion Eponym \ No newline at end of file From 0cc34499adbc8911601d5d41f2fb791b10b90528 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:38:27 -0700 Subject: [PATCH 05/11] feat: `Vector` converting matrix input ( Fixes #16 ) --- Vector.ps1 | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Vector.ps1 b/Vector.ps1 index 48d16ac..8178271 100644 --- a/Vector.ps1 +++ b/Vector.ps1 @@ -70,6 +70,12 @@ .EXAMPLE # Create vectors from a string Vector4 "hi" +.LINK + https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2?wt.mc_id=MVP_321542 +.LINK + https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3?wt.mc_id=MVP_321542 +.LINK + https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector4?wt.mc_id=MVP_321542 #> [Alias('Vector', 'Get-Vector1','Vector1','V1', @@ -148,6 +154,22 @@ filter toVector { $dateArg.Offset.Hours,$dateArg.Offset.Minutes,$dateArg.Offset.Seconds return } + + if ($arg -is [Numerics.Matrix3x2]) { + $arg.M11,$arg.M12, + $arg.M21,$arg.M22, + $arg.M31,$arg.M32 + return + } + + if ($arg -is [Numerics.Matrix4x4]) { + $arg.M11,$arg.M12,$arg.M13,$arg.M14 + $arg.M21,$arg.M22,$arg.M23,$arg.M24 + $arg.M31,$arg.M32,$arg.M33,$arg.M34 + $arg.M41,$arg.M42,$arg.M43,$arg.M44 + return + } + # If the arg is a string if ($arg -is [string]) { # return its bytes From 383af093a2f5c29755ba9eb9ec071f65bd50d4be Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:38:47 -0700 Subject: [PATCH 06/11] feat: `Vector` aliasing ( Fixes #15 ) --- Vector.psd1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Vector.psd1 b/Vector.psd1 index 3e83cbf..f4ff3a9 100644 --- a/Vector.psd1 +++ b/Vector.psd1 @@ -25,7 +25,7 @@ Author = 'James Brundage' CompanyName = 'Start-Automating' # Copyright statement for this module -Copyright = '2025 Start-Automating' +Copyright = '2025-2026 Start-Automating' # Description of the functionality provided by this module Description = 'Vectors in PowerShell' @@ -67,16 +67,16 @@ Description = 'Vectors in PowerShell' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Get-Vector', 'Get-Vector2', 'Get-Vector3', 'Get-Vector4' +FunctionsToExport = 'Get-Vector' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. -CmdletsToExport = '*' +CmdletsToExport = @() # Variables to export from this module -VariablesToExport = '*' +VariablesToExport = @('Vector') # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. -AliasesToExport = 'V1', 'V2', 'V3', 'V4', 'Vector1', 'Vector2', 'Vector3', 'Vector4', 'Vector' +AliasesToExport = 'Get-Vector2', 'Get-Vector3', 'Get-Vector4', 'V1', 'V2', 'V3', 'V4', 'Vector', 'Vector1', 'Vector2', 'Vector3', 'Vector4' # DSC resources to export from this module # DscResourcesToExport = @() From 40043e32ea1257902d453e6411482881997175b9 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:46:10 -0700 Subject: [PATCH 07/11] docs: `Vector` eponym doc corrections ( Fixes #15 ) --- Vector.ps1 | 10 ++- Vector.psd1 | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 2 deletions(-) diff --git a/Vector.ps1 b/Vector.ps1 index 8178271..4c88310 100644 --- a/Vector.ps1 +++ b/Vector.ps1 @@ -1,10 +1,15 @@ <# .SYNOPSIS - Gets a one dimensional vector + Gets vectors .DESCRIPTION - Gets a one dimensional vector (or, more simply, a list of numbers) + Gets a vector in one, two, three, or four dimensions. This will convert a variety of types into numbers. + + `Vector1` will return a list of numbers + `Vector2` will return a list of `[Numerics.Vector2]` + `Vector3` will return a list of `[Numerics.Vector3]` + `Vector4` will return a list of `[Numerics.Vector4]` .NOTES This attempts to convert any type into a number. @@ -15,6 +20,7 @@ * `[string]`s that match a range (`$start..$end`) will output that range * `[Version]`s will output each numeric component * `[semver]`s will output each numeric component, followed by the bytes of a release type + * `[Numerics.Matrix3x2]` and `[Numerics.Matrix4x4]` will return the numbers in the matrix * `[DateTime]` and `[DateTimeOffset]` will become a series of 12 numbers * `year`,`month`,`day` * `hour`, `minute`, `second` diff --git a/Vector.psd1 b/Vector.psd1 index f4ff3a9..6ec371f 100644 --- a/Vector.psd1 +++ b/Vector.psd1 @@ -123,6 +123,185 @@ PrivateData = @{ * SECURITY (#12) '@ + PSIntro = @' +# Vector + +Numbers are great! + +When we measure things with one number, it's technically called a scalar. + +When we measure things with more than one number, it's called a [vector](https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29) + +We can do lots of things with vectors. We can add or substract them, multiply and divide them. + +Vectors are very useful. + +This module helps you use Vectors in PowerShell + +## Vectors in PowerShell + +Vectors are actually built into PowerShell. + +Because PowerShell is built atop of the .NET Framework, +and the .NET Framework has had vector support for over a decade, +PowerShell has had vectors for over a decade. + +~~~PowerShell +# Create a 2D vector +[Numerics.Vector2]::new(1,2) +# Create a 3D vector +[Numerics.Vector3]::new(1,2,3) +# Create a 4D vector +[Numerics.Vector4]::new(1,2,3,4) +~~~ + +This module exists to make vectors a bit more useful by providing commands to construct them. + +### Getting Vectors + +There are a few commands in this module: + +* `Get-Vector` +* `Get-Vector2` +* `Get-Vector3` +* `Get-Vector4` + +Each command constructs a vector of the corresponding dimension. + +A Vector with one dimension is just a list. + +We can also drop the `Get` and just refer to them by vector number + +~~~PowerShell +Vector2 1 2 +Vector3 1 2 3 +Vector4 1 2 3 4 +~~~ + +We can be even shorter, and use `V2`, `V3`, and `V4` + +~~~PowerShell +v2 1 2 +v3 1 2 3 +v4 1 2 3 4 +~~~ + +We can turn anything into a series of vectors. + +~~~PowerShell +v2 1 +v3 1 +v4 1 +~~~ + +Strings can become vectors, too! (after all, each byte is already a number) + +~~~PowerShell +v2 "hi" +v3 "hi" +v4 "hi" +~~~ + +### Vector Operators + +.NET vectors are _very_ powerful, and overload many operators. + +For example, we can add, subtract, multiply, or divide by a scalar. + +~~~PowerShell +# Let's start with addition. +# We can add a scalar to a vector. +(v2 1 2) + 1 +(v3 1 2 3) + 1 +(v4 1 2 3 4) + 1 + +# Let's try substraction: +(v2 1 2) - 1 +(v3 1 2 3) - 1 +(v4 1 2 3 4) - 1 + +# How about multiplication? +(v2 1 2) * 2 +(v3 1 2 3) * 2 +(v4 1 2 3 4) * 2 + +# What about division? +(v2 1 2) / 2 +(v3 1 2 3) / 2 +(v4 1 2 3 4) / 2 +~~~ + +We can also work with other vectors: + +~~~PowerShell +# Adding vectors: +(v2 1 2) + (v2 1 2) +(v3 1 2 3) + (v3 1 2 3) +(v4 1 2 3 4) + (v4 1 2 3 4) + +# Subtracting vectors: +(v2 1 2) - (v2 1 2) +(v3 1 2 3) - (v3 1 2 3) +(v4 1 2 3 4) - (v4 1 2 3 4) + +# Multiplying vectors: +(v2 1 2) * (v2 1 2) +(v3 1 2 3) * (v3 1 2 3) +(v4 1 2 3 4) * (v4 1 2 3 4) + +# Dividing vectors: +(v2 1 2) / (v2 1 2) +(v3 1 2 3) / (v3 1 2 3) +(v4 1 2 3 4) / (v4 1 2 3 4) +~~~ + +### Vector Methods + +Vectors have a large number of methods to work with. + +Let's start simple, by calculating the length of a given vector. + +~~~PowerShell +(v2 1 1).Length() +(v3 1 1 1).Length() +(v4 1 1 1 1).Length() +~~~ + +Many of the most useful things we can do with a vector are exposed as a static methods: + +~~~PowerShell +(v2 1 1) | Get-Member -Static +(v3 1 1 1) | Get-Member -Static +(v4 1 1 1 1) | Get-Member -Static +~~~ + + +We can access static method with `::` + +For a small example, let's find the distance between vectors: + +~~~PowerShell +$vector1 = v2 1 2 +$vector2 = v2 2 1 +$vector1::Distance($vector1, $vector2) +~~~ + +For another simple example, let's find a few point between two points, using +[Linear Interpolation `lerp`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2.lerp?wt.mc_id=MVP_321542) + +~~~PowerShell +$vector1 = v2 1 5 +$vector2 = v2 1 -5 +$vector1::Lerp($vector1, $vector2, 0.25) +$vector1::Lerp($vector1, $vector2, 0.5) +$vector1::Lerp($vector1, $vector2, 0.75) +~~~ + +All of this would not be possible without the great work of the .NET team to build such incredibly useful data structures. + +Hopefully this module helps us all work with vectors! +'@ + # Prerelease string of this module # Prerelease = '' From 9f1ca66eb77ffc9ee449d005c2ad34da9425c0b0 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:47:41 -0700 Subject: [PATCH 08/11] docs: `Vector` `README.md.ps1` ( Fixes #17 ) --- README.md | 237 +++++++++++++++++++++++++++++++++++--- README.md.ps1 | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 528 insertions(+), 18 deletions(-) create mode 100644 README.md.ps1 diff --git a/README.md b/README.md index eac6d0d..ed57756 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Vector +[![Vector](https://img.shields.io/powershellgallery/dt/Vector)](https://www.powershellgallery.com/packages/Vector/) +## Vectors in PowerShell +# Vector Numbers are great! @@ -31,30 +34,18 @@ PowerShell has had vectors for over a decade. This module exists to make vectors a bit more useful by providing commands to construct them. -### Installing and Importing - -We can install the Vector module from the gallery: - -~~~PowerShell -# Install the module from the PowerShell gallery -Install-Module Vector -~~~ - -Once installed, we can import the Vector module with Import-Module: - -~~~PowerShell -Import-Module Vector -~~~ - ### Getting Vectors There are a few commands in this module: +* `Get-Vector` * `Get-Vector2` * `Get-Vector3` * `Get-Vector4` -Each command constructs a vector of the corresponding size. +Each command constructs a vector of the corresponding dimension. + +A Vector with one dimension is just a list. We can also drop the `Get` and just refer to them by vector number @@ -172,7 +163,8 @@ $vector2 = v2 2 1 $vector1::Distance($vector1, $vector2) ~~~ -For another simple example, let's find a few point between two points, using [Linear Interpolation `lerp`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2.lerp?wt.mc_id=MVP_321542) +For another simple example, let's find a few point between two points, using +[Linear Interpolation `lerp`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2.lerp?wt.mc_id=MVP_321542) ~~~PowerShell $vector1 = v2 1 5 @@ -184,4 +176,213 @@ $vector1::Lerp($vector1, $vector2, 0.75) All of this would not be possible without the great work of the .NET team to build such incredibly useful data structures. -Hopefully this module helps us all work with vectors! \ No newline at end of file +Hopefully this module helps us all work with vectors! + +## Installing and Importing + +You can install Vector from the [PowerShell gallery](https://powershellgallery.com/) + +~~~PowerShell +Install-Module Vector -Scope CurrentUser -Force +~~~ + +Once installed, you can import the module with: + +~~~PowerShell +Import-Module Vector -PassThru +~~~ + + +You can also clone the repo and import the module locally: + +~~~PowerShell +git clone https://github.com/PowerShellWeb/Vector +cd ./Vector +Import-Module ./ -PassThru +~~~ + +## Functions +Vector has 1 function +### Get-Vector +#### Gets vectors + +Gets a vector in one, two, three, or four dimensions. + +This will convert a variety of types into numbers. + +`Vector1` will return a list of numbers +`Vector2` will return a list of `[Numerics.Vector2]` +`Vector3` will return a list of `[Numerics.Vector3]` +`Vector4` will return a list of `[Numerics.Vector4]` + +
+Notes + +This attempts to convert any type into a number. + +Some types are special: + +* Primitive types will be casted to float +* `[Numerics.Vector2]`,`[Numerics.Vector3]`,`[Numerics.Vector4]` output each component +* `[string]`s that match a range (`$start..$end`) will output that range +* `[Version]`s will output each numeric component +* `[semver]`s will output each numeric component, followed by the bytes of a release type +* `[Numerics.Matrix3x2]` and `[Numerics.Matrix4x4]` will return the numbers in the matrix +* `[DateTime]` and `[DateTimeOffset]` will become a series of 12 numbers + * `year`,`month`,`day` + * `hour`, `minute`, `second` + * `millisecond`, `microsecond`, `nanosecond` + * `offset.hours`, `offset.minutes`, `offset.seconds` +* `[string]s` will return their bytes in the current `$outputEncoding` +* Anything unknown will be stringified and the bytes will be returned + +
+
+Examples + +#### Example 1 + +Create a vector out of two numbers +~~~PowerShell +Vector2 1 2 +~~~ + + +#### Example 2 + +~~~PowerShell +(Vector2 1 2) + (Vector2 2 1) +~~~ + + +#### Example 3 + +~~~PowerShell +(Vector2 1 2) - (Vector2 2 1) +~~~ + + +#### Example 4 + +Create a thousand vectors +~~~PowerShell +$vectors = Vector2 1..2kb +~~~ + + +#### Example 5 + +Create a thousand vectors in random order, using the pipeline +~~~PowerShell +$vectors = 1..2kb | Get-Random -Count 2kb | Vector2 +~~~ + + +#### Example 6 + +Create a vector from a string +~~~PowerShell +$vector = Vector2 "hi" +~~~ + + +#### Example 7 + +Create a vector out of two numbers +~~~PowerShell +Vector3 1 2 3 +~~~ + + +#### Example 8 + +~~~PowerShell +(Vector3 1 2 3 ) + (Vector3 3 2 1) +~~~ + + +#### Example 9 + +~~~PowerShell +(Vector3 1 2 3 ) - (Vector3 3 2 1) +~~~ + + +#### Example 10 + +Create a thousand vectors +~~~PowerShell +$vectors = Vector3 1..3kb +~~~ + + +#### Example 11 + +Create a thousand vectors in random order, using the pipeline +~~~PowerShell +$vectors = 1..3kb | Get-Random -Count 3kb | Vector3 +~~~ + + +#### Example 12 + +Create a vector from a string +~~~PowerShell +$vector = Vector3 "hi" +~~~ + + +#### Example 13 + +Create a vector out of four numbers +~~~PowerShell +Vector4 1 2 3 4 +~~~ + + +#### Example 14 + +~~~PowerShell +(Vector4 1 2 3 4 ) + (Vector4 4 3 2 1 ) +~~~ + + +#### Example 15 + +~~~PowerShell +(Vector4 1 2 3 4 ) - (Vector4 4 3 2 1) +~~~ + + +#### Example 16 + +Create a thousand vectors +~~~PowerShell +$vectors = Vector4 1..4kb +~~~ + + +#### Example 17 + +Create a thousand vectors in random order, using the pipeline +~~~PowerShell +$vectors = 1..4kb | Get-Random -Count 4kb | Vector4 +~~~ + + +#### Example 18 + +Create vectors from a string +~~~PowerShell +Vector4 "hi" +~~~ + +
+
+Links + +* [system.numerics.vector2 (Learn DotNet)](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector2?wt.mc_id=MVP_321542) +* [system.numerics.vector3 (Learn DotNet)](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3?wt.mc_id=MVP_321542) +* [system.numerics.vector4 (Learn DotNet)](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector4?wt.mc_id=MVP_321542) + +
diff --git a/README.md.ps1 b/README.md.ps1 new file mode 100644 index 0000000..573e240 --- /dev/null +++ b/README.md.ps1 @@ -0,0 +1,309 @@ +<# +.SYNOPSIS + README.md.ps1 +.DESCRIPTION + README.md.ps1 makes README.md + + This is a simple and helpful scripting convention for writing READMEs. + + `./README.md.ps1 > ./README.md` + + Feel free to copy and paste this code. + + Please document your parameters, and add NOTES. +.NOTES + This README.md.ps1 is used to generate help for a module. + + It: + + * Outputs the name and description + * Provides installation instructions + * Lists commands + * Includes aliases + * Includes notes + * Lists parameters + * Lists examples + * Lists links +.EXAMPLE + ./README.md.ps1 > ./README.md +.EXAMPLE + Get-Help ./README.md.ps1 +#> +param( +# The name of the module +[string]$ModuleName = $($PSScriptRoot | Split-Path -Leaf), + +# The domains that serve git repositories. +# If the project uri links to this domain, +# installation instructions will show how to import the module locally. +[string[]] +$GitDomains = @( + 'github.com', 'tangled.org', 'tangled.sh', 'codeberg.org' +), + +# A list of types the module exposes +[Alias('ModuleTypeNames','ModuleTypes')] +[string[]] +$ModuleTypeName = @(), + +# The name of the root directory containing types. +[string] +$TypeRoot = 'Types', + +# If set, we don't need no badges. +[switch] +$NoBadge, + +# If set, will not display gallery instructions or badges +[switch] +$NotOnGallery +) + +Push-Location $PSScriptRoot + +# Import the module +$module = Import-Module "./$ModuleName.psd1" -PassThru + +# And output a header +"# $module" + +if (-not $NoBadge) { + # If it is on the gallery, show the downloads badge. + if (-not $NotOnGallery) { + @( + "[!" + "[$ModuleName](https://img.shields.io/powershellgallery/dt/$ModuleName)" + "](https://www.powershellgallery.com/packages/$ModuleName/)" + ) -join '' + } +} + +# Show the module description +"## $($module.Description)" + +# Show any intro section defined in the manifest +$module.PrivateData.PSData.PSIntro + +#region Boilerplate installation instructions +if (-not $NotOnGallery) { +@" + +## Installing and Importing + +You can install $ModuleName from the [PowerShell gallery](https://powershellgallery.com/) + +~~~PowerShell +Install-Module $($ModuleName) -Scope CurrentUser -Force +~~~ + +Once installed, you can import the module with: + +~~~PowerShell +Import-Module $ModuleName -PassThru +~~~ + +"@ +} +#endregion Gallery installation instructions + +#region Git installation instructions +$projectUri = $module.PrivateData.PSData.ProjectURI -as [uri] + +if ($projectUri.DnsSafeHost -in $GitDomains) { +@" + +You can also clone the repo and import the module locally: + +~~~PowerShell +git clone $projectUri +cd ./$ModuleName +Import-Module ./ -PassThru +~~~ + +"@ +} +#endregion Git installation instructions + +#region Exported Functions +$exportedFunctions = $module.ExportedFunctions + +$uniqueFunctions = @() +$uniqueNames = @(foreach ($function in $exportedFunctions.GetEnumerator()) { + if ($uniqueFunctions -contains $function.Value.ScriptBlock) { + continue + } else { + $uniqueFunctions += $function.Value.ScriptBlock + } + $function.Key +}) + + +if ($uniqueNames) { + + "## Functions" + + "$($ModuleName) has $($uniqueNames.Count) function$( + if ($uniqueNames.Count -gt 1) { "s"} + )" + + $duplicate = @() + foreach ($export in $uniqueNames) { + $exportedFunction = $exportedFunctions[$export] + if ($duplicate -contains $exportedFunction.ScriptBlock) { + continue + } else { + $duplicate += $exportedFunction.ScriptBlock + } + # Get help if it there is help to get + $help = Get-Help $export + # If the help is a string, + if ($help -is [string]) { + # make it preformatted text + "~~~" + "$export" + "~~~" + } else { + # Otherwise, add list the export + "### $($export)" + + # And make it's synopsis a header + "#### $($help.SYNOPSIS)" + + "" + # put the description below that + "$($help.Description.text -join [Environment]::NewLine)" + "" + + $commandAliases = foreach ($aliasName in $module.ExportedAliases.Keys) { + if ($module.ExportedAliases[$aliasName].ResolvedCommand.ScriptBlock -eq + $exportedFunction.ScriptBlock) { + $aliasName + } + } + + $notes = $help.alertSet.alert.text + + if ($notes) { + "
" + "Notes" + "" + $notes -join [Environment]::NewLine + "" + "
" + } + + if ($commandAliases) { + "" + "
" + "Aliases" + "" + foreach ($commandAlias in $commandAliases) { + "- $commandAlias" + } + "
" + "" + "" + + } + + # Show our examples + if ($help.examples.example) { + "
" + "Examples" + + $exampleNumber = 0 + foreach ($example in $help.examples.example) { + $markdownLines = @() + $exampleNumber++ + $nonCommentLine = $false + "" + "#### Example $exampleNumber" + "" + + # Combine the code and remarks + $exampleLines = + @( + $example.Code + foreach ($remark in $example.Remarks.text) { + if (-not $remark) { continue } + $remark + } + ) -join ([Environment]::NewLine) -split '(?>\r\n|\n)' # and split into lines + + # Go thru each line in the example as part of a loop + $codeBlock = @(foreach ($exampleLine in $exampleLines) { + # Any comments until the first uncommentedLine are markdown + if ($exampleLine -match '^\#' -and -not $nonCommentLine) { + $markdownLines += $exampleLine -replace '^\#\s{0,1}' + } else { + $nonCommentLine = $true + $exampleLine + } + }) -join [Environment]::NewLine + + $markdownLines + "~~~PowerShell" + $CodeBlock + "~~~" + "" + } + "
" + } + + # Make a table of parameters + if ($help.parameters.parameter) { + "
" + + "Parameters" + + "" + + "|Name|Type|Description|" + "|-|-|-|" + foreach ($parameter in $help.Parameters.Parameter) { + "|$($parameter.Name)|$($parameter.type.name)|$( + $parameter.description.text -replace '(?>\r\n|\n)', '
' + )|" + } + + "
" + "" + } + + $relatedUris = foreach ($link in $help.relatedLinks.navigationLink) { + if ($link.uri) { + $link.uri + } + } + if ($relatedUris) { + "
" + "Links" + "" + foreach ($related in $relatedUris) { + $relatedUri = $related -as [uri] + if ($relatedUri.DnsSafeHost -eq 'learn.microsoft.com' -and + $relatedUri.LocalPath -match '/dotnet/api') { + "* [$($relatedUri.segments[-1] -replace '/') (Learn DotNet)]($related)" + } + elseif ($relatedUri.DnsSafeHost -eq 'developer.mozilla.org' -and + $relatedUri.LocalPath -match '/(?[^/]+)/reference') { + "* [$($matches.ref) $($relatedUri.segments[-1] -replace '/') (MDN)]($related)" + } + elseif ($relatedUri.DnsSafeHost -eq 'github.com') { + "* [$($relatedUri.Segments -replace '/', ' ') (GitHub)]($related)" + } + elseif ($relatedUri.DnsSafeHost) { + "* [$($relatedUri.DnsSafeHost)$($relatedUri.LocalPath)]($related)" + } else { + "* [$related]($related)" + } + } + "" + "
" + } + } + } +} +#endregion Exported Functions + +Pop-Location \ No newline at end of file From f18a215dce8e3c45da971d337d064928e4a1a847 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:49:11 -0700 Subject: [PATCH 09/11] docs: `Vector` `README.md.ps1` ( Fixes #17 ) Using bullet points --- README.md | 8 ++++---- Vector.ps1 | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ed57756..5a7e519 100644 --- a/README.md +++ b/README.md @@ -210,10 +210,10 @@ Gets a vector in one, two, three, or four dimensions. This will convert a variety of types into numbers. -`Vector1` will return a list of numbers -`Vector2` will return a list of `[Numerics.Vector2]` -`Vector3` will return a list of `[Numerics.Vector3]` -`Vector4` will return a list of `[Numerics.Vector4]` +* `Vector1` will return a list of numbers +* `Vector2` will return a list of `[Numerics.Vector2]` +* `Vector3` will return a list of `[Numerics.Vector3]` +* `Vector4` will return a list of `[Numerics.Vector4]`
Notes diff --git a/Vector.ps1 b/Vector.ps1 index 4c88310..c9af074 100644 --- a/Vector.ps1 +++ b/Vector.ps1 @@ -6,10 +6,10 @@ This will convert a variety of types into numbers. - `Vector1` will return a list of numbers - `Vector2` will return a list of `[Numerics.Vector2]` - `Vector3` will return a list of `[Numerics.Vector3]` - `Vector4` will return a list of `[Numerics.Vector4]` + * `Vector1` will return a list of numbers + * `Vector2` will return a list of `[Numerics.Vector2]` + * `Vector3` will return a list of `[Numerics.Vector3]` + * `Vector4` will return a list of `[Numerics.Vector4]` .NOTES This attempts to convert any type into a number. From d234e467188efced4d9d699142ea8f507882ba36 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:08:21 -0700 Subject: [PATCH 10/11] test: `Vector` tests ( Fixes #14 ) Adding tests for types --- Vector.tests.ps1 | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Vector.tests.ps1 b/Vector.tests.ps1 index 1422003..24dfdab 100644 --- a/Vector.tests.ps1 +++ b/Vector.tests.ps1 @@ -40,4 +40,25 @@ describe Vector { $divide.Y | Should -Be 1 } } + + context 'Vector Types' { + it 'Will return the vector type when no parameters are passed' { + vector | Should -BeOfType ([Type]) + } + it 'Will return Vector2 if the name ends in 2' { + v2 | Should -Be ([Numerics.Vector2]) + vector2 | Should -Be ([Numerics.Vector2]) + Get-Vector2 | Should -Be ([Numerics.Vector2]) + } + it 'Will return Vector3 if the name ends in 3' { + v3 | Should -Be ([Numerics.Vector3]) + vector3 | Should -Be ([Numerics.Vector3]) + Get-Vector3 | Should -Be ([Numerics.Vector3]) + } + it 'Will return Vector4 if the name ends in 4' { + v4 | Should -Be ([Numerics.Vector4]) + vector4 | Should -Be ([Numerics.Vector4]) + Get-Vector4 | Should -Be ([Numerics.Vector4]) + } + } } From 91003bece3079261af3e51e27503e72d9e18c8e0 Mon Sep 17 00:00:00 2001 From: James Brundage <+@users.noreply.github.com> Date: Thu, 13 Aug 2026 09:52:16 -0700 Subject: [PATCH 11/11] release: `Vector` 0.1.1 Updating Module Version, Release Notes, and CHANGELOG --- CHANGELOG.md | 14 +++++++++++++- Vector.psd1 | 37 ++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 803f211..e74d191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,16 @@ -## Vector 0.1: +# Vector + +## Vector 0.1.1 + +* `Vector` is an eponoym (#15) + * This module exposes one command with many aliases +* `Vector` converts `Matrix3x2` and `Matrix4x4` into vectors (#16) +* Vectors return their type when provided no input (#14) +* Added `README.md.ps1` (#17) + +--- + +## Vector 0.1 * Initial Release of Vector module * Commands: diff --git a/Vector.psd1 b/Vector.psd1 index 6ec371f..14d19c9 100644 --- a/Vector.psd1 +++ b/Vector.psd1 @@ -10,7 +10,7 @@ RootModule = 'Vector.psm1' # Version number of this module. -ModuleVersion = '0.1' +ModuleVersion = '0.1.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -93,34 +93,29 @@ PrivateData = @{ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. - Tags = 'PowerShell', 'Vector', 'Math', 'VectorMath' + Tags = 'PowerShell', 'Vector', 'Math' # A URL to the main website for this project. - ProjectURI = 'https://github.com/PowerShellWeb/Vector' + ProjectURI = 'https://github.com/PoshWeb/Vector' # A URL to the license for this module. - LicenseURI = 'https://github.com/PowerShellWeb/Vector/blob/main/LICENSE' + LicenseURI = 'https://github.com/PoshWeb/Vector/blob/main/LICENSE' # A URL to an icon representing this module. # IconUri = '' # ReleaseNotes of this module ReleaseNotes = @' -## Vector 0.1: - -* Initial Release of Vector module -* Commands: - * Get-Vector (#1) - * Get-Vector2 (#2) - * Get-Vector3 (#3) - * Get-Vector4 (#4) -* Vector Workflow (#5) -* Vector Tests (#6) -* Vector Docs - * Demo (#7) - * README (#8) - * FUNDING (#9) - * CODE_OF_CONDUCT (#10) - * CONTRIBUTING (#11) - * SECURITY (#12) +## Vector 0.1.1 + +* `Vector` is an eponoym (#15) + * This module exposes one command with many aliases +* `Vector` converts `Matrix3x2` and `Matrix4x4` into vectors (#16) +* Vectors return their type when provided no input (#14) +* Added `README.md.ps1` (#17) + +--- + +Additional History in [CHANGELOG](https://github.com/PoshWeb/Vector/blob/main/CHANGELOG.md) + '@ PSIntro = @'