KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_zone.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>
24#include <collectors.h>
25#include <footprint.h>
26#include <geometry/shape_arc.h>
30#include <netinfo.h>
31#include <pad.h>
32#include <padstack.h>
33#include <pcb_painter.h>
34#include <pcb_track.h>
35#include <zone.h>
36#include <zone_utils.h>
37
38
43
44
45static std::unique_ptr<ZONE> CreateSquareZone( BOARD_ITEM_CONTAINER& aParent, PCB_LAYER_ID aLayer,
46 const VECTOR2I& aOrigin, const VECTOR2I& aSize )
47{
48 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( &aParent );
49 zone->SetLayer( aLayer );
50
51 std::unique_ptr<SHAPE_POLY_SET> outline = std::make_unique<SHAPE_POLY_SET>();
52 outline->AddOutline( KIGEOM::BoxToLineChain( BOX2I( aOrigin, aSize ) ) );
53
54 zone->SetOutline( outline.release() );
55
56 return zone;
57}
58
59
63static std::unique_ptr<ZONE> CreateSimilarZone( BOARD_ITEM_CONTAINER& aParent, PCB_LAYER_ID aLayer, const ZONE& aOther )
64{
65 auto zone = std::make_unique<ZONE>( &aParent );
66 zone->SetLayer( aLayer );
67
68 std::unique_ptr<SHAPE_POLY_SET> outline = std::make_unique<SHAPE_POLY_SET>( *aOther.Outline() );
69 zone->SetOutline( outline.release() );
70
71 return zone;
72}
73
74
75BOOST_FIXTURE_TEST_SUITE( Zone, ZONE_TEST_FIXTURE )
76
78{
79 ZONE zone( &m_board );
80
81 zone.SetLayer( F_Cu );
82
83 BOOST_TEST( zone.GetLayer() == F_Cu );
84 BOOST_TEST( zone.GetLayer() == zone.GetFirstLayer() );
85
86 BOOST_TEST( zone.IsOnCopperLayer() == true );
87}
88
89BOOST_AUTO_TEST_CASE( MultipleLayers )
90{
91 ZONE zone( &m_board );
92
93 zone.SetLayerSet( { F_Cu, B_Cu } );
94
95 // There is no "the" layer in a multi-layer zone
97 // ... but there is a first layer
98 BOOST_TEST( zone.GetFirstLayer() == F_Cu );
99
100 BOOST_TEST( zone.IsOnCopperLayer() == true );
101}
102
109BOOST_AUTO_TEST_CASE( RescuedLayers )
110{
111 ZONE zone( &m_board );
112
113 zone.SetLayer( Rescue );
114
115 BOOST_TEST( zone.GetLayer() == Rescue );
116 BOOST_TEST( zone.GetLayer() == zone.GetFirstLayer() );
117
118 BOOST_TEST( zone.IsOnCopperLayer() == false );
119}
120
131BOOST_AUTO_TEST_CASE( CircleZoneCutoutRoundTrip )
132{
133 // Build a circular zone outline the same way convert_tool.cpp does for CIRCLE shapes
134 VECTOR2I center( 0, 0 );
135 int radius = pcbIUScale.mmToIU( 10.0 );
136 SHAPE_ARC fullCircle( center - VECTOR2I( radius, 0 ), center + VECTOR2I( radius, 0 ),
137 center - VECTOR2I( radius, 0 ), 0 );
138
139 SHAPE_POLY_SET sourceOutline;
140 sourceOutline.NewOutline();
141 sourceOutline.Append( fullCircle );
142
143 BOOST_TEST_REQUIRE( sourceOutline.ArcCount() > 0 );
144 double sourceArea = sourceOutline.Area();
145 BOOST_TEST_REQUIRE( sourceArea > 0.0 );
146
147 // Draw a small rectangular cutout well inside the circle
148 SHAPE_POLY_SET cutoutOutline;
149 cutoutOutline.NewOutline();
150 int cutoutHalf = pcbIUScale.mmToIU( 1.0 );
151 cutoutOutline.Append( VECTOR2I( -cutoutHalf, -cutoutHalf ) );
152 cutoutOutline.Append( VECTOR2I( cutoutHalf, -cutoutHalf ) );
153 cutoutOutline.Append( VECTOR2I( cutoutHalf, cutoutHalf ) );
154 cutoutOutline.Append( VECTOR2I( -cutoutHalf, cutoutHalf ) );
155
156 // Mirror the fix applied in ZONE_CREATE_HELPER::performZoneCutout: drop arcs before
157 // the boolean so the saved outline cannot reference stale arc endpoints.
158 SHAPE_POLY_SET working( sourceOutline );
159 working.ClearArcs();
160
161 SHAPE_POLY_SET cutout( cutoutOutline );
162 cutout.ClearArcs();
163
164 working.BooleanSubtract( cutout );
165
166 BOOST_TEST( working.ArcCount() == 0 );
167 BOOST_TEST_REQUIRE( working.OutlineCount() == 1 );
168 BOOST_TEST_REQUIRE( working.HoleCount( 0 ) == 1 );
169
170 double expectedArea = sourceArea - cutoutOutline.Area();
171 BOOST_CHECK_CLOSE( working.Area(), expectedArea, 0.1 );
172
173 // Outline must be a simple closed curve with reasonable point count
174 const SHAPE_LINE_CHAIN& outerChain = working.COutline( 0 );
175 BOOST_TEST( outerChain.IsClosed() );
176 BOOST_TEST( outerChain.PointCount() >= 8 );
177 BOOST_TEST( outerChain.SelfIntersecting().has_value() == false );
178
179 const SHAPE_LINE_CHAIN& holeChain = working.CHole( 0, 0 );
180 BOOST_TEST( holeChain.IsClosed() );
181 BOOST_TEST( holeChain.PointCount() == 4 );
182}
183
190BOOST_AUTO_TEST_CASE( EmptyZoneGetPosition )
191{
192 ZONE zone( &m_board );
193 zone.SetLayer( F_Cu );
194
195 BOOST_TEST( zone.GetNumCorners() == 0 );
196 BOOST_CHECK_NO_THROW( zone.GetPosition() );
197 BOOST_TEST( zone.GetPosition() == VECTOR2I( 0, 0 ) );
198}
199
200
201BOOST_AUTO_TEST_CASE( ZoneMergeNull )
202{
203 std::vector<std::unique_ptr<ZONE>> zones;
204
205 zones.emplace_back( std::make_unique<ZONE>( &m_board ) );
206 zones.back()->SetLayer( F_Cu );
207
208 zones.emplace_back( std::make_unique<ZONE>( &m_board ) );
209 zones.back()->SetLayer( F_Cu );
210
211 std::vector<std::unique_ptr<ZONE>> merged = MergeZonesWithSameOutline( std::move( zones ) );
212
213 // They are the same, so they do merge
214 BOOST_TEST( merged.size() == 1 );
215}
216
217
218BOOST_AUTO_TEST_CASE( ZoneMergeNonNullNoMerge )
219{
220 std::vector<std::unique_ptr<ZONE>> zones;
221
222 zones.emplace_back( CreateSquareZone( m_board, F_Cu, VECTOR2I( 0, 0 ), VECTOR2I( 100, 100 ) ) );
223 zones.emplace_back( CreateSquareZone( m_board, B_Cu, VECTOR2I( 200, 200 ), VECTOR2I( 300, 300 ) ) );
224
225 std::vector<std::unique_ptr<ZONE>> merged = MergeZonesWithSameOutline( std::move( zones ) );
226
227 // They are different, so they don't merge
228 BOOST_TEST( merged.size() == 2 );
229}
230
231
232BOOST_AUTO_TEST_CASE( ZoneMergeNonNullMerge )
233{
234 std::vector<std::unique_ptr<ZONE>> zones;
235
236 zones.emplace_back( CreateSquareZone( m_board, F_Cu, VECTOR2I( 0, 0 ), VECTOR2I( 100, 100 ) ) );
237 zones.emplace_back( CreateSimilarZone( m_board, B_Cu, *zones.back() ) );
238
239 std::vector<std::unique_ptr<ZONE>> merged = MergeZonesWithSameOutline( std::move( zones ) );
240
241 // They are the same, so they do merge
242 BOOST_REQUIRE( merged.size() == 1 );
243
244 BOOST_TEST( merged[0]->GetLayerSet() == ( LSET{ F_Cu, B_Cu } ) );
245 BOOST_TEST( merged[0]->GetNumCorners() == 4 );
246}
247
248
249BOOST_AUTO_TEST_CASE( ZoneMergeMergeSameGeomDifferentOrder )
250{
251 std::vector<std::unique_ptr<ZONE>> zones;
252
253 zones.emplace_back( CreateSquareZone( m_board, F_Cu, VECTOR2I( 0, 0 ), VECTOR2I( 100, 100 ) ) );
254 zones.emplace_back( CreateSimilarZone( m_board, B_Cu, *zones.back() ) );
255
256 // Reverse the outline of one of them
257 // Don't go overboard here - detailed tests of CompareGeometry
258 // should be in the SHAPE_LINE_CHAIN tests.
259 auto newPolyB = std::make_unique<SHAPE_POLY_SET>( *zones.back()->Outline() );
260 newPolyB->Outline( 0 ).Reverse();
261 zones.back()->SetOutline( newPolyB.release() );
262
263 std::vector<std::unique_ptr<ZONE>> merged = MergeZonesWithSameOutline( std::move( zones ) );
264
265 // They are the same, so they do merge
266 BOOST_REQUIRE( merged.size() == 1 );
267
268 BOOST_TEST( merged[0]->GetLayerSet() == LSET( { F_Cu, B_Cu } ) );
269 BOOST_TEST( merged[0]->GetNumCorners() == 4 );
270}
271
272static PCB_VIA* AddVia( BOARD& aBoard, const VECTOR2I& aPos, int aNetCode,
273 PCB_LAYER_ID aTopLayer = F_Cu, PCB_LAYER_ID aBotLayer = B_Cu )
274{
275 PCB_VIA* via = new PCB_VIA( &aBoard );
276 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
277 via->SetPosition( aPos );
278 via->SetLayerPair( aTopLayer, aBotLayer );
279 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
280 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
281 via->SetNetCode( aNetCode );
282 aBoard.Add( via );
283 return via;
284}
285
286
287static PAD* AddPadToBoard( BOARD& aBoard, const VECTOR2I& aPos, int aNetCode, PCB_LAYER_ID aLayer = F_Cu )
288{
289 FOOTPRINT* fp = new FOOTPRINT( &aBoard );
290 fp->SetPosition( aPos );
291 aBoard.Add( fp );
292
293 PAD* pad = new PAD( fp );
294 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
295 pad->SetPosition( aPos );
296 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.0 ) ) );
298 pad->SetLayerSet( LSET( { aLayer } ) );
299 pad->SetNetCode( aNetCode );
300 fp->Add( pad );
301 return pad;
302}
303
304
305BOOST_AUTO_TEST_CASE( AutoPriority_NonOverlapping )
306{
307 NETINFO_ITEM* netA = new NETINFO_ITEM( &m_board, wxT( "NetA" ) );
308 m_board.Add( netA );
309 NETINFO_ITEM* netB = new NETINFO_ITEM( &m_board, wxT( "NetB" ) );
310 m_board.Add( netB );
311
312 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
313 VECTOR2I( 0, 0 ),
314 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
315 zoneA->SetNetCode( netA->GetNetCode() );
316 zoneA->SetAssignedPriority( 5 );
317
318 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
319 VECTOR2I( pcbIUScale.mmToIU( 20 ), 0 ),
320 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
321 zoneB->SetNetCode( netB->GetNetCode() );
322 zoneB->SetAssignedPriority( 10 );
323
324 ZONE* ptrA = zoneA.get();
325 ZONE* ptrB = zoneB.get();
326 m_board.Add( zoneA.release() );
327 m_board.Add( zoneB.release() );
328
329 AutoAssignZonePriorities( &m_board );
330
332}
333
334
335BOOST_AUTO_TEST_CASE( AutoPriority_ItemCountWins )
336{
337 NETINFO_ITEM* netA = new NETINFO_ITEM( &m_board, wxT( "NetA" ) );
338 m_board.Add( netA );
339 NETINFO_ITEM* netB = new NETINFO_ITEM( &m_board, wxT( "NetB" ) );
340 m_board.Add( netB );
341
342 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
343 VECTOR2I( 0, 0 ),
344 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
345 zoneA->SetNetCode( netA->GetNetCode() );
346
347 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
348 VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ),
349 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
350 zoneB->SetNetCode( netB->GetNetCode() );
351
352 ZONE* ptrA = zoneA.get();
353 ZONE* ptrB = zoneB.get();
354 m_board.Add( zoneA.release() );
355 m_board.Add( zoneB.release() );
356
357 for( int i = 0; i < 5; i++ )
358 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 7 + i ), pcbIUScale.mmToIU( 10 ) ), netA->GetNetCode() );
359
360 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 7 ) ), netB->GetNetCode() );
361
362 AutoAssignZonePriorities( &m_board );
363
365}
366
367
368BOOST_AUTO_TEST_CASE( AutoPriority_SimilarCountsSmallerWins )
369{
370 NETINFO_ITEM* netA = new NETINFO_ITEM( &m_board, wxT( "NetA" ) );
371 m_board.Add( netA );
372 NETINFO_ITEM* netB = new NETINFO_ITEM( &m_board, wxT( "NetB" ) );
373 m_board.Add( netB );
374
375 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
376 VECTOR2I( 0, 0 ),
377 VECTOR2I( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 30 ) ) );
378 zoneA->SetNetCode( netA->GetNetCode() );
379
380 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
381 VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ),
382 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
383 zoneB->SetNetCode( netB->GetNetCode() );
384
385 ZONE* ptrA = zoneA.get();
386 ZONE* ptrB = zoneB.get();
387 m_board.Add( zoneA.release() );
388 m_board.Add( zoneB.release() );
389
390 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 ), pcbIUScale.mmToIU( 8 ) ), netA->GetNetCode() );
391 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 8 ) ), netA->GetNetCode() );
392 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 ), pcbIUScale.mmToIU( 12 ) ), netB->GetNetCode() );
393 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 12 ) ), netB->GetNetCode() );
394
395 AutoAssignZonePriorities( &m_board );
396
398}
399
400
401BOOST_AUTO_TEST_CASE( AutoPriority_MultiLayerAggregate )
402{
403 m_board.SetCopperLayerCount( 2 );
404
405 NETINFO_ITEM* netA = new NETINFO_ITEM( &m_board, wxT( "NetA" ) );
406 m_board.Add( netA );
407 NETINFO_ITEM* netB = new NETINFO_ITEM( &m_board, wxT( "NetB" ) );
408 m_board.Add( netB );
409
410 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
411 VECTOR2I( 0, 0 ),
412 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
413 zoneA->SetLayerSet( LSET( { F_Cu, B_Cu } ) );
414 zoneA->SetNetCode( netA->GetNetCode() );
415
416 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
417 VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ),
418 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
419 zoneB->SetLayerSet( LSET( { F_Cu, B_Cu } ) );
420 zoneB->SetNetCode( netB->GetNetCode() );
421
422 ZONE* ptrA = zoneA.get();
423 ZONE* ptrB = zoneB.get();
424 m_board.Add( zoneA.release() );
425 m_board.Add( zoneB.release() );
426
427 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 ), pcbIUScale.mmToIU( 8 ) ), netA->GetNetCode(), F_Cu, B_Cu );
428 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 8 ) ), netA->GetNetCode(), F_Cu, B_Cu );
429
430 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 ), pcbIUScale.mmToIU( 12 ) ), netB->GetNetCode(), F_Cu, B_Cu );
431 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), netB->GetNetCode(), F_Cu, B_Cu );
432 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 12 ) ), netB->GetNetCode(), F_Cu, B_Cu );
433
434 AutoAssignZonePriorities( &m_board );
435
437}
438
439
440BOOST_AUTO_TEST_CASE( AutoPriority_SameNetEqualPriority )
441{
442 NETINFO_ITEM* net = new NETINFO_ITEM( &m_board, wxT( "SharedNet" ) );
443 m_board.Add( net );
444
445 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
446 VECTOR2I( 0, 0 ),
447 VECTOR2I( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 30 ) ) );
448 zoneA->SetNetCode( net->GetNetCode() );
449
450 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
451 VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ),
452 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
453 zoneB->SetNetCode( net->GetNetCode() );
454
455 ZONE* ptrA = zoneA.get();
456 ZONE* ptrB = zoneB.get();
457 m_board.Add( zoneA.release() );
458 m_board.Add( zoneB.release() );
459
460 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 ), pcbIUScale.mmToIU( 8 ) ), net->GetNetCode() );
461 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 12 ) ), net->GetNetCode() );
462
463 AutoAssignZonePriorities( &m_board );
464
465 // Same-net overlapping zones are cooperative and must share equal priority
467}
468
469
470BOOST_AUTO_TEST_CASE( AutoPriority_EqualAreaNoChange )
471{
472 NETINFO_ITEM* netA = new NETINFO_ITEM( &m_board, wxT( "NetA" ) );
473 m_board.Add( netA );
474 NETINFO_ITEM* netB = new NETINFO_ITEM( &m_board, wxT( "NetB" ) );
475 m_board.Add( netB );
476
477 // Two identical-sized overlapping zones with no items in the overlap
478 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
479 VECTOR2I( 0, 0 ),
480 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
481 zoneA->SetNetCode( netA->GetNetCode() );
482 zoneA->SetAssignedPriority( 50 );
483
484 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
485 VECTOR2I( 0, 0 ),
486 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
487 zoneB->SetNetCode( netB->GetNetCode() );
488 zoneB->SetAssignedPriority( 50 );
489
490 ZONE* ptrA = zoneA.get();
491 ZONE* ptrB = zoneB.get();
492 m_board.Add( zoneA.release() );
493 m_board.Add( zoneB.release() );
494
495 bool changed = AutoAssignZonePriorities( &m_board );
496
497 // Equal areas, no items: no ordering evidence, priorities must not change
498 BOOST_TEST( changed == false );
499 BOOST_TEST( ptrA->GetAssignedPriority() == 50u );
500 BOOST_TEST( ptrB->GetAssignedPriority() == 50u );
501}
502
503
504BOOST_AUTO_TEST_CASE( AutoPriority_SameNetGroupInheritsEdge )
505{
506 NETINFO_ITEM* netGND = new NETINFO_ITEM( &m_board, wxT( "GND" ) );
507 m_board.Add( netGND );
508 NETINFO_ITEM* netVCC = new NETINFO_ITEM( &m_board, wxT( "VCC" ) );
509 m_board.Add( netVCC );
510
511 // Large GND zone (A) overlaps with small VCC zone (C).
512 // Small GND zone (B) overlaps with A but NOT with C.
513 // A should beat C (more items), and B should inherit A's priority.
514 std::unique_ptr<ZONE> zoneA = CreateSquareZone( m_board, F_Cu,
515 VECTOR2I( 0, 0 ),
516 VECTOR2I( pcbIUScale.mmToIU( 40 ), pcbIUScale.mmToIU( 40 ) ) );
517 zoneA->SetNetCode( netGND->GetNetCode() );
518
519 std::unique_ptr<ZONE> zoneB = CreateSquareZone( m_board, F_Cu,
520 VECTOR2I( pcbIUScale.mmToIU( 25 ), pcbIUScale.mmToIU( 25 ) ),
521 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
522 zoneB->SetNetCode( netGND->GetNetCode() );
523
524 std::unique_ptr<ZONE> zoneC = CreateSquareZone( m_board, F_Cu,
525 VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ),
526 VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
527 zoneC->SetNetCode( netVCC->GetNetCode() );
528
529 ZONE* ptrA = zoneA.get();
530 ZONE* ptrB = zoneB.get();
531 ZONE* ptrC = zoneC.get();
532 m_board.Add( zoneA.release() );
533 m_board.Add( zoneB.release() );
534 m_board.Add( zoneC.release() );
535
536 // GND items in the A/C overlap region
537 for( int i = 0; i < 4; i++ )
538 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 8 + i * 2 ), pcbIUScale.mmToIU( 10 ) ), netGND->GetNetCode() );
539
540 AddVia( m_board, VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 8 ) ), netVCC->GetNetCode() );
541
542 AutoAssignZonePriorities( &m_board );
543
544 // A beats C because GND has more items in the overlap
546
547 // B shares A's priority because they are same-net and overlap
549}
550
551
557{
558public:
559 bool IsLayerVisible( PCB_LAYER_ID ) const override { return true; }
560 PCB_LAYER_ID GetPreferredLayer() const override { return F_Cu; }
561 bool IgnoreLockedItems() const override { return false; }
562 bool IncludeSecondary() const override { return true; }
563 bool IgnoreFPTextOnBack() const override { return false; }
564 bool IgnoreFPTextOnFront() const override { return false; }
565 bool IgnoreFootprintsOnBack() const override { return false; }
566 bool IgnoreFootprintsOnFront() const override { return false; }
567 bool IgnorePadsOnBack() const override { return false; }
568 bool IgnorePadsOnFront() const override { return false; }
569 bool IgnoreThroughHolePads() const override { return false; }
570 bool IgnoreFPValues() const override { return false; }
571 bool IgnoreFPReferences() const override { return false; }
572 bool IgnoreThroughVias() const override { return false; }
573 bool IgnoreBlindBuriedVias() const override { return false; }
574 bool IgnoreMicroVias() const override { return false; }
575 bool IgnoreTracks() const override { return false; }
576 bool IgnoreZoneFills() const override { return true; }
577 bool IgnoreNoNets() const override { return false; }
578 int Accuracy() const override { return 0; }
579 double OnePixelInIU() const override { return 1.0; }
580};
581
582
589BOOST_AUTO_TEST_CASE( RuleAreaCoverageAreaNotZero )
590{
592 GENERAL_COLLECTOR collector;
593 collector.SetGuide( &guide );
594
595 std::unique_ptr<ZONE> ruleArea = CreateSquareZone( m_board, F_Cu,
596 VECTOR2I( 0, 0 ),
597 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
598 ruleArea->SetIsRuleArea( true );
599
600 double zoneArea = FOOTPRINT::GetCoverageArea( ruleArea.get(), collector );
601
602 // The rule area covers a 20 mm x 20 mm region. Its coverage area must reflect that, not 0.
603 BOOST_TEST( zoneArea > 0.0 );
604
605 double expected = (double) pcbIUScale.mmToIU( 20 ) * pcbIUScale.mmToIU( 20 );
606 BOOST_TEST( zoneArea == expected, boost::test_tools::tolerance( 0.001 ) );
607
608 // A small pad enclosed by the rule area must read as much smaller, so the disambiguation
609 // heuristic in GuessSelectionCandidates() will prefer it over the enclosing rule area.
610 PAD* pad = AddPadToBoard( m_board, VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), 0, F_Cu );
611
612 double padArea = FOOTPRINT::GetCoverageArea( pad, collector );
613
614 BOOST_TEST( padArea > 0.0 );
615 BOOST_TEST( padArea < zoneArea );
616}
617
618
623BOOST_AUTO_TEST_CASE( FilledZoneCoverageUsesFilledPolygons )
624{
626 GENERAL_COLLECTOR collector;
627 collector.SetGuide( &guide );
628
629 std::unique_ptr<ZONE> zone = CreateSquareZone( m_board, F_Cu,
630 VECTOR2I( 0, 0 ),
631 VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
632
633 // Fill only a small 2 mm x 2 mm island, far smaller than the 20 mm x 20 mm outline.
634 SHAPE_POLY_SET fill;
636 VECTOR2I( pcbIUScale.mmToIU( 2 ), pcbIUScale.mmToIU( 2 ) ) ) ) );
637 zone->SetFilledPolysList( F_Cu, fill );
638
639 double expected = (double) pcbIUScale.mmToIU( 2 ) * pcbIUScale.mmToIU( 2 );
640 BOOST_TEST( FOOTPRINT::GetCoverageArea( zone.get(), collector ) == expected,
641 boost::test_tools::tolerance( 0.001 ) );
642}
643
644
650BOOST_AUTO_TEST_CASE( RuleAreaOutlineDrawnAboveCopper )
651{
652 const int copperPass = F_Cu;
653 const int zonePass = ZONE_LAYER_FOR( F_Cu );
654
655 BOOST_TEST( KIGFX::ZoneOutlineDrawnOnLayer( true, zonePass ) );
656 BOOST_TEST( !KIGFX::ZoneOutlineDrawnOnLayer( true, copperPass ) );
657
658 BOOST_TEST( KIGFX::ZoneOutlineDrawnOnLayer( false, copperPass ) );
659 BOOST_TEST( !KIGFX::ZoneOutlineDrawnOnLayer( false, zonePass ) );
660}
661
662
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
Abstract interface for BOARD_ITEMs capable of storing other items inside.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1497
An abstract base class whose derivatives may be passed to a GENERAL_COLLECTOR telling it what should ...
Definition collectors.h:50
void SetPosition(const VECTOR2I &aPos) override
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:203
void SetGuide(const COLLECTORS_GUIDE *aGuide)
Record which COLLECTORS_GUIDE to use.
Definition collectors.h:287
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Handle the data for a net.
Definition netinfo.h:50
int GetNetCode() const
Definition netinfo.h:104
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const std::optional< INTERSECTION > SelfIntersecting() const
Check if the line chain is self-intersecting.
bool IsClosed() const override
int PointCount() const
Return the number of points (vertices) in this line chain.
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
double Area()
Return the area of this poly set.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int ArcCount() const
Count the number of arc shapes present.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Minimal COLLECTORS_GUIDE so GetCoverageArea() can be exercised headlessly.
bool IgnoreMicroVias() const override
bool IgnoreThroughHolePads() const override
bool IgnoreBlindBuriedVias() const override
bool IgnorePadsOnFront() const override
int Accuracy() const override
bool IgnoreFootprintsOnFront() const override
bool IgnoreFPReferences() const override
bool IgnoreTracks() const override
bool IgnoreFPTextOnFront() const override
bool IgnoreNoNets() const override
bool IsLayerVisible(PCB_LAYER_ID) const override
bool IgnoreFootprintsOnBack() const override
PCB_LAYER_ID GetPreferredLayer() const override
bool IgnoreZoneFills() const override
bool IncludeSecondary() const override
Determine if the secondary criteria or 2nd choice items should be included.
bool IgnoreThroughVias() const override
bool IgnoreFPValues() const override
double OnePixelInIU() const override
bool IgnorePadsOnBack() const override
bool IgnoreLockedItems() const override
bool IgnoreFPTextOnBack() const override
Handle a list of polygons defining a copper zone.
Definition zone.h:70
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition zone.cpp:574
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
SHAPE_POLY_SET * Outline()
Definition zone.h:418
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:666
VECTOR2I GetPosition() const override
Definition zone.cpp:565
bool IsOnCopperLayer() const override
Definition zone.cpp:616
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:596
unsigned GetAssignedPriority() const
Definition zone.h:122
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:610
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ Rescue
Definition layer_ids.h:117
@ F_Cu
Definition layer_ids.h:60
#define ZONE_LAYER_FOR(boardLayer)
Definition layer_ids.h:387
SHAPE_LINE_CHAIN BoxToLineChain(const BOX2I &aBox)
bool ZoneOutlineDrawnOnLayer(bool aOutlineOnly, int aLayer)
Decide which GAL draw pass paints a zone's outline.
Utility functions for working with shapes.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
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)
VECTOR3I expected(15, 30, 45)
VECTOR2I center
int radius
static PCB_VIA * AddVia(BOARD &aBoard, const VECTOR2I &aPos, int aNetCode, PCB_LAYER_ID aTopLayer=F_Cu, PCB_LAYER_ID aBotLayer=B_Cu)
static std::unique_ptr< ZONE > CreateSquareZone(BOARD_ITEM_CONTAINER &aParent, PCB_LAYER_ID aLayer, const VECTOR2I &aOrigin, const VECTOR2I &aSize)
Definition test_zone.cpp:45
static std::unique_ptr< ZONE > CreateSimilarZone(BOARD_ITEM_CONTAINER &aParent, PCB_LAYER_ID aLayer, const ZONE &aOther)
Create a similar zone (same outline) on a different layer.
Definition test_zone.cpp:63
BOOST_AUTO_TEST_CASE(SingleLayer)
Definition test_zone.cpp:77
static PAD * AddPadToBoard(BOARD &aBoard, const VECTOR2I &aPos, int aNetCode, PCB_LAYER_ID aLayer=F_Cu)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
std::vector< std::unique_ptr< ZONE > > MergeZonesWithSameOutline(std::vector< std::unique_ptr< ZONE > > &&aZones)
Merges zones with identical outlines and nets on different layers into single multi-layer zones.
bool AutoAssignZonePriorities(BOARD *aBoard, PROGRESS_REPORTER *aReporter)
Automatically assign zone priorities based on connectivity analysis of overlapping regions.