distance.cc 8.8 KB
Newer Older
Julian Schakib's avatar
Julian Schakib committed
1
2
3
4
#include "test.hh"

TG_FUZZ_TEST(TypedGeometry, Distance)
{
Philip Trettner's avatar
Philip Trettner committed
5
6
7
    auto rBox1 = tg::aabb1(tg::pos1(-1.0f), tg::pos1(1.0f));
    auto rBox2 = tg::aabb2(tg::pos2(-1.0f, -1.0f), tg::pos2(1.0f, 1.0f));
    auto rBox3 = tg::aabb3(tg::pos3(-1.0f, -1.0f, -1.0f), tg::pos3(1.0f, 1.0f, 1.0f));
Julian Schakib's avatar
Julian Schakib committed
8

9
    // distance_sqr compared with distance
Julian Schakib's avatar
Julian Schakib committed
10
11
12
13
14
    {
        // 3D
        auto a = uniform(rng, rBox3);
        auto b = uniform(rng, rBox3);

15
        auto d2 = distance_sqr(a, b);
16
        auto d = distance(a, b);
17
18
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
19
        // symmetry
20
        CHECK(distance(b, a) == d);
21
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
22
23
24
25
26
27
    }
    {
        // 2D
        auto a = uniform(rng, rBox2);
        auto b = uniform(rng, rBox2);

28
        auto d2 = distance_sqr(a, b);
29
        auto d = distance(a, b);
30
31
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
32
        // symmetry
33
        CHECK(distance(b, a) == d);
34
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
35
36
37
38
39
40
    }
    {
        // 1D
        auto a = uniform(rng, rBox1);
        auto b = uniform(rng, rBox1);

41
        auto d2 = distance_sqr(a, b);
42
        auto d = distance(a, b);
43
44
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
45
        // symmetry
46
        CHECK(distance(b, a) == d);
47
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
48
49
50
51
52
53
54
    }

    // move away from point by random value
    {
        // 3D
        auto a = uniform(rng, rBox3);
        auto dir = normalize(tg::vec3(uniform(rng, rBox3)));
55
        auto rd = uniform(rng, rBox1).x;
Julian Schakib's avatar
Julian Schakib committed
56
57

        auto b = a + dir * rd;
58
        CHECK(distance(a, b) == approx(tg::abs(rd)));
Julian Schakib's avatar
Julian Schakib committed
59

60
        auto d2 = distance_sqr(a, b);
61
        auto d = distance(a, b);
62
63
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
64
        // symmetry
65
        CHECK(distance(b, a) == d);
66
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
67
68
69
70
71
    }
    {
        // 2D
        auto a = uniform(rng, rBox2);
        auto dir = normalize(tg::vec2(uniform(rng, rBox2)));
72
        auto rd = uniform(rng, rBox1).x;
Julian Schakib's avatar
Julian Schakib committed
73
74

        auto b = a + dir * rd;
75
        CHECK(distance(a, b) == approx(tg::abs(rd)));
Julian Schakib's avatar
Julian Schakib committed
76

77
        auto d2 = distance_sqr(a, b);
78
        auto d = distance(a, b);
79
80
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
81
        // symmetry
82
        CHECK(distance(b, a) == d);
83
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
84
85
86
87
88
    }
    {
        // 1D
        auto a = uniform(rng, rBox1);
        auto dir = normalize(tg::vec1(uniform(rng, rBox1)));
89
        auto rd = uniform(rng, rBox1).x;
Julian Schakib's avatar
Julian Schakib committed
90
91

        auto b = a + dir * rd;
92
        CHECK(distance(a, b) == approx(tg::abs(rd)));
Julian Schakib's avatar
Julian Schakib committed
93

94
        auto d2 = distance_sqr(a, b);
95
        auto d = distance(a, b);
96
97
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Julian Schakib's avatar
Julian Schakib committed
98
        // symmetry
99
        CHECK(distance(b, a) == d);
100
        CHECK(distance_sqr(b, a) == d2);
Julian Schakib's avatar
Julian Schakib committed
101
    }
102
103
104
105

    // distance to origin
    {
        auto p = uniform(rng, rBox1);
106
        auto d = distance_to_origin(p);
107
        CHECK(d == approx(tg::length(tg::vec1(p))));
108
109
110
    }
    {
        auto p = uniform(rng, rBox2);
111
        auto d = distance_to_origin(p);
112
        CHECK(d == approx(tg::length(tg::vec2(p))));
113
114
115
    }
    {
        auto p = uniform(rng, rBox3);
116
        auto d = distance_to_origin(p);
117
        CHECK(d == approx(tg::length(tg::vec3(p))));
118
119
120
121
122
123
124
125
126
127
128
    }


    // plane and pos
    {
        // random plane
        auto pl = tg::plane(normalize(tg::vec3(uniform(rng, rBox3))), uniform(rng, rBox1).x);
        // random point
        auto pt = uniform(rng, rBox3);

        // symmetry
129
        auto d2 = distance_sqr(pt, pl);
130
        auto d = distance(pt, pl);
131
132
        CHECK(d == approx(distance(pl, pt)));
        CHECK(d2 == approx(distance_sqr(pl, pt)));
133

134
135
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
136
137

        // move point on plane
Philip Trettner's avatar
Philip Trettner committed
138
139
140
        auto o = tg::pos3(pl.dis * pl.normal);
        auto t = pl.normal;
        while (dot(t, pl.normal) != 0.0f)
141
142
        {
            auto r = normalize(tg::vec3(uniform(rng, rBox3)));
Philip Trettner's avatar
Philip Trettner committed
143
            t = normalize(cross(pl.normal, r));
144
145
        }
        pt = o + t; // origin + tangent
146
        CHECK(distance(pt, pl) == approx(0.0f));
147
148

        auto l = uniform(rng, rBox1).x;
Philip Trettner's avatar
Philip Trettner committed
149
        pt += pl.normal * l; // move along normal
150
        CHECK(distance(pt, pl) == approx(tg::abs(l)));
151
    }
152
153


Philip Trettner's avatar
Philip Trettner committed
154
    // inf_cone and pos
155
    {
156
157
        auto icone = tg::inf_cone_boundary<3, float>(tg::pos3(uniform(rng, rBox3)), normalize(tg::vec3(uniform(rng, rBox3))),
                                                     uniform(rng, tg::angle::from_degree(1.f), tg::angle::from_degree(179.f)));
158
        auto l = uniform(rng, 0.1f, 2.f);
Isaak Lim's avatar
Isaak Lim committed
159
        auto pt = icone.apex - l * icone.opening_dir;
160
        auto d2 = distance_sqr(pt, icone);
161
        auto d = distance(pt, icone);
162
163
164
        CHECK(d == approx(l));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
165
        l = uniform(rng, 0.f, 10.f);
Isaak Lim's avatar
Isaak Lim committed
166
        pt = icone.apex + l * icone.opening_dir;
167
        d = distance(pt, icone);
168
        d2 = distance_sqr(pt, icone);
169
        CHECK(d > 0);
170
        CHECK(d2 > 0);
171
        l = uniform(rng, 0.f, 10.f);
172
        auto r = tg::tan(icone.opening_angle / 2) * l;
173
174
175
        auto rand_dir = normalize(tg::vec3(uniform(rng, rBox3)));
        auto rand_n = normalize(cross(rand_dir, icone.opening_dir));
        auto ortho_dir = normalize(cross(rand_n, icone.opening_dir));
Isaak Lim's avatar
Isaak Lim committed
176
        pt = icone.apex + l * icone.opening_dir + r * ortho_dir;
177
        d = distance(pt, icone);
178
        d2 = distance_sqr(pt, icone);
179
180
181
        CHECK(d == approx(0).epsilon(0.01));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
182
        d = distance(icone.apex, icone);
183
        CHECK(d == approx(0).epsilon(0.01));
184
        pt = {2, -4, 0};
185
        icone = tg::inf_cone_boundary<3, float>({0, 0, 0}, {0, 0, 1}, tg::angle::from_degree(90));
186
        d2 = distance_sqr(pt, icone);
187
        CHECK(d2 == approx(10));
188
189
190
        l = uniform(rng, 0.f, 10.f);
        pt = icone.apex + l * icone.opening_dir;
        d = distance(pt, icone);
191
        CHECK(d == approx(l / sqrt(2)));
192
    }
193
194
195
196


    // sphere and pos
    {
Philip Trettner's avatar
Philip Trettner committed
197
        auto sp = tg::sphere_boundary<3, tg::f32>(tg::pos3(uniform(rng, rBox3)), uniform(rng, 0.f, 10.f));
198
        auto l = uniform(rng, 0.f, 10.f);
199
        auto rand_dir = normalize(tg::vec3(uniform(rng, rBox3)));
Isaak Lim's avatar
Isaak Lim committed
200
        auto pt = sp.center + l * rand_dir;
201
        auto d2 = distance_sqr(pt, sp);
202
        auto d = distance(pt, sp);
203
204
205
        CHECK(d == approx(tg::abs(l - sp.radius)));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
Philip Trettner's avatar
Philip Trettner committed
206
        sp = tg::sphere_boundary<3, tg::f32>(tg::pos3(uniform(rng, rBox3)), uniform(rng, 0.f, 10.f));
Isaak Lim's avatar
Isaak Lim committed
207
        pt = sp.center + sp.radius * rand_dir;
208
        d = distance(pt, sp);
209
        CHECK(d == approx(0).epsilon(0.01));
Philip Trettner's avatar
Philip Trettner committed
210
        auto sp2 = tg::sphere_boundary<2, tg::f32>(tg::pos2(uniform(rng, rBox2)), uniform(rng, 0.f, 10.f));
211
        l = uniform(rng, 0.f, 10.f);
212
        auto rand_dir2 = normalize(tg::vec2(uniform(rng, rBox2)));
Isaak Lim's avatar
Isaak Lim committed
213
        auto pt2 = sp2.center + l * rand_dir2;
214
        d2 = distance_sqr(pt2, sp2);
215
        d = distance(pt2, sp2);
216
217
218
        CHECK(d == approx(tg::abs(l - sp2.radius)));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
219
    }
220
221


Philip Trettner's avatar
Philip Trettner committed
222
    // inf_cylinder and pos
223
    {
224
225
226
        auto itube = tg::inf_cylinder3({tg::pos3(uniform(rng, rBox3)), normalize(tg::vec3(uniform(rng, rBox3)))}, uniform(rng, 0.f, 10.f));
        auto rand_dir = normalize(tg::vec3(uniform(rng, rBox3)));
        auto rand_n = normalize(cross(rand_dir, itube.axis.dir));
Philip Trettner's avatar
Philip Trettner committed
227
        auto ortho_dir = tg::normalize(tg::cross(rand_n, itube.axis.dir));
228
229
        auto l = uniform(rng, -10.f, 10.f);
        auto r = uniform(rng, 0.f, 10.f);
Philip Trettner's avatar
Philip Trettner committed
230
        auto pt = itube.axis[l] + r * ortho_dir;
231
        auto d2 = distance_sqr(pt, itube);
232
        auto d = distance(pt, itube);
233
234
235
        CHECK(d == approx(tg::abs(r - itube.radius)));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
236

237
        auto itube2 = tg::inf_cylinder<2, tg::f32>({tg::pos2(uniform(rng, rBox2)), normalize(tg::vec2(uniform(rng, rBox2)))}, uniform(rng, 0.f, 10.f));
Philip Trettner's avatar
Philip Trettner committed
238
        tg::vec2 ortho_dir2 = {-itube2.axis.dir[1], itube2.axis.dir[0]};
239
240
        l = uniform(rng, -10.f, 10.f);
        r = uniform(rng, 0.f, 10.f);
Philip Trettner's avatar
Philip Trettner committed
241
        auto pt2 = itube2.axis[l] + r * ortho_dir2;
242
        d2 = distance_sqr(pt2, itube2);
243
        d = distance(pt2, itube2);
244
245
246
        CHECK(d == approx(tg::abs(r - itube2.radius)));
        CHECK(d * d == approx(d2));
        CHECK(d == approx(sqrt(d2)));
247
    }
Philip Trettner's avatar
Philip Trettner committed
248
249
250

    // cylinder and pos
    {
251
        auto c = tg::cylinder_boundary<3, float>({-1, -2, -3}, {5, -2, -3}, 2);
Philip Trettner's avatar
Philip Trettner committed
252
253
        CHECK(distance(tg::pos3(-1, -2, -3), c) == approx(0));
        CHECK(distance(tg::pos3(5, -2, -3), c) == approx(0));
254
255
        CHECK(distance(tg::pos3(0, -2, -3), c) == approx(1));
        CHECK(distance(tg::pos3(2, -2, -3), c) == approx(2));
Philip Trettner's avatar
Philip Trettner committed
256
257
        CHECK(distance(tg::pos3(-1, -3, -3), c) == approx(0));
    }
Julian Schakib's avatar
Julian Schakib committed
258
}