Created
March 10, 2014 11:51
-
-
Save BitPuffin/9463633 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Author: Isak Andersson | |
from math import pow, sqrt | |
from macros import error | |
type | |
TVector*[T; D: static[int]] = array[0..D-1, T] ## T = Type, I = Indices - will possibly later be changed to Dimension (number) | |
TVec2* = TVector[float32, 2] | |
TVec3* = TVector[float32, 3] | |
TVec4* = TVector[float32, 4] | |
TDVec2* = TVector[float64, 2] | |
TDVec3* = TVector[float64, 3] | |
TDVec4* = TVector[float64, 4] | |
TIVec2* = TVector[int32, 2] | |
TIVec3* = TVector[int32, 3] | |
TIVec4* = TVector[int32, 4] | |
TUVec2 = TVector[uint32, 2] | |
TUVec3 = TVector[uint32, 3] | |
TUvec4 = TVector[uint32, 4] | |
proc `==`*(a, b: TVector): bool {.noSideEffect.} = | |
for i in low(a)..high(a): | |
if a[i] != b[i]: | |
return false | |
return true | |
## TODO: change tolerance to TReal once regression in compiler has been fixed | |
proc `~=`*(a, b: TVector, tolerance: float = 1.0e-5): bool {.noSideEffect.} = | |
## Approximately equal | |
## Takes in to account that floating points are not usually the same | |
for i in low(a)..high(a): | |
if abs(a[i] - b[i]) >= tolerance: | |
return false | |
return true | |
template `+`*(a: TVector): expr = | |
a | |
proc `+`*(a, b: TVector): TVector {.noSideEffect.} = | |
for i in low(a)..high(a): | |
result[i] = a[i] + b[i] | |
proc `-`*(a: TVector): TVector {.noSideEffect.} = | |
for i in low(a)..high(a): | |
result[i] = -a[i] | |
proc `-`*(a, b: TVector): TVector {.noSideEffect.} = | |
for i in low(a)..high(a): | |
result[i] = a[i] - b[i] | |
proc mag*(a: TVector): float = | |
for i in low(a)..high(a): | |
when TVector.T is int: | |
result += pow(toFloat(a[i]), 2.0) | |
elif TVector.T is float: | |
result += pow(a[i], 2.0) | |
else: | |
{.fatal: "Cannot pow that datatype".} | |
result = sqrt(result) | |
proc `*.`*(a, b: TVector): TVector.T {.noSideEffect.} = | |
## Vector dot product | |
for i in low(a)..high(a): | |
result += a[i] * b[i] | |
proc `*+`*(a, b: TVector): TVector {.noSideEffect.} = | |
## Vector cross product | |
when len(a) != 3: | |
{.fatal: "Cross product only works with 3 dimensional vectors".} | |
result = | |
[a[1] * b[2] - b[1] * a[2], | |
a[2] * b[0] - b[2] * a[0], | |
a[0] * b[1] - b[0] * a[1]] | |
proc dist*(a, b: TVector): float {.noSideEffect.} = | |
result = (a - b).mag | |
proc `*`*[T](a: T; b: TVector): TVector {.noSideEffect.} = | |
for i in low(b)..high(b): | |
result[i] = a * b[i] | |
template `*`*[T](a: TVector; b: T): expr = | |
b * a | |
# Kind of sucks for ints currently, perhaps convert an int vector to float in this case? | |
proc normalized*(a: TVector): TVector = | |
let m = mag(a) | |
for i in low(a)..high(a): | |
result[i] = a[i] / m | |
const | |
xSwizzleChars = {'x', 'X', 'r', 'R', 's', 'S'} | |
ySwizzleChars = {'y', 'Y', 'g', 'G', 't', 'T'} | |
zSwizzleChars = {'z', 'Z', 'b', 'B', 'p', 'P'} | |
wSwizzleChars = {'w', 'W', 'a', 'A', 'q', 'Q'} | |
swizzleChars = xSwizzleChars + ySwizzleChars + zSwizzleChars + wSwizzleChars | |
proc swizzleImpl[I](str: string): array[I, int] {.compileTime.} = | |
for i, ch in str: | |
if ch in xSwizzleChars: | |
result[i] = 0 | |
elif ch in ySwizzleChars: | |
result[i] = 1 | |
elif ch in zSwizzleChars: | |
result[i] = 2 | |
elif ch in wSwizzleChars: | |
result[i] = 3 | |
from strutils import contains | |
template `{}`*(vec: TVector, str: string{lit}): expr {.deprecated.} = | |
## returns a vector where the element type is `T` and the dimension is `str.len`. | |
## The value of each element is that of the index of `vec` that each respective character in `str` | |
## corresponds to. | |
## The corresponding index will be 0 if the character is present in xSwizzleChars, 1 if it's | |
## present in ySwizzleChars and so on. | |
## If any index is larger than that of `I` - 1, then an assertion error will be raised, | |
## though this will eventually be a compile-time error. | |
## Each character must be present in `swizzleChars`, and the length of `str` must be > 0. | |
## Example: | |
## | |
## .. code-block:: Nimrod | |
## var vec3: TVec3i = [1, 3, 37] | |
## assert vec3{"rgbbg"} == [1, 3, 37, 37, 3] | |
## var vec4: TVec4i = [1, 3, 37, 4] | |
## assert vec4{"wWaAqQSTPy"} == [4, 4, 4, 4, 4, 4, 1, 3, 37, 3] | |
when str.contains({char(0)..char(255)} - swizzleChars): | |
{.fatal: "Valid swizzle characters: " & $swizzleChars & ". Got: " & str.} | |
when str.len == 0: | |
{.fatal: "Cannot swizzle zero components".} | |
var result: TVector[vec[0].type, range[0.. <str.len]] | |
for i, component in swizzleImpl[0.. <str.len](str): | |
assert component < vec.len, "Invalid swizzle character found for " & $vec.len & | |
"-dimensional vector. Got: " & str | |
result[i] = vec[component] | |
result | |
proc `$`*(a: TVector): string {.noSideEffect.} = | |
result = "" | |
result &= "[" | |
var h = high(a) | |
for i in low(a)..h: | |
result &= $a[i] | |
if i != h: | |
result &= ", " | |
result &= "]" | |
when isMainModule: | |
var vec3: TVector[int, 3] = [1, 3, 37] | |
#assert vec3{"rgbbg"} == [1, 3, 37, 37, 3] | |
#assert vec3{"rrbbggr"} == [1, 1, 37, 37, 3, 3, 1] | |
var vec4: TVector[int, 4] = [1, 3, 37, 4] | |
#assert vec4{"wWaAqQSTPy"} == [4, 4, 4, 4, 4, 4, 1, 3, 37, 3] | |
#assert vec4{"rgbbg"} == [1, 3, 37, 37, 3] | |
#assert vec4{"rrbaggr"} == [1, 1, 37, 4, 3, 3, 1] | |
assert($vec3 == "[1, 3, 37]") | |
assert($vec4 == "[1, 3, 37, 4]") | |
var vec3f: TVec3 = [2.0'f32, 4.0'f32, 5.0'f32] | |
assert vec3f ~= vec3f | |
assert(vec3f != ([2.0'f32, 4.0'f32, 5.001'f32])) | |
assert(vec3f != ([2.0'f32, 4.001'f32, 5.0'f32])) | |
assert(not (vec3f == ([2.0'f32, 4.001'f32, 5.0'f32]))) | |
assert(vec3f ~= ([2.0'f32, 4.0000001'f32, 5.0'f32])) | |
assert(vec3f ~= ([2.0000001'f32, 4.0'f32, 5.0'f32])) | |
assert(not (vec3f ~= ([2.001'f32, 4.0'f32, 5.0'f32]))) | |
var vec2f: TVector[float, range[0..1]] = [3.2, 83.28] | |
discard vec2f.mag |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment