From 9ad886344b057cf117eb81f766c55a045f341ca4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= <tomasz.wlostowski@cern.ch>
Date: Wed, 22 Mar 2017 14:43:10 +0100
Subject: [PATCH] New connectivity algorithm.

---
 common/draw_frame.cpp                         |    2 +-
 common/geometry/hetriang.cpp                  |   24 +-
 common/tool/action_manager.cpp                |    2 +-
 demos/simulation/rectifier/rectifier.pro      |   86 +-
 include/geometry/poly_grid_partition.h        |  446 +++++
 include/geometry/shape_line_chain.h           |    1 +
 include/profile.h                             |   40 -
 include/ttl/halfedge/hedart.h                 |   25 +-
 include/ttl/halfedge/hetriang.h               |  153 +-
 include/wxBasePcbFrame.h                      |    2 +-
 pcbnew/CMakeLists.txt                         |    2 +
 pcbnew/board_commit.cpp                       |   19 +-
 pcbnew/board_netlist_updater.cpp              |    4 +-
 pcbnew/class_board.cpp                        |   15 +-
 pcbnew/class_board.h                          |   14 +-
 pcbnew/class_board_connected_item.cpp         |   14 +-
 pcbnew/class_board_connected_item.h           |    3 +
 pcbnew/class_zone.h                           |    7 +
 pcbnew/connect.cpp                            |   73 +-
 pcbnew/connectivity.cpp                       |  377 ++++
 pcbnew/connectivity.h                         |  204 +++
 pcbnew/connectivity_algo.cpp                  |  903 ++++++++++
 pcbnew/connectivity_algo.h                    |  926 ++++++++++
 pcbnew/deltrack.cpp                           |    8 +-
 ...ialog_general_options_BoardEditor_base.fbp |  104 +-
 pcbnew/dialogs/dialog_global_deletion.cpp     |    2 +-
 pcbnew/dialogs/dialog_netlist.cpp             |    8 +-
 pcbnew/drc.cpp                                |   24 +-
 pcbnew/files.cpp                              |    2 +-
 pcbnew/loadcmp.cpp                            |    2 +-
 pcbnew/netlist.cpp                            |    2 +-
 pcbnew/pcb_draw_panel_gal.cpp                 |    5 +-
 pcbnew/pcbframe.cpp                           |    6 +-
 pcbnew/ratsnest.cpp                           |    2 +-
 pcbnew/ratsnest_data.cpp                      | 1592 +++++------------
 pcbnew/ratsnest_data.h                        |  586 +-----
 pcbnew/ratsnest_viewitem.cpp                  |   88 +-
 pcbnew/ratsnest_viewitem.h                    |    7 +-
 pcbnew/tools/common_actions.cpp               |  809 +++++++++
 pcbnew/tools/edit_tool.cpp                    |   24 +-
 pcbnew/tools/edit_tool.h                      |    8 +
 pcbnew/tools/pcb_actions.h                    |    1 +
 pcbnew/tools/pcb_editor_control.cpp           |   88 +-
 pcbnew/tools/pcbnew_control.cpp               |    2 +-
 pcbnew/tools/point_editor.cpp                 |    4 +-
 pcbnew/tools/selection_tool.cpp               |   30 +-
 pcbnew/undo_redo.cpp                          |   23 +-
 pcbnew/zones_by_polygon_fill_functions.cpp    |   13 +-
 ...nvert_brd_items_to_polygons_with_Boost.cpp |   15 +-
 ...ones_polygons_insulated_copper_islands.cpp |   76 +-
 50 files changed, 4752 insertions(+), 2121 deletions(-)
 create mode 100644 include/geometry/poly_grid_partition.h
 create mode 100644 pcbnew/connectivity.cpp
 create mode 100644 pcbnew/connectivity.h
 create mode 100644 pcbnew/connectivity_algo.cpp
 create mode 100644 pcbnew/connectivity_algo.h
 create mode 100644 pcbnew/tools/common_actions.cpp

diff --git a/common/draw_frame.cpp b/common/draw_frame.cpp
index 42d99c7586..b14d385cca 100644
--- a/common/draw_frame.cpp
+++ b/common/draw_frame.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;
     }
 }
-
diff --git a/common/geometry/hetriang.cpp b/common/geometry/hetriang.cpp
index 01d8405a7c..2654e02c86 100644
--- a/common/geometry/hetriang.cpp
+++ b/common/geometry/hetriang.cpp
@@ -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;
 }
 
 
diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp
index e1cbb0b2aa..40642d603a 100644
--- a/common/tool/action_manager.cpp
+++ b/common/tool/action_manager.cpp
@@ -220,7 +220,7 @@ void ACTION_MANAGER::UpdateHotKeys()
                 ++global_actions_cnt;
         }
 
-        assert( global_actions_cnt <= 1 );
+    //    assert( global_actions_cnt <= 1 );
     }
 #endif /* not NDEBUG */
 }
diff --git a/demos/simulation/rectifier/rectifier.pro b/demos/simulation/rectifier/rectifier.pro
index 33afc2975f..5d2c541683 100644
--- a/demos/simulation/rectifier/rectifier.pro
+++ b/demos/simulation/rectifier/rectifier.pro
@@ -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
diff --git a/include/geometry/poly_grid_partition.h b/include/geometry/poly_grid_partition.h
new file mode 100644
index 0000000000..10de3e5dfa
--- /dev/null
+++ b/include/geometry/poly_grid_partition.h
@@ -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
diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h
index 3b875c45a1..89e54d9b6e 100644
--- a/include/geometry/shape_line_chain.h
+++ b/include/geometry/shape_line_chain.h
@@ -601,6 +601,7 @@ public:
     }
 
     const VECTOR2I PointAlong( int aPathLength ) const;
+    const SHAPE_LINE_CHAIN RemoveHoles( ) const;
 
 private:
     /// array of vertices
diff --git a/include/profile.h b/include/profile.h
index 20eb6da0b3..4a14fc38a7 100644
--- a/include/profile.h
+++ b/include/profile.h
@@ -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
diff --git a/include/ttl/halfedge/hedart.h b/include/ttl/halfedge/hedart.h
index 2749c5087c..7fbb849bf7 100644
--- a/include/ttl/halfedge/hedart.h
+++ b/include/ttl/halfedge/hedart.h
@@ -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;
     }
 
diff --git a/include/ttl/halfedge/hetriang.h b/include/ttl/halfedge/hetriang.h
index fb2742ffac..03ba5f9bc3 100644
--- a/include/ttl/halfedge/hetriang.h
+++ b/include/ttl/halfedge/hetriang.h
@@ -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
diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h
index 5bd389a05a..94604be2a4 100644
--- a/include/wxBasePcbFrame.h
+++ b/include/wxBasePcbFrame.h
@@ -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:
      */
diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index 08e45b4aca..0b42e6514b 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -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
diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp
index 1c421759c1..23e882fd68 100644
--- a/pcbnew/board_commit.cpp
+++ b/pcbnew/board_commit.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();
 }
diff --git a/pcbnew/board_netlist_updater.cpp b/pcbnew/board_netlist_updater.cpp
index 61700d0f59..945da66f2f 100644
--- a/pcbnew/board_netlist_updater.cpp
+++ b/pcbnew/board_netlist_updater.cpp
@@ -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 );
     }
 
diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp
index 09a4642d46..726f0b39c8 100644
--- a/pcbnew/class_board.cpp
+++ b/pcbnew/class_board.cpp
@@ -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();
+}*/
diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h
index f8a0a5abfe..199ac175f3 100644
--- a/pcbnew/class_board.h
+++ b/pcbnew/class_board.h
@@ -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;
     }
 
     /**
diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp
index b02a5c29a1..d33a100c47 100644
--- a/pcbnew/class_board_connected_item.cpp
+++ b/pcbnew/class_board_connected_item.cpp
@@ -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 );
 }
diff --git a/pcbnew/class_board_connected_item.h b/pcbnew/class_board_connected_item.h
index a4e30425c4..947646c89a 100644
--- a/pcbnew/class_board_connected_item.h
+++ b/pcbnew/class_board_connected_item.h
@@ -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
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index f43da75000..ad9ed1d847 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -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
diff --git a/pcbnew/connect.cpp b/pcbnew/connect.cpp
index 1b42fbd73b..4ec1e8b985 100644
--- a/pcbnew/connect.cpp
+++ b/pcbnew/connect.cpp
@@ -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 );
 }
diff --git a/pcbnew/connectivity.cpp b/pcbnew/connectivity.cpp
new file mode 100644
index 0000000000..1180db42bf
--- /dev/null
+++ b/pcbnew/connectivity.cpp
@@ -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();
+}
diff --git a/pcbnew/connectivity.h b/pcbnew/connectivity.h
new file mode 100644
index 0000000000..d04487b8ca
--- /dev/null
+++ b/pcbnew/connectivity.h
@@ -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
diff --git a/pcbnew/connectivity_algo.cpp b/pcbnew/connectivity_algo.cpp
new file mode 100644
index 0000000000..43067fbb0d
--- /dev/null
+++ b/pcbnew/connectivity_algo.cpp
@@ -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();
+
+}
diff --git a/pcbnew/connectivity_algo.h b/pcbnew/connectivity_algo.h
new file mode 100644
index 0000000000..6fde29ab03
--- /dev/null
+++ b/pcbnew/connectivity_algo.h
@@ -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
diff --git a/pcbnew/deltrack.cpp b/pcbnew/deltrack.cpp
index 47f6d8389b..3b3059559c 100644
--- a/pcbnew/deltrack.cpp
+++ b/pcbnew/deltrack.cpp
@@ -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
diff --git a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp
index 1b2e9dd53c..914e8c4f8a 100644
--- a/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp
+++ b/pcbnew/dialogs/dialog_general_options_BoardEditor_base.fbp
@@ -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>
diff --git a/pcbnew/dialogs/dialog_global_deletion.cpp b/pcbnew/dialogs/dialog_global_deletion.cpp
index 0074b71675..8a84970dab 100644
--- a/pcbnew/dialogs/dialog_global_deletion.cpp
+++ b/pcbnew/dialogs/dialog_global_deletion.cpp
@@ -160,7 +160,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete()
 
         masque_layer &= layers_filter;
 
-        for( item = pcb->m_Drawings; item; item = item->Next() )
+        for( item = pcb->DrawingsList(); item; item = item->Next() )
         {
             KICAD_T type = item->Type();
             LAYER_NUM layer = item->GetLayer();
diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp
index bbde033e3a..4ab271245c 100644
--- a/pcbnew/dialogs/dialog_netlist.cpp
+++ b/pcbnew/dialogs/dialog_netlist.cpp
@@ -43,7 +43,7 @@
 #include <class_board_design_settings.h>
 #include <class_board.h>
 #include <class_module.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 #include <wildcards_and_files_ext.h>
 
 #include <dialog_netlist.h>
@@ -330,9 +330,9 @@ void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
 void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
 {
     // Rebuild the board connectivity:
-    if( m_parent->IsGalCanvasActive() )
-        m_parent->GetBoard()->GetRatsnest()->ProcessBoard();
-
+    auto board = m_parent->GetBoard();
+	//board->GetConnectivity()->Build( board );
+	board->GetConnectivity()->PropagateNets();
     m_parent->Compile_Ratsnest( m_dc, true );
 }
 
diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp
index 034622f3d9..0fc321e5e1 100644
--- a/pcbnew/drc.cpp
+++ b/pcbnew/drc.cpp
@@ -42,6 +42,7 @@
 #include <view/view.h>
 #include <geometry/seg.h>
 #include <ratsnest_data.h>
+#include <connectivity.h>
 
 #include <tool/tool_manager.h>
 #include <tools/pcb_actions.h>
@@ -205,7 +206,7 @@ void DRC::RunTests( wxTextCtrl* aMessages )
         }
 
         m_pcbEditorFrame->Compile_Ratsnest( NULL, true );
-        m_pcb->GetRatsnest()->ProcessBoard();
+        //m_pcb->GetRatsnest()->ProcessBoard();
     }
 
     // someone should have cleared the two lists before calling this.
@@ -558,6 +559,25 @@ void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
 
 void DRC::testUnconnected()
 {
+    std::vector<CN_DISJOINT_NET_ENTRY> report;
+
+    auto connectivity = m_pcb->GetConnectivity();
+
+    connectivity->CheckConnectivity( report );
+
+    printf("Connectivity: %d unconnected\n", report.size());
+
+    for( auto ent : report )
+    {
+    /*    DRC_ITEM* uncItem = new DRC_ITEM( DRCE_UNCONNECTED_PADS,
+                                          msg,
+                                          padEnd->GetSelectMenuText(),
+                                          padStart->GetPosition(), padEnd->GetPosition() );*/
+
+    }
+
+
+#if 0
     if( (m_pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
     {
         wxClientDC dc( m_pcbEditorFrame->GetCanvas() );
@@ -588,6 +608,8 @@ void DRC::testUnconnected()
 
         m_unconnected.push_back( uncItem );
     }
+#endif
+
 }
 
 
diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp
index b6a1583da5..947532a6fb 100644
--- a/pcbnew/files.cpp
+++ b/pcbnew/files.cpp
@@ -584,7 +584,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
     {
         wxBusyCursor dummy;    // Displays an Hourglass while building connectivity
         Compile_Ratsnest( NULL, true );
-        GetBoard()->GetRatsnest()->ProcessBoard();
+        //GetBoard()->GetRatsnest()->ProcessBoard();
     }
 
     // Update info shown by the horizontal toolbars
diff --git a/pcbnew/loadcmp.cpp b/pcbnew/loadcmp.cpp
index 00290b9836..3c7c7cab2d 100644
--- a/pcbnew/loadcmp.cpp
+++ b/pcbnew/loadcmp.cpp
@@ -303,7 +303,7 @@ MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary,
         // (Can happen if the lib is an archive built from a board)
         Rotate_Module( NULL, module, 0, false );
 
-        RecalculateAllTracksNetcode();
+        //RecalculateAllTracksNetcode();
 
         if( aDC )
             module->Draw( m_canvas, aDC, GR_OR );
diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp
index 9024ffb20b..1d013425f3 100644
--- a/pcbnew/netlist.cpp
+++ b/pcbnew/netlist.cpp
@@ -170,7 +170,7 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName,
 
     // Rebuild the board connectivity:
     Compile_Ratsnest( NULL, true );
-    board->GetRatsnest()->ProcessBoard();
+    //board->GetRatsnest()->ProcessBoard();
 
     SetMsgPanel( board );
     m_canvas->Refresh();
diff --git a/pcbnew/pcb_draw_panel_gal.cpp b/pcbnew/pcb_draw_panel_gal.cpp
index 15c99e0100..37bf1d2aeb 100644
--- a/pcbnew/pcb_draw_panel_gal.cpp
+++ b/pcbnew/pcb_draw_panel_gal.cpp
@@ -29,6 +29,7 @@
 #include <worksheet_viewitem.h>
 #include <ratsnest_viewitem.h>
 #include <ratsnest_data.h>
+#include <connectivity.h>
 
 #include <class_colors_design_settings.h>
 #include <class_board.h>
@@ -154,7 +155,7 @@ void PCB_DRAW_PANEL_GAL::DisplayBoard( const BOARD* aBoard )
         m_view->Add( zone );
 
     // Ratsnest
-    m_ratsnest.reset( new KIGFX::RATSNEST_VIEWITEM( aBoard->GetRatsnest() ) );
+    m_ratsnest.reset( new KIGFX::RATSNEST_VIEWITEM( aBoard->GetConnectivity() ) );
     m_view->Add( m_ratsnest.get() );
 
     // Display settings
@@ -334,7 +335,7 @@ void PCB_DRAW_PANEL_GAL::GetMsgPanelInfo( std::vector<MSG_PANEL_ITEM>& aList )
     txt.Printf( wxT( "%d" ), board->GetNetCount() );
     aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
 
-    txt.Printf( wxT( "%d" ), board->GetRatsnest()->GetUnconnectedCount() );
+    txt.Printf( wxT( "%d" ), board->GetConnectivity()->GetUnconnectedCount() );
     aList.push_back( MSG_PANEL_ITEM( _( "Unconnected" ), txt, BLUE ) );
 }
 
diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp
index da73f44d11..e1f06dd745 100644
--- a/pcbnew/pcbframe.cpp
+++ b/pcbnew/pcbframe.cpp
@@ -65,7 +65,7 @@
 #include <class_board.h>
 #include <class_module.h>
 #include <worksheet_viewitem.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 #include <ratsnest_viewitem.h>
 
 #include <tool/tool_manager.h>
@@ -509,8 +509,8 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard )
 
     if( IsGalCanvasActive() )
     {
-        aBoard->GetRatsnest()->ProcessBoard();
-
+        aBoard->GetConnectivity()->Build ( aBoard );
+        
         // reload the worksheet
         SetPageSettings( aBoard->GetPageSettings() );
     }
diff --git a/pcbnew/ratsnest.cpp b/pcbnew/ratsnest.cpp
index 21126fefd1..5bde27e269 100644
--- a/pcbnew/ratsnest.cpp
+++ b/pcbnew/ratsnest.cpp
@@ -170,7 +170,7 @@ void PCB_BASE_FRAME::Compile_Ratsnest( wxDC* aDC, bool aDisplayStatus )
     ClearMsgPanel();
 
     // Rebuild the full pads and net info list
