32#include <boost/test/unit_test.hpp>
47#include <wx/mstream.h>
55 m_board = std::make_unique<BOARD>();
92 pad->SetNumber( padNum );
102 fp->
SetValue( wxT(
"TestComponent" ) );
134 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_layer_test" ) ) );
135 tempFile.SetExt( wxT(
"svg" ) );
146 BOOST_CHECK( plotter.
OpenFile( tempFile.GetFullPath() ) );
151 wxString layerName = wxT(
"F.Cu" );
163 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
167 file.ReadAll( &content );
172 BOOST_CHECK( content.Contains( wxT(
"xmlns:inkscape" ) ) );
175 BOOST_CHECK( content.Contains( wxT(
"inkscape:groupmode=\"layer\"" ) ) );
178 BOOST_CHECK( content.Contains( wxT(
"inkscape:label=\"F.Cu\"" ) ) );
181 BOOST_CHECK( content.Contains( wxT(
"id=\"F.Cu\"" ) ) );
183 wxRemoveFile( tempFile.GetFullPath() );
193 AddTrack( 0, 0, 10, 10,
F_Cu );
217 auto tracks = m_board->Tracks();
220 for(
auto item : tracks )
242 FOOTPRINT* fp = AddFootprint( 25, 25, wxT(
"U1" ) );
243 AddPad( fp, 25, 23, wxT(
"1" ) );
244 AddPad( fp, 25, 27, wxT(
"2" ) );
255 BOOST_CHECK( !pad1->
GetNumber().IsEmpty() );
272 ZONE* zone = m_board->Zones()[0];
286 int rW = 255, gW = 0, bW = 0;
287 int rB = 255, gB = 0, bB = 0;
292 int avgDiff = ( diffR + diffG + diffB ) / 3;
293 int alpha = 255 - avgDiff;
303 int rW = 255, gW = 255, bW = 255;
304 int rB = 0, gB = 0, bB = 0;
309 int avgDiff = ( diffR + diffG + diffB ) / 3;
310 int alpha = 255 - avgDiff;
322 int rW = 192, gW = 192, bW = 192;
323 int rB = 64, gB = 64, bB = 64;
328 int avgDiff = ( diffR + diffG + diffB ) / 3;
329 int alpha = 255 - avgDiff;
331 BOOST_CHECK_CLOSE(
static_cast<double>( alpha ), 128.0, 1.0 );
341 AddTrack( 0, 0, 10, 10,
F_Cu );
350 std::unique_ptr<BOARD_ITEM> clone(
static_cast<BOARD_ITEM*
>( track->
Clone() ) );
351 clone->ClearSelected();
354 BOOST_CHECK( !clone->IsSelected() );
363 FOOTPRINT* fp = AddFootprint( 25, 25, wxT(
"U1" ) );
364 AddPad( fp, 25, 23, wxT(
"1" ) );
365 AddPad( fp, 25, 27, wxT(
"2" ) );
377 BOOST_CHECK(
pad->IsSelected() );
380 std::unique_ptr<FOOTPRINT> clone(
static_cast<FOOTPRINT*
>( fp->
Clone() ) );
381 clone->ClearSelected();
383 clone->RunOnChildren(
391 BOOST_CHECK( !clone->IsSelected() );
393 for(
PAD*
pad : clone->Pads() )
394 BOOST_CHECK( !
pad->IsSelected() );
414 int zonePerCopper = 1;
415 int baseLayerCount = copperLayers * ( 1 + zonePerCopper );
418 int viaLayerCount = 4;
421 int padLayerCount = 1;
424 int holeLayerCount = 5;
427 int padOrder = baseLayerCount + viaLayerCount;
428 int holeStartOrder = padOrder + padLayerCount;
430 BOOST_CHECK( holeStartOrder > padOrder );
441 int bboxWidth = 10000;
442 int bboxHeight = 5000;
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 );
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 );
465 const int maxBitmapSize = 4096;
467 int bboxWidth = 10000;
468 int bboxHeight = 5000;
469 double viewScale = 1.0;
471 int bitmapWidth =
static_cast<int>( bboxWidth * viewScale + 0.5 );
472 int bitmapHeight =
static_cast<int>( bboxHeight * viewScale + 0.5 );
475 if( bitmapWidth > maxBitmapSize || bitmapHeight > maxBitmapSize )
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;
483 BOOST_CHECK( bitmapWidth <= maxBitmapSize );
484 BOOST_CHECK( bitmapHeight <= maxBitmapSize );
487 double aspectRatio =
static_cast<double>( bitmapWidth ) / bitmapHeight;
488 BOOST_CHECK_CLOSE( aspectRatio, 2.0, 0.1 );
498 wxString fCuName = m_board->GetLayerName(
F_Cu );
499 wxString bCuName = m_board->GetLayerName(
B_Cu );
500 wxString fSilkName = m_board->GetLayerName(
F_SilkS );
502 BOOST_CHECK( !fCuName.IsEmpty() );
503 BOOST_CHECK( !bCuName.IsEmpty() );
504 BOOST_CHECK( !fSilkName.IsEmpty() );
507 BOOST_CHECK( fCuName.Contains( wxT(
"Cu" ) ) );
508 BOOST_CHECK( bCuName.Contains( wxT(
"Cu" ) ) );
518 AddTrack( 0, 0, 10, 10,
F_Cu );
519 AddTrack( 0, 0, 10, 10,
B_Cu );
524 for(
auto track : m_board->Tracks() )
525 layers |= track->GetLayerSet();
528 BOOST_CHECK( layers.test(
F_Cu ) );
529 BOOST_CHECK( layers.test(
B_Cu ) );
532 BOOST_CHECK( !layers.test(
F_SilkS ) );
549 m_items.push_back( arc );
570 m_board->Add( line );
571 m_items.push_back( line );
579 m_board->Add( rect );
580 m_items.push_back( rect );
589 m_items.push_back(
circle );
592 size_t shapeCount = 0;
611 text->SetText( wxT(
"Test Label" ) );
615 m_board->Add(
text );
616 m_items.push_back(
text );
619 size_t textCount = 0;
628 BOOST_CHECK(
text->GetText() == wxT(
"Test Label" ) );
645 m_items.push_back(
via );
650 for(
auto item : m_board->Tracks() )
654 foundVia =
static_cast<PCB_VIA*
>( item );
676 m_items.push_back(
via );
681 for(
auto item : m_board->Tracks() )
685 foundVia =
static_cast<PCB_VIA*
>( item );
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 );
711 for(
auto track : m_board->Tracks() )
712 layers |= track->GetLayerSet();
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 ) );
726 FOOTPRINT* fp = AddFootprint( 50, 50, wxT(
"J1" ) );
745 int graphicsCount = 0;
762 FOOTPRINT* fp = AddFootprint( 75, 75, wxT(
"C1" ) );
765 PAD* pad1 =
new PAD( fp );
774 PAD* pad2 =
new PAD( fp );
789 BOOST_CHECK(
pad->GetDrillSize().x == 0 );
800 ZONE* zone =
new ZONE( m_board.get() );
807 m_board->Add( zone );
808 m_items.push_back( zone );
813 BOOST_CHECK( zone->
GetZoneName() == wxT(
"TestZone" ) );
822 AddTrack( 0, 0, 10, 10,
F_Cu );
824 AddFootprint( 40, 40, wxT(
"R1" ) );
832 bbox = item->GetBoundingBox();
834 bbox.
Merge( item->GetBoundingBox() );
851 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_alpha_test" ) ) );
852 tempFile.SetExt( wxT(
"svg" ) );
868 double testAlpha = 0.5;
869 COLOR4D colorWithAlpha( 1.0, 0.0, 0.0, testAlpha );
878 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
882 file.ReadAll( &content );
887 wxString fillOpacityPattern = wxT(
"fill-opacity:0.5" );
888 wxString badFillOpacity = wxT(
"fill-opacity:0" );
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)" );
898 if( content.Contains( wxT(
"fill-opacity:0;" ) ) ||
899 content.Contains( wxT(
"fill-opacity:0 " ) ) ||
900 content.Contains( wxT(
"fill-opacity: 0;" ) ) )
902 BOOST_CHECK_MESSAGE(
false,
903 "SVG should NOT have fill-opacity:0 when color alpha is 0.5" );
906 wxRemoveFile( tempFile.GetFullPath() );
915 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_opaque_test" ) ) );
916 tempFile.SetExt( wxT(
"svg" ) );
932 COLOR4D opaqueColor( 0.0, 0.0, 1.0, 1.0 );
941 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
945 file.ReadAll( &content );
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" );
953 wxRemoveFile( tempFile.GetFullPath() );
963 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_fp_pads" ) ) );
964 tempFile.SetExt( wxT(
"svg" ) );
981 FOOTPRINT* fp = AddFootprint( 25, 25, wxT(
"TestFP" ) );
982 AddPad( fp, 23, 25, wxT(
"1" ) );
983 AddPad( fp, 27, 25, wxT(
"2" ) );
986 COLOR4D padColor( 1.0, 0.0, 0.0, 1.0 );
1000 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
1004 file.ReadAll( &content );
1009 int circleCount = 0;
1012 while( ( pos = content.find( wxT(
"<circle" ), pos ) ) != wxNOT_FOUND )
1018 BOOST_CHECK_MESSAGE( circleCount >= 2,
1019 "SVG should contain circle elements for footprint pads. "
1020 "Found: " << circleCount <<
", expected at least 2" );
1022 wxRemoveFile( tempFile.GetFullPath() );
1031 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_fp_graphics" ) ) );
1032 tempFile.SetExt( wxT(
"svg" ) );
1049 FOOTPRINT* fp = AddFootprint( 50, 50, wxT(
"TestGraphics" ) );
1060 COLOR4D silkColor( 1.0, 1.0, 0.0, 1.0 );
1069 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
1073 file.ReadAll( &content );
1077 bool hasLineContent = content.Contains( wxT(
"<line" ) ) ||
1078 content.Contains( wxT(
"<path" ) ) ||
1079 content.Contains( wxT(
"<polyline" ) );
1081 BOOST_CHECK_MESSAGE( hasLineContent,
1082 "SVG should contain line/path elements for footprint graphics" );
1084 wxRemoveFile( tempFile.GetFullPath() );
1098 std::vector<double> testAlphas = { 0.0, 0.25, 0.5, 0.75, 1.0 };
1100 for(
double expectedAlpha : testAlphas )
1102 wxFileName tempFile( wxFileName::CreateTempFileName( wxT(
"kicad_svg_alpha" ) ) );
1103 tempFile.SetExt( wxT(
"svg" ) );
1119 COLOR4D testColor( 0.5, 0.5, 0.5, expectedAlpha );
1128 wxFFile file( tempFile.GetFullPath(), wxT(
"r" ) );
1132 file.ReadAll( &content );
1136 wxString expectedPattern = wxString::Format( wxT(
"fill-opacity:%.1f" ), expectedAlpha );
1141 if( expectedAlpha == 0.0 )
1143 BOOST_CHECK_MESSAGE( content.Contains( wxT(
"fill-opacity:0" ) ),
1144 "Alpha=0 should produce fill-opacity:0" );
1146 else if( expectedAlpha == 1.0 )
1148 BOOST_CHECK_MESSAGE( content.Contains( wxT(
"fill-opacity:1" ) ),
1149 "Alpha=1 should produce fill-opacity:1" );
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" );
1163 wxRemoveFile( tempFile.GetFullPath() );
constexpr EDA_IU_SCALE pcbIUScale
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...
constexpr size_type GetWidth() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr size_type GetHeight() const
constexpr bool Contains(const Vec &aPoint) const
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
CLIPBOARD_EXPORT_FIXTURE()
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
void AddVia(int x, int y)
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
void SetEnd(const VECTOR2I &aEnd)
A color representation with 4 components: red, green, blue, alpha.
LSET is a set of PCB_LAYER_IDs.
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
void SetAttribute(PAD_ATTRIB aAttribute)
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
static LSET PTHMask()
layer set for a through hole pad
const wxString & GetNumber() const
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
void SetPosition(const VECTOR2I &aPos) override
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
void SetLayerSet(const LSET &aLayers) override
Describe the page size and margins of a paper page on which to eventually print or plot.
void SetHeightMils(double aHeightInMils)
void SetWidthMils(double aWidthInMils)
void SetMid(const VECTOR2I &aMid)
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
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual void SetWidth(int aWidth)
VIATYPE GetViaType() const
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
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.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
const wxString & GetZoneName() const
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
void SetZoneName(const wxString &aName)
PCB_LAYER_ID GetFirstLayer() const
int GetNumCorners(void) const
Access to m_Poly parameters.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_SHAPE
Fill with object color.
PCB_LAYER_ID
A quick note on layer IDs:
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
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()
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
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
VECTOR2< int32_t > VECTOR2I