1 /** 2 Copyright: Copyright (c) 2015-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module voxelman.math.utils; 8 9 import std.traits : isFloatingPoint; 10 import voxelman.math; 11 import std.algorithm : std_clamp = clamp; 12 import dlib.math.utils : isConsiderZero; 13 14 Vector!(T, n) abs(T, size_t n)(Vector!(T, n) vector) pure nothrow 15 { 16 Vector!(T, n) result; 17 foreach(i, elem; vector.arrayof) 18 result[i] = elem < 0 ? -elem : elem; 19 return result; 20 } 21 22 enum Alignment 23 { 24 min, 25 center, 26 max 27 } 28 29 /// Returns offset to add to object position 30 T alignOnAxis(T)(T objSize, Alignment alignment, T areaSize) 31 { 32 final switch (alignment) 33 { 34 case Alignment.min: return 0; 35 case Alignment.center: return areaSize/2 - objSize/2; 36 case Alignment.max: return areaSize - objSize; 37 } 38 } 39 40 bool toggle_bool(ref bool value) 41 { 42 return value = !value; 43 } 44 45 T set_flag(T)(T bits, bool flagValue, T flagBit) 46 { 47 if (flagValue) 48 return bits | flagBit; 49 else 50 return bits & (~flagBit); 51 } 52 53 T toggle_flag(T)(T bits, T flagBit) 54 { 55 return bits ^ flagBit; 56 } 57 58 T divCeil(T)(T a, T b) 59 { 60 return a / b + (a % b > 0); 61 } 62 63 T distance(T) (Vector!(T,2) a, Vector!(T,2) b) 64 { 65 T dx = a.x - b.x; 66 T dy = a.y - b.y; 67 return sqrt((dx * dx) + (dy * dy)); 68 } 69 70 bool isAlmostZero(Vector2f v) 71 { 72 return (isConsiderZero(v.x) && 73 isConsiderZero(v.y)); 74 } 75 76 Vector!(T, n) vector_clamp(T, size_t n)(Vector!(T, n) vector, Vector!(T, n) lower, Vector!(T, n) upper) pure nothrow 77 { 78 Vector!(T, n) result; 79 foreach(i, ref elem; result.arrayof) 80 elem = std_clamp(vector.arrayof[i], lower.arrayof[i], upper.arrayof[i]); 81 return result; 82 } 83 84 Vector!(T, n) vector_min(T, size_t n)(Vector!(T, n) a, Vector!(T, n) b) pure nothrow 85 { 86 Vector!(T, n) result; 87 foreach(i, ref elem; result.arrayof) 88 elem = min(a.arrayof[i], b.arrayof[i]); 89 return result; 90 } 91 92 Vector!(T, n) vector_max(T, size_t n)(Vector!(T, n) a, Vector!(T, n) b) pure nothrow 93 { 94 Vector!(T, n) result; 95 foreach(i, ref elem; result.arrayof) 96 elem = max(a.arrayof[i], b.arrayof[i]); 97 return result; 98 } 99 100 void nansToZero(T, int size)(ref Vector!(T, size) vector) pure nothrow 101 if (isFloatingPoint!T) 102 { 103 foreach(ref item; vector.arrayof) 104 { 105 item = isNaN(item) ? 0 : item; 106 } 107 } 108 109 void nansToZero(T, int size)(ref T[size] vector) pure nothrow 110 if (isFloatingPoint!T) 111 { 112 foreach(ref item; vector) 113 { 114 item = isNaN(item) ? 0 : item; 115 } 116 } 117 118 T nextPOT(T)(T x) 119 { 120 --x; 121 x |= x >> 1; // handle 2 bit numbers 122 x |= x >> 2; // handle 4 bit numbers 123 x |= x >> 4; // handle 8 bit numbers 124 static if (T.sizeof >= 2) x |= x >> 8; // handle 16 bit numbers 125 static if (T.sizeof >= 4) x |= x >> 16; // handle 32 bit numbers 126 static if (T.sizeof >= 8) x |= x >> 32; // handle 64 bit numbers 127 ++x; 128 129 return x; 130 } 131 132 unittest { 133 assert(nextPOT(1) == 1); 134 assert(nextPOT(2) == 2); 135 assert(nextPOT(3) == 4); 136 assert(nextPOT(4) == 4); 137 assert(nextPOT(5) == 8); 138 assert(nextPOT(10) == 16); 139 assert(nextPOT(30) == 32); 140 assert(nextPOT(250) == 256); 141 assert(nextPOT(514) == 1024); 142 assert(nextPOT(1<<15+1) == 1<<16); 143 assert(nextPOT(1UL<<31+1) == 1UL<<32); 144 assert(nextPOT(1UL<<49+1) == 1UL<<50); 145 } 146 147 V lerpMovement(V)(V from, V to, double speed, double dt) 148 { 149 auto curDist = distance(from, to); 150 auto distanceToMove = speed * dt; 151 if (curDist == 0 || distanceToMove == 0) return from; 152 double time = distanceToMove / curDist; 153 return lerpClamp(from, to, time); 154 } 155 156 V lerpClamp(V)(V currentPos, V targetPos, double time) 157 { 158 time = clamp(time, 0.0, 1.0); 159 return lerp(currentPos, targetPos, time); 160 }