project.cc 7.58 KB
Newer Older
1
2
#include "test.hh"

3
4
#include <typed-geometry/tg-std.hh>

5
TG_FUZZ_TEST_MAX_ITS_MAX_CYCLES(TypedGeometry, Project, 25, 100'000'000'000)
6
7
8
9
10
{
    auto const test_obj = [&rng](auto p, auto o) {
        auto proj = project(p, o);

        // Projected point lies in the object
11
12
        auto dist = distance_sqr(proj, o);
        CHECK(dist == approx(0.0f));
13
14
15
16
        CHECK(contains(o, proj, 0.01f));

        dist = distance_sqr(proj, p);
        if (contains(o, p)) // If inside by chance, the projection does not change anything
17
            CHECK(dist == approx(0.0f));
18
19
20
21
        else // Otherwise all other points inside are not closer than the projection
            for (auto i = 0; i < 256; i++)
            {
                auto q = uniform(rng, o);
22
                CHECK(distance_sqr(q, p) >= approx(dist));
23
24
25
26
27
            }

        // Projection of points already sampled from inside changes nothing
        auto pInside = uniform(rng, o);
        proj = project(pInside, o);
28
        dist = distance_sqr(proj, pInside);
29
        CHECK(dist == approx(0.0f));
30
31
    };

Aaron Grabowy's avatar
Aaron Grabowy committed
32
33
34
35
36
37
38
39
40
41
42
43
    auto const test_obj_and_boundary = [&test_obj](auto p, auto o) {
        test_obj(p, o);
        test_obj(p, boundary_of(o));
    };

    auto const test_obj_and_boundary_no_caps = [&test_obj](auto p, auto o) {
        test_obj(p, o);
        test_obj(p, boundary_of(o));
        test_obj(p, boundary_no_caps_of(o));
    };


44
    const auto r = uniform(rng, 0.0f, 10.0f);
45
46
    const auto n2 = tg::dir(uniform(rng, tg::sphere_boundary<2, float>::unit));
    const auto n3 = tg::dir(uniform(rng, tg::sphere_boundary<3, float>::unit));
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

    const auto range1 = tg::aabb1(tg::pos1(-10), tg::pos1(10));
    const auto range2 = tg::aabb2(tg::pos2(-10), tg::pos2(10));
    const auto range3 = tg::aabb3(tg::pos3(-10), tg::pos3(10));
    const auto range4 = tg::aabb4(tg::pos4(-10), tg::pos4(10));

    const auto p1 = uniform(rng, range1);
    const auto p2 = uniform(rng, range2);
    const auto p3 = uniform(rng, range3);
    const auto p4 = uniform(rng, range4);

    const auto pos10 = uniform(rng, range1);
    const auto pos11 = uniform(rng, range1);

    const auto pos20 = uniform(rng, range2);
    const auto pos21 = uniform(rng, range2);
    const auto pos22 = uniform(rng, range2);

    const auto pos30 = uniform(rng, range3);
    const auto pos31 = uniform(rng, range3);
    const auto pos32 = uniform(rng, range3);

    const auto pos40 = uniform(rng, range4);
    const auto pos41 = uniform(rng, range4);

    const auto minPos1 = min(pos10, pos11);
    const auto maxPos1 = max(pos10, pos11);
    const auto minPos2 = min(pos20, pos21);
    const auto maxPos2 = max(pos20, pos21);
    const auto minPos3 = min(pos30, pos31);
    const auto maxPos3 = max(pos30, pos31);
    const auto minPos4 = min(pos40, pos41);
    const auto maxPos4 = max(pos40, pos41);

    const auto axis0 = tg::segment3(pos30, pos31);
82
    const auto disk0 = tg::sphere2in3(pos30, r, n3);
83

Aaron Grabowy's avatar
Aaron Grabowy committed
84
85
86
87
    auto d1 = tg::uniform<tg::dir1>(rng);
    auto m1 = tg::mat1();
    m1[0] = d1 * uniform(rng, 1.0f, 3.0f);

88
    auto d20 = tg::uniform<tg::dir2>(rng);
89
    auto d21 = perpendicular(d20);
90
91
92
93
94
95
96
97
98
99
100
101
    auto m2 = tg::mat2();
    m2[0] = d20 * uniform(rng, 1.0f, 3.0f);
    m2[1] = d21 * uniform(rng, 1.0f, 3.0f);

    auto d30 = tg::uniform<tg::dir3>(rng);
    auto d31 = any_normal(d30);
    auto d32 = normalize(cross(d30, d31));
    auto m3 = tg::mat3();
    m3[0] = d30 * uniform(rng, 1.0f, 3.0f);
    m3[1] = d31 * uniform(rng, 1.0f, 3.0f);
    m3[2] = d32 * uniform(rng, 1.0f, 3.0f);

Aaron Grabowy's avatar
Aaron Grabowy committed
102
103
104
    auto m23 = tg::mat2x3();
    m23[0] = d30 * uniform(rng, 1.0f, 3.0f);
    m23[1] = d31 * uniform(rng, 1.0f, 3.0f);
105

106
    // aabb
Aaron Grabowy's avatar
Aaron Grabowy committed
107
    // TODO: And boundary
108
109
110
111
    test_obj(p1, tg::aabb1(minPos1, maxPos1));
    test_obj(p2, tg::aabb2(minPos2, maxPos2));
    test_obj(p3, tg::aabb3(minPos3, maxPos3));
    test_obj(p4, tg::aabb4(minPos4, maxPos4));
112
    // box
Aaron Grabowy's avatar
Aaron Grabowy committed
113
114
    // TODO: And boundary
    test_obj(p1, tg::box1(pos10, m1));
115
116
    test_obj(p2, tg::box2(pos20, m2));
    test_obj(p3, tg::box3(pos30, m3));
Aaron Grabowy's avatar
Aaron Grabowy committed
117
118
119
    // TODO: box4
    // test_obj(p3, tg::box2in3(pos30, m23)); // TODO: box2in3

Aaron Grabowy's avatar
Aaron Grabowy committed
120
    // capsule
Aaron Grabowy's avatar
Aaron Grabowy committed
121
    test_obj_and_boundary(p3, tg::capsule3(axis0, r));
122
    // cone
Aaron Grabowy's avatar
Aaron Grabowy committed
123
124
    // TODO: And boundary no caps
    // test_obj(p3, tg::cone3(disk0, r)); // TODO: solid cone
125
    test_obj(p3, tg::cone_boundary_no_caps<3, float>(disk0, r));
126
    // cylinder
Aaron Grabowy's avatar
Aaron Grabowy committed
127
    test_obj_and_boundary_no_caps(p3, tg::cylinder3(axis0, r));
128
    // hemisphere
Aaron Grabowy's avatar
Aaron Grabowy committed
129
130
    // TODO: And boundary no caps
    // test_obj(p1, tg::hemisphere1(pos10, r, n1));
131
132
    test_obj(p2, tg::hemisphere2(pos20, r, n2));
    test_obj(p3, tg::hemisphere3(pos30, r, n3));
Aaron Grabowy's avatar
Aaron Grabowy committed
133
    // test_obj(p4, tg::hemisphere4(pos40, r, n4));
134
    // TODO: pyramid once implemented
Aaron Grabowy's avatar
Aaron Grabowy committed
135
    // test_obj(p3, tg::pyramid3(rect0, r));
136
137
138
139
140
141
    // segment
    test_obj(p1, tg::segment1(pos10, pos11));
    test_obj(p2, tg::segment2(pos20, pos21));
    test_obj(p3, tg::segment3(pos30, pos31));
    test_obj(p4, tg::segment4(pos40, pos41));
    // sphere
Aaron Grabowy's avatar
Aaron Grabowy committed
142
143
144
145
146
    test_obj_and_boundary(p1, tg::sphere1(pos10, r));
    test_obj_and_boundary(p2, tg::sphere2(pos20, r));
    test_obj_and_boundary(p3, tg::sphere3(pos30, r));
    test_obj_and_boundary(p4, tg::sphere4(pos40, r));
    test_obj_and_boundary(p3, tg::sphere2in3(pos30, r, n3));
147
    // triangle
148
149
    test_obj(p2, tg::triangle2(pos20, pos21, pos22));
    test_obj(p3, tg::triangle3(pos30, pos31, pos32));
Aaron Grabowy's avatar
Aaron Grabowy committed
150
    // test_obj(p4, tg::triangle4(pos40, pos41, pos42));
151
152
153
}

TG_FUZZ_TEST(TypedGeometry, ProjectObjects)
154
{
Philip Trettner's avatar
Philip Trettner committed
155
156
157
    auto range1 = tg::aabb1(tg::pos1(-10), tg::pos1(10));
    auto range2 = tg::aabb2(tg::pos2(-10), tg::pos2(10));
    auto range3 = tg::aabb3(tg::pos3(-10), tg::pos3(10));
158

159
160
    TG_UNUSED(range2);

161
162
    {
        // plane
Philip Trettner's avatar
Philip Trettner committed
163
        auto n = normalize(uniform(rng, range3) - tg::zero<tg::pos3>());
164
165
166
167
168
169
170
        auto d = uniform(rng, -10.0f, 10.0f);
        auto pl = tg::plane(n, d);

        // point
        auto p = uniform(rng, range3);


171
        auto pp = project(p, pl);
172
173

        // distance initial point to plane
174
        auto dist0 = distance(p, pl);
175
        // distance initial point to point on plane
176
        auto dist1 = distance(p, pp);
177
        // distance point on plane to plane
178
        auto dist2 = distance(pp, pl);
179

180
181
        CHECK(dist0 == approx(dist1));
        CHECK(dist2 == approx(0.0f));
182
    }
183
184
185
186
187

    {
        // line
        auto pos = uniform(rng, range3);
        auto dir = tg::vec3();
188
        while (length_sqr(dir) == 0)
189
190
191
192
193
194
195
196
197
198
            dir = tg::vec3(uniform(rng, range3));
        auto line = tg::line3(pos, normalize(dir));

        auto s = uniform(rng, range1).x;

        // point
        auto p = pos + s * line.dir;

        // create vector which is orthogonal to line direction
        auto ortho = tg::vec3();
199
        while (length_sqr(ortho) == 0)
200
201
202
203
204
205
            ortho = cross(dir, tg::vec3(uniform(rng, range3)));

        // create second point "above" line
        auto pn = p + normalize(ortho);

        // project that point back, it should lie at p's position
206
207
        pn = project(pn, line);
        auto dist1 = distance_sqr(p, pn);
208
        CHECK(dist1 == approx(0.0f));
209
    }
210
211
212
213
214
215
216
217
218
219
220
221
222

    {
        // ray
        auto pos = uniform(rng, range3);
        auto dir = tg::vec3();
        while (length_sqr(dir) == 0)
            dir = tg::vec3(uniform(rng, range3));
        auto dirN = normalize(dir);
        auto line = tg::line3(pos, dirN);
        auto ray = tg::ray3(pos, dirN);

        auto p = uniform(rng, range3);

223
224
        auto projLine = project(p, line);
        auto projRay = project(p, ray);
225
226

        // The projection onto the ray is the same as onto the line if in positive direction, otherwise at the ray origin
227
        auto diff = distance_sqr(projRay, dot(p - pos, dir) > 0 ? projLine : pos);
228
        CHECK(diff == approx(0.0f));
229
    }
230
}