New connectivity algorithm.

This commit is contained in:
Tomasz Włostowski 2017-03-22 14:43:10 +01:00
parent eaba60b89a
commit 9ad886344b
50 changed files with 4752 additions and 2121 deletions

View File

@ -1138,6 +1138,7 @@ void EDA_DRAW_FRAME::UseGalCanvas( bool aEnable )
gal->SetGridOrigin( VECTOR2D( GetGridOrigin() ) );
// Transfer EDA_DRAW_PANEL settings
GetGalCanvas()->GetViewControls()->EnableCursorWarping( !m_canvas->GetEnableZoomNoCenter() );
GetGalCanvas()->GetViewControls()->EnableMousewheelPan( m_canvas->GetEnableMousewheelPan() );
}
@ -1365,4 +1366,3 @@ void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
break;
}
}

View File

@ -55,14 +55,6 @@ using namespace hed;
#endif
void NODE::updateLayers()
{
assert( m_layers.none() );
for( const BOARD_CONNECTED_ITEM* item : m_parents )
m_layers |= item->GetLayerSet();
}
//#define DEBUG_HE
#ifdef DEBUG_HE
@ -402,12 +394,11 @@ std::list<NODE_PTR>* TRIANGULATION::GetNodes() const
#endif
std::list<EDGE_PTR>* TRIANGULATION::GetEdges( bool aSkipBoundaryEdges ) const
void TRIANGULATION::GetEdges( std::list<EDGE_PTR>& aEdges, bool aSkipBoundaryEdges ) const
{
// collect all arcs (one half edge for each arc)
// (boundary edges are also collected).
std::list<EDGE_PTR>::const_iterator it;
std::list<EDGE_PTR>* elist = new std::list<EDGE_PTR>;
for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it )
{
@ -419,13 +410,13 @@ std::list<EDGE_PTR>* TRIANGULATION::GetEdges( bool aSkipBoundaryEdges ) const
if( ( !twinedge && !aSkipBoundaryEdges )
|| ( twinedge && ( (size_t) edge.get() > (size_t) twinedge.get() ) ) )
elist->push_front( edge );
{
aEdges.push_front( edge );
}
edge = edge->GetNextEdgeInFace();
}
}
return elist;
}
@ -613,7 +604,8 @@ void TRIANGULATION::OptimizeDelaunay()
// Collect all interior edges (one half edge for each arc)
bool skip_boundary_edges = true;
std::list<EDGE_PTR>* elist = GetEdges( skip_boundary_edges );
std::list<EDGE_PTR> elist;
GetEdges( elist, skip_boundary_edges );
// Assumes that elist has only one half-edge for each arc.
bool cycling_check = true;
@ -624,7 +616,7 @@ void TRIANGULATION::OptimizeDelaunay()
{
optimal = true;
for( it = elist->begin(); it != elist->end(); ++it )
for( it = elist.begin(); it != elist.end(); ++it )
{
EDGE_PTR edge = *it;
@ -637,8 +629,6 @@ void TRIANGULATION::OptimizeDelaunay()
}
}
}
delete elist;
}

View File

@ -220,7 +220,7 @@ void ACTION_MANAGER::UpdateHotKeys()
++global_actions_cnt;
}
assert( global_actions_cnt <= 1 );
// assert( global_actions_cnt <= 1 );
}
#endif /* not NDEBUG */
}

View File

@ -1,6 +1,6 @@
update=13/08/2016 16:32:14
update=pią, 7 paź 2016, 14:28:36
version=1
last_client=kicad
last_client=eeschema
[general]
version=1
RootSch=
@ -29,4 +29,84 @@ version=1
NetIExt=net
[eeschema]
version=1
LibDir=
LibDir=/home/twl/Kicad-dev/kicad-library/library
[eeschema/libraries]
LibName1=74xgxx
LibName2=74xx
LibName3=ac-dc
LibName4=actel
LibName5=AD8051
LibName6=adc-dac
LibName7=Altera
LibName8=analog_devices
LibName9=analog_switches
LibName10=atmel
LibName11=audio
LibName12=bbd
LibName13=brooktre
LibName14=cmos4000
LibName15=cmos_ieee
LibName16=conn
LibName17=contrib
LibName18=cypress
LibName19=dc-dc
LibName20=device
LibName21=digital-audio
LibName22=diode
LibName23=display
LibName24=dsp
LibName25=elec-unifil
LibName26=ESD_Protection
LibName27=ftdi
LibName28=gennum
LibName29=graphic
LibName30=hc11
LibName31=intel
LibName32=interface
LibName33=ir
LibName34=Lattice
LibName35=linear
LibName36=logo
LibName37=maxim
LibName38=memory
LibName39=microchip
LibName40=microchip_dspic33dsc
LibName41=microchip_pic10mcu
LibName42=microchip_pic12mcu
LibName43=microchip_pic16mcu
LibName44=microchip_pic18mcu
LibName45=microchip_pic32mcu
LibName46=microcontrollers
LibName47=motor_drivers
LibName48=motorola
LibName49=msp430
LibName50=nordicsemi
LibName51=nxp_armmcu
LibName52=onsemi
LibName53=opto
LibName54=Oscillators
LibName55=philips
LibName56=power
LibName57=powerint
LibName58=Power_Management
LibName59=references
LibName60=regul
LibName61=relays
LibName62=rfcom
LibName63=sensors
LibName64=silabs
LibName65=siliconi
LibName66=stm8
LibName67=stm32
LibName68=supertex
LibName69=switches
LibName70=texas
LibName71=transf
LibName72=transistors
LibName73=ttl_ieee
LibName74=valves
LibName75=video
LibName76=Worldsemi
LibName77=Xicor
LibName78=xilinx
LibName79=Zilog

View File

@ -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

View File

@ -601,6 +601,7 @@ public:
}
const VECTOR2I PointAlong( int aPathLength ) const;
const SHAPE_LINE_CHAIN RemoveHoles( ) const;
private:
/// array of vertices

View File

@ -37,9 +37,6 @@
#include <iomanip>
#include <wx/log.h>
#include <cstdio>
#include <string>
/**
* The class PROF_COUNTER is a small class to help profiling.
* It allows the calculation of the elapsed time (in millisecondes) between
@ -154,41 +151,4 @@ private:
*/
unsigned GetRunningMicroSecs();
class PROF_COUNTER
{
public:
PROF_COUNTER(const std::string& name, bool autostart = true)
{
m_name = name;
m_running= false;
if(autostart)
start();
}
void start()
{
m_running = true;
prof_start(&m_cnt);
}
void stop()
{
if(!m_running)
return;
m_running=false;
prof_end(&m_cnt);
}
void show()
{
stop();
fprintf(stderr,"%s took %.1f milliseconds.\n", m_name.c_str(), (double)m_cnt.msecs());
}
private:
std::string m_name;
prof_counter m_cnt;
bool m_running;
};
#endif

View File

@ -2,21 +2,21 @@
* Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT,
* Applied Mathematics, Norway.
*
* Contact information: E-mail: tor.dokken@sintef.no
* SINTEF ICT, Department of Applied Mathematics,
* P.O. Box 124 Blindern,
* 0314 Oslo, Norway.
* Contact information: E-mail: tor.dokken@sintef.no
* SINTEF ICT, Department of Applied Mathematics,
* P.O. Box 124 Blindern,
* 0314 Oslo, Norway.
*
* This file is part of TTL.
*
* TTL is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* License, or (at your option) any later version.
*
* TTL 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
* TTL 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
@ -34,7 +34,7 @@
* disclosing the source code of your own applications.
*
* This file may be used in accordance with the terms contained in a
* written agreement between you and SINTEF ICT.
* written agreement between you and SINTEF ICT.
*/
#ifndef _HALF_EDGE_DART_
@ -69,6 +69,7 @@ public:
DART( const EDGE_PTR& aEdge, bool aDir = true )
{
m_edge = aEdge;
assert ( m_edge );
m_dir = aDir;
}
@ -76,6 +77,7 @@ public:
DART( const DART& aDart )
{
m_edge = aDart.m_edge;
assert ( m_edge );
m_dir = aDart.m_dir;
}
@ -91,6 +93,7 @@ public:
return *this;
m_edge = aDart.m_edge;
assert ( m_edge );
m_dir = aDart.m_dir;
return *this;
@ -121,11 +124,13 @@ public:
if( m_dir )
{
m_edge = m_edge->GetNextEdgeInFace()->GetNextEdgeInFace();
assert ( m_edge );
m_dir = false;
}
else
{
m_edge = m_edge->GetNextEdgeInFace();
assert ( m_edge );
m_dir = true;
}
@ -138,6 +143,7 @@ public:
if( m_edge->GetTwinEdge() )
{
m_edge = m_edge->GetTwinEdge();
assert ( m_edge );
m_dir = !m_dir;
}
@ -150,6 +156,7 @@ public:
void Init( const EDGE_PTR& aEdge, bool aDir = true )
{
m_edge = aEdge;
assert(m_edge);
m_dir = aDir;
}

View File

