File: PolygonConnectorTest.cpp

package info (click to toggle)
cura-engine 1%3A5.0.0-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,860 kB
  • sloc: cpp: 52,613; python: 322; makefile: 10; sh: 2
file content (178 lines) | stat: -rw-r--r-- 8,200 bytes parent folder | download | duplicates (2)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <gtest/gtest.h>
#include <unordered_set>

#include <../src/utils/polygon.h> //To create polygons to test with.
#include <../src/utils/PolygonConnector.h> //The class under test.

namespace cura
{

class PolygonConnectorTest : public testing::Test
{
public:
    Polygon test_square;
    Polygon test_square_around; //Larger, around the first square.
    Polygon test_square_adjacent; //Next to the first square.
    Polygon test_triangle;
    Polygon test_circle;
    Polygon test_convex_shape;
    Polygons test_shapes; //All above polygons! As well as an inset of 100 microns of them.

    PolygonConnector* pc;
    Polygons connected_polygons;
    std::vector<VariableWidthLines> connected_paths;

    virtual void SetUp()
    {
        test_square.emplace_back(0, 0);
        test_square.emplace_back(1000, 0);
        test_square.emplace_back(1000, 1000);
        test_square.emplace_back(0, 1000);
    
        test_square_around.emplace_back(1100, 1100);
        test_square_around.emplace_back(-100, 1100);
        test_square_around.emplace_back(-100, -100);
        test_square_around.emplace_back(1100, -100);

        test_square_adjacent.emplace_back(1100, 200);
        test_square_adjacent.emplace_back(2100, 200);
        test_square_adjacent.emplace_back(2100, 1200);
        test_square_adjacent.emplace_back(1100, 1200);

        constexpr coord_t line_width = 100;
        pc = new PolygonConnector(line_width);
    }

    void TearDown()
    {
        delete pc;
    }

};

/*!
 * Test creating a bridge between two squares that are nested in each other at
 * precisely the line width apart.
 *
 * This is a common occurrence with skin.
 */
TEST_F(PolygonConnectorTest, getBridgeNestedSquares)
{
    std::vector<Polygon> to_connect({test_square_around});
    std::optional<PolygonConnector::PolygonBridge<Polygon>> bridge = pc->getBridge(test_square, to_connect);

    ASSERT_NE(bridge, std::nullopt) << "The two polygons are nested simply, so they are definitely positioned closely enough to bridge. They are also wide enough.";

    EXPECT_EQ(vSize(bridge->a.from_point - bridge->a.to_point), 100) << "The polygons are 100 units spaced out concentrically, so this is the shortest possible bridge.";
    EXPECT_EQ(vSize(bridge->b.from_point - bridge->b.to_point), 100) << "The second bridge should also be equally short in this case.";
    EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a.from_point, bridge->a.to_point, bridge->b.from_point, bridge->b.to_point), 100 * 100) << "The bridges should be spaced 1 line width (100 units) apart.";
    EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b.from_point, bridge->a.from_point, bridge->a.to_point), 0) << "Connection B should be to the right of connection A.";
    EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b.to_point, bridge->a.from_point, bridge->a.to_point), 0) << "Connection B should be to the right of connection A.";
}

/*!
 * Test creating a bridge between two adjacent squares that are spaced 1 line
 * width apart.
 *
 * This is a common occurrence with multiplied infill.
 */
TEST_F(PolygonConnectorTest, getBridgeAdjacentSquares)
{
    std::vector<Polygon> to_connect({test_square_adjacent});
    std::optional<PolygonConnector::PolygonBridge<Polygon>> bridge = pc->getBridge(test_square, to_connect);

    ASSERT_NE(bridge, std::nullopt) << "The two polygons are adjacent, spaced closely enough to bridge and with enough room.";

    EXPECT_EQ(vSize(bridge->a.from_point - bridge->a.to_point), 100) << "The polygons are 100 units spaced apart, so this is the shortest possible bridge.";
    EXPECT_EQ(vSize(bridge->b.from_point - bridge->b.to_point), 100) << "The second bridge should also be equally short in this case.";
    EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a.from_point, bridge->a.to_point, bridge->b.from_point, bridge->b.to_point), 100 * 100) << "The bridges should be spaced 1 line width (100 units) apart.";
    EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b.from_point, bridge->a.from_point, bridge->a.to_point), 0) << "Connection B should be to the right of connection A.";
    EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b.to_point, bridge->a.from_point, bridge->a.to_point), 0) << "Connection B should be to the right of connection A.";
}

