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:
parent
eaba60b89a
commit
9ad886344b
common
demos/simulation/rectifier
include
pcbnew
CMakeLists.txtboard_commit.cppboard_netlist_updater.cppclass_board.cppclass_board.hclass_board_connected_item.cppclass_board_connected_item.hclass_zone.hconnect.cppconnectivity.cppconnectivity.hconnectivity_algo.cppconnectivity_algo.hdeltrack.cpp
dialogs
drc.cppfiles.cpploadcmp.cppnetlist.cpppcb_draw_panel_gal.cpppcbframe.cppratsnest.cppratsnest_data.cppratsnest_data.hratsnest_viewitem.cppratsnest_viewitem.htools
common_actions.cppedit_tool.cppedit_tool.hpcb_actions.hpcb_editor_control.cpppcbnew_control.cpppoint_editor.cppselection_tool.cpp
undo_redo.cppzones_by_polygon_fill_functions.cppzones_convert_brd_items_to_polygons_with_Boost.cppzones_polygons_insulated_copper_islands.cpp@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,7 +220,7 @@ void ACTION_MANAGER::UpdateHotKeys()
|
||||
++global_actions_cnt;
|
||||
}
|
||||
|
||||
assert( global_actions_cnt <= 1 );
|
||||
// assert( global_actions_cnt <= 1 );
|
||||
}
|
||||
#endif /* not NDEBUG */
|
||||
}
|
||||
|
@ -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
|
||||
|
446
include/geometry/poly_grid_partition.h
Normal file
446
include/geometry/poly_grid_partition.h
Normal 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
|
@ -601,6 +601,7 @@ public:
|
||||
}
|
||||
|
||||
const VECTOR2I PointAlong( int aPathLength ) const;
|
||||
const SHAPE_LINE_CHAIN RemoveHoles( ) const;
|
||||
|
||||
private:
|
||||
/// array of vertices
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
377
pcbnew/connectivity.cpp
Normal 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
204
pcbnew/connectivity.h
Normal 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
|
903
pcbnew/connectivity_algo.cpp
Normal file
903
pcbnew/connectivity_algo.cpp
Normal 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
926
pcbnew/connectivity_algo.h
Normal 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
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user