@ -42,8 +42,8 @@
#ifndef _HE_TRIANG_H_
#define _HE_TRIANG_H_
//#define TTL_USE_NODE_ID // Each node gets it's own unique id
//#define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false)
#define TTL_USE_NODE_ID // Each node gets it's own unique id
#define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false)
#include <list>
#include <unordered_set>
@ -53,8 +53,10 @@
#include <ttl/ttl_util.h>
#include <memory>
#include <layers_id_colors_and_visibility.h>
#include <math/vector2d.h>
class BOARD_CONNECTED_ITEM;
class CN_CLUSTER;
namespace ttl
{
@ -103,37 +105,25 @@ protected:
/// Node coordinates
const int m_x, m_y;
/// Tag for quick connection resolution
int m_tag;
/// Whether it the node can be a target for ratsnest lines
bool m_noline;
/// List of board items that share this node
std::unordered_set<const BOARD_CONNECTED_ITEM*> m_parents;
/// Layers that are occupied by this node
LSET m_layers;
/// Recomputes the layers used by this node
void updateLayers();
public:
/// Constructor
NODE( int aX = 0, int aY = 0 ) :
NODE( int aX = 0, int aY = 0, std::shared_ptr<CN_CLUSTER> aCluster = nullptr ) :
#ifdef TTL_USE_NODE_FLAG
m_flag( false ),
#endif
#ifdef TTL_USE_NODE_ID
m_id( id_count++ ),
#endif
m_x( aX ), m_y( aY ), m_tag( -1 ), m_noline( false )
m_x( aX ), m_y( aY )
{
m_layers.reset();
}
/// Destructor
~NODE() {}
~NODE() {
}
const VECTOR2D Pos() const { return VECTOR2D( m_x, m_y ); }
/// Returns the x-coordinate
inline int GetX() const
@ -147,32 +137,19 @@ public:
return m_y;
}
/// Returns tag, common identifier for connected nodes
inline int GetTag() const
inline VECTOR2I GetPos() 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;
return VECTOR2I( m_x, m_y );
}
#ifdef TTL_USE_NODE_ID
/// Returns the id (TTL_USE_NODE_ID must be defined)
inline void SetId( int aId )
{
m_id = aId;
}
inline int Id() const
{
return m_id;
@ -192,39 +169,6 @@ public:
return m_flag;
}
#endif
inline unsigned int GetRefCount() const
{
return m_parents.size();
}
inline void AddParent( const BOARD_CONNECTED_ITEM* aParent )
{
m_parents.insert( aParent );
m_layers.reset(); // mark as needs updating
}
inline void RemoveParent( const BOARD_CONNECTED_ITEM* aParent )
{
auto it = m_parents.find( aParent );
if( it != m_parents.end() )
{
m_parents.erase( it );
m_layers.reset(); // mark as needs updating
}
}
const LSET& GetLayers()
{
if( m_layers.none() )
updateLayers();
return m_layers;
}
// Tag used for unconnected items.
static const int TAG_UNCONNECTED = -1;
};
@ -236,23 +180,14 @@ class EDGE
{
public:
/// Constructor
EDGE() : m_weight( 0 ), m_isLeadingEdge( false )
EDGE() : m_isLeadingEdge( false )
{
}
/// Destructor
virtual ~EDGE()
{
}
/// Returns tag, common identifier for connected nodes
inline int GetTag() const
{
int tag = GetSourceNode()->GetTag();
if( tag >= 0 )
return tag;
return GetTargetNode()->GetTag();
}
/// Sets the source node
@ -288,6 +223,9 @@ public:
/// Returns the twin edge
inline EDGE_PTR GetTwinEdge() const
{
if( m_twinEdge.expired() )
return nullptr;
return m_twinEdge.lock();
}
@ -299,6 +237,7 @@ public:
/// Returns the next edge in face
inline const EDGE_PTR& GetNextEdgeInFace() const
{
assert ( m_nextEdgeInFace );
return m_nextEdgeInFace;
}
@ -314,16 +253,6 @@ public:
return m_nextEdgeInFace->GetSourceNode();
}
inline void SetWeight( unsigned int weight )
{
m_weight = weight;
}
inline unsigned int GetWeight() const
{
return m_weight;
}
void Clear()
{
m_sourceNode.reset();
@ -340,41 +269,9 @@ protected:
NODE_PTR m_sourceNode;
EDGE_WEAK_PTR m_twinEdge;
EDGE_PTR m_nextEdgeInFace;
unsigned int m_weight;
bool m_isLeadingEdge;
};
/**
* \class EDGE_MST
* \brief \b Specialization of %EDGE class to be used for Minimum Spanning Tree algorithm.
*/
class EDGE_MST : public EDGE
{
private:
NODE_PTR m_target;
public:
EDGE_MST( const NODE_PTR& aSource, const NODE_PTR& aTarget, unsigned int aWeight = 0 ) :
m_target( aTarget )
{
m_sourceNode = aSource;
m_weight = aWeight;
}
/// @copydoc Edge::setSourceNode()
virtual const NODE_PTR& GetTargetNode() const override
{
return m_target;
}
private:
EDGE_MST( const EDGE& aEdge )
{
assert( false );
}
};
class DART; // Forward declaration (class in this namespace)
/**
@ -500,7 +397,7 @@ public:
}
/// Returns a list of half-edges (one half-edge for each arc)
std::list<EDGE_PTR>* GetEdges( bool aSkipBoundaryEdges = false ) const;
void GetEdges( std::list<EDGE_PTR>& aEdges, bool aSkipBoundaryEdges = false ) const;
#ifdef TTL_USE_NODE_FLAG
/// Sets flag in all the nodes

View File

@ -566,7 +566,7 @@ public:
* search connections between tracks and pads and propagate pad net codes to the track
* segments.
*/
void RecalculateAllTracksNetcode();
void ComputeLegacyConnections ();
/* Functions relative to Undo/redo commands:
*/

View File

@ -220,6 +220,8 @@ set( PCBNEW_CLASS_SRCS
class_pcb_layer_box_selector.cpp
clean.cpp
connect.cpp
connectivity.cpp
connectivity_algo.cpp
controle.cpp
dimension.cpp
cross-probing.cpp

View File

@ -30,6 +30,7 @@
#include <view/view.h>
#include <board_commit.h>
#include <tools/pcb_tool.h>
#include <connectivity.h>
#include <functional>
using namespace std::placeholders;
@ -60,7 +61,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry )
KIGFX::VIEW* view = m_toolMgr->GetView();
BOARD* board = (BOARD*) m_toolMgr->GetModel();
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame();
RN_DATA* ratsnest = board->GetRatsnest();
auto connectivity = board->GetConnectivity();
std::set<EDA_ITEM*> savedModules;
if( Empty() )
@ -262,7 +263,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry )
}
view->Update ( boardItem );
ratsnest->Update( boardItem );
connectivity->Update( boardItem );
break;
}
@ -278,7 +279,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry )
if( TOOL_MANAGER* toolMgr = frame->GetToolManager() )
toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
frame->OnModify();
frame->UpdateMsgPanel();
@ -307,7 +308,7 @@ void BOARD_COMMIT::Revert()
PICKED_ITEMS_LIST undoList;
KIGFX::VIEW* view = m_toolMgr->GetView();
BOARD* board = (BOARD*) m_toolMgr->GetModel();
RN_DATA* ratsnest = board->GetRatsnest();
auto connectivity = board->GetConnectivity();
for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it )
{
@ -325,7 +326,7 @@ void BOARD_COMMIT::Revert()
}
view->Remove( item );
ratsnest->Remove( item );
connectivity->Remove( item );
break;
case CHT_REMOVE:
@ -337,7 +338,7 @@ void BOARD_COMMIT::Revert()
}
view->Add( item );
ratsnest->Add( item );
connectivity->Add( item );
break;
case CHT_MODIFY:
@ -349,7 +350,7 @@ void BOARD_COMMIT::Revert()
}
view->Remove( item );
ratsnest->Remove( item );
connectivity->Remove( item );
item->SwapData( copy );
@ -365,7 +366,7 @@ void BOARD_COMMIT::Revert()
}
view->Add( item );
ratsnest->Add( item );
connectivity->Add( item );
delete copy;
break;
}
@ -376,7 +377,7 @@ void BOARD_COMMIT::Revert()
}
}
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
clear();
}

View File

@ -41,7 +41,7 @@
#include <class_zone.h>
#include <pcb_netlist.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <reporter.h>
#include <board_netlist_updater.h>
@ -669,7 +669,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
{
m_commit.Push( _( "Update netlist" ) );
m_frame->Compile_Ratsnest( NULL, false );
m_board->GetRatsnest()->ProcessBoard();
m_board->GetConnectivity()->Build( m_board );
testConnectivity( aNetlist );
}

View File

@ -58,6 +58,7 @@
#include <class_pcb_text.h>
#include <class_mire.h>
#include <class_dimension.h>
#include <connectivity.h>
/* This is an odd place for this, but CvPcb won't link if it is
@ -106,7 +107,8 @@ BOARD::BOARD() :
m_designSettings.SetCustomViaDrill( m_designSettings.GetCurrentViaDrill() );
// Initialize ratsnest
m_ratsnest = new RN_DATA( this );
m_connectivity.reset( new CONNECTIVITY_DATA() );
m_connectivity->Build( this );
}
@ -118,8 +120,6 @@ BOARD::~BOARD()
Delete( area_to_remove );
}
delete m_ratsnest;
m_FullRatsnest.clear();
m_LocalRatsnest.clear();
@ -942,7 +942,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
}
aBoardItem->SetParent( this );
m_ratsnest->Add( aBoardItem );
m_connectivity->Add( aBoardItem );
}
@ -1011,7 +1011,7 @@ void BOARD::Remove( BOARD_ITEM* aBoardItem )
wxFAIL_MSG( wxT( "BOARD::Remove() needs more ::Type() support" ) );
}
m_ratsnest->Remove( aBoardItem );
m_connectivity->Remove( aBoardItem );
}
@ -2895,3 +2895,8 @@ bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
return success;
}
/*RN_DATA* BOARD::GetRatsnest() const
{
return m_connectivity->GetRatsnest();
}*/

View File