-    RecalculateAllTracksNetcode();
+    ComputeLegacyConnections();
 
     if( aDisplayStatus )
     {
diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp
index fb2d6032ce..c9fb1e95e3 100644
--- a/pcbnew/ratsnest_data.cpp
+++ b/pcbnew/ratsnest_data.cpp
@@ -1,9 +1,9 @@
 /*
  * This program source code file is part of KICAD, a free EDA CAD application.
  *
- * Copyright (C) 2013-2015 CERN
- * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
+ * 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
@@ -32,104 +32,77 @@
 #include <omp.h>
 #endif /* USE_OPENMP */
 
+#ifdef PROFILE
+#include <profile.h>
+#endif
+
 #include <ratsnest_data.h>
-
-#include <class_board.h>
-#include <class_module.h>
-#include <class_pad.h>
-#include <class_track.h>
-#include <class_zone.h>
-
 #include <functional>
 using namespace std::placeholders;
 
-#include <geometry/shape_poly_set.h>
-
 #include <cassert>
 #include <algorithm>
 #include <limits>
 
-#ifdef PROFILE
-#include <profile.h>
-#endif
+#include <connectivity_algo.h>
 
-static uint64_t getDistance( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2 )
+static uint64_t getDistance( const CN_ANCHOR_PTR& aNode1, const CN_ANCHOR_PTR& aNode2 )
 {
-    // Drop the least significant bits to avoid overflow
-    int64_t x = ( aNode1->GetX() - aNode2->GetX() ) >> 16;
-    int64_t y = ( aNode1->GetY() - aNode2->GetY() ) >> 16;
+    double  dx = ( aNode1->Pos().x - aNode2->Pos().x );
+    double  dy = ( aNode1->Pos().y - aNode2->Pos().y );
 
-    // We do not need sqrt() here, as the distance is computed only for comparison
-    return ( x * x + y * y );
+    return sqrt( dx * dx + dy * dy );
+}
+
+static bool sortWeight( const CN_EDGE& aEdge1, const CN_EDGE& aEdge2 )
+{
+    return aEdge1.GetWeight() < aEdge2.GetWeight();
 }
 
 
-static bool sortDistance( const RN_NODE_PTR& aOrigin, const RN_NODE_PTR& aNode1,
-                   const RN_NODE_PTR& aNode2 )
+/*bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond )
+ *  {
+ *   return aFirst->GetX() == aSecond->GetX() && aFirst->GetY() == aSecond->GetY();
+ *  }
+ *
+ *  bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond )
+ *  {
+ *   return aFirst->GetX() != aSecond->GetX() || aFirst->GetY() != aSecond->GetY();
+ *  }
+ *
+ *  RN_NODE_AND_FILTER operator&&( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 )
+ *  {
+ *   return RN_NODE_AND_FILTER( aFilter1, aFilter2 );
+ *  }
+ *
+ *  RN_NODE_OR_FILTER operator||( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 )
+ *  {
+ *   return RN_NODE_OR_FILTER( aFilter1, aFilter2 );
+ *  }
+ *
+ *  static bool isEdgeConnectingNode( const RN_EDGE_PTR& aEdge, const RN_NODE_PTR& aNode )
+ *  {
+ *   return aEdge->GetSourceNode() == aNode || aEdge->GetTargetNode() == aNode;
+ *  }
+ */
+
+static const std::vector<CN_EDGE> kruskalMST( std::list<CN_EDGE>& aEdges,
+        std::vector<CN_ANCHOR_PTR>& aNodes )
 {
-    return getDistance( aOrigin, aNode1 ) < getDistance( aOrigin, aNode2 );
-}
-
-
-static bool sortWeight( const RN_EDGE_PTR& aEdge1, const RN_EDGE_PTR& aEdge2 )
-{
-    return aEdge1->GetWeight() < aEdge2->GetWeight();
-}
-
-
-bool sortArea( const RN_POLY& aP1, const RN_POLY& aP2 )
-{
-    return aP1.m_bbox.GetArea() < aP2.m_bbox.GetArea();
-}
-
-
-bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond )
-{
-    return aFirst->GetX() == aSecond->GetX() && aFirst->GetY() == aSecond->GetY();
-}
-
-
-bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond )
-{
-    return aFirst->GetX() != aSecond->GetX() || aFirst->GetY() != aSecond->GetY();
-}
-
-
-RN_NODE_AND_FILTER operator&&( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 )
-{
-    return RN_NODE_AND_FILTER( aFilter1, aFilter2 );
-}
-
-
-RN_NODE_OR_FILTER operator||( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 )
-{
-    return RN_NODE_OR_FILTER( aFilter1, aFilter2 );
-}
-
-
-static bool isEdgeConnectingNode( const RN_EDGE_PTR& aEdge, const RN_NODE_PTR& aNode )
-{
-    return aEdge->GetSourceNode() == aNode || aEdge->GetTargetNode() == aNode;
-}
-
-
-static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
-                                                 std::vector<RN_NODE_PTR>& aNodes )
-{
-    unsigned int nodeNumber = aNodes.size();
-    unsigned int mstExpectedSize = nodeNumber - 1;
-    unsigned int mstSize = 0;
+    unsigned int    nodeNumber = aNodes.size();
+    unsigned int    mstExpectedSize = nodeNumber - 1;
+    unsigned int    mstSize = 0;
     bool ratsnestLines = false;
 
+    //printf("mst nodes : %d edges : %d\n", aNodes.size(), aEdges.size () );
     // The output
-    std::vector<RN_EDGE_MST_PTR>* mst = new std::vector<RN_EDGE_MST_PTR>;
-    mst->reserve( mstExpectedSize );
+    std::vector<CN_EDGE> mst;
 
     // Set tags for marking cycles
-    std::unordered_map<RN_NODE_PTR, int> tags;
+    std::unordered_map<CN_ANCHOR_PTR, int> tags;
     unsigned int tag = 0;
 
-    for( RN_NODE_PTR& node : aNodes )
+    for( auto& node : aNodes )
     {
         node->SetTag( tag );
         tags[node] = tag++;
@@ -137,6 +110,7 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
 
     // Lists of nodes connected together (subtrees) to detect cycles in the graph
     std::vector<std::list<int> > cycles( nodeNumber );
+
     for( unsigned int i = 0; i < nodeNumber; ++i )
         cycles[i].push_back( i );
 
@@ -145,10 +119,11 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
 
     while( mstSize < mstExpectedSize && !aEdges.empty() )
     {
-        RN_EDGE_PTR& dt = aEdges.front();
+        //printf("mstSize %d %d\n", mstSize, mstExpectedSize);
+        auto& dt = aEdges.front();
 
-        int srcTag = tags[dt->GetSourceNode()];
-        int trgTag = tags[dt->GetTargetNode()];
+        int srcTag  = tags[dt.GetSourceNode()];
+        int trgTag  = tags[dt.GetTargetNode()];
 
         // Check if by adding this edge we are going to join two different forests
         if( srcTag != trgTag )
@@ -156,7 +131,7 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
             // Because edges are sorted by their weight, first we always process connected
             // items (weight == 0). Once we stumble upon an edge with non-zero weight,
             // it means that the rest of the lines are ratsnest.
-            if( !ratsnestLines && dt->GetWeight() != 0 )
+            if( !ratsnestLines && dt.GetWeight() != 0 )
                 ratsnestLines = true;
 
             // Update tags
@@ -166,23 +141,22 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
                 {
                     tags[aNodes[*it]] = srcTag;
                 }
+
                 // Do a copy of edge, but make it RN_EDGE_MST. In contrary to RN_EDGE,
                 // RN_EDGE_MST saves both source and target node and does not require any other
                 // edges to exist for getting source/target nodes
-                RN_EDGE_MST_PTR newEdge = std::make_shared<RN_EDGE_MST>( dt->GetSourceNode(),
-                                                                         dt->GetTargetNode(),
-                                                                         dt->GetWeight() );
+                CN_EDGE newEdge ( dt.GetSourceNode(), dt.GetTargetNode(), dt.GetWeight() );
 
-                assert( newEdge->GetSourceNode()->GetTag() != newEdge->GetTargetNode()->GetTag() );
-                assert( newEdge->GetWeight() > 0 );
+                assert( newEdge.GetSourceNode()->GetTag() != newEdge.GetTargetNode()->GetTag() );
+                assert( newEdge.GetWeight() > 0 );
 
-                mst->push_back( newEdge );
+                mst.push_back( newEdge );
                 ++mstSize;
             }
             else
             {
-                //for( it = cycles[trgTag].begin(), itEnd = cycles[trgTag].end(); it != itEnd; ++it )
-                //for( auto it : cycles[trgTag] )
+                // for( it = cycles[trgTag].begin(), itEnd = cycles[trgTag].end(); it != itEnd; ++it )
+                // for( auto it : cycles[trgTag] )
                 for( auto it = cycles[trgTag].begin(); it != cycles[trgTag].end(); ++it )
                 {
                     tags[aNodes[*it]] = srcTag;
@@ -202,172 +176,160 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
     }
 
     // Probably we have discarded some of edges, so reduce the size
-    mst->resize( mstSize );
+    mst.resize( mstSize );
 
     return mst;
 }
 
-
-void RN_NET::validateEdge( RN_EDGE_MST_PTR& aEdge )
+class RN_NET::TRIANGULATOR_STATE
 {
-    RN_NODE_PTR source = aEdge->GetSourceNode();
-    RN_NODE_PTR target = aEdge->GetTargetNode();
-    bool update = false, changed = false;
+private:
+    std::vector<CN_ANCHOR_PTR>  m_allNodes;
+    std::vector<hed::NODE_PTR>  m_triangulationNodes;
 
-    // If any of nodes belonging to the edge has the flag set,
-    // change it to the closest node that has flag cleared
-    // note: finding the right nodes can be done iteratively to get the best results,
-    // but it is not likely to be worth the time cost
-    do
+public:
+
+    void Clear()
     {
-        if( changed || source->GetNoLine() )
+        m_allNodes.clear();
+    }
+
+    void AddNode( CN_ANCHOR_PTR aNode )
+    {
+        m_allNodes.push_back( aNode );
+    }
+
+    const std::list<CN_EDGE> Triangulate()
+    {
+        std::list<CN_EDGE> mstEdges;
+        std::list<hed::EDGE_PTR> triangEdges;
+        std::vector<hed::NODE_PTR> triNodes;
+
+        using ANCHOR_LIST = std::vector<CN_ANCHOR_PTR>;
+        std::vector<ANCHOR_LIST> anchorChains;
+
+        triNodes.reserve( m_allNodes.size() );
+        anchorChains.reserve ( m_allNodes.size() );
+
+        std::sort( m_allNodes.begin(), m_allNodes.end(),
+                [] ( const CN_ANCHOR_PTR& aNode1, const CN_ANCHOR_PTR& aNode2 )
         {
-            changed = false;
-            std::list<RN_NODE_PTR> closest = GetClosestNodes( target,
-                    LINE_TARGET_SAME_TAG( source->GetTag() ) );
-
-            if( !closest.empty() )
+            if( aNode1->Pos().y < aNode2->Pos().y )
+                return true;
+            else if( aNode1->Pos().y == aNode2->Pos().y )
             {
-                RN_NODE_PTR& node = closest.front();
+                return aNode1->Pos().x < aNode2->Pos().x;
+            }
 
-                if( node != source )
-                {
-                    changed = true;
-                    update = true;
-                    source = node;
-                }
+            return false;
+        }
+                );
+
+        CN_ANCHOR_PTR prev, last;
+        int id = 0;
+
+        for( auto n : m_allNodes )
+        {
+            anchorChains.push_back( ANCHOR_LIST() );
+        }
+
+        for( auto n : m_allNodes )
+        {
+            if( !prev || prev->Pos() != n->Pos() )
+            {
+                auto tn = std::make_shared<hed::NODE> ( n->Pos().x, n->Pos().y );
+                tn->SetId( id );
+                triNodes.push_back( tn );
+            }
+
+            id++;
+            prev = n;
+        }
+
+        int prevId = 0;
+
+        for( auto n : triNodes )
+        {
+            for( int i = prevId; i < n->Id(); i++ )
+                anchorChains[prevId].push_back( m_allNodes[ i ] );
+
+            prevId = n->Id();
+        }
+
+        for( int i = prevId; i < id; i++ )
+            anchorChains[prevId].push_back( m_allNodes[ i ] );
+
+
+        hed::TRIANGULATION triangulator;
+        triangulator.CreateDelaunay( triNodes.begin(), triNodes.end() );
+        triangulator.GetEdges( triangEdges );
+
+        for( auto e : triangEdges )
+        {
+            auto    src = m_allNodes[ e->GetSourceNode()->Id() ];
+            auto    dst = m_allNodes[ e->GetTargetNode()->Id() ];
+
+            mstEdges.emplace_back( src, dst, getDistance( src, dst ) );
+        }
+
+        for( int i = 0; i < anchorChains.size(); i++ )
+        {
+            auto& chain = anchorChains[i];
+
+            if( chain.size() < 2 )
+                continue;
+
+            std::sort( chain.begin(), chain.end(),
+                    [] ( const CN_ANCHOR_PTR& a, const CN_ANCHOR_PTR& b ) {
+                return a->GetCluster().get() < b->GetCluster().get();
+            } );
+
+            for( auto j = 1; j < chain.size(); j++ )
+            {
+                const auto& prevNode    = chain[j - 1];
+                const auto& curNode     = chain[j];
+                int weight = prevNode->GetCluster() != curNode->GetCluster() ? 1 : 0;
+                mstEdges.push_back( CN_EDGE ( prevNode, curNode, weight ) );
             }
         }
 
-        if( changed || target->GetNoLine() )
-        {
-            changed = false;
-            std::list<RN_NODE_PTR> closest = GetClosestNodes( source,
-                    LINE_TARGET_SAME_TAG( target->GetTag() ) );
-
-            if( !closest.empty() )
-            {
-                RN_NODE_PTR& node = closest.front();
-
-                if( node != target )
-                {
-                    changed = true;
-                    update = true;
-                    target = node;
-                }
-            }
-        }
+        return mstEdges;
     }
-    while( changed );
+};
 
-    assert( source->GetTag() >= 0 && target->GetTag() >= 0 );
-    assert( source->GetTag() != target->GetTag() );
-    assert( source != target );
+#include <profile.h>
 
-    // Replace an invalid edge with new, valid one
-    if( update )
-        aEdge.reset( new RN_EDGE_MST( source, target ) );
-}
-
-
-void RN_NET::removeNode( RN_NODE_PTR& aNode, const BOARD_CONNECTED_ITEM* aParent )
+RN_NET::RN_NET() : m_dirty( true ), m_visible( true )
 {
-    aNode->RemoveParent( aParent );
-
-    if( m_links.RemoveNode( aNode ) )
-    {
-        clearNode( aNode );
-        m_dirty = true;
-    }
+    m_triangulator.reset( new TRIANGULATOR_STATE );
 }
 
-
-void RN_NET::removeEdge( RN_EDGE_MST_PTR& aEdge, const BOARD_CONNECTED_ITEM* aParent )
-{
-    // Save nodes, so they can be cleared later
-    RN_NODE_PTR start = aEdge->GetSourceNode();
-    RN_NODE_PTR end = aEdge->GetTargetNode();
-
-    start->RemoveParent( aParent );
-    end->RemoveParent( aParent );
-
-    // Connection has to be removed before running RemoveNode(),
-    // as RN_NODE influences the reference counter
-    m_links.RemoveConnection( aEdge );
-
-    // Remove nodes associated with the edge. It is done in a safe way, there is a check
-    // if nodes are not used by other edges.
-    if( m_links.RemoveNode( start ) )
-        clearNode( start );
-
-    if( m_links.RemoveNode( end ) )
-        clearNode( end );
-
-    m_dirty = true;
-}
-
-
-const RN_NODE_PTR& RN_LINKS::AddNode( int aX, int aY )
-{
-    RN_NODE_SET::iterator node;
-    bool wasNewElement;
-
-    std::tie( node, wasNewElement ) = m_nodes.emplace( std::make_shared<RN_NODE>( aX, aY ) );
-
-    return *node;
-}
-
-
-bool RN_LINKS::RemoveNode( const RN_NODE_PTR& aNode )
-{
-    if( aNode->GetRefCount() == 0 )
-    {
-        m_nodes.erase( aNode );
-
-        return true;
-    }
-
-    return false;
-}
-
-
-RN_EDGE_MST_PTR RN_LINKS::AddConnection( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2,
-                                         unsigned int aDistance )
-{
-    assert( aNode1 != aNode2 );
-    RN_EDGE_MST_PTR edge = std::make_shared<RN_EDGE_MST>( aNode1, aNode2, aDistance );
-    m_edges.push_back( edge );
-
-    return edge;
-}
-
-
 void RN_NET::compute()
 {
-    const RN_LINKS::RN_NODE_SET& boardNodes = m_links.GetNodes();
-    const RN_LINKS::RN_EDGE_LIST& boardEdges = m_links.GetConnections();
 
     // Special cases do not need complicated algorithms (actually, it does not work well with
     // the Delaunay triangulator)
-    if( boardNodes.size() <= 2 )
+    //printf("compute nodes :  %d\n", m_nodes.size() );
+    if( m_nodes.size() <= 2 )
     {
-        m_rnEdges.reset( new std::vector<RN_EDGE_MST_PTR>( 0 ) );
+        m_rnEdges.clear();
 
         // Check if the only possible connection exists
-        if( boardEdges.size() == 0 && boardNodes.size() == 2 )
+        if( m_boardEdges.size() == 0 && m_nodes.size() == 2 )
         {
-            RN_LINKS::RN_NODE_SET::const_iterator last = ++boardNodes.begin();
+            auto last = ++m_nodes.begin();
 
             // There can be only one possible connection, but it is missing
-            RN_EDGE_MST_PTR edge = std::make_shared<RN_EDGE_MST>( *boardNodes.begin(), *last );
-            edge->GetSourceNode()->SetTag( 0 );
-            edge->GetTargetNode()->SetTag( 1 );
-            m_rnEdges->push_back( edge );
+            CN_EDGE edge (*m_nodes.begin(), *last );
+            edge.GetSourceNode()->SetTag( 0 );
+            edge.GetTargetNode()->SetTag( 1 );
+
+            m_rnEdges.push_back( edge );
         }
         else
         {
-            // Set tags to nodes as connected
-            for( RN_NODE_PTR node : boardNodes )
+            // Set tags to m_nodes as connected
+            for( auto node : m_nodes )
                 node->SetTag( 0 );
         }
 
@@ -375,941 +337,375 @@ void RN_NET::compute()
         return;
     }
 
-    // Move and sort (sorting speeds up) all nodes to a vector for the Delaunay triangulation
-    std::vector<RN_NODE_PTR> nodes( boardNodes.size() );
-    std::partial_sort_copy( boardNodes.begin(), boardNodes.end(), nodes.begin(), nodes.end() );
 
-    TRIANGULATOR triangulator;
-    triangulator.CreateDelaunay( nodes.begin(), nodes.end() );
-    std::unique_ptr<RN_LINKS::RN_EDGE_LIST> triangEdges( triangulator.GetEdges() );
+    m_triangulator->Clear();
 
-    // Compute weight/distance for edges resulting from triangulation
-    RN_LINKS::RN_EDGE_LIST::iterator eit, eitEnd;
-    for( eit = (*triangEdges).begin(), eitEnd = (*triangEdges).end(); eit != eitEnd; ++eit )
-        (*eit)->SetWeight( getDistance( (*eit)->GetSourceNode(), (*eit)->GetTargetNode() ) );
+    for( auto n : m_nodes )
+    {
+        m_triangulator->AddNode( n );
+    }
 
-    // Add the currently existing connections list to the results of triangulation
-    std::copy( boardEdges.begin(), boardEdges.end(), std::front_inserter( *triangEdges ) );
+    #ifdef PROFILE
+    PROF_COUNTER cnt("triangulate");
+    #endif
+    auto triangEdges = m_triangulator->Triangulate();
+    #ifdef PROFILE
+    cnt.Show();
+    #endif
 
-    // Get the minimal spanning tree
-    m_rnEdges.reset( kruskalMST( *triangEdges, nodes ) );
+    for( const auto& e : m_boardEdges )
+        triangEdges.push_back( e );
+
+// Get the minimal spanning tree
+#ifdef PROFILE
+    PROF_COUNTER cnt2("mst");
+#endif
+    m_rnEdges = kruskalMST( triangEdges, m_nodes );
+#ifdef PROFILE
+    cnt2.Show();
+#endif
 }
 
 
-void RN_NET::clearNode( const RN_NODE_PTR& aNode )
-{
-    if( !m_rnEdges )
-        return;
-
-    std::vector<RN_EDGE_MST_PTR>::iterator newEnd;
-
-    // Remove all ratsnest edges for associated with the node
-    newEnd = std::remove_if( m_rnEdges->begin(), m_rnEdges->end(),
-                             std::bind( isEdgeConnectingNode, _1, std::cref( aNode ) ) );
-
-    m_rnEdges->resize( std::distance( m_rnEdges->begin(), newEnd ) );
-}
-
-
-RN_POLY::RN_POLY( const SHAPE_POLY_SET* aParent,
-                  int aSubpolygonIndex,
-                  RN_LINKS& aConnections, const BOX2I& aBBox ) :
-    m_subpolygonIndex( aSubpolygonIndex ),
-    m_bbox( aBBox ),
-    m_parentPolyset( aParent )
-{
-    const VECTOR2I& p = aParent->CVertex( 0, aSubpolygonIndex, -1 );
-
-    m_node = aConnections.AddNode( p.x, p.y );
-
-    // Mark it as not appropriate as a destination of ratsnest edges
-    // (edges coming out from a polygon vertex look weird)
-    m_node->SetNoLine( true );
-}
-
-
-bool RN_POLY::HitTest( const RN_NODE_PTR& aNode ) const
-{
-    VECTOR2I p( aNode->GetX(), aNode->GetY() );
-
-    return m_parentPolyset->Contains( p, m_subpolygonIndex );
-}
-
 
 void RN_NET::Update()
 {
-    // Add edges resulting from nodes being connected by zones
-    processZones();
-    processPads();
-
     compute();
 
-    for( RN_EDGE_MST_PTR& edge : *m_rnEdges )
-        validateEdge( edge );
-
     m_dirty = false;
 }
 
 
-bool RN_NET::AddItem( const D_PAD* aPad )
+void RN_NET::Clear()
 {
-    // Ratsnest is not computed for non-copper pads
-    if( ( aPad->GetLayerSet() & LSET::AllCuMask() ).none() )
-        return false;
-
-    RN_NODE_PTR node = m_links.AddNode( aPad->GetPosition().x, aPad->GetPosition().y );
-    node->AddParent( aPad );
-    m_pads[aPad].m_Node = node;
-    m_dirty = true;
-
-    return true;
-}
-
-
-bool RN_NET::AddItem( const VIA* aVia )
-{
-    RN_NODE_PTR node = m_links.AddNode( aVia->GetPosition().x, aVia->GetPosition().y );
-    node->AddParent( aVia );
-    m_vias[aVia] = node;
-    m_dirty = true;
-
-    return true;
-}
-
-
-bool RN_NET::AddItem( const TRACK* aTrack )
-{
-    if( aTrack->GetStart() == aTrack->GetEnd() )
-        return false;
-
-    RN_NODE_PTR start = m_links.AddNode( aTrack->GetStart().x, aTrack->GetStart().y );
-    RN_NODE_PTR end = m_links.AddNode( aTrack->GetEnd().x, aTrack->GetEnd().y );
-
-    start->AddParent( aTrack );
-    end->AddParent( aTrack );
-    m_tracks[aTrack] = m_links.AddConnection( start, end );
-    m_dirty = true;
-
-    return true;
-}
-
-
-bool RN_NET::AddItem( const ZONE_CONTAINER* aZone )
-{
-    // Prepare a list of polygons (every zone can contain one or more polygons)
-    const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList();
-
-    // This ensures that we record aZone as added even if it contains no polygons.
-    (void) m_zones[aZone];
-
-    for( int i = 0; i < polySet.OutlineCount(); ++i )
-    {
-        const SHAPE_LINE_CHAIN& path = polySet.COutline( i );
-
-        RN_POLY poly = RN_POLY( &polySet, i, m_links, path.BBox() );
-        m_zones[aZone].m_Polygons.push_back( poly );
-    }
+    m_rnEdges.clear();
+    m_boardEdges.clear();
+    m_nodes.clear();
 
     m_dirty = true;
-
-    return true;
-}
-
-
-bool RN_NET::RemoveItem( const D_PAD* aPad )
-{
-    PAD_NODE_MAP::iterator it = m_pads.find( aPad );
-
-    if( it == m_pads.end() )
-        return false;
-
-    RN_PAD_DATA& pad_data = it->second;
-    removeNode( pad_data.m_Node, aPad );
-
-    for( RN_EDGE_MST_PTR& edge : pad_data.m_Edges )
-        removeEdge( edge, aPad );
-
-    m_pads.erase( aPad );
-
-    return true;
-}
-
-
-bool RN_NET::RemoveItem( const VIA* aVia )
-{
-    VIA_NODE_MAP::iterator it = m_vias.find( aVia );
-
-    if( it == m_vias.end() )
-        return false;
-
-    removeNode( it->second, aVia );
-    m_vias.erase( it );
-
-    return true;
-}
-
-
-bool RN_NET::RemoveItem( const TRACK* aTrack )
-{
-    TRACK_EDGE_MAP::iterator it = m_tracks.find( aTrack );
-
-    if( it == m_tracks.end() )
-        return false;
-
-    removeEdge( it->second, aTrack );
-    m_tracks.erase( it );
-
-    return true;
-}
-
-
-bool RN_NET::RemoveItem( const ZONE_CONTAINER* aZone )
-{
-    ZONE_DATA_MAP::iterator it = m_zones.find( aZone );
-
-    if( it == m_zones.end() )
-        return false;
-
-    RN_ZONE_DATA& zoneData = it->second;
-
-    // Remove all subpolygons that make the zone
-    std::deque<RN_POLY>& polygons = zoneData.m_Polygons;
-    for( RN_POLY& polygon : polygons )
-        removeNode( polygon.GetNode(), aZone );
-    polygons.clear();
-
-    // Remove all connections added by the zone
-    std::deque<RN_EDGE_MST_PTR>& edges = zoneData.m_Edges;
-
-    for( RN_EDGE_MST_PTR edge : edges )
-        removeEdge( edge, aZone );
-
-    edges.clear();
-    m_zones.erase( it );
-
-    return true;
 }
 
+#if 0
 
 const RN_NODE_PTR RN_NET::GetClosestNode( const RN_NODE_PTR& aNode ) const
 {
-    const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
-    RN_LINKS::RN_NODE_SET::const_iterator it, itEnd;
-
-    unsigned int minDistance = std::numeric_limits<unsigned int>::max();
-    RN_NODE_PTR closest;
-
-    for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it )
-    {
-        RN_NODE_PTR node = *it;
-
-        // Obviously the distance between node and itself is the shortest,
-        // that's why we have to skip it
-        if( node != aNode )
-        {
-            unsigned int distance = getDistance( node, aNode );
-            if( distance < minDistance )
-            {
-                minDistance = distance;
-                closest = node;
-            }
-        }
-    }
-
-    return closest;
+    /*const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
+     *  RN_LINKS::RN_NODE_LISt::const_iterator it, itEnd;
+     *
+     *  unsigned int minDistance = std::numeric_limits<unsigned int>::max();
+     *  RN_NODE_PTR closest;
+     *
+     *  for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it )
+     *  {
+     *   RN_NODE_PTR node = *it;
+     *
+     *   // Obviously the distance between node and itself is the shortest,
+     *   // that's why we have to skip it
+     *   if( node != aNode )
+     *   {
+     *       unsigned int distance = getDistance( node, aNode );
+     *       if( distance < minDistance )
+     *       {
+     *           minDistance = distance;
+     *           closest = node;
+     *       }
+     *   }
+     *  }
+     *
+     *  return closest;*/
 }
 
 
 const RN_NODE_PTR RN_NET::GetClosestNode( const RN_NODE_PTR& aNode,
-                                          const RN_NODE_FILTER& aFilter ) const
+        const RN_NODE_FILTER& aFilter ) const
 {
-    const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
-    RN_LINKS::RN_NODE_SET::const_iterator it, itEnd;
-
-    unsigned int minDistance = std::numeric_limits<unsigned int>::max();
-    RN_NODE_PTR closest;
-
-    for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it )
-    {
-        RN_NODE_PTR node = *it;
-
-        // Obviously the distance between node and itself is the shortest,
-        // that's why we have to skip it
-        if( node != aNode && aFilter( node ) )
-        {
-            unsigned int distance = getDistance( node, aNode );
-
-            if( distance < minDistance )
-            {
-                minDistance = distance;
-                closest = node;
-            }
-        }
-    }
-
-    return closest;
+    /*const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
+     *  RN_LINKS::RN_NODE_SET::const_iterator it, itEnd;
+     *
+     *  unsigned int minDistance = std::numeric_limits<unsigned int>::max();
+     *  RN_NODE_PTR closest;
+     *
+     *  for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it )
+     *  {
+     *   RN_NODE_PTR node = *it;
+     *
+     *   // Obviously the distance between node and itself is the shortest,
+     *   // that's why we have to skip it
+     *   if( node != aNode && aFilter( node ) )
+     *   {
+     *       unsigned int distance = getDistance( node, aNode );
+     *
+     *       if( distance < minDistance )
+     *       {
+     *           minDistance = distance;
+     *           closest = node;
+     *       }
+     *   }
+     *  }
+     *
+     *  return closest;*/
 }
 
 
 std::list<RN_NODE_PTR> RN_NET::GetClosestNodes( const RN_NODE_PTR& aNode, int aNumber ) const
 {
-    std::list<RN_NODE_PTR> closest;
-    const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
-
-    // Copy nodes
-    std::copy( nodes.begin(), nodes.end(), std::back_inserter( closest ) );
-
-    // Sort by the distance from aNode
-    closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
-
-    // aNode should not be returned in the results
-    closest.remove( aNode );
-
-    // Trim the result to the asked size
-    if( aNumber > 0 )
-        closest.resize( std::min( (size_t)aNumber, nodes.size() ) );
-
-    return closest;
+    /*std::list<RN_NODE_PTR> closest;
+     *  const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
+     *
+     *  // Copy nodes
+     *  std::copy( nodes.begin(), nodes.end(), std::back_inserter( closest ) );
+     *
+     *  // Sort by the distance from aNode
+     *  closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
+     *
+     *  // aNode should not be returned in the results
+     *  closest.remove( aNode );
+     *
+     *  // Trim the result to the asked size
+     *  if( aNumber > 0 )
+     *   closest.resize( std::min( (size_t)aNumber, nodes.size() ) );
+     *  return closest;*/
 }
 
 
 std::list<RN_NODE_PTR> RN_NET::GetClosestNodes( const RN_NODE_PTR& aNode,
-                                                const RN_NODE_FILTER& aFilter, int aNumber ) const
+        const RN_NODE_FILTER& aFilter, int aNumber ) const
 {
-    std::list<RN_NODE_PTR> closest;
-    const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
-
-    // Copy filtered nodes
-    std::copy_if( nodes.begin(), nodes.end(), std::back_inserter( closest ), std::cref( aFilter ) );
-
-    // Sort by the distance from aNode
-    closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
-
-    // aNode should not be returned in the results
-    closest.remove( aNode );
-
-    // Trim the result to the asked size
-    if( aNumber > 0 )
-        closest.resize( std::min( static_cast<size_t>( aNumber ), nodes.size() ) );
-
-    return closest;
-}
-
-
-void RN_NET::AddSimple( const BOARD_CONNECTED_ITEM* aItem )
-{
-    for( RN_NODE_PTR node : GetNodes( aItem ) )
-    {
-        // Block all nodes, so they do not become targets for dynamic ratsnest lines
-        AddBlockedNode( node );
-
-        // Filter out junctions
-        if( node->GetRefCount() == 1 )
-            m_simpleNodes.insert( node );
-    }
+    /*std::list<RN_NODE_PTR> closest;
+     *  const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
+     *
+     *  // Copy filtered nodes
+     *  std::copy_if( nodes.begin(), nodes.end(), std::back_inserter( closest ), std::cref( aFilter ) );
+     *
+     *  // Sort by the distance from aNode
+     *  closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
+     *
+     *  // aNode should not be returned in the results
+     *  closest.remove( aNode );
+     *
+     *  // Trim the result to the asked size
+     *  if( aNumber > 0 )
+     *   closest.resize( std::min( static_cast<size_t>( aNumber ), nodes.size() ) );
+     *  return closest;*/
 }
 
 
 std::list<RN_NODE_PTR> RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) const
 {
-    std::list<RN_NODE_PTR> nodes;
-
-    switch( aItem->Type() )
-    {
-    case PCB_PAD_T:
-    {
-        PAD_NODE_MAP::const_iterator it = m_pads.find( static_cast<const D_PAD*>( aItem ) );
-
-        if( it != m_pads.end() )
-            nodes.push_back( it->second.m_Node );
-    }
-    break;
-
-    case PCB_VIA_T:
-    {
-        VIA_NODE_MAP::const_iterator it = m_vias.find( static_cast<const VIA*>( aItem ) );
-
-        if( it != m_vias.end() )
-            nodes.push_back( it->second );
-    }
-    break;
-
-    case PCB_TRACE_T:
-    {
-        TRACK_EDGE_MAP::const_iterator it = m_tracks.find( static_cast<const TRACK*>( aItem ) );
-
-        if( it != m_tracks.end() )
-        {
-            nodes.push_back( it->second->GetSourceNode() );
-            nodes.push_back( it->second->GetTargetNode() );
-        }
-    }
-    break;
-
-    case PCB_ZONE_AREA_T:
-    {
-        ZONE_DATA_MAP::const_iterator itz = m_zones.find( static_cast<const ZONE_CONTAINER*>( aItem ) );
-
-        if( itz != m_zones.end() )
-        {
-            const std::deque<RN_POLY>& polys = itz->second.m_Polygons;
-
-            for( std::deque<RN_POLY>::const_iterator it = polys.begin(); it != polys.end(); ++it )
-                nodes.push_back( it->GetNode() );
-        }
-    }
-    break;
-
-    default:
-        break;
-    }
-
-    return nodes;
+    /*std::list<RN_NODE_PTR> nodes;
+     *
+     *  switch( aItem->Type() )
+     *  {
+     *  case PCB_PAD_T:
+     *  {
+     *   PAD_NODE_MAP::const_iterator it = m_pads.find( static_cast<const D_PAD*>( aItem ) );
+     *
+     *   if( it != m_pads.end() )
+     *       nodes.push_back( it->second.m_Node );
+     *  }
+     *  break;
+     *
+     *  case PCB_VIA_T:
+     *  {
+     *   VIA_NODE_MAP::const_iterator it = m_vias.find( static_cast<const VIA*>( aItem ) );
+     *
+     *   if( it != m_vias.end() )
+     *       nodes.push_back( it->second );
+     *  }
+     *  break;
+     *
+     *  case PCB_TRACE_T:
+     *  {
+     *   TRACK_EDGE_MAP::const_iterator it = m_tracks.find( static_cast<const TRACK*>( aItem ) );
+     *
+     *   if( it != m_tracks.end() )
+     *   {
+     *       nodes.push_back( it->second->GetSourceNode() );
+     *       nodes.push_back( it->second->GetTargetNode() );
+     *   }
+     *  }
+     *  break;
+     *
+     *  case PCB_ZONE_AREA_T:
+     *  {
+     *   ZONE_DATA_MAP::const_iterator itz = m_zones.find( static_cast<const ZONE_CONTAINER*>( aItem ) );
+     *
+     *   if( itz != m_zones.end() )
+     *   {
+     *       const std::deque<RN_POLY>& polys = itz->second.m_Polygons;
+     *
+     *       for( std::deque<RN_POLY>::const_iterator it = polys.begin(); it != polys.end(); ++it )
+     *           nodes.push_back( it->GetNode() );
+     *   }
+     *  }
+     *  break;
+     *
+     *  default:
+     *   break;
+     *  }
+     *
+     *  return nodes;*/
 }
 
 
