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, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <board.h>
25#include <footprint.h>
26#include <pcb_shape.h>
27
28
29static bool CourtyardEqualPredicate( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
30{
31 // The courtyards get a tiny epsilon to handle polygonisaton errors
32 const int courtyardEpsilon = pcbIUScale.mmToIU( 0.005 );
33
34 if( a.OutlineCount() != b.OutlineCount() )
35 return false;
36
37 // We can only use this predicate on single-outline polys unless we do more work.
38 // Because we don't know the sub-outlines are in the same order.
39 BOOST_REQUIRE( a.OutlineCount() == 1 );
40
41 return KI_TEST::ChainsAreCyclicallyEqual( a.Outline( 0 ), b.Outline( 0 ), courtyardEpsilon );
42};
43
44
45BOOST_AUTO_TEST_SUITE( Footprint )
46
47
48BOOST_AUTO_TEST_CASE( FootprintCourtyardAndHull )
49{
50 // Footprint courtyards are cached internally. Some operations manipulate the
51 // cache efficiently, some rebuild it. In any case, the courtyard should always
52 // be consistent with the geometry of the footprint. Same for the bounding hull.
53
54 BOARD board;
55 FOOTPRINT fp( &board );
56
57 const int lineW = pcbIUScale.mmToIU( 0.05 );
58 const int courtyardH = pcbIUScale.mmToIU( 1.0 );
59 const int courtyardW = pcbIUScale.mmToIU( 2.0 );
60
61 const std::vector<VECTOR2I> courtyardPoints = {
62 { 0, 0 },
63 { courtyardW, 0 },
64 { courtyardW, courtyardH },
65 { 0, courtyardH },
66 };
67
68 const auto assertCourtyardMatches = [&]( PCB_LAYER_ID layer, const SHAPE_LINE_CHAIN& aExpectedCourtyard )
69 {
70 const SHAPE_POLY_SET& courtyard = fp.GetCourtyard( layer );
71
72 BOOST_REQUIRE( courtyard.OutlineCount() == 1 );
73 BOOST_CHECK_PREDICATE( CourtyardEqualPredicate, ( courtyard.Outline( 0 ) )( aExpectedCourtyard ) );
74 };
75
76 const auto assertNoCourtyard = [&]( PCB_LAYER_ID layer )
77 {
78 const SHAPE_POLY_SET& courtyard = fp.GetCourtyard( layer );
79
80 BOOST_TEST( courtyard.OutlineCount() == 0 );
81 };
82
83 const auto assertHullMatch = [&]( const SHAPE_LINE_CHAIN& aExpectedHull )
84 {
85 const SHAPE_POLY_SET& hull = fp.GetBoundingHull();
86
87 BOOST_REQUIRE( hull.OutlineCount() == 1 );
88 BOOST_CHECK_PREDICATE( KI_TEST::ChainsAreCyclicallyEqual, ( hull.Outline( 0 ) )(aExpectedHull) ( 0 ) );
89 };
90
91 {
92 std::unique_ptr<PCB_SHAPE> courtyardPoly = std::make_unique<PCB_SHAPE>( &fp, SHAPE_T::POLY );
93 courtyardPoly->SetLayer( F_CrtYd );
94 courtyardPoly->SetPolyPoints( courtyardPoints );
95 courtyardPoly->SetWidth( lineW );
96
97 fp.Add( courtyardPoly.release() );
98 }
99
100 // We'll modify this in lock-step with the footprint
101 SHAPE_LINE_CHAIN expectedCourtyard( courtyardPoints, true );
102 // The hull is hard to calculate - we'll take the initial one as a given
103 SHAPE_LINE_CHAIN expectedHull = fp.GetBoundingHull().Outline( 0 );
104
105 BOOST_TEST_CONTEXT( "Initial courtyard" )
106 {
107 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
108 assertNoCourtyard( B_CrtYd );
109 }
110
111 const VECTOR2I moveVector = VECTOR2I( courtyardW, 0 );
112
113 fp.Move( moveVector );
114 expectedCourtyard.Move( moveVector );
115 expectedHull.Move( moveVector );
116
117 BOOST_TEST_CONTEXT( "Moved courtyard" )
118 {
119 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
120 assertNoCourtyard( B_CrtYd );
121 assertHullMatch( expectedHull );
122 }
123
124 fp.Rotate( VECTOR2I( 0, 0 ), EDA_ANGLE( 90.0 ) );
125 expectedCourtyard.Rotate( EDA_ANGLE( 90.0 ), VECTOR2I( 0, 0 ) );
126 expectedHull.Rotate( EDA_ANGLE( 90.0 ), VECTOR2I( 0, 0 ) );
127
128 BOOST_TEST_CONTEXT( "Rotated courtyard" )
129 {
130 assertCourtyardMatches( F_CrtYd, expectedCourtyard );
131 assertNoCourtyard( B_CrtYd );
132 assertHullMatch( expectedHull );
133 }
134
136 expectedCourtyard.Mirror( VECTOR2I( 0, 0 ), FLIP_DIRECTION::LEFT_RIGHT );
137 expectedHull.Mirror( VECTOR2I( 0, 0 ), FLIP_DIRECTION::LEFT_RIGHT );
138
139 const BOX2I flippedExpectedBox = BOX2I::ByCorners( VECTOR2I( -courtyardW, 0 ), VECTOR2I( 0, courtyardH ) );
140
141 BOOST_TEST_CONTEXT( "Flipped courtyard" )
142 {
143 assertCourtyardMatches( B_CrtYd, expectedCourtyard );
144 assertNoCourtyard( F_CrtYd );
145 assertHullMatch( expectedHull );
146 }
147}
148
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition box2.h:66
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:56
@ F_CrtYd
Definition layer_ids.h:112
@ B_CrtYd
Definition layer_ids.h:111
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
bool ChainsAreCyclicallyEqual(const SHAPE_LINE_CHAIN &aChainA, const SHAPE_LINE_CHAIN &aChainB, int aTol)
Check that two chains are cyclically equal.
Definition geometry.cpp:40
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_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
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:683