@ -45,6 +45,9 @@
#include <pcb_plot_params.h>
#include <board_item_container.h>
#include <memory>
using std::unique_ptr;
class PCB_BASE_FRAME;
class PCB_EDIT_FRAME;
@ -60,7 +63,7 @@ class NETLIST;
class REPORTER;
class RN_DATA;
class SHAPE_POLY_SET;
class CONNECTIVITY_DATA;
/**
* Enum LAYER_T
@ -187,7 +190,7 @@ private:
int m_fileFormatVersionAtLoad; ///< the version loaded from the file
NETINFO_LIST m_NetInfo; ///< net info list (name, design constraints ..
RN_DATA* m_ratsnest;
std::shared_ptr<CONNECTIVITY_DATA> m_connectivity;
BOARD_DESIGN_SETTINGS m_designSettings;
ZONE_SETTINGS m_zoneSettings;
@ -291,13 +294,14 @@ public:
BOARD_ITEM* Duplicate( const BOARD_ITEM* aItem, bool aAddToBoard = false );
/**
* Function GetRatsnest()
* Function GetConnectivity()
* returns list of missing connections between components/tracks.
* @return RATSNEST* is an object that contains informations about missing connections.
*/
RN_DATA* GetRatsnest() const
std::shared_ptr<CONNECTIVITY_DATA> GetConnectivity() const
{
return m_ratsnest;
return m_connectivity;
}
/**

View File

@ -34,7 +34,7 @@
#include <class_board.h>
#include <class_board_item.h>
#include <ratsnest_data.h>
#include <connectivity.h>
BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) :
BOARD_ITEM( aParent, idtype ), m_netinfo( &NETINFO_LIST::ORPHANED_ITEM ),
@ -50,11 +50,11 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
// set the m_netinfo to the dummy NETINFO_LIST::ORPHANED
BOARD* board = GetBoard();
RN_DATA* ratsnest = board ? board->GetRatsnest() : NULL;
bool addRatsnest = false;
//auto connectivity = board ? board->GetConnectivity() : nullptr;
//bool addRatsnest = false;
if( ratsnest )
addRatsnest = ratsnest->Remove( this );
//if( connectivity )
//addRatsnest = connectivity->Remove( this );
if( ( aNetCode >= 0 ) && board )
m_netinfo = board->FindNet( aNetCode );
@ -65,8 +65,8 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
assert( m_netinfo );
// Add only if it was previously added to the ratsnest
if( addRatsnest )
ratsnest->Add( this );
//if( addRatsnest )
// connectivity->Add( this );
return ( m_netinfo != NULL );
}

View File

@ -37,6 +37,7 @@
class NETCLASS;
class TRACK;
class D_PAD;
class CN_BOARD_ITEM_DATA;
/**
* Class BOARD_CONNECTED_ITEM
@ -50,6 +51,8 @@ class BOARD_CONNECTED_ITEM : public BOARD_ITEM
friend class CONNECTIONS;
public:
// These 2 members are used for temporary storage during connections calculations:
std::vector<TRACK*> m_TracksConnected; // list of other tracks connected to me
std::vector<D_PAD*> m_PadsConnected; // list of other pads connected to me

View File

@ -637,6 +637,12 @@ public:
m_FillSegmList.insert( m_FillSegmList.end(), aSegments.begin(), aSegments.end() );
}
SHAPE_POLY_SET& RawPolysList()
{
return m_RawPolysList;
}
wxString GetSelectMenuText() const override;
BITMAP_DEF GetMenuImage() const override;
@ -781,6 +787,7 @@ private:
* described by m_Poly can have many filled areas
*/
SHAPE_POLY_SET m_FilledPolysList;
SHAPE_POLY_SET m_RawPolysList;
HATCH_STYLE m_hatchStyle; // hatch style, see enum above
int m_hatchPitch; // for DIAGONAL_EDGE, distance between 2 hatch lines

View File

@ -39,9 +39,13 @@
// Helper classes to handle connection points
#include <connect.h>
const bool g_UseLegacyConnectionAlgo = false;
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb );
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
// Local functions
static void RebuildTrackChain( BOARD* pcb );
@ -853,13 +857,9 @@ void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
return;
}
/* search connections between tracks and pads and propagate pad net codes to the track
* segments.
* Pads netcodes are assumed to be up to date.
*/
void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
void PCB_BASE_FRAME::ComputeLegacyConnections()
{
// Build the net info list
GetBoard()->BuildListOfNets();
@ -872,7 +872,6 @@ void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
t->end = NULL;
t->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, false );
t->SetZoneSubNet( 0 );
t->SetNetCode( NETINFO_LIST::UNCONNECTED );
}
// If no pad, reset pointers and netcode, and do nothing else
@ -886,72 +885,12 @@ void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
// First pass: build connections between track segments and pads.
connections.SearchTracksConnectedToPads();
// For tracks connected to at least one pad,
// set the track net code to the pad netcode
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
{
if( t->m_PadsConnected.size() )
t->SetNetCode( t->m_PadsConnected[0]->GetNetCode() );
}
// Pass 2: build connections between track ends
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
{
connections.SearchConnectedTracks( t );
connections.GetConnectedTracks( t );
}
// Propagate net codes from a segment to other connected segments
bool new_pass_request = true; // set to true if a track has its netcode changed from 0
// to a known netcode to re-evaluate netcodes
// of connected items
while( new_pass_request )
{
new_pass_request = false;
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
{
int netcode = t->GetNetCode();
if( netcode == 0 )
{
// try to find a connected item having a netcode
for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
{
int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
if( altnetcode )
{
new_pass_request = true;
netcode = altnetcode;
t->SetNetCode(netcode);
break;
}
}
}
if( netcode ) // this track has a netcode
{
// propagate this netcode to connected tracks having no netcode
for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
{
int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
if( altnetcode == 0 )
{
t->m_TracksConnected[kk]->SetNetCode(netcode);
new_pass_request = true;
}
}
}
}
}
if( IsGalCanvasActive() )
{
/// @todo LEGACY tracks might have changed their nets, so we need to refresh labels in GAL
for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
GetGalCanvas()->GetView()->Update( track );
}
// Sort the track list by net codes:
RebuildTrackChain( m_Pcb );
}

377
pcbnew/connectivity.cpp Normal file
View File

@ -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();
}

204
pcbnew/connectivity.h Normal file
View File

@ -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

View File

@ -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();
}

926
pcbnew/connectivity_algo.h Normal file
View File

@ -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

View File

@ -33,7 +33,7 @@
#include <confirm.h>
#include <wxPcbStruct.h>
#include <macros.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <class_board.h>
#include <class_track.h>
@ -123,7 +123,7 @@ TRACK* PCB_EDIT_FRAME::Delete_Segment( wxDC* DC, TRACK* aTrack )
// Remove the segment from list, but do not delete it (it will be stored i n undo list)
GetBoard()->Remove( aTrack );
GetBoard()->GetRatsnest()->Remove( aTrack );
GetBoard()->GetConnectivity()->Remove( aTrack );
// redraw the area where the track was
m_canvas->RefreshDrawingRect( aTrack->GetBoundingBox() );
@ -173,7 +173,7 @@ void PCB_EDIT_FRAME::Delete_net( wxDC* DC, TRACK* aTrack )
if( segm->GetNetCode() != netcode )
break;
GetBoard()->GetRatsnest()->Remove( segm );
GetBoard()->GetConnectivity()->Remove( segm );
GetBoard()->m_Track.Remove( segm );
// redraw the area where the track was
@ -219,7 +219,7 @@ void PCB_EDIT_FRAME::Remove_One_Track( wxDC* DC, TRACK* pt_segm )
<< TO_UTF8( TRACK::ShowState( tracksegment->GetStatus() ) ) \
<< std::endl; )
GetBoard()->GetRatsnest()->Remove( tracksegment );
GetBoard()->GetConnectivity()->Remove( tracksegment );
GetBoard()->m_Track.Remove( tracksegment );
// redraw the area where the track was

View File