-void RN_NET::GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, RN_ITEM_TYPE aType ) const
+void RN_NET::GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, const KICAD_T aTypes[] ) const
 {
-    if( aType & RN_PADS )
-    {
-        for( auto it : m_pads )
-            aOutput.push_back( const_cast<D_PAD*>( it.first ) );
-    }
-
-    if( aType & RN_VIAS )
-    {
-        for( auto it : m_vias )
-            aOutput.push_back( const_cast<VIA*>( it.first ) );
-    }
-
-    if( aType & RN_TRACKS )
-    {
-        for( auto it : m_tracks )
-            aOutput.push_back( const_cast<TRACK*>( it.first ) );
-    }
-
-    if( aType & RN_ZONES )
-    {
-        for( auto it : m_zones )
-            aOutput.push_back( const_cast<ZONE_CONTAINER*>( it.first ) );
-    }
-}
-
-
-void RN_NET::ClearSimple()
-{
-    for( const RN_NODE_PTR& node : m_blockedNodes )
-        node->SetNoLine( false );
-
-    m_blockedNodes.clear();
-    m_simpleNodes.clear();
+/*    if( aType & RN_PADS )
+ *   {
+ *       for( auto it : m_pads )
+ *           aOutput.push_back( const_cast<D_PAD*>( it.first ) );
+ *   }
+ *
+ *   if( aType & RN_VIAS )
+ *   {
+ *       for( auto it : m_vias )
+ *           aOutput.push_back( const_cast<VIA*>( it.first ) );
+ *   }
+ *
+ *   if( aType & RN_TRACKS )
+ *   {
+ *       for( auto it : m_tracks )
+ *           aOutput.push_back( const_cast<TRACK*>( it.first ) );
+ *   }
+ *
+ *   if( aType & RN_ZONES )
+ *   {
+ *       for( auto it : m_zones )
+ *           aOutput.push_back( const_cast<ZONE_CONTAINER*>( it.first ) );
+ *   }*/
 }
 
 
 void RN_NET::GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
-                                std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                                RN_ITEM_TYPE aTypes ) const
+        std::list<BOARD_CONNECTED_ITEM*>& aOutput,
+        const KICAD_T aTypes[] ) const
 {
-    std::list<RN_NODE_PTR> nodes = GetNodes( aItem );
-    assert( !nodes.empty() );
-
-    int tag = nodes.front()->GetTag();
-    assert( tag >= 0 );
-
-    if( aTypes & RN_PADS )
-    {
-        for( PAD_NODE_MAP::const_iterator it = m_pads.begin(); it != m_pads.end(); ++it )
-        {
-            if( it->second.m_Node->GetTag() == tag )
-                aOutput.push_back( const_cast<D_PAD*>( it->first ) );
-        }
-    }
-
-    if( aTypes & RN_VIAS )
-    {
-        for( VIA_NODE_MAP::const_iterator it = m_vias.begin(); it != m_vias.end(); ++it )
-        {
-            if( it->second->GetTag() == tag )
-                aOutput.push_back( const_cast<VIA*>( it->first ) );
-        }
-    }
-
-    if( aTypes & RN_TRACKS )
-    {
-        for( TRACK_EDGE_MAP::const_iterator it = m_tracks.begin(); it != m_tracks.end(); ++it )
-        {
-            if( it->second->GetTag() == tag )
-                aOutput.push_back( const_cast<TRACK*>( it->first ) );
-        }
-    }
-
-    if( aTypes & RN_ZONES )
-    {
-        for( ZONE_DATA_MAP::const_iterator it = m_zones.begin(); it != m_zones.end(); ++it )
-        {
-            for( const RN_EDGE_MST_PTR& edge : it->second.m_Edges )
-            {
-                if( edge->GetTag() == tag )
-                {
-                    aOutput.push_back( const_cast<ZONE_CONTAINER*>( it->first ) );
-                    break;
-                }
-            }
-        }
-    }
+/*    std::list<RN_NODE_PTR> nodes = GetNodes( aItem );
+ *   assert( !nodes.empty() );
+ *
+ *   int tag = nodes.front()->GetTag();
+ *   assert( tag >= 0 );
+ *
+ *   if( aTypes & RN_PADS )
+ *   {
+ *       for( PAD_NODE_MAP::const_iterator it = m_pads.begin(); it != m_pads.end(); ++it )
+ *       {
+ *           if( it->second.m_Node->GetTag() == tag )
+ *               aOutput.push_back( const_cast<D_PAD*>( it->first ) );
+ *       }
+ *   }
+ *
+ *   if( aTypes & RN_VIAS )
+ *   {
+ *       for( VIA_NODE_MAP::const_iterator it = m_vias.begin(); it != m_vias.end(); ++it )
+ *       {
+ *           if( it->second->GetTag() == tag )
+ *               aOutput.push_back( const_cast<VIA*>( it->first ) );
+ *       }
+ *   }
+ *
+ *   if( aTypes & RN_TRACKS )
+ *   {
+ *       for( TRACK_EDGE_MAP::const_iterator it = m_tracks.begin(); it != m_tracks.end(); ++it )
+ *       {
+ *           if( it->second->GetTag() == tag )
+ *               aOutput.push_back( const_cast<TRACK*>( it->first ) );
+ *       }
+ *   }
+ *
+ *   if( aTypes & RN_ZONES )
+ *   {
+ *       for( ZONE_DATA_MAP::const_iterator it = m_zones.begin(); it != m_zones.end(); ++it )
+ *       {
+ *           for( const RN_EDGE_MST_PTR& edge : it->second.m_Edges )
+ *           {
+ *               if( edge->GetTag() == tag )
+ *               {
+ *                   aOutput.push_back( const_cast<ZONE_CONTAINER*>( it->first ) );
+ *                   break;
+ *               }
+ *           }
+ *       }
+ *   }*/
 }
 
 
