Skip to content

Instantly share code, notes, and snippets.

@MrSmith33
Created May 7, 2021 22:59
Show Gist options
  • Save MrSmith33/aadbe180d5a3a12d98ffd3f3d2f2f75f to your computer and use it in GitHub Desktop.
Save MrSmith33/aadbe180d5a3a12d98ffd3f3d2f2f75f to your computer and use it in GitHub Desktop.
Vector thingy
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