@ -846,7 +846,6 @@
<property name="minimum_size"></property>
<property name="name">bMiddleRightBoxSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="0">
@ -1580,7 +1579,6 @@
<property name="minimum_size"></property>
<property name="name">sbSizer2PAN</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="0">
@ -1849,6 +1847,108 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">Advanced/Developer</property>
<property name="minimum_size"></property>
<property name="name">sbSizer4</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Use legacy connectivity algorithm</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbUseLegacyConnectivityAlgo</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -160,7 +160,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete()
masque_layer &= layers_filter;
for( item = pcb->m_Drawings; item; item = item->Next() )
for( item = pcb->DrawingsList(); item; item = item->Next() )
{
KICAD_T type = item->Type();
LAYER_NUM layer = item->GetLayer();

View File

@ -43,7 +43,7 @@
#include <class_board_design_settings.h>
#include <class_board.h>
#include <class_module.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <wildcards_and_files_ext.h>
#include <dialog_netlist.h>
@ -330,9 +330,9 @@ void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
{
// Rebuild the board connectivity:
if( m_parent->IsGalCanvasActive() )
m_parent->GetBoard()->GetRatsnest()->ProcessBoard();
auto board = m_parent->GetBoard();
//board->GetConnectivity()->Build( board );
board->GetConnectivity()->PropagateNets();
m_parent->Compile_Ratsnest( m_dc, true );
}

View File

@ -42,6 +42,7 @@
#include <view/view.h>
#include <geometry/seg.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
@ -205,7 +206,7 @@ void DRC::RunTests( wxTextCtrl* aMessages )
}
m_pcbEditorFrame->Compile_Ratsnest( NULL, true );
m_pcb->GetRatsnest()->ProcessBoard();
//m_pcb->GetRatsnest()->ProcessBoard();
}
// someone should have cleared the two lists before calling this.
@ -558,6 +559,25 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
void DRC::testUnconnected()
{
std::vector<CN_DISJOINT_NET_ENTRY> report;
auto connectivity = m_pcb->GetConnectivity();
connectivity->CheckConnectivity( report );
printf("Connectivity: %d unconnected\n", report.size());
for( auto ent : report )
{
/* DRC_ITEM* uncItem = new DRC_ITEM( DRCE_UNCONNECTED_PADS,
msg,
padEnd->GetSelectMenuText(),
padStart->GetPosition(), padEnd->GetPosition() );*/
}
#if 0
if( (m_pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
{
wxClientDC dc( m_pcbEditorFrame->GetCanvas() );
@ -588,6 +608,8 @@ void DRC::testUnconnected()
m_unconnected.push_back( uncItem );
}
#endif
}

View File

@ -584,7 +584,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
{
wxBusyCursor dummy; // Displays an Hourglass while building connectivity
Compile_Ratsnest( NULL, true );
GetBoard()->GetRatsnest()->ProcessBoard();
//GetBoard()->GetRatsnest()->ProcessBoard();
}
// Update info shown by the horizontal toolbars

View File

@ -303,7 +303,7 @@ MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary,
// (Can happen if the lib is an archive built from a board)
Rotate_Module( NULL, module, 0, false );
RecalculateAllTracksNetcode();
//RecalculateAllTracksNetcode();
if( aDC )
module->Draw( m_canvas, aDC, GR_OR );

View File

@ -170,7 +170,7 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName,
// Rebuild the board connectivity:
Compile_Ratsnest( NULL, true );
board->GetRatsnest()->ProcessBoard();
//board->GetRatsnest()->ProcessBoard();
SetMsgPanel( board );
m_canvas->Refresh();

View File

@ -29,6 +29,7 @@
#include <worksheet_viewitem.h>
#include <ratsnest_viewitem.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <class_colors_design_settings.h>
#include <class_board.h>
@ -154,7 +155,7 @@ void PCB_DRAW_PANEL_GAL::DisplayBoard( const BOARD* aBoard )
m_view->Add( zone );
// Ratsnest
m_ratsnest.reset( new KIGFX::RATSNEST_VIEWITEM( aBoard->GetRatsnest() ) );
m_ratsnest.reset( new KIGFX::RATSNEST_VIEWITEM( aBoard->GetConnectivity() ) );
m_view->Add( m_ratsnest.get() );
// Display settings
@ -334,7 +335,7 @@ void PCB_DRAW_PANEL_GAL::GetMsgPanelInfo( std::vector<MSG_PANEL_ITEM>& aList )
txt.Printf( wxT( "%d" ), board->GetNetCount() );
aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
txt.Printf( wxT( "%d" ), board->GetRatsnest()->GetUnconnectedCount() );
txt.Printf( wxT( "%d" ), board->GetConnectivity()->GetUnconnectedCount() );
aList.push_back( MSG_PANEL_ITEM( _( "Unconnected" ), txt, BLUE ) );
}

View File

@ -65,7 +65,7 @@
#include <class_board.h>
#include <class_module.h>
#include <worksheet_viewitem.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <ratsnest_viewitem.h>
#include <tool/tool_manager.h>
@ -509,8 +509,8 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard )
if( IsGalCanvasActive() )
{
aBoard->GetRatsnest()->ProcessBoard();
aBoard->GetConnectivity()->Build ( aBoard );
// reload the worksheet
SetPageSettings( aBoard->GetPageSettings() );
}

View File

