21#include <boost/test/unit_test.hpp>
88 for(
int i = 0; i <
expected.PointCount(); ++i )
112 auto acceptAll = [](
const VECTOR2I& ) {
return true; };
117 std::vector<VECTOR2I> samples =
122 BOOST_CHECK_GE( samples.size(), 26u );
123 BOOST_CHECK_LE( samples.size(), 30u );
129 "sample " << pt.x <<
"," << pt.y <<
" left the envelope" );
133 const int64_t minDistSq = (int64_t) ( pitch * 0.7 ) * (int64_t) ( pitch * 0.7 );
135 for(
size_t i = 0; i < samples.size(); ++i )
137 for(
size_t j = i + 1; j < samples.size(); ++j )
139 VECTOR2I d = samples[i] - samples[j];
140 BOOST_CHECK_GE( (int64_t) d.
x * d.
x + (int64_t) d.
y * d.
y, minDistSq );
148 envelope, noGuarded, pitch,
154 BOOST_CHECK( !leftHalf.empty() );
155 BOOST_CHECK_LT( leftHalf.size(), samples.size() );
157 for(
const VECTOR2I& pt : leftHalf )
158 BOOST_CHECK_LT( pt.x, midX );
171 const int trackWidth =
pcbIUScale.mmToIU( 0.2 );
172 const int envelopeOffset =
pcbIUScale.mmToIU( 0.607 );
178 centreY + trackWidth / 2 );
180 traceLen + envelopeOffset,
181 centreY + envelopeOffset );
183 auto acceptAll = [](
const VECTOR2I& ) {
return true; };
188 BOOST_REQUIRE_GT( pitch * 0.7, 2.0 * envelopeOffset );
190 std::vector<VECTOR2I> samples =
200 else if( pt.y > centreY )
205 BOOST_CHECK_GE( above, 8 );
206 BOOST_CHECK_GE( below, 8 );
209 std::vector<int> aboveXs;
214 aboveXs.push_back( pt.x );
217 std::sort( aboveXs.begin(), aboveXs.end() );
219 for(
size_t i = 1; i < aboveXs.size(); ++i )
220 BOOST_CHECK_GE( aboveXs[i] - aboveXs[i - 1], (
int) ( pitch * 0.7 ) );
251 BOOST_REQUIRE_EQUAL( bCells->size(), aCells->size() );
253 for(
size_t i = 0; i < aCells->size(); ++i )
260 auto board = std::make_unique<BOARD>();
261 board->Add(
new NETINFO_ITEM( board.get(), wxT(
"GND" ), 1 ) );
263 ZONE* zone =
new ZONE( board.get() );
274 board->Add( stitch );
278 auto path = std::filesystem::temp_directory_path() /
"qa_via_stitch_roundtrip.kicad_pcb";
284 BOOST_REQUIRE_EQUAL( board2->Generators().size(), 1 );
305 auto savedCells = stitch->
GetProperties().
get_opt<std::vector<VECTOR2I>>(
"excluded_grid_cells" );
306 auto loadedCells = loaded->
GetProperties().
get_opt<std::vector<VECTOR2I>>(
"excluded_grid_cells" );
310 BOOST_REQUIRE_EQUAL( loadedCells->size(), savedCells->size() );
313 BOOST_REQUIRE_EQUAL( savedCells->size(), 1 );
317 std::ifstream in(
path );
318 std::string
text( ( std::istreambuf_iterator<char>( in ) ),
319 std::istreambuf_iterator<char>() );
321 BOOST_CHECK(
text.find(
"excluded_grid_cells" ) != std::string::npos );
322 BOOST_CHECK(
text.find(
"(ij 3 3)" ) != std::string::npos );
339 return props.
get_opt<std::vector<VECTOR2I>>(
"excluded_grid_cells" ).has_value()
356 BOOST_CHECK( !excluded( stitch ) );
377 BOOST_CHECK( !props.
get_opt<std::vector<VECTOR2I>>(
"excluded_grid_cells" ).has_value() );
379 BOOST_REQUIRE_EQUAL(
chain->PointCount(), 1 );
447 BOOST_REQUIRE_EQUAL( cells->size(), 1 );
459 m_toolMgr.SetEnvironment(
m_board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
482 ids.insert( item->m_Uuid );
490 std::set<VECTOR2I> positions;
495 positions.insert( item->GetPosition() );
514 m_board = std::make_unique<BOARD>();
518 std::make_shared<DRC_ENGINE>(
m_board.get(), &
m_board->GetDesignSettings() );
519 drcEngine->InitEngine( wxFileName() );
520 m_board->GetDesignSettings().m_DRCEngine = drcEngine;
569 m_board->SetCopperLayerCount( 4 );
570 m_board->GetDesignSettings().SetCopperLayerCount( 4 );
591 m_board->SetProject(
nullptr );
607 BOOST_REQUIRE_MESSAGE( !
m_stitch,
"more than one stitch generator on the board" );
612 BOOST_REQUIRE_MESSAGE(
m_stitch,
"no via-stitch generator on the board" );
629 std::set<VECTOR2I> before = childViaPositions();
630 BOOST_REQUIRE_GT( before.size(), 10 );
640 std::set<VECTOR2I> after = childViaPositions();
655 BOOST_REQUIRE_GT( childViaPositions().size(), 10 );
661 std::set<VECTOR2I> coarse = childViaPositions();
668 for(
const VECTOR2I& pos : childViaPositions() )
680 std::set<KIID> first = childViaIds();
683 BOOST_REQUIRE_GT( first.size(), 10 );
686 std::vector<VECTOR2I> positions;
688 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
691 positions.push_back( item->GetPosition() );
694 const int64_t minDistSq =
697 for(
size_t i = 0; i < positions.size(); ++i )
699 for(
size_t j = i + 1; j < positions.size(); ++j )
701 VECTOR2I d = positions[i] - positions[j];
702 int64_t distSq = (int64_t) d.
x * d.
x + (int64_t) d.
y * d.
y;
704 BOOST_CHECK_MESSAGE( distSq >= minDistSq,
705 "vias " << i <<
" and " << j <<
" closer than the pitch" );
712 std::set<KIID> second = childViaIds();
714 BOOST_CHECK( first == second );
722 std::set<KIID> before = childViaIds();
723 BOOST_REQUIRE_GT( before.size(), 10 );
729 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
733 victim =
static_cast<PCB_VIA*
>( item );
743 m_stitch->ExcludePosition( victimPos );
746 std::set<KIID> after = childViaIds();
751 for(
const KIID&
id : after )
755 m_stitch->ClearExclusion( victimPos );
758 std::set<KIID> restored = childViaIds();
764 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
766 if( item->Type() ==
PCB_VIA_T && item->GetPosition() == victimPos )
770 BOOST_CHECK( found );
778 std::set<KIID> before = childViaIds();
779 BOOST_REQUIRE_GT( before.size(), 10 );
781 std::vector<VECTOR2I> victimPositions;
783 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
785 if( item->Type() ==
PCB_VIA_T && victimPositions.size() < 3 )
786 victimPositions.push_back( item->GetPosition() );
789 BOOST_REQUIRE_EQUAL( victimPositions.size(), 3 );
790 BOOST_CHECK( !m_stitch->HasExclusions() );
792 for(
const VECTOR2I& pos : victimPositions )
793 m_stitch->ExcludePosition( pos );
795 BOOST_CHECK( m_stitch->HasExclusions() );
800 m_stitch->ClearAllExclusions();
801 BOOST_CHECK( !m_stitch->HasExclusions() );
807 for(
const VECTOR2I& pos : victimPositions )
811 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
813 if( item->Type() ==
PCB_VIA_T && item->GetPosition() == pos )
817 BOOST_CHECK( found );
828 std::set<VECTOR2I> positions = childViaPositions();
829 BOOST_REQUIRE_GT( positions.size(), 10 );
831 bool overThreeLayers =
false;
832 bool overTwoLayers =
false;
834 for(
const VECTOR2I& pos : positions )
837 overThreeLayers =
true;
839 overTwoLayers =
true;
842 BOOST_CHECK( overThreeLayers );
843 BOOST_CHECK_MESSAGE( overTwoLayers,
844 "no vias placed where only the two inner planes overlap" );
853 loadBoard( wxT(
"issue25303" ) );
860 std::set<VECTOR2I> positions = childViaPositions();
861 BOOST_REQUIRE_GT( positions.size(), 100 );
865 const int pourEdge =
pcbIUScale.mmToIU( 107 );
871 for(
const VECTOR2I& pos : positions )
873 if( pos.x < pourEdge )
878 maxX = std::max( maxX, pos.x );
881 BOOST_CHECK_GT( underPour, 20 );
882 BOOST_CHECK_MESSAGE( beyondPour > 20,
"stitching stopped at the edge of the F.Cu pour" );
885 BOOST_CHECK_GT( maxX,
pcbIUScale.mmToIU( 122 ) );
890 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
892 BOOST_REQUIRE_EQUAL( item->Type(),
PCB_VIA_T );
897 BOOST_CHECK( outline.
Contains(
via->GetPosition() ) );
907 loadBoard( wxT(
"issue25265" ) );
914 for(
ZONE* zone : m_board->Zones() )
917 const std::vector<PAD*> pads = m_board->GetPads();
918 int sameNetPadsInside = 0;
922 if(
pad->GetNetCode() == m_stitch->GetNetCode()
923 && m_stitch->Outline().Contains(
pad->GetPosition() ) )
929 BOOST_REQUIRE_MESSAGE( sameNetPadsInside > 0,
930 "no pads on the stitch net sit inside the stitch outline" );
934 BOOST_REQUIRE_GT( childViaPositions().size(), 100 );
936 for(
BOARD_ITEM* item : m_stitch->GetBoardItems() )
938 BOOST_REQUIRE_EQUAL( item->Type(),
PCB_VIA_T );
948 if( !
pad->FlashLayer( layer ) )
952 !
pad->GetEffectiveShape( layer )->Collide( &viaCopper ),
953 wxString::Format(
"Via at (%.3f, %.3f) sits on pad %s of %s (net %s)",
957 pad->GetParentFootprint()->GetReferenceAsString(),
958 pad->GetNetname() ) );
967 loadBoard( wxT(
"stitch_fp_rulearea" ) );
969 ZONE* ruleArea =
nullptr;
971 for(
FOOTPRINT* footprint : m_board->Footprints() )
973 for(
ZONE* zone : footprint->Zones() )
975 if( zone->GetIsRuleArea() && zone->GetDoNotAllowVias() )
977 BOOST_REQUIRE_MESSAGE( !ruleArea,
"more than one via keepout on the board" );
983 BOOST_REQUIRE_MESSAGE( ruleArea,
"no footprint via keepout on the board" );
993 BOOST_REQUIRE_MESSAGE( outsideStitch.
IsEmpty(),
994 "keepout is not wholly inside the stitch outline" );
998 BOOST_REQUIRE_MESSAGE(
1000 "footprint frame and board frame overlap; test can't discriminate" );
1004 const std::set<VECTOR2I> positions = childViaPositions();
1006 BOOST_REQUIRE_GT( positions.size(), 20 );
1008 for(
const VECTOR2I& pos : positions )
1010 BOOST_CHECK_MESSAGE(
1011 !keepout.
Contains( pos, -1, 0,
true ),
1012 wxString::Format(
"Via at (%.3f, %.3f) sits inside the footprint via keepout",
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
constexpr bool Intersects(const BOX2< Vec > &aRect) const
virtual void SetParent(EDA_ITEM *aParent)
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
void SetOutline(const SHAPE_POLY_SET &aOutline)
const SHAPE_POLY_SET & Outline() const
static std::vector< VECTOR2I > SampleGuardEnvelope(const SHAPE_POLY_SET &aEnvelope, const SHAPE_POLY_SET &aGuarded, int aPitch, const std::function< bool(const VECTOR2I &)> &aIsValid)
Determine via positions around the perimeter of a guard envelope.
void SetMode(PCB_VIA_STITCH_MODE aVal)
PCB_VIA_STITCH_LAYOUT GetLayout() const
static constexpr uint32_t POISSON_TILE_SEED
Fixed seed for baking the toroidal Poisson pattern.
bool HasExclusions() const
const STRING_ANY_MAP GetProperties() const override
PCB_VIA_STITCH_MODE GetMode() const
static const std::vector< VECTOR2D > & bakedPoissonTile()
Helper method to cache the poisson tile we pattern.
static constexpr int POISSON_TILE_PITCHES
Tile size for the POISSON layout, in units of pitch.
void SetNetCode(int aNetCode)
void SetProperties(const STRING_ANY_MAP &aProps) override
void SetLayout(PCB_VIA_STITCH_LAYOUT aVal)
void ExcludePosition(const VECTOR2I &aPos)
Add a board position to the exclusion set so the next Update() skips it.
void SetSeed(uint32_t aVal)
VECTOR2I GetPosition() const override
void SetDrill(int aDrill)
void SetWidth(int aWidth) override
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
int OutlineCount() const
Return the number of outlines in the set.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
A name/value tuple with unique names and wxAny values.
std::optional< T > get_opt(const std::string &aKey) const
Handle a list of polygons defining a copper zone.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
SHAPE_POLY_SET GetBoardOutline() const
void SetLayerSet(const LSET &aLayerSet) override
SHAPE_POLY_SET GetLibraryOutline() const
static bool empty(const wxTextEntryBase *aCtrl)
PCB_LAYER_ID
A quick note on layer IDs:
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
void FillZones(BOARD *m_board)
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.
@ STITCH
Fill the outline with vias with a pattern.
@ GUARD
Place vias to guard a net contained within.
@ POISSON
Tiled poisson distribution.
@ STAGGERED
Odd rows shifted by half the pitch.
@ PLAIN
Regular row/column grid.
#define SKIP_CONNECTIVITY
SETTINGS_MANAGER m_settingsManager
void loadBoard(const wxString &aRelPath)
void attachToolManager()
The BOARD_COMMITs in regenerate() need a tool to hang off.
PCB_VIA_STITCH * m_stitch
std::set< VECTOR2I > childViaPositions() const
std::set< KIID > childViaIds() const
KI_TEST::DUMMY_TOOL * m_dummyTool
std::unique_ptr< BOARD > m_board
STITCH_PARTIAL_LAYER_FIXTURE()
void addGndZone(const LSET &aLayers, int aLeft, int aRight)
Add a full-height GND pour on aLayers, spanning x from aLeft to aRight.
void finishSetup()
Fill the poured zones and attach a stitch generator ready to Update().
STITCH_SYNTHETIC_FIXTURE()
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
const SHAPE_LINE_CHAIN chain
BOOST_CHECK_EQUAL(result, "25.4")
BOOST_AUTO_TEST_CASE(BakedPatternConstantsLocked)
static void checkOutlinesEqual(const SHAPE_POLY_SET &aExpected, const SHAPE_POLY_SET &aActual)
static void configureStitch(PCB_VIA_STITCH *aStitch)
BOOST_FIXTURE_TEST_CASE(LayoutRoundTripKeepsGridAnchored, STITCH_UPDATE_FIXTURE)
static SHAPE_POLY_SET makeRectPoly(int aX1, int aY1, int aX2, int aY2)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
@ FULL
pads are covered by copper