KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_fillet.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) 2018 KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <boost/test/unit_test.hpp>
25
28
31
32#include <algorithm>
33
34#include "geom_test_utils.h"
35
37{
38};
39
43BOOST_FIXTURE_TEST_SUITE( Fillet, FilletFixture )
44
45/*
46 * @brief check that a single segment of a fillet complies with the geometric
47 * constraint:
48 *
49 * 1: The end points are radius from the centre point
50 * 2: The mid point error is acceptable
51 * 3: The segment midpoints are perpendicular to the radius
52 */
53void TestFilletSegmentConstraints( const SEG& aSeg, VECTOR2I aRadCentre,
54 int aRadius, int aError )
55{
56 const auto diffA = aRadCentre - aSeg.A;
57 const auto diffB = aRadCentre - aSeg.B;
58 const auto diffC = aRadCentre - aSeg.Center();
59
60 // Check 1: radii (error of 1 for rounding)
61 BOOST_CHECK_PREDICATE(
62 KI_TEST::IsWithinAndBelow<int>, ( diffA.EuclideanNorm() )( aRadius )( 1 ) );
63 BOOST_CHECK_PREDICATE(
64 KI_TEST::IsWithinAndBelow<int>, ( diffB.EuclideanNorm() )( aRadius )( 1 ) );
65
66 // Check 2: Mid-point error
67 BOOST_CHECK_PREDICATE(
68 KI_TEST::IsWithinAndBelow<int>, ( diffC.EuclideanNorm() )( aRadius )( aError + 1 ) );
69
70 // Check 3: Mid-point -> radius centre perpendicular
71 const EDA_ANGLE perpendularityMaxError = ANGLE_90 / 10;
72 BOOST_CHECK_PREDICATE( GEOM_TEST::ArePerpendicular<int>,
73 ( diffC )( aSeg.A - aSeg.B )( perpendularityMaxError ) );
74}
75
76
80void TestSquareFillet( int aSquareSize, int aRadius, int aError )
81{
82 using namespace GEOM_TEST;
83
84 SHAPE_POLY_SET squarePolySet;
85
86 squarePolySet.AddOutline( KI_TEST::BuildSquareChain( aSquareSize, VECTOR2I( 0, 0 ) ) );
87
88 SHAPE_POLY_SET filleted = FilletPolySet( squarePolySet, aRadius, aError );
89
90 // expect a single filleted polygon
91 BOOST_CHECK_EQUAL( filleted.OutlineCount(), 1 );
92
93 auto segIter = filleted.IterateSegments();
94
95 const VECTOR2I radCentre { aSquareSize / 2 - aRadius,
96 aSquareSize / 2 - aRadius };
97
98 int checked = 0;
99
100 for( ; segIter; segIter++ )
101 {
102 // Only check the first Quadrant
103 if ( SegmentCompletelyInQuadrant( *segIter, QUADRANT::Q1 ) )
104 {
105 TestFilletSegmentConstraints( *segIter, radCentre, aRadius, aError );
106 checked++;
107 }
108 }
109
110 // we expect there to be at least one segment in the fillet
111 BOOST_CHECK( checked > 0 );
112}
113
114
118void TestConcaveSquareFillet( int aSquareSize, int aRadius, int aError )
119{
120 using namespace GEOM_TEST;
121
122 SHAPE_POLY_SET polySet;
123 SHAPE_LINE_CHAIN polyLine;
124
125 /*
126 * L-shape:
127 * ----
128 * | |
129 * ---- |
130 * | |
131 * --------
132 */
133
134 polyLine.Append( VECTOR2I{ 0, 0 } );
135 polyLine.Append( VECTOR2I{ 0, aSquareSize / 2 } );
136 polyLine.Append( VECTOR2I{ aSquareSize / 2 , aSquareSize / 2 } );
137 polyLine.Append( VECTOR2I{ aSquareSize / 2 , aSquareSize } );
138 polyLine.Append( VECTOR2I{ aSquareSize, aSquareSize } );
139 polyLine.Append( VECTOR2I{ aSquareSize, 0 } );
140
141 polyLine.SetClosed( true );
142
143 polySet.AddOutline( polyLine );
144
145 SHAPE_POLY_SET filleted = FilletPolySet(polySet, aRadius, aError);
146
147 // expect a single filleted polygon
148 BOOST_CHECK_EQUAL( filleted.OutlineCount(), 1 );
149
150 auto segIter = filleted.IterateSegments();
151
152 const VECTOR2I radCentre { aSquareSize / 2 - aRadius,
153 aSquareSize / 2 + aRadius };
154
155 int checked = 0;
156
157 for( ; segIter; segIter++ )
158 {
159 // Only check segments around the concave corner
160 if ( SegmentCompletelyWithinRadius( *segIter, radCentre, aRadius + 1) )
161 {
162 TestFilletSegmentConstraints( *segIter, radCentre, aRadius, aError );
163 checked++;
164 }
165 }
166
167 // we expect there to be at least one segment in the fillet
168 BOOST_CHECK( checked > 0 );
169}
170
171
173{
176 int error;
177};
178
179const std::vector<SquareFilletTestCase> squareFilletCases {
180 { 1000, 120, 10 },
181 { 1000, 10, 1 },
182
183 /* Large error relative to fillet */
184 { 1000, 10, 5 },
185
186 /* Very small error relative to fillet(many segments in interpolation) */
187 { 70000, 1000, 1 },
188};
189
194BOOST_AUTO_TEST_CASE( SquareFillet )
195{
196 for ( const auto& testCase : squareFilletCases )
197 {
198 TestSquareFillet( testCase.squareSize, testCase.radius, testCase.error );
199 }
200}
201
202BOOST_AUTO_TEST_CASE( SquareConcaveFillet )
203{
204 for ( const auto& testCase : squareFilletCases )
205 {
206 TestConcaveSquareFillet( testCase.squareSize, testCase.radius, testCase.error );
207 }
208}
209
210
Definition: seg.h:42
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
SEGMENT_ITERATOR IterateSegments(int aFirst, int aLast, bool aIterateHoles=false)
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
int OutlineCount() const
Return the number of outlines in the set.
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
Utilities for creating useful line chain idioms commonly founds in QA utilities and tests.
Utility functions for testing geometry functions.
SHAPE_LINE_CHAIN BuildSquareChain(int aSize, const VECTOR2I &aCentre)
Builds a square SHAPE_LINE_CHAIN of a certain size at a certain centre.
const std::vector< SquareFilletTestCase > squareFilletCases
void TestConcaveSquareFillet(int aSquareSize, int aRadius, int aError)
: Create a square concave corner, fillet and check correctness
void TestFilletSegmentConstraints(const SEG &aSeg, VECTOR2I aRadCentre, int aRadius, int aError)
Declares the FilletFixture struct as the boost test fixture.
Definition: test_fillet.cpp:53
BOOST_AUTO_TEST_CASE(SquareFillet)
Tests the SHAPE_POLY_SET::FilletPolygon method against certain geometric constraints.
void TestSquareFillet(int aSquareSize, int aRadius, int aError)
: Create a square, fillet it, and check a corner for correctness
Definition: test_fillet.cpp:80
BOOST_AUTO_TEST_SUITE_END()
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691