@ -170,7 +170,7 @@ void PCB_BASE_FRAME::Compile_Ratsnest( wxDC* aDC, bool aDisplayStatus )
ClearMsgPanel();
// Rebuild the full pads and net info list
RecalculateAllTracksNetcode();
ComputeLegacyConnections();
if( aDisplayStatus )
{

File diff suppressed because it is too large Load Diff

View File

@ -30,50 +30,28 @@
#ifndef RATSNEST_DATA_H
#define RATSNEST_DATA_H
#include <ttl/halfedge/hetriang.h>
#include <ttl/halfedge/hetraits.h>
#include <core/typeinfo.h>
#include <math/box2.h>
#include <deque>
#include <unordered_set>
#include <unordered_map>
#include <ttl/halfedge/hetriang.h>
#include <ttl/halfedge/hetraits.h>
#include <connectivity_algo.h>
class BOARD;
class BOARD_ITEM;
class BOARD_CONNECTED_ITEM;
class MODULE;
class D_PAD;
class VIA;
class TRACK;
class ZONE_CONTAINER;
class SHAPE_POLY_SET;
///> Types of items that are handled by the class
enum RN_ITEM_TYPE
{
RN_PADS = 0x01,
RN_VIAS = 0x02,
RN_TRACKS = 0x04,
RN_ZONES = 0x08,
RN_ALL = 0xFF
};
// Preserve KiCad coding style policy
typedef hed::NODE RN_NODE;
typedef hed::NODE_PTR RN_NODE_PTR;
typedef hed::EDGE RN_EDGE;
typedef hed::EDGE_PTR RN_EDGE_PTR;
typedef hed::EDGE_MST RN_EDGE_MST;
typedef hed::TRIANGULATION TRIANGULATOR;
typedef std::shared_ptr<hed::EDGE_MST> RN_EDGE_MST_PTR;
bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond );
bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond );
class CN_CLUSTER;
class CN_CONNECTIVITY_ALGO;
struct RN_NODE_OR_FILTER;
struct RN_NODE_AND_FILTER;
#if 0
///> General interface for filtering out nodes in search functions.
struct RN_NODE_FILTER : public std::unary_function<const RN_NODE_PTR&, bool>
{
@ -96,7 +74,7 @@ struct LINE_TARGET : public RN_NODE_FILTER
{
bool operator()( const RN_NODE_PTR& aNode ) const override
{
return !aNode->GetNoLine();
return true;
}
};
@ -109,7 +87,7 @@ struct LINE_TARGET_SAME_TAG : public RN_NODE_FILTER
bool operator()( const RN_NODE_PTR& aNode ) const override
{
return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
return aNode->GetTag() == m_tag;
}
private:
@ -124,7 +102,7 @@ struct LINE_TARGET_DIFF_TAG : public RN_NODE_FILTER
bool operator()( const RN_NODE_PTR& aNode ) const override
{
return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
return aNode->GetTag() != m_tag;
}
private:
@ -163,168 +141,26 @@ struct RN_NODE_OR_FILTER : public RN_NODE_FILTER
const RN_NODE_FILTER& m_filter2;
};
///> Functor comparing if two nodes are equal by their coordinates. It is required to make set of
///> shared pointers work properly.
struct RN_NODE_COMPARE : std::binary_function<RN_NODE_PTR, RN_NODE_PTR, bool>
struct RN_NODE_COMPARE : std::binary_function<CN_ANCHOR_PTR, CN_ANCHOR_PTR, bool>
{
bool operator()( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2 ) const
bool operator()( const CN_ANCHOR_PTR& aNode1, const CN_ANCHOR_PTR& aNode2 ) const
{
return aNode1 == aNode2;
if ( aNode1->GetY() < aNode2->GetY() )
return true;
else if ( aNode1->GetY() == aNode2->GetY() )
{
if ( aNode1->GetX() == aNode2->GetX() )
return aNode1->GetCluster() < aNode2->GetCluster();
else
return aNode1->GetX() < aNode2->GetX();
}
return false;
}
};
///> Functor calculating hash for a given node. It is required to make set of shared pointers
///> work properly.
struct RN_NODE_HASH : std::unary_function<RN_NODE_PTR, std::size_t>
{
std::size_t operator()( const RN_NODE_PTR& aNode ) const
{
std::size_t hash = 2166136261u;
hash ^= aNode->GetX();
hash *= 16777619;
hash ^= aNode->GetY();
return hash;
}
};
/**
* Class RN_LINKS
* Manages data describing nodes and connections for a given net.
*/
class RN_LINKS
{
public:
// Helper typedefs
typedef std::unordered_set<RN_NODE_PTR, RN_NODE_HASH, RN_NODE_COMPARE> RN_NODE_SET;
typedef std::list<RN_EDGE_PTR> RN_EDGE_LIST;
/**
* Function AddNode()
* Adds a node with given coordinates and returns pointer to the newly added node. If the node
* existed before, only appropriate pointer is returned.
* @param aX is the x coordinate of a node.
* @param aY is the y coordinate of a node.
* @return Pointer to the node with given coordinates.
*/
const RN_NODE_PTR& AddNode( int aX, int aY );
/**
* Function RemoveNode()
* Removes a node described by a given node pointer.
* @param aNode is a pointer to node to be removed.
* @return True if node was removed, false if there were other references, so it was kept.
*/
bool RemoveNode( const RN_NODE_PTR& aNode );
/**
* Function GetNodes()
* Returns the set of currently used nodes.
* @return The set of currently used nodes.
*/
const RN_NODE_SET& GetNodes() const
{
return m_nodes;
}
/**
* Function AddConnection()
* Adds a connection between two nodes and of given distance. Edges with distance equal 0 are
* considered to be existing connections. Distance different than 0 means that the connection
* is missing.
* @param aNode1 is the origin node of a new connection.
* @param aNode2 is the end node of a new connection.
* @param aDistance is the distance of the connection (0 means that nodes are actually
* connected, >0 means a missing connection).
*/
RN_EDGE_MST_PTR AddConnection( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2,
unsigned int aDistance = 0 );
/**
* Function RemoveConnection()
* Removes a connection described by a given edge pointer.
* @param aEdge is a pointer to edge to be removed.
*/
void RemoveConnection( const RN_EDGE_PTR& aEdge )
{
m_edges.remove( aEdge );
}
/**
* Function GetConnections()
* Returns the list of edges that currently connect nodes.
* @return the list of edges that currently connect nodes.
*/
const RN_EDGE_LIST& GetConnections() const
{
return m_edges;
}
protected:
///> Set of nodes that are expected to be connected together (vias, tracks, pads).
RN_NODE_SET m_nodes;
///> List of edges that currently connect nodes.
RN_EDGE_LIST m_edges;
};
/**
* Class RN_POLY
* Describes a single subpolygon (ZONE_CONTAINER is supposed to contain one or more of those) and
* performs fast point-inside-polygon test.
*/
class RN_POLY
{
public:
RN_POLY( const SHAPE_POLY_SET* aParent,
int aSubpolygonIndex,
RN_LINKS& aConnections, const BOX2I& aBBox );
/**
* Function GetNode()
* Returns node representing a polygon (it has the same coordinates as the first point of its
* bounding polyline.
*/
inline const RN_NODE_PTR& GetNode() const
{
return m_node;
}
inline RN_NODE_PTR& GetNode()
{
return m_node;
}
/**
* Function HitTest()
* Tests if selected node is located within polygon boundaries.
* @param aNode is a node to be checked.
* @return True is the node is located within polygon boundaries.
*/
bool HitTest( const RN_NODE_PTR& aNode ) const;
private:
///> Index of the outline in the parent polygon set
int m_subpolygonIndex;
///> Bounding box of the polygon.
BOX2I m_bbox;
///> Polygon set containing the geometry
const SHAPE_POLY_SET* m_parentPolyset;
///> Node representing a polygon (it has the same coordinates as the first point of its
///> bounding polyline.
RN_NODE_PTR m_node;
friend bool sortArea( const RN_POLY& aP1, const RN_POLY& aP2 );
};
#endif
/**
* Class RN_NET
@ -334,8 +170,7 @@ class RN_NET
{
public:
///> Default constructor.
RN_NET() : m_dirty( true ), m_visible( true )
{}
RN_NET();
/**
* Function SetVisible()
@ -383,9 +218,9 @@ public:
* Returns pointer to a vector of edges that makes ratsnest for a given net.
* @return Pointer to a vector of edges that makes ratsnest for a given net.
*/
const std::vector<RN_EDGE_MST_PTR>* GetUnconnected() const
const std::vector<CN_EDGE> GetUnconnected() const
{
return m_rnEdges.get();
return m_rnEdges;
}
/**
@ -393,70 +228,12 @@ public:
* Recomputes ratsnest for a net.
*/
void Update();
void Clear();
/**
* Function AddItem()
* Adds an appropriate node associated with selected pad, so it is
* taken into account during ratsnest computations.
* @param aPad is a pad for which node is added.
*/
bool AddItem( const D_PAD* aPad );
void AddCluster( std::shared_ptr<CN_CLUSTER> aCluster );
/**
* Function AddItem()
* Adds an appropriate node associated with selected via, so it is
* taken into account during ratsnest computations.
* @param aVia is a via for which node is added.
*/
bool AddItem( const VIA* aVia );
/**
* Function AddItem()
* Adds appropriate nodes and edges associated with selected track, so they are
* taken into account during ratsnest computations.
* @param aTrack is a track for which nodes and edges are added.
*/
bool AddItem( const TRACK* aTrack );
/**
* Function AddItem()
* Processes zone to split it into subpolygons and adds appropriate nodes for them, so they are
* taken into account during ratsnest computations.
* @param aZone is a zone to be processed.
*/
bool AddItem( const ZONE_CONTAINER* aZone );
/**
* Function RemoveItem()
* Removes all nodes and edges associated with selected pad, so they are not
* taken into account during ratsnest computations anymore.
* @param aPad is a pad for which nodes and edges are removed.
*/
bool RemoveItem( const D_PAD* aPad );
/**
* Function RemoveItem()
* Removes all nodes and edges associated with selected via, so they are not
* taken into account during ratsnest computations anymore.
* @param aVia is a via for which nodes and edges are removed.
*/
bool RemoveItem( const VIA* aVia );
/**
* Function RemoveItem()
* Removes all nodes and edges associated with selected track, so they are not
* taken into account during ratsnest computations anymore.
* @param aTrack is a track for which nodes and edges are removed.
*/
bool RemoveItem( const TRACK* aTrack );
/**
* Function RemoveItem()
* Removes all nodes and edges associated with selected zone, so they are not
* taken into account during ratsnest computations anymore.
* @param aZone is a zone for which nodes and edges are removed.
*/
bool RemoveItem( const ZONE_CONTAINER* aZone );
unsigned int GetNodeCount() const;
/**
* Function GetNodes()
@ -464,7 +241,12 @@ public:
* @param aItem is an item for which the list is generated.
* @return List of associated nodes.
*/
std::list<RN_NODE_PTR> GetNodes( const BOARD_CONNECTED_ITEM* aItem ) const;
std::list<CN_ANCHOR_PTR> GetNodes( const BOARD_CONNECTED_ITEM* aItem ) const;
const std::vector<CN_EDGE>& GetEdges() const
{
return m_rnEdges;
}
/**
* Function GetAllItems()
@ -472,14 +254,16 @@ public:
* @param aOutput is the list that will have items added.
* @param aType determines the type of added items.
*/
void GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, RN_ITEM_TYPE aType = RN_ALL ) const;
void GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, const KICAD_T aTypes[] ) const;
/**
* Function GetClosestNode()
* Returns a single node that lies in the shortest distance from a specific node.
* @param aNode is the node for which the closest node is searched.
*/
const RN_NODE_PTR GetClosestNode( const RN_NODE_PTR& aNode ) const;
const CN_ANCHOR_PTR GetClosestNode( const CN_ANCHOR_PTR& aNode ) const;
bool NearestBicoloredPair( const RN_NET& aOtherNet, CN_ANCHOR_PTR& aNode1, CN_ANCHOR_PTR& aNode2 ) const;
/**
* Function GetClosestNode()
@ -488,8 +272,8 @@ public:
* @param aNode is the node for which the closest node is searched.
* @param aFilter is a functor that filters nodes.
*/
const RN_NODE_PTR GetClosestNode( const RN_NODE_PTR& aNode,
const RN_NODE_FILTER& aFilter ) const;
/*const CN_ANCHOR_PTR GetClosestNode( const RN_NODE_PTR& aNode,
const RN_NODE_FILTER& aFilter ) const;*/
/**
* Function GetClosestNodes()
@ -499,7 +283,7 @@ public:
* belong to the same net are returned. If asked number is greater than number of possible
* nodes then the size of list is limited to number of possible nodes.
*/
std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode, int aNumber = -1 ) const;
//std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode, int aNumber = -1 ) const;
/**
* Function GetClosestNodes()
@ -510,291 +294,33 @@ public:
* belong to the same net are returned. If asked number is greater than number of possible
* nodes then the size of list is limited to number of possible nodes.
*/
std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode,
const RN_NODE_FILTER& aFilter, int aNumber = -1 ) const;
//std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode,
// const RN_NODE_FILTER& aFilter, int aNumber = -1 ) const;
/**
* Function AddSimple()
* Changes drawing mode for an item to simple (i.e. one ratsnest line per node).
* @param aItem is the item that changes its drawing mode.
*/
void AddSimple( const BOARD_CONNECTED_ITEM* aItem );
/**
* Function AddBlockedNode()
* Specifies a node as not suitable as a ratsnest line target (i.e. ratsnest lines will not
* target the node). The status is cleared after calling ClearSimple().
* @param aNode is the node that is not going to be used as a ratsnest line target.
*/
inline void AddBlockedNode( RN_NODE_PTR& aNode )
{
m_blockedNodes.insert( aNode );
aNode->SetNoLine( true );
}
/**
* Function GetSimpleNodes()
* Returns list of nodes for which ratsnest is drawn in simple mode (i.e. one
* ratsnest line per node).
* @return list of nodes for which ratsnest is drawn in simple mode.
*/
inline const std::unordered_set<RN_NODE_PTR>& GetSimpleNodes() const
{
return m_simpleNodes;
}
/**
* Function ClearSimple()
* Removes all nodes and edges that are used for displaying ratsnest in simple mode.
*/
void ClearSimple();
/**
* Function GetConnectedItems()
* Adds items that are connected together to a list.
* @param aItem is the reference item to find other connected items.
* @param aOutput is the list that will contain found items.
* @param aTypes allows to filter by item types.
*/
void GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
std::list<BOARD_CONNECTED_ITEM*>& aOutput,
RN_ITEM_TYPE aTypes = RN_ALL ) const;
protected:
///> Validates edge, i.e. modifies source and target nodes for an edge
///> to make sure that they are not ones with the flag set.
void validateEdge( RN_EDGE_MST_PTR& aEdge );
///> Removes a link between a node and a parent,
///> and clears linked edges if it was the last parent.
void removeNode( RN_NODE_PTR& aNode, const BOARD_CONNECTED_ITEM* aParent );
///> Removes a link between an edge and a parent,
///> and clears its node data if it was the last parent.
void removeEdge( RN_EDGE_MST_PTR& aEdge, const BOARD_CONNECTED_ITEM* aParent );
///> Removes all ratsnest edges for a given node.
void clearNode( const RN_NODE_PTR& aNode );
///> Adds appropriate edges for nodes that are connected by zones.
void processZones();
///> Adds additional edges to account for connections made by items located in pads areas.
void processPads();
///> Recomputes ratsnset from scratch.
void compute();
////> Stores information about connections for a given net.
RN_LINKS m_links;
///> Vector of nodes
std::vector<CN_ANCHOR_PTR> m_nodes;
///> Vector of edges that make pre-defined connections
std::vector<CN_EDGE> m_boardEdges;
///> Vector of edges that makes ratsnest for a given net.
std::shared_ptr< std::vector<RN_EDGE_MST_PTR> > m_rnEdges;
///> List of nodes which will not be used as ratsnest target nodes.
std::unordered_set<RN_NODE_PTR> m_blockedNodes;
///> Nodes to be displayed using the simplified ratsnest algorithm.
std::unordered_set<RN_NODE_PTR> m_simpleNodes;
std::vector<CN_EDGE> m_rnEdges;
///> Flag indicating necessity of recalculation of ratsnest for a net.
bool m_dirty;
///> Structure to hold ratsnest data for ZONE_CONTAINER objects.
typedef struct
{
///> Subpolygons belonging to a zone
std::deque<RN_POLY> m_Polygons;
///> Connections to other nodes
std::deque<RN_EDGE_MST_PTR> m_Edges;
} RN_ZONE_DATA;
///> Structureo to hold ratsnest data for D_PAD objects.
typedef struct
{
///> Node representing the pad.
RN_NODE_PTR m_Node;
///> Helper nodes that make for connections to items located in the pad area.
std::deque<RN_EDGE_MST_PTR> m_Edges;
} RN_PAD_DATA;
///> Helper typedefs
typedef std::unordered_map<const D_PAD*, RN_PAD_DATA> PAD_NODE_MAP;
typedef std::unordered_map<const VIA*, RN_NODE_PTR> VIA_NODE_MAP;
typedef std::unordered_map<const TRACK*, RN_EDGE_MST_PTR> TRACK_EDGE_MAP;
typedef std::unordered_map<const ZONE_CONTAINER*, RN_ZONE_DATA> ZONE_DATA_MAP;
///> Map that associates nodes in the ratsnest model to respective nodes.
PAD_NODE_MAP m_pads;
///> Map that associates nodes in the ratsnest model to respective vias.
VIA_NODE_MAP m_vias;
///> Map that associates edges in the ratsnest model to respective tracks.
TRACK_EDGE_MAP m_tracks;
///> Map that associates groups of subpolygons in the ratsnest model to respective zones.
ZONE_DATA_MAP m_zones;
///> Visibility flag.
bool m_visible;
class TRIANGULATOR_STATE;
std::shared_ptr<TRIANGULATOR_STATE> m_triangulator;
};
/**
* Class RN_DATA
*
* Stores information about unconnected items for a board.
*/
class RN_DATA
{
public:
/**
* Default constructor
* @param aBoard is the board to be processed in order to look for unconnected items.
*/
RN_DATA( const BOARD* aBoard ) : m_board( aBoard ) {}
/**
* Function Add()
* Adds an item to the ratsnest data.
* @param aItem is an item to be added.
* @return True if operation succeeded.
*/
bool Add( const BOARD_ITEM* aItem );
/**
* Function Remove()
* Removes an item from the ratsnest data.
* @param aItem is an item to be updated.
* @return True if operation succeeded.
*/
bool Remove( const BOARD_ITEM* aItem );
/**
* Function Update()
* Updates the ratsnest 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 Update( const BOARD_ITEM* aItem );
/**
* Function AddSimple()
* Sets an item to be drawn in simple mode (i.e. one line per node, instead of full ratsnest).
* It is used for drawing quick, temporary ratsnest, eg. while moving an item.
* @param aItem is an item to be drawn in simple node.
*/
void AddSimple( const BOARD_ITEM* aItem );
/**
* Function AddBlocked()
* Specifies an item as not suitable as a ratsnest line target (i.e. ratsnest lines will not
* target its node(s)). The status is cleared after calling ClearSimple().
* @param aItem is the item of which node(s) are not going to be used as a ratsnest line target.
*/
void AddBlocked( const BOARD_ITEM* aItem );
/**
* Function ClearSimple()
* Clears the list of nodes for which ratsnest is drawn in simple mode (one line per node).
*/
void ClearSimple()
{
for( RN_NET& net : m_nets )
net.ClearSimple();
}
/**
* Function ProcessBoard()
* Prepares data for computing (computes a list of current nodes and connections). It is
* required to run only once after loading a board.
*/
void ProcessBoard();
/**
* Function Recalculate()
* Recomputes ratsnest for selected net number or all nets that need updating.
* @param aNet is a net number. If it is negative, all nets that need updating are recomputed.
*/
void Recalculate( int aNet = -1 );
/**
* Function GetNetCount()
* Returns the number of nets handled by the ratsnest.
* @return Number of the nets.
*/
int GetNetCount() const
{
return m_nets.size();
}
/**
* Function GetNet()
* Returns ratsnest grouped by net numbers.
* @param aNetCode is the net code.
* @return Ratsnest data for a specified net.
*/
RN_NET& GetNet( int aNetCode )
{
assert( aNetCode > 0 ); // ratsnest does not handle the unconnected net
return m_nets[aNetCode];
}
/**
* Function GetConnectedItems()
* Adds items that are connected together to a list.
* @param aItem is the reference item to find other connected items.
* @param aOutput is the list that will contain found items.
* @param aTypes allows to filter by item types.
*/
void GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
std::list<BOARD_CONNECTED_ITEM*>& aOutput,
RN_ITEM_TYPE aTypes = RN_ALL ) const;
/**
* Function GetNetItems()
* Adds all items that belong to a certain net to a list.
* @param aNetCode is the net code.
* @param aOutput is the list that will have items added.
* @param aTypes allows to filter by item types.
*/
void GetNetItems( int aNetCode, std::list<BOARD_CONNECTED_ITEM*>& aOutput,
RN_ITEM_TYPE aTypes = RN_ALL ) const;
/**
* Function AreConnected()
* Checks if two items are connected with copper.
* @param aItem is the first item.
* @param aOther is the second item.
* @return true if they are connected, false otherwise.
*/
bool AreConnected( const BOARD_CONNECTED_ITEM* aItem, const BOARD_CONNECTED_ITEM* aOther );
/**
* Function GetUnconnectedCount()
* Returns the number of missing connections.
* @return Number of missing connections.
*/
int GetUnconnectedCount() const;
protected:
/**
* Function updateNet()
* Recomputes ratsnest for a single net.
* @param aNetCode is the net number to be recomputed.
*/
void updateNet( int aNetCode );
///> Board to be processed.
const BOARD* m_board;
///> Stores information about ratsnest grouped by net numbers.
std::vector<RN_NET> m_nets;
};
#endif /* RATSNEST_DATA_H */

