KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_ipc2581.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <filesystem>
21#include <fstream>
22#include <iterator>
23#include <map>
24#include <string>
25
27
29
30#include <board.h>
31#include <footprint.h>
32#include <pad.h>
33#include <lset.h>
34#include <base_units.h>
35#include <core/mirror.h>
36
37#include <wx/filename.h>
38
39
40BOOST_AUTO_TEST_SUITE( Ipc2581Io )
41
42
43
56BOOST_AUTO_TEST_CASE( Issue18013_FlippedFootprintRotation )
57{
58 BOARD board;
59
60 auto addFootprint =
61 [&]( const wxString& aRef, const VECTOR2I& aPos, bool aFlip ) -> FOOTPRINT*
62 {
63 FOOTPRINT* fp = new FOOTPRINT( &board );
64 fp->SetReference( aRef );
65 fp->SetPosition( aPos );
66 board.Add( fp );
67
68 PAD* pad = new PAD( fp );
69 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
70 pad->SetNumber( wxT( "1" ) );
71 pad->SetAttribute( PAD_ATTRIB::SMD );
73 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1.0 ), pcbIUScale.mmToIU( 1.0 ) ) );
74 pad->SetLayerSet( LSET( { F_Cu, F_Mask } ) );
75 fp->Add( pad );
76
77 // Flip first, then set the absolute board orientation so GetOrientation()
78 // is deterministic regardless of any rotation the flip itself applies.
79 if( aFlip )
81
82 fp->SetOrientationDegrees( 30 );
83
84 return fp;
85 };
86
87 FOOTPRINT* flipped = addFootprint( wxT( "U1" ), VECTOR2I( pcbIUScale.mmToIU( 50 ), pcbIUScale.mmToIU( 50 ) ),
88 true );
89 FOOTPRINT* top = addFootprint( wxT( "U2" ), VECTOR2I( pcbIUScale.mmToIU( 60 ), pcbIUScale.mmToIU( 60 ) ), false );
90
91 BOOST_REQUIRE( flipped->IsFlipped() );
92 BOOST_REQUIRE( !top->IsFlipped() );
93
94 PCB_IO_IPC2581 ipc2581Plugin;
95
96 wxString tempPath = wxFileName::CreateTempFileName( wxT( "kicad_ipc2581_test" ) );
97
98 std::map<std::string, UTF8> props;
99 props["units"] = "mm";
100 props["version"] = "C";
101 props["sigfig"] = "3";
102
103 BOOST_REQUIRE_NO_THROW( ipc2581Plugin.SaveBoard( tempPath, board, &props ) );
104 BOOST_REQUIRE( wxFileExists( tempPath ) );
105
106 std::ifstream xmlFile( tempPath.ToStdString() );
107 BOOST_REQUIRE( xmlFile.is_open() );
108
109 std::string xml( ( std::istreambuf_iterator<char>( xmlFile ) ),
110 std::istreambuf_iterator<char>() );
111 xmlFile.close();
112
113 // Return the <Component>...</Component> block for a given refDes so the checks below
114 // cannot bleed across into a sibling component.
115 auto componentRegion =
116 [&]( const std::string& aRef ) -> std::string
117 {
118 size_t start = xml.find( "refDes=\"" + aRef + "\"" );
119
120 if( start == std::string::npos )
121 return std::string();
122
123 size_t end = xml.find( "</Component>", start );
124
125 return xml.substr( start, end == std::string::npos ? std::string::npos
126 : end - start );
127 };
128
129 std::string u1 = componentRegion( "U1" );
130 BOOST_REQUIRE_MESSAGE( !u1.empty(), "Flipped component U1 should be exported" );
131
132 BOOST_CHECK_MESSAGE( u1.find( "mirror=\"true\"" ) != std::string::npos,
133 "Flipped component must carry mirror=\"true\". Region: " + u1 );
134 BOOST_CHECK_MESSAGE( u1.find( "rotation=\"150.0\"" ) != std::string::npos,
135 "Flipped 30 degree component must export rotation=\"150.0\". Region: " + u1 );
136
137 // Guard against the two known incorrect formulas so the test fails on regression.
138 BOOST_CHECK_MESSAGE( u1.find( "rotation=\"330.0\"" ) == std::string::npos,
139 "Flipped rotation must not be a bare Invert() (330.0). Region: " + u1 );
140 BOOST_CHECK_MESSAGE( u1.find( "rotation=\"30.0\"" ) == std::string::npos,
141 "Flipped rotation must not be the unadjusted orientation (30.0). Region: " + u1 );
142
143 std::string u2 = componentRegion( "U2" );
144 BOOST_REQUIRE_MESSAGE( !u2.empty(), "Top component U2 should be exported" );
145
146 BOOST_CHECK_MESSAGE( u2.find( "mirror=\"true\"" ) == std::string::npos,
147 "Top component must not be mirrored. Region: " + u2 );
148 BOOST_CHECK_MESSAGE( u2.find( "rotation=\"30.0\"" ) != std::string::npos,
149 "Top 30 degree component must export rotation=\"30.0\". Region: " + u2 );
150
151 std::filesystem::remove( std::filesystem::path( tempPath.ToStdString() ) );
152}
153
154
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
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 SetPosition(const VECTOR2I &aPos) override
void SetOrientationDegrees(double aOrientation)
Definition footprint.h:464
bool IsFlipped() const
Definition footprint.h:660
void SetReference(const wxString &aReference)
Definition footprint.h:907
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
VECTOR2I GetPosition() const override
Definition footprint.h:435
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
@ 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 SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
@ F_Mask
Definition layer_ids.h:93
@ F_Cu
Definition layer_ids.h:60
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ RECTANGLE
Definition padstack.h:53
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
static FOOTPRINT * addFootprint(BOARD &aBoard, const wxString &aReference)
KIBIS top(path, &reporter)
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683