KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_footprint.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 The 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
26
27#include <board.h>
29#include <footprint.h>
30#include <pcb_shape.h>
31
32
33static bool CourtyardEqualPredicate( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
34{
35 // The courtyards get a tiny epsilon to handle polygonisaton errors
36 const int courtyardEpsilon = pcbIUScale.mmToIU( 0.005 );
37
38 if( a.OutlineCount() != b.OutlineCount() )
39 return false;
40
41 // We can only use this predicate on single-outline polys unless we do more work.
42 // Because we don't know the sub-outlines are in the same order.
43 BOOST_REQUIRE( a.OutlineCount() == 1 );
44
45 return KI_TEST::ChainsAreCyclicallyEqual( a.Outline( 0 ), b.Outline( 0 ), courtyardEpsilon );
46};
47
48
49BOOST_AUTO_TEST_SUITE( Footprint )
50
51
52BOOST_AUTO_TEST_CASE( FootprintCourtyardAndHull )
53{
54 // Footprint courtyards are cached internally. Some operations manipulate the
55 // cache efficiently, some rebuild it. In any case, the courtyard should always
56 // be consistent with the geometry of the footprint. Same for the bounding hull.
57
58 BOARD board;
59 FOOTPRINT fp( &board );
60
61 const int lineW = pcbIUScale.mmToIU( 0.05 );
62 const int courtyardH = pcbIUScale.mmToIU( 1.0 );
63 const int courtyardW = pcbIUScale.mmToIU( 2.0 );
64
65 const std::vector<VECTOR2I> courtyardPoints = {
66 { 0, 0 },
67 { courtyardW, 0 },
68 { courtyardW, courtyardH },
69 { 0, courtyardH },
70 };
71
72 const auto assertCourtyardMatches = [&]( PCB_LAYER_ID layer, const SHAPE_LINE_CHAIN& aExpectedCourtyard )
73 {
74 const SHAPE_POLY_SET& courtyard = fp.GetCourtyard( layer );
75
76 BOOST_REQUIRE( courtyard.OutlineCount() == 1 );
77 BOOST_CHECK_PREDICATE( CourtyardEqualPredicate, ( courtyard.Outline( 0 ) )( aExpectedCourtyard ) );
78 };
79
80 const auto assertNoCourtyard = [&]( PCB_LAYER_ID layer )
81 {
82 const SHAPE_POLY_SET& courtyard = fp.GetCourtyard( layer );
83
84 BOOST_TEST( courtyard.OutlineCount() == 0 );
85 };
86
87 const auto assertHullMatch = [&]( const SHAPE_LINE_CHAIN& aExpectedHull )
88 {
89 const SHAPE_POLY_SET& hull = fp.GetBoundingHull();
90
91 BOOST_REQUIRE( hull.OutlineCount() == 1 );
92 BOOST_CHECK_PREDICATE( KI_TEST::ChainsAreCyclicallyEqual, ( hull.Outline( 0 ) )(aExpectedHull) ( 0 ) );
93 };
94
95 {
96 std::unique_ptr<PCB_SHAPE> courtyardPoly = std::make_unique<PCB_SHAPE>( &fp, SHAPE_T::POLY );
97 courtyardPoly->SetLayer( F_CrtYd );
98 courtyardPoly->SetPolyPoints( courtyardPoints );
99 courtyardPoly->SetWidth( lineW );
100
101 fp.Add( courtyardPoly.release() );
102 }
103
104 // We'll modify this in lock-step with the footprint
105 SHAPE_LINE_CHAIN expectedCourtyard( courtyardPoints, true );
106 // The hull is hard to calculate - we'll take the initial one as a given
107 SHAPE_LINE_CHAIN expectedHull = fp.GetBoundingHull().Outline( 0 );
108
109 BOOST_TEST_CONTEXT( "Initial courtyard" )
110 {
111 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
112 assertNoCourtyard( B_CrtYd );
113 }
114
115 const VECTOR2I moveVector = VECTOR2I( courtyardW, 0 );
116
117 fp.Move( moveVector );
118 expectedCourtyard.Move( moveVector );
119 expectedHull.Move( moveVector );
120
121 BOOST_TEST_CONTEXT( "Moved courtyard" )
122 {
123 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
124 assertNoCourtyard( B_CrtYd );
125 assertHullMatch( expectedHull );
126 }
127
128 fp.Rotate( VECTOR2I( 0, 0 ), EDA_ANGLE( 90.0 ) );
129 expectedCourtyard.Rotate( EDA_ANGLE( 90.0 ), VECTOR2I( 0, 0 ) );
130 expectedHull.Rotate( EDA_ANGLE( 90.0 ), VECTOR2I( 0, 0 ) );
131
132 BOOST_TEST_CONTEXT( "Rotated courtyard" )
133 {
134 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
135 assertNoCourtyard( B_CrtYd );
136 assertHullMatch( expectedHull );
137 }
138
140 expectedCourtyard.Mirror( VECTOR2I( 0, 0 ), FLIP_DIRECTION::LEFT_RIGHT );
141 expectedHull.Mirror( VECTOR2I( 0, 0 ), FLIP_DIRECTION::LEFT_RIGHT );
142
143 const BOX2I flippedExpectedBox = BOX2I::ByCorners( VECTOR2I( -courtyardW, 0 ), VECTOR2I( 0, courtyardH ) );
144
145 BOOST_TEST_CONTEXT( "Flipped courtyard" )
146 {
147 assertCourtyardMatches( B_CrtYd, expectedCourtyard );
148 assertNoCourtyard( F_CrtYd );
149 assertHullMatch( expectedHull );
150 }
151}
152
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition box2.h:70
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both).
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_CrtYd
Definition layer_ids.h:115
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:28
bool ChainsAreCyclicallyEqual(const SHAPE_LINE_CHAIN &aChainA, const SHAPE_LINE_CHAIN &aChainB, int aTol)
Check that two chains are cyclically equal.
Definition geometry.cpp:44
Utility functions for working with shapes.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static bool CourtyardEqualPredicate(const SHAPE_POLY_SET &a, const SHAPE_POLY_SET &b)
BOOST_TEST(contains==c.ExpectedContains)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
BOOST_TEST_CONTEXT("Test Clearance")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695