KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drill_chart.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 3
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
21
22#include <filesystem>
23#include <set>
24
25#include <board.h>
26#include <eda_text.h>
27#include <i18n_utility.h>
29#include <footprint.h>
30#include <pad.h>
31#include <pcb_drill_chart.h>
32#include <pcb_table.h>
33#include <pcb_tablecell.h>
34#include <pcb_drill_map.h>
35#include <pcb_shape.h>
39#include <pcb_track.h>
40#include <base_units.h>
41#include <core/kicad_algo.h>
43#include <view/view.h>
45
46#include <google/protobuf/any.pb.h>
47#include <wx/filename.h>
48
49
50namespace
51{
52
54void buildHoles( BOARD& aBoard )
55{
56 aBoard.SetCopperLayerCount( 6 );
57
58 for( int i = 0; i < 2; ++i )
59 {
60 PCB_VIA* via = new PCB_VIA( &aBoard );
61 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
62 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( i * 5 ), 0 ) );
63 via->SetLayerPair( F_Cu, B_Cu );
64 via->SetDrill( pcbIUScale.mmToIU( 0.30 ) );
65 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.60 ) );
66 aBoard.Add( via );
67 }
68
69 PCB_VIA* big = new PCB_VIA( &aBoard );
71 big->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 20 ), 0 ) );
72 big->SetLayerPair( F_Cu, B_Cu );
73 big->SetDrill( pcbIUScale.mmToIU( 0.60 ) );
74 big->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 1.0 ) );
75 aBoard.Add( big );
76
77 FOOTPRINT* fp = new FOOTPRINT( &aBoard );
78 fp->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 30 ), 0 ) );
79
80 PAD* pad = new PAD( fp );
81 pad->SetAttribute( PAD_ATTRIB::NPTH );
82 pad->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 30 ), 0 ) );
83 pad->SetDrillSize( VECTOR2I( pcbIUScale.mmToIU( 3.2 ), pcbIUScale.mmToIU( 3.2 ) ) );
84 pad->SetSize( PADSTACK::ALL_LAYERS,
85 VECTOR2I( pcbIUScale.mmToIU( 3.2 ), pcbIUScale.mmToIU( 3.2 ) ) );
86 fp->Add( pad );
87 aBoard.Add( fp );
88}
89
90
91void buildOutline( BOARD& aBoard, const BOX2I& aBox )
92{
93 const VECTOR2I corners[] = {
94 aBox.GetOrigin(),
95 { aBox.GetRight(), aBox.GetTop() },
96 aBox.GetEnd(),
97 { aBox.GetLeft(), aBox.GetBottom() },
98 };
99
100 for( int ii = 0; ii < 4; ++ii )
101 {
102 PCB_SHAPE* edge = new PCB_SHAPE( &aBoard, SHAPE_T::SEGMENT );
103 edge->SetLayer( Edge_Cuts );
104 edge->SetStart( corners[ii] );
105 edge->SetEnd( corners[( ii + 1 ) % 4] );
106 aBoard.Add( edge );
107 }
108}
109
110
111int cellCount( const PCB_DRILL_CHART& aChart, const wxString& aText )
112{
113 int count = 0;
114
115 for( const PCB_TABLECELL* cell : aChart.GetCells() )
116 {
117 if( cell->GetText() == aText )
118 count++;
119 }
120
121 return count;
122}
123
124} // namespace
125
126
127BOOST_AUTO_TEST_SUITE( DrillChart )
128
129
130BOOST_AUTO_TEST_CASE( GroupsHolesBySizeAndPlating )
131{
132 BOARD board;
133 buildHoles( board );
134
135 PCB_DRILL_CHART chart( &board );
136 chart.RebuildCells( board );
137
138 // Heading, three groups (0.3 PTH, 0.6 PTH, 3.2 NPTH) and totals. No caption row
139 BOOST_CHECK_EQUAL( chart.GetRowCount(), 5 );
140
141 // Two vias share one size, so they collapse into a single row reporting two operations
142 BOOST_CHECK_EQUAL( cellCount( chart, wxT( "2" ) ), 1 );
143
144 BOOST_CHECK_EQUAL( cellCount( chart, wxT( "Yes" ) ), 2 );
145 BOOST_CHECK_EQUAL( cellCount( chart, wxT( "No" ) ), 1 );
146}
147
148
149BOOST_AUTO_TEST_CASE( RebuildKeepsCellIdentity )
150{
151 BOARD board;
152 buildHoles( board );
153
154 PCB_DRILL_CHART chart( &board );
155 chart.RebuildCells( board );
156
157 std::vector<KIID> before;
158
159 for( const PCB_TABLECELL* cell : chart.GetCells() )
160 before.push_back( cell->m_Uuid );
161
162 chart.RebuildCells( board );
163
164 std::vector<KIID> after;
165
166 for( const PCB_TABLECELL* cell : chart.GetCells() )
167 after.push_back( cell->m_Uuid );
168
169 // Clearing and repopulating would mint new UUIDs every rebuild and break selection
170 // restore and file diffs
171 BOOST_CHECK( before == after );
172}
173
174
175BOOST_AUTO_TEST_CASE( AChartFollowsTheBoardWithoutBeingAsked )
176{
177 BOARD board;
178 buildHoles( board );
179
180 PCB_DRILL_CHART* chart = new PCB_DRILL_CHART( &board );
181 chart->SetLayer( User_1 );
182 board.Add( chart );
183 chart->RebuildCells( board );
184
185 const int rowsBefore = chart->GetRowCount();
186 const uint64_t builtAt = chart->GetBuiltGeneration();
187
188 // Nothing moved, so the refresh is one comparison and the cells stay as they are
189 RefreshDrillCharts( board );
190
191 BOOST_CHECK_EQUAL( chart->GetBuiltGeneration(), builtAt );
192 BOOST_CHECK_EQUAL( chart->GetRowCount(), rowsBefore );
193
194 PCB_VIA* via = new PCB_VIA( &board );
195 via->SetPadstackMode( PADSTACK::MODE::NORMAL );
196 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 40 ), 0 ) );
197 via->SetLayerPair( F_Cu, B_Cu );
198 via->SetDrill( pcbIUScale.mmToIU( 0.45 ) );
199 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.80 ) );
200 board.Add( via );
201
202 RefreshDrillCharts( board );
203
204 // A new hole size is a new row, and nobody had to ask for it
205 BOOST_CHECK_EQUAL( chart->GetRowCount(), rowsBefore + 1 );
207}
208
209
210BOOST_AUTO_TEST_CASE( HolesReportTheDrillSymbolLayerOfAMap )
211{
212 BOARD board;
213 buildHoles( board );
214
215 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
216 map->SetLayer( User_1 );
217 board.Add( map );
218
220
221 const int symbolLayer = DRILL_SYMBOL_LAYER_FOR( User_1 );
222 int reporting = 0;
223
224 for( FOOTPRINT* fp : board.Footprints() )
225 {
226 for( PAD* pad : fp->Pads() )
227 {
228 if( !pad->HasHole() )
229 continue;
230
231 const std::vector<int> layers = pad->ViewGetLayers();
232
233 if( alg::contains( layers, symbolLayer ) )
234 reporting++;
235 }
236 }
237
238 for( PCB_TRACK* track : board.Tracks() )
239 {
240 if( track->Type() != PCB_VIA_T )
241 continue;
242
243 const std::vector<int> layers = track->ViewGetLayers();
244
245 if( alg::contains( layers, symbolLayer ) )
246 reporting++;
247 }
248
249 // Without this the canvas has nothing to draw the marks on, even though the plotter
250 // renders them perfectly well from the same data
251
252 // note: for an ubscure reason, on MINGW, KIGFX::VIEW::VIEW_MAX_LAYERS need to be copied
253 // to an intermediate variable to avoid link issues
254 const int view_max_layers = KIGFX::VIEW::VIEW_MAX_LAYERS;
255
256 BOOST_TEST_MESSAGE( "DRILL_SYMBOL_START=" << (int) LAYER_DRILL_SYMBOL_START
257 << " END=" << (int) LAYER_DRILL_SYMBOL_END
258 << " GAL_END=" << (int) GAL_LAYER_ID_END
259 << " VIEW_MAX=" << view_max_layers
260 << " symbolLayer=" << symbolLayer );
261
262 // The view creates layers 0..VIEW_MAX_LAYERS-1. Anything above that is silently dropped
263 // when an item is indexed, so it would never be drawn
264 BOOST_CHECK_MESSAGE( symbolLayer < view_max_layers,
265 "layer " << symbolLayer << " exceeds VIEW_MAX_LAYERS "
266 << view_max_layers );
267
268 BOOST_CHECK_MESSAGE( reporting > 0, "no hole reports layer " << symbolLayer );
269
270 map->SetLayer( Eco1_User );
272
273 BOOST_CHECK( !board.DrillSymbolLayers().Contains( User_1 ) );
275
276 const int migratedSymbolLayer = DRILL_SYMBOL_LAYER_FOR( Eco1_User );
277
278 for( PCB_TRACK* track : board.Tracks() )
279 {
280 if( track->Type() != PCB_VIA_T )
281 continue;
282
283 const std::vector<int> layers = track->ViewGetLayers();
284 BOOST_CHECK( !alg::contains( layers, symbolLayer ) );
285 BOOST_CHECK( alg::contains( layers, migratedSymbolLayer ) );
286 }
287}
288
289
290BOOST_AUTO_TEST_CASE( MapIsHitAtItsMarksAndNowhereElse )
291{
292 BOARD board;
293 buildHoles( board );
294
295 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
296 map->SetLayer( User_1 );
297 board.Add( map );
298
299 const VECTOR2I hole( 0, 0 );
300 const VECTOR2I empty( pcbIUScale.mmToIU( 12 ), pcbIUScale.mmToIU( 12 ) );
301
302 BOOST_CHECK( map->HitTest( hole, 0 ) );
303 BOOST_CHECK( !map->HitTest( empty, 0 ) );
304
305 // The marks travel with the offset. The holes they mark stay where they are
306 const VECTOR2I offset( pcbIUScale.mmToIU( 50 ), pcbIUScale.mmToIU( 40 ) );
307 map->SetOffset( offset );
308
309 BOOST_CHECK( !map->HitTest( hole, 0 ) );
310 BOOST_CHECK( map->HitTest( hole + offset, 0 ) );
311}
312
313
314BOOST_AUTO_TEST_CASE( MapIgnoresRotateAndFlipsOnlyItsLayer )
315{
316 BOARD board;
317 buildHoles( board );
318
319 PCB_DRILL_MAP map( &board );
320 const VECTOR2I offset( pcbIUScale.mmToIU( 50 ), pcbIUScale.mmToIU( 40 ) );
321 const VECTOR2I centre( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 20 ) );
322
323 map.SetLayer( F_Fab );
324 map.SetOffset( offset );
325 map.Rotate( centre, EDA_ANGLE( 90.0, DEGREES_T ) );
326
327 BOOST_CHECK( map.GetOffset() == offset );
329
330 // The offset displaces a mark from its own hole, so there is nothing to mirror. The side
331 // the map documents does move with the board
332 map.SetOffset( offset );
333 map.Flip( centre, FLIP_DIRECTION::LEFT_RIGHT );
334
335 BOOST_CHECK( map.GetOffset() == offset );
337
338 map.Flip( centre, FLIP_DIRECTION::TOP_BOTTOM );
339
340 BOOST_CHECK( map.GetOffset() == offset );
342
343 // A user layer has no other side, so it stays put
344 map.SetLayer( User_1 );
345 map.Flip( centre, FLIP_DIRECTION::LEFT_RIGHT );
346
348}
349
350
351BOOST_AUTO_TEST_CASE( MapWithoutABoardIsUsableAndFlippable )
352{
353 // Every current caller passes a board, but a 1 nm symbol would be invisible and
354 // unhittable, and flipping a detached map must not dereference the board it has not got
355 PCB_DRILL_MAP map( nullptr );
356
357 BOOST_CHECK_GT( map.GetSymbolSize(), pcbIUScale.mmToIU( 0.1 ) );
358 BOOST_CHECK_GT( map.GetSymbolExtent(), 0 );
359
360 map.SetLayer( F_Fab );
362
364}
365
366
367BOOST_AUTO_TEST_CASE( MapIsHitOnItsOutlineWhenTheBoardHasNoHoles )
368{
369 BOARD board;
370
371 const BOX2I outlineBox( { pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 20 ) },
372 { pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 40 ) } );
373 buildOutline( board, outlineBox );
374
375 PCB_DRILL_MAP map( &board );
376 const VECTOR2I offset( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 80 ) );
377
378 map.SetLayer( User_1 );
379 map.SetOffset( offset );
380
381 // The outline is drawn and plotted, so it has to be selectable. Without holes there are
382 // no marks to hit instead
383 BOOST_CHECK( map.HitTest( outlineBox.GetOrigin() + offset, 0 ) );
384 BOOST_CHECK( map.HitTest( VECTOR2I( outlineBox.GetLeft(), outlineBox.GetCenter().y ) + offset, 0 ) );
385
386 // Inside the outline is not on it, and neither is the undisplaced board
387 BOOST_CHECK( !map.HitTest( outlineBox.GetCenter() + offset, 0 ) );
388 BOOST_CHECK( !map.HitTest( outlineBox.GetOrigin(), 0 ) );
389}
390
391
392BOOST_AUTO_TEST_CASE( MapOwnsItsSymbolSizeAndOnlyExposesOffsets )
393{
394 BOARD board;
395 const int defaultSize = pcbIUScale.mmToIU( 2.5 );
397
398 PCB_DRILL_MAP map( &board );
400
401 const auto& properties = PROPERTY_MANAGER::Instance().GetProperties( TYPE_HASH( PCB_DRILL_MAP ) );
402 std::set<wxString> names;
403
404 for( const PROPERTY_BASE* property : properties )
405 names.insert( property->Name() );
406
407 BOOST_CHECK( names.contains( wxT( "Offset X" ) ) );
408 BOOST_CHECK( names.contains( wxT( "Offset Y" ) ) );
409 BOOST_CHECK( names.contains( wxT( "Symbol Size" ) ) );
410 BOOST_CHECK( !names.contains( wxT( "Position X" ) ) );
411 BOOST_CHECK( !names.contains( wxT( "Position Y" ) ) );
412}
413
414
415BOOST_AUTO_TEST_CASE( MapSymbolSizeSurvivesCloneSwapAndProtobuf )
416{
417 BOARD board;
418 const int customSize = pcbIUScale.mmToIU( 3.75 );
419
420 PCB_DRILL_MAP map( &board );
421 map.SetLayer( User_1 );
422 map.SetSymbolSize( customSize );
423
424 std::unique_ptr<EDA_ITEM> clone( map.Clone() );
425 PCB_DRILL_MAP* copy = dynamic_cast<PCB_DRILL_MAP*>( clone.get() );
427 BOOST_CHECK_EQUAL( copy->GetSymbolSize(), customSize );
428
429 PCB_DRILL_MAP other( &board );
430 other.SetLayer( User_1 );
431 const int otherSize = pcbIUScale.mmToIU( 1.25 );
432 other.SetSymbolSize( otherSize );
433 map.SwapItemData( &other );
434 BOOST_CHECK_EQUAL( map.GetSymbolSize(), otherSize );
435 BOOST_CHECK_EQUAL( other.GetSymbolSize(), customSize );
436
437 google::protobuf::Any container;
438 other.Serialize( container );
439
440 PCB_DRILL_MAP restored( &board );
441 BOOST_REQUIRE( restored.Deserialize( container ) );
442 BOOST_CHECK_EQUAL( restored.GetSymbolSize(), customSize );
443}
444
445
446BOOST_AUTO_TEST_CASE( MapSymbolSizeSurvivesBoardFileRoundTrip )
447{
448 BOARD board;
449 const int customSize = pcbIUScale.mmToIU( 4.25 );
450
451 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
452 map->SetLayer( User_1 );
453 map->SetSymbolSize( customSize );
454 board.Add( map );
455
456 const std::filesystem::path path(
457 wxFileName::CreateTempFileName( wxT( "qa_drill_map_roundtrip" ) ).ToStdString() );
458 KI_TEST::DumpBoardToFile( board, path.string() );
459
460 std::unique_ptr<BOARD> restored = KI_TEST::ReadBoardFromFileOrStream( path.string() );
461 BOOST_REQUIRE( restored );
462
463 const std::vector<const PCB_DRILL_MAP*> maps = restored->DrillMapsOnLayer( User_1 );
464 BOOST_REQUIRE_EQUAL( maps.size(), 1 );
465 BOOST_CHECK_EQUAL( maps.front()->GetSymbolSize(), customSize );
466}
467
468
469BOOST_AUTO_TEST_CASE( HoleViewBoundsIncludeDisplacedMapSymbols )
470{
471 BOARD board;
472 buildHoles( board );
473
474 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
475 map->SetLayer( User_1 );
476 map->SetOffset( { pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 80 ) } );
477 map->SetSymbolSize( pcbIUScale.mmToIU( 12 ) );
478 board.Add( map );
479
480 PCB_TRACK* via = board.Tracks().front();
481 const VECTOR2I displacedSymbol = via->GetPosition() + map->GetOffset();
482
483 BOOST_CHECK( via->ViewBBox().Contains( displacedSymbol ) );
484 BOOST_CHECK( via->ViewBBox().Contains( displacedSymbol + VECTOR2I( 2 * map->GetSymbolSize(), 0 ) ) );
485}
486
487
488BOOST_AUTO_TEST_CASE( MapBoardOutlineFollowsItsOffset )
489{
490 BOARD board;
491 buildHoles( board );
492
493 const BOX2I outlineBox( { pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 20 ) },
494 { pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 40 ) } );
495 buildOutline( board, outlineBox );
496
497 PCB_DRILL_MAP map( &board );
498 const VECTOR2I offset( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 80 ) );
499 map.SetOffset( offset );
500
501 const std::shared_ptr<const SHAPE_POLY_SET> outlines = map.GetBoardOutlines();
502
503 BOOST_REQUIRE_EQUAL( outlines->OutlineCount(), 1 );
504 BOOST_CHECK( outlines->BBox() == BOX2I( outlineBox.GetOrigin() + offset, outlineBox.GetSize() ) );
505}
506
507
508BOOST_AUTO_TEST_CASE( SpanChoiceRoundTripsThroughTheBoardSpans )
509{
510 BOARD board;
511 buildHoles( board );
512
513 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
514 map->SetLayer( User_1 );
515 board.Add( map );
516
517 BOOST_CHECK_EQUAL( map->GetSpanChoice(), -1 );
518
519 const std::vector<DRILL_SPAN> spans = EnumerateDrillSpans( board );
520
521 BOOST_REQUIRE( !spans.empty() );
522
523 map->SetSpanChoice( 0 );
524
525 BOOST_CHECK( !map->GetAllSpans() );
526 BOOST_CHECK( map->GetSpan() == spans[0] );
527 BOOST_CHECK_EQUAL( map->GetSpanChoice(), 0 );
528
529 // A choice the board cannot honour means every span, not a map with nothing on it
530 map->SetSpanChoice( static_cast<int>( spans.size() ) );
531
532 BOOST_CHECK( map->GetAllSpans() );
533 BOOST_CHECK_EQUAL( map->GetSpanChoice(), -1 );
534}
535
536
537BOOST_AUTO_TEST_CASE( ChartCellTextIsNotUserEditableButItsFormattingIs )
538{
539 BOARD board;
540 buildHoles( board );
541
542 PCB_DRILL_CHART chart( &board );
543 chart.RebuildCells( board );
544
545 PCB_TABLE table( &board );
546 table.SetColCount( 1 );
547 table.ResizeCells( 1, 1 );
548
549 BOOST_REQUIRE( !chart.GetCells().empty() );
550 BOOST_REQUIRE( !table.GetCells().empty() );
551
553 propMgr.Rebuild();
554
555 PROPERTY_BASE* text = propMgr.GetProperty( TYPE_HASH( EDA_TEXT ), _HKI( "Text" ) );
556
558
559 // Scoped to PCB_TABLECELL rather than set on the EDA_TEXT descriptor, which eeschema
560 // shares. The base property itself must stay writeable
561 BOOST_CHECK( text->Writeable( chart.GetCells().front() ) );
562
563 // The chart says what the board says. An ordinary table is still the user's to write
564 BOOST_CHECK( !propMgr.IsWriteableFor( TYPE_HASH( PCB_TABLECELL ), text, chart.GetCells().front() ) );
565 BOOST_CHECK( propMgr.IsWriteableFor( TYPE_HASH( PCB_TABLECELL ), text, table.GetCells().front() ) );
566}
567
568
569BOOST_AUTO_TEST_CASE( OnlyHolesCarryTheDrillSymbolMargin )
570{
571 BOARD board;
572 buildHoles( board );
573
574 FOOTPRINT* fp = new FOOTPRINT( &board );
575 fp->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50 ), 0 ) );
576
577 PAD* smd = new PAD( fp );
579 smd->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50 ), 0 ) );
580 smd->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
581 fp->Add( smd );
582 board.Add( fp );
583
584 const BOX2I unmapped = smd->ViewBBox();
585
586 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
587 map->SetLayer( User_1 );
588 map->SetOffset( { pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 80 ) } );
589 board.Add( map );
591
592 // An SMD pad draws no symbol, so widening its bounds to the far side of the board would
593 // only defeat culling
594 BOOST_CHECK( smd->ViewBBox() == unmapped );
595
596 PCB_TRACK* segment = new PCB_TRACK( &board );
597 segment->SetStart( VECTOR2I( 0, 0 ) );
598 segment->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 ) );
599 segment->SetWidth( pcbIUScale.mmToIU( 0.2 ) );
600 board.Add( segment );
601
602 BOOST_CHECK( !segment->ViewBBox().Contains( segment->GetStart() + map->GetOffset() ) );
603}
604
605
606BOOST_AUTO_TEST_CASE( MovingAMapUpdatesTheHoleViewBounds )
607{
608 BOARD board;
609 buildHoles( board );
610
611 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( &board );
612 map->SetLayer( User_1 );
613 map->SetSymbolSize( pcbIUScale.mmToIU( 2 ) );
614 board.Add( map );
616
617 PCB_TRACK* via = board.Tracks().front();
618
619 map->SetOffset( { pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 80 ) } );
621
622 // The layer set has not changed, only the offset, and the cached placements have to
623 // notice that or the marks are culled where they now are
624 BOOST_CHECK( via->ViewBBox().Contains( via->GetPosition() + map->GetOffset() ) );
625}
626
627
628BOOST_AUTO_TEST_CASE( CellFormattingSurvivesARebuild )
629{
630 BOARD board;
631 buildHoles( board );
632
633 PCB_DRILL_CHART chart( &board );
634 chart.RebuildCells( board );
635
636 // The last data row, past the heading
637 const int row = chart.GetRowCount() - 2;
638
639 BOOST_REQUIRE( row > 1 );
640
641 for( int col = 0; col < chart.GetColCount(); ++col )
642 {
643 chart.GetCell( row, col )->SetBold( true );
644 chart.GetCell( row, col )->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.5 ),
645 pcbIUScale.mmToIU( 2.5 ) ) );
646 }
647
648 chart.RebuildCells( board );
649
650 // Cells are reused rather than recreated, which is what lets the ordinary table
651 // formatting be the chart's formatting
652 BOOST_CHECK( chart.GetCell( row, 0 )->IsBold() );
653 BOOST_CHECK_EQUAL( chart.GetCell( row, 0 )->GetTextHeight(), pcbIUScale.mmToIU( 2.5 ) );
654}
655
656
659int rowShowingDiameter( const PCB_DRILL_CHART& aChart, const wxString& aText )
660{
661 for( const PCB_TABLECELL* cell : aChart.GetCells() )
662 {
663 if( cell->GetText() == aText )
664 return cell->GetRow();
665 }
666
667 return -1;
668}
669
670
671BOOST_AUTO_TEST_CASE( CellFormattingFollowsItsGroupWhenAGroupIsAdded )
672{
673 BOARD board;
674 buildHoles( board );
675
676 PCB_DRILL_CHART chart( &board );
677 chart.RebuildCells( board );
678
679 // The 3.2 mm mounting hole, which is the largest and so the last data row
680 const int before = rowShowingDiameter( chart, wxT( "3.200" ) );
681
682 BOOST_REQUIRE( before > 1 );
683 BOOST_REQUIRE( chart.IsDataRow( before ) );
684
685 for( int col = 0; col < chart.GetColCount(); ++col )
686 chart.GetCell( before, col )->SetBold( true );
687
688 // A smaller hole than any already present, so it takes the first data row and pushes
689 // every existing group down one
690 PCB_VIA* tiny = new PCB_VIA( &board );
692 tiny->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 40 ), 0 ) );
693 tiny->SetLayerPair( F_Cu, B_Cu );
694 tiny->SetDrill( pcbIUScale.mmToIU( 0.15 ) );
695 tiny->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.40 ) );
696 board.Add( tiny );
697
698 chart.RebuildCells( board );
699
700 const int after = rowShowingDiameter( chart, wxT( "3.200" ) );
701
702 BOOST_REQUIRE( after > 1 );
703 BOOST_CHECK_NE( after, before );
704
705 // The formatting belongs to the group, not to the row number it happened to occupy
706 BOOST_CHECK( chart.GetCell( after, 0 )->IsBold() );
707 BOOST_CHECK( !chart.GetCell( before, 0 )->IsBold() );
708}
709
710
711BOOST_AUTO_TEST_CASE( CellFormattingFollowsItsGroupWhenAGroupIsRemoved )
712{
713 BOARD board;
714 buildHoles( board );
715
716 PCB_DRILL_CHART chart( &board );
717 chart.RebuildCells( board );
718
719 const int before = rowShowingDiameter( chart, wxT( "3.200" ) );
720
721 BOOST_REQUIRE( before > 1 );
722
723 for( int col = 0; col < chart.GetColCount(); ++col )
724 chart.GetCell( before, col )->SetBold( true );
725
726 // Drop the smallest group entirely, so the rows below it move up. Both 0.30 vias have to
727 // go. One of them left behind keeps the group and the table the same shape.
728 std::vector<PCB_TRACK*> doomed;
729
730 for( PCB_TRACK* track : board.Tracks() )
731 {
732 if( track->Type() == PCB_VIA_T
733 && static_cast<PCB_VIA*>( track )->GetDrillValue() == pcbIUScale.mmToIU( 0.30 ) )
734 {
735 doomed.push_back( track );
736 }
737 }
738
739 BOOST_REQUIRE_EQUAL( doomed.size(), 2 );
740
741 for( PCB_TRACK* track : doomed )
742 {
743 board.Remove( track );
744 delete track;
745 }
746
747 const int rowsBefore = chart.GetRowCount();
748
749 chart.RebuildCells( board );
750
751 // The group really did go, or the rest of this proves nothing
752 BOOST_REQUIRE_EQUAL( chart.GetRowCount(), rowsBefore - 1 );
753
754 const int after = rowShowingDiameter( chart, wxT( "3.200" ) );
755
756 BOOST_REQUIRE( after > 1 );
757 BOOST_REQUIRE_NE( after, before );
758 BOOST_CHECK( chart.GetCell( after, 0 )->IsBold() );
759}
760
761
762BOOST_AUTO_TEST_CASE( RowsKeepSeparateCellsWhenARebuildReordersThem )
763{
764 BOARD board;
765 buildHoles( board );
766
767 // A buried via drilled like the through ones. The profile groups by span, so it reports
768 // its own row rather than joining theirs
769 PCB_VIA* buried = new PCB_VIA( &board );
771 buried->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 ) );
772
773 // Before the layer pair: SanitizeLayers() puts a through via back on F_Cu/B_Cu, which
774 // would quietly merge this into the through group and leave nothing to tell apart
775 buried->SetViaType( VIATYPE::BURIED );
776 buried->SetLayerPair( In1_Cu, In2_Cu );
777 buried->SetDrill( pcbIUScale.mmToIU( 0.30 ) );
778 buried->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.60 ) );
779 board.Add( buried );
780
781 PCB_DRILL_CHART chart( &board );
782 chart.RebuildCells( board );
783
784 const std::map<int, std::string> keys = chart.RowKeys();
785 std::set<std::string> distinct;
786
787 for( const auto& [row, key] : keys )
788 distinct.insert( key );
789
790 // The through 0.30s, the buried 0.30, the 0.60 via and the 3.2 mm mounting hole
791 BOOST_REQUIRE_EQUAL( keys.size(), 4 );
792
793 // Identity has to tell apart rows the chart is showing separately
794 BOOST_CHECK_EQUAL( distinct.size(), keys.size() );
795
796 // A rebuild that reorders the rows is what makes the migration run
797 PCB_VIA* tiny = new PCB_VIA( &board );
799 tiny->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 40 ), 0 ) );
800 tiny->SetLayerPair( F_Cu, B_Cu );
801 tiny->SetDrill( pcbIUScale.mmToIU( 0.15 ) );
802 tiny->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.40 ) );
803 board.Add( tiny );
804
805 chart.RebuildCells( board );
806
807 // Two rows holding one cell would be freed twice when the table goes
808 std::set<const PCB_TABLECELL*> seen;
809
810 for( const PCB_TABLECELL* cell : chart.GetCells() )
811 {
812 BOOST_REQUIRE( cell );
813 BOOST_CHECK( seen.insert( cell ).second );
814 }
815
816 BOOST_CHECK_EQUAL( seen.size(), chart.GetCells().size() );
817}
818
819
820BOOST_AUTO_TEST_CASE( RowKeysSurviveABoardFileRoundTrip )
821{
822 BOARD board;
823 buildHoles( board );
824
825 PCB_DRILL_CHART* chart = new PCB_DRILL_CHART( &board );
826 chart->SetLayer( User_1 );
827 chart->RebuildCells( board );
828 board.Add( chart );
829
830 const std::map<int, std::string> keys = chart->RowKeys();
831
832 BOOST_REQUIRE( !keys.empty() );
833
834 const std::filesystem::path path(
835 wxFileName::CreateTempFileName( wxT( "qa_drill_chart_rowkeys" ) ).ToStdString() );
836 KI_TEST::DumpBoardToFile( board, path.string() );
837
838 std::unique_ptr<BOARD> restored = KI_TEST::ReadBoardFromFileOrStream( path.string() );
839 BOOST_REQUIRE( restored );
840
841 const PCB_DRILL_CHART* reloaded = nullptr;
842
843 for( const BOARD_ITEM* item : restored->Drawings() )
844 {
845 if( item->Type() == PCB_DRILL_CHART_T )
846 reloaded = static_cast<const PCB_DRILL_CHART*>( item );
847 }
848
849 BOOST_REQUIRE( reloaded );
850
851 // Without these the first rebuild after a load has nothing to match the loaded rows
852 // against, and formatting would migrate by position
853 BOOST_CHECK( reloaded->RowKeys() == keys );
854}
855
856
857BOOST_AUTO_TEST_CASE( ChartIsVisitedOnceWhenBothTypesAreScanned )
858{
859 BOARD board;
860 buildHoles( board );
861
862 PCB_DRILL_CHART chart( &board );
863 chart.RebuildCells( board );
864
865 int hits = 0;
866
867 INSPECTOR_FUNC inspector =
868 [&hits]( EDA_ITEM* aItem, void* aTestData )
869 {
870 if( aItem->Type() == PCB_DRILL_CHART_T )
871 hits++;
872
874 };
875
876 // A chart answers to both, and collecting it twice puts it in the disambiguation menu
877 // twice
878 chart.Visit( inspector, nullptr, { PCB_TABLE_T, PCB_DRILL_CHART_T } );
879
880 BOOST_CHECK_EQUAL( hits, 1 );
881}
882
883
884BOOST_AUTO_TEST_CASE( FreshChartIsBuiltAtTheOrigin )
885{
886 BOARD board;
887 buildHoles( board );
888
889 PCB_DRILL_CHART chart( &board );
890 chart.SetLayer( Cmts_User );
891 chart.RebuildCells( board );
892
893 const BOX2I bbox = chart.GetBoundingBox();
894
895 // A new cell carries a half-INT_MAX rectangle and Normalize() anchors on cell 0's centre,
896 // so without correction the chart lands half a metre off the board
897 BOOST_CHECK_MESSAGE( std::abs( bbox.GetLeft() ) < pcbIUScale.mmToIU( 1 )
898 && std::abs( bbox.GetTop() ) < pcbIUScale.mmToIU( 1 ),
899 "chart origin is (" << bbox.GetLeft() << "," << bbox.GetTop()
900 << "), expected near 0" );
901
902 // Cells keep their wide default rectangle so the text does not wrap. A chart this size
903 // must be wider than it is tall
904 BOOST_CHECK( bbox.GetWidth() > bbox.GetHeight() );
905}
906
907
908BOOST_AUTO_TEST_CASE( RebuildKeepsChartPosition )
909{
910 BOARD board;
911 buildHoles( board );
912
913 PCB_DRILL_CHART chart( &board );
914 chart.SetLayer( Cmts_User );
915 chart.RebuildCells( board );
916
917 const VECTOR2I placed( pcbIUScale.mmToIU( 60 ), pcbIUScale.mmToIU( 40 ) );
918 chart.Move( placed );
919
920 const VECTOR2I before = chart.GetPosition();
921 chart.RebuildCells( board );
922
923 // A rebuild must not walk the chart across the board
924 BOOST_CHECK_EQUAL( chart.GetPosition().x, before.x );
925 BOOST_CHECK_EQUAL( chart.GetPosition().y, before.y );
926}
927
928
929BOOST_AUTO_TEST_CASE( CloneAndSwapPreserveChartSettings )
930{
931 BOARD board;
932 buildHoles( board );
933
934 PCB_DRILL_CHART chart( &board );
936 chart.SetPrecision( 5 );
937 chart.RebuildCells( board );
938
939 std::unique_ptr<EDA_ITEM> clone( chart.Clone() );
940
941 // A base PCB_TABLE clone would still report PCB_DRILL_CHART_T and then be cast to one
942 BOOST_REQUIRE_EQUAL( clone->Type(), PCB_DRILL_CHART_T );
943
944 PCB_DRILL_CHART* copy = dynamic_cast<PCB_DRILL_CHART*>( clone.get() );
946 BOOST_CHECK( copy->GetUnits() == DRILL_CHART_UNITS::INCH );
947 BOOST_CHECK_EQUAL( copy->GetPrecision(), 5 );
948
949 copy->SetPrecision( 2 );
950 chart.SwapItemData( copy );
951
952 BOOST_CHECK_EQUAL( chart.GetPrecision(), 2 );
953 BOOST_CHECK_EQUAL( copy->GetPrecision(), 5 );
954}
955
956
957BOOST_AUTO_TEST_CASE( EverySymbolResolvesWithoutAChart )
958{
959 BOARD board;
960 buildHoles( board );
961
962 // A drill map must show marks on a board where no chart has ever been placed, so the
963 // resolver has to cover every group rather than reading assignments the profile lacks
964 BOOST_CHECK( board.GetDesignSettings().GetDrillSymbolProfile().Assignments().empty() );
965
966 const std::map<std::string, DRILL_SYMBOL_ASSIGNMENT> resolved = ResolveDrillSymbols( board );
967
969 model.Build( board, EnumerateDrillSpans( board ) );
970
971 BOOST_REQUIRE( !model.Groups().empty() );
972 BOOST_CHECK_EQUAL( resolved.size(), model.Groups().size() );
973
974 for( const DRILL_CHART_GROUP& group : model.Groups() )
975 BOOST_CHECK_MESSAGE( resolved.count( group.m_Key ), "no symbol for " << group.m_Key );
976
977 // Resolving must not have written anything back to the board
978 BOOST_CHECK( board.GetDesignSettings().GetDrillSymbolProfile().Assignments().empty() );
979}
980
981
982BOOST_AUTO_TEST_CASE( HandFormattedCellsSurviveABoardFileRoundTrip )
983{
984 BOARD board;
985 buildHoles( board );
986
987 PCB_DRILL_CHART* chart = new PCB_DRILL_CHART( &board );
988 chart->SetLayer( User_1 );
989 board.Add( chart );
990 chart->RebuildCells( board );
991
992 const int row = chart->GetRowCount() - 2;
993
994 BOOST_REQUIRE( row > 1 );
995
996 const VECTOR2I textSize( pcbIUScale.mmToIU( 2.5 ), pcbIUScale.mmToIU( 2.5 ) );
997
998 for( int col = 0; col < chart->GetColCount(); ++col )
999 {
1000 chart->GetCell( row, col )->SetBold( true );
1001 chart->GetCell( row, col )->SetTextSize( textSize );
1002 }
1003
1004 const std::filesystem::path path(
1005 wxFileName::CreateTempFileName( wxT( "qa_drill_chart_cellfmt" ) ).ToStdString() );
1006 KI_TEST::DumpBoardToFile( board, path.string() );
1007
1008 std::unique_ptr<BOARD> restored = KI_TEST::ReadBoardFromFileOrStream( path.string() );
1009 BOOST_REQUIRE( restored );
1010
1011 PCB_DRILL_CHART* reloaded = nullptr;
1012
1013 for( BOARD_ITEM* item : restored->Drawings() )
1014 {
1015 if( item->Type() == PCB_DRILL_CHART_T )
1016 reloaded = static_cast<PCB_DRILL_CHART*>( item );
1017 }
1018
1019 BOOST_REQUIRE( reloaded );
1020
1021 // The rebuild every load performs has to migrate the formatting onto the new cells, which
1022 // it can only do if the old ones came back out of the file
1023 reloaded->RebuildCells( *restored );
1024
1025 BOOST_REQUIRE( reloaded->GetRowCount() - 2 == row );
1026 BOOST_CHECK( reloaded->GetCell( row, 0 )->IsBold() );
1027 BOOST_CHECK_EQUAL( reloaded->GetCell( row, 0 )->GetTextHeight(), textSize.y );
1028}
1029
1030
1031BOOST_AUTO_TEST_CASE( DefaultColumnHeadingsSurviveBeingLeftOutOfTheFile )
1032{
1033 BOARD board;
1034 buildHoles( board );
1035
1036 PCB_DRILL_CHART* chart = new PCB_DRILL_CHART( &board );
1037 chart->SetLayer( User_1 );
1038 board.Add( chart );
1039 chart->RebuildCells( board );
1040
1041 const std::vector<DRILL_CHART_COLUMN> columns = chart->Columns();
1042
1043 const std::filesystem::path path(
1044 wxFileName::CreateTempFileName( wxT( "qa_drill_chart_coldefaults" ) ).ToStdString() );
1045 KI_TEST::DumpBoardToFile( board, path.string() );
1046
1047 std::unique_ptr<BOARD> restored = KI_TEST::ReadBoardFromFileOrStream( path.string() );
1048 BOOST_REQUIRE( restored );
1049
1050 const PCB_DRILL_CHART* reloaded = nullptr;
1051
1052 for( const BOARD_ITEM* item : restored->Drawings() )
1053 {
1054 if( item->Type() == PCB_DRILL_CHART_T )
1055 reloaded = static_cast<const PCB_DRILL_CHART*>( item );
1056 }
1057
1058 BOOST_REQUIRE( reloaded );
1059 BOOST_REQUIRE_EQUAL( reloaded->Columns().size(), columns.size() );
1060
1061 for( size_t ii = 0; ii < columns.size(); ++ii )
1062 {
1063 BOOST_CHECK( reloaded->Columns()[ii].m_Heading == columns[ii].m_Heading );
1064 BOOST_CHECK( reloaded->Columns()[ii].m_Align == columns[ii].m_Align );
1065 }
1066}
1067
1068
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
General utilities for PCB file IO for QA programs.
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
DRILL_SYMBOL_PROFILE & GetDrillSymbolProfile()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
void SwapItemData(BOARD_ITEM *aImage)
Swap data between aItem and aImage.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
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
void RefreshDrillSymbolLayers()
Definition board.cpp:234
const LSET & DrillSymbolLayers() const
Layers that currently have a drill map on them.
Definition board.h:603
uint64_t GetDrillModelGeneration() const
Definition board.h:587
const FOOTPRINTS & Footprints() const
Definition board.h:463
const TRACKS & Tracks() const
Definition board.h:461
void SetCopperLayerCount(int aCount)
Definition board.cpp:1137
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1668
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetTop() const
Definition box2.h:226
constexpr coord_type GetBottom() const
Definition box2.h:219
const std::map< std::string, DRILL_SYMBOL_ASSIGNMENT > & Assignments() const
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual int GetTextHeight() const
Definition eda_text.h:307
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:305
bool IsBold() const
Definition eda_text.h:215
void SetPosition(const VECTOR2I &aPos) override
std::deque< PAD * > & Pads()
Definition footprint.h:404
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:773
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
@ 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
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:1639
void SetPosition(const VECTOR2I &aPos) override
Definition pad.cpp:235
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:255
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pad.cpp:2873
A drill chart placed on the board, kept in step with the holes.
std::vector< DRILL_CHART_COLUMN > & Columns()
uint64_t GetBuiltGeneration() const
Board drill generation the cells were built at.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void RebuildCells(const BOARD &aBoard, DRILL_SYMBOL_PROFILE *aAssignedProfile=nullptr)
Regenerate the cells from the board.
const std::map< int, std::string > & RowKeys() const
Drill group each generated row reports on, by table row.
int GetPrecision() const
void SetPrecision(int aPrecision)
Clamped.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
bool IsDataRow(int aRow) const
True for a row that reports a drill group, false for the title, heading and totals.
void SetUnits(DRILL_CHART_UNITS aUnits)
Turns on drill symbols at the holes, for one layer.
bool GetAllSpans() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void SetSpanChoice(int aIndex)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
int GetSymbolSize() const
void SetSymbolSize(int aSize)
int GetSymbolExtent() const
const DRILL_SPAN & GetSpan() const
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Configuration operations, deliberately not geometry transforms.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
std::shared_ptr< const SHAPE_POLY_SET > GetBoardOutlines() const
The board outline displaced by this map's offset.
const VECTOR2I & GetOffset() const
void SetOffset(const VECTOR2I &aOffset)
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
int GetSpanChoice() const
The span as an index into the board's spans, with -1 for every span.
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
int GetRowCount() const
Definition pcb_table.h:123
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
PCB_TABLECELL * GetCell(int aRow, int aCol) const
Definition pcb_table.h:150
std::vector< PCB_TABLECELL * > GetCells() const
Definition pcb_table.h:160
int GetColCount() const
Definition pcb_table.h:121
VECTOR2I GetPosition() const override
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
void SetDrill(int aDrill)
Definition pcb_track.h:771
void SetPadstackMode(PADSTACK::MODE aMode)
Definition pcb_track.h:482
void SetPosition(const VECTOR2I &aPoint) override
Definition pcb_track.h:581
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:411
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void SetWidth(int aWidth) override
Provide class metadata.Helper macro to map type hashes to names.
const std::vector< PROPERTY_BASE * > & GetProperties(TYPE_ID aType) const
Return all properties for a specific type.
bool IsWriteableFor(TYPE_ID aItemClass, PROPERTY_BASE *aProp, INSPECTABLE *aItem)
Checks overriden availability and original availability of a property, returns false if the property ...
static PROPERTY_MANAGER & Instance()
void Rebuild()
Rebuild the list of all registered properties.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
static bool empty(const wxTextEntryBase *aCtrl)
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard)
Every drill span present on the board, through-holes first.
std::map< std::string, DRILL_SYMBOL_ASSIGNMENT > ResolveDrillSymbols(const BOARD &aBoard)
The symbol every hole should carry, without touching the board.
static std::string ToStdString(const wxString &aStr)
@ DEGREES_T
Definition eda_angle.h:31
static const wxSize defaultSize(FRAME_T aFrameType, wxWindow *aWindow)
std::function< INSPECT_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Used to inspect and possibly collect the (search) results of iterating over a list or tree of KICAD_T...
Definition eda_item.h:88
@ SEGMENT
Definition eda_shape.h:56
Some functions to handle hotkeys in KiCad.
@ LAYER_DRILL_SYMBOL_START
Drill symbols, one channel per board layer.
Definition layer_ids.h:376
@ GAL_LAYER_ID_END
Definition layer_ids.h:379
@ LAYER_DRILL_SYMBOL_END
Definition layer_ids.h:377
#define DRILL_SYMBOL_LAYER_FOR(boardLayer)
Definition layer_ids.h:391
@ Edge_Cuts
Definition layer_ids.h:108
@ Cmts_User
Definition layer_ids.h:104
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ In2_Cu
Definition layer_ids.h:63
@ F_Fab
Definition layer_ids.h:115
@ In1_Cu
Definition layer_ids.h:62
@ User_1
Definition layer_ids.h:120
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
void DumpBoardToFile(BOARD &board, const std::filesystem::path &aFilename)
Utility function to simply write a Board out to a file.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
#define _HKI(x)
Definition page_info.cpp:40
void RefreshDrillCharts(BOARD &aBoard)
Bring every chart on the board up to date.
#define TYPE_HASH(x)
Definition property.h:74
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
int rowShowingDiameter(const PCB_DRILL_CHART &aChart, const wxString &aText)
The row reporting a given drill group, or -1.
BOOST_AUTO_TEST_CASE(GroupsHolesBySizeAndPlating)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
KIBIS_MODEL * model
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683