38#include <boost/test/unit_test.hpp>
60std::map<int, std::vector<VECTOR2D>> ReadBoardOutlineLoops(
const std::filesystem::path& aEmnPath )
62 std::ifstream in( aEmnPath );
63 BOOST_REQUIRE_MESSAGE( in,
"Cannot open exported .emn: " << aEmnPath.string() );
65 std::map<int, std::vector<VECTOR2D>> loops;
67 bool inSection =
false;
69 while( std::getline( in, line ) )
71 if( line.find(
".BOARD_OUTLINE" ) != std::string::npos )
77 if( line.find(
".END_BOARD_OUTLINE" ) != std::string::npos )
83 std::istringstream ss( line );
84 std::vector<std::string> tokens;
86 for( std::string tok; ss >> tok; )
87 tokens.push_back( tok );
91 if( tokens.size() < 4 )
94 const std::string& first = tokens.front();
95 const bool isLoopIndex =
96 std::all_of( first.begin(), first.end(), [](
unsigned char c ) { return std::isdigit( c ); } );
100 loops[std::stoi( first )].emplace_back( std::stod( tokens[1] ),
101 std::stod( tokens[2] ) );
112void CheckLoopContainsPoints(
const std::vector<VECTOR2D>& aLoopPoints,
113 const std::vector<VECTOR2I>& aExpectedIU )
120 const bool found = std::any_of( aLoopPoints.begin(), aLoopPoints.end(),
123 return std::abs( pt.x - expX ) < 1e-3
124 && std::abs( pt.y - expY ) < 1e-3;
127 BOOST_CHECK_MESSAGE( found,
"Cutout corner (" << expX <<
", " << expY
128 <<
") missing from exported loop" );
144 cutout =
static_cast<PCB_SHAPE*
>( item );
160 BOOST_REQUIRE_MESSAGE( std::filesystem::exists( sourceBoard ),
"Missing test board " << sourceBoard );
165 const std::filesystem::path outDir =
166 std::filesystem::temp_directory_path() /
"kicad_idf_cutout_test";
167 std::filesystem::create_directories( outDir );
169 const std::filesystem::path emnPath = outDir /
"cutout.emn";
170 std::filesystem::remove( emnPath );
179 const bool ok = exporter.
Export( wxString::FromUTF8( emnPath.string().c_str() ) );
181 BOOST_REQUIRE_MESSAGE( ok,
"IDF export failed: " <<
reporter.GetMessages() );
184 const std::map<int, std::vector<VECTOR2D>> loops = ReadBoardOutlineLoops( emnPath );
187 BOOST_CHECK_MESSAGE( loops.count( 0 ) == 1,
"Board outline (loop 0) missing from .emn" );
188 BOOST_REQUIRE_MESSAGE( loops.count( 1 ) == 1,
"Footprint cutout (loop 1) missing from .emn" );
192 PCB_SHAPE* cutout = GetCutoutShape( board->Footprints().front() );
198 CheckLoopContainsPoints( loops.at( 1 ),
199 { start, VECTOR2I( end.x, start.y ), end,
200 VECTOR2I( start.x, end.y ) } );
202 std::filesystem::remove_all( outDir );
211 BOOST_REQUIRE_MESSAGE( std::filesystem::exists( sourceBoard ),
"Missing test board " << sourceBoard );
217 FOOTPRINT* footprint = board->Footprints().front();
220 const std::filesystem::path outDir =
221 std::filesystem::temp_directory_path() /
"kicad_idf_poly_cutout_test";
222 std::filesystem::create_directories( outDir );
224 const std::filesystem::path emnPath = outDir /
"poly_cutout.emn";
225 std::filesystem::remove( emnPath );
234 const bool ok = exporter.
Export( wxString::FromUTF8( emnPath.string().c_str() ) );
236 BOOST_REQUIRE_MESSAGE( ok,
"IDF export failed: " <<
reporter.GetMessages() );
239 const std::map<int, std::vector<VECTOR2D>> loops = ReadBoardOutlineLoops( emnPath );
241 BOOST_CHECK_MESSAGE( loops.count( 0 ) == 1,
"Board outline (loop 0) missing from .emn" );
242 BOOST_REQUIRE_MESSAGE( loops.count( 1 ) == 1,
243 "Rotated polygon cutout (loop 1) missing from .emn" );
246 PCB_SHAPE* cutout = GetCutoutShape( footprint );
249 std::vector<VECTOR2I> corners;
252 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
253 corners.push_back(
chain.CPoint( ii ) );
255 CheckLoopContainsPoints( loops.at( 1 ), corners );
257 std::filesystem::remove_all( outDir );
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
SHAPE_POLY_SET & GetPolyShape()
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Provide an extensible class to resolve 3D model paths.
bool Export(const wxString &aFullFileName) const
Generate IDFv3 compliant board (*.emn) and library (*.emp) files for aPcb.
IDF_SETTINGS::COORD_ORIGIN m_originMode
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
A wrapper for reporting to a wxString object.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(FootprintCutoutIsExported)
IbisParser parser & reporter
VECTOR3I expected(15, 30, 45)
const SHAPE_LINE_CHAIN chain
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D