1 #include "objects/geometry/Vector.h"
2 #include "catch.hpp"
3 #include "tests/Approx.h"
4 #include "utils/Utils.h"
5 
6 using namespace Sph;
7 
8 
9 TEST_CASE("Vector construction", "[vector]") {
10     // construct from single value
11     Vector v2(5._f);
12     for (int i = 0; i < 3; ++i) {
13         REQUIRE(v2[i] == 5._f);
14     }
15 
16     // copy construct
17     Vector v3(v2);
18     for (int i = 0; i < 3; ++i) {
19         REQUIRE(v3[i] == 5._f);
20     }
21 
22     // "move" construct
23     Vector v4(Vector(3._f));
24     for (int i = 0; i < 3; ++i) {
25         REQUIRE(v4[i] == 3._f);
26     }
27 
28     Vector v5(5._f, 4._f, 3._f, 2._f);
29     REQUIRE(v5[0] == 5._f);
30     REQUIRE(v5[1] == 4._f);
31     REQUIRE(v5[2] == 3._f);
32     REQUIRE(v5[3] == 2._f);
33 }
34 
35 TEST_CASE("Vector binary operators", "[vector]") {
36     Vector v3(4._f, 6._f, -12._f);
37     Vector v4(2._f, -3._f, -4._f);
38     REQUIRE(v3 + v4 == Vector(6._f, 3._f, -16._f));
39     REQUIRE(v3 - v4 == Vector(2._f, 9._f, -8._f));
40     REQUIRE(v3 * v4 == Vector(8._f, -18._f, 48._f));
41     REQUIRE(v3 / v4 == Vector(2._f, -2._f, 3._f));
42     REQUIRE(v3 * 2._f == Vector(8._f, 12._f, -24._f));
43     REQUIRE(2._f * v3 == Vector(8._f, 12._f, -24._f));
44     REQUIRE(v3 / 2._f == Vector(2._f, 3._f, -6._f));
45     REQUIRE(v3 * 2._f == Vector(8._f, 12._f, -24._f));
46     REQUIRE(2._f * v3 == Vector(8._f, 12._f, -24._f));
47     REQUIRE(v3 / 2._f == Vector(2._f, 3._f, -6._f));
48 }
49 
50 TEST_CASE("Vector unary operators", "[vector]") {
51     Vector v1(3._f, -4._f, 1._f);
52     Vector v2(1._f, 2._f, 3._f);
53     v1 += v2;
54     REQUIRE(v1 == Vector(4._f, -2._f, 4._f));
55     REQUIRE(v2 == Vector(1._f, 2._f, 3._f)); // unchanged
56     v2 -= v1;
57     REQUIRE(v2 == Vector(-3._f, 4._f, -1._f));
58     v1 *= 2;
59     REQUIRE(v1 == Vector(8._f, -4._f, 8._f));
60     v1 /= 2;
61     REQUIRE(v1 == Vector(4._f, -2._f, 4._f));
62 
63     REQUIRE(-v2 == Vector(3._f, -4, 1._f));
64 }
65 
66 TEST_CASE("Vector comparisons 1", "[vector]") {
67     Vector v(6._f, 3._f, 2._f);
68     REQUIRE(v == v);
69     REQUIRE(v == Vector(6._f, 3._f, 2._f));
70     REQUIRE(Vector(6._f, 3._f, 2._f) == v);
71     REQUIRE(v != Vector(5._f, 3._f, 2._f));
72     REQUIRE(v != Vector(6._f, 4._f, 2._f));
73     REQUIRE(v != Vector(6._f, 3._f, 1._f));
74 }
75 
76 TEST_CASE("Vector comparisons 2", "[vectors]") {
77     // dummy components should not influence equality
78     const Vector v1(1.f, 1.f, 3.f, 5.f);
79     const Vector v2(1.f, 2.f, 4.f, 0.f);
80     REQUIRE(v1 != v2);
81 
82     const Vector v3(1.f, 1.f, 3.f, 5.f);
83     const Vector v4(1.f, 1.f, 3.f, 0.f);
84     REQUIRE(v3 == v4);
85 }
86 
87 TEST_CASE("Vector length", "[vector]") {
88     Vector v1(3._f, 4._f, 12._f);
89     REQUIRE(getSqrLength(v1) == 169._f);
90     REQUIRE(getLength(v1) == 13._f);
91     Vector v2(1._f);
92     REQUIRE(getLength(v2) == Sph::sqrt(3._f));
93 }
94 
95 TEST_CASE("Vector normalization", "[vector]") {
96     Vector v1(3._f, 4._f, 5._f);
97     const Float length = getLength(v1);
98     Vector nv1 = getNormalized(v1);
99     REQUIRE(nv1[0] == 3._f / length);
100     REQUIRE(nv1[1] == 4._f / length);
101     REQUIRE(nv1[2] == 5._f / length);
102     REQUIRE(nv1 == approx(v1 / length));
103 
104     Float l;
105     Vector nv2;
106     tieToTuple(nv2, l) = getNormalizedWithLength(v1);
107     REQUIRE(l == approx(length));
108     REQUIRE(nv2 == approx(nv1));
109 }
110 
111 TEST_CASE("Vector products", "[vector]") {
112     // dot product
113     Vector v1(1._f, 2._f, 3._f);
114     Vector v2(4._f, -5._f, 6._f);
115     REQUIRE(dot(v1, v2) == 12._f);
116     REQUIRE(dot(v2, v1) == 12._f);
117 
118     // cross product
119     Vector expected(27._f, 6._f, -13._f);
120     REQUIRE(cross(v1, v2) == expected);
121     REQUIRE(cross(v2, v1) == -expected);
122 
123     const int nRounds = 10;
124     for (int i = 0; i < nRounds; ++i) {
125         const Vector v1 = randomVector();
126         const Vector v2 = randomVector();
127         // cross product is perpendicular to both vectors
128         const Vector c = cross(v1, v2);
129         const Float dot1 = dot(c, v1);
130         const Float dot2 = dot(c, v2);
131         REQUIRE(abs(dot1) <= EPS);
132         REQUIRE(abs(dot2) <= EPS);
133     }
134 }
135 
136 TEST_CASE("Vector utilities", "[vector]") {
137     // spherical coordinates
138     Vector v = sphericalToCartesian(Sph::sqrt(2._f), PI / 2._f, PI / 4._f);
139     REQUIRE(v == approx(Vector(1._f, 1._f, 0._f)));
140 
141     SphericalCoords spherical = cartensianToSpherical(v);
142     REQUIRE(spherical.r == approx(sqrt(2._f)));
143     REQUIRE(spherical.theta == approx(PI / 2._f));
144     REQUIRE(spherical.phi == approx(PI / 4._f));
145 }
146 
147 TEST_CASE("Vector inequalities", "[vectors]") {
148     const int nRounds = 10;
149     for (int i = 0; i < nRounds; ++i) {
150         // normalization
151         const Vector v1 = randomVector();
152         REQUIRE(abs(getLength(getNormalized(v1)) - 1._f) <= EPS);
153 
154         // triangle inequality
155         const Vector v2 = randomVector();
156         REQUIRE(getLength(v1 + v2) <= getLength(v1) + getLength(v2));
157 
158         // Cauchy-Schwarz inequality
159         REQUIRE(abs(dot(v1, v2)) <= getLength(v1) * getLength(v2));
160     }
161 }
162 
163 TEST_CASE("Vector Component-wise min and max", "[vectors]") {
164     Vector v1(6._f, -7._f, 8._f);
165     Vector v2(-1._f, 3._f, 5._f);
166     REQUIRE(max(v1, v2) == Vector(6._f, 3._f, 8._f));
167     REQUIRE(min(v1, v2) == Vector(-1._f, -7._f, 5._f));
168 }
169 
170 TEST_CASE("Vector MinElement", "[vector]") {
171     REQUIRE(minElement(Vector(-1._f, 5._f, 2._f)) == -1._f);
172     REQUIRE(minElement(Vector(5._f, 5._f, 2._f)) == 2._f);
173     REQUIRE(minElement(Vector(-1._f, -5._f, 3._f)) == -5._f);
174 }
175 
176 TEST_CASE("Vector abs", "[vector]") {
177     REQUIRE(abs(Vector(-1._f, 0._f, 1._f)) == Vector(1._f, 0._f, 1._f));
178     REQUIRE(abs(Vector(-1._f, -2._f, -5._f)) == Vector(1._f, 2._f, 5._f));
179     REQUIRE(abs(Vector(0._f)) == Vector(0._f));
180     REQUIRE(abs(Vector(5._f, 5._f, -1._f)) == Vector(5._f, 5._f, 1._f));
181 }
182 
183 TEST_CASE("Vector cast", "[vector]") {
184     BasicVector<float> vf(1.f, 2.f, 3.f, 4.f);
185     BasicVector<double> dv = vectorCast<double>(vf);
186     REQUIRE(dv == BasicVector<double>(1., 2., 3., 4.));
187 
188     BasicVector<float> vf2 = vectorCast<float>(dv);
189     REQUIRE(vf2 == BasicVector<float>(1.f, 2.f, 3.f, 4.f));
190 
191     BasicVector<float> vf3 = vectorCast<float>(vf2); // casting on the same precision
192     REQUIRE(vf3 == BasicVector<float>(1.f, 2.f, 3.f, 4.f));
193 }
194 
195 TEST_CASE("Vector almostEqual", "[vector]") {
196     REQUIRE(almostEqual(Vector(1._f, 2._f, 3._f), Vector(1._f, 2._f, 3._f)));
197     REQUIRE_FALSE(almostEqual(Vector(1._f, 2._f, 3._f), Vector(1._f, -2._f, 3._f)));
198     REQUIRE_FALSE(almostEqual(Vector(1._f, 2._f, 3._f), Vector(1._f, 2._f, 2.9_f)));
199     REQUIRE(almostEqual(Vector(1._f, 2._f, 3._f), Vector(1._f, 2._f, 2.9_f), 0.1_f));
200 
201     REQUIRE(almostEqual(Vector(1.e10_f), Vector(1.1e10_f), 0.1_f));
202     REQUIRE_FALSE(almostEqual(Vector(1.e10_f), Vector(1.1e10_f), 0.01_f));
203     REQUIRE(almostEqual(Vector(1.e12_f, -2.e12_f, 0.5_f), Vector(1.e12_f, -2.e12_f, 10._f), 1.e-6_f));
204     REQUIRE_FALSE(almostEqual(Vector(1.e12_f, -2.e12_f, 0.5_f), Vector(1.e12_f, -2.e12_f, 10._f), 1e-12_f));
205 
206     REQUIRE(almostEqual(Vector(1.e-10_f), Vector(1.1e-10_f), 1.e-6_f));
207     REQUIRE_FALSE(almostEqual(Vector(1.e-10_f), Vector(1.1e-10_f), 1.e-15_f));
208     REQUIRE(almostEqual(Vector(1.e-12_f, -2.e-12_f, 0._f), Vector(1.e-12_f, 1.e-18_f - 2.e-12_f, 0._f)));
209 }
210 
211 TEST_CASE("Vector lexicographicalLess", "[vector]") {
212     REQUIRE(lexicographicalLess(Vector(5._f, 3._f, 1._f), Vector(2._f, 1._f, 2._f)));
213     REQUIRE_FALSE(lexicographicalLess(Vector(5._f, 3._f, 1._f), Vector(2._f, 1._f, 0.5_f)));
214     REQUIRE(lexicographicalLess(Vector(5._f, 0._f, 1._f), Vector(2._f, 1._f, 1._f)));
215     REQUIRE_FALSE(lexicographicalLess(Vector(5._f, 3._f, 1._f), Vector(2._f, 1._f, 1._f)));
216     REQUIRE(lexicographicalLess(Vector(1._f, 3._f, 1._f), Vector(2._f, 3._f, 1._f)));
217     REQUIRE_FALSE(lexicographicalLess(Vector(5._f, 3._f, 1._f), Vector(2._f, 3._f, 1._f)));
218 }
219 
220 TEST_CASE("Vector less", "[vector]") {
221     Vector v1(2._f, 3._f, 6._f);
222     Vector v2(3._f, 3._f, 3._f);
223     REQUIRE(less(v1, v2) == Vector(1._f, 0._f, 0.f));
224 
225     Vector v3(2._f, 5._f, -1._f, 1._f);
226     Vector v4(3._f, 6._f, -2._f, -3._f);
227     REQUIRE(less(v3, v4) == Vector(1._f, 1._f, 0._f, 0._f));
228 }
229 
230 TEST_CASE("Vector unit", "[vector]") {
231     REQUIRE(Vector::unit(0) == Vector(1, 0, 0));
232     REQUIRE(Vector::unit(1) == Vector(0, 1, 0));
233     REQUIRE(Vector::unit(2) == Vector(0, 0, 1));
234     REQUIRE_SPH_ASSERT(Vector::unit(3));
235 }
236 
237 /// \todo also test tensors
238 /*TEST_CASE("Vector clampWithDerivative", "[vector]") {
239     Vector v(-1._f, 3._f, 6._f);
240     Vector dv(20._f, 21._f, 22._f);
241     Range r(0._f, 4._f);
242     tie(v, dv) = clampWithDerivative(v, dv, r);
243     REQUIRE(v == Vector(0._f, 3._f, 4._f));
244     REQUIRE(dv == Vector(0._f, 21._f, 0._f));
245 }
246 */
247