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