50 changed files with 4706 additions and 2075 deletions
-
2common/draw_frame.cpp
-
24common/geometry/hetriang.cpp
-
2common/tool/action_manager.cpp
-
86demos/simulation/rectifier/rectifier.pro
-
446include/geometry/poly_grid_partition.h
-
1include/geometry/shape_line_chain.h
-
40include/profile.h
-
25include/ttl/halfedge/hedart.h
-
149include/ttl/halfedge/hetriang.h
-
2include/wxBasePcbFrame.h
-
2pcbnew/CMakeLists.txt
-
19pcbnew/board_commit.cpp
-
4pcbnew/board_netlist_updater.cpp
-
15pcbnew/class_board.cpp
-
14pcbnew/class_board.h
-
14pcbnew/class_board_connected_item.cpp
-
3pcbnew/class_board_connected_item.h
-
7pcbnew/class_zone.h
-
73pcbnew/connect.cpp
-
377pcbnew/connectivity.cpp
-
204pcbnew/connectivity.h
-
903pcbnew/connectivity_algo.cpp
-
926pcbnew/connectivity_algo.h
-
8pcbnew/deltrack.cpp
-
104pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp
-
2pcbnew/dialogs/dialog_global_deletion.cpp
-
8pcbnew/dialogs/dialog_netlist.cpp
-
24pcbnew/drc.cpp
-
2pcbnew/files.cpp
-
2pcbnew/loadcmp.cpp
-
2pcbnew/netlist.cpp
-
5pcbnew/pcb_draw_panel_gal.cpp
-
6pcbnew/pcbframe.cpp
-
2pcbnew/ratsnest.cpp
-
1510pcbnew/ratsnest_data.cpp
-
584pcbnew/ratsnest_data.h
-
88pcbnew/ratsnest_viewitem.cpp
-
7pcbnew/ratsnest_viewitem.h
-
809pcbnew/tools/common_actions.cpp
-
24pcbnew/tools/edit_tool.cpp
-
8pcbnew/tools/edit_tool.h
-
1pcbnew/tools/pcb_actions.h
-
88pcbnew/tools/pcb_editor_control.cpp
-
2pcbnew/tools/pcbnew_control.cpp
-
4pcbnew/tools/point_editor.cpp
-
30pcbnew/tools/selection_tool.cpp
-
23pcbnew/undo_redo.cpp
-
13pcbnew/zones_by_polygon_fill_functions.cpp
-
15pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
-
72pcbnew/zones_polygons_insulated_copper_islands.cpp
@ -0,0 +1,446 @@ |
|||
/* |
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016-2017 CERN |
|||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef __POLY_GRID_PARTITION_H |
|||
#define __POLY_GRID_PARTITION_H |
|||
|
|||
#include <geometry/seg.h> |
|||
#include <geometry/shape_line_chain.h> |
|||
|
|||
#include <vector> |
|||
#include <algorithm> |
|||
#include <unordered_map> |
|||
#include <set> |
|||
|
|||
/** |
|||
* Class POLY_GRID_PARTITION |
|||
* |
|||
* Provides a fast test for point inside polygon by splitting the edges |
|||
* of the polygon into a rectangular grid. |
|||
*/ |
|||
class POLY_GRID_PARTITION |
|||
{ |
|||
private: |
|||
enum HASH_FLAG |
|||
{ |
|||
LEAD_H = 1, |
|||
LEAD_V = 2, |
|||
TRAIL_H = 4, |
|||
TRAIL_V = 8 |
|||
}; |
|||
|
|||
using EDGE_LIST = std::vector<int>; |
|||
|
|||
template <class T> |
|||
inline void hash_combine( std::size_t& seed, const T& v ) |
|||
{ |
|||
std::hash<T> hasher; |
|||
seed ^= hasher( v ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); |
|||
} |
|||
|
|||
struct segsEqual |
|||
{ |
|||
bool operator()( const SEG& a, const SEG& b ) const |
|||
{ |
|||
return (a.A == b.A && a.B == b.B) || (a.A == b.B && a.B == b.A); |
|||
} |
|||
}; |
|||
|
|||
struct segHash |
|||
{ |
|||
std::size_t operator()( const SEG& a ) const |
|||
{ |
|||
std::size_t seed = 0; |
|||
|
|||
return a.A.x + a.B.x + a.A.y + a.B.y; |
|||
|
|||
return seed; |
|||
} |
|||
}; |
|||
|
|||
const VECTOR2I grid2poly( const VECTOR2I& p ) const |
|||
{ |
|||
int px = rescale( p.x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x; |
|||
int py = rescale( p.y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y; // (int) floor( (double) p.y / m_gridSize * (double) m_bbox.GetHeight() + m_bbox.GetPosition().y ); |
|||
|
|||
return VECTOR2I( px, py ); |
|||
} |
|||
|
|||
int grid2polyX( int x ) const |
|||
{ |
|||
return rescale( x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x; |
|||
} |
|||
|
|||
int grid2polyY( int y ) const |
|||
{ |
|||
return rescale( y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y; |
|||
} |
|||
|
|||
const VECTOR2I poly2grid( const VECTOR2I& p ) const |
|||
{ |
|||
int px = rescale( p.x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() ); |
|||
int py = rescale( p.y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() ); |
|||
|
|||
if( px < 0 ) |
|||
px = 0; |
|||
|
|||
if( px >= m_gridSize ) |
|||
px = m_gridSize - 1; |
|||
|
|||
if( py < 0 ) |
|||
py = 0; |
|||
|
|||
if( py >= m_gridSize ) |
|||
py = m_gridSize - 1; |
|||
|
|||
return VECTOR2I( px, py ); |
|||
} |
|||
|
|||
int poly2gridX( int x ) const |
|||
{ |
|||
int px = rescale( x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() ); |
|||
|
|||
if( px < 0 ) |
|||
px = 0; |
|||
|
|||
if( px >= m_gridSize ) |
|||
px = m_gridSize - 1; |
|||
|
|||
return px; |
|||
} |
|||
|
|||
int poly2gridY( int y ) const |
|||
{ |
|||
int py = rescale( y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() ); |
|||
|
|||
if( py < 0 ) |
|||
py = 0; |
|||
|
|||
if( py >= m_gridSize ) |
|||
py = m_gridSize - 1; |
|||
|
|||
return py; |
|||
} |
|||
|
|||
void build( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize ) |
|||
{ |
|||
m_outline = aPolyOutline; |
|||
m_bbox = m_outline.BBox(); |
|||
m_gridSize = gridSize; |
|||
|
|||
m_outline.SetClosed( true ); |
|||
|
|||
m_grid.reserve( gridSize * gridSize ); |
|||
|
|||
for( int y = 0; y < gridSize; y++ ) |
|||
{ |
|||
for( int x = 0; x < gridSize; x++ ) |
|||
{ |
|||
m_grid.push_back( EDGE_LIST() ); |
|||
} |
|||
} |
|||
|
|||
VECTOR2I ref_v( 0, 1 ); |
|||
VECTOR2I ref_h( 0, 1 ); |
|||
|
|||
m_flags.reserve( m_outline.SegmentCount() ); |
|||
|
|||
std::unordered_map<SEG, int, segHash, segsEqual> edgeSet; |
|||
|
|||
for( int i = 0; i<m_outline.SegmentCount(); i++ ) |
|||
{ |
|||
SEG edge = m_outline.CSegment( i ); |
|||
|
|||
if( edgeSet.find( edge ) == edgeSet.end() ) |
|||
{ |
|||
edgeSet[edge] = 1; |
|||
} |
|||
else |
|||
{ |
|||
edgeSet[edge]++; |
|||
} |
|||
} |
|||
|
|||
for( int i = 0; i<m_outline.SegmentCount(); i++ ) |
|||
{ |
|||
auto edge = m_outline.CSegment( i ); |
|||
auto dir = edge.B - edge.A; |
|||
int flags = 0; |
|||
|
|||
if( edgeSet[edge] == 1 ) |
|||
{ |
|||
if( dir.Dot( ref_h ) > 0 ) |
|||
{ |
|||
flags |= LEAD_H; |
|||
} |
|||
else if( dir.Dot( ref_h ) < 0 ) |
|||
{ |
|||
flags |= TRAIL_H; |
|||
} |
|||
} |
|||
|
|||
m_flags.push_back( flags ); |
|||
|
|||
if( !flags ) |
|||
continue; |
|||
|
|||
std::set<int> indices; |
|||
|
|||
indices.insert( m_gridSize * poly2gridY( edge.A.y ) + poly2gridX( edge.A.x ) ); |
|||
indices.insert( m_gridSize * poly2gridY( edge.B.y ) + poly2gridX( edge.B.x ) ); |
|||
|
|||
if( edge.A.x > edge.B.x ) |
|||
std::swap( edge.A, edge.B ); |
|||
|
|||
dir = edge.B - edge.A; |
|||
|
|||
if( dir.x != 0 ) |
|||
{ |
|||
int gx0 = poly2gridX( edge.A.x ) + 1; |
|||
int gx1 = poly2gridX( edge.B.x ); |
|||
|
|||
for( int x = gx0; x <= gx1; x++ ) |
|||
{ |
|||
int px = grid2polyX( x ); |
|||
int py = ( edge.A.y + rescale( dir.y, px - edge.A.x, dir.x ) ); |
|||
int yy = poly2gridY( py ); |
|||
|
|||
indices.insert( m_gridSize * yy + x ); |
|||
|
|||
if( x > 0 ) |
|||
indices.insert( m_gridSize * yy + x - 1 ); |
|||
} |
|||
} |
|||
|
|||
if( edge.A.y > edge.B.y ) |
|||
std::swap( edge.A, edge.B ); |
|||
|
|||
dir = edge.B - edge.A; |
|||
|
|||
if( dir.y != 0 ) |
|||
{ |
|||
int gy0 = poly2gridY( edge.A.y ) + 1; |
|||
int gy1 = poly2gridY( edge.B.y ); |
|||
|
|||
for( int y = gy0; y <= gy1; y++ ) |
|||
{ |
|||
int py = grid2polyY( y ); |
|||
int px = ( edge.A.x + rescale( dir.x, py - edge.A.y, dir.y ) ); |
|||
int xx = poly2gridX( px ); |
|||
|
|||
indices.insert( m_gridSize * y + xx ); |
|||
|
|||
if( y > 0 ) |
|||
indices.insert( m_gridSize * (y - 1) + xx ); |
|||
} |
|||
} |
|||
|
|||
for( auto idx : indices ) |
|||
m_grid[idx].push_back( i ); |
|||
} |
|||
} |
|||
|
|||
bool inRange( int v1, int v2, int x ) const |
|||
{ |
|||
if( v1 < v2 ) |
|||
{ |
|||
return x >= v1 && x <= v2; |
|||
} |
|||
|
|||
return x >= v2 && x <= v1; |
|||
} |
|||
|
|||
struct SCAN_STATE |
|||
{ |
|||
SCAN_STATE() |
|||
{ |
|||
dist_max = INT_MAX; |
|||
nearest = -1; |
|||
nearest_prev = -1; |
|||
}; |
|||
|
|||
int dist_prev; |
|||
int dist_max; |
|||
int nearest_prev; |
|||
int nearest; |
|||
}; |
|||
|
|||
void scanCell( SCAN_STATE& state, const EDGE_LIST& cell, const VECTOR2I& aP ) const |
|||
{ |
|||
for( auto index : cell ) |
|||
{ |
|||
const SEG& edge = m_outline.CSegment( index ); |
|||
|
|||
if( edge.A.y == edge.B.y ) // horizontal edge |
|||
continue; |
|||
|
|||
if( m_flags[index] == 0 ) // a slit |
|||
continue; |
|||
|
|||
if( inRange( edge.A.y, edge.B.y, aP.y ) ) |
|||
{ |
|||
int dist = 0; |
|||
|
|||
if( edge.A.y == aP.y ) |
|||
{ |
|||
dist = -(aP.x - edge.A.x); |
|||
} |
|||
else if( edge.B.y == aP.y ) |
|||
{ |
|||
dist = -(aP.x - edge.B.x); |
|||
} |
|||
else |
|||
{ |
|||
const VECTOR2I e( edge.B - edge.A ); |
|||
const VECTOR2I ff( 1, 0 ); |
|||
const VECTOR2I ac( aP - edge.A ); |
|||
|
|||
auto d = ff.Cross( e ); |
|||
auto q = e.Cross( ac ); |
|||
|
|||
using ecoord = VECTOR2I::extended_type; |
|||
|
|||
dist = rescale( q, (ecoord) 1, d ); |
|||
} |
|||
|
|||
if( dist == 0 ) |
|||
{ |
|||
if( state.nearest_prev < 0 || state.nearest != index ) |
|||
{ |
|||
state.dist_prev = state.dist_max; |
|||
state.nearest_prev = state.nearest; |
|||
} |
|||
|
|||
state.nearest = index; |
|||
state.dist_max = 0; |
|||
return; |
|||
} |
|||
|
|||
if( dist != 0 && std::abs( dist ) <= std::abs( state.dist_max ) ) |
|||
{ |
|||
if( state.nearest_prev < 0 || state.nearest != index ) |
|||
{ |
|||
state.dist_prev = state.dist_max; |
|||
state.nearest_prev = state.nearest; |
|||
} |
|||
|
|||
state.dist_max = dist; |
|||
state.nearest = index; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public: |
|||
|
|||
POLY_GRID_PARTITION( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize ) |
|||
{ |
|||
build( aPolyOutline, gridSize ); |
|||
} |
|||
|
|||
int ContainsPoint( const VECTOR2I& aP ) // const |
|||
{ |
|||
const auto gridPoint = poly2grid( aP ); |
|||
|
|||
if( !m_bbox.Contains( aP ) ) |
|||
return false; |
|||
|
|||
SCAN_STATE state; |
|||
const EDGE_LIST& cell = m_grid[ m_gridSize * gridPoint.y + gridPoint.x ]; |
|||
|
|||
scanCell( state, cell, aP ); |
|||
|
|||
if( state.nearest < 0 ) |
|||
{ |
|||
state = SCAN_STATE(); |
|||
|
|||
for( int d = 1; d <= m_gridSize; d++ ) |
|||
{ |
|||
int xl = gridPoint.x - d; |
|||
int xh = gridPoint.x + d; |
|||
|
|||
if( xl >= 0 ) |
|||
{ |
|||
const EDGE_LIST& cell2 = m_grid[ m_gridSize * gridPoint.y + xl ]; |
|||
scanCell( state, cell2, aP ); |
|||
|
|||
if( state.nearest >= 0 ) |
|||
break; |
|||
} |
|||
|
|||
if( xh < m_gridSize ) |
|||
{ |
|||
const EDGE_LIST& cell2 = m_grid[ m_gridSize * gridPoint.y + xh ]; |
|||
scanCell( state, cell2, aP ); |
|||
|
|||
if( state.nearest >= 0 ) |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( state.nearest < 0 ) |
|||
return 0; |
|||
|
|||
if( state.dist_max == 0 ) |
|||
return 1; |
|||
|
|||
if( state.nearest_prev >= 0 && state.dist_max == state.dist_prev ) |
|||
{ |
|||
int d = std::abs( state.nearest_prev - state.nearest ); |
|||
|
|||
if( (d == 1) && ( (m_flags[state.nearest_prev] & m_flags[state.nearest]) == 0 ) ) |
|||
{ |
|||
return 0; |
|||
} |
|||
else if( d > 1 ) |
|||
{ |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
if( state.dist_max > 0 ) |
|||
{ |
|||
return m_flags[state.nearest] & LEAD_H ? 1 : 0; |
|||
} |
|||
else |
|||
{ |
|||
return m_flags[state.nearest] & TRAIL_H ? 1 : 0; |
|||
} |
|||
} |
|||
|
|||
const BOX2I& BBox() const |
|||
{ |
|||
return m_bbox; |
|||
} |
|||
|
|||
private: |
|||
int m_gridSize; |
|||
SHAPE_LINE_CHAIN m_outline; |
|||
BOX2I m_bbox; |
|||
std::vector<int> m_flags; |
|||
std::vector<EDGE_LIST> m_grid; |
|||
}; |
|||
|
|||
#endif |
|||
@ -0,0 +1,377 @@ |
|||
/*
|
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 CERN |
|||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> |
|||
* |
|||
* 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 |
|||
*/ |
|||
#define PROFILE
|
|||
|
|||
#ifdef PROFILE
|
|||
#include <profile.h>
|
|||
#endif
|
|||
|
|||
#include <connectivity.h>
|
|||
#include <connectivity_algo.h>
|
|||
#include <ratsnest_data.h>
|
|||
|
|||
#ifdef USE_OPENMP
|
|||
#include <omp.h>
|
|||
#endif /* USE_OPENMP */
|
|||
|
|||
CONNECTIVITY_DATA::CONNECTIVITY_DATA() |
|||
{ |
|||
m_connAlgo.reset( new CN_CONNECTIVITY_ALGO ); |
|||
} |
|||
|
|||
|
|||
CONNECTIVITY_DATA::~CONNECTIVITY_DATA() |
|||
{ |
|||
Clear(); |
|||
} |
|||
|
|||
|
|||
bool CONNECTIVITY_DATA::Add( BOARD_ITEM* aItem ) |
|||
{ |
|||
m_connAlgo->Add( aItem ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool CONNECTIVITY_DATA::Remove( BOARD_ITEM* aItem ) |
|||
{ |
|||
m_connAlgo->Remove( aItem ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
* Function Update() |
|||
* Updates the connectivity data for an item. |
|||
* @param aItem is an item to be updated. |
|||
* @return True if operation succeeded. The item will not be updated if it was not previously |
|||
* added to the ratsnest. |
|||
*/ |
|||
bool CONNECTIVITY_DATA::Update( BOARD_ITEM* aItem ) |
|||
{ |
|||
m_connAlgo->Remove( aItem ); |
|||
m_connAlgo->Add( aItem ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::Build( BOARD* aBoard ) |
|||
{ |
|||
m_connAlgo.reset( new CN_CONNECTIVITY_ALGO ); |
|||
m_connAlgo->Build( aBoard ); |
|||
|
|||
RecalculateRatsnest(); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::Build( const std::vector<BOARD_ITEM*>& aItems ) |
|||
{ |
|||
m_connAlgo.reset( new CN_CONNECTIVITY_ALGO ); |
|||
m_connAlgo->Build( aItems ); |
|||
|
|||
RecalculateRatsnest(); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::updateRatsnest() |
|||
{ |
|||
int lastNet = m_connAlgo->NetCount(); |
|||
|
|||
#ifdef PROFILE
|
|||
PROF_COUNTER rnUpdate( "update-ratsnest" ); |
|||
#endif
|
|||
|
|||
int nDirty = 0; |
|||
|
|||
int i; |
|||
|
|||
#ifdef USE_OPENMP
|
|||
#pragma omp parallel shared(lastNet) private(i)
|
|||
{ |
|||
#pragma omp for schedule(guided, 1)
|
|||
#else /* USE_OPENMP */
|
|||
{ |
|||
#endif
|
|||
|
|||
// Start with net number 1, as 0 stands for not connected
|
|||
for( i = 1; i < lastNet; ++i ) |
|||
{ |
|||
if( m_nets[i]->IsDirty() ) |
|||
{ |
|||
m_nets[i]->Update(); |
|||
nDirty++; |
|||
} |
|||
} |
|||
} /* end of parallel section */ |
|||
#ifdef PROFILE
|
|||
rnUpdate.Show(); |
|||
#endif /* PROFILE */
|
|||
printf( "Dirty: %d\n", nDirty ); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::addRatsnestCluster( std::shared_ptr<CN_CLUSTER> aCluster ) |
|||
{ |
|||
auto rnNet = m_nets[ aCluster->OriginNet() ]; |
|||
|
|||
rnNet->AddCluster( aCluster ); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::RecalculateRatsnest() |
|||
{ |
|||
int lastNet = m_connAlgo->NetCount(); |
|||
|
|||
if( lastNet >= (int) m_nets.size() ) |
|||
{ |
|||
unsigned int prevSize = m_nets.size(); |
|||
m_nets.resize( lastNet + 1 ); |
|||
|
|||
for( unsigned int i = prevSize; i < m_nets.size(); i++ ) |
|||
m_nets[i] = new RN_NET; |
|||
} |
|||
|
|||
auto clusters = m_connAlgo->GetClusters(); |
|||
|
|||
int dirtyNets = 0; |
|||
|
|||
for( int net = 0; net < lastNet; net++ ) |
|||
if( m_connAlgo->IsNetDirty( net ) ) |
|||
{ |
|||
m_nets[net]->Clear(); |
|||
dirtyNets++; |
|||
} |
|||
|
|||
|
|||
|
|||
for( auto c : clusters ) |
|||
{ |
|||
int net = c->OriginNet(); |
|||
|
|||
if( m_connAlgo->IsNetDirty( net ) ) |
|||
{ |
|||
addRatsnestCluster( c ); |
|||
} |
|||
} |
|||
|
|||
m_connAlgo->ClearDirtyFlags(); |
|||
|
|||
updateRatsnest(); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::blockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems ) |
|||
{ |
|||
std::vector<BOARD_CONNECTED_ITEM*> citems; |
|||
|
|||
for( auto item : aItems ) |
|||
{ |
|||
if( item->Type() == PCB_MODULE_T ) |
|||
{ |
|||
for( auto pad : static_cast<MODULE*>(item)->PadsIter() ) |
|||
citems.push_back( pad ); |
|||
} |
|||
else |
|||
{ |
|||
citems.push_back( static_cast<BOARD_CONNECTED_ITEM*>(item) ); |
|||
} |
|||
} |
|||
|
|||
for( auto item : citems ) |
|||
{ |
|||
auto& entry = m_connAlgo->ItemEntry( item ); |
|||
|
|||
for( auto cnItem : entry.GetItems() ) |
|||
{ |
|||
for( auto anchor : cnItem->Anchors() ) |
|||
anchor->SetNoLine( true ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
int CONNECTIVITY_DATA::GetNetCount() const |
|||
{ |
|||
return m_connAlgo->NetCount(); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, |
|||
std::vector<int>& aIslands ) |
|||
{ |
|||
m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands ); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems ) |
|||
{ |
|||
m_dynamicConnectivity.reset( new CONNECTIVITY_DATA ); |
|||
m_dynamicConnectivity->Build( aItems ); |
|||
|
|||
m_dynamicRatsnest.clear(); |
|||
|
|||
blockRatsnestItems( aItems ); |
|||
|
|||
for( unsigned int nc = 1; nc < m_dynamicConnectivity->m_nets.size(); nc++ ) |
|||
{ |
|||
auto dynNet = m_dynamicConnectivity->m_nets[nc]; |
|||
|
|||
if( dynNet->GetNodeCount() != 0 ) |
|||
{ |
|||
auto ourNet = m_nets[nc]; |
|||
CN_ANCHOR_PTR nodeA, nodeB; |
|||
|
|||
if( ourNet->NearestBicoloredPair( *dynNet, nodeA, nodeB ) ) |
|||
{ |
|||
RN_DYNAMIC_LINE l; |
|||
l.a = nodeA->Pos(); |
|||
l.b = nodeB->Pos(); |
|||
l.netCode = nc; |
|||
|
|||
m_dynamicRatsnest.push_back( l ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for( auto net : m_dynamicConnectivity->m_nets ) |
|||
{ |
|||
if( !net ) |
|||
continue; |
|||
|
|||
const auto& edges = net->GetUnconnected(); |
|||
|
|||
if( edges.empty() ) |
|||
continue; |
|||
|
|||
for( const auto& edge : edges ) |
|||
{ |
|||
const auto& nodeA = edge.GetSourceNode(); |
|||
const auto& nodeB = edge.GetTargetNode(); |
|||
RN_DYNAMIC_LINE l; |
|||
|
|||
l.a = nodeA->Pos(); |
|||
l.b = nodeB->Pos(); |
|||
l.netCode = 0; |
|||
m_dynamicRatsnest.push_back( l ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
const std::vector<RN_DYNAMIC_LINE>& CONNECTIVITY_DATA::GetDynamicRatsnest() const |
|||
{ |
|||
return m_dynamicRatsnest; |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::ClearDynamicRatsnest() |
|||
{ |
|||
m_dynamicConnectivity.reset(); |
|||
m_dynamicRatsnest.clear(); |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::PropagateNets() |
|||
{ |
|||
m_connAlgo->PropagateNets(); |
|||
} |
|||
|
|||
|
|||
unsigned int CONNECTIVITY_DATA::GetUnconnectedCount() const |
|||
{ |
|||
unsigned int unconnected = 0; |
|||
|
|||
for( auto net : m_nets ) |
|||
{ |
|||
if( !net ) |
|||
continue; |
|||
|
|||
const auto& edges = net->GetUnconnected(); |
|||
|
|||
if( edges.empty() ) |
|||
continue; |
|||
|
|||
unconnected += edges.size(); |
|||
} |
|||
|
|||
return unconnected; |
|||
} |
|||
|
|||
|
|||
void CONNECTIVITY_DATA::Clear() |
|||
{ |
|||
for( auto net : m_nets ) |
|||
delete net; |
|||
|
|||
m_nets.clear(); |
|||
} |
|||
|
|||
|
|||
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetConnectedItems( |
|||
const BOARD_CONNECTED_ITEM* aItem, |
|||
const KICAD_T aTypes[] ) const |
|||
{ |
|||
std::list<BOARD_CONNECTED_ITEM*> rv; |
|||
const auto clusters = m_connAlgo->SearchClusters( CN_CONNECTIVITY_ALGO::CSM_CONNECTIVITY_CHECK, aTypes, aItem->GetNetCode() ); |
|||
|
|||
for ( auto cl : clusters ) |
|||
if ( cl->Contains (aItem ) ) |
|||
{ |
|||
for ( const auto item : *cl ) |
|||
rv.push_back( item->Parent() ); |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
|
|||
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems( |
|||
int aNetCode, |
|||
const KICAD_T aTypes[] ) const |
|||
{ |
|||
|
|||
} |
|||
|
|||
bool CONNECTIVITY_DATA::CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport ) |
|||
{ |
|||
RecalculateRatsnest(); |
|||
|
|||
for ( auto net : m_nets ) |
|||
{ |
|||
if ( net ) |
|||
{ |
|||
for ( const auto& edge: net->GetEdges() ) |
|||
{ |
|||
CN_DISJOINT_NET_ENTRY ent; |
|||
ent.net = edge.GetSourceNode()->Parent()->GetNetCode(); |
|||
ent.a = edge.GetSourceNode()->Parent(); |
|||
ent.b = edge.GetTargetNode()->Parent(); |
|||
ent.anchorA = edge.GetSourceNode()->Pos(); |
|||
ent.anchorB = edge.GetTargetNode()->Pos(); |
|||
aReport.push_back( ent ); |
|||
} |
|||
} |
|||
} |
|||
return aReport.empty(); |
|||
} |
|||
@ -0,0 +1,204 @@ |
|||
/* |
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2013-2017 CERN |
|||
* @author Maciej Suminski <maciej.suminski@cern.ch> |
|||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef __CONNECTIVITY_H |
|||
#define __CONNECTIVITY_H |
|||
|
|||
#include <core/typeinfo.h> |
|||
|
|||
#include <wx/string.h> |
|||
#include <vector> |
|||
#include <list> |
|||
#include <memory> |
|||
|
|||
#include <math/vector2d.h> |
|||
|
|||
class CN_ITEM; |
|||
class CN_CLUSTER; |
|||
class CN_CONNECTIVITY_ALGO; |
|||
class BOARD; |
|||
class BOARD_CONNECTED_ITEM; |
|||
class BOARD_ITEM; |
|||
class ZONE_CONTAINER; |
|||
class RN_DATA; |
|||
class RN_NET; |
|||
|
|||
struct CN_DISJOINT_NET_ENTRY |
|||
{ |
|||
int net; |
|||
BOARD_CONNECTED_ITEM* a, * b; |
|||
VECTOR2I anchorA, anchorB; |
|||
}; |
|||
|
|||
struct RN_DYNAMIC_LINE |
|||
{ |
|||
int netCode; |
|||
VECTOR2I a, b; |
|||
}; |
|||
|
|||
// a wrapper class encompassing the connectivity computation algorithm and the |
|||
class CONNECTIVITY_DATA |
|||
{ |
|||
public: |
|||
CONNECTIVITY_DATA(); |
|||
~CONNECTIVITY_DATA(); |
|||
|
|||
|
|||
/** |
|||
* Function Build() |
|||
* Builds the connectivity database for the board aBoard. |
|||
*/ |
|||
void Build( BOARD* aBoard ); |
|||
|
|||
/** |
|||
* Function Build() |
|||
* Builds the connectivity database for a set of items aItems. |
|||
*/ |
|||
void Build( const std::vector<BOARD_ITEM*>& aItems ); |
|||
|
|||
/** |
|||
* Function Add() |
|||
* Adds an item to the connectivity data. |
|||
* @param aItem is an item to be added. |
|||
* @return True if operation succeeded. |
|||
*/ |
|||
bool Add( BOARD_ITEM* aItem ); |
|||
|
|||
/** |
|||
* Function Remove() |
|||
* Removes an item from the connectivity data. |
|||
* @param aItem is an item to be updated. |
|||
* @return True if operation succeeded. |
|||
*/ |
|||
bool Remove( BOARD_ITEM* aItem ); |
|||
|
|||
/** |
|||
* Function Update() |
|||
* Updates the connectivity data for an item. |
|||
* @param aItem is an item to be updated. |
|||
* @return True if operation succeeded. |
|||
*/ |
|||
bool Update( BOARD_ITEM* aItem ); |
|||
|
|||
/** |
|||
* Function Clear() |
|||
* Erases the connectivity database. |
|||
*/ |
|||
|
|||
void Clear(); |
|||
|
|||
/** |
|||
* Function GetNetCount() |
|||
* Returns the total number of nets in the connectivity database. |
|||
*/ |
|||
int GetNetCount() const; |
|||
|
|||
/** |
|||
* Function GetRatsnestForNet() |
|||
* Returns the ratsnest, expressed as a set of graph edges for a given net. |
|||
*/ |
|||
RN_NET* GetRatsnestForNet( int aNet ) |
|||
{ |
|||
return m_nets[aNet]; |
|||
} |
|||
|
|||
/** |
|||
* Function PropagateNets() |
|||
* Propagates the net codes from the source pads to the tracks/vias. |
|||
*/ |
|||
void PropagateNets(); |
|||
|
|||
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport ); |
|||
|
|||
/** |
|||
* Function FindIsolatedCopperIslands() |
|||
* Searches for copper islands in zone aZone that are not connected to any pad. |
|||
* @param aZone zone to test |
|||
* @param aIslands list of islands that have no connections (outline indices in the polygon set) |
|||
*/ |
|||
void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands ); |
|||
|
|||
/** |
|||
* Function RecalculateRatsnest() |
|||
* Updates the ratsnest for the board. |
|||
*/ |
|||
void RecalculateRatsnest(); |
|||
|
|||
/** |
|||
* Function GetUnconnectedCount() |
|||
* Returns the number of remaining edges in the ratsnest. |
|||
*/ |
|||
unsigned int GetUnconnectedCount() const; |
|||
|
|||
|
|||
/** |
|||
* Function ClearDynamicRatsnest() |
|||
* Erases the temporary dynamic ratsnest (i.e. the ratsnest lines that) |
|||
* pcbnew displays when moving an item/set of items |
|||
*/ |
|||
void ClearDynamicRatsnest(); |
|||
|
|||
/** |
|||
* Function ComputeDynamicRatsnest() |
|||
* Calculates the temporary dynamic ratsnest (i.e. the ratsnest lines that) |
|||
* for the set of items aItems. |
|||
*/ |
|||
void ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems ); |
|||
|
|||
|
|||
const std::vector<RN_DYNAMIC_LINE>& GetDynamicRatsnest() const; |
|||
|
|||
/** |
|||
* Function GetConnectedItems() |
|||
* Returns a list of items connected to a source item aItem. |
|||
* @param aItem is the reference item to find other connected items. |
|||
* @param aTypes allows to filter by item types. |
|||
*/ |
|||
const std::list<BOARD_CONNECTED_ITEM*> GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem, |
|||
const KICAD_T aTypes[] ) const; |
|||
|
|||
/** |
|||
* Function GetNetItems() |
|||
* Returns the list of items that belong to a certain net. |
|||
* @param aNetCode is the net code. |
|||
* @param aTypes allows to filter by item types. |
|||
*/ |
|||
const std::list<BOARD_CONNECTED_ITEM*> GetNetItems( int aNetCode, |
|||
const KICAD_T aTypes[] ) const; |
|||
|
|||
private: |
|||
|
|||
void updateRatsnest(); |
|||
void addRatsnestCluster( std::shared_ptr<CN_CLUSTER> aCluster ); |
|||
void blockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems ); |
|||
|
|||
std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity; |
|||
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo; |
|||
|
|||
std::vector<RN_DYNAMIC_LINE> m_dynamicRatsnest; |
|||
std::vector<RN_NET*> m_nets; |
|||
}; |
|||
|
|||
#endif |
|||
@ -0,0 +1,903 @@ |
|||
/*
|
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016-2017 CERN |
|||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <connectivity_algo.h>
|
|||
|
|||
#ifdef PROFILE
|
|||
#include <profile.h>
|
|||
#endif
|
|||
|
|||
bool operator<( const CN_ANCHOR_PTR a, const CN_ANCHOR_PTR b ) |
|||
{ |
|||
if( a->Pos().x == b->Pos().x ) |
|||
return a->Pos().y < b->Pos().y; |
|||
else |
|||
return a->Pos().x < b->Pos().x; |
|||
} |
|||
|
|||
bool CN_ANCHOR::IsDirty() const |
|||
{ |
|||
return m_item->Dirty(); |
|||
} |
|||
|
|||
CN_CLUSTER::CN_CLUSTER() |
|||
{ |
|||
m_items.reserve( 64 ); |
|||
m_originPad = nullptr; |
|||
m_originNet = -1; |
|||
m_conflicting = false; |
|||
} |
|||
|
|||
CN_CLUSTER::~CN_CLUSTER() |
|||
{ |
|||
|
|||
} |
|||
|
|||
wxString CN_CLUSTER::OriginNetName() const |
|||
{ |
|||
if( !m_originPad ) |
|||
return "<none>"; |
|||
else |
|||
return m_originPad->Parent()->GetNetname(); |
|||
} |
|||
|
|||
bool CN_CLUSTER::Contains( const CN_ITEM* aItem ) |
|||
{ |
|||
return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end(); |
|||
} |
|||
|
|||
|
|||
bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem ) |
|||
{ |
|||
for( auto item : m_items ) |
|||
if( item->Parent() == aItem ) |
|||
return true; |
|||
return false; |
|||
} |
|||
|
|||
void CN_ITEM::Dump() |
|||
{ |
|||
printf(" valid: %d, connected: \n", !!Valid()); |
|||
for(auto i : m_connected ) |
|||
{ |
|||
TRACK *t = static_cast<TRACK*>(i->Parent()); |
|||
printf(" - %p %d\n", t, t->Type() ); |
|||
} |
|||
} |
|||
|
|||
void CN_CLUSTER::Dump() |
|||
{ |
|||
for( auto item : m_items ) |
|||
{ |
|||
wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(), |
|||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() ); |
|||
printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(), |
|||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() ); |
|||
item->Dump(); |
|||
|
|||
} |
|||
} |
|||
|
|||
void CN_CLUSTER::Add( CN_ITEM* item ) |
|||
{ |
|||
|
|||
m_items.push_back( item ); |
|||
|
|||
if ( m_originNet < 0 ) |
|||
{ |
|||
m_originNet = item->Net(); |
|||
} |
|||
|
|||
if( item->Parent()->Type() == PCB_PAD_T ) |
|||
{ |
|||
if( !m_originPad ) |
|||
{ |
|||
m_originPad = item; |
|||
m_originNet = item->Net(); |
|||
} |
|||
if( m_originPad && item->Net() != m_originNet ) |
|||
{ |
|||
m_conflicting = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
CN_CONNECTIVITY_ALGO::CN_CONNECTIVITY_ALGO() |
|||
{ |
|||
} |
|||
|
|||
CN_CONNECTIVITY_ALGO::~CN_CONNECTIVITY_ALGO() |
|||
{ |
|||
Clear(); |
|||
} |
|||
|
|||
bool CN_CONNECTIVITY_ALGO::Remove( BOARD_ITEM* aItem ) |
|||
{ |
|||
markItemNetAsDirty ( aItem ); |
|||
|
|||
switch( aItem->Type() ) |
|||
{ |
|||
case PCB_MODULE_T: |
|||
for ( auto pad : static_cast<MODULE *> (aItem ) -> PadsIter() ) |
|||
{ |
|||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( pad ) ].MarkItemsAsInvalid(); |
|||
m_itemMap.erase ( static_cast<BOARD_CONNECTED_ITEM*>( pad ) ); |
|||
} |
|||
m_padList.SetDirty(true); |
|||
|
|||
break; |
|||
case PCB_PAD_T: |
|||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ].MarkItemsAsInvalid(); |
|||
m_itemMap.erase ( static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ); |
|||
m_padList.SetDirty(true); |
|||
break; |
|||
|
|||
case PCB_TRACE_T: |
|||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ].MarkItemsAsInvalid(); |
|||
m_itemMap.erase ( static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ); |
|||
m_trackList.SetDirty(true); |
|||
break; |
|||
|
|||
case PCB_VIA_T: |
|||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ].MarkItemsAsInvalid(); |
|||
m_itemMap.erase ( static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ); |
|||
m_viaList.SetDirty(true); |
|||
|
|||
break; |
|||
|
|||
|
|||
case PCB_ZONE_AREA_T: |
|||
case PCB_ZONE_T: |
|||
{ |
|||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ].MarkItemsAsInvalid(); |
|||
m_itemMap.erase ( static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ); |
|||
m_zoneList.SetDirty(true); |
|||
|
|||
break; |
|||
} |
|||
default: |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
|
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::markItemNetAsDirty( const BOARD_ITEM *aItem ) |
|||
{ |
|||
if ( aItem->IsConnected () ) |
|||
{ |
|||
auto citem = static_cast<const BOARD_CONNECTED_ITEM*> ( aItem ); |
|||
markNetAsDirty ( citem->GetNetCode() ); |
|||
} else { |
|||
if ( aItem->Type() == PCB_MODULE_T ) |
|||
{ |
|||
auto mod = static_cast <const MODULE *> ( aItem ); |
|||
for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() ) |
|||
markNetAsDirty ( pad->GetNetCode() ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem ) |
|||
{ |
|||
markItemNetAsDirty ( aItem ); |
|||
|
|||
switch( aItem->Type() ) |
|||
{ |
|||
case PCB_MODULE_T: |
|||
for ( auto pad : static_cast<MODULE *> (aItem ) -> PadsIter() ) |
|||
{ |
|||
if ( m_itemMap.find ( pad ) != m_itemMap.end() ) |
|||
return false; |
|||
|
|||
add( m_padList, pad ); |
|||
} |
|||
|
|||
break; |
|||
|
|||
case PCB_PAD_T: |
|||
if ( m_itemMap.find ( static_cast<D_PAD *> ( aItem ) ) != m_itemMap.end() ) |
|||
return false; |
|||
|
|||
add( m_padList, static_cast<D_PAD *> ( aItem ) ); |
|||
|
|||
break; |
|||
|
|||
case PCB_TRACE_T: |
|||
{ |
|||
if ( m_itemMap.find ( static_cast<TRACK *> ( aItem ) ) != m_itemMap.end() ) |
|||
return false; |
|||
|
|||
add( m_trackList, static_cast<TRACK *> ( aItem ) ); |
|||
|
|||
break; |
|||
} |
|||
case PCB_VIA_T: |
|||
if ( m_itemMap.find ( static_cast<VIA *> ( aItem ) ) != m_itemMap.end() ) |
|||
return false; |
|||
|
|||
add( m_viaList, static_cast<VIA*> (aItem )); |
|||
|
|||
break; |
|||
|
|||
|
|||
case PCB_ZONE_AREA_T: |
|||
case PCB_ZONE_T: |
|||
{ |
|||
auto zone = static_cast<ZONE_CONTAINER*> ( aItem ); |
|||
|
|||
if ( m_itemMap.find ( static_cast<ZONE_CONTAINER *> ( aItem ) ) != m_itemMap.end() ) |
|||
return false; |
|||
|
|||
m_itemMap[zone] = ITEM_MAP_ENTRY(); |
|||
|
|||
for( auto zitem : m_zoneList.Add( zone ) ) |
|||
m_itemMap[zone].Link(zitem); |
|||
|
|||
break; |
|||
} |
|||
default: |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones ) |
|||
{ |
|||
int totalDirtyCount = 0; |
|||
|
|||
if ( m_lastSearchWithZones != aIncludeZones ) |
|||
{ |
|||
m_padList.MarkAllAsDirty(); |
|||
m_viaList.MarkAllAsDirty(); |
|||
m_trackList.MarkAllAsDirty(); |
|||
m_zoneList.MarkAllAsDirty(); |
|||
} |
|||
|
|||
m_lastSearchWithZones = aIncludeZones; |
|||
|
|||
auto checkForConnection = [] ( const CN_ANCHOR_PTR point, CN_ITEM *aRefItem, int aMaxDist = 0) |
|||
{ |
|||
const auto parent = aRefItem->Parent(); |
|||
|
|||
|
|||
assert ( point->Item() ); |
|||
assert ( point->Item()->Parent() ); |
|||
assert ( aRefItem->Parent() ); |
|||
|
|||
if ( !point->Item()->Valid() ) |
|||
return; |
|||
|
|||
if ( !aRefItem->Valid() ) |
|||
return; |
|||
|
|||
if( parent == point->Item()->Parent() ) |
|||
return; |
|||
|
|||
if( !( parent->GetLayerSet() & |
|||
point->Item()->Parent()->GetLayerSet() ).any() ) |
|||
return; |
|||
|
|||
switch ( parent->Type() ) |
|||
{ |
|||
case PCB_PAD_T: |
|||
case PCB_VIA_T: |
|||
|
|||
if( parent->HitTest( wxPoint( point->Pos().x, point->Pos().y ) ) ) |
|||
CN_ITEM::Connect( aRefItem, point->Item() ); |
|||
|
|||
break; |
|||
case PCB_TRACE_T: |
|||
{ |
|||
const auto track = static_cast<TRACK*> ( parent ); |
|||
|
|||
const VECTOR2I d_start( VECTOR2I( track->GetStart() ) - point->Pos() ); |
|||
const VECTOR2I d_end( VECTOR2I( track->GetEnd() ) - point->Pos() ); |
|||
|
|||
if( d_start.EuclideanNorm() < aMaxDist |
|||
|| d_end.EuclideanNorm() < aMaxDist ) |
|||
CN_ITEM::Connect( aRefItem, point->Item() ); |
|||
break; |
|||
|
|||
} |
|||
|
|||
case PCB_ZONE_T: |
|||
case PCB_ZONE_AREA_T: |
|||
{ |
|||
const auto zone = static_cast<ZONE_CONTAINER*> ( parent ); |
|||
auto zoneItem = static_cast<CN_ZONE*> ( aRefItem ); |
|||
|
|||
if( point->Item()->Net() != parent->GetNetCode() ) |
|||
return; |
|||
|
|||
if( !( zone->GetLayerSet() & |
|||
point->Item()->Parent()->GetLayerSet() ).any() ) |
|||
return; |
|||
|
|||
if ( zoneItem->ContainsAnchor ( point ) ) |
|||
{ |
|||
CN_ITEM::Connect( zoneItem, point->Item() ); |
|||
} |
|||
|
|||
break; |
|||
|
|||
} |
|||
default : |
|||
assert ( false ); |
|||
} |
|||
}; |
|||
|
|||
auto checkInterZoneConnection = [] ( CN_ZONE* testedZone, CN_ZONE *aRefZone ) |
|||
{ |
|||
const auto parentZone = static_cast<const ZONE_CONTAINER*>(aRefZone->Parent()); |
|||
|
|||
if( testedZone->Parent()->Type () != PCB_ZONE_AREA_T ) |
|||
return; |
|||
|
|||
if (testedZone == aRefZone) |
|||
return; |
|||
|
|||
if (testedZone->Parent() == aRefZone->Parent()) |
|||
return; |
|||
|
|||
|
|||
if( testedZone->Net() != parentZone->GetNetCode() ) |
|||
return; // we only test zones belonging to the same net
|
|||
|
|||
if( !( testedZone->Parent()->GetLayerSet() & |
|||
parentZone->GetLayerSet() ).any() ) |
|||
return; // and on same layer
|
|||
|
|||
const auto& outline = parentZone->GetFilledPolysList().COutline( aRefZone->SubpolyIndex() ); |
|||
|
|||
for( int i = 0; i < outline.PointCount(); i++ ) |
|||
if( testedZone ->ContainsPoint( outline.CPoint(i) ) ) |
|||
{ |
|||
CN_ITEM::Connect ( aRefZone, testedZone ); |
|||
return; |
|||
} |
|||
|
|||
const auto testedZoneParent = static_cast<const ZONE_CONTAINER*>(testedZone->Parent()); |
|||
|
|||
const auto& outline2 = testedZoneParent->GetFilledPolysList().COutline( testedZone->SubpolyIndex() ); |
|||
|
|||
for( int i = 0; i < outline2.PointCount(); i++ ) |
|||
if( aRefZone ->ContainsPoint( outline2.CPoint(i) ) ) |
|||
{ |
|||
CN_ITEM::Connect ( aRefZone, testedZone ); |
|||
return; |
|||
} |
|||
|
|||
}; |
|||
|
|||
|
|||
#ifdef CONNECTIVITY_DEBUG
|
|||
printf("Search start\n"); |
|||
#endif
|
|||
|
|||
std::vector<CN_ITEM *> garbage; |
|||
garbage.reserve(1024); |
|||
|
|||
m_padList.RemoveInvalidItems(garbage); |
|||
m_viaList.RemoveInvalidItems(garbage); |
|||
m_trackList.RemoveInvalidItems(garbage); |
|||
m_zoneList.RemoveInvalidItems(garbage); |
|||
|
|||
for ( auto item : garbage ) |
|||
delete item; |
|||
|
|||
//auto all = allItemsInBoard();
|
|||
|
|||
#ifdef CONNECTIVITY_DEBUG
|
|||
for ( auto item : m_padList ) |
|||
if ( all.find( item->Parent() ) == all.end() ) { printf("FAiling pad : %p\n", item->Parent() ); assert ( false ); } |
|||
for ( auto item : m_viaList ) |
|||
if ( all.find( item->Parent() ) == all.end() ) { printf("FAiling via : %p\n", item->Parent() ); assert ( false ); } |
|||
for ( auto item : m_trackList ) |
|||
if ( all.find( item->Parent() ) == all.end() ) { printf("FAiling track : %p\n", item->Parent() ); assert ( false ); } |
|||
for ( auto item : m_zoneList ) |
|||
if ( all.find( item->Parent() ) == all.end() ) { printf("FAiling zome : %p\n", item->Parent() ); assert ( false ); } |
|||
#endif
|
|||
|
|||
|
|||
using namespace std::placeholders; |
|||
|
|||
#ifdef PROFILE
|
|||
PROF_COUNTER search_cnt( "search-connections" ); |
|||
PROF_COUNTER search_basic( "search-basic" ); |
|||
#endif
|
|||
|
|||
if ( m_padList.IsDirty() || m_trackList.IsDirty() || m_viaList.IsDirty() ) |
|||
{ |
|||
totalDirtyCount++; |
|||
|
|||
for( auto padItem : m_padList ) |
|||
{ |
|||
auto pad = static_cast<D_PAD*> ( padItem->Parent() ); |
|||
auto searchPads = std::bind( checkForConnection, _1, padItem ); |
|||
|
|||
m_padList.FindNearby( pad->ShapePos(), pad->GetBoundingRadius(), searchPads ); |
|||
m_trackList.FindNearby( pad->ShapePos(), pad->GetBoundingRadius(), searchPads ); |
|||
m_viaList.FindNearby( pad->ShapePos(), pad->GetBoundingRadius(), searchPads ); |
|||
} |
|||
|
|||
for( auto& trackItem : m_trackList ) |
|||
{ |
|||
auto track = static_cast<TRACK*> ( trackItem->Parent() ); |
|||
int dist_max = track->GetWidth() / 2; |
|||
auto searchTracks = std::bind( checkForConnection, _1, trackItem, dist_max ); |
|||
|
|||
m_trackList.FindNearby( track->GetStart(), dist_max, searchTracks ); |
|||
m_trackList.FindNearby( track->GetEnd(), dist_max, searchTracks ); |
|||
} |
|||
|
|||
for( auto& viaItem : m_viaList ) |
|||
{ |
|||
auto via = static_cast<VIA*> ( viaItem->Parent() ); |
|||
int dist_max = via->GetWidth() / 2; |
|||
auto searchVias = std::bind( checkForConnection, _1, viaItem, dist_max ); |
|||
|
|||
totalDirtyCount++; |
|||
m_viaList.FindNearby( via->GetStart(), dist_max, searchVias ); |
|||
m_trackList.FindNearby( via->GetStart(), dist_max, searchVias ); |
|||
} |
|||
} |
|||
|
|||
#ifdef PROFILE
|
|||
search_basic.Show(); |
|||
#endif
|
|||
|
|||
if( aIncludeZones ) |
|||
{ |
|||
for( auto& item : m_zoneList ) |
|||
{ |
|||
auto zoneItem = static_cast<CN_ZONE *> (item); |
|||
auto searchZones = std::bind( checkForConnection, _1, zoneItem ); |
|||
|
|||
if( zoneItem->Dirty() ) |
|||
{ |
|||
totalDirtyCount++; |
|||
m_viaList.FindNearby( zoneItem->BBox(), searchZones ); |
|||
m_trackList.FindNearby( zoneItem->BBox(), searchZones ); |
|||
m_padList.FindNearby( zoneItem->BBox(), searchZones ); |
|||
m_zoneList.FindNearbyZones( zoneItem->BBox(), std::bind( checkInterZoneConnection, _1, zoneItem ) ); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
m_zoneList.ClearDirtyFlags(); |
|||
} |
|||
|
|||
m_padList.ClearDirtyFlags(); |
|||
m_viaList.ClearDirtyFlags(); |
|||
m_trackList.ClearDirtyFlags(); |
|||
|
|||
#ifdef CONNECTIVITY_DEBUG
|
|||
printf("Search end\n"); |
|||
#endif
|
|||
|
|||
#ifdef PROFILE
|
|||
search_cnt.Show(); |
|||
#endif
|
|||
|
|||
} |
|||
|
|||
void CN_ITEM::RemoveInvalidRefs() |
|||
{ |
|||
auto lastConn = std::remove_if(m_connected.begin(), m_connected.end(), [] ( CN_ITEM * item) { |
|||
return !item->Valid(); |
|||
|
|||
} ); |
|||
|
|||
m_connected.resize( lastConn - m_connected.begin() ); |
|||
} |
|||
|
|||
void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM *>& aGarbage ) |
|||
{ |
|||
auto lastAnchor = std::remove_if(m_anchors.begin(), m_anchors.end(), [] ( const CN_ANCHOR_PTR anchor) { |
|||
return !anchor->Valid(); |
|||
|
|||
} ); |
|||
|
|||
m_anchors.resize( lastAnchor - m_anchors.begin() ); |
|||
|
|||
auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM * item) { |
|||
if ( !item->Valid() ) |
|||
{ |
|||
aGarbage.push_back ( item ); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} ); |
|||
|
|||
m_items.resize( lastItem - m_items.begin() ); |
|||
|
|||
// fixme: mem leaks
|
|||
|
|||
for ( auto item : m_items ) |
|||
item->RemoveInvalidRefs(); |
|||
} |
|||
|
|||
|
|||
bool CN_CONNECTIVITY_ALGO::isDirty() const |
|||
{ |
|||
return m_viaList.IsDirty() || m_trackList.IsDirty() || m_zoneList.IsDirty() || m_padList.IsDirty(); |
|||
} |
|||
|
|||
const CN_CONNECTIVITY_ALGO::CLUSTERS CN_CONNECTIVITY_ALGO::SearchClusters( CLUSTER_SEARCH_MODE aMode ) |
|||
{ |
|||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_MODULE_T, EOT }; |
|||
return SearchClusters ( aMode, types, -1 ); |
|||
} |
|||
|
|||
const CN_CONNECTIVITY_ALGO::CLUSTERS CN_CONNECTIVITY_ALGO::SearchClusters( CLUSTER_SEARCH_MODE aMode, const KICAD_T aTypes[], int aSingleNet ) |
|||
{ |
|||
bool includeZones = ( aMode != CSM_PROPAGATE ); |
|||
bool withinAnyNet = ( aMode != CSM_PROPAGATE ); |
|||
|
|||
std::deque<CN_ITEM*> Q; |
|||
CN_ITEM* head = nullptr; |
|||
CLUSTERS clusters; |
|||
|
|||
if ( isDirty() ) |
|||
searchConnections( includeZones ); |
|||
|
|||
auto addToSearchList = [&head, withinAnyNet, aSingleNet, aTypes] ( CN_ITEM *aItem ) |
|||
{ |
|||
if ( withinAnyNet && aItem->Net() <= 0 ) |
|||
return; |
|||
|
|||
if( !aItem->Valid() ) |
|||
return; |
|||
|
|||
if ( aSingleNet >=0 && aItem->Net() != aSingleNet ) |
|||
return; |
|||
|
|||
bool found = false; |
|||
|
|||
for ( int i = 0; aTypes[i] != EOT; i++ ) |
|||
if ( aItem->Parent()->Type() == aTypes[i] ) |
|||
{ |
|||
found = true; |
|||
break; |
|||
} |
|||
|
|||
if (!found) |
|||
return; |
|||
|
|||
aItem->ListClear(); |
|||
aItem->SetVisited( false ); |
|||
|
|||
if ( !head ) |
|||
head = aItem; |
|||
else |
|||
head->ListInsert( aItem ); |
|||
}; |
|||
|
|||
std::for_each( m_padList.begin(), m_padList.end(), addToSearchList ); |
|||
std::for_each( m_trackList.begin(), m_trackList.end(), addToSearchList ); |
|||
std::for_each( m_viaList.begin(), m_viaList.end(), addToSearchList ); |
|||
|
|||
if (includeZones) |
|||
{ |
|||
std::for_each( m_zoneList.begin(), m_zoneList.end(), addToSearchList ); |
|||
} |
|||
|
|||
|
|||
while( head ) |
|||
{ |
|||
CN_CLUSTER_PTR cluster ( new CN_CLUSTER() ); |
|||
|
|||
Q.clear(); |
|||
CN_ITEM* root = head; |
|||
root->SetVisited ( true ); |
|||
|
|||
head = root->ListRemove(); |
|||
|
|||
Q.push_back( root ); |
|||
|
|||
while( Q.size() ) |
|||
{ |
|||
CN_ITEM* current = Q.front(); |
|||
|
|||
Q.pop_front(); |
|||
cluster->Add( current ); |
|||
|
|||
for( auto n : current->ConnectedItems() ) |
|||
{ |
|||
if ( withinAnyNet && n->Net() != root->Net() ) |
|||
continue; |
|||
|
|||
if( !n->Visited() && n->Valid() ) |
|||
{ |
|||
n->SetVisited( true ); |
|||
Q.push_back( n ); |
|||
head = n->ListRemove(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
clusters.push_back( cluster ); |
|||
} |
|||
|
|||
|
|||
std::sort( clusters.begin(), clusters.end(), []( CN_CLUSTER_PTR a, CN_CLUSTER_PTR b ) { |
|||
return a->OriginNet() < b->OriginNet(); |
|||
} ); |
|||
|
|||
#ifdef CONNECTIVITY_DEBUG
|
|||
printf("Active clusters: %d\n"); |
|||
for (auto cl:clusters) |
|||
{ |
|||
printf("Net %d\n", cl->OriginNet()); |
|||
cl->Dump(); |
|||
} |
|||
#endif
|
|||
|
|||
return clusters; |
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::Build( BOARD* aBoard ) |
|||
{ |
|||
for( int i = 0; i<aBoard->GetAreaCount(); i++ ) |
|||
{ |
|||
auto zone = aBoard->GetArea( i ); |
|||
Add( zone ); |
|||
} |
|||
|
|||
for( auto tv : aBoard->Tracks() ) |
|||
Add( tv ); |
|||
|
|||
for( auto mod : aBoard->Modules() ) |
|||
for( auto pad : mod->PadsIter() ) |
|||
Add( pad ); |
|||
|
|||
/*wxLogTrace( "CN", "zones : %lu, pads : %lu vias : %lu tracks : %lu\n",
|
|||
m_zoneList.Size(), m_padList.Size(), |
|||
m_viaList.Size(), m_trackList.Size() );*/ |
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::Build( const std::vector<BOARD_ITEM *> &aItems ) |
|||
{ |
|||
for ( auto item : aItems ) |
|||
{ |
|||
switch( item->Type() ) |
|||
{ |
|||
case PCB_TRACE_T: |
|||
case PCB_VIA_T: |
|||
case PCB_ZONE_T: |
|||
case PCB_PAD_T: |
|||
Add( item ); |
|||
break; |
|||
|
|||
case PCB_MODULE_T: |
|||
{ |
|||
for( auto pad : static_cast<MODULE*>(item)->PadsIter() ) |
|||
{ |
|||
Add( pad ); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::propagateConnections() |
|||
{ |
|||
for( auto cluster : m_connClusters ) |
|||
{ |
|||
if( cluster->IsConflicting() ) |
|||
{ |
|||
wxLogTrace( "CN", "Conflicting nets in cluster %p\n", cluster.get() ); |
|||
} |
|||
else if( cluster->IsOrphaned() ) |
|||
{ |
|||
wxLogTrace( "CN", "Skipping orphaned cluster %p [net: %s]\n", cluster.get(), |
|||
(const char*) cluster->OriginNetName() ); |
|||
} |
|||
else if( cluster->HasValidNet() ) |
|||
{ |
|||
// normal cluster: just propagate from the pads
|
|||
int n_changed = 0; |
|||
|
|||
for( auto item : *cluster ) |
|||
{ |
|||
if( item->CanChangeNet() ) |
|||
{ |
|||
item->Parent()->SetNetCode( cluster->OriginNet() ); |
|||
n_changed++; |
|||
} |
|||
} |
|||
|
|||
if( n_changed ) |
|||
wxLogTrace( "CN", "Cluster %p : net : %d %s\n", cluster.get(), |
|||
cluster->OriginNet(), (const char*) cluster->OriginNetName() ); |
|||
else |
|||
wxLogTrace( "CN", "Cluster %p : nothing to propagate\n", cluster.get() ); |
|||
} |
|||
else |
|||
{ |
|||
wxLogTrace( "CN", "Cluster %p : connected to unused net\n", cluster.get() ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void CN_CONNECTIVITY_ALGO::PropagateNets() |
|||
{ |
|||
//searchConnections( false );
|
|||
m_connClusters = SearchClusters( CSM_PROPAGATE ); |
|||
propagateConnections(); |
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands ) |
|||
{ |
|||
|
|||
if ( aZone->GetFilledPolysList().IsEmpty() ) |
|||
return; |
|||
|
|||
aIslands.clear(); |
|||
|
|||
Remove( aZone ); |
|||
Add( aZone ); |
|||
|
|||
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK ); |
|||
|
|||
for( auto cluster : m_connClusters ) |
|||
if( cluster->Contains( aZone ) && cluster->IsOrphaned() ) |
|||
{ |
|||
for( auto z : *cluster ) |
|||
{ |
|||
if( z->Parent() == aZone ) |
|||
{ |
|||
aIslands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
wxLogTrace( "CN", "Found %llu isolated islands\n", aIslands.size() ); |
|||
} |
|||
|
|||
const CN_CONNECTIVITY_ALGO::CLUSTERS& CN_CONNECTIVITY_ALGO::GetClusters() |
|||
{ |
|||
m_ratsnestClusters = SearchClusters( CSM_RATSNEST ); |
|||
return m_ratsnestClusters; |
|||
}; |
|||
|
|||
void CN_CONNECTIVITY_ALGO::markNetAsDirty ( int aNet ) |
|||
{ |
|||
if(aNet <= 0) |
|||
return; |
|||
|
|||
if(m_dirtyNets.size() <= aNet ) |
|||
m_dirtyNets.resize(aNet + 1); |
|||
m_dirtyNets[ aNet ] = true; |
|||
} |
|||
|
|||
int CN_ITEM::AnchorCount() const |
|||
{ |
|||
return m_parent->Type() == PCB_TRACE_T ? 2 : 1; |
|||
} |
|||
|
|||
const VECTOR2I CN_ITEM::GetAnchor( int n ) const |
|||
{ |
|||
switch ( m_parent->Type() ) |
|||
{ |
|||
case PCB_PAD_T: |
|||
return static_cast<const D_PAD *>(m_parent)->ShapePos(); |
|||
break; |
|||
|
|||
case PCB_TRACE_T: |
|||
{ |
|||
auto tr = static_cast<const TRACK *>(m_parent); |
|||
return (n == 0 ? tr->GetStart() : tr->GetEnd() ); |
|||
|
|||
break; |
|||
} |
|||
|
|||
case PCB_VIA_T: |
|||
return static_cast<const VIA *>(m_parent)->GetStart(); |
|||
|
|||
default: |
|||
assert(false); |
|||
return VECTOR2I(); |
|||
} |
|||
} |
|||
|
|||
int CN_ZONE::AnchorCount() const |
|||
{ |
|||
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() ); |
|||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); |
|||
|
|||
return outline.PointCount() ? 1 : 0; |
|||
} |
|||
|
|||
const VECTOR2I CN_ZONE::GetAnchor(int n ) const |
|||
{ |
|||
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() ); |
|||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex ); |
|||
|
|||
return outline.CPoint(0); |
|||
} |
|||
|
|||
/*const std::vector<VECTOR2I> CN_CLUSTER::GetAnchors()
|
|||
{ |
|||
std::vector<VECTOR2I> anchors; |
|||
|
|||
for ( auto item : m_items ) |
|||
{ |
|||
int cnt = item->AnchorCount(); |
|||
for (int i = 0 ; i < cnt; i++) |
|||
{ |
|||
anchors.push_back( item->GetAnchor(i) ); |
|||
} |
|||
} |
|||
|
|||
return anchors; |
|||
}*/ |
|||
|
|||
int CN_ITEM::Net() const |
|||
{ |
|||
if (!m_parent) |
|||
return -1; |
|||
return m_parent->GetNetCode(); |
|||
} |
|||
|
|||
|
|||
BOARD_CONNECTED_ITEM *CN_ANCHOR::Parent() const |
|||
{ |
|||
return m_item->Parent(); |
|||
} |
|||
|
|||
|
|||
bool CN_ANCHOR::Valid() const |
|||
{ |
|||
if( !m_item ) |
|||
return false; |
|||
return m_item->Valid(); |
|||
} |
|||
|
|||
void CN_CONNECTIVITY_ALGO::Clear() |
|||
{ |
|||
m_ratsnestClusters.clear(); |
|||
m_connClusters.clear(); |
|||
m_itemMap.clear(); |
|||
m_padList.Clear(); |
|||
m_trackList.Clear(); |
|||
m_viaList.Clear(); |
|||
m_zoneList.Clear(); |
|||
|
|||
} |
|||
@ -0,0 +1,926 @@ |
|||
/* |
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2013-2017 CERN |
|||
* @author Maciej Suminski <maciej.suminski@cern.ch> |
|||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
// #define CONNECTIVITY_DEBUG |
|||
|
|||
#ifndef __CONNECTIVITY_ALGO_H |
|||
#define __CONNECTIVITY_ALGO_H |
|||
|
|||
#include <class_board.h> |
|||
#include <class_pad.h> |
|||
#include <class_module.h> |
|||
#include <class_zone.h> |
|||
|
|||
#include <geometry/shape_poly_set.h> |
|||
#include <geometry/poly_grid_partition.h> |
|||
|
|||
#include <memory> |
|||
#include <algorithm> |
|||
#include <functional> |
|||
#include <vector> |
|||
#include <deque> |
|||
|
|||
#include <connectivity.h> |
|||
|
|||
class CN_ITEM; |
|||
class CN_CONNECTIVITY_ALGO_IMPL; |
|||
class CN_RATSNEST_NODES; |
|||
class CN_CLUSTER; |
|||
class BOARD; |
|||
class BOARD_CONNECTED_ITEM; |
|||
class BOARD_ITEM; |
|||
class ZONE_CONTAINER; |
|||
|
|||
class CN_ANCHOR |
|||
{ |
|||
public: |
|||
CN_ANCHOR() |
|||
{ |
|||
m_item = nullptr; |
|||
} |
|||
|
|||
CN_ANCHOR( const VECTOR2I& aPos, CN_ITEM* aItem ) |
|||
{ |
|||
m_pos = aPos; |
|||
m_item = aItem; |
|||
assert( m_item ); |
|||
} |
|||
|
|||
bool Valid() const; |
|||
|
|||
|
|||
CN_ITEM* Item() const |
|||
{ |
|||
return m_item; |
|||
} |
|||
|
|||
BOARD_CONNECTED_ITEM* Parent() const; |
|||
|
|||
const VECTOR2I& Pos() const |
|||
{ |
|||
return m_pos; |
|||
} |
|||
|
|||
bool IsDirty() const; |
|||
|
|||
/// Returns tag, common identifier for connected nodes |
|||
inline int GetTag() const |
|||
{ |
|||
return m_tag; |
|||
} |
|||
|
|||
/// Sets tag, common identifier for connected nodes |
|||
inline void SetTag( int aTag ) |
|||
{ |
|||
m_tag = aTag; |
|||
} |
|||
|
|||
/// Decides whether this node can be a ratsnest line target |
|||
inline void SetNoLine( bool aEnable ) |
|||
{ |
|||
m_noline = aEnable; |
|||
} |
|||
|
|||
/// Returns true if this node can be a target for ratsnest lines |
|||
inline const bool& GetNoLine() const |
|||
{ |
|||
return m_noline; |
|||
} |
|||
|
|||
inline void SetCluster( std::shared_ptr<CN_CLUSTER> aCluster ) |
|||
{ |
|||
m_cluster = aCluster; |
|||
} |
|||
|
|||
inline std::shared_ptr<CN_CLUSTER> GetCluster() const |
|||
{ |
|||
return m_cluster; |
|||
} |
|||
|
|||
// Tag used for unconnected items. |
|||
static const int TAG_UNCONNECTED = -1; |
|||
|
|||
private: |
|||
/// Position of the anchor |
|||
VECTOR2I m_pos; |
|||
|
|||
/// Item owning the anchor |
|||
CN_ITEM* m_item = nullptr; |
|||
|
|||
/// Tag for quick connection resolution |
|||
int m_tag = -1; |
|||
|
|||
/// Whether it the node can be a target for ratsnest lines |
|||
bool m_noline = false; |
|||
|
|||
/// Cluster to which the anchor belongs |
|||
std::shared_ptr<CN_CLUSTER> m_cluster; |
|||
}; |
|||
|
|||
|
|||
typedef std::shared_ptr<CN_ANCHOR> CN_ANCHOR_PTR; |
|||
typedef std::vector<CN_ANCHOR_PTR> CN_ANCHORS; |
|||
|
|||
class CN_EDGE |
|||
{ |
|||
public: |
|||
CN_EDGE() {}; |
|||
CN_EDGE( CN_ANCHOR_PTR aSource, CN_ANCHOR_PTR aTarget, int aWeight = 0 ) : |
|||
m_source( aSource ), |
|||
m_target( aTarget ), |
|||
m_weight( aWeight ) {} |
|||
|
|||
CN_ANCHOR_PTR GetSourceNode() const { return m_source; } |
|||
CN_ANCHOR_PTR GetTargetNode() const { return m_target; } |
|||
int GetWeight() const { return m_weight; } |
|||
|
|||
void SetSourceNode( const CN_ANCHOR_PTR& aNode ) { m_source = aNode; } |
|||
void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; } |
|||
void SetWeight( unsigned int weight ) { m_weight = weight; } |
|||
|
|||
private: |
|||
CN_ANCHOR_PTR m_source; |
|||
CN_ANCHOR_PTR m_target; |
|||
unsigned int m_weight = 0; |
|||
}; |
|||
|
|||
class CN_CLUSTER |
|||
{ |
|||
private: |
|||
|
|||
bool m_conflicting = false; |
|||
int m_originNet = 0; |
|||
CN_ITEM* m_originPad = nullptr; |
|||
std::vector<CN_ITEM*> m_items; |
|||
|
|||
public: |
|||
CN_CLUSTER(); |
|||
~CN_CLUSTER(); |
|||
|
|||
bool HasValidNet() const |
|||
{ |
|||
return m_originNet >= 0; |
|||
} |
|||
|
|||
int OriginNet() const |
|||
{ |
|||
return m_originNet; |
|||
} |
|||
|
|||
wxString OriginNetName() const; |
|||
|
|||
bool Contains( const CN_ITEM* aItem ); |
|||
bool Contains( const BOARD_CONNECTED_ITEM* aItem ); |
|||
void Dump(); |
|||
|
|||
int Size() const |
|||
{ |
|||
return m_items.size(); |
|||
} |
|||
|
|||
bool HasNet() const |
|||
{ |
|||
return m_originNet >= 0; |
|||
} |
|||
|
|||
bool IsOrphaned() const |
|||
{ |
|||
return m_originPad == nullptr; |
|||
} |
|||
|
|||
bool IsConflicting() const |
|||
{ |
|||
return m_conflicting; |
|||
} |
|||
|
|||
void Add( CN_ITEM* item ); |
|||
|
|||
using ITER = decltype(m_items)::iterator; |
|||
|
|||
ITER begin() { return m_items.begin(); }; |
|||
ITER end() { return m_items.end(); }; |
|||
}; |
|||
|
|||
typedef std::shared_ptr<CN_CLUSTER> CN_CLUSTER_PTR; |
|||
|
|||
// a lightweight intrusive list container |
|||
template <class T> |
|||
class INTRUSIVE_LIST |
|||
{ |
|||
public: |
|||
INTRUSIVE_LIST<T>() |
|||
{ |
|||
ListClear(); |
|||
} |
|||
|
|||
void ListClear() |
|||
{ |
|||
m_prev = nullptr; |
|||
m_next = nullptr; |
|||
m_root = (T*) this; |
|||
m_count = 1; |
|||
} |
|||
|
|||
T* ListRemove() |
|||
{ |
|||
if( m_prev ) |
|||
m_prev->m_next = m_next; |
|||
|
|||
if( m_next ) |
|||
m_next->m_prev = m_prev; |
|||
|
|||
m_root->m_count--; |
|||
|
|||
T* rv = nullptr; |
|||
|
|||
if( m_prev ) |
|||
rv = m_prev; |
|||
else if( m_next ) |
|||
rv = m_next; |
|||
|
|||
m_root = nullptr; |
|||
m_prev = nullptr; |
|||
m_next = nullptr; |
|||
return rv; |
|||
} |
|||
|
|||
int ListSize() const |
|||
{ |
|||
return m_root ? m_root->m_count : 0; |
|||
} |
|||
|
|||
void ListInsert( T* item ) |
|||
{ |
|||
if( !m_root ) |
|||
m_root = item; |
|||
|
|||
if( m_next ) |
|||
m_next->m_prev = item; |
|||
|
|||
item->m_prev = (T*) this; |
|||
item->m_next = m_next; |
|||
item->m_root = m_root; |
|||
m_root->m_count++; |
|||
|
|||
m_next = item; |
|||
} |
|||
|
|||
T* ListNext() const { return m_next; }; |
|||
T* ListPrev() const { return m_prev; }; |
|||
|
|||
private: |
|||
int m_count; |
|||
T* m_prev; |
|||
T* m_next; |
|||
T* m_root; |
|||
}; |
|||
|
|||
// basic connectivity item |
|||
class CN_ITEM : public INTRUSIVE_LIST<CN_ITEM> |
|||
{ |
|||
private: |
|||
BOARD_CONNECTED_ITEM* m_parent; |
|||
|
|||
using CONNECTED_ITEMS = std::vector<CN_ITEM*>; |
|||
|
|||
// list of items physically connected (touching) |
|||
CONNECTED_ITEMS m_connected; |
|||
|
|||
CN_ANCHORS m_anchors; |
|||
|
|||
// visited flag for the BFS scan |
|||
bool m_visited; |
|||
|
|||
// can the net propagator modify the netcode? |
|||
bool m_canChangeNet; |
|||
|
|||
// valid flag, used to identify garbage items (we use lazy removal) |
|||
bool m_valid; |
|||
|
|||
// dirty flag, used to identify recently added item not yet scanned into the connectivity search |
|||
bool m_dirty; |
|||
|
|||
public: |
|||
void Dump(); |
|||
|
|||
CN_ITEM( BOARD_CONNECTED_ITEM* aParent, bool aCanChangeNet, int aAnchorCount = 2 ) |
|||
{ |
|||
m_parent = aParent; |
|||
m_canChangeNet = aCanChangeNet; |
|||
m_visited = false; |
|||
m_valid = true; |
|||
m_dirty = true; |
|||
m_anchors.reserve( 2 ); |
|||
} |
|||
|
|||
virtual ~CN_ITEM() {}; |
|||
|
|||
CN_ANCHOR_PTR AddAnchor( const VECTOR2I& aPos ) |
|||
{ |
|||
m_anchors.emplace_back( std::make_shared<CN_ANCHOR> ( aPos, this ) ); |
|||
//printf("%p add %d\n", this, m_anchors.size() ); |
|||
return m_anchors.back(); |
|||
} |
|||
|
|||
CN_ANCHORS& Anchors() |
|||
{ |
|||
return m_anchors; |
|||
} |
|||
|
|||
void SetValid( bool aValid ) |
|||
{ |
|||
m_valid = aValid; |
|||
} |
|||
|
|||
bool Valid() const |
|||
{ |
|||
return m_valid; |
|||
} |
|||
|
|||
void SetDirty( bool aDirty ) |
|||
{ |
|||
m_dirty = aDirty; |
|||
} |
|||
|
|||
bool Dirty() const |
|||
{ |
|||
return m_dirty; |
|||
} |
|||
|
|||
BOARD_CONNECTED_ITEM* Parent() const |
|||
{ |
|||
return m_parent; |
|||
} |
|||
|
|||
const CONNECTED_ITEMS& ConnectedItems() const |
|||
{ |
|||
return m_connected; |
|||
} |
|||
|
|||
void ClearConnections() |
|||
{ |
|||
m_connected.clear(); |
|||
} |
|||
|
|||
void SetVisited( bool aVisited ) |
|||
{ |
|||
m_visited = aVisited; |
|||
} |
|||
|
|||
bool Visited() const |
|||
{ |
|||
return m_visited; |
|||
} |
|||
|
|||
bool CanChangeNet() const |
|||
{ |
|||
return m_canChangeNet; |
|||
} |
|||
|
|||
static void Connect( CN_ITEM* a, CN_ITEM* b ) |
|||
{ |
|||
bool foundA = false, foundB = false; |
|||
|
|||
for( auto item : a->m_connected ) |
|||
{ |
|||
if( item == b ) |
|||
{ |
|||
foundA = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
for( auto item : b->m_connected ) |
|||
{ |
|||
if( item == a ) |
|||
{ |
|||
foundB = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if( !foundA ) |
|||
a->m_connected.push_back( b ); |
|||
|
|||
if( !foundB ) |
|||
b->m_connected.push_back( a ); |
|||
} |
|||
|
|||
void RemoveInvalidRefs(); |
|||
|
|||
virtual int AnchorCount() const; |
|||
virtual const VECTOR2I GetAnchor( int n ) const; |
|||
|
|||
int Net() const; |
|||
}; |
|||
|
|||
typedef std::shared_ptr<CN_ITEM> CN_ITEM_PTR; |
|||
|
|||
class CN_LIST |
|||
{ |
|||
private: |
|||
bool m_dirty; |
|||
std::vector<CN_ANCHOR_PTR> m_anchors; |
|||
|
|||
protected: |
|||
std::vector<CN_ITEM*> m_items; |
|||
|
|||
void addAnchor( VECTOR2I pos, CN_ITEM* item ) |
|||
{ |
|||
m_anchors.push_back( item->AddAnchor( pos ) ); |
|||
} |
|||
|
|||
private: |
|||
|
|||
void sort() |
|||
{ |
|||
if( m_dirty ) |
|||
{ |
|||
std::sort( m_anchors.begin(), m_anchors.end() ); |
|||
|
|||
m_dirty = false; |
|||
} |
|||
} |
|||
|
|||
public: |
|||
CN_LIST() |
|||
{ |
|||
m_dirty = false; |
|||
}; |
|||
|
|||
void Clear() |
|||
{ |
|||
for( auto item : m_items ) |
|||
delete item; |
|||
|
|||
m_items.clear(); |
|||
} |
|||
|
|||
using ITER = decltype(m_items)::iterator; |
|||
|
|||
ITER begin() { return m_items.begin(); }; |
|||
ITER end() { return m_items.end(); }; |
|||
|
|||
template <class T> |
|||
void FindNearby( VECTOR2I aPosition, int aDistMax, T aFunc, bool aDirtyOnly = false ); |
|||
|
|||
template <class T> |
|||
void FindNearby( BOX2I aBBox, T aFunc, bool aDirtyOnly = false ); |
|||
|
|||
void SetDirty( bool aDirty = true ) |
|||
{ |
|||
m_dirty = aDirty; |
|||
} |
|||
|
|||
bool IsDirty() const |
|||
{ |
|||
return m_dirty; |
|||
} |
|||
|
|||
void ClearConnections() |
|||
{ |
|||
for( auto& anchor : m_anchors ) |
|||
anchor->Item()->ClearConnections(); |
|||
} |
|||
|
|||
void RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage ); |
|||
|
|||
void ClearDirtyFlags() |
|||
{ |
|||
for( auto item : m_items ) |
|||
item->SetDirty( false ); |
|||
|
|||
SetDirty( false ); |
|||
} |
|||
|
|||
void MarkAllAsDirty() |
|||
{ |
|||
for( auto item : m_items ) |
|||
item->SetDirty( true ); |
|||
|
|||
SetDirty( true ); |
|||
} |
|||
|
|||
int Size() const |
|||
{ |
|||
return m_items.size(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
class CN_PAD_LIST : public CN_LIST |
|||
{ |
|||
public: |
|||
|
|||
CN_ITEM* Add( D_PAD* pad ) |
|||
{ |
|||
auto item = new CN_ITEM( pad, false, 2 ); |
|||
|
|||
addAnchor( pad->ShapePos(), item ); |
|||
m_items.push_back( item ); |
|||
|
|||
SetDirty(); |
|||
return item; |
|||
}; |
|||
}; |
|||
|
|||
class CN_TRACK_LIST : public CN_LIST |
|||
{ |
|||
public: |
|||
CN_ITEM* Add( TRACK* track ) |
|||
{ |
|||
auto item = new CN_ITEM( track, true ); |
|||
|
|||
m_items.push_back( item ); |
|||
|
|||
addAnchor( track->GetStart(), item ); |
|||
addAnchor( track->GetEnd(), item ); |
|||
SetDirty(); |
|||
|
|||
return item; |
|||
}; |
|||
}; |
|||
|
|||
class CN_VIA_LIST : public CN_LIST |
|||
{ |
|||
public: |
|||
CN_ITEM* Add( VIA* via ) |
|||
{ |
|||
auto item = new CN_ITEM( via, true ); |
|||
|
|||
m_items.push_back( item ); |
|||
addAnchor( via->GetStart(), item ); |
|||
SetDirty(); |
|||
return item; |
|||
}; |
|||
}; |
|||
|
|||
class CN_ZONE : public CN_ITEM |
|||
{ |
|||
public: |
|||
CN_ZONE( ZONE_CONTAINER* aParent, bool aCanChangeNet, int aSubpolyIndex ) : |
|||
CN_ITEM( aParent, aCanChangeNet ), |
|||
m_subpolyIndex( aSubpolyIndex ) |
|||
{ |
|||
SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList().COutline( aSubpolyIndex ); |
|||
|
|||
outline.SetClosed( true ); |
|||
outline.Simplify(); |
|||
|
|||
m_cachedPoly.reset( new POLY_GRID_PARTITION( outline, 16 ) ); |
|||
} |
|||
|
|||
int SubpolyIndex() const |
|||
{ |
|||
return m_subpolyIndex; |
|||
} |
|||
|
|||
bool ContainsAnchor( const CN_ANCHOR_PTR anchor ) const |
|||
{ |
|||
return m_cachedPoly->ContainsPoint( anchor->Pos() ); |
|||
} |
|||
|
|||
bool ContainsPoint( const VECTOR2I p ) const |
|||
{ |
|||
return m_cachedPoly->ContainsPoint( p ); |
|||
} |
|||
|
|||
const BOX2I& BBox() const |
|||
{ |
|||
return m_cachedPoly->BBox(); |
|||
} |
|||
|
|||
virtual int AnchorCount() const; |
|||
virtual const VECTOR2I GetAnchor( int n ) const; |
|||
|
|||
private: |
|||
std::vector<VECTOR2I> m_testOutlinePoints; |
|||
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly; |
|||
int m_subpolyIndex; |
|||
}; |
|||
|
|||
|
|||
class CN_ZONE_LIST : public CN_LIST |
|||
{ |
|||
public: |
|||
CN_ZONE_LIST() {} |
|||
|
|||
const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone ) |
|||
{ |
|||
const auto& polys = zone->GetFilledPolysList(); |
|||
|
|||
std::vector<CN_ITEM*> rv; |
|||
|
|||
for( int j = 0; j < polys.OutlineCount(); j++ ) |
|||
{ |
|||
CN_ZONE* zitem = new CN_ZONE( zone, false, j ); |
|||
const auto& outline = zone->GetFilledPolysList().COutline( j ); |
|||
|
|||
for( int k = 0; k < outline.PointCount(); k++ ) |
|||
addAnchor( outline.CPoint( k ), zitem ); |
|||
|
|||
m_items.push_back( zitem ); |
|||
rv.push_back( zitem ); |
|||
SetDirty(); |
|||
} |
|||
|
|||
return rv; |
|||
}; |
|||
|
|||
template <class T> |
|||
void FindNearbyZones( BOX2I aBBox, T aFunc, bool aDirtyOnly = false ); |
|||
}; |
|||
|
|||
template <class T> |
|||
void CN_LIST::FindNearby( BOX2I aBBox, T aFunc, bool aDirtyOnly ) |
|||
{ |
|||
for( auto p : m_anchors ) |
|||
{ |
|||
if( p->Valid() && aBBox.Contains( p->Pos() ) ) |
|||
if( !aDirtyOnly || p->IsDirty() ) |
|||
aFunc( p ); |
|||
|
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
template <class T> |
|||
void CN_ZONE_LIST::FindNearbyZones( BOX2I aBBox, T aFunc, bool aDirtyOnly ) |
|||
{ |
|||
for( auto item : m_items ) |
|||
{ |
|||
auto zone = static_cast<CN_ZONE*> ( item ); |
|||
|
|||
if( aBBox.Intersects( zone->BBox() ) ) |
|||
{ |
|||
if( !aDirtyOnly || zone->Dirty() ) |
|||
{ |
|||
aFunc( zone ); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
template <class T> |
|||
void CN_LIST::FindNearby( VECTOR2I aPosition, int aDistMax, T aFunc, bool aDirtyOnly ) |
|||
{ |
|||
/* Search items in m_Candidates that position is <= aDistMax from aPosition |
|||
* (Rectilinear distance) |
|||
* m_Candidates is sorted by X then Y values, so a fast binary search is used |
|||
* to locate the "best" entry point in list |
|||
* The best entry is a pad having its m_Pos.x == (or near) aPosition.x |
|||
* All candidates are near this candidate in list |
|||
* So from this entry point, a linear search is made to find all candidates |
|||
*/ |
|||
|
|||
sort(); |
|||
|
|||
int idxmax = m_anchors.size() - 1; |
|||
|
|||
int delta = idxmax + 1; |
|||
int idx = 0; // Starting index is the beginning of list |
|||
|
|||
while( delta ) |
|||
{ |
|||
// Calculate half size of remaining interval to test. |
|||
// Ensure the computed value is not truncated (too small) |
|||
if( (delta & 1) && ( delta > 1 ) ) |
|||
delta++; |
|||
|
|||
delta /= 2; |
|||
|
|||
auto p = m_anchors[idx]; |
|||
|
|||
int dist = p->Pos().x - aPosition.x; |
|||
|
|||
if( std::abs( dist ) <= aDistMax ) |
|||
{ |
|||
break; // A good entry point is found. The list can be scanned from this point. |
|||
} |
|||
else if( p->Pos().x < aPosition.x ) // We should search after this point |
|||
{ |
|||
idx += delta; |
|||
|
|||
if( idx > idxmax ) |
|||
idx = idxmax; |
|||
} |
|||
else // We should search before this p |
|||
{ |
|||
idx -= delta; |
|||
|
|||
if( idx < 0 ) |
|||
idx = 0; |
|||
} |
|||
} |
|||
|
|||
/* Now explore the candidate list from the "best" entry point found |
|||
* (candidate "near" aPosition.x) |
|||
* We exp the list until abs(candidate->m_Point.x - aPosition.x) > aDistMashar* Currently a linear search is made because the number of candidates |
|||
* having the right X position is usually small |
|||
*/ |
|||
// search next candidates in list |
|||
VECTOR2I diff; |
|||
|
|||
for( int ii = idx; ii <= idxmax; ii++ ) |
|||
{ |
|||
auto& p = m_anchors[ii]; |
|||
diff = p->Pos() - aPosition;; |
|||
|
|||
if( std::abs( diff.x ) > aDistMax ) |
|||
break; // Exit: the distance is to long, we cannot find other candidates |
|||
|
|||
if( std::abs( diff.y ) > aDistMax ) |
|||
continue; // the y distance is to long, but we can find other candidates |
|||
|
|||
// We have here a good candidate: add it |
|||
if( p->Valid() ) |
|||
if( !aDirtyOnly || p->IsDirty() ) |
|||
aFunc( p ); |
|||
|
|||
|
|||
} |
|||
|
|||
// search previous candidates in list |
|||
for( int ii = idx - 1; ii >=0; ii-- ) |
|||
{ |
|||
auto& p = m_anchors[ii]; |
|||
diff = p->Pos() - aPosition; |
|||
|
|||
if( abs( diff.x ) > aDistMax ) |
|||
break; |
|||
|
|||
if( abs( diff.y ) > aDistMax ) |
|||
continue; |
|||
|
|||
// We have here a good candidate:add it |
|||
if( p->Valid() ) |
|||
if( !aDirtyOnly || p->IsDirty() ) |
|||
aFunc( p ); |
|||
|
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
class CN_CONNECTIVITY_ALGO |
|||
{ |
|||
public: |
|||
enum CLUSTER_SEARCH_MODE |
|||
{ |
|||
CSM_PROPAGATE, |
|||
CSM_CONNECTIVITY_CHECK, |
|||
CSM_RATSNEST |
|||
}; |
|||
|
|||
using CLUSTERS = std::vector<CN_CLUSTER_PTR>; |
|||
|
|||
private: |
|||
|
|||
bool m_lastSearchWithZones = false; |
|||
|
|||
class ITEM_MAP_ENTRY |
|||
{ |
|||
public: |
|||
ITEM_MAP_ENTRY( CN_ITEM* aItem = nullptr ) |
|||
{ |
|||
if( aItem ) |
|||
m_items.push_back( aItem ); |
|||
} |
|||
|
|||
void MarkItemsAsInvalid() |
|||
{ |
|||
for( auto item : m_items ) |
|||
{ |
|||
item->SetValid( false ); |
|||
} |
|||
} |
|||
|
|||
void Link( CN_ITEM* aItem ) |
|||
{ |
|||
m_items.push_back( aItem ); |
|||
} |
|||
|
|||
const std::list<CN_ITEM*> GetItems() const |
|||
{ |
|||
return m_items; |
|||
} |
|||
|
|||
std::list<CN_ITEM*> m_items; |
|||
}; |
|||
|
|||
|
|||
CN_PAD_LIST m_padList; |
|||
CN_TRACK_LIST m_trackList; |
|||
CN_VIA_LIST m_viaList; |
|||
CN_ZONE_LIST m_zoneList; |
|||
|
|||
using ITEM_MAP_PAIR = std::pair <const BOARD_CONNECTED_ITEM*, ITEM_MAP_ENTRY>; |
|||
|
|||
std::unordered_map<const BOARD_CONNECTED_ITEM*, ITEM_MAP_ENTRY> m_itemMap; |
|||
|
|||
CLUSTERS m_connClusters; |
|||
CLUSTERS m_ratsnestClusters; |
|||
std::vector<bool> m_dirtyNets; |
|||
|
|||
void searchConnections( bool aIncludeZones = false ); |
|||
|
|||
void update(); |
|||
void propagateConnections(); |
|||
|
|||
template <class Container, class BItem> |
|||
void add( Container& c, BItem brditem ) |
|||
{ |
|||
auto item = c.Add( brditem ); |
|||
|
|||
m_itemMap[ brditem ] = ITEM_MAP_ENTRY( item ); |
|||
} |
|||
|
|||
bool addConnectedItem( BOARD_CONNECTED_ITEM* aItem ); |
|||
bool isDirty() const; |
|||
|
|||
void markNetAsDirty( int aNet ); |
|||
void markItemNetAsDirty( const BOARD_ITEM* aItem ); |
|||
|
|||
public: |
|||
|
|||
CN_CONNECTIVITY_ALGO(); |
|||
~CN_CONNECTIVITY_ALGO(); |
|||
|
|||
ITEM_MAP_ENTRY& ItemEntry( const BOARD_CONNECTED_ITEM* aItem ) |
|||
{ |
|||
return m_itemMap[ aItem ]; |
|||
} |
|||
|
|||
bool IsNetDirty( int aNet ) const |
|||
{ |
|||
return m_dirtyNets[ aNet ]; |
|||
} |
|||
|
|||
void ClearDirtyFlags() |
|||
{ |
|||
for( auto i = m_dirtyNets.begin(); i != m_dirtyNets.end(); ++i ) |
|||
*i = false; |
|||
} |
|||
|
|||
void GetDirtyClusters( CLUSTERS& aClusters ) |
|||
{ |
|||
for( auto cl : m_ratsnestClusters ) |
|||
{ |
|||
int net = cl->OriginNet(); |
|||
|
|||
if( net >= 0 && m_dirtyNets[net] ) |
|||
aClusters.push_back( cl ); |
|||
} |
|||
} |
|||
|
|||
int NetCount() const |
|||
{ |
|||
return m_dirtyNets.size(); |
|||
} |
|||
|
|||
void Build( BOARD* aBoard ); |
|||
void Build( const std::vector<BOARD_ITEM*>& aItems ); |
|||
|
|||
void Clear(); |
|||
|
|||
bool Remove( BOARD_ITEM* aItem ); |
|||
bool Add( BOARD_ITEM* aItem ); |
|||
|
|||
const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode, const KICAD_T aTypes[], int aSingleNet ); |
|||
const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode ); |
|||
|
|||
void PropagateNets(); |
|||
void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands ); |
|||
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport ); |
|||
|
|||
const CLUSTERS& GetClusters(); |
|||
int GetUnconnectedCount(); |
|||
}; |
|||
|
|||
bool operator<( const CN_ANCHOR_PTR a, const CN_ANCHOR_PTR b ); |
|||
|
|||
#endif |
|||
1510
pcbnew/ratsnest_data.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,809 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2013-2016 CERN |
|||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* @author Maciej Suminski <maciej.suminski@cern.ch> |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include "common_actions.h"
|
|||
#include <tool/action_manager.h>
|
|||
#include <pcbnew_id.h>
|
|||
#include <layers_id_colors_and_visibility.h>
|
|||
#include <bitmaps.h>
|
|||
#include <wx/defs.h>
|
|||
#include <hotkeys.h>
|
|||
|
|||
// These members are static in class COMMON_ACTIONS: Build them here:
|
|||
|
|||
// Selection tool actions
|
|||
TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", |
|||
AS_GLOBAL, 0, |
|||
"", "", NULL, AF_ACTIVATE ); // No description, it is not supposed to be shown anywhere
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectionCursor( "pcbnew.InteractiveSelection.Cursor", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); // No description, it is not supposed to be shown anywhere
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectItem( "pcbnew.InteractiveSelection.SelectItem", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); // No description, it is not supposed to be shown anywhere
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::unselectItem( "pcbnew.InteractiveSelection.UnselectItem", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); // No description, it is not supposed to be shown anywhere
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectionClear( "pcbnew.InteractiveSelection.Clear", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); // No description, it is not supposed to be shown anywhere
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectConnection( "pcbnew.InteractiveSelection.SelectConnection", |
|||
AS_GLOBAL, 'U', |
|||
_( "Trivial Connection" ), _( "Selects a connection between two junctions." ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectCopper( "pcbnew.InteractiveSelection.SelectCopper", |
|||
AS_GLOBAL, 'I', |
|||
_( "Copper Connection" ), _( "Selects whole copper connection." ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectNet( "pcbnew.InteractiveSelection.SelectNet", |
|||
AS_GLOBAL, 0, |
|||
_( "Whole Net" ), _( "Selects all tracks & vias belonging to the same net." ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::selectSameSheet( "pcbnew.InteractiveSelection.SelectSameSheet", |
|||
AS_GLOBAL, 'P', |
|||
_( "Same Sheet" ), _( "Selects all modules and tracks in the same schematic sheet" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::find( "pcbnew.InteractiveSelection.Find", |
|||
AS_GLOBAL, 0, //TOOL_ACTION::LegacyHotKey( HK_FIND_ITEM ), // handled by wxWidgets
|
|||
_( "Find Item" ), _( "Searches the document for an item" ), find_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_GET_AND_MOVE_FOOTPRINT ) ); |
|||
|
|||
|
|||
// Edit tool actions
|
|||
TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_MODULE_WITH_MODEDIT ), |
|||
_( "Open in Footprint Editor" ), |
|||
_( "Opens the selected footprint in the Footprint Editor" ), |
|||
module_editor_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::copyPadToSettings( "pcbnew.InteractiveEdit.copyPadToSettings", |
|||
AS_GLOBAL, 0, |
|||
_( "Copy Pad Settings to Current Settings" ), |
|||
_( "Copies the properties of selected pad to the current template pad settings." ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::copySettingsToPads( "pcbnew.InteractiveEdit.copySettingsToPads", |
|||
AS_GLOBAL, 0, |
|||
_( "Copy Current Settings to Pads" ), |
|||
_( "Copies the current template pad settings to the selected pad(s)." ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::globalEditPads( "pcbnew.InteractiveEdit.globalPadEdit", |
|||
AS_GLOBAL, 0, |
|||
_( "Global Pad Edition" ), |
|||
_( "Changes pad properties globally." ), push_pad_settings_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MOVE_ITEM ), |
|||
_( "Move" ), _( "Moves the selected item(s)" ), move_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drag( "pcbnew.InteractiveEdit.dragItem", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DRAG_TRACK_KEEP_SLOPE ), |
|||
_( "Drag" ), _( "Drags the selected item(s)" ), drag_track_segment_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::duplicate( "pcbnew.InteractiveEdit.duplicate", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE_ITEM ), |
|||
_( "Duplicate" ), _( "Duplicates the selected item(s)" ), duplicate_module_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::duplicateIncrement( "pcbnew.InteractiveEdit.duplicateIncrementPads", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE_ITEM_AND_INCREMENT ), |
|||
_( "Duplicate" ), _( "Duplicates the selected item(s), incrementing pad numbers" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::moveExact( "pcbnew.InteractiveEdit.moveExact", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MOVE_ITEM_EXACT ), |
|||
_( "Move Exactly..." ), _( "Moves the selected item(s) by an exact amount" ), |
|||
move_module_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::createArray( "pcbnew.InteractiveEdit.createArray", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_CREATE_ARRAY ), |
|||
_( "Create Array" ), _( "Create array" ), array_module_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::rotateCw( "pcbnew.InteractiveEdit.rotateCw", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ROTATE_ITEM ), |
|||
_( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ), |
|||
rotate_cw_xpm, AF_NONE, (void*) 1 ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::rotateCcw( "pcbnew.InteractiveEdit.rotateCcw", |
|||
AS_GLOBAL, MD_SHIFT + 'R', |
|||
_( "Rotate Counter-clockwise" ), _( "Rotates selected item(s) counter-clockwise" ), |
|||
rotate_ccw_xpm, AF_NONE, (void*) -1 ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_FLIP_ITEM ), |
|||
_( "Flip" ), _( "Flips selected item(s)" ), swap_layer_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::mirror( "pcbnew.InteractiveEdit.mirror", |
|||
AS_GLOBAL, 0, |
|||
_( "Mirror" ), _( "Mirrors selected item" ), mirror_h_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.remove", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_BACK_SPACE ), |
|||
_( "Remove" ), _( "Deletes selected item(s)" ), delete_xpm, |
|||
AF_NONE, (void*) REMOVE_FLAGS::NORMAL ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::removeAlt( "pcbnew.InteractiveEdit.removeAlt", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DELETE ), |
|||
_( "Remove (Alternative)" ), _( "Deletes selected item(s)" ), delete_xpm, |
|||
AF_NONE, (void*) REMOVE_FLAGS::ALT ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::exchangeFootprints( "pcbnew.InteractiveEdit.ExchangeFootprints", |
|||
AS_GLOBAL, 0, |
|||
_( "Exchange Footprint(s)" ), _( "Change the footprint used for modules" ), |
|||
import_module_xpm ); |
|||
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_ITEM ), |
|||
_( "Properties..." ), _( "Displays item properties dialog" ), editor_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::editModifiedSelection( "pcbnew.InteractiveEdit.ModifiedSelection", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
|
|||
// Drawing tool actions
|
|||
TOOL_ACTION COMMON_ACTIONS::drawLine( "pcbnew.InteractiveDrawing.line", |
|||
AS_GLOBAL, 0, |
|||
_( "Draw Line" ), _( "Draw a line" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawCircle( "pcbnew.InteractiveDrawing.circle", |
|||
AS_GLOBAL, 0, |
|||
_( "Draw Circle" ), _( "Draw a circle" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawArc( "pcbnew.InteractiveDrawing.arc", |
|||
AS_GLOBAL, 0, |
|||
_( "Draw Arc" ), _( "Draw an arc" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::placeText( "pcbnew.InteractiveDrawing.text", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Text" ), _( "Add a text" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawDimension( "pcbnew.InteractiveDrawing.dimension", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Dimension" ), _( "Add a dimension" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawZone( "pcbnew.InteractiveDrawing.zone", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Filled Zone" ), _( "Add a filled zone" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawKeepout( "pcbnew.InteractiveDrawing.keepout", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Keepout Area" ), _( "Add a keepout area" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawZoneCutout( "pcbnew.InteractiveDrawing.zoneCutout", |
|||
AS_GLOBAL, 0, |
|||
_( "Add a Zone Cutout" ), _( "Add a cutout area of an existing zone" ), |
|||
add_zone_cutout_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drawSimilarZone( "pcbnew.InteractiveDrawing.similarZone", |
|||
AS_GLOBAL, 0, |
|||
_( "Add a Similar Zone" ), _( "Add a zone with the same settings as an existing zone" ), |
|||
add_zone_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::placeDXF( "pcbnew.InteractiveDrawing.placeDXF", |
|||
AS_GLOBAL, 0, |
|||
"Place DXF", "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::setAnchor( "pcbnew.InteractiveDrawing.setAnchor", |
|||
AS_GLOBAL, 0, |
|||
_( "Place the Footprint Anchor" ), _( "Place the footprint anchor" ), |
|||
NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::incWidth( "pcbnew.InteractiveDrawing.incWidth", |
|||
AS_CONTEXT, '+', |
|||
_( "Increase Line Width" ), _( "Increase the line width" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::decWidth( "pcbnew.InteractiveDrawing.decWidth", |
|||
AS_CONTEXT, '-', |
|||
_( "Decrease Line Width" ), _( "Decrease the line width" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::arcPosture( "pcbnew.InteractiveDrawing.arcPosture", |
|||
AS_CONTEXT, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_POSTURE ), |
|||
_( "Switch Arc Posture" ), _( "Switch the arc posture" ) ); |
|||
|
|||
|
|||
// View Controls
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomIn( "common.Control.zoomIn", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_IN ), |
|||
_( "Zoom In" ), "", zoom_in_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomOut( "common.Control.zoomOut", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_OUT ), |
|||
_( "Zoom Out" ), "", zoom_out_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomInCenter( "common.Control.zoomInCenter", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomOutCenter( "common.Control.zoomOutCenter", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomCenter( "common.Control.zoomCenter", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_CENTER ), |
|||
_( "Center" ), "", zoom_center_on_screen_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomFitScreen( "common.Control.zoomFitScreen", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_AUTO ), |
|||
_( "Zoom Auto" ), "", zoom_fit_in_page_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomPreset( "common.Control.zoomPreset", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
|
|||
// Display modes
|
|||
TOOL_ACTION COMMON_ACTIONS::trackDisplayMode( "pcbnew.Control.trackDisplayMode", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_DISPLAY_MODE ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::padDisplayMode( "pcbnew.Control.padDisplayMode", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::viaDisplayMode( "pcbnew.Control.viaDisplayMode", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneDisplayEnable( "pcbnew.Control.zoneDisplayEnable", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneDisplayDisable( "pcbnew.Control.zoneDisplayDisable", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneDisplayOutlines( "pcbnew.Control.zoneDisplayOutlines", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::highContrastMode( "pcbnew.Control.highContrastMode", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_HIGHCONTRAST_MODE ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::highContrastInc( "pcbnew.Control.highContrastInc", |
|||
AS_GLOBAL, '>', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::highContrastDec( "pcbnew.Control.highContrastDec", |
|||
AS_GLOBAL, '<', |
|||
"", "" ); |
|||
|
|||
|
|||
// Layer control
|
|||
TOOL_ACTION COMMON_ACTIONS::layerTop( "pcbnew.Control.layerTop", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COMPONENT ), |
|||
"", "", NULL, AF_NONE, (void*) F_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner1( "pcbnew.Control.layerInner1", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER1 ), |
|||
"", "", NULL, AF_NONE, (void*) In1_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner2( "pcbnew.Control.layerInner2", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER2 ), |
|||
"", "", NULL, AF_NONE, (void*) In2_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner3( "pcbnew.Control.layerInner3", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER3 ), |
|||
"", "", NULL, AF_NONE, (void*) In3_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner4( "pcbnew.Control.layerInner4", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER4 ), |
|||
"", "", NULL, AF_NONE, (void*) In4_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner5( "pcbnew.Control.layerInner5", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER5 ), |
|||
"", "", NULL, AF_NONE, (void*) In5_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerInner6( "pcbnew.Control.layerInner6", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER6 ), |
|||
"", "", NULL, AF_NONE, (void*) In6_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerBottom( "pcbnew.Control.layerBottom", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COPPER ), |
|||
"", "", NULL, AF_NONE, (void*) B_Cu ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerNext( "pcbnew.Control.layerNext", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_NEXT ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerPrev( "pcbnew.Control.layerPrev", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_PREVIOUS ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerToggle( "pcbnew.Control.layerToggle", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_THROUGH_VIA ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerAlphaInc( "pcbnew.Control.layerAlphaInc", |
|||
AS_GLOBAL, '}', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerAlphaDec( "pcbnew.Control.layerAlphaDec", |
|||
AS_GLOBAL, '{', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::layerChanged( "pcbnew.Control.layerChanged", |
|||
AS_GLOBAL, 0, |
|||
"", "", NULL, AF_NOTIFY ); |
|||
|
|||
|
|||
// Grid control
|
|||
TOOL_ACTION COMMON_ACTIONS::gridFast1( "common.Control.gridFast1", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_FASTGRID1 ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridFast2( "common.Control.gridFast2", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_FASTGRID2 ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridNext( "common.Control.gridNext", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_NEXT ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridPrev( "common.Control.gridPrev", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_PREVIOUS ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridSetOrigin( "common.Control.gridSetOrigin", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SET_GRID_ORIGIN ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridResetOrigin( "common.Control.gridResetOrigin", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_RESET_GRID_ORIGIN ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::gridPreset( "common.Control.gridPreset", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
// Track & via size control
|
|||
TOOL_ACTION COMMON_ACTIONS::trackWidthInc( "pcbnew.EditorControl.trackWidthInc", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_WIDTH_TO_NEXT ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::trackWidthDec( "pcbnew.EditorControl.trackWidthDec", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_WIDTH_TO_PREVIOUS ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::viaSizeInc( "pcbnew.EditorControl.viaSizeInc", |
|||
AS_GLOBAL, '\'', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::viaSizeDec( "pcbnew.EditorControl.viaSizeDec", |
|||
AS_GLOBAL, '\\', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::trackViaSizeChanged( "pcbnew.EditorControl.trackViaSizeChanged", |
|||
AS_GLOBAL, 0, |
|||
"", "", NULL, AF_NOTIFY ); |
|||
|
|||
|
|||
// Zone actions
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneFill( "pcbnew.EditorControl.zoneFill", |
|||
AS_GLOBAL, 0, |
|||
_( "Fill" ), _( "Fill zone(s)" ), fill_zone_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneFillAll( "pcbnew.EditorControl.zoneFillAll", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_FILL_OR_REFILL ), |
|||
_( "Fill All" ), _( "Fill all zones" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneUnfill( "pcbnew.EditorControl.zoneUnfill", |
|||
AS_GLOBAL, 0, |
|||
_( "Unfill" ), _( "Unfill zone(s)" ), zone_unfill_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneUnfillAll( "pcbnew.EditorControl.zoneUnfillAll", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_REMOVE_FILLED ), |
|||
_( "Unfill All" ), _( "Unfill all zones" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneMerge( "pcbnew.EditorControl.zoneMerge", |
|||
AS_GLOBAL, 0, |
|||
_( "Merge Zones" ), _( "Merge zones" ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoneDuplicate( "pcbnew.EditorControl.zoneDuplicate", |
|||
AS_GLOBAL, 0, |
|||
_( "Duplicate Zone onto Layer" ), _( "Duplicate zone outline onto a different layer" ), |
|||
zone_duplicate_xpm ); |
|||
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::placeTarget( "pcbnew.EditorControl.placeTarget", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Layer Alignment Target" ), _( "Add a layer alignment target" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::placeModule( "pcbnew.EditorControl.placeModule", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_MODULE ), |
|||
_( "Add Footprint" ), _( "Add a footprint" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::drillOrigin( "pcbnew.EditorControl.drillOrigin", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::crossProbeSchToPcb( "pcbnew.EditorControl.crossProbSchToPcb", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::toggleLock( "pcbnew.EditorControl.toggleLock", |
|||
AS_GLOBAL, 'L', |
|||
"Toggle Lock", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::lock( "pcbnew.EditorControl.lock", |
|||
AS_GLOBAL, 0, |
|||
_( "Lock" ), "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::unlock( "pcbnew.EditorControl.unlock", |
|||
AS_GLOBAL, 0, |
|||
_( "Unlock" ), "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::appendBoard( "pcbnew.EditorControl.appendBoard", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::highlightNet( "pcbnew.EditorControl.highlightNet", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::highlightNetCursor( "pcbnew.EditorControl.highlightNetCursor", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
|
|||
// Module editor tools
|
|||
TOOL_ACTION COMMON_ACTIONS::placePad( "pcbnew.ModuleEditor.placePad", |
|||
AS_GLOBAL, 0, |
|||
_( "Add Pad" ), _( "Add a pad" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads", |
|||
AS_GLOBAL, 0, |
|||
_( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::copyItems( "pcbnew.ModuleEditor.copyItems", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_COPY_ITEM ), |
|||
_( "Copy" ), _( "Copy items" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::pasteItems( "pcbnew.ModuleEditor.pasteItems", |
|||
AS_GLOBAL, MD_CTRL + int( 'V' ), |
|||
_( "Paste" ), _( "Paste items" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::moduleEdgeOutlines( "pcbnew.ModuleEditor.graphicOutlines", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::moduleTextOutlines( "pcbnew.ModuleEditor.textOutlines", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
// Pad tools
|
|||
TOOL_ACTION COMMON_ACTIONS::copyPadSettings( |
|||
"pcbnew.PadTool.CopyPadSettings", |
|||
AS_GLOBAL, 0, |
|||
_( "Copy Pad Settings" ), _( "Copy current pad's settings to the board design settings" ), |
|||
copy_pad_settings_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::applyPadSettings( |
|||
"pcbnew.PadTool.ApplyPadSettings", |
|||
AS_GLOBAL, 0, |
|||
_( "Apply Pad Settings" ), _( "Copy the board design settings pad properties to the current pad" ), |
|||
apply_pad_settings_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::pushPadSettings( |
|||
"pcbnew.PadTool.PushPadSettings", |
|||
AS_GLOBAL, 0, |
|||
_( "Push Pad Settings" ), _( "Copy the current pad settings to other pads" ), |
|||
push_pad_settings_xpm ); |
|||
|
|||
// Cursor control
|
|||
TOOL_ACTION COMMON_ACTIONS::cursorUp( "pcbnew.Control.cursorUp", |
|||
AS_GLOBAL, WXK_UP, "", "", NULL, AF_NONE, (void*) CURSOR_UP ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorDown( "pcbnew.Control.cursorDown", |
|||
AS_GLOBAL, WXK_DOWN, "", "" , NULL, AF_NONE, (void*) CURSOR_DOWN ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorLeft( "pcbnew.Control.cursorLeft", |
|||
AS_GLOBAL, WXK_LEFT, "", "" , NULL, AF_NONE, (void*) CURSOR_LEFT ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorRight( "pcbnew.Control.cursorRight", |
|||
AS_GLOBAL, WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) CURSOR_RIGHT ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::cursorUpFast( "pcbnew.Control.cursorUpFast", |
|||
AS_GLOBAL, MD_CTRL + WXK_UP, "", "", NULL, AF_NONE, (void*) ( CURSOR_UP | CURSOR_FAST_MOVE ) ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorDownFast( "pcbnew.Control.cursorDownFast", |
|||
AS_GLOBAL, MD_CTRL + WXK_DOWN, "", "" , NULL, AF_NONE, (void*) ( CURSOR_DOWN | CURSOR_FAST_MOVE ) ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorLeftFast( "pcbnew.Control.cursorLeftFast", |
|||
AS_GLOBAL, MD_CTRL + WXK_LEFT, "", "" , NULL, AF_NONE, (void*) ( CURSOR_LEFT | CURSOR_FAST_MOVE ) ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorRightFast( "pcbnew.Control.cursorRightFast", |
|||
AS_GLOBAL, MD_CTRL + WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) ( CURSOR_RIGHT | CURSOR_FAST_MOVE ) ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::cursorClick( "pcbnew.Control.cursorClick", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_LEFT_CLICK ), |
|||
"", "", NULL, AF_NONE, (void*) CURSOR_CLICK ); |
|||
TOOL_ACTION COMMON_ACTIONS::cursorDblClick( "pcbnew.Control.cursorDblClick", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_LEFT_DCLICK ), |
|||
"", "", NULL, AF_NONE, (void*) CURSOR_DBL_CLICK ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::panUp( "pcbnew.Control.panUp", |
|||
AS_GLOBAL, MD_SHIFT + WXK_UP, "", "", NULL, AF_NONE, (void*) CURSOR_UP ); |
|||
TOOL_ACTION COMMON_ACTIONS::panDown( "pcbnew.Control.panDown", |
|||
AS_GLOBAL, MD_SHIFT + WXK_DOWN, "", "" , NULL, AF_NONE, (void*) CURSOR_DOWN ); |
|||
TOOL_ACTION COMMON_ACTIONS::panLeft( "pcbnew.Control.panLeft", |
|||
AS_GLOBAL, MD_SHIFT + WXK_LEFT, "", "" , NULL, AF_NONE, (void*) CURSOR_LEFT ); |
|||
TOOL_ACTION COMMON_ACTIONS::panRight( "pcbnew.Control.panRight", |
|||
AS_GLOBAL, MD_SHIFT + WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) CURSOR_RIGHT ); |
|||
|
|||
// Miscellaneous
|
|||
TOOL_ACTION COMMON_ACTIONS::selectionTool( "pcbnew.Control.selectionTool", |
|||
AS_GLOBAL, 0, |
|||
"", "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::zoomTool( "pcbnew.Control.zoomTool", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_SELECTION ), |
|||
_( "Zoom to Selection" ), "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::pickerTool( "pcbnew.Picker", AS_GLOBAL, 0, "", "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::resetCoords( "pcbnew.Control.resetCoords", |
|||
AS_GLOBAL, ' ', |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::switchCursor( "pcbnew.Control.switchCursor", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::switchUnits( "pcbnew.Control.switchUnits", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_UNITS ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::deleteItemCursor( "pcbnew.Control.deleteItemCursor", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::showHelp( "pcbnew.Control.showHelp", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_HELP ), |
|||
"", "" ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::toBeDone( "pcbnew.Control.toBeDone", |
|||
AS_GLOBAL, 0, // dialog saying it is not implemented yet
|
|||
"", "" ); // so users are aware of that
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::showLocalRatsnest( "pcbnew.Control.showLocalRatsnest", |
|||
AS_GLOBAL, 0, |
|||
"", "" ); |
|||
|
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateSingle( "pcbnew.InteractiveRouter.SingleTrack", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_TRACK ), |
|||
_( "Interactive Router (Single Tracks)" ), |
|||
_( "Run push & shove router (single tracks)" ), ps_router_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateDiffPair( "pcbnew.InteractiveRouter.DiffPair", |
|||
AS_GLOBAL, '6', |
|||
_( "Interactive Router (Differential Pairs)" ), |
|||
_( "Run push & shove router (differential pairs)" ), ps_diff_pair_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateSettingsDialog( "pcbnew.InteractiveRouter.SettingsDialog", |
|||
AS_GLOBAL, 0, |
|||
_( "Interactive Router Settings" ), |
|||
_( "Open Interactive Router settings" ), NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateDpDimensionsDialog( "pcbnew.InteractiveRouter.DpDimensionsDialog", |
|||
AS_GLOBAL, 0, |
|||
_( "Differential Pair Dimension settings" ), |
|||
_( "Open Differential Pair Dimension settings" ), ps_diff_pair_gap_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateTuneSingleTrace( "pcbnew.LengthTuner.TuneSingleTrack", |
|||
AS_GLOBAL, '7', |
|||
_( "Tune length of a single track" ), "", ps_tune_length_xpm, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPair( "pcbnew.LengthTuner.TuneDiffPair", |
|||
AS_GLOBAL, '8', |
|||
_( "Tune length of a differential pair" ), "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPairSkew( "pcbnew.LengthTuner.TuneDiffPairSkew", |
|||
AS_GLOBAL, '9', |
|||
_( "Tune skew of a differential pair" ), "", NULL, AF_ACTIVATE ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::routerInlineDrag( "pcbnew.InteractiveRouter.InlineDrag", |
|||
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DRAG_TRACK_KEEP_SLOPE ), |
|||
_( "Drag Track/Via" ), _( "Drags tracks and vias without breaking connections" ), |
|||
drag_track_segment_xpm ); |
|||
|
|||
// Point editor
|
|||
TOOL_ACTION COMMON_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner", |
|||
AS_GLOBAL, 0, |
|||
_( "Create Corner" ), _( "Create a corner" ), add_corner_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::pointEditorRemoveCorner( "pcbnew.PointEditor.removeCorner", |
|||
AS_GLOBAL, 0, |
|||
_( "Remove Corner" ), _( "Remove corner" ), delete_xpm ); |
|||
|
|||
// Placement tool
|
|||
TOOL_ACTION COMMON_ACTIONS::alignTop( "pcbnew.Place.alignTop", |
|||
AS_GLOBAL, 0, |
|||
_( "Align to Top" ), |
|||
_( "Aligns selected items to the top edge" ), up_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::alignBottom( "pcbnew.Place.alignBottom", |
|||
AS_GLOBAL, 0, |
|||
_( "Align to Bottom" ), |
|||
_( "Aligns selected items to the bottom edge" ), down_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::alignLeft( "pcbnew.Place.alignLeft", |
|||
AS_GLOBAL, 0, |
|||
_( "Align to Left" ), |
|||
_( "Aligns selected items to the left edge" ), left_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::alignRight( "pcbnew.Place.alignRight", |
|||
AS_GLOBAL, 0, |
|||
_( "Align to Right" ), |
|||
_( "Aligns selected items to the right edge" ), right_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::distributeHorizontally( "pcbnew.Place.distributeHorizontally", |
|||
AS_GLOBAL, 0, |
|||
_( "Distribute Horizontally" ), |
|||
_( "Distributes selected items along the horizontal axis" ), distribute_horizontal_xpm ); |
|||
|
|||
TOOL_ACTION COMMON_ACTIONS::distributeVertically( "pcbnew.Place.distributeVertically", |
|||
AS_GLOBAL, 0, |
|||
_( "Distribute Vertically" ), |
|||
_( "Distributes selected items along the vertical axis" ), distribute_vertical_xpm ); |
|||
|
|||
|
|||
boost::optional<TOOL_EVENT> COMMON_ACTIONS::TranslateLegacyId( int aId ) |
|||
{ |
|||
switch( aId ) |
|||
{ |
|||
case ID_PCB_MODULE_BUTT: |
|||
return COMMON_ACTIONS::placeModule.MakeEvent(); |
|||
|
|||
case ID_TRACK_BUTT: |
|||
return COMMON_ACTIONS::routerActivateSingle.MakeEvent(); |
|||
|
|||
case ID_DIFF_PAIR_BUTT: |
|||
return COMMON_ACTIONS::routerActivateDiffPair.MakeEvent(); |
|||
|
|||
case ID_TUNE_SINGLE_TRACK_LEN_BUTT: |
|||
return COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent(); |
|||
|
|||
case ID_TUNE_DIFF_PAIR_LEN_BUTT: |
|||
return COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent(); |
|||
|
|||
case ID_TUNE_DIFF_PAIR_SKEW_BUTT: |
|||
return COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent(); |
|||
|
|||
case ID_MENU_INTERACTIVE_ROUTER_SETTINGS: |
|||
return COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent(); |
|||
|
|||
case ID_MENU_DIFF_PAIR_DIMENSIONS: |
|||
return COMMON_ACTIONS::routerActivateDpDimensionsDialog.MakeEvent(); |
|||
|
|||
case ID_PCB_ZONES_BUTT: |
|||
return COMMON_ACTIONS::drawZone.MakeEvent(); |
|||
|
|||
case ID_PCB_KEEPOUT_AREA_BUTT: |
|||
return COMMON_ACTIONS::drawKeepout.MakeEvent(); |
|||
|
|||
case ID_PCB_ADD_LINE_BUTT: |
|||
case ID_MODEDIT_LINE_TOOL: |
|||
return COMMON_ACTIONS::drawLine.MakeEvent(); |
|||
|
|||
case ID_PCB_CIRCLE_BUTT: |
|||
case ID_MODEDIT_CIRCLE_TOOL: |
|||
return COMMON_ACTIONS::drawCircle.MakeEvent(); |
|||
|
|||
case ID_PCB_ARC_BUTT: |
|||
case ID_MODEDIT_ARC_TOOL: |
|||
return COMMON_ACTIONS::drawArc.MakeEvent(); |
|||
|
|||
case ID_PCB_ADD_TEXT_BUTT: |
|||
case ID_MODEDIT_TEXT_TOOL: |
|||
return COMMON_ACTIONS::placeText.MakeEvent(); |
|||
|
|||
case ID_PCB_DIMENSION_BUTT: |
|||
return COMMON_ACTIONS::drawDimension.MakeEvent(); |
|||
|
|||
case ID_PCB_MIRE_BUTT: |
|||
return COMMON_ACTIONS::placeTarget.MakeEvent(); |
|||
|
|||
case ID_MODEDIT_PAD_TOOL: |
|||
return COMMON_ACTIONS::placePad.MakeEvent(); |
|||
|
|||
case ID_GEN_IMPORT_DXF_FILE: |
|||
return COMMON_ACTIONS::placeDXF.MakeEvent(); |
|||
|
|||
case ID_MODEDIT_ANCHOR_TOOL: |
|||
return COMMON_ACTIONS::setAnchor.MakeEvent(); |
|||
|
|||
case ID_PCB_PLACE_GRID_COORD_BUTT: |
|||
case ID_MODEDIT_PLACE_GRID_COORD: |
|||
return COMMON_ACTIONS::gridSetOrigin.MakeEvent(); |
|||
|
|||
case ID_ZOOM_IN: // toolbar button "Zoom In"
|
|||
return COMMON_ACTIONS::zoomInCenter.MakeEvent(); |
|||
|
|||
case ID_ZOOM_OUT: // toolbar button "Zoom In"
|
|||
return COMMON_ACTIONS::zoomOutCenter.MakeEvent(); |
|||
|
|||
case ID_ZOOM_PAGE: // toolbar button "Fit on Screen"
|
|||
return COMMON_ACTIONS::zoomFitScreen.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_TRACKS_SKETCH: |
|||
return COMMON_ACTIONS::trackDisplayMode.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_PADS_SKETCH: |
|||
return COMMON_ACTIONS::padDisplayMode.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_VIAS_SKETCH: |
|||
return COMMON_ACTIONS::viaDisplayMode.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_ZONES: |
|||
return COMMON_ACTIONS::zoneDisplayEnable.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_ZONES_DISABLE: |
|||
return COMMON_ACTIONS::zoneDisplayDisable.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_ZONES_OUTLINES_ONLY: |
|||
return COMMON_ACTIONS::zoneDisplayOutlines.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_MODULE_EDGE_SKETCH: |
|||
return COMMON_ACTIONS::moduleEdgeOutlines.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_MODULE_TEXT_SKETCH: |
|||
return COMMON_ACTIONS::moduleTextOutlines.MakeEvent(); |
|||
|
|||
case ID_TB_OPTIONS_SHOW_HIGH_CONTRAST_MODE: |
|||
return COMMON_ACTIONS::highContrastMode.MakeEvent(); |
|||
|
|||
case ID_FIND_ITEMS: |
|||
return COMMON_ACTIONS::find.MakeEvent(); |
|||
|
|||
case ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST: |
|||
return COMMON_ACTIONS::findMove.MakeEvent(); |
|||
|
|||
case ID_NO_TOOL_SELECTED: |
|||
return COMMON_ACTIONS::selectionTool.MakeEvent(); |
|||
|
|||
case ID_ZOOM_SELECTION: |
|||
return COMMON_ACTIONS::zoomTool.MakeEvent(); |
|||
|
|||
case ID_PCB_DELETE_ITEM_BUTT: |
|||
case ID_MODEDIT_DELETE_TOOL: |
|||
return COMMON_ACTIONS::deleteItemCursor.MakeEvent(); |
|||
|
|||
case ID_PCB_PLACE_OFFSET_COORD_BUTT: |
|||
return COMMON_ACTIONS::drillOrigin.MakeEvent(); |
|||
|
|||
case ID_PCB_HIGHLIGHT_BUTT: |
|||
return COMMON_ACTIONS::highlightNetCursor.MakeEvent(); |
|||
|
|||
case ID_APPEND_FILE: |
|||
return COMMON_ACTIONS::appendBoard.MakeEvent(); |
|||
|
|||
case ID_PCB_SHOW_1_RATSNEST_BUTT: |
|||
return COMMON_ACTIONS::showLocalRatsnest.MakeEvent(); |
|||
} |
|||
|
|||
return boost::optional<TOOL_EVENT>(); |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue