7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-14 12:49:34 +00:00

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>

Some files were not shown because too many files have changed in this diff Show More