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 }