diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 5ecc8f8232..d24c37bdfe 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -203,6 +203,7 @@ set( COMMON_SRCS wildcards_and_files_ext.cpp worksheet.cpp wxwineda.cpp + wxunittext.cpp xnode.cpp zoom.cpp ) diff --git a/common/draw_panel_gal.cpp b/common/draw_panel_gal.cpp index 0ec6a1130b..1b293c63ac 100644 --- a/common/draw_panel_gal.cpp +++ b/common/draw_panel_gal.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or @@ -67,7 +67,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin m_viewControls = new KIGFX::WX_VIEW_CONTROLS( m_view, this ); - Connect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this ); /* Generic events for the Tool Dispatcher */ @@ -125,7 +124,7 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) m_view->UpdateItems(); m_gal->BeginDrawing(); - m_gal->ClearScreen(); + m_gal->ClearScreen( m_painter->GetSettings()->GetBackgroundColor() ); if( m_view->IsDirty() ) { @@ -184,10 +183,21 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect ) } +void EDA_DRAW_PANEL_GAL::StartDrawing() +{ + m_pendingRefresh = false; + Connect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); + + wxPaintEvent redrawEvent; + wxPostEvent( this, redrawEvent ); +} + + void EDA_DRAW_PANEL_GAL::StopDrawing() { - Disconnect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); + m_pendingRefresh = true; m_refreshTimer.Stop(); + Disconnect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); } @@ -198,8 +208,7 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) return; // Prevent refreshing canvas during backend switch - m_pendingRefresh = true; - m_refreshTimer.Stop(); + StopDrawing(); delete m_gal; @@ -219,7 +228,6 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) wxSize size = GetClientSize(); m_gal->ResizeScreen( size.GetX(), size.GetY() ); - m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); if( m_painter ) m_painter->SetGAL( m_gal ); @@ -228,7 +236,6 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) m_view->SetGAL( m_gal ); m_currentGal = aGalType; - m_pendingRefresh = false; } diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 13055c7aed..a6f1429721 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -315,10 +315,10 @@ void CAIRO_GAL::Flush() } -void CAIRO_GAL::ClearScreen() +void CAIRO_GAL::ClearScreen( const COLOR4D& aColor ) { - cairo_set_source_rgb( currentContext, - backgroundColor.r, backgroundColor.g, backgroundColor.b ); + backgroundColor = aColor; + cairo_set_source_rgb( currentContext, aColor.r, aColor.g, aColor.b ); cairo_rectangle( currentContext, 0.0, 0.0, screenSize.x, screenSize.y ); cairo_fill( currentContext ); } @@ -973,7 +973,7 @@ void CAIRO_GAL::initSurface() cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL ); // Clear the screen - ClearScreen(); + ClearScreen( backgroundColor ); // Compute the world <-> screen transformations ComputeWorldScreenMatrix(); diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 5bd59303a2..568772f96a 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -589,10 +589,10 @@ void OPENGL_GAL::Flush() } -void OPENGL_GAL::ClearScreen() +void OPENGL_GAL::ClearScreen( const COLOR4D& aColor ) { // Clear screen - glClearColor( backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a ); + glClearColor( aColor.r, aColor.g, aColor.b, aColor.a ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } diff --git a/common/geometry/shape_collisions.cpp b/common/geometry/shape_collisions.cpp index 604335b43e..52db4ecb81 100644 --- a/common/geometry/shape_collisions.cpp +++ b/common/geometry/shape_collisions.cpp @@ -23,11 +23,13 @@ */ #include +#include #include #include #include #include +#include typedef VECTOR2I::extended_type ecoord; @@ -45,25 +47,21 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int return false; if( aNeedMTV ) - aMTV = delta.Resize( sqrt( abs( min_dist_sq - dist_sq ) ) + 1 ); + aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error return true; } -static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance, - bool aNeedMTV, VECTOR2I& aMTV ) +static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance, + bool aNeedMTV, VECTOR2I& aMTV ) { const VECTOR2I c = aB.GetCenter(); const VECTOR2I p0 = aA.GetPosition(); const VECTOR2I size = aA.GetSize(); - const ecoord r = aB.GetRadius(); - const ecoord min_dist = aClearance + r; - const ecoord min_dist_sq = min_dist * min_dist; - - if( aA.BBox( 0 ).Contains( c ) ) - return true; - + const int r = aB.GetRadius(); + const int min_dist = aClearance + r; + const VECTOR2I vts[] = { VECTOR2I( p0.x, p0.y ), @@ -73,33 +71,35 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int a VECTOR2I( p0.x, p0.y ) }; - ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX; + int nearest_seg_dist = INT_MAX; VECTOR2I nearest; bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x ) && c.y >= p0.y && c.y <= ( p0.y + size.y ); - if( !inside ) - { - for( int i = 0; i < 4; i++ ) - { - const SEG seg( vts[i], vts[i + 1] ); - ecoord dist_sq = seg.SquaredDistance( c ); - if( dist_sq < min_dist_sq ) - { - if( !aNeedMTV ) - return true; - else - { - nearest = seg.NearestPoint( c ); - nearest_seg_dist_sq = dist_sq; - } - } + if( !aNeedMTV && inside ) + return true; + + for( int i = 0; i < 4; i++ ) + { + const SEG seg( vts[i], vts[i + 1] ); + + VECTOR2I pn = seg.NearestPoint( c ); + + int d = ( pn - c ).EuclideanNorm(); + + if( ( d < min_dist ) && !aNeedMTV ) + return true; + + if( d < nearest_seg_dist ) + { + nearest = pn; + nearest_seg_dist = d; } } - if( nearest_seg_dist_sq >= min_dist_sq && !inside ) + if( nearest_seg_dist >= min_dist && !inside ) return false; VECTOR2I delta = c - nearest; @@ -107,25 +107,77 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int a if( !aNeedMTV ) return true; + if( inside ) - aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) ); + aMTV = -delta.Resize( abs( min_dist + 1 + nearest_seg_dist ) + 1 ); else - aMTV = delta.Resize( sqrt( abs( r * r - nearest_seg_dist_sq ) + 1 ) ); + aMTV = delta.Resize( abs( min_dist + 1 - nearest_seg_dist ) + 1 ); + return true; } +static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aClearance ) +{ + VECTOR2I nearest = aB.NearestPoint( aA.GetCenter() ); + VECTOR2I f (0, 0); + + int dist = ( nearest - aA.GetCenter() ).EuclideanNorm(); + int min_dist = aClearance + aA.GetRadius(); + + if( dist < min_dist ) + f = ( aA.GetCenter() - nearest ).Resize ( min_dist - dist + 10 ); + + return f; +} + + static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) { + bool found = false; + VECTOR2I::extended_type clSq = (VECTOR2I::extended_type) aClearance * aClearance; + + for( int s = 0; s < aB.SegmentCount(); s++ ) { + if( aA.Collide( aB.CSegment( s ), aClearance ) ) - return true; + { + found = true; + break; + } } - return false; + if( !aNeedMTV || !found ) + return found; + + SHAPE_CIRCLE cmoved( aA ); + VECTOR2I f_total( 0, 0 ); + + for( int s = 0; s < aB.SegmentCount(); s++ ) + { + VECTOR2I f = pushoutForce( cmoved, aB.CSegment( s ), aClearance ); + cmoved.SetCenter( cmoved.GetCenter() + f ); + f_total += f; + } + + aMTV = f_total; + return found; +} + + +static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance, + bool aNeedMTV, VECTOR2I& aMTV ) +{ + bool col = aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2); + + if( col && aNeedMTV ) + { + aMTV = pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2); + } + return col; } @@ -155,74 +207,123 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, in } -bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, - bool aNeedMTV, VECTOR2I& aMTV ) +static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance, + bool aNeedMTV, VECTOR2I& aMTV ) { - switch( aA->Type() ) - { - case SH_RECT: - switch( aB->Type() ) - { - case SH_CIRCLE: - return Collide( *static_cast( aA ), - *static_cast( aB ), aClearance, aNeedMTV, aMTV ); + return aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2 ); +} - case SH_LINE_CHAIN: - return Collide( *static_cast( aA ), - *static_cast( aB ), aClearance, aNeedMTV, aMTV ); - default: - break; - } - break; +static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, int aClearance, + bool aNeedMTV, VECTOR2I& aMTV ) +{ + return aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2 ); +} - case SH_CIRCLE: - switch( aB->Type() ) - { - case SH_RECT: - return Collide( *static_cast( aB ), - *static_cast( aA ), aClearance, aNeedMTV, aMTV ); - case SH_CIRCLE: - return Collide( *static_cast( aA ), - *static_cast( aB ), aClearance, aNeedMTV, aMTV ); +static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, int aClearance, + bool aNeedMTV, VECTOR2I& aMTV ) +{ + if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2 ) ) + return true; - case SH_LINE_CHAIN: - return Collide( *static_cast( aA ), - *static_cast( aB ), aClearance, aNeedMTV, aMTV ); + return false; +} - default: - break; - } - break; - case SH_LINE_CHAIN: - switch( aB->Type() ) - { - case SH_RECT: - return Collide( *static_cast( aB ), - *static_cast( aA ), aClearance, aNeedMTV, aMTV ); +template bool +CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) +{ + return Collide (*static_cast( aA ), + *static_cast( aB ), + aClearance, aNeedMTV, aMTV); +} - case SH_CIRCLE: - return Collide( *static_cast( aB ), - *static_cast( aA ), aClearance, aNeedMTV, aMTV ); +bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) +{ + switch( aA->Type() ) + { + case SH_RECT: + switch( aB->Type() ) + { + case SH_CIRCLE: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); - case SH_LINE_CHAIN: - return Collide( *static_cast( aA ), - *static_cast( aB ), aClearance, aNeedMTV, aMTV ); + case SH_LINE_CHAIN: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); - default: - break; - } - break; + case SH_SEGMENT: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); - default: - break; - } + default: + break; + } - assert( 0 ); // unsupported_collision + case SH_CIRCLE: + switch( aB->Type() ) + { + case SH_RECT: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); - return false; + case SH_CIRCLE: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + case SH_LINE_CHAIN: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + case SH_SEGMENT: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + default: + break; + } + + case SH_LINE_CHAIN: + switch( aB->Type() ) + { + case SH_RECT: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_CIRCLE: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_LINE_CHAIN: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + case SH_SEGMENT: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + default: + break; + } + + case SH_SEGMENT: + switch( aB->Type() ) + { + case SH_RECT: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_CIRCLE: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_LINE_CHAIN: + return CollCase( aB, aA, aClearance, aNeedMTV, aMTV ); + + case SH_SEGMENT: + return CollCase( aA, aB, aClearance, aNeedMTV, aMTV ); + + default: + break; + } + + default: + break; + } + + bool unsupported_collision = true; + + assert( unsupported_collision == false ); + + return false; } diff --git a/common/geometry/shape_line_chain.cpp b/common/geometry/shape_line_chain.cpp index 7ac8c10eae..e442fcd503 100644 --- a/common/geometry/shape_line_chain.cpp +++ b/common/geometry/shape_line_chain.cpp @@ -135,6 +135,9 @@ int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP ) const { int d = INT_MAX; + if( IsClosed() && PointInside( aP ) ) + return 0; + for( int s = 0; s < SegmentCount(); s++ ) d = std::min( d, CSegment( s ).Distance( aP ) ); @@ -179,7 +182,7 @@ int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP ) int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const { - for( int s = 0; s< PointCount(); s++ ) + for( int s = 0; s < PointCount(); s++ ) if( CPoint( s ) == aP ) return s; @@ -187,6 +190,16 @@ int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const } +int SHAPE_LINE_CHAIN::FindSegment( const VECTOR2I& aP ) const +{ + for( int s = 0; s < SegmentCount(); s++ ) + if( CSegment( s ).Distance( aP ) <= 1 ) + return s; + + return -1; +} + + const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const { SHAPE_LINE_CHAIN rv; @@ -261,6 +274,9 @@ int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& if( a.Collinear( b ) ) { + is.our = a; + is.their = b; + if( a.Contains( b.A ) ) { is.p = b.A; aIp.push_back( is ); } if( a.Contains( b.B ) ) { is.p = b.B; aIp.push_back( is ); } if( b.Contains( a.A ) ) { is.p = a.A; aIp.push_back( is ); } @@ -282,44 +298,6 @@ int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& } return aIp.size(); - - for( int s1 = 0; s1 < SegmentCount(); s1++ ) - { - for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ ) - { - const SEG& a = CSegment( s1 ); - const SEG& b = aChain.CSegment( s2 ); - OPT_VECTOR2I p = a.Intersect( b ); - INTERSECTION is; - - if( p ) - { - is.p = *p; - is.our = a; - is.their = b; - aIp.push_back( is ); - } - else if( a.Collinear( b ) ) - { - if( a.A != b.A && a.A != b.B && b.Contains( a.A ) ) - { - is.p = a.A; - is.our = a; - is.their = b; - aIp.push_back( is ); - } - else if( a.B != b.A && a.B != b.B && b.Contains( a.B ) ) - { - is.p = a.B; - is.our = a; - is.their = b; - aIp.push_back( is ); - } - } - } - } - - return aIp.size(); } @@ -372,10 +350,13 @@ bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const { - if( SegmentCount() < 1 ) + if( !PointCount() ) + return false; + + else if( PointCount() == 1 ) return m_points[0] == aP; - for( int i = 1; i < SegmentCount(); i++ ) + for( int i = 0; i < SegmentCount(); i++ ) { const SEG s = CSegment( i ); @@ -534,3 +515,30 @@ const std::string SHAPE_LINE_CHAIN::Format() const return ss.str(); } + + +bool SHAPE_LINE_CHAIN::CompareGeometry ( const SHAPE_LINE_CHAIN & aOther ) const +{ + SHAPE_LINE_CHAIN a(*this), b(aOther); + a.Simplify(); + b.Simplify(); + + if(a.m_points.size() != b.m_points.size()) + return false; + + for(int i = 0; i < a.PointCount(); i++) + if(a.CPoint(i) != b.CPoint(i)) + return false; + return true; +} + +bool SHAPE_LINE_CHAIN::Intersects( const SHAPE_LINE_CHAIN& aChain ) const +{ + INTERSECTIONS dummy; + return Intersect(aChain, dummy) != 0; +} + +SHAPE* SHAPE_LINE_CHAIN::Clone() const +{ + return new SHAPE_LINE_CHAIN( *this ); +} diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index 51c85aa273..444143b0fb 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -50,6 +50,7 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) // action name without specifying at least toolName is not valid assert( aAction->GetName().find( '.', 0 ) != std::string::npos ); + // TOOL_ACTIONs must have unique names & ids assert( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() ); assert( m_actionIdIndex.find( aAction->m_id ) == m_actionIdIndex.end() ); @@ -60,6 +61,8 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) if( aAction->HasHotKey() ) m_actionHotKeys[aAction->m_currentHotKey].push_back( aAction ); + + aAction->setActionMgr( this ); } @@ -69,6 +72,7 @@ void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) m_actionIdIndex.erase( aAction->m_id ); // Indicate that the ACTION_MANAGER no longer care about the object + aAction->setActionMgr( NULL ); aAction->setId( -1 ); if( aAction->HasHotKey() ) diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 6dfab27e58..b6277e16a7 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -26,44 +26,55 @@ #include #include #include +#include #include CONTEXT_MENU::CONTEXT_MENU() : - m_titleSet( false ), m_selected( -1 ), m_handler( this ), m_tool( NULL ) + m_titleSet( false ), m_selected( -1 ), m_tool( NULL ) { - m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); + setCustomEventHandler( boost::bind( &CONTEXT_MENU::handleCustomEvent, this, _1 ) ); - // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu) - wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu ); - m_menu.AddPendingEvent( menuEvent ); + setupEvents(); } CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : - m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_handler( this ), m_tool( aMenu.m_tool ) + m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_tool( aMenu.m_tool ), + m_toolActions( aMenu.m_toolActions ), m_customHandler( aMenu.m_customHandler ) { - m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - - // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu) - wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu ); - m_menu.AddPendingEvent( menuEvent ); - // Copy all the menu entries - for( unsigned i = 0; i < aMenu.m_menu.GetMenuItemCount(); ++i ) + for( unsigned i = 0; i < aMenu.GetMenuItemCount(); ++i ) { - wxMenuItem* item = aMenu.m_menu.FindItemByPosition( i ); - m_menu.Append( new wxMenuItem( &m_menu, item->GetId(), item->GetItemLabel(), - wxEmptyString, wxITEM_NORMAL ) ); + wxMenuItem* item = aMenu.FindItemByPosition( i ); + + if( item->IsSubMenu() ) + { +#ifdef DEBUG + // Submenus of a CONTEXT_MENU are supposed to be CONTEXT_MENUs as well + assert( dynamic_cast( item->GetSubMenu() ) ); +#endif + + CONTEXT_MENU* menu = new CONTEXT_MENU( static_cast( *item->GetSubMenu() ) ); + AppendSubMenu( menu, item->GetItemLabel(), wxEmptyString ); + } + else + { + wxMenuItem* newItem = new wxMenuItem( this, item->GetId(), item->GetItemLabel(), + wxEmptyString, item->GetKind() ); + + Append( newItem ); + copyItem( item, newItem ); + } } - // Copy tool actions that are available to choose from context menu - m_toolActions = aMenu.m_toolActions; + setupEvents(); +} + + +void CONTEXT_MENU::setupEvents() +{ + Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CONTEXT_MENU::onMenuEvent ), NULL, this ); + Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CONTEXT_MENU::onMenuEvent ), NULL, this ); } @@ -71,15 +82,16 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle ) { // TODO handle an empty string (remove title and separator) - // Unfortunately wxMenu::SetTitle() does nothing.. + // Unfortunately wxMenu::SetTitle() does nothing.. (at least wxGTK) + if( m_titleSet ) { - m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle ); + FindItemByPosition( 0 )->SetItemLabel( aTitle ); } else { - m_menu.InsertSeparator( 0 ); - m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) ); + InsertSeparator( 0 ); + Insert( 0, new wxMenuItem( this, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) ); m_titleSet = true; } } @@ -89,11 +101,11 @@ void CONTEXT_MENU::Add( const wxString& aLabel, int aId ) { #ifdef DEBUG - if( m_menu.FindItem( aId ) != NULL ) + if( FindItem( aId ) != NULL ) wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in" "undefined behaviour" ) ); #endif - m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) ); + Append( new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) ); } @@ -101,17 +113,29 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) { /// ID numbers for tool actions need to have a value higher than m_actionId int id = m_actionId + aAction.GetId(); - wxString menuEntry; + + wxMenuItem* item = new wxMenuItem( this, id, + wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 ), + wxString( aAction.GetDescription().c_str(), wxConvUTF8 ), wxITEM_NORMAL ); if( aAction.HasHotKey() ) - menuEntry = wxString( ( aAction.GetMenuItem() + '\t' + - getHotKeyDescription( aAction ) ).c_str(), wxConvUTF8 ); - else - menuEntry = wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 ); + { + int key = aAction.GetHotKey() & ~MD_MODIFIER_MASK; + int mod = aAction.GetHotKey() & MD_MODIFIER_MASK; + int flags = wxACCEL_NORMAL; - m_menu.Append( new wxMenuItem( &m_menu, id, menuEntry, - wxString( aAction.GetDescription().c_str(), wxConvUTF8 ), wxITEM_NORMAL ) ); + switch( mod ) + { + case MD_ALT: flags = wxACCEL_ALT; break; + case MD_CTRL: flags = wxACCEL_CTRL; break; + case MD_SHIFT: flags = wxACCEL_SHIFT; break; + } + wxAcceleratorEntry accel( flags, key, id, item ); + item->SetAccel( &accel ); + } + + Append( item ); m_toolActions[id] = &aAction; } @@ -121,38 +145,17 @@ void CONTEXT_MENU::Clear() m_titleSet = false; // Remove all the entries from context menu - for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i ) - m_menu.Destroy( m_menu.FindItemByPosition( 0 ) ); + for( unsigned i = 0; i < GetMenuItemCount(); ++i ) + Destroy( FindItemByPosition( 0 ) ); m_toolActions.clear(); } -std::string CONTEXT_MENU::getHotKeyDescription( const TOOL_ACTION& aAction ) const +void CONTEXT_MENU::onMenuEvent( wxEvent& aEvent ) { - int hotkey = aAction.GetHotKey(); + OPT_TOOL_EVENT evt; - std::string description = ""; - - if( hotkey & MD_ALT ) - description += "ALT+"; - - if( hotkey & MD_CTRL ) - description += "CTRL+"; - - if( hotkey & MD_SHIFT ) - description += "SHIFT+"; - - // TODO dispatch keys such as Fx, TAB, PG_UP/DN, HOME, END, etc. - description += char( hotkey & ~MD_MODIFIER_MASK ); - - return description; -} - - -void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) -{ - TOOL_EVENT evt; wxEventType type = aEvent.GetEventType(); // When the currently chosen item in the menu is changed, an update event is issued. @@ -165,21 +168,42 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) else if( type == wxEVT_COMMAND_MENU_SELECTED ) { // Store the selected position - m_menu->m_selected = aEvent.GetId(); + m_selected = aEvent.GetId(); // Check if there is a TOOL_ACTION for the given ID - if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) + if( m_toolActions.count( aEvent.GetId() ) == 1 ) { - evt = m_menu->m_toolActions[aEvent.GetId()]->MakeEvent(); + evt = m_toolActions[aEvent.GetId()]->MakeEvent(); } else { + evt = m_customHandler( aEvent ); + // Handling non-action menu entries (e.g. items in clarification list) - evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, aEvent.GetId() ); + if( !evt ) + evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, aEvent.GetId() ); } } + assert( m_tool ); // without tool & tool manager we cannot handle events + // forward the action/update event to the TOOL_MANAGER - if( m_menu->m_tool ) - m_menu->m_tool->GetManager()->ProcessEvent( evt ); + if( evt && m_tool ) + m_tool->GetManager()->ProcessEvent( *evt ); +} + + +void CONTEXT_MENU::copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const +{ + assert( !aSource->IsSubMenu() ); // it does not transfer submenus + + aDest->SetKind( aSource->GetKind() ); + aDest->SetHelp( aSource->GetHelp() ); + aDest->Enable( aSource->IsEnabled() ); + + if( aSource->IsCheckable() ) + aDest->Check( aSource->IsChecked() ); + + if( aSource->GetKind() == wxITEM_NORMAL ) + aDest->SetBitmap( aSource->GetBitmap() ); } diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 502dccfbdb..4e66a1271c 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -240,6 +240,13 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION, mods ); evt->SetMousePosition( pos ); } + +#ifdef __APPLE__ + // TODO That's a big ugly workaround, somehow DRAWPANEL_GAL loses focus + // after second LMB click and currently I have no means to do better debugging + if( type == wxEVT_LEFT_UP ) + m_editFrame->GetGalCanvas()->SetFocus(); +#endif /* __APPLE__ */ } // Keyboard handling diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index e83b8fc6d2..a0bba9c51f 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -103,14 +103,6 @@ TOOL_MANAGER::TOOL_MANAGER() : TOOL_MANAGER::~TOOL_MANAGER() -{ - DeleteAll(); - - delete m_actionMgr; -} - - -void TOOL_MANAGER::DeleteAll() { std::map::iterator it, it_end; @@ -122,6 +114,7 @@ void TOOL_MANAGER::DeleteAll() } m_toolState.clear(); + delete m_actionMgr; } @@ -308,8 +301,6 @@ int TOOL_MANAGER::GetPriority( int aToolId ) const for( std::deque::const_iterator it = m_activeTools.begin(), itEnd = m_activeTools.end(); it != itEnd; ++it ) { - std::cout << FindTool( *it )->GetName() << std::endl; - if( *it == aToolId ) return priority; @@ -497,7 +488,7 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) st->contextMenuTrigger = CMENU_OFF; boost::scoped_ptr menu( new CONTEXT_MENU( *st->contextMenu ) ); - GetEditFrame()->PopupMenu( menu->GetMenu() ); + GetEditFrame()->PopupMenu( menu.get() ); // If nothing was chosen from the context menu, we must notify the tool as well if( menu->GetSelected() < 0 ) @@ -513,8 +504,7 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) if( m_view->IsDirty() ) { PCB_EDIT_FRAME* f = static_cast( GetEditFrame() ); - if( f->IsGalCanvasActive() ) - f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER. + f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER. } return false; diff --git a/common/view/view.cpp b/common/view/view.cpp index 4bf71ec638..5e213c0c1d 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -1019,3 +1019,38 @@ void VIEW::UpdateItems() m_needsUpdate.clear(); } + +struct VIEW::extentsVisitor { + BOX2I extents; + bool first; + + extentsVisitor() + { + first = true; + } + + bool operator()( VIEW_ITEM* aItem ) + { + if(first) + extents = aItem->ViewBBox(); + else + extents.Merge ( aItem->ViewBBox() ); + return false; + } + }; + +const BOX2I VIEW::CalculateExtents() +{ + + extentsVisitor v; + BOX2I fullScene; + fullScene.SetMaximum(); + + + BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers ) + { + l->items->Query( fullScene, v ); + } + + return v.extents; +} diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 22eb3ee47e..acd88316fa 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -160,12 +160,12 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent ) // Set scaling speed depending on scroll wheel event interval if( timeDiff < 500 && timeDiff > 0 ) { - zoomScale = ( aEvent.GetWheelRotation() > 0.0 ) ? 2.05 - timeDiff / 500 : + zoomScale = ( aEvent.GetWheelRotation() > 0 ) ? 2.05 - timeDiff / 500 : 1.0 / ( 2.05 - timeDiff / 500 ); } else { - zoomScale = ( aEvent.GetWheelRotation() > 0.0 ) ? 1.05 : 0.95; + zoomScale = ( aEvent.GetWheelRotation() > 0 ) ? 1.05 : 0.95; } VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) ); @@ -217,6 +217,11 @@ void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent ) { case AUTO_PANNING: { +#if wxCHECK_VERSION( 3, 0, 0 ) + if( !m_parentPanel->HasFocus() ) + break; +#endif + double borderSize = std::min( m_autoPanMargin * m_view->GetScreenPixelSize().x, m_autoPanMargin * m_view->GetScreenPixelSize().y ); diff --git a/common/wxunittext.cpp b/common/wxunittext.cpp new file mode 100644 index 0000000000..743f973dce --- /dev/null +++ b/common/wxunittext.cpp @@ -0,0 +1,199 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 "wxunittext.h" +#include +#include +#include +#include +#include +#if wxCHECK_VERSION( 2, 9, 0 ) +#include +#endif +#include + +WX_UNIT_TEXT::WX_UNIT_TEXT( wxWindow* aParent, const wxString& aLabel, double aValue, double aStep ) : + wxPanel( aParent, wxID_ANY ), + m_step( aStep ) +{ + // Use the currently selected units + m_units = g_UserUnit; + + wxBoxSizer* sizer; + sizer = new wxBoxSizer( wxHORIZONTAL ); + + // Helper label + m_inputLabel = new wxStaticText( this, wxID_ANY, aLabel, + wxDefaultPosition, wxDefaultSize, 0 ); + wxSize size = m_inputLabel->GetMinSize(); + size.SetWidth( 150 ); + m_inputLabel->SetMinSize( size ); + sizer->Add( m_inputLabel, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5 ); + + // Main input control + m_inputValue = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_PROCESS_ENTER ); + + SetValue( aValue ); + sizer->Add( m_inputValue, 0, wxALIGN_CENTER_VERTICAL | wxALL ); + +#if wxCHECK_VERSION( 2, 9, 0 ) // Sorry guys, I am tired of dealing with 2.8 compatibility + wxFloatingPointValidator validator( 4, NULL, wxNUM_VAL_NO_TRAILING_ZEROES ); + validator.SetRange( 0.0, std::numeric_limits::max() ); + m_inputValue->SetValidator( validator ); + + // Spin buttons for modifying values using the mouse + m_spinButton = new wxSpinButton( this, wxID_ANY ); + m_spinButton->SetRange( std::numeric_limits::min(), std::numeric_limits::max() ); + + m_spinButton->SetCanFocus( false ); + sizer->Add( m_spinButton, 0, wxALIGN_CENTER_VERTICAL | wxALL ); + + Connect( wxEVT_SPIN_UP, wxSpinEventHandler( WX_UNIT_TEXT::onSpinUpEvent ), NULL, this ); + Connect( wxEVT_SPIN_DOWN, wxSpinEventHandler( WX_UNIT_TEXT::onSpinDownEvent ), NULL, this ); +#endif + + sizer->AddSpacer( 5 ); + + // Create units label + m_unitLabel = new wxStaticText( this, wxID_ANY, GetUnitsLabel( g_UserUnit ), + wxDefaultPosition, wxDefaultSize, 0 ); + sizer->Add( m_unitLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL ); + + SetSizer( sizer ); + Layout(); +} + + +WX_UNIT_TEXT::~WX_UNIT_TEXT() +{ +} + + +void WX_UNIT_TEXT::SetUnits( EDA_UNITS_T aUnits, bool aConvert ) +{ + assert( !aConvert ); // TODO conversion does not work yet + + m_unitLabel->SetLabel( GetUnitsLabel( g_UserUnit ) ); +} + + +void WX_UNIT_TEXT::SetValue( double aValue ) +{ + if( aValue >= 0.0 ) + { + m_inputValue->SetValue( wxString( Double2Str( aValue ).c_str(), wxConvUTF8 ) ); + m_inputValue->MarkDirty(); + } + else + { + m_inputValue->SetValue( DEFAULT_VALUE ); + } +} + + +/*boost::optional WX_UNIT_TEXT::GetValue( EDA_UNITS_T aUnit ) const +{ + if( aUnit == m_units ) + return GetValue(); // no conversion needed + + switch( m_units ) + { + case MILLIMETRES: + switch( aUnit ) + { + case INCHES: + iu = Mils2iu( GetValue() * 1000.0 ); + break; + + case UNSCALED_UNITS: + iu = GetValue(); + break; + } + break; + + case INCHES: + switch( aUnit ) + { + case MILLIMETRES: + return Mils2mm( GetValue() * 1000.0 ); + break; + + case UNSCALED_UNITS: + return Mils2iu( GetValue() * 1000.0 ); + break; + } + break; + + case UNSCALED_UNITS: + switch( aUnit ) + { + case MILLIMETRES: + return Iu2Mils( GetValue() ) / 1000.0; + break; + +// case INCHES: +// return +// break; + } + break; + } + + assert( false ); // seems that there are some conversions missing + + return 0.0; +}*/ + + +boost::optional WX_UNIT_TEXT::GetValue() const +{ + wxString text = m_inputValue->GetValue(); + double value; + + if( text == DEFAULT_VALUE ) + return boost::optional( -1.0 ); + + if( !text.ToDouble( &value ) ) + return boost::optional(); + + return boost::optional( value ); +} + + +void WX_UNIT_TEXT::onSpinUpEvent( wxSpinEvent& aEvent ) +{ + SetValue( *GetValue() + m_step ); +} + + +void WX_UNIT_TEXT::onSpinDownEvent( wxSpinEvent& aEvent ) +{ + double newValue = *GetValue() - m_step; + + if( newValue >= 0.0 ) + SetValue( newValue ); +} + + +const wxString WX_UNIT_TEXT::DEFAULT_VALUE = _( "default "); diff --git a/demos/ecc83/ecc83-pp_v2.kicad_pcb b/demos/ecc83/ecc83-pp_v2.kicad_pcb index 829002c32f..cbef03d486 100644 --- a/demos/ecc83/ecc83-pp_v2.kicad_pcb +++ b/demos/ecc83/ecc83-pp_v2.kicad_pcb @@ -1,12 +1,12 @@ -(kicad_pcb (version 3) (host pcbnew "(2013-01-12 BZR 3902)-testing") +(kicad_pcb (version 3) (host pcbnew "(2014-05-16 BZR 4868)-product") (general (links 20) (no_connects 0) - (area 119.824499 89.789 168.465501 133.477) + (area 118.759514 89.3318 168.465501 133.6802) (thickness 1.6002) (drawings 4) - (tracks 62) + (tracks 63) (zones 0) (modules 15) (nets 10) @@ -16,33 +16,38 @@ (layers (15 Dessus signal) (0 Dessous signal) - (16 Dessous.Adhes user) - (17 Dessus.Adhes user) - (18 Dessous.Pate user) - (19 Dessus.Pate user) - (20 Dessous.SilkS user) - (21 Dessus.SilkS user) - (22 Dessous.Masque user) - (23 Dessus.Masque user) - (24 Dessin.User user) + (16 B.Adhes user) + (17 F.Adhes user) + (18 B.Paste user) + (19 F.Paste user) + (20 B.SilkS user) + (21 F.SilkS user) + (22 B.Mask user) + (23 F.Mask user) + (24 Dwgs.User user) (25 Cmts.User user) (26 Eco1.User user) (27 Eco2.User user) - (28 Contours.Ci user) + (28 Edge.Cuts user) ) (setup (last_trace_width 0.8636) + (user_trace_width 1) + (user_trace_width 2) + (user_trace_width 3) (trace_clearance 0.508) (zone_clearance 0.635) (zone_45_only no) - (trace_min 0.254) + (trace_min 0.154) (segment_width 0.381) (edge_width 0.381) (via_size 1.905) (via_drill 0.635) (via_min_size 0.889) (via_min_drill 0.508) + (user_via 2 1) + (user_via 3 2) (uvia_size 0.508) (uvia_drill 0.127) (uvias_allowed no) @@ -62,7 +67,7 @@ (layerselection 3178497) (usegerberextensions true) (excludeedgelayer true) - (linewidth 60) + (linewidth 0.150000) (plotframeref false) (viasonmask false) (mode 1) @@ -104,7 +109,6 @@ (via_drill 0.635) (uvia_dia 0.508) (uvia_drill 0.127) - (add_net "") (add_net GND) (add_net N-000001) (add_net N-000002) @@ -120,21 +124,17 @@ (at 131.445 99.06 90) (descr "Condensateur polarise") (tags CP) - (fp_text reference C1 (at 0 2.54 90) (layer Dessus.SilkS) + (fp_text reference C1 (at 0 2.54 90) (layer F.SilkS) (effects (font (size 1.27 1.27) (thickness 0.254))) ) - (fp_text value 10uF (at 0 -2.54 90) (layer Dessus.SilkS) + (fp_text value 10uF (at 0 -2.54 90) (layer F.SilkS) (effects (font (size 1.27 1.27) (thickness 0.254))) ) - (fp_circle (center 0 0) (end 4.826 -2.794) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole rect (at -2.54 0 90) (size 1.778 1.778) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 7 N-000006) - ) - (pad 2 thru_hole circle (at 2.54 0 90) (size 1.778 1.778) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_circle (center 0 0) (end 4.826 -2.794) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole rect (at -2.54 0 90) (size 1.778 1.778) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 7 N-000006)) + (pad 2 thru_hole circle (at 2.54 0 90) (size 1.778 1.778) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model discret/c_vert_c2v10.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -147,28 +147,24 @@ (descr "Resitance 3 pas") (tags R) (autoplace_cost180 10) - (fp_text reference R1 (at 0 0 270) (layer Dessus.SilkS) + (fp_text reference R1 (at 0 0 270) (layer F.SilkS) (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_text value 1.5K (at 0 0 270) (layer Dessus.SilkS) hide + (fp_text value 1.5K (at 0 0 270) (layer F.SilkS) hide (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_line (start -3.81 0) (end -3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.81 0) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 0) (end 3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 1.016) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 5 N-000004) - ) - (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 9 N-000008) - ) + (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 5 N-000004)) + (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 9 N-000008)) (model discret/resistor.wrl (at (xyz 0 0 0)) (scale (xyz 0.3 0.3 0.3)) @@ -181,28 +177,24 @@ (descr "Resitance 3 pas") (tags R) (autoplace_cost180 10) - (fp_text reference R3 (at 0 0 270) (layer Dessus.SilkS) + (fp_text reference R3 (at 0 0 270) (layer F.SilkS) (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_text value 100K (at 0 0 270) (layer Dessus.SilkS) hide + (fp_text value 100K (at 0 0 270) (layer F.SilkS) hide (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_line (start -3.81 0) (end -3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.81 0) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 0) (end 3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 1.016) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 4 N-000003) - ) - (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 4 N-000003)) + (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model discret/resistor.wrl (at (xyz 0 0 0)) (scale (xyz 0.3 0.3 0.3)) @@ -215,28 +207,24 @@ (descr "Resitance 3 pas") (tags R) (autoplace_cost180 10) - (fp_text reference R4 (at 0 0 270) (layer Dessus.SilkS) + (fp_text reference R4 (at 0 0 270) (layer F.SilkS) (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_text value 47K (at 0 0 270) (layer Dessus.SilkS) hide + (fp_text value 47K (at 0 0 270) (layer F.SilkS) hide (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_line (start -3.81 0) (end -3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.81 0) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 0) (end 3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 1.016) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 8 N-000007) - ) - (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 8 N-000007)) + (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model discret/resistor.wrl (at (xyz 0 0 0)) (scale (xyz 0.3 0.3 0.3)) @@ -249,28 +237,24 @@ (descr "Resitance 3 pas") (tags R) (autoplace_cost180 10) - (fp_text reference R2 (at 0 0 90) (layer Dessus.SilkS) + (fp_text reference R2 (at 0 0 90) (layer F.SilkS) (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_text value 1.5K (at 0 0 90) (layer Dessus.SilkS) hide + (fp_text value 1.5K (at 0 0 90) (layer F.SilkS) hide (effects (font (size 1.397 1.27) (thickness 0.2032))) ) - (fp_line (start -3.81 0) (end -3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.81 0) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 0) (end 3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 3.302 1.016) (end 3.302 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 6 N-000005) - ) - (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.3048)) + (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 6 N-000005)) + (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model discret/resistor.wrl (at (xyz 0 0 0)) (scale (xyz 0.3 0.3 0.3)) @@ -282,95 +266,83 @@ (at 123.19 93.98) (descr "module 1 pin (ou trou mecanique de percage)") (tags DEV) - (fp_text reference 1PIN (at 0 -3.048) (layer Dessus.SilkS) + (fp_text reference 1PIN (at 0 -3.048) (layer F.SilkS) (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_text value P*** (at 0 2.794) (layer Dessus.SilkS) hide + (fp_text value P*** (at 0 2.794) (layer F.SilkS) hide (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_circle (center 0 0) (end 0 -2.286) (layer Dessus.SilkS) (width 0.381)) - (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) - (layers *.Cu *.Mask Dessus.SilkS) - ) + (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) (layers *.Cu *.Mask F.SilkS)) ) (module 1pin (layer Dessus) (tedit 200000) (tstamp 454CC090) (at 165.1 93.98) (descr "module 1 pin (ou trou mecanique de percage)") (tags DEV) - (fp_text reference 1PIN (at 0 -3.048) (layer Dessus.SilkS) + (fp_text reference 1PIN (at 0 -3.048) (layer F.SilkS) (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_text value GND (at 0 2.794) (layer Dessus.SilkS) hide + (fp_text value GND (at 0 2.794) (layer F.SilkS) hide (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_circle (center 0 0) (end 0 -2.286) (layer Dessus.SilkS) (width 0.381)) - (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) - (layers *.Cu *.Mask Dessus.SilkS) - ) + (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) (layers *.Cu *.Mask F.SilkS)) ) (module 1pin (layer Dessus) (tedit 200000) (tstamp 454CC096) (at 165.1 129.54) (descr "module 1 pin (ou trou mecanique de percage)") (tags DEV) - (fp_text reference 1PIN (at 0 -3.048) (layer Dessus.SilkS) + (fp_text reference 1PIN (at 0 -3.048) (layer F.SilkS) (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_text value P*** (at 0 2.794) (layer Dessus.SilkS) hide + (fp_text value P*** (at 0 2.794) (layer F.SilkS) hide (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_circle (center 0 0) (end 0 -2.286) (layer Dessus.SilkS) (width 0.381)) - (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) - (layers *.Cu *.Mask Dessus.SilkS) - ) + (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) (layers *.Cu *.Mask F.SilkS)) ) (module 1pin (layer Dessus) (tedit 200000) (tstamp 454CC09B) (at 123.19 129.54) (descr "module 1 pin (ou trou mecanique de percage)") (tags DEV) - (fp_text reference 1PIN (at 0 -3.048) (layer Dessus.SilkS) + (fp_text reference 1PIN (at 0 -3.048) (layer F.SilkS) (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_text value P*** (at 0 2.794) (layer Dessus.SilkS) hide + (fp_text value P*** (at 0 2.794) (layer F.SilkS) hide (effects (font (size 1.016 1.016) (thickness 0.254))) ) - (fp_circle (center 0 0) (end 0 -2.286) (layer Dessus.SilkS) (width 0.381)) - (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) - (layers *.Cu *.Mask Dessus.SilkS) - ) + (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048) (layers *.Cu *.Mask F.SilkS)) ) (module CP8 (layer Dessus) (tedit 200000) (tstamp 4549F3BE) (at 131.445 118.745 270) (descr "Condensateur polarise") (tags CP) - (fp_text reference C2 (at 1.27 1.27 270) (layer Dessus.SilkS) - (effects (font (size 1.524 1.524) (thickness 0.3048))) + (fp_text reference C2 (at 1.27 1.27 270) (layer F.SilkS) + (effects (font (thickness 0.3048))) ) - (fp_text value 680nF (at 1.27 -1.27 270) (layer Dessus.SilkS) - (effects (font (size 1.524 1.524) (thickness 0.3048))) - ) - (fp_line (start -10.16 0) (end -8.89 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -7.62 1.27) (end -8.89 1.27) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -8.89 1.27) (end -8.89 -1.27) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -8.89 -1.27) (end -7.62 -1.27) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -7.62 2.54) (end -7.62 -2.54) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -7.62 -2.54) (end 8.89 -2.54) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 8.89 -2.54) (end 8.89 2.54) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 8.89 2.54) (end -7.62 2.54) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start 8.89 0) (end 10.16 0) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -5.08 -2.54) (end -5.08 2.54) (layer Dessus.SilkS) (width 0.3048)) - (fp_line (start -6.35 2.54) (end -6.35 -2.54) (layer Dessus.SilkS) (width 0.3048)) - (pad 1 thru_hole rect (at -10.16 0 270) (size 1.778 1.778) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 4 N-000003) - ) - (pad 2 thru_hole circle (at 10.16 0 270) (size 1.778 1.778) (drill 0.8128) - (layers *.Cu *.Mask Dessus.SilkS) - (net 9 N-000008) + (fp_text value 680nF (at 1.27 -1.27 270) (layer F.SilkS) + (effects (font (thickness 0.3048))) ) + (fp_line (start -10.16 0) (end -8.89 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -7.62 1.27) (end -8.89 1.27) (layer F.SilkS) (width 0.3048)) + (fp_line (start -8.89 1.27) (end -8.89 -1.27) (layer F.SilkS) (width 0.3048)) + (fp_line (start -8.89 -1.27) (end -7.62 -1.27) (layer F.SilkS) (width 0.3048)) + (fp_line (start -7.62 2.54) (end -7.62 -2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start -7.62 -2.54) (end 8.89 -2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start 8.89 -2.54) (end 8.89 2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start 8.89 2.54) (end -7.62 2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start 8.89 0) (end 10.16 0) (layer F.SilkS) (width 0.3048)) + (fp_line (start -5.08 -2.54) (end -5.08 2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start -6.35 2.54) (end -6.35 -2.54) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole rect (at -10.16 0 270) (size 1.778 1.778) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 4 N-000003)) + (pad 2 thru_hole circle (at 10.16 0 270) (size 1.778 1.778) (drill 0.8128) (layers *.Cu *.Mask F.SilkS) + (net 9 N-000008)) (model discret/c_pol.wrl (at (xyz 0 0 0)) (scale (xyz 0.8 0.8 0.8)) @@ -379,53 +351,33 @@ ) (module ECC-83-2 (layer Dessus) (tedit 46F8A1CF) (tstamp 454A08DD) - (at 149.225 109.22) - (fp_text reference U1 (at 0 -11.43) (layer Dessus.SilkS) - (effects (font (size 1.524 1.524) (thickness 0.3048))) + (at 193.675 101.4984) + (fp_text reference U1 (at 0 -11.43) (layer F.SilkS) + (effects (font (thickness 0.3048))) ) - (fp_text value ECC83 (at 0 11.43) (layer Dessus.SilkS) - (effects (font (size 1.524 1.524) (thickness 0.3048))) - ) - (fp_circle (center 0 0) (end 10.16 1.27) (layer Dessus.SilkS) (width 0.381)) - (pad 1 thru_hole oval (at 3.4544 4.75488 306) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 5 N-000004) - ) - (pad 2 thru_hole oval (at 5.60832 1.8288 342) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 8 N-000007) - ) - (pad 3 thru_hole oval (at 5.60832 -1.8288 18) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 6 N-000005) - ) - (pad 4 thru_hole oval (at 3.4544 -4.75488 54) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 2 N-000001) - ) - (pad 5 thru_hole oval (at 0 -5.8928 90) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 2 N-000001) - ) - (pad 6 thru_hole oval (at -3.4544 -4.75488 306) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 7 N-000006) - ) - (pad 7 thru_hole oval (at -5.60832 -1.8288 342) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 5 N-000004) - ) - (pad 8 thru_hole oval (at -5.60832 1.78816 18) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 9 N-000008) - ) - (pad 9 thru_hole oval (at -3.4544 4.75488 54) (size 2.032 3.048) (drill oval 1.016 2.032) - (layers *.Cu *.Mask Dessus.SilkS) - (net 3 N-000002) - ) - (pad 10 thru_hole circle (at 0 0) (size 4.50088 4.50088) (drill 3.0988) - (layers *.Cu *.Mask Dessus.SilkS) + (fp_text value ECC83 (at 0 11.43) (layer F.SilkS) + (effects (font (thickness 0.3048))) ) + (fp_circle (center 0 0) (end 10.16 1.27) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole oval (at 3.4544 4.75488 306) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 5 N-000004)) + (pad 2 thru_hole oval (at 5.60832 1.8288 342) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 8 N-000007)) + (pad 3 thru_hole oval (at 5.60832 -1.8288 18) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 6 N-000005)) + (pad 4 thru_hole oval (at 3.4544 -4.75488 54) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 2 N-000001)) + (pad 5 thru_hole oval (at 0 -5.8928 90) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 2 N-000001)) + (pad 6 thru_hole oval (at -3.4544 -4.75488 306) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 7 N-000006)) + (pad 7 thru_hole oval (at -5.60832 -1.8288 342) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 5 N-000004)) + (pad 8 thru_hole oval (at -5.60832 1.78816 18) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 9 N-000008)) + (pad 9 thru_hole oval (at -3.4544 4.75488 54) (size 2.032 3.048) (drill oval 1.016 2.032) (layers *.Cu *.Mask F.SilkS) + (net 3 N-000002)) + (pad 10 thru_hole circle (at 0 0) (size 4.50088 4.50088) (drill 3.0988) (layers *.Cu *.Mask F.SilkS)) (model valves/ecc83.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -437,24 +389,20 @@ (at 149.225 128.905 180) (descr "Connecteurs 2 pins") (tags "CONN DEV") - (fp_text reference P4 (at 0 -1.905 180) (layer Dessus.SilkS) + (fp_text reference P4 (at 0 -1.905 180) (layer F.SilkS) (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_text value CONN_2 (at 0 -1.905 180) (layer Dessus.SilkS) hide + (fp_text value CONN_2 (at 0 -1.905 180) (layer F.SilkS) hide (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (pad 1 thru_hole rect (at -1.27 0 180) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 2 N-000001) - ) - (pad 2 thru_hole circle (at 1.27 0 180) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 3 N-000002) - ) + (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer F.SilkS) (width 0.1524)) + (pad 1 thru_hole rect (at -1.27 0 180) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 2 N-000001)) + (pad 2 thru_hole circle (at 1.27 0 180) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 3 N-000002)) (model pin_array/pins_array_2x1.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -466,24 +414,20 @@ (at 123.19 109.855 90) (descr "Connecteurs 2 pins") (tags "CONN DEV") - (fp_text reference P2 (at 0 -1.905 90) (layer Dessus.SilkS) + (fp_text reference P2 (at 0 -1.905 90) (layer F.SilkS) (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_text value OUT (at 0 -1.905 90) (layer Dessus.SilkS) hide + (fp_text value OUT (at 0 -1.905 90) (layer F.SilkS) hide (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (pad 1 thru_hole rect (at -1.27 0 90) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 4 N-000003) - ) - (pad 2 thru_hole circle (at 1.27 0 90) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer F.SilkS) (width 0.1524)) + (pad 1 thru_hole rect (at -1.27 0 90) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 4 N-000003)) + (pad 2 thru_hole circle (at 1.27 0 90) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model pin_array/pins_array_2x1.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -495,24 +439,20 @@ (at 165.1 111.76 270) (descr "Connecteurs 2 pins") (tags "CONN DEV") - (fp_text reference P1 (at 0 -1.905 270) (layer Dessus.SilkS) + (fp_text reference P1 (at 0 -1.905 270) (layer F.SilkS) (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_text value IN (at 0 -1.905 270) (layer Dessus.SilkS) hide + (fp_text value IN (at 0 -1.905 270) (layer F.SilkS) hide (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (pad 1 thru_hole rect (at -1.27 0 270) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) - (pad 2 thru_hole circle (at 1.27 0 270) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 8 N-000007) - ) + (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer F.SilkS) (width 0.1524)) + (pad 1 thru_hole rect (at -1.27 0 270) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) + (pad 2 thru_hole circle (at 1.27 0 270) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 8 N-000007)) (model pin_array/pins_array_2x1.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -524,24 +464,20 @@ (at 123.19 101.6 90) (descr "Connecteurs 2 pins") (tags "CONN DEV") - (fp_text reference P3 (at 0 -1.905 90) (layer Dessus.SilkS) + (fp_text reference P3 (at 0 -1.905 90) (layer F.SilkS) (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_text value POWER (at 0 -1.905 90) (layer Dessus.SilkS) hide + (fp_text value POWER (at 0 -1.905 90) (layer F.SilkS) hide (effects (font (size 0.762 0.762) (thickness 0.1524))) ) - (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer Dessus.SilkS) (width 0.1524)) - (pad 1 thru_hole rect (at -1.27 0 90) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 7 N-000006) - ) - (pad 2 thru_hole circle (at 1.27 0 90) (size 1.524 1.524) (drill 1.016) - (layers *.Cu *.Mask Dessus.SilkS) - (net 1 GND) - ) + (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer F.SilkS) (width 0.1524)) + (pad 1 thru_hole rect (at -1.27 0 90) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 7 N-000006)) + (pad 2 thru_hole circle (at 1.27 0 90) (size 1.524 1.524) (drill 1.016) (layers *.Cu *.Mask F.SilkS) + (net 1 GND)) (model pin_array/pins_array_2x1.wrl (at (xyz 0 0 0)) (scale (xyz 1 1 1)) @@ -549,73 +485,74 @@ ) ) - (gr_line (start 168.275 132.715) (end 120.015 132.715) (angle 90) (layer Contours.Ci) (width 0.381)) - (gr_line (start 168.275 90.805) (end 120.015 90.805) (angle 90) (layer Contours.Ci) (width 0.381)) - (gr_line (start 168.275 90.805) (end 168.275 132.715) (angle 90) (layer Contours.Ci) (width 0.381)) - (gr_line (start 120.015 90.805) (end 120.015 132.715) (angle 90) (layer Contours.Ci) (width 0.381)) + (gr_line (start 168.275 132.715) (end 120.015 132.715) (angle 90) (layer Edge.Cuts) (width 0.381)) + (gr_line (start 168.275 90.805) (end 120.015 90.805) (angle 90) (layer Edge.Cuts) (width 0.381)) + (gr_line (start 168.275 90.805) (end 168.275 132.715) (angle 90) (layer Edge.Cuts) (width 0.381)) + (gr_line (start 120.015 90.805) (end 120.015 132.715) (angle 90) (layer Edge.Cuts) (width 0.381)) - (segment (start 165.1 110.49) (end 167.005 110.49) (width 0.8636) (layer Dessous) (net 1) (status 800)) - (segment (start 121.285 108.585) (end 121.285 118.745) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 121.285 100.33) (end 121.285 108.585) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 123.19 100.33) (end 127 96.52) (width 0.8636) (layer Dessous) (net 1) (status 800)) - (segment (start 127 96.52) (end 131.445 96.52) (width 0.8636) (layer Dessous) (net 1) (status 400)) - (segment (start 131.445 96.52) (end 161.925 96.52) (width 0.8636) (layer Dessous) (net 1) (status 800)) - (segment (start 161.925 96.52) (end 165.1 99.695) (width 0.8636) (layer Dessous) (net 1) (status 400)) - (segment (start 167.005 110.49) (end 167.005 122.174) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 123.19 100.33) (end 121.285 100.33) (width 0.8636) (layer Dessous) (net 1) (status 800)) - (segment (start 121.285 108.585) (end 123.19 108.585) (width 0.8636) (layer Dessous) (net 1) (status 400)) - (segment (start 165.354 123.825) (end 167.005 122.174) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 165.1 123.825) (end 165.354 123.825) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 167.005 101.6) (end 165.1 99.695) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 167.005 101.6) (end 167.005 110.49) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 121.285 119.38) (end 121.285 118.745) (width 0.8636) (layer Dessous) (net 1)) (segment (start 124.46 122.555) (end 121.285 119.38) (width 0.8636) (layer Dessous) (net 1)) - (segment (start 150.495 128.905) (end 150.495 116.332) (width 0.8636) (layer Dessous) (net 2) (status 800)) - (segment (start 152.6794 104.46512) (end 152.6794 110.8456) (width 0.8636) (layer Dessous) (net 2) (status 800)) - (segment (start 151.54148 103.3272) (end 152.6794 104.46512) (width 0.8636) (layer Dessous) (net 2) (status 400)) - (segment (start 149.225 103.3272) (end 151.54148 103.3272) (width 0.8636) (layer Dessous) (net 2)) - (segment (start 149.86 113.665) (end 149.86 115.697) (width 0.8636) (layer Dessous) (net 2)) - (segment (start 149.86 115.697) (end 150.495 116.332) (width 0.8636) (layer Dessous) (net 2)) + (segment (start 121.285 119.38) (end 121.285 118.745) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 167.005 101.6) (end 167.005 110.49) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 167.005 101.6) (end 165.1 99.695) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 165.1 123.825) (end 165.354 123.825) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 165.354 123.825) (end 167.005 122.174) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 121.285 108.585) (end 123.19 108.585) (width 0.8636) (layer Dessous) (net 1) (status 400)) + (segment (start 123.19 100.33) (end 121.285 100.33) (width 0.8636) (layer Dessous) (net 1) (status 800)) + (segment (start 167.005 110.49) (end 167.005 122.174) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 161.925 96.52) (end 165.1 99.695) (width 0.8636) (layer Dessous) (net 1) (status 400)) + (segment (start 131.445 96.52) (end 161.925 96.52) (width 0.8636) (layer Dessous) (net 1) (status 800)) + (segment (start 127 96.52) (end 131.445 96.52) (width 0.8636) (layer Dessous) (net 1) (status 400)) + (segment (start 123.19 100.33) (end 127 96.52) (width 0.8636) (layer Dessous) (net 1) (status 800)) + (segment (start 121.285 100.33) (end 121.285 108.585) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 121.285 108.585) (end 121.285 118.745) (width 0.8636) (layer Dessous) (net 1)) + (segment (start 165.1 110.49) (end 167.005 110.49) (width 0.8636) (layer Dessous) (net 1) (status 800)) (segment (start 152.6794 110.8456) (end 149.86 113.665) (width 0.8636) (layer Dessous) (net 2)) - (segment (start 147.955 116.15928) (end 145.7706 113.97488) (width 0.8636) (layer Dessous) (net 3) (status 400)) + (segment (start 149.86 115.697) (end 150.495 116.332) (width 0.8636) (layer Dessous) (net 2)) + (segment (start 149.86 113.665) (end 149.86 115.697) (width 0.8636) (layer Dessous) (net 2)) + (segment (start 149.225 103.3272) (end 151.54148 103.3272) (width 0.8636) (layer Dessous) (net 2)) + (segment (start 151.54148 103.3272) (end 152.6794 104.46512) (width 0.8636) (layer Dessous) (net 2) (status 400)) + (segment (start 152.6794 104.46512) (end 152.6794 110.8456) (width 0.8636) (layer Dessous) (net 2) (status 800)) + (segment (start 150.495 128.905) (end 150.495 116.332) (width 0.8636) (layer Dessous) (net 2) (status 800)) (segment (start 147.955 128.905) (end 147.955 116.15928) (width 0.8636) (layer Dessous) (net 3) (status 800)) - (segment (start 128.905 111.125) (end 123.19 111.125) (width 0.8636) (layer Dessous) (net 4) (status 400)) - (segment (start 131.445 108.585) (end 128.905 111.125) (width 0.8636) (layer Dessous) (net 4) (status 800)) - (segment (start 123.825 114.935) (end 123.19 114.3) (width 0.8636) (layer Dessous) (net 4)) - (segment (start 123.19 114.3) (end 123.19 111.125) (width 0.8636) (layer Dessous) (net 4)) + (segment (start 147.955 116.15928) (end 145.7706 113.97488) (width 0.8636) (layer Dessous) (net 3) (status 400)) (segment (start 124.46 114.935) (end 123.825 114.935) (width 0.8636) (layer Dessous) (net 4)) - (segment (start 140.97 123.825) (end 139.065 125.73) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 139.065 125.73) (end 130.175 125.73) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 130.175 125.73) (end 128.905 127) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 143.61668 107.3912) (end 142.1638 107.3912) (width 0.8636) (layer Dessous) (net 5) (status 800)) - (segment (start 140.97 108.585) (end 140.97 121.285) (width 0.8636) (layer Dessous) (net 5) (status 400)) - (segment (start 142.1638 107.3912) (end 140.97 108.585) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 140.97 121.285) (end 140.97 123.825) (width 0.8636) (layer Dessous) (net 5) (status 800)) - (segment (start 154.94 116.23548) (end 152.6794 113.97488) (width 0.8636) (layer Dessous) (net 5) (status 400)) - (segment (start 154.94 130.175) (end 154.94 116.23548) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 128.905 127) (end 128.905 130.175) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 128.905 130.175) (end 130.175 131.445) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 130.175 131.445) (end 153.67 131.445) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 123.19 114.3) (end 123.19 111.125) (width 0.8636) (layer Dessous) (net 4)) + (segment (start 123.825 114.935) (end 123.19 114.3) (width 0.8636) (layer Dessous) (net 4)) + (segment (start 131.445 108.585) (end 128.905 111.125) (width 0.8636) (layer Dessous) (net 4) (status 800)) + (segment (start 128.905 111.125) (end 123.19 111.125) (width 0.8636) (layer Dessous) (net 4) (status 400)) (segment (start 153.67 131.445) (end 154.94 130.175) (width 0.8636) (layer Dessous) (net 5)) - (segment (start 165.0238 107.3912) (end 165.1 107.315) (width 0.8636) (layer Dessous) (net 6) (status 400)) + (segment (start 130.175 131.445) (end 153.67 131.445) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 128.905 130.175) (end 130.175 131.445) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 128.905 127) (end 128.905 130.175) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 154.94 130.175) (end 154.94 116.23548) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 154.94 116.23548) (end 152.6794 113.97488) (width 0.8636) (layer Dessous) (net 5) (status 400)) + (segment (start 140.97 121.285) (end 140.97 123.825) (width 0.8636) (layer Dessous) (net 5) (status 800)) + (segment (start 142.1638 107.3912) (end 140.97 108.585) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 140.97 108.585) (end 140.97 121.285) (width 0.8636) (layer Dessous) (net 5) (status 400)) + (segment (start 143.61668 107.3912) (end 142.1638 107.3912) (width 0.8636) (layer Dessous) (net 5) (status 800)) + (segment (start 130.175 125.73) (end 128.905 127) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 139.065 125.73) (end 130.175 125.73) (width 0.8636) (layer Dessous) (net 5)) + (segment (start 140.97 123.825) (end 139.065 125.73) (width 0.8636) (layer Dessous) (net 5)) (segment (start 154.83332 107.3912) (end 165.0238 107.3912) (width 0.8636) (layer Dessous) (net 6) (status 800)) - (segment (start 124.46 102.87) (end 125.73 101.6) (width 0.8636) (layer Dessous) (net 7)) - (segment (start 131.445 101.6) (end 142.90548 101.6) (width 0.8636) (layer Dessous) (net 7) (status 800)) - (segment (start 142.90548 101.6) (end 145.7706 104.46512) (width 0.8636) (layer Dessous) (net 7) (status 400)) - (segment (start 123.19 102.87) (end 124.46 102.87) (width 0.8636) (layer Dessous) (net 7) (status 800)) + (segment (start 165.0238 107.3912) (end 165.1 107.315) (width 0.8636) (layer Dessous) (net 6) (status 400)) + (segment (start 190.2206 96.74352) (end 181.84622 96.74352) (width 0.8636) (layer Dessous) (net 7)) (segment (start 125.73 101.6) (end 131.445 101.6) (width 0.8636) (layer Dessous) (net 7) (status 400)) - (segment (start 154.83332 111.0488) (end 159.9438 111.0488) (width 0.8636) (layer Dessous) (net 8) (status 800)) - (segment (start 165.1 113.03) (end 165.1 116.205) (width 0.8636) (layer Dessous) (net 8) (status C00)) - (segment (start 159.9438 111.0488) (end 161.925 113.03) (width 0.8636) (layer Dessous) (net 8)) + (segment (start 123.19 102.87) (end 124.46 102.87) (width 0.8636) (layer Dessous) (net 7) (status 800)) + (segment (start 142.90548 101.6) (end 145.7706 104.46512) (width 0.8636) (layer Dessous) (net 7) (status 400)) + (segment (start 131.445 101.6) (end 142.90548 101.6) (width 0.8636) (layer Dessous) (net 7) (status 800)) + (segment (start 124.46 102.87) (end 125.73 101.6) (width 0.8636) (layer Dessous) (net 7)) (segment (start 161.925 113.03) (end 165.1 113.03) (width 0.8636) (layer Dessous) (net 8) (status 400)) - (segment (start 131.445 128.905) (end 140.97 128.905) (width 0.8636) (layer Dessous) (net 9) (status C00)) - (segment (start 143.61668 111.00816) (end 143.61668 111.65332) (width 0.8636) (layer Dessous) (net 9) (status 800)) - (segment (start 143.51 127.635) (end 143.51 116.84) (width 0.8636) (layer Dessous) (net 9)) - (segment (start 142.24 128.905) (end 143.51 127.635) (width 0.8636) (layer Dessous) (net 9)) - (segment (start 140.97 128.905) (end 142.24 128.905) (width 0.8636) (layer Dessous) (net 9) (status 800)) - (segment (start 143.61668 111.65332) (end 142.875 112.395) (width 0.8636) (layer Dessous) (net 9)) - (segment (start 142.875 112.395) (end 142.875 116.205) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 159.9438 111.0488) (end 161.925 113.03) (width 0.8636) (layer Dessous) (net 8)) + (segment (start 165.1 113.03) (end 165.1 116.205) (width 0.8636) (layer Dessous) (net 8) (status C00)) + (segment (start 154.83332 111.0488) (end 159.9438 111.0488) (width 0.8636) (layer Dessous) (net 8) (status 800)) (segment (start 142.875 116.205) (end 143.51 116.84) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 142.875 112.395) (end 142.875 116.205) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 143.61668 111.65332) (end 142.875 112.395) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 140.97 128.905) (end 142.24 128.905) (width 0.8636) (layer Dessous) (net 9) (status 800)) + (segment (start 142.24 128.905) (end 143.51 127.635) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 143.51 127.635) (end 143.51 116.84) (width 0.8636) (layer Dessous) (net 9)) + (segment (start 143.61668 111.00816) (end 143.61668 111.65332) (width 0.8636) (layer Dessous) (net 9) (status 800)) + (segment (start 131.445 128.905) (end 140.97 128.905) (width 0.8636) (layer Dessous) (net 9) (status C00)) (zone (net 1) (net_name GND) (layer Dessous) (tstamp 4EED96A1) (hatch edge 0.508) (connect_pads (clearance 0.635)) diff --git a/include/class_board_design_settings.h b/include/class_board_design_settings.h index 67e0c73a88..8d04fe0922 100644 --- a/include/class_board_design_settings.h +++ b/include/class_board_design_settings.h @@ -8,8 +8,44 @@ #include // NB_COLORS #include #include +#include #include +/** + * Struct VIA_DIMENSION + * is a small helper container to handle a stock of specific vias each with + * unique diameter and drill sizes in the BOARD class. + */ +struct VIA_DIMENSION +{ + int m_Diameter; // <= 0 means use Netclass via diameter + int m_Drill; // <= 0 means use Netclass via drill + + VIA_DIMENSION() + { + m_Diameter = 0; + m_Drill = 0; + } + + VIA_DIMENSION( int aDiameter, int aDrill ) + { + m_Diameter = aDiameter; + m_Drill = aDrill; + } + + bool operator==( const VIA_DIMENSION& aOther ) const + { + return ( m_Diameter == aOther.m_Diameter ) && ( m_Drill == aOther.m_Drill ); + } + + bool operator<( const VIA_DIMENSION& aOther ) const + { + if( m_Diameter != aOther.m_Diameter ) + return m_Diameter < aOther.m_Diameter; + + return m_Drill < aOther.m_Drill; + } +}; /** * Class BOARD_DESIGN_SETTINGS @@ -18,6 +54,17 @@ class BOARD_DESIGN_SETTINGS { public: + // The first value is the current netclass via size + /// Vias size and drill list + std::vector m_ViasDimensionsList; + + // The first value is the current netclass track width + /// Track width list + std::vector m_TrackWidthList; + + /// List of current netclasses. There is always the default netclass. + NETCLASSES m_NetClasses; + bool m_MicroViasAllowed; ///< true to allow micro vias bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias VIATYPE_T m_CurrentViaType; ///< via type (VIA_BLIND_BURIED, VIA_THROUGH VIA_MICROVIA) @@ -52,15 +99,216 @@ public: D_PAD m_Pad_Master; -public: BOARD_DESIGN_SETTINGS(); + /** + * Function GetDefault + * @return the default netclass. + */ + inline NETCLASS* GetDefault() const + { + return m_NetClasses.GetDefault(); + } + + /** + * Function GetCurrentNetClassName + * @return the current net class name. + */ + const wxString& GetCurrentNetClassName() const + { + return m_currentNetClassName; + } + + /** + * Function SetCurrentNetClass + * Must be called after a netclass selection (or after a netclass parameter change + * Initialize vias and tracks values displayed in comb boxes of the auxiliary toolbar + * and some others parameters (netclass name ....) + * @param aNetClassName = the new netclass name + * @return true if lists of tracks and vias sizes are modified + */ + bool SetCurrentNetClass( const wxString& aNetClassName ); + + /** + * Function GetBiggestClearanceValue + * @return the biggest clearance value found in NetClasses list + */ + int GetBiggestClearanceValue(); + + /** + * Function GetSmallestClearanceValue + * @return the smallest clearance value found in NetClasses list + */ + int GetSmallestClearanceValue(); + + /** + * Function GetCurrentMicroViaSize + * @return the current micro via size, + * that is the current netclass value + */ + int GetCurrentMicroViaSize(); + + /** + * Function GetCurrentMicroViaDrill + * @return the current micro via drill, + * that is the current netclass value + */ + int GetCurrentMicroViaDrill(); + + /** + * Function GetTrackWidthIndex + * @return the current track width list index. + */ + unsigned GetTrackWidthIndex() const { return m_trackWidthIndex; } + + /** + * Function SetTrackWidthIndex + * sets the current track width list index to \a aIndex. + * + * @param aIndex is the track width list index. + */ + void SetTrackWidthIndex( unsigned aIndex ); + + /** + * Function GetCurrentTrackWidth + * @return the current track width, according to the selected options + * ( using the default netclass value or a preset/custom value ) + * the default netclass is always in m_TrackWidthList[0] + */ + int GetCurrentTrackWidth() const + { + return m_useCustomTrackVia ? m_customTrackWidth : m_TrackWidthList[m_trackWidthIndex]; + } + + /** + * Function SetCustomTrackWidth + * Sets custom width for track (i.e. not available in netclasses or preset list). To have + * it returned with GetCurrentTrackWidth() you need to enable custom track & via sizes + * (UseCustomTrackViaSize()). + * @param aWidth is the new track width. + */ + void SetCustomTrackWidth( int aWidth ) + { + m_customTrackWidth = aWidth; + } + + /** + * Function GetCustomTrackWidth + * @return Current custom width for a track. + */ + int GetCustomTrackWidth() const + { + return m_customTrackWidth; + } + + /** + * Function GetViaSizeIndex + * @return the current via size list index. + */ + unsigned GetViaSizeIndex() const { return m_viaSizeIndex; } + + /** + * Function SetViaSizeIndex + * sets the current via size list index to \a aIndex. + * + * @param aIndex is the via size list index. + */ + void SetViaSizeIndex( unsigned aIndex ); + + /** + * Function GetCurrentViaSize + * @return the current via size, according to the selected options + * ( using the default netclass value or a preset/custom value ) + * the default netclass is always in m_TrackWidthList[0] + */ + int GetCurrentViaSize() const + { + if( m_useCustomTrackVia ) + return m_customViaSize.m_Diameter; + else + return m_ViasDimensionsList[m_viaSizeIndex].m_Diameter; + } + + /** + * Function SetCustomViaSize + * Sets custom size for via diameter (i.e. not available in netclasses or preset list). To have + * it returned with GetCurrentViaSize() you need to enable custom track & via sizes + * (UseCustomTrackViaSize()). + * @param aSize is the new drill diameter. + */ + void SetCustomViaSize( int aSize ) + { + m_customViaSize.m_Diameter = aSize; + } + + /** + * Function GetCustomViaSize + * @return Current custom size for the via diameter. + */ + int GetCustomViaSize() const + { + return m_customViaSize.m_Diameter; + } + + /** + * Function GetCurrentViaDrill + * @return the current via size, according to the selected options + * ( using the default netclass value or a preset/custom value ) + * the default netclass is always in m_TrackWidthList[0] + */ + int GetCurrentViaDrill() const; + + /** + * Function SetCustomViaDrill + * Sets custom size for via drill (i.e. not available in netclasses or preset list). To have + * it returned with GetCurrentViaDrill() you need to enable custom track & via sizes + * (UseCustomTrackViaSize()). + * @param aDrill is the new drill size. + */ + void SetCustomViaDrill( int aDrill ) + { + m_customViaSize.m_Drill = aDrill; + } + + /** + * Function GetCustomViaDrill + * @return Current custom size for the via drill. + */ + int GetCustomViaDrill() const + { + return m_customViaSize.m_Drill; + } + + /** + * Function UseCustomTrackViaSize + * Enables/disables custom track/via size settings. If enabled, values set with + * SetCustomTrackWidth()/SetCustomViaSize()/SetCustomViaDrill() are used for newly created + * tracks and vias. + * @param aEnabled decides if custom settings should be used for new tracks/vias. + */ + void UseCustomTrackViaSize( bool aEnabled ) + { + m_useCustomTrackVia = aEnabled; + } + + /** + * Function UseCustomTrackViaSize + * @return True if custom sizes of tracks & vias are enabled, false otherwise. + */ + bool UseCustomTrackViaSize() const + { + return m_useCustomTrackVia; + } + /** * Function GetVisibleLayers * returns a bit-mask of all the layers that are visible * @return int - the visible layers in bit-mapped form. */ - LAYER_MSK GetVisibleLayers() const; + LAYER_MSK GetVisibleLayers() const + { + return m_visibleLayers; + } /** * Function SetVisibleAlls @@ -74,7 +322,10 @@ public: * changes the bit-mask of visible layers * @param aMask = The new bit-mask of visible layers */ - void SetVisibleLayers( LAYER_MSK aMask ); + void SetVisibleLayers( LAYER_MSK aMask ) + { + m_visibleLayers = aMask & m_enabledLayers & FULL_LAYERS; + } /** * Function IsLayerVisible @@ -85,7 +336,7 @@ public: bool IsLayerVisible( LAYER_NUM aLayer ) const { // If a layer is disabled, it is automatically invisible - return m_VisibleLayers & m_EnabledLayers & GetLayerMask( aLayer ); + return m_visibleLayers & m_enabledLayers & GetLayerMask( aLayer ); } /** @@ -103,7 +354,7 @@ public: */ int GetVisibleElements() const { - return m_VisibleElements; + return m_visibleElements; } /** @@ -113,7 +364,7 @@ public: */ void SetVisibleElements( int aMask ) { - m_VisibleElements = aMask; + m_visibleElements = aMask; } /** @@ -128,7 +379,7 @@ public: { assert( aElementCategory >= 0 && aElementCategory < END_PCB_VISIBLE_LIST ); - return ( m_VisibleElements & ( 1 << aElementCategory ) ); + return ( m_visibleElements & ( 1 << aElementCategory ) ); } /** @@ -147,7 +398,7 @@ public: */ inline LAYER_MSK GetEnabledLayers() const { - return m_EnabledLayers; + return m_enabledLayers; } /** @@ -165,7 +416,7 @@ public: */ bool IsLayerEnabled( LAYER_NUM aLayer ) const { - return m_EnabledLayers & GetLayerMask( aLayer ); + return m_enabledLayers & GetLayerMask( aLayer ); } /** @@ -174,7 +425,7 @@ public: */ int GetCopperLayerCount() const { - return m_CopperLayerCount; + return m_copperLayerCount; } /** @@ -196,11 +447,35 @@ public: void SetBoardThickness( int aThickness ) { m_boardThickness = aThickness; } private: - int m_CopperLayerCount; ///< Number of copper layers for this design - LAYER_MSK m_EnabledLayers; ///< Bit-mask for layer enabling - LAYER_MSK m_VisibleLayers; ///< Bit-mask for layer visibility - int m_VisibleElements; ///< Bit-mask for element category visibility + /// Index for #m_ViasDimensionsList to select the current via size. + /// 0 is the index selection of the default value Netclass + unsigned m_viaSizeIndex; + + // Index for m_TrackWidthList to select the value. + /// 0 is the index selection of the default value Netclass + unsigned m_trackWidthIndex; + + ///> Use custom values for track/via sizes (not specified in net class nor in the size lists). + bool m_useCustomTrackVia; + + ///> Custom track width (used after UseCustomTrackViaSize( true ) was called). + int m_customTrackWidth; + + ///> Custom via size (used after UseCustomTrackViaSize( true ) was called). + VIA_DIMENSION m_customViaSize; + + int m_copperLayerCount; ///< Number of copper layers for this design + LAYER_MSK m_enabledLayers; ///< Bit-mask for layer enabling + LAYER_MSK m_visibleLayers; ///< Bit-mask for layer visibility + int m_visibleElements; ///< Bit-mask for element category visibility int m_boardThickness; ///< Board thickness for 3D viewer + + /// Current net class name used to display netclass info. + /// This is also the last used netclass after starting a track. + wxString m_currentNetClassName; + + void formatNetClass( NETCLASS* aNetClass, OUTPUTFORMATTER* aFormatter, int aNestLevel, + int aControlBits ) const throw( IO_ERROR ); }; #endif // BOARD_DESIGN_SETTINGS_H_ diff --git a/include/class_draw_panel_gal.h b/include/class_draw_panel_gal.h index 4ec05ed65d..16de3a139c 100644 --- a/include/class_draw_panel_gal.h +++ b/include/class_draw_panel_gal.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or @@ -111,9 +111,16 @@ public: m_eventDispatcher = aEventDispatcher; } + /** + * Function StartDrawing() + * Begins drawing if it was stopped previously. + */ + void StartDrawing(); + /** * Function StopDrawing() - * Prevents the GAL canvas from further drawing till it is recreated. + * Prevents the GAL canvas from further drawing till it is recreated + * or StartDrawing() is called. */ void StopDrawing(); diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 352e262931..6b44b1d476 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -135,7 +135,7 @@ public: virtual void Flush(); /// @copydoc GAL::ClearScreen() - virtual void ClearScreen(); + virtual void ClearScreen( const COLOR4D& aColor ); // ----------------- // Attribute setting @@ -309,7 +309,7 @@ private: /// Type definition for an graphics group element typedef struct { - GRAPHICS_COMMAND command; ///< Command to execute + GRAPHICS_COMMAND command; ///< Command to execute double arguments[MAX_CAIRO_ARGUMENTS]; ///< Arguments for Cairo commands bool boolArgument; ///< A bool argument int intArgument; ///< An int argument @@ -333,6 +333,7 @@ private: unsigned int* bitmapBufferBackup; ///< Backup storage of the cairo image int stride; ///< Stride value for Cairo bool isInitialized; ///< Are Cairo image & surface ready to use + COLOR4D backgroundColor; ///< Background color // Methods void storePath(); ///< Store the actual path diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index 50b5c355c7..6d904d2016 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -168,8 +168,11 @@ public: /// @brief Force all remaining objects to be drawn. virtual void Flush() = 0; - /// @brief Clear the screen. - virtual void ClearScreen() = 0; + /** + * @brief Clear the screen. + * @param aColor is the color used for clearing. + */ + virtual void ClearScreen( const COLOR4D& aColor ) = 0; // ----------------- // Attribute setting @@ -225,16 +228,6 @@ public: return strokeColor; } - /** - * @brief Set the background color. - * - * @param aColor is the color for background filling. - */ - inline virtual void SetBackgroundColor( const COLOR4D& aColor ) - { - backgroundColor = aColor; - } - /** * @brief Set the line width. * @@ -849,7 +842,6 @@ protected: bool isFillEnabled; ///< Is filling of graphic objects enabled ? bool isStrokeEnabled; ///< Are the outlines stroked ? - COLOR4D backgroundColor; ///< The background color COLOR4D fillColor; ///< The fill color COLOR4D strokeColor; ///< The color of the outlines diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index d5c97aada9..10c4fea54d 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -143,7 +143,7 @@ public: virtual void Flush(); /// @copydoc GAL::ClearScreen() - virtual void ClearScreen(); + virtual void ClearScreen( const COLOR4D& aColor ); // -------------- // Transformation diff --git a/include/geometry/seg.h b/include/geometry/seg.h index cf5b8d50c9..af8161bb80 100644 --- a/include/geometry/seg.h +++ b/include/geometry/seg.h @@ -46,17 +46,14 @@ public: * to an object the segment belongs to (e.g. a line chain) or references to locally stored * points (m_a, m_b). */ - VECTOR2I& A; - VECTOR2I& B; + VECTOR2I A; + VECTOR2I B; /** Default constructor * Creates an empty (0, 0) segment, locally-referenced */ - SEG() : A( m_a ), B( m_b ) + SEG() { - A = m_a; - B = m_b; - m_is_local = true; m_index = -1; } @@ -64,13 +61,10 @@ public: * Constructor * Creates a segment between (aX1, aY1) and (aX2, aY2), locally referenced */ - SEG( int aX1, int aY1, int aX2, int aY2 ) : A( m_a ), B( m_b ) + SEG( int aX1, int aY1, int aX2, int aY2 ) : + A ( VECTOR2I( aX1, aY1 ) ), + B ( VECTOR2I( aX2, aY2 ) ) { - m_a = VECTOR2I( aX1, aY1 ); - m_b = VECTOR2I( aX2, aY2 ); - A = m_a; - B = m_b; - m_is_local = true; m_index = -1; } @@ -78,11 +72,8 @@ public: * Constructor * Creates a segment between (aA) and (aB), locally referenced */ - SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : A( m_a ), B( m_b ), m_a( aA ), m_b( aB ) + SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : A( aA ), B( aB ) { - A = m_a; - B = m_b; - m_is_local = true; m_index = -1; } @@ -93,44 +84,24 @@ public: * @param aB reference to the end point in the parent shape * @param aIndex index of the segment within the parent shape */ - SEG ( VECTOR2I& aA, VECTOR2I& aB, int aIndex ) : A( aA ), B( aB ) + SEG ( const VECTOR2I& aA, const VECTOR2I& aB, int aIndex ) : A( aA ), B( aB ) { - m_is_local = false; m_index = aIndex; } /** * Copy constructor */ - SEG ( const SEG& aSeg ) : A( m_a ), B( m_b ) + SEG ( const SEG& aSeg ) : A( aSeg.A ), B( aSeg.B ), m_index ( aSeg.m_index ) { - if( aSeg.m_is_local ) - { - m_a = aSeg.m_a; - m_b = aSeg.m_b; - A = m_a; - B = m_b; - m_is_local = true; - m_index = -1; - } - else - { - A = aSeg.A; - B = aSeg.B; - m_index = aSeg.m_index; - m_is_local = false; - } } SEG& operator=( const SEG& aSeg ) { A = aSeg.A; B = aSeg.B; - m_a = aSeg.m_a; - m_b = aSeg.m_b; m_index = aSeg.m_index; - m_is_local = aSeg.m_is_local; - + return *this; } @@ -244,14 +215,14 @@ public: */ bool Collinear( const SEG& aSeg ) const { - ecoord qa = A.y - B.y; - ecoord qb = B.x - A.x; - ecoord qc = -qa * A.x - qb * A.y; + ecoord qa1 = A.y - B.y; + ecoord qb1 = B.x - A.x; + ecoord qc1 = -qa1 * A.x - qb1 * A.y; + ecoord qa2 = aSeg.A.y - aSeg.B.y; + ecoord qb2 = aSeg.B.x - aSeg.A.x; + ecoord qc2 = -qa2 * aSeg.A.x - qb2 * aSeg.A.y; - ecoord d1 = std::abs( aSeg.A.x * qa + aSeg.A.y * qb + qc ); - ecoord d2 = std::abs( aSeg.B.x * qa + aSeg.B.y * qb + qc ); - - return ( d1 <= 1 && d2 <= 1 ); + return ( qa1 == qa2 ) && ( qb1 == qb2 ) && ( qc1 == qc2 ); } /** @@ -289,14 +260,8 @@ public: private: bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const; - ///> locally stored start/end coordinates (used when m_is_local == true) - VECTOR2I m_a, m_b; - ///> index withing the parent shape (used when m_is_local == false) int m_index; - - ///> locality flag - bool m_is_local; }; @@ -344,8 +309,7 @@ inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg ) { - if( aSeg.m_is_local ) - aStream << "[ local " << aSeg.A << " - " << aSeg.B << " ]"; + aStream << "[ " << aSeg.A << " - " << aSeg.B << " ]"; return aStream; } diff --git a/include/geometry/shape_circle.h b/include/geometry/shape_circle.h index a11cd4da8f..e4b668b68c 100644 --- a/include/geometry/shape_circle.h +++ b/include/geometry/shape_circle.h @@ -38,9 +38,20 @@ public: SHAPE( SH_CIRCLE ), m_radius( aRadius ), m_center( aCenter ) {} + SHAPE_CIRCLE ( const SHAPE_CIRCLE& aOther ) : + SHAPE( SH_CIRCLE ), + m_radius( aOther.m_radius ), + m_center( aOther.m_center ) + {}; + ~SHAPE_CIRCLE() {} + SHAPE* Clone() const + { + return new SHAPE_CIRCLE( *this ); + } + const BOX2I BBox( int aClearance = 0 ) const { const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance ); diff --git a/include/geometry/shape_index.h b/include/geometry/shape_index.h index 24b174e1fa..49b0e124f9 100644 --- a/include/geometry/shape_index.h +++ b/include/geometry/shape_index.h @@ -43,7 +43,7 @@ template static const SHAPE* shapeFunctor( T aItem ) { - return aItem->GetShape(); + return aItem->Shape(); } diff --git a/include/geometry/shape_index_list.h b/include/geometry/shape_index_list.h index 0d0e644803..194ae5ffd9 100644 --- a/include/geometry/shape_index_list.h +++ b/include/geometry/shape_index_list.h @@ -30,7 +30,7 @@ template const SHAPE* defaultShapeFunctor( const T aItem ) { - return aItem->GetShape(); + return aItem->Shape(); } template > diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index da6494e91a..b3bd7d9c2d 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -116,6 +116,8 @@ public: ~SHAPE_LINE_CHAIN() {} + SHAPE* Clone() const; + /** * Function Clear() * Removes all points from the line chain. @@ -366,6 +368,11 @@ public: } } + void Insert( int aVertex, const VECTOR2I& aP ) + { + m_points.insert( m_points.begin() + aVertex, aP ); + } + /** * Function Replace() * @@ -417,6 +424,15 @@ public: */ int Find( const VECTOR2I& aP ) const; + /** + * Function FindSegment() + * + * Searches for segment containing point aP. + * @param aP the point to be looked for + * @return index of the correspoinding segment in the line chain or negative when not found. + */ + int FindSegment( const VECTOR2I& aP ) const; + /** * Function Slice() * @@ -429,7 +445,7 @@ public: struct compareOriginDistance { - compareOriginDistance( VECTOR2I& aOrigin ): + compareOriginDistance( const VECTOR2I& aOrigin ): m_origin( aOrigin ) {} @@ -441,6 +457,8 @@ public: VECTOR2I m_origin; }; + bool Intersects( const SHAPE_LINE_CHAIN& aChain ) const; + /** * Function Intersect() * @@ -533,6 +551,8 @@ public: return false; } + bool CompareGeometry( const SHAPE_LINE_CHAIN & aOther ) const; + private: /// array of vertices std::vector m_points; diff --git a/include/geometry/shape_rect.h b/include/geometry/shape_rect.h index d2c5f22a33..bc3ba44d17 100644 --- a/include/geometry/shape_rect.h +++ b/include/geometry/shape_rect.h @@ -53,10 +53,22 @@ public: * Constructor * Creates a rectangle defined by top-left corner aP0, width aW and height aH. */ - SHAPE_RECT( const VECTOR2I& aP0, int aW, int aH ) : + SHAPE_RECT( const VECTOR2I& aP0, int aW, int aH ) : SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {} + SHAPE_RECT ( const SHAPE_RECT& aOther ) : + SHAPE( SH_RECT ), + m_p0( aOther.m_p0 ), + m_w( aOther.m_w ), + m_h( aOther.m_h ) + {}; + + SHAPE* Clone() const + { + return new SHAPE_RECT( *this ); + } + /// @copydoc SHAPE::BBox() const BOX2I BBox( int aClearance = 0 ) const { @@ -90,11 +102,11 @@ public: if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) ) return true; - VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ), - VECTOR2I( m_p0.x, m_p0.y + m_h ), - VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ), - VECTOR2I( m_p0.x + m_w, m_p0.y ), - VECTOR2I( m_p0.x, m_p0.y ) }; + VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ), + VECTOR2I( m_p0.x, m_p0.y + m_h ), + VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ), + VECTOR2I( m_p0.x + m_w, m_p0.y ), + VECTOR2I( m_p0.x, m_p0.y ) }; for( int i = 0; i < 4; i++ ) { diff --git a/include/geometry/shape_segment.h b/include/geometry/shape_segment.h new file mode 100644 index 0000000000..5f18760bd7 --- /dev/null +++ b/include/geometry/shape_segment.h @@ -0,0 +1,90 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Tomasz Wlostowski + * + * 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 __SHAPE_SEGMENT_H +#define __SHAPE_SEGMENT_H + +#include +#include + +class SHAPE_SEGMENT : public SHAPE { + +public: + SHAPE_SEGMENT(): + SHAPE( SH_SEGMENT ), m_width( 0 ) {}; + + SHAPE_SEGMENT( const VECTOR2I& aA, const VECTOR2I& aB, int aWidth = 0 ): + SHAPE( SH_SEGMENT ), m_seg( aA, aB ), m_width( aWidth ) {}; + + SHAPE_SEGMENT( const SEG& aSeg, int aWidth = 0 ): + SHAPE( SH_SEGMENT ), m_seg( aSeg ), m_width( aWidth ) {}; + + ~SHAPE_SEGMENT() {}; + + SHAPE* Clone() const + { + return new SHAPE_SEGMENT( m_seg, m_width ); + } + + const BOX2I BBox( int aClearance = 0 ) const + { + return BOX2I( m_seg.A, m_seg.B - m_seg.A ).Inflate( aClearance + m_width / 2 ); + } + + bool Collide( const SEG& aSeg, int aClearance = 0 ) const + { + return m_seg.Distance( aSeg ) <= m_width / 2 + aClearance; + } + + bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const + { + return m_seg.Distance( aP ) <= m_width / 2 + aClearance; + } + + void SetSeg ( const SEG& aSeg ) + { + m_seg = aSeg; + } + + const SEG& GetSeg () const + { + return m_seg; + } + + void SetWidth ( int aWidth ) + { + m_width = aWidth; + } + + int GetWidth() const + { + return m_width; + } + +private: + SEG m_seg; + int m_width; +}; + +#endif diff --git a/include/math/math_util.h b/include/math/math_util.h index 812b52fba8..cb3ce50460 100644 --- a/include/math/math_util.h +++ b/include/math/math_util.h @@ -40,6 +40,11 @@ T rescale( T aNumerator, T aValue, T aDenominator ) return aNumerator * aValue / aDenominator; } +template +int sign( T val ) +{ + return ( T( 0 ) < val) - ( val < T( 0 ) ); +} // explicit specializations for integer types, taking care of overflow. template <> diff --git a/include/math/vector2d.h b/include/math/vector2d.h index feee5ff060..5bb43e5872 100644 --- a/include/math/vector2d.h +++ b/include/math/vector2d.h @@ -28,6 +28,7 @@ #ifndef VECTOR2D_H_ #define VECTOR2D_H_ +#include #include #include #include @@ -376,7 +377,7 @@ VECTOR2 VECTOR2::Resize( T aNewLength ) const return VECTOR2 ( ( x < 0 ? -1 : 1 ) * sqrt( rescale( l_sq_new, (extended_type) x * x, l_sq_current ) ), - ( y < 0 ? -1 : 1 ) * sqrt( rescale( l_sq_new, (extended_type) y * y, l_sq_current ) ) ); + ( y < 0 ? -1 : 1 ) * sqrt( rescale( l_sq_new, (extended_type) y * y, l_sq_current ) ) ) * sign( aNewLength ); } diff --git a/include/painter.h b/include/painter.h index 34376d985d..afa74aa482 100644 --- a/include/painter.h +++ b/include/painter.h @@ -177,6 +177,36 @@ public: return m_worksheetLineWidth; } + /** + * Function TranslateColor + * Returns the color responding to the one of EDA_COLOR_T enum values. + * @param EDA_COLOR_T color equivalent. + */ + const COLOR4D& TranslateColor( EDA_COLOR_T aColor ) + { + return m_legacyColorMap[aColor]; + } + + /** + * Function GetBackgroundColor + * Returns current background color settings. + * @return Background color. + */ + const COLOR4D& GetBackgroundColor() const + { + return m_backgroundColor; + } + + /** + * Function SetBackgroundColor + * Sets new color for background. + * @param aColor is the new background color. + */ + void SetBackgroundColor( const COLOR4D& aColor ) + { + m_backgroundColor = aColor; + } + protected: /** * Function update @@ -203,6 +233,8 @@ protected: float m_outlineWidth; ///< Line width used when drawing outlines float m_worksheetLineWidth; ///< Line width used when drawing worksheet + COLOR4D m_backgroundColor; ///< The background color + /// Map of colors that were usually used for display std::map m_legacyColorMap; }; diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index df6f7cb0b7..709e0d34e7 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -28,6 +28,7 @@ #include #include #include +#include class TOOL_INTERACTIVE; @@ -37,7 +38,7 @@ class TOOL_INTERACTIVE; * Defines the structure of a context (usually right-click) popup menu * for a given tool. */ -class CONTEXT_MENU +class CONTEXT_MENU : public wxMenu { public: ///> Default constructor @@ -71,6 +72,7 @@ public: */ void Add( const TOOL_ACTION& aAction ); + /** * Function Clear() * Removes all the entries from the menu (as well as its title). It leaves the menu in the @@ -89,32 +91,29 @@ public: return m_selected; } - /** - * Function GetMenu() - * Returns the instance of wxMenu object used to display the menu. - */ - wxMenu* GetMenu() const +protected: + void setCustomEventHandler( boost::function aHandler ) { - return const_cast( &m_menu ); + m_customHandler = aHandler; + } + + virtual OPT_TOOL_EVENT handleCustomEvent(const wxEvent& aEvent ) + { + return OPT_TOOL_EVENT(); } private: - ///> Class CMEventHandler takes care of handling menu events. After reception of particular - ///> events, it translates them to TOOL_EVENTs that may control tools. - class CMEventHandler : public wxEvtHandler - { - public: - ///> Default constructor - ///> aMenu is the CONTEXT_MENU instance for which it handles events. - CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {}; + /** + * Function copyItem + * Copies all properties of a menu entry to another. + */ + void copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const; - ///> Handler for menu events. - void onEvent( wxEvent& aEvent ); + ///> Initializes handlers for events. + void setupEvents(); - private: - ///> CONTEXT_MENU instance for which it handles events. - CONTEXT_MENU* m_menu; - }; + ///> Event handler. + void onMenuEvent( wxEvent& aEvent ); friend class TOOL_INTERACTIVE; @@ -128,25 +127,14 @@ private: m_tool = aTool; } - /** - * Function getHotKeyDescription() - * Returns a hot key in the string format accepted by wxMenu. - * @param aAction is the action with hot key to be translated.. - * @return Hot key in the string format compatible with wxMenu. - */ - std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const; - ///> Flag indicating that the menu title was set up. bool m_titleSet; - ///> Instance of wxMenu used for display of the context menu. - wxMenu m_menu; - ///> Stores the id number of selected item. int m_selected; ///> Instance of menu event handler. - CMEventHandler m_handler; + //CMEventHandler m_handler; ///> Creator of the menu TOOL_INTERACTIVE* m_tool; @@ -156,6 +144,9 @@ private: /// Associates tool actions with menu item IDs. Non-owning. std::map m_toolActions; + + /// Custom events handler, allows to translate wxEvents to TOOL_EVENTs. + boost::function m_customHandler; }; #endif diff --git a/include/tool/tool_action.h b/include/tool/tool_action.h index 8fb81e5d8d..4097fd2f7f 100644 --- a/include/tool/tool_action.h +++ b/include/tool/tool_action.h @@ -52,12 +52,12 @@ public: m_currentHotKey( aDefaultHotKey ), m_menuItem( aMenuItem ), m_menuDescription( aMenuDesc ), m_id( -1 ) { - TOOL_MANAGER::Instance().RegisterAction( this ); + TOOL_MANAGER::GetActionList().push_back( this ); } ~TOOL_ACTION() { - TOOL_MANAGER::Instance().UnregisterAction( this ); + TOOL_MANAGER::GetActionList().remove( this ); } bool operator==( const TOOL_ACTION& aRhs ) const @@ -195,6 +195,12 @@ private: m_id = aId; } + /// Assigns ACTION_MANAGER object that handles the TOOL_ACTION. + void setActionMgr( ACTION_MANAGER* aManager ) + { + m_actionMgr = aManager; + } + /// Name of the action (convention is: app.[tool.]action.name) std::string m_name; @@ -219,11 +225,14 @@ private: /// Unique ID for fast matching. Assigned by ACTION_MANAGER. int m_id; + /// Action manager that handles this TOOL_ACTION. + ACTION_MANAGER* m_actionMgr; + /// Origin of the action -// const TOOL_BASE* m_origin; + // const TOOL_BASE* m_origin; /// Originating UI object -// wxWindow* m_uiOrigin; + // wxWindow* m_uiOrigin; }; #endif diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h index 1e4563a7e0..c8861c7ff1 100644 --- a/include/tool/tool_manager.h +++ b/include/tool/tool_manager.h @@ -48,20 +48,10 @@ class wxWindow; class TOOL_MANAGER { public: - static TOOL_MANAGER& Instance() - { - static TOOL_MANAGER manager; - - return manager; - } + TOOL_MANAGER(); ~TOOL_MANAGER(); - /** - * Deletes all the tools that were registered in the TOOL_MANAGER. - */ - void DeleteAll(); - /** * Generates an unique ID from for a tool with given name. */ @@ -251,9 +241,20 @@ public: m_passEvent = true; } -private: - TOOL_MANAGER(); + /** + * Returns list of TOOL_ACTIONs. TOOL_ACTIONs add themselves to the list upon their + * creation. + * @return List of TOOL_ACTIONs. + */ + static std::list& GetActionList() + { + // TODO I am afraid this approach won't work when we reach multitab version of kicad. + static std::list actionList; + return actionList; + } + +private: struct TOOL_STATE; typedef std::pair TRANSITION; diff --git a/include/view/view.h b/include/view/view.h index 694042724f..2930af1844 100644 --- a/include/view/view.h +++ b/include/view/view.h @@ -507,6 +507,8 @@ public: */ void UpdateItems(); + const BOX2I CalculateExtents() ; + static const int VIEW_MAX_LAYERS = 128; ///< maximum number of layers that may be shown private: @@ -534,6 +536,8 @@ private: struct unlinkItem; struct updateItemsColor; struct changeItemsDepth; + struct extentsVisitor; + ///* Redraws contents within rect aRect void redrawRect( const BOX2I& aRect ); diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index b2ce7d9a23..19d66214ac 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -90,7 +90,7 @@ protected: /// main window. wxAuiToolBar* m_auxiliaryToolBar; - TOOL_MANAGER& m_toolManager; + TOOL_MANAGER* m_toolManager; TOOL_DISPATCHER* m_toolDispatcher; void updateGridSelectBox(); diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 0e19dc8e22..b9321922a8 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -248,6 +248,7 @@ public: void OnUpdateZoneDisplayStyle( wxUpdateUIEvent& aEvent ); void OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent ); void OnUpdateSelectAutoTrackWidth( wxUpdateUIEvent& aEvent ); + void OnUpdateSelectCustomTrackWidth( wxUpdateUIEvent& aEvent ); void OnUpdateAutoPlaceModulesMode( wxUpdateUIEvent& aEvent ); void OnUpdateAutoPlaceTracksMode( wxUpdateUIEvent& aEvent ); void OnUpdateMuWaveToolbar( wxUpdateUIEvent& aEvent ); diff --git a/include/wxunittext.h b/include/wxunittext.h new file mode 100644 index 0000000000..54c52e14dc --- /dev/null +++ b/include/wxunittext.h @@ -0,0 +1,144 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 WXUNITTEXT_H_ +#define WXUNITTEXT_H_ + +#include +#include + +namespace boost +{ + template + class optional; +} +class wxTextCtrl; +class wxSpinButton; +class wxStaticText; + +class WX_UNIT_TEXT : public wxPanel +{ +public: + /** + * Constructor. + * @param aParent is the parent window. + * @param aLabel is the label displayed next to the text input control. + * @param aValue is the initial value for the control. + * @param aStep is the step size when using spin buttons. + */ + WX_UNIT_TEXT( wxWindow* aParent, const wxString& aLabel = _( "Size:" ), + double aValue = 0.0, double aStep = 0.1 ); + + virtual ~WX_UNIT_TEXT(); + + /** + * Function SetUnits + * Changes the units used by the control. + * @param aUnits is the new unit to be used. + * @param aConvert decides if the current value should be converted to the value in new units + * or should it stay the same. + */ + void SetUnits( EDA_UNITS_T aUnits, bool aConvert = false ); + + /** + * Function SetValue + * Sets new value for the control. + * @param aValue is the new value. + */ + virtual void SetValue( double aValue ); + + /** + * Function GetValue + * Returns the current value using specified units (if currently used units are different, then + * they are converted first). + * @param aUnits is the wanted unit. + */ + //virtual double GetValue( EDA_UNITS_T aUnits ) const; + + /** + * Function GetValue + * Returns the current value in currently used units. + */ + virtual boost::optional GetValue() const; + + /** + * Function GetUnits + * Returns currently used units. + */ + EDA_UNITS_T GetUnits() const + { + return m_units; + } + + /** + * Function SetStep + * Sets the difference introduced by a single spin button click. + * @param aStep is new step size. + */ + void SetStep( double aStep ) + { + assert( aStep > 0.0 ); + + m_step = aStep; + } + + /** + * Function GetStep + * Returns the difference introduced by a single spin button click. + */ + double GetStep() const + { + return m_step; + } + +protected: + ///> Spin up button click event handler. + void onSpinUpEvent( wxSpinEvent& aEvent ); + + ///> Spin down button click event handler. + void onSpinDownEvent( wxSpinEvent& aEvent ); + + ///> Label for the input (e.g. "Size:") + wxStaticText* m_inputLabel; + + ///> Text input control. + wxTextCtrl* m_inputValue; + + ///> Spin buttons for changing the value using mouse. + wxSpinButton* m_spinButton; + + ///> Label showing currently used units. + wxStaticText* m_unitLabel; + + ///> Currently used units. + EDA_UNITS_T m_units; + + ///> Step size (added/subtracted difference if spin buttons are used). + double m_step; + + ///> Default value (or non-specified) + static const wxString DEFAULT_VALUE; +}; + +#endif /* WXUNITTEXT_H_ */ diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index ae2292bf13..2fc30d1fc7 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -97,6 +97,8 @@ set( PCBNEW_DIALOGS dialogs/dialog_netlist_fbp.cpp dialogs/dialog_pcb_text_properties.cpp dialogs/dialog_pcb_text_properties_base.cpp + dialogs/dialog_pns_settings.cpp + dialogs/dialog_pns_settings_base.cpp dialogs/dialog_non_copper_zones_properties_base.cpp dialogs/dialog_pad_properties.cpp dialogs/dialog_pad_properties_base.cpp @@ -115,6 +117,8 @@ set( PCBNEW_DIALOGS dialogs/dialog_set_grid.cpp dialogs/dialog_set_grid_base.cpp dialogs/dialog_target_properties_base.cpp + dialogs/dialog_track_via_size.cpp + dialogs/dialog_track_via_size_base.cpp footprint_wizard.cpp footprint_wizard_frame.cpp dialogs/dialog_footprint_wizard_list_base.cpp diff --git a/pcbnew/autorouter/routing_matrix.cpp b/pcbnew/autorouter/routing_matrix.cpp index 8449c90bc1..ee1890bf2a 100644 --- a/pcbnew/autorouter/routing_matrix.cpp +++ b/pcbnew/autorouter/routing_matrix.cpp @@ -201,7 +201,7 @@ void PlaceCells( BOARD* aPcb, int net_code, int flag ) LAYER_MSK layerMask; // use the default NETCLASS? - NETCLASS* nc = aPcb->m_NetClasses.GetDefault(); + NETCLASS* nc = aPcb->GetDesignSettings().GetDefault(); int trackWidth = nc->GetTrackWidth(); int clearance = nc->GetClearance(); diff --git a/pcbnew/autorouter/solve.cpp b/pcbnew/autorouter/solve.cpp index 8ddf52f040..0e0120c458 100644 --- a/pcbnew/autorouter/solve.cpp +++ b/pcbnew/autorouter/solve.cpp @@ -280,7 +280,7 @@ int PCB_EDIT_FRAME::Solve( wxDC* DC, int aLayersCount ) m_canvas->SetAbortRequest( false ); - s_Clearance = GetBoard()->m_NetClasses.GetDefault()->GetClearance(); + s_Clearance = GetBoard()->GetDesignSettings().GetDefault()->GetClearance(); // Prepare the undo command info s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but... @@ -428,7 +428,7 @@ static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe, result = NOSUCCESS; - marge = s_Clearance + ( pcbframe->GetBoard()->GetCurrentTrackWidth() / 2 ); + marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 ); /* clear direction flags */ i = RoutingMatrix.m_Nrows * RoutingMatrix.m_Ncols * sizeof(DIR_CELL); @@ -1174,7 +1174,7 @@ static void OrCell_Trace( BOARD* pcb, int col, int row, ( RoutingMatrix.m_GridRouting * col ))); g_CurrentTrackSegment->SetEnd( g_CurrentTrackSegment->GetStart() ); - g_CurrentTrackSegment->SetWidth( pcb->GetCurrentViaSize() ); + g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentViaSize() ); newVia->SetViaType( pcb->GetDesignSettings().m_CurrentViaType ); g_CurrentTrackSegment->SetNetCode( current_net_code ); @@ -1233,7 +1233,7 @@ static void OrCell_Trace( BOARD* pcb, int col, int row, } } - g_CurrentTrackSegment->SetWidth( pcb->GetCurrentTrackWidth() ); + g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentTrackWidth() ); if( g_CurrentTrackSegment->GetStart() != g_CurrentTrackSegment->GetEnd() ) { @@ -1275,8 +1275,8 @@ static void AddNewTrace( PCB_EDIT_FRAME* pcbframe, wxDC* DC ) EDA_DRAW_PANEL* panel = pcbframe->GetCanvas(); PCB_SCREEN* screen = pcbframe->GetScreen(); - marge = s_Clearance + ( pcbframe->GetBoard()->GetCurrentTrackWidth() / 2 ); - via_marge = s_Clearance + ( pcbframe->GetBoard()->GetCurrentViaSize() / 2 ); + marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 ); + via_marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentViaSize() / 2 ); dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x; dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y; diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index 3bbade6770..5577650436 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -133,10 +133,10 @@ END_EVENT_TABLE() PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType, const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, long aStyle, const wxString & aFrameName ) : - EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ), - m_toolManager( TOOL_MANAGER::Instance() ) + EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) { m_Pcb = NULL; + m_toolManager = NULL; m_toolDispatcher = NULL; m_DisplayPadFill = true; // How to draw pads @@ -159,6 +159,9 @@ PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame this, -1, wxPoint( 0, 0 ), m_FrameSize, EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ) ); + // GAL should not be active yet + GetGalCanvas()->StopDrawing(); + // Hide by default, it has to be explicitly shown GetGalCanvas()->Hide(); @@ -832,7 +835,7 @@ void PCB_BASE_FRAME::LoadSettings( wxConfigBase* aCfg ) } // Some more required layers settings - view->SetRequired( ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( VIAS_VISIBLE ) ); + view->SetRequired( ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ) ); view->SetRequired( ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) ); view->SetRequired( NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) ); diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index db51056d02..56b5ca63d2 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -637,7 +637,7 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& aEvent ) // Inform tools that undo command was issued TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager.ProcessEvent( event ); + m_toolManager->ProcessEvent( event ); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); @@ -660,7 +660,7 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& aEvent ) // Inform tools that redo command was issued TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager.ProcessEvent( event ); + m_toolManager->ProcessEvent( event ); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index a7b4e35987..2fc5fa7d3e 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -66,8 +66,7 @@ wxPoint BOARD_ITEM::ZeroOffset( 0, 0 ); BOARD::BOARD() : BOARD_ITEM( (BOARD_ITEM*) NULL, PCB_T ), m_NetInfo( this ), - m_paper( PAGE_INFO::A4 ), - m_NetClasses( this ) + m_paper( PAGE_INFO::A4 ) { // we have not loaded a board yet, assume latest until then. m_fileFormatVersionAtLoad = LEGACY_BOARD_FILE_VERSION; @@ -92,19 +91,18 @@ BOARD::BOARD() : m_Layer[layer].m_Type = LT_UNDEFINED; } - m_NetClasses.GetDefault()->SetDescription( _( "This is the default net class." ) ); + NETCLASS* defaultClass = m_designSettings.GetDefault(); + defaultClass->SetDescription( _( "This is the default net class." ) ); - m_viaSizeIndex = 0; - m_trackWidthIndex = 0; - - /* Dick 5-Feb-2012: this seems unnecessary. I don't believe the comment - near line 70 of class_netclass.cpp. I stepped through with debugger. - Perhaps something else is at work, it is not a constructor race. // Initialize default values in default netclass. - */ - m_NetClasses.GetDefault()->SetParams(); + defaultClass->SetParams( m_designSettings ); + m_designSettings.SetCurrentNetClass( defaultClass->GetName() ); - SetCurrentNetClass( m_NetClasses.GetDefault()->GetName() ); + // Set sensible initial values for custom track width & via size + m_designSettings.UseCustomTrackViaSize( false ); + m_designSettings.SetCustomTrackWidth( m_designSettings.GetCurrentTrackWidth() ); + m_designSettings.SetCustomViaSize( m_designSettings.GetCurrentViaSize() ); + m_designSettings.SetCustomViaDrill( m_designSettings.GetCurrentViaDrill() ); // Initialize ratsnest m_ratsnest = new RN_DATA( this ); @@ -313,100 +311,6 @@ void BOARD::PopHighLight() } -bool BOARD::SetCurrentNetClass( const wxString& aNetClassName ) -{ - NETCLASS* netClass = m_NetClasses.Find( aNetClassName ); - bool lists_sizes_modified = false; - - // if not found (should not happen) use the default - if( netClass == NULL ) - netClass = m_NetClasses.GetDefault(); - - m_currentNetClassName = netClass->GetName(); - - // Initialize others values: - if( m_ViasDimensionsList.size() == 0 ) - { - VIA_DIMENSION viadim; - lists_sizes_modified = true; - m_ViasDimensionsList.push_back( viadim ); - } - - if( m_TrackWidthList.size() == 0 ) - { - lists_sizes_modified = true; - m_TrackWidthList.push_back( 0 ); - } - - /* note the m_ViasDimensionsList[0] and m_TrackWidthList[0] values - * are always the Netclass values - */ - if( m_ViasDimensionsList[0].m_Diameter != netClass->GetViaDiameter() ) - lists_sizes_modified = true; - - m_ViasDimensionsList[0].m_Diameter = netClass->GetViaDiameter(); - - if( m_TrackWidthList[0] != netClass->GetTrackWidth() ) - lists_sizes_modified = true; - - m_TrackWidthList[0] = netClass->GetTrackWidth(); - - if( m_viaSizeIndex >= m_ViasDimensionsList.size() ) - m_viaSizeIndex = m_ViasDimensionsList.size(); - - if( m_trackWidthIndex >= m_TrackWidthList.size() ) - m_trackWidthIndex = m_TrackWidthList.size(); - - return lists_sizes_modified; -} - - -int BOARD::GetBiggestClearanceValue() -{ - int clearance = m_NetClasses.GetDefault()->GetClearance(); - - //Read list of Net Classes - for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); nc++ ) - { - NETCLASS* netclass = nc->second; - clearance = std::max( clearance, netclass->GetClearance() ); - } - - return clearance; -} - - -int BOARD::GetSmallestClearanceValue() -{ - int clearance = m_NetClasses.GetDefault()->GetClearance(); - - //Read list of Net Classes - for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); nc++ ) - { - NETCLASS* netclass = nc->second; - clearance = std::min( clearance, netclass->GetClearance() ); - } - - return clearance; -} - - -int BOARD::GetCurrentMicroViaSize() -{ - NETCLASS* netclass = m_NetClasses.Find( m_currentNetClassName ); - - return netclass->GetuViaDiameter(); -} - - -int BOARD::GetCurrentMicroViaDrill() -{ - NETCLASS* netclass = m_NetClasses.Find( m_currentNetClassName ); - - return netclass->GetuViaDrill(); -} - - bool BOARD::SetLayer( LAYER_NUM aIndex, const LAYER& aLayer ) { if( aIndex < NB_COPPER_LAYERS ) @@ -2194,24 +2098,6 @@ TRACK* BOARD::CreateLockPoint( wxPoint& aPosition, TRACK* aSegment, PICKED_ITEMS } -void BOARD::SetViaSizeIndex( unsigned aIndex ) -{ - if( aIndex >= m_ViasDimensionsList.size() ) - m_viaSizeIndex = m_ViasDimensionsList.size(); - else - m_viaSizeIndex = aIndex; -} - - -void BOARD::SetTrackWidthIndex( unsigned aIndex ) -{ - if( aIndex >= m_TrackWidthList.size() ) - m_trackWidthIndex = m_TrackWidthList.size(); - else - m_trackWidthIndex = aIndex; -} - - ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, LAYER_NUM aLayer, wxPoint aStartPointPosition, int aHatch ) { diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 308f69a13d..41777b60c8 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -111,8 +111,6 @@ public: /** The type of the layer */ LAYER_T m_Type; -// int m_Color; - /** * Function ShowType * converts a LAYER_T enum to a const char* @@ -136,52 +134,15 @@ private: }; -/** - * Struct VIA_DIMENSION - * is a small helper container to handle a stock of specific vias each with - * unique diameter and drill sizes in the BOARD class. - */ -struct VIA_DIMENSION -{ - int m_Diameter; // <= 0 means use Netclass via diameter - int m_Drill; // <= 0 means use Netclass via drill - - VIA_DIMENSION() - { - m_Diameter = 0; - m_Drill = 0; - } - - VIA_DIMENSION( int aDiameter, int aDrill ) - { - m_Diameter = aDiameter; - m_Drill = aDrill; - } - - bool operator == ( const VIA_DIMENSION& other ) const - { - return (m_Diameter == other.m_Diameter) && (m_Drill == other.m_Drill); - } - - bool operator < ( const VIA_DIMENSION& other ) const - { - if( m_Diameter != other.m_Diameter ) - return m_Diameter < other.m_Diameter; - - return m_Drill < other.m_Drill; - } -}; - - // Helper class to handle high light nets class HIGH_LIGHT_INFO { friend class BOARD; + protected: int m_netCode; // net selected for highlight (-1 when no net selected ) bool m_highLightOn; // highlight active -protected: void Clear() { m_netCode = -1; @@ -247,17 +208,6 @@ private: /// Number of unconnected nets in the current rats nest. int m_unconnectedNetCount; - /// Current net class name used to display netclass info. - /// This is also the last used netclass after starting a track. - wxString m_currentNetClassName; - - /// Index for #m_ViasDimensionsList to select the current via size. - /// 0 is the index selection of the default value Netclass - unsigned m_viaSizeIndex; - - // Index for m_TrackWidthList to select the value. - unsigned m_trackWidthIndex; - /** * Function chainMarkedSegments * is used by MarkTrace() to set the BUSY flag of connected segments of the trace @@ -269,10 +219,6 @@ private: */ void chainMarkedSegments( wxPoint aPosition, LAYER_MSK aLayerMask, TRACK_PTRS* aList ); - void formatNetClass( NETCLASS* aNetClass, OUTPUTFORMATTER* aFormatter, int aNestLevel, - int aControlBits ) const - throw( IO_ERROR ); - public: void SetFileName( const wxString& aFileName ) { m_fileName = aFileName; } @@ -296,22 +242,6 @@ public: /// zone contour currently in progress ZONE_CONTAINER* m_CurrentZoneContour; - /// List of current netclasses. There is always the default netclass. - NETCLASSES m_NetClasses; - - // handling of vias and tracks size: - // the first value is always the value of the current NetClass - // The others values are extra values - - // The first value is the current netclass via size // TODO verify - /// Vias size and drill list - std::vector m_ViasDimensionsList; - - // The first value is the current netclass track width // TODO verify - /// Track width list - std::vector m_TrackWidthList; - - BOARD(); ~BOARD(); @@ -639,7 +569,10 @@ public: * Function SetDesignSettings * @param aDesignSettings the new BOARD_DESIGN_SETTINGS to use */ - void SetDesignSettings( const BOARD_DESIGN_SETTINGS& aDesignSettings ) { m_designSettings = aDesignSettings; } + void SetDesignSettings( const BOARD_DESIGN_SETTINGS& aDesignSettings ) + { + m_designSettings = aDesignSettings; + } const PAGE_INFO& GetPageSettings() const { return m_paper; } void SetPageSettings( const PAGE_INFO& aPageSettings ) { m_paper = aPageSettings; } @@ -685,6 +618,19 @@ public: CPOLYGONS_LIST& aHoles, wxString* aErrorText = NULL ); + /** + * Function ConvertBrdLayerToPolygonalContours + * Build a set of polygons which are the outlines of copper items + * (pads, tracks, vias, texts, zones) + * Holes in vias or pads are ignored + * Usefull to export the shape of copper layers to dxf polygons + * or 3D viewer + * the polygons are not merged. + * @param aLayer = A copper layer, like LAYER_N_BACK, etc. + * @param aOutlines The CPOLYGONS_LIST to fill in with items outline. + */ + void ConvertBrdLayerToPolygonalContours( LAYER_NUM aLayer, CPOLYGONS_LIST& aOutlines ); + /** * Function GetLayerName * returns the name of a layer given by aLayer. Copper layers may @@ -770,7 +716,6 @@ public: return m_FullRatsnest.size(); } - /** * Function GetNodesCount * @return the number of pads members of nets (i.e. with netcode > 0) @@ -799,20 +744,6 @@ public: */ void SetUnconnectedNetCount( unsigned aCount ) { m_unconnectedNetCount = aCount; } - /** - * Function SetCurrentNetClassName - * sets the current net class name to \a aName. - * - * @param aName is a reference to a wxString object containing the current net class name. - */ - void SetCurrentNetClassName( const wxString& aName ) { m_currentNetClassName = aName; } - - /** - * Function GetCurrentNetClassName - * @return the current net class name. - */ - const wxString& GetCurrentNetClassName() const { return m_currentNetClassName; } - /** * Function GetPadCount * @return the number of pads in board @@ -1021,11 +952,6 @@ public: */ int SortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount ); - /**************************************/ - /** - * Function relative to NetClasses: **/ - /**************************************/ - /** * Function SynchronizeNetsAndNetClasses * copies NETCLASS info to each NET, based on NET membership in a NETCLASS. @@ -1035,104 +961,6 @@ public: */ void SynchronizeNetsAndNetClasses(); - /** - * Function SetCurrentNetClass - * Must be called after a netclass selection (or after a netclass parameter change - * Initialize vias and tracks values displayed in comb boxes of the auxiliary toolbar - * and some others parameters (netclass name ....) - * @param aNetClassName = the new netclass name - * @return true if lists of tracks and vias sizes are modified - */ - bool SetCurrentNetClass( const wxString& aNetClassName ); - - /** - * Function GetBiggestClearanceValue - * @return the biggest clearance value found in NetClasses list - */ - int GetBiggestClearanceValue(); - - /** - * Function GetSmallestClearanceValue - * @return the smallest clearance value found in NetClasses list - */ - int GetSmallestClearanceValue(); - - /** - * Function GetTrackWidthIndex - * @return the current track width list index. - */ - unsigned GetTrackWidthIndex() const { return m_trackWidthIndex; } - - /** - * Function SetTrackWidthIndex - * sets the current track width list index to \a aIndex. - * - * @param aIndex is the track width list index. - */ - void SetTrackWidthIndex( unsigned aIndex ); - - /** - * Function GetCurrentTrackWidth - * @return the current track width, according to the selected options - * ( using the default netclass value or a preset value ) - * the default netclass is always in m_TrackWidthList[0] - */ - int GetCurrentTrackWidth() const - { - return m_TrackWidthList[m_trackWidthIndex]; - } - - /** - * Function GetViaSizeIndex - * @return the current via size list index. - */ - unsigned GetViaSizeIndex() const { return m_viaSizeIndex; } - - /** - * Function SetViaSizeIndex - * sets the current via size list index to \a aIndex. - * - * @param aIndex is the via size list index. - */ - void SetViaSizeIndex( unsigned aIndex ); - - /** - * Function GetCurrentViaSize - * @return the current via size, according to the selected options - * ( using the default netclass value or a preset value ) - * the default netclass is always in m_TrackWidthList[0] - */ - int GetCurrentViaSize() - { - return m_ViasDimensionsList[m_viaSizeIndex].m_Diameter; - } - - /** - * Function GetCurrentViaDrill - * @return the current via size, according to the selected options - * ( using the default netclass value or a preset value ) - * the default netclass is always in m_TrackWidthList[0] - */ - int GetCurrentViaDrill() - { - return m_ViasDimensionsList[m_viaSizeIndex].m_Drill > 0 ? - m_ViasDimensionsList[m_viaSizeIndex].m_Drill : -1; - } - - /** - * Function GetCurrentMicroViaSize - * @return the current micro via size, - * that is the current netclass value - */ - int GetCurrentMicroViaSize(); - - /** - * Function GetCurrentMicroViaDrill - * @return the current micro via drill, - * that is the current netclass value - */ - int GetCurrentMicroViaDrill(); - /***************************************************************************/ wxString GetClass() const diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp index 0248131d35..0b91036802 100644 --- a/pcbnew/class_board_connected_item.cpp +++ b/pcbnew/class_board_connected_item.cpp @@ -144,7 +144,7 @@ NETCLASS* BOARD_CONNECTED_ITEM::GetNetClass() const if( netclass ) return netclass; else - return board->m_NetClasses.GetDefault(); + return board->GetDesignSettings().GetDefault(); } @@ -158,7 +158,7 @@ wxString BOARD_CONNECTED_ITEM::GetNetClassName() const else { BOARD* board = GetBoard(); - name = board->m_NetClasses.GetDefault()->GetName(); + name = NETCLASS::Default; } return name; diff --git a/pcbnew/class_board_design_settings.cpp b/pcbnew/class_board_design_settings.cpp index 31ef22a23f..aac977d827 100644 --- a/pcbnew/class_board_design_settings.cpp +++ b/pcbnew/class_board_design_settings.cpp @@ -54,13 +54,13 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : m_Pad_Master( NULL ) { - m_EnabledLayers = ALL_LAYERS; // All layers enabled at first. + m_enabledLayers = ALL_LAYERS; // All layers enabled at first. // SetCopperLayerCount() will adjust this. SetVisibleLayers( FULL_LAYERS ); // set all but hidden text as visible. - m_VisibleElements = ~( 1 << MOD_TEXT_INVISIBLE ); + m_visibleElements = ~( 1 << MOD_TEXT_INVISIBLE ); SetCopperLayerCount( 2 ); // Default design is a double sided board @@ -81,7 +81,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : m_PcbTextSize = wxSize( DEFAULT_TEXT_PCB_SIZE, DEFAULT_TEXT_PCB_SIZE ); // current Pcb (not module) Text size - m_TrackMinWidth = DMils2iu( 100 ); // track min value for width ((min copper size value + m_TrackMinWidth = DMils2iu( 100 ); // track min value for width (min copper size value) m_ViasMinSize = DMils2iu( 350 ); // vias (not micro vias) min diameter m_ViasMinDrill = DMils2iu( 200 ); // vias (not micro vias) min drill diameter m_MicroViasMinSize = DMils2iu( 200 ); // micro vias (not vias) min diameter @@ -102,6 +102,9 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : // Layer thickness for 3D viewer m_boardThickness = Millimeter2iu( DEFAULT_BOARD_THICKNESS_MM ); + + m_viaSizeIndex = 0; + m_trackWidthIndex = 0; } // Add parameters to save in project config. @@ -171,32 +174,144 @@ void BOARD_DESIGN_SETTINGS::AppendConfigs( PARAM_CFG_ARRAY* aResult ) } -// see pcbstruct.h -LAYER_MSK BOARD_DESIGN_SETTINGS::GetVisibleLayers() const +bool BOARD_DESIGN_SETTINGS::SetCurrentNetClass( const wxString& aNetClassName ) { - return m_VisibleLayers; + NETCLASS* netClass = m_NetClasses.Find( aNetClassName ); + bool lists_sizes_modified = false; + + // if not found (should not happen) use the default + if( netClass == NULL ) + netClass = m_NetClasses.GetDefault(); + + m_currentNetClassName = netClass->GetName(); + + // Initialize others values: + if( m_ViasDimensionsList.size() == 0 ) + { + VIA_DIMENSION viadim; + lists_sizes_modified = true; + m_ViasDimensionsList.push_back( viadim ); + } + + if( m_TrackWidthList.size() == 0 ) + { + lists_sizes_modified = true; + m_TrackWidthList.push_back( 0 ); + } + + /* note the m_ViasDimensionsList[0] and m_TrackWidthList[0] values + * are always the Netclass values + */ + if( m_ViasDimensionsList[0].m_Diameter != netClass->GetViaDiameter() ) + lists_sizes_modified = true; + + m_ViasDimensionsList[0].m_Diameter = netClass->GetViaDiameter(); + + if( m_TrackWidthList[0] != netClass->GetTrackWidth() ) + lists_sizes_modified = true; + + m_TrackWidthList[0] = netClass->GetTrackWidth(); + + if( GetViaSizeIndex() >= m_ViasDimensionsList.size() ) + SetViaSizeIndex( m_ViasDimensionsList.size() ); + + if( GetTrackWidthIndex() >= m_TrackWidthList.size() ) + SetTrackWidthIndex( m_TrackWidthList.size() ); + + return lists_sizes_modified; +} + + +int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() +{ + int clearance = m_NetClasses.GetDefault()->GetClearance(); + + //Read list of Net Classes + for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); nc++ ) + { + NETCLASS* netclass = nc->second; + clearance = std::max( clearance, netclass->GetClearance() ); + } + + return clearance; +} + + +int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue() +{ + int clearance = m_NetClasses.GetDefault()->GetClearance(); + + //Read list of Net Classes + for( NETCLASSES::const_iterator nc = m_NetClasses.begin(); nc != m_NetClasses.end(); nc++ ) + { + NETCLASS* netclass = nc->second; + clearance = std::min( clearance, netclass->GetClearance() ); + } + + return clearance; +} + + +int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaSize() +{ + NETCLASS* netclass = m_NetClasses.Find( m_currentNetClassName ); + + return netclass->GetuViaDiameter(); +} + + +int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaDrill() +{ + NETCLASS* netclass = m_NetClasses.Find( m_currentNetClassName ); + + return netclass->GetuViaDrill(); +} + + +void BOARD_DESIGN_SETTINGS::SetViaSizeIndex( unsigned aIndex ) +{ + if( aIndex >= m_ViasDimensionsList.size() ) + m_viaSizeIndex = m_ViasDimensionsList.size(); + else + m_viaSizeIndex = aIndex; +} + + +int BOARD_DESIGN_SETTINGS::GetCurrentViaDrill() const +{ + int drill; + + if( m_useCustomTrackVia ) + drill = m_customViaSize.m_Drill; + else + drill = m_ViasDimensionsList[m_viaSizeIndex].m_Drill; + + return drill > 0 ? drill : -1; +} + + +void BOARD_DESIGN_SETTINGS::SetTrackWidthIndex( unsigned aIndex ) +{ + if( aIndex >= m_TrackWidthList.size() ) + m_trackWidthIndex = m_TrackWidthList.size(); + else + m_trackWidthIndex = aIndex; } void BOARD_DESIGN_SETTINGS::SetVisibleAlls() { SetVisibleLayers( FULL_LAYERS ); - m_VisibleElements = -1; -} - - -void BOARD_DESIGN_SETTINGS::SetVisibleLayers( LAYER_MSK aMask ) -{ - m_VisibleLayers = aMask & m_EnabledLayers & FULL_LAYERS; + m_visibleElements = -1; } void BOARD_DESIGN_SETTINGS::SetLayerVisibility( LAYER_NUM aLayer, bool aNewState ) { if( aNewState && IsLayerEnabled( aLayer ) ) - m_VisibleLayers |= GetLayerMask( aLayer ); + m_visibleLayers |= GetLayerMask( aLayer ); else - m_VisibleLayers &= ~GetLayerMask( aLayer ); + m_visibleLayers &= ~GetLayerMask( aLayer ); } @@ -206,9 +321,9 @@ void BOARD_DESIGN_SETTINGS::SetElementVisibility( int aElementCategory, bool aNe return; if( aNewState ) - m_VisibleElements |= 1 << aElementCategory; + m_visibleElements |= 1 << aElementCategory; else - m_VisibleElements &= ~( 1 << aElementCategory ); + m_visibleElements &= ~( 1 << aElementCategory ); } @@ -216,17 +331,17 @@ void BOARD_DESIGN_SETTINGS::SetCopperLayerCount( int aNewLayerCount ) { // if( aNewLayerCount < 2 ) aNewLayerCount = 2; - m_CopperLayerCount = aNewLayerCount; + m_copperLayerCount = aNewLayerCount; // ensure consistency with the m_EnabledLayers member - m_EnabledLayers &= ~ALL_CU_LAYERS; - m_EnabledLayers |= LAYER_BACK; + m_enabledLayers &= ~ALL_CU_LAYERS; + m_enabledLayers |= LAYER_BACK; - if( m_CopperLayerCount > 1 ) - m_EnabledLayers |= LAYER_FRONT; + if( m_copperLayerCount > 1 ) + m_enabledLayers |= LAYER_FRONT; for( LAYER_NUM ii = LAYER_N_2; ii < aNewLayerCount - 1; ++ii ) - m_EnabledLayers |= GetLayerMask( ii ); + m_enabledLayers |= GetLayerMask( ii ); } @@ -235,13 +350,13 @@ void BOARD_DESIGN_SETTINGS::SetEnabledLayers( LAYER_MSK aMask ) // Back and front layers are always enabled. aMask |= LAYER_BACK | LAYER_FRONT; - m_EnabledLayers = aMask; + m_enabledLayers = aMask; // A disabled layer cannot be visible - m_VisibleLayers &= aMask; + m_visibleLayers &= aMask; // update m_CopperLayerCount to ensure its consistency with m_EnabledLayers - m_CopperLayerCount = LayerMaskCountSet( aMask & ALL_CU_LAYERS); + m_copperLayerCount = LayerMaskCountSet( aMask & ALL_CU_LAYERS); } diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index bc55907cb3..5673c06f2d 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -447,7 +447,7 @@ const EDA_RECT MODULE::GetBoundingBox() const // Add the Clearance shape size: (shape around the pads when the // clearance is shown. Not optimized, but the draw cost is small // (perhaps smaller than optimization). - int biggest_clearance = GetBoard()->GetBiggestClearanceValue(); + int biggest_clearance = GetBoard()->GetDesignSettings().GetBiggestClearanceValue(); area.Inflate( biggest_clearance ); return area; diff --git a/pcbnew/class_netclass.cpp b/pcbnew/class_netclass.cpp index 73729324ef..daa72ff32b 100644 --- a/pcbnew/class_netclass.cpp +++ b/pcbnew/class_netclass.cpp @@ -39,59 +39,43 @@ const wxChar NETCLASS::Default[] = wxT( "Default" ); // Initial values for netclass initialization -int NETCLASS::DEFAULT_CLEARANCE = DMils2iu( 100 ); // track to track and track to pads clearance -int NETCLASS::DEFAULT_VIA_DRILL = DMils2iu( 250 ); // default via drill -int NETCLASS::DEFAULT_UVIA_DRILL = DMils2iu( 50 ); // micro via drill +const int NETCLASS::DEFAULT_CLEARANCE = DMils2iu( 100 ); // track to track and track to pads clearance +const int NETCLASS::DEFAULT_VIA_DRILL = DMils2iu( 250 ); // default via drill +const int NETCLASS::DEFAULT_UVIA_DRILL = DMils2iu( 50 ); // micro via drill -NETCLASS::NETCLASS( BOARD* aParent, const wxString& aName, const NETCLASS* initialParameters ) : - m_Parent( aParent ), +NETCLASS::NETCLASS( const wxString& aName ) : m_Name( aName ) { - // use initialParameters if not NULL, else set the initial - // parameters from boardDesignSettings (try to change this) - SetParams( initialParameters ); + // Default settings + SetClearance( DEFAULT_CLEARANCE ); + SetViaDrill( DEFAULT_VIA_DRILL ); + SetuViaDrill( DEFAULT_UVIA_DRILL ); } -void NETCLASS::SetParams( const NETCLASS* defaults ) +void NETCLASS::SetParams( const NETCLASS& aDefaults ) { - if( defaults ) - { - SetClearance( defaults->GetClearance() ); - SetTrackWidth( defaults->GetTrackWidth() ); - SetViaDiameter( defaults->GetViaDiameter() ); - SetViaDrill( defaults->GetViaDrill() ); - SetuViaDiameter( defaults->GetuViaDiameter() ); - SetuViaDrill( defaults->GetuViaDrill() ); - } - else - { + SetClearance( aDefaults.GetClearance() ); + SetTrackWidth( aDefaults.GetTrackWidth() ); + SetViaDiameter( aDefaults.GetViaDiameter() ); + SetViaDrill( aDefaults.GetViaDrill() ); + SetuViaDiameter( aDefaults.GetuViaDiameter() ); + SetuViaDrill( aDefaults.GetuViaDrill() ); +} -/* Dick 5-Feb-2012: I do not believe this comment to be true with current code. - It is certainly not a constructor race. Normally items are initialized - within a class according to the order of their appearance. - // Note: - // We use m_Parent->GetDesignSettings() to get some default values - // But when this function is called when instantiating a BOARD class, - // by the NETCLASSES constructor that calls NETCLASS constructor, - // the BOARD constructor (see BOARD::BOARD) is not yet run, - // and BOARD::m_designSettings contains not yet initialized values. - // So inside the BOARD constructor itself, you SHOULD recall SetParams -*/ +void NETCLASS::SetParams( const BOARD_DESIGN_SETTINGS& aSettings ) +{ + SetTrackWidth( aSettings.m_TrackMinWidth ); + SetViaDiameter( aSettings.m_ViasMinSize ); + SetuViaDiameter( aSettings.m_MicroViasMinSize ); - const BOARD_DESIGN_SETTINGS& g = m_Parent->GetDesignSettings(); - - SetTrackWidth( g.m_TrackMinWidth ); - SetViaDiameter( g.m_ViasMinSize ); - SetuViaDiameter( g.m_MicroViasMinSize ); - - // Use default values for next parameters: - SetClearance( DEFAULT_CLEARANCE ); - SetViaDrill( DEFAULT_VIA_DRILL ); - SetuViaDrill( DEFAULT_UVIA_DRILL ); - } + // TODO: BOARD_DESIGN_SETTINGS may provide the following parameters - should it? + // Use default values for next parameters: + SetClearance( DEFAULT_CLEARANCE ); + SetViaDrill( DEFAULT_VIA_DRILL ); + SetuViaDrill( DEFAULT_UVIA_DRILL ); } @@ -100,9 +84,8 @@ NETCLASS::~NETCLASS() } -NETCLASSES::NETCLASSES( BOARD* aParent ) : - m_Parent( aParent ), - m_Default( aParent, NETCLASS::Default ) +NETCLASSES::NETCLASSES() : + m_Default( NETCLASS::Default ) { } @@ -198,7 +181,7 @@ NETCLASS* NETCLASSES::Find( const wxString& aName ) const void BOARD::SynchronizeNetsAndNetClasses() { - // D(printf("start\n");) // simple performance/timing indicator. + NETCLASSES& netClasses = m_designSettings.m_NetClasses; // set all NETs to the default NETCLASS, then later override some // as we go through the NETCLASSes. @@ -206,19 +189,19 @@ void BOARD::SynchronizeNetsAndNetClasses() for( NETINFO_LIST::iterator net( m_NetInfo.begin() ), netEnd( m_NetInfo.end() ); net != netEnd; ++net ) { - net->SetClass( m_NetClasses.GetDefault() ); + net->SetClass( netClasses.GetDefault() ); } // Add netclass name and pointer to nets. If a net is in more than one netclass, // set the net's name and pointer to only the first netclass. Subsequent // and therefore bogus netclass memberships will be deleted in logic below this loop. - for( NETCLASSES::iterator clazz=m_NetClasses.begin(); clazz!=m_NetClasses.end(); ++clazz ) + for( NETCLASSES::iterator clazz = netClasses.begin(); clazz != netClasses.end(); ++clazz ) { NETCLASS* netclass = clazz->second; - for( NETCLASS::iterator member = netclass->begin(); member!=netclass->end(); ++member ) + for( NETCLASS::iterator member = netclass->begin(); member != netclass->end(); ++member ) { - const wxString& netname = *member; + const wxString& netname = *member; // although this overall function seems to be adequately fast, // FindNet( wxString ) uses now a fast binary search and is fast @@ -237,14 +220,14 @@ void BOARD::SynchronizeNetsAndNetClasses() // contain netnames that do not exist, by deleting all netnames from // every netclass and re-adding them. - for( NETCLASSES::iterator clazz=m_NetClasses.begin(); clazz!=m_NetClasses.end(); ++clazz ) + for( NETCLASSES::iterator clazz = netClasses.begin(); clazz != netClasses.end(); ++clazz ) { NETCLASS* netclass = clazz->second; netclass->Clear(); } - m_NetClasses.GetDefault()->Clear(); + netClasses.GetDefault()->Clear(); for( NETINFO_LIST::iterator net( m_NetInfo.begin() ), netEnd( m_NetInfo.end() ); net != netEnd; ++net ) @@ -253,14 +236,12 @@ void BOARD::SynchronizeNetsAndNetClasses() // because of the std:map<> this should be fast, and because of // prior logic, netclass should not be NULL. - NETCLASS* netclass = m_NetClasses.Find( classname ); + NETCLASS* netclass = netClasses.Find( classname ); wxASSERT( netclass ); netclass->Add( net->GetNetname() ); } - - // D(printf("stop\n");) } @@ -286,36 +267,6 @@ void NETCLASS::Show( int nestLevel, std::ostream& os ) const #endif -int NETCLASS::GetTrackMinWidth() const -{ - return m_Parent->GetDesignSettings().m_TrackMinWidth; -} - - -int NETCLASS::GetViaMinDiameter() const -{ - return m_Parent->GetDesignSettings().m_ViasMinSize; -} - - -int NETCLASS::GetViaMinDrill() const -{ - return m_Parent->GetDesignSettings().m_ViasMinDrill; -} - - -int NETCLASS::GetuViaMinDiameter() const -{ - return m_Parent->GetDesignSettings().m_MicroViasMinSize; -} - - -int NETCLASS::GetuViaMinDrill() const -{ - return m_Parent->GetDesignSettings().m_MicroViasMinDrill; -} - - void NETCLASS::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const throw( IO_ERROR ) { @@ -333,14 +284,7 @@ void NETCLASS::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl aFormatter->Print( aNestLevel+1, "(uvia_drill %s)\n", FMT_IU( GetuViaDrill() ).c_str() ); for( NETCLASS::const_iterator it = begin(); it != end(); ++it ) - { - NETINFO_ITEM* netinfo = m_Parent->FindNet( *it ); - - if( netinfo && netinfo->GetNodesCount() > 0 ) - { - aFormatter->Print( aNestLevel+1, "(add_net %s)\n", aFormatter->Quotew( *it ).c_str() ); - } - } + aFormatter->Print( aNestLevel+1, "(add_net %s)\n", aFormatter->Quotew( *it ).c_str() ); aFormatter->Print( aNestLevel, ")\n\n" ); } diff --git a/pcbnew/class_netclass.h b/pcbnew/class_netclass.h index d5e0005357..0d79013df8 100644 --- a/pcbnew/class_netclass.h +++ b/pcbnew/class_netclass.h @@ -41,6 +41,7 @@ class LINE_READER; class BOARD; +class BOARD_DESIGN_SETTINGS; /** @@ -53,17 +54,15 @@ class NETCLASS { private: // Default values used to init a NETCLASS - static int DEFAULT_CLEARANCE; - static int DEFAULT_VIA_DRILL; - static int DEFAULT_UVIA_DRILL; + static const int DEFAULT_CLEARANCE; + static const int DEFAULT_VIA_DRILL; + static const int DEFAULT_UVIA_DRILL; protected: - - BOARD* m_Parent; wxString m_Name; ///< Name of the net class wxString m_Description; ///< what this NETCLASS is for. - typedef std::set STRINGSET; + typedef std::set STRINGSET; STRINGSET m_Members; ///< names of NET members of this class @@ -85,12 +84,9 @@ public: /** * Constructor * stuffs a NETCLASS instance with aParent, aName, and optionally the initialParameters - * @param aParent = the parent board * @param aName = the name of this new netclass - * @param initialParameters is a NETCLASS to copy parameters from, or if - * NULL tells me to copy default settings from BOARD::m_designSettings. */ - NETCLASS( BOARD* aParent, const wxString& aName, const NETCLASS* initialParameters = NULL ); + NETCLASS( const wxString& aName ); ~NETCLASS(); @@ -115,7 +111,6 @@ public: return m_Members.size(); } - /** * Function Clear * empties the collection of members. @@ -125,7 +120,6 @@ public: m_Members.clear(); } - /** * Function AddMember * adds \a aNetname to this NETCLASS if it is not already in this NETCLASS. @@ -169,34 +163,35 @@ public: void SetClearance( int aClearance ) { m_Clearance = aClearance; } int GetTrackWidth() const { return m_TrackWidth; } - int GetTrackMinWidth() const; void SetTrackWidth( int aWidth ) { m_TrackWidth = aWidth; } int GetViaDiameter() const { return m_ViaDia; } - int GetViaMinDiameter() const; void SetViaDiameter( int aDia ) { m_ViaDia = aDia; } int GetViaDrill() const { return m_ViaDrill; } - int GetViaMinDrill() const; void SetViaDrill( int aSize ) { m_ViaDrill = aSize; } int GetuViaDiameter() const { return m_uViaDia; } - int GetuViaMinDiameter() const; void SetuViaDiameter( int aSize ) { m_uViaDia = aSize; } int GetuViaDrill() const { return m_uViaDrill; } - int GetuViaMinDrill() const; void SetuViaDrill( int aSize ) { m_uViaDrill = aSize; } - /** * Function SetParams * will set all the parameters by copying them from \a defaults. * Parameters are the values like m_ViaSize, etc, but do not include m_Description. - * @param defaults is another NETCLASS to copy from. If NULL, then copy - * from global preferences instead. + * @param aDefaults is another NETCLASS object to copy from. */ - void SetParams( const NETCLASS* defaults = NULL ); + void SetParams( const NETCLASS& aDefaults ); + + /** + * Function SetParams + * will set all the parameters by copying them from board design settings. + * @param aSettings is a BOARD_DESIGN_SETTINGS object to copy from. Clearance, via drill and + * microvia drill values are taken from the defaults. + */ + void SetParams( const BOARD_DESIGN_SETTINGS& aSettings ); /** * Function Format @@ -225,9 +220,7 @@ public: class NETCLASSES { private: - BOARD* m_Parent; - - typedef std::map NETCLASSMAP; + typedef std::map NETCLASSMAP; /// all the NETCLASSes except the default one. NETCLASSMAP m_NetClasses; @@ -236,7 +229,7 @@ private: NETCLASS m_Default; public: - NETCLASSES( BOARD* aParent = NULL ); + NETCLASSES(); ~NETCLASSES(); /** @@ -245,7 +238,7 @@ public: */ void Clear(); - typedef NETCLASSMAP::iterator iterator; + typedef NETCLASSMAP::iterator iterator; iterator begin() { return m_NetClasses.begin(); } iterator end() { return m_NetClasses.end(); } @@ -253,7 +246,6 @@ public: const_iterator begin() const { return m_NetClasses.begin(); } const_iterator end() const { return m_NetClasses.end(); } - /** * Function GetCount * @return the number of netclasses, excluding the default one. @@ -263,6 +255,10 @@ public: return m_NetClasses.size(); } + /** + * Function GetDefault + * @return the default net class. + */ NETCLASS* GetDefault() const { return (NETCLASS*) &m_Default; diff --git a/pcbnew/dialogs/dialog_design_rules.cpp b/pcbnew/dialogs/dialog_design_rules.cpp index f83be84b9e..13f6da13c9 100644 --- a/pcbnew/dialogs/dialog_design_rules.cpp +++ b/pcbnew/dialogs/dialog_design_rules.cpp @@ -190,15 +190,15 @@ void DIALOG_DESIGN_RULES::PrintCurrentSettings() m_MessagesList->AppendToPage( _( "Current general settings:
" ) ); // Display min values: - value = StringFromValue( g_UserUnit, m_BrdSettings.m_TrackMinWidth, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings->m_TrackMinWidth, true ); msg.Printf( _( "Minimum value for tracks width: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); - value = StringFromValue( g_UserUnit, m_BrdSettings.m_ViasMinSize, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings->m_ViasMinSize, true ); msg.Printf( _( "Minimum value for vias diameter: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); - value = StringFromValue( g_UserUnit, m_BrdSettings.m_MicroViasMinSize, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings->m_MicroViasMinSize, true ); msg.Printf( _( "Minimum value for microvias diameter: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); } @@ -212,7 +212,7 @@ void DIALOG_DESIGN_RULES::InitDialogRules() SetReturnCode( 0 ); m_Pcb = m_Parent->GetBoard(); - m_BrdSettings = m_Pcb->GetDesignSettings(); + m_BrdSettings = &m_Pcb->GetDesignSettings(); // Initialize the Rules List InitRulesList(); @@ -220,13 +220,8 @@ void DIALOG_DESIGN_RULES::InitDialogRules() // copy all NETs into m_AllNets by adding them as NETCUPs. // @todo go fix m_Pcb->SynchronizeNetsAndNetClasses() so that the netcode==0 is not present in the BOARD::m_NetClasses - - - NETCLASS* netclass; - - NETCLASSES& netclasses = m_Pcb->m_NetClasses; - - netclass = netclasses.GetDefault(); + NETCLASSES& netclasses = m_BrdSettings->m_NetClasses; + NETCLASS* netclass = netclasses.GetDefault(); // Initialize list of nets for Default Net Class for( NETCLASS::const_iterator name = netclass->begin(); name != netclass->end(); ++name ) @@ -262,23 +257,23 @@ void DIALOG_DESIGN_RULES::InitGlobalRules() AddUnitSymbol( *m_MicroViaMinDrillTitle ); AddUnitSymbol( *m_TrackMinWidthTitle ); - PutValueInLocalUnits( *m_SetViasMinSizeCtrl, m_BrdSettings.m_ViasMinSize ); - PutValueInLocalUnits( *m_SetViasMinDrillCtrl, m_BrdSettings.m_ViasMinDrill ); + PutValueInLocalUnits( *m_SetViasMinSizeCtrl, m_BrdSettings->m_ViasMinSize ); + PutValueInLocalUnits( *m_SetViasMinDrillCtrl, m_BrdSettings->m_ViasMinDrill ); - if( m_BrdSettings.m_BlindBuriedViaAllowed ) + if( m_BrdSettings->m_BlindBuriedViaAllowed ) m_OptViaType->SetSelection( 1 ); - m_AllowMicroViaCtrl->SetSelection( m_BrdSettings.m_MicroViasAllowed ? 1 : 0 ); - PutValueInLocalUnits( *m_SetMicroViasMinSizeCtrl, m_BrdSettings.m_MicroViasMinSize ); - PutValueInLocalUnits( *m_SetMicroViasMinDrillCtrl, m_BrdSettings.m_MicroViasMinDrill ); - PutValueInLocalUnits( *m_SetTrackMinWidthCtrl, m_BrdSettings.m_TrackMinWidth ); + m_AllowMicroViaCtrl->SetSelection( m_BrdSettings->m_MicroViasAllowed ? 1 : 0 ); + PutValueInLocalUnits( *m_SetMicroViasMinSizeCtrl, m_BrdSettings->m_MicroViasMinSize ); + PutValueInLocalUnits( *m_SetMicroViasMinDrillCtrl, m_BrdSettings->m_MicroViasMinDrill ); + PutValueInLocalUnits( *m_SetTrackMinWidthCtrl, m_BrdSettings->m_TrackMinWidth ); // Initialize Vias and Tracks sizes lists. // note we display only extra values, never the current netclass value. // (the first value in history list) - m_TracksWidthList = m_Parent->GetBoard()->m_TrackWidthList; + m_TracksWidthList = m_BrdSettings->m_TrackWidthList; m_TracksWidthList.erase( m_TracksWidthList.begin() ); // remove the netclass value - m_ViasDimensionsList = m_Parent->GetBoard()->m_ViasDimensionsList; + m_ViasDimensionsList = m_BrdSettings->m_ViasDimensionsList; m_ViasDimensionsList.erase( m_ViasDimensionsList.begin() ); // remove the netclass value InitDimensionsLists(); } @@ -484,7 +479,7 @@ static void class2gridRow( wxGrid* grid, int row, NETCLASS* nc ) */ void DIALOG_DESIGN_RULES::InitRulesList() { - NETCLASSES& netclasses = m_Pcb->m_NetClasses; + NETCLASSES& netclasses = m_BrdSettings->m_NetClasses; // the +1 is for the Default NETCLASS. if( netclasses.GetCount() + 1 > (unsigned) m_grid->GetNumberRows() ) @@ -524,7 +519,7 @@ static void gridRow2class( wxGrid* grid, int row, NETCLASS* nc ) */ void DIALOG_DESIGN_RULES::CopyRulesListToBoard() { - NETCLASSES& netclasses = m_Pcb->m_NetClasses; + NETCLASSES& netclasses = m_BrdSettings->m_NetClasses; // Remove all netclasses from board. We'll copy new list after netclasses.Clear(); @@ -535,9 +530,9 @@ void DIALOG_DESIGN_RULES::CopyRulesListToBoard() // Copy other NetClasses : for( int row = 1; row < m_grid->GetNumberRows(); ++row ) { - NETCLASS* nc = new NETCLASS( m_Pcb, m_grid->GetRowLabelValue( row ) ); + NETCLASS* nc = new NETCLASS( m_grid->GetRowLabelValue( row ) ); - if( !m_Pcb->m_NetClasses.Add( nc ) ) + if( !m_BrdSettings->m_NetClasses.Add( nc ) ) { // this netclass cannot be added because an other netclass with the same name exists // Should not occur because OnAddNetclassClick() tests for existing NetClass names @@ -568,20 +563,20 @@ void DIALOG_DESIGN_RULES::CopyRulesListToBoard() void DIALOG_DESIGN_RULES::CopyGlobalRulesToBoard() /*************************************************/ { - m_BrdSettings.m_BlindBuriedViaAllowed = m_OptViaType->GetSelection() > 0; + m_BrdSettings->m_BlindBuriedViaAllowed = m_OptViaType->GetSelection() > 0; // Update vias minimum values for DRC - m_BrdSettings.m_ViasMinSize = ValueFromTextCtrl( *m_SetViasMinSizeCtrl ); - m_BrdSettings.m_ViasMinDrill = ValueFromTextCtrl( *m_SetViasMinDrillCtrl ); + m_BrdSettings->m_ViasMinSize = ValueFromTextCtrl( *m_SetViasMinSizeCtrl ); + m_BrdSettings->m_ViasMinDrill = ValueFromTextCtrl( *m_SetViasMinDrillCtrl ); - m_BrdSettings.m_MicroViasAllowed = m_AllowMicroViaCtrl->GetSelection() == 1; + m_BrdSettings->m_MicroViasAllowed = m_AllowMicroViaCtrl->GetSelection() == 1; // Update microvias minimum values for DRC - m_BrdSettings.m_MicroViasMinSize = ValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); - m_BrdSettings.m_MicroViasMinDrill = ValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); + m_BrdSettings->m_MicroViasMinSize = ValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); + m_BrdSettings->m_MicroViasMinDrill = ValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); // Update tracks minimum values for DRC - m_BrdSettings.m_TrackMinWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); + m_BrdSettings->m_TrackMinWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); } @@ -634,12 +629,12 @@ void DIALOG_DESIGN_RULES::CopyDimensionsListsToBoard() // Sort new list by by increasing value sort( m_ViasDimensionsList.begin(), m_ViasDimensionsList.end() ); - std::vector * tlist = &m_Parent->GetBoard()->m_TrackWidthList; + std::vector* tlist = &m_BrdSettings->m_TrackWidthList; tlist->erase( tlist->begin() + 1, tlist->end() ); // Remove old "custom" sizes tlist->insert( tlist->end(), m_TracksWidthList.begin(), m_TracksWidthList.end() ); //Add new "custom" sizes // Reinitialize m_ViaSizeList - std::vector * vialist = &m_Parent->GetBoard()->m_ViasDimensionsList; + std::vector* vialist = &m_BrdSettings->m_ViasDimensionsList; vialist->erase( vialist->begin() + 1, vialist->end() ); vialist->insert( vialist->end(), m_ViasDimensionsList.begin(), m_ViasDimensionsList.end() ); } @@ -671,11 +666,9 @@ void DIALOG_DESIGN_RULES::OnOkButtonClick( wxCommandEvent& event ) CopyGlobalRulesToBoard(); CopyDimensionsListsToBoard(); - m_Pcb->SetDesignSettings( m_BrdSettings ); - EndModal( wxID_OK ); - m_Pcb->SetCurrentNetClass( NETCLASS::Default ); + m_BrdSettings->SetCurrentNetClass( NETCLASS::Default ); } @@ -755,7 +748,7 @@ void DIALOG_DESIGN_RULES::OnRemoveNetclassClick( wxCommandEvent& event ) for( unsigned ii = 0; ii < select.GetCount(); ii++ ) { int grid_row = select[ii]; - if( grid_row != 0 ) // Do not remove the default class + if( grid_row != 0 ) // Do not remove the default class { wxString classname = m_grid->GetRowLabelValue( grid_row ); m_grid->DeleteRows( grid_row ); diff --git a/pcbnew/dialogs/dialog_design_rules.h b/pcbnew/dialogs/dialog_design_rules.h index 3bfbfd8d57..f7206b5175 100644 --- a/pcbnew/dialogs/dialog_design_rules.h +++ b/pcbnew/dialogs/dialog_design_rules.h @@ -40,7 +40,7 @@ private: PCB_EDIT_FRAME* m_Parent; BOARD* m_Pcb; - BOARD_DESIGN_SETTINGS m_BrdSettings; + BOARD_DESIGN_SETTINGS* m_BrdSettings; static int s_LastTabSelection; ///< which tab user had open last diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp index 02577075cd..5f3afd55f1 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp @@ -46,21 +46,22 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() // Display current setup for tracks and vias BOARD* board = m_Parent->GetBoard(); - NETCLASSES& netclasses = board->m_NetClasses; - NETINFO_ITEM* net = board->FindNet( m_Netcode ); + BOARD_DESIGN_SETTINGS& dsnSettings = board->GetDesignSettings(); + NETCLASSES& netclasses = dsnSettings.m_NetClasses; NETCLASS* netclass = netclasses.GetDefault(); + NETINFO_ITEM* net = board->FindNet( m_Netcode ); if( net ) { m_CurrentNetName->SetLabel( net->GetNetname() ); - m_CurrentNetclassName->SetLabel( board->GetCurrentNetClassName() ); - netclass = netclasses.Find( board->GetCurrentNetClassName() ); + m_CurrentNetclassName->SetLabel( dsnSettings.GetCurrentNetClassName() ); + netclass = netclasses.Find( dsnSettings.GetCurrentNetClassName() ); } /* Disable the option "copy current to net" if we have only default netclass values * i.e. when m_TrackWidthSelector and m_ViaSizeSelector are set to 0 */ - if( !board->GetTrackWidthIndex() && !board->GetViaSizeIndex() ) + if( !dsnSettings.GetTrackWidthIndex() && !dsnSettings.GetViaSizeIndex() ) { m_Net2CurrValueButton->Enable( false ); m_OptionID = ID_NETCLASS_VALUES_TO_CURRENT_NET; @@ -77,9 +78,9 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 0, msg ); - if( board->GetTrackWidthIndex() ) + if( dsnSettings.GetTrackWidthIndex() ) { - value = board->GetCurrentTrackWidth(); + value = dsnSettings.GetCurrentTrackWidth(); msg = StringFromValue( g_UserUnit, value, true ); } else @@ -91,9 +92,9 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 1, msg ); - if( board->GetViaSizeIndex() ) + if( dsnSettings.GetViaSizeIndex() ) { - value = board->GetCurrentViaSize(); + value = dsnSettings.GetCurrentViaSize(); msg = StringFromValue( g_UserUnit, value, true ); } else @@ -103,7 +104,7 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() value = netclass->GetViaDrill(); // Display via drill msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 2, msg ); - value = board->GetCurrentViaDrill(); + value = dsnSettings.GetCurrentViaDrill(); if( value >= 0 ) msg = StringFromValue( g_UserUnit, value, true ); else diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index bf9e0d28ac..4c9f615ed7 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -70,8 +70,8 @@ void DIALOG_PLOT::Init_Dialog() // The reasonable width correction value must be in a range of // [-(MinTrackWidth-1), +(MinClearanceValue-1)] decimils. - m_widthAdjustMinValue = -(m_board->GetDesignSettings().m_TrackMinWidth - 1); - m_widthAdjustMaxValue = m_board->GetSmallestClearanceValue() - 1; + m_widthAdjustMinValue = -( m_board->GetDesignSettings().m_TrackMinWidth - 1 ); + m_widthAdjustMaxValue = m_board->GetDesignSettings().GetSmallestClearanceValue() - 1; switch( m_plotOpts.GetFormat() ) { diff --git a/pcbnew/dialogs/dialog_pns_settings.cpp b/pcbnew/dialogs/dialog_pns_settings.cpp new file mode 100644 index 0000000000..0368294ab1 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings.cpp @@ -0,0 +1,75 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 3 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, see . + */ + +/** + * Push and Shove router settings dialog. + */ + +#include "dialog_pns_settings.h" +#include + +DIALOG_PNS_SETTINGS::DIALOG_PNS_SETTINGS( wxWindow* aParent, PNS_ROUTING_SETTINGS& aSettings ) : + DIALOG_PNS_SETTINGS_BASE( aParent ), m_settings( aSettings ) +{ + // "Figure out what's best" is not available yet + m_mode->Enable( RM_Smart, false ); + + // Load widgets' values from settings + m_mode->SetSelection( m_settings.Mode() ); + m_shoveVias->SetValue( m_settings.ShoveVias() ); + m_backPressure->SetValue( m_settings.JumpOverObstacles() ); + m_removeLoops->SetValue( m_settings.RemoveLoops() ); + m_suggestEnding->SetValue( m_settings.SuggestFinish() ); + m_autoNeckdown->SetValue( m_settings.SmartPads() ); + m_effort->SetValue( m_settings.OptimizerEffort() ); + m_smoothDragged->SetValue( m_settings.SmoothDraggedSegments() ); + m_violateDrc->SetValue( m_settings.CanViolateDRC() ); +} + + +void DIALOG_PNS_SETTINGS::OnClose( wxCloseEvent& aEvent ) +{ + // Do nothing, it is result of ESC pressing + EndModal( 0 ); +} + + +void DIALOG_PNS_SETTINGS::OnOkClick( wxCommandEvent& aEvent ) +{ + // Save widgets' values to settings + m_settings.SetMode( (PNS_MODE) m_mode->GetSelection() ); + m_settings.SetShoveVias( m_shoveVias->GetValue() ); + m_settings.SetJumpOverObstacles( m_backPressure->GetValue() ); + m_settings.SetRemoveLoops( m_removeLoops->GetValue() ); + m_settings.SetSuggestFinish ( m_suggestEnding->GetValue() ); + m_settings.SetSmartPads( m_autoNeckdown->GetValue() ); + m_settings.SetOptimizerEffort( (PNS_OPTIMIZATION_EFFORT) m_effort->GetValue() ); + m_settings.SetSmoothDraggedSegments( m_smoothDragged->GetValue() ); + m_settings.SetCanViolateDRC( m_violateDrc->GetValue() ); + + EndModal( 1 ); +} + + +void DIALOG_PNS_SETTINGS::OnCancelClick( wxCommandEvent& aEvent ) +{ + // Do nothing + EndModal( 0 ); +} diff --git a/pcbnew/dialogs/dialog_pns_settings.h b/pcbnew/dialogs/dialog_pns_settings.h new file mode 100644 index 0000000000..2241ed60dc --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings.h @@ -0,0 +1,45 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 3 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, see . + */ + +/** + * Push and Shove router settings dialog. + */ + +#ifndef __dialog_pns_settings__ +#define __dialog_pns_settings__ + +#include "dialog_pns_settings_base.h" + +class PNS_ROUTING_SETTINGS; + +class DIALOG_PNS_SETTINGS : public DIALOG_PNS_SETTINGS_BASE +{ + public: + DIALOG_PNS_SETTINGS( wxWindow* aParent, PNS_ROUTING_SETTINGS& aSettings ); + + virtual void OnClose( wxCloseEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); + + private: + PNS_ROUTING_SETTINGS& m_settings; +}; + +#endif // __dialog_pns_settings__ diff --git a/pcbnew/dialogs/dialog_pns_settings_base.cpp b/pcbnew/dialogs/dialog_pns_settings_base.cpp new file mode 100644 index 0000000000..b675f8fd9d --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings_base.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 30 2013) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_pns_settings_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_PNS_SETTINGS_BASE::DIALOG_PNS_SETTINGS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxString m_modeChoices[] = { _("Highlight collisions"), _("Shove"), _("Walk around"), _("Figure out what's best") }; + int m_modeNChoices = sizeof( m_modeChoices ) / sizeof( wxString ); + m_mode = new wxRadioBox( this, wxID_ANY, _("Mode"), wxDefaultPosition, wxDefaultSize, m_modeNChoices, m_modeChoices, 1, wxRA_SPECIFY_COLS ); + m_mode->SetSelection( 1 ); + bMainSizer->Add( m_mode, 0, wxALL, 5 ); + + wxStaticBoxSizer* bOptions; + bOptions = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Options") ), wxVERTICAL ); + + m_shoveVias = new wxCheckBox( this, wxID_ANY, _("Shove vias"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_shoveVias, 0, wxALL, 5 ); + + m_backPressure = new wxCheckBox( this, wxID_ANY, _("Jump over obstacles"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_backPressure, 0, wxALL, 5 ); + + m_removeLoops = new wxCheckBox( this, wxID_ANY, _("Remove redundant tracks"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_removeLoops, 0, wxALL, 5 ); + + m_autoNeckdown = new wxCheckBox( this, wxID_ANY, _("Automatic neckdown"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_autoNeckdown, 0, wxALL, 5 ); + + m_smoothDragged = new wxCheckBox( this, wxID_ANY, _("Smooth dragged segments"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_smoothDragged, 0, wxALL, 5 ); + + m_violateDrc = new wxCheckBox( this, wxID_ANY, _("Allow DRC violations"), wxDefaultPosition, wxDefaultSize, 0 ); + bOptions->Add( m_violateDrc, 0, wxALL, 5 ); + + m_suggestEnding = new wxCheckBox( this, wxID_ANY, _("Suggest track finish"), wxDefaultPosition, wxDefaultSize, 0 ); + m_suggestEnding->Enable( false ); + + bOptions->Add( m_suggestEnding, 0, wxALL, 5 ); + + wxBoxSizer* bEffort; + bEffort = new wxBoxSizer( wxHORIZONTAL ); + + m_effortLabel = new wxStaticText( this, wxID_ANY, _("Optimizer effort"), wxDefaultPosition, wxDefaultSize, 0 ); + m_effortLabel->Wrap( -1 ); + bEffort->Add( m_effortLabel, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bEffort->Add( 0, 0, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSlider; + bSlider = new wxBoxSizer( wxVERTICAL ); + + m_effort = new wxSlider( this, wxID_ANY, 1, 0, 2, wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS|wxSL_BOTTOM|wxSL_HORIZONTAL|wxSL_TOP ); + bSlider->Add( m_effort, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSliderLabels; + bSliderLabels = new wxBoxSizer( wxHORIZONTAL ); + + m_lowLabel = new wxStaticText( this, wxID_ANY, _("low"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lowLabel->Wrap( -1 ); + m_lowLabel->SetFont( wxFont( 8, 70, 90, 90, false, wxEmptyString ) ); + + bSliderLabels->Add( m_lowLabel, 0, 0, 5 ); + + + bSliderLabels->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_highLabel = new wxStaticText( this, wxID_ANY, _("high"), wxDefaultPosition, wxDefaultSize, 0 ); + m_highLabel->Wrap( -1 ); + m_highLabel->SetFont( wxFont( 8, 70, 90, 90, false, wxEmptyString ) ); + + bSliderLabels->Add( m_highLabel, 0, 0, 5 ); + + + bSlider->Add( bSliderLabels, 1, wxEXPAND, 5 ); + + + bEffort->Add( bSlider, 1, wxEXPAND, 5 ); + + + bOptions->Add( bEffort, 1, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bButtons; + bButtons = new wxBoxSizer( wxHORIZONTAL ); + + m_ok = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ok->SetDefault(); + bButtons->Add( m_ok, 1, wxALL, 5 ); + + m_cancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtons->Add( m_cancel, 1, wxALL, 5 ); + + + bOptions->Add( bButtons, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( bOptions, 1, wxEXPAND, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_SETTINGS_BASE::OnClose ) ); + m_ok->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_SETTINGS_BASE::OnOkClick ), NULL, this ); + m_cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_SETTINGS_BASE::OnCancelClick ), NULL, this ); +} + +DIALOG_PNS_SETTINGS_BASE::~DIALOG_PNS_SETTINGS_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_SETTINGS_BASE::OnClose ) ); + m_ok->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_SETTINGS_BASE::OnOkClick ), NULL, this ); + m_cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_SETTINGS_BASE::OnCancelClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_pns_settings_base.fbp b/pcbnew/dialogs/dialog_pns_settings_base.fbp new file mode 100644 index 0000000000..dd008e9e25 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings_base.fbp @@ -0,0 +1,1414 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_pns_settings_base + 1000 + none + 1 + DIALOG_PNS_SETTINGS_BASE + + . + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_PNS_SETTINGS_BASE + + 289,504 + wxDEFAULT_DIALOG_STYLE + + Interactive Router settings + + + + + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Highlight collisions" "Shove" "Walk around" "Figure out what's best" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Mode + 1 + + 0 + + + 0 + + 1 + m_mode + 1 + + + protected + 1 + + Resizable + 1 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + wxID_ANY + Options + + bOptions + wxVERTICAL + none + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shove vias + + 0 + + + 0 + + 1 + m_shoveVias + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Jump over obstacles + + 0 + + + 0 + + 1 + m_backPressure + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Remove redundant tracks + + 0 + + + 0 + + 1 + m_removeLoops + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Automatic neckdown + + 0 + + + 0 + + 1 + m_autoNeckdown + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Smooth dragged segments + + 0 + + + 0 + + 1 + m_smoothDragged + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Allow DRC violations + + 0 + + + 0 + + 1 + m_violateDrc + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + Suggest track finish + + 0 + + + 0 + + 1 + m_suggestEnding + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + bEffort + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Optimizer effort + + 0 + + + 0 + + 1 + m_effortLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + protected + 0 + + + + 5 + wxEXPAND + 1 + + + bSlider + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 2 + + 1 + + 0 + + 0 + + 1 + m_effort + 1 + + + protected + 1 + + Resizable + 1 + + wxSL_AUTOTICKS|wxSL_BOTTOM|wxSL_HORIZONTAL|wxSL_TOP + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSliderLabels + wxHORIZONTAL + none + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,90,8,70,0 + 0 + 0 + wxID_ANY + low + + 0 + + + 0 + + 1 + m_lowLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + ,90,90,8,70,0 + 0 + 0 + wxID_ANY + high + + 0 + + + 0 + + 1 + m_highLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bButtons + wxHORIZONTAL + none + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_OK + OK + + 0 + + + 0 + + 1 + m_ok + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnOkClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + + 0 + + 1 + m_cancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_pns_settings_base.h b/pcbnew/dialogs/dialog_pns_settings_base.h new file mode 100644 index 0000000000..ceb135dc58 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings_base.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 30 2013) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_PNS_SETTINGS_BASE_H__ +#define __DIALOG_PNS_SETTINGS_BASE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_PNS_SETTINGS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_PNS_SETTINGS_BASE : public wxDialog +{ + private: + + protected: + wxRadioBox* m_mode; + wxCheckBox* m_shoveVias; + wxCheckBox* m_backPressure; + wxCheckBox* m_removeLoops; + wxCheckBox* m_autoNeckdown; + wxCheckBox* m_smoothDragged; + wxCheckBox* m_violateDrc; + wxCheckBox* m_suggestEnding; + wxStaticText* m_effortLabel; + wxSlider* m_effort; + wxStaticText* m_lowLabel; + wxStaticText* m_highLabel; + wxButton* m_ok; + wxButton* m_cancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_PNS_SETTINGS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Interactive Router settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 289,504 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~DIALOG_PNS_SETTINGS_BASE(); + +}; + +#endif //__DIALOG_PNS_SETTINGS_BASE_H__ diff --git a/pcbnew/dialogs/dialog_track_via_size.cpp b/pcbnew/dialogs/dialog_track_via_size.cpp new file mode 100644 index 0000000000..8a51cafdb4 --- /dev/null +++ b/pcbnew/dialogs/dialog_track_via_size.cpp @@ -0,0 +1,91 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 3 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, see . + */ + +/** + * Push and Shove router track width and via size dialog. + */ + +#include "dialog_track_via_size.h" +#include +#include +#include + +DIALOG_TRACK_VIA_SIZE::DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, PNS_ROUTING_SETTINGS& aSettings ) : + DIALOG_TRACK_VIA_SIZE_BASE( aParent ), + m_settings( aSettings ) +{ + // Load router settings to dialog fields + m_trackWidth->SetValue( To_User_Unit( m_trackWidth->GetUnits(), m_settings.GetTrackWidth() ) ); + m_viaDiameter->SetValue( To_User_Unit( m_viaDiameter->GetUnits(), m_settings.GetViaDiameter() ) ); + m_viaDrill->SetValue( To_User_Unit( m_viaDrill->GetUnits(), m_settings.GetViaDrill() ) ); + + m_trackWidth->SetFocus(); + + // Pressing ENTER when any of the text input fields is active applies changes + #if wxCHECK_VERSION( 3, 0, 0 ) + Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE::onOkClick ), NULL, this ); + #else + Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE::onOkClick ), NULL, this ); + #endif +} + + +bool DIALOG_TRACK_VIA_SIZE::check() +{ + // Wrong input + if( !m_trackWidth->GetValue() || !m_viaDiameter->GetValue() || !m_viaDrill->GetValue() ) + return false; + + // Via drill should be smaller than via diameter + if( *m_viaDrill->GetValue() >= m_viaDiameter->GetValue() ) + return false; + + return true; +} + + +void DIALOG_TRACK_VIA_SIZE::onClose( wxCloseEvent& aEvent ) +{ + EndModal( 0 ); +} + + +void DIALOG_TRACK_VIA_SIZE::onOkClick( wxCommandEvent& aEvent ) +{ + if( check() ) + { + // Store dialog values to the router settings + m_settings.SetTrackWidth( From_User_Unit( m_trackWidth->GetUnits(), *m_trackWidth->GetValue() ) ); + m_settings.SetViaDiameter( From_User_Unit( m_viaDiameter->GetUnits(), *m_viaDiameter->GetValue() ) ); + m_settings.SetViaDrill( From_User_Unit( m_viaDrill->GetUnits(), *m_viaDrill->GetValue() ) ); + EndModal( 1 ); + } + else + { + DisplayError( GetParent(), _( "Settings are incorrect" ) ); + m_trackWidth->SetFocus(); + } +} + + +void DIALOG_TRACK_VIA_SIZE::onCancelClick( wxCommandEvent& aEvent ) +{ + EndModal( 0 ); +} diff --git a/pcbnew/dialogs/dialog_track_via_size.h b/pcbnew/dialogs/dialog_track_via_size.h new file mode 100644 index 0000000000..92a03e8ec6 --- /dev/null +++ b/pcbnew/dialogs/dialog_track_via_size.h @@ -0,0 +1,52 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014 CERN + * Author: Maciej Suminski + * + * 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 3 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, see . + */ + +/** + * Push and Shove router track width and via size dialog. + */ + +#ifndef __dialog_track_via_size__ +#define __dialog_track_via_size__ + +#include "dialog_track_via_size_base.h" + +class PNS_ROUTING_SETTINGS; + +/** Implementing DIALOG_TRACK_VIA_SIZE_BASE */ +class DIALOG_TRACK_VIA_SIZE : public DIALOG_TRACK_VIA_SIZE_BASE +{ + public: + /** Constructor */ + DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, PNS_ROUTING_SETTINGS& aSettings ); + + protected: + // Routings settings that are modified by the dialog. + PNS_ROUTING_SETTINGS& m_settings; + + ///> Checks if values given in the dialog are sensible. + bool check(); + + // Handlers for DIALOG_TRACK_VIA_SIZE_BASE events. + void onClose( wxCloseEvent& aEvent ); + void onOkClick( wxCommandEvent& aEvent ); + void onCancelClick( wxCommandEvent& aEvent ); +}; + +#endif // __dialog_track_via_size__ diff --git a/pcbnew/dialogs/dialog_track_via_size_base.cpp b/pcbnew/dialogs/dialog_track_via_size_base.cpp new file mode 100644 index 0000000000..a402009da1 --- /dev/null +++ b/pcbnew/dialogs/dialog_track_via_size_base.cpp @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 30 2013) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_track_via_size_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_TRACK_VIA_SIZE_BASE::DIALOG_TRACK_VIA_SIZE_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizes; + bSizes = new wxBoxSizer( wxVERTICAL ); + + m_trackWidth = new WX_UNIT_TEXT( this, _("Track width:") ); + bSizes->Add( m_trackWidth, 0, wxALL, 5 ); + + m_viaDiameter = new WX_UNIT_TEXT( this, _("Via diameter:") ); + bSizes->Add( m_viaDiameter, 0, wxALL, 5 ); + + m_viaDrill = new WX_UNIT_TEXT( this, _("Via drill:") ); + bSizes->Add( m_viaDrill, 0, wxALL, 5 ); + + wxBoxSizer* bButtons; + bButtons = new wxBoxSizer( wxHORIZONTAL ); + + m_ok = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtons->Add( m_ok, 1, wxALL, 5 ); + + m_cancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + bButtons->Add( m_cancel, 1, wxALL, 5 ); + + + bSizes->Add( bButtons, 0, wxEXPAND, 5 ); + + + this->SetSizer( bSizes ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onClose ) ); + m_ok->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onOkClick ), NULL, this ); + m_cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onCancelClick ), NULL, this ); +} + +DIALOG_TRACK_VIA_SIZE_BASE::~DIALOG_TRACK_VIA_SIZE_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onClose ) ); + m_ok->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onOkClick ), NULL, this ); + m_cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TRACK_VIA_SIZE_BASE::onCancelClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_track_via_size_base.fbp b/pcbnew/dialogs/dialog_track_via_size_base.fbp new file mode 100644 index 0000000000..61462d3330 --- /dev/null +++ b/pcbnew/dialogs/dialog_track_via_size_base.fbp @@ -0,0 +1,539 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_track_via_size_base + 1000 + none + 1 + DIALOG_TRACK_VIA_SIZE_BASE + + . + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_TRACK_VIA_SIZE_BASE + + 388,164 + wxDEFAULT_DIALOG_STYLE + + Track width and via size + + + + + + + + + + + + + + onClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizes + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + WX_UNIT_TEXT + 1 + m_trackWidth = new WX_UNIT_TEXT( this, _("Track width:") ); + + 1 + WX_UNIT_TEXT* m_trackWidth; + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + #include <wxunittext.h> + + 0 + + + 0 + + 1 + m_trackWidth + 1 + + + protected + 1 + + Resizable + + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + WX_UNIT_TEXT + 1 + m_viaDiameter = new WX_UNIT_TEXT( this, _("Via diameter:") ); + + 1 + WX_UNIT_TEXT* m_viaDiameter; + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + #include <wxunittext.h> + + 0 + + + 0 + + 1 + m_viaDiameter + 1 + + + protected + 1 + + Resizable + + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + WX_UNIT_TEXT + 1 + m_viaDrill = new WX_UNIT_TEXT( this, _("Via drill:") ); + + 1 + WX_UNIT_TEXT* m_viaDrill; + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + #include <wxunittext.h> + + 0 + + + 0 + + 1 + m_viaDrill + 1 + + + protected + 1 + + Resizable + + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bButtons + wxHORIZONTAL + none + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_OK + OK + + 0 + + + 0 + + 1 + m_ok + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onOkClick + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + + 0 + + 1 + m_cancel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onCancelClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_track_via_size_base.h b/pcbnew/dialogs/dialog_track_via_size_base.h new file mode 100644 index 0000000000..de4f0e43a1 --- /dev/null +++ b/pcbnew/dialogs/dialog_track_via_size_base.h @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 30 2013) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_TRACK_VIA_SIZE_BASE_H__ +#define __DIALOG_TRACK_VIA_SIZE_BASE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_TRACK_VIA_SIZE_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_TRACK_VIA_SIZE_BASE : public wxDialog +{ + private: + + protected: + WX_UNIT_TEXT* m_trackWidth; + WX_UNIT_TEXT* m_viaDiameter; + WX_UNIT_TEXT* m_viaDrill; + wxButton* m_ok; + wxButton* m_cancel; + + // Virtual event handlers, overide them in your derived class + virtual void onClose( wxCloseEvent& event ) { event.Skip(); } + virtual void onOkClick( wxCommandEvent& event ) { event.Skip(); } + virtual void onCancelClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_TRACK_VIA_SIZE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Track width and via size"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 388,164 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~DIALOG_TRACK_VIA_SIZE_BASE(); + +}; + +#endif //__DIALOG_TRACK_VIA_SIZE_BASE_H__ diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index b32ddb65b4..67c451c721 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -403,7 +403,7 @@ bool DRC::testNetClasses() { bool ret = true; - NETCLASSES& netclasses = m_pcb->m_NetClasses; + NETCLASSES& netclasses = m_pcb->GetDesignSettings().m_NetClasses; wxString msg; // construct this only once here, not in a loop, since somewhat expensive. diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index 04394d2d08..ed48f149ab 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -154,6 +154,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) wxPoint shape_pos; NETCLASS* netclass = aRefSeg->GetNetClass(); + BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings(); /* In order to make some calculations more easier or faster, * pads and tracks coordinates will be made relative to the reference segment origin @@ -173,7 +174,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // test if the via size is smaller than minimum if( refvia->GetViaType() == VIA_MICROVIA ) { - if( refvia->GetWidth() < netclass->GetuViaMinDiameter() ) + if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_MICROVIA, m_currentMarker ); @@ -182,7 +183,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) } else { - if( refvia->GetWidth() < netclass->GetViaMinDiameter() ) + if( refvia->GetWidth() < dsnSettings.m_ViasMinSize ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_VIA, m_currentMarker ); @@ -231,7 +232,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) } else // This is a track segment { - if( aRefSeg->GetWidth() < netclass->GetTrackMinWidth() ) + if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker ); diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 4f93574ab2..2e59478403 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1133,7 +1133,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const loadAllSections( doc ); - BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings(); + BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings(); if( m_min_trace < designSettings.m_TrackMinWidth ) designSettings.m_TrackMinWidth = m_min_trace; @@ -1146,7 +1146,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const if( m_rules->mdWireWire ) { - NETCLASS* defaultNetclass = m_board->m_NetClasses.GetDefault(); + NETCLASS* defaultNetclass = designSettings.GetDefault(); int clearance = KiROUND( m_rules->mdWireWire ); if( clearance < defaultNetclass->GetClearance() ) diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index 51de425839..7c2a02804f 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -1391,15 +1391,15 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) // Cancel the current tool // TODO while sending a lot of cancel events works for sure, it is not the most // elegant way to cancel a tool, this should be probably done another way - while( m_toolManager.GetCurrentTool()->GetName() != "pcbnew.InteractiveSelection" && + while( m_toolManager->GetCurrentTool()->GetName() != "pcbnew.InteractiveSelection" && trials++ < MAX_TRIALS ) { TOOL_EVENT cancel( TC_ANY, TA_CANCEL_TOOL ); - m_toolManager.ProcessEvent( cancel ); + m_toolManager->ProcessEvent( cancel ); } if( !actionName.empty() ) - m_toolManager.RunAction( actionName ); + m_toolManager->RunAction( actionName ); } } else diff --git a/pcbnew/edit_track_width.cpp b/pcbnew/edit_track_width.cpp index c371ee0978..b0ec02eb13 100644 --- a/pcbnew/edit_track_width.cpp +++ b/pcbnew/edit_track_width.cpp @@ -43,7 +43,7 @@ bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, if( net ) new_width = net->GetTrackWidth(); else - new_width = GetBoard()->GetCurrentTrackWidth(); + new_width = GetDesignSettings().GetCurrentTrackWidth(); if( aTrackItem->Type() == PCB_VIA_T ) { @@ -58,8 +58,8 @@ bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, } else { - new_width = GetBoard()->GetCurrentViaSize(); - new_drill = GetBoard()->GetCurrentViaDrill(); + new_width = GetDesignSettings().GetCurrentViaSize(); + new_drill = GetDesignSettings().GetCurrentViaDrill(); } if( via->GetViaType() == VIA_MICROVIA ) @@ -67,7 +67,7 @@ bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK* aTrackItem, if( net ) new_width = net->GetMicroViaSize(); else - new_width = GetBoard()->GetCurrentMicroViaSize(); + new_width = GetDesignSettings().GetCurrentMicroViaSize(); } } diff --git a/pcbnew/editrack-part2.cpp b/pcbnew/editrack-part2.cpp index ef7ed1642f..07967de9c9 100644 --- a/pcbnew/editrack-part2.cpp +++ b/pcbnew/editrack-part2.cpp @@ -98,7 +98,7 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) VIA* via = new VIA( GetBoard() ); via->SetFlags( IS_NEW ); via->SetViaType( GetDesignSettings().m_CurrentViaType ); - via->SetWidth( GetBoard()->GetCurrentViaSize()); + via->SetWidth( GetDesignSettings().GetCurrentViaSize()); via->SetNetCode( GetBoard()->GetHighLightNetCode() ); via->SetEnd( g_CurrentTrackSegment->GetEnd() ); via->SetStart( g_CurrentTrackSegment->GetEnd() ); @@ -106,7 +106,7 @@ bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC ) // Usual via is from copper to component. // layer pair is LAYER_N_BACK and LAYER_N_FRONT. via->SetLayerPair( LAYER_N_BACK, LAYER_N_FRONT ); - via->SetDrill( GetBoard()->GetCurrentViaDrill() ); + via->SetDrill( GetDesignSettings().GetCurrentViaDrill() ); LAYER_NUM first_layer = GetActiveLayer(); LAYER_NUM last_layer; diff --git a/pcbnew/editrack.cpp b/pcbnew/editrack.cpp index 220668148c..715ac98f8d 100644 --- a/pcbnew/editrack.cpp +++ b/pcbnew/editrack.cpp @@ -167,12 +167,12 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) // Display info about track Net class, and init track and vias sizes: g_CurrentTrackSegment->SetNetCode( GetBoard()->GetHighLightNetCode() ); - GetBoard()->SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() ); + GetDesignSettings().SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() ); g_CurrentTrackSegment->SetLayer( GetScreen()->m_Active_Layer ); - g_CurrentTrackSegment->SetWidth( GetBoard()->GetCurrentTrackWidth() ); + g_CurrentTrackSegment->SetWidth( GetDesignSettings().GetCurrentTrackWidth() ); - if( GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) + if( GetDesignSettings().m_UseConnectedTrackWidth ) { if( TrackOnStartPoint && TrackOnStartPoint->Type() == PCB_TRACE_T ) g_CurrentTrackSegment->SetWidth( TrackOnStartPoint->GetWidth()); @@ -282,8 +282,8 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) newTrack->SetLayer( GetScreen()->m_Active_Layer ); - if( !GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) - newTrack->SetWidth( GetBoard()->GetCurrentTrackWidth() ); + if( !GetDesignSettings().m_UseConnectedTrackWidth ) + newTrack->SetWidth( GetDesignSettings().GetCurrentTrackWidth() ); DBG( g_CurrentTrackList.VerifyListIntegrity(); ); @@ -691,7 +691,7 @@ void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPo DisplayOpt.ShowTrackClearanceMode = SHOW_CLEARANCE_ALWAYS; // Values to Via circle - int boardViaRadius = frame->GetBoard()->GetCurrentViaSize()/2; + int boardViaRadius = frame->GetDesignSettings().GetCurrentViaSize()/2; int viaRadiusWithClearence = boardViaRadius+netclass->GetClearance(); EDA_RECT* panelClipBox=aPanel->GetClipBox(); @@ -718,8 +718,8 @@ void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPo // Set track parameters, that can be modified while creating the track g_CurrentTrackSegment->SetLayer( screen->m_Active_Layer ); - if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) - g_CurrentTrackSegment->SetWidth( frame->GetBoard()->GetCurrentTrackWidth() ); + if( !frame->GetDesignSettings().m_UseConnectedTrackWidth ) + g_CurrentTrackSegment->SetWidth( frame->GetDesignSettings().GetCurrentTrackWidth() ); if( g_TwoSegmentTrackBuild ) { @@ -729,8 +729,8 @@ void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPo { previous_track->SetLayer( screen->m_Active_Layer ); - if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth ) - previous_track->SetWidth( frame->GetBoard()->GetCurrentTrackWidth() ); + if( !frame->GetDesignSettings().m_UseConnectedTrackWidth ) + previous_track->SetWidth( frame->GetDesignSettings().GetCurrentTrackWidth() ); } } diff --git a/pcbnew/event_handlers_tracks_vias_sizes.cpp b/pcbnew/event_handlers_tracks_vias_sizes.cpp index 52428a3834..0ccd13a6a5 100644 --- a/pcbnew/event_handlers_tracks_vias_sizes.cpp +++ b/pcbnew/event_handlers_tracks_vias_sizes.cpp @@ -41,8 +41,8 @@ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) case ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES: GetDesignSettings().m_UseConnectedTrackWidth = false; - GetBoard()->SetTrackWidthIndex( 0 ); - GetBoard()->SetViaSizeIndex( 0 ); + GetDesignSettings().SetTrackWidthIndex( 0 ); + GetDesignSettings().SetViaSizeIndex( 0 ); break; case ID_POPUP_PCB_SELECT_AUTO_WIDTH: @@ -69,7 +69,7 @@ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) m_canvas->MoveCursorToCrossHair(); GetDesignSettings().m_UseConnectedTrackWidth = false; ii = id - ID_POPUP_PCB_SELECT_WIDTH1; - GetBoard()->SetTrackWidthIndex( ii ); + GetDesignSettings().SetTrackWidthIndex( ii ); break; case ID_POPUP_PCB_SELECT_VIASIZE1: // this is the default Netclass selection @@ -91,17 +91,17 @@ void PCB_EDIT_FRAME::Tracks_and_Vias_Size_Event( wxCommandEvent& event ) // select the new current value for via size (via diameter) m_canvas->MoveCursorToCrossHair(); ii = id - ID_POPUP_PCB_SELECT_VIASIZE1; - GetBoard()->SetViaSizeIndex( ii ); + GetDesignSettings().SetViaSizeIndex( ii ); break; case ID_AUX_TOOLBAR_PCB_TRACK_WIDTH: ii = m_SelTrackWidthBox->GetCurrentSelection(); - GetBoard()->SetTrackWidthIndex( ii ); + GetDesignSettings().SetTrackWidthIndex( ii ); break; case ID_AUX_TOOLBAR_PCB_VIA_SIZE: ii = m_SelViaSizeBox->GetCurrentSelection(); - GetBoard()->SetViaSizeIndex( ii ); + GetDesignSettings().SetViaSizeIndex( ii ); break; default: diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 27262d6f38..10eaa4be0a 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -356,7 +356,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in } else { - GetBoard()->m_NetClasses.Clear(); + GetDesignSettings().m_NetClasses.Clear(); } BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK @@ -485,7 +485,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in #endif // Update info shown by the horizontal toolbars - GetBoard()->SetCurrentNetClass( NETCLASS::Default ); + GetDesignSettings().SetCurrentNetClass( NETCLASS::Default ); ReFillLayerWidget(); ReCreateLayerBox(); @@ -678,7 +678,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF // Select default Netclass before writing file. // Useful to save default values in headers - GetBoard()->SetCurrentNetClass( GetBoard()->m_NetClasses.GetDefault()->GetName() ); + GetDesignSettings().SetCurrentNetClass( NETCLASS::Default ); try { diff --git a/pcbnew/hotkeys_board_editor.cpp b/pcbnew/hotkeys_board_editor.cpp index 14931a0fa4..1cffe09577 100644 --- a/pcbnew/hotkeys_board_editor.cpp +++ b/pcbnew/hotkeys_board_editor.cpp @@ -199,10 +199,10 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit if( GetCanvas()->IsMouseCaptured() ) GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false ); - if( GetBoard()->GetTrackWidthIndex() < GetBoard()->m_TrackWidthList.size() - 1 ) - GetBoard()->SetTrackWidthIndex( GetBoard()->GetTrackWidthIndex() + 1 ); + if( GetDesignSettings().GetTrackWidthIndex() < GetDesignSettings().m_TrackWidthList.size() - 1 ) + GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().GetTrackWidthIndex() + 1 ); else - GetBoard()->SetTrackWidthIndex( 0 ); + GetDesignSettings().SetTrackWidthIndex( 0 ); if( GetCanvas()->IsMouseCaptured() ) GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false ); @@ -213,10 +213,10 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit if( GetCanvas()->IsMouseCaptured() ) GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false ); - if( GetBoard()->GetTrackWidthIndex() <= 0 ) - GetBoard()->SetTrackWidthIndex( GetBoard()->m_TrackWidthList.size() -1 ); + if( GetDesignSettings().GetTrackWidthIndex() <= 0 ) + GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().m_TrackWidthList.size() -1 ); else - GetBoard()->SetTrackWidthIndex( GetBoard()->GetTrackWidthIndex() - 1 ); + GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().GetTrackWidthIndex() - 1 ); if( GetCanvas()->IsMouseCaptured() ) GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false ); diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 5c4b280dda..f77c4dfbb4 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -60,6 +60,17 @@ */ static const wxString traceFootprintLibrary( wxT( "KicadFootprintLib" ) ); +///> Removes empty nets (i.e. with node count equal zero) from net classes +void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass ) +{ + for( NETCLASS::const_iterator it = aNetClass.begin(); it != aNetClass.end(); ++it ) + { + NETINFO_ITEM* netinfo = aBoard.FindNet( *it ); + + if( netinfo && netinfo->GetNodesCount() <= 0 ) // hopefully there are no nets with negative + aNetClass.Remove( it ); // node count, but you never know.. + } +} /** * Class FP_CACHE_ITEM @@ -483,6 +494,8 @@ void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const throw( IO_ERROR ) { + const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings(); + m_out->Print( 0, "\n" ); m_out->Print( aNestLevel, "(general\n" ); @@ -496,7 +509,7 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const FMTIU( aBoard->GetBoundingBox().GetRight() ).c_str(), FMTIU( aBoard->GetBoundingBox().GetBottom() ).c_str() ); m_out->Print( aNestLevel+1, "(thickness %s)\n", - FMTIU( aBoard->GetDesignSettings().GetBoardThickness() ).c_str() ); + FMTIU( dsnSettings.GetBoardThickness() ).c_str() ); m_out->Print( aNestLevel+1, "(drawings %d)\n", aBoard->m_Drawings.GetCount() ); m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); @@ -551,15 +564,15 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const // Save current default track width, for compatibility with older Pcbnew version; m_out->Print( aNestLevel+1, "(last_trace_width %s)\n", - FMTIU( aBoard->GetCurrentTrackWidth() ).c_str() ); + FMTIU( dsnSettings.GetCurrentTrackWidth() ).c_str() ); // Save custom tracks width list (the first is not saved here: this is the netclass value - for( unsigned ii = 1; ii < aBoard->m_TrackWidthList.size(); ii++ ) + for( unsigned ii = 1; ii < dsnSettings.m_TrackWidthList.size(); ii++ ) m_out->Print( aNestLevel+1, "(user_trace_width %s)\n", - FMTIU( aBoard->m_TrackWidthList[ii] ).c_str() ); + FMTIU( dsnSettings.m_TrackWidthList[ii] ).c_str() ); m_out->Print( aNestLevel+1, "(trace_clearance %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetClearance() ).c_str() ); + FMTIU( dsnSettings.GetDefault()->GetClearance() ).c_str() ); // ZONE_SETTINGS m_out->Print( aNestLevel+1, "(zone_clearance %s)\n", @@ -568,78 +581,79 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const aBoard->GetZoneSettings().m_Zone_45_Only ? "yes" : "no" ); m_out->Print( aNestLevel+1, "(trace_min %s)\n", - FMTIU( aBoard->GetDesignSettings().m_TrackMinWidth ).c_str() ); + FMTIU( dsnSettings.m_TrackMinWidth ).c_str() ); m_out->Print( aNestLevel+1, "(segment_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_DrawSegmentWidth ).c_str() ); + FMTIU( dsnSettings.m_DrawSegmentWidth ).c_str() ); m_out->Print( aNestLevel+1, "(edge_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_EdgeSegmentWidth ).c_str() ); + FMTIU( dsnSettings.m_EdgeSegmentWidth ).c_str() ); // Save current default via size, for compatibility with older Pcbnew version; m_out->Print( aNestLevel+1, "(via_size %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDiameter() ).c_str() ); + FMTIU( dsnSettings.GetDefault()->GetViaDiameter() ).c_str() ); m_out->Print( aNestLevel+1, "(via_drill %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetViaDrill() ).c_str() ); + FMTIU( dsnSettings.GetDefault()->GetViaDrill() ).c_str() ); m_out->Print( aNestLevel+1, "(via_min_size %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ViasMinSize ).c_str() ); + FMTIU( dsnSettings.m_ViasMinSize ).c_str() ); m_out->Print( aNestLevel+1, "(via_min_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ViasMinDrill ).c_str() ); + FMTIU( dsnSettings.m_ViasMinDrill ).c_str() ); // Save custom vias diameters list (the first is not saved here: this is // the netclass value - for( unsigned ii = 1; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) + for( unsigned ii = 1; ii < dsnSettings.m_ViasDimensionsList.size(); ii++ ) m_out->Print( aNestLevel+1, "(user_via %s %s)\n", - FMTIU( aBoard->m_ViasDimensionsList[ii].m_Diameter ).c_str(), - FMTIU( aBoard->m_ViasDimensionsList[ii].m_Drill ).c_str() ); + FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Diameter ).c_str(), + FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Drill ).c_str() ); // for old versions compatibility: - if( aBoard->GetDesignSettings().m_BlindBuriedViaAllowed ) + if( dsnSettings.m_BlindBuriedViaAllowed ) m_out->Print( aNestLevel+1, "(blind_buried_vias_allowed yes)\n" ); + m_out->Print( aNestLevel+1, "(uvia_size %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDiameter() ).c_str() ); + FMTIU( dsnSettings.GetDefault()->GetuViaDiameter() ).c_str() ); m_out->Print( aNestLevel+1, "(uvia_drill %s)\n", - FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDrill() ).c_str() ); + FMTIU( dsnSettings.GetDefault()->GetuViaDrill() ).c_str() ); m_out->Print( aNestLevel+1, "(uvias_allowed %s)\n", - ( aBoard->GetDesignSettings().m_MicroViasAllowed ) ? "yes" : "no" ); + ( dsnSettings.m_MicroViasAllowed ) ? "yes" : "no" ); m_out->Print( aNestLevel+1, "(uvia_min_size %s)\n", - FMTIU( aBoard->GetDesignSettings().m_MicroViasMinSize ).c_str() ); + FMTIU( dsnSettings.m_MicroViasMinSize ).c_str() ); m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_MicroViasMinDrill ).c_str() ); + FMTIU( dsnSettings.m_MicroViasMinDrill ).c_str() ); m_out->Print( aNestLevel+1, "(pcb_text_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_PcbTextWidth ).c_str() ); + FMTIU( dsnSettings.m_PcbTextWidth ).c_str() ); m_out->Print( aNestLevel+1, "(pcb_text_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_PcbTextSize.y ).c_str() ); + FMTIU( dsnSettings.m_PcbTextSize.x ).c_str(), + FMTIU( dsnSettings.m_PcbTextSize.y ).c_str() ); m_out->Print( aNestLevel+1, "(mod_edge_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleSegmentWidth ).c_str() ); + FMTIU( dsnSettings.m_ModuleSegmentWidth ).c_str() ); m_out->Print( aNestLevel+1, "(mod_text_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_ModuleTextSize.y ).c_str() ); + FMTIU( dsnSettings.m_ModuleTextSize.x ).c_str(), + FMTIU( dsnSettings.m_ModuleTextSize.y ).c_str() ); m_out->Print( aNestLevel+1, "(mod_text_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_ModuleTextWidth ).c_str() ); + FMTIU( dsnSettings.m_ModuleTextWidth ).c_str() ); m_out->Print( aNestLevel+1, "(pad_size %s %s)\n", - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().x ).c_str(), - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetSize().y ).c_str() ); + FMTIU( dsnSettings.m_Pad_Master.GetSize().x ).c_str(), + FMTIU( dsnSettings.m_Pad_Master.GetSize().y ).c_str() ); m_out->Print( aNestLevel+1, "(pad_drill %s)\n", - FMTIU( aBoard->GetDesignSettings().m_Pad_Master.GetDrillSize().x ).c_str() ); + FMTIU( dsnSettings.m_Pad_Master.GetDrillSize().x ).c_str() ); m_out->Print( aNestLevel+1, "(pad_to_mask_clearance %s)\n", - FMTIU( aBoard->GetDesignSettings().m_SolderMaskMargin ).c_str() ); + FMTIU( dsnSettings.m_SolderMaskMargin ).c_str() ); - if( aBoard->GetDesignSettings().m_SolderMaskMinWidth ) + if( dsnSettings.m_SolderMaskMinWidth ) m_out->Print( aNestLevel+1, "(solder_mask_min_width %s)\n", - FMTIU( aBoard->GetDesignSettings().m_SolderMaskMinWidth ).c_str() ); + FMTIU( dsnSettings.m_SolderMaskMinWidth ).c_str() ); - if( aBoard->GetDesignSettings().m_SolderPasteMargin != 0 ) + if( dsnSettings.m_SolderPasteMargin != 0 ) m_out->Print( aNestLevel+1, "(pad_to_paste_clearance %s)\n", - FMTIU( aBoard->GetDesignSettings().m_SolderPasteMargin ).c_str() ); + FMTIU( dsnSettings.m_SolderPasteMargin ).c_str() ); - if( aBoard->GetDesignSettings().m_SolderPasteMarginRatio != 0 ) + if( dsnSettings.m_SolderPasteMarginRatio != 0 ) m_out->Print( aNestLevel+1, "(pad_to_paste_clearance_ratio %s)\n", - Double2Str( aBoard->GetDesignSettings().m_SolderPasteMarginRatio ).c_str() ); + Double2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() ); m_out->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n", FMTIU( aBoard->GetAuxOrigin().x ).c_str(), @@ -651,7 +665,7 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const FMTIU( aBoard->GetGridOrigin().y ).c_str() ); m_out->Print( aNestLevel+1, "(visible_elements %X)\n", - aBoard->GetDesignSettings().GetVisibleElements() ); + dsnSettings.GetVisibleElements() ); aBoard->GetPlotOptions().Format( m_out, aNestLevel+1 ); @@ -669,15 +683,18 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const m_out->Print( 0, "\n" ); // Save the default net class first. - aBoard->m_NetClasses.GetDefault()->Format( m_out, aNestLevel, m_ctl ); + NETCLASS defaultNC = *dsnSettings.GetDefault(); + filterNetClass( *aBoard, defaultNC ); // Remove empty nets (from a copy of a netclass) + defaultNC.Format( m_out, aNestLevel, m_ctl ); // Save the rest of the net classes alphabetically. - for( NETCLASSES::const_iterator it = aBoard->m_NetClasses.begin(); - it != aBoard->m_NetClasses.end(); + for( NETCLASSES::const_iterator it = dsnSettings.m_NetClasses.begin(); + it != dsnSettings.m_NetClasses.end(); ++it ) { - NETCLASS* netclass = it->second; - netclass->Format( m_out, aNestLevel, m_ctl ); + NETCLASS netclass = *it->second; + filterNetClass( *aBoard, netclass ); // Remove empty nets (from a copy of a netclass) + netclass.Format( m_out, aNestLevel, m_ctl ); } // Save the modules. @@ -707,7 +724,7 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const /// will not be saved. // Save the polygon (which are the newer technology) zones. - for( int i=0; i < aBoard->GetAreaCount(); ++i ) + for( int i = 0; i < aBoard->GetAreaCount(); ++i ) Format( aBoard->GetArea( i ), aNestLevel ); } diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index d94852db4c..f2f174267b 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -632,7 +632,9 @@ void LEGACY_PLUGIN::loadSHEET() void LEGACY_PLUGIN::loadSETUP() { - NETCLASS* netclass_default = m_board->m_NetClasses.GetDefault(); + NETCLASS* netclass_default = m_board->GetDesignSettings().GetDefault(); + // TODO Orson: is it really necessary to first operate on a copy and then apply it? + // would not it be better to use reference here and apply all the changes instantly? BOARD_DESIGN_SETTINGS bds = m_board->GetDesignSettings(); ZONE_SETTINGS zs = m_board->GetZoneSettings(); char* line; @@ -692,7 +694,7 @@ void LEGACY_PLUGIN::loadSETUP() else if( TESTLINE( "TrackWidthList" ) ) { BIU tmp = biuParse( line + SZ( "TrackWidthList" ) ); - m_board->m_TrackWidthList.push_back( tmp ); + bds.m_TrackWidthList.push_back( tmp ); } else if( TESTLINE( "TrackClearence" ) ) @@ -754,7 +756,8 @@ void LEGACY_PLUGIN::loadSETUP() if( data ) // DRILL may not be present ? drill = biuParse( data ); - m_board->m_ViasDimensionsList.push_back( VIA_DIMENSION( diameter, drill ) ); + bds.m_ViasDimensionsList.push_back( VIA_DIMENSION( diameter, + drill ) ); } else if( TESTLINE( "ViaDrill" ) ) @@ -894,7 +897,7 @@ void LEGACY_PLUGIN::loadSETUP() // at all, the global defaults should go into a preferences // file instead so they are there to start new board // projects. - m_board->m_NetClasses.GetDefault()->SetParams(); + m_board->GetDesignSettings().GetDefault()->SetParams( m_board->GetDesignSettings() ); return; // preferred exit } @@ -907,23 +910,24 @@ void LEGACY_PLUGIN::loadSETUP() * Sort lists by by increasing value and remove duplicates * (the first value is not tested, because it is the netclass value */ - sort( m_board->m_ViasDimensionsList.begin() + 1, m_board->m_ViasDimensionsList.end() ); - sort( m_board->m_TrackWidthList.begin() + 1, m_board->m_TrackWidthList.end() ); + BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings(); + sort( designSettings.m_ViasDimensionsList.begin() + 1, designSettings.m_ViasDimensionsList.end() ); + sort( designSettings.m_TrackWidthList.begin() + 1, designSettings.m_TrackWidthList.end() ); - for( unsigned ii = 1; ii < m_board->m_ViasDimensionsList.size() - 1; ii++ ) + for( unsigned ii = 1; ii < designSettings.m_ViasDimensionsList.size() - 1; ii++ ) { - if( m_board->m_ViasDimensionsList[ii] == m_board->m_ViasDimensionsList[ii + 1] ) + if( designSettings.m_ViasDimensionsList[ii] == designSettings.m_ViasDimensionsList[ii + 1] ) { - m_board->m_ViasDimensionsList.erase( m_board->m_ViasDimensionsList.begin() + ii ); + designSettings.m_ViasDimensionsList.erase( designSettings.m_ViasDimensionsList.begin() + ii ); ii--; } } - for( unsigned ii = 1; ii < m_board->m_TrackWidthList.size() - 1; ii++ ) + for( unsigned ii = 1; ii < designSettings.m_TrackWidthList.size() - 1; ii++ ) { - if( m_board->m_TrackWidthList[ii] == m_board->m_TrackWidthList[ii + 1] ) + if( designSettings.m_TrackWidthList[ii] == designSettings.m_TrackWidthList[ii + 1] ) { - m_board->m_TrackWidthList.erase( m_board->m_TrackWidthList.begin() + ii ); + designSettings.m_TrackWidthList.erase( designSettings.m_TrackWidthList.begin() + ii ); ii--; } } @@ -2109,7 +2113,7 @@ void LEGACY_PLUGIN::loadNETCLASS() // yet since that would bypass duplicate netclass name checking within the BOARD. // store it temporarily in an auto_ptr until successfully inserted into the BOARD // just before returning. - auto_ptr nc( new NETCLASS( m_board, wxEmptyString ) ); + auto_ptr nc( new NETCLASS( wxEmptyString ) ); while( ( line = READLINE( m_reader ) ) != NULL ) { @@ -2171,7 +2175,7 @@ void LEGACY_PLUGIN::loadNETCLASS() else if( TESTLINE( "$EndNCLASS" ) ) { - if( m_board->m_NetClasses.Add( nc.get() ) ) + if( m_board->GetDesignSettings().m_NetClasses.Add( nc.get() ) ) { nc.release(); } @@ -2980,8 +2984,8 @@ void LEGACY_PLUGIN::saveSHEET( const BOARD* aBoard ) const void LEGACY_PLUGIN::saveSETUP( const BOARD* aBoard ) const { - NETCLASS* netclass_default = aBoard->m_NetClasses.GetDefault(); const BOARD_DESIGN_SETTINGS& bds = aBoard->GetDesignSettings(); + NETCLASS* netclass_default = bds.GetDefault(); fprintf( m_fp, "$SETUP\n" ); @@ -3005,11 +3009,12 @@ void LEGACY_PLUGIN::saveSETUP( const BOARD* aBoard ) const } // Save current default track width, for compatibility with older Pcbnew version; - fprintf( m_fp, "TrackWidth %s\n", fmtBIU( aBoard->GetCurrentTrackWidth() ).c_str() ); + fprintf( m_fp, "TrackWidth %s\n", + fmtBIU( aBoard->GetDesignSettings().GetCurrentTrackWidth() ).c_str() ); // Save custom tracks width list (the first is not saved here: this is the netclass value - for( unsigned ii = 1; ii < aBoard->m_TrackWidthList.size(); ii++ ) - fprintf( m_fp, "TrackWidthList %s\n", fmtBIU( aBoard->m_TrackWidthList[ii] ).c_str() ); + for( unsigned ii = 1; ii < aBoard->GetDesignSettings().m_TrackWidthList.size(); ii++ ) + fprintf( m_fp, "TrackWidthList %s\n", fmtBIU( aBoard->GetDesignSettings().m_TrackWidthList[ii] ).c_str() ); fprintf( m_fp, "TrackClearence %s\n", fmtBIU( netclass_default->GetClearance() ).c_str() ); @@ -3030,10 +3035,10 @@ void LEGACY_PLUGIN::saveSETUP( const BOARD* aBoard ) const // Save custom vias diameters list (the first is not saved here: this is // the netclass value - for( unsigned ii = 1; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) + for( unsigned ii = 1; ii < aBoard->GetDesignSettings().m_ViasDimensionsList.size(); ii++ ) fprintf( m_fp, "ViaSizeList %s %s\n", - fmtBIU( aBoard->m_ViasDimensionsList[ii].m_Diameter ).c_str(), - fmtBIU( aBoard->m_ViasDimensionsList[ii].m_Drill ).c_str() ); + fmtBIU( aBoard->GetDesignSettings().m_ViasDimensionsList[ii].m_Diameter ).c_str(), + fmtBIU( aBoard->GetDesignSettings().m_ViasDimensionsList[ii].m_Drill ).c_str() ); // for old versions compatibility: fprintf( m_fp, "MicroViaSize %s\n", fmtBIU( netclass_default->GetuViaDiameter() ).c_str() ); @@ -3093,7 +3098,7 @@ void LEGACY_PLUGIN::saveBOARD_ITEMS( const BOARD* aBoard ) const } // Saved nets do not include netclass names, so save netclasses after nets. - saveNETCLASSES( &aBoard->m_NetClasses ); + saveNETCLASSES( &aBoard->GetDesignSettings().m_NetClasses ); // save the modules for( MODULE* m = aBoard->m_Modules; m; m = (MODULE*) m->Next() ) @@ -3114,7 +3119,7 @@ void LEGACY_PLUGIN::saveBOARD_ITEMS( const BOARD* aBoard ) const savePCB_TARGET( (PCB_TARGET*) gr ); break; case PCB_DIMENSION_T: - saveDIMENTION( (DIMENSION*) gr ); + saveDIMENSION( (DIMENSION*) gr ); break; default: THROW_IO_ERROR( wxString::Format( UNKNOWN_GRAPHIC_FORMAT, gr->Type() ) ); @@ -3758,7 +3763,7 @@ void LEGACY_PLUGIN::saveZONE_CONTAINER( const ZONE_CONTAINER* me ) const } -void LEGACY_PLUGIN::saveDIMENTION( const DIMENSION* me ) const +void LEGACY_PLUGIN::saveDIMENSION( const DIMENSION* me ) const { // note: COTATION was the previous name of DIMENSION // this old keyword is used here for compatibility diff --git a/pcbnew/legacy_plugin.h b/pcbnew/legacy_plugin.h index dec3bfcbac..a9efbaa053 100644 --- a/pcbnew/legacy_plugin.h +++ b/pcbnew/legacy_plugin.h @@ -261,7 +261,7 @@ protected: void savePCB_TEXT( const TEXTE_PCB* aText ) const; void savePCB_TARGET( const PCB_TARGET* aTarget ) const; void savePCB_LINE( const DRAWSEGMENT* aStroke ) const; - void saveDIMENTION( const DIMENSION* aDimension ) const; + void saveDIMENSION( const DIMENSION* aDimension ) const; void saveTRACK( const TRACK* aTrack ) const; /** diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 11aa831c27..b95b8529fe 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -315,7 +315,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() AddMenuItem( viewMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) ); text = AddHotkeyName( _( "&Fit on Screen" ), g_Pcbnew_Editor_Hokeys_Descr, - HK_ZOOM_AUTO ); + HK_ZOOM_AUTO, IS_ACCELERATOR ); AddMenuItem( viewMenu, ID_ZOOM_PAGE, text, HELP_ZOOM_FIT, KiBitmap( zoom_fit_in_page_xpm ) ); diff --git a/pcbnew/muonde.cpp b/pcbnew/muonde.cpp index f943b13c42..ba2be9e2b4 100644 --- a/pcbnew/muonde.cpp +++ b/pcbnew/muonde.cpp @@ -215,7 +215,7 @@ MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) } // Calculate the elements. - Mself.m_Width = GetBoard()->GetCurrentTrackWidth(); + Mself.m_Width = GetDesignSettings().GetCurrentTrackWidth(); std::vector buffer; ll = BuildCornersList_S_Shape( buffer, Mself.m_Start, Mself.m_End, Mself.lng, Mself.m_Width ); @@ -561,7 +561,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWaveBasicShape( const wxString& name, int pad_c module->Pads().PushFront( pad ); - int tw = GetBoard()->GetCurrentTrackWidth(); + int tw = GetDesignSettings().GetCurrentTrackWidth(); pad->SetSize( wxSize( tw, tw ) ); pad->SetPosition( module->GetPosition() ); @@ -588,7 +588,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWaveComponent( int shape_type ) int angle = 0; // Enter the size of the gap or stub - int gap_size = GetBoard()->GetCurrentTrackWidth(); + int gap_size = GetDesignSettings().GetCurrentTrackWidth(); switch( shape_type ) { @@ -1104,7 +1104,7 @@ void PCB_EDIT_FRAME::Edit_Gap( wxDC* DC, MODULE* aModule ) gap_size = ValueFromString( g_UserUnit, msg ); // Updating sizes of pads forming the gap. - int tw = GetBoard()->GetCurrentTrackWidth(); + int tw = GetDesignSettings().GetCurrentTrackWidth(); pad->SetSize( wxSize( tw, tw ) ); pad->SetY0( 0 ); @@ -1118,7 +1118,7 @@ void PCB_EDIT_FRAME::Edit_Gap( wxDC* DC, MODULE* aModule ) pad->SetPosition( padpos ); - tw = GetBoard()->GetCurrentTrackWidth(); + tw = GetDesignSettings().GetCurrentTrackWidth(); next_pad->SetSize( wxSize( tw, tw ) ); next_pad->SetY0( 0 ); diff --git a/pcbnew/onleftclick.cpp b/pcbnew/onleftclick.cpp index dc5b0b97ee..922d04e727 100644 --- a/pcbnew/onleftclick.cpp +++ b/pcbnew/onleftclick.cpp @@ -161,7 +161,7 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) case PCB_TRACE_T: case PCB_VIA_T: case PCB_PAD_T: - GetBoard()->SetCurrentNetClass( + GetDesignSettings().SetCurrentNetClass( ((BOARD_CONNECTED_ITEM*)DrawStruct)->GetNetClassName() ); updateTraceWidthSelectBox(); updateViaSizeSelectBox(); diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index 372538c1b1..ffb14ac90a 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -464,7 +464,7 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) wxPoint cursorPosition = GetCrossHairPosition(); wxString msg; - GetBoard()->SetCurrentNetClass( Track->GetNetClassName() ); + GetDesignSettings().SetCurrentNetClass( Track->GetNetClassName() ); updateTraceWidthSelectBox(); updateViaSizeSelectBox(); @@ -532,7 +532,7 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) AddMenuItem( PopMenu, ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA, msg, KiBitmap( select_w_layer_xpm ) ); - if( GetBoard()->GetDesignSettings().m_BlindBuriedViaAllowed ) + if( GetDesignSettings().m_BlindBuriedViaAllowed ) { msg = AddHotkeyName( _( "Place Blind/Buried Via" ), g_Board_Editor_Hokeys_Descr, HK_ADD_BLIND_BURIED_VIA ); @@ -834,9 +834,9 @@ void PCB_EDIT_FRAME::createPopUpMenuForFpPads( D_PAD* Pad, wxMenu* menu ) if( flags ) // Currently in edit, no others commands possible return; - if( GetBoard()->GetCurrentNetClassName() != Pad->GetNetClassName() ) + if( GetDesignSettings().GetCurrentNetClassName() != Pad->GetNetClassName() ) { - GetBoard()->SetCurrentNetClass( Pad->GetNetClassName() ); + GetDesignSettings().SetCurrentNetClass( Pad->GetNetClassName() ); updateTraceWidthSelectBox(); updateViaSizeSelectBox(); } @@ -957,17 +957,17 @@ static wxMenu* Append_Track_Width_List( BOARD* aBoard ) if( aBoard->GetDesignSettings().m_UseConnectedTrackWidth ) trackwidth_menu->Check( ID_POPUP_PCB_SELECT_AUTO_WIDTH, true ); - if( aBoard->GetViaSizeIndex() != 0 - || aBoard->GetTrackWidthIndex() != 0 + if( aBoard->GetDesignSettings().GetViaSizeIndex() != 0 + || aBoard->GetDesignSettings().GetTrackWidthIndex() != 0 || aBoard->GetDesignSettings().m_UseConnectedTrackWidth ) trackwidth_menu->Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Netclass Values" ), _( "Use track and via sizes from their Netclass values" ), true ); - for( unsigned ii = 0; ii < aBoard->m_TrackWidthList.size(); ii++ ) + for( unsigned ii = 0; ii < aBoard->GetDesignSettings().m_TrackWidthList.size(); ii++ ) { - value = StringFromValue( g_UserUnit, aBoard->m_TrackWidthList[ii], true ); + value = StringFromValue( g_UserUnit, aBoard->GetDesignSettings().m_TrackWidthList[ii], true ); msg.Printf( _( "Track %s" ), GetChars( value ) ); if( ii == 0 ) @@ -978,15 +978,16 @@ static wxMenu* Append_Track_Width_List( BOARD* aBoard ) trackwidth_menu->AppendSeparator(); - for( unsigned ii = 0; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) + for( unsigned ii = 0; ii < aBoard->GetDesignSettings().m_ViasDimensionsList.size(); ii++ ) { - value = StringFromValue( g_UserUnit, aBoard->m_ViasDimensionsList[ii].m_Diameter, - true ); + value = StringFromValue( g_UserUnit, + aBoard->GetDesignSettings().m_ViasDimensionsList[ii].m_Diameter, + true ); wxString drill = StringFromValue( g_UserUnit, - aBoard->m_ViasDimensionsList[ii].m_Drill, - true ); + aBoard->GetDesignSettings().m_ViasDimensionsList[ii].m_Drill, + true ); - if( aBoard->m_ViasDimensionsList[ii].m_Drill <= 0 ) + if( aBoard->GetDesignSettings().m_ViasDimensionsList[ii].m_Drill <= 0 ) { msg.Printf( _( "Via %s" ), GetChars( value ) ); } diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 0465f450aa..7b72b47497 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -43,6 +43,8 @@ using namespace KIGFX; PCB_RENDER_SETTINGS::PCB_RENDER_SETTINGS() { + m_backgroundColor = COLOR4D( 0.0, 0.0, 0.0, 1.0 ); + // By default everything should be displayed as filled for( unsigned int i = 0; i < END_PCB_VISIBLE_LIST; ++i ) { diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index bfa1ea337d..547120fa9b 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -808,7 +808,9 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) ); T token; - NETCLASS* defaultNetclass = m_board->m_NetClasses.GetDefault(); + NETCLASS* defaultNetClass = m_board->GetDesignSettings().GetDefault(); + // TODO Orson: is it really necessary to first operate on a copy and then apply it? + // would not it be better to use reference here and apply all the changes instantly? BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings(); ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings(); @@ -827,12 +829,12 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) break; case T_user_trace_width: - m_board->m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) ); + designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) ); NeedRIGHT(); break; case T_trace_clearance: - defaultNetclass->SetClearance( parseBoardUnits( T_trace_clearance ) ); + defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) ); NeedRIGHT(); break; @@ -862,12 +864,12 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) break; case T_via_size: - defaultNetclass->SetViaDiameter( parseBoardUnits( T_via_size ) ); + defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) ); NeedRIGHT(); break; case T_via_drill: - defaultNetclass->SetViaDrill( parseBoardUnits( T_via_drill ) ); + defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) ); NeedRIGHT(); break; @@ -885,18 +887,18 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) { int viaSize = parseBoardUnits( "user via size" ); int viaDrill = parseBoardUnits( "user via drill" ); - m_board->m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) ); + designSettings.m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) ); NeedRIGHT(); } break; case T_uvia_size: - defaultNetclass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) ); + defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) ); NeedRIGHT(); break; case T_uvia_drill: - defaultNetclass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); + defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) ); NeedRIGHT(); break; @@ -1046,7 +1048,7 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) // at all, the global defaults should go into a preferences // file instead so they are there to start new board // projects. - m_board->m_NetClasses.GetDefault()->SetParams(); + defaultNetClass->SetParams( m_board->GetDesignSettings() ); } @@ -1080,7 +1082,7 @@ void PCB_PARSER::parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ) T token; - std::auto_ptr nc( new NETCLASS( m_board, wxEmptyString ) ); + std::auto_ptr nc( new NETCLASS( wxEmptyString ) ); // Read netclass name (can be a name or just a number like track width) NeedSYMBOLorNUMBER(); @@ -1133,7 +1135,7 @@ void PCB_PARSER::parseNETCLASS() throw( IO_ERROR, PARSE_ERROR ) NeedRIGHT(); } - if( m_board->m_NetClasses.Add( nc.get() ) ) + if( m_board->GetDesignSettings().m_NetClasses.Add( nc.get() ) ) { nc.release(); } diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 3ed5d2583a..e8d4232b40 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -275,6 +275,8 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_UPDATE_UI( ID_AUX_TOOLBAR_PCB_SELECT_AUTO_WIDTH, PCB_EDIT_FRAME::OnUpdateSelectAutoTrackWidth ) EVT_UPDATE_UI( ID_POPUP_PCB_SELECT_AUTO_WIDTH, PCB_EDIT_FRAME::OnUpdateSelectAutoTrackWidth ) + EVT_UPDATE_UI( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, + PCB_EDIT_FRAME::OnUpdateSelectCustomTrackWidth ) EVT_UPDATE_UI( ID_AUX_TOOLBAR_PCB_VIA_SIZE, PCB_EDIT_FRAME::OnUpdateSelectViaSize ) EVT_UPDATE_UI( ID_TOOLBARH_PCB_MODE_MODULE, PCB_EDIT_FRAME::OnUpdateAutoPlaceModulesMode ) EVT_UPDATE_UI( ID_TOOLBARH_PCB_MODE_TRACKS, PCB_EDIT_FRAME::OnUpdateAutoPlaceTracksMode ) @@ -493,9 +495,9 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard ) ViewReloadBoard( aBoard ); // update the tool manager with the new board and its view. - m_toolManager.SetEnvironment( aBoard, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - m_toolManager.ResetTools( TOOL_BASE::MODEL_RELOAD ); + m_toolManager->SetEnvironment( aBoard, GetGalCanvas()->GetView(), + GetGalCanvas()->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); } } @@ -544,6 +546,7 @@ void PCB_EDIT_FRAME::ViewReloadBoard( const BOARD* aBoard ) const view->Add( worksheet ); view->Add( aBoard->GetRatsnestViewItem() ); + aBoard->GetRatsnest()->Recalculate(); // Limit panning to the size of worksheet frame GetGalCanvas()->GetViewControls()->SetPanBoundary( aBoard->GetWorksheetViewItem()->ViewBBox() ); @@ -588,7 +591,6 @@ void PCB_EDIT_FRAME::OnQuit( wxCommandEvent& event ) void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) { m_canvas->SetAbortRequest( true ); - GetGalCanvas()->StopDrawing(); if( GetScreen()->IsModify() ) { @@ -612,6 +614,8 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) } } + GetGalCanvas()->StopDrawing(); + // Delete the auto save file if it exists. wxFileName fn = GetBoard()->GetFileName(); @@ -672,13 +676,13 @@ void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) if( aEnable ) { ViewReloadBoard( m_Pcb ); + GetGalCanvas()->GetView()->RecacheAllItems(); - // Update potential changes in the ratsnest - m_Pcb->GetRatsnest()->Recalculate(); - - m_toolManager.SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), + m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), GetGalCanvas()->GetViewControls(), this ); - m_toolManager.ResetTools( TOOL_BASE::GAL_SWITCH ); + m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); + + GetGalCanvas()->StartDrawing(); } } diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index 0ceb7ccde8..785c92417f 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -170,6 +170,7 @@ enum pcbnew_ids ID_AUX_TOOLBAR_PCB_SELECT_AUTO_WIDTH, ID_POPUP_PCB_SELECT_WIDTH_START_RANGE, ID_POPUP_PCB_SELECT_WIDTH, + ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, ID_POPUP_PCB_SELECT_AUTO_WIDTH, ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, ID_POPUP_PCB_SELECT_WIDTH1, diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index ffe88c3c7f..1f40f8ed26 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -60,6 +60,7 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const aGal->SetLineWidth( 1.0 ); RENDER_SETTINGS* rs = m_view->GetPainter()->GetSettings(); COLOR4D color = rs->GetColor( NULL, ITEM_GAL_LAYER( RATSNEST_VISIBLE ) ); + int highlightedNet = rs->GetHighlightNetCode(); for( int i = 1; i < m_data->GetNetCount(); ++i ) { @@ -89,7 +90,8 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const } // Draw the "static" ratsnest - aGal->SetStrokeColor( color ); // using the default ratsnest color + if( i != highlightedNet ) + aGal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted const std::vector* edges = net.GetUnconnected(); if( edges == NULL ) diff --git a/pcbnew/router/CMakeLists.txt b/pcbnew/router/CMakeLists.txt index 329714658b..411216441f 100644 --- a/pcbnew/router/CMakeLists.txt +++ b/pcbnew/router/CMakeLists.txt @@ -10,41 +10,26 @@ include_directories( ) set( PCBNEW_PNS_SRCS - direction.h - pns_via.h - pns_routing_settings.h - pns_shove.cpp - pns_line.cpp - pns_utils.h - pns_layerset.h - trace.h - pns_line.h - pns_walkaround.cpp - pns_node.h - pns_line_placer.cpp - pns_utils.cpp - pns_solid.h + time_limit.cpp + + pns_algo_base.cpp + pns_dragger.cpp pns_item.cpp - pns_via.cpp - pns_node.cpp - pns_solid.cpp - pns_line_placer.h - pns_optimizer.h - pns_walkaround.h - pns_shove.h - pns_router.h - pns_router.cpp - pns_index.h - pns_item.h - pns_optimizer.cpp - pns_joint.h - pns_segment.h - pns_itemset.h pns_itemset.cpp - router_tool.cpp - router_tool.h + pns_line.cpp + pns_line_placer.cpp + pns_logger.cpp + pns_node.cpp + pns_optimizer.cpp + pns_router.cpp + pns_routing_settings.cpp + pns_shove.cpp + pns_solid.cpp + pns_utils.cpp + pns_via.cpp + pns_walkaround.cpp router_preview_item.cpp - router_preview_item.h + router_tool.cpp ) add_library( pnsrouter STATIC ${PCBNEW_PNS_SRCS} ) diff --git a/pcbnew/router/direction.h b/pcbnew/router/direction.h index ad38fcbdef..cd872fccb5 100644 --- a/pcbnew/router/direction.h +++ b/pcbnew/router/direction.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -180,6 +180,11 @@ public: return ( m_dir % 2 ) == 1; } + bool IsDefined() const + { + return m_dir != UNDEFINED; + } + /** * Function BuildInitialTrace() * @@ -204,12 +209,12 @@ public: // we are more horizontal than vertical? if( w > h ) { - mp0 = VECTOR2I( (w - h) * sw, 0 ); // direction: E + mp0 = VECTOR2I( ( w - h ) * sw, 0 ); // direction: E mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE } else { - mp0 = VECTOR2I( 0, sh * (h - w) ); // direction: N + mp0 = VECTOR2I( 0, sh * ( h - w ) ); // direction: N mp1 = VECTOR2I( sw * w, sh * w ); // direction: NE } @@ -232,7 +237,7 @@ public: pl.Append( aP1 ); pl.Simplify(); return pl; - }; + } bool operator==( const DIRECTION_45& aOther ) const { @@ -244,32 +249,73 @@ public: return aOther.m_dir != m_dir; } + /** + * Function Right() + * + * Returns the direction on the right side of this (i.e. turns right + * by 45 deg) + */ const DIRECTION_45 Right() const { DIRECTION_45 r; - r.m_dir = (Directions) (m_dir + 1); - - if( r.m_dir == NW ) - r.m_dir = N; + if ( m_dir != UNDEFINED ) + r.m_dir = static_cast( ( m_dir + 1 ) % 8 ); return r; } -private: - - template - int sign( T val ) const + /** + * Function Left() + * + * Returns the direction on the left side of this (i.e. turns left + * by 45 deg) + */ + const DIRECTION_45 Left() const { - return (T( 0 ) < val) - ( val < T( 0 ) ); + DIRECTION_45 l; + + if ( m_dir == UNDEFINED ) + return l; + + if( m_dir == N ) + l.m_dir = NW; + else + l.m_dir = static_cast( m_dir - 1 ); + + return l; } + /** + * Function ToVector() + * + * Returns a unit vector corresponding to our direction. + */ + const VECTOR2I ToVector() const + { + switch( m_dir ) + { + case N: return VECTOR2I( 0, 1 ); + case S: return VECTOR2I( 0, -1 ); + case E: return VECTOR2I( 1, 0 ); + case W: return VECTOR2I( -1, 0 ); + case NE: return VECTOR2I( 1, 1 ); + case NW: return VECTOR2I( -1, 1 ); + case SE: return VECTOR2I( 1, -1 ); + case SW: return VECTOR2I( -1, -1 ); + + default: + return VECTOR2I( 0, 0 ); + } + } + +private: + /** * Function construct() * Calculates the direction from a vector. If the vector's angle is not a multiple of 45 * degrees, the direction is rounded to the nearest octant. - * @param aVec our vector - */ + * @param aVec our vector */ void construct( const VECTOR2I& aVec ) { m_dir = UNDEFINED; @@ -321,8 +367,9 @@ private: m_dir = S; } } - - Directions m_dir; ///> our actual direction + + ///> our actual direction + Directions m_dir; }; #endif // __DIRECTION_H diff --git a/pcbnew/router/pns_algo_base.cpp b/pcbnew/router/pns_algo_base.cpp new file mode 100644 index 0000000000..7008665428 --- /dev/null +++ b/pcbnew/router/pns_algo_base.cpp @@ -0,0 +1,32 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#include "pns_algo_base.h" +#include "pns_router.h" + +PNS_ROUTING_SETTINGS& PNS_ALGO_BASE::Settings() const +{ + return m_router->Settings(); +} + +PNS_LOGGER *PNS_ALGO_BASE::Logger() +{ + return NULL; +} \ No newline at end of file diff --git a/pcbnew/router/pns_algo_base.h b/pcbnew/router/pns_algo_base.h new file mode 100644 index 0000000000..1aa94333fc --- /dev/null +++ b/pcbnew/router/pns_algo_base.h @@ -0,0 +1,61 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#ifndef __PNS_ALGO_BASE_H +#define __PNS_ALGO_BASE_H + +#include "pns_routing_settings.h" + +class PNS_ROUTER; +class PNS_LOGGER; + +/** + * Class PNS_ALGO_BASE + * + * Base class for all P&S algorithms (shoving, walkaround, line placement, dragging, etc.) + * Holds a bunch of objects commonly used by all algorithms (P&S settings, parent router instance, logging) + **/ + +class PNS_ALGO_BASE +{ +public: + PNS_ALGO_BASE( PNS_ROUTER *aRouter ) : + m_router ( aRouter ) + {} + + virtual ~PNS_ALGO_BASE() {} + + ///> Returns the instance of our router + PNS_ROUTER* Router() const + { + return m_router; + } + + ///> Returns current router settings + PNS_ROUTING_SETTINGS& Settings() const; + + ///> Returns the logger object, allowing to dump geometry to a file. + virtual PNS_LOGGER* Logger(); + +private: + PNS_ROUTER* m_router; +}; + +#endif diff --git a/pcbnew/router/pns_dragger.cpp b/pcbnew/router/pns_dragger.cpp new file mode 100644 index 0000000000..bc43858d95 --- /dev/null +++ b/pcbnew/router/pns_dragger.cpp @@ -0,0 +1,319 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#include + +#include "pns_dragger.h" +#include "pns_shove.h" +#include "pns_router.h" + +PNS_DRAGGER::PNS_DRAGGER( PNS_ROUTER* aRouter ) : + PNS_ALGO_BASE ( aRouter ) +{ + m_world = NULL; + m_shove = NULL; +} + + +PNS_DRAGGER::~PNS_DRAGGER() +{ + if( m_shove ) + delete m_shove; +} + + +void PNS_DRAGGER::SetWorld ( PNS_NODE* aWorld ) +{ + m_world = aWorld; +} + + +bool PNS_DRAGGER::startDragSegment( const VECTOR2D& aP, PNS_SEGMENT* aSeg ) +{ + int w2 = aSeg->Width() / 2; + + m_draggedLine = m_world->AssembleLine ( aSeg, &m_draggedSegmentIndex ); + m_shove->SetInitialLine( m_draggedLine ); + m_lastValidDraggedLine = *m_draggedLine; + m_lastValidDraggedLine.ClearSegmentLinks(); + + if( ( aP - aSeg->Seg().A ).EuclideanNorm() <= w2 ) + m_mode = CORNER; + else if( ( aP - aSeg->Seg().B ).EuclideanNorm() <= w2 ) + { + m_draggedSegmentIndex ++; + m_mode = CORNER; + } else + m_mode = SEGMENT; + + return true; +} + + +bool PNS_DRAGGER::startDragVia( const VECTOR2D& aP, PNS_VIA* aVia ) +{ + m_draggedVia = aVia; + m_initialVia = aVia; + m_mode = VIA; + + VECTOR2I p0( aVia->Pos() ); + PNS_JOINT *jt = m_world->FindJoint( p0, aVia->Layers().Start(), aVia->Net() ); + + BOOST_FOREACH(PNS_ITEM *item, jt->LinkList() ) + { + if( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + int segIndex; + PNS_SEGMENT* seg = (PNS_SEGMENT*) item; + std::auto_ptr l( m_world->AssembleLine( seg, &segIndex ) ); + + if( segIndex != 0 ) + l->Reverse(); + + m_origViaConnections.push_back( *l ); + } + } + + return true; +} + + +bool PNS_DRAGGER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + m_shove = new PNS_SHOVE( m_world, Router() ); + m_lastNode = NULL; + m_draggedItems.Clear(); + m_currentMode = Settings().Mode(); + + TRACE( 2, "StartDragging: item %p [kind %d]", aStartItem % aStartItem->Kind() ); + + switch( aStartItem->Kind() ) + { + case PNS_ITEM::SEGMENT: + return startDragSegment ( aP, static_cast( aStartItem ) ); + + case PNS_ITEM::VIA: + return startDragVia ( aP, static_cast (aStartItem) ); + + default: + return false; + } +} + + +bool PNS_DRAGGER::dragMarkObstacles( const VECTOR2I& aP ) +{ + if( m_lastNode ) + { + delete m_lastNode; + m_lastNode = NULL; + } + + switch( m_mode ) + { + case SEGMENT: + case CORNER: + { + int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine->Width() / 4 : 0; + PNS_LINE tmp( *m_draggedLine ); + + if( m_mode == SEGMENT ) + tmp.DragSegment ( aP, m_draggedSegmentIndex, thresh ); + else + tmp.DragCorner ( aP, m_draggedSegmentIndex, thresh ); + + m_lastNode = m_shove->CurrentNode()->Branch(); + + m_lastValidDraggedLine = tmp; + m_lastValidDraggedLine.ClearSegmentLinks(); + m_lastValidDraggedLine.Unmark(); + + m_lastNode->Add ( &m_lastValidDraggedLine ); + m_draggedItems = PNS_ITEMSET ( &m_lastValidDraggedLine ); + + break; + } + + case VIA: // fixme... + { + m_lastNode = m_shove->CurrentNode()->Branch(); + dumbDragVia ( m_initialVia, m_lastNode, aP ); + + break; + } + } + + if( Settings().CanViolateDRC() ) + m_dragStatus = true; + else + m_dragStatus = !m_world->CheckColliding( m_draggedItems ); + + return true; +} + + +void PNS_DRAGGER::dumbDragVia( PNS_VIA* aVia, PNS_NODE* aNode, const VECTOR2I& aP ) +{ + // fixme: this is awful. + m_draggedVia = aVia->Clone(); + m_draggedVia->SetPos( aP ); + m_draggedItems.Clear(); + m_draggedItems.Add( m_draggedVia ); + + m_lastNode->Remove( aVia ); + m_lastNode->Add( m_draggedVia ); + + BOOST_FOREACH( PNS_LINE &l, m_origViaConnections ) + { + PNS_LINE origLine (l); + PNS_LINE* draggedLine = l.Clone(); + + draggedLine->DragCorner( aP, 0 ); + draggedLine->ClearSegmentLinks(); + + m_draggedItems.AddOwned( draggedLine ); + + m_lastNode->Remove( &origLine ); + m_lastNode->Add( draggedLine ); + } +} + + +bool PNS_DRAGGER::dragShove( const VECTOR2I& aP ) +{ + bool ok = false; + + if( m_lastNode ) + { + delete m_lastNode; + m_lastNode = NULL; + } + + switch( m_mode ) + { + case SEGMENT: + case CORNER: + { + int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine->Width() / 4 : 0; + PNS_LINE tmp( *m_draggedLine ); + + if( m_mode == SEGMENT ) + tmp.DragSegment( aP, m_draggedSegmentIndex, thresh ); + else + tmp.DragCorner( aP, m_draggedSegmentIndex, thresh ); + + PNS_SHOVE::SHOVE_STATUS st = m_shove->ShoveLines( tmp ); + + if( st == PNS_SHOVE::SH_OK ) + ok = true; + else if( st == PNS_SHOVE::SH_HEAD_MODIFIED ) + { + tmp = m_shove->NewHead(); + ok = true; + } + + m_lastNode = m_shove->CurrentNode()->Branch(); + + if( ok ) + m_lastValidDraggedLine = tmp; + + m_lastValidDraggedLine.ClearSegmentLinks(); + m_lastValidDraggedLine.Unmark(); + m_lastNode->Add( &m_lastValidDraggedLine ); + m_draggedItems = PNS_ITEMSET( &m_lastValidDraggedLine ); + + break; + } + + case VIA: + { + PNS_VIA *newVia; + PNS_SHOVE::SHOVE_STATUS st = m_shove->ShoveDraggingVia( m_draggedVia, aP, &newVia ); + + if( st == PNS_SHOVE::SH_OK || st == PNS_SHOVE::SH_HEAD_MODIFIED ) + ok = true; + + m_lastNode = m_shove->CurrentNode()->Branch(); + + if( ok ) + { + m_draggedVia = newVia; + m_draggedItems.Clear(); + } + + break; + } + } + + m_dragStatus = ok; + + return ok; +} + + +bool PNS_DRAGGER::FixRoute() +{ + if( m_dragStatus ) + { + Router()->CommitRouting( CurrentNode() ); + return true; + } + + return false; +} + + +bool PNS_DRAGGER::Drag( const VECTOR2I& aP ) +{ + switch( m_currentMode ) + { + case RM_MarkObstacles: + return dragMarkObstacles( aP ); + + case RM_Shove: + case RM_Walkaround: + case RM_Smart: + return dragShove( aP ); + + default: + return false; + } +} + + +PNS_NODE *PNS_DRAGGER::CurrentNode() const +{ + return m_lastNode; +} + + +const PNS_ITEMSET PNS_DRAGGER::Traces() +{ + return m_draggedItems; +} + + +PNS_LOGGER* PNS_DRAGGER::Logger() +{ + if( m_shove ) + return m_shove->Logger(); + + return NULL; +} diff --git a/pcbnew/router/pns_dragger.h b/pcbnew/router/pns_dragger.h new file mode 100644 index 0000000000..171b8ac79e --- /dev/null +++ b/pcbnew/router/pns_dragger.h @@ -0,0 +1,130 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#ifndef __PNS_DRAGGER_H +#define __PNS_DRAGGER_H + +#include + +#include "pns_node.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_algo_base.h" +#include "pns_itemset.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; + +/** + * Class PNS_DRAGGER + * + * Via, segment and corner dragging algorithm. + */ +class PNS_DRAGGER : public PNS_ALGO_BASE +{ +public: + PNS_DRAGGER( PNS_ROUTER* aRouter ); + ~PNS_DRAGGER(); + + /** + * Function SetWorld() + * + * Sets the board to work on. + */ + void SetWorld( PNS_NODE* aWorld ); + + /** + * Function Start() + * + * Starts routing a single track at point aP, taking item aStartItem as anchor + * (unless NULL). Returns true if a dragging operation has started. + */ + bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + + /** + * Function Drag() + * + * Drags the current segment/corner/via to the point aP. + * @return true, if dragging finished with success. + */ + bool Drag( const VECTOR2I& aP ); + + /** + * Function FixRoute() + * + * Checks if the result of current dragging operation is correct + * and eventually commits it to the world. + * @return true, if dragging finished with success. + */ + bool FixRoute(); + + /** + * Function CurrentNode() + * + * Returns the most recent world state, including all + * items changed due to dragging operation. + */ + PNS_NODE* CurrentNode() const; + + /** + * Function Traces() + * + * Returns the set of dragged items. + */ + const PNS_ITEMSET Traces(); + + /// @copydoc PNS_ALGO_BASE::Logger() + virtual PNS_LOGGER* Logger(); + +private: + typedef std::pair LinePair; + typedef std::vector LinePairVec; + + enum DragMode { + CORNER = 0, + SEGMENT, + VIA + }; + + bool dragMarkObstacles( const VECTOR2I& aP ); + bool dragShove(const VECTOR2I& aP ); + bool startDragSegment( const VECTOR2D& aP, PNS_SEGMENT* aSeg ); + bool startDragVia( const VECTOR2D& aP, PNS_VIA* aVia ); + void dumbDragVia( PNS_VIA* aVia, PNS_NODE* aNode, const VECTOR2I& aP ); + + PNS_NODE* m_world; + PNS_NODE* m_lastNode; + DragMode m_mode; + PNS_LINE* m_draggedLine; + PNS_VIA* m_draggedVia; + PNS_LINE m_lastValidDraggedLine; + PNS_SHOVE* m_shove; + int m_draggedSegmentIndex; + bool m_dragStatus; + PNS_MODE m_currentMode; + std::vector m_origViaConnections; + std::vector m_draggedViaConnections; + PNS_VIA* m_initialVia; + PNS_ITEMSET m_draggedItems; +}; + +#endif diff --git a/pcbnew/router/pns_index.h b/pcbnew/router/pns_index.h index 05d612e597..edb58b33e4 100644 --- a/pcbnew/router/pns_index.h +++ b/pcbnew/router/pns_index.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,12 +15,15 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_INDEX_H #define __PNS_INDEX_H +#include +#include + #include #include @@ -33,77 +36,138 @@ * Class PNS_INDEX * * Custom spatial index, holding our board items and allowing for very fast searches. Items - * are assigned to separate R-Tree subundices depending on their type and spanned layers, reducing + * are assigned to separate R-Tree subindices depending on their type and spanned layers, reducing * overlap and improving search time. **/ - class PNS_INDEX { public: - typedef std::list NetItemsList; - typedef SHAPE_INDEX ItemShapeIndex; - typedef boost::unordered_set ItemSet; + typedef std::list NET_ITEMS_LIST; + typedef SHAPE_INDEX ITEM_SHAPE_INDEX; + typedef boost::unordered_set ITEM_SET; PNS_INDEX(); ~PNS_INDEX(); + /** + * Function Add() + * + * Adds item to the spatial index. + */ void Add( PNS_ITEM* aItem ); + + /** + * Function Remove() + * + * Removes an item from the spatial index. + */ void Remove( PNS_ITEM* aItem ); + + /** + * Function Add() + * + * Replaces one item with another. + */ void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); + /** + * Function Query() + * + * Searches items in the index that are in proximity of aItem. + * For each item, function object aVisitor is called. Only items on + * overlapping layers are considered. + * + * @param aItem item to search against + * @param aMinDistance proximity distance (wrs to the item's shape) + * @param aVisitor function object called on each found item. Return + false from the visitor to stop searching. + * @return number of items found. + */ template - int Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ); + int Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& aVisitor ); + /** + * Function Query() + * + * Searches items in the index that are in proximity of aShape. + * For each item, function object aVisitor is called. Treats all + * layers as colliding. + * + * @param aShape shape to search against + * @param aMinDistance proximity distance (wrs to the item's shape) + * @param aVisitor function object called on each found item. Return + false from the visitor to stop searching. + * @return number of items found. + */ template - int Query( const SHAPE* aShape, int aMinDistance, Visitor& v ); + int Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ); + /** + * Function Clear() + * + * Removes all items from the index. + */ void Clear(); - NetItemsList* GetItemsForNet( int aNet ); - - ItemSet::iterator begin() { return m_allItems.begin(); } - ItemSet::iterator end() { return m_allItems.end(); } - + /** + * Function GetItemsForNet() + * + * Returns list of all items in a given net. + */ + NET_ITEMS_LIST* GetItemsForNet( int aNet ); + + /** + * Function Contains() + * + * Returns true if item aItem exists in the index. + */ bool Contains( PNS_ITEM* aItem ) const { return m_allItems.find( aItem ) != m_allItems.end(); } + /** + * Function Size() + * + * Returns number of items stored in the index. + */ int Size() const { return m_allItems.size(); } + ITEM_SET::iterator begin() { return m_allItems.begin(); } + ITEM_SET::iterator end() { return m_allItems.end(); } + private: static const int MaxSubIndices = 64; static const int SI_Multilayer = 2; static const int SI_SegDiagonal = 0; static const int SI_SegStraight = 1; - static const int SI_Traces = 3; - static const int SI_PadsTop = 0; - static const int SI_PadsBottom = 1; + static const int SI_Traces = 3; + static const int SI_PadsTop = 0; + static const int SI_PadsBottom = 1; template - int querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ); + int querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ); - ItemShapeIndex* getSubindex( const PNS_ITEM* aItem ); + ITEM_SHAPE_INDEX* getSubindex( const PNS_ITEM* aItem ); - ItemShapeIndex* m_subIndices[MaxSubIndices]; - std::map m_netMap; - ItemSet m_allItems; + ITEM_SHAPE_INDEX* m_subIndices[MaxSubIndices]; + std::map m_netMap; + ITEM_SET m_allItems; }; - PNS_INDEX::PNS_INDEX() { memset( m_subIndices, 0, sizeof( m_subIndices ) ); } -PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) +PNS_INDEX::ITEM_SHAPE_INDEX* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) { int idx_n = -1; - const PNS_LAYERSET l = aItem->GetLayers(); + const PNS_LAYERSET l = aItem->Layers(); - switch( aItem->GetKind() ) + switch( aItem->Kind() ) { case PNS_ITEM::VIA: idx_n = SI_Multilayer; @@ -113,9 +177,9 @@ PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) { if( l.IsMultilayer() ) idx_n = SI_Multilayer; - else if( l.Start() == 0 ) // fixme: use kicad layer codes + else if( l.Start() == LAYER_N_BACK) // fixme: use kicad layer codes idx_n = SI_PadsTop; - else if( l.Start() == 15 ) + else if( l.Start() == LAYER_N_FRONT ) idx_n = SI_PadsBottom; break; @@ -133,7 +197,7 @@ PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) assert( idx_n >= 0 && idx_n < MaxSubIndices ); if( !m_subIndices[idx_n] ) - m_subIndices[idx_n] = new ItemShapeIndex; + m_subIndices[idx_n] = new ITEM_SHAPE_INDEX; return m_subIndices[idx_n]; } @@ -141,11 +205,11 @@ PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) void PNS_INDEX::Add( PNS_ITEM* aItem ) { - ItemShapeIndex* idx = getSubindex( aItem ); + ITEM_SHAPE_INDEX* idx = getSubindex( aItem ); idx->Add( aItem ); m_allItems.insert( aItem ); - int net = aItem->GetNet(); + int net = aItem->Net(); if( net >= 0 ) { @@ -156,12 +220,12 @@ void PNS_INDEX::Add( PNS_ITEM* aItem ) void PNS_INDEX::Remove( PNS_ITEM* aItem ) { - ItemShapeIndex* idx = getSubindex( aItem ); + ITEM_SHAPE_INDEX* idx = getSubindex( aItem ); idx->Remove( aItem ); m_allItems.erase( aItem ); - int net = aItem->GetNet(); + int net = aItem->Net(); if( net >= 0 && m_netMap.find( net ) != m_netMap.end() ) m_netMap[net].remove( aItem ); @@ -176,43 +240,43 @@ void PNS_INDEX::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) template -int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ) +int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { if( !m_subIndices[index] ) return 0; - return m_subIndices[index]->Query( aShape, aMinDistance, v, false ); + return m_subIndices[index]->Query( aShape, aMinDistance, aVisitor, false ); } template -int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ) +int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& aVisitor ) { - const SHAPE* shape = aItem->GetShape(); + const SHAPE* shape = aItem->Shape(); int total = 0; - total += querySingle( SI_Multilayer, shape, aMinDistance, v ); + total += querySingle( SI_Multilayer, shape, aMinDistance, aVisitor ); - const PNS_LAYERSET layers = aItem->GetLayers(); + const PNS_LAYERSET layers = aItem->Layers(); if( layers.IsMultilayer() ) { - total += querySingle( SI_PadsTop, shape, aMinDistance, v ); - total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); + total += querySingle( SI_PadsTop, shape, aMinDistance, aVisitor ); + total += querySingle( SI_PadsBottom, shape, aMinDistance, aVisitor ); for( int i = layers.Start(); i <= layers.End(); ++i ) - total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v ); + total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, aVisitor ); } else { int l = layers.Start(); - if( l == 0 ) - total += querySingle( SI_PadsTop, shape, aMinDistance, v ); - else if( l == 15 ) - total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); + if( l == LAYER_N_BACK ) + total += querySingle( SI_PadsTop, shape, aMinDistance, aVisitor ); + else if( l == LAYER_N_FRONT ) + total += querySingle( SI_PadsBottom, shape, aMinDistance, aVisitor ); - total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v ); + total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, aVisitor ); } return total; @@ -220,12 +284,12 @@ int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ) template -int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& v ) +int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { int total = 0; for( int i = 0; i < MaxSubIndices; i++ ) - total += querySingle( i, aShape, aMinDistance, v ); + total += querySingle( i, aShape, aMinDistance, aVisitor ); return total; } @@ -235,7 +299,7 @@ void PNS_INDEX::Clear() { for( int i = 0; i < MaxSubIndices; ++i ) { - ItemShapeIndex* idx = m_subIndices[i]; + ITEM_SHAPE_INDEX* idx = m_subIndices[i]; if( idx ) delete idx; @@ -251,7 +315,7 @@ PNS_INDEX::~PNS_INDEX() } -PNS_INDEX::NetItemsList* PNS_INDEX::GetItemsForNet( int aNet ) +PNS_INDEX::NET_ITEMS_LIST* PNS_INDEX::GetItemsForNet( int aNet ) { if( m_netMap.find( aNet ) == m_netMap.end() ) return NULL; diff --git a/pcbnew/router/pns_item.cpp b/pcbnew/router/pns_item.cpp index 68e04a41c0..67fd14ad7b 100644 --- a/pcbnew/router/pns_item.cpp +++ b/pcbnew/router/pns_item.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include "pns_item.h" @@ -32,7 +32,7 @@ bool PNS_ITEM::collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeed if( !m_layers.Overlaps( aOther->m_layers ) ) return false; - return GetShape()->Collide( aOther->GetShape(), aClearance ); + return Shape()->Collide( aOther->Shape(), aClearance ); // fixme: MTV } @@ -50,15 +50,14 @@ bool PNS_ITEM::Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, const PNS_LINE* line = static_cast( aOther ); if( line->EndsWithVia() ) - return collideSimple( &line->GetVia(), aClearance - line->GetWidth() / 2, aNeedMTV, - aMTV ); + return collideSimple( &line->Via(), aClearance - line->Width() / 2, aNeedMTV, aMTV ); } return false; } -const std::string PNS_ITEM::GetKindStr() const +const std::string PNS_ITEM::KindStr() const { switch( m_kind ) { diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h index c375a7ada5..cf1e24b1c6 100644 --- a/pcbnew/router/pns_item.h +++ b/pcbnew/router/pns_item.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_ITEM_H @@ -26,18 +26,25 @@ #include #include +#include "trace.h" + #include "pns_layerset.h" class BOARD_CONNECTED_ITEM; class PNS_NODE; +enum LineMarker { + MK_HEAD = ( 1 << 0 ), + MK_VIOLATION = ( 1 << 3 ), + MK_LOCKED = ( 1 << 4 ) +}; + /** * Class PNS_ITEM * * Base class for PNS router board items. Implements the shared properties of all PCB items - * net, spanned layers, geometric shape & refererence to owning model. */ - class PNS_ITEM { public: @@ -60,8 +67,9 @@ public: m_movable = true; m_kind = aKind; m_parent = NULL; - m_world = NULL; m_owner = NULL; + m_marker = 0; + m_rank = -1; } PNS_ITEM( const PNS_ITEM& aOther ) @@ -70,61 +78,202 @@ public: m_net = aOther.m_net; m_movable = aOther.m_movable; m_kind = aOther.m_kind; - m_world = aOther.m_world; m_parent = aOther.m_parent; m_owner = NULL; + m_marker = aOther.m_marker; + m_rank = aOther.m_rank; } virtual ~PNS_ITEM(); + /** + * Function Clone() + * + * Returns a deep copy of the item + */ virtual PNS_ITEM* Clone() const = 0; - ///> Returns a convex polygon "hull" of a the item, that is used as the walkaround - /// path. - /// aClearance defines how far from the body of the item the hull should be, - /// aWalkaroundThickness is the width of the line that walks around this hull. + /* + * Function Hull() + * + * Returns a convex polygon "hull" of a the item, that is used as the walk-around + * path. + * @param aClearance defines how far from the body of the item the hull should be, + * @param aWalkaroundThickness is the width of the line that walks around this hull. + */ virtual const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const { return SHAPE_LINE_CHAIN(); - }; + } - PnsKind GetKind() const { return m_kind; } - bool OfKind( int aKind ) const { return (aKind & m_kind) != 0; } + /** + * Function Kind() + * + * Returns the type (kind) of the item + */ + PnsKind Kind() const + { + return m_kind; + } + + /** + * Function OfKind() + * + * Returns true if the item's type matches the mask aKindMask. + */ + bool OfKind( int aKindMask ) const + { + return ( aKindMask & m_kind ) != 0; + } - const std::string GetKindStr() const; + /** + * Function KindStr() + * + * Returns the kind of the item, as string + */ + const std::string KindStr() const; - ///> Gets/Sets the corresponding parent object in the host application's model (pcbnew) - void SetParent( BOARD_CONNECTED_ITEM* aParent ) { m_parent = aParent; } - BOARD_CONNECTED_ITEM* GetParent() const { return m_parent; } + /** + * Function SetParent() + * + * Sets the corresponding parent object in the host application's model. + */ + void SetParent( BOARD_CONNECTED_ITEM* aParent ) + { + m_parent = aParent; + } + + /** + * Function Parent() + * + * Returns the corresponding parent object in the host application's model. + */ + BOARD_CONNECTED_ITEM* Parent() const + { + return m_parent; + } - ///> Net accessors - int GetNet() const { return m_net; } - void SetNet( int aNet ) { m_net = aNet; } + /** + * Function SetNet() + * + * Sets the item's net to aNet + */ + void SetNet( int aNet ) + { + m_net = aNet; + } - ///> Layers accessors - const PNS_LAYERSET& GetLayers() const { return m_layers; } - void SetLayers( const PNS_LAYERSET& aLayers ) { m_layers = aLayers; } + /** + * Function Net() + * + * Returns the item's net. + */ + int Net() const + { + return m_net; + } + + /** + * Function SetLayers() + * + * Sets the layers spanned by the item to aLayers. + */ + void SetLayers( const PNS_LAYERSET& aLayers ) + { + m_layers = aLayers; + } + + /** + * Function SetLayer() + * + * Sets the layers spanned by the item to a single layer aLayer. + */ void SetLayer( int aLayer ) { m_layers = PNS_LAYERSET( aLayer, aLayer ); } - ///> Ownership management. An item can belong to a single PNS_NODE or stay unowned. - void SetOwner( PNS_NODE* aOwner ) { m_owner = aOwner; } - bool BelongsTo( PNS_NODE* aNode ) const { return m_owner == aNode; } - PNS_NODE* GetOwner() const { return m_owner; } + /** + * Function Layers() + * + * Returns the contiguous set of layers spanned by the item. + */ + const PNS_LAYERSET& Layers() const + { + return m_layers; + } + + /** + * Function Layer() + * + * Returns the item's layer, for single-layered items only. + */ + virtual int Layer() const + { + return Layers().Start(); + } - ///> Sets the world that is used for collision resolution. - void SetWorld( PNS_NODE* aWorld ) { m_world = aWorld; } - PNS_NODE* GetWorld() const { return m_world; } + /** + * Function LayersOverlap() + * + * Returns true if the set of layers spanned by aOther overlaps our + * layers. + */ + bool LayersOverlap( const PNS_ITEM* aOther ) const + { + return Layers().Overlaps( aOther->Layers() ); + } - ///> Collision function. Checks if the item aOther is closer to us than - /// aClearance and returns true if so. It can also calculate a minimum translation vector that - /// resolves the collision if needed. + /** + * Functon SetOwner() + * + * Sets the node that owns this item. An item can belong to a single + * PNS_NODE or stay unowned. + */ + void SetOwner( PNS_NODE* aOwner ) + { + m_owner = aOwner; + } + + /** + * Function BelongsTo() + * + * Returns true if the item is owned by the node aNode. + */ + bool BelongsTo( PNS_NODE* aNode ) const + { + return m_owner == aNode; + } + + /** + * Function Owner() + * + * Returns the owner of this item, or NULL if there's none. + */ + PNS_NODE* Owner() const { return m_owner; } + + /** + * Function Collide() + * + * Checks for a collision (clearance violation) with between us and item aOther. + * Collision checking takes all PCB stuff into accound (layers, nets, DRC rules). + * Optionally returns a minimum translation vector for force propagation + * algorithm. + * + * @param aOther item to check collision against + * @param aClearance desired clearance + * @param aNeedMTV when true, the minimum translation vector is calculated + * @param aMTV the minimum translation vector + * @param true, if a collision was found. + */ virtual bool Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const; - ///> A shortcut without MTV calculation + /** + * Function Collide() + * + * A shortcut for PNS_ITEM::Colllide() without MTV stuff. + */ bool Collide( const PNS_ITEM* aOther, int aClearance ) const { VECTOR2I dummy; @@ -132,26 +281,67 @@ public: return Collide( aOther, aClearance, false, dummy ); } - ///> Returns the geometric shape of the item - virtual const SHAPE* GetShape() const + /** + * Function Shape() + * + * Returns the geometrical shape of the item. Used + * for collision detection & spatial indexing. + */ + virtual const SHAPE* Shape() const { return NULL; } + virtual void Mark(int aMarker) + { + m_marker = aMarker; + } + + virtual void Unmark () + { + m_marker = 0; + } + + virtual int Marker() const + { + return m_marker; + } + + virtual void SetRank( int aRank ) + { + m_rank = aRank; + } + + virtual int Rank() const + { + return m_rank; + } + + virtual VECTOR2I Anchor( int n ) const + { + return VECTOR2I (); + } + + virtual int AnchorCount() const + { + return 0; + } + private: bool collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const; protected: - PnsKind m_kind; + PnsKind m_kind; - BOARD_CONNECTED_ITEM* m_parent; - PNS_NODE* m_world; - PNS_NODE* m_owner; - PNS_LAYERSET m_layers; + BOARD_CONNECTED_ITEM* m_parent; + PNS_NODE* m_owner; + PNS_LAYERSET m_layers; - bool m_movable; - int m_net; + bool m_movable; + int m_net; + int m_marker; + int m_rank; }; #endif // __PNS_ITEM_H diff --git a/pcbnew/router/pns_itemset.cpp b/pcbnew/router/pns_itemset.cpp index ebe69dc555..20254b94c0 100644 --- a/pcbnew/router/pns_itemset.cpp +++ b/pcbnew/router/pns_itemset.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,27 +15,41 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include #include "pns_itemset.h" - -PNS_ITEMSET::PNS_ITEMSET() +PNS_ITEMSET::PNS_ITEMSET( PNS_ITEM* aInitialItem ) { + if(aInitialItem) + m_items.push_back(aInitialItem); } PNS_ITEMSET::~PNS_ITEMSET() { + Clear(); +} + + +void PNS_ITEMSET::Clear() +{ + BOOST_FOREACH(PNS_ITEM* item, m_ownedItems) + { + delete item; + } + + m_items.clear(); + m_ownedItems.clear(); } PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd ) { - ItemVector newItems; + ITEM_VECTOR newItems; PNS_LAYERSET l; if( aEnd < 0 ) @@ -43,39 +57,44 @@ PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd ) else l = PNS_LAYERSET( aStart, aEnd ); - BOOST_FOREACH( PNS_ITEM * item, m_items ) + BOOST_FOREACH( PNS_ITEM* item, m_items ) - if( item->GetLayers().Overlaps( l ) ) + if( item->Layers().Overlaps( l ) ) newItems.push_back( item ); m_items = newItems; + return *this; } PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask ) { - ItemVector newItems; + ITEM_VECTOR newItems; - BOOST_FOREACH( PNS_ITEM * item, m_items ) - - if( item->GetKind() & aKindMask ) - newItems.push_back( item ); + BOOST_FOREACH( PNS_ITEM* item, m_items ) + { + if( item->OfKind ( aKindMask ) ) + newItems.push_back( item ); + } m_items = newItems; + return *this; } PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet ) { - ItemVector newItems; + ITEM_VECTOR newItems; - BOOST_FOREACH( PNS_ITEM * item, m_items ) - - if( item->GetNet() == aNet ) - newItems.push_back( item ); + BOOST_FOREACH( PNS_ITEM* item, m_items ) + { + if( item->Net() == aNet ) + newItems.push_back( item ); + } m_items = newItems; + return *this; } diff --git a/pcbnew/router/pns_itemset.h b/pcbnew/router/pns_itemset.h index da2c4a6634..44fe9c3c92 100644 --- a/pcbnew/router/pns_itemset.h +++ b/pcbnew/router/pns_itemset.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_ITEMSET_H @@ -35,12 +35,28 @@ class PNS_ITEMSET { public: - typedef std::vector ItemVector; + typedef std::vector ITEM_VECTOR; + + PNS_ITEMSET( PNS_ITEM* aInitialItem = NULL ); + + PNS_ITEMSET( const PNS_ITEMSET& aOther ) + { + m_items = aOther.m_items; + m_ownedItems = ITEM_VECTOR(); + } + + const PNS_ITEMSET& operator=( const PNS_ITEMSET& aOther ) + { + m_items = aOther.m_items; + m_ownedItems = ITEM_VECTOR(); + + return *this; + } - PNS_ITEMSET(); ~PNS_ITEMSET(); - ItemVector& Items() { return m_items; } + ITEM_VECTOR& Items() { return m_items; } + const ITEM_VECTOR& CItems() const { return m_items; } PNS_ITEMSET& FilterLayers( int aStart, int aEnd = -1 ); PNS_ITEMSET& FilterKinds( int aKindMask ); @@ -48,15 +64,24 @@ public: int Size() { return m_items.size(); } - void Add( PNS_ITEM* item ) + void Add( PNS_ITEM* aItem ) { - m_items.push_back( item ); + m_items.push_back( aItem ); } PNS_ITEM* Get( int index ) const { return m_items[index]; } + void Clear(); + + void AddOwned( PNS_ITEM *aItem ) + { + m_items.push_back( aItem ); + m_ownedItems.push_back( aItem ); + } + private: - ItemVector m_items; + ITEM_VECTOR m_items; + ITEM_VECTOR m_ownedItems; }; #endif diff --git a/pcbnew/router/pns_joint.h b/pcbnew/router/pns_joint.h index 4fd63e177a..1bee21c06f 100644 --- a/pcbnew/router/pns_joint.h +++ b/pcbnew/router/pns_joint.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_JOINT_H @@ -40,11 +40,11 @@ class PNS_JOINT : public PNS_ITEM { public: - typedef std::vector LinkedItems; + typedef std::vector LINKED_ITEMS; ///> Joints are hashed by their position, layers and net. /// Linked items are, obviously, not hashed - struct HashTag + struct HASH_TAG { VECTOR2I pos; int net; @@ -53,8 +53,7 @@ public: PNS_JOINT() : PNS_ITEM( JOINT ) {} - PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, - int aNet = -1 ) : + PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet = -1 ) : PNS_ITEM( JOINT ) { m_tag.pos = aPos; @@ -62,17 +61,17 @@ public: m_layers = aLayers; } - PNS_JOINT( const PNS_JOINT& b ) : + PNS_JOINT( const PNS_JOINT& aB ) : PNS_ITEM( JOINT ) { - m_layers = b.m_layers; - m_tag.pos = b.m_tag.pos; - m_tag.net = b.m_tag.net; - m_linkedItems = b.m_linkedItems; - m_layers = b.m_layers; + m_layers = aB.m_layers; + m_tag.pos = aB.m_tag.pos; + m_tag.net = aB.m_tag.net; + m_linkedItems = aB.m_linkedItems; + m_layers = aB.m_layers; } - PNS_ITEM* Clone() const + PNS_ITEM* Clone ( ) const { assert( false ); return NULL; @@ -85,22 +84,20 @@ public: if( m_linkedItems.size() != 2 ) return false; - if( m_linkedItems[0]->GetKind() != SEGMENT || - m_linkedItems[1]->GetKind() != SEGMENT ) + if( m_linkedItems[0]->Kind() != SEGMENT || m_linkedItems[1]->Kind() != SEGMENT ) return false; PNS_SEGMENT* seg1 = static_cast( m_linkedItems[0] ); PNS_SEGMENT* seg2 = static_cast( m_linkedItems[1] ); - // joints between segments of different widths are not trivial. - return seg1->GetWidth() == seg2->GetWidth(); + // joints between segments of different widths are not considered trivial. + return seg1->Width() == seg2->Width(); } ///> Links the joint to a given board item (when it's added to the PNS_NODE) void Link( PNS_ITEM* aItem ) { - LinkedItems::iterator f = std::find( m_linkedItems.begin(), - m_linkedItems.end(), aItem ); + LINKED_ITEMS::iterator f = std::find( m_linkedItems.begin(), m_linkedItems.end(), aItem ); if( f != m_linkedItems.end() ) return; @@ -112,8 +109,7 @@ public: ///> Returns true if the joint became dangling after unlinking. bool Unlink( PNS_ITEM* aItem ) { - LinkedItems::iterator f = std::find( m_linkedItems.begin(), - m_linkedItems.end(), aItem ); + LINKED_ITEMS::iterator f = std::find( m_linkedItems.begin(), m_linkedItems.end(), aItem ); if( f != m_linkedItems.end() ) m_linkedItems.erase( f ); @@ -131,21 +127,49 @@ public: return static_cast( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] ); } + PNS_VIA* Via() + { + for( LINKED_ITEMS::iterator i = m_linkedItems.begin(); i != m_linkedItems.end(); ++i ) + { + if( (*i)->Kind() == PNS_ITEM::VIA ) + return (PNS_VIA*)( *i ); + } + + return NULL; + } + /// trivial accessors - const HashTag& GetTag() const { return m_tag; } - const VECTOR2I& GetPos() const { return m_tag.pos; } - int GetNet() const { return m_tag.net; } - LinkedItems& GetLinkList() { return m_linkedItems; }; + const HASH_TAG& Tag() const + { + return m_tag; + } + + const VECTOR2I& Pos() const + { + return m_tag.pos; + } + + int Net() const + { + return m_tag.net; + } + + LINKED_ITEMS& LinkList() + { + return m_linkedItems; + } ///> Returns the number of linked items of types listed in aMask. int LinkCount( int aMask = -1 ) const { int n = 0; - for( LinkedItems::const_iterator i = m_linkedItems.begin(); - i != m_linkedItems.end(); ++i ) - if( (*i)->GetKind() & aMask ) + for( LINKED_ITEMS::const_iterator i = m_linkedItems.begin(); + i != m_linkedItems.end(); ++i ) + { + if( (*i)->Kind() & aMask ) n++; + } return n; } @@ -165,9 +189,11 @@ public: m_layers.Merge( aJoint.m_layers ); // fixme: duplicate links (?) - for( LinkedItems::const_iterator i = aJoint.m_linkedItems.begin(); - i != aJoint.m_linkedItems.end(); ++i ) + for( LINKED_ITEMS::const_iterator i = aJoint.m_linkedItems.begin(); + i != aJoint.m_linkedItems.end(); ++i ) + { m_linkedItems.push_back( *i ); + } } bool Overlaps( const PNS_JOINT& rhs ) const @@ -178,27 +204,27 @@ public: private: ///> hash tag for unordered_multimap - HashTag m_tag; + HASH_TAG m_tag; ///> list of items linked to this joint - LinkedItems m_linkedItems; + LINKED_ITEMS m_linkedItems; }; // hash function & comparison operator for boost::unordered_map<> -inline bool operator==( PNS_JOINT::HashTag const& p1, - PNS_JOINT::HashTag const& p2 ) +inline bool operator==( PNS_JOINT::HASH_TAG const& aP1, + PNS_JOINT::HASH_TAG const& aP2 ) { - return p1.pos == p2.pos && p1.net == p2.net; + return aP1.pos == aP2.pos && aP1.net == aP2.net; } -inline std::size_t hash_value( PNS_JOINT::HashTag const& p ) +inline std::size_t hash_value( PNS_JOINT::HASH_TAG const& aP ) { std::size_t seed = 0; - boost::hash_combine( seed, p.pos.x ); - boost::hash_combine( seed, p.pos.y ); - boost::hash_combine( seed, p.net ); + boost::hash_combine( seed, aP.pos.x ); + boost::hash_combine( seed, aP.pos.y ); + boost::hash_combine( seed, aP.net ); return seed; } diff --git a/pcbnew/router/pns_layerset.h b/pcbnew/router/pns_layerset.h index eedc00e31e..7ba05d84ef 100644 --- a/pcbnew/router/pns_layerset.h +++ b/pcbnew/router/pns_layerset.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_LAYERSET_H @@ -50,17 +50,17 @@ public: m_start = m_end = aLayer; } - PNS_LAYERSET( const PNS_LAYERSET& b ) : - m_start( b.m_start ), - m_end( b.m_end ) + PNS_LAYERSET( const PNS_LAYERSET& aB ) : + m_start( aB.m_start ), + m_end( aB.m_end ) {} ~PNS_LAYERSET() {}; - const PNS_LAYERSET& operator=( const PNS_LAYERSET& b ) + const PNS_LAYERSET& operator=( const PNS_LAYERSET& aB ) { - m_start = b.m_start; - m_end = b.m_end; + m_start = aB.m_start; + m_end = aB.m_end; return *this; } diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index 63011b6b75..d7663c4e7d 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -29,262 +29,128 @@ #include "pns_utils.h" #include "pns_router.h" +#include + using boost::optional; +PNS_LINE::PNS_LINE( const PNS_LINE& aOther ) : + PNS_ITEM( aOther ), + m_line( aOther.m_line ), + m_width( aOther.m_width ) +{ + m_net = aOther.m_net; + m_movable = aOther.m_movable; + m_layers = aOther.m_layers; + m_owner = aOther.m_owner; + m_via = aOther.m_via; + m_hasVia = aOther.m_hasVia; + m_marker = aOther.m_marker; + m_rank = aOther.m_rank; + + copyLinks ( &aOther ); +} + + +PNS_LINE::~PNS_LINE() +{ + if( m_segmentRefs ) + delete m_segmentRefs; +} + + +const PNS_LINE& PNS_LINE::operator=( const PNS_LINE& aOther ) +{ + m_line = aOther.m_line; + m_width = aOther.m_width; + m_net = aOther.m_net; + m_movable = aOther.m_movable; + m_owner = aOther.m_owner; + m_layers = aOther.m_layers; + m_via = aOther.m_via; + m_hasVia = aOther.m_hasVia; + m_marker = aOther.m_marker; + m_rank = aOther.m_rank; + + copyLinks ( &aOther ); + + return *this; +} + + PNS_LINE* PNS_LINE::Clone() const { - PNS_LINE* l = new PNS_LINE(); - - l->m_line = m_line; - l->m_width = m_width; - l->m_layers = m_layers; - l->m_net = m_net; - l->m_movable = m_movable; - l->m_segmentRefs = NULL; - l->m_hasVia = m_hasVia; - l->m_via = m_via; + PNS_LINE* l = new PNS_LINE( *this ); return l; } -PNS_LINE* PNS_LINE::CloneProperties() const +void PNS_LINE::Mark( int aMarker ) { - PNS_LINE* l = new PNS_LINE(); - - l->m_width = m_width; - l->m_layers = m_layers; - l->m_net = m_net; - l->m_movable = m_movable; - - return l; + m_marker = aMarker; + + if( m_segmentRefs ) + { + BOOST_FOREACH( PNS_SEGMENT* s, *m_segmentRefs ) + s->Mark( aMarker ); + } } -PNS_SEGMENT* PNS_SEGMENT::Clone() const +void PNS_LINE::Unmark () +{ + if( m_segmentRefs ) + { + BOOST_FOREACH( PNS_SEGMENT* s, *m_segmentRefs ) + s->Unmark(); + } + + m_marker = 0; +} + + +int PNS_LINE::Marker()const +{ + int marker = m_marker; + + if( m_segmentRefs ) + { + BOOST_FOREACH( PNS_SEGMENT* s, *m_segmentRefs ) + marker |= s->Marker(); + } + + return marker; +} + + +void PNS_LINE::copyLinks( const PNS_LINE *aParent ) +{ + if( aParent->m_segmentRefs == NULL ) + { + m_segmentRefs = NULL; + return; + } + + m_segmentRefs = new SEGMENT_REFS(); + *m_segmentRefs = *aParent->m_segmentRefs; +} + + +PNS_SEGMENT* PNS_SEGMENT::Clone( ) const { PNS_SEGMENT* s = new PNS_SEGMENT; - s->m_width = m_width; + s->m_seg = m_seg; s->m_net = m_net; - s->m_shape = m_shape; s->m_layers = m_layers; + s->m_marker = m_marker; + s->m_rank = m_rank; + s->m_owner = m_owner; - return s; // assert(false); + return s; } -#if 1 -bool PNS_LINE::MergeObtuseSegments() -{ - int step = m_line.PointCount() - 3; - int iter = 0; - - int segs_pre = m_line.SegmentCount(); - - if( step < 0 ) - return false; - - SHAPE_LINE_CHAIN current_path( m_line ); - - while( 1 ) - { - iter++; - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - - if( step > max_step ) - step = max_step; - - if( step < 2 ) - { - m_line = current_path; - return current_path.SegmentCount() < segs_pre; - } - - bool found_anything = false; - int n = 0; - - while( n < n_segs - step ) - { - const SEG s1 = current_path.CSegment( n ); - const SEG s2 = current_path.CSegment( n + step ); - SEG s1opt, s2opt; - - if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) ) - { - VECTOR2I ip = *s1.IntersectLines( s2 ); - - if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 ) - { - s1opt = SEG( s1.A, ip ); - s2opt = SEG( ip, s2.B ); - } - else - { - s1opt = SEG( s1.A, ip ); - s2opt = SEG( ip, s2.B ); - } - - - if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) - { - SHAPE_LINE_CHAIN opt_path; - opt_path.Append( s1opt.A ); - opt_path.Append( s1opt.B ); - opt_path.Append( s2opt.B ); - - PNS_LINE opt_track( *this, opt_path ); - - if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) ) - { - current_path.Replace( s1.Index() + 1, s2.Index(), ip ); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - } - - n++; - } - - if( !found_anything ) - { - if( step <= 2 ) - { - m_line = current_path; - return m_line.SegmentCount() < segs_pre; - } - - step--; - } - } - - return m_line.SegmentCount() < segs_pre; -} - - -bool PNS_LINE::MergeSegments() -{ - int step = m_line.PointCount() - 3; - int iter = 0; - - int segs_pre = m_line.SegmentCount(); - - if( step < 0 ) - return false; - - SHAPE_LINE_CHAIN current_path( m_line ); - - while( 1 ) - { - iter++; - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - - if( step > max_step ) - step = max_step; - - if( step < 2 ) - { - m_line = current_path; - return current_path.SegmentCount() < segs_pre; - } - - bool found_anything = false; - int n = 0; - - while( n < n_segs - step ) - { - const SEG s1 = current_path.CSegment( n ); - const SEG s2 = current_path.CSegment( n + step ); - SEG s1opt, s2opt; - - if( n > 0 ) - { - SHAPE_LINE_CHAIN path_straight = DIRECTION_45().BuildInitialTrace( s1.A, - s2.A, false ); - SHAPE_LINE_CHAIN path_diagonal = DIRECTION_45().BuildInitialTrace( s1.A, - s2.A, true ); - } - - if( DIRECTION_45( s1 ) == DIRECTION_45( s2 ) ) - { - if( s1.Collinear( s2 ) ) - { - // printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step); - - SHAPE_LINE_CHAIN opt_path; - opt_path.Append( s1.A ); - opt_path.Append( s2.B ); - - PNS_LINE tmp( *this, opt_path ); - - if( !m_world->CheckColliding( &tmp, PNS_ITEM::ANY ) ) - { - current_path.Remove( s1.Index() + 1, s2.Index() ); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - } - else if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) ) - { - VECTOR2I ip = *s1.IntersectLines( s2 ); - - if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 ) - { - s1opt = SEG( s1.A, ip ); - s2opt = SEG( ip, s2.B ); - } - else - { - s1opt = SEG( s1.A, ip ); - s2opt = SEG( ip, s2.B ); - } - - - if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) - { - SHAPE_LINE_CHAIN opt_path; - opt_path.Append( s1opt.A ); - opt_path.Append( s1opt.B ); - opt_path.Append( s2opt.B ); - - PNS_LINE opt_track( *this, opt_path ); - - if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) ) - { - current_path.Replace( s1.Index() + 1, s2.Index(), ip ); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - } - - n++; - } - - if( !found_anything ) - { - if( step <= 2 ) - { - m_line = current_path; - return m_line.SegmentCount() < segs_pre; - } - - step--; - } - } - - return m_line.SegmentCount() < segs_pre; -} -#endif - - int PNS_LINE::CountCorners( int aAngles ) { int count = 0; @@ -307,340 +173,98 @@ int PNS_LINE::CountCorners( int aAngles ) } -// #define DUMP_TEST_CASES - -// fixme: damn f*****g inefficient and incredibly crappily written -void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPrePath, - SHAPE_LINE_CHAIN& aWalkaroundPath, - SHAPE_LINE_CHAIN& aPostPath, - bool aCw ) const -{ - typedef SHAPE_LINE_CHAIN::INTERSECTION INTERSECTION; - - SHAPE_LINE_CHAIN l_orig( m_line ); - SHAPE_LINE_CHAIN l_hull; - std::vector outside, on_edge, inside; - SHAPE_LINE_CHAIN path; - - std::vector isects; - - // don't calculate walkaround for empty lines - if( m_line.PointCount() < 2 ) - return; - -#ifdef DUMP_TEST_CASES - printf( "%s\n", m_line.Format().c_str() ); - printf( "%s\n", aObstacle.Format().c_str() ); -#endif - - aObstacle.Intersect( m_line, isects ); - - // printf("NewWalk intersectiosn :%d\n" ,isects.size()); - if( !aCw ) - l_hull = aObstacle.Reverse(); - else - l_hull = aObstacle; - - BOOST_FOREACH( INTERSECTION isect, isects ) { - l_orig.Split( isect.p ); - l_hull.Split( isect.p ); - } - - -#ifdef DUMP_TEST_CASES - printf( "%s\n", m_line.Format().c_str() ); - printf( "%s\n", aObstacle.Format().c_str() ); - printf( "%s\n", l_orig.Format().c_str() ); - printf( "%s\n", l_hull.Format().c_str() ); -#endif - - - // printf("Pts: line %d hull %d\n", l_orig.PointCount(), l_hull.PointCount()); - - int first_post = -1; - int last_pre = -1; - - for( int i = 0; i < l_orig.PointCount(); i++ ) - { - int ei = l_hull.Find( l_orig.CPoint( i ) ); - bool edge = ei >= 0; - bool in = l_hull.PointInside( l_orig.CPoint( i ) ) && !edge; - bool out = !( in || edge); - - outside.push_back( out ); - on_edge.push_back( edge ); - inside.push_back( in ); - } - - for( int i = l_orig.PointCount() - 1; i >= 1; i-- ) - if( inside[i] && outside[i - 1] ) - { - SHAPE_LINE_CHAIN::INTERSECTIONS ips; - l_hull.Intersect( SEG( l_orig.CPoint( i ), l_orig.CPoint( i - 1 ) ), ips ); - l_orig.Remove( i, -1 ); - l_orig.Append( ips[0].p ); - break; - } - else if( inside[i] && on_edge[i - 1] ) - { - l_orig.Remove( i, -1 ); - // n = i; - } - else if( !inside[i] ) - break; - - if( !outside.size() && on_edge.size() < 2 ) - return; - - for( int i = 0; i < l_orig.PointCount(); i++ ) - { - const VECTOR2I p = l_orig.Point( i ); - - if( outside[i] || ( on_edge[i] && i == ( l_orig.PointCount() - 1 ) ) ) - { - if( last_pre < 0 ) - aPrePath.Append( p ); - - path.Append( p ); - } - else if( on_edge[i] ) - { - int li = -1; - - if( last_pre < 0 ) - { - aPrePath.Append( p ); - last_pre = path.PointCount(); - } - - if( i == l_orig.PointCount() - 1 || outside[i + 1] ) - { - path.Append( p ); - } - else - { - int vi2 = l_hull.Find( l_orig.CPoint( i ) ); - - path.Append( l_hull.CPoint( vi2 ) ); - - for( int j = (vi2 + 1) % l_hull.PointCount(); - j != vi2; - j = (j + 1) % l_hull.PointCount() ) - { - path.Append( l_hull.CPoint( j ) ); - li = l_orig.Find( l_hull.CPoint( j ) ); - - if( li >= 0 && ( li == ( l_orig.PointCount() - 1 ) || - outside[li + 1] ) ) - break; - } - - if( li >= 0 ) - { - if( i >= li ) - break; - else - i = li; - } - } - - first_post = path.PointCount() - 1; - } - } - - if( last_pre < 0 && first_post < 0 ) - return; - - aWalkaroundPath = path.Slice( last_pre, first_post ); - - if( first_post >= 0 ) - aPostPath = path.Slice( first_post, -1 ); -} - - -bool PNS_LINE::onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei, - bool& is_vertex ) const -{ - int vtx = obstacle.Find( p ); - - if( vtx >= 0 ) - { - ei = vtx; - is_vertex = true; - return true; - } - - for( int s = 0; s < obstacle.SegmentCount(); s++ ) - { - if( obstacle.CSegment( s ).Contains( p ) ) - { - ei = s; - is_vertex = false; - return true; - } - } - - return false; -} - - -bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& aLine, const SHAPE_LINE_CHAIN& aObstacle, - bool aReverse, VECTOR2I& aIp, int& aIndexO, int& aIndexL, bool& aIsVertex ) const -{ - int sc = aLine.SegmentCount(); - - for( int i = 0; i < aLine.SegmentCount(); i++ ) - { - printf( "check-seg rev %d %d/%d %d\n", aReverse, i, sc, sc - 1 - i ); - SEG tmp = aLine.CSegment( aReverse ? sc - 1 - i : i ); - SEG s( tmp.A, tmp.B ); - - if( aReverse ) - { - s.A = tmp.B; - s.B = tmp.A; - } - - if( onEdge( aObstacle, s.A, aIndexO, aIsVertex ) ) - { - aIndexL = (aReverse ? sc - 1 - i : i); - aIp = s.A; - printf( "vertex %d on-%s %d\n", aIndexL, - aIsVertex ? "vertex" : "edge", aIndexO ); - return true; - } - - if( onEdge( aObstacle, s.B, aIndexO, aIsVertex ) ) - { - aIndexL = (aReverse ? sc - 1 - i - 1 : i + 1); - aIp = s.B; - printf( "vertex %d on-%s %d\n", aIndexL, - aIsVertex ? "vertex" : "edge", aIndexO ); - return true; - } - - SHAPE_LINE_CHAIN::INTERSECTIONS ips; - int n_is = aObstacle.Intersect( s, ips ); - - if( n_is > 0 ) - { - aIndexO = ips[0].our.Index(); - aIndexL = aReverse ? sc - 1 - i : i; - printf( "segment-%d intersects edge-%d\n", aIndexL, aIndexO ); - aIp = ips[0].p; - return true; - } - } - - return false; -} - - bool PNS_LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre, SHAPE_LINE_CHAIN& aWalk, SHAPE_LINE_CHAIN& aPost, bool aCw ) const { - const SHAPE_LINE_CHAIN& line = GetCLine(); + const SHAPE_LINE_CHAIN& line ( CLine() ); VECTOR2I ip_start; - int index_o_start, index_l_start; VECTOR2I ip_end; - int index_o_end, index_l_end; - - bool is_vertex_start, is_vertex_end; if( line.SegmentCount() < 1 ) return false; - if( aObstacle.PointInside( line.CPoint( 0 ) ) || - aObstacle.PointInside( line.CPoint( -1 ) ) ) + if( aObstacle.PointInside( line.CPoint( 0 ) ) || aObstacle.PointInside( line.CPoint( -1 ) ) ) return false; -// printf("forward:\n"); - bool found = walkScan( line, aObstacle, false, ip_start, index_o_start, - index_l_start, is_vertex_start ); - // printf("reverse:\n"); - found |= walkScan( line, aObstacle, true, ip_end, index_o_end, index_l_end, is_vertex_end ); + SHAPE_LINE_CHAIN::INTERSECTIONS ips, ips2; - if( !found || ip_start == ip_end ) + line.Intersect( aObstacle, ips ); + + int nearest_dist = INT_MAX; + int farthest_dist = 0; + + SHAPE_LINE_CHAIN::INTERSECTION nearest, farthest; + + for( int i = 0; i < (int) ips.size(); i++ ) + { + const VECTOR2I p = ips[i].p; + int dist = line.PathLength( p ); + + if( dist <= nearest_dist ) + { + nearest_dist = dist; + nearest = ips[i]; + } + + if( dist >= farthest_dist ) + { + farthest_dist = dist; + farthest = ips[i]; + } + } + + if( ips.size() <= 1 || nearest.p == farthest.p ) { aPre = line; return true; } - aPre = line.Slice( 0, index_l_start ); - aPre.Append( ip_start ); + aPre = line.Slice( 0, nearest.our.Index() ); + aPre.Append( nearest.p ); + aPre.Simplify(); + aWalk.Clear(); - aWalk.Append( ip_start ); + aWalk.SetClosed( false ); + aWalk.Append( nearest.p ); - if( aCw ) + int i = nearest.their.Index(); + + assert( nearest.their.Index() >= 0 ); + assert( farthest.their.Index() >= 0 ); + + assert( nearest_dist <= farthest_dist ); + + aObstacle.Split( nearest.p ); + aObstacle.Split( farthest.p ); + + int i_first = aObstacle.Find( nearest.p ); + int i_last = aObstacle.Find( farthest.p ); + + i = i_first; + + while( i != i_last ) { - int is = ( index_o_start + 1 ) % aObstacle.PointCount(); - int ie = ( is_vertex_end ? index_o_end : index_o_end + 1 ) % aObstacle.PointCount(); - - while( 1 ) - { - printf( "is %d\n", is ); - aWalk.Append( aObstacle.CPoint( is ) ); - - if( is == ie ) - break; - - is++; - - if( is == aObstacle.PointCount() ) - is = 0; - } + aWalk.Append( aObstacle.CPoint( i ) ); + i += ( aCw ? 1 : -1 ); + + if( i < 0 ) + i = aObstacle.PointCount() - 1; + else if( i == aObstacle.PointCount() ) + i = 0; } - else - { - int is = index_o_start; - int ie = ( is_vertex_end ? index_o_end : index_o_end ) % aObstacle.PointCount(); - - while( 1 ) - { - printf( "is %d\n", is ); - aWalk.Append( aObstacle.CPoint( is ) ); - - if( is == ie ) - break; - - is--; - - if( is < 0 ) - is = aObstacle.PointCount() - 1; - } - } - - aWalk.Append( ip_end ); + + aWalk.Append( farthest.p ); + aWalk.Simplify(); aPost.Clear(); - aPost.Append( ip_end ); - aPost.Append( line.Slice( is_vertex_end ? index_l_end : index_l_end + 1, -1 ) ); - - // for(int i = (index_o_start + 1) % obstacle.PointCount(); - // i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount()) - // { - // printf("append %d\n", i); - // walk.Append(obstacle.CPoint(i)); - // } + aPost.Append( farthest.p ); + aPost.Append( line.Slice( farthest.our.Index() + 1, -1 ) ); + aPost.Simplify(); return true; } -void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const -{ - SHAPE_LINE_CHAIN walk, post; - - NewWalkaround( aObstacle, aPath, walk, post, aCw ); - aPath.Append( walk ); - aPath.Append( post ); - aPath.Simplify(); -} - - void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPath, bool aCw ) const @@ -656,38 +280,7 @@ void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, const SHAPE_LINE_CHAIN PNS_SEGMENT::Hull( int aClearance, int aWalkaroundThickness ) const { - int d = aClearance + 10; - int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ) + 2; - - const VECTOR2I a = m_shape.CPoint( 0 ); - const VECTOR2I b = m_shape.CPoint( 1 ); - - VECTOR2I dir = b - a; - - VECTOR2I p0 = dir.Perpendicular().Resize( d ); - - VECTOR2I ds = dir.Perpendicular().Resize( x / 2 ); - VECTOR2I pd = dir.Resize( x / 2 ); - VECTOR2I dp = dir.Resize( d ); - - SHAPE_LINE_CHAIN s; - - s.SetClosed( true ); - - s.Append( b + p0 + pd ); - s.Append( b + dp + ds ); - s.Append( b + dp - ds ); - s.Append( b - p0 + pd ); - s.Append( a - p0 - pd ); - s.Append( a - dp - ds ); - s.Append( a - dp + ds ); - s.Append( a + p0 - pd ); - - // make sure the hull outline is always clockwise - if( s.CSegment( 0 ).Side( a ) < 0 ) - return s.Reverse(); - else - return s; + return SegmentHull ( m_seg, aClearance, aWalkaroundThickness ); } @@ -718,13 +311,13 @@ const PNS_LINE PNS_LINE::ClipToNearestObstacle( PNS_NODE* aNode ) const { PNS_LINE l( *this ); - PNS_NODE::OptObstacle obs = aNode->NearestObstacle( &l ); + PNS_NODE::OPT_OBSTACLE obs = aNode->NearestObstacle( &l ); if( obs ) { l.RemoveVia(); - int p = l.GetLine().Split( obs->ip_first ); - l.GetLine().Remove( p + 1, -1 ); + int p = l.Line().Split( obs->m_ipFirst ); + l.Line().Remove( p + 1, -1 ); } return l; @@ -744,3 +337,441 @@ void PNS_LINE::ShowLinks() for( int i = 0; i < (int) m_segmentRefs->size(); i++ ) printf( "seg %d: %p\n", i, (*m_segmentRefs)[i] ); } + +SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECTOR2I& aP ) +{ + optional picked; + int i; + + int d = 2; + + if( aOrigin.CSegment( -1 ).Length() > 100000 * 30 ) // fixme: constant/parameter? + d = 1; + + for( i = aOrigin.SegmentCount() - d; i >= 0; i-- ) + { + DIRECTION_45 d_start ( aOrigin.CSegment( i ) ); + VECTOR2I p_start = aOrigin.CPoint( i ); + SHAPE_LINE_CHAIN paths[2]; + DIRECTION_45 dirs[2]; + DIRECTION_45 d_prev = ( i > 0 ? DIRECTION_45( aOrigin.CSegment( i - 1 ) ) : DIRECTION_45() ); + + for( int j = 0; j < 2; j++ ) + { + paths[j] = d_start.BuildInitialTrace( p_start, aP, j ); + dirs[j] = DIRECTION_45( paths[j].CSegment( 0 ) ); + } + + for( int j = 0; j < 2; j++ ) + { + if( dirs[j] == d_start ) + { + picked = paths[j]; + break; + } + } + + if( picked ) + break; + + for( int j = 0; j < 2; j++ ) + { + if( dirs[j].IsObtuse( d_prev ) ) + { + picked = paths[j]; + break; + } + } + + if( picked ) + break; + } + + if( picked ) + { + SHAPE_LINE_CHAIN path = aOrigin.Slice( 0, i ); + path.Append( *picked ); + + return path; + } + + return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( 0 ), aP, true ); +} + + +void PNS_LINE::DragCorner ( const VECTOR2I& aP, int aIndex, int aSnappingThreshold ) +{ + SHAPE_LINE_CHAIN path; + + VECTOR2I snapped = snapDraggedCorner( m_line, aP, aIndex, aSnappingThreshold ); + + if( aIndex == 0 ) + path = dragCornerInternal( m_line.Reverse(), snapped ).Reverse(); + else if ( aIndex == m_line.SegmentCount() ) + path = dragCornerInternal( m_line, snapped ); + else + { + // fixme: awkward behaviour for "outwards" drags + path = dragCornerInternal( m_line.Slice( 0, aIndex ), snapped ); + SHAPE_LINE_CHAIN path_rev = dragCornerInternal( m_line.Slice( aIndex, -1 ).Reverse(), + snapped ).Reverse(); + path.Append( path_rev ); + } + + path.Simplify(); + m_line = path; +} + + +VECTOR2I PNS_LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, + int aIndex, int aThreshold ) const +{ + int s_start = std::max( aIndex - 2, 0 ); + int s_end = std::min( aIndex + 2, aPath.SegmentCount() - 1 ); + + int i, j; + int best_dist = INT_MAX; + VECTOR2I best_snap = aP; + + if( aThreshold <= 0 ) + return aP; + + for( i = s_start; i <= s_end; i++ ) + { + const SEG& a = aPath.CSegment( i ); + + for( j = s_start; j < i; j++ ) + { + const SEG& b = aPath.CSegment( j ); + + if( !( DIRECTION_45( a ).IsObtuse(DIRECTION_45( b ) ) ) ) + continue; + + OPT_VECTOR2I ip = a.IntersectLines(b); + + if( ip ) + { + int dist = ( *ip - aP ).EuclideanNorm(); + + if( dist < aThreshold && dist < best_dist ) + { + best_dist = dist; + best_snap = *ip; + } + } + } + } + + return best_snap; +} + +VECTOR2I PNS_LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, + int aIndex, int aThreshold ) const +{ + VECTOR2I snap_p[2]; + DIRECTION_45 dragDir( aPath.CSegment( aIndex ) ); + int snap_d[2] = { -1, -1 }; + + if( aThreshold == 0 ) + return aP; + + if( aIndex >= 2 ) + { + SEG s = aPath.CSegment( aIndex - 2 ); + + if( DIRECTION_45( s ) == dragDir ) + snap_d[0] = s.LineDistance( aP ); + + snap_p[0] = s.A; + } + + if( aIndex < aPath.SegmentCount() - 2 ) + { + SEG s = aPath.CSegment( aIndex + 2 ); + + if( DIRECTION_45( s ) == dragDir ) + snap_d[1] = s.LineDistance(aP); + + snap_p[1] = s.A; + } + + VECTOR2I best = aP; + int minDist = INT_MAX; + + for( int i = 0; i < 2; i++ ) + { + if( snap_d[i] >= 0 && snap_d[i] < minDist && snap_d[i] <= aThreshold ) + { + minDist = snap_d[i]; + best = snap_p[i]; + } + } + + return best; +} + + +void PNS_LINE::DragSegment ( const VECTOR2I& aP, int aIndex, int aSnappingThreshold ) +{ + SHAPE_LINE_CHAIN path( m_line ); + VECTOR2I target( aP ); + + SEG guideA[2], guideB[2]; + int index = aIndex; + + target = snapToNeighbourSegments( path, aP, aIndex, aSnappingThreshold ); + + if( index == 0 ) + { + path.Insert( 0, path.CPoint( 0 ) ); + index++; + } + + if( index == path.SegmentCount() - 1 ) + { + path.Insert( path.PointCount() - 1, path.CPoint( -1 ) ); + } + + SEG dragged = path.CSegment( index ); + DIRECTION_45 drag_dir( dragged ); + + SEG s_prev = path.CSegment( index - 1 ); + SEG s_next = path.CSegment( index + 1 ); + + DIRECTION_45 dir_prev( s_prev ); + DIRECTION_45 dir_next( s_next ); + + if( dir_prev == drag_dir ) + { + dir_prev = dir_prev.Left(); + path.Insert( index, path.CPoint( index ) ); + index++; + } + + if( dir_next == drag_dir ) + { + dir_next = dir_next.Right(); + path.Insert( index + 1, path.CPoint( index + 1 ) ); + } + + s_prev = path.CSegment( index - 1 ); + s_next = path.CSegment( index + 1 ); + dragged = path.CSegment( index ); + + bool lockEndpointA = true; + bool lockEndpointB = true; + + if( aIndex == 0 ) + { + if( !lockEndpointA ) + guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Right().Right().ToVector() ); + else + { + guideA[0] = SEG( dragged.A, dragged.A + drag_dir.Right().ToVector() ); + guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Left().ToVector() ); + } + } + else + { + if( dir_prev.IsObtuse(drag_dir ) ) + { + guideA[0] = SEG( s_prev.A, s_prev.A + drag_dir.Left().ToVector() ); + guideA[1] = SEG( s_prev.A, s_prev.A + drag_dir.Right().ToVector() ); + } + else + guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + dir_prev.ToVector() ); + } + + if( aIndex == m_line.SegmentCount() - 1 ) + { + if( !lockEndpointB ) + guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Right().Right().ToVector() ); + else + { + guideB[0] = SEG( dragged.B, dragged.B + drag_dir.Right().ToVector() ); + guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Left().ToVector() ); + } + } + else + { + if( dir_next.IsObtuse( drag_dir ) ) + { + guideB[0] = SEG( s_next.B, s_next.B + drag_dir.Left().ToVector() ); + guideB[1] = SEG( s_next.B, s_next.B + drag_dir.Right().ToVector() ); + } + else + guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + dir_next.ToVector() ); + } + + SEG s_current( target, target + drag_dir.ToVector() ); + + int best_len = INT_MAX; + SHAPE_LINE_CHAIN best; + + for( int i = 0; i < 2; i++ ) + { + for( int j = 0; j < 2; j++ ) + { + OPT_VECTOR2I ip1 = s_current.IntersectLines( guideA[i] ); + OPT_VECTOR2I ip2 = s_current.IntersectLines( guideB[j] ); + + SHAPE_LINE_CHAIN np; + + if( !ip1 || !ip2 ) + continue; + + SEG s1( s_prev.A, *ip1 ); + SEG s2( *ip1, *ip2 ); + SEG s3( *ip2, s_next.B ); + + OPT_VECTOR2I ip; + + if( ip = s1.Intersect( s_next ) ) + { + np.Append ( s1.A ); + np.Append ( *ip ); + np.Append ( s_next.B ); + } + else if( ip = s3.Intersect( s_prev ) ) + { + np.Append ( s_prev.A ); + np.Append ( *ip ); + np.Append ( s3.B ); + } + else if( ip = s1.Intersect( s3 ) ) + { + np.Append( s_prev.A ); + np.Append( *ip ); + np.Append( s_next.B ); + } + else + { + np.Append( s_prev.A ); + np.Append( *ip1 ); + np.Append( *ip2 ); + np.Append( s_next.B ); + } + + if( np.Length() < best_len ) + { + best_len = np.Length(); + best = np; + } + } + } + + if( !lockEndpointA && aIndex == 0 ) + best.Remove( 0, 0 ); + if( !lockEndpointB && aIndex == m_line.SegmentCount() - 1 ) + best.Remove( -1, -1 ); + + if( m_line.PointCount() == 1 ) + m_line = best; + else if( aIndex == 0 ) + m_line.Replace( 0, 1, best ); + else if( aIndex == m_line.SegmentCount() - 1 ) + m_line.Replace( -2, -1, best ); + else + m_line.Replace( aIndex, aIndex + 1, best ); + + m_line.Simplify(); +} + + +bool PNS_LINE::CompareGeometry( const PNS_LINE& aOther ) +{ + return m_line.CompareGeometry( aOther.m_line ); +} + + +void PNS_LINE::Reverse() +{ + m_line = m_line.Reverse(); + + if( m_segmentRefs ) + std::reverse( m_segmentRefs->begin(), m_segmentRefs->end() ); +} + + +void PNS_LINE::AppendVia( const PNS_VIA& aVia ) +{ + if( aVia.Pos() == m_line.CPoint( 0 ) ) + { + Reverse(); + } + + m_hasVia = true; + m_via = aVia; + m_via.SetNet( m_net ); +} + + +void PNS_LINE::SetRank( int aRank ) +{ + m_rank = aRank; + + if( m_segmentRefs ) + { + BOOST_FOREACH( PNS_SEGMENT* s, *m_segmentRefs ) + s->SetRank( aRank ); + } +} + + +int PNS_LINE::Rank() const +{ + int min_rank = INT_MAX; + int rank; + + if( m_segmentRefs ) + { + BOOST_FOREACH( PNS_SEGMENT *s, *m_segmentRefs ) + min_rank = std::min( min_rank, s->Rank() ); + rank = ( min_rank == INT_MAX ) ? -1 : min_rank; + } + else + { + rank = m_rank; + } + + return rank; +} + + +void PNS_LINE::ClipVertexRange( int aStart, int aEnd ) +{ + m_line = m_line.Slice( aStart, aEnd ); + + if( m_segmentRefs ) + { + SEGMENT_REFS* snew = new SEGMENT_REFS( m_segmentRefs->begin() + aStart, + m_segmentRefs->begin() + aEnd ); + + delete m_segmentRefs; + m_segmentRefs = snew; + } +} + + +bool PNS_LINE::HasLoops() const +{ + for( int i = 0; i < PointCount(); i++ ) + { + for( int j = 0; j < PointCount(); j++ ) + { + if( ( std::abs( i - j ) > 1 ) && CPoint( i ) == CPoint( j ) ) + return true; + } + } + + return false; +} + + +void PNS_LINE::ClearSegmentLinks() +{ + if( m_segmentRefs ) + delete m_segmentRefs; + + m_segmentRefs = NULL; +} diff --git a/pcbnew/router/pns_line.h b/pcbnew/router/pns_line.h index ebd07750cf..d77c37ec96 100644 --- a/pcbnew/router/pns_line.h +++ b/pcbnew/router/pns_line.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_LINE_H @@ -42,59 +42,39 @@ class PNS_VIA; * vias, pads, junctions between multiple traces or two traces different widths * and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE). * Instead, they are assembled on-the-fly, based on a via/pad/segment that - * belongs/begins them. + * belongs to/starts/ends them. * * PNS_LINEs can be either loose (consisting of segments that do not belong to * any PNS_NODE) or owned (with segments taken from a PNS_NODE) - these are * returned by PNS_NODE::AssembleLine and friends. * - * A PNS_LINE may have a PNS_VIA attached at its and - this is used by via + * A PNS_LINE may have a PNS_VIA attached at its end (i.e. the last point) - this is used by via * dragging/force propagation stuff. */ +#define PNS_HULL_MARGIN 10 + class PNS_LINE : public PNS_ITEM { public: - typedef std::vector LinkedSegments; - - PNS_LINE() : - PNS_ITEM( LINE ) - { - m_segmentRefs = NULL; - m_hasVia = false; - m_affectedRangeStart = -1; - }; - - PNS_LINE( int aLayer, int aWidth, const SHAPE_LINE_CHAIN& aLine ) : - PNS_ITEM( LINE ) - { - m_line = aLine; - m_width = aWidth; - m_segmentRefs = NULL; - m_hasVia = false; - m_affectedRangeStart = -1; - SetLayer( aLayer ); - } - - PNS_LINE( const PNS_LINE& aOther ) : - PNS_ITEM( aOther ), - m_line( aOther.m_line ), - m_width( aOther.m_width ) - { - m_net = aOther.m_net; - m_movable = aOther.m_movable; - m_world = aOther.m_world; - m_layers = aOther.m_layers; - m_segmentRefs = NULL; - m_via = aOther.m_via; - m_hasVia = aOther.m_hasVia; - m_affectedRangeStart = -1; - } + typedef std::vector SEGMENT_REFS; /** * Constructor - * copies properties (net, layers from a base line), and replaces the shape - * by aLine + * Makes an empty line. + */ + PNS_LINE() : PNS_ITEM( LINE ) + { + m_segmentRefs = NULL; + m_hasVia = false; + } + + PNS_LINE( const PNS_LINE& aOther ) ; + + /** + * Constructor + * Copies properties (net, layers, etc.) from a base line and replaces the shape + * by another **/ PNS_LINE( const PNS_LINE& aBase, const SHAPE_LINE_CHAIN& aLine ) : PNS_ITEM( aBase ), @@ -105,49 +85,101 @@ public: m_layers = aBase.m_layers; m_segmentRefs = NULL; m_hasVia = false; - m_affectedRangeStart = -1; } - ~PNS_LINE() - { - if( m_segmentRefs ) - delete m_segmentRefs; - }; + ~PNS_LINE(); + /// @copydoc PNS_ITEM::Clone() virtual PNS_LINE* Clone() const; - ///> clones the line without cloning the shape - ///> (just the properties - net, width, layers, etc.) - PNS_LINE* CloneProperties() const; + const PNS_LINE& operator=( const PNS_LINE& aOther ); - int GetLayer() const { return GetLayers().Start(); } + ///> Assigns a shape to the line (a polyline/line chain) + void SetShape( const SHAPE_LINE_CHAIN& aLine ) + { + m_line = aLine; + } - ///> Geometry accessors - void SetShape( const SHAPE_LINE_CHAIN& aLine ) { m_line = aLine; } - const SHAPE* GetShape() const { return &m_line; } - SHAPE_LINE_CHAIN& GetLine() { return m_line; } - const SHAPE_LINE_CHAIN& GetCLine() const { return m_line; } + ///> Returns the shape of the line + const SHAPE* Shape() const + { + return &m_line; + } - ///> Width accessors - void SetWidth( int aWidth ) { m_width = aWidth; } - int GetWidth() const { return m_width; } + ///> Modifiable accessor to the underlying shape + SHAPE_LINE_CHAIN& Line() + { + return m_line; + } - ///> Links a segment from a PNS_NODE to this line, making it owned by the node + ///> Const accessor to the underlying shape + const SHAPE_LINE_CHAIN& CLine() const + { + return m_line; + } + + ///> Returns the number of segments in the line + int SegmentCount() const + { + return m_line.SegmentCount(); + } + + ///> Returns the number of points in the line + int PointCount() const + { + return m_line.PointCount(); + } + + ///> Returns the aIdx-th point of the line + const VECTOR2I& CPoint( int aIdx ) const + { + return m_line.CPoint( aIdx ); + } + + ///> Returns the aIdx-th segment of the line + const SEG CSegment( int aIdx ) const + { + return m_line.CSegment( aIdx ); + } + + ///> Sets line width + void SetWidth( int aWidth ) + { + m_width = aWidth; + } + + ///> Returns line width + int Width() const + { + return m_width; + } + + ///> Returns true if the line is geometrically identical as line aOther + bool CompareGeometry( const PNS_LINE& aOther ); + + ///> Reverses the point/vertex order + void Reverse(); + + + /* Linking functions */ + + ///> Adds a reference to a segment registered in a PNS_NODE that is a part of this line. void LinkSegment( PNS_SEGMENT* aSeg ) { if( !m_segmentRefs ) - m_segmentRefs = new std::vector (); + m_segmentRefs = new SEGMENT_REFS(); m_segmentRefs->push_back( aSeg ); } - ///> Returns a list of segments from the owning node that constitute this - ///> line (or NULL if the line is loose) - LinkedSegments* GetLinkedSegments() + ///> Returns the list of segments from the owning node that constitute this + ///> line (or NULL if the line is not linked) + SEGMENT_REFS* LinkedSegments() { return m_segmentRefs; } + ///> Checks if the segment aSeg is a part of the line. bool ContainsSegment( PNS_SEGMENT* aSeg ) const { if( !m_segmentRefs ) @@ -157,14 +189,25 @@ public: aSeg ) != m_segmentRefs->end(); } - ///> Returns this line, but clipped to the nearest obstacle - ///> along, to avoid collision. + ///> Erases the linking information. Used to detach the line from the owning node. + void ClearSegmentLinks(); + + ///> Returns the number of segments that were assembled together to form this line. + int LinkCount() const + { + if( !m_segmentRefs ) + return -1; + + return m_segmentRefs->size(); + } + + ///> Clips the line to the nearest obstacle, traversing from the line's start vertex (0). + ///> Returns the clipped line. const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const; - ///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER) - bool MergeObtuseSegments(); - bool MergeSegments(); - + ///> Clips the line to a given range of vertices. + void ClipVertexRange ( int aStart, int aEnd ); + ///> Returns the number of corners of angles specified by mask aAngles. int CountCorners( int aAngles ); @@ -173,24 +216,13 @@ public: ///> aPrePath = path from origin to the obstacle ///> aWalkaroundPath = path around the obstacle ///> aPostPath = past from obstacle till the end - ///> aCW = whether to walkaround in clockwise or counter-clockwise direction. - void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPrePath, - SHAPE_LINE_CHAIN& aWalkaroundPath, - SHAPE_LINE_CHAIN& aPostPath, + ///> aCW = whether to walk around in clockwise or counter-clockwise direction. + bool Walkaround( SHAPE_LINE_CHAIN aObstacle, + SHAPE_LINE_CHAIN& aPre, + SHAPE_LINE_CHAIN& aWalk, + SHAPE_LINE_CHAIN& aPost, bool aCw ) const; - void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const; - - - bool Walkaround( SHAPE_LINE_CHAIN obstacle, - SHAPE_LINE_CHAIN& pre, - SHAPE_LINE_CHAIN& walk, - SHAPE_LINE_CHAIN& post, - bool cw ) const; - void Walkaround( const SHAPE_LINE_CHAIN& aObstacle, SHAPE_LINE_CHAIN& aPath, bool aCw ) const; @@ -202,62 +234,48 @@ public: bool EndsWithVia() const { return m_hasVia; } - void AppendVia( const PNS_VIA& aVia ) - { - m_hasVia = true; - m_via = aVia; - m_via.SetNet( m_net ); - } - + void AppendVia( const PNS_VIA& aVia ); void RemoveVia() { m_hasVia = false; } - const PNS_VIA& GetVia() const { return m_via; } - void SetAffectedRange( int aStart, int aEnd ) - { - m_affectedRangeStart = aStart; - m_affectedRangeEnd = aEnd; - } + const PNS_VIA& Via() const { return m_via; } + + virtual void Mark( int aMarker ); + virtual void Unmark (); + virtual int Marker() const; + + void DragSegment( const VECTOR2I& aP, int aIndex, int aSnappingThreshold = 0 ); + void DragCorner( const VECTOR2I& aP, int aIndex, int aSnappingThreshold = 0 ); - void ClearAffectedRange() - { - m_affectedRangeStart = -1; - } - - bool GetAffectedRange( int& aStart, int& aEnd ) - { - if( m_affectedRangeStart >= 0 ) - { - aStart = m_affectedRangeStart; - aEnd = m_affectedRangeEnd; - return true; - } - else - { - aStart = 0; - aEnd = m_line.PointCount(); - return false; - } - } + void SetRank( int aRank ); + int Rank() const; + + bool HasLoops() const; private: - bool onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei, bool& is_vertex ) const; - bool walkScan( const SHAPE_LINE_CHAIN& line, const SHAPE_LINE_CHAIN& obstacle, - bool reverse, VECTOR2I& ip, int& index_o, int& index_l, bool& is_vertex ) const; + VECTOR2I snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, + int aIndex, int aThreshold) const; - ///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line. - LinkedSegments* m_segmentRefs; + VECTOR2I snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, + int aIndex, int aThreshold ) const; - ///> Shape of the line + ///> Copies m_segmentRefs from the line aParent. + void copyLinks( const PNS_LINE* aParent ) ; + + ///> List of segments in the owning PNS_NODE (PNS_ITEM::m_owner) that constitute this line, or NULL + ///> if the line is not a part of any node. + SEGMENT_REFS* m_segmentRefs; + + ///> The actual shape of the line SHAPE_LINE_CHAIN m_line; + ///> our width int m_width; - ///> Via at the end and a flag indicating if it's enabled. - PNS_VIA m_via; + ///> If true, the line ends with a via bool m_hasVia; - int m_affectedRangeStart; - int m_affectedRangeEnd; + ///> Via at the end point, if m_hasVia == true + PNS_VIA m_via; }; #endif // __PNS_LINE_H diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 4b9b616f3e..a79993249f 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,12 +15,14 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include #include +#include + #include "trace.h" #include "pns_node.h" @@ -28,23 +30,21 @@ #include "pns_walkaround.h" #include "pns_shove.h" #include "pns_utils.h" +#include "pns_router.h" + +#include using boost::optional; -const double PNS_LINE_PLACER::m_shoveLengthThreshold = 1.7; - -PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE* aWorld ) +PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_ROUTER* aRouter ) : + PNS_ALGO_BASE ( aRouter ) { - m_initial_direction = DIRECTION_45( DIRECTION_45::N ); - m_follow_mouse = false; - m_smoothing_step = 100000; - m_smooth_mouse = false; + m_initial_direction = DIRECTION_45::N; m_iteration = 0; - m_world = aWorld; - m_mode = RM_Smart; - m_follow_mouse = true; + m_world = NULL; m_shove = NULL; -}; + m_currentNode = NULL; +} PNS_LINE_PLACER::~PNS_LINE_PLACER() @@ -54,18 +54,24 @@ PNS_LINE_PLACER::~PNS_LINE_PLACER() } -void PNS_LINE_PLACER::ApplySettings( const PNS_ROUTING_SETTINGS& aSettings ) +void PNS_LINE_PLACER::setWorld ( PNS_NODE* aWorld ) { - m_follow_mouse = aSettings.m_followMouse; - m_mode = aSettings.m_routingMode; - m_walkaroundIterationLimit = aSettings.m_walkaroundIterationLimit; - m_smartPads = aSettings.m_smartPads; + m_world = aWorld; } -void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet, - int aWidth, int aLayer ) +void PNS_LINE_PLACER::AddVia( bool aEnabled, int aDiameter, int aDrill ) { + m_viaDiameter = aDiameter; + m_viaDrill = aDrill; + m_placingVia = aEnabled; +} + + +void PNS_LINE_PLACER::startPlacement( const VECTOR2I& aStart, int aNet, int aWidth, int aLayer ) +{ + assert( m_world != NULL ); + m_direction = m_initial_direction; TRACE( 1, "world %p, intitial-direction %s layer %d\n", m_world % m_direction.Format().c_str() % aLayer ); @@ -73,36 +79,46 @@ void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet, m_tail.SetNet( aNet ); m_head.SetWidth( aWidth ); m_tail.SetWidth( aWidth ); - m_head.GetLine().Clear(); - m_tail.GetLine().Clear(); + m_head.Line().Clear(); + m_tail.Line().Clear(); m_head.SetLayer( aLayer ); m_tail.SetLayer( aLayer ); m_iteration = 0; m_p_start = aStart; - m_currentNode = m_world->Branch(); - m_head.SetWorld( m_currentNode ); - m_tail.SetWorld( m_currentNode ); - // if(m_shove) - // delete m_shove; - m_shove = new PNS_SHOVE( m_currentNode ); + + m_lastNode = NULL; + m_currentNode = m_world; + + m_currentMode = Settings().Mode(); + + if( m_shove ) + delete m_shove; + + m_shove = NULL; + + if( m_currentMode == RM_Shove || m_currentMode == RM_Smart ) + { + m_shove = new PNS_SHOVE( m_world->Branch(), Router() ); + } + m_placingVia = false; } -void PNS_LINE_PLACER::SetInitialDirection( const DIRECTION_45& aDirection ) +void PNS_LINE_PLACER::setInitialDirection( const DIRECTION_45& aDirection ) { m_initial_direction = aDirection; - if( m_tail.GetCLine().SegmentCount() == 0 ) - m_direction = aDirection; + if( m_tail.SegmentCount() == 0 ) + m_direction = aDirection; } bool PNS_LINE_PLACER::handleSelfIntersections() { SHAPE_LINE_CHAIN::INTERSECTIONS ips; - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.Line(); + SHAPE_LINE_CHAIN& tail = m_tail.Line(); // if there is no tail, there is nothing to intersect with if( tail.PointCount() < 2 ) @@ -140,6 +156,7 @@ bool PNS_LINE_PLACER::handleSelfIntersections() m_direction = m_initial_direction; tail.Clear(); head.Clear(); + return true; } else @@ -159,8 +176,11 @@ bool PNS_LINE_PLACER::handleSelfIntersections() bool PNS_LINE_PLACER::handlePullback() { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.Line(); + SHAPE_LINE_CHAIN& tail = m_tail.Line(); + + if( head.PointCount() < 2 ) + return false; int n = tail.PointCount(); @@ -173,8 +193,8 @@ bool PNS_LINE_PLACER::handlePullback() return true; } - DIRECTION_45 first_head( head.Segment( 0 ) ); - DIRECTION_45 last_tail( tail.Segment( -1 ) ); + DIRECTION_45 first_head( head.CSegment( 0 ) ); + DIRECTION_45 last_tail( tail.CSegment( -1 ) ); DIRECTION_45::AngleType angle = first_head.Angle( last_tail ); // case 1: we have a defined routing direction, and the currently computed @@ -184,7 +204,7 @@ bool PNS_LINE_PLACER::handlePullback() // case 2: regardless of the current routing direction, if the tail/head // extremities form an acute or right angle, reduce the tail by one segment // (and hope that further iterations) will result with a cleaner trace - bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT || angle == DIRECTION_45::ANG_ACUTE); + bool pullback_2 = ( angle == DIRECTION_45::ANG_RIGHT || angle == DIRECTION_45::ANG_ACUTE ); if( pullback_1 || pullback_2 ) { @@ -215,11 +235,14 @@ bool PNS_LINE_PLACER::handlePullback() bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.Line(); + SHAPE_LINE_CHAIN& tail = m_tail.Line(); int n = tail.SegmentCount(); + if( head.SegmentCount() < 1 ) + return false; + // Don't attempt this for too short tails if( n < 2 ) return false; @@ -231,7 +254,7 @@ bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) VECTOR2I new_start; int reduce_index = -1; - DIRECTION_45 head_dir( head.Segment( 0 ) ); + DIRECTION_45 head_dir( head.CSegment( 0 ) ); for( int i = tail.SegmentCount() - 1; i >= 0; i-- ) { @@ -247,7 +270,7 @@ bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) if( m_currentNode->CheckColliding( &tmp, PNS_ITEM::ANY ) ) break; - if( DIRECTION_45( replacement.Segment( 0 ) ) == dir ) + if( DIRECTION_45( replacement.CSegment( 0 ) ) == dir ) { new_start = s.A; new_direction = dir; @@ -274,10 +297,10 @@ bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) } -bool PNS_LINE_PLACER::checkObtusity( const SEG& a, const SEG& b ) const +bool PNS_LINE_PLACER::checkObtusity( const SEG& aA, const SEG& aB ) const { - const DIRECTION_45 dir_a( a ); - const DIRECTION_45 dir_b( b ); + const DIRECTION_45 dir_a( aA ); + const DIRECTION_45 dir_b( aB ); return dir_a.IsObtuse( dir_b ) || dir_a == dir_b; } @@ -285,8 +308,8 @@ bool PNS_LINE_PLACER::checkObtusity( const SEG& a, const SEG& b ) const bool PNS_LINE_PLACER::mergeHead() { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.Line(); + SHAPE_LINE_CHAIN& tail = m_tail.Line(); const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_HALF_FULL | @@ -357,20 +380,22 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead ) return true; PNS_LAYERSET allLayers( 0, 15 ); - PNS_VIA v( aHead.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter, aHead.GetNet() ); + PNS_VIA v( aHead.CPoint( -1 ), allLayers, m_viaDiameter, aHead.Net() ); v.SetDrill( m_viaDrill ); VECTOR2I force; - VECTOR2I lead = aHead.GetCLine().CPoint( -1 ) - aHead.GetCLine().CPoint( 0 ); + VECTOR2I lead = aHead.CPoint( -1 ) - aHead.CPoint( 0 ); - if( v.PushoutForce( m_shove->GetCurrentNode(), lead, force, true, 20 ) ) + bool solidsOnly = ( m_currentMode != RM_Walkaround ); + + if( v.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) ) { SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( - aHead.GetCLine().CPoint( 0 ), - aHead.GetCLine().CPoint( -1 ) + force ); + aHead.CPoint( 0 ), + aHead.CPoint( -1 ) + force ); aHead = PNS_LINE( aHead, line ); - v.SetPos( v.GetPos() + force ); + v.SetPos( v.Pos() + force ); return true; } @@ -378,157 +403,206 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead ) } -bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead, - bool aCwWalkaround ) +bool PNS_LINE_PLACER::rhWalkOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - // STAGE 1: route a simple two-segment trace between m_p_start and aP... SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP ); + PNS_LINE initTrack( m_head, line ), walkFull; + int effort = 0; + bool viaOk = handleViaPlacement( initTrack ); + bool rv = true; - PNS_LINE initTrack( m_head, line ); - PNS_LINE walkFull, walkSolids; + PNS_WALKAROUND walkaround( m_currentNode, Router() ); - if( m_mode == RM_Ignore ) + walkaround.SetSolidsOnly( false ); + walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); + + PNS_WALKAROUND::WALKAROUND_STATUS wf = walkaround.Route( initTrack, walkFull, false ); + + switch( Settings().OptimizerEffort() ) { - aNewHead = initTrack; - return true; + case OE_LOW: + effort = 0; + break; + + case OE_MEDIUM: + case OE_FULL: + effort = PNS_OPTIMIZER::MERGE_SEGMENTS; + break; } + if( Settings().SmartPads() ) + effort |= PNS_OPTIMIZER::SMART_PADS; + + if( wf == PNS_WALKAROUND::STUCK ) + { + walkFull = walkFull.ClipToNearestObstacle( m_currentNode ); + rv = true; + } + else if( m_placingVia && viaOk ) + { + PNS_LAYERSET allLayers( 0, 15 ); + PNS_VIA v1( walkFull.CPoint( -1 ), allLayers, m_viaDiameter ); + walkFull.AppendVia( v1 ); + } + + PNS_OPTIMIZER::Optimize( &walkFull, effort, m_currentNode ); + + if( m_currentNode->CheckColliding( &walkFull ) ) + { + TRACEn(0, "strange, walk line colliding\n"); + } + + m_head = walkFull; + aNewHead = walkFull; + + return rv; +} + + +bool PNS_LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ) +{ + m_head.SetShape( m_direction.BuildInitialTrace( m_p_start, aP ) ); + + if( m_placingVia ) + { + PNS_LAYERSET allLayers( 0, 15 ); + PNS_VIA v1( m_head.CPoint( -1 ), allLayers, m_viaDiameter ); + m_head.AppendVia( v1 ); + } + + aNewHead = m_head; + + return m_currentNode->CheckColliding( &m_head ); +} + + +bool PNS_LINE_PLACER::rhShoveOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead ) +{ + SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP ); + PNS_LINE initTrack( m_head, line ); + PNS_LINE walkSolids, l2; + handleViaPlacement( initTrack ); - m_currentNode = m_shove->GetCurrentNode(); - + m_currentNode = m_shove->CurrentNode(); PNS_OPTIMIZER optimizer( m_currentNode ); - PNS_WALKAROUND walkaround( m_currentNode ); - walkaround.SetSolidsOnly( false ); - walkaround.SetIterationLimit( m_mode == RM_Walkaround ? 8 : 5 ); - // walkaround.SetApproachCursor(true, aP); + PNS_WALKAROUND walkaround( m_currentNode, Router() ); - PNS_WALKAROUND::WalkaroundStatus wf = walkaround.Route( initTrack, walkFull ); - -#if 0 - - if( m_mode == RM_Walkaround ) - { - // walkaround. -// PNSDisplayDebugLine (walkFull.GetCLine(), 4); - - if( wf == PNS_WALKAROUND::STUCK ) - { - aNewHead = m_head; - aNewHead.SetShape( walkFull.GetCLine() ); - aNewHead = aNewHead.ClipToNearestObstacle( m_currentNode ); - return false; - } - - aNewHead = m_head; - aNewHead.SetShape( walkFull.GetCLine() ); - -// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start()); - return true; - } - -#endif - - PNS_COST_ESTIMATOR cost_walk, cost_orig; - - walkaround.SetApproachCursor( false, aP ); walkaround.SetSolidsOnly( true ); walkaround.SetIterationLimit( 10 ); - PNS_WALKAROUND::WalkaroundStatus stat_solids = walkaround.Route( initTrack, walkSolids ); + PNS_WALKAROUND::WALKAROUND_STATUS stat_solids = walkaround.Route( initTrack, walkSolids ); optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS ); - optimizer.SetCollisionMask( PNS_ITEM::SOLID ); + optimizer.SetCollisionMask ( PNS_ITEM::SOLID ); optimizer.Optimize( &walkSolids ); - #if 0 - optimizer.SetCollisionMask( -1 ); - optimizer.Optimize( &walkFull ); - #endif - cost_orig.Add( initTrack ); - cost_walk.Add( walkFull ); - if( m_mode == RM_Smart || m_mode == RM_Shove ) + if( stat_solids == PNS_WALKAROUND::DONE ) + l2 = walkSolids; + else + l2 = initTrack.ClipToNearestObstacle( m_shove->CurrentNode() ); + + PNS_LINE l( m_tail ); + l.Line().Append( l2.CLine() ); + l.Line().Simplify(); + + if( m_placingVia ) { - PNS_LINE l2; + PNS_LAYERSET allLayers( 0, 15 ); + PNS_VIA v1( l.CPoint( -1 ), allLayers, m_viaDiameter ); + PNS_VIA v2( l2.CPoint( -1 ), allLayers, m_viaDiameter ); + v1.SetDrill( m_viaDrill ); + v2.SetDrill( m_viaDrill ); - bool walk_better = cost_orig.IsBetter( cost_walk, 1.5, 10.0 ); - walk_better = false; - -#if 0 - printf( "RtTrk width %d %d %d", initTrack.GetWidth(), - walkFull.GetWidth(), walkSolids.GetWidth() ); - printf( "init-coll %d\n", m_currentNode->CheckColliding( &initTrack ) ? 1 : 0 ); - printf( "total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n", - cost_walk.GetCornerCost(), cost_walk.GetLengthCost(), - cost_orig.GetCornerCost(), cost_orig.GetLengthCost(), - walk_better ); -#endif - - if( m_mode == RM_Smart && wf == PNS_WALKAROUND::DONE && walk_better - && walkFull.GetCLine().CPoint( -1 ) == initTrack.GetCLine().CPoint( -1 ) ) - l2 = walkFull; - else if( stat_solids == PNS_WALKAROUND::DONE ) - l2 = walkSolids; - else - l2 = initTrack.ClipToNearestObstacle( m_shove->GetCurrentNode() ); - - PNS_LINE l( m_tail ); - l.GetLine().Append( l2.GetCLine() ); - l.GetLine().Simplify(); - - if( m_placingVia ) - { - PNS_LAYERSET allLayers( 0, 15 ); - PNS_VIA v1( l.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter ); - PNS_VIA v2( l2.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter ); - v1.SetDrill( m_viaDrill ); - v2.SetDrill( m_viaDrill ); - - l.AppendVia( v1 ); - l2.AppendVia( v2 ); - } - - PNS_SHOVE::ShoveStatus status = m_shove->ShoveLines( &l ); - m_currentNode = m_shove->GetCurrentNode(); - - if( status == PNS_SHOVE::SH_OK ) - { - optimizer.SetWorld( m_currentNode ); - optimizer.ClearCache(); - optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); - optimizer.SetCollisionMask( -1 ); - optimizer.Optimize( &l2 ); - - aNewHead = l2; - - return true; - } - else - { - walkaround.SetWorld( m_currentNode ); - walkaround.SetSolidsOnly( false ); - walkaround.SetIterationLimit( 10 ); - walkaround.SetApproachCursor( true, aP ); - walkaround.Route( initTrack, l2 ); - aNewHead = l2.ClipToNearestObstacle( m_shove->GetCurrentNode() ); - // aNewHead = l2; - - return false; - } + l.AppendVia( v1 ); + l2.AppendVia( v2 ); } + l.Line().Simplify(); + + // in certain, uncommon cases there may be loops in the head+tail, In such case, we don't shove to avoid + // screwing up the database. + if( l.HasLoops() ) + { + aNewHead = m_head; + return false; + } + + PNS_SHOVE::SHOVE_STATUS status = m_shove->ShoveLines( l ); + + m_currentNode = m_shove->CurrentNode(); + + if( status == PNS_SHOVE::SH_OK ) + { + optimizer.SetWorld( m_currentNode ); + optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); + optimizer.SetCollisionMask( PNS_ITEM::ANY ); + optimizer.Optimize( &l2 ); + + aNewHead = l2; + + return true; + } + else + { + walkaround.SetWorld( m_currentNode ); + walkaround.SetSolidsOnly( false ); + walkaround.SetIterationLimit( 10 ); + walkaround.SetApproachCursor( true, aP ); + walkaround.Route( initTrack, l2 ); + aNewHead = l2.ClipToNearestObstacle( m_shove->CurrentNode() ); + + return false; + } + + return false; +} + + +bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead ) +{ + switch( m_currentMode ) + { + case RM_MarkObstacles: + return rhMarkObstacles( aP, aNewHead ); + case RM_Walkaround: + return rhWalkOnly ( aP, aNewHead ); + case RM_Shove: + return rhShoveOnly ( aP, aNewHead ); + default: + break; + } + return false; } bool PNS_LINE_PLACER::optimizeTailHeadTransition() { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + PNS_LINE tmp = Trace(); - const int TailLookbackSegments = 5; + if( PNS_OPTIMIZER::Optimize( &tmp, PNS_OPTIMIZER::FANOUT_CLEANUP, m_currentNode ) ) + { + if( tmp.SegmentCount() < 1 ) + return false; - int threshold = std::min( tail.PointCount(), TailLookbackSegments + 1 ); + m_head = tmp; + m_p_start = tmp.CLine().CPoint( 0 ); + m_direction = DIRECTION_45( tmp.CSegment( 0 ) ); + m_tail.Line().Clear(); + + return true; + } + + SHAPE_LINE_CHAIN& head = m_head.Line(); + SHAPE_LINE_CHAIN& tail = m_tail.Line(); + + int tailLookbackSegments = 3; + + //if(m_currentMode() == RM_Walkaround) + // tailLookbackSegments = 10000; + + int threshold = std::min( tail.PointCount(), tailLookbackSegments + 1 ); if( tail.SegmentCount() < 3 ) return false; @@ -536,8 +610,9 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition() // assemble TailLookbackSegments tail segments with the current head SHAPE_LINE_CHAIN opt_line = tail.Slice( -threshold, -1 ); - opt_line.Append( head ); -// opt_line.Simplify(); + int end = std::min(2, head.PointCount() - 1 ); + + opt_line.Append( head.Slice( 0, end ) ); PNS_LINE new_head( m_tail, opt_line ); @@ -545,20 +620,18 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition() // If so, replace the (threshold) last tail points and the head with // the optimized line - // if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS)) - - if( new_head.MergeSegments() ) + if( PNS_OPTIMIZER::Optimize( &new_head, PNS_OPTIMIZER::MERGE_OBTUSE, m_currentNode ) ) { PNS_LINE tmp( m_tail, opt_line ); TRACE( 0, "Placer: optimize tail-head [%d]", threshold ); head.Clear(); - tail.Replace( -threshold, -1, new_head.GetCLine() ); + tail.Replace( -threshold, -1, new_head.CLine() ); tail.Simplify(); - m_p_start = new_head.GetCLine().CPoint( -1 ); - m_direction = DIRECTION_45( new_head.GetCLine().CSegment( -1 ) ); + m_p_start = new_head.CLine().CPoint( -1 ); + m_direction = DIRECTION_45( new_head.CSegment( -1 ) ); return true; } @@ -576,26 +649,24 @@ void PNS_LINE_PLACER::routeStep( const VECTOR2I& aP ) PNS_LINE new_head; - m_follow_mouse = true; - TRACE( 2, "INIT-DIR: %s head: %d, tail: %d segs\n", - m_initial_direction.Format().c_str() % m_head.GetCLine().SegmentCount() % - m_tail.GetCLine().SegmentCount() ); + m_initial_direction.Format().c_str() % m_head.SegmentCount() % + m_tail.SegmentCount() ); for( i = 0; i < n_iter; i++ ) { - if( !go_back && m_follow_mouse ) + if( !go_back && Settings().FollowMouse() ) reduceTail( aP ); go_back = false; - if( !routeHead( aP, new_head, true ) ) + if( !routeHead( aP, new_head ) ) fail = true; if( !new_head.Is45Degree() ) fail = true; - if( !m_follow_mouse ) + if( !Settings().FollowMouse() ) return; m_head = new_head; @@ -615,49 +686,39 @@ void PNS_LINE_PLACER::routeStep( const VECTOR2I& aP ) if( !fail ) { - if( optimizeTailHeadTransition() ) - return; + if( optimizeTailHeadTransition() ) + return; mergeHead(); } } -bool PNS_LINE_PLACER::Route( const VECTOR2I& aP ) +bool PNS_LINE_PLACER::route( const VECTOR2I& aP ) { - if( m_smooth_mouse ) - { - VECTOR2I p_cur = m_p_start; - VECTOR2I step = (aP - m_p_start).Resize( m_smoothing_step ); - - do - { - if( (p_cur - aP).EuclideanNorm() <= m_smoothing_step ) - p_cur = aP; - else - p_cur += step; - - routeStep( p_cur ); - } while( p_cur != aP ); - } - else - routeStep( aP ); - + routeStep( aP ); return CurrentEnd() == aP; } -const PNS_LINE PNS_LINE_PLACER::GetTrace() const +const PNS_LINE PNS_LINE_PLACER::Trace() const { PNS_LINE tmp( m_head ); - tmp.SetShape( m_tail.GetCLine() ); - tmp.GetLine().Append( m_head.GetCLine() ); - tmp.GetLine().Simplify(); + tmp.SetShape( m_tail.CLine() ); + tmp.Line().Append( m_head.CLine() ); + tmp.Line().Simplify(); return tmp; } +const PNS_ITEMSET PNS_LINE_PLACER::Traces() +{ + m_currentTrace = Trace(); + return PNS_ITEMSET( &m_currentTrace ); +} + + void PNS_LINE_PLACER::FlipPosture() { m_initial_direction = m_initial_direction.Right(); @@ -665,14 +726,307 @@ void PNS_LINE_PLACER::FlipPosture() } -void PNS_LINE_PLACER::GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, - PNS_NODE::ItemVector& aAdded ) +PNS_NODE* PNS_LINE_PLACER::CurrentNode( bool aLoopsRemoved ) const { - return m_shove->GetCurrentNode()->GetUpdatedItems( aRemoved, aAdded ); + if( aLoopsRemoved && m_lastNode ) + return m_lastNode; + + return m_currentNode; } -PNS_NODE* PNS_LINE_PLACER::GetCurrentNode() const +void PNS_LINE_PLACER::splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ) { - return m_shove->GetCurrentNode(); + if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_JOINT *jt = aNode->FindJoint( aP, aSeg ); + + if( jt && jt->LinkCount() >= 1 ) + return; + + PNS_SEGMENT* s_old = static_cast( aSeg ); + + PNS_SEGMENT* s_new[2]; + + s_new[0] = s_old->Clone(); + s_new[1] = s_old->Clone(); + + s_new[0]->SetEnds( s_old->Seg().A, aP ); + s_new[1]->SetEnds( aP, s_old->Seg().B ); + + aNode->Remove( s_old ); + aNode->Add( s_new[0], true ); + aNode->Add( s_new[1], true ); + } +} + + +void PNS_LINE_PLACER::SetLayer(int aLayer) +{ + m_currentLayer = aLayer; +} + + +void PNS_LINE_PLACER::SetWidth(int aWidth) +{ + m_currentWidth = aWidth; +} + + +void PNS_LINE_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + VECTOR2I p( aP ); + + static int unknowNetIdx = 0; // -10000; + int net = -1; + + m_lastNode = NULL; + m_placingVia = false; + m_startsOnVia = false; + + bool splitSeg = false; + + if( Router()->SnappingEnabled() ) + p = Router()->SnapToItem( aStartItem, aP, splitSeg ); + + if( !aStartItem || aStartItem->Net() < 0 ) + net = unknowNetIdx--; + else + net = aStartItem->Net(); + + m_currentStart = p; + m_originalStart = p; + m_currentEnd = p; + m_currentNet = net; + + PNS_NODE *rootNode = Router()->GetWorld()->Branch(); + + if( splitSeg ) + splitAdjacentSegments( rootNode, aStartItem, p ); + + setWorld ( rootNode ); + setInitialDirection( Settings().InitialDirection() ); + startPlacement( p, m_currentNet, m_currentWidth, m_currentLayer ); +} + + +void PNS_LINE_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + PNS_LINE current; + VECTOR2I p = aP; + int eiDepth = -1; + + if( aEndItem && aEndItem->Owner() ) + eiDepth = aEndItem->Owner()->Depth(); + + if( m_lastNode ) + { + delete m_lastNode; + m_lastNode = NULL; + } + + route( p ); + + current = Trace(); + + if( !current.PointCount() ) + m_currentEnd = m_p_start; + else + m_currentEnd = current.CLine().CPoint(-1); + + PNS_NODE *latestNode = m_currentNode; + m_lastNode = latestNode->Branch(); + + if( eiDepth >= 0 && aEndItem && latestNode->Depth() > eiDepth && + current.SegmentCount() && current.CPoint( -1 ) == aP ) + { + splitAdjacentSegments( m_lastNode, aEndItem, current.CPoint( -1 ) ); + + if( Settings().RemoveLoops() ) + removeLoops( m_lastNode, ¤t ); + } + + updateLeadingRatLine(); +} + + +bool PNS_LINE_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + bool realEnd = false; + int lastV; + + PNS_LINE pl = Trace(); + + if (m_currentMode == RM_MarkObstacles && + !Settings().CanViolateDRC() && + m_world->CheckColliding( &pl ) ) + return false; + + const SHAPE_LINE_CHAIN& l = pl.CLine(); + + if( !l.SegmentCount() ) + return true; + + VECTOR2I p_pre_last = l.CPoint( -1 ); + const VECTOR2I p_last = l.CPoint( -1 ); + DIRECTION_45 d_last( l.CSegment( -1 ) ); + + if( l.PointCount() > 2 ) + p_pre_last = l.CPoint( -2 ); + + if( aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->Net() ) + realEnd = true; + + if( realEnd || m_placingVia ) + lastV = l.SegmentCount(); + else + lastV = std::max( 1, l.SegmentCount() - 1 ); + + PNS_SEGMENT* lastSeg = NULL; + + for( int i = 0; i < lastV; i++ ) + { + const SEG& s = pl.CSegment( i ); + PNS_SEGMENT* seg = new PNS_SEGMENT( s, m_currentNet ); + seg->SetWidth( pl.Width() ); + seg->SetLayer( m_currentLayer ); + m_lastNode->Add( seg ); + lastSeg = seg; + } + + if( pl.EndsWithVia() ) + m_lastNode->Add( pl.Via().Clone() ); + + if( realEnd ) + simplifyNewLine ( m_lastNode, lastSeg ); + + Router()->CommitRouting ( m_lastNode ); + + m_lastNode = NULL; + + if( !realEnd ) + { + setInitialDirection( d_last ); + VECTOR2I p_start = m_placingVia ? p_last : p_pre_last; + + if( m_placingVia ) + m_currentLayer = Router()->NextCopperLayer( true ); + + setWorld ( Router()->GetWorld()->Branch() ); + startPlacement( p_start, m_head.Net(), m_head.Width(), m_currentLayer ); + + m_startsOnVia = m_placingVia; + m_placingVia = false; + } + + return realEnd; +} + + +void PNS_LINE_PLACER::removeLoops( PNS_NODE* aNode, PNS_LINE* aLatest ) +{ + if( !aLatest->SegmentCount() ) + return; + + aNode->Add( aLatest, true ); + + for( int s = 0; s < aLatest->SegmentCount(); s++ ) + { + PNS_SEGMENT *seg = ( *aLatest->LinkedSegments() )[s]; + PNS_LINE* ourLine = aNode->AssembleLine( seg ); + PNS_JOINT a, b; + std::vector lines; + + aNode->FindLineEnds( ourLine, a, b ); + + if( a == b ) + { + aNode->FindLineEnds( aLatest, a, b); + } + + aNode->FindLinesBetweenJoints( a, b, lines ); + + int removedCount = 0; + int total = 0; + + BOOST_FOREACH( PNS_LINE* line, lines ) + { + total++; + + if( !( line->ContainsSegment( seg ) ) && line->SegmentCount() ) + { + Router()->DisplayDebugLine ( line->CLine(), -1, 10000 ); + + for( int i = 0; i < line->PointCount(); i++ ) + Router()->DisplayDebugPoint( line->CPoint( i ), -1 ); + + aNode->Remove( line ); + removedCount ++; + } + } + + TRACE( 0, "total segs removed: %d/%d\n", removedCount % total ); + + delete ourLine; + } + + aNode->Remove( aLatest ); +} + + +void PNS_LINE_PLACER::simplifyNewLine( PNS_NODE* aNode, PNS_SEGMENT* aLatest ) +{ + PNS_LINE* l = aNode->AssembleLine( aLatest ); + SHAPE_LINE_CHAIN simplified ( l->CLine() ); + + simplified.Simplify(); + + if( simplified.PointCount() != l->PointCount() ) + { + std::auto_ptr lnew ( l->Clone() ); + aNode -> Remove(l); + lnew->SetShape(simplified); + aNode -> Add( lnew.get() ); + } +} + + +void PNS_LINE_PLACER::UpdateSizes( const PNS_ROUTING_SETTINGS& aSettings ) +{ + int trackWidth = aSettings.GetTrackWidth(); + + m_head.SetWidth( trackWidth ); + m_tail.SetWidth( trackWidth ); + + m_viaDiameter = aSettings.GetViaDiameter(); + m_viaDrill = aSettings.GetViaDrill(); +} + + +void PNS_LINE_PLACER::updateLeadingRatLine() +{ + PNS_LINE current = Trace(); + + if( !current.PointCount() ) + return; + + std::auto_ptr tmpNode ( m_lastNode->Branch() ); + tmpNode->Add( ¤t ); + + PNS_JOINT *jt = tmpNode->FindJoint( current.CPoint( -1 ), + current.Layers().Start(), current.Net() ); + + if( !jt ) + return; + + int anchor; + PNS_ITEM *it = tmpNode->NearestUnconnectedItem( jt, &anchor ); + + if( it ) + { + SHAPE_LINE_CHAIN lc; + lc.Append ( current.CPoint( -1 ) ); + lc.Append ( it->Anchor( anchor ) ); + Router()->DisplayDebugLine( lc, 5, 10000 ); + } } diff --git a/pcbnew/router/pns_line_placer.h b/pcbnew/router/pns_line_placer.h index 625e6451b2..66fdb32c17 100644 --- a/pcbnew/router/pns_line_placer.h +++ b/pcbnew/router/pns_line_placer.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_LINE_PLACER_H @@ -29,7 +29,7 @@ #include "pns_node.h" #include "pns_via.h" #include "pns_line.h" -#include "pns_routing_settings.h" +#include "pns_algo_base.h" class PNS_ROUTER; class PNS_SHOVE; @@ -39,29 +39,155 @@ class PNS_ROUTER_BASE; /** * Class PNS_LINE_PLACER * - * Interactively routes a single track. Runs shove and walkaround - * algorithms when needed. + * Single track placement algorithm. Interactively routes a track. + * Applies shove and walkaround algorithms when needed. */ -class PNS_LINE_PLACER +class PNS_LINE_PLACER : public PNS_ALGO_BASE { public: - PNS_LINE_PLACER( PNS_NODE* aWorld ); + PNS_LINE_PLACER( PNS_ROUTER* aRouter ); ~PNS_LINE_PLACER(); - ///> Appends a via at the end of currently placed line. - void AddVia( bool aEnabled, int aDiameter, int aDrill ) - { - m_viaDiameter = aDiameter; - m_viaDrill = aDrill; - m_placingVia = aEnabled; - } - - ///> Starts placement of a line at point aStart. - void StartPlacement( const VECTOR2I& aStart, int aNet, int aWidth, int aLayer ); + /** + * Function Start() + * + * Starts routing a single track at point aP, taking item aStartItem as anchor + * (unless NULL). + */ + void Start ( const VECTOR2I& aP, PNS_ITEM* aStartItem ); /** - * Function Route() + * Function Move() + * + * Moves the end of the currently routed trace to the point aP, taking + * aEndItem as anchor (if not NULL). + * (unless NULL). + */ + void Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + + /** + * Function FixRoute() + * + * Commits the currently routed track to the parent node, taking + * aP as the final end point and aEndItem as the final anchor (if provided). + * @return true, if route has been commited. May return false if the routing + * result is violating design rules - in such case, the track is only committed + * if Settings.CanViolateDRC() is on. + */ + bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + + /** + * Function AddVia() + * + * Enables/disables a via at the end of currently routed trace. + * @param aEnabled if true, a via is attached during placement + * @param aDiameter diameter of the via + * @param aDrill drill of the via + */ + void AddVia( bool aEnabled, int aDiameter, int aDrill ); + + /** + * Function SetLayer() + * + * Sets the current routing layer. + */ + void SetLayer( int aLayer ); + + /** + * Function SetWidth() + * + * Sets the current track width. + */ + void SetWidth( int aWidth ); + + /** + * Function Head() + * + * Returns the "head" of the line being placed, that is the volatile part + * that has not "settled" yet. + */ + const PNS_LINE& Head() const { return m_head; } + + /** + * Function Tail() + * + * Returns the "tail" of the line being placed, the part which has already wrapped around + * and shoved some obstacles. + */ + const PNS_LINE& Tail() const { return m_tail; } + + /** + * Function Trace() + * + * Returns the complete routed line. + */ + const PNS_LINE Trace() const; + + /** + * Function Traces() + * + * Returns the complete routed line, as a single-member PNS_ITEMSET. + */ + const PNS_ITEMSET Traces(); + + /** + * Function CurrentEnd() + * + * Returns the current end of the line being placed. It may not be equal + * to the cursor position due to collisions. + */ + const VECTOR2I& CurrentEnd() const + { + return m_currentEnd; + } + + /** + * Function CurrentNet() + * + * Returns the net code of currently routed track. + */ + int CurrentNet() const + { + return m_currentNet; + } + + /** + * Function CurrentLayer() + * + * Returns the layer of currently routed track. + */ + int CurrentLayer() const + { + return m_currentLayer; + } + + /** + * Function CurrentNode() + * + * Returns the most recent world state. + */ + PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const; + + /** + * Function FlipPosture() + * + * Toggles the current posture (straight/diagonal) of the trace head. + */ + void FlipPosture(); + + /** + * Function UpdateSizes() + * + * Performs on-the-fly update of the width, via diameter & drill size from + * a settings class. Used to dynamically change these parameters as + * the track is routed. + */ + void UpdateSizes( const PNS_ROUTING_SETTINGS& aSettings ); + +private: + /** + * Function route() * * Re-routes the current track to point aP. Returns true, when routing has * completed successfully (i.e. the trace end has reached point aP), and false @@ -70,59 +196,79 @@ public: * @param aP ending point of current route. * @return true, if the routing is complete. */ - bool Route( const VECTOR2I& aP ); + bool route( const VECTOR2I& aP ); - ///> Sets initial routing direction/posture - void SetInitialDirection( const DIRECTION_45& aDirection ); + /** + * Function updateLeadingRatLine() + * + * Draws the "leading" ratsnest line, which connects the end of currently + * routed track and the nearest yet unrouted item. If the routing for + * current net is complete, draws nothing. + */ + void updateLeadingRatLine(); + + /** + * Function setWorld() + * + * Sets the board to route. + */ + void setWorld ( PNS_NODE* aWorld ); + + /** + * Function startPlacement() + * + * Initializes placement of a new line with given parameters. + */ + void startPlacement( const VECTOR2I& aStart, int aNet, int aWidth, int aLayer ); - void ApplySettings( const PNS_ROUTING_SETTINGS& aSettings ); + /** + * Function setInitialDirection() + * + * Sets preferred direction of the very first track segment to be laid. + * Used by posture switching mechanism. + */ + void setInitialDirection( const DIRECTION_45& aDirection ); - ///> Returns the "head" of the line being placed, that is the volatile part - ///> that has not been settled yet - const PNS_LINE& GetHead() const { return m_head; } - ///> Returns the "tail" of the line being placed the part that has been - ///> fixed already (follow mouse mode only) - const PNS_LINE& GetTail() const { return m_tail; } + /** + * Function splitAdjacentSegments() + * + * Checks if point aP lies on segment aSeg. If so, splits the segment in two, + * forming a joint at aP and stores updated topology in node aNode. + */ + void splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ); - ///> Returns the whole routed line - const PNS_LINE GetTrace() const; + /** + * Function removeLoops() + * + * Searches aNode for traces concurrent to aLatest and removes them. Updated + * topology is stored in aNode. + */ + void removeLoops( PNS_NODE* aNode, PNS_LINE* aLatest ); - ///> Returns the current end of the line being placed. It may not be equal - ///> to the cursor position due to collisions. - const VECTOR2I& CurrentEnd() const - { - if( m_head.GetCLine().PointCount() > 0 ) - return m_head.GetCLine().CPoint( -1 ); - else if( m_tail.GetCLine().PointCount() > 0 ) - return m_tail.GetCLine().CPoint( -1 ); - else - return m_p_start; - } - - ///> Returns all items in the world that have been affected by the routing - ///> operation. Used to update data structures of the host application - void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, - PNS_NODE::ItemVector& aAdded ); - - ///> Toggles the current posture (straight/diagonal) of the trace head. - void FlipPosture(); - - ///> Returns the most recent world state - PNS_NODE* GetCurrentNode() const; - -private: - static const double m_shoveLengthThreshold; + /** + * Function simplifyNewLine() + * + * Assembles a line starting from segment aLatest, removes collinear segments + * and redundant vertexes. If a simplification bhas been found, replaces the + * old line with the simplified one in aNode. + */ + void simplifyNewLine ( PNS_NODE *aNode, PNS_SEGMENT *aLatest ); + /** + * Function handleViaPlacement() + * + * Attempts to find a spot to place the via at the end of line aHead. + */ bool handleViaPlacement( PNS_LINE& aHead ); /** * Function checkObtusity() * - * Helper that checks if segments a and b form an obtuse angle + * Helper function, checking if segments a and b form an obtuse angle * (in 45-degree regime). - * @return true, if angle (a, b) is obtuse + * @return true, if angle (aA, aB) is obtuse */ - bool checkObtusity( const SEG& a, const SEG& b ) const; + bool checkObtusity( const SEG& aA, const SEG& aB ) const; /** * Function handleSelfIntersections() @@ -163,8 +309,6 @@ private: */ bool reduceTail( const VECTOR2I& aEnd ); - void fixHeadPosture(); - /** * Function optimizeTailHeadTransition() * @@ -182,8 +326,7 @@ private: * around all colliding solid or non-movable items. Movable segments are * ignored, as they'll be handled later by the shove algorithm. */ - bool routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead, - bool aCwWalkaround = true ); + bool routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead); /** * Function routeStep() @@ -194,19 +337,15 @@ private: */ void routeStep( const VECTOR2I& aP ); - ///> routing mode (walkaround, shove, etc.) - PNS_MODE m_mode; + ///> route step, walkaround mode + bool rhWalkOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead); - ///> follow mouse trail by attaching new segments to the head - ///> as the cursor moves - bool m_follow_mouse; - - ///> mouse smoothing active - bool m_smooth_mouse; - - ///> mouse smoothing step (in world units) - int m_smoothing_step; + ///> route step, shove mode + bool rhShoveOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead); + ///> route step, mark obstacles mode + bool rhMarkObstacles ( const VECTOR2I& aP, PNS_LINE& aNewHead ); + ///> current routing direction DIRECTION_45 m_direction; @@ -235,6 +374,9 @@ private: ///> Current world state PNS_NODE* m_currentNode; + ///> Postprocessed world state (including marked collisions & removed loops) + PNS_NODE* m_lastNode; + ///> Are we placing a via? bool m_placingVia; @@ -244,11 +386,16 @@ private: ///> current via drill int m_viaDrill; - ///> walkaround algorithm iteration limit - int m_walkaroundIterationLimit; + int m_currentWidth; + int m_currentNet; + int m_currentLayer; - ///> smart pads optimizer enabled. - bool m_smartPads; + bool m_startsOnVia; + + VECTOR2I m_originalStart, m_currentEnd, m_currentStart; + PNS_LINE m_currentTrace; + + PNS_MODE m_currentMode; }; #endif // __PNS_LINE_PLACER_H diff --git a/pcbnew/router/pns_logger.cpp b/pcbnew/router/pns_logger.cpp new file mode 100644 index 0000000000..b09578137c --- /dev/null +++ b/pcbnew/router/pns_logger.cpp @@ -0,0 +1,190 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#include "pns_logger.h" +#include "pns_item.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_segment.h" +#include "pns_solid.h" + +#include +#include +#include +#include + +PNS_LOGGER::PNS_LOGGER( ) +{ + m_groupOpened = false; +} + + +PNS_LOGGER::~PNS_LOGGER() +{ +} + + +void PNS_LOGGER::Clear() +{ + m_theLog.str( std::string() ); + m_groupOpened = false; +} + + +void PNS_LOGGER::NewGroup( const std::string& aName, int aIter ) +{ + if( m_groupOpened ) + m_theLog << "endgroup" << std::endl; + + m_theLog << "group " << aName << " " << aIter << std::endl; + m_groupOpened = true; +} + + +void PNS_LOGGER::EndGroup() +{ + if( !m_groupOpened ) + return; + + m_groupOpened = false; + m_theLog << "endgroup" << std::endl; +} + + +void PNS_LOGGER::Log ( const PNS_ITEM* aItem, int aKind, const std::string aName ) +{ + m_theLog << "aItem " << aKind << " " << aName << " "; + m_theLog << aItem->Net() << " " << aItem->Layers().Start() << " " << + aItem->Layers().End() << " " << aItem->Marker() << " " << aItem->Rank(); + + switch( aItem->Kind() ) + { + case PNS_ITEM::LINE: + { + PNS_LINE* l = (PNS_LINE*) aItem; + m_theLog << " line "; + m_theLog << l->Width() << " " << ( l->EndsWithVia() ? 1 : 0 ) << " "; + dumpShape ( l->Shape() ); + m_theLog << std::endl; + break; + } + + case PNS_ITEM::VIA: + { + m_theLog << " via 0 0 "; + dumpShape ( aItem->Shape() ); + m_theLog << std::endl; + break; + } + + case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT* s =(PNS_SEGMENT*) aItem; + m_theLog << " line "; + m_theLog << s->Width() << " 0 linechain 2 0 " << s->Seg().A.x << " " << + s->Seg().A.y << " " << s->Seg().B.x << " " <Seg().B.y << std::endl; + break; + } + + case PNS_ITEM::SOLID: + { + PNS_SOLID* s = (PNS_SOLID*) aItem; + m_theLog << " solid 0 0 "; + dumpShape( s->Shape() ); + m_theLog << std::endl; + break; + } + + default: + break; + } +} + + +void PNS_LOGGER::Log( const SHAPE_LINE_CHAIN *aL, int aKind, const std::string aName ) +{ + m_theLog << "item " << aKind << " " << aName << " "; + m_theLog << 0 << " " << 0 << " " << 0 << " " << 0 << " " << 0; + m_theLog << " line "; + m_theLog << 0 << " " << 0 << " "; + dumpShape( aL ); + m_theLog << std::endl; +} + + +void PNS_LOGGER::Log( const VECTOR2I& aStart, const VECTOR2I& aEnd, + int aKind, const std::string aName) +{ +} + + +void PNS_LOGGER::dumpShape( const SHAPE* aSh ) +{ + switch( aSh->Type() ) + { + case SH_LINE_CHAIN: + { + const SHAPE_LINE_CHAIN* lc = (const SHAPE_LINE_CHAIN*) aSh; + m_theLog << "linechain " << lc->PointCount() << " " << ( lc->IsClosed() ? 1 : 0 ) << " "; + + for( int i = 0; i < lc->PointCount(); i++ ) + m_theLog << lc->CPoint( i ).x << " " << lc->CPoint( i ).y << " "; + + break; + } + + case SH_CIRCLE: + { + const SHAPE_CIRCLE *c = (const SHAPE_CIRCLE*) aSh; + m_theLog << "circle " << c->GetCenter().x << " " << c->GetCenter().y << " " << c->GetRadius(); + break; + } + + case SH_RECT: + { + const SHAPE_RECT* r = (const SHAPE_RECT*) aSh; + m_theLog << "rect " << r->GetPosition().x << " " << r->GetPosition().y << " " << + r->GetSize().x << " " <GetSize().y; + break; + } + + case SH_SEGMENT: + { + const SHAPE_SEGMENT* s = (const SHAPE_SEGMENT*) aSh; + m_theLog << "linechain 2 0 " << s->GetSeg().A.x << " " << s->GetSeg().A.y << " " << + s->GetSeg().B.x << " " << s->GetSeg().B.y; + break; + } + + default: + break; + } +} + +void PNS_LOGGER::Save( const std::string& aFilename ) +{ + EndGroup(); + + FILE* f = fopen( aFilename.c_str(), "wb" ); + printf( "Saving to '%s' [%p]\n", aFilename.c_str(), f ); + const std::string s = m_theLog.str(); + fwrite( s.c_str(), 1, s.length(), f ); + fclose( f ); +} diff --git a/pcbnew/router/pns_logger.h b/pcbnew/router/pns_logger.h new file mode 100644 index 0000000000..9120a43557 --- /dev/null +++ b/pcbnew/router/pns_logger.h @@ -0,0 +1,59 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#ifndef __PNS_LOGGER_H +#define __PNS_LOGGER_H + +#include +#include +#include +#include + +#include + +class PNS_ITEM; +class SHAPE_LINE_CHAIN; +class SHAPE; + +class PNS_LOGGER +{ +public: + PNS_LOGGER(); + ~PNS_LOGGER(); + + void Save( const std::string& aFilename ); + void Clear(); + + void NewGroup( const std::string& aName, int aIter = 0 ); + void EndGroup(); + + void Log( const PNS_ITEM* aItem, int aKind = 0, const std::string aName = std::string() ); + void Log( const SHAPE_LINE_CHAIN *aL, int aKind = 0, const std::string aName = std::string() ); + void Log( const VECTOR2I& aStart, const VECTOR2I& aEnd, int aKind = 0, + const std::string aName = std::string() ); + +private: + void dumpShape ( const SHAPE* aSh ); + + bool m_groupOpened; + std::stringstream m_theLog; +}; + +#endif diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 825be77e57..df63612ab6 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -36,31 +36,41 @@ #include "pns_solid.h" #include "pns_joint.h" #include "pns_index.h" +#include "pns_router.h" using boost::unordered_set; using boost::unordered_map; +#ifdef DEBUG static boost::unordered_set allocNodes; +#endif PNS_NODE::PNS_NODE() { - // printf("MakeNode [%p, total = %d]\n", this, allocNodes.size()); + TRACE( 0, "PNS_NODE::create %p", this ); + m_depth = 0; m_root = this; m_parent = NULL; m_maxClearance = 800000; // fixme: depends on how thick traces are. m_index = new PNS_INDEX; + +#ifdef DEBUG allocNodes.insert( this ); +#endif } PNS_NODE::~PNS_NODE() { + TRACE( 0, "PNS_NODE::delete %p", this ); + if( !m_children.empty() ) { TRACEn( 0, "attempting to free a node that has kids.\n" ); assert( false ); } +#ifdef DEBUG if( allocNodes.find( this ) == allocNodes.end() ) { TRACEn( 0, "attempting to free an already-free'd node.\n" ); @@ -68,34 +78,22 @@ PNS_NODE::~PNS_NODE() } allocNodes.erase( this ); +#endif - for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); - i != m_index->end(); ++i ) + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) + { if( (*i)->BelongsTo( this ) ) delete *i; + } unlinkParent(); delete m_index; } -int PNS_NODE::GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const +int PNS_NODE::GetClearance( const PNS_ITEM* aA, const PNS_ITEM* aB ) const { - int clearance = (*m_clearanceFunctor)( a, b ); - - if( a->OfKind( PNS_ITEM::SEGMENT ) ) - clearance += static_cast(a)->GetWidth() / 2; - - if( a->OfKind( PNS_ITEM::LINE ) ) - clearance += static_cast(a)->GetWidth() / 2; - - if( b->OfKind( PNS_ITEM::SEGMENT ) ) - clearance += static_cast(b)->GetWidth() / 2; - - if( b->OfKind( PNS_ITEM::LINE ) ) - clearance += static_cast(b)->GetWidth() / 2; - - return clearance; + return (*m_clearanceFunctor)( aA, aB ); } @@ -103,8 +101,11 @@ PNS_NODE* PNS_NODE::Branch() { PNS_NODE* child = new PNS_NODE; + TRACE( 0, "PNS_NODE::branch %p (parent %p)", child % this ); + m_children.push_back( child ); + child->m_depth = m_depth + 1; child->m_parent = this; child->m_clearanceFunctor = m_clearanceFunctor; child->m_root = isRoot() ? this : m_root; @@ -114,10 +115,9 @@ PNS_NODE* PNS_NODE::Branch() // to stored items. if( !isRoot() ) { - JointMap::iterator j; + JOINT_MAP::iterator j; - for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); - i != m_index->end(); ++i ) + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) child->m_index->Add( *i ); child->m_joints = m_joints; @@ -150,7 +150,7 @@ void PNS_NODE::unlinkParent() // function object that visits potential obstacles and performs // the actual collision refining -struct PNS_NODE::obstacleVisitor +struct PNS_NODE::OBSTACLE_VISITOR { ///> node we are searching in (either root or a branch) PNS_NODE* m_node; @@ -159,7 +159,7 @@ struct PNS_NODE::obstacleVisitor PNS_NODE* m_override; ///> list of encountered obstacles - Obstacles& m_tab; + OBSTACLES& m_tab; ///> the item we are looking for collisions with const PNS_ITEM* m_item; @@ -173,14 +173,20 @@ struct PNS_NODE::obstacleVisitor ///> number of items found so far int m_matchCount; - obstacleVisitor( PNS_NODE::Obstacles& aTab, const PNS_ITEM* aItem, - int aKindMask ) : + ///> additional clearance + int m_extraClearance; + + OBSTACLE_VISITOR( PNS_NODE::OBSTACLES& aTab, const PNS_ITEM* aItem, int aKindMask ) : m_tab( aTab ), m_item( aItem ), m_kindMask( aKindMask ), m_limitCount( -1 ), - m_matchCount( 0 ) - {}; + m_matchCount( 0 ), + m_extraClearance( 0 ) + { + if( aItem->Kind() == PNS_ITEM::LINE ) + m_extraClearance += static_cast( aItem )->Width() / 2; + } void SetCountLimit( int aLimit ) { @@ -203,14 +209,17 @@ struct PNS_NODE::obstacleVisitor if( m_override && m_override->overrides( aItem ) ) return true; - int clearance = m_node->GetClearance( aItem, m_item ); + int clearance = m_extraClearance + m_node->GetClearance( aItem, m_item ); + + if( aItem->Kind() == PNS_ITEM::LINE ) + clearance += static_cast(aItem)->Width() / 2; if( !aItem->Collide( m_item, clearance ) ) return true; PNS_OBSTACLE obs; - obs.item = aItem; + obs.m_item = aItem; m_tab.push_back( obs ); m_matchCount++; @@ -224,20 +233,22 @@ struct PNS_NODE::obstacleVisitor int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, - PNS_NODE::Obstacles& aObstacles, int aKindMask, int aLimitCount ) + PNS_NODE::OBSTACLES& aObstacles, int aKindMask, int aLimitCount ) { - obstacleVisitor visitor( aObstacles, aItem, aKindMask ); + OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask ); +#ifdef DEBUG assert( allocNodes.find( this ) != allocNodes.end() ); +#endif visitor.SetCountLimit( aLimitCount ); visitor.SetWorld( this, NULL ); - // first, look for colliding items ourselves + // first, look for colliding items in the local index m_index->Query( aItem, m_maxClearance, visitor ); // if we haven't found enough items, look in the root branch as well. - if( !isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0) ) + if( !isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0 ) ) { visitor.SetWorld( m_root, this ); m_root->m_index->Query( aItem, m_maxClearance, visitor ); @@ -247,12 +258,12 @@ int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, } -PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKindMask ) +PNS_NODE::OPT_OBSTACLE PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKindMask ) { - Obstacles obs_list; + OBSTACLES obs_list; bool found_isects = false; - const SHAPE_LINE_CHAIN& line = aItem->GetCLine(); + const SHAPE_LINE_CHAIN& line = aItem->CLine(); obs_list.reserve( 100 ); @@ -265,17 +276,17 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKin } if( aItem->EndsWithVia() ) - n += QueryColliding( &aItem->GetVia(), obs_list, aKindMask ); + n += QueryColliding( &aItem->Via(), obs_list, aKindMask ); // if(! QueryColliding ( aItem, obs_list, aKindMask )) if( !n ) - return OptObstacle(); + return OPT_OBSTACLE(); PNS_LINE& aLine = (PNS_LINE&) *aItem; PNS_OBSTACLE nearest; - nearest.item = NULL; - nearest.dist_first = INT_MAX; + nearest.m_item = NULL; + nearest.m_distFirst = INT_MAX; BOOST_FOREACH( PNS_OBSTACLE obs, obs_list ) { @@ -284,30 +295,30 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKin std::vector isect_list; - int clearance = GetClearance( obs.item, &aLine ); + int clearance = GetClearance( obs.m_item, &aLine ); - SHAPE_LINE_CHAIN hull = obs.item->Hull( clearance ); + SHAPE_LINE_CHAIN hull = obs.m_item->Hull( clearance, aItem->Width() ); if( aLine.EndsWithVia() ) { - int clearance = GetClearance( obs.item, &aLine.GetVia() ); + int clearance = GetClearance( obs.m_item, &aLine.Via() ); - SHAPE_LINE_CHAIN viaHull = aLine.GetVia().Hull( clearance ); + SHAPE_LINE_CHAIN viaHull = aLine.Via().Hull( clearance, aItem->Width() ); viaHull.Intersect( hull, isect_list ); BOOST_FOREACH( SHAPE_LINE_CHAIN::INTERSECTION isect, isect_list ) { - int dist = aLine.GetCLine().Length() + - ( isect.p - aLine.GetVia().GetPos() ).EuclideanNorm(); + int dist = aLine.CLine().Length() + + ( isect.p - aLine.Via().Pos() ).EuclideanNorm(); - if( dist < nearest.dist_first ) + if( dist < nearest.m_distFirst ) { found_isects = true; - nearest.dist_first = dist; - nearest.ip_first = isect.p; - nearest.item = obs.item; - nearest.hull = hull; + nearest.m_distFirst = dist; + nearest.m_ipFirst = isect.p; + nearest.m_item = obs.m_item; + nearest.m_hull = hull; } if( dist > dist_max ) @@ -320,19 +331,19 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKin isect_list.clear(); - hull.Intersect( aLine.GetCLine(), isect_list ); + hull.Intersect( aLine.CLine(), isect_list ); BOOST_FOREACH( SHAPE_LINE_CHAIN::INTERSECTION isect, isect_list ) { - int dist = aLine.GetCLine().PathLength( isect.p ); + int dist = aLine.CLine().PathLength( isect.p ); - if( dist < nearest.dist_first ) + if( dist < nearest.m_distFirst ) { found_isects = true; - nearest.dist_first = dist; - nearest.ip_first = isect.p; - nearest.item = obs.item; - nearest.hull = hull; + nearest.m_distFirst = dist; + nearest.m_ipFirst = isect.p; + nearest.m_item = obs.m_item; + nearest.m_hull = hull; } if( dist > dist_max ) @@ -342,25 +353,42 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKin } } - nearest.ip_last = ip_last; - nearest.dist_last = dist_max; + nearest.m_ipLast = ip_last; + nearest.m_distLast = dist_max; } - return found_isects ? nearest : OptObstacle(); + if( !found_isects ) + nearest.m_item = obs_list[0].m_item; + + return nearest; } -PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKindMask ) +PNS_NODE::OPT_OBSTACLE PNS_NODE::CheckColliding( const PNS_ITEMSET& aSet, int aKindMask ) { - Obstacles obs; + BOOST_FOREACH( const PNS_ITEM* item, aSet.CItems() ) + { + OPT_OBSTACLE obs = CheckColliding( item, aKindMask ); + + if( obs ) + return obs; + } + + return OPT_OBSTACLE(); +} + + +PNS_NODE::OPT_OBSTACLE PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKindMask ) +{ + OBSTACLES obs; obs.reserve( 100 ); - if( aItemA->GetKind() == PNS_ITEM::LINE ) + if( aItemA->Kind() == PNS_ITEM::LINE ) { int n = 0; - const PNS_LINE* line = static_cast(aItemA); - const SHAPE_LINE_CHAIN& l = line->GetCLine(); + const PNS_LINE* line = static_cast( aItemA ); + const SHAPE_LINE_CHAIN& l = line->CLine(); for( int i = 0; i < l.SegmentCount(); i++ ) { @@ -368,43 +396,48 @@ PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKin n += QueryColliding( &s, obs, aKindMask, 1 ); if( n ) - return OptObstacle( obs[0] ); + return OPT_OBSTACLE( obs[0] ); } if( line->EndsWithVia() ) { - n += QueryColliding( &line->GetVia(), obs, aKindMask, 1 ); + n += QueryColliding( &line->Via(), obs, aKindMask, 1 ); if( n ) - return OptObstacle( obs[0] ); + return OPT_OBSTACLE( obs[0] ); } } else if( QueryColliding( aItemA, obs, aKindMask, 1 ) > 0 ) - return OptObstacle( obs[0] ); + return OPT_OBSTACLE( obs[0] ); - return OptObstacle(); + return OPT_OBSTACLE(); } bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, int aKindMask ) { - Obstacles dummy; - assert( aItemB ); - // return QueryColliding(aItemA, dummy, aKindMask, 1) > 0; + int clearance = GetClearance( aItemA, aItemB ); - return aItemA->Collide( aItemB, GetClearance( aItemA, aItemB ) ); + // fixme: refactor + if( aItemA->Kind() == PNS_ITEM::LINE ) + clearance += static_cast( aItemA )->Width() / 2; + if( aItemB->Kind() == PNS_ITEM::LINE ) + clearance += static_cast( aItemB )->Width() / 2; + + return aItemA->Collide( aItemB, clearance ); } -struct hitVisitor +struct HIT_VISITOR { PNS_ITEMSET& m_items; const VECTOR2I& m_point; const PNS_NODE* m_world; - hitVisitor( PNS_ITEMSET& aTab, const VECTOR2I& aPoint, const PNS_NODE* aWorld ) : - m_items( aTab ), m_point( aPoint ), m_world( aWorld ) {}; + HIT_VISITOR( PNS_ITEMSET& aTab, const VECTOR2I& aPoint, const PNS_NODE* aWorld ) : + m_items( aTab ), m_point( aPoint ), m_world( aWorld ) + {} bool operator()( PNS_ITEM* aItem ) { @@ -412,10 +445,7 @@ struct hitVisitor int cl = 0; - if( aItem->GetKind() == PNS_ITEM::SEGMENT ) - cl += static_cast(aItem)->GetWidth() / 2; - - if( aItem->GetShape()->Collide( &cp, cl ) ) + if( aItem->Shape()->Collide( &cp, cl ) ) m_items.Add( aItem ); return true; @@ -426,19 +456,20 @@ struct hitVisitor const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint ) const { PNS_ITEMSET items; + // fixme: we treat a point as an infinitely small circle - this is inefficient. SHAPE_CIRCLE s( aPoint, 0 ); - hitVisitor visitor( items, aPoint, this ); + HIT_VISITOR visitor( items, aPoint, this ); m_index->Query( &s, m_maxClearance, visitor ); if( !isRoot() ) // fixme: could be made cleaner { PNS_ITEMSET items_root; - hitVisitor visitor_root( items_root, aPoint, m_root ); + HIT_VISITOR visitor_root( items_root, aPoint, m_root ); m_root->m_index->Query( &s, m_maxClearance, visitor_root ); - BOOST_FOREACH( PNS_ITEM * item, items_root.Items() ) + BOOST_FOREACH( PNS_ITEM* item, items_root.Items() ) { if( !overrides( item ) ) items.Add( item ); @@ -451,21 +482,21 @@ const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint ) const void PNS_NODE::addSolid( PNS_SOLID* aSolid ) { - linkJoint( aSolid->GetCenter(), aSolid->GetLayers(), aSolid->GetNet(), aSolid ); + linkJoint( aSolid->Pos(), aSolid->Layers(), aSolid->Net(), aSolid ); m_index->Add( aSolid ); } void PNS_NODE::addVia( PNS_VIA* aVia ) { - linkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); + linkJoint( aVia->Pos(), aVia->Layers(), aVia->Net(), aVia ); m_index->Add( aVia ); } -void PNS_NODE::addLine( PNS_LINE* aLine ) +void PNS_NODE::addLine( PNS_LINE* aLine, bool aAllowRedundant ) { - const SHAPE_LINE_CHAIN& l = aLine->GetLine(); + SHAPE_LINE_CHAIN& l = aLine->Line(); for( int i = 0; i < l.SegmentCount(); i++ ) { @@ -474,57 +505,69 @@ void PNS_NODE::addLine( PNS_LINE* aLine ) if( s.A != s.B ) { PNS_SEGMENT* pseg = new PNS_SEGMENT( *aLine, s ); + PNS_SEGMENT* psegR = NULL; - pseg->SetOwner( this ); + if ( !aAllowRedundant ) + psegR = findRedundantSegment( pseg ); - linkJoint( s.A, pseg->GetLayers(), aLine->GetNet(), pseg ); - linkJoint( s.B, pseg->GetLayers(), aLine->GetNet(), pseg ); + if( psegR ) + aLine->LinkSegment( psegR ); + else + { + pseg->SetOwner( this ); - aLine->LinkSegment( pseg ); + linkJoint( s.A, pseg->Layers(), aLine->Net(), pseg ); + linkJoint( s.B, pseg->Layers(), aLine->Net(), pseg ); - m_index->Add( pseg ); - } + aLine->LinkSegment( pseg ); + + m_index->Add( pseg ); + } + } } } -void PNS_NODE::addSegment( PNS_SEGMENT* aSeg ) +void PNS_NODE::addSegment( PNS_SEGMENT* aSeg, bool aAllowRedundant ) { - if( aSeg->GetSeg().A == aSeg->GetSeg().B ) + if( aSeg->Seg().A == aSeg->Seg().B ) { TRACEn( 0, "attempting to add a segment with same end coordinates, ignoring." ) return; } + if( !aAllowRedundant && findRedundantSegment ( aSeg ) ) + return; + aSeg->SetOwner( this ); - linkJoint( aSeg->GetSeg().A, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); - linkJoint( aSeg->GetSeg().B, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + linkJoint( aSeg->Seg().A, aSeg->Layers(), aSeg->Net(), aSeg ); + linkJoint( aSeg->Seg().B, aSeg->Layers(), aSeg->Net(), aSeg ); m_index->Add( aSeg ); } -void PNS_NODE::Add( PNS_ITEM* aItem ) +void PNS_NODE::Add( PNS_ITEM* aItem, bool aAllowRedundant ) { aItem->SetOwner( this ); - switch( aItem->GetKind() ) + switch( aItem->Kind() ) { case PNS_ITEM::SOLID: addSolid( static_cast( aItem ) ); break; case PNS_ITEM::SEGMENT: - addSegment( static_cast( aItem ) ); + addSegment( static_cast( aItem ), aAllowRedundant ); break; case PNS_ITEM::LINE: - addLine( static_cast (aItem) ); + addLine( static_cast( aItem ), aAllowRedundant ); break; case PNS_ITEM::VIA: - addVia( static_cast(aItem) ); + addVia( static_cast( aItem ) ); break; default: @@ -535,6 +578,8 @@ void PNS_NODE::Add( PNS_ITEM* aItem ) void PNS_NODE::doRemove( PNS_ITEM* aItem ) { + // assert(m_root->m_index->Contains(aItem) || m_index->Contains(aItem)); + // case 1: removing an item that is stored in the root node from any branch: // mark it as overridden, but do not remove if( aItem->BelongsTo( m_root ) && !isRoot() ) @@ -553,8 +598,8 @@ void PNS_NODE::doRemove( PNS_ITEM* aItem ) void PNS_NODE::removeSegment( PNS_SEGMENT* aSeg ) { - unlinkJoint( aSeg->GetSeg().A, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); - unlinkJoint( aSeg->GetSeg().B, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + unlinkJoint( aSeg->Seg().A, aSeg->Layers(), aSeg->Net(), aSeg ); + unlinkJoint( aSeg->Seg().B, aSeg->Layers(), aSeg->Net(), aSeg ); doRemove( aSeg ); } @@ -562,12 +607,18 @@ void PNS_NODE::removeSegment( PNS_SEGMENT* aSeg ) void PNS_NODE::removeLine( PNS_LINE* aLine ) { - std::vector* segRefs = aLine->GetLinkedSegments(); + std::vector* segRefs = aLine->LinkedSegments(); - if( !segRefs ) + if(! aLine->SegmentCount() ) return; - assert( aLine->GetOwner() ); + assert (segRefs != NULL); + assert (aLine->Owner()); + + if ( (int) segRefs->size() != aLine->SegmentCount() ) + { + //printf("******weird deletion: segrefs %d segcount %d hasloops %d\n", segRefs->size(), aLine->SegmentCount(), aLine->HasLoops()); + } BOOST_FOREACH( PNS_SEGMENT* seg, *segRefs ) { @@ -575,14 +626,57 @@ void PNS_NODE::removeLine( PNS_LINE* aLine ) } aLine->SetOwner( NULL ); + aLine->ClearSegmentLinks(); } void PNS_NODE::removeVia( PNS_VIA* aVia ) { - unlinkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); + // We have to split a single joint (associated with a via, binding together multiple layers) + // into multiple independent joints. As I'm a lazy bastard, I simply delete the via and all its links and re-insert them. - doRemove( aVia ); + PNS_JOINT::HASH_TAG tag; + + VECTOR2I p( aVia->Pos() ); + PNS_LAYERSET vLayers( aVia->Layers() ); + int net = aVia->Net(); + + PNS_JOINT* jt = FindJoint( p, vLayers.Start(), net ); + PNS_JOINT::LINKED_ITEMS links( jt->LinkList() ); + + tag.net = net; + tag.pos = p; + + bool split; + do + { + split = false; + std::pair range = m_joints.equal_range( tag ); + + if( range.first == m_joints.end() ) + break; + + // find and remove all joints containing the via to be removed + + for( JOINT_MAP::iterator f = range.first; f != range.second; ++f ) + { + if( aVia->LayersOverlap ( &f->second ) ) + { + m_joints.erase( f ); + split = true; + break; + } + } + } while( split ); + + // and re-link them, using the former via's link list + BOOST_FOREACH(PNS_ITEM* item, links) + { + if( item != aVia ) + linkJoint ( p, item->Layers(), net, item ); + } + + doRemove( aVia ); } @@ -595,10 +689,11 @@ void PNS_NODE::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) void PNS_NODE::Remove( PNS_ITEM* aItem ) { - switch( aItem->GetKind() ) + switch( aItem->Kind() ) { case PNS_ITEM::SOLID: - assert( false ); + // fixme: this fucks up the joints, but it's only used for marking colliding obstacles for the moment, so we don't care. + doRemove ( aItem ); break; case PNS_ITEM::SEGMENT: @@ -619,36 +714,37 @@ void PNS_NODE::Remove( PNS_ITEM* aItem ) } -void PNS_NODE::followLine( PNS_SEGMENT* current, bool scanDirection, int& pos, - int limit, VECTOR2I* corners, PNS_SEGMENT** segments ) +void PNS_NODE::followLine( PNS_SEGMENT* aCurrent, bool aScanDirection, int& aPos, + int aLimit, VECTOR2I* aCorners, PNS_SEGMENT** aSegments ) { bool prevReversed = false; for( ; ; ) { const VECTOR2I p = - (scanDirection ^ prevReversed) ? current->GetSeg().B : current->GetSeg().A; - const OptJoint jt = FindJoint( p, current->GetLayer(), current->GetNet() ); + ( aScanDirection ^ prevReversed ) ? aCurrent->Seg().B : aCurrent->Seg().A; + const PNS_JOINT* jt = FindJoint( p, aCurrent ); assert( jt ); - assert( pos > 0 && pos < limit ); + assert( aPos > 0 && aPos < aLimit ); - corners[pos] = jt->GetPos(); - segments[pos] = current; + aCorners[aPos] = jt->Pos(); + aSegments[aPos] = aCurrent; - pos += (scanDirection ? 1 : -1); + aPos += ( aScanDirection ? 1 : -1 ); if( !jt->IsLineCorner() ) break; - current = jt->NextSegment( current ); + aCurrent = jt->NextSegment( aCurrent ); + prevReversed = - ( jt->GetPos() == (scanDirection ? current->GetSeg().B : current->GetSeg().A ) ); + ( jt->Pos() == (aScanDirection ? aCurrent->Seg().B : aCurrent->Seg().A ) ); } } -PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, const OptJoint& a, const OptJoint& b ) +PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex) { const int MaxVerts = 1024; @@ -658,60 +754,157 @@ PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, const OptJoint& a, const Op PNS_LINE* pl = new PNS_LINE; int i_start = MaxVerts / 2, i_end = i_start + 1; - pl->SetWidth( aSeg->GetWidth() ); - pl->SetLayers( aSeg->GetLayers() ); - pl->SetNet( aSeg->GetNet() ); + pl->SetWidth( aSeg->Width() ); + pl->SetLayers( aSeg->Layers() ); + pl->SetNet( aSeg->Net() ); pl->SetOwner( this ); - // pl->LinkSegment(aSeg); - followLine( aSeg, false, i_start, MaxVerts, corners, segs ); followLine( aSeg, true, i_end, MaxVerts, corners, segs ); + int n = 0; - int clip_start = -1, clip_end = -1; + PNS_SEGMENT* prev_seg = NULL; for( int i = i_start + 1; i < i_end; i++ ) { const VECTOR2I& p = corners[i]; - if( a && ( p == a->GetPos() || p == b->GetPos() ) ) + pl->Line().Append( p ); + + if( prev_seg != segs[i] ) { - clip_start = std::min( clip_start, i ); - clip_end = std::max( clip_end, i ); + pl->LinkSegment( segs[i] ); + + if( segs[i] == aSeg && aOriginSegmentIndex ) + *aOriginSegmentIndex = n; + + n++; } - pl->GetLine().Append( p ); - - if( segs[i - 1] != segs[i] ) - pl->LinkSegment( segs[i] ); + prev_seg = segs[i]; } + + assert( pl->SegmentCount() != 0 ); + assert( pl->SegmentCount() == (int) pl->LinkedSegments()->size() ); + return pl; } -void PNS_NODE::FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b ) +void PNS_NODE::FindLineEnds( PNS_LINE* aLine, PNS_JOINT& aA, PNS_JOINT& aB ) { - a = *FindJoint( aLine->GetCLine().CPoint( 0 ), aLine->GetLayers().Start(), aLine->GetNet() ); - b = *FindJoint( aLine->GetCLine().CPoint( -1 ), aLine->GetLayers().Start(), aLine->GetNet() ); + aA = *FindJoint( aLine->CPoint( 0 ), aLine ); + aB = *FindJoint( aLine->CPoint( -1 ), aLine ); } -int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, std::vector& aLines ) +void PNS_NODE::MapConnectivity ( PNS_JOINT* aStart, std::vector& aFoundJoints ) { - BOOST_FOREACH( PNS_ITEM* item, a.GetLinkList() ) + std::deque searchQueue; + std::set processed; + + searchQueue.push_back( aStart ); + processed.insert( aStart ); + + while( !searchQueue.empty() ) { - if( item->GetKind() == PNS_ITEM::SEGMENT ) + PNS_JOINT* current = searchQueue.front(); + searchQueue.pop_front(); + + BOOST_FOREACH( PNS_ITEM* item, current->LinkList() ) { - PNS_SEGMENT* seg = static_cast(item); + if ( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_SEGMENT* seg = static_cast( item ); + PNS_JOINT* a = FindJoint( seg->Seg().A, seg ); + PNS_JOINT* b = FindJoint( seg->Seg().B, seg ); + PNS_JOINT* next = ( *a == *current ) ? b : a; + + if( processed.find( next ) == processed.end() ) + { + processed.insert( next ); + searchQueue.push_back( next ); + } + } + } + } + + BOOST_FOREACH(PNS_JOINT* jt, processed) + aFoundJoints.push_back( jt ); +} + + +PNS_ITEM* PNS_NODE::NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor, int aKindMask ) +{ + std::set disconnected; + std::vector joints; + + AllItemsInNet( aStart->Net(), disconnected ); + MapConnectivity ( aStart, joints ); + + BOOST_FOREACH( PNS_JOINT *jt, joints ) + { + BOOST_FOREACH( PNS_ITEM* link, jt->LinkList() ) + { + if( disconnected.find( link ) != disconnected.end() ) + disconnected.erase( link ); + } + } + + int best_dist = INT_MAX; + PNS_ITEM* best = NULL; + + BOOST_FOREACH( PNS_ITEM* item, disconnected ) + { + if( item->OfKind( aKindMask ) ) + { + for(int i = 0; i < item->AnchorCount(); i++) + { + VECTOR2I p = item->Anchor( i ); + int d = ( p - aStart->Pos() ).EuclideanNorm(); + + if( d < best_dist ) + { + best_dist = d; + best = item; + + if( aAnchor ) + *aAnchor = i; + } + } + } + } + + return best; +} + + +int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& aA, PNS_JOINT& aB, std::vector& aLines ) +{ + BOOST_FOREACH( PNS_ITEM* item, aA.LinkList() ) + { + if( item->Kind() == PNS_ITEM::SEGMENT ) + { + PNS_SEGMENT* seg = static_cast( item ); PNS_LINE* line = AssembleLine( seg ); PNS_JOINT j_start, j_end; + FindLineEnds( line, j_start, j_end ); - if( (j_start == a && j_end == b )|| (j_end == a && j_start == b) ) + int id_start = line->CLine().Find( aA.Pos() ); + int id_end = line->CLine().Find( aB.Pos() ); + + if( id_end < id_start ) + std::swap( id_end, id_start ); + + if( id_start >= 0 && id_end >= 0 ) + { + line->ClipVertexRange ( id_start, id_end ); aLines.push_back( line ); + } else delete line; } @@ -721,14 +914,14 @@ int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, std::vectorsecond.GetLayers().Overlaps( aLayer ) ) - return f->second; + if( f->second.Layers().Overlaps( aLayer ) ) + return &f->second; ++f; } - return OptJoint(); + return NULL; } PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet ) { - PNS_JOINT::HashTag tag; + PNS_JOINT::HASH_TAG tag; tag.pos = aPos; tag.net = aNet; // try to find the joint in this node. - JointMap::iterator f = m_joints.find( tag ); + JOINT_MAP::iterator f = m_joints.find( tag ); - std::pair range; + std::pair range; // not found and we are not root? find in the root and copy results here. if( f == m_joints.end() && !isRoot() ) @@ -787,7 +980,7 @@ PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLaye for( f = range.first; f != range.second; ++f ) { - if( aLayers.Overlaps( f->second.GetLayers() ) ) + if( aLayers.Overlaps( f->second.Layers() ) ) { jt.Merge( f->second ); m_joints.erase( f ); @@ -795,7 +988,8 @@ PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLaye break; } } - } while( merged ); + } + while( merged ); return m_joints.insert( TagJointPair( tag, jt ) )->second; } @@ -808,10 +1002,8 @@ void PNS_JOINT::Dump() const } -void PNS_NODE::linkJoint( const VECTOR2I& aPos, - const PNS_LAYERSET& aLayers, - int aNet, - PNS_ITEM* aWhere ) +void PNS_NODE::linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet, PNS_ITEM* aWhere ) { PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); @@ -820,7 +1012,7 @@ void PNS_NODE::linkJoint( const VECTOR2I& aPos, void PNS_NODE::unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, - int aNet, PNS_ITEM* aWhere ) + int aNet, PNS_ITEM* aWhere ) { // fixme: remove dangling joints PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); @@ -838,7 +1030,7 @@ void PNS_NODE::Dump( bool aLong ) for( i = m_items.begin(); i != m_items.end(); i++ ) { if( (*i)->GetKind() == PNS_ITEM::SEGMENT ) - all_segs.insert( static_cast(*i) ); + all_segs.insert( static_cast( *i ) ); } if( !isRoot() ) @@ -850,24 +1042,24 @@ void PNS_NODE::Dump( bool aLong ) } } - JointMap::iterator j; + JOINT_MAP::iterator j; if( aLong ) - for( j = m_joints.begin(); j!=m_joints.end(); ++j ) + for( j = m_joints.begin(); j != m_joints.end(); ++j ) { printf( "joint : %s, links : %d\n", j->second.GetPos().Format().c_str(), j->second.LinkCount() ); - PNS_JOINT::LinkedItems::const_iterator k; + PNS_JOINT::LINKED_ITEMS::const_iterator k; for( k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k ) { - const PNS_ITEM* item = *k; + const PNS_ITEM* m_item = *k; - switch( item->GetKind() ) + switch( m_item->GetKind() ) { case PNS_ITEM::SEGMENT: { - const PNS_SEGMENT* seg = static_cast(item); + const PNS_SEGMENT* seg = static_cast( m_item ); printf( " -> seg %s %s\n", seg->GetSeg().A.Format().c_str(), seg->GetSeg().B.Format().c_str() ); break; @@ -892,7 +1084,6 @@ void PNS_NODE::Dump( bool aLong ) if( aLong ) printf( "Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() ); - for( std::vector::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j ) { printf( "%s ", (*j)->GetSeg().A.Format().c_str() ); @@ -911,7 +1102,7 @@ void PNS_NODE::Dump( bool aLong ) } -void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded ) +void PNS_NODE::GetUpdatedItems( ITEM_VECTOR& aRemoved, ITEM_VECTOR& aAdded ) { aRemoved.reserve( m_override.size() ); aAdded.reserve( m_index->Size() ); @@ -919,10 +1110,10 @@ void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded ) if( isRoot() ) return; - BOOST_FOREACH( PNS_ITEM * item, m_override ) + BOOST_FOREACH( PNS_ITEM* item, m_override ) aRemoved.push_back( item ); - for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); i!=m_index->end(); ++i ) + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) aAdded.push_back( *i ); } @@ -932,7 +1123,8 @@ void PNS_NODE::releaseChildren() // copy the kids as the PNS_NODE destructor erases the item from the parent node. std::vector kids = m_children; - BOOST_FOREACH( PNS_NODE * node, kids ) { + BOOST_FOREACH( PNS_NODE * node, kids ) + { node->releaseChildren(); delete node; } @@ -947,9 +1139,13 @@ void PNS_NODE::Commit( PNS_NODE* aNode ) BOOST_FOREACH( PNS_ITEM * item, aNode->m_override ) Remove( item ); - for( PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin(); + for( PNS_INDEX::ITEM_SET::iterator i = aNode->m_index->begin(); i != aNode->m_index->end(); ++i ) + { + (*i)->SetRank( -1 ); + (*i)->Unmark(); Add( *i ); + } releaseChildren(); } @@ -957,29 +1153,93 @@ void PNS_NODE::Commit( PNS_NODE* aNode ) void PNS_NODE::KillChildren() { - assert( isRoot() ); - + assert ( isRoot() ); releaseChildren(); } -void PNS_NODE::AllItemsInNet( int aNet, std::list& aItems ) +void PNS_NODE::AllItemsInNet( int aNet, std::set& aItems ) { - PNS_INDEX::NetItemsList* l_cur = m_index->GetItemsForNet( aNet ); - - if( !l_cur ) - return; - - std::copy( aItems.begin(), l_cur->begin(), l_cur->end() ); + PNS_INDEX::NET_ITEMS_LIST* l_cur = m_index->GetItemsForNet( aNet ); + if( l_cur ) + { + BOOST_FOREACH( PNS_ITEM*item, *l_cur ) + aItems.insert( item ); + } + if( !isRoot() ) { - PNS_INDEX::NetItemsList* l_root = m_root->m_index->GetItemsForNet( aNet ); - - for( PNS_INDEX::NetItemsList::iterator i = l_root->begin(); i!= l_root->end(); ++i ) - if( !overrides( *i ) ) - aItems.push_back( *i ); - + PNS_INDEX::NET_ITEMS_LIST* l_root = m_root->m_index->GetItemsForNet( aNet ); + if( l_root ) + for( PNS_INDEX::NET_ITEMS_LIST::iterator i = l_root->begin(); i!= l_root->end(); ++i ) + if( !overrides( *i ) ) + aItems.insert( *i ); } } + + +void PNS_NODE::ClearRanks() +{ + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) + { + (*i)->SetRank( -1 ); + (*i)->Mark( 0 ); + } +} + + +int PNS_NODE::FindByMarker( int aMarker, PNS_ITEMSET& aItems ) +{ + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) + { + if( (*i)->Marker() & aMarker ) + aItems.Add( *i ); + } + + return 0; +} + + +int PNS_NODE::RemoveByMarker( int aMarker ) +{ + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) + { + if ( (*i)->Marker() & aMarker ) + { + Remove( *i ); + } + } + + return 0; +} + + +PNS_SEGMENT* PNS_NODE::findRedundantSegment ( PNS_SEGMENT *aSeg ) +{ + PNS_JOINT* jtStart = FindJoint ( aSeg->Seg().A, aSeg ); + + if( !jtStart ) + return NULL; + + BOOST_FOREACH( PNS_ITEM* item, jtStart->LinkList() ) + { + if( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_SEGMENT* seg2 = (PNS_SEGMENT*) item; + + const VECTOR2I a1( aSeg->Seg().A ); + const VECTOR2I b1( aSeg->Seg().B ); + + const VECTOR2I a2( seg2->Seg().A ); + const VECTOR2I b2( seg2->Seg().B ); + + if( seg2->Layers().Start() == aSeg->Layers().Start() && + ( ( a1 == a2 && b1 == b2 ) || ( a1 == b2 && a2 == b1 ) ) ) + return seg2; + } + } + + return NULL; +} diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index de3e886dc2..f4d728a3d6 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,8 +15,9 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ + #ifndef __PNS_NODE_H #define __PNS_NODE_H @@ -26,7 +27,6 @@ #include #include #include -#include #include #include @@ -43,12 +43,16 @@ class PNS_VIA; class PNS_RATSNEST; class PNS_INDEX; -using boost::shared_ptr; +/** + * Class PNS_CLEARANCE_FUNC + * + * An abstract function object, returning a required clearance between two items. + **/ class PNS_CLEARANCE_FUNC { public: - virtual int operator()( const PNS_ITEM* a, const PNS_ITEM* b ) = 0; + virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) = 0; virtual ~PNS_CLEARANCE_FUNC() {} }; @@ -61,20 +65,20 @@ public: struct PNS_OBSTACLE { ///> Item we search collisions with - PNS_ITEM* head; + PNS_ITEM* m_head; - ///> Item found to be colliding with head - PNS_ITEM* item; + ///> Item found to be colliding with m_head + PNS_ITEM* m_item; - ///> Hull of the colliding item - SHAPE_LINE_CHAIN hull; + ///> Hull of the colliding m_item + SHAPE_LINE_CHAIN m_hull; ///> First and last intersection point between the head item and the hull - ///> of the colliding item - VECTOR2I ip_first, ip_last; + ///> of the colliding m_item + VECTOR2I m_ipFirst, m_ipLast; ///> ... and the distance thereof - int dist_first, dist_last; + int m_distFirst, m_distLast; }; /** @@ -84,25 +88,23 @@ struct PNS_OBSTACLE * hierarchical and indexed way. * Features: * - spatial-indexed container for PCB item shapes - * - collision search (with clearance checking) + * - collision search & clearance checking * - assembly of lines connecting joints, finding loops and unique paths * - lightweight cloning/branching (for recursive optimization and shove * springback) **/ - class PNS_NODE { public: - typedef boost::optional OptObstacle; - typedef std::vector ItemVector; - typedef std::vector Obstacles; - typedef boost::optional OptJoint; - - PNS_NODE(); - ~PNS_NODE(); + typedef boost::optional OPT_OBSTACLE; + typedef std::vector ITEM_VECTOR; + typedef std::vector OBSTACLES; + + PNS_NODE (); + ~PNS_NODE (); ///> Returns the expected clearance between items a and b. - int GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const; + int GetClearance( const PNS_ITEM* aA, const PNS_ITEM* aB ) const; ///> Returns the pre-set worst case clearance between any pair of items int GetMaxClearance() const @@ -110,104 +112,235 @@ public: return m_maxClearance; } + ///> Sets the worst-case clerance between any pair of items void SetMaxClearance( int aClearance ) { m_maxClearance = aClearance; } + ///> Assigns a clerance resolution function object void SetClearanceFunctor( PNS_CLEARANCE_FUNC* aFunc ) { m_clearanceFunctor = aFunc; } - ///> Finds items that collide with aItem and stores collision information - ///> in aObstacles. - int QueryColliding( const PNS_ITEM* aItem, - Obstacles& aObstacles, - int aKindMask = PNS_ITEM::ANY, - int aLimitCount = -1 ); - - ///> Finds the nearest item that collides with aItem. - OptObstacle NearestObstacle( const PNS_LINE* aItem, int aKindMask = PNS_ITEM::ANY ); - - ///> Checks if the item collides with anything else in the world, - ///> and returns it if so. - OptObstacle CheckColliding( const PNS_ITEM* aItem, int aKindMask = PNS_ITEM::ANY ); - - ///> Checks if two items collide [deprecated]. - bool CheckColliding( const PNS_ITEM* aItemA, - const PNS_ITEM* aItemB, - int aKindMask = PNS_ITEM::ANY ); - - ///> Hit detection - const PNS_ITEMSET HitTest( const VECTOR2I& aPoint ) const; - - void Add( PNS_ITEM* aItem ); - void Remove( PNS_ITEM* aItem ); - void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); - - ///> Creates a lightweight copy ("branch") of self. Note that if there are - ///> any branches in use, their parents must NOT be deleted. - PNS_NODE* Branch(); - - ///> Assembles a line connecting two non-trivial joints the - ///> segment aSeg belongs to. - PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg, - const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() ); - - ///> Dumps the contents and joints structure - void Dump( bool aLong = false ); - ///> Returns the number of joints int JointCount() const { return m_joints.size(); } - ///> Returns the lists of items removed and added in this branch, with - ///> respect to the root. - void GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded ); + ///> Returns the number of nodes in the inheritance chain (wrs to the root node) + int Depth() const + { + return m_depth; + } - ///> Copies the changes from a given branch (aNode) to the root. Called on - ///> a non-root branch will fail. + /** + * Function QueryColliding() + * + * Finds items collliding (closer than clearance) with the item aItem. + * @param aItem item to check collisions against + * @param aObstacles set of colliding objects found + * @param aKindMask mask of obstacle types to take into account + * @param aLimitCount stop looking for collisions after finding this number of colliding items + * @return number of obstacles found + */ + int QueryColliding( const PNS_ITEM* aItem, + OBSTACLES& aObstacles, + int aKindMask = PNS_ITEM::ANY, + int aLimitCount = -1 ); + + /** + * Function NearestObstacle() + * + * Follows the line in search of an obstacle that is nearest to the starting to the line's starting + * point. + * @param aItem the item to find collisions with + * @param aKindMask mask of obstacle types to take into account + * @return the obstacle, if found, otherwise empty. + */ + OPT_OBSTACLE NearestObstacle( const PNS_LINE* aItem, + int aKindMask = PNS_ITEM::ANY ); + + /** + * Function CheckColliding() + * + * Checks if the item collides with anything else in the world, + * and if found, returns the obstacle. + * @param aItem the item to find collisions with + * @param aKindMask mask of obstacle types to take into account + * @return the obstacle, if found, otherwise empty. + */ + OPT_OBSTACLE CheckColliding( const PNS_ITEM* aItem, + int aKindMask = PNS_ITEM::ANY ); + + + /** + * Function CheckColliding() + * + * Checks if any item in the set collides with anything else in the world, + * and if found, returns the obstacle. + * @param aSet set of items to find collisions with + * @param aKindMask mask of obstacle types to take into account + * @return the obstacle, if found, otherwise empty. + */ + OPT_OBSTACLE CheckColliding( const PNS_ITEMSET& aSet, + int aKindMask = PNS_ITEM::ANY ); + + + /** + * Function CheckColliding() + * + * Checks if any item in the set collides with anything else in the world, + * and if found, returns the obstacle. + * @param aSet set of items to find collisions with + * @param aKindMask mask of obstacle types to take into account + * @return the obstacle, if found, otherwise empty. + */ + bool CheckColliding( const PNS_ITEM* aItemA, + const PNS_ITEM* aItemB, + int aKindMask = PNS_ITEM::ANY ); + + /** + * Function HitTest() + * + * Finds all items that contain the point aPoint. + * @param aPoint the point + * @return the items + */ + const PNS_ITEMSET HitTest( const VECTOR2I& aPoint ) const; + + /** + * Function Add() + * + * Adds an item to the current node. + * @param aItem item to add + * @param aAllowRedundant if true, duplicate items are allowed (e.g. a segment or via + * at the same coordinates as an existing one) + */ + void Add( PNS_ITEM* aItem, bool aAllowRedundant = false ); + + /** + * Function Remove() + * + * Just as the name says, removes an item from this branch. + * @param aItem item to remove + */ + void Remove( PNS_ITEM* aItem ); + + /** + * Function Replace() + * + * Just as the name says, replaces an item with another one. + * @param aOldItem item to be removed + * @param aNewItem item add instead + */ + void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); + + /** + * Function Branch() + * + * Creates a lightweight copy (called branch) of self that tracks + * the changes (added/removed items) wrs to the root. Note that if there are + * any branches in use, their parents must NOT be deleted. + * @return the new branch + */ + PNS_NODE* Branch(); + + /** + * Function AssembleLine() + * + * Follows the joint map to assemble a line connecting two non-trivial + * joints starting from segment aSeg. + * @param aSeg the initial segment + * @param aOriginSegmentIndex index of aSeg in the resulting line + * @return the line + */ + PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg, int *aOriginSegmentIndex = NULL ); + + ///> Prints the contents and joints structure + void Dump( bool aLong = false ); + + /** + * Function GetUpdatedItems() + * + * Returns the lists of items removed and added in this branch, with + * respect to the root branch. + * @param aRemoved removed items + * @param aAdded added items + */ + void GetUpdatedItems( ITEM_VECTOR& aRemoved, ITEM_VECTOR& aAdded ); + + /** + * Function Commit() + * + * Applies the changes from a given branch (aNode) to the root branch. Called on + * a non-root branch will fail. Calling commit also kills all children nodes of the root branch. + * @param aNode node to commit changes from + */ void Commit( PNS_NODE* aNode ); - ///> finds a joint at a given position, layer and nets - const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet ); + /** + * Function FindJoint() + * + * Searches for a joint at a given position, layer and belonging to given net. + * @return the joint, if found, otherwise empty + */ + PNS_JOINT* FindJoint( const VECTOR2I& aPos, int aLayer, int aNet ); - ///> finds all linest between a pair of joints. Used by the loop removal engine. - int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, - std::vector& aLines ); + /** + * Function FindJoint() + * + * Searches for a joint at a given position, linked to given item. + * @return the joint, if found, otherwise empty + */ + PNS_JOINT* FindJoint( const VECTOR2I& aPos, PNS_ITEM* aItem ) + { + return FindJoint( aPos, aItem->Layers().Start(), aItem->Net() ); + } + + void MapConnectivity( PNS_JOINT* aStart, std::vector & aFoundJoints ); + + PNS_ITEM* NearestUnconnectedItem( PNS_JOINT* aStart, int *aAnchor = NULL, + int aKindMask = PNS_ITEM::ANY); + + + ///> finds all lines between a pair of joints. Used by the loop removal procedure. + int FindLinesBetweenJoints( PNS_JOINT& aA, + PNS_JOINT& aB, + std::vector& aLines ); ///> finds the joints corresponding to the ends of line aLine - void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b ); - - ///> finds all joints that have an (in)direct connection(s) - ///> (i.e. segments/vias) with the joint aJoint. - void FindConnectedJoints( const PNS_JOINT& aJoint, - std::vector& aConnectedJoints ); - + void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& aA, PNS_JOINT& aB ); + ///> Destroys all child nodes. Applicable only to the root node. void KillChildren(); - void AllItemsInNet( int aNet, std::list& aItems ); + void AllItemsInNet( int aNet, std::set& aItems ); + + void ClearRanks(); + + int FindByMarker( int aMarker, PNS_ITEMSET& aItems ); + int RemoveByMarker( int aMarker ); private: - struct obstacleVisitor; - typedef boost::unordered_multimap JointMap; - typedef JointMap::value_type TagJointPair; + struct OBSTACLE_VISITOR; + typedef boost::unordered_multimap JOINT_MAP; + typedef JOINT_MAP::value_type TagJointPair; /// nodes are not copyable - PNS_NODE( const PNS_NODE& b ); - PNS_NODE& operator=( const PNS_NODE& b ); + PNS_NODE( const PNS_NODE& aB ); + PNS_NODE& operator=( const PNS_NODE& aB ); ///> tries to find matching joint and creates a new one if not found - PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, - int aNet ); + PNS_JOINT& touchJoint( const VECTOR2I& aPos, + const PNS_LAYERSET& aLayers, + int aNet ); - ///> touches a joint and links it to an item + ///> touches a joint and links it to an m_item void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, - int aNet, PNS_ITEM* aWhere ); + int aNet, PNS_ITEM* aWhere ); ///> unlinks an item from a joint void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, @@ -215,8 +348,8 @@ private: ///> helpers for adding/removing items void addSolid( PNS_SOLID* aSeg ); - void addSegment( PNS_SEGMENT* aSeg ); - void addLine( PNS_LINE* aLine ); + void addSegment( PNS_SEGMENT* aSeg, bool aAllowRedundant ); + void addLine( PNS_LINE* aLine, bool aAllowRedundant ); void addVia( PNS_VIA* aVia ); void removeSolid( PNS_SOLID* aSeg ); void removeLine( PNS_LINE* aLine ); @@ -232,27 +365,26 @@ private: return m_parent == NULL; } - ///> checks if this branch contains an updated version of the item + ///> checks if this branch contains an updated version of the m_item ///> from the root branch. bool overrides( PNS_ITEM* aItem ) const { return m_override.find( aItem ) != m_override.end(); } - ///> scans the joint map, forming a line starting from segment (current). - void followLine( PNS_SEGMENT* current, - bool scanDirection, - int& pos, - int limit, - VECTOR2I* corners, - PNS_SEGMENT** segments ); + PNS_SEGMENT *findRedundantSegment ( PNS_SEGMENT* aSeg ); - ///> spatial index of all items - // SHAPE_INDEX_LIST m_items; + ///> scans the joint map, forming a line starting from segment (current). + void followLine( PNS_SEGMENT* aCurrent, + bool aScanDirection, + int& aPos, + int aLimit, + VECTOR2I* aCorners, + PNS_SEGMENT** aSegments ); ///> hash table with the joints, linking the items. Joints are hashed by ///> their position, layer set and net. - JointMap m_joints; + JOINT_MAP m_joints; ///> node this node was branched from PNS_NODE* m_parent; @@ -263,7 +395,7 @@ private: ///> list of nodes branched from this one std::vector m_children; - ///> hash of root's items that are more recent in this node + ///> hash of root's items that have been changed in this node boost::unordered_set m_override; ///> worst case item-item clearance @@ -275,8 +407,8 @@ private: ///> Geometric/Net index of the items PNS_INDEX* m_index; - ///> list of currently processed obstacles. - Obstacles m_obstacleList; + ///> depth of the node (number of parent nodes in the inheritance chain) + int m_depth; }; #endif diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index 48e84207e5..6451bca600 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -27,16 +27,14 @@ #include "pns_node.h" #include "pns_optimizer.h" #include "pns_utils.h" +#include "pns_router.h" /** - * * Cost Estimator Methods - * - **/ - -int PNS_COST_ESTIMATOR::CornerCost( const SEG& a, const SEG& b ) + */ +int PNS_COST_ESTIMATOR::CornerCost( const SEG& aA, const SEG& aB ) { - DIRECTION_45 dir_a( a ), dir_b( b ); + DIRECTION_45 dir_a( aA ), dir_b( aB ); switch( dir_a.Angle( dir_b ) ) { @@ -74,29 +72,29 @@ int PNS_COST_ESTIMATOR::CornerCost( const SHAPE_LINE_CHAIN& aLine ) int PNS_COST_ESTIMATOR::CornerCost( const PNS_LINE& aLine ) { - return CornerCost( aLine.GetCLine() ); + return CornerCost( aLine.CLine() ); } void PNS_COST_ESTIMATOR::Add( PNS_LINE& aLine ) { - m_lengthCost += aLine.GetCLine().Length(); + m_lengthCost += aLine.CLine().Length(); m_cornerCost += CornerCost( aLine ); } void PNS_COST_ESTIMATOR::Remove( PNS_LINE& aLine ) { - m_lengthCost -= aLine.GetCLine().Length(); + m_lengthCost -= aLine.CLine().Length(); m_cornerCost -= CornerCost( aLine ); } void PNS_COST_ESTIMATOR::Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ) { - m_lengthCost -= aOldLine.GetCLine().Length(); + m_lengthCost -= aOldLine.CLine().Length(); m_cornerCost -= CornerCost( aOldLine ); - m_lengthCost += aNewLine.GetCLine().Length(); + m_lengthCost += aNewLine.CLine().Length(); m_cornerCost += CornerCost( aNewLine ); } @@ -108,8 +106,8 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost ) return true; - else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost < - m_lengthCost * aLengthTollerance ) + else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && + aOther.m_lengthCost < m_lengthCost * aLengthTollerance ) return true; return false; @@ -117,9 +115,7 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, /** - * * Optimizer - * **/ PNS_OPTIMIZER::PNS_OPTIMIZER( PNS_NODE* aWorld ) : m_world( aWorld ), m_collisionKindMask( PNS_ITEM::ANY ), m_effortLevel( MERGE_SEGMENTS ) @@ -134,18 +130,18 @@ PNS_OPTIMIZER::~PNS_OPTIMIZER() } -struct PNS_OPTIMIZER::CacheVisitor +struct PNS_OPTIMIZER::CACHE_VISITOR { - CacheVisitor( const PNS_ITEM* aOurItem, PNS_NODE* aNode, int aMask ) : + CACHE_VISITOR( const PNS_ITEM* aOurItem, PNS_NODE* aNode, int aMask ) : m_ourItem( aOurItem ), m_collidingItem( NULL ), m_node( aNode ), m_mask( aMask ) - {}; + {} bool operator()( PNS_ITEM* aOtherItem ) { - if( !m_mask & aOtherItem->GetKind() ) + if( !m_mask & aOtherItem->Kind() ) return true; int clearance = m_node->GetClearance( aOtherItem, m_ourItem ); @@ -170,20 +166,20 @@ void PNS_OPTIMIZER::cacheAdd( PNS_ITEM* aItem, bool aIsStatic = false ) return; m_cache.Add( aItem ); - m_cacheTags[aItem].hits = 1; - m_cacheTags[aItem].isStatic = aIsStatic; + m_cacheTags[aItem].m_hits = 1; + m_cacheTags[aItem].m_isStatic = aIsStatic; } void PNS_OPTIMIZER::removeCachedSegments( PNS_LINE* aLine, int aStartVertex, int aEndVertex ) { - std::vector* segs = aLine->GetLinkedSegments(); + PNS_LINE::SEGMENT_REFS* segs = aLine->LinkedSegments(); if( !segs ) return; if( aEndVertex < 0 ) - aEndVertex += aLine->GetCLine().PointCount(); + aEndVertex += aLine->PointCount(); for( int i = aStartVertex; i < aEndVertex - 1; i++ ) { @@ -196,8 +192,8 @@ void PNS_OPTIMIZER::removeCachedSegments( PNS_LINE* aLine, int aStartVertex, int void PNS_OPTIMIZER::CacheRemove( PNS_ITEM* aItem ) { - if( aItem->GetKind() == PNS_ITEM::LINE ) - removeCachedSegments( static_cast (aItem) ); + if( aItem->Kind() == PNS_ITEM::LINE ) + removeCachedSegments( static_cast( aItem ) ); } @@ -218,7 +214,7 @@ void PNS_OPTIMIZER::ClearCache( bool aStaticOnly ) for( CachedItemTags::iterator i = m_cacheTags.begin(); i!= m_cacheTags.end(); ++i ) { - if( i->second.isStatic ) + if( i->second.m_isStatic ) { m_cache.Remove( i->first ); m_cacheTags.erase( i->first ); @@ -229,28 +225,28 @@ void PNS_OPTIMIZER::ClearCache( bool aStaticOnly ) bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache ) { - CacheVisitor v( aItem, m_world, m_collisionKindMask ); + CACHE_VISITOR v( aItem, m_world, m_collisionKindMask ); return m_world->CheckColliding( aItem ); // something is wrong with the cache, need to investigate. - m_cache.Query( aItem->GetShape(), m_world->GetMaxClearance(), v, false ); + m_cache.Query( aItem->Shape(), m_world->GetMaxClearance(), v, false ); if( !v.m_collidingItem ) { - PNS_NODE::OptObstacle obs = m_world->CheckColliding( aItem ); + PNS_NODE::OPT_OBSTACLE obs = m_world->CheckColliding( aItem ); if( obs ) { if( aUpdateCache ) - cacheAdd( obs->item ); + cacheAdd( obs->m_item ); return true; } } else { - m_cacheTags[v.m_collidingItem].hits++; + m_cacheTags[v.m_collidingItem].m_hits++; return true; } @@ -268,7 +264,7 @@ bool PNS_OPTIMIZER::checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOp bool PNS_OPTIMIZER::mergeObtuse( PNS_LINE* aLine ) { - SHAPE_LINE_CHAIN& line = aLine->GetLine(); + SHAPE_LINE_CHAIN& line = aLine->Line(); int step = line.PointCount() - 3; int iter = 0; @@ -360,7 +356,7 @@ bool PNS_OPTIMIZER::mergeObtuse( PNS_LINE* aLine ) bool PNS_OPTIMIZER::mergeFull( PNS_LINE* aLine ) { - SHAPE_LINE_CHAIN& line = aLine->GetLine(); + SHAPE_LINE_CHAIN& line = aLine->Line(); int step = line.SegmentCount() - 1; int segs_pre = line.SegmentCount(); @@ -395,7 +391,7 @@ bool PNS_OPTIMIZER::mergeFull( PNS_LINE* aLine ) } -bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, PNS_LINE* aResult, int aStartVertex, int aEndVertex ) +bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, PNS_LINE* aResult )//, int aStartVertex, int aEndVertex ) { if( !aResult ) aResult = aLine; @@ -415,6 +411,9 @@ bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, PNS_LINE* aResult, int aStartVert if( m_effortLevel & SMART_PADS ) rv |= runSmartPads( aResult ); + if( m_effortLevel & FANOUT_CLEANUP ) + rv |= fanoutCleanup( aResult ); + return rv; } @@ -426,19 +425,19 @@ bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int cost_orig = PNS_COST_ESTIMATOR::CornerCost( aCurrentPath ); - - if( aLine->GetCLine().SegmentCount() < 4 ) + if( aLine->SegmentCount() < 4 ) return false; - DIRECTION_45 orig_start( aLine->GetCLine().CSegment( 0 ) ); - DIRECTION_45 orig_end( aLine->GetCLine().CSegment( -1 ) ); + DIRECTION_45 orig_start( aLine->CSegment( 0 ) ); + DIRECTION_45 orig_end( aLine->CSegment( -1 ) ); while( n < n_segs - step ) { const SEG s1 = aCurrentPath.CSegment( n ); const SEG s2 = aCurrentPath.CSegment( n + step ); - SHAPE_LINE_CHAIN path[2], * picked = NULL; + SHAPE_LINE_CHAIN path[2]; + SHAPE_LINE_CHAIN* picked = NULL; int cost[2]; for( int i = 0; i < 2; i++ ) @@ -481,10 +480,10 @@ bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, } -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth, +PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const { - BreakoutList breakouts; + BREAKOUT_LIST breakouts; for( int angle = 0; angle < 360; angle += 45 ) { @@ -501,12 +500,12 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth, } -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, +PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const { const SHAPE_RECT* rect = static_cast(aShape); VECTOR2I s = rect->GetSize(), c = rect->GetPosition() + VECTOR2I( s.x / 2, s.y / 2 ); - BreakoutList breakouts; + BREAKOUT_LIST breakouts; VECTOR2I d_offset; @@ -516,7 +515,6 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, VECTOR2I d_vert = VECTOR2I( 0, s.y / 2 + aWidth ); VECTOR2I d_horiz = VECTOR2I( s.x / 2 + aWidth, 0 ); - breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_horiz ) ); breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_horiz ) ); breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_vert ) ); @@ -556,52 +554,59 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, } -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::computeBreakouts( int aWidth, +PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::computeBreakouts( int aWidth, const PNS_ITEM* aItem, bool aPermitDiagonal ) const { - switch( aItem->GetKind() ) + switch( aItem->Kind() ) { case PNS_ITEM::VIA: - { - const PNS_VIA* via = static_cast( aItem ); - return circleBreakouts( aWidth, via->GetShape(), aPermitDiagonal ); - } + { + const PNS_VIA* via = static_cast( aItem ); + return circleBreakouts( aWidth, via->Shape(), aPermitDiagonal ); + } case PNS_ITEM::SOLID: + { + const SHAPE* shape = aItem->Shape(); + + switch( shape->Type() ) { - const SHAPE* shape = aItem->GetShape(); + case SH_RECT: + return rectBreakouts( aWidth, shape, aPermitDiagonal ); - switch( shape->Type() ) - { - case SH_RECT: - return rectBreakouts( aWidth, shape, aPermitDiagonal ); - - case SH_CIRCLE: - return circleBreakouts( aWidth, shape, aPermitDiagonal ); - - default: - break; - } + case SH_SEGMENT: + { + const SHAPE_SEGMENT* seg = static_cast (shape); + const SHAPE_RECT rect = ApproximateSegmentAsRect ( *seg ); + return rectBreakouts( aWidth, &rect, aPermitDiagonal ); } + case SH_CIRCLE: + return circleBreakouts( aWidth, shape, aPermitDiagonal ); + + default: + break; + } + } + default: break; } - return BreakoutList(); + return BREAKOUT_LIST(); } PNS_ITEM* PNS_OPTIMIZER::findPadOrVia( int aLayer, int aNet, const VECTOR2I& aP ) const { - PNS_NODE::OptJoint jt = m_world->FindJoint( aP, aLayer, aNet ); + PNS_JOINT* jt = m_world->FindJoint( aP, aLayer, aNet ); if( !jt ) return NULL; - BOOST_FOREACH( PNS_ITEM* item, jt->GetLinkList() ) + BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) { - if( item->GetKind() == PNS_ITEM::VIA || item->GetKind() == PNS_ITEM::SOLID ) + if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) return item; } @@ -621,32 +626,30 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, typedef std::pair RtVariant; std::vector variants; - BreakoutList breakouts = computeBreakouts( aLine->GetWidth(), aPad, true ); + BREAKOUT_LIST breakouts = computeBreakouts( aLine->Width(), aPad, true ); - SHAPE_LINE_CHAIN line = ( aEnd ? aLine->GetCLine().Reverse() : aLine->GetCLine() ); + SHAPE_LINE_CHAIN line = ( aEnd ? aLine->CLine().Reverse() : aLine->CLine() ); - // bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal(); int p_end = std::min( aEndVertex, std::min( 3, line.PointCount() - 1 ) ); for( int p = 1; p <= p_end; p++ ) { BOOST_FOREACH( SHAPE_LINE_CHAIN & l, breakouts ) { - // PNSDisplayDebugLine (l, 0); - for( int diag = 0; diag < 2; diag++ ) { SHAPE_LINE_CHAIN v; SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ), - line.CPoint( p ), diag == 0 ); + line.CPoint( p ), diag == 0 ); DIRECTION_45 dir_bkout( l.CSegment( -1 ) ); - // DIRECTION_45 dir_head ( line.CSegment(p + 1)); + if(!connect.SegmentCount()) + continue; + int ang1 = dir_bkout.Angle( DIRECTION_45( connect.CSegment( 0 ) ) ); int ang2 = 0; - // int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) )); if( (ang1 | ang2) & ForbiddenAngles ) continue; @@ -662,7 +665,6 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, v.Append( line.CPoint( i ) ); PNS_LINE tmp( *aLine, v ); - // tmp.GetLine().Simplify(); int cc = tmp.CountCorners( ForbiddenAngles ); if( cc == 0 ) @@ -689,18 +691,12 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, if( !checkColliding( &tmp ) ) { -/* if(aEnd) - * PNSDisplayDebugLine (l_best, 6); - * else - * PNSDisplayDebugLine (l_best, 5);*/ - if( cost < min_cost || ( cost == min_cost && len < min_len ) ) { l_best = vp.second; p_best = vp.first; found = true; - // if(cost == min_cost) if( cost == min_cost ) min_len = std::min( len, min_len ); @@ -711,12 +707,6 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, if( found ) { -// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount()); - -// if(!aEnd) -// PNSDisplayDebugLine (l_best, 5); -// else - aLine->SetShape( l_best ); return p_best; } @@ -724,18 +714,17 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, return -1; } - bool PNS_OPTIMIZER::runSmartPads( PNS_LINE* aLine ) { - SHAPE_LINE_CHAIN& line = aLine->GetLine(); - + SHAPE_LINE_CHAIN& line = aLine->Line(); + if( line.PointCount() < 3 ) return false; VECTOR2I p_start = line.CPoint( 0 ), p_end = line.CPoint( -1 ); - PNS_ITEM* startPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_start ); - PNS_ITEM* endPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_end ); + PNS_ITEM* startPad = findPadOrVia( aLine->Layer(), aLine->Net(), p_start ); + PNS_ITEM* endPad = findPadOrVia( aLine->Layer(), aLine->Net(), p_end ); int vtx = -1; @@ -744,18 +733,66 @@ bool PNS_OPTIMIZER::runSmartPads( PNS_LINE* aLine ) if( endPad ) smartPadsSingle( aLine, endPad, true, - vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx ); + vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx ); + + aLine->Line().Simplify(); - aLine->GetLine().Simplify(); return true; } bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld ) { - PNS_OPTIMIZER opt( aWorld ? aWorld : aLine->GetWorld() ); + PNS_OPTIMIZER opt( aWorld ); opt.SetEffortLevel( aEffortLevel ); opt.SetCollisionMask( -1 ); return opt.Optimize( aLine ); } + + +bool PNS_OPTIMIZER::fanoutCleanup( PNS_LINE* aLine ) +{ + if( aLine->PointCount() < 3 ) + return false; + + VECTOR2I p_start = aLine->CPoint( 0 ), p_end = aLine->CPoint( -1 ); + + PNS_ITEM* startPad = findPadOrVia( aLine->Layer(), aLine->Net(), p_start ); + PNS_ITEM* endPad = findPadOrVia( aLine->Layer(), aLine->Net(), p_end ); + + int thr = aLine->Width() * 10; + int len = aLine->CLine().Length(); + + if( !startPad ) + return false; + + bool startMatch = startPad->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ); + bool endMatch = false; + + if(endPad) + { + endMatch = endPad->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ); + } else { + endMatch = aLine->EndsWithVia(); + } + + if( startMatch && endMatch && len < thr ) + { + for(int i = 0; i < 2; i++ ) + { + SHAPE_LINE_CHAIN l2 = DIRECTION_45().BuildInitialTrace( p_start, p_end, i ); + PNS_ROUTER::GetInstance()->DisplayDebugLine( l2, 4, 10000 ); + PNS_LINE repl; + repl = PNS_LINE( *aLine, l2 ); + + if( !m_world->CheckColliding( &repl ) ) + { + aLine->SetShape( repl.CLine() ); + return true; + } + } + } + + return false; +} diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index 916e77bb69..fb75b41a53 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_OPTIMIZER_H @@ -27,6 +27,8 @@ #include #include +#include "range.h" + class PNS_NODE; class PNS_LINE; class PNS_ROUTER; @@ -36,23 +38,22 @@ class PNS_ROUTER; * * Calculates the cost of a given line, taking corner angles and total length into account. **/ - class PNS_COST_ESTIMATOR { public: PNS_COST_ESTIMATOR() : m_lengthCost( 0 ), m_cornerCost( 0 ) - {}; + {} - PNS_COST_ESTIMATOR( const PNS_COST_ESTIMATOR& b ) : - m_lengthCost( b.m_lengthCost ), - m_cornerCost( b.m_cornerCost ) - {}; + PNS_COST_ESTIMATOR( const PNS_COST_ESTIMATOR& aB ) : + m_lengthCost( aB.m_lengthCost ), + m_cornerCost( aB.m_cornerCost ) + {} ~PNS_COST_ESTIMATOR() {}; - static int CornerCost( const SEG& a, const SEG& b ); + static int CornerCost( const SEG& aA, const SEG& aB ); static int CornerCost( const SHAPE_LINE_CHAIN& aLine ); static int CornerCost( const PNS_LINE& aLine ); @@ -61,7 +62,7 @@ public: void Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ); bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, - double aCornerTollerace ) const; + double aCornerTollerace ) const; double GetLengthCost() const { return m_lengthCost; } double GetCornerCost() const { return m_cornerCost; } @@ -82,7 +83,6 @@ private: * the procedure as long as the total cost of the line keeps decreasing * - "Smart Pads" - that is, rerouting pad/via exits to make them look nice (SMART_PADS). **/ - class PNS_OPTIMIZER { public: @@ -90,17 +90,17 @@ public: { MERGE_SEGMENTS = 0x01, SMART_PADS = 0x02, - MERGE_OBTUSE = 0x04 + MERGE_OBTUSE = 0x04, + FANOUT_CLEANUP = 0x08 }; PNS_OPTIMIZER( PNS_NODE* aWorld ); ~PNS_OPTIMIZER(); ///> a quick shortcut to optmize a line without creating and setting up an optimizer - static bool Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld = NULL ); + static bool Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld); - bool Optimize( PNS_LINE* aLine, PNS_LINE* aResult = NULL, - int aStartVertex = 0, int aEndVertex = -1 ); + bool Optimize( PNS_LINE* aLine, PNS_LINE* aResult = NULL ); void SetWorld( PNS_NODE* aNode ) { m_world = aNode; } void CacheStaticItem( PNS_ITEM* aItem ); @@ -120,14 +120,14 @@ public: private: static const int MaxCachedItems = 256; - typedef std::vector BreakoutList; + typedef std::vector BREAKOUT_LIST; - struct CacheVisitor; + struct CACHE_VISITOR; - struct CachedItem + struct CACHED_ITEM { - int hits; - bool isStatic; + int m_hits; + bool m_isStatic; }; bool mergeObtuse( PNS_LINE* aLine ); @@ -135,19 +135,18 @@ private: bool removeUglyCorners( PNS_LINE* aLine ); bool runSmartPads( PNS_LINE* aLine ); bool mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step ); + bool fanoutCleanup( PNS_LINE * aLine ); bool checkColliding( PNS_ITEM* aItem, bool aUpdateCache = true ); bool checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath ); - void cacheAdd( PNS_ITEM* aItem, bool aIsStatic ); void removeCachedSegments( PNS_LINE* aLine, int aStartVertex = 0, int aEndVertex = -1 ); - BreakoutList circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; - BreakoutList rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; - BreakoutList ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; - BreakoutList computeBreakouts( int aWidth, const PNS_ITEM* aItem, - bool aPermitDiagonal ) const; + BREAKOUT_LIST circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BREAKOUT_LIST rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BREAKOUT_LIST ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BREAKOUT_LIST computeBreakouts( int aWidth, const PNS_ITEM* aItem, bool aPermitDiagonal ) const; int smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, int aEndVertex ); @@ -155,7 +154,7 @@ private: SHAPE_INDEX_LIST m_cache; - typedef boost::unordered_map CachedItemTags; + typedef boost::unordered_map CachedItemTags; CachedItemTags m_cacheTags; PNS_NODE* m_world; int m_collisionKindMask; diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 9a57b50b16..b233cba9ea 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -42,11 +42,13 @@ #include "pns_solid.h" #include "pns_utils.h" #include "pns_router.h" +#include "pns_shove.h" +#include "pns_dragger.h" #include #include -#include +#include #include #include #include @@ -70,7 +72,7 @@ public: continue; wxString netClassName = ni->GetClassName(); - NETCLASS* nc = aBoard->m_NetClasses.Find( netClassName ); + NETCLASS* nc = aBoard->GetDesignSettings().m_NetClasses.Find( netClassName ); int clearance = nc->GetClearance(); m_clearanceCache[i] = clearance; TRACE( 1, "Add net %d netclass %s clearance %d", i % netClassName.mb_str() % @@ -80,12 +82,28 @@ public: m_defaultClearance = 254000; // aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); } - int operator()( const PNS_ITEM* a, const PNS_ITEM* b ) + int localPadClearance( const PNS_ITEM* aItem ) const { - int net_a = a->GetNet(); - int cl_a = (net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance); - int net_b = b->GetNet(); - int cl_b = (net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance); + if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T ) + return 0; + + const D_PAD* pad = static_cast( aItem->Parent() ); + + return pad->GetLocalClearance(); + } + + int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) + { + int net_a = aA->Net(); + int cl_a = ( net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance ); + int net_b = aB->Net(); + int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance ); + + int pad_a = localPadClearance( aA ); + int pad_b = localPadClearance( aB ); + + cl_a = std::max( cl_a, pad_a ); + cl_b = std::max( cl_b, pad_b ); return std::max( cl_a, cl_b ); } @@ -95,6 +113,7 @@ private: int m_defaultClearance; }; + PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) { PNS_LAYERSET layers( 0, 15 ); @@ -102,6 +121,7 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) switch( aPad->GetAttribute() ) { case PAD_STANDARD: + layers = PNS_LAYERSET( 0, 15 ); break; case PAD_SMD: @@ -112,7 +132,7 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) for( i = FIRST_COPPER_LAYER; i <= LAST_COPPER_LAYER; i++ ) { - if( lmsk & (1 << i) ) + if( lmsk & ( 1 << i ) ) { layers = PNS_LAYERSET( i ); break; @@ -130,49 +150,66 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) solid->SetLayers( layers ); solid->SetNet( aPad->GetNetCode() ); + solid->SetParent( aPad ); + wxPoint wx_c = aPad->GetPosition(); wxSize wx_sz = aPad->GetSize(); VECTOR2I c( wx_c.x, wx_c.y ); VECTOR2I sz( wx_sz.x, wx_sz.y ); - solid->SetCenter( c ); + solid->SetPos( c ); double orient = aPad->GetOrientation() / 10.0; + bool nonOrtho = false; if( orient == 90.0 || orient == 270.0 ) sz = VECTOR2I( sz.y, sz.x ); else if( orient != 0.0 && orient != 180.0 ) { - TRACEn( 0, "non-orthogonal pad rotations not supported yet" ); - delete solid; - return NULL; + // rotated pads are replaced by for the moment by circles due to my laziness ;) + solid->SetShape( new SHAPE_CIRCLE( c, std::min( sz.x, sz.y ) / 2 ) ); + nonOrtho = true; } - switch( aPad->GetShape() ) + if( !nonOrtho ) { - case PAD_CIRCLE: - solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); - break; - - case PAD_OVAL: - if( sz.x == sz.y ) + switch( aPad->GetShape() ) + { + case PAD_CIRCLE: solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); - else + break; + + case PAD_OVAL: + if( sz.x == sz.y ) + solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); + else + { + VECTOR2I delta; + + if( sz.x > sz.y ) + delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 ); + else + delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 ); + + SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta, + std::min( sz.x, sz.y ) ); + solid->SetShape( shape ); + } + break; + + case PAD_RECT: solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) ); - break; + break; - case PAD_RECT: - solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) ); - break; + default: + TRACEn( 0, "unsupported pad shape" ); + delete solid; - default: - TRACEn( 0, "unsupported pad shape" ); - delete solid; - return NULL; + return NULL; + } } - solid->SetParent( aPad ); return solid; } @@ -197,7 +234,9 @@ PNS_ITEM* PNS_ROUTER::syncVia( VIA* aVia ) aVia->GetWidth(), aVia->GetNetCode() ); + v->SetDrill ( aVia->GetDrill() ); v->SetParent( aVia ); + return v; } @@ -214,7 +253,8 @@ int PNS_ROUTER::NextCopperLayer( bool aUp ) LAYER_MSK mask = m_board->GetEnabledLayers() & m_board->GetVisibleLayers(); LAYER_NUM l = m_currentLayer; - do { + do + { l += ( aUp ? 1 : -1 ); if( l > LAST_COPPER_LAYER ) @@ -225,7 +265,8 @@ int PNS_ROUTER::NextCopperLayer( bool aUp ) if( mask & GetLayerMask( l ) ) return l; - } while( l != m_currentLayer ); + } + while( l != m_currentLayer ); return l; } @@ -233,8 +274,6 @@ int PNS_ROUTER::NextCopperLayer( bool aUp ) void PNS_ROUTER::SyncWorld() { - std::vector pads; - if( !m_board ) { TRACEn( 0, "No board attached, aborting sync." ); @@ -243,11 +282,12 @@ void PNS_ROUTER::SyncWorld() ClearWorld(); + int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue(); + m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC( m_board ); m_world = new PNS_NODE(); m_world->SetClearanceFunctor( m_clearanceFunc ); - m_world->SetMaxClearance( 1000000 ); // m_board->GetBiggestClearanceValue()); - pads = m_board->GetPads(); + m_world->SetMaxClearance( 4 * worstClearance ); for( MODULE* module = m_board->m_Modules; module; module = module->Next() ) { @@ -273,8 +313,6 @@ void PNS_ROUTER::SyncWorld() if( item ) m_world->Add( item ); } - - m_placer = new PNS_LINE_PLACER( m_world ); } @@ -291,10 +329,8 @@ PNS_ROUTER::PNS_ROUTER() m_world = NULL; m_placer = NULL; m_previewItems = NULL; - m_start_diagonal = false; m_board = NULL; - - TRACE( 1, "m_board = %p\n", m_board ); + m_dragger = NULL; } @@ -351,13 +387,6 @@ void PNS_ROUTER::ClearWorld() } -void PNS_ROUTER::SetCurrentWidth( int w ) -{ - // fixme: change width while routing - m_currentWidth = w; -} - - bool PNS_ROUTER::RoutingInProgress() const { return m_state != IDLE; @@ -369,53 +398,57 @@ const PNS_ITEMSET PNS_ROUTER::QueryHoverItems( const VECTOR2I& aP ) if( m_state == IDLE ) return m_world->HitTest( aP ); else - return m_placer->GetCurrentNode()->HitTest( aP ); + { + //assert ( m_placer->GetCurrentNode()->checkExists() ); + //TRACE(0,"query-hover [%p]", m_placer->GetCurrentNode()); + return m_placer->CurrentNode()->HitTest( aP ); + } } -const VECTOR2I PNS_ROUTER::SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ) +const VECTOR2I PNS_ROUTER::SnapToItem( PNS_ITEM* aItem, VECTOR2I aP, bool& aSplitsSegment ) { VECTOR2I anchor; - if( !item ) + if( !aItem ) { aSplitsSegment = false; return aP; } - switch( item->GetKind() ) + switch( aItem->Kind() ) { case PNS_ITEM::SOLID: - anchor = static_cast(item)->GetCenter(); + anchor = static_cast( aItem )->Pos(); aSplitsSegment = false; break; case PNS_ITEM::VIA: - anchor = static_cast(item)->GetPos(); + anchor = static_cast( aItem )->Pos(); aSplitsSegment = false; break; case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT* seg = static_cast( aItem ); + const SEG& s = seg->Seg(); + int w = seg->Width(); + + aSplitsSegment = false; + + if( ( aP - s.A ).EuclideanNorm() < w / 2 ) + anchor = s.A; + else if( ( aP - s.B ).EuclideanNorm() < w / 2 ) + anchor = s.B; + else { - PNS_SEGMENT* seg = static_cast( item ); - const SEG& s = seg->GetSeg(); - int w = seg->GetWidth(); - - aSplitsSegment = false; - - if( ( aP - s.A ).EuclideanNorm() < w / 2 ) - anchor = s.A; - else if( ( aP - s.B ).EuclideanNorm() < w / 2 ) - anchor = s.B; - else - { - anchor = s.NearestPoint( aP ); - aSplitsSegment = true; - } - - break; + anchor = s.NearestPoint( aP ); + aSplitsSegment = true; } + break; + } + default: break; } @@ -424,49 +457,52 @@ const VECTOR2I PNS_ROUTER::SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplit } -void PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +bool PNS_ROUTER::StartDragging( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { - VECTOR2I p; + if( !aStartItem || aStartItem->OfKind( PNS_ITEM::SOLID ) ) + return false; + + m_dragger = new PNS_DRAGGER ( this ); + m_dragger->SetWorld( m_world ); - static int unknowNetIdx = 0; // -10000; - - m_placingVia = false; - m_startsOnVia = false; - m_currentNet = -1; - - bool splitSeg = false; - - p = SnapToItem( aStartItem, aP, splitSeg ); - - if( !aStartItem || aStartItem->GetNet() < 0 ) - m_currentNet = unknowNetIdx--; + if( m_dragger->Start ( aP, aStartItem ) ) + m_state = DRAG_SEGMENT; else - m_currentNet = aStartItem->GetNet(); - - m_currentStart = p; - m_originalStart = p; - m_currentEnd = p; - - m_placer->SetInitialDirection( m_start_diagonal ? DIRECTION_45( - DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) ); - m_placer->StartPlacement( m_originalStart, m_currentNet, m_currentWidth, m_currentLayer ); - m_state = ROUTE_TRACK; - - if( splitSeg ) - splitAdjacentSegments( m_placer->GetCurrentNode(), aStartItem, p ); + { + delete m_dragger; + m_state = IDLE; + return false; + } + + return true; } -const VECTOR2I PNS_ROUTER::GetCurrentEnd() const +bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + m_state = ROUTE_TRACK; + + m_placer = new PNS_LINE_PLACER( this ); + m_placer->SetLayer( m_currentLayer ); + m_placer->SetWidth ( m_settings.GetTrackWidth() ); + m_placer->Start( aP, aStartItem ); + m_currentEnd = aP; + m_currentEndItem = NULL; + + return true; +} + + +const VECTOR2I PNS_ROUTER::CurrentEnd() const { return m_currentEnd; } -void PNS_ROUTER::EraseView() +void PNS_ROUTER::eraseView() { BOOST_FOREACH( BOARD_ITEM* item, m_hiddenItems ) - { + { item->ViewSetVisible( true ); } @@ -480,71 +516,137 @@ void PNS_ROUTER::EraseView() } -void PNS_ROUTER::DisplayItem( const PNS_ITEM* aItem, bool aIsHead ) +void PNS_ROUTER::DisplayItem( const PNS_ITEM* aItem, int aColor, int aClearance ) { ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_previewItems ); - m_previewItems->Add( pitem ); + if( aColor >= 0 ) + pitem->SetColor( KIGFX::COLOR4D ( aColor ) ); - if( aIsHead ) - pitem->MarkAsHead(); + if( aClearance >= 0 ) + pitem->SetClearance( aClearance ); + + m_previewItems->Add( pitem ); pitem->ViewSetVisible( true ); m_previewItems->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY | KIGFX::VIEW_ITEM::APPEARANCE ); } +void PNS_ROUTER::DisplayItems( const PNS_ITEMSET& aItems ) +{ + BOOST_FOREACH( const PNS_ITEM *item, aItems.CItems() ) + DisplayItem( item ); +} + + void PNS_ROUTER::DisplayDebugLine( const SHAPE_LINE_CHAIN& aLine, int aType, int aWidth ) { ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_previewItems ); - pitem->DebugLine( aLine, aWidth, aType ); + pitem->Line( aLine, aWidth, aType ); m_previewItems->Add( pitem ); pitem->ViewSetVisible( true ); m_previewItems->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY | KIGFX::VIEW_ITEM::APPEARANCE ); } -void PNS_ROUTER::DisplayDebugBox( const BOX2I& aBox, int aType, int aWidth ) +void PNS_ROUTER::DisplayDebugPoint( const VECTOR2I aPos, int aType ) { + ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_previewItems ); + + pitem->Point( aPos, aType ); + m_previewItems->Add( pitem ); + pitem->ViewSetVisible( true ); + m_previewItems->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY | KIGFX::VIEW_ITEM::APPEARANCE ); } void PNS_ROUTER::Move( const VECTOR2I& aP, PNS_ITEM* endItem ) { - PNS_NODE::ItemVector removed, added; - VECTOR2I p = aP; + m_currentEnd = aP; + m_currentEndItem = endItem; - if( m_state == IDLE ) - return; - - // TODO is something missing here? - if( m_state == START_ROUTING ) + switch( m_state ) { + case ROUTE_TRACK: + movePlacing( aP, endItem ); + break; + + case DRAG_SEGMENT: + moveDragging (aP, endItem ); + break; + + default: + break; } +} - EraseView(); - m_currentEnd = p; - m_placer->Route( p ); +void PNS_ROUTER::moveDragging( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + eraseView(); - PNS_LINE current = m_placer->GetTrace(); + m_dragger->Drag( aP ); + PNS_ITEMSET dragged = m_dragger->Traces(); - DisplayItem( ¤t, true ); + updateView ( m_dragger->CurrentNode(), dragged ); +} - if( current.EndsWithVia() ) - DisplayItem( ¤t.GetVia(), true ); - m_placer->GetCurrentNode()->GetUpdatedItems( removed, added ); +void PNS_ROUTER::markViolations( PNS_NODE* aNode, PNS_ITEMSET& aCurrent, + PNS_NODE::ITEM_VECTOR& aRemoved ) +{ + BOOST_FOREACH( PNS_ITEM *item, aCurrent.Items() ) + { + PNS_NODE::OBSTACLES obstacles; + + aNode->QueryColliding( item, obstacles, PNS_ITEM::ANY ); + + if( item->OfKind( PNS_ITEM::LINE ) ) + { + PNS_LINE *l = static_cast( item ); + + if( l->EndsWithVia() ) + { + PNS_VIA v ( l->Via() ); + aNode->QueryColliding( &v, obstacles, PNS_ITEM::ANY ); + } + } + + BOOST_FOREACH( PNS_OBSTACLE& obs, obstacles ) + { + int clearance = aNode->GetClearance( item, obs.m_item ); + std::auto_ptr tmp( obs.m_item->Clone() ); + tmp->Mark( MK_VIOLATION ); + DisplayItem( tmp.get(), -1, clearance ); + aRemoved.push_back( obs.m_item ); + } + } +} + + +void PNS_ROUTER::updateView( PNS_NODE* aNode, PNS_ITEMSET& aCurrent ) +{ + PNS_NODE::ITEM_VECTOR removed, added; + PNS_NODE::OBSTACLES obstacles; + + if( !aNode ) + return; + + if( Settings().Mode() == RM_MarkObstacles ) + markViolations(aNode, aCurrent, removed); + + aNode->GetUpdatedItems( removed, added ); BOOST_FOREACH( PNS_ITEM* item, added ) - { + { DisplayItem( item ); } BOOST_FOREACH( PNS_ITEM* item, removed ) { - BOARD_ITEM* parent = item->GetParent(); + BOARD_CONNECTED_ITEM* parent = item->Parent(); if( parent ) { @@ -558,46 +660,50 @@ void PNS_ROUTER::Move( const VECTOR2I& aP, PNS_ITEM* endItem ) } -void PNS_ROUTER::splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ) +void PNS_ROUTER::ApplySettings() { - if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) ) + // Change track/via size settings + if( m_state == ROUTE_TRACK) { - PNS_NODE::OptJoint jt = aNode->FindJoint( aP, aSeg->GetLayers().Start(), aSeg->GetNet() ); - - if( jt && jt->LinkCount() >= 1 ) - return; - - PNS_SEGMENT* s_old = static_cast( aSeg ); - PNS_SEGMENT* s_new[2]; - - s_new[0] = s_old->Clone(); - s_new[1] = s_old->Clone(); - - s_new[0]->SetEnds( s_old->GetSeg().A, aP ); - s_new[1]->SetEnds( aP, s_old->GetSeg().B ); - - aNode->Remove( s_old ); - aNode->Add( s_new[0] ); - aNode->Add( s_new[1] ); + m_placer->UpdateSizes( m_settings ); + m_placer->Move( m_currentEnd, m_currentEndItem ); + movePlacing( m_currentEnd, m_currentEndItem ); } } -void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) +void PNS_ROUTER::movePlacing( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - PNS_NODE::ItemVector removed, added; + eraseView(); + + m_placer->Move( aP, aEndItem ); + PNS_LINE current = m_placer->Trace(); + + DisplayItem( ¤t ); + + if( current.EndsWithVia() ) + DisplayItem( ¤t.Via() ); + + PNS_ITEMSET tmp ( ¤t ); + updateView ( m_placer->CurrentNode ( true ), tmp ); +} + + +void PNS_ROUTER::CommitRouting( PNS_NODE* aNode ) +{ + PNS_NODE::ITEM_VECTOR removed, added; aNode->GetUpdatedItems( removed, added ); for( unsigned int i = 0; i < removed.size(); i++ ) { - BOARD_CONNECTED_ITEM* parent = removed[i]->GetParent(); + BOARD_CONNECTED_ITEM* parent = removed[i]->Parent(); if( parent ) { - m_undoBuffer.PushItem( ITEM_PICKER( parent, UR_DELETED ) ); - m_board->Remove( parent ); m_view->Remove( parent ); + m_board->Remove( parent ); + m_undoBuffer.PushItem( ITEM_PICKER( parent, UR_DELETED ) ); } } @@ -605,33 +711,34 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) { BOARD_CONNECTED_ITEM* newBI = NULL; - switch( item->GetKind() ) + switch( item->Kind() ) { case PNS_ITEM::SEGMENT: - { - PNS_SEGMENT* seg = static_cast( item ); - TRACK* track = new TRACK( m_board ); - const SEG& s = seg->GetSeg(); + { + PNS_SEGMENT* seg = static_cast( item ); + TRACK* track = new TRACK( m_board ); + const SEG& s = seg->Seg(); - track->SetStart( wxPoint( s.A.x, s.A.y ) ); - track->SetEnd( wxPoint( s.B.x, s.B.y ) ); - track->SetWidth( seg->GetWidth() ); - track->SetLayer( seg->GetLayers().Start() ); - track->SetNetCode( seg->GetNet() ); - newBI = track; - break; - } + track->SetStart( wxPoint( s.A.x, s.A.y ) ); + track->SetEnd( wxPoint( s.B.x, s.B.y ) ); + track->SetWidth( seg->Width() ); + track->SetLayer( seg->Layers().Start() ); + track->SetNetCode( seg->Net() ); + newBI = track; + break; + } case PNS_ITEM::VIA: - { - VIA* via_board = new VIA( m_board ); - PNS_VIA* via = static_cast( item ); - via_board->SetPosition( wxPoint( via->GetPos().x, via->GetPos().y ) ); - via_board->SetWidth( via->GetDiameter() ); - via_board->SetNetCode( via->GetNet() ); - newBI = via_board; - break; - } + { + VIA* via_board = new VIA( m_board ); + PNS_VIA* via = static_cast( item ); + via_board->SetPosition( wxPoint( via->Pos().x, via->Pos().y ) ); + via_board->SetWidth( via->Diameter() ); + via_board->SetDrill( via->Drill() ); + via_board->SetNetCode( via->Net() ); + newBI = via_board; + break; + } default: break; @@ -657,12 +764,12 @@ PNS_VIA* PNS_ROUTER::checkLoneVia( PNS_JOINT* aJoint ) const PNS_VIA* theVia = NULL; PNS_LAYERSET l; - BOOST_FOREACH( PNS_ITEM* item, aJoint->GetLinkList() ) + BOOST_FOREACH( PNS_ITEM* item, aJoint->LinkList() ) { - if( item->GetKind() == PNS_ITEM::VIA ) + if( item->Kind() == PNS_ITEM::VIA ) theVia = static_cast( item ); - l.Merge( item->GetLayers() ); + l.Merge( item->Layers() ); } if( l.Start() == l.End() ) @@ -672,99 +779,29 @@ PNS_VIA* PNS_ROUTER::checkLoneVia( PNS_JOINT* aJoint ) const } -PNS_NODE* PNS_ROUTER::removeLoops( PNS_NODE* aNode, PNS_SEGMENT* aLatestSeg ) -{ - PNS_LINE* ourLine = aNode->AssembleLine( aLatestSeg ); - PNS_NODE* cleaned = aNode->Branch(); - PNS_JOINT a, b; - - std::vector lines; - - cleaned->FindLineEnds( ourLine, a, b ); - cleaned->FindLinesBetweenJoints( a, b, lines ); - - BOOST_FOREACH( PNS_LINE* line, lines ) - { - if( !( line->ContainsSegment( aLatestSeg ) ) ) - { - cleaned->Remove( line ); - } - } - - return cleaned; -} - - bool PNS_ROUTER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - bool real_end = false; + bool rv = false; - PNS_LINE pl = m_placer->GetTrace(); - const SHAPE_LINE_CHAIN& l = pl.GetCLine(); - - if( !l.SegmentCount() ) - return true; - - VECTOR2I p_pre_last = l.CPoint( -1 ); - const VECTOR2I p_last = l.CPoint( -1 ); - DIRECTION_45 d_last( l.CSegment( -1 ) ); - - if( l.PointCount() > 2 ) - p_pre_last = l.CPoint( -2 ); - - if( aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->GetNet() ) - real_end = true; - - int last = ( real_end || m_placingVia ) ? l.SegmentCount() : std::max( 1, l.SegmentCount() - 1 ); - - PNS_NODE* latest = m_placer->GetCurrentNode(); - - if( real_end ) - splitAdjacentSegments( latest, aEndItem, aP ); - - PNS_SEGMENT* lastSeg = NULL; - - for( int i = 0; i < last; i++ ) + switch( m_state ) { - const SEG& s = pl.GetCLine().CSegment( i ); - PNS_SEGMENT* seg = new PNS_SEGMENT( s, m_currentNet ); - seg->SetWidth( pl.GetWidth() ); - seg->SetLayer( m_currentLayer ); - latest->Add( seg ); - lastSeg = seg; - } + case ROUTE_TRACK: + rv = m_placer->FixRoute( aP, aEndItem ); + m_placingVia = false; + break; + + case DRAG_SEGMENT: + rv = m_dragger->FixRoute(); + break; + + default: + break; + } - if( pl.EndsWithVia() ) - latest->Add( pl.GetVia().Clone() ); - - if( real_end ) - latest = removeLoops( latest, lastSeg ); - - commitRouting( latest ); - - EraseView(); - - if( real_end ) - { - m_state = IDLE; - // m_world->KillChildren(); - } - else - { - m_state = ROUTE_TRACK; - m_placer->SetInitialDirection( d_last ); - m_currentStart = m_placingVia ? p_last : p_pre_last; - - if( m_placingVia ) - m_currentLayer = NextCopperLayer( true ); - - m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, m_currentLayer ); - - m_startsOnVia = m_placingVia; - m_placingVia = false; - } - - return real_end; + if( rv ) + StopRouting(); + + return rv; } @@ -776,43 +813,49 @@ void PNS_ROUTER::StopRouting() if( !RoutingInProgress() ) return; - EraseView(); + if( m_placer ) + delete m_placer; + + if( m_dragger ) + delete m_dragger; + + m_placer = NULL; + m_dragger = NULL; + + eraseView(); m_state = IDLE; m_world->KillChildren(); + m_world->ClearRanks(); } void PNS_ROUTER::FlipPosture() { - if( m_placer->GetTail().GetCLine().SegmentCount() == 0 ) + if( m_state == ROUTE_TRACK ) { - m_start_diagonal = !m_start_diagonal; - m_placer->SetInitialDirection( m_start_diagonal ? - DIRECTION_45( DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) ); - } - else m_placer->FlipPosture(); - - Move( m_currentEnd, NULL ); + m_placer->Move ( m_currentEnd, m_currentEndItem ); + } } -void PNS_ROUTER::SwitchLayer( int layer ) +void PNS_ROUTER::SwitchLayer( int aLayer ) { switch( m_state ) { case IDLE: - m_currentLayer = layer; + m_currentLayer = aLayer; break; case ROUTE_TRACK: - if( m_startsOnVia ) - { - m_currentLayer = layer; - m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, - m_currentLayer ); - } + if( m_startsOnVia ) + { + m_currentLayer = aLayer; + //m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, + // m_currentLayer ); + } + break; default: break; @@ -825,6 +868,51 @@ void PNS_ROUTER::ToggleViaPlacement() if( m_state == ROUTE_TRACK ) { m_placingVia = !m_placingVia; - m_placer->AddVia( m_placingVia, m_currentViaDiameter, m_currentViaDrill ); + m_placer->AddVia( m_placingVia, m_settings.GetViaDiameter(), m_settings.GetViaDrill() ); } } + + +int PNS_ROUTER::GetCurrentNet() const +{ + switch( m_state ) + { + case ROUTE_TRACK: + return m_placer->CurrentNet(); + + default: + return m_currentNet; + } +} + + +int PNS_ROUTER::GetCurrentLayer() const +{ + switch( m_state ) + { + case ROUTE_TRACK: + return m_placer->CurrentLayer(); + + default: + return m_currentLayer; + } +} + + +void PNS_ROUTER::DumpLog() +{ + PNS_LOGGER* logger = NULL; + + switch( m_state ) + { + case DRAG_SEGMENT: + logger = m_dragger->Logger(); + break; + + default: + break; + } + + if( logger ) + logger->Save ( "/tmp/shove.log" ); +} diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index e5fabbeec2..b5fc2a6daa 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_ROUTER_H @@ -32,6 +32,7 @@ #include "pns_routing_settings.h" #include "pns_item.h" #include "pns_itemset.h" +#include "pns_node.h" class BOARD; class BOARD_ITEM; @@ -47,11 +48,13 @@ class PNS_SEGMENT; class PNS_JOINT; class PNS_VIA; class PNS_CLEARANCE_FUNC; -class VIEW_GROUP; +class PNS_SHOVE; +class PNS_DRAGGER; -namespace KIGFX { -class VIEW; -class VIEW_GROUP; +namespace KIGFX +{ + class VIEW; + class VIEW_GROUP; }; @@ -60,16 +63,14 @@ class VIEW_GROUP; * * Main router class. */ - class PNS_ROUTER { private: enum RouterState { IDLE, - START_ROUTING, - ROUTE_TRACK, - FINISH_TRACK + DRAG_SEGMENT, + ROUTE_TRACK }; public: @@ -85,15 +86,15 @@ public: void SetView( KIGFX::VIEW* aView ); bool RoutingInProgress() const; - void StartRouting( const VECTOR2I& aP, PNS_ITEM* aItem ); + bool StartRouting( const VECTOR2I& aP, PNS_ITEM* aItem ); void Move( const VECTOR2I& aP, PNS_ITEM* aItem ); bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aItem ); void StopRouting(); - const VECTOR2I GetCurrentEnd() const; + const VECTOR2I CurrentEnd() const; - int GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const; + int GetClearance( const PNS_ITEM* aA, const PNS_ITEM* aB ) const; PNS_NODE* GetWorld() const { @@ -102,25 +103,22 @@ public: void FlipPosture(); - void DisplayItem( const PNS_ITEM* aItem, bool aIsHead = false ); + void DisplayItem( const PNS_ITEM* aItem, int aColor = -1, int aClearance = -1 ); + void DisplayItems( const PNS_ITEMSET& aItems ); + void DisplayDebugLine( const SHAPE_LINE_CHAIN& aLine, int aType = 0, int aWidth = 0 ); + void DisplayDebugPoint( const VECTOR2I aPos, int aType = 0); void DisplayDebugBox( const BOX2I& aBox, int aType = 0, int aWidth = 0 ); - void EraseView(); void SwitchLayer( int layer ); - int GetCurrentLayer() const { return m_currentLayer; } void ToggleViaPlacement(); - void SetCurrentWidth( int w ); - - void SetCurrentViaDiameter( int d ) { m_currentViaDiameter = d; } - void SetCurrentViaDrill( int d ) { m_currentViaDrill = d; } - int GetCurrentWidth() const { return m_currentWidth; } - int GetCurrentViaDiameter() const { return m_currentViaDiameter; } - int GetCurrentViaDrill() const { return m_currentViaDrill; } - int GetCurrentNet() const { return m_currentNet; } + int GetCurrentLayer() const; + int GetCurrentNet() const; + void DumpLog(); + PNS_CLEARANCE_FUNC* GetClearanceFunc() const { return m_clearanceFunc; @@ -136,13 +134,31 @@ public: // typedef boost::optional optHoverItem; const PNS_ITEMSET QueryHoverItems( const VECTOR2I& aP ); - const VECTOR2I SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ); + const VECTOR2I SnapToItem( PNS_ITEM* aItem, VECTOR2I aP, bool& aSplitsSegment ); + bool StartDragging( const VECTOR2I& aP, PNS_ITEM* aItem ); + + void SetIterLimit( int aX ) { m_iterLimit = aX; } + int GetIterLimit() const { return m_iterLimit; }; + + void SetShowIntermediateSteps( bool aX, int aSnapshotIter = -1 ) + { + m_showInterSteps = aX; + m_snapshotIter = aSnapshotIter; + } + + bool GetShowIntermediateSteps() const { return m_showInterSteps; } + int GetShapshotIter() const { return m_snapshotIter; } + + PNS_ROUTING_SETTINGS& Settings() { return m_settings; } + + void CommitRouting( PNS_NODE* aNode ); + /** * Returns the last changes introduced by the router (since the last time ClearLastChanges() * was called or a new track has been started). */ - const PICKED_ITEMS_LIST& GetLastChanges() const + const PICKED_ITEMS_LIST& GetUndoBuffer() const { return m_undoBuffer; } @@ -150,21 +166,51 @@ public: /** * Clears the list of recent changes, saved to be stored in the undo buffer. */ - void ClearLastChanges() + void ClearUndoBuffer() { m_undoBuffer.ClearItemsList(); } + /** + * Applies stored settings. + * @see Settings() + */ + void ApplySettings(); + + /** + * Changes routing settings to ones passed in the parameter. + * @param aSettings are the new settings. + */ + void LoadSettings( const PNS_ROUTING_SETTINGS& aSettings ) + { + m_settings = aSettings; + + ApplySettings(); + } + + void EnableSnapping( bool aEnable ) + { + m_snappingEnabled = aEnable; + } + + bool SnappingEnabled() const + { + return m_snappingEnabled; + } + private: + void movePlacing( const VECTOR2I& aP, PNS_ITEM* aItem ); + void moveDragging( const VECTOR2I& aP, PNS_ITEM* aItem ); + + void eraseView(); + void updateView( PNS_NODE* aNode, PNS_ITEMSET& aCurrent ); + void clearViewFlags(); // optHoverItem queryHoverItemEx(const VECTOR2I& aP); - PNS_ITEM* pickSingleItem( PNS_ITEMSET& aItems ) const; // std::vector aItems) const; - void splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ); // optHoverItem& aItem); - void commitRouting( PNS_NODE* aNode ); - PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_SEGMENT* aLatestSeg ); - PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_LINE* aNewLine ); + PNS_ITEM* pickSingleItem( PNS_ITEMSET& aItems ) const; + void splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ); PNS_VIA* checkLoneVia( PNS_JOINT* aJoint ) const; PNS_ITEM* syncPad( D_PAD* aPad ); @@ -177,35 +223,44 @@ private: void highlightCurrent( bool enabled ); + void markViolations( PNS_NODE *aNode, PNS_ITEMSET& aCurrent, PNS_NODE::ITEM_VECTOR& aRemoved ); + int m_currentLayer; int m_currentNet; - int m_currentWidth; - int m_currentViaDiameter; - int m_currentViaDrill; - - bool m_start_diagonal; RouterState m_state; BOARD* m_board; PNS_NODE* m_world; + PNS_NODE* m_lastNode; PNS_LINE_PLACER* m_placer; + PNS_DRAGGER *m_dragger; + PNS_LINE* m_draggedLine; + PNS_SHOVE* m_shove; + int m_draggedSegmentIndex; + int m_iterLimit; + bool m_showInterSteps; + int m_snapshotIter; KIGFX::VIEW* m_view; KIGFX::VIEW_GROUP* m_previewItems; + PNS_ITEM* m_currentEndItem; + VECTOR2I m_currentEnd; VECTOR2I m_currentStart; VECTOR2I m_originalStart; bool m_placingVia; bool m_startsOnVia; + bool m_snappingEnabled; + bool m_violation; -// optHoverItem m_startItem, m_endItem; + // optHoverItem m_startItem, m_endItem; PNS_ROUTING_SETTINGS m_settings; PNS_CLEARANCE_FUNC* m_clearanceFunc; - boost::unordered_set m_hiddenItems; + boost::unordered_set m_hiddenItems; ///> Stores list of modified items in the current operation PICKED_ITEMS_LIST m_undoBuffer; diff --git a/pcbnew/router/pns_routing_settings.cpp b/pcbnew/router/pns_routing_settings.cpp new file mode 100644 index 0000000000..cf87359674 --- /dev/null +++ b/pcbnew/router/pns_routing_settings.cpp @@ -0,0 +1,51 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#include "pns_routing_settings.h" + +PNS_ROUTING_SETTINGS::PNS_ROUTING_SETTINGS() +{ + m_routingMode = RM_Walkaround; + m_optimizerEffort = OE_FULL; + m_removeLoops = true; + m_smartPads = true; + m_shoveVias = true; + m_suggestFinish = false; + m_followMouse = true; + m_startDiagonal = false; + m_shoveIterationLimit = 250; + m_shoveTimeLimit = 1000; + m_walkaroundIterationLimit = 40; + m_jumpOverObstacles = false; + m_smoothDraggedSegments = true; + m_canViolateDRC = false; +} + + +TIME_LIMIT PNS_ROUTING_SETTINGS::ShoveTimeLimit() const +{ + return TIME_LIMIT ( m_shoveTimeLimit ); +} + + +int PNS_ROUTING_SETTINGS::ShoveIterationLimit() const +{ + return m_shoveIterationLimit; +} diff --git a/pcbnew/router/pns_routing_settings.h b/pcbnew/router/pns_routing_settings.h index 72a4babef0..5f6de3fa92 100644 --- a/pcbnew/router/pns_routing_settings.h +++ b/pcbnew/router/pns_routing_settings.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,39 +15,146 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ -#ifndef __PNS_ROUTER_SETTINGS -#define __PNS_ROUTER_SETTINGS +#ifndef __PNS_ROUTING_SETTINGS +#define __PNS_ROUTING_SETTINGS +#include "direction.h" +#include "time_limit.h" + ///> Routing modes enum PNS_MODE { - RM_Ignore = 0, ///> Ignore collisions - RM_Shove, ///> Only shove - RM_Walkaround, ///> Only walkaround - RM_Smart ///> Guess what's better + RM_MarkObstacles = 0, ///> Ignore collisions, mark obstacles + RM_Shove, ///> Only shove + RM_Walkaround, ///> Only walkaround + RM_Smart ///> Guess what's better, try to make least mess on the PCB }; +///> Optimization effort +enum PNS_OPTIMIZATION_EFFORT +{ + OE_LOW = 0, + OE_MEDIUM = 1, + OE_FULL = 2 +}; + +/** + * Class PNS_ROUTING_SETTINGS + * + * Contains all persistent settings of the router, such as the mode, optimization effort, etc. + */ + class PNS_ROUTING_SETTINGS { public: - PNS_MODE m_routingMode; + PNS_ROUTING_SETTINGS(); + ///> Returns the routing mode. + PNS_MODE Mode() const { return m_routingMode; } + + ///> Sets the routing mode. + void SetMode( PNS_MODE aMode ) { m_routingMode = aMode; } + + ///> Returns the optimizer effort. Bigger means cleaner traces, but slower routing. + PNS_OPTIMIZATION_EFFORT OptimizerEffort() const { return m_optimizerEffort; } + + ///> Sets the optimizer effort. Bigger means cleaner traces, but slower routing. + void SetOptimizerEffort( PNS_OPTIMIZATION_EFFORT aEffort ) { m_optimizerEffort = aEffort; } + + ///> Returns true if shoving vias is enbled. + bool ShoveVias() const { return m_shoveVias; } + + ///> Enables/disables shoving vias. + void SetShoveVias( bool aShoveVias ) { m_shoveVias = aShoveVias; } + + ///> Returns true if loop (redundant track) removal is on. + bool RemoveLoops() const { return m_removeLoops; } + + ///> Enables/disables loop (redundant track) removal. + void SetRemoveLoops( bool aRemoveLoops ) { m_removeLoops = aRemoveLoops; } + + ///> Returns true if suggesting the finish of currently placed track is on. + bool SuggestFinish() { return m_suggestFinish; } + + ///> Enables displaying suggestions for finishing the currently placed track. + void SetSuggestFinish( bool aSuggestFinish ) { m_suggestFinish = aSuggestFinish; } + + ///> Returns true if Smart Pads (automatic neckdown) is enabled. + bool SmartPads () const { return m_smartPads; } + + ///> Enables/disables Smart Pads (automatic neckdown). + void SetSmartPads( bool aSmartPads ) { m_smartPads = aSmartPads; } + + ///> Returns true if follow mouse mode is active (permanently on for the moment). + bool FollowMouse() const + { + return m_followMouse && !( Mode() == RM_MarkObstacles ); + } + + ///> Returns true if smoothing segments durign dragging is enabled. + bool SmoothDraggedSegments() const { return m_smoothDraggedSegments; } + + ///> Enables/disabled smoothing segments during dragging. + void SetSmoothDraggedSegments( bool aSmooth ) { m_smoothDraggedSegments = aSmooth; } + + ///> Returns true if jumping over unmovable obstacles is on. + bool JumpOverObstacles() const { return m_jumpOverObstacles; } + + ///> Enables/disables jumping over unmovable obstacles. + void SetJumpOverObstacles( bool aJumpOverObstacles ) { m_jumpOverObstacles = aJumpOverObstacles; } + + void SetStartDiagonal(bool aStartDiagonal) { m_startDiagonal = aStartDiagonal; } + + bool CanViolateDRC() const { return m_canViolateDRC; } + void SetCanViolateDRC( bool aViolate ) { m_canViolateDRC = aViolate; } + + void SetTrackWidth( int aWidth ) { m_trackWidth = aWidth; } + int GetTrackWidth() const { return m_trackWidth; } + void SetViaDiameter( int aDiameter ) { m_viaDiameter = aDiameter; } + int GetViaDiameter() const { return m_viaDiameter; } + void SetViaDrill( int aDrill ) { m_viaDrill = aDrill; } + int GetViaDrill() const { return m_viaDrill; } + + const DIRECTION_45 InitialDirection() const + { + if( m_startDiagonal ) + return DIRECTION_45( DIRECTION_45::NE ); + else + return DIRECTION_45( DIRECTION_45::N ); + } + + int ShoveIterationLimit() const; + TIME_LIMIT ShoveTimeLimit() const; + + int WalkaroundIterationLimit() const { return m_walkaroundIterationLimit; }; + TIME_LIMIT WalkaroundTimeLimit() const; + +private: + bool m_shoveVias; + bool m_startDiagonal; bool m_removeLoops; bool m_smartPads; - bool m_suggestEnding; - bool m_shoveOnRequest; - bool m_changePostures; + bool m_suggestFinish; bool m_followMouse; + bool m_jumpOverObstacles; + bool m_smoothDraggedSegments; + bool m_canViolateDRC; - int m_lineWidth; + PNS_MODE m_routingMode; + PNS_OPTIMIZATION_EFFORT m_optimizerEffort; + + int m_trackWidth; int m_viaDiameter; int m_viaDrill; + int m_preferredLayer; int m_walkaroundIterationLimit; int m_shoveIterationLimit; + TIME_LIMIT m_shoveTimeLimit; + TIME_LIMIT m_walkaroundTimeLimit; }; #endif diff --git a/pcbnew/router/pns_segment.h b/pcbnew/router/pns_segment.h index 06ab41dfa0..2550526c2e 100644 --- a/pcbnew/router/pns_segment.h +++ b/pcbnew/router/pns_segment.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_SEGMENT_H @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "pns_item.h" @@ -37,34 +37,29 @@ class PNS_SEGMENT : public PNS_ITEM public: PNS_SEGMENT() : PNS_ITEM( SEGMENT ) - {}; + {} PNS_SEGMENT( const SEG& aSeg, int aNet ) : - PNS_ITEM( SEGMENT ) + PNS_ITEM( SEGMENT ), m_seg( aSeg, 0 ) { m_net = aNet; - m_shape.Clear(); - m_shape.Append( aSeg.A ); - m_shape.Append( aSeg.B ); - }; + } PNS_SEGMENT( const PNS_LINE& aParentLine, const SEG& aSeg ) : - PNS_ITEM( SEGMENT ) + PNS_ITEM( SEGMENT ), + m_seg( aSeg, aParentLine.Width() ) { - m_net = aParentLine.GetNet(); - m_layers = aParentLine.GetLayers(); - m_width = aParentLine.GetWidth(); - m_shape.Clear(); - m_shape.Append( aSeg.A ); - m_shape.Append( aSeg.B ); + m_net = aParentLine.Net(); + m_layers = aParentLine.Layers(); + m_marker = aParentLine.Marker(); + m_rank = aParentLine.Rank(); }; + PNS_SEGMENT* Clone( ) const; - PNS_SEGMENT* Clone() const; - - const SHAPE* GetShape() const + const SHAPE* Shape() const { - return static_cast( &m_shape ); + return static_cast( &m_seg ); } void SetLayer( int aLayer ) @@ -72,53 +67,59 @@ public: SetLayers( PNS_LAYERSET( aLayer ) ); } - int GetLayer() const + int Layer() const { - return GetLayers().Start(); - } - - const SHAPE_LINE_CHAIN& GetCLine() const - { - return m_shape; + return Layers().Start(); } void SetWidth( int aWidth ) { - m_width = aWidth; + m_seg.SetWidth(aWidth); } - int GetWidth() const + int Width() const { - return m_width; + return m_seg.GetWidth(); } - const SEG GetSeg() const + const SEG& Seg() const { - assert( m_shape.PointCount() >= 1 ); + return m_seg.GetSeg(); + } - if( m_shape.PointCount() == 1 ) - return SEG( m_shape.CPoint( 0 ), m_shape.CPoint( 0 ) ); - - return SEG( m_shape.CPoint( 0 ), m_shape.CPoint( 1 ) ); + const SHAPE_LINE_CHAIN CLine() const + { + return SHAPE_LINE_CHAIN( m_seg.GetSeg().A, m_seg.GetSeg().B ); } void SetEnds( const VECTOR2I& a, const VECTOR2I& b ) { - m_shape.Clear(); - m_shape.Append( a ); - m_shape.Append( b ); - } + m_seg.SetSeg( SEG ( a, b ) ); + } void SwapEnds() { - m_shape = m_shape.Reverse(); + SEG tmp = m_seg.GetSeg(); + m_seg.SetSeg( SEG (tmp.B , tmp.A ) ); } const SHAPE_LINE_CHAIN Hull( int aClearance, int aWalkaroundThickness ) const; + virtual VECTOR2I Anchor(int n) const + { + if( n == 0 ) + return m_seg.GetSeg().A; + else + return m_seg.GetSeg().B; + } + + virtual int AnchorCount() const + { + return 2; + } + private: - SHAPE_LINE_CHAIN m_shape; - int m_width; + SHAPE_SEGMENT m_seg; }; #endif diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index ad58ee1feb..8b46a503db 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,477 +15,1110 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include #include -#include +#include #include "trace.h" +#include "range.h" #include "pns_line.h" #include "pns_node.h" #include "pns_walkaround.h" #include "pns_shove.h" +#include "pns_solid.h" #include "pns_optimizer.h" #include "pns_via.h" #include "pns_utils.h" +#include "pns_router.h" +#include "pns_shove.h" + +#include "time_limit.h" #include -PNS_SHOVE::PNS_SHOVE( PNS_NODE* aWorld ) +static void sanityCheck( PNS_LINE *aOld, PNS_LINE *aNew ) +{ + assert( aOld->CPoint( 0 ) == aNew->CPoint( 0 ) ); + assert( aOld->CPoint( -1 ) == aNew->CPoint( -1 ) ); +} + + +PNS_SHOVE::PNS_SHOVE( PNS_NODE* aWorld, PNS_ROUTER* aRouter ) : + PNS_ALGO_BASE ( aRouter ) { m_root = aWorld; - m_iterLimit = 100; -}; +} PNS_SHOVE::~PNS_SHOVE() { + // free all the stuff we've created during routing/dragging operation. + BOOST_FOREACH( PNS_ITEM *item, m_gcItems ) + delete item; } -struct range +// garbage-collected line assembling +PNS_LINE* PNS_SHOVE::assembleLine( const PNS_SEGMENT *aSeg, int *aIndex ) { - range() - { - min_v = max_v = -1; - } + PNS_LINE* l = m_currentNode->AssembleLine( const_cast( aSeg ), aIndex ); - void add( int x ) - { - if( min_v < 0 ) min_v = x; + m_gcItems.push_back(l); - if( max_v < 0 ) max_v = x; - - if( x < min_v ) - min_v = x; - else if( x > max_v ) - max_v = x; - } - - int start() - { - return min_v; - } - - int end() - { - return max_v; - } - - int min_v, max_v; -}; - -// fixme: this is damn f***ing inefficient. And fails much too often due to broken direction finding algorithm. -bool PNS_SHOVE::tryShove( PNS_NODE* aNode, PNS_LINE* aHead, PNS_LINE* aObstacle, - PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding ) -{ - const SHAPE_LINE_CHAIN& head = aHead->GetCLine(); - bool cw = false; - int i; - - if( aHead->EndsWithVia() && !aHead->GetLayers().Overlaps( aObstacle->GetLayers() ) ) - { - int clearance = aNode->GetClearance( aHead, aObstacle ); - SHAPE_LINE_CHAIN hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); - - // SHAPE_LINE_CHAIN path_pre, path_walk_cw, path_walk_ccw, path_post; - - SHAPE_LINE_CHAIN path_cw, path_ccw, * path; - - aObstacle->NewWalkaround( hull, path_cw, true ); - aObstacle->NewWalkaround( hull, path_ccw, false ); - - path = path_ccw.Length() < path_cw.Length() ? &path_ccw : &path_cw; - aResult->SetShape( *path ); - - // PNSDisplayDebugLine (*path, 5); - - if( !aResult->Is45Degree() ) - { - // printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str()); - } - - /*... special case for vias? */ - - return !aNode->CheckColliding( aResult, aHead ); - } - - int ns = head.SegmentCount(); - - if( aHead->EndsWithVia() ) - ns++; - - for( i = 0; i < head.SegmentCount(); i++ ) - { - const PNS_SEGMENT hs( *aHead, head.CSegment( i ) ); - - - if( aNode->CheckColliding( &hs, aObstacle ) ) - { - VECTOR2I v1 = hs.GetSeg().B - hs.GetSeg().A; - VECTOR2I v2 = aObstacleSeg.GetSeg().B - aObstacleSeg.GetSeg().A; - - VECTOR2I::extended_type det = v1.Cross( v2 ); - - if( det > 0 ) - cw = true; - else - cw = false; - - break; - } - } - - if( aInvertWinding ) - { - if( cw ) - cw = false; - else - cw = true; - } - - PNS_LINE shoved( *aObstacle ); - - int clearance = aNode->GetClearance( aHead, aObstacle ); - - range r; - - for( i = 0; i < ns; i++ ) - { - SHAPE_LINE_CHAIN hull; - - if( i < head.SegmentCount() ) - { - const PNS_SEGMENT hs( *aHead, head.CSegment( i ) ); - hull = hs.Hull( clearance, 0 ); - } - else - hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); - - SHAPE_LINE_CHAIN path_pre, path_walk, path_post, tmp; - SHAPE_LINE_CHAIN path_pre2, path_walk2, path_post2; - - // shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); - shoved.NewWalkaround( hull, path_pre, path_walk, path_post, cw ); - - /*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 ) - * { - * TRACE(5, "polyset orig\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre.Format().c_str() % path_walk.Format().c_str() % path_post.Format().c_str()); - * TRACE(5, "polyset err\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre2.Format().c_str() % path_walk2.Format().c_str() % path_post2.Format().c_str()); - * }*/ - - tmp = shoved.GetCLine(); - - if( path_walk.SegmentCount() ) - r.add( i ); - - path_pre.Append( path_walk ); - path_pre.Append( path_post ); - path_pre.Simplify(); - shoved.SetShape( path_pre ); -// shoved.SetAffectedRange ( start, end ); - *aResult = shoved; - - if( !aResult->Is45Degree() ) - { - // TRACE(5, "polyset non-45\npoly %s\npoly %s\npoly %s\nendpolyset\n", tmp.Format().c_str() % hull.Format().c_str() % aResult->GetCLine().Format().c_str()); - } - } - - TRACE( 2, "CW %d affectedRange %d-%d [total %d]", (cw ? 1 : 0) % r.start() % r.end() % ns ); - - return !aNode->CheckColliding( aResult, aHead ); + return l; } -PNS_SHOVE::ShoveStatus PNS_SHOVE::shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, - PNS_LINE* aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult ) +// garbage-collected line cloning +PNS_LINE *PNS_SHOVE::cloneLine ( const PNS_LINE *aLine ) { - bool rv = tryShove( aNode, aCurrent, aObstacle, aObstacleSeg, aResult, false ); + PNS_LINE *l = aLine->Clone(); - if( !rv ) - rv = tryShove( aNode, aCurrent, aObstacle, aObstacleSeg, aResult, true ); + m_gcItems.push_back( l ); + return l; +} - if( !rv ) - { - TRACEn( 2, "Shove failed" ); + +// A dumb function that checks if the shoved line is shoved the right way, e.g. +// visually "outwards" of the line/via applying pressure on it. Unfortunately there's no +// mathematical concept of orientation of an open curve, so we use some primitive heuristics: +// if the shoved line wraps around the start of the "pusher", it's likely shoved in wrong direction. +bool PNS_SHOVE::checkBumpDirection( PNS_LINE *aCurrent, PNS_LINE *aShoved ) const +{ + const SEG ss = aCurrent->CSegment( 0 ); + + int dist = m_currentNode->GetClearance( aCurrent, aShoved ) + PNS_HULL_MARGIN; + + dist += aCurrent->Width() / 2; + dist += aShoved->Width() / 2; + + const VECTOR2I ps = ss.A - ( ss.B - ss.A ).Resize( dist ); + + return !aShoved->CLine().PointOnEdge( ps ); +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::walkaroundLoneVia( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_LINE* aShoved ) +{ + int clearance = m_currentNode->GetClearance( aCurrent, aObstacle ); + const SHAPE_LINE_CHAIN hull = aCurrent->Via().Hull( clearance, aObstacle->Width() ); + SHAPE_LINE_CHAIN path_cw, path_ccw; + + aObstacle->Walkaround( hull, path_cw, true ); + aObstacle->Walkaround( hull, path_ccw, false ); + + const SHAPE_LINE_CHAIN& shortest = path_ccw.Length() < path_cw.Length() ? path_ccw : path_cw; + + if( shortest.PointCount() < 2 ) return SH_INCOMPLETE; - } - aResult->GetLine().Simplify(); + if( aObstacle->CPoint( -1 ) != shortest.CPoint( -1 ) ) + return SH_INCOMPLETE; - const SHAPE_LINE_CHAIN& sh_shoved = aResult->GetCLine(); - const SHAPE_LINE_CHAIN& sh_orig = aObstacle->GetCLine(); + if( aObstacle->CPoint( 0 ) != shortest.CPoint( 0 ) ) + return SH_INCOMPLETE; - if( sh_shoved.SegmentCount() > 1 && sh_shoved.CPoint( 0 ) == sh_orig.CPoint( 0 ) - && sh_shoved.CPoint( -1 ) == sh_orig.CPoint( -1 ) ) + aShoved->SetShape( shortest ); + + if( m_currentNode->CheckColliding( aShoved, aCurrent ) ) + return SH_INCOMPLETE; + + return SH_OK; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processHullSet( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_LINE* aShoved, const HULL_SET& aHulls ) +{ + const SHAPE_LINE_CHAIN& obs = aObstacle->CLine(); + bool failingDirCheck = false; + int attempt; + + for( attempt = 0; attempt < 4; attempt++ ) + { + bool invertTraversal = ( attempt >= 2 ); + bool clockwise = attempt % 2; + int vFirst = -1, vLast = -1; + + SHAPE_LINE_CHAIN path; + PNS_LINE l( *aObstacle ); + + for( int i = 0; i < (int) aHulls.size(); i++ ) + { + const SHAPE_LINE_CHAIN& hull = aHulls[invertTraversal ? aHulls.size() - 1 - i : i]; + + l.Walkaround( hull, path, clockwise ); + path.Simplify(); + l.SetShape( path ); + } + + for( int i = 0; i < std::min ( path.PointCount(), obs.PointCount() ); i++ ) + { + if( path.CPoint( i ) != obs.CPoint( i ) ) + { + vFirst = i; + break; + } + } + + int k = obs.PointCount() - 1; + for( int i = path.PointCount() - 1; i >= 0 && k >= 0; i--, k-- ) + { + if( path.CPoint( i ) != obs.CPoint( k ) ) + { + vLast = i; + break; + } + } + + if( ( vFirst < 0 || vLast < 0 ) && !path.CompareGeometry( aObstacle->CLine() ) ) + { + TRACE( 100, "attempt %d fail vfirst-last", attempt ); + continue; + } + + if( path.CPoint( -1 ) != obs.CPoint( -1 ) || path.CPoint( 0 ) != obs.CPoint( 0 ) ) + { + TRACE( 100, "attempt %d fail vend-start\n", attempt ); + continue; + } + + if( !checkBumpDirection( aCurrent, &l ) ) + { + TRACE( 100, "attempt %d fail direction-check", attempt ); + failingDirCheck = true; + aShoved->SetShape( l.CLine() ); + + continue; + } + + if( path.SelfIntersecting() ) + { + TRACE( 100, "attempt %d fail self-intersect", attempt ); + continue; + } + + bool colliding = m_currentNode->CheckColliding( &l, aCurrent ); + + if( ( aCurrent->Marker() & MK_HEAD ) && !colliding ) + { + PNS_JOINT* jtStart = m_currentNode->FindJoint( aCurrent->CPoint( 0 ), aCurrent ); + + BOOST_FOREACH( PNS_ITEM* item, jtStart->LinkList() ) + { + if( m_currentNode->CheckColliding( item, &l ) ) + colliding = true; + } + } + + if( colliding ) + { + TRACE( 100, "attempt %d fail coll-check", attempt ); + continue; + } + + aShoved->SetShape( l.CLine() ); + return SH_OK; - else if( !sh_shoved.SegmentCount() ) - return SH_NULL; - else - return SH_INCOMPLETE; + } + + return failingDirCheck ? SH_OK : SH_INCOMPLETE; } -bool PNS_SHOVE::reduceSpringback( PNS_LINE* aHead ) +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_LINE* aShoved ) { - bool rv = false; + aShoved->ClearSegmentLinks(); - while( !m_nodeStack.empty() ) + bool obstacleIsHead = false; + + if( aObstacle->LinkedSegments() ) { - SpringbackTag st_stack = m_nodeStack.back(); - bool tail_ok = true; + BOOST_FOREACH( PNS_SEGMENT* s, *aObstacle->LinkedSegments() ) - if( !st_stack.node->CheckColliding( aHead ) && tail_ok ) + if( s->Marker() & MK_HEAD ) { - rv = true; - delete st_stack.node; - m_nodeStack.pop_back(); - } - else + obstacleIsHead = true; break; + } + } + + SHOVE_STATUS rv; + + bool viaOnEnd = aCurrent->EndsWithVia(); + + if( viaOnEnd && ( !aCurrent->LayersOverlap( aObstacle ) || aCurrent->SegmentCount() == 0 ) ) + { + rv = walkaroundLoneVia( aCurrent, aObstacle, aShoved ); + } + else + { + int w = aObstacle->Width(); + int n_segs = aCurrent->SegmentCount(); + int clearance = m_currentNode->GetClearance( aCurrent, aObstacle ); + + HULL_SET hulls; + + hulls.reserve( n_segs + 1 ); + + for( int i = 0; i < n_segs; i++ ) + { + PNS_SEGMENT seg( *aCurrent, aCurrent->CSegment( i ) ); + hulls.push_back( seg.Hull( clearance, w ) ); + } + + if( viaOnEnd ) + hulls.push_back ( aCurrent->Via().Hull( clearance, w ) ); + + rv = processHullSet ( aCurrent, aObstacle, aShoved, hulls ); + } + + if( obstacleIsHead ) + aShoved->Mark( aShoved->Marker() | MK_HEAD ); + + return rv; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE* aCurrent, PNS_SEGMENT* aObstacleSeg ) +{ + int segIndex; + PNS_LINE* obstacleLine = assembleLine( aObstacleSeg, &segIndex ); + PNS_LINE* shovedLine = cloneLine( obstacleLine ); + + SHOVE_STATUS rv = processSingleLine( aCurrent, obstacleLine, shovedLine ); + + assert ( obstacleLine->LayersOverlap( shovedLine ) ); + + if( rv == SH_OK ) + { + if ( shovedLine->Marker() & MK_HEAD ) + m_newHead = *shovedLine; + + sanityCheck( obstacleLine, shovedLine ); + m_currentNode->Replace( obstacleLine, shovedLine ); + sanityCheck( obstacleLine, shovedLine ); + + int rank = aCurrent->Rank(); + shovedLine->SetRank( rank - 1 ); + + pushLine( shovedLine ); + } + +#ifdef DEBUG + m_logger.NewGroup ("on-colliding-segment", m_iter); + m_logger.Log ( aObstacleSeg, 0, "obstacle-segment"); + m_logger.Log ( aCurrent, 1, "current-line"); + m_logger.Log ( obstacleLine, 2, "obstacle-line"); + m_logger.Log ( shovedLine, 3, "shoved-line"); +#endif + + return rv; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE *aCurrent, PNS_LINE *aObstacle ) +{ + PNS_LINE* shovedLine = cloneLine( aObstacle ); + + SHOVE_STATUS rv = processSingleLine( aCurrent, aObstacle, shovedLine ); + + if( rv == SH_OK ) + { + if ( shovedLine->Marker() & MK_HEAD ) + m_newHead = *shovedLine; + + sanityCheck( aObstacle, shovedLine ); + m_currentNode->Replace( aObstacle, shovedLine ); + sanityCheck( aObstacle, shovedLine ); + + int rank = aObstacle->Rank(); + shovedLine->SetRank ( rank ); + + pushLine( shovedLine ); + + #ifdef DEBUG + m_logger.NewGroup( "on-colliding-line", m_iter ); + m_logger.Log( aObstacle, 0, "obstacle-line" ); + m_logger.Log( aCurrent, 1, "current-line" ); + m_logger.Log( shovedLine, 3, "shoved-line" ); + #endif } return rv; } -bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, PNS_LINE* aHead, const PNS_COST_ESTIMATOR& aCost ) +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE* aCurrent, PNS_SOLID* aObstacleSolid ) { - BOX2I headBB = aHead->GetCLine().BBox(); - SpringbackTag st; + PNS_WALKAROUND walkaround( m_currentNode, Router() ); + PNS_LINE* walkaroundLine = cloneLine( aCurrent ); + + if( aCurrent->EndsWithVia() ) + { + PNS_VIA vh = aCurrent->Via(); + PNS_VIA* via = NULL; + PNS_JOINT* jtStart = m_currentNode->FindJoint ( vh.Pos(), aCurrent ); - st.node = aNode; - st.cost = aCost; - st.length = std::max( headBB.GetWidth(), headBB.GetHeight() );; + if( !jtStart ) + return SH_INCOMPLETE; + + BOOST_FOREACH( PNS_ITEM* item, jtStart->LinkList() ) + { + if( item->OfKind( PNS_ITEM::VIA ) ) + { + via = (PNS_VIA*) item; + break; + } + } + + if( via && m_currentNode->CheckColliding( via, aObstacleSolid ) ) + return onCollidingVia( aObstacleSolid, via ); + } + + walkaround.SetSolidsOnly( true ); + walkaround.SetIterationLimit ( 8 ); // fixme: make configurable + + int currentRank = aCurrent->Rank(); + int nextRank; + + if( !Settings().JumpOverObstacles() ) + { + nextRank = currentRank + 10000; + walkaround.SetSingleDirection( false ); + } + else + { + nextRank = currentRank - 1; + walkaround.SetSingleDirection( true ); + } + + if( walkaround.Route( *aCurrent, *walkaroundLine, false ) != PNS_WALKAROUND::DONE ) + return SH_INCOMPLETE; + + walkaroundLine->ClearSegmentLinks(); + walkaroundLine->Unmark(); + walkaroundLine->Line().Simplify(); + + if( walkaroundLine->HasLoops() ) + return SH_INCOMPLETE; + + if( aCurrent->Marker() & MK_HEAD ) + { + walkaroundLine->Mark( MK_HEAD ); + m_newHead = *walkaroundLine; + } + + m_currentNode->Replace( aCurrent, walkaroundLine ); + walkaroundLine->SetRank ( nextRank ); + +#ifdef DEBUG + m_logger.NewGroup( "on-colliding-solid", m_iter ); + m_logger.Log( aObstacleSolid, 0, "obstacle-solid" ); + m_logger.Log( aCurrent, 1, "current-line" ); + m_logger.Log( walkaroundLine, 3, "walk-line" ); +#endif + + popLine(); + pushLine( walkaroundLine ); + + return SH_OK; +} + + +bool PNS_SHOVE::reduceSpringback( const PNS_ITEMSET& aHeadSet ) +{ + bool rv = false; + + while( !m_nodeStack.empty() ) + { + SPRINGBACK_TAG spTag = m_nodeStack.back(); + + if( !spTag.m_node->CheckColliding( aHeadSet ) ) + { + rv = true; + + delete spTag.m_node; + m_nodeStack.pop_back(); + } + else + break; + } + + return rv; +} + + +bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET& aHeadItems, + const PNS_COST_ESTIMATOR& aCost ) +{ + SPRINGBACK_TAG st; + + st.m_node = aNode; + st.m_cost = aCost; + st.m_headItems = aHeadItems; m_nodeStack.push_back( st ); + return true; } -const PNS_COST_ESTIMATOR PNS_SHOVE::TotalCost() const +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank ) { - if( m_nodeStack.empty() ) - return PNS_COST_ESTIMATOR(); - else - return m_nodeStack.back().cost; + LINE_PAIR_VEC draggedLines; + VECTOR2I p0 ( aVia->Pos() ); + PNS_JOINT* jt = m_currentNode->FindJoint( p0, 1, aVia->Net() ); + PNS_VIA* pushedVia = aVia -> Clone(); + + pushedVia->SetPos( p0 + aForce ); + pushedVia->Mark( aVia->Marker() ); + + if( aVia->Marker() & MK_HEAD ) + { + m_draggedVia = pushedVia; + } + + if( !jt ) + { + TRACEn( 1, "weird, can't find the center-of-via joint\n" ); + return SH_INCOMPLETE; + } + + BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) + { + if( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_SEGMENT* seg = (PNS_SEGMENT*) item; + LINE_PAIR lp; + int segIndex; + + lp.first = assembleLine( seg, &segIndex ); + + assert( segIndex == 0 || ( segIndex == ( lp.first->SegmentCount() - 1 ) ) ); + + if( segIndex == 0 ) + lp.first->Reverse(); + + lp.second = cloneLine( lp.first ); + lp.second->ClearSegmentLinks(); + lp.second->DragCorner( p0 + aForce, lp.second->CLine().Find( p0 ) ); + lp.second->AppendVia ( *pushedVia ); + draggedLines.push_back( lp ); + } + } + + m_currentNode->Remove( aVia ); + m_currentNode->Add ( pushedVia ); + + if( aVia->BelongsTo( m_currentNode ) ) + delete aVia; + + pushedVia->SetRank( aCurrentRank - 1 ); + +#ifdef DEBUG + m_logger.Log ( aVia, 0, "obstacle-via"); + m_logger.Log ( pushedVia, 1, "pushed-via"); +#endif + + BOOST_FOREACH( LINE_PAIR lp, draggedLines ) + { + if( lp.first->Marker() & MK_HEAD ) + { + lp.second->Mark( MK_HEAD ); + m_newHead = *lp.second; + } + + unwindStack(lp.first); + + if( lp.second->SegmentCount() ) + { + m_currentNode->Replace( lp.first, lp.second ); + lp.second->SetRank( aCurrentRank - 1 ); + pushLine( lp.second ); + } + else + m_currentNode->Remove( lp.first ); + +#ifdef DEBUG + m_logger.Log( lp.first, 2, "fan-pre" ); + m_logger.Log( lp.second, 3, "fan-post" ); +#endif + } + + return SH_OK; } -PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines( PNS_LINE* aCurrentHead ) +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingVia (PNS_ITEM* aCurrent, PNS_VIA* aObstacleVia ) { - std::stack lineStack; - PNS_NODE* node, * parent; + int clearance = m_currentNode->GetClearance( aCurrent, aObstacleVia ) ; + LINE_PAIR_VEC draggedLines; + VECTOR2I p0( aObstacleVia->Pos() ); + bool colLine = false, colVia = false; + PNS_LINE *currentLine = NULL; + VECTOR2I mtvLine, mtvVia, mtv, mtvSolid; + int rank = -1; + + if( aCurrent->OfKind( PNS_ITEM::LINE ) ) + { +#ifdef DEBUG + m_logger.NewGroup( "push-via-by-line", m_iter ); + m_logger.Log( aCurrent, 4, "current" ); +#endif + + currentLine = (PNS_LINE*) aCurrent; + colLine = CollideShapes( aObstacleVia->Shape(), currentLine->Shape(), + clearance + currentLine->Width() / 2 + PNS_HULL_MARGIN, + true, mtvLine ); + + if( currentLine->EndsWithVia() ) + colVia = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(), + clearance + PNS_HULL_MARGIN, true, mtvVia ); + + if( !colLine && !colVia ) + return SH_OK; + + if( colLine && colVia ) + mtv = mtvVia.EuclideanNorm() > mtvLine.EuclideanNorm() ? mtvVia : mtvLine; + else if( colLine ) + mtv = mtvLine; + else + mtv = mtvVia; + + rank = currentLine->Rank(); + } + else if (aCurrent->OfKind(PNS_ITEM::SOLID)) + { + CollideShapes( aObstacleVia->Shape(), aCurrent->Shape(), + clearance + PNS_HULL_MARGIN, true, mtvSolid ); + mtv = mtvSolid; + rank = aCurrent->Rank() + 10000; + } + + return pushVia( aObstacleVia, mtv, rank ); +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onReverseCollidingVia( PNS_LINE* aCurrent, PNS_VIA* aObstacleVia ) +{ + std::vector steps; + int n = 0; + PNS_LINE* cur = cloneLine( aCurrent ); + cur->ClearSegmentLinks(); + + PNS_JOINT* jt = m_currentNode->FindJoint( aObstacleVia->Pos(), aObstacleVia ); + PNS_LINE* shoved = cloneLine( aCurrent ); + shoved->ClearSegmentLinks(); + + cur->RemoveVia(); + unwindStack(aCurrent); + + BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) + { + if( item->OfKind( PNS_ITEM::SEGMENT ) && item->LayersOverlap( aCurrent ) ) + { + PNS_SEGMENT* seg = (PNS_SEGMENT*) item; + PNS_LINE* head = assembleLine( seg ); + + head->AppendVia( *aObstacleVia ); + + SHOVE_STATUS st = processSingleLine ( head, cur, shoved ); + + if( st != SH_OK ) + { +#ifdef DEBUG + m_logger.NewGroup( "on-reverse-via-fail-shove", m_iter ); + m_logger.Log( aObstacleVia, 0, "the-via" ); + m_logger.Log( aCurrent, 1, "current-line" ); + m_logger.Log( shoved, 3, "shoved-line" ); +#endif + + return st; + } + + cur->SetShape( shoved->CLine() ); + n++; + } + } + + if( !n ) + { +#ifdef DEBUG + m_logger.NewGroup( "on-reverse-via-fail-lonevia", m_iter ); + m_logger.Log( aObstacleVia, 0, "the-via" ); + m_logger.Log( aCurrent, 1, "current-line" ); +#endif + + PNS_LINE head( *aCurrent ); + head.Line().Clear(); + head.AppendVia( *aObstacleVia ); + head.ClearSegmentLinks(); + + SHOVE_STATUS st = processSingleLine( &head, aCurrent, shoved ); + + if( st != SH_OK ) + return st; + + cur->SetShape ( shoved->CLine() ); + } + + if( aCurrent->EndsWithVia() ) + shoved->AppendVia( aCurrent->Via() ); + +#ifdef DEBUG + m_logger.NewGroup( "on-reverse-via", m_iter ); + m_logger.Log( aObstacleVia, 0, "the-via" ); + m_logger.Log( aCurrent, 1, "current-line" ); + m_logger.Log( shoved, 3, "shoved-line" ); +#endif + int currentRank = aCurrent->Rank(); + m_currentNode->Replace ( aCurrent, shoved ); + + pushLine( shoved ); + shoved->SetRank( currentRank ); + + return SH_OK; +} + + +void PNS_SHOVE::unwindStack( PNS_SEGMENT *aSeg ) +{ + for( std::vector::iterator i = m_lineStack.begin(); i != m_lineStack.end(); ) + { + if( (*i)->ContainsSegment ( aSeg ) ) + i = m_lineStack.erase( i ); + else + i++; + } + + for( std::vector::iterator i = m_optimizerQueue.begin(); i != m_optimizerQueue.end(); ) + { + if( (*i)->ContainsSegment( aSeg ) ) + i = m_optimizerQueue.erase( i ); + else + i++; + } +} + + +void PNS_SHOVE::unwindStack( PNS_ITEM* aItem ) +{ + if( aItem->OfKind( PNS_ITEM::SEGMENT ) ) + unwindStack( static_cast( aItem ) ); + else if( aItem->OfKind( PNS_ITEM::LINE ) ) + { + PNS_LINE* l = static_cast( aItem ); + + if ( !l->LinkedSegments() ) + return; + + BOOST_FOREACH( PNS_SEGMENT* seg, *l->LinkedSegments() ) + unwindStack( seg ); + } +} + + +void PNS_SHOVE::pushLine( PNS_LINE* aL ) +{ + if( aL->LinkCount() >= 0 && ( aL->LinkCount() != aL->SegmentCount() ) ) + assert( false ); + + m_lineStack.push_back( aL ); + m_optimizerQueue.push_back( aL ); +} + + +void PNS_SHOVE::popLine( ) +{ + PNS_LINE* l = m_lineStack.back(); + + for( std::vector::iterator i = m_optimizerQueue.begin(); i != m_optimizerQueue.end(); ) + { + if( ( *i ) == l ) + { + i = m_optimizerQueue.erase( i ); + } + else + i++; + } + + m_lineStack.pop_back(); +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveIteration( int aIter ) +{ + PNS_LINE* currentLine = m_lineStack.back(); + PNS_NODE::OPT_OBSTACLE nearest; + SHOVE_STATUS st; + + PNS_ITEM::PnsKind search_order[] = { PNS_ITEM::SOLID, PNS_ITEM::VIA, PNS_ITEM::SEGMENT }; + + for( int i = 0; i < 3; i++ ) + { + nearest = m_currentNode->NearestObstacle( currentLine, search_order[i] ); + + if( nearest ) + break; + } + + if( !nearest ) + { + m_lineStack.pop_back(); + return SH_OK; + } + + PNS_ITEM* ni = nearest->m_item; + + unwindStack( ni ); + + if( !ni->OfKind( PNS_ITEM::SOLID ) && ni->Rank() >= 0 && ni->Rank() > currentLine->Rank() ) + { + switch( ni->Kind() ) + { + case PNS_ITEM::VIA: + { + PNS_VIA* revVia = (PNS_VIA*) ni; + TRACE( 2, "iter %d: reverse-collide-via", aIter ); + + if( currentLine->EndsWithVia() && m_currentNode->CheckColliding( ¤tLine->Via(), revVia ) ) + { + st = SH_INCOMPLETE; + } + else + { + st = onReverseCollidingVia ( currentLine, revVia ); + } + + break; + } + + case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT* seg = (PNS_SEGMENT*) ni; + TRACE( 2, "iter %d: reverse-collide-segment ", aIter ); + PNS_LINE* revLine = assembleLine( seg ); + + popLine(); + st = onCollidingLine( revLine, currentLine ); + pushLine( revLine ); + break; + } + + default: + assert( false ); + } + } + else + { // "forward" collisoins + switch( ni->Kind() ) + { + case PNS_ITEM::SEGMENT: + TRACE( 2, "iter %d: collide-segment ", aIter ); + st = onCollidingSegment( currentLine, (PNS_SEGMENT*) ni ); + break; + + case PNS_ITEM::VIA: + TRACE( 2, "iter %d: shove-via ", aIter ); + st = onCollidingVia( currentLine, (PNS_VIA*) ni ); + break; + + case PNS_ITEM::SOLID: + TRACE( 2, "iter %d: walk-solid ", aIter ); + st = onCollidingSolid( currentLine, (PNS_SOLID*) ni ); + break; + + default: + break; + } + } + + return st; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveMainLoop() +{ + SHOVE_STATUS st = SH_OK; + + TRACE( 1, "ShoveStart [root: %d jts, current: %d jts]", m_root->JointCount() % + m_currentNode->JointCount() ); + + int iterLimit = Settings().ShoveIterationLimit(); + TIME_LIMIT timeLimit = Settings().ShoveTimeLimit(); + + m_iter = 0; + + timeLimit.Restart(); + + while( !m_lineStack.empty() ) + { + st = shoveIteration( m_iter ); + + m_iter++; + + if( st == SH_INCOMPLETE || timeLimit.Expired() || m_iter >= iterLimit ) + { + st = SH_INCOMPLETE; + break; + } + } + + return st; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) +{ + SHOVE_STATUS st = SH_OK; + + // empty head? nothing to shove... + if( !aCurrentHead.SegmentCount() ) + return SH_INCOMPLETE; + + PNS_LINE* head = cloneLine( &aCurrentHead ); + head->ClearSegmentLinks(); + + m_lineStack.clear(); + m_optimizerQueue.clear(); + m_newHead = OPT_LINE(); + m_logger.Clear(); + + PNS_ITEMSET headSet( cloneLine( &aCurrentHead ) ); + + reduceSpringback( headSet ); + + PNS_NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; + + m_currentNode = parent->Branch(); + m_currentNode->ClearRanks(); + m_currentNode->Add( head ); + + head->Mark( MK_HEAD ); + head->SetRank( 100000 ); + + m_logger.NewGroup( "initial", 0 ); + m_logger.Log( head, 0, "head" ); + PNS_VIA* headVia = NULL; - bool fail = false; - int iter = 0; - - PNS_LINE* head = aCurrentHead->Clone(); - - reduceSpringback( aCurrentHead ); - - parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().node; - node = parent->Branch(); - - lineStack.push( head ); - - // node->Add(tail); - node->Add( head ); if( head->EndsWithVia() ) { - headVia = head->GetVia().Clone(); - node->Add( headVia ); + headVia = head->Via().Clone(); + m_currentNode->Add( headVia ); + headVia->Mark( MK_HEAD ); + headVia->SetRank( 100000 ); + m_logger.Log( headVia, 0, "head-via" ); } - PNS_OPTIMIZER optimizer( node ); + pushLine( head ); + st = shoveMainLoop(); + runOptimizer( m_currentNode, head ); - optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS | PNS_OPTIMIZER::SMART_PADS ); - optimizer.SetCollisionMask( -1 ); - PNS_NODE::OptObstacle nearest; - - optimizer.CacheStaticItem( head ); - - if( headVia ) - optimizer.CacheStaticItem( headVia ); - - TRACE( 1, "ShoveStart [root: %d jts, node: %d jts]", m_root->JointCount() % - node->JointCount() ); - - // PNS_ITEM *lastWalkSolid = NULL; - prof_counter totalRealTime; - - wxLongLong t_start = wxGetLocalTimeMillis(); - - while( !lineStack.empty() ) + if( m_newHead && st == SH_OK ) { - wxLongLong t_cur = wxGetLocalTimeMillis(); + st = SH_HEAD_MODIFIED; + Router()->DisplayDebugLine( m_newHead->CLine(), 3, 20000 ); + } - if( (t_cur - t_start).ToLong() > ShoveTimeLimit ) - { - fail = true; - break; - } + m_currentNode->RemoveByMarker( MK_HEAD ); - iter++; + TRACE( 1, "Shove status : %s after %d iterations", + ( ( st == SH_OK || st == SH_HEAD_MODIFIED ) ? "OK" : "FAILURE") % m_iter ); - if( iter > m_iterLimit ) - { - fail = true; - break; - } - - PNS_LINE* currentLine = lineStack.top(); - - prof_start( &totalRealTime ); - nearest = node->NearestObstacle( currentLine, PNS_ITEM::ANY ); - prof_end( &totalRealTime ); - - TRACE( 2, "t-nearestObstacle %lld us", totalRealTime.usecs() ); - - if( !nearest ) - { - if( lineStack.size() > 1 ) - { - PNS_LINE* original = lineStack.top(); - PNS_LINE optimized; - int r_start, r_end; - - original->GetAffectedRange( r_start, r_end ); - - TRACE( 1, "Iter %d optimize-line [range %d-%d, total %d]", - iter % r_start % r_end % original->GetCLine().PointCount() ); - // lastWalkSolid = NULL; - prof_start( &totalRealTime ); - - if( optimizer.Optimize( original, &optimized ) ) - { - node->Remove( original ); - optimizer.CacheRemove( original ); - node->Add( &optimized ); - - if( original->BelongsTo( node ) ) - delete original; - } - - prof_end( &totalRealTime ); - - TRACE( 2, "t-optimizeObstacle %lld us", totalRealTime.usecs() ); - } - - lineStack.pop(); - } - else - { - switch( nearest->item->GetKind() ) - { - case PNS_ITEM::SEGMENT: - { - TRACE( 1, "Iter %d shove-line", iter ); - - PNS_SEGMENT* pseg = static_cast(nearest->item); - PNS_LINE* collidingLine = node->AssembleLine( pseg ); - PNS_LINE* shovedLine = collidingLine->CloneProperties(); - - prof_start( &totalRealTime ); - ShoveStatus st = shoveSingleLine( node, currentLine, collidingLine, - *pseg, shovedLine ); - prof_end( &totalRealTime ); - - TRACE( 2, "t-shoveSingle %lld us", totalRealTime.usecs() ); - - if( st == SH_OK ) - { - node->Replace( collidingLine, shovedLine ); - - if( collidingLine->BelongsTo( node ) ) - delete collidingLine; - - optimizer.CacheRemove( collidingLine ); - lineStack.push( shovedLine ); - } - else - fail = true; - - // lastWalkSolid = NULL; - - break; - } // case SEGMENT - - case PNS_ITEM::SOLID: - case PNS_ITEM::VIA: - { - TRACE( 1, "Iter %d walkaround-solid [%p]", iter % nearest->item ); - - if( lineStack.size() == 1 ) - { - fail = true; - break; - } - -/* if(lastWalkSolid == nearest->item) - * { - * fail = true; - * break; - * }*/ - - PNS_WALKAROUND walkaround( node ); - PNS_LINE* walkaroundLine = currentLine->CloneProperties(); - - walkaround.SetSolidsOnly( true ); - walkaround.SetSingleDirection( true ); - - prof_start( &totalRealTime ); - walkaround.Route( *currentLine, *walkaroundLine, false ); - prof_end( &totalRealTime ); - - TRACE( 2, "t-walkSolid %lld us", totalRealTime.usecs() ); - - - node->Replace( currentLine, walkaroundLine ); - - if( currentLine->BelongsTo( node ) ) - delete currentLine; - - optimizer.CacheRemove( currentLine ); - lineStack.top() = walkaroundLine; - - // lastWalkSolid = nearest->item; - break; - } - - default: - break; - } // switch - - if( fail ) - break; - } - } - - node->Remove( head ); - delete head; - - if( headVia ) + if( st == SH_OK || st == SH_HEAD_MODIFIED ) { - node->Remove( headVia ); - delete headVia; - } - - TRACE( 1, "Shove status : %s after %d iterations", (fail ? "FAILED" : "OK") % iter ); - - if( !fail ) - { - pushSpringback( node, aCurrentHead, PNS_COST_ESTIMATOR() ); - return SH_OK; + pushSpringback( m_currentNode, headSet, PNS_COST_ESTIMATOR() ); } else { - delete node; - return SH_INCOMPLETE; + delete m_currentNode; + + m_currentNode = parent; + m_newHead = OPT_LINE(); } + + return st; +} + + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveDraggingVia( PNS_VIA* aVia, const VECTOR2I& aWhere, + PNS_VIA** aNewVia ) +{ + SHOVE_STATUS st = SH_OK; + + m_lineStack.clear(); + m_optimizerQueue.clear(); + m_newHead = OPT_LINE(); + m_draggedVia = NULL; + + //reduceSpringback( aCurrentHead ); + + PNS_NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; + m_currentNode = parent->Branch(); + m_currentNode->ClearRanks(); + + aVia->Mark( MK_HEAD ); + + st = pushVia( aVia, ( aWhere - aVia->Pos() ), 0 ); + st = shoveMainLoop(); + runOptimizer( m_currentNode, NULL ); + + if( st == SH_OK || st == SH_HEAD_MODIFIED ) + { + pushSpringback( m_currentNode, PNS_ITEMSET(), PNS_COST_ESTIMATOR() ); + } + else + { + delete m_currentNode; + m_currentNode = parent; + } + + if( aNewVia ) + *aNewVia = m_draggedVia; + + return st; +} + + +void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) +{ + PNS_OPTIMIZER optimizer( aNode ); + int optFlags = 0, n_passes = 0, extend = 0; + + PNS_OPTIMIZATION_EFFORT effort = Settings().OptimizerEffort(); + + switch( effort ) + { + case OE_LOW: + optFlags = PNS_OPTIMIZER::MERGE_OBTUSE; + n_passes = 1; + extend = 0; + break; + + case OE_MEDIUM: + optFlags = PNS_OPTIMIZER::MERGE_OBTUSE; + n_passes = 2; + extend = 1; + break; + + case OE_FULL: + optFlags = PNS_OPTIMIZER::MERGE_SEGMENTS; + n_passes = 2; + break; + + default: + break; + } + + if( Settings().SmartPads() ) + optFlags |= PNS_OPTIMIZER::SMART_PADS ; + + optimizer.SetEffortLevel( optFlags ); + optimizer.SetCollisionMask( PNS_ITEM::ANY ); + + for( int pass = 0; pass < n_passes; pass++ ) + { + std::reverse( m_optimizerQueue.begin(), m_optimizerQueue.end() ); + + for( std::vector::iterator i = m_optimizerQueue.begin(); + i != m_optimizerQueue.end(); ++i) + { + PNS_LINE* line = *i; + + if( !( line -> Marker() & MK_HEAD ) ) + { + if( effort == OE_MEDIUM || effort == OE_LOW ) + { + RANGE r = findShovedVertexRange( line ); + + if( r.Defined() ) + { + int start_v = std::max( 0, r.MinV() - extend ); + int end_v = std::min( line->PointCount() - 1 , r.MaxV() + extend ); + line->ClipVertexRange( start_v, end_v ); + } + } + + PNS_LINE optimized; + + if( optimizer.Optimize( line, &optimized ) ) + { + aNode->Remove( line ); + line->SetShape( optimized.CLine() ); + aNode->Add( line ); + } + } + } + } + + +} + + +const RANGE PNS_SHOVE::findShovedVertexRange( PNS_LINE *aL ) +{ + RANGE r; + + for( int i = 0; i < aL->SegmentCount(); i++ ) + { + PNS_SEGMENT* s = (*aL->LinkedSegments())[i]; + PNS_JOINT* jt = m_root->FindJoint( s->Seg().A, s->Layer(), s->Net() ); + bool found = false; + + if( jt ) + { + BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) + { + if( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_SEGMENT* s_old = (PNS_SEGMENT*) item; + + if( s_old->Net() == s->Net() && + s_old->Layer() == s->Layer() && + s_old->Seg().A == s->Seg().A && + s_old->Seg().B == s->Seg().B ) + { + found = true; + break; + } + } + } + } + + if( !found ) + { + r.Grow( i ); + r.Grow( i + 1 ); + } + } + + return r; +} + + +PNS_NODE* PNS_SHOVE::CurrentNode() +{ + return m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; +} + + +const PNS_LINE PNS_SHOVE::NewHead() const +{ + assert( m_newHead ); + + return *m_newHead; +} + +void PNS_SHOVE::SetInitialLine( PNS_LINE* aInitial ) +{ + m_root = m_root->Branch(); + m_root->Remove ( aInitial ); } diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index 581d2f49f9..53568ab281 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_SHOVE_H @@ -25,61 +25,116 @@ #include #include "pns_optimizer.h" +#include "pns_routing_settings.h" +#include "pns_algo_base.h" +#include "pns_logger.h" +#include "range.h" class PNS_LINE; class PNS_NODE; class PNS_ROUTER; -class PNS_SHOVE +/** + * Class PNS_SHOVE + * + * The actual Push and Shove algorithm. + */ + +class PNS_SHOVE : public PNS_ALGO_BASE { public: - PNS_SHOVE( PNS_NODE* aWorld ); - ~PNS_SHOVE(); - enum ShoveStatus + enum SHOVE_STATUS { SH_OK = 0, SH_NULL, - SH_INCOMPLETE + SH_INCOMPLETE, + SH_HEAD_MODIFIED }; - ShoveStatus ShoveLines( PNS_LINE* aCurrentHead ); + PNS_SHOVE( PNS_NODE* aWorld, PNS_ROUTER* aRouter ); + ~PNS_SHOVE(); - PNS_NODE* GetCurrentNode() + virtual PNS_LOGGER* Logger() { - return m_nodeStack.empty() ? m_root : m_nodeStack.back().node; + return &m_logger; } - const PNS_COST_ESTIMATOR TotalCost() const; + SHOVE_STATUS ShoveLines( const PNS_LINE& aCurrentHead ); + SHOVE_STATUS ShoveDraggingVia( PNS_VIA*aVia, const VECTOR2I& aWhere, PNS_VIA** aNewVia ); - void Reset(); - void KillChildNodes(); + PNS_NODE* CurrentNode(); + + const PNS_LINE NewHead() const; + + void SetInitialLine ( PNS_LINE* aInitial ); private: - static const int ShoveTimeLimit = 3000; + typedef std::vector HULL_SET; + typedef boost::optional OPT_LINE; + typedef std::pair LINE_PAIR; + typedef std::vector LINE_PAIR_VEC; - bool tryShove( PNS_NODE* aWorld, PNS_LINE* aTrack, PNS_LINE* aObstacle, - PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding ); - - ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle, - PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult ); - - bool reduceSpringback( PNS_LINE* aHead ); - bool pushSpringback( PNS_NODE* aNode, PNS_LINE* aHead, const PNS_COST_ESTIMATOR& aCost ); - - struct SpringbackTag + struct SPRINGBACK_TAG { - int64_t length; - int segments; - VECTOR2I p; - PNS_NODE* node; - PNS_COST_ESTIMATOR cost; + int64_t m_length; + int m_segments; + VECTOR2I m_p; + PNS_NODE* m_node; + PNS_ITEMSET m_headItems; + PNS_COST_ESTIMATOR m_cost; }; - std::vector m_nodeStack; - PNS_NODE* m_root; - PNS_NODE* m_currentNode; - int m_iterLimit; + SHOVE_STATUS processSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ); + SHOVE_STATUS processHullSet( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_LINE* aShoved, const HULL_SET& hulls ); + + bool reduceSpringback( const PNS_ITEMSET& aHeadItems ); + bool pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET &aHeadItems, + const PNS_COST_ESTIMATOR& aCost ); + + SHOVE_STATUS walkaroundLoneVia( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ); + bool checkBumpDirection( PNS_LINE* aCurrent, PNS_LINE* aShoved ) const; + + SHOVE_STATUS onCollidingLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle ); + SHOVE_STATUS onCollidingSegment( PNS_LINE* aCurrent, PNS_SEGMENT* aObstacleSeg ); + SHOVE_STATUS onCollidingSolid( PNS_LINE* aCurrent, PNS_SOLID* aObstacleSolid ); + SHOVE_STATUS onCollidingVia( PNS_ITEM* aCurrent, PNS_VIA* aObstacleVia ); + SHOVE_STATUS onReverseCollidingVia( PNS_LINE* aCurrent, PNS_VIA* aObstacleVia ); + SHOVE_STATUS pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank ); + + void unwindStack( PNS_SEGMENT* aSeg ); + void unwindStack( PNS_ITEM *aItem ); + + void runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ); + + void pushLine( PNS_LINE *aL ); + void popLine(); + + const RANGE findShovedVertexRange( PNS_LINE *aL ); + + PNS_LINE* assembleLine( const PNS_SEGMENT* aSeg, int* aIndex = NULL ); + PNS_LINE* cloneLine( const PNS_LINE* aLine ); + + SHOVE_STATUS shoveIteration( int aIter ); + SHOVE_STATUS shoveMainLoop(); + + std::vector m_nodeStack; + std::vector m_lineStack; + std::vector m_optimizerQueue; + std::vector m_gcItems; + + PNS_NODE* m_root; + PNS_NODE* m_currentNode; + PNS_LINE* m_currentHead; + PNS_LINE* m_collidingLine; + + OPT_LINE m_newHead; + + PNS_LOGGER m_logger; + PNS_VIA* m_draggedVia; + + int m_iter; }; -#endif +#endif // __PNS_SHOVE_H diff --git a/pcbnew/router/pns_solid.cpp b/pcbnew/router/pns_solid.cpp index 807f9faa0b..6305ceabc4 100644 --- a/pcbnew/router/pns_solid.cpp +++ b/pcbnew/router/pns_solid.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -30,22 +30,29 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness ) const { + int cl = aClearance + aWalkaroundThickness / 2; + switch( m_shape->Type() ) { case SH_RECT: - { - SHAPE_RECT* rect = static_cast( m_shape ); - return OctagonalHull( rect->GetPosition(), rect->GetSize(), - aClearance + 1, 0.2 * aClearance ); - } + { + SHAPE_RECT* rect = static_cast( m_shape ); + return OctagonalHull( rect->GetPosition(), rect->GetSize(), cl + 1, 0.2 * cl ); + } case SH_CIRCLE: - { - SHAPE_CIRCLE* circle = static_cast( m_shape ); - int r = circle->GetRadius(); - return OctagonalHull( circle->GetCenter() - VECTOR2I( r, r ), VECTOR2I( 2 * r, 2 * r ), - aClearance + 1, 0.52 * (r + aClearance) ); - } + { + SHAPE_CIRCLE* circle = static_cast( m_shape ); + int r = circle->GetRadius(); + return OctagonalHull( circle->GetCenter() - VECTOR2I( r, r ), VECTOR2I( 2 * r, 2 * r ), + cl + 1, 0.52 * ( r + cl ) ); + } + + case SH_SEGMENT: + { + SHAPE_SEGMENT* seg = static_cast ( m_shape ); + return SegmentHull( *seg, aClearance, aWalkaroundThickness ); + } default: break; @@ -55,10 +62,8 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness } -PNS_ITEM* PNS_SOLID::Clone() const +PNS_ITEM* PNS_SOLID::Clone ( ) const { - // solids are never cloned as the shove algorithm never moves them - assert( false ); - - return NULL; + PNS_ITEM* solid = new PNS_SOLID( *this ); + return solid; } diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index b6f38a2851..88f8431d24 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_SOLID_H @@ -42,9 +42,16 @@ public: delete m_shape; } + PNS_SOLID( const PNS_SOLID& aSolid ) : + PNS_ITEM ( aSolid ) + { + m_shape = aSolid.m_shape->Clone(); + m_pos = aSolid.m_pos; + } + PNS_ITEM* Clone() const; - const SHAPE* GetShape() const { return m_shape; } + const SHAPE* Shape() const { return m_shape; } const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const; @@ -56,18 +63,28 @@ public: m_shape = shape; } - const VECTOR2I& GetCenter() const + const VECTOR2I& Pos() const { - return m_center; + return m_pos; } - void SetCenter( const VECTOR2I& aCenter ) + void SetPos( const VECTOR2I& aCenter ) { - m_center = aCenter; + m_pos = aCenter; + } + + virtual VECTOR2I Anchor( int aN ) const + { + return m_pos; + } + + virtual int AnchorCount() const + { + return 1; } private: - VECTOR2I m_center; + VECTOR2I m_pos; SHAPE* m_shape; }; diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index c787753534..5a69e673d8 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,17 +15,17 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include "pns_utils.h" #include "pns_line.h" #include "pns_router.h" -const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, - const VECTOR2I& aSize, - int aClearance, - int aChamfer ) +#include + +const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize, + int aClearance, int aChamfer ) { SHAPE_LINE_CHAIN s; @@ -42,3 +42,52 @@ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, return s; } + + +const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, + int aWalkaroundThickness ) +{ + int d = aSeg.GetWidth() / 2 + aClearance + aWalkaroundThickness / 2 + HULL_MARGIN; + int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ); + + const VECTOR2I a = aSeg.GetSeg().A; + const VECTOR2I b = aSeg.GetSeg().B; + + VECTOR2I dir = b - a; + VECTOR2I p0 = dir.Perpendicular().Resize( d ); + VECTOR2I ds = dir.Perpendicular().Resize( x / 2 ); + VECTOR2I pd = dir.Resize( x / 2 ); + VECTOR2I dp = dir.Resize( d ); + + SHAPE_LINE_CHAIN s; + + s.SetClosed( true ); + + s.Append( b + p0 + pd ); + s.Append( b + dp + ds ); + s.Append( b + dp - ds ); + s.Append( b - p0 + pd ); + s.Append( a - p0 - pd ); + s.Append( a - dp - ds ); + s.Append( a - dp + ds ); + s.Append( a + p0 - pd ); + + // make sure the hull outline is always clockwise + if( s.CSegment( 0 ).Side( a ) < 0 ) + return s.Reverse(); + else + return s; +} + + +SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ) +{ + SHAPE_RECT r; + + VECTOR2I delta( aSeg.GetWidth() / 2, aSeg.GetWidth() / 2 ); + VECTOR2I p0( aSeg.GetSeg().A - delta ); + VECTOR2I p1( aSeg.GetSeg().B + delta ); + + return SHAPE_RECT( std::min( p0.x, p1.x ), std::min( p0.y, p1.y ), + std::abs( p1.x - p0.x ), std::abs( p1.y - p0.y ) ); +} diff --git a/pcbnew/router/pns_utils.h b/pcbnew/router/pns_utils.h index 655720f1f1..5bf6d9313b 100644 --- a/pcbnew/router/pns_utils.h +++ b/pcbnew/router/pns_utils.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_UTILS_H @@ -23,10 +23,19 @@ #include #include +#include +#include + +#define HULL_MARGIN 10 /** Various utility functions */ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize, - int aClearance, int aChamfer ); + int aClearance, int aChamfer ); + +const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, + int aWalkaroundThickness ); + +SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ); #endif // __PNS_UTILS_H diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index 30666d78ab..f7ff5e9461 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,132 +15,46 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include "pns_via.h" #include "pns_node.h" #include "pns_utils.h" +#include "pns_router.h" #include -static bool Circle2Circle( VECTOR2I p1, VECTOR2I p2, int r1, int r2, VECTOR2I& force ) -{ - int mindist = r1 + r2; - VECTOR2I delta = p2 - p1; - int dist = delta.EuclideanNorm(); - - if( dist >= mindist ) - return false; - - force = delta.Resize( abs( mindist - dist ) + 1 ); - return true; -}; - -static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECTOR2I& force ) -{ - VECTOR2I vts[] = - { - VECTOR2I( rp0.x, rp0.y ), - VECTOR2I( rp0.x, rp0.y + rsize.y ), - VECTOR2I( rp0.x + rsize.x, rp0.y + rsize.y ), - VECTOR2I( rp0.x + rsize.x, rp0.y ), - VECTOR2I( rp0.x, rp0.y ) - }; - - int dist = INT_MAX; - VECTOR2I nearest; - - for( int i = 0; i < 4; i++ ) - { - SEG s( vts[i], vts[i + 1] ); - - VECTOR2I pn = s.NearestPoint( cc ); - - int d = (pn - cc).EuclideanNorm(); - - if( d < dist ) - { - nearest = pn; - dist = d; - } - } - - bool inside = cc.x >= rp0.x && cc.x <= (rp0.x + rsize.x) - && cc.y >= rp0.y && cc.y <= (rp0.y + rsize.y); - - VECTOR2I delta = cc - nearest; - - if( dist >= cr && !inside ) - return false; - - if( inside ) - force = -delta.Resize( abs( cr + dist ) + 1 ); - else - force = delta.Resize( abs( cr - dist ) + 1 ); - - return true; -}; - - -static bool ShPushoutForce( const SHAPE* shape, VECTOR2I p, int r, VECTOR2I& force, int clearance ) -{ - switch( shape->Type() ) - { - case SH_CIRCLE: - { - const SHAPE_CIRCLE* cir = static_cast(shape); - return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force ); - } - - case SH_RECT: - { - const SHAPE_RECT* rect = static_cast(shape); - return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force ); - } - - default: - return false; - } - - return false; -} - - -bool PNS_VIA::PushoutForce( PNS_NODE* aNode, - const VECTOR2I& aDirection, - VECTOR2I& aForce, - bool aSolidsOnly, - int aMaxIterations ) +bool PNS_VIA::PushoutForce( PNS_NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForce, + bool aSolidsOnly, int aMaxIterations ) { int iter = 0; PNS_VIA mv( *this ); - VECTOR2I force, totalForce; + VECTOR2I force, totalForce, force2; while( iter < aMaxIterations ) { - PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv, + PNS_NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv, aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY ); if( !obs ) break; - int clearance = aNode->GetClearance( obs->item, &mv ); + int clearance = aNode->GetClearance( obs->m_item, &mv ); - if( iter > 10 ) + if( iter > aMaxIterations / 2 ) { - VECTOR2I l = -aDirection.Resize( m_diameter / 4 ); + VECTOR2I l = aDirection.Resize( m_diameter / 2 ); totalForce += l; - mv.SetPos( mv.GetPos() + l ); + mv.SetPos( mv.Pos() + l ); } - if( ShPushoutForce( obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force, - clearance ) ) - { - totalForce += force; - mv.SetPos( mv.GetPos() + force ); - } + bool col = CollideShapes( obs->m_item->Shape(), mv.Shape(), clearance, true, force2 ); + if( col ) { + totalForce += force2; + mv.SetPos( mv.Pos() + force2 ); + } iter++; } @@ -149,13 +63,34 @@ bool PNS_VIA::PushoutForce( PNS_NODE* aNode, return false; aForce = totalForce; + return true; } const SHAPE_LINE_CHAIN PNS_VIA::Hull( int aClearance, int aWalkaroundThickness ) const { + int cl = ( aClearance + aWalkaroundThickness / 2 ); + return OctagonalHull( m_pos - - VECTOR2I( m_diameter / 2, m_diameter / 2 ), VECTOR2I( m_diameter, - m_diameter ), aClearance + 1, (2 * aClearance + m_diameter) * 0.26 ); + VECTOR2I( m_diameter / 2, m_diameter / 2 ), VECTOR2I( m_diameter, m_diameter ), + cl + 1, ( 2 * cl + m_diameter ) * 0.26 ); +} + + +PNS_VIA* PNS_VIA::Clone ( ) const +{ + PNS_VIA* v = new PNS_VIA(); + + v->SetNet( Net() ); + v->SetLayers( Layers() ); + v->m_pos = m_pos; + v->m_diameter = m_diameter; + v->m_drill = m_drill; + v->m_owner = NULL; + v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); + v->m_rank = m_rank; + v->m_marker = m_marker; + + return v; } diff --git a/pcbnew/router/pns_via.h b/pcbnew/router/pns_via.h index 1a0fc2a2bd..00a4587b74 100644 --- a/pcbnew/router/pns_via.h +++ b/pcbnew/router/pns_via.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_VIA_H @@ -32,7 +32,8 @@ class PNS_VIA : public PNS_ITEM { public: PNS_VIA() : - PNS_ITEM( VIA ) {}; + PNS_ITEM( VIA ) + {} PNS_VIA( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aDiameter, int aNet = -1 ) : PNS_ITEM( VIA ) @@ -42,19 +43,24 @@ public: m_pos = aPos; m_diameter = aDiameter; m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 ); - }; - - - PNS_VIA( const PNS_VIA& b ) : PNS_ITEM( VIA ) - { - SetNet( b.GetNet() ); - SetLayers( b.GetLayers() ); - m_pos = b.m_pos; - m_diameter = b.m_diameter; - m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); } - const VECTOR2I& GetPos() const + + PNS_VIA( const PNS_VIA& aB ) : + PNS_ITEM( VIA ) + { + SetNet( aB.Net() ); + SetLayers( aB.Layers() ); + m_pos = aB.m_pos; + m_diameter = aB.m_diameter; + m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); + m_marker = aB.m_marker; + m_rank = aB.m_rank; + m_owner = aB.m_owner; + m_drill = aB.m_drill; + } + + const VECTOR2I& Pos() const { return m_pos; } @@ -65,7 +71,7 @@ public: m_shape.SetCenter( aPos ); } - int GetDiameter() const + int Diameter() const { return m_diameter; } @@ -76,7 +82,7 @@ public: m_shape.SetRadius( m_diameter / 2 ); } - int GetDrill() const + int Drill() const { return m_drill; } @@ -92,28 +98,26 @@ public: bool aSolidsOnly = true, int aMaxIterations = 10 ); - const SHAPE* GetShape() const + const SHAPE* Shape() const { return &m_shape; } - PNS_VIA* Clone() const - { - PNS_VIA* v = new PNS_VIA(); - - v->SetNet( GetNet() ); - v->SetLayers( GetLayers() ); - v->m_pos = m_pos; - v->m_diameter = m_diameter; - v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); - - return v; - } + PNS_VIA* Clone ( ) const; const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const; + + virtual VECTOR2I Anchor( int n ) const + { + return m_pos; + } + + virtual int AnchorCount() const + { + return 1; + } private: - int m_diameter; int m_drill; VECTOR2I m_pos; diff --git a/pcbnew/router/pns_walkaround.cpp b/pcbnew/router/pns_walkaround.cpp index 185def64d2..071f762a32 100644 --- a/pcbnew/router/pns_walkaround.cpp +++ b/pcbnew/router/pns_walkaround.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include @@ -32,22 +32,22 @@ using boost::optional; void PNS_WALKAROUND::start( const PNS_LINE& aInitialPath ) { m_iteration = 0; - m_iteration_limit = 50; + m_iterationLimit = 50; } -PNS_NODE::OptObstacle PNS_WALKAROUND::nearestObstacle( const PNS_LINE& aPath ) +PNS_NODE::OPT_OBSTACLE PNS_WALKAROUND::nearestObstacle( const PNS_LINE& aPath ) { - return m_world->NearestObstacle( &aPath, - m_solids_only ? (PNS_ITEM::SOLID | PNS_ITEM::VIA) : PNS_ITEM::ANY ); + return m_world->NearestObstacle( &aPath, m_itemMask ); } -PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath, - bool aWindingDirection ) +PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::singleStep( PNS_LINE& aPath, + bool aWindingDirection ) { optional& current_obs = aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1]; + bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1]; if( !current_obs ) @@ -55,33 +55,41 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath, SHAPE_LINE_CHAIN path_pre[2], path_walk[2], path_post[2]; - VECTOR2I last = aPath.GetCLine().CPoint( -1 ); + VECTOR2I last = aPath.CPoint( -1 ); - if( ( current_obs->hull ).PointInside( last ) ) + if( ( current_obs->m_hull ).PointInside( last ) ) { m_recursiveBlockageCount++; if( m_recursiveBlockageCount < 3 ) - aPath.GetLine().Append( current_obs->hull.NearestPoint( last ) ); + aPath.Line().Append( current_obs->m_hull.NearestPoint( last ) ); else { aPath = aPath.ClipToNearestObstacle( m_world ); - return STUCK; + return DONE; } } - aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0], - path_post[0], aWindingDirection ); - aPath.NewWalkaround( current_obs->hull, path_pre[1], path_walk[1], - path_post[1], !aWindingDirection ); + aPath.Walkaround( current_obs->m_hull, path_pre[0], path_walk[0], + path_post[0], aWindingDirection ); + aPath.Walkaround( current_obs->m_hull, path_pre[1], path_walk[1], + path_post[1], !aWindingDirection ); +#ifdef DEBUG + m_logger.NewGroup( aWindingDirection ? "walk-cw" : "walk-ccw", m_iteration ); + m_logger.Log( &path_walk[0], 0, "path-walk" ); + m_logger.Log( &path_pre[0], 1, "path-pre" ); + m_logger.Log( &path_post[0], 4, "path-post" ); + m_logger.Log( ¤t_obs->m_hull, 2, "hull" ); + m_logger.Log( current_obs->m_item, 3, "item" ); +#endif + int len_pre = path_walk[0].Length(); int len_alt = path_walk[1].Length(); - + PNS_LINE walk_path( aPath, path_walk[1] ); - bool alt_collides = m_world->CheckColliding( &walk_path, - m_solids_only ? PNS_ITEM::SOLID : PNS_ITEM::ANY ); + bool alt_collides = m_world->CheckColliding( &walk_path, m_itemMask ); SHAPE_LINE_CHAIN pnew; @@ -118,12 +126,11 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath, } -PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitialPath, - PNS_LINE& aWalkPath, - bool aOptimize ) +PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitialPath, + PNS_LINE& aWalkPath, bool aOptimize ) { PNS_LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); - WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; + WALKAROUND_STATUS s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; SHAPE_LINE_CHAIN best_path; start( aInitialPath ); @@ -133,7 +140,7 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial aWalkPath = aInitialPath; - while( m_iteration < m_iteration_limit ) + while( m_iteration < m_iterationLimit ) { if( s_cw != STUCK ) s_cw = singleStep( path_cw, true ); @@ -143,9 +150,9 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial if( ( s_cw == DONE && s_ccw == DONE ) || ( s_cw == STUCK && s_ccw == STUCK ) ) { - int len_cw = path_cw.GetCLine().Length(); - int len_ccw = path_ccw.GetCLine().Length(); - + int len_cw = path_cw.CLine().Length(); + int len_ccw = path_ccw.CLine().Length(); + if( m_forceLongerPath ) aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); else @@ -166,17 +173,16 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial m_iteration++; } - - if( m_iteration == m_iteration_limit ) + + if( m_iteration == m_iterationLimit ) { - int len_cw = path_cw.GetCLine().Length(); - int len_ccw = path_ccw.GetCLine().Length(); - + int len_cw = path_cw.CLine().Length(); + int len_ccw = path_ccw.CLine().Length(); if( m_forceLongerPath ) - aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); + aWalkPath = ( len_cw > len_ccw ? path_cw : path_ccw ); else - aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); + aWalkPath = ( len_cw < len_ccw ? path_cw : path_ccw ); } if( m_cursorApproachMode ) @@ -185,7 +191,7 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial // int len_ccw = path_ccw.GetCLine().Length(); bool found = false; - SHAPE_LINE_CHAIN l = aWalkPath.GetCLine(); + SHAPE_LINE_CHAIN l = aWalkPath.CLine(); for( int i = 0; i < l.SegmentCount(); i++ ) { @@ -198,7 +204,6 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial if( dist_n <= dist_a && dist_n < dist_b ) { - // PNSDisplayDebugLine( l, 3 ); l.Remove( i + 1, -1 ); l.Append( nearest ); l.Simplify(); @@ -214,13 +219,21 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitial } } - aWalkPath.SetWorld( m_world ); - aWalkPath.GetLine().Simplify(); + aWalkPath.Line().Simplify(); - WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; + if( aWalkPath.SegmentCount() < 1 ) + return STUCK; + + if( aWalkPath.CPoint( -1 ) != aInitialPath.CPoint( -1 ) ) + return STUCK; + + if( aWalkPath.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) + return STUCK; + + WALKAROUND_STATUS st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; if( aOptimize && st == DONE ) - PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world ); + PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world ); return st; } diff --git a/pcbnew/router/pns_walkaround.h b/pcbnew/router/pns_walkaround.h index 609b80d2ce..71b9c1ce2d 100644 --- a/pcbnew/router/pns_walkaround.h +++ b/pcbnew/router/pns_walkaround.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __PNS_WALKAROUND_H @@ -23,22 +23,29 @@ #include "pns_line.h" #include "pns_node.h" +#include "pns_router.h" +#include "pns_logger.h" +#include "pns_algo_base.h" -class PNS_WALKAROUND +class PNS_WALKAROUND : public PNS_ALGO_BASE { static const int DefaultIterationLimit = 50; public: - PNS_WALKAROUND( PNS_NODE* aWorld ) : - m_world( aWorld ), m_iteration_limit( DefaultIterationLimit ) + PNS_WALKAROUND( PNS_NODE* aWorld, PNS_ROUTER* aRouter ) : + PNS_ALGO_BASE ( aRouter ), + m_world( aWorld ), + m_iterationLimit( DefaultIterationLimit ) { m_forceSingleDirection = false; m_forceLongerPath = false; m_cursorApproachMode = false; - }; + m_itemMask = PNS_ITEM::ANY; + } + ~PNS_WALKAROUND() {}; - enum WalkaroundStatus + enum WALKAROUND_STATUS { IN_PROGRESS = 0, DONE, @@ -52,18 +59,27 @@ public: void SetIterationLimit( const int aIterLimit ) { - m_iteration_limit = aIterLimit; + m_iterationLimit = aIterLimit; } void SetSolidsOnly( bool aSolidsOnly ) { - m_solids_only = aSolidsOnly; + if( aSolidsOnly ) + m_itemMask = PNS_ITEM::SOLID; + else + m_itemMask = PNS_ITEM::ANY; } - void SetSingleDirection( bool aForceSingleDirection ) + void SetItemMask( int aMask ) + { + m_itemMask = aMask; + } + + void SetSingleDirection( bool aForceSingleDirection ) { m_forceSingleDirection = aForceSingleDirection; - m_forceLongerPath = true; + m_forceLongerPath = aForceSingleDirection; + //printf("FSD %d FPD %d\n", m_forceSingleDirection?1:0, m_forceLongerPath ? 1: 0); } void SetApproachCursor( bool aEnabled, const VECTOR2I& aPos ) @@ -72,26 +88,32 @@ public: m_cursorApproachMode = aEnabled; } - WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, + WALKAROUND_STATUS Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize = true ); + virtual PNS_LOGGER* Logger() + { + return &m_logger; + } + private: void start( const PNS_LINE& aInitialPath ); - WalkaroundStatus singleStep( PNS_LINE& aPath, bool aWindingDirection ); - PNS_NODE::OptObstacle nearestObstacle( const PNS_LINE& aPath ); + WALKAROUND_STATUS singleStep( PNS_LINE& aPath, bool aWindingDirection ); + PNS_NODE::OPT_OBSTACLE nearestObstacle( const PNS_LINE& aPath ); PNS_NODE* m_world; int m_recursiveBlockageCount; int m_iteration; - int m_iteration_limit; - bool m_solids_only; + int m_iterationLimit; + int m_itemMask; bool m_forceSingleDirection, m_forceLongerPath; bool m_cursorApproachMode; VECTOR2I m_cursorPos; - PNS_NODE::OptObstacle m_currentObstacle[2]; + PNS_NODE::OPT_OBSTACLE m_currentObstacle[2]; bool m_recursiveCollision[2]; + PNS_LOGGER m_logger; }; #endif // __PNS_WALKAROUND_H diff --git a/pcbnew/router/range.h b/pcbnew/router/range.h new file mode 100644 index 0000000000..0778cf70e7 --- /dev/null +++ b/pcbnew/router/range.h @@ -0,0 +1,93 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#ifndef __RANGE_H +#define __RANGE_H + +template +class RANGE +{ + public: + RANGE( T aMin, T aMax ) : + m_min( aMin ), + m_max( aMax ), + m_defined( true ) {} + + RANGE(): + m_defined( false ) {} + + T MinV() const + { + return m_min; + } + + T MaxV() const + { + return m_max; + } + + void Set( T aMin, T aMax ) const + { + m_max = aMax; + m_min = aMin; + } + + void Grow( T aValue ) + { + if( !m_defined ) + { + m_min = aValue; + m_max = aValue; + m_defined = true; + } + else + { + m_min = std::min( m_min, aValue ); + m_max = std::max( m_max, aValue ); + } + } + + bool Inside( const T& aValue ) const + { + if( !m_defined ) + return true; + + return aValue >= m_min && aValue <= m_max; + } + + bool Overlaps ( const RANGE& aOther ) const + { + if( !m_defined || !aOther.m_defined ) + return true; + + return m_max >= aOther.m_min && m_min <= aOther.m_max; + } + + bool Defined() const + { + return m_defined; + } + + private: + T m_min, m_max; + bool m_defined; +}; + +#endif diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index 8ce1db4721..85a7062b5a 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,13 +15,16 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #include +#include + #include "class_track.h" #include +#include #include "router_preview_item.h" @@ -34,9 +37,11 @@ using namespace KIGFX; ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem, VIEW_GROUP* aParent ) : EDA_ITEM( NOT_USED ) { - m_Flags = 0; m_parent = aParent; - m_layer = DRAW_N; + + m_shape = NULL; + m_clearance = -1; + m_originLayer = m_layer = ITEM_GAL_LAYER ( GP_OVERLAY ); if( aItem ) Update( aItem ); @@ -50,62 +55,72 @@ ROUTER_PREVIEW_ITEM::~ROUTER_PREVIEW_ITEM() void ROUTER_PREVIEW_ITEM::Update( const PNS_ITEM* aItem ) { - m_layer = aItem->GetLayers().Start(); + m_originLayer = aItem->Layers().Start(); - m_color = getLayerColor( m_layer ); + assert( m_originLayer >= 0 ); + + m_layer = m_originLayer; + m_color = getLayerColor( m_originLayer ); m_color.a = 0.8; - - switch( aItem->GetKind() ) + m_depth = BaseOverlayDepth - aItem->Layers().Start(); + m_shape = aItem->Shape()->Clone(); + + switch( aItem->Kind() ) { case PNS_ITEM::LINE: - m_type = PR_LINE; - m_width = static_cast(aItem)->GetWidth(); - m_line = *static_cast( aItem->GetShape() ); + m_type = PR_SHAPE; + m_width = ( (PNS_LINE*) aItem )->Width(); + break; case PNS_ITEM::SEGMENT: - m_type = PR_LINE; - m_width = static_cast(aItem)->GetWidth(); - m_line = *static_cast( aItem->GetShape() ); + { + PNS_SEGMENT* seg = (PNS_SEGMENT*) aItem; + m_type = PR_SHAPE; + m_width = seg->Width(); break; + } case PNS_ITEM::VIA: - m_type = PR_VIA; + m_type = PR_SHAPE; + m_width = 0; m_color = COLOR4D( 0.7, 0.7, 0.7, 0.8 ); - m_width = static_cast(aItem)->GetDiameter(); - m_viaCenter = static_cast(aItem)->GetPos(); + m_depth = ViaOverlayDepth; + break; + + case PNS_ITEM::SOLID: + m_type = PR_SHAPE; + m_width = 0; break; default: break; } + if( aItem->Marker() & MK_VIOLATION ) + m_color = COLOR4D( 0, 1, 0, 1 ); + + if( aItem->Marker() & MK_HEAD ) + m_color.Brighten( 0.7 ); + ViewSetVisible( true ); ViewUpdate( GEOMETRY | APPEARANCE ); } -void ROUTER_PREVIEW_ITEM::MarkAsHead() -{ - if( m_type != PR_VIA ) - m_color.Saturate( 1.0 ); -} - - const BOX2I ROUTER_PREVIEW_ITEM::ViewBBox() const { BOX2I bbox; switch( m_type ) { - case PR_LINE: - bbox = m_line.BBox(); + case PR_SHAPE: + bbox = m_shape->BBox(); bbox.Inflate( m_width / 2 ); return bbox; - case PR_VIA: - bbox = BOX2I( m_viaCenter, VECTOR2I( 0, 0 ) ); - bbox.Inflate( m_width / 2 ); + case PR_POINT: + bbox = BOX2I ( m_pos - VECTOR2I( 100000, 100000 ), VECTOR2I( 200000, 200000 ) ); return bbox; default: @@ -116,77 +131,126 @@ const BOX2I ROUTER_PREVIEW_ITEM::ViewBBox() const } +void ROUTER_PREVIEW_ITEM::drawLineChain( const SHAPE_LINE_CHAIN &aL, KIGFX::GAL* aGal ) const +{ + for( int s = 0; s < aL.SegmentCount(); s++ ) + aGal->DrawLine( aL.CSegment( s ).A, aL.CSegment( s ).B ); + + if( aL.IsClosed() ) + aGal->DrawLine( aL.CSegment( -1 ).B, aL.CSegment( 0 ).A ); +} + + void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const { - switch( m_type ) + //col.Brighten(0.7); + aGal->SetLayerDepth( m_depth ); + + if( m_type == PR_SHAPE ) { - case PR_LINE: - aGal->SetLayerDepth( -100.0 ); aGal->SetLineWidth( m_width ); aGal->SetStrokeColor( m_color ); - aGal->SetIsStroke( true ); - aGal->SetIsFill( false ); - - for( int s = 0; s < m_line.SegmentCount(); s++ ) - aGal->DrawLine( m_line.CSegment( s ).A, m_line.CSegment( s ).B ); - - if( m_line.IsClosed() ) - aGal->DrawLine( m_line.CSegment( -1 ).B, m_line.CSegment( 0 ).A ); - break; - - case PR_VIA: - aGal->SetLayerDepth( -101.0 ); - aGal->SetIsStroke( false ); - aGal->SetIsFill( true ); aGal->SetFillColor( m_color ); - aGal->DrawCircle( m_viaCenter, m_width / 2 ); - break; + aGal->SetIsStroke( m_width ? true : false ); + aGal->SetIsFill( true ); - default: - break; + if( !m_shape ) + return; + + switch( m_shape->Type() ) + { + case SH_LINE_CHAIN: + { + const SHAPE_LINE_CHAIN* l = (const SHAPE_LINE_CHAIN*) m_shape; + drawLineChain( *l, aGal ); + break; + } + + case SH_SEGMENT: + { + const SHAPE_SEGMENT* s = (const SHAPE_SEGMENT*) m_shape; + aGal->DrawLine( s->GetSeg().A, s->GetSeg().B ); + + if( m_clearance > 0 ) + { + aGal->SetLayerDepth( ClearanceOverlayDepth ); + aGal->SetStrokeColor( COLOR4D( DARKDARKGRAY )); + aGal->SetLineWidth( m_width + 2 * m_clearance ); + aGal->DrawLine( s->GetSeg().A, s->GetSeg().B ); + } + + break; + } + + case SH_CIRCLE: + { + const SHAPE_CIRCLE* c = (const SHAPE_CIRCLE*) m_shape; + aGal->DrawCircle( c->GetCenter(), c->GetRadius() ); + + if( m_clearance > 0 ) + { + aGal->SetLayerDepth( ClearanceOverlayDepth ); + aGal->SetFillColor( COLOR4D( DARKDARKGRAY ) ); + aGal->SetIsStroke( false ); + aGal->DrawCircle( c->GetCenter(), c->GetRadius() + m_clearance ); + } + + break; + } + + case SH_RECT: + { + const SHAPE_RECT* r = (const SHAPE_RECT*) m_shape; + aGal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() ); + + if( m_clearance > 0 ) + { + aGal->SetLayerDepth( ClearanceOverlayDepth ); + VECTOR2I p0( r->GetPosition() ), s( r->GetSize() ); + aGal->SetStrokeColor( COLOR4D( DARKDARKGRAY ) ); + aGal->SetIsStroke( true ); + aGal->SetLineWidth( 2 * m_clearance ); + aGal->DrawLine( p0, VECTOR2I( p0.x + s.x, p0.y ) ); + aGal->DrawLine( p0, VECTOR2I( p0.x, p0.y + s.y ) ); + aGal->DrawLine( p0 + s , VECTOR2I( p0.x + s.x, p0.y ) ); + aGal->DrawLine( p0 + s, VECTOR2I( p0.x, p0.y + s.y ) ); + } + + break; + } + } } } -void ROUTER_PREVIEW_ITEM::DebugLine( const SHAPE_LINE_CHAIN& aLine, int aWidth, int aStyle ) +void ROUTER_PREVIEW_ITEM::Line( const SHAPE_LINE_CHAIN& aLine, int aWidth, int aStyle ) { -#if 0 - m_line = aLine; + m_originLayer = m_layer = 0; m_width = aWidth; m_color = assignColor( aStyle ); + m_type = PR_SHAPE; + m_depth = -2047; + m_shape = aLine.Clone(); - - m_type = PR_LINE; + ViewSetVisible( true ); ViewUpdate( GEOMETRY | APPEARANCE ); -#endif } -void ROUTER_PREVIEW_ITEM::DebugBox( const BOX2I& aBox, int aStyle ) +void ROUTER_PREVIEW_ITEM::Point( const VECTOR2I& aPos, int aStyle ) { -#if 0 - assert( false ); +} - m_line.Clear(); - m_line.Append( aBox.GetX(), aBox.GetY() ); - m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight() ); - m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight() ); - m_line.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight() ); - m_line.SetClosed( true ); - m_width = 20000; - m_color = assignColor( aStyle ); - m_type = PR_LINE; - ViewUpdate( GEOMETRY | APPEARANCE ); -#endif + +void ROUTER_PREVIEW_ITEM::Box( const BOX2I& aBox, int aStyle ) +{ } const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor( int aLayer ) const { - // assert (m_view != NULL); - PCB_RENDER_SETTINGS* settings = - static_cast ( m_parent->GetView()->GetPainter()->GetSettings() ); + static_cast( m_parent->GetView()->GetPainter()->GetSettings() ); return settings->GetLayerColor( aLayer ); } @@ -202,10 +266,10 @@ const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const color = COLOR4D( 0, 1, 0, 1 ); break; case 1: - color = COLOR4D( 1, 0, 0, 0.3 ); break; + color = COLOR4D( 1, 0, 0, 1 ); break; case 2: - color = COLOR4D( 1, 0.5, 0.5, 1 ); break; + color = COLOR4D( 1, 1, 0, 1 ); break; case 3: color = COLOR4D( 0, 0, 1, 1 ); break; @@ -220,9 +284,11 @@ const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const color = COLOR4D( 0, 1, 1, 1 ); break; case 32: - color = COLOR4D( 0, 0, 1, 0.5 ); break; + color = COLOR4D( 0, 0, 1, 1 ); break; default: + color = COLOR4D( 0.4, 0.4, 0.4, 1 ); break; + break; } diff --git a/pcbnew/router/router_preview_item.h b/pcbnew/router/router_preview_item.h index 058c47f816..c22e21c5e6 100644 --- a/pcbnew/router/router_preview_item.h +++ b/pcbnew/router/router_preview_item.h @@ -1,7 +1,7 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -15,7 +15,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __ROUTER_PREVIEW_ITEM_H @@ -44,28 +44,35 @@ class PNS_ROUTER; class ROUTER_PREVIEW_ITEM : public EDA_ITEM { public: - enum ItemType + enum ITEM_TYPE { - PR_VIA, - PR_LINE, - PR_STUCK_MARKER + PR_STUCK_MARKER = 0, + PR_POINT, + PR_SHAPE }; - - enum ItemFlags - { - PR_SUGGESTION = 1 - }; - + ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem = NULL, KIGFX::VIEW_GROUP* aParent = NULL ); ~ROUTER_PREVIEW_ITEM(); void Update( const PNS_ITEM* aItem ); void StuckMarker( VECTOR2I& aPosition ); - void DebugLine( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 ); - void DebugBox( const BOX2I& aBox, int aStyle = 0 ); + + void Line( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 ); + void Box( const BOX2I& aBox, int aStyle = 0 ); + void Point ( const VECTOR2I& aPos, int aStyle = 0); - void Show( int a, std::ostream& b ) const {}; + void SetColor( const KIGFX::COLOR4D& aColor ) + { + m_color = aColor; + } + + void SetClearance( int aClearance ) + { + m_clearance = aClearance; + } + + void Show( int aA, std::ostream& aB ) const {}; const BOX2I ViewBBox() const; @@ -77,7 +84,7 @@ public: aCount = 1; } - void MarkAsHead(); + void drawLineChain( const SHAPE_LINE_CHAIN& aL, KIGFX::GAL *aGal ) const; private: const KIGFX::COLOR4D assignColor( int aStyle ) const; @@ -86,17 +93,25 @@ private: KIGFX::VIEW_GROUP* m_parent; PNS_ROUTER* m_router; - SHAPE_LINE_CHAIN m_line; + SHAPE* m_shape; - ItemType m_type; + ITEM_TYPE m_type; + int m_style; int m_width; int m_layer; + int m_originLayer; + int m_clearance; + + // fixme: shouldn't this go to VIEW? + static const int ClearanceOverlayDepth = -2000; + static const int BaseOverlayDepth = -2020; + static const int ViaOverlayDepth = -2046; + + double m_depth; KIGFX::COLOR4D m_color; - - VECTOR2I m_stuckPosition; - VECTOR2I m_viaCenter; + VECTOR2I m_pos; }; #endif diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 8fe733fb8c..eace67a44f 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -15,22 +15,28 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ +#include + #include #include +#include #include "class_draw_panel_gal.h" -#include "class_board_item.h" #include "class_board.h" #include #include +#include #include #include #include #include +#include +#include +#include #include #include @@ -45,30 +51,181 @@ using namespace KIGFX; using boost::optional; -//static TOOL_ACTION ACT_AutoEndRoute( "pcbnew.InteractiveRouter.AutoEndRoute", AS_CONTEXT, 'G' ); -//static TOOL_ACTION ACT_PlaceVia( "pcbnew.InteractiveRouter.PlaceVia", AS_CONTEXT, 'V' ); -//static TOOL_ACTION ACT_OpenRouteOptions( "pcbnew.InteractiveRouter.OpenRouterOptions", AS_CONTEXT, 'T' ); -//static TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT, '/' ); -//static TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END ); +static TOOL_ACTION ACT_NewTrack( "pcbnew.InteractiveRouter.NewTrack", + AS_CONTEXT, 'X', + "New Track", "Starts laying a new track."); +static TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack", + AS_CONTEXT, WXK_END, + "End Track", "Stops laying the current track."); +static TOOL_ACTION ACT_AutoEndRoute( "pcbnew.InteractiveRouter.AutoEndRoute", + AS_CONTEXT, 'F', + "Auto-end Track", "Automagically finishes currently routed track." ); +static TOOL_ACTION ACT_Drag( "pcbnew.InteractiveRouter.Drag", + AS_CONTEXT, 'G', + "Drag Track/Via", "Drags a track or a via." ); +static TOOL_ACTION ACT_PlaceThroughVia( "pcbnew.InteractiveRouter.PlaceVia", + AS_CONTEXT, 'V', + "Place Through Via", "Adds a through-hole via at the end of currently routed track." ); +static TOOL_ACTION ACT_CustomTrackWidth( "pcbnew.InteractiveRouter.CustomTrackWidth", + AS_CONTEXT, 'W', + "Custom Track Width", "Shows a dialog for changing the track width and via size."); +static TOOL_ACTION ACT_RouterOptions( "pcbnew.InteractiveRouter.RouterOptions", + AS_CONTEXT, 'E', + "Routing Options...", "Shows a dialog containing router options."); +static TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture", + AS_CONTEXT, '/', + "Switch Track Posture", "Switches posture of the currenly routed track."); ROUTER_TOOL::ROUTER_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) { m_router = NULL; - m_menu = new CONTEXT_MENU; - - m_menu->SetTitle( wxT( "Interactive router" ) ); // fixme: not implemented yet. Sorry. - m_menu->Add( wxT( "Cancel" ), 1 ); - m_menu->Add( wxT( "New track" ), 2 ); - m_menu->Add( wxT( "End track" ), 3 ); - m_menu->Add( wxT( "Auto-end track" ), 4 ); - m_menu->Add( wxT( "Place via" ), 5 ); - m_menu->Add( wxT( "Switch posture" ), 6 ); - - m_menu->Add( wxT( "Routing options..." ), 7 ); } +class CONTEXT_TRACK_WIDTH_MENU: public CONTEXT_MENU +{ +public: + CONTEXT_TRACK_WIDTH_MENU() + { + setCustomEventHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::handleCustomEvent, + this, _1 ) ); + } + + void SetBoard( BOARD* aBoard ) + { + BOARD_DESIGN_SETTINGS& bds = aBoard->GetDesignSettings(); + + wxString msg; + m_board = aBoard; + + Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Custom size" ), + wxEmptyString, wxITEM_CHECK ); + + Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use the starting track width" ), + _( "Route using the width of the starting track." ), wxITEM_CHECK ); + + Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use netclass values" ), + _( "Use track and via sizes from the net class" ), wxITEM_CHECK ); + + for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ ) + { + msg = _( "Track "); + msg << StringFromValue( g_UserUnit, bds.m_TrackWidthList[i], true ); + + if( i == 0 ) + msg << _( " (from netclass)" ); + + Append( ID_POPUP_PCB_SELECT_WIDTH1 + i, msg, wxEmptyString, wxITEM_CHECK ); + } + + AppendSeparator(); + + for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ ) + { + msg = _("Via "); + msg << StringFromValue( g_UserUnit, bds.m_ViasDimensionsList[i].m_Diameter, true ); + wxString drill = StringFromValue( g_UserUnit, + bds.m_ViasDimensionsList[i].m_Drill, + true ); + + if( bds.m_ViasDimensionsList[i].m_Drill <= 0 ) + { + msg << _ (", drill: default"); + } + else + { + msg << _ (", drill: ") << drill; + } + + if( i == 0 ) + msg << _( " (from netclass)" ); + + Append( ID_POPUP_PCB_SELECT_VIASIZE1 + i, msg, wxEmptyString, wxITEM_CHECK ); + } + } + +protected: + OPT_TOOL_EVENT handleCustomEvent( const wxEvent& aEvent ) + { +#if ID_POPUP_PCB_SELECT_VIASIZE1 < ID_POPUP_PCB_SELECT_WIDTH1 +#error You have changed event ids order, it breaks code. Check the source code for more details. +// Recognising type of event (track width/via size) is based on comparison if the event id is +// within a specific range. If ranges of event ids changes, then the following is not valid anymore. +#endif + BOARD_DESIGN_SETTINGS &bds = m_board->GetDesignSettings(); + + int id = aEvent.GetId(); + + // Initial settings, to be modified below + bds.m_UseConnectedTrackWidth = false; + bds.UseCustomTrackViaSize( false ); + + if( id == ID_POPUP_PCB_SELECT_CUSTOM_WIDTH ) + { + bds.UseCustomTrackViaSize( true ); + } + + else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH ) + { + bds.m_UseConnectedTrackWidth = true; + } + + else if( id == ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES ) + { + bds.SetViaSizeIndex( 0 ); + bds.SetTrackWidthIndex( 0 ); + } + + else if( id > ID_POPUP_PCB_SELECT_VIASIZE1 ) // via size has changed + { + assert( id < ID_POPUP_PCB_SELECT_WIDTH_END_RANGE ); + + bds.SetViaSizeIndex( id - ID_POPUP_PCB_SELECT_VIASIZE1 ); + } + + else // track width has changed + { + assert( id >= ID_POPUP_PCB_SELECT_WIDTH1 ); + assert( id < ID_POPUP_PCB_SELECT_VIASIZE ); + + bds.SetTrackWidthIndex( id - ID_POPUP_PCB_SELECT_WIDTH1 ); + } + + return OPT_TOOL_EVENT( COMMON_ACTIONS::trackViaSizeChanged.MakeEvent() ); + } + + BOARD* m_board; +}; + + +class ROUTER_TOOL_MENU: public CONTEXT_MENU +{ +public: + ROUTER_TOOL_MENU( BOARD* aBoard ) + { + SetTitle( wxT( "Interactive Router" ) ); + Add( ACT_NewTrack ); + Add( ACT_EndTrack ); +// Add( ACT_AutoEndRoute ); // fixme: not implemented yet. Sorry. + Add( ACT_Drag ); + Add( ACT_PlaceThroughVia ); + Add( ACT_SwitchPosture ); + + AppendSeparator ( ); + + CONTEXT_TRACK_WIDTH_MENU* trackMenu = new CONTEXT_TRACK_WIDTH_MENU; + trackMenu->SetBoard( aBoard ); + AppendSubMenu( trackMenu, wxT( "Select Track Width" ) ); + + Add( ACT_CustomTrackWidth ); + + AppendSeparator ( ); + Add( ACT_RouterOptions ); + } +}; + + ROUTER_TOOL::~ROUTER_TOOL() { delete m_router; @@ -86,6 +243,7 @@ void ROUTER_TOOL::Reset( RESET_REASON aReason ) m_router->ClearWorld(); m_router->SetBoard( getModel( PCB_T ) ); m_router->SyncWorld(); + m_router->LoadSettings( m_settings ); m_needsSync = false; if( getView() ) @@ -100,14 +258,16 @@ int ROUTER_TOOL::getDefaultWidth( int aNetCode ) int w, d1, d2; getNetclassDimensions( aNetCode, w, d1, d2 ); + return w; } void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth, - int& aViaDiameter, int& aViaDrill ) +int& aViaDiameter, int& aViaDrill ) { BOARD* board = getModel( PCB_T ); + BOARD_DESIGN_SETTINGS &bds = board->GetDesignSettings(); NETCLASS* netClass = NULL; NETINFO_ITEM* ni = board->FindNet( aNetCode ); @@ -115,11 +275,11 @@ void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth, if( ni ) { wxString netClassName = ni->GetClassName(); - netClass = board->m_NetClasses.Find( netClassName ); + netClass = bds.m_NetClasses.Find( netClassName ); } if( !netClass ) - netClass = board->m_NetClasses.GetDefault(); + netClass = bds.GetDefault(); aWidth = netClass->GetTrackWidth(); aViaDiameter = netClass->GetViaDiameter(); @@ -134,74 +294,67 @@ PNS_ITEM* ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa if( aLayer > 0 ) tl = aLayer; - PNS_ITEM* picked_seg = NULL; - PNS_ITEM* picked_via = NULL; + PNS_ITEM* prioritized[4]; + + for(int i = 0; i < 4; i++) + prioritized[i] = 0; + PNS_ITEMSET candidates = m_router->QueryHoverItems( aWhere ); BOOST_FOREACH( PNS_ITEM* item, candidates.Items() ) { - if( !IsCopperLayer( item->GetLayers().Start() ) ) + if( !IsCopperLayer( item->Layers().Start() ) ) continue; - if( item->GetParent() && !item->GetParent()->ViewIsVisible() && - !item->GetParent()->IsSelected() ) - continue; + // fixme: this causes flicker with live loop removal... + //if( item->Parent() && !item->Parent()->ViewIsVisible() ) + // continue; - if( aNet < 0 || item->GetNet() == aNet ) + if( aNet < 0 || item->Net() == aNet ) { if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) { - if( item->GetLayers().Overlaps( tl ) || !picked_via ) - picked_via = item; + if( !prioritized[2] ) + prioritized[2] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[0] = item; } else { - if( item->GetLayers().Overlaps( tl ) || !picked_seg ) - picked_seg = item; + if( !prioritized[3] ) + prioritized[3] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[1] = item; } } } - if( DisplayOpt.ContrastModeDisplay ) + PNS_ITEM* rv = NULL; + for( int i = 0; i < 4; i++ ) { - if( picked_seg && !picked_seg->GetLayers().Overlaps( tl ) ) - picked_seg = NULL; + PNS_ITEM* item = prioritized[i]; + + if( DisplayOpt.ContrastModeDisplay ) + if( item && !item->Layers().Overlaps( tl ) ) + item = NULL; + + if( item ) + { + rv = item; + break; + } } - PNS_ITEM* rv = picked_via ? picked_via : picked_seg; - - if( rv && aLayer >= 0 && !rv->GetLayers().Overlaps( aLayer ) ) + if( rv && aLayer >= 0 && !rv->Layers().Overlaps( aLayer ) ) rv = NULL; if( rv ) - TRACE( 0, "%s, layer : %d, tl: %d", rv->GetKindStr().c_str() % rv->GetLayers().Start() % - tl ); + TRACE( 0, "%s, layer : %d, tl: %d", rv->KindStr().c_str() % rv->Layers().Start() % tl ); return rv; } -void ROUTER_TOOL::setMsgPanel( bool aEnabled, int aEntry, - const wxString& aUpperMessage, const wxString& aLowerMessage ) -{ - PCB_EDIT_FRAME* frame = getEditFrame (); - - if( m_panelItems.size() <= (unsigned int) aEntry ) - m_panelItems.resize( aEntry + 1 ); - - m_panelItems[aEntry] = MSG_PANEL_ITEM( aUpperMessage, aLowerMessage, BLACK ); - frame->SetMsgPanel( m_panelItems ); -} - - -void ROUTER_TOOL::clearMsgPanel() -{ - PCB_EDIT_FRAME* frame = getEditFrame (); - - frame->ClearMsgPanel(); -} - - void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode ) { RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings(); @@ -215,36 +368,105 @@ void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode ) } +void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) +{ +#ifdef DEBUG + if( aEvent.IsKeyPressed() ) + { + switch( aEvent.KeyCode() ) + { + case 'S': + TRACEn( 2, "saving drag/route log...\n" ); + m_router->DumpLog(); + break; + } + } + else +#endif + if( aEvent.IsAction( &ACT_RouterOptions ) ) + { + DIALOG_PNS_SETTINGS settingsDlg( m_toolMgr->GetEditFrame(), m_router->Settings() ); + + if( settingsDlg.ShowModal() ) + m_router->ApplySettings(); + } + + else if( aEvent.IsAction( &ACT_CustomTrackWidth ) ) + { + DIALOG_TRACK_VIA_SIZE sizeDlg( m_toolMgr->GetEditFrame(), m_router->Settings() ); + BOARD_DESIGN_SETTINGS& bds = getModel( PCB_T )->GetDesignSettings(); + + sizeDlg.ShowModal(); + + // TODO it should be changed, router settings won't keep track & via sizes in the future + bds.SetCustomTrackWidth( m_router->Settings().GetTrackWidth() ); + bds.SetCustomViaSize( m_router->Settings().GetViaDiameter() ); + bds.SetCustomViaDrill( m_router->Settings().GetViaDrill() ); + bds.UseCustomTrackViaSize( true ); + + // TODO Should be done another way, but RunAction() won't work here. As the ROUTER_TOOL + // did not call Wait(), it does not wait for events and therefore the sent event + // won't arrive here + TOOL_EVENT event = COMMON_ACTIONS::trackViaSizeChanged.MakeEvent(); + handleCommonEvents( event ); + } + + else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) + { + BOARD_DESIGN_SETTINGS& bds = getModel( PCB_T )->GetDesignSettings(); + + m_router->Settings().SetTrackWidth( bds.GetCurrentTrackWidth() ); + m_router->Settings().SetViaDiameter( bds.GetCurrentViaSize() ); + m_router->Settings().SetViaDrill( bds.GetCurrentViaDrill() ); + m_router->ApplySettings(); + } +} + + void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) { VIEW_CONTROLS* ctls = getViewControls(); int tl = getView()->GetTopLayer(); + VECTOR2I cp = ctls->GetCursorPosition(); PNS_ITEM* startItem = NULL; if( aEvent.IsMotion() || aEvent.IsClick() ) { VECTOR2I p = aEvent.Position(); startItem = pickSingleItem( p ); + bool snapEnabled = !aEvent.Modifier(MD_SHIFT); + m_router->EnableSnapping ( snapEnabled ); - if( startItem && startItem->GetNet() >= 0 ) + if( !snapEnabled && startItem && !startItem->Layers().Overlaps( tl ) ) + startItem = NULL; + + if( startItem && startItem->Net() >= 0 ) { bool dummy; - VECTOR2I cursorPos = m_router->SnapToItem( startItem, p, dummy ); - ctls->ForceCursorPosition( true, cursorPos ); + VECTOR2I psnap = m_router->SnapToItem( startItem, p, dummy ); + + if( snapEnabled ) + { + m_startSnapPoint = psnap; + ctls->ForceCursorPosition( true, psnap ); + } + else + { + m_startSnapPoint = cp; + ctls->ForceCursorPosition( false ); + } - m_startSnapPoint = cursorPos; - - if( startItem->GetLayers().IsMultilayer() ) + if( startItem->Layers().IsMultilayer() ) m_startLayer = tl; else - m_startLayer = startItem->GetLayers().Start(); + m_startLayer = startItem->Layers().Start(); m_startItem = startItem; } else { m_startItem = NULL; - m_startSnapPoint = p; + m_startSnapPoint = cp; m_startLayer = tl; ctls->ForceCursorPosition( false ); } @@ -255,13 +477,18 @@ void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) { VIEW_CONTROLS* ctls = getViewControls(); - VECTOR2I p = aEvent.Position(); + VECTOR2I p = getView()->ToWorld( ctls->GetMousePosition() ); + VECTOR2I cp = ctls->GetCursorPosition(); int layer; - if( m_router->GetCurrentNet() < 0 || !m_startItem ) + bool snapEnabled = !aEvent.Modifier(MD_SHIFT); + + m_router->EnableSnapping ( snapEnabled ); + + if( !snapEnabled || m_router->GetCurrentNet() < 0 || !m_startItem ) { m_endItem = NULL; - m_endSnapPoint = p; + m_endSnapPoint = cp; return; } @@ -272,7 +499,7 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) else layer = m_router->GetCurrentLayer(); - PNS_ITEM* endItem = pickSingleItem( p, m_startItem->GetNet(), layer ); + PNS_ITEM* endItem = pickSingleItem( p, m_startItem->Net(), layer ); if( endItem ) { @@ -284,57 +511,38 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) else { m_endItem = NULL; - m_endSnapPoint = ctls->GetCursorPosition(); + m_endSnapPoint = cp; ctls->ForceCursorPosition( false ); } - // Draw ratsnest for the currently routed track - RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); - ratsnest->ClearSimple(); - - if( ( m_endItem == NULL || m_endItem == m_startItem ) && m_startItem->GetNet() > 0 ) - { - // The ending node has to be first, so the line for the track is drawn first - ratsnest->AddSimple( m_endSnapPoint, m_startItem->GetNet() ); - - // Those nodes are added just to force ratsnest not to drawn - // lines to already routed parts of the track - const PICKED_ITEMS_LIST& changes = m_router->GetLastChanges(); - for( unsigned int i = 0; i < changes.GetCount(); ++i ) - { - // Block the new tracks, do not handle tracks that were moved - // (moved tracks are saved in the undo buffer with UR_DELETED status instead) - if( changes.GetPickedItemStatus( i ) == UR_NEW ) - ratsnest->AddBlocked( static_cast( changes.GetPickedItem( i ) ) ); - } - - // Also the origin of the new track should be skipped in the ratsnest shown for the routed track - ratsnest->AddBlocked( static_cast( m_startItem->GetParent() ) ); - } - if( m_endItem ) - TRACE( 0, "%s, layer : %d", m_endItem->GetKindStr().c_str() % - m_endItem->GetLayers().Start() ); + TRACE( 0, "%s, layer : %d", m_endItem->KindStr().c_str() % m_endItem->Layers().Start() ); } -void ROUTER_TOOL::startRouting() +void ROUTER_TOOL::performRouting() { + PCB_EDIT_FRAME* frame = getEditFrame(); bool saveUndoBuffer = true; VIEW_CONTROLS* ctls = getViewControls(); - int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1 ); + if( getModel( PCB_T )->GetDesignSettings().m_UseConnectedTrackWidth ) + { + int width = getDefaultWidth( m_startItem ? m_startItem->Net() : -1 ); - if( m_startItem && m_startItem->OfKind( PNS_ITEM::SEGMENT ) ) - width = static_cast( m_startItem )->GetWidth(); + if( m_startItem && m_startItem->OfKind( PNS_ITEM::SEGMENT ) ) + width = static_cast( m_startItem )->Width(); + + m_router->Settings().SetTrackWidth( width ); + } - m_router->SetCurrentWidth( width ); m_router->SwitchLayer( m_startLayer ); - getEditFrame()->SetTopLayer( m_startLayer ); + frame->SetActiveLayer( m_startLayer ); + frame->GetGalCanvas()->SetFocus(); - if( m_startItem && m_startItem->GetNet() >= 0 ) - highlightNet( true, m_startItem->GetNet() ); + if( m_startItem && m_startItem->Net() >= 0 ) + highlightNet( true, m_startItem->Net() ); ctls->ForceCursorPosition( false ); ctls->SetAutoPan( true ); @@ -367,42 +575,37 @@ void ROUTER_TOOL::startRouting() m_router->Move( m_endSnapPoint, m_endItem ); } - else if( evt->IsKeyPressed() ) + else if( evt->IsAction( &ACT_PlaceThroughVia ) ) { - switch( std::toupper( evt->KeyCode() ) ) - { - case 'V': - { - int w, diameter, drill; - getNetclassDimensions( m_router->GetCurrentNet(), w, diameter, drill ); - m_router->SetCurrentViaDiameter( diameter ); - m_router->SetCurrentViaDrill( drill ); - m_router->ToggleViaPlacement(); - getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); - m_router->Move( m_endSnapPoint, m_endItem ); - break; - } - - case '/': - m_router->FlipPosture(); - break; - - case '+': - case '=': - m_router->SwitchLayer( m_router->NextCopperLayer( true ) ); - updateEndItem( *evt ); - getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); - m_router->Move( m_endSnapPoint, m_endItem ); - - break; - - case '-': - m_router->SwitchLayer( m_router->NextCopperLayer( false ) ); - getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); - m_router->Move( m_endSnapPoint, m_endItem ); - break; - } + m_router->ToggleViaPlacement(); + frame->SetTopLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); } + else if( evt->IsAction( &ACT_SwitchPosture ) ) + { + m_router->FlipPosture(); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsAction( &COMMON_ACTIONS::layerNext ) ) + { + m_router->SwitchLayer( m_router->NextCopperLayer( true ) ); + updateEndItem( *evt ); + frame->SetActiveLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsAction( &COMMON_ACTIONS::layerPrev ) ) + { + m_router->SwitchLayer( m_router->NextCopperLayer( false ) ); + frame->SetActiveLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsAction( &ACT_EndTrack ) ) + { + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) + break; + } + + handleCommonEvents(*evt); } m_router->StopRouting(); @@ -410,10 +613,9 @@ void ROUTER_TOOL::startRouting() if( saveUndoBuffer ) { // Save the recent changes in the undo buffer - getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), - UR_UNSPECIFIED ); - m_router->ClearLastChanges(); - getEditFrame()->OnModify(); + frame->SaveCopyInUndoList( m_router->GetUndoBuffer(), UR_UNSPECIFIED ); + m_router->ClearUndoBuffer(); + frame->OnModify(); } else { @@ -430,14 +632,27 @@ void ROUTER_TOOL::startRouting() int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) { VIEW_CONTROLS* ctls = getViewControls(); + BOARD* board = getModel( PCB_T ); + BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); - // SetContextMenu ( m_menu ); - // setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing")); - getEditFrame()->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Add tracks" ) ); + // Deselect all items + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear ); + + getEditFrame()->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, + _( "Interactive Router" ) ); ctls->SetSnapping( true ); ctls->ShowCursor( true ); + // Set current track widths & via size + m_router->Settings().SetTrackWidth( bds.GetCurrentTrackWidth() ); + m_router->Settings().SetViaDiameter( bds.GetCurrentViaSize() ); + m_router->Settings().SetViaDrill( bds.GetCurrentViaDrill() ); + + ROUTER_TOOL_MENU *ctxMenu = new ROUTER_TOOL_MENU( board ); + + SetContextMenu ( ctxMenu ); + // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { @@ -453,21 +668,90 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) m_needsSync = true; else if( evt->IsMotion() ) updateStartItem( *evt ); - else if( evt->IsClick( BUT_LEFT ) ) + else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_NewTrack ) ) { updateStartItem( *evt ); - startRouting(); - } - } - // clearMsgPanel(); + if( evt->Modifier( MD_CTRL ) ) + performDragging(); + else + performRouting(); + } else if ( evt->IsAction( &ACT_Drag ) ) + performDragging(); + + handleCommonEvents(*evt); + } // Restore the default settings ctls->SetAutoPan( false ); ctls->ShowCursor( false ); - ctls->ForceCursorPosition( false ); - getEditFrame()->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + // Store routing settings till the next invocation + m_settings = m_router->Settings(); + delete ctxMenu; + return 0; } + + +void ROUTER_TOOL::performDragging() +{ + PCB_EDIT_FRAME* frame = getEditFrame(); + bool saveUndoBuffer = true; + VIEW_CONTROLS* ctls = getViewControls(); + + bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem ); + + if( !dragStarted ) + return; + + if( m_startItem && m_startItem->Net() >= 0 ) + highlightNet( true, m_startItem->Net() ); + + ctls->ForceCursorPosition( false ); + ctls->SetAutoPan( true ); + + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( evt->IsCancel() ) + break; + else if( evt->Action() == TA_UNDO_REDO ) + { + saveUndoBuffer = false; + break; + } + else if( evt->IsMotion() ) + { + updateEndItem( *evt ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsClick( BUT_LEFT ) ) + { + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) + break; + } + + handleCommonEvents( *evt ); + } + + if( m_router->RoutingInProgress() ) + m_router->StopRouting(); + + if( saveUndoBuffer ) + { + // Save the recent changes in the undo buffer + frame->SaveCopyInUndoList( m_router->GetUndoBuffer(), UR_UNSPECIFIED ); + m_router->ClearUndoBuffer(); + frame->OnModify(); + } + else + { + // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now + m_needsSync = true; + } + + ctls->SetAutoPan( false ); + ctls->ForceCursorPosition( false ); + highlightNet( false ); +} diff --git a/pcbnew/router/router_tool.h b/pcbnew/router/router_tool.h index 42bbceb19c..e2e1119fe3 100644 --- a/pcbnew/router/router_tool.h +++ b/pcbnew/router/router_tool.h @@ -1,8 +1,9 @@ /* * KiRouter - a push-and-(sometimes-)shove PCB router * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2014 CERN * Author: Tomasz Wlostowski + * Author: Maciej Suminski * * 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 @@ -15,7 +16,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __ROUTER_TOOL_H @@ -24,6 +25,8 @@ #include #include +#include + #include #include @@ -31,11 +34,12 @@ #include #include "pns_layerset.h" +#include "pns_routing_settings.h" class PNS_ROUTER; class PNS_ITEM; -class ROUTER_TOOL : public TOOL_INTERACTIVE +class APIEXPORT ROUTER_TOOL : public TOOL_INTERACTIVE { public: ROUTER_TOOL(); @@ -45,25 +49,26 @@ public: int Main( TOOL_EVENT& aEvent ); private: - PNS_ITEM* pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); - void setMsgPanel( bool enabled, int entry, const wxString& aUpperMessage = wxT(""), - const wxString& aLowerMessage = wxT("") ); - void clearMsgPanel(); - int getDefaultWidth( int aNetCode ); - void startRouting(); - void highlightNet( bool enabled, int netcode = -1 ); + + void performRouting(); + void performDragging(); + + void highlightNet( bool aEnabled, int aNetcode = -1 ); void updateStartItem( TOOL_EVENT& aEvent ); void updateEndItem( TOOL_EVENT& aEvent ); void getNetclassDimensions( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill ); + void handleCommonEvents( TOOL_EVENT& evt ); + MSG_PANEL_ITEMS m_panelItems; PNS_ROUTER* m_router; + PNS_ROUTING_SETTINGS m_settings; ///< Stores routing settings between router invocations PNS_ITEM* m_startItem; int m_startLayer; @@ -72,11 +77,10 @@ private: PNS_ITEM* m_endItem; VECTOR2I m_endSnapPoint; + CONTEXT_MENU* m_menu; + ///> Flag marking that the router's world needs syncing. bool m_needsSync; - - /*boost::shared_ptr m_menu;*/ - CONTEXT_MENU* m_menu; }; #endif diff --git a/pcbnew/router/time_limit.cpp b/pcbnew/router/time_limit.cpp new file mode 100644 index 0000000000..b4cef54869 --- /dev/null +++ b/pcbnew/router/time_limit.cpp @@ -0,0 +1,51 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#include + +#include "time_limit.h" + +TIME_LIMIT::TIME_LIMIT( int aMilliseconds ) : + m_limitMs( aMilliseconds ) +{ + Restart(); +} + + +TIME_LIMIT::~TIME_LIMIT() +{} + + +bool TIME_LIMIT::Expired() const +{ + return ( wxGetLocalTimeMillis().GetValue() - m_startTics ) >= m_limitMs; +} + + +void TIME_LIMIT::Restart() +{ + m_startTics = wxGetLocalTimeMillis().GetValue(); +} + + +void TIME_LIMIT::Set( int aMilliseconds ) +{ + m_limitMs = aMilliseconds; +} diff --git a/pcbnew/router/time_limit.h b/pcbnew/router/time_limit.h new file mode 100644 index 0000000000..8c7a07db5e --- /dev/null +++ b/pcbnew/router/time_limit.h @@ -0,0 +1,42 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2014 CERN + * Author: Tomasz Wlostowski + * + * 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 3 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, see . + */ + +#ifndef __TIME_LIMIT_H +#define __TIME_LIMIT_H + +#include + +class TIME_LIMIT +{ +public: + TIME_LIMIT( int aMilliseconds = 0 ); + ~TIME_LIMIT(); + + bool Expired() const; + void Restart(); + + void Set( int aMilliseconds ); + +private: + int m_limitMs; + int64_t m_startTics; +}; + +#endif diff --git a/pcbnew/router/trace.h b/pcbnew/router/trace.h index 1f8a3e32c9..c115b67881 100644 --- a/pcbnew/router/trace.h +++ b/pcbnew/router/trace.h @@ -15,35 +15,32 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * with this program. If not, see . */ #ifndef __TRACE_H #define __TRACE_H -// #ifdef DEBUG -#if 0 - #include #include #include -static void _trace_print( const char* aFuncName, int level, const std::string& aMsg ) +static inline void _trace_print( const char* aFuncName, int aLevel, const std::string& aMsg ) { - std::cerr << "trace[" << level << "]: " << aFuncName << ": " << aMsg << std::endl; +#ifdef DEBUG + std::cerr << "trace[" << aLevel << "]: " << aFuncName << ": " << aMsg << std::endl; +#endif } -#define TRACE( level, fmt, ... ) \ - _trace_print( __FUNCTION__, level, ( boost::format( fmt ) % __VA_ARGS__ ).str() ); - -#define TRACEn( level, msg ) \ - _trace_print( __FUNCTION__, level, std::string( msg ) ); +#ifdef PNS_DEBUG + #define TRACE( level, fmt, ... ) \ + _trace_print( __FUNCTION__, level, ( boost::format( fmt ) % __VA_ARGS__ ).str() ); + #define TRACEn( level, msg ) \ + _trace_print( __FUNCTION__, level, std::string( msg ) ); #else - -#define TRACE( level, fmt, ... ) -#define TRACEn( level, msg ) - + #define TRACE( ... ) + #define TRACEn( ... ) #endif #endif diff --git a/pcbnew/scripting/pcbnew_scripting_helpers.cpp b/pcbnew/scripting/pcbnew_scripting_helpers.cpp index 42a0a14391..62b21b3df1 100644 --- a/pcbnew/scripting/pcbnew_scripting_helpers.cpp +++ b/pcbnew/scripting/pcbnew_scripting_helpers.cpp @@ -86,7 +86,7 @@ bool SaveBoard( wxString& aFileName, BOARD* aBoard, { aBoard->m_Status_Pcb &= ~CONNEXION_OK; aBoard->SynchronizeNetsAndNetClasses(); - aBoard->SetCurrentNetClass( aBoard->m_NetClasses.GetDefault()->GetName() ); + aBoard->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default ); #if 0 wxString header; diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index ef452ce66d..089925576c 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -1476,9 +1476,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) //------------------------------------------------------------- { char rule[80]; + NETCLASS* defaultClass = aBoard->GetDesignSettings().m_NetClasses.GetDefault(); - int defaultTrackWidth = aBoard->m_NetClasses.GetDefault()->GetTrackWidth(); - int defaultClearance = aBoard->m_NetClasses.GetDefault()->GetClearance(); + int defaultTrackWidth = defaultClass->GetTrackWidth(); + int defaultClearance = defaultClass->GetClearance(); double clearance = scale( defaultClearance ); @@ -1829,7 +1830,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) //-----< output vias used in netclasses >----------------------------------- { - NETCLASSES& nclasses = aBoard->m_NetClasses; + NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses; // Assume the netclass vias are all the same kind of thru, blind, or buried vias. // This is in lieu of either having each netclass via have its own layer pair in @@ -2039,7 +2040,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) //--------------------------------------------------------- - NETCLASSES& nclasses = aBoard->m_NetClasses; + NETCLASSES& nclasses = aBoard->GetDesignSettings().m_NetClasses; exportNETCLASS( nclasses.GetDefault(), aBoard ); diff --git a/pcbnew/tool_pcb.cpp b/pcbnew/tool_pcb.cpp index ec4d07df7d..c115cbcc37 100644 --- a/pcbnew/tool_pcb.cpp +++ b/pcbnew/tool_pcb.cpp @@ -620,9 +620,9 @@ void PCB_EDIT_FRAME::updateTraceWidthSelectBox() m_SelTrackWidthBox->Clear(); - for( unsigned ii = 0; ii < GetBoard()->m_TrackWidthList.size(); ii++ ) + for( unsigned ii = 0; ii < GetDesignSettings().m_TrackWidthList.size(); ii++ ) { - msg = _( "Track " ) + CoordinateToString( GetBoard()->m_TrackWidthList[ii], true ); + msg = _( "Track " ) + CoordinateToString( GetDesignSettings().m_TrackWidthList[ii], true ); if( ii == 0 ) msg << _( " *" ); @@ -630,10 +630,10 @@ void PCB_EDIT_FRAME::updateTraceWidthSelectBox() m_SelTrackWidthBox->Append( msg ); } - if( GetBoard()->GetTrackWidthIndex() >= GetBoard()->m_TrackWidthList.size() ) - GetBoard()->SetTrackWidthIndex( 0 ); + if( GetDesignSettings().GetTrackWidthIndex() >= GetDesignSettings().m_TrackWidthList.size() ) + GetDesignSettings().SetTrackWidthIndex( 0 ); - m_SelTrackWidthBox->SetSelection( GetBoard()->GetTrackWidthIndex() ); + m_SelTrackWidthBox->SetSelection( GetDesignSettings().GetTrackWidthIndex() ); } @@ -646,14 +646,14 @@ void PCB_EDIT_FRAME::updateViaSizeSelectBox() m_SelViaSizeBox->Clear(); - for( unsigned ii = 0; ii < GetBoard()->m_ViasDimensionsList.size(); ii++ ) + for( unsigned ii = 0; ii < GetDesignSettings().m_ViasDimensionsList.size(); ii++ ) { msg = _( "Via " ); - msg << CoordinateToString( GetBoard()->m_ViasDimensionsList[ii].m_Diameter, true ); + msg << CoordinateToString( GetDesignSettings().m_ViasDimensionsList[ii].m_Diameter, true ); - if( GetBoard()->m_ViasDimensionsList[ii].m_Drill ) + if( GetDesignSettings().m_ViasDimensionsList[ii].m_Drill ) msg << wxT("/ ") - << CoordinateToString( GetBoard()->m_ViasDimensionsList[ii].m_Drill, true ); + << CoordinateToString( GetDesignSettings().m_ViasDimensionsList[ii].m_Drill, true ); if( ii == 0 ) msg << _( " *" ); @@ -661,10 +661,10 @@ void PCB_EDIT_FRAME::updateViaSizeSelectBox() m_SelViaSizeBox->Append( msg ); } - if( GetBoard()->GetViaSizeIndex() >= GetBoard()->m_ViasDimensionsList.size() ) - GetBoard()->SetViaSizeIndex( 0 ); + if( GetDesignSettings().GetViaSizeIndex() >= GetDesignSettings().m_ViasDimensionsList.size() ) + GetDesignSettings().SetViaSizeIndex( 0 ); - m_SelViaSizeBox->SetSelection( GetBoard()->GetViaSizeIndex() ); + m_SelViaSizeBox->SetSelection( GetDesignSettings().GetViaSizeIndex() ); } diff --git a/pcbnew/toolbars_update_user_interface.cpp b/pcbnew/toolbars_update_user_interface.cpp index ac2f65a490..b94bc75d59 100644 --- a/pcbnew/toolbars_update_user_interface.cpp +++ b/pcbnew/toolbars_update_user_interface.cpp @@ -55,14 +55,16 @@ void PCB_EDIT_FRAME::OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent ) { if( aEvent.GetId() == ID_AUX_TOOLBAR_PCB_TRACK_WIDTH ) { - if( m_SelTrackWidthBox->GetSelection() != (int) GetBoard()->GetTrackWidthIndex() ) - m_SelTrackWidthBox->SetSelection( GetBoard()->GetTrackWidthIndex() ); + if( m_SelTrackWidthBox->GetSelection() != (int) GetDesignSettings().GetTrackWidthIndex() ) + m_SelTrackWidthBox->SetSelection( GetDesignSettings().GetTrackWidthIndex() ); } else { bool check = ( ( ( ID_POPUP_PCB_SELECT_WIDTH1 + - (int) GetBoard()->GetTrackWidthIndex() ) == aEvent.GetId() ) && - !GetDesignSettings().m_UseConnectedTrackWidth ); + (int) GetDesignSettings().GetTrackWidthIndex() ) == aEvent.GetId() ) && + !GetDesignSettings().m_UseConnectedTrackWidth && + !GetDesignSettings().UseCustomTrackViaSize() ); + aEvent.Check( check ); } } @@ -70,7 +72,14 @@ void PCB_EDIT_FRAME::OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent ) void PCB_EDIT_FRAME::OnUpdateSelectAutoTrackWidth( wxUpdateUIEvent& aEvent ) { - aEvent.Check( GetDesignSettings().m_UseConnectedTrackWidth ); + aEvent.Check( GetDesignSettings().m_UseConnectedTrackWidth && + !GetDesignSettings().UseCustomTrackViaSize() ); +} + + +void PCB_EDIT_FRAME::OnUpdateSelectCustomTrackWidth( wxUpdateUIEvent& aEvent ) +{ + aEvent.Check( GetDesignSettings().UseCustomTrackViaSize() ); } @@ -80,14 +89,15 @@ void PCB_EDIT_FRAME::OnUpdateSelectViaSize( wxUpdateUIEvent& aEvent ) if( aEvent.GetId() == ID_AUX_TOOLBAR_PCB_VIA_SIZE ) { - if( m_SelViaSizeBox->GetSelection() != (int) GetBoard()->GetViaSizeIndex() ) - m_SelViaSizeBox->SetSelection( GetBoard()->GetViaSizeIndex() ); + if( m_SelViaSizeBox->GetSelection() != (int) GetDesignSettings().GetViaSizeIndex() ) + m_SelViaSizeBox->SetSelection( GetDesignSettings().GetViaSizeIndex() ); } else { bool check = ( ( ( ID_POPUP_PCB_SELECT_VIASIZE1 + - (int) GetBoard()->GetViaSizeIndex() ) == aEvent.GetId() ) && - !GetDesignSettings().m_UseConnectedTrackWidth ); + (int) GetDesignSettings().GetViaSizeIndex() ) == aEvent.GetId() ) && + !GetDesignSettings().m_UseConnectedTrackWidth && + !GetDesignSettings().UseCustomTrackViaSize() ); aEvent.Check( check ); } diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 45e9ba17fc..539de05ceb 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -208,11 +208,11 @@ TOOL_ACTION COMMON_ACTIONS::layerAlphaDec( "pcbnew.layerAlphaDec", // Grid control TOOL_ACTION COMMON_ACTIONS::gridFast1( "pcbnew.gridFast1", - AS_GLOBAL, (int)MD_ALT + '1', + AS_GLOBAL, MD_ALT + '1', "", "" ); TOOL_ACTION COMMON_ACTIONS::gridFast2( "pcbnew.gridFast2", - AS_GLOBAL, (int)MD_ALT + '2', + AS_GLOBAL, MD_ALT + '2', "", "" ); TOOL_ACTION COMMON_ACTIONS::gridNext( "pcbnew.gridNext", @@ -220,7 +220,7 @@ TOOL_ACTION COMMON_ACTIONS::gridNext( "pcbnew.gridNext", "", "" ); TOOL_ACTION COMMON_ACTIONS::gridPrev( "pcbnew.gridPrev", - AS_GLOBAL, (int)MD_CTRL + '`', + AS_GLOBAL, MD_CTRL + '`', "", "" ); @@ -241,6 +241,7 @@ TOOL_ACTION COMMON_ACTIONS::viaSizeDec( "pcbnew.viaSizeDec", AS_GLOBAL, '\\', "", "" ); +TOOL_ACTION COMMON_ACTIONS::trackViaSizeChanged( "pcbnew.trackViaSizeChanged", AS_GLOBAL, 0, "", "" ); // Miscellaneous TOOL_ACTION COMMON_ACTIONS::resetCoords( "pcbnew.resetCoords", @@ -248,7 +249,7 @@ TOOL_ACTION COMMON_ACTIONS::resetCoords( "pcbnew.resetCoords", "", "" ); TOOL_ACTION COMMON_ACTIONS::switchUnits( "pcbnew.switchUnits", - AS_GLOBAL, (int)MD_CTRL + 'U', + AS_GLOBAL, MD_CTRL + 'U', "", "" ); TOOL_ACTION COMMON_ACTIONS::showHelp( "pcbnew.showHelp", diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 38569af29a..671a509699 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -137,6 +137,8 @@ public: static TOOL_ACTION viaSizeInc; static TOOL_ACTION viaSizeDec; + static TOOL_ACTION trackViaSizeChanged; // notification + // Miscellaneous static TOOL_ACTION resetCoords; static TOOL_ACTION switchUnits; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 8dac46385c..c0e30627dc 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -92,9 +92,6 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; - // Offset from the dragged item's center (anchor) - wxPoint offset; - KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); controls->ShowCursor( true ); @@ -141,18 +138,18 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { - VECTOR2I cursor( controls->GetCursorPosition() ); + m_cursor = controls->GetCursorPosition(); if( m_dragging ) { - wxPoint movement = wxPoint( cursor.x, cursor.y ) - + wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition(); // Drag items to the current cursor position for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - item->Move( movement + offset ); + item->Move( movement + m_offset ); } updateRatsnest( true ); @@ -163,8 +160,9 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - - wxPoint( cursor.x, cursor.y ); + // Update dragging offset (distance between cursor and the first dragged item) + m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - + wxPoint( m_cursor.x, m_cursor.y ); m_dragging = true; } @@ -227,14 +225,13 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) { // Display properties dialog BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); - VECTOR2I cursor = getViewControls()->GetCursorPosition(); // Check if user wants to edit pad or module properties if( item->Type() == PCB_MODULE_T ) { for( D_PAD* pad = static_cast( item )->Pads(); pad; pad = pad->Next() ) { - if( pad->ViewBBox().Contains( cursor ) ) + if( pad->ViewBBox().Contains( getViewControls()->GetCursorPosition() ) ) { // Turns out that user wants to edit a pad properties item = pad; @@ -298,6 +295,10 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) updateRatsnest( m_dragging ); + // Update dragging offset (distance between cursor and the first dragged item) + m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - + rotatePoint; + if( m_dragging ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); else @@ -348,6 +349,10 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) updateRatsnest( m_dragging ); + // Update dragging offset (distance between cursor and the first dragged item) + m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - + flipPoint; + if( m_dragging ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); else @@ -483,12 +488,16 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION_TOOL::SELECTION& aSelec { if( aSelection.Size() == 1 ) { - return static_cast( aSelection.items.GetPickedItem( 0 ) )->GetPosition(); + return static_cast( aSelection.items.GetPickedItem( 0 ) )->GetPosition() - m_offset; } else { - VECTOR2I cursor = getViewControls()->GetCursorPosition(); - return wxPoint( cursor.x, cursor.y ); + // If EDIT_TOOL is not currently active then it means that the cursor position is not + // updated, so we have to fetch the latest value + if( m_toolMgr->GetCurrentToolId() != m_toolId ) + m_cursor = getViewControls()->GetCursorPosition(); + + return wxPoint( m_cursor.x, m_cursor.y ); } } diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index b5f6f1fc0d..b23f076e96 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -98,6 +98,13 @@ private: ///> Flag determining if anything is being dragged right now bool m_dragging; + ///> Offset from the dragged item's center (anchor) + wxPoint m_offset; + + ///> Last cursor position (needed for getModificationPoint() to avoid changes + ///> of edit reference point). + VECTOR2I m_cursor; + ///> Removes and frees a single BOARD_ITEM. void remove( BOARD_ITEM* aItem ); diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index 0decc244d7..eaefa97678 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -45,8 +46,8 @@ void PCB_EDIT_FRAME::setupTools() { // Create the manager and dispatcher & route draw panel events to the dispatcher - m_toolManager = TOOL_MANAGER::Instance(); - m_toolDispatcher = new TOOL_DISPATCHER( &m_toolManager, this ); + m_toolManager = new TOOL_MANAGER; + m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, this ); GetGalCanvas()->SetEventDispatcher( m_toolDispatcher ); // Connect handlers to toolbar buttons @@ -59,26 +60,31 @@ void PCB_EDIT_FRAME::setupTools() wxCommandEventHandler( PCB_EDIT_FRAME::onGenericCommand ), NULL, this ); #endif - // Register tools - m_toolManager.RegisterTool( new SELECTION_TOOL ); - m_toolManager.RegisterTool( new ROUTER_TOOL ); - m_toolManager.RegisterTool( new EDIT_TOOL ); - m_toolManager.RegisterTool( new DRAWING_TOOL ); - m_toolManager.RegisterTool( new POINT_EDITOR ); - m_toolManager.RegisterTool( new PCBNEW_CONTROL ); + // Register actions + std::list& actionList = m_toolManager->GetActionList(); + BOOST_FOREACH( TOOL_ACTION* action, actionList ) + m_toolManager->RegisterAction( action ); - m_toolManager.SetEnvironment( NULL, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - m_toolManager.ResetTools( TOOL_BASE::RUN ); + // Register tools + m_toolManager->RegisterTool( new SELECTION_TOOL ); + m_toolManager->RegisterTool( new ROUTER_TOOL ); + m_toolManager->RegisterTool( new EDIT_TOOL ); + m_toolManager->RegisterTool( new DRAWING_TOOL ); + m_toolManager->RegisterTool( new POINT_EDITOR ); + m_toolManager->RegisterTool( new PCBNEW_CONTROL ); + + m_toolManager->SetEnvironment( NULL, GetGalCanvas()->GetView(), + GetGalCanvas()->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::RUN ); // Run the selection tool, it is supposed to be always active - m_toolManager.InvokeTool( "pcbnew.InteractiveSelection" ); + m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" ); } void PCB_EDIT_FRAME::destroyTools() { - m_toolManager.DeleteAll(); + delete m_toolManager; delete m_toolDispatcher; } diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp index f01203178f..3fb689e71f 100644 --- a/pcbnew/tools/pcbnew_control.cpp +++ b/pcbnew/tools/pcbnew_control.cpp @@ -61,17 +61,14 @@ bool PCBNEW_CONTROL::Init() int PCBNEW_CONTROL::ZoomInOut( TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); - KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); + double zoomScale = 1.0; if( aEvent.IsAction( &COMMON_ACTIONS::zoomIn ) ) - m_frame->SetPrevZoom(); + zoomScale = 1.3; else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOut ) ) - m_frame->SetNextZoom(); + zoomScale = 0.7; - double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); - double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); - - view->SetScale( zoom, getViewControls()->GetCursorPosition() ); + view->SetScale( view->GetScale() * zoomScale, getViewControls()->GetCursorPosition() ); setTransitions(); return 0; @@ -81,17 +78,14 @@ int PCBNEW_CONTROL::ZoomInOut( TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::ZoomInOutCenter( TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); - KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); + double zoomScale = 1.0; - if( aEvent.IsAction( &COMMON_ACTIONS::zoomInCenter ) ) - m_frame->SetPrevZoom(); - else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOutCenter ) ) - m_frame->SetNextZoom(); + if( aEvent.IsAction( &COMMON_ACTIONS::zoomIn ) ) + zoomScale = 1.3; + else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOut ) ) + zoomScale = 0.7; - double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); - double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); - - view->SetScale( zoom ); + view->SetScale( view->GetScale() * zoomScale ); setTransitions(); return 0; @@ -119,10 +113,6 @@ int PCBNEW_CONTROL::ZoomFitScreen( TOOL_EVENT& aEvent ) double iuPerY = screenSize.y ? boardBBox.GetHeight() / screenSize.y : 1.0; double bestZoom = std::max( iuPerX, iuPerY ); - // This is needed to avoid "jumpy" zooms if first hot key was used and then mouse scroll - // (or other way round). - m_frame->GetScreen()->SetZoom( bestZoom ); - double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); double zoom = 1.0 / ( zoomFactor * bestZoom ); @@ -426,17 +416,20 @@ int PCBNEW_CONTROL::GridPrev( TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::TrackWidthInc( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - int widthIndex = board->GetTrackWidthIndex() + 1; + int widthIndex = board->GetDesignSettings().GetTrackWidthIndex() + 1; - if( widthIndex >= (int) board->m_TrackWidthList.size() ) - widthIndex = board->m_TrackWidthList.size() - 1; + if( widthIndex >= (int) board->GetDesignSettings().m_TrackWidthList.size() ) + widthIndex = board->GetDesignSettings().m_TrackWidthList.size() - 1; - board->SetTrackWidthIndex( widthIndex ); + board->GetDesignSettings().SetTrackWidthIndex( widthIndex ); + board->GetDesignSettings().UseCustomTrackViaSize( false ); wxUpdateUIEvent dummy; getEditFrame()->OnUpdateSelectTrackWidth( dummy ); setTransitions(); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); + return 0; } @@ -444,17 +437,20 @@ int PCBNEW_CONTROL::TrackWidthInc( TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::TrackWidthDec( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - int widthIndex = board->GetTrackWidthIndex() - 1; + int widthIndex = board->GetDesignSettings().GetTrackWidthIndex() - 1; if( widthIndex < 0 ) widthIndex = 0; - board->SetTrackWidthIndex( widthIndex ); + board->GetDesignSettings().SetTrackWidthIndex( widthIndex ); + board->GetDesignSettings().UseCustomTrackViaSize( false ); wxUpdateUIEvent dummy; getEditFrame()->OnUpdateSelectTrackWidth( dummy ); setTransitions(); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); + return 0; } @@ -462,17 +458,20 @@ int PCBNEW_CONTROL::TrackWidthDec( TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::ViaSizeInc( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - int sizeIndex = board->GetViaSizeIndex() + 1; + int sizeIndex = board->GetDesignSettings().GetViaSizeIndex() + 1; - if( sizeIndex >= (int) board->m_ViasDimensionsList.size() ) - sizeIndex = board->m_ViasDimensionsList.size() - 1; + if( sizeIndex >= (int) board->GetDesignSettings().m_ViasDimensionsList.size() ) + sizeIndex = board->GetDesignSettings().m_ViasDimensionsList.size() - 1; - board->SetViaSizeIndex( sizeIndex ); + board->GetDesignSettings().SetViaSizeIndex( sizeIndex ); + board->GetDesignSettings().UseCustomTrackViaSize( false ); wxUpdateUIEvent dummy; getEditFrame()->OnUpdateSelectViaSize( dummy ); setTransitions(); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); + return 0; } @@ -480,17 +479,20 @@ int PCBNEW_CONTROL::ViaSizeInc( TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::ViaSizeDec( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - int sizeIndex = board->GetViaSizeIndex() - 1; + int sizeIndex = board->GetDesignSettings().GetViaSizeIndex() - 1; if( sizeIndex < 0 ) sizeIndex = 0; - board->SetViaSizeIndex( sizeIndex ); + board->GetDesignSettings().SetViaSizeIndex( sizeIndex ); + board->GetDesignSettings().UseCustomTrackViaSize( false ); wxUpdateUIEvent dummy; getEditFrame()->OnUpdateSelectViaSize( dummy ); setTransitions(); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); + return 0; } diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 2511cb687e..1917076f59 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -147,8 +147,13 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them else if( evt->IsDrag( BUT_LEFT ) ) { - if( m_selection.Empty() || m_additive ) + if( m_additive ) { + selectMultiple(); + } + else if( m_selection.Empty() ) + { + // There is nothing selected, so try to select something if( !selectSingle( getView()->ToWorld( getViewControls()->GetMousePosition() ), false ) ) { // If nothings has been selected or user wants to select more @@ -227,6 +232,7 @@ bool SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere, bool aAllowDisambigua BOARD_ITEM* item; GENERAL_COLLECTORS_GUIDE guide = getEditFrame()->GetCollectorsGuide(); GENERAL_COLLECTOR collector; + const KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_LINE_T, EOT }; // preferred types collector.Collect( pcb, GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); @@ -252,6 +258,15 @@ bool SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere, bool aAllowDisambigua collector.Remove( i ); } + // Check if among the selection candidates there is only one instance of preferred type + item = prefer( collector, types ); + if( item ) + { + toggleSelection( item ); + + return true; + } + // Let's see if there is still disambiguation in selection.. if( collector.GetCount() == 1 ) { @@ -681,6 +696,38 @@ void SELECTION_TOOL::highlightNet( const VECTOR2I& aPoint ) } +BOARD_ITEM* SELECTION_TOOL::prefer( GENERAL_COLLECTOR& aCollector, const KICAD_T aTypes[] ) const +{ + BOARD_ITEM* preferred = NULL; + + int typesNr = 0; + while( aTypes[typesNr++] != EOT ); // count number of types, excluding the sentinel (EOT) + + for( int i = 0; i < aCollector.GetCount(); ++i ) + { + KICAD_T type = aCollector[i]->Type(); + + for( int j = 0; j < typesNr - 1; ++j ) // Check if the item's type is in our list + { + if( aTypes[j] == type ) + { + if( preferred == NULL ) + { + preferred = aCollector[i]; // save the first matching item + break; + } + else + { + return NULL; // there is more than one preferred item, so there is no clear choice + } + } + } + } + + return preferred; +} + + void SELECTION_TOOL::SELECTION::clear() { items.ClearItemsList(); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 609fcafda5..0850286d24 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -229,6 +229,16 @@ private: */ void highlightNet( const VECTOR2I& aPoint ); + /** + * Function prefer() + * Checks if collector's list contains only single entry of asked types. If so, it returns it. + * @param aCollector is the collector that has a list of items to be queried. + * @param aTypes is the list of searched/preferred types. + * @return Pointer to the preferred item, if there is only one entry of given type or NULL + * if there are more entries or no entries at all. + */ + BOARD_ITEM* prefer( GENERAL_COLLECTOR& aCollector, const KICAD_T aTypes[] ) const; + /// Visual representation of selection box SELECTION_AREA* m_selArea; 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 c51da1fc1c..b41d859b65 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -176,7 +176,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) */ EDA_RECT item_boundingbox; EDA_RECT zone_boundingbox = GetBoundingBox(); - int biggest_clearance = aPcb->GetBiggestClearanceValue(); + int biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue(); biggest_clearance = std::max( biggest_clearance, zone_clearance ); zone_boundingbox.Inflate( biggest_clearance ); diff --git a/pcbnew/zones_convert_to_polygons_aux_functions.cpp b/pcbnew/zones_convert_to_polygons_aux_functions.cpp index be02fd0d40..9861b0d120 100644 --- a/pcbnew/zones_convert_to_polygons_aux_functions.cpp +++ b/pcbnew/zones_convert_to_polygons_aux_functions.cpp @@ -138,7 +138,7 @@ void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer, EDA_RECT item_boundingbox; EDA_RECT zone_boundingbox = aZone->GetBoundingBox(); - int biggest_clearance = aPcb->GetBiggestClearanceValue(); + int biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue(); biggest_clearance = std::max( biggest_clearance, zone_clearance ); zone_boundingbox.Inflate( biggest_clearance );