KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pns_basics.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#include <optional>
27
28#include <pcbnew/board.h>
29#include <pcbnew/pad.h>
30#include <pcbnew/pcb_track.h>
31
33#include <router/pns_item.h>
35#include <router/pns_node.h>
36#include <router/pns_router.h>
37#include <router/pns_segment.h>
38#include <router/pns_solid.h>
39#include <router/pns_via.h>
40
41static bool isCopper( const PNS::ITEM* aItem )
42{
43 if( !aItem )
44 return false;
45
46 BOARD_ITEM* parent = aItem->Parent();
47
48 if( parent && parent->Type() == PCB_PAD_T )
49 {
50 PAD* pad = static_cast<PAD*>( parent );
51
52 if( pad->IsAperturePad() || pad->IsNPTHWithNoCopper() )
53 return false;
54 }
55
56 return true;
57}
58
59
60static bool isHole( const PNS::ITEM* aItem )
61{
62 if( !aItem )
63 return false;
64
65 return aItem->OfKind( PNS::ITEM::HOLE_T );
66}
67
68
69static bool isEdge( const PNS::ITEM* aItem )
70{
71 if( !aItem )
72 return false;
73
74 const BOARD_ITEM *parent = aItem->BoardItem();
75
76 return parent && ( parent->IsOnLayer( Edge_Cuts ) || parent->IsOnLayer( Margin ) );
77}
78
79
81{
82public:
86
88
89 virtual int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB,
90 bool aUseClearanceEpsilon = true ) override
91 {
92 PNS::CONSTRAINT constraint;
93 int rv = 0;
94 PNS_LAYER_RANGE layers;
95
96 if( !aB )
97 layers = aA->Layers();
98 else if( isEdge( aA ) )
99 layers = aB->Layers();
100 else if( isEdge( aB ) )
101 layers = aA->Layers();
102 else
103 layers = aA->Layers().Intersection( aB->Layers() );
104
105 // Normalize layer range (no -1 magic numbers)
107
108 for( int layer = layers.Start(); layer <= layers.End(); ++layer )
109 {
110 if( isHole( aA ) && isHole( aB) )
111 {
112 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, layer, &constraint ) )
113 {
114 if( constraint.m_Value.Min() > rv )
115 rv = constraint.m_Value.Min();
116 }
117 }
118 else if( isHole( aA ) || isHole( aB ) )
119 {
120 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
121 {
122 if( constraint.m_Value.Min() > rv )
123 rv = constraint.m_Value.Min();
124 }
125 }
126 else if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
127 {
128 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
129 {
130 if( constraint.m_Value.Min() > rv )
131 rv = constraint.m_Value.Min();
132 }
133 }
134 else if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
135 {
136 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
137 {
138 if( constraint.m_Value.Min() > rv )
139 rv = constraint.m_Value.Min();
140 }
141 }
142 }
143
144 return rv;
145 }
146
147 virtual PNS::NET_HANDLE DpCoupledNet( PNS::NET_HANDLE aNet ) override { return nullptr; }
148 virtual int DpNetPolarity( PNS::NET_HANDLE aNet ) override { return -1; }
149
150 virtual bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
151 PNS::NET_HANDLE& aNetN ) override
152 {
153 return false;
154 }
155
156 virtual int NetCode( PNS::NET_HANDLE aNet ) override
157 {
158 return -1;
159 }
160
161 virtual wxString NetName( PNS::NET_HANDLE aNet ) override
162 {
163 return wxEmptyString;
164 }
165
166 virtual bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
167 const PNS::ITEM* aItemB, int aLayer,
168 PNS::CONSTRAINT* aConstraint ) override
169 {
170 ITEM_KEY key;
171
172 key.a = aItemA;
173 key.b = aItemB;
174 key.type = aType;
175
176 auto it = m_ruleMap.find( key );
177
178 if( it == m_ruleMap.end() )
179 {
180 int cl;
181 switch( aType )
182 {
186 default: return false;
187 }
188
189 //printf("GetDef %s %s %d cl %d\n", aItemA->KindStr().c_str(), aItemB->KindStr().c_str(), aType, cl );
190
191 aConstraint->m_Type = aType;
192 aConstraint->m_Value.SetMin( cl );
193
194 return true;
195 }
196 else
197 {
198 *aConstraint = it->second;
199 }
200
201 return true;
202 }
203
204 int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
205
206 struct ITEM_KEY
207 {
208 const PNS::ITEM* a = nullptr;
209 const PNS::ITEM* b = nullptr;
211
212 bool operator==( const ITEM_KEY& other ) const
213 {
214 return a == other.a && b == other.b && type == other.type;
215 }
216
217 bool operator<( const ITEM_KEY& other ) const
218 {
219 if( a < other.a )
220 {
221 return true;
222 }
223 else if ( a == other.a )
224 {
225 if( b < other.b )
226 return true;
227 else if ( b == other.b )
228 return type < other.type;
229 }
230
231 return false;
232 }
233 };
234
235 bool IsInNetTie( const PNS::ITEM* aA ) override { return false; }
236
237 bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
238 const PNS::ITEM* aCollidingItem ) override
239 {
240 return false;
241 }
242
243 bool IsDrilledHole( const PNS::ITEM* aItem ) override { return false; }
244
245 bool IsNonPlatedSlot( const PNS::ITEM* aItem ) override { return false; }
246
247 bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override
248 {
249 return false;
250 }
251
252 void AddMockRule( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
253 PNS::CONSTRAINT& aConstraint )
254 {
255 ITEM_KEY key;
256
257 key.a = aItemA;
258 key.b = aItemB;
259 key.type = aType;
260
261 m_ruleMap[key] = aConstraint;
262 }
263
264 int m_defaultClearance = 200000;
265 int m_defaultHole2Hole = 220000;
267
268private:
269 std::map<ITEM_KEY, PNS::CONSTRAINT> m_ruleMap;
271};
272
273struct PNS_TEST_FIXTURE;
274
276{
277public:
279 m_testFixture( aFixture )
280 {}
281
283
284 void HideItem( PNS::ITEM* aItem ) override {};
285 void DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit = false,
286 int aFlags = 0 ) override {};
288
289 bool TestInheritTrackWidth( PNS::ITEM* aItem, int* aInheritedWidth,
290 const VECTOR2I& aStartPosition = VECTOR2I() )
291 {
292 m_startLayer = aItem->Layer();
293 return inheritTrackWidth( aItem, aInheritedWidth, aStartPosition );
294 }
295
296private:
298};
299
300
316
317
322
323static void dumpObstacles( const PNS::NODE::OBSTACLES &obstacles )
324{
325 for( const PNS::OBSTACLE& obs : obstacles )
326 {
327 BOOST_TEST_MESSAGE( wxString::Format( "%p [%s] - %p [%s], clearance %d",
328 obs.m_head, obs.m_head->KindStr().c_str(),
329 obs.m_item, obs.m_item->KindStr().c_str(),
330 obs.m_clearance ) );
331 }
332}
333
335{
336 PNS::VIA* v1 = new PNS::VIA( VECTOR2I( 0, 1000000 ), PNS_LAYER_RANGE( F_Cu, B_Cu ), 50000, 10000 );
337 PNS::VIA* v2 = new PNS::VIA( VECTOR2I( 0, 2000000 ), PNS_LAYER_RANGE( F_Cu, B_Cu ), 50000, 10000 );
338
339 std::unique_ptr<PNS::NODE> world ( new PNS::NODE );
340
341 v1->SetNet( (PNS::NET_HANDLE) 1 );
342 v2->SetNet( (PNS::NET_HANDLE) 2 );
343
344 world->SetMaxClearance( 10000000 );
345 world->SetRuleResolver( &m_ruleResolver );
346
347 world->AddRaw( v1 );
348 world->AddRaw( v2 );
349
350 BOOST_TEST_MESSAGE( "via to via, no violations" );
351 {
352 PNS::NODE::OBSTACLES obstacles;
353 int count = world->QueryColliding( v1, obstacles );
354 dumpObstacles( obstacles );
355 BOOST_CHECK_EQUAL( obstacles.size(), 0 );
356 BOOST_CHECK_EQUAL( count, 0 );
357 }
358
359 BOOST_TEST_MESSAGE( "via to via, forced copper to copper violation" );
360 {
361 PNS::NODE::OBSTACLES obstacles;
362 m_ruleResolver.m_defaultClearance = 1000000;
363 world->QueryColliding( v1, obstacles );
364 dumpObstacles( obstacles );
365
366 BOOST_CHECK_EQUAL( obstacles.size(), 1 );
367 const auto& first = *obstacles.begin();
368
369 BOOST_CHECK_EQUAL( first.m_head, v1 );
370 BOOST_CHECK_EQUAL( first.m_item, v2 );
371 BOOST_CHECK_EQUAL( first.m_clearance, m_ruleResolver.m_defaultClearance );
372 }
373
374 BOOST_TEST_MESSAGE( "via to via, forced hole to hole violation" );
375 {
376 PNS::NODE::OBSTACLES obstacles;
377 m_ruleResolver.m_defaultClearance = 200000;
378 m_ruleResolver.m_defaultHole2Hole = 1000000;
379
380 world->QueryColliding( v1, obstacles );
381 dumpObstacles( obstacles );
382
383 BOOST_CHECK_EQUAL( obstacles.size(), 1 );
384 auto iter = obstacles.begin();
385 const auto& first = *iter++;
386
387 BOOST_CHECK_EQUAL( first.m_head, v1->Hole() );
388 BOOST_CHECK_EQUAL( first.m_item, v2->Hole() );
389 BOOST_CHECK_EQUAL( first.m_clearance, m_ruleResolver.m_defaultHole2Hole );
390 }
391
392 BOOST_TEST_MESSAGE( "via to via, forced copper to hole violation" );
393 {
394 PNS::NODE::OBSTACLES obstacles;
395 m_ruleResolver.m_defaultHole2Hole = 220000;
396 m_ruleResolver.m_defaultHole2Copper = 1000000;
397
398 world->QueryColliding( v1, obstacles );
399 dumpObstacles( obstacles );
400
401 BOOST_CHECK_EQUAL( obstacles.size(), 2 );
402 auto iter = obstacles.begin();
403 const auto& first = *iter++;
404
405 // There is no guarantee on what order the two collisions will be in...
406 BOOST_CHECK( ( first.m_head == v1 && first.m_item == v2->Hole() )
407 || ( first.m_head == v1->Hole() && first.m_item == v2 ) );
408
409 BOOST_CHECK_EQUAL( first.m_clearance, m_ruleResolver.m_defaultHole2Copper );
410 }
411}
412
413
414BOOST_FIXTURE_TEST_CASE( PNSViaBackdrillRetention, PNS_TEST_FIXTURE )
415{
416 PNS::VIA via( VECTOR2I( 1000, 2000 ), PNS_LAYER_RANGE( F_Cu, B_Cu ), 40000, 20000, nullptr,
418 via.SetHoleLayers( PNS_LAYER_RANGE( F_Cu, In2_Cu ) );
419 via.SetHolePostMachining( std::optional<PAD_DRILL_POST_MACHINING_MODE>( PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK ) );
420 via.SetSecondaryDrill( std::optional<int>( 12000 ) );
421 via.SetSecondaryHoleLayers( std::optional<PNS_LAYER_RANGE>( PNS_LAYER_RANGE( F_Cu, In1_Cu ) ) );
422 via.SetSecondaryHolePostMachining( std::optional<PAD_DRILL_POST_MACHINING_MODE>( PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED ) );
423
424 PNS::VIA viaCopy( via );
425 std::unique_ptr<PNS::VIA> viaClone( via.Clone() );
426
427 auto checkVia = [&]( const PNS::VIA& candidate )
428 {
429 BOOST_CHECK_EQUAL( candidate.HoleLayers().Start(), via.HoleLayers().Start() );
430 BOOST_CHECK_EQUAL( candidate.HoleLayers().End(), via.HoleLayers().End() );
431 BOOST_CHECK( candidate.HolePostMachining().has_value() );
432 BOOST_CHECK( candidate.HolePostMachining().value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK );
433 BOOST_CHECK( candidate.SecondaryDrill().has_value() );
434 BOOST_CHECK_EQUAL( candidate.SecondaryDrill().value(), via.SecondaryDrill().value() );
435 BOOST_CHECK( candidate.SecondaryHoleLayers().has_value() );
436 BOOST_CHECK_EQUAL( candidate.SecondaryHoleLayers()->Start(),
437 via.SecondaryHoleLayers()->Start() );
438 BOOST_CHECK_EQUAL( candidate.SecondaryHoleLayers()->End(),
439 via.SecondaryHoleLayers()->End() );
440 BOOST_CHECK( candidate.SecondaryHolePostMachining().has_value() );
441
442 // run this BOOST_CHECK only if possible to avoid crash
443 if( candidate.SecondaryHolePostMachining().has_value() )
444 BOOST_CHECK( candidate.SecondaryHolePostMachining().value() == via.SecondaryHolePostMachining().value() );
445 };
446
447 checkVia( viaCopy );
448 checkVia( *viaClone );
449}
450
451
452BOOST_AUTO_TEST_CASE( PCBViaBackdrillCloneRetainsData )
453{
454 BOARD board;
455 PCB_VIA via( &board );
456
457 via.SetPrimaryDrillStartLayer( F_Cu );
458 via.SetPrimaryDrillEndLayer( B_Cu );
459 via.SetFrontPostMachining( std::optional<PAD_DRILL_POST_MACHINING_MODE>( PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK ) );
460 via.SetSecondaryDrillSize( std::optional<int>( 15000 ) );
461 via.SetSecondaryDrillStartLayer( F_Cu );
462 via.SetSecondaryDrillEndLayer( In2_Cu );
463
464 via.SetBackPostMachining( std::optional<PAD_DRILL_POST_MACHINING_MODE>( PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE ) );
465 via.SetTertiaryDrillSize( std::optional<int>( 8000 ) );
466 via.SetTertiaryDrillStartLayer( B_Cu );
467 via.SetTertiaryDrillEndLayer( In4_Cu );
468
469 PCB_VIA viaCopy( via );
470 std::unique_ptr<PCB_VIA> viaClone( static_cast<PCB_VIA*>( via.Clone() ) );
471
472 auto checkVia = [&]( const PCB_VIA& candidate )
473 {
474 BOOST_CHECK_EQUAL( candidate.GetPrimaryDrillStartLayer(), via.GetPrimaryDrillStartLayer() );
475 BOOST_CHECK_EQUAL( candidate.GetPrimaryDrillEndLayer(), via.GetPrimaryDrillEndLayer() );
476 BOOST_CHECK( candidate.GetFrontPostMachining().has_value() );
477 BOOST_CHECK_EQUAL( static_cast<int>( candidate.GetFrontPostMachining().value() ),
478 static_cast<int>( via.GetFrontPostMachining().value() ) );
479 BOOST_CHECK( candidate.GetSecondaryDrillSize().has_value() );
480 BOOST_CHECK_EQUAL( candidate.GetSecondaryDrillSize().value(),
481 via.GetSecondaryDrillSize().value() );
482 BOOST_CHECK_EQUAL( candidate.GetSecondaryDrillStartLayer(),
483 via.GetSecondaryDrillStartLayer() );
484 BOOST_CHECK_EQUAL( candidate.GetSecondaryDrillEndLayer(),
485 via.GetSecondaryDrillEndLayer() );
486
487 BOOST_CHECK( candidate.GetBackPostMachining().has_value() );
488 BOOST_CHECK_EQUAL( static_cast<int>( candidate.GetBackPostMachining().value() ),
489 static_cast<int>( via.GetBackPostMachining().value() ) );
490 BOOST_CHECK( candidate.GetTertiaryDrillSize().has_value() );
491 BOOST_CHECK_EQUAL( candidate.GetTertiaryDrillSize().value(),
492 via.GetTertiaryDrillSize().value() );
493 BOOST_CHECK_EQUAL( candidate.GetTertiaryDrillStartLayer(),
494 via.GetTertiaryDrillStartLayer() );
495 BOOST_CHECK_EQUAL( candidate.GetTertiaryDrillEndLayer(),
496 via.GetTertiaryDrillEndLayer() );
497 };
498
499 checkVia( viaCopy );
500 checkVia( *viaClone );
501}
502
503
512BOOST_AUTO_TEST_CASE( PNSLayerRangeSwapBehavior )
513{
514 // On a 2-layer board with FRONT_INNER_BACK mode, BoardCopperLayerCount() returns 2.
515 // The code would calculate PNS_LAYER_RANGE(1, 2 - 2) = PNS_LAYER_RANGE(1, 0)
516 // Since start > end, the constructor swaps them to (0, 1), which would span
517 // both F_Cu and B_Cu incorrectly.
518
519 PNS_LAYER_RANGE innerLayersRange2Layer( 1, 0 ); // What would happen on 2-layer board
520
521 // Verify the swap behavior that causes the bug
522 BOOST_CHECK_EQUAL( innerLayersRange2Layer.Start(), 0 );
523 BOOST_CHECK_EQUAL( innerLayersRange2Layer.End(), 1 );
524 BOOST_CHECK( innerLayersRange2Layer.Overlaps( 0 ) ); // F_Cu
525 BOOST_CHECK( innerLayersRange2Layer.Overlaps( 1 ) ); // B_Cu
526
527 // On a 4-layer board, inner layers are 1 and 2, so PNS_LAYER_RANGE(1, 4-2) = (1, 2)
528 PNS_LAYER_RANGE innerLayersRange4Layer( 1, 2 ); // Correct for 4-layer board
529
530 BOOST_CHECK_EQUAL( innerLayersRange4Layer.Start(), 1 );
531 BOOST_CHECK_EQUAL( innerLayersRange4Layer.End(), 2 );
532 BOOST_CHECK( !innerLayersRange4Layer.Overlaps( 0 ) ); // F_Cu - should not overlap
533 BOOST_CHECK( innerLayersRange4Layer.Overlaps( 1 ) ); // In1_Cu
534 BOOST_CHECK( innerLayersRange4Layer.Overlaps( 2 ) ); // In2_Cu
535 BOOST_CHECK( !innerLayersRange4Layer.Overlaps( 3 ) ); // B_Cu - should not overlap
536}
537
538
546BOOST_FIXTURE_TEST_CASE( PNSSegmentSplitPreservesLockedState, PNS_TEST_FIXTURE )
547{
548 std::unique_ptr<PNS::NODE> world( new PNS::NODE );
549 world->SetMaxClearance( 10000000 );
550 world->SetRuleResolver( &m_ruleResolver );
551
553
554 VECTOR2I segStart( 0, 0 );
555 VECTOR2I segEnd( 10000000, 0 );
556 VECTOR2I splitPt( 5000000, 0 );
557
558 PNS::SEGMENT* lockedSeg = new PNS::SEGMENT( SEG( segStart, segEnd ), net );
559 lockedSeg->SetWidth( 250000 );
560 lockedSeg->SetLayers( PNS_LAYER_RANGE( F_Cu ) );
561 lockedSeg->Mark( PNS::MK_LOCKED );
562
563 BOOST_CHECK( lockedSeg->IsLocked() );
564
565 world->AddRaw( lockedSeg );
566
567 // Clone the locked segment and set up two halves (simulating SplitAdjacentSegments)
568 std::unique_ptr<PNS::SEGMENT> clone1( PNS::Clone( *lockedSeg ) );
569 std::unique_ptr<PNS::SEGMENT> clone2( PNS::Clone( *lockedSeg ) );
570
571 clone1->SetEnds( segStart, splitPt );
572 clone2->SetEnds( splitPt, segEnd );
573
574 BOOST_CHECK_MESSAGE( clone1->IsLocked(),
575 "First half of split locked segment must retain locked state" );
576 BOOST_CHECK_MESSAGE( clone2->IsLocked(),
577 "Second half of split locked segment must retain locked state" );
578 BOOST_CHECK_EQUAL( clone1->Width(), lockedSeg->Width() );
579 BOOST_CHECK_EQUAL( clone2->Width(), lockedSeg->Width() );
580}
581
582
590BOOST_FIXTURE_TEST_CASE( PNSInheritTrackWidthCursorProximity, PNS_TEST_FIXTURE )
591{
592 std::unique_ptr<PNS::NODE> world( new PNS::NODE );
593 world->SetMaxClearance( 10000000 );
594 world->SetRuleResolver( &m_ruleResolver );
595
596 VECTOR2I padPos( 0, 0 );
598
599 // Pad at origin with a small circular shape
601 pad->SetShape( new SHAPE_CIRCLE( padPos, 500000 ) );
602 pad->SetPos( padPos );
603 pad->SetLayers( PNS_LAYER_RANGE( F_Cu ) );
604 pad->SetNet( net );
605 world->AddRaw( pad );
606
607 // Narrow track going right (250um width)
608 int narrowWidth = 250000;
609 PNS::SEGMENT* narrowSeg = new PNS::SEGMENT( SEG( padPos, VECTOR2I( 5000000, 0 ) ), net );
610 narrowSeg->SetWidth( narrowWidth );
611 narrowSeg->SetLayers( PNS_LAYER_RANGE( F_Cu ) );
612 world->AddRaw( narrowSeg );
613
614 // Wide track going up (500um width)
615 int wideWidth = 500000;
616 PNS::SEGMENT* wideSeg = new PNS::SEGMENT( SEG( padPos, VECTOR2I( 0, -5000000 ) ), net );
617 wideSeg->SetWidth( wideWidth );
618 wideSeg->SetLayers( PNS_LAYER_RANGE( F_Cu ) );
619 world->AddRaw( wideSeg );
620
621 int inherited = 0;
622
623 // Without cursor position, should fall back to minimum width
624 BOOST_CHECK( m_iface->TestInheritTrackWidth( pad, &inherited ) );
625 BOOST_CHECK_EQUAL( inherited, narrowWidth );
626
627 // Cursor near the narrow track (to the right) should select narrow width
628 inherited = 0;
629 BOOST_CHECK( m_iface->TestInheritTrackWidth( pad, &inherited, VECTOR2I( 2000000, 0 ) ) );
630 BOOST_CHECK_EQUAL( inherited, narrowWidth );
631
632 // Cursor near the wide track (upward) should select wide width
633 inherited = 0;
634 BOOST_CHECK( m_iface->TestInheritTrackWidth( pad, &inherited, VECTOR2I( 0, -2000000 ) ) );
635 BOOST_CHECK_EQUAL( inherited, wideWidth );
636
637 // Cursor slightly offset toward narrow track should still select narrow
638 inherited = 0;
639 BOOST_CHECK( m_iface->TestInheritTrackWidth( pad, &inherited, VECTOR2I( 100000, 50000 ) ) );
640 BOOST_CHECK_EQUAL( inherited, narrowWidth );
641
642 // Cursor slightly offset toward wide track should select wide
643 inherited = 0;
644 BOOST_CHECK( m_iface->TestInheritTrackWidth( pad, &inherited, VECTOR2I( 50000, -100000 ) ) );
645 BOOST_CHECK_EQUAL( inherited, wideWidth );
646}
647
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:319
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
T Min() const
Definition minoptmax.h:33
void SetMin(T v)
Definition minoptmax.h:41
PNS::RULE_RESOLVER * GetRuleResolver() override
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
void HideItem(PNS::ITEM *aItem) override
MOCK_PNS_KICAD_IFACE(PNS_TEST_FIXTURE *aFixture)
PNS_TEST_FIXTURE * m_testFixture
bool TestInheritTrackWidth(PNS::ITEM *aItem, int *aInheritedWidth, const VECTOR2I &aStartPosition=VECTOR2I())
virtual int NetCode(PNS::NET_HANDLE aNet) override
bool IsNetTieExclusion(const PNS::ITEM *aItem, const VECTOR2I &aCollisionPos, const PNS::ITEM *aCollidingItem) override
bool IsKeepout(const PNS::ITEM *aObstacle, const PNS::ITEM *aItem, bool *aEnforce) override
virtual int Clearance(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aUseClearanceEpsilon=true) override
virtual bool QueryConstraint(PNS::CONSTRAINT_TYPE aType, const PNS::ITEM *aItemA, const PNS::ITEM *aItemB, int aLayer, PNS::CONSTRAINT *aConstraint) override
bool IsInNetTie(const PNS::ITEM *aA) override
std::map< ITEM_KEY, PNS::CONSTRAINT > m_ruleMap
virtual PNS::NET_HANDLE DpCoupledNet(PNS::NET_HANDLE aNet) override
bool IsDrilledHole(const PNS::ITEM *aItem) override
void AddMockRule(PNS::CONSTRAINT_TYPE aType, const PNS::ITEM *aItemA, const PNS::ITEM *aItemB, PNS::CONSTRAINT &aConstraint)
bool IsNonPlatedSlot(const PNS::ITEM *aItem) override
virtual bool DpNetPair(const PNS::ITEM *aItem, PNS::NET_HANDLE &aNetP, PNS::NET_HANDLE &aNetN) override
virtual wxString NetName(PNS::NET_HANDLE aNet) override
int ClearanceEpsilon() const override
virtual int DpNetPolarity(PNS::NET_HANDLE aNet) override
Definition pad.h:55
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * Parent() const
Definition pns_item.h:199
void SetLayers(const PNS_LAYER_RANGE &aLayers)
Definition pns_item.h:213
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual int Layer() const
Definition pns_item.h:216
bool OfKind(int aKindMask) const
Definition pns_item.h:181
virtual void Mark(int aMarker) const
Definition pns_item.h:261
virtual BOARD_ITEM * BoardItem() const
Definition pns_item.h:207
bool IsLocked() const
Definition pns_item.h:278
Keep the router "world" - i.e.
Definition pns_node.h:240
std::set< OBSTACLE > OBSTACLES
Definition pns_node.h:252
int Width() const override
Definition pns_segment.h:88
void SetWidth(int aWidth) override
Definition pns_segment.h:83
bool inheritTrackWidth(PNS::ITEM *aItem, int *aInheritedWidth, const VECTOR2I &aStartPosition)
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
int End() const
PNS_LAYER_RANGE Intersection(const PNS_LAYER_RANGE &aOther) const
Shortcut for comparisons/overlap tests.
Definition seg.h:42
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:174
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ In2_Cu
Definition layer_ids.h:67
@ Margin
Definition layer_ids.h:113
@ In4_Cu
Definition layer_ids.h:69
@ In1_Cu
Definition layer_ids.h:66
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:171
@ F_Cu
Definition layer_ids.h:64
CONSTRAINT_TYPE
Definition pns_node.h:52
void * NET_HANDLE
Definition pns_item.h:55
@ MK_LOCKED
Definition pns_item.h:45
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
Definition pns_item.h:344
@ THROUGH
Definition pcb_track.h:68
bool operator<(const ITEM_KEY &other) const
bool operator==(const ITEM_KEY &other) const
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:73
MINOPTMAX< int > m_Value
Definition pns_node.h:75
CONSTRAINT_TYPE m_Type
Definition pns_node.h:74
Hold an object colliding with another object, along with some useful data about the collision.
Definition pns_node.h:88
SETTINGS_MANAGER m_settingsManager
MOCK_RULE_RESOLVER m_ruleResolver
PNS::ROUTER * m_router
MOCK_PNS_KICAD_IFACE * m_iface
VECTOR3I v1(5, 5, 5)
static bool isEdge(const PNS::ITEM *aItem)
static bool isHole(const PNS::ITEM *aItem)
static void dumpObstacles(const PNS::NODE::OBSTACLES &obstacles)
BOOST_FIXTURE_TEST_CASE(PNSHoleCollisions, PNS_TEST_FIXTURE)
static bool isCopper(const PNS::ITEM *aItem)
BOOST_AUTO_TEST_CASE(PCBViaBackdrillCloneRetainsData)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2I v2(1, 0)
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695