2011-09-23 13:57:12 +00:00
|
|
|
/**
|
|
|
|
* @file class_board.cpp
|
|
|
|
* @brief BOARD class functions.
|
|
|
|
*/
|
|
|
|
|
2012-06-08 09:56:42 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2018-06-02 16:14:34 +00:00
|
|
|
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
2012-06-08 09:56:42 +00:00
|
|
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
|
|
|
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
|
|
|
*
|
2019-03-01 13:36:53 +00:00
|
|
|
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
2012-06-08 09:56:42 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2011-02-25 16:23:24 +00:00
|
|
|
#include <limits.h>
|
2011-10-31 13:44:13 +00:00
|
|
|
#include <algorithm>
|
2017-07-17 12:55:31 +00:00
|
|
|
#include <iterator>
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <common.h>
|
2012-04-01 20:51:56 +00:00
|
|
|
#include <kicad_string.h>
|
2018-01-29 15:39:40 +00:00
|
|
|
#include <pcb_base_frame.h>
|
2013-01-12 17:32:24 +00:00
|
|
|
#include <msgpanel.h>
|
2013-09-14 20:33:22 +00:00
|
|
|
#include <pcb_netlist.h>
|
2013-04-25 16:29:35 +00:00
|
|
|
#include <reporter.h>
|
2013-08-24 08:08:55 +00:00
|
|
|
#include <base_units.h>
|
2013-11-25 15:50:03 +00:00
|
|
|
#include <ratsnest_data.h>
|
2014-03-03 16:15:41 +00:00
|
|
|
#include <ratsnest_viewitem.h>
|
|
|
|
#include <worksheet_viewitem.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
|
|
|
|
#include <pcbnew.h>
|
2013-11-02 00:24:38 +00:00
|
|
|
#include <collectors.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
|
|
|
|
#include <class_board.h>
|
|
|
|
#include <class_module.h>
|
|
|
|
#include <class_track.h>
|
|
|
|
#include <class_zone.h>
|
|
|
|
#include <class_marker_pcb.h>
|
2015-02-12 03:22:24 +00:00
|
|
|
#include <class_drawsegment.h>
|
|
|
|
#include <class_pcb_text.h>
|
2017-10-31 15:38:10 +00:00
|
|
|
#include <class_pcb_target.h>
|
2015-02-12 03:22:24 +00:00
|
|
|
#include <class_dimension.h>
|
2018-10-12 06:17:15 +00:00
|
|
|
#include <connectivity/connectivity_data.h>
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2007-12-01 05:37:44 +00:00
|
|
|
|
2018-01-28 09:35:33 +00:00
|
|
|
/**
|
|
|
|
* A singleton item of this class is returned for a weak reference that no longer exists.
|
|
|
|
* Its sole purpose is to flag the item as having been deleted.
|
|
|
|
*/
|
|
|
|
class DELETED_BOARD_ITEM : public BOARD_ITEM
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DELETED_BOARD_ITEM() :
|
|
|
|
BOARD_ITEM( nullptr, NOT_USED )
|
|
|
|
{}
|
|
|
|
|
2018-04-10 10:52:12 +00:00
|
|
|
wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override
|
|
|
|
{
|
|
|
|
return _( "(Deleted Item)" );
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString GetClass() const override
|
|
|
|
{
|
|
|
|
return wxT( "DELETED_BOARD_ITEM" );
|
|
|
|
}
|
2018-01-28 09:35:33 +00:00
|
|
|
|
|
|
|
// pure virtuals:
|
|
|
|
const wxPoint GetPosition() const override { return wxPoint(); }
|
|
|
|
void SetPosition( const wxPoint& ) override {}
|
|
|
|
void Draw( EDA_DRAW_PANEL* , wxDC* , GR_DRAWMODE , const wxPoint& ) override {}
|
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
void Show( int , std::ostream& ) const override {}
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
DELETED_BOARD_ITEM g_DeletedItem;
|
|
|
|
|
|
|
|
|
2011-09-30 18:15:37 +00:00
|
|
|
/* This is an odd place for this, but CvPcb won't link if it is
|
2009-05-28 08:42:24 +00:00
|
|
|
* in class_board_item.cpp like I first tried it.
|
|
|
|
*/
|
|
|
|
wxPoint BOARD_ITEM::ZeroOffset( 0, 0 );
|
2008-04-01 05:21:50 +00:00
|
|
|
|
2017-10-08 14:08:42 +00:00
|
|
|
// this is a dummy colors settings (defined colors are the vdefulat values)
|
|
|
|
// used to initialize the board.
|
|
|
|
// these settings will be overriden later, depending on the draw frame that displays the board.
|
|
|
|
// However, when a board is created by a python script, outside a frame, the colors must be set
|
|
|
|
// so dummyColorsSettings provide this default initialization
|
|
|
|
static COLORS_DESIGN_SETTINGS dummyColorsSettings( FRAME_PCB );
|
2011-09-14 20:04:58 +00:00
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
BOARD::BOARD() :
|
2016-05-13 15:31:54 +00:00
|
|
|
BOARD_ITEM_CONTAINER( (BOARD_ITEM*) NULL, PCB_T ),
|
2017-09-01 11:36:55 +00:00
|
|
|
m_paper( PAGE_INFO::A4 ), m_NetInfo( this )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
// we have not loaded a board yet, assume latest until then.
|
2012-04-07 18:05:56 +00:00
|
|
|
m_fileFormatVersionAtLoad = LEGACY_BOARD_FILE_VERSION;
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
|
2017-10-08 14:08:42 +00:00
|
|
|
m_colorsSettings = &dummyColorsSettings;
|
2009-11-12 15:43:38 +00:00
|
|
|
m_Status_Pcb = 0; // Status word: bit 1 = calculate.
|
|
|
|
m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the
|
2011-09-15 17:58:35 +00:00
|
|
|
// zone contour currently in progress
|
2011-12-10 05:33:24 +00:00
|
|
|
|
|
|
|
BuildListOfNets(); // prepare pad and netlist containers.
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
2008-03-04 04:22:27 +00:00
|
|
|
{
|
2014-06-29 13:05:51 +00:00
|
|
|
m_Layer[layer].m_name = GetStandardLayerName( ToLAYER_ID( layer ) );
|
2012-06-16 22:49:24 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
if( IsCopperLayer( layer ) )
|
|
|
|
m_Layer[layer].m_type = LT_SIGNAL;
|
2012-06-16 22:49:24 +00:00
|
|
|
else
|
2014-06-24 16:17:18 +00:00
|
|
|
m_Layer[layer].m_type = LT_UNDEFINED;
|
2008-03-04 04:22:27 +00:00
|
|
|
}
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2015-03-13 16:48:42 +00:00
|
|
|
// Initialize default netclass.
|
2014-05-20 09:29:37 +00:00
|
|
|
NETCLASSPTR defaultClass = m_designSettings.GetDefault();
|
2014-05-13 09:22:51 +00:00
|
|
|
defaultClass->SetDescription( _( "This is the default net class." ) );
|
|
|
|
m_designSettings.SetCurrentNetClass( defaultClass->GetName() );
|
2013-11-25 15:50:03 +00:00
|
|
|
|
2014-05-13 09:22:51 +00:00
|
|
|
// Set sensible initial values for custom track width & via size
|
2014-05-13 09:22:51 +00:00
|
|
|
m_designSettings.UseCustomTrackViaSize( false );
|
|
|
|
m_designSettings.SetCustomTrackWidth( m_designSettings.GetCurrentTrackWidth() );
|
|
|
|
m_designSettings.SetCustomViaSize( m_designSettings.GetCurrentViaSize() );
|
|
|
|
m_designSettings.SetCustomViaDrill( m_designSettings.GetCurrentViaDrill() );
|
2014-05-13 09:22:51 +00:00
|
|
|
|
2014-03-03 16:15:41 +00:00
|
|
|
// Initialize ratsnest
|
2017-03-22 13:43:10 +00:00
|
|
|
m_connectivity.reset( new CONNECTIVITY_DATA() );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2007-08-30 22:20:52 +00:00
|
|
|
BOARD::~BOARD()
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
while( m_ZoneDescriptorList.size() )
|
2008-12-03 10:32:53 +00:00
|
|
|
{
|
|
|
|
ZONE_CONTAINER* area_to_remove = m_ZoneDescriptorList[0];
|
|
|
|
Delete( area_to_remove );
|
|
|
|
}
|
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
DeleteMARKERs();
|
2008-02-12 01:02:53 +00:00
|
|
|
DeleteZONEOutlines();
|
|
|
|
|
|
|
|
delete m_CurrentZoneContour;
|
|
|
|
m_CurrentZoneContour = NULL;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2017-08-17 15:55:05 +00:00
|
|
|
void BOARD::BuildConnectivity()
|
|
|
|
{
|
|
|
|
GetConnectivity()->Build( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-18 17:24:25 +00:00
|
|
|
const wxPoint BOARD::GetPosition() const
|
2012-06-01 07:39:32 +00:00
|
|
|
{
|
2013-08-29 10:06:06 +00:00
|
|
|
return ZeroOffset;
|
|
|
|
}
|
2012-06-01 07:39:32 +00:00
|
|
|
|
2017-12-17 17:43:43 +00:00
|
|
|
|
2013-08-29 10:06:06 +00:00
|
|
|
void BOARD::SetPosition( const wxPoint& aPos )
|
|
|
|
{
|
|
|
|
wxLogWarning( wxT( "This should not be called on the BOARD object") );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BOARD::Move( const wxPoint& aMoveVector ) // overload
|
|
|
|
{
|
2013-11-02 00:24:38 +00:00
|
|
|
// @todo : anything like this elsewhere? maybe put into GENERAL_COLLECTOR class.
|
|
|
|
static const KICAD_T top_level_board_stuff[] = {
|
|
|
|
PCB_MARKER_T,
|
|
|
|
PCB_TEXT_T,
|
|
|
|
PCB_LINE_T,
|
|
|
|
PCB_DIMENSION_T,
|
|
|
|
PCB_TARGET_T,
|
|
|
|
PCB_VIA_T,
|
|
|
|
PCB_TRACE_T,
|
2014-09-10 15:18:42 +00:00
|
|
|
// PCB_PAD_T, Can't be at board level
|
|
|
|
// PCB_MODULE_TEXT_T, Can't be at board level
|
2013-11-02 00:24:38 +00:00
|
|
|
PCB_MODULE_T,
|
2013-11-02 19:49:46 +00:00
|
|
|
PCB_ZONE_AREA_T,
|
2013-11-02 00:24:38 +00:00
|
|
|
EOT
|
|
|
|
};
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
|
|
|
|
{
|
|
|
|
BOARD_ITEM* brd_item = (BOARD_ITEM*) item;
|
|
|
|
|
|
|
|
// aMoveVector was snapshotted, don't need "data".
|
|
|
|
brd_item->Move( aMoveVector );
|
|
|
|
|
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
};
|
|
|
|
|
|
|
|
Visit( inspector, NULL, top_level_board_stuff );
|
2012-06-01 07:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-19 20:34:09 +00:00
|
|
|
TRACKS BOARD::TracksInNet( int aNetCode )
|
|
|
|
{
|
|
|
|
TRACKS ret;
|
|
|
|
|
|
|
|
INSPECTOR_FUNC inspector = [aNetCode,&ret] ( EDA_ITEM* item, void* testData )
|
|
|
|
{
|
|
|
|
TRACK* t = (TRACK*) item;
|
|
|
|
|
|
|
|
if( t->GetNetCode() == aNetCode )
|
|
|
|
ret.push_back( t );
|
|
|
|
|
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
};
|
|
|
|
|
|
|
|
// visit this BOARD's TRACKs and VIAs with above TRACK INSPECTOR which
|
|
|
|
// appends all in aNetCode to ret.
|
|
|
|
Visit( inspector, NULL, GENERAL_COLLECTOR::Tracks );
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function removeTrack
|
|
|
|
* removes aOneToRemove from aList, which is a non-owning std::vector
|
|
|
|
*/
|
|
|
|
static void removeTrack( TRACKS* aList, TRACK* aOneToRemove )
|
|
|
|
{
|
|
|
|
aList->erase( std::remove( aList->begin(), aList->end(), aOneToRemove ), aList->end() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void otherEnd( const TRACK& aTrack, const wxPoint& aNotThisEnd, wxPoint* aOtherEnd )
|
|
|
|
{
|
|
|
|
if( aTrack.GetStart() == aNotThisEnd )
|
|
|
|
{
|
|
|
|
*aOtherEnd = aTrack.GetEnd();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxASSERT( aTrack.GetEnd() == aNotThisEnd );
|
|
|
|
*aOtherEnd = aTrack.GetStart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function find_vias_and_tracks_at
|
2016-09-20 15:59:43 +00:00
|
|
|
* collects TRACKs and VIAs at aPos and returns the @a track_count which excludes vias.
|
2016-07-19 20:34:09 +00:00
|
|
|
*/
|
|
|
|
static int find_vias_and_tracks_at( TRACKS& at_next, TRACKS& in_net, LSET& lset, const wxPoint& next )
|
|
|
|
{
|
|
|
|
// first find all vias (in this net) at 'next' location, and expand LSET with each
|
|
|
|
for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); )
|
|
|
|
{
|
|
|
|
TRACK* t = *it;
|
|
|
|
|
|
|
|
if( t->Type() == PCB_VIA_T && (t->GetLayerSet() & lset).any() &&
|
|
|
|
( t->GetStart() == next || t->GetEnd() == next ) )
|
|
|
|
{
|
|
|
|
lset |= t->GetLayerSet();
|
|
|
|
at_next.push_back( t );
|
2016-12-30 13:36:23 +00:00
|
|
|
it = in_net.erase( it );
|
2016-07-19 20:34:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
int track_count = 0;
|
|
|
|
|
|
|
|
// with expanded lset, find all tracks with an end on any of the layers in lset
|
2016-08-10 10:17:56 +00:00
|
|
|
for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); /* iterates in the loop body */ )
|
2016-07-19 20:34:09 +00:00
|
|
|
{
|
|
|
|
TRACK* t = *it;
|
|
|
|
|
2016-08-10 10:17:56 +00:00
|
|
|
if( ( t->GetLayerSet() & lset ).any() && ( t->GetStart() == next || t->GetEnd() == next ) )
|
2016-07-19 20:34:09 +00:00
|
|
|
{
|
|
|
|
at_next.push_back( t );
|
2016-08-10 10:17:56 +00:00
|
|
|
it = in_net.erase( it );
|
2016-07-19 20:34:09 +00:00
|
|
|
++track_count;
|
|
|
|
}
|
|
|
|
else
|
2016-08-10 10:17:56 +00:00
|
|
|
{
|
2016-07-19 20:34:09 +00:00
|
|
|
++it;
|
2016-08-10 10:17:56 +00:00
|
|
|
}
|
2016-07-19 20:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return track_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function checkConnectedTo
|
|
|
|
* returns if aTracksInNet contains a copper pathway to aGoal when starting with
|
|
|
|
* aFirstTrack. aFirstTrack should have one end situated on aStart, and the
|
|
|
|
* traversal testing begins from the other end of aFirstTrack.
|
|
|
|
* <p>
|
|
|
|
* The function throws an exception instead of returning bool so that detailed
|
|
|
|
* information can be provided about a possible failure in the track layout.
|
|
|
|
*
|
|
|
|
* @throw IO_ERROR - if points are not connected, with text saying why.
|
|
|
|
*/
|
|
|
|
static void checkConnectedTo( BOARD* aBoard, TRACKS* aList, const TRACKS& aTracksInNet,
|
|
|
|
const wxPoint& aGoal, const wxPoint& aStart, TRACK* aFirstTrack )
|
|
|
|
{
|
|
|
|
TRACKS in_net = aTracksInNet; // copy source list so the copy can be modified
|
|
|
|
wxPoint next;
|
|
|
|
|
|
|
|
otherEnd( *aFirstTrack, aStart, &next );
|
|
|
|
|
|
|
|
aList->push_back( aFirstTrack );
|
|
|
|
removeTrack( &in_net, aFirstTrack );
|
|
|
|
|
|
|
|
LSET lset( aFirstTrack->GetLayer() );
|
|
|
|
|
|
|
|
while( in_net.size() )
|
|
|
|
{
|
|
|
|
if( next == aGoal )
|
|
|
|
return; // success
|
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
// Want an exact match on the position of next, i.e. pad at next,
|
|
|
|
// not a forgiving HitTest() with tolerance type of match, otherwise the overall
|
|
|
|
// algorithm will not work. GetPadFast() is an exact match as I write this.
|
|
|
|
if( aBoard->GetPadFast( next, lset ) )
|
2016-07-19 20:34:09 +00:00
|
|
|
{
|
|
|
|
std::string m = StrPrintf(
|
2016-09-20 15:59:43 +00:00
|
|
|
"intervening pad at:(xy %s) between start:(xy %s) and goal:(xy %s)",
|
2019-01-08 05:42:50 +00:00
|
|
|
FormatInternalUnits( next ).c_str(),
|
|
|
|
FormatInternalUnits( aStart ).c_str(),
|
|
|
|
FormatInternalUnits( aGoal ).c_str()
|
2016-07-19 20:34:09 +00:00
|
|
|
);
|
|
|
|
THROW_IO_ERROR( m );
|
|
|
|
}
|
|
|
|
|
|
|
|
int track_count = find_vias_and_tracks_at( *aList, in_net, lset, next );
|
|
|
|
|
|
|
|
if( track_count != 1 )
|
|
|
|
{
|
|
|
|
std::string m = StrPrintf(
|
|
|
|
"found %d tracks intersecting at (xy %s), exactly 2 would be acceptable.",
|
2016-09-20 15:59:43 +00:00
|
|
|
track_count + aList->size() == 1 ? 1 : 0,
|
2019-01-08 05:42:50 +00:00
|
|
|
FormatInternalUnits( next ).c_str()
|
2016-07-19 20:34:09 +00:00
|
|
|
);
|
|
|
|
THROW_IO_ERROR( m );
|
|
|
|
}
|
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
// reduce lset down to the layer that the last track at 'next' is on.
|
2016-07-19 20:34:09 +00:00
|
|
|
lset = aList->back()->GetLayerSet();
|
|
|
|
|
|
|
|
otherEnd( *aList->back(), next, &next );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string m = StrPrintf(
|
|
|
|
"not enough tracks connecting start:(xy %s) and goal:(xy %s).",
|
2019-01-08 05:42:50 +00:00
|
|
|
FormatInternalUnits( aStart ).c_str(),
|
|
|
|
FormatInternalUnits( aGoal ).c_str()
|
2016-07-19 20:34:09 +00:00
|
|
|
);
|
|
|
|
THROW_IO_ERROR( m );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
TRACKS BOARD::TracksInNetBetweenPoints( const wxPoint& aStartPos, const wxPoint& aGoalPos, int aNetCode )
|
2016-07-19 20:34:09 +00:00
|
|
|
{
|
|
|
|
TRACKS in_between_pts;
|
2016-09-20 15:59:43 +00:00
|
|
|
TRACKS on_start_point;
|
2016-07-19 20:34:09 +00:00
|
|
|
TRACKS in_net = TracksInNet( aNetCode ); // a small subset of TRACKs and VIAs
|
|
|
|
|
|
|
|
for( auto t : in_net )
|
|
|
|
{
|
|
|
|
if( t->Type() == PCB_TRACE_T && ( t->GetStart() == aStartPos || t->GetEnd() == aStartPos ) )
|
2016-09-20 15:59:43 +00:00
|
|
|
on_start_point.push_back( t );
|
2016-07-19 20:34:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
wxString per_path_problem_text;
|
2016-07-19 20:34:09 +00:00
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
for( auto t : on_start_point ) // explore each trace (path) leaving aStartPos
|
2016-07-19 20:34:09 +00:00
|
|
|
{
|
|
|
|
// checkConnectedTo() fills in_between_pts on every attempt. For failures
|
|
|
|
// this set needs to be cleared.
|
|
|
|
in_between_pts.clear();
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2016-09-20 15:59:43 +00:00
|
|
|
checkConnectedTo( this, &in_between_pts, in_net, aGoalPos, aStartPos, t );
|
2016-07-19 20:34:09 +00:00
|
|
|
}
|
|
|
|
catch( const IO_ERROR& ioe ) // means not connected
|
|
|
|
{
|
2016-09-20 15:59:43 +00:00
|
|
|
per_path_problem_text += "\n\t";
|
|
|
|
per_path_problem_text += ioe.Problem();
|
2016-07-19 20:34:09 +00:00
|
|
|
continue; // keep trying, there may be other paths leaving from aStartPos
|
|
|
|
}
|
|
|
|
|
|
|
|
// success, no exception means a valid connection,
|
|
|
|
// return this set of TRACKS without throwing.
|
|
|
|
return in_between_pts;
|
|
|
|
}
|
|
|
|
|
2016-09-20 15:59:43 +00:00
|
|
|
wxString m = wxString::Format(
|
|
|
|
"no clean path connecting start:(xy %s) with goal:(xy %s)",
|
2019-01-08 05:42:50 +00:00
|
|
|
FormatInternalUnits( aStartPos ).c_str(),
|
|
|
|
FormatInternalUnits( aGoalPos ).c_str()
|
2016-07-19 20:34:09 +00:00
|
|
|
);
|
2016-09-20 15:59:43 +00:00
|
|
|
|
|
|
|
THROW_IO_ERROR( m + per_path_problem_text );
|
2016-07-19 20:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
void BOARD::chainMarkedSegments( TRACK* aTrackList, wxPoint aPosition,
|
|
|
|
const LSET& aLayerSet, TRACKS* aList )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
LSET layer_set = aLayerSet;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
if( !aTrackList ) // no tracks at all in board
|
2011-09-16 15:54:50 +00:00
|
|
|
return;
|
|
|
|
|
2018-01-04 16:10:17 +00:00
|
|
|
D_PAD* pad = NULL;
|
2018-06-12 14:50:18 +00:00
|
|
|
double distanceToPadCenter = std::numeric_limits<double>::max();
|
2018-01-04 16:10:17 +00:00
|
|
|
|
2011-09-16 15:54:50 +00:00
|
|
|
/* Set the BUSY flag of all connected segments, first search starting at
|
|
|
|
* aPosition. The search ends when a pad is found (end of a track), a
|
|
|
|
* segment end has more than one other segment end connected, or when no
|
|
|
|
* connected item found.
|
|
|
|
*
|
2018-06-12 14:50:18 +00:00
|
|
|
* Vias are a special case because they can connect segments
|
2011-09-16 15:54:50 +00:00
|
|
|
* on other layers and they change the layer mask. They can be a track
|
2018-06-12 14:50:18 +00:00
|
|
|
* end or not. They will be analyzed later, and vias on terminal points
|
2011-09-16 15:54:50 +00:00
|
|
|
* of the track will be considered as part of this track if they do not
|
2018-06-12 14:50:18 +00:00
|
|
|
* connect segments on a other track together and will be considered as
|
2018-04-08 10:28:59 +00:00
|
|
|
* part of a other track when removing the via, the segments of that other
|
2011-09-16 15:54:50 +00:00
|
|
|
* track are disconnected.
|
|
|
|
*/
|
|
|
|
for( ; ; )
|
|
|
|
{
|
2018-01-04 16:10:17 +00:00
|
|
|
if( !pad )
|
|
|
|
pad = GetPad( aPosition, layer_set );
|
2018-06-12 08:05:12 +00:00
|
|
|
|
2018-01-04 16:10:17 +00:00
|
|
|
if( pad )
|
|
|
|
distanceToPadCenter = GetLineLength( aPosition, pad->GetCenter() );
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
/* Test for a via: a via changes the layer mask and can connect a lot
|
|
|
|
* of segments at location aPosition. When found, the via is just
|
|
|
|
* pushed in list. Vias will be examined later, when all connected
|
|
|
|
* segment are found and push in list. This is because when a via
|
|
|
|
* is found we do not know at this time the number of connected items
|
|
|
|
* and we do not know if this via is on the track or finish the track
|
|
|
|
*/
|
2018-06-12 14:50:18 +00:00
|
|
|
TRACK* via = aTrackList->GetVia( NULL, aPosition, layer_set );
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
if( via )
|
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
layer_set = via->GetLayerSet();
|
2011-09-16 15:54:50 +00:00
|
|
|
aList->push_back( via );
|
|
|
|
}
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
int seg_count = 0;
|
|
|
|
TRACK* candidate = NULL;
|
|
|
|
|
|
|
|
/* Search all segments connected to point aPosition.
|
|
|
|
* if only 1 segment at aPosition: then this segment is "candidate"
|
2011-09-16 15:54:50 +00:00
|
|
|
* if > 1 segment:
|
2016-07-12 19:05:54 +00:00
|
|
|
* then end of "track" (because more than 2 segments are connected at aPosition)
|
2011-09-16 15:54:50 +00:00
|
|
|
*/
|
2018-06-12 14:50:18 +00:00
|
|
|
TRACK* segment = aTrackList;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
while( ( segment = ::GetTrack( segment, NULL, aPosition, layer_set ) ) != NULL )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
if( segment->GetState( BUSY ) ) // already found and selected: skip it
|
|
|
|
{
|
|
|
|
segment = segment->Next();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( segment == via ) // just previously found: skip it
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
segment = segment->Next();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( ++seg_count == 1 ) // if first connected item: then segment is candidate
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
candidate = segment;
|
|
|
|
segment = segment->Next();
|
|
|
|
}
|
2016-07-12 19:05:54 +00:00
|
|
|
else // More than 1 segment connected -> location is end of track
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( candidate ) // A candidate is found: flag it and push it in list
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
/* Initialize parameters to search items connected to this
|
|
|
|
* candidate:
|
|
|
|
* we must analyze connections to its other end
|
|
|
|
*/
|
2013-01-13 00:04:00 +00:00
|
|
|
if( aPosition == candidate->GetStart() )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2013-01-13 00:04:00 +00:00
|
|
|
aPosition = candidate->GetEnd();
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-01-13 00:04:00 +00:00
|
|
|
aPosition = candidate->GetStart();
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
|
2018-01-04 16:10:17 +00:00
|
|
|
/* If we are in a pad, only candidates approaching the pad center
|
|
|
|
* are accepted.
|
|
|
|
*/
|
|
|
|
if( pad )
|
|
|
|
{
|
|
|
|
if( GetPad( aPosition, layer_set ) != pad )
|
|
|
|
return;
|
2018-06-12 08:05:12 +00:00
|
|
|
|
2018-01-04 16:10:17 +00:00
|
|
|
if( GetLineLength( aPosition, pad->GetCenter() ) > distanceToPadCenter )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
layer_set = candidate->GetLayerSet();
|
|
|
|
|
|
|
|
// flag this item and push it in list of selected items
|
2011-09-16 15:54:50 +00:00
|
|
|
aList->push_back( candidate );
|
2013-03-30 17:24:04 +00:00
|
|
|
candidate->SetState( BUSY, true );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
void BOARD::PushHighLight()
|
2011-04-14 18:44:46 +00:00
|
|
|
{
|
2012-04-01 20:51:56 +00:00
|
|
|
m_highLightPrevious = m_highLight;
|
2011-04-14 18:44:46 +00:00
|
|
|
}
|
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
void BOARD::PopHighLight()
|
2011-04-14 18:44:46 +00:00
|
|
|
{
|
2012-04-01 20:51:56 +00:00
|
|
|
m_highLight = m_highLightPrevious;
|
|
|
|
m_highLightPrevious.Clear();
|
2011-04-14 18:44:46 +00:00
|
|
|
}
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
bool BOARD::SetLayerDescr( PCB_LAYER_ID aIndex, const LAYER& aLayer )
|
2012-06-09 17:00:13 +00:00
|
|
|
{
|
2019-01-06 16:43:12 +00:00
|
|
|
if( unsigned( aIndex ) < arrayDim( m_Layer ) )
|
2012-06-09 17:00:13 +00:00
|
|
|
{
|
|
|
|
m_Layer[ aIndex ] = aLayer;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-15 13:31:47 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
const PCB_LAYER_ID BOARD::GetLayerID( const wxString& aLayerName ) const
|
2015-02-15 13:31:47 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
// Look for the BOARD specific copper layer names
|
2017-03-13 03:19:33 +00:00
|
|
|
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
2015-02-15 13:31:47 +00:00
|
|
|
{
|
2015-06-04 12:54:07 +00:00
|
|
|
if ( IsCopperLayer( layer ) && ( m_Layer[ layer ].m_name == aLayerName ) )
|
2015-02-15 13:31:47 +00:00
|
|
|
{
|
|
|
|
return ToLAYER_ID( layer );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise fall back to the system standard layer names
|
2017-03-13 03:19:33 +00:00
|
|
|
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
2015-02-15 13:31:47 +00:00
|
|
|
{
|
2015-06-04 12:54:07 +00:00
|
|
|
if( GetStandardLayerName( ToLAYER_ID( layer ) ) == aLayerName )
|
2015-02-15 13:31:47 +00:00
|
|
|
{
|
|
|
|
return ToLAYER_ID( layer );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return UNDEFINED_LAYER;
|
|
|
|
}
|
2012-06-09 17:00:13 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
const wxString BOARD::GetLayerName( PCB_LAYER_ID aLayer ) const
|
2008-01-23 01:50:16 +00:00
|
|
|
{
|
2012-06-16 22:49:24 +00:00
|
|
|
// All layer names are stored in the BOARD.
|
2013-04-09 16:00:46 +00:00
|
|
|
if( IsLayerEnabled( aLayer ) )
|
2008-03-04 04:22:27 +00:00
|
|
|
{
|
2013-03-20 04:46:32 +00:00
|
|
|
// Standard names were set in BOARD::BOARD() but they may be
|
|
|
|
// over-ridden by BOARD::SetLayerName().
|
|
|
|
// For copper layers, return the actual copper layer name,
|
|
|
|
// otherwise return the Standard English layer name.
|
2013-04-09 16:00:46 +00:00
|
|
|
if( IsCopperLayer( aLayer ) )
|
2014-06-24 16:17:18 +00:00
|
|
|
return m_Layer[aLayer].m_name;
|
2008-03-04 04:22:27 +00:00
|
|
|
}
|
|
|
|
|
2013-04-09 16:00:46 +00:00
|
|
|
return GetStandardLayerName( aLayer );
|
2009-12-07 03:46:13 +00:00
|
|
|
}
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
bool BOARD::SetLayerName( PCB_LAYER_ID aLayer, const wxString& aLayerName )
|
2008-03-01 13:15:41 +00:00
|
|
|
{
|
2013-04-09 16:00:46 +00:00
|
|
|
if( !IsCopperLayer( aLayer ) )
|
2009-10-18 23:22:26 +00:00
|
|
|
return false;
|
|
|
|
|
2018-09-29 13:25:22 +00:00
|
|
|
if( aLayerName == wxEmptyString )
|
2009-10-18 23:22:26 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// no quote chars in the name allowed
|
|
|
|
if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )
|
|
|
|
return false;
|
2008-03-04 04:22:27 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
wxString nameTemp = aLayerName;
|
2008-03-04 04:22:27 +00:00
|
|
|
|
2009-10-18 23:22:26 +00:00
|
|
|
// replace any spaces with underscores before we do any comparing
|
2014-06-24 16:17:18 +00:00
|
|
|
nameTemp.Replace( wxT( " " ), wxT( "_" ) );
|
2009-10-18 23:22:26 +00:00
|
|
|
|
2013-04-09 16:00:46 +00:00
|
|
|
if( IsLayerEnabled( aLayer ) )
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
m_Layer[aLayer].m_name = nameTemp;
|
2008-03-04 04:22:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2008-03-01 13:15:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
LAYER_T BOARD::GetLayerType( PCB_LAYER_ID aLayer ) const
|
2008-03-01 13:15:41 +00:00
|
|
|
{
|
2013-04-09 16:00:46 +00:00
|
|
|
if( !IsCopperLayer( aLayer ) )
|
2009-10-18 23:22:26 +00:00
|
|
|
return LT_SIGNAL;
|
|
|
|
|
|
|
|
//@@IMB: The original test was broken due to the discontinuity
|
|
|
|
// in the layer sequence.
|
2013-04-09 16:00:46 +00:00
|
|
|
if( IsLayerEnabled( aLayer ) )
|
2014-06-24 16:17:18 +00:00
|
|
|
return m_Layer[aLayer].m_type;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-03-01 13:15:41 +00:00
|
|
|
return LT_SIGNAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
bool BOARD::SetLayerType( PCB_LAYER_ID aLayer, LAYER_T aLayerType )
|
2008-03-01 13:15:41 +00:00
|
|
|
{
|
2013-04-09 16:00:46 +00:00
|
|
|
if( !IsCopperLayer( aLayer ) )
|
2009-10-18 23:22:26 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
//@@IMB: The original test was broken due to the discontinuity
|
|
|
|
// in the layer sequence.
|
2013-04-09 16:00:46 +00:00
|
|
|
if( IsLayerEnabled( aLayer ) )
|
2008-03-04 04:22:27 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
m_Layer[aLayer].m_type = aLayerType;
|
2008-03-04 04:22:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-03-04 04:22:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* LAYER::ShowType( LAYER_T aType )
|
|
|
|
{
|
|
|
|
const char* cp;
|
|
|
|
|
|
|
|
switch( aType )
|
|
|
|
{
|
|
|
|
default:
|
2009-05-28 08:42:24 +00:00
|
|
|
case LT_SIGNAL:
|
2009-11-12 15:43:38 +00:00
|
|
|
cp = "signal";
|
|
|
|
break;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
case LT_POWER:
|
2009-11-12 15:43:38 +00:00
|
|
|
cp = "power";
|
|
|
|
break;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
case LT_MIXED:
|
2009-11-12 15:43:38 +00:00
|
|
|
cp = "mixed";
|
|
|
|
break;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
case LT_JUMPER:
|
2009-11-12 15:43:38 +00:00
|
|
|
cp = "jumper";
|
|
|
|
break;
|
2008-03-04 04:22:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return cp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LAYER_T LAYER::ParseType( const char* aType )
|
|
|
|
{
|
|
|
|
if( strcmp( aType, "signal" ) == 0 )
|
|
|
|
return LT_SIGNAL;
|
|
|
|
else if( strcmp( aType, "power" ) == 0 )
|
|
|
|
return LT_POWER;
|
|
|
|
else if( strcmp( aType, "mixed" ) == 0 )
|
|
|
|
return LT_MIXED;
|
|
|
|
else if( strcmp( aType, "jumper" ) == 0 )
|
|
|
|
return LT_JUMPER;
|
|
|
|
else
|
2012-06-09 17:00:13 +00:00
|
|
|
return LT_UNDEFINED;
|
2008-03-01 13:15:41 +00:00
|
|
|
}
|
|
|
|
|
2012-06-09 17:00:13 +00:00
|
|
|
|
2008-01-23 01:50:16 +00:00
|
|
|
int BOARD::GetCopperLayerCount() const
|
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
return m_designSettings.GetCopperLayerCount();
|
2008-01-23 01:50:16 +00:00
|
|
|
}
|
2010-01-31 20:01:46 +00:00
|
|
|
|
2012-06-09 17:00:13 +00:00
|
|
|
|
2010-01-21 07:41:30 +00:00
|
|
|
void BOARD::SetCopperLayerCount( int aCount )
|
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
m_designSettings.SetCopperLayerCount( aCount );
|
2010-01-21 07:41:30 +00:00
|
|
|
}
|
2008-01-23 01:50:16 +00:00
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
LSET BOARD::GetEnabledLayers() const
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
return m_designSettings.GetEnabledLayers();
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
LSET BOARD::GetVisibleLayers() const
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
return m_designSettings.GetVisibleLayers();
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
void BOARD::SetEnabledLayers( LSET aLayerSet )
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
m_designSettings.SetEnabledLayers( aLayerSet );
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
void BOARD::SetVisibleLayers( LSET aLayerSet )
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
m_designSettings.SetVisibleLayers( aLayerSet );
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
2009-10-18 23:22:26 +00:00
|
|
|
void BOARD::SetVisibleElements( int aMask )
|
|
|
|
{
|
2012-03-12 00:40:48 +00:00
|
|
|
// Call SetElementVisibility for each item
|
|
|
|
// to ensure specific calculations that can be needed by some items,
|
|
|
|
// just changing the visibility flags could be not sufficient.
|
2017-03-13 03:19:33 +00:00
|
|
|
for( GAL_LAYER_ID ii = GAL_LAYER_ID_START; ii < GAL_LAYER_ID_BITMASK_END; ++ii )
|
2010-01-30 14:46:26 +00:00
|
|
|
{
|
2017-03-13 03:19:33 +00:00
|
|
|
int item_mask = 1 << GAL_LAYER_INDEX( ii );
|
2013-03-31 13:27:46 +00:00
|
|
|
SetElementVisibility( ii, aMask & item_mask );
|
2010-01-30 14:46:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-06 05:44:19 +00:00
|
|
|
|
|
|
|
void BOARD::SetVisibleAlls()
|
2010-01-30 14:46:26 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
SetVisibleLayers( LSET().set() );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2012-02-06 05:44:19 +00:00
|
|
|
// Call SetElementVisibility for each item,
|
|
|
|
// to ensure specific calculations that can be needed by some items
|
2017-03-13 03:19:33 +00:00
|
|
|
for( GAL_LAYER_ID ii = GAL_LAYER_ID_START; ii < GAL_LAYER_ID_BITMASK_END; ++ii )
|
2010-01-30 14:46:26 +00:00
|
|
|
SetElementVisibility( ii, true );
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
|
|
|
|
int BOARD::GetVisibleElements() const
|
2009-10-18 23:22:26 +00:00
|
|
|
{
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
return m_designSettings.GetVisibleElements();
|
2009-10-18 23:22:26 +00:00
|
|
|
}
|
|
|
|
|
2010-01-21 20:53:01 +00:00
|
|
|
|
2017-10-05 18:11:55 +00:00
|
|
|
bool BOARD::IsElementVisible( GAL_LAYER_ID aLayer ) const
|
2010-01-25 06:45:34 +00:00
|
|
|
{
|
2017-10-05 18:11:55 +00:00
|
|
|
return m_designSettings.IsElementVisible( aLayer );
|
2010-01-25 06:45:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-05 18:11:55 +00:00
|
|
|
void BOARD::SetElementVisibility( GAL_LAYER_ID aLayer, bool isEnabled )
|
2010-01-25 06:45:34 +00:00
|
|
|
{
|
2017-10-05 18:11:55 +00:00
|
|
|
m_designSettings.SetElementVisibility( aLayer, isEnabled );
|
2012-02-06 05:44:19 +00:00
|
|
|
|
2017-10-05 18:11:55 +00:00
|
|
|
switch( aLayer )
|
2010-01-25 06:45:34 +00:00
|
|
|
{
|
2017-03-13 03:19:33 +00:00
|
|
|
case LAYER_RATSNEST:
|
2017-06-23 17:22:44 +00:00
|
|
|
{
|
2017-04-24 20:26:11 +00:00
|
|
|
bool visible = IsElementVisible( LAYER_RATSNEST );
|
2012-03-12 00:40:48 +00:00
|
|
|
// we must clear or set the CH_VISIBLE flags to hide/show ratsnest
|
|
|
|
// because we have a tool to show/hide ratsnest relative to a pad or a module
|
2010-01-30 14:46:26 +00:00
|
|
|
// so the hide/show option is a per item selection
|
2017-04-24 20:26:11 +00:00
|
|
|
|
2018-09-21 12:41:28 +00:00
|
|
|
for( unsigned int net = 1 /* skip "No Net" at [0] */; net < GetNetCount(); net++ )
|
2017-06-29 22:45:50 +00:00
|
|
|
{
|
|
|
|
auto rn = GetConnectivity()->GetRatsnestForNet( net );
|
|
|
|
if( rn )
|
|
|
|
rn->SetVisible( visible );
|
|
|
|
}
|
2017-06-23 17:22:44 +00:00
|
|
|
|
|
|
|
for( auto track : Tracks() )
|
2017-04-24 20:26:11 +00:00
|
|
|
track->SetLocalRatsnestVisible( isEnabled );
|
2017-06-23 17:22:44 +00:00
|
|
|
|
2017-04-24 20:26:11 +00:00
|
|
|
for( auto mod : Modules() )
|
2017-06-23 17:22:44 +00:00
|
|
|
{
|
|
|
|
for( auto pad : mod->Pads() )
|
2017-04-24 20:26:11 +00:00
|
|
|
pad->SetLocalRatsnestVisible( isEnabled );
|
2017-06-23 17:22:44 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 20:26:11 +00:00
|
|
|
for( int i = 0; i<GetAreaCount(); i++ )
|
2010-01-30 14:46:26 +00:00
|
|
|
{
|
2017-04-24 20:26:11 +00:00
|
|
|
auto zone = GetArea( i );
|
|
|
|
zone->SetLocalRatsnestVisible( isEnabled );
|
2010-01-30 14:46:26 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 20:26:11 +00:00
|
|
|
m_Status_Pcb = 0;
|
|
|
|
|
|
|
|
break;
|
2017-06-23 17:22:44 +00:00
|
|
|
}
|
|
|
|
|
2010-01-25 06:45:34 +00:00
|
|
|
default:
|
2012-02-06 05:44:19 +00:00
|
|
|
;
|
2010-01-25 06:45:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-05 18:11:55 +00:00
|
|
|
bool BOARD::IsModuleLayerVisible( PCB_LAYER_ID aLayer )
|
2010-01-31 20:01:46 +00:00
|
|
|
{
|
2017-10-05 18:11:55 +00:00
|
|
|
switch( aLayer )
|
2013-04-07 11:55:18 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
case F_Cu:
|
2017-03-13 03:19:33 +00:00
|
|
|
return IsElementVisible( LAYER_MOD_FR );
|
2013-04-07 11:55:18 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
case B_Cu:
|
2017-03-13 03:19:33 +00:00
|
|
|
return IsElementVisible( LAYER_MOD_BK );
|
2013-04-07 11:55:18 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
wxFAIL_MSG( wxT( "BOARD::IsModuleLayerVisible() param error: bad layer" ) );
|
2010-01-31 20:01:46 +00:00
|
|
|
return true;
|
2013-04-07 11:55:18 +00:00
|
|
|
}
|
2010-01-31 20:01:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-13 15:31:54 +00:00
|
|
|
void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
|
2007-11-27 22:49:35 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
if( aBoardItem == NULL )
|
2008-02-12 01:02:53 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
wxFAIL_MSG( wxT( "BOARD::Add() param error: aBoardItem NULL" ) );
|
2008-02-12 01:02:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
switch( aBoardItem->Type() )
|
|
|
|
{
|
2016-01-29 10:29:56 +00:00
|
|
|
case PCB_NETINFO_T:
|
|
|
|
m_NetInfo.AppendNet( (NETINFO_ITEM*) aBoardItem );
|
2016-09-05 10:19:30 +00:00
|
|
|
break;
|
2016-01-29 10:29:56 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
// this one uses a vector
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MARKER_T:
|
2009-08-01 19:26:05 +00:00
|
|
|
m_markers.push_back( (MARKER_PCB*) aBoardItem );
|
2007-11-27 22:49:35 +00:00
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2008-01-06 17:19:36 +00:00
|
|
|
// this one uses a vector
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_ZONE_AREA_T:
|
2008-01-06 17:19:36 +00:00
|
|
|
m_ZoneDescriptorList.push_back( (ZONE_CONTAINER*) aBoardItem );
|
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_TRACE_T:
|
|
|
|
case PCB_VIA_T:
|
2019-06-29 02:23:00 +00:00
|
|
|
|
|
|
|
// N.B. This inserts a small memory leak as we lose the
|
|
|
|
if( !IsCopperLayer( aBoardItem->GetLayer() ) )
|
|
|
|
{
|
|
|
|
wxFAIL_MSG( wxT( "BOARD::Add() Cannot place Track on non-copper layer" ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-13 15:31:54 +00:00
|
|
|
if( aMode == ADD_APPEND )
|
2015-06-18 19:23:01 +00:00
|
|
|
{
|
|
|
|
m_Track.PushBack( (TRACK*) aBoardItem );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TRACK* insertAid;
|
|
|
|
insertAid = ( (TRACK*) aBoardItem )->GetBestInsertPoint( this );
|
|
|
|
m_Track.Insert( (TRACK*) aBoardItem, insertAid );
|
|
|
|
}
|
|
|
|
|
2011-08-09 14:13:01 +00:00
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2018-09-29 17:58:31 +00:00
|
|
|
case PCB_SEGZONE_T:
|
2016-05-13 15:31:54 +00:00
|
|
|
if( aMode == ADD_APPEND )
|
2018-05-12 19:37:43 +00:00
|
|
|
m_SegZoneDeprecated.PushBack( (SEGZONE*) aBoardItem );
|
2008-12-04 04:28:11 +00:00
|
|
|
else
|
2018-05-12 19:37:43 +00:00
|
|
|
m_SegZoneDeprecated.PushFront( (SEGZONE*) aBoardItem );
|
2011-10-01 19:24:27 +00:00
|
|
|
|
2008-12-03 10:32:53 +00:00
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MODULE_T:
|
2016-05-13 15:31:54 +00:00
|
|
|
if( aMode == ADD_APPEND )
|
2008-12-04 04:28:11 +00:00
|
|
|
m_Modules.PushBack( (MODULE*) aBoardItem );
|
|
|
|
else
|
|
|
|
m_Modules.PushFront( (MODULE*) aBoardItem );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-06-05 15:57:41 +00:00
|
|
|
// Because the list of pads has changed, reset the status
|
2011-09-14 20:04:58 +00:00
|
|
|
// This indicate the list of pad and nets must be recalculated before use
|
2009-06-05 15:57:41 +00:00
|
|
|
m_Status_Pcb = 0;
|
2008-12-04 04:28:11 +00:00
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_DIMENSION_T:
|
|
|
|
case PCB_LINE_T:
|
|
|
|
case PCB_TEXT_T:
|
2011-09-07 19:41:04 +00:00
|
|
|
case PCB_TARGET_T:
|
2016-05-13 15:31:54 +00:00
|
|
|
if( aMode == ADD_APPEND )
|
2008-12-04 04:28:11 +00:00
|
|
|
m_Drawings.PushBack( aBoardItem );
|
|
|
|
else
|
|
|
|
m_Drawings.PushFront( aBoardItem );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
break;
|
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
// other types may use linked list
|
2007-11-27 22:49:35 +00:00
|
|
|
default:
|
2011-08-09 14:13:01 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
2011-09-07 19:41:04 +00:00
|
|
|
msg.Printf( wxT( "BOARD::Add() needs work: BOARD_ITEM type (%d) not handled" ),
|
|
|
|
aBoardItem->Type() );
|
2011-08-09 14:13:01 +00:00
|
|
|
wxFAIL_MSG( msg );
|
2016-05-30 08:44:05 +00:00
|
|
|
return;
|
2011-08-09 14:13:01 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-11-27 22:49:35 +00:00
|
|
|
}
|
2014-01-30 14:46:39 +00:00
|
|
|
|
2016-05-30 08:44:05 +00:00
|
|
|
aBoardItem->SetParent( this );
|
2017-03-22 13:43:10 +00:00
|
|
|
m_connectivity->Add( aBoardItem );
|
2007-11-27 22:49:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-13 15:31:54 +00:00
|
|
|
void BOARD::Remove( BOARD_ITEM* aBoardItem )
|
2007-11-27 22:49:35 +00:00
|
|
|
{
|
2011-09-14 20:04:58 +00:00
|
|
|
// find these calls and fix them! Don't send me no stinking' NULL.
|
2008-12-06 21:20:50 +00:00
|
|
|
wxASSERT( aBoardItem );
|
2007-12-29 19:15:58 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
switch( aBoardItem->Type() )
|
|
|
|
{
|
2016-01-29 10:29:56 +00:00
|
|
|
case PCB_NETINFO_T:
|
2016-01-29 14:43:40 +00:00
|
|
|
{
|
|
|
|
NETINFO_ITEM* item = (NETINFO_ITEM*) aBoardItem;
|
|
|
|
m_NetInfo.RemoveNet( item );
|
2016-01-29 10:29:56 +00:00
|
|
|
break;
|
2016-01-29 14:43:40 +00:00
|
|
|
}
|
2016-05-13 15:31:54 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MARKER_T:
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2008-12-06 21:20:50 +00:00
|
|
|
// find the item in the vector, then remove it
|
2009-11-12 15:43:38 +00:00
|
|
|
for( unsigned i = 0; i<m_markers.size(); ++i )
|
2007-11-27 22:49:35 +00:00
|
|
|
{
|
2009-08-01 19:26:05 +00:00
|
|
|
if( m_markers[i] == (MARKER_PCB*) aBoardItem )
|
2007-11-27 22:49:35 +00:00
|
|
|
{
|
2008-12-06 21:20:50 +00:00
|
|
|
m_markers.erase( m_markers.begin() + i );
|
2007-11-27 22:49:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
break;
|
2007-12-29 19:15:58 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_ZONE_AREA_T: // this one uses a vector
|
2007-12-29 19:15:58 +00:00
|
|
|
// find the item in the vector, then delete then erase it.
|
2009-11-12 15:43:38 +00:00
|
|
|
for( unsigned i = 0; i<m_ZoneDescriptorList.size(); ++i )
|
2007-12-29 19:15:58 +00:00
|
|
|
{
|
|
|
|
if( m_ZoneDescriptorList[i] == (ZONE_CONTAINER*) aBoardItem )
|
|
|
|
{
|
2008-12-06 21:20:50 +00:00
|
|
|
m_ZoneDescriptorList.erase( m_ZoneDescriptorList.begin() + i );
|
2007-12-29 19:15:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MODULE_T:
|
2008-12-06 21:20:50 +00:00
|
|
|
m_Modules.Remove( (MODULE*) aBoardItem );
|
2008-12-06 08:21:54 +00:00
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_TRACE_T:
|
|
|
|
case PCB_VIA_T:
|
2008-12-06 21:20:50 +00:00
|
|
|
m_Track.Remove( (TRACK*) aBoardItem );
|
2008-12-06 08:21:54 +00:00
|
|
|
break;
|
|
|
|
|
2018-09-29 17:58:31 +00:00
|
|
|
case PCB_SEGZONE_T:
|
2018-05-12 19:37:43 +00:00
|
|
|
m_SegZoneDeprecated.Remove( (SEGZONE*) aBoardItem );
|
2008-12-06 08:21:54 +00:00
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_DIMENSION_T:
|
|
|
|
case PCB_LINE_T:
|
|
|
|
case PCB_TEXT_T:
|
2011-09-07 19:41:04 +00:00
|
|
|
case PCB_TARGET_T:
|
2008-12-06 21:20:50 +00:00
|
|
|
m_Drawings.Remove( aBoardItem );
|
2008-12-06 08:21:54 +00:00
|
|
|
break;
|
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
// other types may use linked list
|
|
|
|
default:
|
2009-05-28 08:42:24 +00:00
|
|
|
wxFAIL_MSG( wxT( "BOARD::Remove() needs more ::Type() support" ) );
|
2007-11-27 22:49:35 +00:00
|
|
|
}
|
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
m_connectivity->Remove( aBoardItem );
|
2007-12-03 05:14:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-28 12:11:43 +00:00
|
|
|
wxString BOARD::GetSelectMenuText( EDA_UNITS_T aUnits ) const
|
|
|
|
{
|
|
|
|
return wxString::Format( _( "PCB" ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
void BOARD::DeleteMARKERs()
|
|
|
|
{
|
2009-08-01 19:26:05 +00:00
|
|
|
// the vector does not know how to delete the MARKER_PCB, it holds pointers
|
2018-09-17 09:54:49 +00:00
|
|
|
for( MARKER_PCB* marker : m_markers )
|
|
|
|
delete marker;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
m_markers.clear();
|
|
|
|
}
|
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-12-29 19:15:58 +00:00
|
|
|
void BOARD::DeleteZONEOutlines()
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
// the vector does not know how to delete the ZONE Outlines, it holds pointers
|
|
|
|
for( ZONE_CONTAINER* zone : m_ZoneDescriptorList )
|
|
|
|
delete zone;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2007-12-29 19:15:58 +00:00
|
|
|
m_ZoneDescriptorList.clear();
|
|
|
|
}
|
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
|
2018-08-23 22:41:57 +00:00
|
|
|
BOARD_ITEM* BOARD::GetItem( void* aWeakReference )
|
2018-01-28 09:35:33 +00:00
|
|
|
{
|
|
|
|
for( TRACK* track : Tracks() )
|
|
|
|
if( track == aWeakReference )
|
|
|
|
return track;
|
|
|
|
|
|
|
|
for( MODULE* module : Modules() )
|
|
|
|
{
|
|
|
|
if( module == aWeakReference )
|
|
|
|
return module;
|
|
|
|
|
|
|
|
for( D_PAD* pad : module->Pads() )
|
|
|
|
if( pad == aWeakReference )
|
|
|
|
return pad;
|
|
|
|
|
2018-08-23 22:41:57 +00:00
|
|
|
if( &module->Reference() == aWeakReference )
|
|
|
|
return &module->Reference();
|
|
|
|
|
|
|
|
if( &module->Value() == aWeakReference )
|
|
|
|
return &module->Value();
|
|
|
|
|
|
|
|
for( BOARD_ITEM* drawing : module->GraphicalItems() )
|
|
|
|
if( drawing == aWeakReference )
|
|
|
|
return drawing;
|
2018-01-28 09:35:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for( ZONE_CONTAINER* zone : Zones() )
|
|
|
|
if( zone == aWeakReference )
|
|
|
|
return zone;
|
|
|
|
|
2018-08-23 22:41:57 +00:00
|
|
|
for( BOARD_ITEM* drawing : Drawings() )
|
|
|
|
if( drawing == aWeakReference )
|
|
|
|
return drawing;
|
2018-01-28 09:35:33 +00:00
|
|
|
|
|
|
|
// Not found; weak reference has been deleted.
|
|
|
|
return &g_DeletedItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-10 05:33:24 +00:00
|
|
|
int BOARD::GetNumSegmTrack() const
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
return m_Track.GetCount();
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
2007-08-04 20:05:54 +00:00
|
|
|
|
|
|
|
|
2011-12-10 05:33:24 +00:00
|
|
|
int BOARD::GetNumSegmZone() const
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2018-05-12 19:37:43 +00:00
|
|
|
return m_SegZoneDeprecated.GetCount();
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-04 05:55:03 +00:00
|
|
|
unsigned BOARD::GetNodesCount( int aNet )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2018-05-12 17:07:04 +00:00
|
|
|
unsigned retval = 0;
|
|
|
|
for( auto mod : Modules() )
|
|
|
|
{
|
|
|
|
for( auto pad : mod->Pads() )
|
2018-06-04 05:55:03 +00:00
|
|
|
{
|
|
|
|
if( ( aNet == -1 && pad->GetNetCode() > 0 ) || aNet == pad->GetNetCode() )
|
2018-05-12 17:07:04 +00:00
|
|
|
retval++;
|
2018-06-04 05:55:03 +00:00
|
|
|
}
|
2018-05-12 17:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
2017-06-23 16:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned BOARD::GetUnconnectedNetCount() const
|
|
|
|
{
|
|
|
|
return m_connectivity->GetUnconnectedCount();
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-23 04:31:26 +00:00
|
|
|
EDA_RECT BOARD::ComputeBoundingBox( bool aBoardEdgesOnly ) const
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2011-09-01 21:39:38 +00:00
|
|
|
EDA_RECT area;
|
2019-05-25 14:43:55 +00:00
|
|
|
LSET visible = GetVisibleLayers();
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2011-02-25 16:23:24 +00:00
|
|
|
// Check segments, dimensions, texts, and fiducials
|
2011-12-10 05:33:24 +00:00
|
|
|
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
|
2007-08-04 20:05:54 +00:00
|
|
|
{
|
2019-08-16 05:58:45 +00:00
|
|
|
if( aBoardEdgesOnly && ( item->GetLayer() != Edge_Cuts ) )
|
2011-09-01 21:39:38 +00:00
|
|
|
continue;
|
2011-02-25 16:23:24 +00:00
|
|
|
|
2019-08-16 05:58:45 +00:00
|
|
|
if( ( item->GetLayerSet() & visible ).any() )
|
2011-09-01 21:39:38 +00:00
|
|
|
area.Merge( item->GetBoundingBox() );
|
2011-02-25 16:23:24 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 05:58:45 +00:00
|
|
|
// Check modules
|
|
|
|
for( MODULE* module = m_Modules; module; module = module->Next() )
|
2011-02-25 16:23:24 +00:00
|
|
|
{
|
2019-08-16 05:58:45 +00:00
|
|
|
if( !( module->GetLayerSet() & visible ).any() )
|
|
|
|
continue;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2019-08-16 05:58:45 +00:00
|
|
|
if( aBoardEdgesOnly )
|
|
|
|
{
|
|
|
|
for( const auto edge : module->GraphicalItems() )
|
|
|
|
{
|
|
|
|
if( edge->GetLayer() == Edge_Cuts )
|
|
|
|
area.Merge( edge->GetBoundingBox() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
area.Merge( module->GetBoundingBox() );
|
2011-02-25 16:23:24 +00:00
|
|
|
}
|
2019-08-16 05:58:45 +00:00
|
|
|
}
|
2011-02-25 16:23:24 +00:00
|
|
|
|
2019-08-16 05:58:45 +00:00
|
|
|
if( !aBoardEdgesOnly )
|
|
|
|
{
|
2011-02-25 16:23:24 +00:00
|
|
|
// Check tracks
|
|
|
|
for( TRACK* track = m_Track; track; track = track->Next() )
|
2007-08-04 20:05:54 +00:00
|
|
|
{
|
2019-08-16 05:58:45 +00:00
|
|
|
if( ( track->GetLayerSet() & visible ).any() )
|
2011-09-01 21:39:38 +00:00
|
|
|
area.Merge( track->GetBoundingBox() );
|
2007-08-04 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
2011-02-25 16:23:24 +00:00
|
|
|
// Check segment zones
|
2018-05-12 19:37:43 +00:00
|
|
|
for( TRACK* track = m_SegZoneDeprecated; track; track = track->Next() )
|
2011-02-25 16:23:24 +00:00
|
|
|
{
|
2019-08-16 05:58:45 +00:00
|
|
|
if( ( track->GetLayerSet() & visible ).any() )
|
2011-09-01 21:39:38 +00:00
|
|
|
area.Merge( track->GetBoundingBox() );
|
2011-02-25 16:23:24 +00:00
|
|
|
}
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2011-02-25 16:23:24 +00:00
|
|
|
// Check polygonal zones
|
2018-09-17 09:54:49 +00:00
|
|
|
for( auto aZone : m_ZoneDescriptorList )
|
2011-02-25 16:23:24 +00:00
|
|
|
{
|
2019-08-16 05:58:45 +00:00
|
|
|
if( ( aZone->GetLayerSet() & visible ).any() )
|
2011-09-01 21:39:38 +00:00
|
|
|
area.Merge( aZone->GetBoundingBox() );
|
2011-02-25 16:23:24 +00:00
|
|
|
}
|
2007-08-04 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
return area;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
2007-08-06 02:02:39 +00:00
|
|
|
|
|
|
|
|
2018-04-10 10:52:12 +00:00
|
|
|
void BOARD::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
|
2007-08-20 19:33:15 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
wxString txt;
|
2013-01-12 17:32:24 +00:00
|
|
|
int viasCount = 0;
|
|
|
|
int trackSegmentsCount = 0;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
for( BOARD_ITEM* item = m_Track; item; item = item->Next() )
|
2007-08-20 19:33:15 +00:00
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
if( item->Type() == PCB_VIA_T )
|
2009-05-28 08:42:24 +00:00
|
|
|
viasCount++;
|
2010-09-18 08:29:40 +00:00
|
|
|
else
|
|
|
|
trackSegmentsCount++;
|
2007-08-20 19:33:15 +00:00
|
|
|
}
|
|
|
|
|
2011-12-10 05:33:24 +00:00
|
|
|
txt.Printf( wxT( "%d" ), GetPadCount() );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Pads" ), txt, DARKGREEN ) );
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
txt.Printf( wxT( "%d" ), viasCount );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Vias" ), txt, DARKGREEN ) );
|
2007-08-20 19:33:15 +00:00
|
|
|
|
2010-09-18 08:29:40 +00:00
|
|
|
txt.Printf( wxT( "%d" ), trackSegmentsCount );
|
2014-11-15 19:06:05 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Track Segments" ), txt, DARKGREEN ) );
|
2010-09-18 08:29:40 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
txt.Printf( wxT( "%d" ), GetNodesCount() );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Nodes" ), txt, DARKCYAN ) );
|
2007-08-20 19:33:15 +00:00
|
|
|
|
2018-09-21 12:41:28 +00:00
|
|
|
txt.Printf( wxT( "%d" ), m_NetInfo.GetNetCount() - 1 /* Don't include "No Net" in count */ );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
|
2007-08-20 19:33:15 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
txt.Printf( wxT( "%d" ), GetConnectivity()->GetUnconnectedCount() );
|
2018-05-02 09:31:06 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Unrouted" ), txt, BLUE ) );
|
2007-08-20 19:33:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
|
2007-08-06 02:02:39 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
KICAD_T stype;
|
|
|
|
SEARCH_RESULT result = SEARCH_CONTINUE;
|
|
|
|
const KICAD_T* p = scanTypes;
|
|
|
|
bool done = false;
|
2007-08-24 03:40:04 +00:00
|
|
|
|
2007-08-30 22:20:52 +00:00
|
|
|
#if 0 && defined(DEBUG)
|
2009-05-28 08:42:24 +00:00
|
|
|
std::cout << GetClass().mb_str() << ' ';
|
2008-02-12 01:02:53 +00:00
|
|
|
#endif
|
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
while( !done )
|
2007-08-06 02:02:39 +00:00
|
|
|
{
|
2007-08-24 03:40:04 +00:00
|
|
|
stype = *p;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-09 21:15:08 +00:00
|
|
|
switch( stype )
|
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_T:
|
2016-07-12 19:05:54 +00:00
|
|
|
result = inspector( this, testData ); // inspect me
|
2007-08-24 03:40:04 +00:00
|
|
|
// skip over any types handled in the above call.
|
|
|
|
++p;
|
2007-08-09 21:15:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Instances of the requested KICAD_T live in a list, either one
|
2009-05-28 08:42:24 +00:00
|
|
|
* that I manage, or that my modules manage. If it's a type managed
|
|
|
|
* by class MODULE, then simply pass it on to each module's
|
|
|
|
* MODULE::Visit() function by way of the
|
|
|
|
* IterateForward( m_Modules, ... ) call.
|
|
|
|
*/
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MODULE_T:
|
|
|
|
case PCB_PAD_T:
|
|
|
|
case PCB_MODULE_TEXT_T:
|
|
|
|
case PCB_MODULE_EDGE_T:
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-09 21:15:08 +00:00
|
|
|
// this calls MODULE::Visit() on each module.
|
2007-08-24 03:40:04 +00:00
|
|
|
result = IterateForward( m_Modules, inspector, testData, p );
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
// skip over any types handled in the above call.
|
2009-05-28 08:42:24 +00:00
|
|
|
for( ; ; )
|
2007-08-24 03:40:04 +00:00
|
|
|
{
|
|
|
|
switch( stype = *++p )
|
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MODULE_T:
|
|
|
|
case PCB_PAD_T:
|
|
|
|
case PCB_MODULE_TEXT_T:
|
|
|
|
case PCB_MODULE_EDGE_T:
|
2007-08-24 03:40:04 +00:00
|
|
|
continue;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
2007-08-24 03:40:04 +00:00
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-09 21:15:08 +00:00
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_LINE_T:
|
|
|
|
case PCB_TEXT_T:
|
|
|
|
case PCB_DIMENSION_T:
|
2011-09-07 19:41:04 +00:00
|
|
|
case PCB_TARGET_T:
|
2007-08-24 03:40:04 +00:00
|
|
|
result = IterateForward( m_Drawings, inspector, testData, p );
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
// skip over any types handled in the above call.
|
2009-05-28 08:42:24 +00:00
|
|
|
for( ; ; )
|
2007-08-24 03:40:04 +00:00
|
|
|
{
|
|
|
|
switch( stype = *++p )
|
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_LINE_T:
|
|
|
|
case PCB_TEXT_T:
|
|
|
|
case PCB_DIMENSION_T:
|
2011-09-07 19:41:04 +00:00
|
|
|
case PCB_TARGET_T:
|
2007-08-24 03:40:04 +00:00
|
|
|
continue;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
2007-08-24 03:40:04 +00:00
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
;
|
2007-08-09 21:15:08 +00:00
|
|
|
break;
|
2007-08-30 22:20:52 +00:00
|
|
|
|
2009-11-12 15:43:38 +00:00
|
|
|
#if 0 // both these are on same list, so we must scan it twice in order
|
|
|
|
// to get VIA priority, using new #else code below.
|
2014-04-25 06:00:04 +00:00
|
|
|
// But we are not using separate lists for TRACKs and VIA, because
|
2009-11-12 15:43:38 +00:00
|
|
|
// items are ordered (sorted) in the linked
|
2008-02-12 01:02:53 +00:00
|
|
|
// list by netcode AND by physical distance:
|
2009-11-12 15:43:38 +00:00
|
|
|
// when created, if a track or via is connected to an existing track or
|
|
|
|
// via, it is put in linked list after this existing track or via
|
2008-02-12 01:02:53 +00:00
|
|
|
// So usually, connected tracks or vias are grouped in this list
|
2011-09-14 20:04:58 +00:00
|
|
|
// So the algorithm (used in ratsnest computations) which computes the
|
2009-11-12 15:43:38 +00:00
|
|
|
// track connectivity is faster (more than 100 time regarding to
|
2012-04-01 20:51:56 +00:00
|
|
|
// a non ordered list) because when it searches for a connection, first
|
2009-11-12 15:43:38 +00:00
|
|
|
// it tests the near (near in term of linked list) 50 items
|
2008-02-12 01:02:53 +00:00
|
|
|
// from the current item (track or via) in test.
|
2009-11-12 15:43:38 +00:00
|
|
|
// Usually, because of this sort, a connected item (if exists) is
|
|
|
|
// found.
|
|
|
|
// If not found (and only in this case) an exhaustive (and time
|
|
|
|
// consuming) search is made, but this case is statistically rare.
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_VIA_T:
|
|
|
|
case PCB_TRACE_T:
|
2007-08-24 03:40:04 +00:00
|
|
|
result = IterateForward( m_Track, inspector, testData, p );
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
// skip over any types handled in the above call.
|
2009-05-28 08:42:24 +00:00
|
|
|
for( ; ; )
|
2007-08-24 03:40:04 +00:00
|
|
|
{
|
|
|
|
switch( stype = *++p )
|
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_VIA_T:
|
|
|
|
case PCB_TRACE_T:
|
2007-08-24 03:40:04 +00:00
|
|
|
continue;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
2007-08-24 03:40:04 +00:00
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-30 22:20:52 +00:00
|
|
|
break;
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-08-30 22:20:52 +00:00
|
|
|
#else
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_VIA_T:
|
2007-08-30 22:20:52 +00:00
|
|
|
result = IterateForward( m_Track, inspector, testData, p );
|
|
|
|
++p;
|
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_TRACE_T:
|
2007-08-30 22:20:52 +00:00
|
|
|
result = IterateForward( m_Track, inspector, testData, p );
|
|
|
|
++p;
|
|
|
|
break;
|
|
|
|
#endif
|
2007-11-27 22:49:35 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_MARKER_T:
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2009-08-01 19:26:05 +00:00
|
|
|
// MARKER_PCBS are in the m_markers std::vector
|
2009-11-12 15:43:38 +00:00
|
|
|
for( unsigned i = 0; i<m_markers.size(); ++i )
|
2007-11-27 22:49:35 +00:00
|
|
|
{
|
|
|
|
result = m_markers[i]->Visit( inspector, testData, p );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
if( result == SEARCH_QUIT )
|
|
|
|
break;
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-11-27 22:49:35 +00:00
|
|
|
++p;
|
|
|
|
break;
|
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
case PCB_ZONE_AREA_T:
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
// PCB_ZONE_AREA_T are in the m_ZoneDescriptorList std::vector
|
2009-11-12 15:43:38 +00:00
|
|
|
for( unsigned i = 0; i< m_ZoneDescriptorList.size(); ++i )
|
2007-12-29 19:15:58 +00:00
|
|
|
{
|
2011-09-07 19:41:04 +00:00
|
|
|
result = m_ZoneDescriptorList[i]->Visit( inspector, testData, p );
|
|
|
|
|
2007-12-29 19:15:58 +00:00
|
|
|
if( result == SEARCH_QUIT )
|
|
|
|
break;
|
|
|
|
}
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2007-12-29 19:15:58 +00:00
|
|
|
++p;
|
|
|
|
break;
|
|
|
|
|
2018-09-29 17:58:31 +00:00
|
|
|
case PCB_SEGZONE_T:
|
2018-05-12 19:37:43 +00:00
|
|
|
result = IterateForward( m_SegZoneDeprecated, inspector, testData, p );
|
2007-08-24 03:40:04 +00:00
|
|
|
++p;
|
2007-08-09 21:15:08 +00:00
|
|
|
break;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2007-08-24 03:40:04 +00:00
|
|
|
default: // catch EOT or ANY OTHER type here and return.
|
|
|
|
done = true;
|
2007-08-09 21:15:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2007-08-09 21:15:08 +00:00
|
|
|
if( result == SEARCH_QUIT )
|
|
|
|
break;
|
2007-08-06 02:02:39 +00:00
|
|
|
}
|
2007-08-09 21:15:08 +00:00
|
|
|
|
2008-02-12 01:02:53 +00:00
|
|
|
return result;
|
2007-08-06 02:02:39 +00:00
|
|
|
}
|
2007-08-06 20:26:59 +00:00
|
|
|
|
|
|
|
|
2010-12-29 17:47:32 +00:00
|
|
|
NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const
|
2007-08-20 19:33:15 +00:00
|
|
|
{
|
2011-12-10 05:33:24 +00:00
|
|
|
// the first valid netcode is 1 and the last is m_NetInfo.GetCount()-1.
|
2015-01-23 11:24:32 +00:00
|
|
|
// zero is reserved for "no connection" and is not actually a net.
|
2009-07-20 05:18:47 +00:00
|
|
|
// NULL is returned for non valid netcodes
|
2009-08-10 02:22:56 +00:00
|
|
|
|
2018-09-21 12:41:28 +00:00
|
|
|
wxASSERT( m_NetInfo.GetNetCount() > 0 );
|
2015-01-23 11:24:32 +00:00
|
|
|
|
|
|
|
if( aNetcode == NETINFO_LIST::UNCONNECTED && m_NetInfo.GetNetCount() == 0 )
|
2016-01-29 10:29:56 +00:00
|
|
|
return &NETINFO_LIST::ORPHANED_ITEM;
|
2014-11-24 15:34:47 +00:00
|
|
|
else
|
|
|
|
return m_NetInfo.GetNetItem( aNetcode );
|
2007-08-20 19:33:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
|
2008-01-06 20:58:27 +00:00
|
|
|
{
|
2014-01-10 17:04:07 +00:00
|
|
|
return m_NetInfo.GetNetItem( aNetname );
|
2008-01-06 20:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-07 17:10:12 +00:00
|
|
|
MODULE* BOARD::FindModuleByReference( const wxString& aReference ) const
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
MODULE* found = nullptr;
|
2013-11-02 00:24:38 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
// search only for MODULES
|
|
|
|
static const KICAD_T scanTypes[] = { PCB_MODULE_T, EOT };
|
2008-02-07 17:10:12 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
|
|
|
|
{
|
|
|
|
MODULE* module = (MODULE*) item;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( aReference == module->GetReference() )
|
|
|
|
{
|
|
|
|
found = module;
|
|
|
|
return SEARCH_QUIT;
|
2008-02-07 17:10:12 +00:00
|
|
|
}
|
2008-01-06 20:58:27 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
};
|
2008-02-07 17:10:12 +00:00
|
|
|
|
|
|
|
// visit this BOARD with the above inspector
|
|
|
|
BOARD* nonconstMe = (BOARD*) this;
|
2016-07-12 19:05:54 +00:00
|
|
|
nonconstMe->Visit( inspector, NULL, scanTypes );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
return found;
|
2008-02-07 17:10:12 +00:00
|
|
|
}
|
2008-01-06 20:58:27 +00:00
|
|
|
|
|
|
|
|
2013-11-02 00:24:38 +00:00
|
|
|
MODULE* BOARD::FindModule( const wxString& aRefOrTimeStamp, bool aSearchByTimeStamp ) const
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2013-11-02 00:24:38 +00:00
|
|
|
if( aSearchByTimeStamp )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2013-11-02 00:24:38 +00:00
|
|
|
for( MODULE* module = m_Modules; module; module = module->Next() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
|
|
|
if( aRefOrTimeStamp.CmpNoCase( module->GetPath() ) == 0 )
|
|
|
|
return module;
|
|
|
|
}
|
2013-11-02 00:24:38 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FindModuleByReference( aRefOrTimeStamp );
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-02 16:14:34 +00:00
|
|
|
|
|
|
|
// The pad count for each netcode, stored in a buffer for a fast access.
|
|
|
|
// This is needed by the sort function sortNetsByNodes()
|
|
|
|
static std::vector<int> padCountListByNet;
|
|
|
|
|
|
|
|
// Sort nets by decreasing pad count.
|
|
|
|
// For same pad count, sort by alphabetic names
|
2014-08-29 06:47:05 +00:00
|
|
|
static bool sortNetsByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2018-06-02 16:14:34 +00:00
|
|
|
int countA = padCountListByNet[a->GetNet()];
|
|
|
|
int countB = padCountListByNet[b->GetNet()];
|
2014-08-29 06:47:05 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
if( countA == countB )
|
|
|
|
return a->GetNetname() < b->GetNetname();
|
|
|
|
else
|
|
|
|
return countB < countA;
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-29 06:47:05 +00:00
|
|
|
// Sort nets by alphabetic names
|
|
|
|
static bool sortNetsByNames( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
|
|
|
|
{
|
|
|
|
return a->GetNetname() < b->GetNetname();
|
|
|
|
}
|
2007-12-17 20:18:04 +00:00
|
|
|
|
* KIWAY Milestone A): Make major modules into DLL/DSOs.
! The initial testing of this commit should be done using a Debug build so that
all the wxASSERT()s are enabled. Also, be sure and keep enabled the
USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it
off is senseless anyways. If you want stable code, go back to a prior version,
the one tagged with "stable".
* Relocate all functionality out of the wxApp derivative into more finely
targeted purposes:
a) DLL/DSO specific
b) PROJECT specific
c) EXE or process specific
d) configuration file specific data
e) configuration file manipulations functions.
All of this functionality was blended into an extremely large wxApp derivative
and that was incompatible with the desire to support multiple concurrently
loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects.
An amazing amount of organization come from simply sorting each bit of
functionality into the proper box.
* Switch to wxConfigBase from wxConfig everywhere except instantiation.
* Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD,
PGM_SINGLE_TOP,
* Remove "Return" prefix on many function names.
* Remove obvious comments from CMakeLists.txt files, and from else() and endif()s.
* Fix building boost for use in a DSO on linux.
* Remove some of the assumptions in the CMakeLists.txt files that windows had
to be the host platform when building windows binaries.
* Reduce the number of wxStrings being constructed at program load time via
static construction.
* Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that
these functions are useful even when the wxConfigBase comes from another
source, as is the case in the KICAD_MANAGER_FRAME.
* Move the setting of the KIPRJMOD environment variable into class PROJECT,
so that it can be moved into a project variable soon, and out of FP_LIB_TABLE.
* Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all
its child wxFrames and wxDialogs now have a Kiway() member function which
returns a KIWAY& that that window tree branch is in support of. This is like
wxWindows DNA in that child windows get this member with proper value at time
of construction.
* Anticipate some of the needs for milestones B) and C) and make code
adjustments now in an effort to reduce work in those milestones.
* No testing has been done for python scripting, since milestone C) has that
being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
|
|
|
int BOARD::SortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount )
|
2007-12-17 20:18:04 +00:00
|
|
|
{
|
2011-12-10 05:33:24 +00:00
|
|
|
if( m_NetInfo.GetNetCount() == 0 )
|
2009-05-28 08:42:24 +00:00
|
|
|
return 0;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2009-08-10 02:22:56 +00:00
|
|
|
// Build the list
|
2009-05-28 08:42:24 +00:00
|
|
|
std::vector <NETINFO_ITEM*> netBuffer;
|
2009-08-10 02:22:56 +00:00
|
|
|
|
2011-12-10 05:33:24 +00:00
|
|
|
netBuffer.reserve( m_NetInfo.GetNetCount() );
|
2018-11-03 17:13:16 +00:00
|
|
|
int max_netcode = 0;
|
2009-08-10 02:22:56 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( NETINFO_ITEM* net : m_NetInfo )
|
2008-02-12 01:02:53 +00:00
|
|
|
{
|
2018-11-03 17:13:16 +00:00
|
|
|
auto netcode = net->GetNet();
|
|
|
|
|
|
|
|
if( netcode > 0 )
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
netBuffer.push_back( net );
|
2018-11-03 17:13:16 +00:00
|
|
|
max_netcode = std::max( netcode, max_netcode);
|
|
|
|
}
|
2008-02-12 01:02:53 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 02:22:56 +00:00
|
|
|
// sort the list
|
2009-05-28 08:42:24 +00:00
|
|
|
if( aSortbyPadsCount )
|
2018-06-02 16:14:34 +00:00
|
|
|
{
|
|
|
|
// Build the pad count by net:
|
|
|
|
padCountListByNet.clear();
|
|
|
|
std::vector<D_PAD*> pads = GetPads();
|
|
|
|
|
2018-11-03 17:13:16 +00:00
|
|
|
padCountListByNet.assign( max_netcode + 1, 0 );
|
2018-06-02 16:14:34 +00:00
|
|
|
|
|
|
|
for( D_PAD* pad : pads )
|
|
|
|
padCountListByNet[pad->GetNetCode()]++;
|
|
|
|
|
2014-08-29 06:47:05 +00:00
|
|
|
sort( netBuffer.begin(), netBuffer.end(), sortNetsByNodes );
|
2018-06-02 16:14:34 +00:00
|
|
|
}
|
2014-08-29 06:47:05 +00:00
|
|
|
else
|
2018-11-03 17:13:16 +00:00
|
|
|
{
|
2014-08-29 06:47:05 +00:00
|
|
|
sort( netBuffer.begin(), netBuffer.end(), sortNetsByNames );
|
2018-11-03 17:13:16 +00:00
|
|
|
}
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( NETINFO_ITEM* net : netBuffer )
|
|
|
|
aNames.Add( net->GetNetname() );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
return netBuffer.size();
|
2007-12-17 20:18:04 +00:00
|
|
|
}
|
2007-10-30 21:30:58 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
void BOARD::RedrawAreasOutlines( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, PCB_LAYER_ID aLayer )
|
2008-01-23 08:01:38 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
if( !aDC )
|
|
|
|
return;
|
2008-01-23 08:01:38 +00:00
|
|
|
|
2008-02-12 01:02:53 +00:00
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
ZONE_CONTAINER* edge_zone = GetArea( ii );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
|
2008-04-01 05:21:50 +00:00
|
|
|
edge_zone->Draw( panel, aDC, aDrawMode );
|
2008-02-12 01:02:53 +00:00
|
|
|
}
|
2008-01-23 08:01:38 +00:00
|
|
|
}
|
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
void BOARD::RedrawFilledAreas( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, PCB_LAYER_ID aLayer )
|
2008-09-26 19:51:36 +00:00
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
if( !aDC )
|
|
|
|
return;
|
2008-09-26 19:51:36 +00:00
|
|
|
|
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
|
|
{
|
2009-05-28 08:42:24 +00:00
|
|
|
ZONE_CONTAINER* edge_zone = GetArea( ii );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
if( (aLayer < 0) || ( aLayer == edge_zone->GetLayer() ) )
|
2008-09-26 19:51:36 +00:00
|
|
|
edge_zone->DrawFilledArea( panel, aDC, aDrawMode );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-30 21:30:58 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos,
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer, int aNetCode )
|
2008-11-27 10:12:46 +00:00
|
|
|
{
|
|
|
|
if( aEndLayer < 0 )
|
|
|
|
aEndLayer = aStartLayer;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
if( aEndLayer < aStartLayer )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( aEndLayer, aStartLayer );
|
2008-11-27 10:12:46 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( ZONE_CONTAINER* area : m_ZoneDescriptorList )
|
2008-11-27 10:12:46 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
if( area->GetLayer() < aStartLayer || area->GetLayer() > aEndLayer )
|
2009-05-28 08:42:24 +00:00
|
|
|
continue;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
// In locate functions we must skip tagged items with BUSY flag set.
|
|
|
|
if( area->GetState( BUSY ) )
|
2008-11-27 10:12:46 +00:00
|
|
|
continue;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2014-02-25 10:40:34 +00:00
|
|
|
if( aNetCode >= 0 && area->GetNetCode() != aNetCode )
|
2013-09-18 19:21:11 +00:00
|
|
|
continue;
|
|
|
|
|
2008-11-27 10:12:46 +00:00
|
|
|
if( area->HitTestFilledArea( aRefPos ) )
|
|
|
|
return area;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-28 08:42:24 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
int BOARD::SetAreasNetCodesFromNetNames()
|
2009-05-24 18:28:36 +00:00
|
|
|
{
|
|
|
|
int error_count = 0;
|
|
|
|
|
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
ZONE_CONTAINER* it = GetArea( ii );
|
|
|
|
|
|
|
|
if( !it->IsOnCopperLayer() )
|
2009-05-24 18:28:36 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
it->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
2009-05-24 18:28:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-30 04:40:16 +00:00
|
|
|
if( it->GetNetCode() != 0 ) // i.e. if this zone is connected to a net
|
2009-05-24 18:28:36 +00:00
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
const NETINFO_ITEM* net = it->GetNet();
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
if( net )
|
|
|
|
{
|
2014-06-30 04:40:16 +00:00
|
|
|
it->SetNetCode( net->GetNet() );
|
2009-05-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error_count++;
|
2011-09-14 20:04:58 +00:00
|
|
|
|
|
|
|
// keep Net Name and set m_NetCode to -1 : error flag.
|
2014-06-30 04:40:16 +00:00
|
|
|
it->SetNetCode( -1 );
|
2009-05-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error_count;
|
|
|
|
}
|
2008-11-27 10:12:46 +00:00
|
|
|
|
2007-10-30 21:30:58 +00:00
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
VIA* BOARD::GetViaByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer) const
|
2011-09-14 20:04:58 +00:00
|
|
|
{
|
2014-04-30 19:16:22 +00:00
|
|
|
for( VIA *via = GetFirstVia( m_Track); via; via = GetFirstVia( via->Next() ) )
|
2011-09-14 20:04:58 +00:00
|
|
|
{
|
2014-04-30 19:16:22 +00:00
|
|
|
if( (via->GetStart() == aPosition) &&
|
|
|
|
(via->GetState( BUSY | IS_DELETED ) == 0) &&
|
|
|
|
((aLayer == UNDEFINED_LAYER) || (via->IsOnLayer( aLayer ))) )
|
|
|
|
return via;
|
2011-09-14 20:04:58 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
return NULL;
|
2011-09-14 20:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
D_PAD* BOARD::GetPad( const wxPoint& aPosition, LSET aLayerSet )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
if( !aLayerSet.any() )
|
|
|
|
aLayerSet = LSET::AllCuMask();
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
for( MODULE* module = m_Modules; module; module = module->Next() )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2018-05-22 22:37:24 +00:00
|
|
|
D_PAD* pad = NULL;
|
|
|
|
|
|
|
|
if( module->HitTest( aPosition ) )
|
|
|
|
pad = module->GetPad( aPosition, aLayerSet );
|
2014-06-24 16:17:18 +00:00
|
|
|
|
|
|
|
if( pad )
|
|
|
|
return pad;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
return NULL;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-25 17:13:33 +00:00
|
|
|
D_PAD* BOARD::GetPad( TRACK* aTrace, ENDPOINT_T aEndPoint )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
const wxPoint& aPosition = aTrace->GetEndPoint( aEndPoint );
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
LSET lset( aTrace->GetLayer() );
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2018-05-22 22:37:24 +00:00
|
|
|
return GetPad( aPosition, lset );
|
2017-07-17 12:55:31 +00:00
|
|
|
}
|
|
|
|
|
2017-09-18 09:25:32 +00:00
|
|
|
|
2017-07-17 12:55:31 +00:00
|
|
|
std::list<TRACK*> BOARD::GetTracksByPosition( const wxPoint& aPosition, PCB_LAYER_ID aLayer ) const
|
|
|
|
{
|
|
|
|
std::list<TRACK*> tracks;
|
2017-09-18 09:25:32 +00:00
|
|
|
|
|
|
|
for( TRACK* track = GetFirstTrack( m_Track ); track; track = GetFirstTrack( track->Next() ) )
|
2017-07-17 12:55:31 +00:00
|
|
|
{
|
2017-09-18 09:25:32 +00:00
|
|
|
if( ( ( track->GetStart() == aPosition ) || track->GetEnd() == aPosition ) &&
|
2017-07-17 12:55:31 +00:00
|
|
|
( track->GetState( BUSY | IS_DELETED ) == 0 ) &&
|
|
|
|
( ( aLayer == UNDEFINED_LAYER ) || ( track->IsOnLayer( aLayer ) ) ) )
|
|
|
|
|
|
|
|
tracks.push_back( track );
|
|
|
|
}
|
2017-09-18 09:25:32 +00:00
|
|
|
|
2017-07-17 12:55:31 +00:00
|
|
|
return tracks;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
D_PAD* BOARD::GetPadFast( const wxPoint& aPosition, LSET aLayerSet )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2017-03-22 13:51:07 +00:00
|
|
|
for( auto mod : Modules() )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2017-04-25 09:06:24 +00:00
|
|
|
for ( auto pad : mod->Pads() )
|
2017-03-22 13:51:07 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
if( pad->GetPosition() != aPosition )
|
2011-09-15 17:58:35 +00:00
|
|
|
continue;
|
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
// Pad found, it must be on the correct layer
|
2016-07-12 19:05:54 +00:00
|
|
|
if( ( pad->GetLayerSet() & aLayerSet ).any() )
|
2011-09-15 17:58:35 +00:00
|
|
|
return pad;
|
2018-01-28 09:35:33 +00:00
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
return nullptr;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
D_PAD* BOARD::GetPad( std::vector<D_PAD*>& aPadList, const wxPoint& aPosition, LSET aLayerSet )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
// Search aPadList for aPosition
|
2011-10-31 13:44:13 +00:00
|
|
|
// aPadList is sorted by X then Y values, and a fast binary search is used
|
|
|
|
int idxmax = aPadList.size()-1;
|
|
|
|
|
|
|
|
int delta = aPadList.size();
|
2011-12-28 15:14:46 +00:00
|
|
|
|
|
|
|
int idx = 0; // Starting index is the beginning of list
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
while( delta )
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2011-12-28 15:14:46 +00:00
|
|
|
// Calculate half size of remaining interval to test.
|
|
|
|
// Ensure the computed value is not truncated (too small)
|
2011-10-31 13:44:13 +00:00
|
|
|
if( (delta & 1) && ( delta > 1 ) )
|
|
|
|
delta++;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
delta /= 2;
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
D_PAD* pad = aPadList[idx];
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( pad->GetPosition() == aPosition ) // candidate found
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2011-10-31 13:44:13 +00:00
|
|
|
// The pad must match the layer mask:
|
2016-07-12 19:05:54 +00:00
|
|
|
if( ( aLayerSet & pad->GetLayerSet() ).any() )
|
2011-10-31 13:44:13 +00:00
|
|
|
return pad;
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// More than one pad can be at aPosition
|
|
|
|
// search for a pad at aPosition that matched this mask
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// search next
|
|
|
|
for( int ii = idx+1; ii <= idxmax; ii++ )
|
|
|
|
{
|
|
|
|
pad = aPadList[ii];
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( pad->GetPosition() != aPosition )
|
2011-10-31 13:44:13 +00:00
|
|
|
break;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( ( aLayerSet & pad->GetLayerSet() ).any() )
|
2011-10-31 13:44:13 +00:00
|
|
|
return pad;
|
|
|
|
}
|
|
|
|
// search previous
|
|
|
|
for( int ii = idx-1 ;ii >=0; ii-- )
|
|
|
|
{
|
|
|
|
pad = aPadList[ii];
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( pad->GetPosition() != aPosition )
|
2011-10-31 13:44:13 +00:00
|
|
|
break;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( ( aLayerSet & pad->GetLayerSet() ).any() )
|
2011-10-31 13:44:13 +00:00
|
|
|
return pad;
|
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
// Not found:
|
|
|
|
return 0;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( pad->GetPosition().x == aPosition.x ) // Must search considering Y coordinate
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
if( pad->GetPosition().y < aPosition.y ) // Must search after this item
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2011-10-31 13:44:13 +00:00
|
|
|
idx += delta;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
if( idx > idxmax )
|
|
|
|
idx = idxmax;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
2011-10-31 13:44:13 +00:00
|
|
|
else // Must search before this item
|
2011-09-15 17:58:35 +00:00
|
|
|
{
|
2011-10-31 13:44:13 +00:00
|
|
|
idx -= delta;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
if( idx < 0 )
|
|
|
|
idx = 0;
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-19 04:02:19 +00:00
|
|
|
else if( pad->GetPosition().x < aPosition.x ) // Must search after this item
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
|
|
|
idx += delta;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
if( idx > idxmax )
|
|
|
|
idx = idxmax;
|
|
|
|
}
|
|
|
|
else // Must search before this item
|
|
|
|
{
|
|
|
|
idx -= delta;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
if( idx < 0 )
|
|
|
|
idx = 0;
|
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-31 13:44:13 +00:00
|
|
|
/**
|
|
|
|
* Function SortPadsByXCoord
|
|
|
|
* is used by GetSortedPadListByXCoord to Sort a pad list by x coordinate value.
|
2012-09-11 07:33:17 +00:00
|
|
|
* This function is used to build ordered pads lists
|
2011-10-31 13:44:13 +00:00
|
|
|
*/
|
2012-09-11 07:33:17 +00:00
|
|
|
bool sortPadsByXthenYCoord( D_PAD* const & ref, D_PAD* const & comp )
|
2011-10-31 13:44:13 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
if( ref->GetPosition().x == comp->GetPosition().x )
|
|
|
|
return ref->GetPosition().y < comp->GetPosition().y;
|
|
|
|
return ref->GetPosition().x < comp->GetPosition().x;
|
2011-10-31 13:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-17 21:21:03 +00:00
|
|
|
void BOARD::GetSortedPadListByXthenYCoord( std::vector<D_PAD*>& aVector, int aNetCode )
|
2011-09-17 01:22:26 +00:00
|
|
|
{
|
2017-03-22 13:51:07 +00:00
|
|
|
for ( auto mod : Modules() )
|
2011-12-17 21:21:03 +00:00
|
|
|
{
|
2017-04-25 09:06:24 +00:00
|
|
|
for ( auto pad : mod->Pads( ) )
|
2011-12-17 21:21:03 +00:00
|
|
|
{
|
2017-03-22 13:51:07 +00:00
|
|
|
if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
|
|
|
|
{
|
|
|
|
aVector.push_back( pad );
|
|
|
|
}
|
2011-12-17 21:21:03 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
|
2011-09-17 01:22:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-23 23:02:40 +00:00
|
|
|
void BOARD::PadDelete( D_PAD* aPad )
|
|
|
|
{
|
2018-07-26 14:20:16 +00:00
|
|
|
GetConnectivity()->Remove( aPad );
|
2015-09-23 23:02:40 +00:00
|
|
|
aPad->DeleteStructure();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
TRACK* BOARD::GetVisibleTrack( TRACK* aStartingTrace, const wxPoint& aPosition,
|
|
|
|
LSET aLayerSet ) const
|
2011-09-16 14:13:02 +00:00
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
for( TRACK* track = aStartingTrace; track; track = track->Next() )
|
2011-09-16 14:13:02 +00:00
|
|
|
{
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID layer = track->GetLayer();
|
2011-09-16 14:13:02 +00:00
|
|
|
|
|
|
|
if( track->GetState( BUSY | IS_DELETED ) )
|
|
|
|
continue;
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
// track's layer is not visible
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
if( m_designSettings.IsLayerVisible( layer ) == false )
|
2011-09-16 14:13:02 +00:00
|
|
|
continue;
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( track->Type() == PCB_VIA_T ) // VIA encountered.
|
2011-09-16 14:13:02 +00:00
|
|
|
{
|
|
|
|
if( track->HitTest( aPosition ) )
|
|
|
|
return track;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
if( !aLayerSet[layer] )
|
|
|
|
continue; // track's layer is not in aLayerSet
|
2011-09-16 14:13:02 +00:00
|
|
|
|
|
|
|
if( track->HitTest( aPosition ) )
|
|
|
|
return track;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
TRACK* BOARD::MarkTrace( TRACK* aTrackList, TRACK* aTrace, int* aCount,
|
2012-12-12 11:57:17 +00:00
|
|
|
double* aTraceLength, double* aPadToDieLength,
|
|
|
|
bool aReorder )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
Pcbnew: major swig fix.
* Switched hashtables.h over to std::undordered_map from boost version.
* Added new macros DECL_VEC_FOR_SWIG() and DECL_MAP_FOR_SWIG() in macros.h.
These along with future DECL_HASH_FOR_SWIG() unify the declaration to swig
and C++ so that the resultant type name is common in both languages, and
the types AGREE.
* Fixed swigging of NETINFO_ITEM and NETINFO_LIST via magic.
* Newly exposed (python wrapped) are: D_PADS, TRACKS (was TRACK_PTRS),
NETNAME_MAP, NETCODE_MAP, wxString (without constructor purposely, read
comment in wx.i), MARKERS, ZONE_CONTAINERS, NETCLASSPTR, KICAD_T types.
* std::vector<SOMETHING*> tends to end up named SOMETHINGS in C++ and python.
Having the name consistent between like types is helpful, and between
languages. std::map<> ends up as SOMETHING_MAP.
* NETINFO_LIST::m_netNames and NETINFO_LIST::m_netCodes are now std::map
instead of hashtables, because swig does not yet support std::unordered_map.
* You can now get to any netclass or net info. NETNAMES_MAP and NETCODES_MAP
are traversable basically the same as a python dictionary using a python
string (not wsString) as the key! The wxString typemap converts python
string to wxString before the lookup happens. Iteration also works.
2016-07-18 17:23:09 +00:00
|
|
|
TRACKS trackList;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
if( aCount )
|
|
|
|
*aCount = 0;
|
|
|
|
|
|
|
|
if( aTraceLength )
|
|
|
|
*aTraceLength = 0;
|
|
|
|
|
|
|
|
if( aTrace == NULL )
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// Ensure the flag BUSY of all tracks of the board is cleared
|
|
|
|
// because we use it to mark segments of the track
|
2018-06-12 14:50:18 +00:00
|
|
|
for( TRACK* track = aTrackList; track; track = track->Next() )
|
2013-03-30 17:24:04 +00:00
|
|
|
track->SetState( BUSY, false );
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
// Set flags of the initial track segment
|
2013-03-30 17:24:04 +00:00
|
|
|
aTrace->SetState( BUSY, true );
|
2015-07-10 16:43:25 +00:00
|
|
|
LSET layer_set = aTrace->GetLayerSet();
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
trackList.push_back( aTrace );
|
|
|
|
|
|
|
|
/* Examine the initial track segment : if it is really a segment, this is
|
|
|
|
* easy.
|
|
|
|
* If it is a via, one must search for connected segments.
|
|
|
|
* If <=2, this via connect 2 segments (or is connected to only one
|
|
|
|
* segment) and this via and these 2 segments are a part of a track.
|
|
|
|
* If > 2 only this via is flagged (the track has only this via)
|
|
|
|
*/
|
2011-10-01 19:24:27 +00:00
|
|
|
if( aTrace->Type() == PCB_VIA_T )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2018-06-12 14:50:18 +00:00
|
|
|
TRACK* segm1 = ::GetTrack( aTrackList, NULL, aTrace->GetStart(), layer_set );
|
2015-07-10 16:43:25 +00:00
|
|
|
TRACK* segm2 = NULL;
|
|
|
|
TRACK* segm3 = NULL;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( segm1 )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
segm2 = ::GetTrack( segm1->Next(), NULL, aTrace->GetStart(), layer_set );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( segm2 )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
segm3 = ::GetTrack( segm2->Next(), NULL, aTrace->GetStart(), layer_set );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( segm3 )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
// More than 2 segments are connected to this via.
|
|
|
|
// The "track" is only this via.
|
|
|
|
|
2011-09-16 15:54:50 +00:00
|
|
|
if( aCount )
|
|
|
|
*aCount = 1;
|
|
|
|
|
|
|
|
return aTrace;
|
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( segm1 ) // search for other segments connected to the initial segment start point
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
layer_set = segm1->GetLayerSet();
|
2018-06-12 14:50:18 +00:00
|
|
|
chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &trackList );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( segm2 ) // search for other segments connected to the initial segment end point
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
layer_set = segm2->GetLayerSet();
|
2018-06-12 14:50:18 +00:00
|
|
|
chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &trackList );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else // mark the chain using both ends of the initial segment
|
|
|
|
{
|
Pcbnew: major swig fix.
* Switched hashtables.h over to std::undordered_map from boost version.
* Added new macros DECL_VEC_FOR_SWIG() and DECL_MAP_FOR_SWIG() in macros.h.
These along with future DECL_HASH_FOR_SWIG() unify the declaration to swig
and C++ so that the resultant type name is common in both languages, and
the types AGREE.
* Fixed swigging of NETINFO_ITEM and NETINFO_LIST via magic.
* Newly exposed (python wrapped) are: D_PADS, TRACKS (was TRACK_PTRS),
NETNAME_MAP, NETCODE_MAP, wxString (without constructor purposely, read
comment in wx.i), MARKERS, ZONE_CONTAINERS, NETCLASSPTR, KICAD_T types.
* std::vector<SOMETHING*> tends to end up named SOMETHINGS in C++ and python.
Having the name consistent between like types is helpful, and between
languages. std::map<> ends up as SOMETHING_MAP.
* NETINFO_LIST::m_netNames and NETINFO_LIST::m_netCodes are now std::map
instead of hashtables, because swig does not yet support std::unordered_map.
* You can now get to any netclass or net info. NETNAMES_MAP and NETCODES_MAP
are traversable basically the same as a python dictionary using a python
string (not wsString) as the key! The wxString typemap converts python
string to wxString before the lookup happens. Iteration also works.
2016-07-18 17:23:09 +00:00
|
|
|
TRACKS from_start;
|
|
|
|
TRACKS from_end;
|
2015-07-10 16:43:25 +00:00
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
chainMarkedSegments( aTrackList, aTrace->GetStart(), layer_set, &from_start );
|
|
|
|
chainMarkedSegments( aTrackList, aTrace->GetEnd(), layer_set, &from_end );
|
2015-07-10 16:43:25 +00:00
|
|
|
|
|
|
|
// combine into one trackList:
|
|
|
|
trackList.insert( trackList.end(), from_start.begin(), from_start.end() );
|
|
|
|
trackList.insert( trackList.end(), from_end.begin(), from_end.end() );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now examine selected vias and flag them if they are on the track
|
|
|
|
// If a via is connected to only one or 2 segments, it is flagged (is on the track)
|
|
|
|
// If a via is connected to more than 2 segments, it is a track end, and it
|
2015-07-10 16:43:25 +00:00
|
|
|
// is removed from the list.
|
|
|
|
// Go through the list backwards.
|
2011-09-16 15:54:50 +00:00
|
|
|
for( int i = trackList.size() - 1; i>=0; --i )
|
|
|
|
{
|
2015-07-10 16:43:25 +00:00
|
|
|
::VIA* via = dynamic_cast< ::VIA* >( trackList[i] );
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( !via )
|
2011-09-16 15:54:50 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if( via == aTrace )
|
|
|
|
continue;
|
|
|
|
|
2013-03-30 17:24:04 +00:00
|
|
|
via->SetState( BUSY, true ); // Try to flag it. the flag will be cleared later if needed
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
layer_set = via->GetLayerSet();
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
TRACK* track = ::GetTrack( aTrackList, NULL, via->GetStart(), layer_set );
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
// GetTrace does not consider tracks flagged BUSY.
|
|
|
|
// So if no connected track found, this via is on the current track
|
|
|
|
// only: keep it
|
|
|
|
if( track == NULL )
|
|
|
|
continue;
|
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
/* If a track is found, this via connects also other segments of
|
2018-04-08 10:28:59 +00:00
|
|
|
* the other track. This case happens when a via ends the selected
|
2011-09-16 15:54:50 +00:00
|
|
|
* track but must we consider this via is on the selected track, or
|
2018-04-08 10:28:59 +00:00
|
|
|
* on a other track.
|
2011-09-16 15:54:50 +00:00
|
|
|
* (this is important when selecting a track for deletion: must this
|
|
|
|
* via be deleted or not?)
|
2015-07-10 16:43:25 +00:00
|
|
|
* We consider this via to be on our track if other segments connected
|
2011-09-16 15:54:50 +00:00
|
|
|
* to this via remain connected when removing this via.
|
2015-07-10 16:43:25 +00:00
|
|
|
* We search for all other segments connected together:
|
|
|
|
* if they are on the same layer, then the via is on the selected track;
|
2018-04-08 10:28:59 +00:00
|
|
|
* if they are on different layers, the via is on a other track.
|
2011-09-16 15:54:50 +00:00
|
|
|
*/
|
2013-03-31 13:27:46 +00:00
|
|
|
LAYER_NUM layer = track->GetLayer();
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
while( ( track = ::GetTrack( track->Next(), NULL, via->GetStart(), layer_set ) ) != NULL )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
if( layer != track->GetLayer() )
|
|
|
|
{
|
2018-04-08 10:28:59 +00:00
|
|
|
// The via connects segments of a other track: it is removed
|
|
|
|
// from list because it is member of a other track
|
2013-03-30 17:24:04 +00:00
|
|
|
via->SetState( BUSY, false );
|
2011-09-16 15:54:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Rearrange the track list in order to have flagged segments linked
|
|
|
|
* from firstTrack so the NbSegmBusy segments are consecutive segments
|
|
|
|
* in list, the first item in the full track list is firstTrack, and
|
|
|
|
* the NbSegmBusy-1 next items (NbSegmBusy when including firstTrack)
|
|
|
|
* are the flagged segments
|
|
|
|
*/
|
2016-07-12 19:05:54 +00:00
|
|
|
int busy_count = 0;
|
|
|
|
TRACK* firstTrack;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2018-06-12 14:50:18 +00:00
|
|
|
for( firstTrack = aTrackList; firstTrack; firstTrack = firstTrack->Next() )
|
2011-09-16 15:54:50 +00:00
|
|
|
{
|
|
|
|
// Search for the first flagged BUSY segments
|
|
|
|
if( firstTrack->GetState( BUSY ) )
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
busy_count = 1;
|
2011-09-16 15:54:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( firstTrack == NULL )
|
|
|
|
return NULL;
|
|
|
|
|
2016-10-14 08:35:08 +00:00
|
|
|
// First step: calculate the track length and find the pads (when exist)
|
|
|
|
// at each end of the trace.
|
2011-09-16 15:54:50 +00:00
|
|
|
double full_len = 0;
|
2012-12-12 11:57:17 +00:00
|
|
|
double lenPadToDie = 0;
|
2016-10-14 08:35:08 +00:00
|
|
|
// Because we have a track (a set of track segments between 2 nodes),
|
|
|
|
// only 2 pads (maximum) will be taken in account:
|
|
|
|
// that are on each end of the track, if any.
|
|
|
|
// keep trace of them, to know the die length and the track length ibside each pad.
|
|
|
|
D_PAD* s_pad = NULL; // the pad on one end of the trace
|
|
|
|
D_PAD* e_pad = NULL; // the pad on the other end of the trace
|
|
|
|
int dist_fromstart = INT_MAX;
|
|
|
|
int dist_fromend = INT_MAX;
|
|
|
|
|
|
|
|
for( TRACK* track = firstTrack; track; track = track->Next() )
|
|
|
|
{
|
|
|
|
if( !track->GetState( BUSY ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
layer_set = track->GetLayerSet();
|
|
|
|
D_PAD * pad_on_start = GetPad( track->GetStart(), layer_set );
|
|
|
|
D_PAD * pad_on_end = GetPad( track->GetEnd(), layer_set );
|
|
|
|
|
|
|
|
// a segment fully inside a pad does not contribute to the track len
|
2018-04-08 10:28:59 +00:00
|
|
|
// (another track end inside this pad will contribute to this lenght)
|
2016-10-14 08:35:08 +00:00
|
|
|
if( pad_on_start && ( pad_on_start == pad_on_end ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
full_len += track->GetLength();
|
|
|
|
|
|
|
|
if( pad_on_start == NULL && pad_on_end == NULL )
|
|
|
|
// This most of time the case
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// At this point, we can have one track end on a pad, or the 2 track ends on
|
|
|
|
// 2 different pads.
|
|
|
|
// We don't know what pad (s_pad or e_pad) must be used to store the
|
|
|
|
// start point and the end point of the track, so if a pad is already set,
|
|
|
|
// use the other
|
|
|
|
if( pad_on_start )
|
|
|
|
{
|
|
|
|
SEG segm( track->GetStart(), pad_on_start->GetPosition() );
|
|
|
|
int dist = segm.Length();
|
|
|
|
|
|
|
|
if( s_pad == NULL )
|
|
|
|
{
|
|
|
|
dist_fromstart = dist;
|
|
|
|
s_pad = pad_on_start;
|
|
|
|
}
|
|
|
|
else if( e_pad == NULL )
|
|
|
|
{
|
|
|
|
dist_fromend = dist;
|
|
|
|
e_pad = pad_on_start;
|
|
|
|
}
|
2019-12-03 13:08:56 +00:00
|
|
|
else // If we have a via in a pad in the middle of a trace
|
2016-10-14 08:35:08 +00:00
|
|
|
{
|
2019-12-03 13:08:56 +00:00
|
|
|
// In this case, we want the distance between the farthest pads
|
|
|
|
// Forgive me this anti-pattern. This is a v5-only fix, so complete refactor is
|
|
|
|
// a non-starter.
|
|
|
|
if( dist_fromend < dist_fromstart )
|
|
|
|
{
|
|
|
|
if( dist > dist_fromend )
|
|
|
|
{
|
|
|
|
dist_fromend = dist;
|
|
|
|
e_pad = pad_on_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( dist > dist_fromstart )
|
|
|
|
{
|
|
|
|
dist_fromstart = dist;
|
|
|
|
s_pad = pad_on_start;
|
|
|
|
}
|
|
|
|
}
|
2016-10-14 08:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pad_on_end )
|
|
|
|
{
|
|
|
|
SEG segm( track->GetEnd(), pad_on_end->GetPosition() );
|
|
|
|
int dist = segm.Length();
|
|
|
|
|
|
|
|
if( s_pad == NULL )
|
|
|
|
{
|
|
|
|
dist_fromstart = dist;
|
|
|
|
s_pad = pad_on_end;
|
|
|
|
}
|
|
|
|
else if( e_pad == NULL )
|
|
|
|
{
|
|
|
|
dist_fromend = dist;
|
|
|
|
e_pad = pad_on_end;
|
|
|
|
}
|
2019-12-03 13:08:56 +00:00
|
|
|
else // If we have a via in a pad in the middle of a trace
|
2016-10-14 08:35:08 +00:00
|
|
|
{
|
2019-12-03 13:08:56 +00:00
|
|
|
// In this case, we want the distance between the farthest pads
|
|
|
|
// Forgive me this anti-pattern. This is a v5-only fix, so complete refactor is
|
|
|
|
// a non-starter.
|
|
|
|
if( dist_fromend < dist_fromstart )
|
|
|
|
{
|
|
|
|
if( dist > dist_fromend )
|
|
|
|
{
|
|
|
|
dist_fromend = dist;
|
|
|
|
e_pad = pad_on_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( dist > dist_fromstart )
|
|
|
|
{
|
|
|
|
dist_fromstart = dist;
|
|
|
|
s_pad = pad_on_start;
|
|
|
|
}
|
|
|
|
}
|
2016-10-14 08:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
if( aReorder )
|
|
|
|
{
|
|
|
|
DLIST<TRACK>* list = (DLIST<TRACK>*)firstTrack->GetList();
|
|
|
|
wxASSERT( list );
|
|
|
|
|
|
|
|
/* Rearrange the chain starting at firstTrack
|
2016-07-12 19:05:54 +00:00
|
|
|
* All other BUSY flagged items are moved from their position to the end
|
2011-09-16 15:54:50 +00:00
|
|
|
* of the flagged list
|
|
|
|
*/
|
|
|
|
TRACK* next;
|
|
|
|
|
|
|
|
for( TRACK* track = firstTrack->Next(); track; track = next )
|
|
|
|
{
|
|
|
|
next = track->Next();
|
|
|
|
|
|
|
|
if( track->GetState( BUSY ) ) // move it!
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
busy_count++;
|
2011-09-16 15:54:50 +00:00
|
|
|
track->UnLink();
|
|
|
|
list->Insert( track, firstTrack->Next() );
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( aTraceLength )
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
busy_count = 0;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
for( TRACK* track = firstTrack; track; track = track->Next() )
|
|
|
|
{
|
|
|
|
if( track->GetState( BUSY ) )
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
busy_count++;
|
2013-03-30 17:24:04 +00:00
|
|
|
track->SetState( BUSY, false );
|
2011-09-16 15:54:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 08:35:08 +00:00
|
|
|
if( s_pad )
|
|
|
|
{
|
|
|
|
full_len += dist_fromstart;
|
|
|
|
lenPadToDie += (double) s_pad->GetPadToDieLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( e_pad )
|
|
|
|
{
|
|
|
|
full_len += dist_fromend;
|
|
|
|
lenPadToDie += (double) e_pad->GetPadToDieLength();
|
|
|
|
}
|
|
|
|
|
2011-09-16 15:54:50 +00:00
|
|
|
if( aTraceLength )
|
2014-07-24 06:43:23 +00:00
|
|
|
*aTraceLength = full_len;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
2012-12-12 11:57:17 +00:00
|
|
|
if( aPadToDieLength )
|
2014-07-24 06:43:23 +00:00
|
|
|
*aPadToDieLength = lenPadToDie;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
if( aCount )
|
2016-07-12 19:05:54 +00:00
|
|
|
*aCount = busy_count;
|
2011-09-16 15:54:50 +00:00
|
|
|
|
|
|
|
return firstTrack;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
MODULE* BOARD::GetFootprint( const wxPoint& aPosition, PCB_LAYER_ID aActiveLayer,
|
2011-09-16 18:54:04 +00:00
|
|
|
bool aVisibleOnly, bool aIgnoreLocked )
|
|
|
|
{
|
|
|
|
MODULE* pt_module;
|
|
|
|
MODULE* module = NULL;
|
2013-04-07 11:55:18 +00:00
|
|
|
MODULE* alt_module = NULL;
|
2011-09-16 18:54:04 +00:00
|
|
|
int min_dim = 0x7FFFFFFF;
|
|
|
|
int alt_min_dim = 0x7FFFFFFF;
|
2013-04-07 11:55:18 +00:00
|
|
|
bool current_layer_back = IsBackLayer( aActiveLayer );
|
2011-09-16 18:54:04 +00:00
|
|
|
|
2015-11-04 08:48:34 +00:00
|
|
|
for( pt_module = m_Modules; pt_module; pt_module = pt_module->Next() )
|
2011-09-16 18:54:04 +00:00
|
|
|
{
|
|
|
|
// is the ref point within the module's bounds?
|
|
|
|
if( !pt_module->HitTest( aPosition ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// if caller wants to ignore locked modules, and this one is locked, skip it.
|
|
|
|
if( aIgnoreLocked && pt_module->IsLocked() )
|
|
|
|
continue;
|
|
|
|
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID layer = pt_module->GetLayer();
|
2011-09-16 18:54:04 +00:00
|
|
|
|
2013-04-07 11:55:18 +00:00
|
|
|
// Filter non visible modules if requested
|
2014-06-24 16:17:18 +00:00
|
|
|
if( !aVisibleOnly || IsModuleLayerVisible( layer ) )
|
2013-04-07 11:55:18 +00:00
|
|
|
{
|
2013-11-24 17:48:14 +00:00
|
|
|
EDA_RECT bb = pt_module->GetFootprintRect();
|
2014-06-24 16:17:18 +00:00
|
|
|
|
2013-04-07 11:55:18 +00:00
|
|
|
int offx = bb.GetX() + bb.GetWidth() / 2;
|
|
|
|
int offy = bb.GetY() + bb.GetHeight() / 2;
|
2011-09-16 18:54:04 +00:00
|
|
|
|
2013-04-07 11:55:18 +00:00
|
|
|
// off x & offy point to the middle of the box.
|
|
|
|
int dist = ( aPosition.x - offx ) * ( aPosition.x - offx ) +
|
|
|
|
( aPosition.y - offy ) * ( aPosition.y - offy );
|
2011-09-16 18:54:04 +00:00
|
|
|
|
2013-04-07 11:55:18 +00:00
|
|
|
if( current_layer_back == IsBackLayer( layer ) )
|
2011-09-16 18:54:04 +00:00
|
|
|
{
|
2013-04-07 11:55:18 +00:00
|
|
|
if( dist <= min_dim )
|
|
|
|
{
|
|
|
|
// better footprint shown on the active side
|
|
|
|
module = pt_module;
|
|
|
|
min_dim = dist;
|
|
|
|
}
|
2011-09-16 18:54:04 +00:00
|
|
|
}
|
2013-04-07 11:55:18 +00:00
|
|
|
else if( aVisibleOnly && IsModuleLayerVisible( layer ) )
|
2011-09-16 18:54:04 +00:00
|
|
|
{
|
2013-04-07 11:55:18 +00:00
|
|
|
if( dist <= alt_min_dim )
|
|
|
|
{
|
|
|
|
// better footprint shown on the other side
|
|
|
|
alt_module = pt_module;
|
|
|
|
alt_min_dim = dist;
|
|
|
|
}
|
2011-09-16 18:54:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( module )
|
|
|
|
{
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2013-04-07 11:55:18 +00:00
|
|
|
if( alt_module)
|
2011-09-16 18:54:04 +00:00
|
|
|
{
|
2013-04-07 11:55:18 +00:00
|
|
|
return alt_module;
|
2011-09-16 18:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
BOARD_CONNECTED_ITEM* BOARD::GetLockPoint( const wxPoint& aPosition, LSET aLayerSet )
|
2011-09-17 01:22:26 +00:00
|
|
|
{
|
|
|
|
for( MODULE* module = m_Modules; module; module = module->Next() )
|
|
|
|
{
|
2016-07-12 19:05:54 +00:00
|
|
|
D_PAD* pad = module->GetPad( aPosition, aLayerSet );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
|
|
|
if( pad )
|
|
|
|
return pad;
|
|
|
|
}
|
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
// No pad has been located so check for a segment of the trace.
|
2016-07-12 19:05:54 +00:00
|
|
|
TRACK* segment = ::GetTrack( m_Track, NULL, aPosition, aLayerSet );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2016-07-12 19:05:54 +00:00
|
|
|
if( !segment )
|
|
|
|
segment = GetVisibleTrack( m_Track, aPosition, aLayerSet );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TRACK* BOARD::CreateLockPoint( wxPoint& aPosition, TRACK* aSegment, PICKED_ITEMS_LIST* aList )
|
|
|
|
{
|
2012-02-04 20:30:00 +00:00
|
|
|
/* creates an intermediate point on aSegment and break it into two segments
|
|
|
|
* at aPosition.
|
|
|
|
* The new segment starts from aPosition and ends at the end point of
|
|
|
|
* aSegment. The original segment now ends at aPosition.
|
|
|
|
*/
|
2013-01-13 00:04:00 +00:00
|
|
|
if( aSegment->GetStart() == aPosition || aSegment->GetEnd() == aPosition )
|
2011-09-17 01:22:26 +00:00
|
|
|
return NULL;
|
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
// A via is a good lock point
|
2011-10-01 19:24:27 +00:00
|
|
|
if( aSegment->Type() == PCB_VIA_T )
|
2011-09-17 01:22:26 +00:00
|
|
|
{
|
2013-01-13 00:04:00 +00:00
|
|
|
aPosition = aSegment->GetStart();
|
2011-09-17 01:22:26 +00:00
|
|
|
return aSegment;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculation coordinate of intermediate point relative to the start point of aSegment
|
2013-01-13 00:04:00 +00:00
|
|
|
wxPoint delta = aSegment->GetEnd() - aSegment->GetStart();
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
// calculate coordinates of aPosition relative to aSegment->GetStart()
|
|
|
|
wxPoint lockPoint = aPosition - aSegment->GetStart();
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2012-02-04 20:30:00 +00:00
|
|
|
// lockPoint must be on aSegment:
|
|
|
|
// Ensure lockPoint.y/lockPoint.y = delta.y/delta.x
|
2011-09-17 01:22:26 +00:00
|
|
|
if( delta.x == 0 )
|
2014-06-24 16:17:18 +00:00
|
|
|
lockPoint.x = 0; // horizontal segment
|
2011-09-17 01:22:26 +00:00
|
|
|
else
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
lockPoint.y = KiROUND( ( (double)lockPoint.x * delta.y ) / delta.x );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
|
|
|
/* Create the intermediate point (that is to say creation of a new
|
|
|
|
* segment, beginning at the intermediate point.
|
|
|
|
*/
|
2013-01-13 00:04:00 +00:00
|
|
|
lockPoint += aSegment->GetStart();
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2012-01-14 19:50:32 +00:00
|
|
|
TRACK* newTrack = (TRACK*)aSegment->Clone();
|
2012-02-04 20:30:00 +00:00
|
|
|
// The new segment begins at the new point,
|
2013-01-13 00:04:00 +00:00
|
|
|
newTrack->SetStart(lockPoint);
|
2012-02-04 20:30:00 +00:00
|
|
|
newTrack->start = aSegment;
|
2013-03-30 17:24:04 +00:00
|
|
|
newTrack->SetState( BEGIN_ONPAD, false );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
|
|
|
DLIST<TRACK>* list = (DLIST<TRACK>*)aSegment->GetList();
|
|
|
|
wxASSERT( list );
|
|
|
|
list->Insert( newTrack, aSegment->Next() );
|
|
|
|
|
|
|
|
if( aList )
|
|
|
|
{
|
2012-02-04 20:30:00 +00:00
|
|
|
// Prepare the undo command for the now track segment
|
|
|
|
ITEM_PICKER picker( newTrack, UR_NEW );
|
|
|
|
aList->PushItem( picker );
|
|
|
|
// Prepare the undo command for the old track segment
|
|
|
|
// before modifications
|
|
|
|
picker.SetItem( aSegment );
|
|
|
|
picker.SetStatus( UR_CHANGED );
|
|
|
|
picker.SetLink( aSegment->Clone() );
|
2011-09-17 01:22:26 +00:00
|
|
|
aList->PushItem( picker );
|
|
|
|
}
|
|
|
|
|
2012-02-04 20:30:00 +00:00
|
|
|
// Old track segment now ends at new point.
|
2013-01-13 00:04:00 +00:00
|
|
|
aSegment->SetEnd(lockPoint);
|
2011-09-17 01:22:26 +00:00
|
|
|
aSegment->end = newTrack;
|
2013-03-30 17:24:04 +00:00
|
|
|
aSegment->SetState( END_ONPAD, false );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2014-04-25 17:13:33 +00:00
|
|
|
D_PAD * pad = GetPad( newTrack, ENDPOINT_START );
|
2011-09-17 01:22:26 +00:00
|
|
|
|
2015-07-10 16:43:25 +00:00
|
|
|
if( pad )
|
2011-09-17 01:22:26 +00:00
|
|
|
{
|
|
|
|
newTrack->start = pad;
|
2013-03-30 17:24:04 +00:00
|
|
|
newTrack->SetState( BEGIN_ONPAD, true );
|
2011-09-17 01:22:26 +00:00
|
|
|
aSegment->end = pad;
|
2013-03-30 17:24:04 +00:00
|
|
|
aSegment->SetState( END_ONPAD, true );
|
2011-09-17 01:22:26 +00:00
|
|
|
}
|
|
|
|
|
2012-02-04 20:30:00 +00:00
|
|
|
aPosition = lockPoint;
|
2011-09-17 01:22:26 +00:00
|
|
|
return newTrack;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode,
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID aLayer, wxPoint aStartPointPosition, int aHatch )
|
2013-03-20 14:50:12 +00:00
|
|
|
{
|
|
|
|
ZONE_CONTAINER* new_area = InsertArea( aNetcode,
|
|
|
|
m_ZoneDescriptorList.size( ) - 1,
|
|
|
|
aLayer, aStartPointPosition.x,
|
|
|
|
aStartPointPosition.y, aHatch );
|
|
|
|
|
|
|
|
if( aNewZonesList )
|
|
|
|
{
|
|
|
|
ITEM_PICKER picker( new_area, UR_NEW );
|
|
|
|
aNewZonesList->PushItem( picker );
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BOARD::RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to_remove )
|
|
|
|
{
|
|
|
|
if( area_to_remove == NULL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( aDeletedList )
|
|
|
|
{
|
|
|
|
ITEM_PICKER picker( area_to_remove, UR_DELETED );
|
|
|
|
aDeletedList->PushItem( picker );
|
|
|
|
Remove( area_to_remove ); // remove from zone list, but does not delete it
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Delete( area_to_remove );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-19 11:29:57 +00:00
|
|
|
ZONE_CONTAINER* BOARD::InsertArea( int aNetcode, int aAreaIdx, PCB_LAYER_ID aLayer,
|
|
|
|
int aCornerX, int aCornerY, int aHatch )
|
2013-03-20 14:50:12 +00:00
|
|
|
{
|
|
|
|
ZONE_CONTAINER* new_area = new ZONE_CONTAINER( this );
|
|
|
|
|
2017-06-19 11:29:57 +00:00
|
|
|
new_area->SetNetCode( aNetcode );
|
|
|
|
new_area->SetLayer( aLayer );
|
2013-03-20 14:50:12 +00:00
|
|
|
new_area->SetTimeStamp( GetNewTimeStamp() );
|
|
|
|
|
2017-06-19 11:29:57 +00:00
|
|
|
if( aAreaIdx < (int) ( m_ZoneDescriptorList.size() - 1 ) )
|
|
|
|
m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + aAreaIdx + 1, new_area );
|
2013-03-20 14:50:12 +00:00
|
|
|
else
|
|
|
|
m_ZoneDescriptorList.push_back( new_area );
|
|
|
|
|
2017-06-19 11:29:57 +00:00
|
|
|
new_area->SetHatchStyle( (ZONE_CONTAINER::HATCH_STYLE) aHatch );
|
|
|
|
|
|
|
|
// Add the first corner to the new zone
|
|
|
|
new_area->AppendCorner( wxPoint( aCornerX, aCornerY ), -1 );
|
2017-02-23 04:31:26 +00:00
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
return new_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, ZONE_CONTAINER* aCurrArea )
|
|
|
|
{
|
|
|
|
// mark all areas as unmodified except this one, if modified
|
2018-09-17 09:54:49 +00:00
|
|
|
for( ZONE_CONTAINER* zone : m_ZoneDescriptorList )
|
|
|
|
zone->SetLocalFlags( 0 );
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2013-03-26 09:58:40 +00:00
|
|
|
aCurrArea->SetLocalFlags( 1 );
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
if( aCurrArea->Outline()->IsSelfIntersecting() )
|
2013-03-20 14:50:12 +00:00
|
|
|
{
|
2017-03-07 12:06:00 +00:00
|
|
|
aCurrArea->UnHatch();
|
|
|
|
|
|
|
|
// Normalize copied area and store resulting number of polygons
|
|
|
|
int n_poly = aCurrArea->Outline()->NormalizeAreaOutlines();
|
2013-03-20 14:50:12 +00:00
|
|
|
|
|
|
|
// If clipping has created some polygons, we must add these new copper areas.
|
|
|
|
if( n_poly > 1 )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* NewArea;
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
// Move the newly created polygons to new areas, removing them from the current area
|
2013-03-20 14:50:12 +00:00
|
|
|
for( int ip = 1; ip < n_poly; ip++ )
|
|
|
|
{
|
2017-03-07 12:06:00 +00:00
|
|
|
// Create new copper area and copy poly into it
|
|
|
|
SHAPE_POLY_SET* new_p = new SHAPE_POLY_SET( aCurrArea->Outline()->UnitSet( ip ) );
|
2014-02-25 10:40:34 +00:00
|
|
|
NewArea = AddArea( aNewZonesList, aCurrArea->GetNetCode(), aCurrArea->GetLayer(),
|
2017-03-07 12:06:00 +00:00
|
|
|
wxPoint(0, 0), aCurrArea->GetHatchStyle() );
|
2013-03-20 14:50:12 +00:00
|
|
|
|
|
|
|
// remove the poly that was automatically created for the new area
|
|
|
|
// and replace it with a poly from NormalizeAreaOutlines
|
|
|
|
delete NewArea->Outline();
|
|
|
|
NewArea->SetOutline( new_p );
|
2017-03-07 12:06:00 +00:00
|
|
|
NewArea->Hatch();
|
2013-03-26 09:58:40 +00:00
|
|
|
NewArea->SetLocalFlags( 1 );
|
2013-03-20 14:50:12 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
SHAPE_POLY_SET* new_p = new SHAPE_POLY_SET( aCurrArea->Outline()->UnitSet( 0 ) );
|
|
|
|
delete aCurrArea->Outline();
|
|
|
|
aCurrArea->SetOutline( new_p );
|
|
|
|
}
|
2013-03-20 14:50:12 +00:00
|
|
|
}
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
aCurrArea->Hatch();
|
2013-03-20 14:50:12 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
void BOARD::updateComponentPadConnections( NETLIST& aNetlist, MODULE* footprint,
|
|
|
|
COMPONENT* component, REPORTER& aReporter )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
for( auto pad : footprint->Pads() )
|
|
|
|
{
|
|
|
|
COMPONENT_NET net = component->GetNet( pad->GetName() );
|
|
|
|
|
|
|
|
if( !net.IsValid() ) // Footprint pad had no net.
|
|
|
|
{
|
|
|
|
if( !pad->GetNetname().IsEmpty() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Clearing component %s pin %s net." ),
|
|
|
|
footprint->GetReference(),
|
|
|
|
pad->GetName() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !aNetlist.IsDryRun() )
|
|
|
|
{
|
|
|
|
m_connectivity->Remove( pad );
|
|
|
|
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // Footprint pad has a net.
|
|
|
|
{
|
2018-10-18 09:35:59 +00:00
|
|
|
const wxString& netName = net.GetNetName();
|
|
|
|
NETINFO_ITEM* netinfo = FindNet( netName );
|
|
|
|
|
|
|
|
if( netinfo && !aNetlist.IsDryRun() )
|
|
|
|
netinfo->SetIsCurrent( true );
|
|
|
|
|
|
|
|
if( pad->GetNetname() != netName )
|
2018-09-17 09:54:49 +00:00
|
|
|
{
|
|
|
|
msg.Printf( _( "Changing footprint %s pad %s net from %s to %s." ),
|
|
|
|
footprint->GetReference(),
|
|
|
|
pad->GetName(),
|
|
|
|
pad->GetNetname(),
|
2018-10-18 09:35:59 +00:00
|
|
|
netName );
|
2018-09-17 09:54:49 +00:00
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
if( !aNetlist.IsDryRun() )
|
|
|
|
{
|
|
|
|
if( netinfo == NULL )
|
|
|
|
{
|
|
|
|
// It is a new net, we have to add it
|
|
|
|
netinfo = new NETINFO_ITEM( this, net.GetNetName() );
|
|
|
|
Add( netinfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_connectivity->Remove( pad );
|
|
|
|
pad->SetNetCode( netinfo->GetNet() );
|
|
|
|
m_connectivity->Add( pad );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-24 08:08:55 +00:00
|
|
|
void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets,
|
2018-09-17 09:54:49 +00:00
|
|
|
std::vector<MODULE*>* aNewFootprints, REPORTER& aReporter )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
wxPoint bestPosition;
|
|
|
|
wxString msg;
|
2016-01-10 21:24:13 +00:00
|
|
|
std::vector<MODULE*> newFootprints;
|
2018-05-01 12:52:11 +00:00
|
|
|
std::map< ZONE_CONTAINER*, std::vector<D_PAD*> > zoneConnectionsCache;
|
2018-09-17 09:54:49 +00:00
|
|
|
MODULE* lastPreexistingFootprint = m_Modules.GetLast();
|
2018-05-01 12:52:11 +00:00
|
|
|
|
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* zone = GetArea( ii );
|
|
|
|
|
|
|
|
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
zoneConnectionsCache[ zone ] = m_connectivity->GetConnectedPads( zone );
|
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
|
|
|
|
if( !IsEmpty() )
|
|
|
|
{
|
|
|
|
// Position new components below any existing board features.
|
2017-02-23 04:31:26 +00:00
|
|
|
EDA_RECT bbbox = GetBoardEdgesBoundingBox();
|
2013-04-25 16:29:35 +00:00
|
|
|
|
|
|
|
if( bbbox.GetWidth() || bbbox.GetHeight() )
|
|
|
|
{
|
|
|
|
bestPosition.x = bbbox.Centre().x;
|
2013-08-23 09:22:19 +00:00
|
|
|
bestPosition.y = bbbox.GetBottom() + Millimeter2iu( 10 );
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Position new components in the center of the page when the board is empty.
|
|
|
|
wxSize pageSize = m_paper.GetSizeIU();
|
|
|
|
|
|
|
|
bestPosition.x = pageSize.GetWidth() / 2;
|
|
|
|
bestPosition.y = pageSize.GetHeight() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Status_Pcb = 0;
|
|
|
|
|
2018-10-18 09:35:59 +00:00
|
|
|
// Mark all nets (except <no net>) as stale; we'll update those to current that
|
|
|
|
// we find in the netlist
|
|
|
|
for( NETINFO_ITEM* net : m_NetInfo )
|
|
|
|
net->SetIsCurrent( net->GetNet() == 0 );
|
|
|
|
|
2013-04-25 16:29:35 +00:00
|
|
|
for( i = 0; i < aNetlist.GetCount(); i++ )
|
|
|
|
{
|
2013-08-23 09:22:19 +00:00
|
|
|
COMPONENT* component = aNetlist.GetComponent( i );
|
2018-09-17 09:54:49 +00:00
|
|
|
int matchCount = 0;
|
2018-10-01 21:05:31 +00:00
|
|
|
MODULE* tmp;
|
2013-11-02 00:24:38 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
msg.Printf( _( "Checking netlist symbol footprint \"%s:%s:%s\"." ),
|
|
|
|
component->GetReference(),
|
|
|
|
component->GetTimeStamp(),
|
|
|
|
GetChars( component->GetFPID().Format() ) );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_INFO );
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-10-01 21:05:31 +00:00
|
|
|
for( MODULE* footprint = m_Modules; footprint; footprint = footprint->Next() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-10-01 21:05:31 +00:00
|
|
|
bool match;
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-10-01 21:05:31 +00:00
|
|
|
if( aNetlist.IsFindByTimeStamp() )
|
|
|
|
match = footprint->GetPath() == component->GetTimeStamp();
|
|
|
|
else
|
2018-10-02 17:17:16 +00:00
|
|
|
match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0;
|
2018-09-17 09:54:49 +00:00
|
|
|
|
|
|
|
if( match )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
// Test for footprint change.
|
|
|
|
if( !component->GetFPID().empty() && footprint->GetFPID() != component->GetFPID() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
if( aNetlist.GetReplaceFootprints() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2013-04-26 15:11:52 +00:00
|
|
|
if( component->GetModule() != NULL )
|
2013-08-23 06:38:57 +00:00
|
|
|
{
|
2018-07-08 20:01:40 +00:00
|
|
|
msg.Printf( _( "Changing symbol %s footprint from %s to %s." ),
|
2018-09-17 09:54:49 +00:00
|
|
|
footprint->GetReference(),
|
2017-07-24 19:02:59 +00:00
|
|
|
GetChars( footprint->GetFPID().Format() ),
|
|
|
|
GetChars( component->GetFPID().Format() ) );
|
2018-09-17 09:54:49 +00:00
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
2013-08-23 06:38:57 +00:00
|
|
|
}
|
2013-04-26 15:11:52 +00:00
|
|
|
else
|
2013-08-23 06:38:57 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
msg.Printf( _( "Cannot change symbol %s footprint due to missing footprint %s." ),
|
|
|
|
footprint->GetReference(),
|
2017-07-24 19:02:59 +00:00
|
|
|
GetChars( component->GetFPID().Format() ) );
|
2018-09-17 09:54:49 +00:00
|
|
|
aReporter.Report( msg, REPORTER::RPT_ERROR );
|
2013-08-23 06:38:57 +00:00
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( !aNetlist.IsDryRun() && (component->GetModule() != NULL) )
|
2017-01-23 20:30:11 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
wxASSERT( footprint != NULL );
|
|
|
|
MODULE* newFootprint = new MODULE( *component->GetModule() );
|
|
|
|
|
|
|
|
if( aNetlist.IsFindByTimeStamp() )
|
|
|
|
newFootprint->SetReference( footprint->GetReference() );
|
|
|
|
else
|
|
|
|
newFootprint->SetPath( footprint->GetPath() );
|
|
|
|
|
|
|
|
// Copy placement and pad net names.
|
|
|
|
// optionally, copy or not local settings (like local clearances)
|
|
|
|
// if the second parameter is "true", previous values will be used.
|
|
|
|
// if "false", the default library values of the new footprint
|
|
|
|
// will be used
|
|
|
|
footprint->CopyNetlistSettings( newFootprint, false );
|
|
|
|
|
|
|
|
// Compare the footprint name only, in case the nickname is empty or in case
|
|
|
|
// user moved the footprint to a new library. Chances are if footprint name is
|
|
|
|
// same then the footprint is very nearly the same and the two texts should
|
|
|
|
// be kept at same size, position, and rotation.
|
|
|
|
if( newFootprint->GetFPID().GetLibItemName() == footprint->GetFPID().GetLibItemName() )
|
|
|
|
{
|
|
|
|
newFootprint->Reference().SetEffects( footprint->Reference() );
|
|
|
|
newFootprint->Value().SetEffects( footprint->Value() );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_connectivity->Remove( footprint );
|
|
|
|
Remove( footprint );
|
|
|
|
|
|
|
|
Add( newFootprint, ADD_APPEND );
|
|
|
|
m_connectivity->Add( footprint );
|
|
|
|
|
|
|
|
footprint = newFootprint;
|
2017-01-23 20:30:11 +00:00
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
// Test for reference designator field change.
|
|
|
|
if( footprint->GetReference() != component->GetReference() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-07-08 20:01:40 +00:00
|
|
|
msg.Printf( _( "Changing footprint %s reference to %s." ),
|
2018-09-17 09:54:49 +00:00
|
|
|
footprint->GetReference(),
|
|
|
|
component->GetReference() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( !aNetlist.IsDryRun() )
|
|
|
|
footprint->SetReference( component->GetReference() );
|
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
// Test for value field change.
|
|
|
|
if( footprint->GetValue() != component->GetValue() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-07-08 20:01:40 +00:00
|
|
|
msg.Printf( _( "Changing footprint %s value from %s to %s." ),
|
2018-09-17 09:54:49 +00:00
|
|
|
footprint->GetReference(),
|
|
|
|
footprint->GetValue(),
|
|
|
|
component->GetValue() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( !aNetlist.IsDryRun() )
|
|
|
|
footprint->SetValue( component->GetValue() );
|
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
// Test for time stamp change.
|
|
|
|
if( footprint->GetPath() != component->GetTimeStamp() )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-07-08 20:01:40 +00:00
|
|
|
msg.Printf( _( "Changing component path \"%s:%s\" to \"%s\"." ),
|
2018-09-17 09:54:49 +00:00
|
|
|
footprint->GetReference(),
|
|
|
|
footprint->GetPath(),
|
|
|
|
component->GetTimeStamp() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_INFO );
|
2013-04-25 16:29:35 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( !aNetlist.IsDryRun() )
|
|
|
|
footprint->SetPath( component->GetTimeStamp() );
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
2015-02-17 16:32:47 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
updateComponentPadConnections( aNetlist, footprint, component, aReporter );
|
|
|
|
|
|
|
|
matchCount++;
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
2018-09-17 09:54:49 +00:00
|
|
|
|
|
|
|
if( footprint == lastPreexistingFootprint )
|
2013-04-25 16:29:35 +00:00
|
|
|
{
|
2018-09-21 07:58:50 +00:00
|
|
|
// No sense going through the newly-created footprints: end loop
|
2018-09-17 09:54:49 +00:00
|
|
|
break;
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-17 09:54:49 +00:00
|
|
|
|
2018-10-01 21:05:31 +00:00
|
|
|
if( matchCount == 0 )
|
|
|
|
{
|
|
|
|
if( component->GetModule() != NULL )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Adding new symbol %s footprint %s." ),
|
|
|
|
component->GetReference(),
|
|
|
|
GetChars( component->GetFPID().Format() ) );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Cannot add new symbol %s due to missing footprint %s." ),
|
|
|
|
component->GetReference(),
|
|
|
|
GetChars( component->GetFPID().Format() ) );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ERROR );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !aNetlist.IsDryRun() && (component->GetModule() != NULL) )
|
|
|
|
{
|
|
|
|
// Owned by NETLIST, can only copy it.
|
|
|
|
tmp = new MODULE( *component->GetModule() );
|
|
|
|
tmp->SetParent( this );
|
|
|
|
tmp->SetPosition( bestPosition );
|
|
|
|
tmp->SetTimeStamp( GetNewTimeStamp() );
|
|
|
|
newFootprints.push_back( tmp );
|
|
|
|
Add( tmp, ADD_APPEND );
|
|
|
|
m_connectivity->Add( tmp );
|
|
|
|
|
|
|
|
updateComponentPadConnections( aNetlist, tmp, component, aReporter );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( matchCount > 1 )
|
2018-09-17 09:54:49 +00:00
|
|
|
{
|
|
|
|
msg.Printf( _( "Multiple footprints found for \"%s\"." ), component->GetReference() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ERROR );
|
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove all components not in the netlist.
|
|
|
|
if( aNetlist.GetDeleteExtraFootprints() )
|
|
|
|
{
|
|
|
|
MODULE* nextModule;
|
2013-08-23 09:22:19 +00:00
|
|
|
const COMPONENT* component;
|
2013-04-25 16:29:35 +00:00
|
|
|
|
|
|
|
for( MODULE* module = m_Modules; module != NULL; module = nextModule )
|
|
|
|
{
|
|
|
|
nextModule = module->Next();
|
|
|
|
|
|
|
|
if( module->IsLocked() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( aNetlist.IsFindByTimeStamp() )
|
|
|
|
component = aNetlist.GetComponentByTimeStamp( module->GetPath() );
|
|
|
|
else
|
|
|
|
component = aNetlist.GetComponentByReference( module->GetReference() );
|
|
|
|
|
|
|
|
if( component == NULL )
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
msg.Printf( _( "Removing unused footprint %s." ), module->GetReference() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
2013-04-25 16:29:35 +00:00
|
|
|
|
|
|
|
if( !aNetlist.IsDryRun() )
|
2017-06-30 12:07:55 +00:00
|
|
|
{
|
|
|
|
m_connectivity->Remove( module );
|
2013-04-25 16:29:35 +00:00
|
|
|
module->DeleteStructure();
|
2017-06-30 12:07:55 +00:00
|
|
|
}
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-23 09:22:19 +00:00
|
|
|
|
2015-01-22 12:06:34 +00:00
|
|
|
BuildListOfNets();
|
|
|
|
std::vector<D_PAD*> padlist = GetPads();
|
2017-06-30 12:07:55 +00:00
|
|
|
auto connAlgo = m_connectivity->GetConnectivityAlgo();
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2013-08-24 08:08:55 +00:00
|
|
|
// If needed, remove the single pad nets:
|
|
|
|
if( aDeleteSinglePadNets && !aNetlist.IsDryRun() )
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
std::vector<unsigned int> padCount( (unsigned) connAlgo->NetCount() );
|
2013-11-02 00:24:38 +00:00
|
|
|
|
2018-05-21 00:06:01 +00:00
|
|
|
for( const auto cnItem : connAlgo->ItemList() )
|
2013-08-24 08:08:55 +00:00
|
|
|
{
|
2018-05-21 00:06:01 +00:00
|
|
|
if( !cnItem->Valid() || cnItem->Parent()->Type() != PCB_PAD_T )
|
2018-01-19 10:18:41 +00:00
|
|
|
continue;
|
|
|
|
|
2017-06-30 12:07:55 +00:00
|
|
|
int net = cnItem->Parent()->GetNetCode();
|
2013-08-24 08:08:55 +00:00
|
|
|
|
2017-06-30 12:07:55 +00:00
|
|
|
if( net > 0 )
|
|
|
|
++padCount[net];
|
|
|
|
}
|
2013-08-24 08:08:55 +00:00
|
|
|
|
2017-07-01 08:40:18 +00:00
|
|
|
for( i = 0; i < (unsigned)connAlgo->NetCount(); ++i )
|
2017-06-30 12:07:55 +00:00
|
|
|
{
|
|
|
|
// First condition: only one pad in the net
|
|
|
|
if( padCount[i] == 1 )
|
2013-08-24 08:08:55 +00:00
|
|
|
{
|
2017-06-30 12:07:55 +00:00
|
|
|
// Second condition, no zones attached to the pad
|
|
|
|
D_PAD* pad = nullptr;
|
|
|
|
int zoneCount = 0;
|
|
|
|
const KICAD_T types[] = { PCB_PAD_T, PCB_ZONE_AREA_T, EOT };
|
|
|
|
auto netItems = m_connectivity->GetNetItems( i, types );
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2017-06-30 12:07:55 +00:00
|
|
|
for( const auto item : netItems )
|
|
|
|
{
|
|
|
|
if( item->Type() == PCB_ZONE_AREA_T )
|
2013-08-24 08:08:55 +00:00
|
|
|
{
|
2017-06-30 12:07:55 +00:00
|
|
|
wxASSERT( !pad || pad->GetNet() == item->GetNet() );
|
|
|
|
++zoneCount;
|
2013-08-24 08:08:55 +00:00
|
|
|
}
|
2017-06-30 12:07:55 +00:00
|
|
|
else if( item->Type() == PCB_PAD_T )
|
2015-01-22 12:06:34 +00:00
|
|
|
{
|
2017-06-30 12:07:55 +00:00
|
|
|
wxASSERT( !pad );
|
|
|
|
pad = static_cast<D_PAD*>( item );
|
2015-01-22 12:06:34 +00:00
|
|
|
}
|
2013-08-24 08:08:55 +00:00
|
|
|
}
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2017-07-26 09:54:15 +00:00
|
|
|
wxASSERT( pad ); // pad = 0 means the pad list is not up to date
|
2013-08-24 08:08:55 +00:00
|
|
|
|
2017-07-26 09:54:15 +00:00
|
|
|
if( pad && zoneCount == 0 )
|
2017-06-30 12:07:55 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
msg.Printf( _( "Remove single pad net %s." ), GetChars( pad->GetNetname() ) );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
2013-08-24 08:08:55 +00:00
|
|
|
|
2017-06-30 12:07:55 +00:00
|
|
|
m_connectivity->Remove( pad );
|
|
|
|
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-24 08:08:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 12:52:11 +00:00
|
|
|
// Verify that board contains all pads in netlist: if it doesn't then footprints are
|
|
|
|
// wrong or missing.
|
|
|
|
// Note that we use references to find the footprints as they're already updated by this
|
|
|
|
// point (whether by-reference or by-timestamp).
|
2018-09-17 09:54:49 +00:00
|
|
|
wxString padname;
|
|
|
|
for( i = 0; i < aNetlist.GetCount(); i++ )
|
2013-08-23 09:22:19 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
const COMPONENT* component = aNetlist.GetComponent( i );
|
|
|
|
MODULE* footprint = FindModuleByReference( component->GetReference() );
|
|
|
|
|
|
|
|
if( footprint == NULL ) // It can be missing in partial designs
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Explore all pins/pads in component
|
|
|
|
for( unsigned jj = 0; jj < component->GetNetCount(); jj++ )
|
2013-08-23 09:22:19 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
const COMPONENT_NET& net = component->GetNet( jj );
|
|
|
|
padname = net.GetPinName();
|
2013-08-23 09:22:19 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( footprint->FindPadByName( padname ) )
|
|
|
|
continue; // OK, pad found
|
2013-08-23 09:22:19 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
// not found: bad footprint, report error
|
|
|
|
msg.Printf( _( "Symbol %s pad %s not found in footprint %s.\n" ),
|
|
|
|
component->GetReference(),
|
|
|
|
padname,
|
|
|
|
GetChars( footprint->GetFPID().Format() ) );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ERROR );
|
2013-08-23 09:22:19 +00:00
|
|
|
}
|
2018-05-01 12:52:11 +00:00
|
|
|
}
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2018-05-01 12:52:11 +00:00
|
|
|
// Test copper zones to detect "dead" nets (nets without any pad):
|
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* zone = GetArea( ii );
|
|
|
|
|
|
|
|
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( m_connectivity->GetPadCount( zone->GetNetCode() ) == 0 )
|
2015-01-22 12:06:34 +00:00
|
|
|
{
|
2018-05-01 12:52:11 +00:00
|
|
|
// Look for a pad in the zone's connected-pad-cache which has been updated to
|
|
|
|
// a new net and use that. While this won't always be the right net, the dead
|
|
|
|
// net is guaranteed to be wrong.
|
|
|
|
NETINFO_ITEM* updatedNet = nullptr;
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2018-05-01 12:52:11 +00:00
|
|
|
for( D_PAD* pad : zoneConnectionsCache[ zone ] )
|
|
|
|
{
|
|
|
|
if( pad->GetNetname() != zone->GetNetname() )
|
|
|
|
{
|
|
|
|
updatedNet = pad->GetNet();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
if( updatedNet )
|
2018-05-01 12:52:11 +00:00
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
msg.Printf( _( "Updating copper zone from net %s to %s." ),
|
|
|
|
zone->GetNetname(),
|
|
|
|
updatedNet->GetNetname() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Copper zone (net %s) has no pads connected." ),
|
|
|
|
zone->GetNetname() );
|
|
|
|
aReporter.Report( msg, REPORTER::RPT_WARNING );
|
2018-05-01 12:52:11 +00:00
|
|
|
}
|
2015-01-22 12:06:34 +00:00
|
|
|
|
2018-05-01 12:52:11 +00:00
|
|
|
if( updatedNet && !aNetlist.IsDryRun() )
|
2015-01-22 12:06:34 +00:00
|
|
|
{
|
2018-05-01 12:52:11 +00:00
|
|
|
m_connectivity->Remove( zone );
|
|
|
|
zone->SetNet( updatedNet );
|
|
|
|
m_connectivity->Add( zone );
|
2015-01-22 12:06:34 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-23 09:22:19 +00:00
|
|
|
}
|
2016-01-10 21:24:13 +00:00
|
|
|
|
2017-07-04 05:00:38 +00:00
|
|
|
m_connectivity->RecalculateRatsnest();
|
|
|
|
|
2016-01-10 21:24:13 +00:00
|
|
|
std::swap( newFootprints, *aNewFootprints );
|
2013-04-25 16:29:35 +00:00
|
|
|
}
|
|
|
|
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
|
2016-05-11 08:17:34 +00:00
|
|
|
BOARD_ITEM* BOARD::Duplicate( const BOARD_ITEM* aItem,
|
|
|
|
bool aAddToBoard )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
|
|
|
BOARD_ITEM* new_item = NULL;
|
|
|
|
|
|
|
|
switch( aItem->Type() )
|
|
|
|
{
|
|
|
|
case PCB_MODULE_T:
|
|
|
|
case PCB_TEXT_T:
|
|
|
|
case PCB_LINE_T:
|
|
|
|
case PCB_TRACE_T:
|
2015-02-19 13:55:46 +00:00
|
|
|
case PCB_VIA_T:
|
2015-02-12 03:22:24 +00:00
|
|
|
case PCB_ZONE_AREA_T:
|
|
|
|
case PCB_TARGET_T:
|
|
|
|
case PCB_DIMENSION_T:
|
2015-02-18 19:29:52 +00:00
|
|
|
new_item = static_cast<BOARD_ITEM*>( aItem->Clone() );
|
2015-02-12 03:22:24 +00:00
|
|
|
break;
|
2015-02-18 19:29:52 +00:00
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
default:
|
|
|
|
// Un-handled item for duplication
|
2016-03-18 10:28:11 +00:00
|
|
|
new_item = NULL;
|
2015-02-12 03:22:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-21 11:47:43 +00:00
|
|
|
if( new_item && aAddToBoard )
|
|
|
|
Add( new_item );
|
2015-02-18 19:29:52 +00:00
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-04 08:42:09 +00:00
|
|
|
/* Extracts the board outlines and build a closed polygon
|
|
|
|
* from lines, arcs and circle items on edge cut layer
|
|
|
|
* Any closed outline inside the main outline is a hole
|
|
|
|
* All contours should be closed, i.e. are valid vertices for a closed polygon
|
|
|
|
* return true if success, false if a contour is not valid
|
|
|
|
*/
|
2018-06-18 15:34:43 +00:00
|
|
|
extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
|
2018-11-28 12:11:43 +00:00
|
|
|
wxString* aErrorText, unsigned int aTolerance,
|
|
|
|
wxPoint* aErrorLocation = nullptr );
|
2017-03-20 12:05:38 +00:00
|
|
|
|
2017-06-30 11:40:20 +00:00
|
|
|
|
2018-11-28 12:11:43 +00:00
|
|
|
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, wxString* aErrorText, wxPoint* aErrorLocation )
|
2013-10-04 08:42:09 +00:00
|
|
|
{
|
2018-11-28 12:11:43 +00:00
|
|
|
bool success = BuildBoardPolygonOutlines( this, aOutlines, aErrorText,
|
2019-03-01 13:36:53 +00:00
|
|
|
ARC_HIGH_DEF, aErrorLocation );
|
2017-03-23 07:56:52 +00:00
|
|
|
|
|
|
|
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
|
|
|
|
aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
2013-10-04 08:42:09 +00:00
|
|
|
}
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
|
|
|
|
const std::vector<D_PAD*> BOARD::GetPads()
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
std::vector<D_PAD*> allPads;
|
2017-03-22 13:51:07 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( MODULE* mod : Modules() )
|
|
|
|
{
|
|
|
|
for( D_PAD* pad : mod->Pads() )
|
|
|
|
allPads.push_back( pad );
|
2017-03-22 13:51:07 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
return allPads;
|
2017-03-22 13:51:07 +00:00
|
|
|
}
|
|
|
|
|
2017-06-30 11:40:20 +00:00
|
|
|
|
2018-05-12 17:07:04 +00:00
|
|
|
unsigned BOARD::GetPadCount()
|
2017-03-22 13:51:07 +00:00
|
|
|
{
|
2018-05-12 17:07:04 +00:00
|
|
|
unsigned retval = 0;
|
2018-09-17 09:54:49 +00:00
|
|
|
|
2018-05-12 17:07:04 +00:00
|
|
|
for( auto mod : Modules() )
|
|
|
|
retval += mod->Pads().Size();
|
|
|
|
|
|
|
|
return retval;
|
2017-03-22 13:51:07 +00:00
|
|
|
}
|
|
|
|
|
2017-06-30 11:40:20 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
/**
|
|
|
|
* Function GetPad
|
|
|
|
* @return D_PAD* - at the \a aIndex
|
|
|
|
*/
|
|
|
|
D_PAD* BOARD::GetPad( unsigned aIndex ) const
|
|
|
|
{
|
|
|
|
unsigned count = 0;
|
2017-06-30 11:40:20 +00:00
|
|
|
|
|
|
|
for( MODULE* mod = m_Modules; mod ; mod = mod->Next() ) // FIXME: const DLIST_ITERATOR
|
2017-03-22 13:51:07 +00:00
|
|
|
{
|
2017-06-30 11:40:20 +00:00
|
|
|
for( D_PAD* pad = mod->PadsList(); pad; pad = pad->Next() )
|
2017-03-22 13:51:07 +00:00
|
|
|
{
|
2017-06-30 11:40:20 +00:00
|
|
|
if( count == aIndex )
|
2017-03-22 13:51:07 +00:00
|
|
|
return pad;
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-09-26 11:48:07 +00:00
|
|
|
|
|
|
|
void BOARD::ClearAllNetCodes()
|
|
|
|
{
|
2018-09-17 09:54:49 +00:00
|
|
|
for( auto zone : Zones() )
|
2017-09-26 11:48:07 +00:00
|
|
|
zone->SetNetCode( 0 );
|
2017-09-29 09:40:10 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( auto pad : GetPads() )
|
|
|
|
pad->SetNetCode( 0 );
|
2017-09-26 11:48:07 +00:00
|
|
|
|
2018-09-17 09:54:49 +00:00
|
|
|
for( auto track : Tracks() )
|
2017-09-26 11:48:07 +00:00
|
|
|
track->SetNetCode( 0 );
|
|
|
|
}
|
2018-09-23 17:21:16 +00:00
|
|
|
|
|
|
|
const std::vector<BOARD_CONNECTED_ITEM*> BOARD::AllConnectedItems()
|
|
|
|
{
|
|
|
|
std::vector<BOARD_CONNECTED_ITEM*> items;
|
|
|
|
|
|
|
|
for( auto track : Tracks() )
|
|
|
|
{
|
|
|
|
items.push_back( track );
|
|
|
|
}
|
|
|
|
|
|
|
|
for( auto mod : Modules() )
|
|
|
|
{
|
|
|
|
for( auto pad : mod->Pads() )
|
|
|
|
{
|
|
|
|
items.push_back( pad );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = 0; i<GetAreaCount(); i++ )
|
|
|
|
{
|
|
|
|
auto zone = GetArea( i );
|
|
|
|
items.push_back( zone );
|
|
|
|
}
|
|
|
|
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BOARD::SanitizeNetcodes()
|
|
|
|
{
|
|
|
|
for ( auto item : AllConnectedItems() )
|
|
|
|
{
|
|
|
|
if( FindNet( item->GetNetCode() ) == nullptr )
|
|
|
|
item->SetNetCode( NETINFO_LIST::ORPHANED );
|
|
|
|
}
|
|
|
|
}
|