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

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

#include <iostream>

7
8
9
10
11
12
TG_FUZZ_TEST_MAX_ITS(TypedGeometry, Project, 20)
{
    auto const test_obj = [&rng](auto p, auto o) {
        auto proj = project(p, o);

        // Projected point lies in the object
13
14
        auto dist = distance_sqr(proj, o);
        CHECK(dist == approx(0.0f));
15
16
17
18
        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
19
            CHECK(dist == approx(0.0f));
20
21
22
23
        else // Otherwise all other points inside are not closer than the projection
            for (auto i = 0; i < 256; i++)
            {
                auto q = uniform(rng, o);
24
                CHECK(distance_sqr(q, p) >= approx(dist));
25
26
27
28
29
            }

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

Aaron Grabowy's avatar
Aaron Grabowy committed
34
35
36
37
38
39
40
41
42
43
44
45
    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));
    };


46
    const auto r = uniform(rng, 0.0f, 10.0f);
47
48
    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));
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
82
83

    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);
84
    const auto disk0 = tg::sphere2in3(pos30, r, n3);
85

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

90
    auto d20 = tg::uniform<tg::dir2>(rng);
91
    auto d21 = perpendicular(d20);
92
93
94
95
96
97
98
99
100
101
102
103
    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
104
105
106
    auto m23 = tg::mat2x3();
    m23[0] = d30 * uniform(rng, 1.0f, 3.0f);
    m23[1] = d31 * uniform(rng, 1.0f, 3.0f);
107

108
    // aabb
Aaron Grabowy's avatar
Aaron Grabowy committed
109
    // TODO: And boundary
110
111
112
113
    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));
114
    // box
Aaron Grabowy's avatar
Aaron Grabowy committed
115
116
    // TODO: And boundary
    test_obj(p1, tg::box1(pos10, m1));
117
118
    test_obj(p2, tg::box2(pos20, m2));
    test_obj(p3, tg::box3(pos30, m3));
Aaron Grabowy's avatar
Aaron Grabowy committed
119
120
121
    // TODO: box4
    // test_obj(p3, tg::box2in3(pos30, m23)); // TODO: box2in3

Aaron Grabowy's avatar
Aaron Grabowy committed
122
    // capsule
Aaron Grabowy's avatar
Aaron Grabowy committed
123
    test_obj_and_boundary(p3, tg::capsule3(axis0, r));
124
    // cone
Aaron Grabowy's avatar
Aaron Grabowy committed
125
126
    // TODO: And boundary no caps
    // test_obj(p3, tg::cone3(disk0, r)); // TODO: solid cone
127
    test_obj(p3, tg::cone_boundary_no_caps<3, float>(disk0, r));
128
    // cylinder
Aaron Grabowy's avatar
Aaron Grabowy committed
129
    test_obj_and_boundary_no_caps(p3, tg::cylinder3(axis0, r));
130
    // hemisphere
Aaron Grabowy's avatar
Aaron Grabowy committed
131
132
    // TODO: And boundary no caps
    // test_obj(p1, tg::hemisphere1(pos10, r, n1));
133
134
    test_obj(p2, tg::hemisphere2(pos20, r, n2));
    test_obj(p3, tg::hemisphere3(pos30, r, n3));
Aaron Grabowy's avatar
Aaron Grabowy committed
135
    // test_obj(p4, tg::hemisphere4(pos40, r, n4));
136
    // TODO: pyramid once implemented
Aaron Grabowy's avatar
Aaron Grabowy committed
137
    // test_obj(p3, tg::pyramid3(rect0, r));
138
139
140
141
142
143
    // 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
144
145
146
147
148
    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));
149
    // triangle
150
151
152
153
    (void)pos22;
    (void)pos32;
    // FIXME: test_obj(p2, tg::triangle2(pos20, pos21, pos22));
    // FIXME: test_obj(p3, tg::triangle3(pos30, pos31, pos32));
Aaron Grabowy's avatar
Aaron Grabowy committed
154
    // test_obj(p4, tg::triangle4(pos40, pos41, pos42));
155
156
157
}

TG_FUZZ_TEST(TypedGeometry, ProjectObjects)
158
{
Philip Trettner's avatar
Philip Trettner committed
159
160
161
    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));
162

163
164
    TG_UNUSED(range2);

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

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


175
        auto pp = project(p, pl);
176
177

        // distance initial point to plane
178
        auto dist0 = distance(p, pl);
179
        // distance initial point to point on plane
180
        auto dist1 = distance(p, pp);
181
        // distance point on plane to plane
182
        auto dist2 = distance(pp, pl);
183

184
185
        CHECK(dist0 == approx(dist1));
        CHECK(dist2 == approx(0.0f));
186
    }
187
188
189
190
191

    {
        // line
        auto pos = uniform(rng, range3);
        auto dir = tg::vec3();
192
        while (length_sqr(dir) == 0)
193
194
195
196
197
198
199
200
201
202
            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();
203
        while (length_sqr(ortho) == 0)
204
205
206
207
208
209
            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
210
211
        pn = project(pn, line);
        auto dist1 = distance_sqr(p, pn);
212
        CHECK(dist1 == approx(0.0f));
213
    }
214
215
216
217
218
219
220
221
222
223
224
225
226

    {
        // 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);

227
228
        auto projLine = project(p, line);
        auto projRay = project(p, ray);
229
230

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