View File

@ -29,15 +29,18 @@
#include <ratsnest_viewitem.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <gal/graphics_abstraction_layer.h>
#include <pcb_painter.h>
#include <layers_id_colors_and_visibility.h>
#include <memory>
#include <view/view.h>
namespace KIGFX {
RATSNEST_VIEWITEM::RATSNEST_VIEWITEM( RN_DATA* aData ) :
RATSNEST_VIEWITEM::RATSNEST_VIEWITEM( std::shared_ptr<CONNECTIVITY_DATA> aData ) :
EDA_ITEM( NOT_USED ), m_data( aData )
{
}
@ -52,63 +55,76 @@ const BOX2I RATSNEST_VIEWITEM::ViewBBox() const
return bbox;
}
#include <geometry/seg.h>
std::vector<SEG> delEdges;
void clearDEdges() { delEdges.clear(); }
void addDEdge ( SEG edge ) { delEdges.push_back(edge); }
void RATSNEST_VIEWITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
{
static const double crossSize = 100000.0;
auto gal = aView->GetGAL();
gal->SetIsStroke( true );
gal->SetIsStroke( true );
gal->SetIsFill( false );
gal->SetLineWidth( 1.0 );
auto rs = aView->GetPainter()->GetSettings();
auto color = rs->GetColor( NULL, LAYER_RATSNEST );
int highlightedNet = rs->GetHighlightNetCode();
gal->SetStrokeColor( color.Brightened( 0.8 ) );
for (auto s : delEdges)
gal->DrawLine( s.A, s.B );
// Draw the "dynamic" ratsnest (i.e. for objects that may be currently being moved)
for( const auto& l : m_data->GetDynamicRatsnest() )
{
if ( l.a == l.b )
{
gal->DrawLine( VECTOR2I( l.a.x - crossSize, l.a.y - crossSize ), VECTOR2I( l.b.x + crossSize, l.b.y + crossSize ) );
gal->DrawLine( VECTOR2I( l.a.x - crossSize, l.a.y + crossSize ), VECTOR2I( l.b.x + crossSize, l.b.y - crossSize ) );
} else {
gal->DrawLine( l.a, l.b );
}
}
// Dynamic ratsnest (for e.g. dragged items)
for( int i = 1; i < m_data->GetNetCount(); ++i )
{
RN_NET& net = m_data->GetNet( i );
RN_NET* net = m_data->GetRatsnestForNet( i );
if( !net.IsVisible() )
if( !net->IsVisible() )
continue;
// Set brighter color for the temporary ratsnest
gal->SetStrokeColor( color.Brightened( 0.8 ) );
// Draw the "dynamic" ratsnest (i.e. for objects that may be currently being moved)
for( const RN_NODE_PTR& node : net.GetSimpleNodes() )
{
// Skipping nodes with higher reference count avoids displaying redundant lines
if( node->GetRefCount() > 1 )
continue;
RN_NODE_PTR dest = net.GetClosestNode( node, LINE_TARGET() );
if( dest )
{
VECTOR2D origin( node->GetX(), node->GetY() );
VECTOR2D end( dest->GetX(), dest->GetY() );
gal->DrawLine( origin, end );
}
}
// Draw the "static" ratsnest
if( i != highlightedNet )
gal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted
const std::vector<RN_EDGE_MST_PTR>* edges = net.GetUnconnected();
if( edges == NULL )
continue;
for( const RN_EDGE_MST_PTR& edge : *edges )
for( const auto& edge : net->GetUnconnected() )
{
const RN_NODE_PTR& sourceNode = edge->GetSourceNode();
const RN_NODE_PTR& targetNode = edge->GetTargetNode();
VECTOR2D source( sourceNode->GetX(), sourceNode->GetY() );
VECTOR2D target( targetNode->GetX(), targetNode->GetY() );
const auto& sourceNode = edge.GetSourceNode();
const auto& targetNode = edge.GetTargetNode();
const VECTOR2I source( sourceNode->Pos() );
const VECTOR2I target( targetNode->Pos() );
gal->DrawLine( source, target );
if ( !sourceNode->GetNoLine() && !targetNode->GetNoLine() )
{
if ( source == target )
{
constexpr int CROSS_SIZE = 200000;
gal->DrawLine( VECTOR2I( source.x - CROSS_SIZE, source.y - CROSS_SIZE ), VECTOR2I( source.x + CROSS_SIZE, source.y + CROSS_SIZE ) );
gal->DrawLine( VECTOR2I( source.x - CROSS_SIZE, source.y + CROSS_SIZE ), VECTOR2I( source.x + CROSS_SIZE, source.y - CROSS_SIZE ) );
}
else
{
gal->DrawLine( source, target );
}
}
}
}
}

