File: min-bbox-test.cpp

package info (click to toggle)
lib2geom 1.4-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,124 kB
  • sloc: cpp: 64,251; python: 2,889; ansic: 1,963; makefile: 37
file content (86 lines) | stat: -rw-r--r-- 2,257 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
82
83
84
85
86
// SPDX-License-Identifier: GPL-2.0-or-later
#include <2geom/convex-hull.h>
#include <2geom/transforms.h>
#include <gtest/gtest.h>
#include <glib.h>

namespace Geom {

// Get the axis-aligned bouding box of a set of points, transforming by affine first.
auto aligned_bbox(std::vector<Point> const &pts, Affine const &affine = identity())
{
    OptRect rect;
    for (auto &pt : pts) {
        rect.expandTo(pt * affine);
    }
    return rect;
}

// Get an approximation to the minimum bouding box area.
double approx_min(std::vector<Point> const &pts)
{
    int constexpr N = 100;

    double min = std::numeric_limits<double>::max();

    for (int i = 0; i < N; i++) {
        auto t = (double)i / N * M_PI * 0.5;
        min = std::min(min, aligned_bbox(pts, Rotate(t)).area());
    }

    return min;
}

// Get a random collection of points.
auto randpts()
{
    std::vector<Point> pts;

    int count = 5 + (g_random_int() % 10);
    for (int i = 0; i < count; i++) {
        pts.emplace_back(g_random_double(), g_random_double());
    }

    return pts;
}

TEST(MinBBoxTest, Empty)
{
    auto const hull = ConvexHull();
    auto [rotation, optrect] = hull.minAreaRotation();
    EXPECT_FALSE(optrect);
}

TEST(MinBBoxTest, SinglePoint)
{
    auto const hull = ConvexHull(Point(0, 0));
    auto [rotation, optrect] = hull.minAreaRotation();
    EXPECT_EQ(optrect, Rect::from_xywh(0, 0, 0, 0));
}

TEST(MinBBoxTest, Randomised)
{
    g_random_set_seed(0xdeadbeef);

    for (int i = 0; i < 100; i++) {
        auto const pts = randpts();
        auto const hull = ConvexHull(pts);

        auto [rotation, optrect] = hull.minAreaRotation();

        // The point set is never empty, so the returned bounds should not be empty.
        ASSERT_TRUE(optrect);

        // Ensure that the returned bounds is indeed the bounds at the returned rotation.
        auto rect2 = aligned_bbox(pts, rotation);
        for (int i = 0; i < 2; i++) {
            ASSERT_NEAR(optrect->min()[i], rect2->min()[i], 1e-5);
            ASSERT_NEAR(optrect->max()[i], rect2->max()[i], 1e-5);
        }

        // Ensure that no other rotations give tighter bounds than the returned rotation.
        ASSERT_LE(optrect->area(), approx_min(pts));
    }
}

} // namespace Geom