1 // Copyright 2016 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "draco/core/vector_d.h"
16 
17 #include <sstream>
18 
19 #include "draco/core/draco_test_base.h"
20 
21 namespace {
22 
23 typedef draco::Vector2f Vector2f;
24 typedef draco::Vector3f Vector3f;
25 typedef draco::Vector4f Vector4f;
26 typedef draco::Vector5f Vector5f;
27 typedef draco::Vector2ui Vector2ui;
28 typedef draco::Vector3ui Vector3ui;
29 typedef draco::Vector4ui Vector4ui;
30 typedef draco::Vector5ui Vector5ui;
31 
32 typedef draco::VectorD<int32_t, 3> Vector3i;
33 typedef draco::VectorD<int32_t, 4> Vector4i;
34 
35 template <class CoeffT, int dimension_t>
TestSquaredDistance(const draco::VectorD<CoeffT,dimension_t> v1,const draco::VectorD<CoeffT,dimension_t> v2,const CoeffT result)36 void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1,
37                          const draco::VectorD<CoeffT, dimension_t> v2,
38                          const CoeffT result) {
39   CoeffT squared_distance = SquaredDistance(v1, v2);
40   ASSERT_EQ(squared_distance, result);
41   squared_distance = SquaredDistance(v2, v1);
42   ASSERT_EQ(squared_distance, result);
43 }
44 
TEST(VectorDTest,TestOperators)45 TEST(VectorDTest, TestOperators) {
46   {
47     const Vector3f v;
48     ASSERT_EQ(v[0], 0);
49     ASSERT_EQ(v[1], 0);
50     ASSERT_EQ(v[2], 0);
51   }
52   Vector3f v(1, 2, 3);
53   ASSERT_EQ(v[0], 1);
54   ASSERT_EQ(v[1], 2);
55   ASSERT_EQ(v[2], 3);
56 
57   Vector3f w = v;
58   ASSERT_TRUE(v == w);
59   ASSERT_FALSE(v != w);
60   ASSERT_EQ(w[0], 1);
61   ASSERT_EQ(w[1], 2);
62   ASSERT_EQ(w[2], 3);
63 
64   w = -v;
65   ASSERT_EQ(w[0], -1);
66   ASSERT_EQ(w[1], -2);
67   ASSERT_EQ(w[2], -3);
68 
69   w = v + v;
70   ASSERT_EQ(w[0], 2);
71   ASSERT_EQ(w[1], 4);
72   ASSERT_EQ(w[2], 6);
73 
74   w = w - v;
75   ASSERT_EQ(w[0], 1);
76   ASSERT_EQ(w[1], 2);
77   ASSERT_EQ(w[2], 3);
78 
79   // Scalar multiplication from left and right.
80   w = v * 2.f;
81   ASSERT_EQ(w[0], 2);
82   ASSERT_EQ(w[1], 4);
83   ASSERT_EQ(w[2], 6);
84   w = 2.f * v;
85   ASSERT_EQ(w[0], 2);
86   ASSERT_EQ(w[1], 4);
87   ASSERT_EQ(w[2], 6);
88 
89   ASSERT_EQ(v.SquaredNorm(), 14);
90   ASSERT_EQ(v.Dot(v), 14);
91 
92   Vector3f new_v = v;
93   new_v.Normalize();
94   const float eps = 0.001;
95   const float magnitude = std::sqrt(v.SquaredNorm());
96   const float new_magnitude = std::sqrt(new_v.SquaredNorm());
97   ASSERT_LE(new_magnitude, 1 + eps);
98   ASSERT_GE(new_magnitude, 1 - eps);
99   for (int i = 0; i < 3; ++i) {
100     new_v[i] *= magnitude;
101     ASSERT_LE(new_v[i], v[i] + eps);
102     ASSERT_GE(new_v[i], v[i] - eps);
103   }
104 
105   Vector3f x(0, 0, 0);
106   x.Normalize();
107   for (int i = 0; i < 3; ++i) {
108     ASSERT_EQ(0, x[i]);
109   }
110 }
111 
TEST(VectorDTest,TestSquaredDistance)112 TEST(VectorDTest, TestSquaredDistance) {
113   // Test Vector2f: float, 2D.
114   Vector2f v1_2f(5.5, 10.5);
115   Vector2f v2_2f(3.5, 15.5);
116   float result_f = 29;
117   TestSquaredDistance(v1_2f, v2_2f, result_f);
118 
119   // Test Vector3f: float, 3D.
120   Vector3f v1_3f(5.5, 10.5, 2.3);
121   Vector3f v2_3f(3.5, 15.5, 0);
122   result_f = 34.29;
123   TestSquaredDistance(v1_3f, v2_3f, result_f);
124 
125   // Test Vector4f: float, 4D.
126   Vector4f v1_4f(5.5, 10.5, 2.3, 7.2);
127   Vector4f v2_4f(3.5, 15.5, 0, 9.9);
128   result_f = 41.58;
129   TestSquaredDistance(v1_4f, v2_4f, result_f);
130 
131   // Test Vector5f: float, 5D.
132   Vector5f v1_5f(5.5, 10.5, 2.3, 7.2, 1.0);
133   Vector5f v2_5f(3.5, 15.5, 0, 9.9, 0.2);
134   result_f = 42.22;
135   TestSquaredDistance(v1_5f, v2_5f, result_f);
136 
137   // Test Vector 2ui: uint32_t, 2D.
138   Vector2ui v1_2ui(5, 10);
139   Vector2ui v2_2ui(3, 15);
140   uint32_t result_ui = 29;
141   TestSquaredDistance(v1_2ui, v2_2ui, result_ui);
142 
143   // Test Vector 3ui: uint32_t, 3D.
144   Vector3ui v1_3ui(5, 10, 2);
145   Vector3ui v2_3ui(3, 15, 0);
146   result_ui = 33;
147   TestSquaredDistance(v1_3ui, v2_3ui, result_ui);
148 
149   // Test Vector 4ui: uint32_t, 4D.
150   Vector4ui v1_4ui(5, 10, 2, 7);
151   Vector4ui v2_4ui(3, 15, 0, 9);
152   result_ui = 37;
153   TestSquaredDistance(v1_4ui, v2_4ui, result_ui);
154 
155   // Test Vector 5ui: uint32_t, 5D.
156   Vector5ui v1_5ui(5, 10, 2, 7, 1);
157   Vector5ui v2_5ui(3, 15, 0, 9, 12);
158   result_ui = 158;
159   TestSquaredDistance(v1_5ui, v2_5ui, result_ui);
160 }
161 
TEST(VectorDTest,TestCrossProduct3D)162 TEST(VectorDTest, TestCrossProduct3D) {
163   const Vector3i e1(1, 0, 0);
164   const Vector3i e2(0, 1, 0);
165   const Vector3i e3(0, 0, 1);
166   const Vector3i o(0, 0, 0);
167   ASSERT_EQ(e3, draco::CrossProduct(e1, e2));
168   ASSERT_EQ(e1, draco::CrossProduct(e2, e3));
169   ASSERT_EQ(e2, draco::CrossProduct(e3, e1));
170   ASSERT_EQ(-e3, draco::CrossProduct(e2, e1));
171   ASSERT_EQ(-e1, draco::CrossProduct(e3, e2));
172   ASSERT_EQ(-e2, draco::CrossProduct(e1, e3));
173   ASSERT_EQ(o, draco::CrossProduct(e1, e1));
174   ASSERT_EQ(o, draco::CrossProduct(e2, e2));
175   ASSERT_EQ(o, draco::CrossProduct(e3, e3));
176 
177   // Orthogonality of result for some general vectors.
178   const Vector3i v1(123, -62, 223);
179   const Vector3i v2(734, 244, -13);
180   const Vector3i orth = draco::CrossProduct(v1, v2);
181   ASSERT_EQ(0, v1.Dot(orth));
182   ASSERT_EQ(0, v2.Dot(orth));
183 }
184 
TEST(VectorDTest,TestAbsSum)185 TEST(VectorDTest, TestAbsSum) {
186   // Testing const of function and zero.
187   const Vector3i v(0, 0, 0);
188   ASSERT_EQ(v.AbsSum(), 0);
189   // Testing semantic.
190   ASSERT_EQ(Vector3i(0, 0, 0).AbsSum(), 0);
191   ASSERT_EQ(Vector3i(1, 2, 3).AbsSum(), 6);
192   ASSERT_EQ(Vector3i(-1, -2, -3).AbsSum(), 6);
193   ASSERT_EQ(Vector3i(-2, 4, -8).AbsSum(), 14);
194   // Other dimension.
195   ASSERT_EQ(Vector4i(-2, 4, -8, 3).AbsSum(), 17);
196 }
197 
TEST(VectorDTest,TestMinMaxCoeff)198 TEST(VectorDTest, TestMinMaxCoeff) {
199   // Test verifies that MinCoeff() and MaxCoeff() functions work as intended.
200   const Vector4i vi(-10, 5, 2, 3);
201   ASSERT_EQ(vi.MinCoeff(), -10);
202   ASSERT_EQ(vi.MaxCoeff(), 5);
203 
204   const Vector3f vf(6.f, 1000.f, -101.f);
205   ASSERT_EQ(vf.MinCoeff(), -101.f);
206   ASSERT_EQ(vf.MaxCoeff(), 1000.f);
207 }
208 
TEST(VectorDTest,TestOstream)209 TEST(VectorDTest, TestOstream) {
210   // Tests that the vector can be stored in a provided std::ostream.
211   const draco::VectorD<int64_t, 3> vector(1, 2, 3);
212   std::stringstream str;
213   str << vector << " ";
214   ASSERT_EQ(str.str(), "1 2 3 ");
215 }
216 
TEST(VectorDTest,TestConvertConstructor)217 TEST(VectorDTest, TestConvertConstructor) {
218   // Tests that a vector can be constructed from another vector with a different
219   // type.
220   const draco::VectorD<int64_t, 3> vector(1, 2, 3);
221 
222   const draco::VectorD<float, 3> vector3f(vector);
223   ASSERT_EQ(vector3f, draco::Vector3f(1.f, 2.f, 3.f));
224 
225   const draco::VectorD<float, 2> vector2f(vector);
226   ASSERT_EQ(vector2f, draco::Vector2f(1.f, 2.f));
227 
228   const draco::VectorD<float, 4> vector4f(vector3f);
229   ASSERT_EQ(vector4f, draco::Vector4f(1.f, 2.f, 3.f, 0.f));
230 
231   const draco::VectorD<double, 1> vector1d(vector3f);
232   ASSERT_EQ(vector1d[0], 1.0);
233 }
234 
235 }  // namespace
236