-void RN_DATA::AddSimple( const BOARD_ITEM* aItem )
-{
-    if( aItem->IsConnected() )
-    {
-        const BOARD_CONNECTED_ITEM* item = static_cast<const BOARD_CONNECTED_ITEM*>( aItem );
-        int net = item->GetNetCode();
+// const RN_NODE_PTR& RN_NET::AddNode( int aX, int aY )
+// {
+// return m_links.AddNode( aX, aY );
+// }
 
-        // Do not process orphaned & unconnected items
-        if( net <= NETINFO_LIST::UNCONNECTED )
-            return;
-
-        m_nets[net].AddSimple( item );
-    }
-    else if( aItem->Type() == PCB_MODULE_T )
-    {
-        const MODULE* module = static_cast<const MODULE*>( aItem );
-
-        for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
-            AddSimple( pad );
-    }
-}
-
-
-void RN_DATA::AddBlocked( const BOARD_ITEM* aItem )
-{
-    if( aItem->IsConnected() )
-    {
-        const BOARD_CONNECTED_ITEM* item = static_cast<const BOARD_CONNECTED_ITEM*>( aItem );
-        int net = item->GetNetCode();
-
-        // Do not process orphaned & unconnected items
-        if( net <= NETINFO_LIST::UNCONNECTED )
-            return;
-
-        // Block all nodes belonging to the item
-        for( RN_NODE_PTR node : m_nets[net].GetNodes( item ) )
-            m_nets[net].AddBlockedNode( node );
-    }
-    else if( aItem->Type() == PCB_MODULE_T )
-    {
-        const MODULE* module = static_cast<const MODULE*>( aItem );
-
-        for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
-            AddBlocked( pad );
-    }
-}
-
-
-void RN_DATA::GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
-                                 std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                                 RN_ITEM_TYPE aTypes ) const
-{
-    int net = aItem->GetNetCode();
-
-    if( net < 1 )
-        return;
-
-    assert( net < (int) m_nets.size() );
-
-    m_nets[net].GetConnectedItems( aItem, aOutput, aTypes );
-}
-
-
-void RN_DATA::GetNetItems( int aNetCode, std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                           RN_ITEM_TYPE aTypes ) const
-{
-    if( aNetCode < 1 )
-        return;
-
-    assert( aNetCode < (int) m_nets.size() );
-
-    m_nets[aNetCode].GetAllItems( aOutput, aTypes );
-}
-
-
-bool RN_DATA::AreConnected( const BOARD_CONNECTED_ITEM* aItem, const BOARD_CONNECTED_ITEM* aOther )
-{
-    int net1 = aItem->GetNetCode();
-    int net2 = aOther->GetNetCode();
-
-    if( net1 < 1 || net2 < 1 || net1 != net2 )
-        return false;
-
-    assert( net1 < (int) m_nets.size() && net2 < (int) m_nets.size() );
-
-    // net1 == net2
-    std::list<RN_NODE_PTR> items1 = m_nets[net1].GetNodes( aItem );
-    std::list<RN_NODE_PTR> items2 = m_nets[net1].GetNodes( aOther );
-
-    assert( !items1.empty() && !items2.empty() );
-
-    return ( items1.front()->GetTag() == items2.front()->GetTag() );
-}
-
-
-int RN_DATA::GetUnconnectedCount() const
-{
-    int count = 0;
-
-    for( unsigned i = 0; i < m_nets.size(); ++i )
-    {
-        const std::vector<RN_EDGE_MST_PTR>* unconnected = m_nets[i].GetUnconnected();
-
-        if( unconnected )
-            count += unconnected->size();
-    }
-
-    return count;
-}
-
-
-void RN_NET::processZones()
-{
-    for( ZONE_DATA_MAP::iterator it = m_zones.begin(); it != m_zones.end(); ++it )
-    {
-        const ZONE_CONTAINER* zone = it->first;
-        RN_ZONE_DATA& zoneData = it->second;
-
-        // Reset existing connections
-        for( RN_EDGE_MST_PTR edge : zoneData.m_Edges )
-            m_links.RemoveConnection( edge );
-
-        zoneData.m_Edges.clear();
-        LSET layers = zone->GetLayerSet();
-
-        // Compute new connections
-        RN_LINKS::RN_NODE_SET candidates = m_links.GetNodes();
-        RN_LINKS::RN_NODE_SET::const_iterator point, pointEnd;
-
-        // Sorting by area should speed up the processing, as smaller polygons are computed
-        // faster and may reduce the number of points for further checks
-        std::sort( zoneData.m_Polygons.begin(), zoneData.m_Polygons.end(), sortArea );
-
-        for( std::deque<RN_POLY>::iterator poly = zoneData.m_Polygons.begin(),
-                polyEnd = zoneData.m_Polygons.end(); poly != polyEnd; ++poly )
-        {
-            const RN_NODE_PTR& node = poly->GetNode();
-
-            point = candidates.begin();
-            pointEnd = candidates.end();
-
-            while( point != pointEnd )
-            {
-                if( *point != node && ( (*point)->GetLayers() & layers ).any()
-                        && poly->HitTest( *point ) )
-                {
-                    //(*point)->AddParent( zone );  // do not assign parent for helper links
-
-                    RN_EDGE_MST_PTR connection = m_links.AddConnection( node, *point );
-                    zoneData.m_Edges.push_back( connection );
-
-                    // This point already belongs to a polygon, we do not need to check it anymore
-                    point = candidates.erase( point );
-                    pointEnd = candidates.end();
-                }
-                else
-                {
-                    ++point;
-                }
-            }
-        }
-    }
-}
-
-
-void RN_NET::processPads()
-{
-    for( PAD_NODE_MAP::iterator it = m_pads.begin(); it != m_pads.end(); ++it )
-    {
-        const D_PAD* pad = it->first;
-        RN_NODE_PTR node = it->second.m_Node;
-        std::deque<RN_EDGE_MST_PTR>& edges = it->second.m_Edges;
-
-        // Reset existing connections
-        for( RN_EDGE_MST_PTR edge : edges )
-            m_links.RemoveConnection( edge );
-
-        LSET layers = pad->GetLayerSet();
-        const RN_LINKS::RN_NODE_SET& candidates = m_links.GetNodes();
-        RN_LINKS::RN_NODE_SET::const_iterator point, pointEnd;
-
-        point = candidates.begin();
-        pointEnd = candidates.end();
-
-        while( point != pointEnd )
-        {
-            if( *point != node && ( (*point)->GetLayers() & layers ).any() &&
-                    pad->HitTest( wxPoint( (*point)->GetX(), (*point)->GetY() ) ) )
-            {
-                //(*point)->AddParent( pad );   // do not assign parent for helper links
-
-                RN_EDGE_MST_PTR connection = m_links.AddConnection( node, *point );
-                edges.push_back( connection );
-            }
-
-            ++point;
-        }
-    }
-}
-
-
-bool RN_DATA::Add( const BOARD_ITEM* aItem )
-{
-    int net = NETINFO_LIST::ORPHANED;
-
-    if( aItem->IsConnected() )
-    {
-        net = static_cast<const BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode();
-    }
-    else if( aItem->Type() == PCB_MODULE_T )
-    {
-        const MODULE* module = static_cast<const MODULE*>( aItem );
-
-        for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
-        {
-            net = pad->GetNetCode();
-
-            // Do not process orphaned items
-            if( net <= NETINFO_LIST::ORPHANED )
-                continue;
-
-            Add( pad );
-        }
-
-        return true;
-    }
-    else if( aItem->Type() == PCB_NETINFO_T )
-    {
-        int netCount = m_board->GetNetCount();
-
-        if( (unsigned) netCount > m_nets.size() )
-            m_nets.resize( netCount );
-
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-
-    if( net < 0 )
-        return false;
-
-    // Autoresize is necessary e.g. for module editor
-    if( net >= (int) m_nets.size() )
-        m_nets.resize( net + 1 );
-
-    switch( aItem->Type() )
-    {
-    case PCB_PAD_T:
-        return m_nets[net].AddItem( static_cast<const D_PAD*>( aItem ) );
-        break;
-
-    case PCB_TRACE_T:
-        return m_nets[net].AddItem( static_cast<const TRACK*>( aItem ) );
-        break;
-
-    case PCB_VIA_T:
-        return m_nets[net].AddItem( static_cast<const VIA*>( aItem ) );
-        break;
-
-    case PCB_ZONE_AREA_T:
-        return m_nets[net].AddItem( static_cast<const ZONE_CONTAINER*>( aItem ) );
-        break;
-
-    default:
-        break;
-    }
-
-    return false;
-}
-
-
-bool RN_DATA::Remove( const BOARD_ITEM* aItem )
-{
-    int net = NETINFO_LIST::ORPHANED;
-
-    if( aItem->IsConnected() )
-    {
-        net = static_cast<const BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode();
-    }
-    else if( aItem->Type() == PCB_MODULE_T )
-    {
-        const MODULE* module = static_cast<const MODULE*>( aItem );
-
-        for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
-        {
-            net = pad->GetNetCode();
-
-            // Do not process orphaned items
-            if( net <= NETINFO_LIST::ORPHANED )
-                continue;
-
-            Remove( pad );
-        }
-
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-
-    if( net < 0 )
-        return false;
-
-    // Autoresize is necessary e.g. for module editor
-    if( net >= (int) m_nets.size() )
-    {
-        m_nets.resize( net + 1 );
-        return false;     // if it was resized, then surely the item had not been added before
-    }
-
-    switch( aItem->Type() )
-    {
-    case PCB_PAD_T:
-        return m_nets[net].RemoveItem( static_cast<const D_PAD*>( aItem ) );
-        break;
-
-    case PCB_TRACE_T:
-        return m_nets[net].RemoveItem( static_cast<const TRACK*>( aItem ) );
-        break;
-
-    case PCB_VIA_T:
-        return m_nets[net].RemoveItem( static_cast<const VIA*>( aItem ) );
-        break;
-
-    case PCB_ZONE_AREA_T:
-        return m_nets[net].RemoveItem( static_cast<const ZONE_CONTAINER*>( aItem ) );
-        break;
-
-    default:
-        break;
-    }
-
-    return false;
-}
-
-
-bool RN_DATA::Update( const BOARD_ITEM* aItem )
-{
-    if( Remove( aItem ) )
-    {
-        bool res = Add( aItem );
-        assert( res );
-        (void) res;
-        return true;
-    }
-
-    return false;
-}
-
-
-void RN_DATA::ProcessBoard()
-{
-    int netCount = m_board->GetNetCount();
-    m_nets.clear();
-    m_nets.resize( netCount );
-    int netCode;
-
-    // Iterate over all items that may need to be connected
-    for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
-    {
-        for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
-        {
-            netCode = pad->GetNetCode();
-
-            assert( netCode >= 0 && netCode < netCount );
-
-            if( netCode >= 0 && netCode < netCount )
-                m_nets[netCode].AddItem( pad );
-        }
-    }
-
-    for( TRACK* track = m_board->m_Track; track; track = track->Next() )
-    {
-        netCode = track->GetNetCode();
-
-        assert( netCode >= 0 && netCode < netCount );
-
-        if( netCode >= 0 && netCode < netCount )
-        {
-            if( track->Type() == PCB_VIA_T )
-                m_nets[netCode].AddItem( static_cast<VIA*>( track ) );
-            else if( track->Type() == PCB_TRACE_T )
-                m_nets[netCode].AddItem( track );
-        }
-    }
-
-    for( int i = 0; i < m_board->GetAreaCount(); ++i )
-    {
-        ZONE_CONTAINER* zone = m_board->GetArea( i );
-
-        netCode = zone->GetNetCode();
-
-        assert( netCode >= 0 && netCode < netCount );
-
-        if( netCode >= 0 && netCode < netCount )
-            m_nets[netCode].AddItem( zone );
-    }
-
-    Recalculate();
-}
-
-
-void RN_DATA::Recalculate( int aNet )
-{
-    unsigned int netCount = m_board->GetNetCount();
-
-    if( aNet <= 0 && netCount > 1 )              // Recompute everything
-    {
-#ifdef PROFILE
-    PROF_COUNTER totalRealTime;
 #endif
 
-        unsigned int i;
-
-#ifdef USE_OPENMP
-        #pragma omp parallel shared(netCount) 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 < netCount; ++i )
-            {
-                if( m_nets[i].IsDirty() )
-                    updateNet( i );
-            }
-        }  /* end of parallel section */
-#ifdef PROFILE
-    totalRealTime.Stop();
-    wxLogDebug( "Recalculate all nets: %.1f ms", totalRealTime.msecs() );
-#endif /* PROFILE */
-    }
-    else if( aNet > 0 )         // Recompute only specific net
-    {
-        updateNet( aNet );
-    }
-}
-
-
-void RN_DATA::updateNet( int aNetCode )
+void RN_NET::AddCluster( CN_CLUSTER_PTR aCluster )
 {
-    assert( aNetCode < (int) m_nets.size() );
+    CN_ANCHOR_PTR firstAnchor;
 
-    if( aNetCode < 1 || aNetCode > (int) m_nets.size() )
-        return;
+    for( auto item : *aCluster )
+    {
+        bool isZone = dynamic_cast<CN_ZONE*>(item) != nullptr;
+        auto& anchors = item->Anchors();
+        int nAnchors = isZone ? 1 : anchors.size();
 
-    m_nets[aNetCode].ClearSimple();
-    m_nets[aNetCode].Update();
+        if ( nAnchors > anchors.size() )
+            nAnchors = anchors.size();
+
+        //printf("item %p anchors : %d\n", item, anchors.size() );
+        //printf("add item %p anchors : %d net : %d\n", item, item->Anchors().size(), item->Parent()->GetNetCode() );
+
+        for ( int i = 0; i < nAnchors; i++ )
+        {
+        //    printf("add anchor %p\n", anchors[i].get() );
+
+            anchors[i]->SetCluster( aCluster );
+            m_nodes.push_back(anchors[i]);
+
+            if( firstAnchor )
+            {
+                if( firstAnchor != anchors[i] )
+                {
+                    m_boardEdges.emplace_back( firstAnchor, anchors[i], 0 );
+                }
+            }
+            else
+            {
+                firstAnchor = anchors[i];
+            }
+        }
+    }
+}
+
+bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, CN_ANCHOR_PTR& aNode1,
+        CN_ANCHOR_PTR& aNode2 ) const
+{
+    bool rv = false;
+
+    VECTOR2I::extended_type distMax = VECTOR2I::ECOORD_MAX;
+
+    for( auto nodeA : m_nodes )
+    {
+        for( auto nodeB : aOtherNet.m_nodes )
+        {
+            if( !nodeA->GetNoLine() )
+            {
+                auto squaredDist = (nodeA->Pos() - nodeB->Pos() ).SquaredEuclideanNorm();
+
+                if( squaredDist < distMax )
+                {
+                    rv = true;
+                    distMax = squaredDist;
+                    aNode1  = nodeA;
+                    aNode2  = nodeB;
+                }
+            }
+        }
+    }
+
+    return rv;
+}
+
+
+unsigned int RN_NET::GetNodeCount() const
+{
+    return m_nodes.size();
 }
diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h
index 94d97c4263..67fd8ca0a2 100644
--- a/pcbnew/ratsnest_data.h
+++ b/pcbnew/ratsnest_data.h
@@ -30,50 +30,28 @@
 #ifndef RATSNEST_DATA_H
 #define RATSNEST_DATA_H
 
-#include <ttl/halfedge/hetriang.h>
-#include <ttl/halfedge/hetraits.h>
-
+#include <core/typeinfo.h>
 #include <math/box2.h>
 
 #include <deque>
 #include <unordered_set>
 #include <unordered_map>
 
+#include <ttl/halfedge/hetriang.h>
+#include <ttl/halfedge/hetraits.h>
+
+#include <connectivity_algo.h>
+
 class BOARD;
 class BOARD_ITEM;
 class BOARD_CONNECTED_ITEM;
-class MODULE;
-class D_PAD;
-class VIA;
-class TRACK;
-class ZONE_CONTAINER;
-class SHAPE_POLY_SET;
-
-///> Types of items that are handled by the class
-enum RN_ITEM_TYPE
-{
-    RN_PADS    = 0x01,
-    RN_VIAS    = 0x02,
-    RN_TRACKS  = 0x04,
-    RN_ZONES   = 0x08,
-    RN_ALL     = 0xFF
-};
-
-// Preserve KiCad coding style policy
-typedef hed::NODE           RN_NODE;
-typedef hed::NODE_PTR       RN_NODE_PTR;
-typedef hed::EDGE           RN_EDGE;
-typedef hed::EDGE_PTR       RN_EDGE_PTR;
-typedef hed::EDGE_MST       RN_EDGE_MST;
-typedef hed::TRIANGULATION  TRIANGULATOR;
-typedef std::shared_ptr<hed::EDGE_MST> RN_EDGE_MST_PTR;
-
-bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond );
-bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond );
+class CN_CLUSTER;
+class CN_CONNECTIVITY_ALGO;
 
 struct RN_NODE_OR_FILTER;
 struct RN_NODE_AND_FILTER;
 
+#if 0
 ///> General interface for filtering out nodes in search functions.
 struct RN_NODE_FILTER : public std::unary_function<const RN_NODE_PTR&, bool>
 {
@@ -96,7 +74,7 @@ struct LINE_TARGET : public RN_NODE_FILTER
 {
     bool operator()( const RN_NODE_PTR& aNode ) const override
     {
-        return !aNode->GetNoLine();
+        return true;
     }
 };
 
@@ -109,7 +87,7 @@ struct LINE_TARGET_SAME_TAG : public RN_NODE_FILTER
 
     bool operator()( const RN_NODE_PTR& aNode ) const override
     {
-        return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
+        return aNode->GetTag() == m_tag;
     }
 
 private:
@@ -124,7 +102,7 @@ struct LINE_TARGET_DIFF_TAG : public RN_NODE_FILTER
 
     bool operator()( const RN_NODE_PTR& aNode ) const override
     {
-        return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
+        return aNode->GetTag() != m_tag;
     }
 
 private:
@@ -163,168 +141,26 @@ struct RN_NODE_OR_FILTER : public RN_NODE_FILTER
         const RN_NODE_FILTER& m_filter2;
 };
 
-
 ///> Functor comparing if two nodes are equal by their coordinates. It is required to make set of
 ///> shared pointers work properly.
-struct RN_NODE_COMPARE : std::binary_function<RN_NODE_PTR, RN_NODE_PTR, bool>
+struct RN_NODE_COMPARE : std::binary_function<CN_ANCHOR_PTR, CN_ANCHOR_PTR, bool>
 {
-    bool operator()( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2 ) const
+    bool operator()( const CN_ANCHOR_PTR& aNode1, const CN_ANCHOR_PTR& aNode2 ) const
     {
-        return aNode1 == aNode2;
+        if ( aNode1->GetY() < aNode2->GetY() )
+            return true;
+        else if ( aNode1->GetY() == aNode2->GetY() )
+        {
+            if ( aNode1->GetX() == aNode2->GetX() )
+                return aNode1->GetCluster() < aNode2->GetCluster();
+            else
+                return aNode1->GetX() < aNode2->GetX();
+        }
+        return false;
     }
 };
 
-///> Functor calculating hash for a given node. It is required to make set of shared pointers
-///> work properly.
-struct RN_NODE_HASH : std::unary_function<RN_NODE_PTR, std::size_t>
-{
-    std::size_t operator()( const RN_NODE_PTR& aNode ) const
-    {
-        std::size_t hash = 2166136261u;
-
-        hash ^= aNode->GetX();
-        hash *= 16777619;
-        hash ^= aNode->GetY();
-
-        return hash;
-    }
-};
-
-
-/**
- * Class RN_LINKS
- * Manages data describing nodes and connections for a given net.
- */
-class RN_LINKS
-{
-public:
-    // Helper typedefs
-    typedef std::unordered_set<RN_NODE_PTR, RN_NODE_HASH, RN_NODE_COMPARE> RN_NODE_SET;
-    typedef std::list<RN_EDGE_PTR> RN_EDGE_LIST;
-
-    /**
-     * Function AddNode()
-     * Adds a node with given coordinates and returns pointer to the newly added node. If the node
-     * existed before, only appropriate pointer is returned.
-     * @param aX is the x coordinate of a node.
-     * @param aY is the y coordinate of a node.
-     * @return Pointer to the node with given coordinates.
-     */
-    const RN_NODE_PTR& AddNode( int aX, int aY );
-
-    /**
-     * Function RemoveNode()
-     * Removes a node described by a given node pointer.
-     * @param aNode is a pointer to node to be removed.
-     * @return True if node was removed, false if there were other references, so it was kept.
-     */
-    bool RemoveNode( const RN_NODE_PTR& aNode );
-
-    /**
-     * Function GetNodes()
-     * Returns the set of currently used nodes.
-     * @return The set of currently used nodes.
-     */
-    const RN_NODE_SET& GetNodes() const
-    {
-        return m_nodes;
-    }
-
-    /**
-     * Function AddConnection()
-     * Adds a connection between two nodes and of given distance. Edges with distance equal 0 are
-     * considered to be existing connections. Distance different than 0 means that the connection
-     * is missing.
-     * @param aNode1 is the origin node of a new connection.
-     * @param aNode2 is the end node of a new connection.
-     * @param aDistance is the distance of the connection (0 means that nodes are actually
-     * connected, >0 means a missing connection).
-     */
-    RN_EDGE_MST_PTR AddConnection( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2,
-                                    unsigned int aDistance = 0 );
-
-    /**
-     * Function RemoveConnection()
-     * Removes a connection described by a given edge pointer.
-     * @param aEdge is a pointer to edge to be removed.
-     */
-    void RemoveConnection( const RN_EDGE_PTR& aEdge )
-    {
-        m_edges.remove( aEdge );
-    }
-
-    /**
-     * Function GetConnections()
-     * Returns the list of edges that currently connect nodes.
-     * @return the list of edges that currently connect nodes.
-     */
-    const RN_EDGE_LIST& GetConnections() const
-    {
-        return m_edges;
-    }
-
-protected:
-    ///> Set of nodes that are expected to be connected together (vias, tracks, pads).
-    RN_NODE_SET m_nodes;
-
-    ///> List of edges that currently connect nodes.
-    RN_EDGE_LIST m_edges;
-};
-
-
-/**
- * Class RN_POLY
- * Describes a single subpolygon (ZONE_CONTAINER is supposed to contain one or more of those) and
- * performs fast point-inside-polygon test.
- */
-class RN_POLY
-{
-public:
-    RN_POLY( const SHAPE_POLY_SET* aParent,
-             int aSubpolygonIndex,
-             RN_LINKS& aConnections, const BOX2I& aBBox );
-
-    /**
-     * Function GetNode()
-     * Returns node representing a polygon (it has the same coordinates as the first point of its
-     * bounding polyline.
-     */
-    inline const RN_NODE_PTR& GetNode() const
-    {
-        return m_node;
-    }
-
-    inline RN_NODE_PTR& GetNode()
-    {
-        return m_node;
-    }
-
-    /**
-     * Function HitTest()
-     * Tests if selected node is located within polygon boundaries.
-     * @param aNode is a node to be checked.
-     * @return True is the node is located within polygon boundaries.
-     */
-    bool HitTest( const RN_NODE_PTR& aNode ) const;
-
-private:
-
-    ///> Index of the outline in the parent polygon set
-    int m_subpolygonIndex;
-
-    ///> Bounding box of the polygon.
-    BOX2I m_bbox;
-
-    ///> Polygon set containing the geometry
-    const SHAPE_POLY_SET* m_parentPolyset;
-
-    ///> Node representing a polygon (it has the same coordinates as the first point of its
-    ///> bounding polyline.
-    RN_NODE_PTR m_node;
-
-    friend bool sortArea( const RN_POLY& aP1, const RN_POLY& aP2 );
-};
-
+#endif
 
 /**
  * Class RN_NET
@@ -334,8 +170,7 @@ class RN_NET
 {
 public:
     ///> Default constructor.
-    RN_NET() : m_dirty( true ), m_visible( true )
-    {}
+    RN_NET();
 
     /**
      * Function SetVisible()
@@ -383,9 +218,9 @@ public:
      * Returns pointer to a vector of edges that makes ratsnest for a given net.
      * @return Pointer to a vector of edges that makes ratsnest for a given net.
      */
