Created
May 7, 2021 22:59
-
-
Save MrSmith33/aadbe180d5a3a12d98ffd3f3d2f2f75f to your computer and use it in GitHub Desktop.
Vector thingy
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
import std.stdio; | |
void main() | |
{ | |
/* | |
(vec2(1,5)-ivec2(9,9)).writeln; | |
vec2 v; | |
enum size = v.data.length; | |
*/ | |
import std.math; | |
foreach (i; 0..8) | |
{ | |
auto angle = i * 45; | |
auto rad = degtorad(angle); | |
auto v = vec2(cos(rad), sin(rad)); | |
auto angle2 = radtodeg(atan2(v.y, v.x)); | |
auto angle3 = radtodeg(atan(v.y / v.x)); | |
auto angle4 = v.point_direction.radtodeg; | |
writefln("% 5s % 5.5s % 5.5s % 5.5s", angle, angle2, angle3, angle4); | |
} | |
//atan2(1f,0f).writeln; | |
} | |
float point_direction(vec2 p1, vec2 p2) { return point_direction(p2 - p1); } | |
float point_direction(vec2 a) | |
{ | |
if (a.y < 0) result = 2*PI - result; | |
return atan2(a.y, a.x); | |
} | |
float angle_between(vec2 a, vec2 b) | |
{ | |
import std.math; | |
// cos(alpha) = (a dot b) / (a.len * b.len) | |
float cosAlpha = a.dot(b) / sqrt(a.lengthSqr * b.lengthSqr); | |
float result = acos(cosAlpha); | |
return result; | |
} | |
/* | |
angle test1 test2 test3 | |
0 0 0 0 | |
45 45 45 45 | |
90 90 -90 90 | |
135 135 -45 135 | |
180 -180 0 180 | |
225 -135 45 135 | |
270 -90 -90 90 | |
315 -45 -45 45 | |
*/ | |
float degtorad(float deg) | |
{ | |
import std.math; | |
return deg * (PI / 180); | |
} | |
float radtodeg(float rad) | |
{ | |
import std.math; | |
return rad * (180 / PI); | |
} | |
template isVector(T) | |
{ | |
static if (is(T == Vector!(T2, N2), T2, int N2)) | |
enum isVector = true; | |
else | |
enum isVector = false; | |
} | |
struct Vector(T, int N) | |
{ | |
import std.traits : CommonType, isNumeric, isDynamicArray, isArray, isInstanceOf; | |
import std.conv : to; | |
import std.exception : enforce; | |
T[N] data; | |
alias data this; | |
this(T arg) { | |
data[] = arg; | |
} | |
this(T[N] args) { | |
data = args; | |
} | |
this(T2 : Vector!(T3, N2), T3, int N2)(T2 vec) if (N2 >= N) { | |
data = vec[0..N]; | |
} | |
this(Args...)(Args args) if (args.length <= N) | |
{ | |
enum staticIndex0 = 0; | |
static foreach (argIndex, arg; args) | |
{ | |
static if (isNumeric!(typeof(arg))) | |
{ | |
data[mixin("staticIndex"~to!string(argIndex))] = cast(T)arg; | |
mixin("enum staticIndex"~to!string(argIndex+1)~" = staticIndex"~to!string(argIndex)~" +1;"); | |
} | |
else static if (isVector!(typeof(arg))) | |
{ | |
mixin("enum staticIndex"~to!string(argIndex+1)~" = staticIndex"~to!string(argIndex)~" +arg.data.length;"); | |
foreach (j, elem; arg.data) | |
data[mixin("staticIndex"~to!string(argIndex)) + j] = cast(T)elem; | |
} | |
else static if (isArray!(typeof(arg))) | |
{ | |
static if (isDynamicArray!(typeof(arg))) | |
{ | |
static assert(argIndex == args.length-1, "Dynamic array allowed only as last parameter"); | |
enforce(mixin("staticIndex"~to!string(argIndex)) + arg.length == N, "length mismatch"); | |
} | |
else | |
{ | |
mixin("enum staticIndex"~to!string(argIndex+1)~" = staticIndex"~to!string(argIndex)~" +arg.length;"); | |
} | |
foreach (j, elem; arg) | |
data[mixin("staticIndex"~to!string(argIndex)) + j] = cast(T)elem; | |
} | |
} | |
static if (!isDynamicArray!(typeof(args[$-1]))) | |
{ | |
static assert(mixin("staticIndex"~to!string(args.length)) == data.length); | |
} | |
} | |
template opDispatch(string swizzle) | |
{ | |
@property @safe pure: | |
enum len = swizzle.length; | |
enum ubyte[len+1] indicies = swizzleIndicies!len(swizzle); | |
static assert(indicies[len] == 1, "'" ~ swizzle ~ "' is invalid swizzling"); | |
ref T opDispatch()() if (len == 1) { | |
return data[indicies[0]]; | |
} | |
auto opDispatch()() if (len > 1) { | |
Vector!(T, len) result; | |
static foreach (i, elemIndex; indicies[0..$-1]) | |
result.data[i] = data[elemIndex]; | |
return result; | |
} | |
auto opDispatch()(Vector!(T, len) other) if (len > 1) { | |
Vector!(T, len) result; | |
static foreach (i, elemIndex; indicies[0..$-1]) | |
result.data[i] = data[elemIndex] = other.data[i]; | |
return result; | |
} | |
} | |
Vector!(T, N) opUnary(string op)() if (op != "++" && op != "--" && op != "*") | |
{ | |
Vector!(T, N) result; | |
foreach(i; 0..N) result.data[i] = mixin(op~"data[i]"); | |
return result; | |
} | |
Vector!(T, N) opUnary(string op)() if (op == "++" || op == "--") | |
{ | |
Vector!(T, N) result; | |
foreach(i; 0..N) result.data[i] = mixin(op~"data[i]"); | |
return result; | |
} | |
template opBinary(string op, T2 : Vector!(T3, N), T3) { | |
alias RetT = CommonType!(T, T3); | |
Vector!(RetT, N) opBinary(T2 rhs) | |
{ | |
Vector!(RetT, N) result; | |
foreach(i; 0..N) result.data[i] = mixin("data[i] "~op~" rhs.data[i]"); | |
return result; | |
} | |
} | |
template opBinary(string op, T2) if (isNumeric!T2) { | |
alias RetT = CommonType!(T, T2); | |
Vector!(RetT, N) opBinary(T2 rhs) | |
{ | |
Vector!(RetT, N) result; | |
foreach(i; 0..N) result.data[i] = mixin("data[i] "~op~" rhs"); | |
return result; | |
} | |
} | |
template opOpAssign(string op, T2 : Vector!(T3, N), T3) { | |
alias RetT = CommonType!(T, T3); | |
Vector!(RetT, N) opOpAssign(T2 rhs) | |
{ | |
Vector!(RetT, N) result; | |
foreach(i; 0..N) mixin("data[i] "~op~"= rhs.data[i];"); | |
return this; | |
} | |
} | |
template opOpAssign(string op, T2) if (isNumeric!T2) { | |
alias RetT = CommonType!(T, T2); | |
Vector!(RetT, N) opOpAssign(T2 rhs) | |
{ | |
Vector!(RetT, N) result; | |
foreach(i; 0..N) mixin("data[i] "~op~"= rhs;"); | |
return this; | |
} | |
} | |
template opBinaryRight(string op, T2) if (isNumeric!T2) { | |
alias RetT = CommonType!(T, T2); | |
Vector!(RetT, N) opBinaryRight(T2 rhs) | |
{ | |
Vector!(RetT, N) result; | |
foreach(i; 0..N) result.data[i] = mixin("rhs "~op~" data[i]"); | |
return result; | |
} | |
} | |
T dot(Vector!(T, N) other) | |
{ | |
T result = 0; | |
foreach(i; 0..N) result += data[i] * other.data[i]; | |
return result; | |
} | |
T lengthSqr() | |
{ | |
T result = 0; | |
foreach(i; 0..N) result += data[i] * data[i]; | |
return result; | |
} | |
void toString(Sink)(Sink sink) | |
{ | |
import std.format : formattedWrite; | |
formattedWrite(sink, "%s%s(%(%s, %))", T.stringof, N, data); | |
} | |
} | |
alias ivec2 = Vector!(int, 2); | |
alias ivec3 = Vector!(int, 3); | |
alias ivec4 = Vector!(int, 4); | |
alias vec1 = Vector!(float, 1); | |
alias vec2 = Vector!(float, 2); | |
alias vec3 = Vector!(float, 3); | |
alias vec4 = Vector!(float, 4); | |
unittest | |
{ | |
ivec4 v = ivec4(0, 1, 2, 3); | |
assert(v == ivec4(0, 1, 2, 3)); | |
assert(v.xyzw == ivec4(0, 1, 2, 3)); | |
assert(v.stpq == ivec4(0, 1, 2, 3)); | |
assert(v.rgba == ivec4(0, 1, 2, 3)); | |
assert(v.x == 0); | |
assert(v.y == 1); | |
assert(v.z == 2); | |
assert(v.w == 3); | |
assert(v.xy == ivec2(0,1)); | |
assert(v.wwzx == ivec4(3,3,2,0)); | |
v.xy = ivec2(7,8); | |
assert(v.xy == ivec2(7,8)); | |
v.xy = v.yx; | |
assert(v.xy == ivec2(8,7)); | |
v.x = 1; | |
assert(v == ivec4(1, 7, 2, 3)); | |
immutable binOps = ["+","-","*","/","%","^^","&","|","^","<<",">>",">>>"]; | |
// binary ops | |
static foreach (op; binOps) {{ | |
enum test1 = "(ivec2(8, 2) "~op~" ivec2(3, 5)) == ivec2(8"~op~"3, 2"~op~"5)"; | |
enum test2 = "(ivec2(8, 2) "~op~" 5) == ivec2(8"~op~"5, 2"~op~"5)"; | |
enum test3 = "(5 "~op~" ivec2(8, 2)) == ivec2(5"~op~"8, 5"~op~"2)"; | |
assert(mixin(test1), test1); | |
assert(mixin(test2), test2); | |
assert(mixin(test3), test3); | |
ivec2 v4 = ivec2(8, 2); | |
enum test4 = "v4 "~op~"= ivec2(3, 5);"; | |
mixin(test4); | |
assert(v4 == mixin("ivec2(8, 2) "~op~" ivec2(3, 5)"), test4); | |
ivec2 v5 = ivec2(8, 2); | |
enum test5 = "v5 "~op~"= 5;"; | |
mixin(test5); | |
assert(v5 == mixin("ivec2(8, 2) "~op~" 5"), test5); | |
}} | |
// unary ops | |
static foreach (op; ["-","+","~","++","--"]) {{ | |
int v1 = 8, v2 = 2; | |
enum test1 = op~"ivec2(8, 2) == ivec2("~op~"v1, "~op~"v2)"; | |
assert(mixin(test1), test1); | |
}} | |
static foreach (op; ["~","in"]) {{ | |
static assert(!__traits(compiles, mixin("ivec2(8, 2) "~op~" ivec2(3, 5)"))); | |
}} | |
assert(swizzleIndicies!4("xvzw")[4] == 0); | |
assert(swizzleIndicies!4("xyzw") == [0,1,2,3,1]); | |
} | |
static assert(!__traits(compiles, ivec4(0, 1, 2, 3).ccc)); | |
/// | |
@safe nothrow unittest | |
{ | |
assert(vec1(1.0f) == [1.0f]); | |
assert(vec2(1.0f) == [1.0f, 1.0f]); | |
assert(vec3(1.0f) == [1.0f, 1.0f, 1.0f]); | |
assert(vec4(1.0f) == [1.0f, 1.0f, 1.0f, 1.0f]); | |
} | |
/// | |
@safe nothrow unittest | |
{ | |
assert(vec1(1.0f) == [1.0f]); | |
assert(vec2(1.0f, 2.0f) == [1.0f, 2.0f]); | |
assert(vec3(1.0f, 2.0f, 3.0f) == [1.0f, 2.0f, 3.0f]); | |
assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
} | |
/// | |
@safe unittest | |
{ | |
float[4] staticArray4D = [1.0, 2.0f, 3.0f, 4.0f]; | |
float[] dynamicSlice1D = staticArray4D[3 .. 4]; | |
float[] dynamicSlice2D = staticArray4D[2 .. 4]; | |
float[] dynamicSlice3D = staticArray4D[1 .. 4]; | |
assert(vec1(dynamicSlice1D) == [4.0f]); | |
assert(vec2(dynamicSlice2D) == [3.0f, 4.0f]); | |
assert(vec3(dynamicSlice3D) == [2.0f, 3.0f, 4.0f]); | |
assert(vec4(staticArray4D) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
} | |
/// | |
@safe nothrow unittest | |
{ | |
float[2] staticArray2D = [1.0, 2.0f]; | |
assert(vec3(staticArray2D, 3.0f) == [1.0f, 2.0f, 3.0f]); | |
assert(vec3(0.0f, staticArray2D) == [0.0f, 1.0f, 2.0f]); | |
assert(vec4(staticArray2D, staticArray2D) == [1.0f, 2.0f, 1.0f, 2.0f]); | |
assert(vec4(3.0f, 4.0f, staticArray2D) == [3.0f, 4.0f, 1.0f, 2.0f]); | |
assert(vec4(staticArray2D, 3.0f, 4.0f) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
assert(vec4(0.0f, staticArray2D, 3.0f) == [0.0f, 1.0f, 2.0f, 3.0f]); | |
float[3] staticArray3D = [1.0f, 2.0f, 3.0f]; | |
assert(vec4(staticArray3D, 4.0f) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
assert(vec4(0.0f, staticArray3D) == [0.0f, 1.0f, 2.0f, 3.0f]); | |
} | |
/// | |
@safe unittest | |
{ | |
float[] dynamicSlice2D = [1.0, 2.0f]; | |
assert(vec4(3.0f, 4.0f, dynamicSlice2D) == [3.0f, 4.0f, 1.0f, 2.0f]); | |
static assert(!__traits(compiles, vec4(dynamicSlice2D, dynamicSlice2D))); | |
static assert(!__traits(compiles, vec4(dynamicSlice2D, 3.0f, 4.0f))); | |
static assert(!__traits(compiles, vec4(0.0f, dynamicSlice2D, 3.0f))); | |
float[] dynamicSlice3D = [1.0, 2.0f, 3.0f]; | |
assert(vec4(0.0f, dynamicSlice3D) == [0.0f, 1.0f, 2.0f, 3.0f]); | |
static assert(!__traits(compiles, vec4(dynamicSlice3D, 4.0f))); | |
} | |
/// | |
@safe nothrow unittest | |
{ | |
enum vec4 vector4D = vec4(1.0, 2.0f, 3.0f, 4.0f); | |
assert(vec1(vector4D) == vector4D[0 .. 1]); | |
assert(vec2(vector4D) == vector4D[0 .. 2]); | |
assert(vec3(vector4D) == vector4D[0 .. 3]); | |
} | |
/// | |
@safe nothrow unittest | |
{ | |
enum vec2 vector2D = vec2(1.0, 2.0f); | |
assert(vec3(vector2D, 3.0f) == [1.0f, 2.0f, 3.0f]); | |
assert(vec3(0.0f, vector2D) == [0.0f, 1.0f, 2.0f]); | |
assert(vec4(vector2D, vector2D) == [1.0f, 2.0f, 1.0f, 2.0f]); | |
assert(vec4(3.0f, 4.0f, vector2D) == [3.0f, 4.0f, 1.0f, 2.0f]); | |
assert(vec4(vector2D, 3.0f, 4.0f) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
assert(vec4(0.0f, vector2D, 3.0f) == [0.0f, 1.0f, 2.0f, 3.0f]); | |
enum vec3 vector3D = vec3(1.0f, 2.0f, 3.0f); | |
assert(vec4(vector3D, 4.0f) == [1.0f, 2.0f, 3.0f, 4.0f]); | |
assert(vec4(0.0f, vector3D) == [0.0f, 1.0f, 2.0f, 3.0f]); | |
} | |
/// | |
@safe nothrow unittest | |
{ | |
static assert(!__traits(compiles, vec2(1.0f, 2.0f, 3.0f))); | |
static assert(!__traits(compiles, vec4(1.0f, 2.0f, 3.0f))); | |
import std.exception : assertThrown; | |
float[] dynamicSlice3D = [1.0, 2.0f, 3.0f]; | |
assertThrown(vec2(dynamicSlice3D)); | |
assertThrown(vec4(dynamicSlice3D)); | |
} | |
/// last elem is 0 if invalid, 1 if valid | |
ubyte[N+1] swizzleIndicies(size_t N)(string swizzle) | |
{ | |
ubyte[N+1] result; | |
swizzleIndicies(swizzle, result[]); | |
return result; | |
} | |
/// ditto | |
void swizzleIndicies(string swizzle, ubyte[] result) | |
{ | |
size_t N = swizzle.length; | |
assert(N+1 == result.length); | |
// 0 xyzw, 1 stpq, 2 rgba | |
// [a b]c d e f[g]h i j k l m n o[p q r s t]u v[w x y z] | |
immutable ubyte[26] indicies = [3,2,4,4,4,4,1,4,4,4,4,4,4,4,4,2,3,0,0,1,4,4,3,0,1,2]; // 4 is invalid | |
immutable ubyte[26] groups = [2,2,3,3,3,3,2,3,3,3,3,3,3,3,3,1,1,2,1,1,3,3,0,0,0,0]; // 3 is invalid | |
ubyte prevGroup = groups[swizzle[0]-'a']; | |
foreach (i, char elem; swizzle) | |
{ | |
if (elem >= 'a' && elem <= 'z') | |
{ | |
ubyte index = indicies[elem-'a']; | |
ubyte group = groups[elem-'a']; | |
bool hasInvalidElement = index == 4; | |
bool hasMultipleGroups = group != prevGroup; | |
if (hasInvalidElement || hasMultipleGroups) return; | |
prevGroup = group; | |
result[i] = index; | |
} | |
else | |
{ | |
return; | |
} | |
} | |
result[N] = 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment