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 body 65 { 66 T dx = a.x - b.x; 67 T dy = a.y - b.y; 68 return sqrt((dx * dx) + (dy * dy)); 69 } 70 71 bool isAlmostZero(Vector2f v) 72 { 73 return (isConsiderZero(v.x) && 74 isConsiderZero(v.y)); 75 } 76 77 Vector!(T, n) vector_clamp(T, size_t n)(Vector!(T, n) vector, Vector!(T, n) lower, Vector!(T, n) upper) pure nothrow 78 { 79 Vector!(T, n) result; 80 foreach(i, ref elem; result.arrayof) 81 elem = std_clamp(vector.arrayof[i], lower.arrayof[i], upper.arrayof[i]); 82 return result; 83 } 84 85 Vector!(T, n) vector_min(T, size_t n)(Vector!(T, n) a, Vector!(T, n) b) pure nothrow 86 { 87 Vector!(T, n) result; 88 foreach(i, ref elem; result.arrayof) 89 elem = min(a.arrayof[i], b.arrayof[i]); 90 return result; 91 } 92 93 Vector!(T, n) vector_max(T, size_t n)(Vector!(T, n) a, Vector!(T, n) b) pure nothrow 94 { 95 Vector!(T, n) result; 96 foreach(i, ref elem; result.arrayof) 97 elem = max(a.arrayof[i], b.arrayof[i]); 98 return result; 99 } 100 101 void nansToZero(T, int size)(ref Vector!(T, size) vector) pure nothrow 102 if (isFloatingPoint!T) 103 { 104 foreach(ref item; vector.arrayof) 105 { 106 item = isNaN(item) ? 0 : item; 107 } 108 } 109 110 void nansToZero(T, int size)(ref T[size] vector) pure nothrow 111 if (isFloatingPoint!T) 112 { 113 foreach(ref item; vector) 114 { 115 item = isNaN(item) ? 0 : item; 116 } 117 } 118 119 T nextPOT(T)(T x) 120 { 121 --x; 122 x |= x >> 1; // handle 2 bit numbers 123 x |= x >> 2; // handle 4 bit numbers 124 x |= x >> 4; // handle 8 bit numbers 125 static if (T.sizeof >= 2) x |= x >> 8; // handle 16 bit numbers 126 static if (T.sizeof >= 4) x |= x >> 16; // handle 32 bit numbers 127 static if (T.sizeof >= 8) x |= x >> 32; // handle 64 bit numbers 128 ++x; 129 130 return x; 131 } 132 133 unittest { 134 assert(nextPOT(1) == 1); 135 assert(nextPOT(2) == 2); 136 assert(nextPOT(3) == 4); 137 assert(nextPOT(4) == 4); 138 assert(nextPOT(5) == 8); 139 assert(nextPOT(10) == 16); 140 assert(nextPOT(30) == 32); 141 assert(nextPOT(250) == 256); 142 assert(nextPOT(514) == 1024); 143 assert(nextPOT(1<<15+1) == 1<<16); 144 assert(nextPOT(1UL<<31+1) == 1UL<<32); 145 assert(nextPOT(1UL<<49+1) == 1UL<<50); 146 } 147 148 V lerpMovement(V)(V from, V to, double speed, double dt) 149 { 150 auto curDist = distance(from, to); 151 auto distanceToMove = speed * dt; 152 if (curDist == 0 || distanceToMove == 0) return from; 153 double time = distanceToMove / curDist; 154 return lerpClamp(from, to, time); 155 } 156 157 V lerpClamp(V)(V currentPos, V targetPos, double time) 158 { 159 time = clamp(time, 0.0, 1.0); 160 return lerp(currentPos, targetPos, time); 161 }