-    const std::vector<RN_EDGE_MST_PTR>* GetUnconnected() const
+    const std::vector<CN_EDGE> GetUnconnected() const
     {
-        return m_rnEdges.get();
+        return m_rnEdges;
     }
 
     /**
@@ -393,70 +228,12 @@ public:
      * Recomputes ratsnest for a net.
      */
     void Update();
+    void Clear();
 
-    /**
-     * Function AddItem()
-     * Adds an appropriate node associated with selected pad, so it is
-     * taken into account during ratsnest computations.
-     * @param aPad is a pad for which node is added.
-     */
-    bool AddItem( const D_PAD* aPad );
+    void AddCluster( std::shared_ptr<CN_CLUSTER> aCluster );
 
-    /**
-     * Function AddItem()
-     * Adds an appropriate node associated with selected via, so it is
-     * taken into account during ratsnest computations.
-     * @param aVia is a via for which node is added.
-     */
-    bool AddItem( const VIA* aVia );
 
-    /**
-     * Function AddItem()
-     * Adds appropriate nodes and edges associated with selected track, so they are
-     * taken into account during ratsnest computations.
-     * @param aTrack is a track for which nodes and edges are added.
-     */
-    bool AddItem( const TRACK* aTrack );
-
-    /**
-     * Function AddItem()
-     * Processes zone to split it into subpolygons and adds appropriate nodes for them, so they are
-     * taken into account during ratsnest computations.
-     * @param aZone is a zone to be processed.
-     */
-    bool AddItem( const ZONE_CONTAINER* aZone );
-
-    /**
-     * Function RemoveItem()
-     * Removes all nodes and edges associated with selected pad, so they are not
-     * taken into account during ratsnest computations anymore.
-     * @param aPad is a pad for which nodes and edges are removed.
-     */
-    bool RemoveItem( const D_PAD* aPad );
-
-    /**
-     * Function RemoveItem()
-     * Removes all nodes and edges associated with selected via, so they are not
-     * taken into account during ratsnest computations anymore.
-     * @param aVia is a via for which nodes and edges are removed.
-     */
-    bool RemoveItem( const VIA* aVia );
-
-    /**
-     * Function RemoveItem()
-     * Removes all nodes and edges associated with selected track, so they are not
-     * taken into account during ratsnest computations anymore.
-     * @param aTrack is a track for which nodes and edges are removed.
-     */
-    bool RemoveItem( const TRACK* aTrack );
-
-    /**
-     * Function RemoveItem()
-     * Removes all nodes and edges associated with selected zone, so they are not
-     * taken into account during ratsnest computations anymore.
-     * @param aZone is a zone for which nodes and edges are removed.
-     */
-    bool RemoveItem( const ZONE_CONTAINER* aZone );
+    unsigned int GetNodeCount() const;
 
     /**
      * Function GetNodes()
@@ -464,7 +241,12 @@ public:
      * @param aItem is an item for which the list is generated.
      * @return List of associated nodes.
      */
-    std::list<RN_NODE_PTR> GetNodes( const BOARD_CONNECTED_ITEM* aItem ) const;
+    std::list<CN_ANCHOR_PTR> GetNodes( const BOARD_CONNECTED_ITEM* aItem ) const;
+
+    const std::vector<CN_EDGE>& GetEdges() const
+    {
+        return m_rnEdges;
+    }
 
     /**
      * Function GetAllItems()
@@ -472,14 +254,16 @@ public:
      * @param aOutput is the list that will have items added.
      * @param aType determines the type of added items.
      */
-    void GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, RN_ITEM_TYPE aType = RN_ALL ) const;
+    void GetAllItems( std::list<BOARD_CONNECTED_ITEM*>& aOutput, const KICAD_T aTypes[] ) const;
 
     /**
      * Function GetClosestNode()
      * Returns a single node that lies in the shortest distance from a specific node.
      * @param aNode is the node for which the closest node is searched.
      */
-    const RN_NODE_PTR GetClosestNode( const RN_NODE_PTR& aNode ) const;
+    const CN_ANCHOR_PTR GetClosestNode( const CN_ANCHOR_PTR& aNode ) const;
+
+    bool NearestBicoloredPair( const RN_NET& aOtherNet, CN_ANCHOR_PTR& aNode1, CN_ANCHOR_PTR& aNode2 ) const;
 
     /**
      * Function GetClosestNode()
@@ -488,8 +272,8 @@ public:
      * @param aNode is the node for which the closest node is searched.
      * @param aFilter is a functor that filters nodes.
      */
-    const RN_NODE_PTR GetClosestNode( const RN_NODE_PTR& aNode,
-                                      const RN_NODE_FILTER& aFilter ) const;
+    /*const CN_ANCHOR_PTR GetClosestNode( const RN_NODE_PTR& aNode,
+                                      const RN_NODE_FILTER& aFilter ) const;*/
 
     /**
      * Function GetClosestNodes()
@@ -499,7 +283,7 @@ public:
      * belong to the same net are returned. If asked number is greater than number of possible
      * nodes then the size of list is limited to number of possible nodes.
      */
-    std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode, int aNumber = -1 ) const;
+    //std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode, int aNumber = -1 ) const;
 
     /**
      * Function GetClosestNodes()
@@ -510,291 +294,33 @@ public:
      * belong to the same net are returned. If asked number is greater than number of possible
      * nodes then the size of list is limited to number of possible nodes.
      */
-    std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode,
-                                            const RN_NODE_FILTER& aFilter, int aNumber = -1 ) const;
+    //std::list<RN_NODE_PTR> GetClosestNodes( const RN_NODE_PTR& aNode,
+    //                                        const RN_NODE_FILTER& aFilter, int aNumber = -1 ) const;
 
-    /**
-     * Function AddSimple()
-     * Changes drawing mode for an item to simple (i.e. one ratsnest line per node).
-     * @param aItem is the item that changes its drawing mode.
-     */
-    void AddSimple( const BOARD_CONNECTED_ITEM* aItem );
-
-    /**
-     * Function AddBlockedNode()
-     * Specifies a node as not suitable as a ratsnest line target (i.e. ratsnest lines will not
-     * target the node). The status is cleared after calling ClearSimple().
-     * @param aNode is the node that is not going to be used as a ratsnest line target.
-     */
-    inline void AddBlockedNode( RN_NODE_PTR& aNode )
-    {
-        m_blockedNodes.insert( aNode );
-        aNode->SetNoLine( true );
-    }
-
-    /**
-     * Function GetSimpleNodes()
-     * Returns list of nodes for which ratsnest is drawn in simple mode (i.e. one
-     * ratsnest line per node).
-     * @return list of nodes for which ratsnest is drawn in simple mode.
-     */
-    inline const std::unordered_set<RN_NODE_PTR>& GetSimpleNodes() const
-    {
-        return m_simpleNodes;
-    }
-
-    /**
-     * Function ClearSimple()
-     * Removes all nodes and edges that are used for displaying ratsnest in simple mode.
-     */
-    void ClearSimple();
-
-    /**
-     * Function GetConnectedItems()
-     * Adds items that are connected together to a list.
-     * @param aItem is the reference item to find other connected items.
-     * @param aOutput is the list that will contain found items.
-     * @param aTypes allows to filter by item types.
-     */
-    void GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
-                            std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                            RN_ITEM_TYPE aTypes = RN_ALL ) const;
 
 protected:
-    ///> Validates edge, i.e. modifies source and target nodes for an edge
-    ///> to make sure that they are not ones with the flag set.
-    void validateEdge( RN_EDGE_MST_PTR& aEdge );
-
-    ///> Removes a link between a node and a parent,
-    ///> and clears linked edges if it was the last parent.
-    void removeNode( RN_NODE_PTR& aNode, const BOARD_CONNECTED_ITEM* aParent );
-
-    ///> Removes a link between an edge and a parent,
-    ///> and clears its node data if it was the last parent.
-    void removeEdge( RN_EDGE_MST_PTR& aEdge, const BOARD_CONNECTED_ITEM* aParent );
-
-    ///> Removes all ratsnest edges for a given node.
-    void clearNode( const RN_NODE_PTR& aNode );
-
-    ///> Adds appropriate edges for nodes that are connected by zones.
-    void processZones();
-
-    ///> Adds additional edges to account for connections made by items located in pads areas.
-    void processPads();
-
     ///> Recomputes ratsnset from scratch.
     void compute();
 
-    ////> Stores information about connections for a given net.
-    RN_LINKS m_links;
+    ///> Vector of nodes
+    std::vector<CN_ANCHOR_PTR> m_nodes;
+
+    ///> Vector of edges that make pre-defined connections
+    std::vector<CN_EDGE> m_boardEdges;
 
     ///> Vector of edges that makes ratsnest for a given net.
-    std::shared_ptr< std::vector<RN_EDGE_MST_PTR> > m_rnEdges;
-
-    ///> List of nodes which will not be used as ratsnest target nodes.
-    std::unordered_set<RN_NODE_PTR> m_blockedNodes;
-
-    ///> Nodes to be displayed using the simplified ratsnest algorithm.
-    std::unordered_set<RN_NODE_PTR> m_simpleNodes;
+    std::vector<CN_EDGE> m_rnEdges;
 
     ///> Flag indicating necessity of recalculation of ratsnest for a net.
     bool m_dirty;
 
-    ///> Structure to hold ratsnest data for ZONE_CONTAINER objects.
-    typedef struct
-    {
-        ///> Subpolygons belonging to a zone
-        std::deque<RN_POLY> m_Polygons;
-
-        ///> Connections to other nodes
-        std::deque<RN_EDGE_MST_PTR> m_Edges;
-    } RN_ZONE_DATA;
-
-    ///> Structureo to hold ratsnest data for D_PAD objects.
-    typedef struct
-    {
-        ///> Node representing the pad.
-        RN_NODE_PTR m_Node;
-
-        ///> Helper nodes that make for connections to items located in the pad area.
-        std::deque<RN_EDGE_MST_PTR> m_Edges;
-    } RN_PAD_DATA;
-
-    ///> Helper typedefs
-    typedef std::unordered_map<const D_PAD*, RN_PAD_DATA> PAD_NODE_MAP;
-    typedef std::unordered_map<const VIA*, RN_NODE_PTR> VIA_NODE_MAP;
-    typedef std::unordered_map<const TRACK*, RN_EDGE_MST_PTR> TRACK_EDGE_MAP;
-    typedef std::unordered_map<const ZONE_CONTAINER*, RN_ZONE_DATA> ZONE_DATA_MAP;
-
-    ///> Map that associates nodes in the ratsnest model to respective nodes.
-    PAD_NODE_MAP m_pads;
-
-    ///> Map that associates nodes in the ratsnest model to respective vias.
-    VIA_NODE_MAP m_vias;
-
-    ///> Map that associates edges in the ratsnest model to respective tracks.
-    TRACK_EDGE_MAP m_tracks;
-
-    ///> Map that associates groups of subpolygons in the ratsnest model to respective zones.
-    ZONE_DATA_MAP m_zones;
-
     ///> Visibility flag.
     bool m_visible;
+
+    class TRIANGULATOR_STATE;
+
+    std::shared_ptr<TRIANGULATOR_STATE> m_triangulator;
 };
 
 
-/**
- * Class RN_DATA
- *
- * Stores information about unconnected items for a board.
- */
-class RN_DATA
-{
-public:
-    /**
-     * Default constructor
-     * @param aBoard is the board to be processed in order to look for unconnected items.
-     */
-    RN_DATA( const BOARD* aBoard ) : m_board( aBoard ) {}
-
-    /**
-     * Function Add()
-     * Adds an item to the ratsnest data.
-     * @param aItem is an item to be added.
-     * @return True if operation succeeded.
-     */
-    bool Add( const BOARD_ITEM* aItem );
-
-    /**
-     * Function Remove()
-     * Removes an item from the ratsnest data.
-     * @param aItem is an item to be updated.
-     * @return True if operation succeeded.
-     */
-    bool Remove( const BOARD_ITEM* aItem );
-
-    /**
-     * Function Update()
-     * Updates the ratsnest data for an item.
-     * @param aItem is an item to be updated.
-     * @return True if operation succeeded. The item will not be updated if it was not previously
-     * added to the ratsnest.
-     */
-    bool Update( const BOARD_ITEM* aItem );
-
-    /**
-     * Function AddSimple()
-     * Sets an item to be drawn in simple mode (i.e. one line per node, instead of full ratsnest).
-     * It is used for drawing quick, temporary ratsnest, eg. while moving an item.
-     * @param aItem is an item to be drawn in simple node.
-     */
-    void AddSimple( const BOARD_ITEM* aItem );
-
-    /**
-     * Function AddBlocked()
-     * Specifies an item as not suitable as a ratsnest line target (i.e. ratsnest lines will not
-     * target its node(s)). The status is cleared after calling ClearSimple().
-     * @param aItem is the item of which node(s) are not going to be used as a ratsnest line target.
-     */
-    void AddBlocked( const BOARD_ITEM* aItem );
-
-    /**
-     * Function ClearSimple()
-     * Clears the list of nodes for which ratsnest is drawn in simple mode (one line per node).
-     */
-    void ClearSimple()
-    {
-        for( RN_NET& net : m_nets )
-            net.ClearSimple();
-    }
-
-    /**
-     * Function ProcessBoard()
-     * Prepares data for computing (computes a list of current nodes and connections). It is
-     * required to run only once after loading a board.
-     */
-    void ProcessBoard();
-
-    /**
-     * Function Recalculate()
-     * Recomputes ratsnest for selected net number or all nets that need updating.
-     * @param aNet is a net number. If it is negative, all nets that need updating are recomputed.
-     */
-    void Recalculate( int aNet = -1 );
-
-    /**
-     * Function GetNetCount()
-     * Returns the number of nets handled by the ratsnest.
-     * @return Number of the nets.
-     */
-    int GetNetCount() const
-    {
-        return m_nets.size();
-    }
-
-    /**
-     * Function GetNet()
-     * Returns ratsnest grouped by net numbers.
-     * @param aNetCode is the net code.
-     * @return Ratsnest data for a specified net.
-     */
-    RN_NET& GetNet( int aNetCode )
-    {
-        assert( aNetCode > 0 );     // ratsnest does not handle the unconnected net
-
-        return m_nets[aNetCode];
-    }
-
-    /**
-     * Function GetConnectedItems()
-     * Adds items that are connected together to a list.
-     * @param aItem is the reference item to find other connected items.
-     * @param aOutput is the list that will contain found items.
-     * @param aTypes allows to filter by item types.
-     */
-    void GetConnectedItems( const BOARD_CONNECTED_ITEM* aItem,
-                            std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                            RN_ITEM_TYPE aTypes = RN_ALL ) const;
-
-    /**
-     * Function GetNetItems()
-     * Adds all items that belong to a certain net to a list.
-     * @param aNetCode is the net code.
-     * @param aOutput is the list that will have items added.
-     * @param aTypes allows to filter by item types.
-     */
-    void GetNetItems( int aNetCode, std::list<BOARD_CONNECTED_ITEM*>& aOutput,
-                            RN_ITEM_TYPE aTypes = RN_ALL ) const;
-
-    /**
-     * Function AreConnected()
-     * Checks if two items are connected with copper.
-     * @param aItem is the first item.
-     * @param aOther is the second item.
-     * @return true if they are connected, false otherwise.
-     */
-    bool AreConnected( const BOARD_CONNECTED_ITEM* aItem, const BOARD_CONNECTED_ITEM* aOther );
-
-    /**
-     * Function GetUnconnectedCount()
-     * Returns the number of missing connections.
-     * @return Number of missing connections.
-     */
-    int GetUnconnectedCount() const;
-
-protected:
-    /**
-     * Function updateNet()
-     * Recomputes ratsnest for a single net.
-     * @param aNetCode is the net number to be recomputed.
-     */
-    void updateNet( int aNetCode );
-
-    ///> Board to be processed.
-    const BOARD* m_board;
-
-    ///> Stores information about ratsnest grouped by net numbers.
-    std::vector<RN_NET> m_nets;
-};
-
 #endif /* RATSNEST_DATA_H */
diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp
index 2d8fff6fd4..6e7ce40e70 100644
--- a/pcbnew/ratsnest_viewitem.cpp
+++ b/pcbnew/ratsnest_viewitem.cpp
@@ -29,15 +29,18 @@
 
 #include <ratsnest_viewitem.h>
 #include <ratsnest_data.h>
+#include <connectivity.h>
 #include <gal/graphics_abstraction_layer.h>
 #include <pcb_painter.h>
 #include <layers_id_colors_and_visibility.h>
 
+#include <memory>
+
 #include <view/view.h>
 
 namespace KIGFX {
 
-RATSNEST_VIEWITEM::RATSNEST_VIEWITEM( RN_DATA* aData ) :
+RATSNEST_VIEWITEM::RATSNEST_VIEWITEM(  std::shared_ptr<CONNECTIVITY_DATA> aData ) :
         EDA_ITEM( NOT_USED ), m_data( aData )
 {
 }
@@ -52,63 +55,76 @@ const BOX2I RATSNEST_VIEWITEM::ViewBBox() const
     return bbox;
 }
 
