KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_keepout.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) 2025 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>
29#include <board.h>
30#include <zone.h>
31
32using namespace PADS_IO;
33
34
35BOOST_AUTO_TEST_SUITE( PadsKeepoutParsing )
36
37
38BOOST_AUTO_TEST_CASE( KeepoutStruct_DefaultConstruction )
39{
40 KEEPOUT keepout;
41 BOOST_CHECK( keepout.outline.empty() );
42 BOOST_CHECK( keepout.layers.empty() );
43 BOOST_CHECK_EQUAL( static_cast<int>( keepout.type ), static_cast<int>( KEEPOUT_TYPE::ALL ) );
44 BOOST_CHECK( keepout.no_traces );
45 BOOST_CHECK( keepout.no_vias );
46 BOOST_CHECK( keepout.no_copper );
47 BOOST_CHECK( !keepout.no_components );
48}
49
50
51BOOST_AUTO_TEST_CASE( KeepoutType_AllKeepout )
52{
53 KEEPOUT keepout;
54 keepout.type = KEEPOUT_TYPE::ALL;
55 keepout.no_traces = true;
56 keepout.no_vias = true;
57 keepout.no_copper = true;
58
59 BOOST_CHECK_EQUAL( static_cast<int>( keepout.type ), static_cast<int>( KEEPOUT_TYPE::ALL ) );
60 BOOST_CHECK( keepout.no_traces );
61 BOOST_CHECK( keepout.no_vias );
62 BOOST_CHECK( keepout.no_copper );
63}
64
65
66BOOST_AUTO_TEST_CASE( KeepoutType_ViaOnly )
67{
68 KEEPOUT keepout;
69 keepout.type = KEEPOUT_TYPE::VIA;
70 keepout.no_traces = false;
71 keepout.no_vias = true;
72 keepout.no_copper = false;
73
74 BOOST_CHECK_EQUAL( static_cast<int>( keepout.type ), static_cast<int>( KEEPOUT_TYPE::VIA ) );
75 BOOST_CHECK( !keepout.no_traces );
76 BOOST_CHECK( keepout.no_vias );
77 BOOST_CHECK( !keepout.no_copper );
78}
79
80
81BOOST_AUTO_TEST_CASE( KeepoutType_RouteOnly )
82{
83 KEEPOUT keepout;
84 keepout.type = KEEPOUT_TYPE::ROUTE;
85 keepout.no_traces = true;
86 keepout.no_vias = false;
87 keepout.no_copper = false;
88
89 BOOST_CHECK_EQUAL( static_cast<int>( keepout.type ), static_cast<int>( KEEPOUT_TYPE::ROUTE ) );
90 BOOST_CHECK( keepout.no_traces );
91 BOOST_CHECK( !keepout.no_vias );
92 BOOST_CHECK( !keepout.no_copper );
93}
94
95
96BOOST_AUTO_TEST_CASE( KeepoutType_PlacementOnly )
97{
98 KEEPOUT keepout;
100 keepout.no_traces = false;
101 keepout.no_vias = false;
102 keepout.no_copper = false;
103 keepout.no_components = true;
104
105 BOOST_CHECK_EQUAL( static_cast<int>( keepout.type ), static_cast<int>( KEEPOUT_TYPE::PLACEMENT ) );
106 BOOST_CHECK( !keepout.no_traces );
107 BOOST_CHECK( !keepout.no_vias );
108 BOOST_CHECK( !keepout.no_copper );
109 BOOST_CHECK( keepout.no_components );
110}
111
112
113BOOST_AUTO_TEST_CASE( KeepoutOutline_RectanglePoints )
114{
115 KEEPOUT keepout;
116 keepout.outline.emplace_back( 0, 0 );
117 keepout.outline.emplace_back( 100, 0 );
118 keepout.outline.emplace_back( 100, 100 );
119 keepout.outline.emplace_back( 0, 100 );
120
121 BOOST_REQUIRE_EQUAL( keepout.outline.size(), 4 );
122 BOOST_CHECK_EQUAL( keepout.outline[0].x, 0 );
123 BOOST_CHECK_EQUAL( keepout.outline[0].y, 0 );
124 BOOST_CHECK_EQUAL( keepout.outline[2].x, 100 );
125 BOOST_CHECK_EQUAL( keepout.outline[2].y, 100 );
126}
127
128
129BOOST_AUTO_TEST_CASE( KeepoutLayers_SingleLayer )
130{
131 KEEPOUT keepout;
132 keepout.layers.push_back( 1 );
133
134 BOOST_REQUIRE_EQUAL( keepout.layers.size(), 1 );
135 BOOST_CHECK_EQUAL( keepout.layers[0], 1 );
136}
137
138
139BOOST_AUTO_TEST_CASE( KeepoutLayers_MultipleLayers )
140{
141 KEEPOUT keepout;
142 keepout.layers.push_back( 1 );
143 keepout.layers.push_back( 2 );
144 keepout.layers.push_back( 4 );
145
146 BOOST_REQUIRE_EQUAL( keepout.layers.size(), 3 );
147 BOOST_CHECK_EQUAL( keepout.layers[0], 1 );
148 BOOST_CHECK_EQUAL( keepout.layers[1], 2 );
149 BOOST_CHECK_EQUAL( keepout.layers[2], 4 );
150}
151
152
153BOOST_AUTO_TEST_CASE( KeepoutLayers_AllLayers )
154{
155 // Empty layers vector means all layers
156 KEEPOUT keepout;
157
158 BOOST_CHECK( keepout.layers.empty() );
159}
160
161
162BOOST_AUTO_TEST_CASE( ParseKeepoutFile )
163{
164 wxString filename = KI_TEST::GetPcbnewTestDataDir() + "plugins/pads/keepout_test.asc";
165
166 PARSER parser;
167 parser.Parse( filename );
168
169 const auto& keepouts = parser.GetKeepouts();
170
171 BOOST_REQUIRE_EQUAL( keepouts.size(), 5 );
172
173 // Verify KEEPOUT (all restrictions)
174 bool found_keepout = false;
175
176 for( const auto& ko : keepouts )
177 {
178 if( ko.type == KEEPOUT_TYPE::ALL && ko.outline.size() == 4 )
179 {
180 found_keepout = true;
181 BOOST_CHECK( ko.no_traces );
182 BOOST_CHECK( ko.no_vias );
183 BOOST_CHECK( ko.no_copper );
184 break;
185 }
186 }
187
188 BOOST_CHECK( found_keepout );
189
190 // Verify RESTRICTVIA (via only)
191 bool found_via_restrict = false;
192
193 for( const auto& ko : keepouts )
194 {
195 if( ko.type == KEEPOUT_TYPE::VIA )
196 {
197 found_via_restrict = true;
198 BOOST_CHECK( !ko.no_traces );
199 BOOST_CHECK( ko.no_vias );
200 BOOST_CHECK( !ko.no_copper );
201 break;
202 }
203 }
204
205 BOOST_CHECK( found_via_restrict );
206
207 // Verify RESTRICTROUTE (routing only)
208 bool found_route_restrict = false;
209
210 for( const auto& ko : keepouts )
211 {
212 if( ko.type == KEEPOUT_TYPE::ROUTE )
213 {
214 found_route_restrict = true;
215 BOOST_CHECK( ko.no_traces );
216 BOOST_CHECK( !ko.no_vias );
217 BOOST_CHECK( !ko.no_copper );
218 break;
219 }
220 }
221
222 BOOST_CHECK( found_route_restrict );
223
224 // Verify RESTRICTAREA (all copper)
225 bool found_area_restrict = false;
226
227 for( const auto& ko : keepouts )
228 {
229 if( ko.type == KEEPOUT_TYPE::ALL && ko.outline.size() > 0 )
230 {
231 // This could be the general KEEPOUT or the RESTRICTAREA
232 // We need to verify we have at least one
233 found_area_restrict = true;
234 }
235 }
236
237 BOOST_CHECK( found_area_restrict );
238
239 // Verify PLACEMENT_KEEPOUT
240 bool found_placement = false;
241
242 for( const auto& ko : keepouts )
243 {
244 if( ko.type == KEEPOUT_TYPE::PLACEMENT )
245 {
246 found_placement = true;
247 BOOST_CHECK( !ko.no_traces );
248 BOOST_CHECK( !ko.no_vias );
249 BOOST_CHECK( !ko.no_copper );
250 BOOST_CHECK( ko.no_components );
251 break;
252 }
253 }
254
255 BOOST_CHECK( found_placement );
256}
257
258
259BOOST_AUTO_TEST_CASE( ParseKeepoutOutlineGeometry )
260{
261 wxString filename = KI_TEST::GetPcbnewTestDataDir() + "plugins/pads/keepout_test.asc";
262
263 PARSER parser;
264 parser.Parse( filename );
265
266 const auto& keepouts = parser.GetKeepouts();
267
268 // Find the first keepout with 4 points (the rectangular KEEPOUT)
269 const KEEPOUT* rect_keepout = nullptr;
270
271 for( const auto& ko : keepouts )
272 {
273 if( ko.type == KEEPOUT_TYPE::ALL && ko.outline.size() == 4 )
274 {
275 rect_keepout = &ko;
276 break;
277 }
278 }
279
280 BOOST_REQUIRE( rect_keepout != nullptr );
281
282 // File defines KEEPOUT_RECT at 100,100 with 4 corners relative to that:
283 // 0,0 / 200,0 / 200,200 / 0,200
284 // So absolute coordinates should be: 100,100 / 300,100 / 300,300 / 100,300
285 BOOST_REQUIRE_EQUAL( rect_keepout->outline.size(), 4 );
286
287 // The first point should be at (100, 100) in PADS coordinates
288 BOOST_CHECK_CLOSE( rect_keepout->outline[0].x, 100.0, 0.1 );
289 BOOST_CHECK_CLOSE( rect_keepout->outline[0].y, 100.0, 0.1 );
290
291 // The third point should be at (300, 300)
292 BOOST_CHECK_CLOSE( rect_keepout->outline[2].x, 300.0, 0.1 );
293 BOOST_CHECK_CLOSE( rect_keepout->outline[2].y, 300.0, 0.1 );
294}
295
296
297BOOST_AUTO_TEST_CASE( ImportKeepoutAsRuleArea )
298{
299 PCB_IO_PADS plugin;
300 wxString filename = KI_TEST::GetPcbnewTestDataDir() + "plugins/pads/keepout_test.asc";
301
302 std::unique_ptr<BOARD> board( plugin.LoadBoard( filename, nullptr, nullptr, nullptr ) );
303 BOOST_REQUIRE( board != nullptr );
304
305 // Count rule areas (keepout zones)
306 int ruleAreaCount = 0;
307 int allKeepoutCount = 0;
308 int viaKeepoutCount = 0;
309 int routeKeepoutCount = 0;
310 int placementKeepoutCount = 0;
311
312 for( ZONE* zone : board->Zones() )
313 {
314 if( zone->GetIsRuleArea() )
315 {
316 ruleAreaCount++;
317
318 if( zone->GetZoneName().StartsWith( wxT( "Keepout_" ) ) )
319 allKeepoutCount++;
320 else if( zone->GetZoneName().StartsWith( wxT( "ViaKeepout_" ) ) )
321 viaKeepoutCount++;
322 else if( zone->GetZoneName().StartsWith( wxT( "RouteKeepout_" ) ) )
323 routeKeepoutCount++;
324 else if( zone->GetZoneName().StartsWith( wxT( "PlacementKeepout_" ) ) )
325 placementKeepoutCount++;
326 }
327 }
328
329 // The test file should have 5 keepouts (KEEPOUT, RESTRICTVIA, RESTRICTROUTE, RESTRICTAREA, PLACEMENT_KEEPOUT)
330 BOOST_CHECK_EQUAL( ruleAreaCount, 5 );
331 BOOST_CHECK_EQUAL( allKeepoutCount, 2 ); // KEEPOUT and RESTRICTAREA both become Keepout_*
332 BOOST_CHECK_EQUAL( viaKeepoutCount, 1 );
333 BOOST_CHECK_EQUAL( routeKeepoutCount, 1 );
334 BOOST_CHECK_EQUAL( placementKeepoutCount, 1 );
335}
336
337
338BOOST_AUTO_TEST_CASE( KeepoutConstraintFlags )
339{
340 PCB_IO_PADS plugin;
341 wxString filename = KI_TEST::GetPcbnewTestDataDir() + "plugins/pads/keepout_test.asc";
342
343 std::unique_ptr<BOARD> board( plugin.LoadBoard( filename, nullptr, nullptr, nullptr ) );
344 BOOST_REQUIRE( board != nullptr );
345
346 // Find ViaKeepout and verify only vias are prohibited
347 ZONE* viaKeepout = nullptr;
348
349 for( ZONE* zone : board->Zones() )
350 {
351 if( zone->GetZoneName().StartsWith( wxT( "ViaKeepout_" ) ) )
352 {
353 viaKeepout = zone;
354 break;
355 }
356 }
357
358 BOOST_REQUIRE( viaKeepout != nullptr );
359 BOOST_CHECK( viaKeepout->GetDoNotAllowVias() );
360 BOOST_CHECK( !viaKeepout->GetDoNotAllowTracks() );
361 BOOST_CHECK( !viaKeepout->GetDoNotAllowZoneFills() );
362 BOOST_CHECK( !viaKeepout->GetDoNotAllowFootprints() );
363
364 // Find RouteKeepout and verify only tracks are prohibited
365 ZONE* routeKeepout = nullptr;
366
367 for( ZONE* zone : board->Zones() )
368 {
369 if( zone->GetZoneName().StartsWith( wxT( "RouteKeepout_" ) ) )
370 {
371 routeKeepout = zone;
372 break;
373 }
374 }
375
376 BOOST_REQUIRE( routeKeepout != nullptr );
377 BOOST_CHECK( routeKeepout->GetDoNotAllowTracks() );
378 BOOST_CHECK( !routeKeepout->GetDoNotAllowVias() );
379 BOOST_CHECK( !routeKeepout->GetDoNotAllowZoneFills() );
380 BOOST_CHECK( !routeKeepout->GetDoNotAllowFootprints() );
381
382 // Find PlacementKeepout and verify only footprints are prohibited
383 ZONE* placementKeepout = nullptr;
384
385 for( ZONE* zone : board->Zones() )
386 {
387 if( zone->GetZoneName().StartsWith( wxT( "PlacementKeepout_" ) ) )
388 {
389 placementKeepout = zone;
390 break;
391 }
392 }
393
394 BOOST_REQUIRE( placementKeepout != nullptr );
395 BOOST_CHECK( placementKeepout->GetDoNotAllowFootprints() );
396 BOOST_CHECK( !placementKeepout->GetDoNotAllowTracks() );
397 BOOST_CHECK( !placementKeepout->GetDoNotAllowVias() );
398 BOOST_CHECK( !placementKeepout->GetDoNotAllowZoneFills() );
399}
400
401
General utilities for PCB file IO for QA programs.
const std::vector< KEEPOUT > & GetKeepouts() const
void Parse(const wxString &aFileName)
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
Handle a list of polygons defining a copper zone.
Definition zone.h:73
bool GetDoNotAllowVias() const
Definition zone.h:730
bool GetDoNotAllowTracks() const
Definition zone.h:731
bool GetDoNotAllowFootprints() const
Definition zone.h:733
bool GetDoNotAllowZoneFills() const
Definition zone.h:729
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
@ ROUTE
Routing keepout (traces)
@ PLACEMENT
Component placement keepout.
A keepout area definition.
std::vector< ARC_POINT > outline
Keepout boundary.
bool no_vias
Prohibit vias (V restriction)
bool no_components
Prohibit component placement (P restriction)
bool no_copper
Prohibit copper pours (C restriction)
KEEPOUT_TYPE type
Type of keepout.
bool no_traces
Prohibit traces (R restriction)
std::vector< int > layers
Affected layers (empty = all)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(KeepoutStruct_DefaultConstruction)
BOOST_CHECK_EQUAL(result, "25.4")