KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_clipboard_export.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
31
32#include <boost/test/unit_test.hpp>
33
34#include <board.h>
35#include <footprint.h>
36#include <pad.h>
37#include <pcb_track.h>
38#include <pcb_shape.h>
39#include <pcb_text.h>
40#include <pcb_field.h>
41#include <zone.h>
42#include <lset.h>
43
45#include <pcb_painter.h>
46#include <wx/ffile.h>
47#include <wx/mstream.h>
48
49
51{
52public:
54 {
55 m_board = std::make_unique<BOARD>();
56 m_board->SetEnabledLayers( LSET::AllCuMask() | LSET::AllTechMask() );
57 m_board->SetVisibleLayers( m_board->GetEnabledLayers() );
58 }
59
61
62 void AddTrack( int x1, int y1, int x2, int y2, PCB_LAYER_ID layer = F_Cu )
63 {
64 PCB_TRACK* track = new PCB_TRACK( m_board.get() );
65 track->SetStart( VECTOR2I( pcbIUScale.mmToIU( x1 ), pcbIUScale.mmToIU( y1 ) ) );
66 track->SetEnd( VECTOR2I( pcbIUScale.mmToIU( x2 ), pcbIUScale.mmToIU( y2 ) ) );
67 track->SetWidth( pcbIUScale.mmToIU( 0.25 ) );
68 track->SetLayer( layer );
69 m_board->Add( track );
70 m_items.push_back( track );
71 }
72
73 void AddVia( int x, int y )
74 {
75 PCB_VIA* via = new PCB_VIA( m_board.get() );
76 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( x ), pcbIUScale.mmToIU( y ) ) );
77 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.8 ) );
78 via->SetDrill( pcbIUScale.mmToIU( 0.4 ) );
79 via->SetViaType( VIATYPE::THROUGH );
80 m_board->Add( via );
81 m_items.push_back( via );
82 }
83
84 void AddPad( FOOTPRINT* fp, int x, int y, const wxString& padNum, PAD_SHAPE shape = PAD_SHAPE::CIRCLE )
85 {
86 PAD* pad = new PAD( fp );
87 pad->SetPosition( VECTOR2I( pcbIUScale.mmToIU( x ), pcbIUScale.mmToIU( y ) ) );
88 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
89 pad->SetDrillSize( VECTOR2I( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.8 ) ) );
90 pad->SetShape( PADSTACK::ALL_LAYERS, shape );
91 pad->SetAttribute( PAD_ATTRIB::PTH );
92 pad->SetNumber( padNum );
93 pad->SetLayerSet( PAD::PTHMask() );
94 fp->Add( pad );
95 }
96
97 FOOTPRINT* AddFootprint( int x, int y, const wxString& ref = wxT( "U1" ) )
98 {
99 FOOTPRINT* fp = new FOOTPRINT( m_board.get() );
100 fp->SetPosition( VECTOR2I( pcbIUScale.mmToIU( x ), pcbIUScale.mmToIU( y ) ) );
101 fp->SetReference( ref );
102 fp->SetValue( wxT( "TestComponent" ) );
103 m_board->Add( fp );
104 m_items.push_back( fp );
105 return fp;
106 }
107
108 void AddZone( PCB_LAYER_ID layer = F_Cu )
109 {
110 ZONE* zone = new ZONE( m_board.get() );
111 zone->SetLayer( layer );
112 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 0 ), pcbIUScale.mmToIU( 0 ) ), -1 );
113 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 0 ), pcbIUScale.mmToIU( 10 ) ), -1 );
114 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ), -1 );
115 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 0 ) ), -1 );
116 m_board->Add( zone );
117 m_items.push_back( zone );
118 }
119
120 std::unique_ptr<BOARD> m_board;
121 std::vector<BOARD_ITEM*> m_items;
122};
123
124
125BOOST_FIXTURE_TEST_SUITE( ClipboardExportTests, CLIPBOARD_EXPORT_FIXTURE )
126
127
128
132BOOST_AUTO_TEST_CASE( SvgPlotter_LayerSupport )
133{
134 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_layer_test" ) ) );
135 tempFile.SetExt( wxT( "svg" ) );
136
137 // Create an SVG plotter
138 SVG_PLOTTER plotter;
139
140 PAGE_INFO pageInfo;
141 pageInfo.SetWidthMils( 1000 );
142 pageInfo.SetHeightMils( 1000 );
143 plotter.SetPageSettings( pageInfo );
144 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
145
146 BOOST_CHECK( plotter.OpenFile( tempFile.GetFullPath() ) );
147
148 plotter.StartPlot( wxT( "1" ) );
149
150 // Create a layer with a known name
151 wxString layerName = wxT( "F.Cu" );
152 plotter.StartLayer( layerName );
153
154 // Draw something in the layer
155 plotter.SetColor( COLOR4D( 1.0, 0, 0, 1.0 ) );
156 plotter.ThickSegment( VECTOR2I( 100, 100 ), VECTOR2I( 500, 500 ), 50, nullptr );
157
158 plotter.EndLayer();
159
160 plotter.EndPlot();
161
162 // Read the SVG file and verify layer structure
163 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
164 BOOST_REQUIRE( file.IsOpened() );
165
166 wxString content;
167 file.ReadAll( &content );
168 file.Close();
169
170 // Verify the SVG contains proper layer structure
171 // Should have Inkscape namespace
172 BOOST_CHECK( content.Contains( wxT( "xmlns:inkscape" ) ) );
173
174 // Should have layer group with inkscape:groupmode="layer"
175 BOOST_CHECK( content.Contains( wxT( "inkscape:groupmode=\"layer\"" ) ) );
176
177 // Should have the layer name in inkscape:label
178 BOOST_CHECK( content.Contains( wxT( "inkscape:label=\"F.Cu\"" ) ) );
179
180 // Should have the layer name in id attribute
181 BOOST_CHECK( content.Contains( wxT( "id=\"F.Cu\"" ) ) );
182
183 wxRemoveFile( tempFile.GetFullPath() );
184}
185
186
190BOOST_AUTO_TEST_CASE( SvgExport_ContainsTracks )
191{
192 // Add a track to the board
193 AddTrack( 0, 0, 10, 10, F_Cu );
194
195 // Verify the track was added
196 BOOST_CHECK_EQUAL( m_board->Tracks().size(), 1 );
197
198 // Verify the track has correct properties
199 PCB_TRACK* track = static_cast<PCB_TRACK*>( m_board->Tracks().front() );
200 BOOST_CHECK_EQUAL( track->GetLayer(), F_Cu );
201 BOOST_CHECK_EQUAL( track->GetStart().x, pcbIUScale.mmToIU( 0 ) );
202 BOOST_CHECK_EQUAL( track->GetStart().y, pcbIUScale.mmToIU( 0 ) );
203 BOOST_CHECK_EQUAL( track->GetEnd().x, pcbIUScale.mmToIU( 10 ) );
204 BOOST_CHECK_EQUAL( track->GetEnd().y, pcbIUScale.mmToIU( 10 ) );
205}
206
207
211BOOST_AUTO_TEST_CASE( SvgExport_ContainsVias )
212{
213 // Add a via to the board
214 AddVia( 5, 5 );
215
216 // Verify the via was added
217 auto tracks = m_board->Tracks();
218 PCB_VIA* via = nullptr;
219
220 for( auto item : tracks )
221 {
222 if( item->Type() == PCB_VIA_T )
223 {
224 via = static_cast<PCB_VIA*>( item );
225 break;
226 }
227 }
228
229 BOOST_REQUIRE( via != nullptr );
230 BOOST_CHECK_EQUAL( via->GetPosition().x, pcbIUScale.mmToIU( 5 ) );
231 BOOST_CHECK_EQUAL( via->GetPosition().y, pcbIUScale.mmToIU( 5 ) );
232 BOOST_CHECK( via->GetViaType() == VIATYPE::THROUGH );
233}
234
235
239BOOST_AUTO_TEST_CASE( SvgExport_ContainsFootprintPads )
240{
241 // Add a footprint with pads
242 FOOTPRINT* fp = AddFootprint( 25, 25, wxT( "U1" ) );
243 AddPad( fp, 25, 23, wxT( "1" ) );
244 AddPad( fp, 25, 27, wxT( "2" ) );
245
246 // Verify the footprint was added
247 BOOST_CHECK_EQUAL( m_board->Footprints().size(), 1 );
248
249 // Verify the footprint has pads
250 BOOST_CHECK_EQUAL( fp->Pads().size(), 2 );
251
252 // Verify pad properties
253 PAD* pad1 = fp->Pads()[0];
254 // Pad numbers are set via SetNumber() and are non-empty after creation
255 BOOST_CHECK( !pad1->GetNumber().IsEmpty() );
256 BOOST_CHECK( ( pad1->GetLayerSet() & LSET( { F_Cu } ) ).any() );
257}
258
259
263BOOST_AUTO_TEST_CASE( SvgExport_ContainsZones )
264{
265 // Add a zone to the board
266 AddZone( F_Cu );
267
268 // Verify the zone was added
269 BOOST_CHECK_EQUAL( m_board->Zones().size(), 1 );
270
271 // Verify the zone has corners
272 ZONE* zone = m_board->Zones()[0];
273 BOOST_CHECK( zone->GetNumCorners() >= 4 );
275}
276
277
282BOOST_AUTO_TEST_CASE( PngExport_AlphaComputation_FullyOpaque )
283{
284 // Test fully opaque pixel (alpha = 255)
285 // A fully opaque red pixel renders identically on both backgrounds
286 int rW = 255, gW = 0, bW = 0; // Red on white
287 int rB = 255, gB = 0, bB = 0; // Red on black (same because opaque)
288
289 int diffR = rW - rB; // 0
290 int diffG = gW - gB; // 0
291 int diffB = bW - bB; // 0
292 int avgDiff = ( diffR + diffG + diffB ) / 3; // 0
293 int alpha = 255 - avgDiff; // 255
294
295 BOOST_CHECK_EQUAL( alpha, 255 );
296}
297
298
299BOOST_AUTO_TEST_CASE( PngExport_AlphaComputation_FullyTransparent )
300{
301 // Test fully transparent pixel (alpha = 0)
302 // A transparent pixel shows the background color
303 int rW = 255, gW = 255, bW = 255; // White background shows through
304 int rB = 0, gB = 0, bB = 0; // Black background shows through
305
306 int diffR = rW - rB; // 255
307 int diffG = gW - gB; // 255
308 int diffB = bW - bB; // 255
309 int avgDiff = ( diffR + diffG + diffB ) / 3; // 255
310 int alpha = 255 - avgDiff; // 0
311
312 BOOST_CHECK_EQUAL( alpha, 0 );
313}
314
315
316BOOST_AUTO_TEST_CASE( PngExport_AlphaComputation_SemiTransparent )
317{
318 // Test semi-transparent pixel (alpha ≈ 128)
319 // Foreground: gray (128, 128, 128), alpha = 0.5
320 // On white: 0.5*128 + 0.5*255 = 192
321 // On black: 0.5*128 + 0.5*0 = 64
322 int rW = 192, gW = 192, bW = 192;
323 int rB = 64, gB = 64, bB = 64;
324
325 int diffR = rW - rB; // 128
326 int diffG = gW - gB; // 128
327 int diffB = bW - bB; // 128
328 int avgDiff = ( diffR + diffG + diffB ) / 3; // 128
329 int alpha = 255 - avgDiff; // 127
330
331 BOOST_CHECK_CLOSE( static_cast<double>( alpha ), 128.0, 1.0 ); // Allow 1% tolerance
332}
333
334
339BOOST_AUTO_TEST_CASE( PngExport_UnselectedColors )
340{
341 AddTrack( 0, 0, 10, 10, F_Cu );
342
343 PCB_TRACK* track = static_cast<PCB_TRACK*>( m_board->Tracks().front() );
344
345 // Set selected state
346 track->SetSelected();
347 BOOST_CHECK( track->IsSelected() );
348
349 // Clone and clear selection (as done in renderSelectionToBitmap)
350 std::unique_ptr<BOARD_ITEM> clone( static_cast<BOARD_ITEM*>( track->Clone() ) );
351 clone->ClearSelected();
352
353 // Verify selection is cleared
354 BOOST_CHECK( !clone->IsSelected() );
355}
356
357
361BOOST_AUTO_TEST_CASE( PngExport_FootprintChildrenUnselected )
362{
363 FOOTPRINT* fp = AddFootprint( 25, 25, wxT( "U1" ) );
364 AddPad( fp, 25, 23, wxT( "1" ) );
365 AddPad( fp, 25, 27, wxT( "2" ) );
366
367 // Set footprint and children as selected
368 fp->SetSelected();
369
370 for( PAD* pad : fp->Pads() )
371 pad->SetSelected();
372
373 // Verify selected state
374 BOOST_CHECK( fp->IsSelected() );
375
376 for( PAD* pad : fp->Pads() )
377 BOOST_CHECK( pad->IsSelected() );
378
379 // Clone and clear selection (as done in renderSelectionToBitmap)
380 std::unique_ptr<FOOTPRINT> clone( static_cast<FOOTPRINT*>( fp->Clone() ) );
381 clone->ClearSelected();
382
383 clone->RunOnChildren(
384 []( BOARD_ITEM* child )
385 {
386 child->ClearSelected();
387 },
389
390 // Verify selection is cleared
391 BOOST_CHECK( !clone->IsSelected() );
392
393 for( PAD* pad : clone->Pads() )
394 BOOST_CHECK( !pad->IsSelected() );
395}
396
397
402BOOST_AUTO_TEST_CASE( PngExport_LayerOrder )
403{
404 // The implementation sets layer order as follows:
405 // 1. Copper layers and their zones (lowest)
406 // 2. Via types
407 // 3. Pads
408 // 4. Holes (highest - drawn on top)
409
410 // Verify the concept: holes should have higher order than pads/vias
411
412 // Count copper layers (32) + zone layers (32) = 64 base layers
413 int copperLayers = LSET::AllCuMask().CuStack().size();
414 int zonePerCopper = 1;
415 int baseLayerCount = copperLayers * ( 1 + zonePerCopper );
416
417 // Via layers (4): THROUGH, BLIND, BURIED, MICROVIA
418 int viaLayerCount = 4;
419
420 // Pads layer (1)
421 int padLayerCount = 1;
422
423 // Hole layers (5): VIA_HOLES, VIA_HOLEWALLS, PAD_PLATEDHOLES, PAD_HOLEWALLS, NON_PLATEDHOLES
424 int holeLayerCount = 5;
425
426 // Verify holes come after pads in the ordering
427 int padOrder = baseLayerCount + viaLayerCount;
428 int holeStartOrder = padOrder + padLayerCount;
429
430 BOOST_CHECK( holeStartOrder > padOrder );
431 BOOST_CHECK_EQUAL( holeLayerCount, 5 );
432}
433
434
438BOOST_AUTO_TEST_CASE( PngExport_BitmapSizeCalculation )
439{
440 // Test the formula: bitmapSize = bbox_IU * viewScale
441 int bboxWidth = 10000; // 10000 IU
442 int bboxHeight = 5000; // 5000 IU
443
444 // At viewScale = 1.0
445 double viewScale1 = 1.0;
446 int bitmapWidth1 = static_cast<int>( bboxWidth * viewScale1 + 0.5 );
447 int bitmapHeight1 = static_cast<int>( bboxHeight * viewScale1 + 0.5 );
448 BOOST_CHECK_EQUAL( bitmapWidth1, 10000 );
449 BOOST_CHECK_EQUAL( bitmapHeight1, 5000 );
450
451 // At viewScale = 0.5 (zoomed out)
452 double viewScale2 = 0.5;
453 int bitmapWidth2 = static_cast<int>( bboxWidth * viewScale2 + 0.5 );
454 int bitmapHeight2 = static_cast<int>( bboxHeight * viewScale2 + 0.5 );
455 BOOST_CHECK_EQUAL( bitmapWidth2, 5000 );
456 BOOST_CHECK_EQUAL( bitmapHeight2, 2500 );
457}
458
459
463BOOST_AUTO_TEST_CASE( PngExport_BitmapSizeClamping )
464{
465 const int maxBitmapSize = 4096;
466
467 int bboxWidth = 10000;
468 int bboxHeight = 5000;
469 double viewScale = 1.0;
470
471 int bitmapWidth = static_cast<int>( bboxWidth * viewScale + 0.5 );
472 int bitmapHeight = static_cast<int>( bboxHeight * viewScale + 0.5 );
473
474 // Apply clamping as in plotSelectionToPng
475 if( bitmapWidth > maxBitmapSize || bitmapHeight > maxBitmapSize )
476 {
477 double scaleDown = static_cast<double>( maxBitmapSize ) / std::max( bitmapWidth, bitmapHeight );
478 bitmapWidth = static_cast<int>( bitmapWidth * scaleDown + 0.5 );
479 bitmapHeight = static_cast<int>( bitmapHeight * scaleDown + 0.5 );
480 viewScale *= scaleDown;
481 }
482
483 BOOST_CHECK( bitmapWidth <= maxBitmapSize );
484 BOOST_CHECK( bitmapHeight <= maxBitmapSize );
485
486 // Check aspect ratio is preserved (2:1)
487 double aspectRatio = static_cast<double>( bitmapWidth ) / bitmapHeight;
488 BOOST_CHECK_CLOSE( aspectRatio, 2.0, 0.1 );
489}
490
491
495BOOST_AUTO_TEST_CASE( SvgExport_LayerNames )
496{
497 // Verify standard layer names are available
498 wxString fCuName = m_board->GetLayerName( F_Cu );
499 wxString bCuName = m_board->GetLayerName( B_Cu );
500 wxString fSilkName = m_board->GetLayerName( F_SilkS );
501
502 BOOST_CHECK( !fCuName.IsEmpty() );
503 BOOST_CHECK( !bCuName.IsEmpty() );
504 BOOST_CHECK( !fSilkName.IsEmpty() );
505
506 // Standard names should be like "F.Cu", "B.Cu", "F.SilkS"
507 BOOST_CHECK( fCuName.Contains( wxT( "Cu" ) ) );
508 BOOST_CHECK( bCuName.Contains( wxT( "Cu" ) ) );
509}
510
511
515BOOST_AUTO_TEST_CASE( SvgExport_CollectLayers )
516{
517 // Add items on different layers
518 AddTrack( 0, 0, 10, 10, F_Cu );
519 AddTrack( 0, 0, 10, 10, B_Cu );
520
521 // Create a selection-like layer set
522 LSET layers;
523
524 for( auto track : m_board->Tracks() )
525 layers |= track->GetLayerSet();
526
527 // Should contain both F.Cu and B.Cu
528 BOOST_CHECK( layers.test( F_Cu ) );
529 BOOST_CHECK( layers.test( B_Cu ) );
530
531 // Should not contain unrelated layers
532 BOOST_CHECK( !layers.test( F_SilkS ) );
533}
534
535
539BOOST_AUTO_TEST_CASE( SvgExport_ContainsArcs )
540{
541 // Add an arc track to the board
542 PCB_ARC* arc = new PCB_ARC( m_board.get() );
543 arc->SetStart( VECTOR2I( pcbIUScale.mmToIU( 0 ), pcbIUScale.mmToIU( 0 ) ) );
544 arc->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 0 ) ) );
545 arc->SetMid( VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ) );
546 arc->SetWidth( pcbIUScale.mmToIU( 0.25 ) );
547 arc->SetLayer( F_Cu );
548 m_board->Add( arc );
549 m_items.push_back( arc );
550
551 // Verify the arc was added and has correct properties
552 BOOST_CHECK_EQUAL( m_board->Tracks().size(), 1 );
554 // Arc should have non-zero angle
555 BOOST_CHECK( !arc->GetAngle().IsZero() );
556}
557
558
562BOOST_AUTO_TEST_CASE( SvgExport_ContainsPcbShapes )
563{
564 // Add a line shape on copper
565 PCB_SHAPE* line = new PCB_SHAPE( m_board.get(), SHAPE_T::SEGMENT );
566 line->SetStart( VECTOR2I( pcbIUScale.mmToIU( 0 ), pcbIUScale.mmToIU( 0 ) ) );
567 line->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
568 line->SetLayer( F_Cu );
569 line->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.15 ), LINE_STYLE::SOLID ) );
570 m_board->Add( line );
571 m_items.push_back( line );
572
573 // Add a rectangle shape
574 PCB_SHAPE* rect = new PCB_SHAPE( m_board.get(), SHAPE_T::RECTANGLE );
575 rect->SetStart( VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 0 ) ) );
576 rect->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 30 ), pcbIUScale.mmToIU( 10 ) ) );
577 rect->SetLayer( F_Cu );
578 rect->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.15 ), LINE_STYLE::SOLID ) );
579 m_board->Add( rect );
580 m_items.push_back( rect );
581
582 // Add a circle shape
583 PCB_SHAPE* circle = new PCB_SHAPE( m_board.get(), SHAPE_T::CIRCLE );
584 circle->SetCenter( VECTOR2I( pcbIUScale.mmToIU( 45 ), pcbIUScale.mmToIU( 5 ) ) );
585 circle->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 50 ), pcbIUScale.mmToIU( 5 ) ) ); // radius = 5mm
586 circle->SetLayer( F_Cu );
587 circle->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.15 ), LINE_STYLE::SOLID ) );
588 m_board->Add( circle );
589 m_items.push_back( circle );
590
591 // Verify shapes were added
592 size_t shapeCount = 0;
593
594 for( BOARD_ITEM* item : m_board->Drawings() )
595 {
596 if( item->Type() == PCB_SHAPE_T )
597 shapeCount++;
598 }
599
600 BOOST_CHECK_EQUAL( shapeCount, 3 );
601}
602
603
607BOOST_AUTO_TEST_CASE( SvgExport_ContainsPcbText )
608{
609 // Add text on silkscreen
610 PCB_TEXT* text = new PCB_TEXT( m_board.get() );
611 text->SetText( wxT( "Test Label" ) );
612 text->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 10 ), pcbIUScale.mmToIU( 10 ) ) );
613 text->SetLayer( F_SilkS );
614 text->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
615 m_board->Add( text );
616 m_items.push_back( text );
617
618 // Verify the text was added
619 size_t textCount = 0;
620
621 for( BOARD_ITEM* item : m_board->Drawings() )
622 {
623 if( item->Type() == PCB_TEXT_T )
624 textCount++;
625 }
626
627 BOOST_CHECK_EQUAL( textCount, 1 );
628 BOOST_CHECK( text->GetText() == wxT( "Test Label" ) );
629 BOOST_CHECK_EQUAL( text->GetLayer(), F_SilkS );
630}
631
632
636BOOST_AUTO_TEST_CASE( SvgExport_ContainsBlindVia )
637{
638 PCB_VIA* via = new PCB_VIA( m_board.get() );
639 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 15 ), pcbIUScale.mmToIU( 15 ) ) );
640 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.6 ) );
641 via->SetDrill( pcbIUScale.mmToIU( 0.3 ) );
642 via->SetViaType( VIATYPE::BLIND );
643 via->SetLayerPair( F_Cu, In1_Cu );
644 m_board->Add( via );
645 m_items.push_back( via );
646
647 // Verify the blind via was added
648 PCB_VIA* foundVia = nullptr;
649
650 for( auto item : m_board->Tracks() )
651 {
652 if( item->Type() == PCB_VIA_T )
653 {
654 foundVia = static_cast<PCB_VIA*>( item );
655 break;
656 }
657 }
658
659 BOOST_REQUIRE( foundVia != nullptr );
660 BOOST_CHECK( foundVia->GetViaType() == VIATYPE::BLIND );
661}
662
663
667BOOST_AUTO_TEST_CASE( SvgExport_ContainsMicroVia )
668{
669 PCB_VIA* via = new PCB_VIA( m_board.get() );
670 via->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) );
671 via->SetWidth( PADSTACK::ALL_LAYERS, pcbIUScale.mmToIU( 0.4 ) );
672 via->SetDrill( pcbIUScale.mmToIU( 0.2 ) );
673 via->SetViaType( VIATYPE::MICROVIA );
674 via->SetLayerPair( F_Cu, In1_Cu );
675 m_board->Add( via );
676 m_items.push_back( via );
677
678 // Verify the micro via was added
679 PCB_VIA* foundVia = nullptr;
680
681 for( auto item : m_board->Tracks() )
682 {
683 if( item->Type() == PCB_VIA_T )
684 {
685 foundVia = static_cast<PCB_VIA*>( item );
686 break;
687 }
688 }
689
690 BOOST_REQUIRE( foundVia != nullptr );
691 BOOST_CHECK( foundVia->GetViaType() == VIATYPE::MICROVIA );
692}
693
694
698BOOST_AUTO_TEST_CASE( SvgExport_MultipleCopperLayers )
699{
700 AddTrack( 0, 0, 10, 10, F_Cu );
701 AddTrack( 0, 0, 10, 10, In1_Cu );
702 AddTrack( 0, 0, 10, 10, In2_Cu );
703 AddTrack( 0, 0, 10, 10, B_Cu );
704
705 // Verify tracks were added on different layers
706 BOOST_CHECK_EQUAL( m_board->Tracks().size(), 4 );
707
708 // Collect layers from tracks
709 LSET layers;
710
711 for( auto track : m_board->Tracks() )
712 layers |= track->GetLayerSet();
713
714 BOOST_CHECK( layers.test( F_Cu ) );
715 BOOST_CHECK( layers.test( In1_Cu ) );
716 BOOST_CHECK( layers.test( In2_Cu ) );
717 BOOST_CHECK( layers.test( B_Cu ) );
718}
719
720
724BOOST_AUTO_TEST_CASE( SvgExport_FootprintGraphics )
725{
726 FOOTPRINT* fp = AddFootprint( 50, 50, wxT( "J1" ) );
727
728 // Add a line to the footprint silkscreen
729 PCB_SHAPE* fpLine = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
730 fpLine->SetStart( VECTOR2I( pcbIUScale.mmToIU( -2 ), pcbIUScale.mmToIU( -2 ) ) );
731 fpLine->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 2 ), pcbIUScale.mmToIU( -2 ) ) );
732 fpLine->SetLayer( F_SilkS );
733 fpLine->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.12 ), LINE_STYLE::SOLID ) );
734 fp->Add( fpLine );
735
736 // Add a rectangle to the footprint fabrication layer
737 PCB_SHAPE* fpRect = new PCB_SHAPE( fp, SHAPE_T::RECTANGLE );
738 fpRect->SetStart( VECTOR2I( pcbIUScale.mmToIU( -3 ), pcbIUScale.mmToIU( -3 ) ) );
739 fpRect->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 3 ), pcbIUScale.mmToIU( 3 ) ) );
740 fpRect->SetLayer( F_Fab );
741 fpRect->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.1 ), LINE_STYLE::SOLID ) );
742 fp->Add( fpRect );
743
744 // Verify footprint graphics were added
745 int graphicsCount = 0;
746
747 for( BOARD_ITEM* item : fp->GraphicalItems() )
748 {
749 if( item->Type() == PCB_SHAPE_T )
750 graphicsCount++;
751 }
752
753 BOOST_CHECK_EQUAL( graphicsCount, 2 );
754}
755
756
760BOOST_AUTO_TEST_CASE( SvgExport_ContainsSmdPads )
761{
762 FOOTPRINT* fp = AddFootprint( 75, 75, wxT( "C1" ) );
763
764 // Add SMD pads (no hole)
765 PAD* pad1 = new PAD( fp );
766 pad1->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 74 ), pcbIUScale.mmToIU( 75 ) ) );
767 pad1->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.5 ) ) );
770 pad1->SetNumber( wxT( "1" ) );
771 pad1->SetLayerSet( LSET( { F_Cu, F_Paste, F_Mask } ) );
772 fp->Add( pad1 );
773
774 PAD* pad2 = new PAD( fp );
775 pad2->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 76 ), pcbIUScale.mmToIU( 75 ) ) );
776 pad2->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.5 ) ) );
779 pad2->SetNumber( wxT( "2" ) );
780 pad2->SetLayerSet( LSET( { F_Cu, F_Paste, F_Mask } ) );
781 fp->Add( pad2 );
782
783 // Verify SMD pads were added
784 BOOST_CHECK_EQUAL( fp->Pads().size(), 2 );
785
786 for( PAD* pad : fp->Pads() )
787 {
788 BOOST_CHECK( pad->GetAttribute() == PAD_ATTRIB::SMD );
789 BOOST_CHECK( pad->GetDrillSize().x == 0 ); // No drill for SMD
790 }
791}
792
793
797BOOST_AUTO_TEST_CASE( SvgExport_ZoneWithNet )
798{
799 // Create a zone on bottom copper
800 ZONE* zone = new ZONE( m_board.get() );
801 zone->SetLayer( B_Cu );
802 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 0 ) ), -1 );
803 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 100 ), pcbIUScale.mmToIU( 20 ) ), -1 );
804 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 120 ), pcbIUScale.mmToIU( 20 ) ), -1 );
805 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 120 ), pcbIUScale.mmToIU( 0 ) ), -1 );
806 zone->SetZoneName( wxT( "TestZone" ) );
807 m_board->Add( zone );
808 m_items.push_back( zone );
809
810 // Verify the zone was added
811 BOOST_CHECK_EQUAL( m_board->Zones().size(), 1 );
813 BOOST_CHECK( zone->GetZoneName() == wxT( "TestZone" ) );
814}
815
816
820BOOST_AUTO_TEST_CASE( BoundingBox_MultipleItems )
821{
822 AddTrack( 0, 0, 10, 10, F_Cu );
823 AddVia( 20, 20 );
824 AddFootprint( 40, 40, wxT( "R1" ) );
825
826 // Compute bounding box for all items
827 BOX2I bbox;
828
829 for( BOARD_ITEM* item : m_items )
830 {
831 if( bbox.GetWidth() == 0 && bbox.GetHeight() == 0 )
832 bbox = item->GetBoundingBox();
833 else
834 bbox.Merge( item->GetBoundingBox() );
835 }
836
837 // Bounding box should encompass all items
838 BOOST_CHECK( bbox.GetWidth() > 0 );
839 BOOST_CHECK( bbox.GetHeight() > 0 );
840 BOOST_CHECK( bbox.Contains( VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ) ) );
841 BOOST_CHECK( bbox.Contains( VECTOR2I( pcbIUScale.mmToIU( 20 ), pcbIUScale.mmToIU( 20 ) ) ) );
842}
843
844
849BOOST_AUTO_TEST_CASE( SvgExport_FillOpacity_MatchesColorAlpha )
850{
851 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_alpha_test" ) ) );
852 tempFile.SetExt( wxT( "svg" ) );
853
854 SVG_PLOTTER plotter;
855
856 PAGE_INFO pageInfo;
857 pageInfo.SetWidthMils( 1000 );
858 pageInfo.SetHeightMils( 1000 );
859 plotter.SetPageSettings( pageInfo );
860 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
861 plotter.SetColorMode( true );
862
863 BOOST_REQUIRE( plotter.OpenFile( tempFile.GetFullPath() ) );
864
865 plotter.StartPlot( wxT( "1" ) );
866
867 // Test with a color that has alpha = 0.5
868 double testAlpha = 0.5;
869 COLOR4D colorWithAlpha( 1.0, 0.0, 0.0, testAlpha );
870 plotter.SetColor( colorWithAlpha );
871
872 // Draw a filled shape to trigger the fill-opacity output
873 plotter.Rect( VECTOR2I( 100, 100 ), VECTOR2I( 500, 500 ), FILL_T::FILLED_SHAPE, 10 );
874
875 plotter.EndPlot();
876
877 // Read the SVG file and verify fill-opacity
878 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
879 BOOST_REQUIRE( file.IsOpened() );
880
881 wxString content;
882 file.ReadAll( &content );
883 file.Close();
884
885 // The SVG should contain fill-opacity matching our alpha value
886 // It should NOT have fill-opacity:0 for a color with alpha=0.5
887 wxString fillOpacityPattern = wxT( "fill-opacity:0.5" );
888 wxString badFillOpacity = wxT( "fill-opacity:0" );
889
890 // Check that the alpha value is represented in fill-opacity
891 // Note: The SVG plotter uses 4-digit precision, so 0.5 should be "0.5000"
892 BOOST_CHECK_MESSAGE( content.Contains( wxT( "fill-opacity:0.5" ) ) ||
893 content.Contains( wxT( "fill-opacity: 0.5" ) ),
894 "SVG should contain fill-opacity matching color alpha (0.5)" );
895
896 // Verify we don't have fill-opacity:0 (which would make the fill invisible)
897 // Check that if fill-opacity:0 exists, it's not at the start (might be 0.5xxx)
898 if( content.Contains( wxT( "fill-opacity:0;" ) ) ||
899 content.Contains( wxT( "fill-opacity:0 " ) ) ||
900 content.Contains( wxT( "fill-opacity: 0;" ) ) )
901 {
902 BOOST_CHECK_MESSAGE( false,
903 "SVG should NOT have fill-opacity:0 when color alpha is 0.5" );
904 }
905
906 wxRemoveFile( tempFile.GetFullPath() );
907}
908
909
913BOOST_AUTO_TEST_CASE( SvgExport_FillOpacity_FullyOpaque )
914{
915 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_opaque_test" ) ) );
916 tempFile.SetExt( wxT( "svg" ) );
917
918 SVG_PLOTTER plotter;
919
920 PAGE_INFO pageInfo;
921 pageInfo.SetWidthMils( 1000 );
922 pageInfo.SetHeightMils( 1000 );
923 plotter.SetPageSettings( pageInfo );
924 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
925 plotter.SetColorMode( true );
926
927 BOOST_REQUIRE( plotter.OpenFile( tempFile.GetFullPath() ) );
928
929 plotter.StartPlot( wxT( "1" ) );
930
931 // Test with a fully opaque color (alpha = 1.0)
932 COLOR4D opaqueColor( 0.0, 0.0, 1.0, 1.0 );
933 plotter.SetColor( opaqueColor );
934
935 // Draw a filled rectangle
936 plotter.Rect( VECTOR2I( 100, 100 ), VECTOR2I( 500, 500 ), FILL_T::FILLED_SHAPE, 10 );
937
938 plotter.EndPlot();
939
940 // Read the SVG file
941 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
942 BOOST_REQUIRE( file.IsOpened() );
943
944 wxString content;
945 file.ReadAll( &content );
946 file.Close();
947
948 // The SVG should have fill-opacity:1.0 for fully opaque colors
949 BOOST_CHECK_MESSAGE( content.Contains( wxT( "fill-opacity:1" ) ) ||
950 content.Contains( wxT( "fill-opacity: 1" ) ),
951 "SVG should contain fill-opacity:1 for fully opaque colors" );
952
953 wxRemoveFile( tempFile.GetFullPath() );
954}
955
956
961BOOST_AUTO_TEST_CASE( SvgExport_FootprintPads_IncludedInOutput )
962{
963 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_fp_pads" ) ) );
964 tempFile.SetExt( wxT( "svg" ) );
965
966 SVG_PLOTTER plotter;
967
968 PAGE_INFO pageInfo;
969 pageInfo.SetWidthMils( 2000 );
970 pageInfo.SetHeightMils( 2000 );
971 plotter.SetPageSettings( pageInfo );
972 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
973 plotter.SetColorMode( true );
974
975 BOOST_REQUIRE( plotter.OpenFile( tempFile.GetFullPath() ) );
976
977 plotter.StartPlot( wxT( "1" ) );
978 plotter.StartLayer( wxT( "F.Cu" ) );
979
980 // Create a footprint with multiple pads
981 FOOTPRINT* fp = AddFootprint( 25, 25, wxT( "TestFP" ) );
982 AddPad( fp, 23, 25, wxT( "1" ) ); // Pad 1
983 AddPad( fp, 27, 25, wxT( "2" ) ); // Pad 2
984
985 // Set color and draw circles at pad positions to simulate pad plotting
986 COLOR4D padColor( 1.0, 0.0, 0.0, 1.0 );
987 plotter.SetColor( padColor );
988
989 for( PAD* pad : fp->Pads() )
990 {
991 // Draw a circle at each pad position
992 int radius = pcbIUScale.mmToIU( 0.75 ); // Half of 1.5mm pad size
993 plotter.Circle( pad->GetPosition(), radius * 2, FILL_T::FILLED_SHAPE, 0 );
994 }
995
996 plotter.EndLayer();
997 plotter.EndPlot();
998
999 // Read the SVG file
1000 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
1001 BOOST_REQUIRE( file.IsOpened() );
1002
1003 wxString content;
1004 file.ReadAll( &content );
1005 file.Close();
1006
1007 // The SVG should contain circle elements for the pads
1008 // Count circle elements - should have at least 2 for our 2 pads
1009 int circleCount = 0;
1010 int pos = 0;
1011
1012 while( ( pos = content.find( wxT( "<circle" ), pos ) ) != wxNOT_FOUND )
1013 {
1014 circleCount++;
1015 pos += 7; // Move past "<circle"
1016 }
1017
1018 BOOST_CHECK_MESSAGE( circleCount >= 2,
1019 "SVG should contain circle elements for footprint pads. "
1020 "Found: " << circleCount << ", expected at least 2" );
1021
1022 wxRemoveFile( tempFile.GetFullPath() );
1023}
1024
1025
1029BOOST_AUTO_TEST_CASE( SvgExport_FootprintGraphics_IncludedInOutput )
1030{
1031 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_fp_graphics" ) ) );
1032 tempFile.SetExt( wxT( "svg" ) );
1033
1034 SVG_PLOTTER plotter;
1035
1036 PAGE_INFO pageInfo;
1037 pageInfo.SetWidthMils( 2000 );
1038 pageInfo.SetHeightMils( 2000 );
1039 plotter.SetPageSettings( pageInfo );
1040 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
1041 plotter.SetColorMode( true );
1042
1043 BOOST_REQUIRE( plotter.OpenFile( tempFile.GetFullPath() ) );
1044
1045 plotter.StartPlot( wxT( "1" ) );
1046 plotter.StartLayer( wxT( "F.SilkS" ) );
1047
1048 // Create a footprint with graphical items
1049 FOOTPRINT* fp = AddFootprint( 50, 50, wxT( "TestGraphics" ) );
1050
1051 // Add a line to the footprint silkscreen
1052 PCB_SHAPE* fpLine = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
1053 fpLine->SetStart( VECTOR2I( pcbIUScale.mmToIU( 48 ), pcbIUScale.mmToIU( 48 ) ) );
1054 fpLine->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 52 ), pcbIUScale.mmToIU( 48 ) ) );
1055 fpLine->SetLayer( F_SilkS );
1056 fpLine->SetStroke( STROKE_PARAMS( pcbIUScale.mmToIU( 0.12 ), LINE_STYLE::SOLID ) );
1057 fp->Add( fpLine );
1058
1059 // Draw line using plotter (simulating what plotSelectionToSvg does)
1060 COLOR4D silkColor( 1.0, 1.0, 0.0, 1.0 );
1061 plotter.SetColor( silkColor );
1062 plotter.ThickSegment( fpLine->GetStart(), fpLine->GetEnd(),
1063 pcbIUScale.mmToIU( 0.12 ), nullptr );
1064
1065 plotter.EndLayer();
1066 plotter.EndPlot();
1067
1068 // Read the SVG file
1069 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
1070 BOOST_REQUIRE( file.IsOpened() );
1071
1072 wxString content;
1073 file.ReadAll( &content );
1074 file.Close();
1075
1076 // The SVG should contain line or path elements for the silkscreen graphics
1077 bool hasLineContent = content.Contains( wxT( "<line" ) ) ||
1078 content.Contains( wxT( "<path" ) ) ||
1079 content.Contains( wxT( "<polyline" ) );
1080
1081 BOOST_CHECK_MESSAGE( hasLineContent,
1082 "SVG should contain line/path elements for footprint graphics" );
1083
1084 wxRemoveFile( tempFile.GetFullPath() );
1085}
1086
1087
1092BOOST_AUTO_TEST_CASE( SvgExport_ColorAlpha_PreservedThroughSetColor )
1093{
1094 // This test verifies that when we call SetColor with a COLOR4D that has
1095 // a specific alpha value, the SVG output reflects that alpha in fill-opacity.
1096
1097 // Test various alpha values
1098 std::vector<double> testAlphas = { 0.0, 0.25, 0.5, 0.75, 1.0 };
1099
1100 for( double expectedAlpha : testAlphas )
1101 {
1102 wxFileName tempFile( wxFileName::CreateTempFileName( wxT( "kicad_svg_alpha" ) ) );
1103 tempFile.SetExt( wxT( "svg" ) );
1104
1105 SVG_PLOTTER plotter;
1106
1107 PAGE_INFO pageInfo;
1108 pageInfo.SetWidthMils( 500 );
1109 pageInfo.SetHeightMils( 500 );
1110 plotter.SetPageSettings( pageInfo );
1111 plotter.SetViewport( VECTOR2I( 0, 0 ), 1, 1.0, false );
1112 plotter.SetColorMode( true );
1113
1114 BOOST_REQUIRE( plotter.OpenFile( tempFile.GetFullPath() ) );
1115
1116 plotter.StartPlot( wxT( "1" ) );
1117
1118 // Set color with specific alpha
1119 COLOR4D testColor( 0.5, 0.5, 0.5, expectedAlpha );
1120 plotter.SetColor( testColor );
1121
1122 // Draw something
1123 plotter.Circle( VECTOR2I( 250, 250 ), 200, FILL_T::FILLED_SHAPE, 10 );
1124
1125 plotter.EndPlot();
1126
1127 // Read and verify
1128 wxFFile file( tempFile.GetFullPath(), wxT( "r" ) );
1129 BOOST_REQUIRE( file.IsOpened() );
1130
1131 wxString content;
1132 file.ReadAll( &content );
1133 file.Close();
1134
1135 // Build the expected fill-opacity pattern
1136 wxString expectedPattern = wxString::Format( wxT( "fill-opacity:%.1f" ), expectedAlpha );
1137
1138 // For alpha=0, we should find "fill-opacity:0" (which is correct for transparent)
1139 // For alpha=1, we should find "fill-opacity:1"
1140 // For alpha=0.5, we should find "fill-opacity:0.5"
1141 if( expectedAlpha == 0.0 )
1142 {
1143 BOOST_CHECK_MESSAGE( content.Contains( wxT( "fill-opacity:0" ) ),
1144 "Alpha=0 should produce fill-opacity:0" );
1145 }
1146 else if( expectedAlpha == 1.0 )
1147 {
1148 BOOST_CHECK_MESSAGE( content.Contains( wxT( "fill-opacity:1" ) ),
1149 "Alpha=1 should produce fill-opacity:1" );
1150 }
1151 else
1152 {
1153 // For intermediate values, check we don't have fill-opacity:0 or fill-opacity:1
1154 // when we shouldn't
1155 bool hasSemiTransparent = content.Contains( wxString::Format( wxT( "fill-opacity:%.4f" ), expectedAlpha ) ) ||
1156 content.Contains( wxString::Format( wxT( "fill-opacity:%.1f" ), expectedAlpha ) );
1157 BOOST_CHECK_MESSAGE( hasSemiTransparent ||
1158 !( content.Contains( wxT( "fill-opacity:0;" ) ) ||
1159 content.Contains( wxT( "fill-opacity:1.0000;" ) ) ),
1160 "Alpha=" << expectedAlpha << " should not produce fill-opacity:0 or 1" );
1161 }
1162
1163 wxRemoveFile( tempFile.GetFullPath() );
1164 }
1165}
1166
1167
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
void AddZone(PCB_LAYER_ID layer=F_Cu)
void AddPad(FOOTPRINT *fp, int x, int y, const wxString &padNum, PAD_SHAPE shape=PAD_SHAPE::CIRCLE)
~CLIPBOARD_EXPORT_FIXTURE()=default
std::unique_ptr< BOARD > m_board
void AddTrack(int x1, int y1, int x2, int y2, PCB_LAYER_ID layer=F_Cu)
FOOTPRINT * AddFootprint(int x, int y, const wxString &ref=wxT("U1"))
std::vector< BOARD_ITEM * > m_items
bool IsZero() const
Definition eda_angle.h:136
void ClearSelected()
Definition eda_item.h:143
bool IsSelected() const
Definition eda_item.h:127
void SetSelected()
Definition eda_item.h:140
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:216
void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:178
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:174
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:220
void SetPosition(const VECTOR2I &aPos) override
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::deque< PAD * > & Pads()
Definition footprint.h:304
void SetReference(const wxString &aReference)
Definition footprint.h:747
void SetValue(const wxString &aValue)
Definition footprint.h:768
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
DRAWINGS & GraphicalItems()
Definition footprint.h:307
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:246
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:659
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:55
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:1316
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:560
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:337
const wxString & GetNumber() const
Definition pad.h:137
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:187
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:136
void SetPosition(const VECTOR2I &aPos) override
Definition pad.h:203
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:259
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:1588
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
void SetHeightMils(double aHeightInMils)
void SetWidthMils(double aWidthInMils)
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:346
EDA_ANGLE GetAngle() const
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition pcb_shape.h:92
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:150
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:153
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_track.cpp:71
const VECTOR2I & GetStart() const
Definition pcb_track.h:154
const VECTOR2I & GetEnd() const
Definition pcb_track.h:151
virtual void SetWidth(int aWidth)
Definition pcb_track.h:147
VIATYPE GetViaType() const
Definition pcb_track.h:455
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:77
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition plotter.h:169
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition plotter.h:163
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
virtual void SetColor(const COLOR4D &color) override
The SetColor implementation is split with the subclasses: the PSLIKE computes the rgb values,...
Simple container to manage line stroke parameters.
virtual bool StartPlot(const wxString &aPageNumber) override
Create SVG file header.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
void EndLayer()
End the current layer group in the SVG output.
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width, int aCornerRadius=0) override
virtual bool EndPlot() override
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width) override
void StartLayer(const wxString &aLayerName)
Start a new named layer group in the SVG output.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:517
const wxString & GetZoneName() const
Definition zone.h:159
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition zone.cpp:1135
void SetZoneName(const wxString &aName)
Definition zone.h:160
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:493
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:515
@ RECURSE
Definition eda_item.h:51
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_Paste
Definition layer_ids.h:104
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ In2_Cu
Definition layer_ids.h:67
@ F_Fab
Definition layer_ids.h:119
@ F_SilkS
Definition layer_ids.h:100
@ In1_Cu
Definition layer_ids.h:66
@ F_Cu
Definition layer_ids.h:64
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition padstack.h:52
@ RECTANGLE
Definition padstack.h:54
@ THROUGH
Definition pcb_track.h:68
@ MICROVIA
Definition pcb_track.h:71
Plotting engines similar to ps (PostScript, Gerber, svg)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(SvgPlotter_LayerSupport)
Test that SVG_PLOTTER supports the StartLayer and EndLayer methods for proper Inkscape-compatible lay...
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
int radius
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695