KiCad PCB EDA Suite
test_shape_poly_set_arcs.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2021 Roberto Fernandez Bautista <[email protected]>
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <string>
22 #include <tuple>
24 
27 
28 #include "fixtures_geometry.h"
29 #include "geom_test_utils.h"
30 
31 
32 BOOST_AUTO_TEST_SUITE( CurvedPolys )
33 
34 
35 
39 BOOST_AUTO_TEST_CASE( TestSimplify )
40 {
41  KI_TEST::CommonTestData testData;
42 
43  std::map<std::string, SHAPE_POLY_SET> polysToTest =
44  {
45  { "Case 1: Single polygon", testData.holeyCurvedPolySingle },
46  { "Case 2: Wraparound polygon", testData.curvedPolyWrapRound },
47  //{ "Case 3: Multi polygon", testData.holeyCurvedPolyMulti } // This test fails right now:
48  // clipper seems to not handle
49  // multiple outlines correctly
50  };
51 
52  for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
53  {
54  BOOST_TEST_CONTEXT( testCase.first )
55  {
56  SHAPE_POLY_SET testPoly = testCase.second;
57 
58  double originalArea = testPoly.Area();
59 
60  std::vector<SHAPE_ARC> originalArcs;
61  testPoly.GetArcs( originalArcs );
62 
63  for( int i = 1; i <= 3; i++ )
64  {
65  BOOST_TEST_CONTEXT( "Simplify Iteration " << i )
66  {
67  testPoly.Simplify( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
68 
69  std::vector<SHAPE_ARC> foundArcs;
70  testPoly.GetArcs( foundArcs );
71 
73  BOOST_CHECK_EQUAL( testPoly.Area(), originalArea );
74  BOOST_CHECK_EQUAL( originalArcs.size(), foundArcs.size() );
75  KI_TEST::CheckUnorderedMatches( originalArcs, foundArcs,
76  []( const SHAPE_ARC& aA, const SHAPE_ARC& aB ) -> bool
77  {
78  // We accept that the arcs could be reversed after Simplify
79  return aA == aB || aA.Reversed() == aB;
80  } );
81 
82  }
83  }
84  }
85  }
86 }
87 
88 
92 BOOST_AUTO_TEST_CASE( TestIntersectUnion )
93 {
94  KI_TEST::CommonTestData testData;
95 
96  std::map<std::string, SHAPE_POLY_SET> polysToTest = {
97  { "Case 1: Single polygon", testData.holeyCurvedPolySingle },
98  //{ "Case 2: Multi polygon", testData.holeyCurvedPolyMulti } // This test fails right now:
99  // clipper seems to not handle
100  // multiple outlines correctly
101  };
102 
103  for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
104  {
105  BOOST_TEST_CONTEXT( testCase.first )
106  {
107  SHAPE_POLY_SET testPoly = testCase.second;
108  SHAPE_POLY_SET opPoly = testData.holeyCurvedPolyInter;
109 
110  // Remove all arcs before any booleanOps
111  // @todo Remove the below two lines when boolean ops can be carried out on curved polys
112  opPoly.ClearArcs();
113  testPoly.ClearArcs();
114 
115  BOOST_CHECK( GEOM_TEST::IsPolySetValid( testPoly ) );
117 
118  double testPolyArea = testPoly.Area();
119  double opPolyArea = opPoly.Area();
120 
121  SHAPE_POLY_SET intersectionPoly = testPoly;
122  intersectionPoly.BooleanIntersection( opPoly, SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
123  double intersectArea = intersectionPoly.Area();
124 
125  BOOST_CHECK( GEOM_TEST::IsPolySetValid( intersectionPoly ) );
126 
127 
128  SHAPE_POLY_SET unionPoly = testPoly;
129  unionPoly.BooleanAdd( opPoly, SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
130  double unionArea = unionPoly.Area();
131 
132  BOOST_CHECK( GEOM_TEST::IsPolySetValid( unionPoly ) );
133 
134  // Acceptable error of 0.01% (fails at 0.001% for some - this is a Clipper limitation)
135  BOOST_CHECK_CLOSE( testPolyArea + opPolyArea - intersectArea, unionArea, 0.01 );
136  }
137  }
138 }
139 
140 
144 BOOST_AUTO_TEST_CASE( TestClearArcs )
145 {
146  KI_TEST::CommonTestData testData;
147 
148  std::map<std::string, SHAPE_POLY_SET> polysToTest = {
149  { "Case 1: Single polygon", testData.holeyCurvedPolySingle },
150  { "Case 2: Intersect polygon", testData.holeyCurvedPolyInter },
151  { "Case 3: Multi polygon", testData.holeyCurvedPolyMulti }
152  };
153 
154  for( std::pair<std::string, SHAPE_POLY_SET> testCase : polysToTest )
155  {
156  BOOST_TEST_CONTEXT( testCase.first )
157  {
158  SHAPE_POLY_SET testPoly = testCase.second;
159  double originalArea = testPoly.Area();
160  testPoly.ClearArcs();
161 
162  BOOST_CHECK( GEOM_TEST::IsPolySetValid( testPoly ) );
163  BOOST_CHECK_EQUAL( testPoly.Area(), originalArea ); // Area should not have changed
164 
165  std::vector<SHAPE_ARC> arcBuffer;
166  testPoly.GetArcs( arcBuffer );
167 
168  BOOST_CHECK_EQUAL( arcBuffer.size(), 0 ); // All arcs should have been removed
169  }
170  }
171 }
172 
173 BOOST_AUTO_TEST_SUITE_END()
SHAPE_POLY_SET holeyCurvedPolySingle
Polygon with a single outline + multiple holes.
SHAPE_POLY_SET holeyCurvedPolyMulti
Polygon with a multiple outlines + multiple holes.
bool IsPolySetValid(const SHAPE_POLY_SET &aSet)
Verify that a SHAPE_POLY_SET has been assembled correctly by verifying each of the outlines and holes...
Common data for some of the SHAPE_POLY_SET tests:
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
double Area()
Count the number of arc shapes present.
BOOST_CHECK(v2.Cross(v1)==1)
Represent a set of closed polygons.
void Simplify(POLYGON_MODE aFastMode)
void CheckUnorderedMatches(const EXP_CONT &aExpected, const FOUND_CONT &aFound, MATCH_PRED aMatchPredicate)
Check that a container of "found" objects matches a container of "expected" objects.
#define BOOST_TEST_CONTEXT(A)
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
BOOST_AUTO_TEST_CASE(TestSimplify)
Simplify the polygon a large number of times and check that the area does not change and also that th...
void GetArcs(std::vector< SHAPE_ARC > &aArcBuffer) const
Removes all arc references from all the outlines and holes in the polyset.
SHAPE_POLY_SET holeyCurvedPolyInter
Polygon with a single outlines + multiple holes.
void ClearArcs()
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_POLY_SET curvedPolyWrapRound
Causes arc wraparound when reloading from Clipper see https://gitlab.com/kicad/code/kicad/-/issues/96...
SHAPE_ARC Reversed() const
Definition: shape_arc.cpp:581