/*!
 * Test that the bridge is created in the location where the polygons are
 * closest together.
 */
TEST_F(PolygonConnectorTest, getBridgeClosest)
{
    Polygon adjacent_slanted; //A polygon that's adjacent to the first square, but tilted such that the vertex at [1100,200] is definitely the closest.
    adjacent_slanted.emplace_back(1100, 200);
    adjacent_slanted.emplace_back(2100, 200);
    adjacent_slanted.emplace_back(2140, 1200);
    adjacent_slanted.emplace_back(1140, 1200);
    std::vector<Polygon> to_connect({adjacent_slanted});

    std::optional<PolygonConnector::PolygonBridge<Polygon>> bridge = pc->getBridge(test_square, to_connect);

    ASSERT_NE(bridge, std::nullopt) << "The two polygons are adjacent and spaced closely enough to bridge along their entire side, even with the slant.";

    EXPECT_EQ(bridge->b.from_point, Point(1000, 200)) << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there.";
    EXPECT_EQ(bridge->b.to_point, Point(1100, 200)) << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there.";
    EXPECT_GT(LinearAlg2D::pointIsLeftOfLine(bridge->a.from_point, bridge->b.from_point, bridge->b.to_point), 0) << "Connection A should be to the left of connection B.";
    EXPECT_GT(LinearAlg2D::pointIsLeftOfLine(bridge->a.to_point, bridge->b.from_point, bridge->b.to_point), 0) << "Connection A should be to the left of connection B.";
}

/*!
 * Test attempting to create a bridge when the polygons are too far apart.
 */
TEST_F(PolygonConnectorTest, getBridgeTooFar)
{
    Polygon too_far; //More than 1.5 line width away.
    too_far.emplace_back(1200, 0);
    too_far.emplace_back(2200, 0);
    too_far.emplace_back(2200, 1000);
    too_far.emplace_back(1200, 1000);
    std::vector<Polygon> to_connect({too_far});

    std::optional<PolygonConnector::PolygonBridge<Polygon>> bridge = pc->getBridge(test_square, to_connect);

    EXPECT_EQ(bridge, std::nullopt) << "The two polygons are 200 units apart where they are closest, which is more than 1.5 times the line width (100), so they can't be connected.";
}

/*!
 * Test attempting to create a bridge when the connecting part is too narrow.
 *
 * Since the bridging lines need to be spaced 1 line width apart, they can't be
 * too close together. If the bridge can't be constructed keeping proper spacing
 * the bridge should fail to be created.
 */
TEST_F(PolygonConnectorTest, getBridgeTooNarrow)
{
    Polygon too_narrow;
    too_narrow.emplace_back(1100, 400);
    too_narrow.emplace_back(2100, 400);
    too_narrow.emplace_back(2100, 480); //Less than 100 units wide.
    too_narrow.emplace_back(1100, 480);
    std::vector<Polygon> to_connect({too_narrow});

    std::optional<PolygonConnector::PolygonBridge<Polygon>> bridge = pc->getBridge(test_square, to_connect);

    EXPECT_EQ(bridge, std::nullopt) << "Where the two polygons are adjacent is only 80 units wide. This is not enough to create a bridge with the connecting lines spaced 1 line width (100 units) apart.";
}

/*!
 * Try connecting four nested polygons.
 *
 * Let's play a game of connect four!
 */
TEST_F(PolygonConnectorTest, connectFourNested)
{
    Polygons connecting;
    connecting.add(test_square_around); //1200-wide square.
    connecting.add(test_square); //1000-wide square.
    connecting.add(test_square.offset(-100)); //800-wide square.
    connecting.add(test_square.offset(-200)); //600-wide square.

    pc->add(connecting);
    Polygons output_polygons;
    std::vector<VariableWidthLines> output_paths;
    pc->connect(output_polygons, output_paths);

    EXPECT_EQ(output_polygons.size(), 1) << "All four polygons should've gotten connected into 1 single polygon.";
}

}