View File

@ -30,18 +30,19 @@
#ifndef RATSNEST_VIEWITEM_H
#define RATSNEST_VIEWITEM_H
#include <memory>
#include <base_struct.h>
#include <math/vector2d.h>
class GAL;
class RN_DATA;
class CONNECTIVITY_DATA;
namespace KIGFX
{
class RATSNEST_VIEWITEM : public EDA_ITEM
{
public:
RATSNEST_VIEWITEM( RN_DATA* aData );
RATSNEST_VIEWITEM( std::shared_ptr<CONNECTIVITY_DATA> aData );
/// @copydoc VIEW_ITEM::ViewBBox()
const BOX2I ViewBBox() const override;
@ -69,7 +70,7 @@ public:
protected:
///> Object containing ratsnest data.
RN_DATA* m_data;
std::shared_ptr<CONNECTIVITY_DATA> m_data;
};
} // namespace KIGFX

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>();
}

View File

@ -42,7 +42,7 @@
#include <view/view_controls.h>
#include <view/view.h>
#include <gal/graphics_abstraction_layer.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <confirm.h>
#include <bitmaps.h>
#include <hotkeys.h>
@ -301,6 +301,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{
static_cast<BOARD_ITEM*>( item )->Move( movement + m_offset );
}
updateRatsnest( true );
}
else if( !m_dragging ) // Prepare to start dragging
{
@ -410,6 +412,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
// Update dragging offset (distance between cursor and the first dragged item)
m_offset = static_cast<BOARD_ITEM*>( selection.Front() )->GetPosition() - modPoint;
getView()->Update( &selection );
updateRatsnest( true );
}
}
@ -422,6 +425,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
}
} while( ( evt = Wait() ) ); //Should be assignment not equality test
getModel<BOARD>()->GetConnectivity()->ClearDynamicRatsnest();
controls->ForceCursorPosition( false );
controls->ShowCursor( false );
controls->SetSnapping( false );
@ -516,6 +521,8 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
if( !m_dragging )
m_commit->Push( _( "Rotate" ) );
else
updateRatsnest( true );
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -622,6 +629,8 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
if( !m_dragging )
m_commit->Push( _( "Mirror" ) );
else
updateRatsnest( true );
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -655,6 +664,8 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
if( !m_dragging )
m_commit->Push( _( "Flip" ) );
else
updateRatsnest( true );
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -1138,6 +1149,17 @@ void EDIT_TOOL::SetTransitions()
Go( &EDIT_TOOL::MeasureTool, PCB_ACTIONS::measureTool.MakeEvent() );
}
void EDIT_TOOL::updateRatsnest( bool aRedraw )
{
auto& selection = m_selectionTool->GetSelection();
auto connectivity = getModel<BOARD>()->GetConnectivity();
std::vector<BOARD_ITEM *> items;
for ( auto item : selection )
items.push_back ( static_cast<BOARD_ITEM *>( item ) );
connectivity->ComputeDynamicRatsnest( items );
}
wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection )
{

View File

@ -32,6 +32,7 @@
class BOARD_COMMIT;
class BOARD_ITEM;
class SELECTION_TOOL;
class CONNECTIVITY_DATA;
/**
* Class EDIT_TOOL
@ -144,6 +145,13 @@ private:
///> of edit reference point).
VECTOR2I m_cursor;
std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity;
///> Updates ratsnest for selected items.
///> @param aRedraw says if selected items should be drawn using the simple mode (e.g. one line
///> per item).
void updateRatsnest( bool aRedraw );
///> Returns the right modification point (e.g. for rotation), depending on the number of
///> selected items.
wxPoint getModificationPoint( const SELECTION& aSelection );

View File

@ -356,6 +356,7 @@ public:
static TOOL_ACTION crossProbeSchToPcb;
static TOOL_ACTION appendBoard;
static TOOL_ACTION showHelp;
static TOOL_ACTION showLocalRatsnest;
static TOOL_ACTION toBeDone;
/// Find an item

View File

@ -41,8 +41,7 @@
#include <class_draw_panel_gal.h>
#include <class_module.h>
#include <class_mire.h>
#include <ratsnest_data.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <collectors.h>
#include <zones_functions_for_undo_redo.h>
#include <board_commit.h>
@ -481,7 +480,12 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent )
}
}
view->Remove( &preview );
controls->ShowCursor( false );
controls->SetSnapping( false );
controls->SetAutoPan( false );
controls->CaptureCursor( false );
view->Remove( &preview );
m_frame->SetNoToolSelected();
return 0;
@ -637,7 +641,7 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
@ -651,13 +655,11 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
m_frame->Fill_Zone( zone );
zone->SetIsFilled( true );
ratsnest->Update( zone );
getView()->Update( zone );
}
commit.Push( _( "Fill Zone" ) );
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
return 0;
}
@ -666,7 +668,7 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
{
BOARD* board = getModel<BOARD>();
RN_DATA* ratsnest = board->GetRatsnest();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
@ -678,13 +680,11 @@ int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
m_frame->Fill_Zone( zone );
zone->SetIsFilled( true );
ratsnest->Update( zone );
getView()->Update( zone );
}
commit.Push( _( "Fill All Zones" ) );
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
return 0;
}
@ -694,7 +694,7 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
@ -708,13 +708,11 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
ratsnest->Update( zone );
getView()->Update( zone );
}
commit.Push( _( "Unfill Zone" ) );
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
return 0;
}
@ -723,7 +721,7 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
{
BOARD* board = getModel<BOARD>();
RN_DATA* ratsnest = board->GetRatsnest();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
@ -735,13 +733,11 @@ int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
ratsnest->Update( zone );
getView()->Update( zone );
}
commit.Push( _( "Unfill All Zones" ) );
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
return 0;
}
@ -808,22 +804,29 @@ int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent )
netcode = curr_area->GetNetCode();
if( firstZone->GetNetCode() != netcode )
continue;
if( firstZone )
{
if( firstZone->GetNetCode() != netcode )
continue;
if( curr_area->GetPriority() != firstZone->GetPriority() )
continue;
if( curr_area->GetPriority() != firstZone->GetPriority() )
continue;
if( curr_area->GetIsKeepout() != firstZone->GetIsKeepout() )
continue;
if( curr_area->GetIsKeepout() != firstZone->GetIsKeepout() )
continue;
if( curr_area->GetLayer() != firstZone->GetLayer() )
continue;
if( curr_area->GetLayer() != firstZone->GetLayer() )
continue;
if( !board->TestAreaIntersection( curr_area, firstZone ) )
continue;
if( !board->TestAreaIntersection( curr_area, firstZone ) )
continue;
toMerge.push_back( curr_area );
toMerge.push_back( curr_area );
}
else
{
toMerge.push_back( curr_area );
}
}
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -1055,6 +1058,31 @@ int PCB_EDITOR_CONTROL::HighlightNetCursor( const TOOL_EVENT& aEvent )
return 0;
}
static bool showLocalRatsnest( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPosition )
{
aFrame->SetAuxOrigin( wxPoint( aPosition.x, aPosition.y ) );
aItem->SetPosition( aPosition );
aView->MarkDirty();
return true;
}
int PCB_EDITOR_CONTROL::ShowLocalRatsnest( const TOOL_EVENT& aEvent )
{
Activate();
auto picker = m_toolMgr->GetTool<PICKER_TOOL>();
assert( picker );
m_frame->SetToolID( ID_PCB_SHOW_1_RATSNEST_BUTT, wxCURSOR_PENCIL, _( "Pick Components for Local Ratsnest" ) );
//picker->SetClickHandler( std::bind( showLocalRatsnest, m_toolMgr, _1 ) );
picker->SetSnapping( false );
picker->Activate();
Wait();
return 0;
}
int PCB_EDITOR_CONTROL::UpdateSelectionRatsnest( const TOOL_EVENT& aEvent )
{

View File

@ -44,7 +44,7 @@
#include <pcbnew_id.h>
#include <wxPcbStruct.h>
#include <pcb_draw_panel_gal.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <tool/tool_manager.h>
#include <gal/graphics_abstraction_layer.h>
#include <view/view_controls.h>

View File

@ -43,7 +43,7 @@ using namespace std::placeholders;
#include <class_zone.h>
#include <class_board.h>
#include <class_module.h>
#include <ratsnest_data.h>
#include <connectivity.h>
// Point editor
TOOL_ACTION PCB_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner",
@ -551,7 +551,7 @@ void POINT_EDITOR::finishItem() const
if( zone->IsFilled() )
{
getEditFrame<PCB_EDIT_FRAME>()->Fill_Zone( zone );
zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
// zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
}
}
}

View File

@ -51,7 +51,7 @@ using namespace std::placeholders;
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include "selection_tool.h"
#include "pcb_bright_box.h"
@ -830,24 +830,24 @@ void SELECTION_TOOL::selectAllItemsConnectedToTrack( TRACK& aSourceTrack )
void SELECTION_TOOL::selectAllItemsConnectedToItem( BOARD_CONNECTED_ITEM& aSourceItem )
{
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
std::list<BOARD_CONNECTED_ITEM*> itemsList;
ratsnest->GetConnectedItems( &aSourceItem, itemsList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
auto connectivity = board()->GetConnectivity();
for( BOARD_CONNECTED_ITEM* i : itemsList )
select( i );
std::list<BOARD_CONNECTED_ITEM*> items;
items = connectivity->GetConnectedItems( &aSourceItem, types );
for( auto item : connectivity->GetConnectedItems( &aSourceItem, types ) )
select( item );
}
void SELECTION_TOOL::selectAllItemsOnNet( int aNetCode )
{
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
std::list<BOARD_CONNECTED_ITEM*> itemsList;
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
auto connectivity = board()->GetConnectivity();
ratsnest->GetNetItems( aNetCode, itemsList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
for( BOARD_CONNECTED_ITEM* i : itemsList )
select( i );
for( auto item : connectivity->GetNetItems( aNetCode, types ) )
select( item );
}
@ -913,12 +913,12 @@ void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
// now we need to find all modules that are connected to each of these nets
// then we need to determine if these modules are in the list of modules
// belonging to this sheet ( modList )
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
//RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
std::list<int> removeCodeList;
for( int netCode : netcodeList )
{
std::list<BOARD_CONNECTED_ITEM*> netPads;
ratsnest->GetNetItems( netCode, netPads, (RN_ITEM_TYPE)( RN_PADS ) );
// ratsnest->GetNetItems( netCode, netPads, (RN_ITEM_TYPE)( RN_PADS ) );
for( BOARD_CONNECTED_ITEM* mitem : netPads )
{
bool found = ( std::find( modList.begin(), modList.end(), mitem->GetParent() ) != modList.end() );
@ -945,7 +945,7 @@ void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
for( int netCode : netcodeList )
{
ratsnest->GetNetItems( netCode, localConnectionList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
//ratsnest->GetNetItems( netCode, localConnectionList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
}
for( BOARD_ITEM* i : modList )

View File

@ -45,7 +45,7 @@ using namespace std::placeholders;
#include <class_zone.h>
#include <class_edge_mod.h>
#include <ratsnest_data.h>
#include <connectivity.h>
#include <tools/selection_tool.h>
#include <tool/tool_manager.h>
@ -383,7 +383,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
bool deep_reBuild_ratsnest = false; // true later if pointers must be rebuilt
KIGFX::VIEW* view = GetGalCanvas()->GetView();
RN_DATA* ratsnest = GetBoard()->GetRatsnest();
auto connectivity = GetBoard()->GetConnectivity();
// Undo in the reverse order of list creation: (this can allow stacked changes
// like the same item can be changes and deleted in the same complex command
@ -468,7 +468,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
}
view->Remove( item );
ratsnest->Remove( item );
connectivity->Remove( item );
item->SwapData( image );
@ -482,7 +482,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
}
view->Add( item );
ratsnest->Add( item );
connectivity->Add( item );
item->ClearFlags();
}
@ -518,27 +518,27 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
case UR_MOVED:
item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
view->Update( item, KIGFX::GEOMETRY );
ratsnest->Update( item );
connectivity->Update( item );
break;
case UR_ROTATED:
item->Rotate( aList->m_TransformPoint,
aRedoCommand ? m_rotationAngle : -m_rotationAngle );
view->Update( item, KIGFX::GEOMETRY );
ratsnest->Update( item );
connectivity->Update( item );
break;
case UR_ROTATED_CLOCKWISE:
item->Rotate( aList->m_TransformPoint,
aRedoCommand ? -m_rotationAngle : m_rotationAngle );
view->Update( item, KIGFX::GEOMETRY );
ratsnest->Update( item );
connectivity->Update( item );
break;
case UR_FLIPPED:
item->Flip( aList->m_TransformPoint );
view->Update( item, KIGFX::LAYERS );
ratsnest->Update( item );
connectivity->Update( item );
break;
default:
@ -555,7 +555,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
if( not_found )
wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );
// Rebuild pointers and ratsnest that can be changed.
// Rebuild pointers and connectivity that can be changed.
if( reBuild_ratsnest )
{
// Compile ratsnest propagates nets from pads to tracks
@ -565,10 +565,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
if( IsGalCanvasActive() )
{
if( deep_reBuild_ratsnest )
ratsnest->ProcessBoard();
else
ratsnest->Recalculate();
connectivity->RecalculateRatsnest();
}
}
}

View File

@ -43,7 +43,8 @@
#include <pcbnew.h>
#include <zones.h>
#include <view/view.h>
#include <connectivity.h>
#include <board_commit.h>
#define FORMAT_STRING _( "Filling zone %d out of %d (net %s)..." )
@ -116,11 +117,15 @@ int PCB_EDIT_FRAME::Fill_Zone( ZONE_CONTAINER* aZone )
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
BOARD_COMMIT commit ( this );
commit.Modify( aZone );
aZone->BuildFilledSolidAreasPolygons( GetBoard() );
GetGalCanvas()->GetView()->Update( aZone, KIGFX::ALL );
GetBoard()->GetRatsnest()->Update( aZone );
commit.Push ( _("Fill Zone"), false );
OnModify();
//GetGalCanvas()->GetView()->Update( aZone, KIGFX::ALL );
//GetBoard()->GetConnectivity()->Update( aZone );
//OnModify();
return 0;
}

View File

@ -74,7 +74,7 @@
* To emit zone data to a file when filling zones for the debugging purposes,
* set this 'true' and build.
*/
static const bool g_DumpZonesWhenFilling = false;
static const bool g_DumpZonesWhenFilling = true;
extern void BuildUnconnectedThermalStubsPolygonList( SHAPE_POLY_SET& aCornerBuffer,
BOARD* aPcb, ZONE_CONTAINER* aZone,
@ -437,6 +437,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
SHAPE_POLY_SET solidAreas = *m_smoothedPoly;
printf("VC %d\n", solidAreas.VertexCount());
solidAreas.Inflate( -outline_half_thickness, segsPerCircle );
solidAreas.Simplify( POLY_CALC_MODE );
@ -473,10 +475,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
m_FilledPolysList = areas_fractured;
// Remove insulated islands:
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
SHAPE_POLY_SET thermalHoles;
// Test thermal stubs connections and add polygons to remove unconnected stubs.
@ -506,10 +504,13 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
m_FilledPolysList = th_fractured;
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
}
m_RawPolysList = m_FilledPolysList;
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
if(g_DumpZonesWhenFilling)
dumper->EndGroup();
}

