Browse Source
Pcbnew: arrays skip existing names
Pcbnew: arrays skip existing names
The current module cannot be queried for existing pads as we add them (because we never commit, until we finish the whole array). Instead, pre-gather the names and check as we add, skipping any existing names. Note: this will not prevent arrays becoming "mis-ordered", but there is not a lot we can do to prevent all possible errors. Fixes: 1808706 * https://bugs.launchpad.net/kicad/+bug/1808706 The same principle could be used to skip existing ref-des'es on PCBs.pull/13/head
committed by
Seth Hillbrand
6 changed files with 272 additions and 6 deletions
-
1pcbnew/CMakeLists.txt
-
17pcbnew/array_creator.cpp
-
74pcbnew/array_pad_name_provider.cpp
-
64pcbnew/array_pad_name_provider.h
-
1qa/pcbnew/CMakeLists.txt
-
121qa/pcbnew/test_array_pad_name_provider.cpp
@ -0,0 +1,74 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <array_pad_name_provider.h>
|
|||
|
|||
#include <class_pad.h>
|
|||
|
|||
|
|||
ARRAY_PAD_NAME_PROVIDER::ARRAY_PAD_NAME_PROVIDER( |
|||
const MODULE* aMod, const ARRAY_OPTIONS& aArrayOpts ) |
|||
: m_arrayOpts( aArrayOpts ) |
|||
{ |
|||
// start by numbering the first new item
|
|||
m_current_pad_index = 1; |
|||
|
|||
// construct the set of existing pad numbers
|
|||
if( aArrayOpts.GetNumberingStartIsSpecified() ) |
|||
{ |
|||
// if we start from a specified point, we don't look at existing
|
|||
// names, so it's just an empty "reserved" set
|
|||
} |
|||
else |
|||
{ |
|||
// no module, no reserved names either
|
|||
if( aMod ) |
|||
{ |
|||
// reserve the name of each existing pad
|
|||
for( D_PAD* pad = aMod->PadsList(); pad; pad = pad->Next() ) |
|||
{ |
|||
m_existing_pad_names.insert( pad->GetName() ); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
wxString ARRAY_PAD_NAME_PROVIDER::GetNextPadName() |
|||
{ |
|||
return getNextName( m_current_pad_index, m_existing_pad_names ); |
|||
} |
|||
|
|||
|
|||
wxString ARRAY_PAD_NAME_PROVIDER::getNextName( int& aIndex, const std::set<wxString>& aExisting ) |
|||
{ |
|||
wxString next_name; |
|||
|
|||
do |
|||
{ |
|||
next_name = m_arrayOpts.GetItemNumber( aIndex ); |
|||
aIndex++; |
|||
} while( aExisting.count( next_name ) != 0 ); |
|||
|
|||
return next_name; |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef PCBNEW_ARRAY_PAD_NAME_PROVIDER__H |
|||
#define PCBNEW_ARRAY_PAD_NAME_PROVIDER__H |
|||
|
|||
|
|||
#include <array_options.h> |
|||
#include <class_module.h> |
|||
|
|||
/** |
|||
* Simple class that sequentially provides names from an #ARRAY_OPTIONS |
|||
* object, making sure that they do not conflict with names already existing |
|||
* in a #MODULE. |
|||
*/ |
|||
class ARRAY_PAD_NAME_PROVIDER |
|||
{ |
|||
public: |
|||
/** |
|||
* @param aMod the module to gather existing names from (nullptr for no module) |
|||
* @oaram aArrayOpts the array options that provide the candidate names |
|||
*/ |
|||
ARRAY_PAD_NAME_PROVIDER( const MODULE* aMod, const ARRAY_OPTIONS& aArrayOpts ); |
|||
|
|||
/** |
|||
* Get the next available pad name. |
|||
*/ |
|||
wxString GetNextPadName(); |
|||
|
|||
private: |
|||
/** |
|||
* Get the next name from a given index/list combo |
|||
* @param aIndex index to start at, will be updated |
|||
* @param aExisting the set of existing names to skip |
|||
* @return the first name found that's not in aExisting |
|||
*/ |
|||
wxString getNextName( int& aIndex, const std::set<wxString>& aExisting ); |
|||
|
|||
const ARRAY_OPTIONS& m_arrayOpts; |
|||
std::set<wxString> m_existing_pad_names; |
|||
int m_current_pad_index; |
|||
}; |
|||
|
|||
#endif // PCBNEW_ARRAY_PAD_NAME_PROVIDER__H |
|||
@ -0,0 +1,121 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
/**
|
|||
* @file test_array_pad_name_provider.cpp |
|||
* Test suite for the #ARRAY_PAD_NAME_PROVIDER class |
|||
*/ |
|||
|
|||
#include <unit_test_utils/unit_test_utils.h>
|
|||
|
|||
#include <array_pad_name_provider.h> // UUT
|
|||
|
|||
#include <common.h> // make_unique
|
|||
|
|||
#include <class_module.h>
|
|||
#include <class_pad.h>
|
|||
|
|||
/**
|
|||
* Make a module with a given list of named pads |
|||
*/ |
|||
static std::unique_ptr<MODULE> ModuleWithPads( const std::vector<wxString> aNames ) |
|||
{ |
|||
auto module = std::make_unique<MODULE>( nullptr ); |
|||
|
|||
for( const auto& name : aNames ) |
|||
{ |
|||
auto pad = std::make_unique<D_PAD>( module.get() ); |
|||
|
|||
pad->SetName( name ); |
|||
|
|||
module->PadsList().PushBack( pad.release() ); |
|||
} |
|||
|
|||
return module; |
|||
} |
|||
|
|||
/**
|
|||
* Declare the test suite |
|||
*/ |
|||
BOOST_AUTO_TEST_SUITE( ArrayPadNameProv ) |
|||
|
|||
|
|||
struct APNP_CASE |
|||
{ |
|||
std::string m_case_name; |
|||
std::vector<wxString> m_existing_pads; |
|||
std::unique_ptr<ARRAY_OPTIONS> m_arr_opts; |
|||
std::vector<wxString> m_exp_arr_names; |
|||
}; |
|||
|
|||
|
|||
std::vector<APNP_CASE> GetAPNPCases() |
|||
{ |
|||
std::vector<APNP_CASE> cases; |
|||
|
|||
auto opts = std::make_unique<ARRAY_GRID_OPTIONS>(); |
|||
|
|||
// simple linear numbering
|
|||
opts->m_2dArrayNumbering = false; |
|||
opts->m_numberingOffsetX = 0; |
|||
opts->m_priAxisNumType = ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_NUMERIC; |
|||
|
|||
cases.push_back( { |
|||
"Simple linear, skip some", |
|||
{ "1", "3" }, |
|||
std::move( opts ), |
|||
{ "2", "4", "5", "6", "7" }, |
|||
} ); |
|||
|
|||
opts = std::make_unique<ARRAY_GRID_OPTIONS>(); |
|||
|
|||
// Grid numberings with skips don't make a lot of sense, there is
|
|||
// no particular contract made for them
|
|||
|
|||
return cases; |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE( Cases ) |
|||
{ |
|||
for( const auto& c : GetAPNPCases() ) |
|||
{ |
|||
BOOST_TEST_CONTEXT( c.m_case_name ) |
|||
{ |
|||
auto module = ModuleWithPads( c.m_existing_pads ); |
|||
|
|||
ARRAY_PAD_NAME_PROVIDER apnp( module.get(), *c.m_arr_opts ); |
|||
|
|||
std::vector<wxString> got_names; |
|||
|
|||
for( unsigned i = 0; i < c.m_exp_arr_names.size(); ++i ) |
|||
{ |
|||
got_names.push_back( apnp.GetNextPadName() ); |
|||
} |
|||
|
|||
BOOST_CHECK_EQUAL_COLLECTIONS( c.m_exp_arr_names.begin(), c.m_exp_arr_names.end(), |
|||
got_names.begin(), got_names.end() ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_SUITE_END() |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue