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 }