View File

@ -5,7 +5,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -25,78 +25,24 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <fctsys.h>
#include <common.h>
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_zone.h>
#include <pcbnew.h>
#include <zones.h>
#include <polygon_test_point_inside.h>
#include <connectivity.h>
void ZONE_CONTAINER::TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb )
{
if( m_FilledPolysList.IsEmpty() )
return;
std::vector<int> islands;
// Build a list of points connected to the net:
// list of coordinates of pads and vias on this layer and on this net.
std::vector <wxPoint> listPointsCandidates;
auto connectivity = aPcb->GetConnectivity();
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
connectivity->FindIsolatedCopperIslands( this, islands );
std::sort( islands.begin(), islands.end(), std::greater<int>() );
for( auto idx : islands )
{
for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
{
if( !pad->IsOnLayer( GetLayer() ) )
continue;
if( pad->GetNetCode() != GetNetCode() )
continue;
listPointsCandidates.push_back( pad->GetPosition() );
}
m_FilledPolysList.DeletePolygon( idx );
}
for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
{
if( !track->IsOnLayer( GetLayer() ) )
continue;
if( track->GetNetCode() != GetNetCode() )
continue;
listPointsCandidates.push_back( track->GetStart() );
if( track->Type() != PCB_VIA_T )
listPointsCandidates.push_back( track->GetEnd() );
}
// test if a point is inside
for( int outline = 0; outline < m_FilledPolysList.OutlineCount(); outline++ )
{
bool connected = false;
for( unsigned ic = 0; ic < listPointsCandidates.size(); ic++ )
{
// test if this area is connected to a board item:
wxPoint pos = listPointsCandidates[ic];
if( m_FilledPolysList.Contains( VECTOR2I( pos.x, pos.y ), outline ) )
{
connected = true;
break;
}
}
if( !connected ) // this polygon is connected: analyse next polygon
{
m_FilledPolysList.DeletePolygon( outline );
outline--;
}
}
connectivity->Update( this );
}