+#include <geometry/seg.h>
+std::vector<SEG> delEdges;
+
+void clearDEdges() { delEdges.clear(); }
+void addDEdge ( SEG edge ) { delEdges.push_back(edge); }
+
 
 void RATSNEST_VIEWITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
 {
+    static const double crossSize = 100000.0;
+
     auto gal = aView->GetGAL();
-    gal->SetIsStroke( true );
+	gal->SetIsStroke( true );
     gal->SetIsFill( false );
     gal->SetLineWidth( 1.0 );
     auto rs = aView->GetPainter()->GetSettings();
     auto color = rs->GetColor( NULL, LAYER_RATSNEST );
+
     int highlightedNet = rs->GetHighlightNetCode();
 
+    gal->SetStrokeColor( color.Brightened( 0.8 ) );
+    for (auto s : delEdges)
+        gal->DrawLine( s.A, s.B );
+
+
+    // Draw the "dynamic" ratsnest (i.e. for objects that may be currently being moved)
+    for( const auto& l : m_data->GetDynamicRatsnest() )
+    {
+        if ( l.a == l.b )
+        {
+            gal->DrawLine( VECTOR2I( l.a.x - crossSize, l.a.y - crossSize ), VECTOR2I( l.b.x + crossSize, l.b.y + crossSize ) );
+            gal->DrawLine( VECTOR2I( l.a.x - crossSize, l.a.y + crossSize ), VECTOR2I( l.b.x + crossSize, l.b.y - crossSize ) );
+        } else {
+            gal->DrawLine( l.a, l.b );
+        }
+    }
+
     // Dynamic ratsnest (for e.g. dragged items)
     for( int i = 1; i < m_data->GetNetCount(); ++i )
     {
-        RN_NET& net = m_data->GetNet( i );
+        RN_NET* net = m_data->GetRatsnestForNet( i );
 
-        if( !net.IsVisible() )
+        if( !net->IsVisible() )
             continue;
 
-        // Set brighter color for the temporary ratsnest
-        gal->SetStrokeColor( color.Brightened( 0.8 ) );
-
-        // Draw the "dynamic" ratsnest (i.e. for objects that may be currently being moved)
-        for( const RN_NODE_PTR& node : net.GetSimpleNodes() )
-        {
-            // Skipping nodes with higher reference count avoids displaying redundant lines
-            if( node->GetRefCount() > 1 )
-                continue;
-
-            RN_NODE_PTR dest = net.GetClosestNode( node, LINE_TARGET() );
-
-            if( dest )
-            {
-                VECTOR2D origin( node->GetX(), node->GetY() );
-                VECTOR2D end( dest->GetX(), dest->GetY() );
-
-                gal->DrawLine( origin, end );
-            }
-        }
-
         // Draw the "static" ratsnest
         if( i != highlightedNet )
             gal->SetStrokeColor( color );  // using the default ratsnest color for not highlighted
 
-        const std::vector<RN_EDGE_MST_PTR>* edges = net.GetUnconnected();
-
-        if( edges == NULL )
-            continue;
-
-        for( const RN_EDGE_MST_PTR& edge : *edges )
+        for( const auto& edge : net->GetUnconnected() )
         {
-            const RN_NODE_PTR& sourceNode = edge->GetSourceNode();
-            const RN_NODE_PTR& targetNode = edge->GetTargetNode();
-            VECTOR2D source( sourceNode->GetX(), sourceNode->GetY() );
-            VECTOR2D target( targetNode->GetX(), targetNode->GetY() );
+            const auto& sourceNode = edge.GetSourceNode();
+            const auto& targetNode = edge.GetTargetNode();
+            const VECTOR2I source( sourceNode->Pos() );
+            const VECTOR2I target( targetNode->Pos() );
 
-            gal->DrawLine( source, target );
+            if ( !sourceNode->GetNoLine() && !targetNode->GetNoLine() )
+            {
+                if ( source == target )
+                {
+                    constexpr int CROSS_SIZE = 200000;
+
+                    gal->DrawLine( VECTOR2I( source.x - CROSS_SIZE, source.y - CROSS_SIZE ), VECTOR2I( source.x + CROSS_SIZE, source.y + CROSS_SIZE ) );
+                    gal->DrawLine( VECTOR2I( source.x - CROSS_SIZE, source.y + CROSS_SIZE ), VECTOR2I( source.x + CROSS_SIZE, source.y - CROSS_SIZE ) );
+                }
+                else
+                {
+                    gal->DrawLine( source, target );
+                }
+            }
         }
     }
 }
diff --git a/pcbnew/ratsnest_viewitem.h b/pcbnew/ratsnest_viewitem.h
index 7573e59ce4..22729a03e5 100644
--- a/pcbnew/ratsnest_viewitem.h
+++ b/pcbnew/ratsnest_viewitem.h
@@ -30,18 +30,19 @@
 #ifndef RATSNEST_VIEWITEM_H
 #define RATSNEST_VIEWITEM_H
 
+#include <memory>
 #include <base_struct.h>
 #include <math/vector2d.h>
 
 class GAL;
-class RN_DATA;
+class CONNECTIVITY_DATA;
 
 namespace KIGFX
 {
 class RATSNEST_VIEWITEM : public EDA_ITEM
 {
 public:
-    RATSNEST_VIEWITEM( RN_DATA* aData );
+    RATSNEST_VIEWITEM( std::shared_ptr<CONNECTIVITY_DATA> aData );
 
     /// @copydoc VIEW_ITEM::ViewBBox()
     const BOX2I ViewBBox() const override;
@@ -69,7 +70,7 @@ public:
 
 protected:
     ///> Object containing ratsnest data.
-    RN_DATA* m_data;
+     std::shared_ptr<CONNECTIVITY_DATA> m_data;
 };
 
 }   // namespace KIGFX
diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp
new file mode 100644
index 0000000000..e4f35c0b14
--- /dev/null
+++ b/pcbnew/tools/common_actions.cpp
@@ -0,0 +1,809 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013-2016 CERN
+ * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
+ * @author Maciej Suminski <maciej.suminski@cern.ch>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "common_actions.h"
+#include <tool/action_manager.h>
+#include <pcbnew_id.h>
+#include <layers_id_colors_and_visibility.h>
+#include <bitmaps.h>
+#include <wx/defs.h>
+#include <hotkeys.h>
+
+// These members are static in class COMMON_ACTIONS: Build them here:
+
+// Selection tool actions
+TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection",
+        AS_GLOBAL, 0,
+        "", "", NULL, AF_ACTIVATE ); // No description, it is not supposed to be shown anywhere
+
+TOOL_ACTION COMMON_ACTIONS::selectionCursor( "pcbnew.InteractiveSelection.Cursor",
+        AS_GLOBAL, 0,
+        "", "" );    // No description, it is not supposed to be shown anywhere
+
+TOOL_ACTION COMMON_ACTIONS::selectItem( "pcbnew.InteractiveSelection.SelectItem",
+        AS_GLOBAL, 0,
+        "", "" );    // No description, it is not supposed to be shown anywhere
+
+TOOL_ACTION COMMON_ACTIONS::unselectItem( "pcbnew.InteractiveSelection.UnselectItem",
+        AS_GLOBAL, 0,
+        "", "" );    // No description, it is not supposed to be shown anywhere
+
+TOOL_ACTION COMMON_ACTIONS::selectionClear( "pcbnew.InteractiveSelection.Clear",
+        AS_GLOBAL, 0,
+        "", "" );    // No description, it is not supposed to be shown anywhere
+
+TOOL_ACTION COMMON_ACTIONS::selectConnection( "pcbnew.InteractiveSelection.SelectConnection",
+        AS_GLOBAL, 'U',
+        _( "Trivial Connection" ), _( "Selects a connection between two junctions." ) );
+
+TOOL_ACTION COMMON_ACTIONS::selectCopper( "pcbnew.InteractiveSelection.SelectCopper",
+        AS_GLOBAL, 'I',
+        _( "Copper Connection" ), _( "Selects whole copper connection." ) );
+
+TOOL_ACTION COMMON_ACTIONS::selectNet( "pcbnew.InteractiveSelection.SelectNet",
+        AS_GLOBAL, 0,
+        _( "Whole Net" ), _( "Selects all tracks & vias belonging to the same net." ) );
+
+TOOL_ACTION COMMON_ACTIONS::selectSameSheet( "pcbnew.InteractiveSelection.SelectSameSheet",
+        AS_GLOBAL,  'P',
+        _( "Same Sheet" ), _( "Selects all modules and tracks in the same schematic sheet" ) );
+
+TOOL_ACTION COMMON_ACTIONS::find( "pcbnew.InteractiveSelection.Find",
+        AS_GLOBAL, 0, //TOOL_ACTION::LegacyHotKey( HK_FIND_ITEM ), // handled by wxWidgets
+        _( "Find Item" ), _( "Searches the document for an item" ), find_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_GET_AND_MOVE_FOOTPRINT ) );
+
+
+// Edit tool actions
+TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_MODULE_WITH_MODEDIT ),
+        _( "Open in Footprint Editor" ),
+        _( "Opens the selected footprint in the Footprint Editor" ),
+        module_editor_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::copyPadToSettings( "pcbnew.InteractiveEdit.copyPadToSettings",
+        AS_GLOBAL, 0,
+        _( "Copy Pad Settings to Current Settings" ),
+        _( "Copies the properties of selected pad to the current template pad settings." ) );
+
+TOOL_ACTION COMMON_ACTIONS::copySettingsToPads( "pcbnew.InteractiveEdit.copySettingsToPads",
+        AS_GLOBAL, 0,
+        _( "Copy Current Settings to Pads" ),
+        _( "Copies the current template pad settings to the selected pad(s)." ) );
+
+TOOL_ACTION COMMON_ACTIONS::globalEditPads( "pcbnew.InteractiveEdit.globalPadEdit",
+        AS_GLOBAL, 0,
+        _( "Global Pad Edition" ),
+        _( "Changes pad properties globally." ), push_pad_settings_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MOVE_ITEM ),
+        _( "Move" ), _( "Moves the selected item(s)" ), move_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drag( "pcbnew.InteractiveEdit.dragItem",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DRAG_TRACK_KEEP_SLOPE ),
+        _( "Drag" ), _( "Drags the selected item(s)" ), drag_track_segment_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::duplicate( "pcbnew.InteractiveEdit.duplicate",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE_ITEM ),
+        _( "Duplicate" ), _( "Duplicates the selected item(s)" ), duplicate_module_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::duplicateIncrement( "pcbnew.InteractiveEdit.duplicateIncrementPads",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE_ITEM_AND_INCREMENT ),
+        _( "Duplicate" ), _( "Duplicates the selected item(s), incrementing pad numbers" ) );
+
+TOOL_ACTION COMMON_ACTIONS::moveExact( "pcbnew.InteractiveEdit.moveExact",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MOVE_ITEM_EXACT ),
+        _( "Move Exactly..." ), _( "Moves the selected item(s) by an exact amount" ),
+        move_module_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::createArray( "pcbnew.InteractiveEdit.createArray",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_CREATE_ARRAY ),
+        _( "Create Array" ), _( "Create array" ), array_module_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::rotateCw( "pcbnew.InteractiveEdit.rotateCw",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ROTATE_ITEM ),
+        _( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ),
+        rotate_cw_xpm, AF_NONE, (void*) 1 );
+
+TOOL_ACTION COMMON_ACTIONS::rotateCcw( "pcbnew.InteractiveEdit.rotateCcw",
+        AS_GLOBAL, MD_SHIFT + 'R',
+        _( "Rotate Counter-clockwise" ), _( "Rotates selected item(s) counter-clockwise" ),
+        rotate_ccw_xpm, AF_NONE, (void*) -1 );
+
+TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_FLIP_ITEM ),
+        _( "Flip" ), _( "Flips selected item(s)" ), swap_layer_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::mirror( "pcbnew.InteractiveEdit.mirror",
+        AS_GLOBAL, 0,
+        _( "Mirror" ), _( "Mirrors selected item" ), mirror_h_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.remove",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_BACK_SPACE ),
+        _( "Remove" ), _( "Deletes selected item(s)" ), delete_xpm,
+        AF_NONE, (void*) REMOVE_FLAGS::NORMAL );
+
+TOOL_ACTION COMMON_ACTIONS::removeAlt( "pcbnew.InteractiveEdit.removeAlt",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DELETE ),
+        _( "Remove (Alternative)" ), _( "Deletes selected item(s)" ), delete_xpm,
+        AF_NONE, (void*) REMOVE_FLAGS::ALT );
+
+TOOL_ACTION COMMON_ACTIONS::exchangeFootprints( "pcbnew.InteractiveEdit.ExchangeFootprints",
+        AS_GLOBAL, 0,
+        _( "Exchange Footprint(s)" ), _( "Change the footprint used for modules" ),
+        import_module_xpm );
+
+
+TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_ITEM ),
+        _( "Properties..." ), _( "Displays item properties dialog" ), editor_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::editModifiedSelection( "pcbnew.InteractiveEdit.ModifiedSelection",
+        AS_GLOBAL, 0,
+        "", "" );
+
+
+// Drawing tool actions
+TOOL_ACTION COMMON_ACTIONS::drawLine( "pcbnew.InteractiveDrawing.line",
+        AS_GLOBAL, 0,
+        _( "Draw Line" ), _( "Draw a line" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawCircle( "pcbnew.InteractiveDrawing.circle",
+        AS_GLOBAL, 0,
+        _( "Draw Circle" ), _( "Draw a circle" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawArc( "pcbnew.InteractiveDrawing.arc",
+        AS_GLOBAL, 0,
+        _( "Draw Arc" ), _( "Draw an arc" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::placeText( "pcbnew.InteractiveDrawing.text",
+        AS_GLOBAL, 0,
+        _( "Add Text" ), _( "Add a text" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawDimension( "pcbnew.InteractiveDrawing.dimension",
+        AS_GLOBAL, 0,
+        _( "Add Dimension" ), _( "Add a dimension" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawZone( "pcbnew.InteractiveDrawing.zone",
+        AS_GLOBAL, 0,
+        _( "Add Filled Zone" ), _( "Add a filled zone" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawKeepout( "pcbnew.InteractiveDrawing.keepout",
+        AS_GLOBAL, 0,
+        _( "Add Keepout Area" ), _( "Add a keepout area" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawZoneCutout( "pcbnew.InteractiveDrawing.zoneCutout",
+        AS_GLOBAL, 0,
+        _( "Add a Zone Cutout" ), _( "Add a cutout area of an existing zone" ),
+        add_zone_cutout_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drawSimilarZone( "pcbnew.InteractiveDrawing.similarZone",
+        AS_GLOBAL, 0,
+        _( "Add a Similar Zone" ), _( "Add a zone with the same settings as an existing zone" ),
+        add_zone_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::placeDXF( "pcbnew.InteractiveDrawing.placeDXF",
+        AS_GLOBAL, 0,
+        "Place DXF", "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::setAnchor( "pcbnew.InteractiveDrawing.setAnchor",
+        AS_GLOBAL, 0,
+        _( "Place the Footprint Anchor" ), _( "Place the footprint anchor" ),
+        NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::incWidth( "pcbnew.InteractiveDrawing.incWidth",
+        AS_CONTEXT, '+',
+        _( "Increase Line Width" ), _( "Increase the line width" ) );
+
+TOOL_ACTION COMMON_ACTIONS::decWidth( "pcbnew.InteractiveDrawing.decWidth",
+        AS_CONTEXT, '-',
+        _( "Decrease Line Width" ), _( "Decrease the line width" ) );
+
+TOOL_ACTION COMMON_ACTIONS::arcPosture( "pcbnew.InteractiveDrawing.arcPosture",
+        AS_CONTEXT, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_POSTURE ),
+        _( "Switch Arc Posture" ), _( "Switch the arc posture" ) );
+
+
+// View Controls
+TOOL_ACTION COMMON_ACTIONS::zoomIn( "common.Control.zoomIn",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_IN ),
+        _( "Zoom In" ), "", zoom_in_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoomOut( "common.Control.zoomOut",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_OUT ),
+        _( "Zoom Out" ), "", zoom_out_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoomInCenter( "common.Control.zoomInCenter",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::zoomOutCenter( "common.Control.zoomOutCenter",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::zoomCenter( "common.Control.zoomCenter",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_CENTER ),
+        _( "Center" ), "", zoom_center_on_screen_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoomFitScreen( "common.Control.zoomFitScreen",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_AUTO ),
+        _( "Zoom Auto" ), "", zoom_fit_in_page_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoomPreset( "common.Control.zoomPreset",
+        AS_GLOBAL, 0,
+        "", "" );
+
+
+// Display modes
+TOOL_ACTION COMMON_ACTIONS::trackDisplayMode( "pcbnew.Control.trackDisplayMode",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_DISPLAY_MODE ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::padDisplayMode( "pcbnew.Control.padDisplayMode",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::viaDisplayMode( "pcbnew.Control.viaDisplayMode",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::zoneDisplayEnable( "pcbnew.Control.zoneDisplayEnable",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::zoneDisplayDisable( "pcbnew.Control.zoneDisplayDisable",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::zoneDisplayOutlines( "pcbnew.Control.zoneDisplayOutlines",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::highContrastMode( "pcbnew.Control.highContrastMode",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_HIGHCONTRAST_MODE ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::highContrastInc( "pcbnew.Control.highContrastInc",
+        AS_GLOBAL, '>',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::highContrastDec( "pcbnew.Control.highContrastDec",
+        AS_GLOBAL, '<',
+        "", "" );
+
+
+// Layer control
+TOOL_ACTION COMMON_ACTIONS::layerTop( "pcbnew.Control.layerTop",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COMPONENT ),
+        "", "", NULL, AF_NONE, (void*) F_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner1( "pcbnew.Control.layerInner1",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER1 ),
+        "", "", NULL, AF_NONE, (void*) In1_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner2( "pcbnew.Control.layerInner2",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER2 ),
+        "", "", NULL, AF_NONE, (void*) In2_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner3( "pcbnew.Control.layerInner3",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER3 ),
+        "", "", NULL, AF_NONE, (void*) In3_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner4( "pcbnew.Control.layerInner4",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER4 ),
+        "", "", NULL, AF_NONE, (void*) In4_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner5( "pcbnew.Control.layerInner5",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER5 ),
+        "", "", NULL, AF_NONE, (void*) In5_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerInner6( "pcbnew.Control.layerInner6",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_INNER6 ),
+        "", "", NULL, AF_NONE, (void*) In6_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerBottom( "pcbnew.Control.layerBottom",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_COPPER ),
+        "", "", NULL, AF_NONE, (void*) B_Cu );
+
+TOOL_ACTION COMMON_ACTIONS::layerNext( "pcbnew.Control.layerNext",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_NEXT ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::layerPrev( "pcbnew.Control.layerPrev",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_LAYER_TO_PREVIOUS ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::layerToggle( "pcbnew.Control.layerToggle",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_THROUGH_VIA ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::layerAlphaInc( "pcbnew.Control.layerAlphaInc",
+        AS_GLOBAL, '}',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::layerAlphaDec( "pcbnew.Control.layerAlphaDec",
+        AS_GLOBAL, '{',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::layerChanged( "pcbnew.Control.layerChanged",
+        AS_GLOBAL, 0,
+        "", "", NULL, AF_NOTIFY );
+
+
+// Grid control
+TOOL_ACTION COMMON_ACTIONS::gridFast1( "common.Control.gridFast1",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_FASTGRID1 ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridFast2( "common.Control.gridFast2",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_FASTGRID2 ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridNext( "common.Control.gridNext",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_NEXT ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridPrev( "common.Control.gridPrev",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_GRID_TO_PREVIOUS ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridSetOrigin( "common.Control.gridSetOrigin",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SET_GRID_ORIGIN ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridResetOrigin( "common.Control.gridResetOrigin",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_RESET_GRID_ORIGIN ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::gridPreset( "common.Control.gridPreset",
+        AS_GLOBAL, 0,
+        "", "" );
+
+// Track & via size control
+TOOL_ACTION COMMON_ACTIONS::trackWidthInc( "pcbnew.EditorControl.trackWidthInc",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_WIDTH_TO_NEXT ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::trackWidthDec( "pcbnew.EditorControl.trackWidthDec",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_TRACK_WIDTH_TO_PREVIOUS ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::viaSizeInc( "pcbnew.EditorControl.viaSizeInc",
+        AS_GLOBAL, '\'',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::viaSizeDec( "pcbnew.EditorControl.viaSizeDec",
+        AS_GLOBAL, '\\',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::trackViaSizeChanged( "pcbnew.EditorControl.trackViaSizeChanged",
+        AS_GLOBAL, 0,
+        "", "", NULL, AF_NOTIFY );
+
+
+// Zone actions
+TOOL_ACTION COMMON_ACTIONS::zoneFill( "pcbnew.EditorControl.zoneFill",
+        AS_GLOBAL, 0,
+        _( "Fill" ), _( "Fill zone(s)" ), fill_zone_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoneFillAll( "pcbnew.EditorControl.zoneFillAll",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_FILL_OR_REFILL ),
+        _( "Fill All" ), _( "Fill all zones" ) );
+
+TOOL_ACTION COMMON_ACTIONS::zoneUnfill( "pcbnew.EditorControl.zoneUnfill",
+        AS_GLOBAL, 0,
+        _( "Unfill" ), _( "Unfill zone(s)" ), zone_unfill_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::zoneUnfillAll( "pcbnew.EditorControl.zoneUnfillAll",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_REMOVE_FILLED ),
+        _( "Unfill All" ), _( "Unfill all zones" ) );
+
+TOOL_ACTION COMMON_ACTIONS::zoneMerge( "pcbnew.EditorControl.zoneMerge",
+        AS_GLOBAL, 0,
+        _( "Merge Zones" ), _( "Merge zones" ) );
+
+TOOL_ACTION COMMON_ACTIONS::zoneDuplicate( "pcbnew.EditorControl.zoneDuplicate",
+        AS_GLOBAL, 0,
+        _( "Duplicate Zone onto Layer" ), _( "Duplicate zone outline onto a different layer" ),
+        zone_duplicate_xpm );
+
+
+TOOL_ACTION COMMON_ACTIONS::placeTarget( "pcbnew.EditorControl.placeTarget",
+        AS_GLOBAL, 0,
+        _( "Add Layer Alignment Target" ), _( "Add a layer alignment target" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::placeModule( "pcbnew.EditorControl.placeModule",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_MODULE ),
+        _( "Add Footprint" ), _( "Add a footprint" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::drillOrigin( "pcbnew.EditorControl.drillOrigin",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::crossProbeSchToPcb( "pcbnew.EditorControl.crossProbSchToPcb",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::toggleLock( "pcbnew.EditorControl.toggleLock",
+        AS_GLOBAL, 'L',
+        "Toggle Lock", "" );
+
+TOOL_ACTION COMMON_ACTIONS::lock( "pcbnew.EditorControl.lock",
+        AS_GLOBAL, 0,
+        _( "Lock" ), "" );
+
+TOOL_ACTION COMMON_ACTIONS::unlock( "pcbnew.EditorControl.unlock",
+        AS_GLOBAL, 0,
+        _( "Unlock" ), "" );
+
+TOOL_ACTION COMMON_ACTIONS::appendBoard( "pcbnew.EditorControl.appendBoard",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::highlightNet( "pcbnew.EditorControl.highlightNet",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::highlightNetCursor( "pcbnew.EditorControl.highlightNetCursor",
+        AS_GLOBAL, 0,
+        "", "" );
+
+
+// Module editor tools
+TOOL_ACTION COMMON_ACTIONS::placePad( "pcbnew.ModuleEditor.placePad",
+        AS_GLOBAL, 0,
+        _( "Add Pad" ), _( "Add a pad" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads",
+        AS_GLOBAL, 0,
+        _( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::copyItems( "pcbnew.ModuleEditor.copyItems",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_COPY_ITEM ),
+        _( "Copy" ), _( "Copy items" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::pasteItems( "pcbnew.ModuleEditor.pasteItems",
+        AS_GLOBAL, MD_CTRL + int( 'V' ),
+        _( "Paste" ), _( "Paste items" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::moduleEdgeOutlines( "pcbnew.ModuleEditor.graphicOutlines",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::moduleTextOutlines( "pcbnew.ModuleEditor.textOutlines",
+       AS_GLOBAL, 0,
+       "", "" );
+
+// Pad tools
+TOOL_ACTION COMMON_ACTIONS::copyPadSettings(
+        "pcbnew.PadTool.CopyPadSettings",
+        AS_GLOBAL, 0,
+        _( "Copy Pad Settings" ), _( "Copy current pad's settings to the board design settings" ),
+        copy_pad_settings_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::applyPadSettings(
+        "pcbnew.PadTool.ApplyPadSettings",
+        AS_GLOBAL, 0,
+        _( "Apply Pad Settings" ), _( "Copy the board design settings pad properties to the current pad" ),
+        apply_pad_settings_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::pushPadSettings(
+        "pcbnew.PadTool.PushPadSettings",
+        AS_GLOBAL, 0,
+        _( "Push Pad Settings" ), _( "Copy the current pad settings to other pads" ),
+        push_pad_settings_xpm );
+
+// Cursor control
+TOOL_ACTION COMMON_ACTIONS::cursorUp( "pcbnew.Control.cursorUp",
+        AS_GLOBAL, WXK_UP, "", "", NULL, AF_NONE, (void*) CURSOR_UP );
+TOOL_ACTION COMMON_ACTIONS::cursorDown( "pcbnew.Control.cursorDown",
+        AS_GLOBAL, WXK_DOWN, "", "" , NULL, AF_NONE, (void*) CURSOR_DOWN );
+TOOL_ACTION COMMON_ACTIONS::cursorLeft( "pcbnew.Control.cursorLeft",
+        AS_GLOBAL, WXK_LEFT, "", "" , NULL, AF_NONE, (void*) CURSOR_LEFT );
+TOOL_ACTION COMMON_ACTIONS::cursorRight( "pcbnew.Control.cursorRight",
+        AS_GLOBAL, WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) CURSOR_RIGHT );
+
+TOOL_ACTION COMMON_ACTIONS::cursorUpFast( "pcbnew.Control.cursorUpFast",
+        AS_GLOBAL, MD_CTRL + WXK_UP, "", "", NULL, AF_NONE, (void*) ( CURSOR_UP | CURSOR_FAST_MOVE ) );
+TOOL_ACTION COMMON_ACTIONS::cursorDownFast( "pcbnew.Control.cursorDownFast",
+        AS_GLOBAL, MD_CTRL + WXK_DOWN, "", "" , NULL, AF_NONE, (void*) ( CURSOR_DOWN | CURSOR_FAST_MOVE ) );
+TOOL_ACTION COMMON_ACTIONS::cursorLeftFast( "pcbnew.Control.cursorLeftFast",
+        AS_GLOBAL, MD_CTRL + WXK_LEFT, "", "" , NULL, AF_NONE, (void*) ( CURSOR_LEFT | CURSOR_FAST_MOVE ) );
+TOOL_ACTION COMMON_ACTIONS::cursorRightFast( "pcbnew.Control.cursorRightFast",
+        AS_GLOBAL, MD_CTRL + WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) ( CURSOR_RIGHT | CURSOR_FAST_MOVE ) );
+
+TOOL_ACTION COMMON_ACTIONS::cursorClick( "pcbnew.Control.cursorClick",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_LEFT_CLICK ),
+        "", "", NULL, AF_NONE, (void*) CURSOR_CLICK );
+TOOL_ACTION COMMON_ACTIONS::cursorDblClick( "pcbnew.Control.cursorDblClick",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_LEFT_DCLICK ),
+        "", "", NULL, AF_NONE, (void*) CURSOR_DBL_CLICK );
+
+TOOL_ACTION COMMON_ACTIONS::panUp( "pcbnew.Control.panUp",
+        AS_GLOBAL, MD_SHIFT + WXK_UP, "", "", NULL, AF_NONE, (void*) CURSOR_UP );
+TOOL_ACTION COMMON_ACTIONS::panDown( "pcbnew.Control.panDown",
+        AS_GLOBAL, MD_SHIFT + WXK_DOWN, "", "" , NULL, AF_NONE, (void*) CURSOR_DOWN );
+TOOL_ACTION COMMON_ACTIONS::panLeft( "pcbnew.Control.panLeft",
+        AS_GLOBAL, MD_SHIFT + WXK_LEFT, "", "" , NULL, AF_NONE, (void*) CURSOR_LEFT );
+TOOL_ACTION COMMON_ACTIONS::panRight( "pcbnew.Control.panRight",
+        AS_GLOBAL, MD_SHIFT + WXK_RIGHT, "", "" , NULL, AF_NONE, (void*) CURSOR_RIGHT );
+
+// Miscellaneous
+TOOL_ACTION COMMON_ACTIONS::selectionTool( "pcbnew.Control.selectionTool",
+        AS_GLOBAL, 0,
+        "", "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::zoomTool( "pcbnew.Control.zoomTool",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZOOM_SELECTION ),
+        _( "Zoom to Selection" ), "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::pickerTool( "pcbnew.Picker", AS_GLOBAL, 0, "", "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::resetCoords( "pcbnew.Control.resetCoords",
+        AS_GLOBAL, ' ',
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::switchCursor( "pcbnew.Control.switchCursor",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::switchUnits( "pcbnew.Control.switchUnits",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SWITCH_UNITS ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::deleteItemCursor( "pcbnew.Control.deleteItemCursor",
+        AS_GLOBAL, 0,
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::showHelp( "pcbnew.Control.showHelp",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_HELP ),
+        "", "" );
+
+TOOL_ACTION COMMON_ACTIONS::toBeDone( "pcbnew.Control.toBeDone",
+        AS_GLOBAL, 0,           // dialog saying it is not implemented yet
+        "", "" );               // so users are aware of that
+
+TOOL_ACTION COMMON_ACTIONS::showLocalRatsnest( "pcbnew.Control.showLocalRatsnest",
+                AS_GLOBAL, 0,
+                "", "" );               
+
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateSingle( "pcbnew.InteractiveRouter.SingleTrack",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ADD_NEW_TRACK ),
+        _( "Interactive Router (Single Tracks)" ),
+        _( "Run push & shove router (single tracks)" ), ps_router_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateDiffPair( "pcbnew.InteractiveRouter.DiffPair",
+        AS_GLOBAL, '6',
+        _( "Interactive Router (Differential Pairs)" ),
+        _( "Run push & shove router (differential pairs)" ), ps_diff_pair_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateSettingsDialog( "pcbnew.InteractiveRouter.SettingsDialog",
+        AS_GLOBAL, 0,
+        _( "Interactive Router Settings" ),
+        _( "Open Interactive Router settings" ), NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateDpDimensionsDialog( "pcbnew.InteractiveRouter.DpDimensionsDialog",
+        AS_GLOBAL, 0,
+        _( "Differential Pair Dimension settings" ),
+        _( "Open Differential Pair Dimension settings" ), ps_diff_pair_gap_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateTuneSingleTrace( "pcbnew.LengthTuner.TuneSingleTrack",
+        AS_GLOBAL, '7',
+        _( "Tune length of a single track" ), "", ps_tune_length_xpm, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPair( "pcbnew.LengthTuner.TuneDiffPair",
+        AS_GLOBAL, '8',
+        _( "Tune length of a differential pair" ), "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPairSkew( "pcbnew.LengthTuner.TuneDiffPairSkew",
+        AS_GLOBAL, '9',
+        _( "Tune skew of a differential pair" ), "", NULL, AF_ACTIVATE );
+
+TOOL_ACTION COMMON_ACTIONS::routerInlineDrag( "pcbnew.InteractiveRouter.InlineDrag",
+        AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DRAG_TRACK_KEEP_SLOPE ),
+        _( "Drag Track/Via" ), _( "Drags tracks and vias without breaking connections" ),
+        drag_track_segment_xpm );
+
+// Point editor
+TOOL_ACTION COMMON_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner",
+        AS_GLOBAL, 0,
+        _( "Create Corner" ), _( "Create a corner" ), add_corner_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::pointEditorRemoveCorner( "pcbnew.PointEditor.removeCorner",
+        AS_GLOBAL, 0,
+        _( "Remove Corner" ), _( "Remove corner" ), delete_xpm );
+
+// Placement tool
+TOOL_ACTION COMMON_ACTIONS::alignTop( "pcbnew.Place.alignTop",
+        AS_GLOBAL, 0,
+        _( "Align to Top" ),
+        _( "Aligns selected items to the top edge" ), up_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::alignBottom( "pcbnew.Place.alignBottom",
+        AS_GLOBAL, 0,
+        _( "Align to Bottom" ),
+        _( "Aligns selected items to the bottom edge" ), down_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::alignLeft( "pcbnew.Place.alignLeft",
+        AS_GLOBAL, 0,
+        _( "Align to Left" ),
+        _( "Aligns selected items to the left edge" ), left_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::alignRight( "pcbnew.Place.alignRight",
+        AS_GLOBAL, 0,
+        _( "Align to Right" ),
+        _( "Aligns selected items to the right edge" ), right_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::distributeHorizontally( "pcbnew.Place.distributeHorizontally",
+        AS_GLOBAL, 0,
+        _( "Distribute Horizontally" ),
+        _( "Distributes selected items along the horizontal axis" ), distribute_horizontal_xpm );
+
+TOOL_ACTION COMMON_ACTIONS::distributeVertically( "pcbnew.Place.distributeVertically",
+        AS_GLOBAL, 0,
+        _( "Distribute Vertically" ),
+        _( "Distributes selected items along the vertical axis" ), distribute_vertical_xpm );
+
+
+boost::optional<TOOL_EVENT> COMMON_ACTIONS::TranslateLegacyId( int aId )
+{
+    switch( aId )
+    {
+    case ID_PCB_MODULE_BUTT:
+        return COMMON_ACTIONS::placeModule.MakeEvent();
+
+    case ID_TRACK_BUTT:
+        return COMMON_ACTIONS::routerActivateSingle.MakeEvent();
+
+    case ID_DIFF_PAIR_BUTT:
+        return COMMON_ACTIONS::routerActivateDiffPair.MakeEvent();
+
+    case ID_TUNE_SINGLE_TRACK_LEN_BUTT:
+        return COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent();
+
+    case ID_TUNE_DIFF_PAIR_LEN_BUTT:
+        return COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent();
+
+    case ID_TUNE_DIFF_PAIR_SKEW_BUTT:
+        return COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent();
+
+    case ID_MENU_INTERACTIVE_ROUTER_SETTINGS:
+        return COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent();
+
+    case ID_MENU_DIFF_PAIR_DIMENSIONS:
+        return COMMON_ACTIONS::routerActivateDpDimensionsDialog.MakeEvent();
+
+    case ID_PCB_ZONES_BUTT:
+        return COMMON_ACTIONS::drawZone.MakeEvent();
+
+    case ID_PCB_KEEPOUT_AREA_BUTT:
+        return COMMON_ACTIONS::drawKeepout.MakeEvent();
+
+    case ID_PCB_ADD_LINE_BUTT:
+    case ID_MODEDIT_LINE_TOOL:
+        return COMMON_ACTIONS::drawLine.MakeEvent();
+
+    case ID_PCB_CIRCLE_BUTT:
+    case ID_MODEDIT_CIRCLE_TOOL:
+        return COMMON_ACTIONS::drawCircle.MakeEvent();
+
+    case ID_PCB_ARC_BUTT:
+    case ID_MODEDIT_ARC_TOOL:
+        return COMMON_ACTIONS::drawArc.MakeEvent();
+
+    case ID_PCB_ADD_TEXT_BUTT:
+    case ID_MODEDIT_TEXT_TOOL:
+        return COMMON_ACTIONS::placeText.MakeEvent();
+
+    case ID_PCB_DIMENSION_BUTT:
+        return COMMON_ACTIONS::drawDimension.MakeEvent();
+
+    case ID_PCB_MIRE_BUTT:
+        return COMMON_ACTIONS::placeTarget.MakeEvent();
+
+    case ID_MODEDIT_PAD_TOOL:
+        return COMMON_ACTIONS::placePad.MakeEvent();
+
+    case ID_GEN_IMPORT_DXF_FILE:
+        return COMMON_ACTIONS::placeDXF.MakeEvent();
+
+    case ID_MODEDIT_ANCHOR_TOOL:
+        return COMMON_ACTIONS::setAnchor.MakeEvent();
+
+    case ID_PCB_PLACE_GRID_COORD_BUTT:
+    case ID_MODEDIT_PLACE_GRID_COORD:
+        return COMMON_ACTIONS::gridSetOrigin.MakeEvent();
+
+    case ID_ZOOM_IN:        // toolbar button "Zoom In"
+        return COMMON_ACTIONS::zoomInCenter.MakeEvent();
+
+    case ID_ZOOM_OUT:       // toolbar button "Zoom In"
+        return COMMON_ACTIONS::zoomOutCenter.MakeEvent();
+
+    case ID_ZOOM_PAGE:      // toolbar button "Fit on Screen"
+        return COMMON_ACTIONS::zoomFitScreen.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_TRACKS_SKETCH:
+        return COMMON_ACTIONS::trackDisplayMode.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_PADS_SKETCH:
+        return COMMON_ACTIONS::padDisplayMode.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_VIAS_SKETCH:
+        return COMMON_ACTIONS::viaDisplayMode.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_ZONES:
+        return COMMON_ACTIONS::zoneDisplayEnable.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_ZONES_DISABLE:
+        return COMMON_ACTIONS::zoneDisplayDisable.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_ZONES_OUTLINES_ONLY:
+        return COMMON_ACTIONS::zoneDisplayOutlines.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_MODULE_EDGE_SKETCH:
+        return COMMON_ACTIONS::moduleEdgeOutlines.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_MODULE_TEXT_SKETCH:
+        return COMMON_ACTIONS::moduleTextOutlines.MakeEvent();
+
+    case ID_TB_OPTIONS_SHOW_HIGH_CONTRAST_MODE:
+        return COMMON_ACTIONS::highContrastMode.MakeEvent();
+
+    case ID_FIND_ITEMS:
+        return COMMON_ACTIONS::find.MakeEvent();
+
+    case ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST:
+        return COMMON_ACTIONS::findMove.MakeEvent();
+
+    case ID_NO_TOOL_SELECTED:
+        return COMMON_ACTIONS::selectionTool.MakeEvent();
+
+    case ID_ZOOM_SELECTION:
+        return COMMON_ACTIONS::zoomTool.MakeEvent();
+
+    case ID_PCB_DELETE_ITEM_BUTT:
+    case ID_MODEDIT_DELETE_TOOL:
+        return COMMON_ACTIONS::deleteItemCursor.MakeEvent();
+
+    case ID_PCB_PLACE_OFFSET_COORD_BUTT:
+        return COMMON_ACTIONS::drillOrigin.MakeEvent();
+
+    case ID_PCB_HIGHLIGHT_BUTT:
+        return COMMON_ACTIONS::highlightNetCursor.MakeEvent();
+
+    case ID_APPEND_FILE:
+        return COMMON_ACTIONS::appendBoard.MakeEvent();
+
+    case ID_PCB_SHOW_1_RATSNEST_BUTT:
+        return COMMON_ACTIONS::showLocalRatsnest.MakeEvent();
+    }
+
+    return boost::optional<TOOL_EVENT>();
+}
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index 99d5afd118..4a00d4a5b9 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -42,7 +42,7 @@
 #include <view/view_controls.h>
 #include <view/view.h>
 #include <gal/graphics_abstraction_layer.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 #include <confirm.h>
 #include <bitmaps.h>
 #include <hotkeys.h>
@@ -301,6 +301,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
                 {
                     static_cast<BOARD_ITEM*>( item )->Move( movement + m_offset );
                 }
+
+                updateRatsnest( true );
             }
             else if( !m_dragging )    // Prepare to start dragging
             {
@@ -410,6 +412,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
                 // Update dragging offset (distance between cursor and the first dragged item)
                 m_offset = static_cast<BOARD_ITEM*>( selection.Front() )->GetPosition() - modPoint;
                 getView()->Update( &selection );
+                updateRatsnest( true );
             }
         }
 
@@ -422,6 +425,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
         }
     } while( ( evt = Wait() ) ); //Should be assignment not equality test
 
+    getModel<BOARD>()->GetConnectivity()->ClearDynamicRatsnest();
+
     controls->ForceCursorPosition( false );
     controls->ShowCursor( false );
     controls->SetSnapping( false );
@@ -516,6 +521,8 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
 
     if( !m_dragging )
         m_commit->Push( _( "Rotate" ) );
+    else
+        updateRatsnest( true );
 
     if( selection.IsHover() )
         m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@@ -622,6 +629,8 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
 
     if( !m_dragging )
         m_commit->Push( _( "Mirror" ) );
+    else
+        updateRatsnest( true );
 
     if( selection.IsHover() )
         m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@@ -655,6 +664,8 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
 
     if( !m_dragging )
         m_commit->Push( _( "Flip" ) );
+    else
+        updateRatsnest( true );
 
     if( selection.IsHover() )
         m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@@ -1138,6 +1149,17 @@ void EDIT_TOOL::SetTransitions()
     Go( &EDIT_TOOL::MeasureTool,             PCB_ACTIONS::measureTool.MakeEvent() );
 }
 
+void EDIT_TOOL::updateRatsnest( bool aRedraw )
+{
+    auto& selection = m_selectionTool->GetSelection();
+    auto connectivity = getModel<BOARD>()->GetConnectivity();
+    std::vector<BOARD_ITEM *> items;
+
+    for ( auto item : selection )
+        items.push_back ( static_cast<BOARD_ITEM *>( item ) );
+
+    connectivity->ComputeDynamicRatsnest( items );
+}
 
 wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection )
 {
diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h
index 6ca3d7be0a..821dd0788b 100644
--- a/pcbnew/tools/edit_tool.h
+++ b/pcbnew/tools/edit_tool.h
@@ -32,6 +32,7 @@
 class BOARD_COMMIT;
 class BOARD_ITEM;
 class SELECTION_TOOL;
+class CONNECTIVITY_DATA;
 
 /**
  * Class EDIT_TOOL
@@ -144,6 +145,13 @@ private:
     ///> of edit reference point).
     VECTOR2I m_cursor;
 
+    std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity;
+
+    ///> Updates ratsnest for selected items.
+    ///> @param aRedraw says if selected items should be drawn using the simple mode (e.g. one line
+    ///> per item).
+    void updateRatsnest( bool aRedraw );
+
     ///> Returns the right modification point (e.g. for rotation), depending on the number of
     ///> selected items.
     wxPoint getModificationPoint( const SELECTION& aSelection );
diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h
index c86c97cee7..fadc5d9c38 100644
--- a/pcbnew/tools/pcb_actions.h
+++ b/pcbnew/tools/pcb_actions.h
@@ -356,6 +356,7 @@ public:
     static TOOL_ACTION crossProbeSchToPcb;
     static TOOL_ACTION appendBoard;
     static TOOL_ACTION showHelp;
+    static TOOL_ACTION showLocalRatsnest;
     static TOOL_ACTION toBeDone;
 
     /// Find an item
diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp
index 83305988c3..3baeb7ee92 100644
--- a/pcbnew/tools/pcb_editor_control.cpp
+++ b/pcbnew/tools/pcb_editor_control.cpp
@@ -41,8 +41,7 @@
 #include <class_draw_panel_gal.h>
 #include <class_module.h>
 #include <class_mire.h>
-#include <ratsnest_data.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 #include <collectors.h>
 #include <zones_functions_for_undo_redo.h>
 #include <board_commit.h>
@@ -481,7 +480,12 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent )
         }
     }
 
-    view->Remove( &preview );
+	controls->ShowCursor( false );
+    controls->SetSnapping( false );
+    controls->SetAutoPan( false );
+    controls->CaptureCursor( false );
+    
+	view->Remove( &preview );
     m_frame->SetNoToolSelected();
 
     return 0;
@@ -637,7 +641,7 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
 {
     auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
     const auto& selection = selTool->GetSelection();
-    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
+    auto connectivity = getModel<BOARD>()->GetConnectivity();
 
     BOARD_COMMIT commit( this );
 
@@ -651,13 +655,11 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
 
         m_frame->Fill_Zone( zone );
         zone->SetIsFilled( true );
-        ratsnest->Update( zone );
-        getView()->Update( zone );
     }
 
     commit.Push( _( "Fill Zone" ) );
 
-    ratsnest->Recalculate();
+    connectivity->RecalculateRatsnest();
 
     return 0;
 }
@@ -666,7 +668,7 @@ int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
 int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
 {
     BOARD* board = getModel<BOARD>();
-    RN_DATA* ratsnest = board->GetRatsnest();
+    auto connectivity = getModel<BOARD>()->GetConnectivity();
 
     BOARD_COMMIT commit( this );
 
@@ -678,13 +680,11 @@ int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
 
         m_frame->Fill_Zone( zone );
         zone->SetIsFilled( true );
-        ratsnest->Update( zone );
-        getView()->Update( zone );
     }
 
     commit.Push( _( "Fill All Zones" ) );
 
-    ratsnest->Recalculate();
+    connectivity->RecalculateRatsnest();
 
     return 0;
 }
@@ -694,7 +694,7 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
 {
     auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
     const auto& selection = selTool->GetSelection();
-    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
+    auto connectivity = getModel<BOARD>()->GetConnectivity();
 
     BOARD_COMMIT commit( this );
 
@@ -708,13 +708,11 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
 
         zone->SetIsFilled( false );
         zone->ClearFilledPolysList();
-        ratsnest->Update( zone );
-        getView()->Update( zone );
     }
 
     commit.Push( _( "Unfill Zone" ) );
 
-    ratsnest->Recalculate();
+    connectivity->RecalculateRatsnest();
 
     return 0;
 }
@@ -723,7 +721,7 @@ int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
 int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
 {
     BOARD* board = getModel<BOARD>();
-    RN_DATA* ratsnest = board->GetRatsnest();
+    auto connectivity = getModel<BOARD>()->GetConnectivity();
 
     BOARD_COMMIT commit( this );
 
@@ -735,13 +733,11 @@ int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
 
         zone->SetIsFilled( false );
         zone->ClearFilledPolysList();
-        ratsnest->Update( zone );
-        getView()->Update( zone );
     }
 
     commit.Push( _( "Unfill All Zones" ) );
 
-    ratsnest->Recalculate();
+    connectivity->RecalculateRatsnest();
 
     return 0;
 }
@@ -808,22 +804,29 @@ int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent )
 
         netcode = curr_area->GetNetCode();
 
-        if( firstZone->GetNetCode() != netcode )
-            continue;
+        if( firstZone )
+        {
+		    if( firstZone->GetNetCode() != netcode )
+		        continue;
 
-        if( curr_area->GetPriority() != firstZone->GetPriority() )
-            continue;
+		    if( curr_area->GetPriority() != firstZone->GetPriority() )
+		        continue;
 
-        if( curr_area->GetIsKeepout() != firstZone->GetIsKeepout() )
-            continue;
+		    if( curr_area->GetIsKeepout() != firstZone->GetIsKeepout() )
+		        continue;
 
-        if( curr_area->GetLayer() != firstZone->GetLayer() )
-            continue;
+		    if( curr_area->GetLayer() != firstZone->GetLayer() )
+		        continue;
 
-        if( !board->TestAreaIntersection( curr_area, firstZone ) )
-            continue;
+		    if( !board->TestAreaIntersection( curr_area, firstZone ) )
+		        continue;
 
-        toMerge.push_back( curr_area );
+		    toMerge.push_back( curr_area );
+		}
+        else
+        {
+            toMerge.push_back( curr_area );
+        }
     }
 
     m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@@ -1055,6 +1058,31 @@ int PCB_EDITOR_CONTROL::HighlightNetCursor( const TOOL_EVENT& aEvent )
     return 0;
 }
 
+static bool showLocalRatsnest( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
+                            KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPosition )
+{
+    aFrame->SetAuxOrigin( wxPoint( aPosition.x, aPosition.y ) );
+    aItem->SetPosition( aPosition );
+    aView->MarkDirty();
+
+    return true;
+}
+
+int PCB_EDITOR_CONTROL::ShowLocalRatsnest( const TOOL_EVENT& aEvent )
+{
+    Activate();
+
+    auto picker = m_toolMgr->GetTool<PICKER_TOOL>();
+    assert( picker );
+
+    m_frame->SetToolID( ID_PCB_SHOW_1_RATSNEST_BUTT, wxCURSOR_PENCIL, _( "Pick Components for Local Ratsnest" ) );
+    //picker->SetClickHandler( std::bind( showLocalRatsnest, m_toolMgr, _1 ) );
+    picker->SetSnapping( false );
+    picker->Activate();
+    Wait();
+
+    return 0;
+}
 
 int PCB_EDITOR_CONTROL::UpdateSelectionRatsnest( const TOOL_EVENT& aEvent )
 {
diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp
index 9a00d90bfb..51f92df33e 100644
--- a/pcbnew/tools/pcbnew_control.cpp
+++ b/pcbnew/tools/pcbnew_control.cpp
@@ -44,7 +44,7 @@
 #include <pcbnew_id.h>
 #include <wxPcbStruct.h>
 #include <pcb_draw_panel_gal.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 #include <tool/tool_manager.h>
 #include <gal/graphics_abstraction_layer.h>
 #include <view/view_controls.h>
diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp
index 3e55a20893..fa11fa1950 100644
--- a/pcbnew/tools/point_editor.cpp
+++ b/pcbnew/tools/point_editor.cpp
@@ -43,7 +43,7 @@ using namespace std::placeholders;
 #include <class_zone.h>
 #include <class_board.h>
 #include <class_module.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 
 // Point editor
 TOOL_ACTION PCB_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner",
@@ -551,7 +551,7 @@ void POINT_EDITOR::finishItem() const
         if( zone->IsFilled() )
         {
             getEditFrame<PCB_EDIT_FRAME>()->Fill_Zone( zone );
-            zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
+//            zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
         }
     }
 }
diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
index 1b97c11ffa..ed03a30011 100644
--- a/pcbnew/tools/selection_tool.cpp
+++ b/pcbnew/tools/selection_tool.cpp
@@ -51,7 +51,7 @@ using namespace std::placeholders;
 
 #include <tool/tool_event.h>
 #include <tool/tool_manager.h>
-#include <ratsnest_data.h>
+#include <connectivity.h>
 
 #include "selection_tool.h"
 #include "pcb_bright_box.h"
@@ -830,24 +830,24 @@ void SELECTION_TOOL::selectAllItemsConnectedToTrack( TRACK& aSourceTrack )
 
 void SELECTION_TOOL::selectAllItemsConnectedToItem( BOARD_CONNECTED_ITEM& aSourceItem )
 {
-    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
-    std::list<BOARD_CONNECTED_ITEM*> itemsList;
-    ratsnest->GetConnectedItems( &aSourceItem, itemsList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
+	constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
+    auto connectivity = board()->GetConnectivity();
 
-    for( BOARD_CONNECTED_ITEM* i : itemsList )
-        select( i );
+    std::list<BOARD_CONNECTED_ITEM*> items;
+    items = connectivity->GetConnectedItems( &aSourceItem, types );
+
+    for( auto item : connectivity->GetConnectedItems( &aSourceItem, types ) )
+        select( item );
 }
 
 
 void SELECTION_TOOL::selectAllItemsOnNet( int aNetCode )
 {
-    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
-    std::list<BOARD_CONNECTED_ITEM*> itemsList;
+    constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
+    auto connectivity = board()->GetConnectivity();
 
-    ratsnest->GetNetItems( aNetCode, itemsList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
-
-    for( BOARD_CONNECTED_ITEM* i : itemsList )
-        select( i );
+    for( auto item : connectivity->GetNetItems( aNetCode, types ) )
+        select( item );
 }
 
 
@@ -913,12 +913,12 @@ void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
     // now we need to find all modules that are connected to each of these nets
     // then we need to determine if these modules are in the list of modules
     // belonging to this sheet ( modList )
-    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
+    //RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
     std::list<int> removeCodeList;
     for( int netCode : netcodeList )
     {
         std::list<BOARD_CONNECTED_ITEM*> netPads;
-        ratsnest->GetNetItems( netCode, netPads, (RN_ITEM_TYPE)( RN_PADS ) );
+    //    ratsnest->GetNetItems( netCode, netPads, (RN_ITEM_TYPE)( RN_PADS ) );
         for( BOARD_CONNECTED_ITEM* mitem : netPads )
         {
             bool found = ( std::find( modList.begin(), modList.end(), mitem->GetParent() ) != modList.end() );
@@ -945,7 +945,7 @@ void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
     std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
     for( int netCode : netcodeList )
     {
-        ratsnest->GetNetItems( netCode, localConnectionList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
+        //ratsnest->GetNetItems( netCode, localConnectionList, (RN_ITEM_TYPE)( RN_TRACKS | RN_VIAS ) );
     }
 
     for( BOARD_ITEM* i : modList )
diff --git a/pcbnew/undo_redo.cpp b/pcbnew/undo_redo.cpp
index ede5340917..16b6923b0b 100644
--- a/pcbnew/undo_redo.cpp
+++ b/pcbnew/undo_redo.cpp
@@ -45,7 +45,7 @@ using namespace std::placeholders;
 #include <class_zone.h>
 #include <class_edge_mod.h>
 
-#include <ratsnest_data.h>
+#include <connectivity.h>
 
 #include <tools/selection_tool.h>
 #include <tool/tool_manager.h>
@@ -383,7 +383,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
     bool        deep_reBuild_ratsnest = false;  // true later if pointers must be rebuilt
 
     KIGFX::VIEW* view = GetGalCanvas()->GetView();
-    RN_DATA* ratsnest = GetBoard()->GetRatsnest();
+    auto connectivity = GetBoard()->GetConnectivity();
 
     // Undo in the reverse order of list creation: (this can allow stacked changes
     // like the same item can be changes and deleted in the same complex command
@@ -468,7 +468,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
             }
 
             view->Remove( item );
-            ratsnest->Remove( item );
+            connectivity->Remove( item );
 
             item->SwapData( image );
 
@@ -482,7 +482,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
             }
 
             view->Add( item );
-            ratsnest->Add( item );
+            connectivity->Add( item );
             item->ClearFlags();
 
         }
@@ -518,27 +518,27 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
         case UR_MOVED:
             item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
             view->Update( item, KIGFX::GEOMETRY );
-            ratsnest->Update( item );
+            connectivity->Update( item );
             break;
 
         case UR_ROTATED:
             item->Rotate( aList->m_TransformPoint,
                           aRedoCommand ? m_rotationAngle : -m_rotationAngle );
             view->Update( item, KIGFX::GEOMETRY );
-            ratsnest->Update( item );
+            connectivity->Update( item );
             break;
 
         case UR_ROTATED_CLOCKWISE:
             item->Rotate( aList->m_TransformPoint,
                           aRedoCommand ? -m_rotationAngle : m_rotationAngle );
             view->Update( item, KIGFX::GEOMETRY );
-            ratsnest->Update( item );
+            connectivity->Update( item );
             break;
 
         case UR_FLIPPED:
             item->Flip( aList->m_TransformPoint );
             view->Update( item, KIGFX::LAYERS );
-            ratsnest->Update( item );
+            connectivity->Update( item );
             break;
 
         default:
@@ -555,7 +555,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
     if( not_found )
         wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );
 
-    // Rebuild pointers and ratsnest that can be changed.
+    // Rebuild pointers and connectivity that can be changed.
     if( reBuild_ratsnest )
     {
         // Compile ratsnest propagates nets from pads to tracks
@@ -565,10 +565,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
 
         if( IsGalCanvasActive() )
         {
-            if( deep_reBuild_ratsnest )
-                ratsnest->ProcessBoard();
-            else
-                ratsnest->Recalculate();
+			connectivity->RecalculateRatsnest();         
         }
     }
 }
diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp
index ebe2964ff6..7590ffadda 100644
--- a/pcbnew/zones_by_polygon_fill_functions.cpp
+++ b/pcbnew/zones_by_polygon_fill_functions.cpp
@@ -43,7 +43,8 @@
 #include <pcbnew.h>
 #include <zones.h>
 
-#include <view/view.h>
+#include <connectivity.h>
+#include <board_commit.h>
 
 #define FORMAT_STRING _( "Filling zone %d out of %d (net %s)..." )
 
@@ -116,11 +117,15 @@ int PCB_EDIT_FRAME::Fill_Zone( ZONE_CONTAINER* aZone )
 
     wxBusyCursor dummy;     // Shows an hourglass cursor (removed by its destructor)
 
+    BOARD_COMMIT  commit ( this );
+    commit.Modify( aZone );
     aZone->BuildFilledSolidAreasPolygons( GetBoard() );
-    GetGalCanvas()->GetView()->Update( aZone, KIGFX::ALL );
-    GetBoard()->GetRatsnest()->Update( aZone );
+    commit.Push ( _("Fill Zone"), false );
 
-    OnModify();
+    //GetGalCanvas()->GetView()->Update( aZone, KIGFX::ALL );
+    //GetBoard()->GetConnectivity()->Update( aZone );
+
+    //OnModify();
 
     return 0;
 }
diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
index cafe6f5606..364a2a3b6b 100644
--- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
+++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
@@ -74,7 +74,7 @@
  * To emit zone data to a file when filling zones for the debugging purposes,
  * set this 'true' and build.
  */
-static const bool g_DumpZonesWhenFilling = false;
+static const bool g_DumpZonesWhenFilling = true;
 
 extern void BuildUnconnectedThermalStubsPolygonList( SHAPE_POLY_SET& aCornerBuffer,
                                                      BOARD* aPcb, ZONE_CONTAINER* aZone,
@@ -437,6 +437,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
 
     SHAPE_POLY_SET solidAreas = *m_smoothedPoly;
 
+    printf("VC %d\n", solidAreas.VertexCount());
+
     solidAreas.Inflate( -outline_half_thickness, segsPerCircle );
     solidAreas.Simplify( POLY_CALC_MODE );
 
@@ -473,10 +475,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
 
     m_FilledPolysList = areas_fractured;
 
-    // Remove insulated islands:
-    if( GetNetCode() > 0 )
-        TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
-
     SHAPE_POLY_SET thermalHoles;
 
     // Test thermal stubs connections and add polygons to remove unconnected stubs.
@@ -506,10 +504,13 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
 
         m_FilledPolysList = th_fractured;
 
-        if( GetNetCode() > 0 )
-            TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
     }
 
+    m_RawPolysList = m_FilledPolysList;
+
+	if( GetNetCode() > 0 )
+        TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
+
     if(g_DumpZonesWhenFilling)
         dumper->EndGroup();
 }
diff --git a/pcbnew/zones_polygons_insulated_copper_islands.cpp b/pcbnew/zones_polygons_insulated_copper_islands.cpp
index bfb861e12e..5fc36c7aa5 100644
--- a/pcbnew/zones_polygons_insulated_copper_islands.cpp
+++ b/pcbnew/zones_polygons_insulated_copper_islands.cpp
@@ -5,7 +5,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
- * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,78 +25,24 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <fctsys.h>
-#include <common.h>
-
 #include <class_board.h>
-#include <class_module.h>
-#include <class_track.h>
 #include <class_zone.h>
-
-#include <pcbnew.h>
-#include <zones.h>
-#include <polygon_test_point_inside.h>
-
+#include <connectivity.h>
 
 void ZONE_CONTAINER::TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb )
 {
-    if( m_FilledPolysList.IsEmpty() )
-        return;
+    std::vector<int> islands;
 
-    // Build a list of points connected to the net:
-    // list of coordinates of pads and vias on this layer and on this net.
-    std::vector <wxPoint> listPointsCandidates;
+    auto connectivity = aPcb->GetConnectivity();
 
-    for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
+    connectivity->FindIsolatedCopperIslands( this, islands );
+
+    std::sort( islands.begin(), islands.end(), std::greater<int>() );
+
+    for( auto idx : islands )
     {
-        for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
-        {
-            if( !pad->IsOnLayer( GetLayer() ) )
-                continue;
-
-            if( pad->GetNetCode() != GetNetCode() )
-                continue;
-
-            listPointsCandidates.push_back( pad->GetPosition() );
-        }
+        m_FilledPolysList.DeletePolygon( idx );
     }
 
-    for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
-    {
-        if( !track->IsOnLayer( GetLayer() ) )
-            continue;
-
-        if( track->GetNetCode() != GetNetCode() )
-            continue;
-
-        listPointsCandidates.push_back( track->GetStart() );
-
-        if( track->Type() != PCB_VIA_T )
-            listPointsCandidates.push_back( track->GetEnd() );
-    }
-
-    // test if a point is inside
-
-    for( int outline = 0; outline < m_FilledPolysList.OutlineCount(); outline++ )
-    {
-        bool connected = false;
-
-        for( unsigned ic = 0; ic < listPointsCandidates.size(); ic++ )
-        {
-            // test if this area is connected to a board item:
-            wxPoint pos = listPointsCandidates[ic];
-
-            if( m_FilledPolysList.Contains( VECTOR2I( pos.x, pos.y ), outline ) )
-            {
-                connected = true;
-                break;
-            }
-        }
-
-        if( !connected )                 // this polygon is connected: analyse next polygon
-        {
-            m_FilledPolysList.DeletePolygon( outline );
-            outline--;
-        }
-    }
+    connectivity->Update( this );
 }