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
27
30
31#include <algorithm>
32
33#include "geom_test_utils.h"
34
36{
37};
38
42BOOST_FIXTURE_TEST_SUITE( Fillet, FilletFixture )
43
44/*
45 * @brief check that a single segment of a fillet complies with the geometric
46 * constraint:
47 *
48 * 1: The end points are radius from the centre point
49 * 2: The mid point error is acceptable
50 * 3: The segment midpoints are perpendicular to the radius
51 */
52void TestFilletSegmentConstraints( const SEG& aSeg, VECTOR2I aRadCentre,
53 int aRadius, int aError )
54{
55 const auto diffA = aRadCentre - aSeg.A;
56 const auto diffB = aRadCentre - aSeg.B;
57 const auto diffC = aRadCentre - aSeg.Center();
58
59 // Check 1: radii (error of 1 for rounding)
60 BOOST_CHECK_PREDICATE(
61 KI_TEST::IsWithinAndBelow<int>, ( diffA.EuclideanNorm() )( aRadius )( 1 ) );
62 BOOST_CHECK_PREDICATE(
63 KI_TEST::IsWithinAndBelow<int>, ( diffB.EuclideanNorm() )( aRadius )( 1 ) );
64
65 // Check 2: Mid-point error
66 BOOST_CHECK_PREDICATE(
67 KI_TEST::IsWithinAndBelow<int>, ( diffC.EuclideanNorm() )( aRadius )( aError + 1 ) );
68
69 // Check 3: Mid-point -> radius centre perpendicular
70 const EDA_ANGLE perpendularityMaxError = ANGLE_90 / 10;
71 BOOST_CHECK_PREDICATE( GEOM_TEST::ArePerpendicular<int>,
72 ( diffC )( aSeg.A - aSeg.B )( perpendularityMaxError ) );
73}
74
75
79void TestSquareFillet( int aSquareSize, int aRadius, int aError )
80{
81 using namespace GEOM_TEST;
82
83 SHAPE_POLY_SET squarePolySet;
84
85 squarePolySet.AddOutline( MakeSquarePolyLine(aSquareSize, VECTOR2I(0, 0) ) );
86
87 SHAPE_POLY_SET filleted = FilletPolySet(squarePolySet, aRadius, aError);
88
89 // expect a single filleted polygon
90 BOOST_CHECK_EQUAL( filleted.OutlineCount(), 1 );
91
92 auto segIter = filleted.IterateSegments();
93
94 const VECTOR2I radCentre { aSquareSize / 2 - aRadius,
95 aSquareSize / 2 - aRadius };
96
97 int checked = 0;
98
99 for( ; segIter; segIter++ )
100 {
101 // Only check the first Quadrant
102 if ( SegmentCompletelyInQuadrant( *segIter, QUADRANT::Q1 ) )
103 {
104 TestFilletSegmentConstraints( *segIter, radCentre, aRadius, aError );
105 checked++;
106 }
107 }
108
109 // we expect there to be at least one segment in the fillet
110 BOOST_CHECK( checked > 0 );
111}
112
113
117void TestConcaveSquareFillet( int aSquareSize, int aRadius, int aError )
118{
119 using namespace GEOM_TEST;
120
121 SHAPE_POLY_SET polySet;
122 SHAPE_LINE_CHAIN polyLine;
123
124 /*
125 * L-shape:
126 * ----
127 * | |
128 * ---- |
129 * | |
130 * --------
131 */
132
133 polyLine.Append( VECTOR2I{ 0, 0 } );
134 polyLine.Append( VECTOR2I{ 0, aSquareSize / 2 } );
135 polyLine.Append( VECTOR2I{ aSquareSize / 2 , aSquareSize / 2 } );
136 polyLine.Append( VECTOR2I{ aSquareSize / 2 , aSquareSize } );
137 polyLine.Append( VECTOR2I{ aSquareSize, aSquareSize } );
138 polyLine.Append( VECTOR2I{ aSquareSize, 0 } );
139
140 polyLine.SetClosed( true );
141
142 polySet.AddOutline( polyLine );
143
144 SHAPE_POLY_SET filleted = FilletPolySet(polySet, aRadius, aError);
145
146 // expect a single filleted polygon
147 BOOST_CHECK_EQUAL( filleted.OutlineCount(), 1 );
148
149 auto segIter = filleted.IterateSegments();
150
151 const VECTOR2I radCentre { aSquareSize / 2 - aRadius,
152 aSquareSize / 2 + aRadius };
153
154 int checked = 0;
155
156 for( ; segIter; segIter++ )
157 {
158 // Only check segments around the concave corner
159 if ( SegmentCompletelyWithinRadius( *segIter, radCentre, aRadius + 1) )
160 {
161 TestFilletSegmentConstraints( *segIter, radCentre, aRadius, aError );
162 checked++;
163 }
164 }
165
166 // we expect there to be at least one segment in the fillet
167 BOOST_CHECK( checked > 0 );
168}
169
170
172{
175 int error;
176};
177
178const std::vector<SquareFilletTestCase> squareFilletCases {
179 { 1000, 120, 10 },
180 { 1000, 10, 1 },
181
182 /* Large error relative to fillet */
183 { 1000, 10, 5 },
184
185 /* Very small error relative to fillet(many segments in interpolation) */
186 { 70000, 1000, 1 },
187};
188
193BOOST_AUTO_TEST_CASE( SquareFillet )
194{
195 for ( const auto& testCase : squareFilletCases )
196 {
197 TestSquareFillet( testCase.squareSize, testCase.radius, testCase.error );
198 }
199}
200
201BOOST_AUTO_TEST_CASE( SquareConcaveFillet )
202{
203 for ( const auto& testCase : squareFilletCases )
204 {
205 TestConcaveSquareFillet( testCase.squareSize, testCase.radius, testCase.error );
206 }
207}
208
209
210BOOST_AUTO_TEST_SUITE_END()
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
Utility functions for testing geometry functions.
BOOST_CHECK(box.ClosestPointTo(VECTOR2D(0, 0))==VECTOR2D(1, 2))
Test suite for KiCad math code.
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:52
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:79
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:638