From ee66a3cd1df5f96d833bc0aa06eee9c82ae75182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Mon, 19 Jan 2015 19:35:05 +0100 Subject: [PATCH 01/23] common: added WX_UNIT_INPUT to CMakeLists --- common/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 05822f5e35..29154361df 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -204,6 +204,7 @@ set( COMMON_SRCS worksheet.cpp wxwineda.cpp wxunittext.cpp + wx_unit_input.cpp xnode.cpp zoom.cpp ) From f0c913c65e09824db57a3b1495a54990ea1c6a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:35:18 +0100 Subject: [PATCH 02/23] common: added WX_STATUS_POPUP and WX_UNIT_BINDER widget classes --- common/CMakeLists.txt | 4 +- common/wx_status_popup.cpp | 63 ++++++++++++++++++++++++++ common/wx_unit_binder.cpp | 73 ++++++++++++++++++++++++++++++ include/wx_status_popup.h | 58 ++++++++++++++++++++++++ include/wx_unit_binder.h | 91 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 common/wx_status_popup.cpp create mode 100644 common/wx_unit_binder.cpp create mode 100644 include/wx_status_popup.h create mode 100644 include/wx_unit_binder.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e7d11f5da1..509d99ba14 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -204,8 +204,8 @@ set( COMMON_SRCS wildcards_and_files_ext.cpp worksheet.cpp wxwineda.cpp - wxunittext.cpp - wx_unit_input.cpp + wx_unit_binder.cpp + wx_status_popup.cpp xnode.cpp zoom.cpp ) diff --git a/common/wx_status_popup.cpp b/common/wx_status_popup.cpp new file mode 100644 index 0000000000..5daa877def --- /dev/null +++ b/common/wx_status_popup.cpp @@ -0,0 +1,63 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2015 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 + */ + +/** + * Transient mouse following popup window implementation. + */ + +#include +#include + +WX_STATUS_POPUP::WX_STATUS_POPUP ( PCB_EDIT_FRAME *parent ) : + wxPopupWindow ( parent ) +{ + m_panel = new wxPanel( this, wxID_ANY ); + m_panel->SetBackgroundColour( *wxLIGHT_GREY ); + + m_topSizer = new wxBoxSizer( wxVERTICAL ); + m_panel->SetSizer( m_topSizer ); + +} + +void WX_STATUS_POPUP::updateSize() +{ + m_topSizer->Fit( m_panel ); + SetClientSize( m_panel->GetSize( ) ); +} + +WX_STATUS_POPUP::~WX_STATUS_POPUP() +{ +} + +void WX_STATUS_POPUP::Popup(wxWindow *focus) +{ + Show(true); + Raise(); +} + +void WX_STATUS_POPUP::Move( const wxPoint& aWhere ) +{ + SetPosition ( aWhere ); +} + \ No newline at end of file diff --git a/common/wx_unit_binder.cpp b/common/wx_unit_binder.cpp new file mode 100644 index 0000000000..14883d7cff --- /dev/null +++ b/common/wx_unit_binder.cpp @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2015 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 +#include +#include +#include +#include +#if wxCHECK_VERSION( 2, 9, 0 ) +#include +#endif + +#include + +#include "wx_unit_binder.h" + +WX_UNIT_BINDER::WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl *aTextInput, wxStaticText *aUnitLabel, wxSpinButton *aSpinButton ) +{ + // Use the currently selected units + m_units = g_UserUnit; + m_textCtrl = aTextInput; + m_textCtrl->SetValue ( wxT("0") ); + m_unitLabel = aUnitLabel; + m_unitLabel->SetLabel ( GetAbbreviatedUnitsLabel (m_units)); +} + + +WX_UNIT_BINDER::~WX_UNIT_BINDER() +{ +} + +void WX_UNIT_BINDER::SetValue( int aValue ) +{ + wxString s = StringFromValue( m_units, aValue, false ); + + m_textCtrl->SetValue ( s ); + + m_unitLabel->SetLabel ( GetAbbreviatedUnitsLabel (m_units)); +} + +int WX_UNIT_BINDER::GetValue() const +{ + wxString s = m_textCtrl->GetValue(); + + return ValueFromString( m_units, s ); +} + +void WX_UNIT_BINDER::Enable ( bool aEnable ) +{ + m_textCtrl->Enable ( aEnable ); + m_unitLabel->Enable ( aEnable ); +} diff --git a/include/wx_status_popup.h b/include/wx_status_popup.h new file mode 100644 index 0000000000..a050704006 --- /dev/null +++ b/include/wx_status_popup.h @@ -0,0 +1,58 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2015 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 __WX_STATUS_POPUP_H_ +#define __WX_STATUS_POPUP_H_ + + +#include +#include + +class PCB_EDIT_FRAME; + +/** + * Class WX_STATUS_POPUP + * + * A tiny, headerless popup window used to display useful status (e.g. line length + * tuning info) next to the mouse cursor. + */ + +class WX_STATUS_POPUP: public wxPopupWindow +{ +public: + WX_STATUS_POPUP ( PCB_EDIT_FRAME *parent ); + virtual ~WX_STATUS_POPUP(); + + virtual void Popup(wxWindow *focus = NULL); + virtual void Move( const wxPoint &aWhere ); + +protected: + + void updateSize(); + + wxPanel *m_panel; + wxBoxSizer *m_topSizer; +}; + +#endif /* __WX_STATUS_POPUP_H_*/ diff --git a/include/wx_unit_binder.h b/include/wx_unit_binder.h new file mode 100644 index 0000000000..34d092ee18 --- /dev/null +++ b/include/wx_unit_binder.h @@ -0,0 +1,91 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2015 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 __WX_UNIT_BINDER_H_ +#define __WX_UNIT_BINDER_H_ + +#include +#include + +class wxTextCtrl; +class wxSpinButton; +class wxStaticText; + +class WX_UNIT_BINDER +{ +public: + + /** + * Constructor. + * @param aParent is the parent window. + * @param aTextInput is the text input widget used to edit the given value. + * @param aUnitLabel is the units label displayed next to the text field. + * @param aSpinButton is an optional spin button (for adjusting the input value) + */ + WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl *aTextInput, wxStaticText *aUnitLabel, wxSpinButton *aSpinButton = NULL ); + + virtual ~WX_UNIT_BINDER(); + + /** + * Function SetValue + * Sets new value (in Internal Units) for the text field, taking care of units conversion. + * @param aValue is the new value. + */ + virtual void SetValue( int aValue ); + + /** + * Function GetValue + * Returns the current value in Internal Units. + */ + virtual int GetValue() const; + + /** + * Function Enable + * Enables/diasables the binded widgets + */ + void Enable ( bool aEnable ); + +protected: + + void onTextChanged ( wxEvent& aEvent ); + + ///> Text input control. + wxTextCtrl* m_textCtrl; + + ///> 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). + int m_step; + int m_min; + int m_max; + + ///> Default value (or non-specified) + static const wxString DEFAULT_VALUE; +}; + +#endif /* __WX_UNIT_BINDER_H_ */ From da8e9e9beeb2d7fc1345f7936dff99e5fb72102e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:36:27 +0100 Subject: [PATCH 03/23] added Remove() and CountTypes() methods in COLLECTOR class --- include/class_collector.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/class_collector.h b/include/class_collector.h index 294fa0b3d9..f8c90a6582 100644 --- a/include/class_collector.h +++ b/include/class_collector.h @@ -129,6 +129,23 @@ public: m_List.erase( m_List.begin() + aIndex ); } + /** + * Function Remove + * removes the item aItem (if exists in the collector). + * @param aItem the item to be removed. + */ + void Remove( const EDA_ITEM *aItem ) + { + for( size_t i = 0; i < m_List.size(); i++ ) + { + if( m_List[i] == aItem ) + { + m_List.erase( m_List.begin() + i); + return; + } + } + } + /** * Function operator[int] * is used for read only access and returns the object at \a aIndex. @@ -223,6 +240,23 @@ public: else return false; } + /** + * Function CountType + * counts the number of items matching aType + * @param aType type we are interested in + * @return number of occurences + */ + int CountType( KICAD_T aType ) + { + int cnt = 0; + for( size_t i = 0; i < m_List.size(); i++ ) + { + if( m_List[i]->Type() == aType ) + cnt++; + } + return cnt; + } + /** * Function Collect From c87b136522aa071a7e118214fbedd69a2ad08a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:40:11 +0100 Subject: [PATCH 04/23] geometry: new methods and fixes in SEG class --- common/geometry/seg.cpp | 2 ++ include/geometry/seg.h | 65 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/common/geometry/seg.cpp b/common/geometry/seg.cpp index daff746f98..8ec1565fb5 100644 --- a/common/geometry/seg.cpp +++ b/common/geometry/seg.cpp @@ -35,6 +35,7 @@ bool SEG::PointCloserThan( const VECTOR2I& aP, int aDist ) const { VECTOR2I d = B - A; ecoord dist_sq = (ecoord) aDist * aDist; + ecoord dist_sq_thr = (ecoord) (aDist + 1) * (aDist + 1); SEG::ecoord l_squared = d.Dot( d ); SEG::ecoord t = d.Dot( aP - A ); @@ -60,6 +61,7 @@ bool SEG::PointCloserThan( const VECTOR2I& aP, int aDist ) const if( num > ( dist_sq + 100 ) ) return false; + else if( num < ( dist_sq - 100 ) ) return true; } diff --git a/include/geometry/seg.h b/include/geometry/seg.h index 43ceec3b41..855271a512 100644 --- a/include/geometry/seg.h +++ b/include/geometry/seg.h @@ -206,6 +206,13 @@ public: return sqrt( SquaredDistance( aP ) ); } + void CanonicalCoefs ( ecoord& qA, ecoord& qB, ecoord& qC) const + { + qA = A.y - B.y; + qB = B.x - A.x; + qC = -qA * A.x - qB * A.y; + } + /** * Function Collinear() * @@ -215,16 +222,38 @@ 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 qa, qb, qc; + CanonicalCoefs ( qa, qb, qc ); + 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 ); } + bool ApproxCollinear( const SEG& aSeg ) const + { + ecoord p, q, r; + CanonicalCoefs ( p, q, r ); + + ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); + ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + + return std::abs(dist1) <= 1 && std::abs(dist2) <= 1; + } + + bool ApproxParallel ( const SEG& aSeg ) const + { + ecoord p, q, r; + CanonicalCoefs ( p, q, r ); + + ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); + ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + + return std::abs(dist1 - dist2) <= 1; + } + + bool Overlaps( const SEG& aSeg ) const { if( aSeg.A == aSeg.B ) // single point corner case @@ -262,6 +291,8 @@ public: return ( A - B ).SquaredEuclideanNorm(); } + ecoord TCoef ( const VECTOR2I& aP ) const; + /** * Function Index() * @@ -277,7 +308,11 @@ public: bool PointCloserThan( const VECTOR2I& aP, int aDist ) const; -// friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg ); + void Reverse() + { + std::swap ( A, B ); + } + private: bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const; @@ -288,9 +323,18 @@ private: inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const { - // fixme: numerical errors for large integers - assert( false ); - return VECTOR2I( 0, 0 ); + VECTOR2I d = B - A; + ecoord l_squared = d.Dot( d ); + + if( l_squared == 0 ) + return A; + + ecoord t = d.Dot( aP - A ); + + int xp = rescale( t, (ecoord)d.x, l_squared ); + int yp = rescale( t, (ecoord)d.y, l_squared ); + + return A + VECTOR2I( xp, yp ); } @@ -305,6 +349,11 @@ inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const return aDetermineSide ? dist : abs( dist ); } +inline SEG::ecoord SEG::TCoef ( const VECTOR2I& aP ) const +{ + VECTOR2I d = B - A; + return d.Dot ( aP - A); +} inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const { From 8a4bf35b5b2884d5ee2a4998b15d7a46d9caee29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:40:27 +0100 Subject: [PATCH 05/23] math: added OPT_BOX2 type --- include/math/box2.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/math/box2.h b/include/math/box2.h index 467558e676..5bf6ddd03c 100644 --- a/include/math/box2.h +++ b/include/math/box2.h @@ -30,6 +30,7 @@ #include #include +#include /** * Class BOX2 @@ -467,6 +468,8 @@ public: typedef BOX2 BOX2I; typedef BOX2 BOX2D; +typedef boost::optional OPT_BOX2I; + // FIXME should be removed to avoid multiple typedefs for the same type typedef BOX2D DBOX; From 8bd9dd49bb86df7bbcab26f44a766d50675924a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:43:02 +0100 Subject: [PATCH 06/23] view: added quick hiding mechanism in VIEW/VIEW_ITEM --- common/view/view.cpp | 2 +- common/view/view_item.cpp | 11 -------- include/view/view_item.h | 58 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/common/view/view.cpp b/common/view/view.cpp index 981c8b0d31..2186c87264 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -564,7 +564,7 @@ struct VIEW::drawItem bool operator()( VIEW_ITEM* aItem ) { // Conditions that have te be fulfilled for an item to be drawn - bool drawCondition = aItem->ViewIsVisible() && + bool drawCondition = aItem->isRenderable() && aItem->ViewGetLOD( layer ) < view->m_scale; if( !drawCondition ) return true; diff --git a/common/view/view_item.cpp b/common/view/view_item.cpp index 900e030e61..f1713f3f0f 100644 --- a/common/view/view_item.cpp +++ b/common/view/view_item.cpp @@ -29,17 +29,6 @@ using namespace KIGFX; -void VIEW_ITEM::ViewSetVisible( bool aIsVisible ) -{ - // update only if the visibility has really changed - if( m_visible != aIsVisible ) - { - m_visible = aIsVisible; - ViewUpdate( APPEARANCE ); - } -} - - void VIEW_ITEM::ViewRelease() { if( m_view && m_view->IsDynamic() ) diff --git a/include/view/view_item.h b/include/view/view_item.h index b2fc558f94..be28c9230f 100644 --- a/include/view/view_item.h +++ b/include/view/view_item.h @@ -76,7 +76,17 @@ public: ALL = 0xff }; - VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_requiredUpdate( ALL ), + /** + * Enum VIEW_VISIBILITY_FLAGS. + * Defines the visibility of the item (temporarily hidden, invisible, etc). + */ + enum VIEW_VISIBILITY_FLAGS { + VISIBLE = 0x01, /// Item is visible (in general) + HIDDEN = 0x02 /// Item is temporarily hidden (e.g. being used by a tool). Overrides VISIBLE flag. + }; + + + VIEW_ITEM() : m_view( NULL ), m_flags( VISIBLE ), m_requiredUpdate( ALL ), m_groups( NULL ), m_groupsSize( 0 ) {} /** @@ -128,7 +138,38 @@ public: * * @param aIsVisible: whether the item is visible (on all layers), or not. */ - void ViewSetVisible( bool aIsVisible = true ); + void ViewSetVisible( bool aIsVisible = true ) + { + bool cur_visible = m_flags & VISIBLE; + + if( cur_visible != aIsVisible ) + { + if(aIsVisible) + m_flags |= VISIBLE; + else + m_flags &= ~VISIBLE; + ViewUpdate( APPEARANCE | COLOR ); + } + } + + /** + * Function ViewHide() + * Temporarily hides the item in the view (e.g. for overlaying) + * + * @param aHide: whether the item is hidden (on all layers), or not. + */ + void ViewHide ( bool aHide = true ) + { + if(! (m_flags & VISIBLE) ) + return; + + if(aHide) + m_flags |= HIDDEN; + else + m_flags &= ~HIDDEN; + + ViewUpdate( APPEARANCE ); + } /** * Function ViewIsVisible() @@ -139,7 +180,7 @@ public: */ bool ViewIsVisible() const { - return m_visible; + return m_flags & VISIBLE; } /** @@ -201,7 +242,7 @@ protected: } VIEW* m_view; ///< Current dynamic view the item is assigned to. - bool m_visible; ///< Are we visible in the current dynamic VIEW. + int m_flags; ///< Visibility flags int m_requiredUpdate; ///< Flag required for updating ///* Helper for storing cached items group ids @@ -295,6 +336,15 @@ protected: { m_requiredUpdate = NONE; } + + /** + * Function isRenderable() + * Returns if the item should be drawn or not. + */ + bool isRenderable() const + { + return m_flags == VISIBLE; + } }; } // namespace KIGFX From aaf1b634d7fb73f8c2912569bf464cf33d4df92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:44:23 +0100 Subject: [PATCH 07/23] base_struct.h: added DP_COUPLED flag --- include/base_struct.h | 3 +++ include/wxBasePcbFrame.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/include/base_struct.h b/include/base_struct.h index 18283dbac4..84500d2cca 100644 --- a/include/base_struct.h +++ b/include/base_struct.h @@ -146,6 +146,9 @@ public: #define HIGHLIGHTED (1 << 25) ///< item is drawn in normal colors, when the rest is darkened #define BRIGHTENED (1 << 26) ///< item is drawn with a bright contour +#define DP_COUPLED (1 << 27) ///< item is coupled with another item making a differential pair + ///< (applies to segments only) + #define EDA_ITEM_ALL_FLAGS -1 typedef unsigned STATUS_FLAGS; diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index 5f0bf6e7a0..5f07ca30ce 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -657,6 +657,8 @@ public: */ void SetFastGrid2(); + void ClearSelection(); + DECLARE_EVENT_TABLE() }; From 83ffb8969f5908be0c62203533cd8844472a6d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:45:29 +0100 Subject: [PATCH 08/23] gal: minor comment fix --- include/gal/opengl/vertex_item.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gal/opengl/vertex_item.h b/include/gal/opengl/vertex_item.h index 3b56e35a05..1905b9511e 100644 --- a/include/gal/opengl/vertex_item.h +++ b/include/gal/opengl/vertex_item.h @@ -50,7 +50,7 @@ public: /** * Function GetSize() * Returns information about number of vertices stored. - * @return Number of vertices. + * @param Number of vertices. */ inline unsigned int GetSize() const { @@ -69,7 +69,7 @@ public: /** * Function GetVertices() - * areturn a pointer to the data used by the VERTEX_ITEM. + * Returns pointer to the data used by the VERTEX_ITEM. */ VERTEX* GetVertices() const; From a3cf29488199ac965c8af7e395ae3e821d0b7dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:50:28 +0100 Subject: [PATCH 09/23] bitmaps: added diff pair/length matching dialog images --- bitmaps_png/CMakeLists.txt | 11 + .../tune_diff_pair_length_legend.cpp | 871 ++++++++++++++++++ .../cpp_other/tune_diff_pair_skew_legend.cpp | 362 ++++++++ .../tune_single_track_length_legend.cpp | 655 +++++++++++++ .../sources/tune_diff_pair_length_legend.png | Bin 0 -> 13724 bytes .../sources/tune_diff_pair_skew_legend.png | Bin 0 -> 5576 bytes .../tune_single_track_length_legend.png | Bin 0 -> 10264 bytes include/bitmaps.h | 3 + 8 files changed, 1902 insertions(+) create mode 100644 bitmaps_png/cpp_other/tune_diff_pair_length_legend.cpp create mode 100644 bitmaps_png/cpp_other/tune_diff_pair_skew_legend.cpp create mode 100644 bitmaps_png/cpp_other/tune_single_track_length_legend.cpp create mode 100644 bitmaps_png/sources/tune_diff_pair_length_legend.png create mode 100644 bitmaps_png/sources/tune_diff_pair_skew_legend.png create mode 100644 bitmaps_png/sources/tune_single_track_length_legend.png diff --git a/bitmaps_png/CMakeLists.txt b/bitmaps_png/CMakeLists.txt index 322836ed2f..2da6321b60 100644 --- a/bitmaps_png/CMakeLists.txt +++ b/bitmaps_png/CMakeLists.txt @@ -555,6 +555,12 @@ set( BMAPS_BIG wizard_add_fplib_icon ) +set( BMAPS_OTHER + tune_diff_pair_length_legend + tune_diff_pair_skew_legend + tune_single_track_length_legend + ) + # @todo keep these in sync with .bzrignore set( TMP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tmp" ) @@ -728,5 +734,10 @@ foreach( bmn ${BMAPS_BIG} ) list( APPEND CPP_LIST cpp_48/${bmn}.cpp ) endforeach() +foreach( bmn ${BMAPS_OTHER} ) + #message( "library add cpp_other/${bmn}.cpp" ) + list( APPEND CPP_LIST cpp_other/${bmn}.cpp ) +endforeach() + #add_library( bitmaps SHARED ${CPP_LIST} ) add_library( bitmaps STATIC ${CPP_LIST} ) diff --git a/bitmaps_png/cpp_other/tune_diff_pair_length_legend.cpp b/bitmaps_png/cpp_other/tune_diff_pair_length_legend.cpp new file mode 100644 index 0000000000..58dee697ba --- /dev/null +++ b/bitmaps_png/cpp_other/tune_diff_pair_length_legend.cpp @@ -0,0 +1,871 @@ + +/* Do not modify this file, it was automatically generated by the + * PNG2cpp CMake script, using a *.png file as input. + */ + +#include + +static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xbd, 0x08, 0x02, 0x00, 0x00, 0x01, 0x62, 0xd4, 0xc7, + 0x28, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x1e, 0xc2, 0x00, 0x00, 0x1e, + 0xc2, 0x01, 0x6e, 0xd0, 0x75, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x89, 0x2a, 0x8d, 0x06, 0x00, 0x00, 0x20, 0x00, 0x49, + 0x44, 0x41, 0x54, 0x78, 0x9c, 0xec, 0x5d, 0x89, 0x5f, 0x13, 0x47, 0xdf, 0xf7, 0xbf, 0x78, 0x9f, + 0xb7, 0x87, 0x56, 0x6b, 0xa5, 0x9e, 0xd5, 0x5a, 0xab, 0x4f, 0xb5, 0x6a, 0xd5, 0xbe, 0xad, 0x3e, + 0x56, 0xad, 0xad, 0x55, 0x6b, 0xb5, 0x7d, 0xb4, 0x15, 0x10, 0xf0, 0x40, 0x0e, 0x45, 0xee, 0x53, + 0xb9, 0x54, 0x3c, 0x50, 0xf1, 0x00, 0xc5, 0x03, 0x39, 0xaa, 0x56, 0x2e, 0x41, 0x45, 0x2b, 0x2a, + 0x2a, 0xa2, 0x45, 0x41, 0x39, 0xc2, 0x4d, 0x20, 0x1c, 0xe1, 0x0a, 0x10, 0x92, 0x90, 0x77, 0xc2, + 0x84, 0xc9, 0x64, 0xef, 0xdd, 0x84, 0x24, 0x46, 0xbe, 0x9f, 0xf9, 0x2c, 0xcb, 0xec, 0xec, 0x6f, + 0xbe, 0xfb, 0xcd, 0xec, 0xec, 0xdc, 0x33, 0x42, 0x6d, 0x0c, 0x54, 0x36, 0xc9, 0xe8, 0x2e, 0x8d, + 0x80, 0x7f, 0x9a, 0x9b, 0x9b, 0x04, 0xd8, 0xf5, 0x89, 0x7b, 0xba, 0xd9, 0xe3, 0xaf, 0x47, 0x65, + 0xad, 0x5d, 0xbd, 0x0a, 0x70, 0x02, 0x1c, 0x6d, 0x04, 0x02, 0x10, 0x79, 0xf5, 0xd5, 0x9e, 0x73, + 0xff, 0x10, 0x3c, 0xc9, 0x71, 0x08, 0x8f, 0x00, 0xda, 0x2a, 0xf9, 0xe8, 0xfd, 0xca, 0x65, 0xdf, + 0x34, 0x1f, 0x3f, 0x04, 0x4e, 0xc0, 0xbf, 0xee, 0x31, 0x8f, 0x8d, 0x16, 0x81, 0x63, 0x58, 0x0e, + 0x8c, 0x00, 0x1c, 0x3b, 0x3a, 0x3a, 0xfa, 0x15, 0x0a, 0x69, 0x72, 0x02, 0x38, 0x77, 0x39, 0x94, + 0x6b, 0x9c, 0x08, 0xbc, 0xe3, 0x0a, 0xc0, 0xb1, 0x6a, 0xf5, 0x0a, 0xe4, 0xd3, 0x18, 0xe2, 0x07, + 0x8e, 0xf6, 0x81, 0x59, 0xb4, 0x11, 0xf4, 0xf7, 0xf7, 0x73, 0x8f, 0xc0, 0x4b, 0x40, 0x04, 0x32, + 0x99, 0x36, 0xb5, 0x25, 0x27, 0x5e, 0xae, 0xad, 0xad, 0x61, 0x8e, 0xc0, 0x3b, 0xee, 0xe9, 0x40, + 0x04, 0xcb, 0x79, 0x44, 0xc0, 0x0b, 0x14, 0x11, 0xec, 0x1d, 0xb2, 0x08, 0xe6, 0xcd, 0x9e, 0x65, + 0xfc, 0x08, 0xbc, 0x60, 0x04, 0x3f, 0x2d, 0x1f, 0xf5, 0xce, 0xff, 0x00, 0x07, 0xce, 0x2b, 0x16, + 0x7f, 0xa5, 0x26, 0xbd, 0x0a, 0x9a, 0x08, 0x36, 0xfd, 0xba, 0x1e, 0x86, 0x80, 0xb0, 0xf3, 0xcd, + 0x80, 0x6e, 0x4b, 0x60, 0x56, 0x5e, 0x69, 0x2b, 0x6b, 0x04, 0xe0, 0x08, 0x6f, 0x87, 0x49, 0x36, + 0xf0, 0xc2, 0x73, 0x10, 0x87, 0xad, 0x57, 0x9a, 0xad, 0x77, 0x9a, 0x6b, 0xf4, 0x43, 0x96, 0x27, + 0x60, 0xc8, 0x03, 0xbc, 0x62, 0x61, 0x04, 0xcb, 0xc0, 0x31, 0x24, 0xd0, 0x1f, 0x1c, 0x95, 0xb2, + 0xae, 0xf2, 0x59, 0x53, 0x09, 0xc1, 0xb4, 0x11, 0xd8, 0xfe, 0xbe, 0x11, 0x79, 0xd5, 0xbb, 0x38, + 0xd5, 0xbb, 0x6c, 0xad, 0x77, 0xdd, 0xd6, 0x18, 0xe2, 0x8b, 0x3c, 0xc9, 0x71, 0xe0, 0x11, 0x20, + 0x28, 0x9a, 0x9b, 0xc0, 0x73, 0x94, 0xcf, 0xf9, 0xac, 0xc1, 0x67, 0x97, 0xd8, 0xdb, 0xbd, 0x21, + 0xc0, 0x93, 0xe5, 0x09, 0x6a, 0xfe, 0xfb, 0x33, 0x7c, 0x70, 0x4d, 0x1c, 0x9e, 0xa9, 0xac, 0x11, + 0x90, 0xc1, 0xe9, 0x47, 0x86, 0x71, 0x10, 0x1e, 0xc2, 0x98, 0x11, 0x88, 0xbe, 0xfa, 0x37, 0x38, + 0xb6, 0x74, 0xca, 0xab, 0x9b, 0xbb, 0x87, 0x24, 0x02, 0x80, 0xe6, 0xe3, 0x87, 0xc1, 0xd1, 0xe5, + 0xf0, 0x7d, 0x62, 0x04, 0xab, 0xbe, 0x13, 0x12, 0xc1, 0x94, 0x09, 0x36, 0x04, 0x1f, 0x49, 0x78, + 0x30, 0x38, 0x3a, 0xee, 0xbb, 0x6d, 0x9c, 0x08, 0xc8, 0x90, 0x84, 0x07, 0x81, 0xa3, 0x03, 0x39, + 0x02, 0x63, 0x49, 0x44, 0xf8, 0x9d, 0xe1, 0x09, 0xc8, 0x7d, 0xbb, 0x72, 0xef, 0x18, 0x33, 0x02, + 0x68, 0x1a, 0xb8, 0x6b, 0x4f, 0xc4, 0xb8, 0x27, 0x7b, 0x04, 0x78, 0x56, 0xc1, 0x1a, 0x07, 0xfa, + 0x57, 0x2e, 0x2a, 0x63, 0x8f, 0xa0, 0x42, 0x24, 0x4a, 0x4f, 0x4b, 0xe3, 0xe8, 0x92, 0x76, 0x6e, + 0x4b, 0xdc, 0xe1, 0x04, 0x1c, 0x17, 0xee, 0x7a, 0x4f, 0x60, 0x08, 0x8a, 0xeb, 0x3a, 0x98, 0xac, + 0x73, 0x11, 0x87, 0x12, 0xe0, 0x97, 0xd8, 0x1a, 0x79, 0x47, 0xd5, 0xdf, 0x7f, 0x24, 0xad, 0x14, + 0x9c, 0x93, 0x3f, 0xb7, 0x86, 0x16, 0x58, 0x98, 0x7d, 0x04, 0x5a, 0x0f, 0x4a, 0x2a, 0x82, 0x27, + 0xe0, 0x37, 0xe8, 0xca, 0xcb, 0x05, 0xc7, 0x96, 0x53, 0xd1, 0xe4, 0x08, 0x04, 0x5a, 0x47, 0x25, + 0x2d, 0x70, 0xf4, 0xf5, 0xf2, 0x54, 0xd3, 0x64, 0x82, 0x46, 0xb0, 0x0e, 0x31, 0x54, 0xd6, 0xe1, + 0xc7, 0x8b, 0xc5, 0xfa, 0x98, 0xf7, 0xdf, 0xf9, 0x71, 0x05, 0x4b, 0x26, 0x45, 0x69, 0x1d, 0xe2, + 0xcd, 0x54, 0x66, 0xc8, 0xad, 0xcf, 0x9e, 0xf9, 0x19, 0xad, 0x75, 0xca, 0x32, 0x0f, 0x70, 0xbe, + 0xf1, 0xcf, 0xb8, 0x58, 0x5f, 0xb7, 0xe6, 0x27, 0x70, 0x94, 0x26, 0xc4, 0x2b, 0x7b, 0xba, 0xe1, + 0x25, 0xf0, 0xf5, 0x07, 0x65, 0x1e, 0xe0, 0x34, 0xd6, 0xb3, 0xb3, 0x6e, 0xd0, 0x59, 0xd9, 0x7d, + 0xea, 0x09, 0x65, 0x81, 0x87, 0xac, 0x0c, 0xf9, 0x5f, 0x0a, 0xee, 0xf5, 0x3b, 0x1d, 0x35, 0x05, + 0x1e, 0x57, 0x4d, 0x81, 0xa7, 0xfb, 0x59, 0x3e, 0x6e, 0x8b, 0xd5, 0x3a, 0xf4, 0x01, 0xae, 0xde, + 0x7d, 0x07, 0x2c, 0xf0, 0x30, 0xe9, 0xae, 0xea, 0xed, 0x05, 0x41, 0x3b, 0x6f, 0x67, 0x91, 0x23, + 0xa0, 0xb3, 0x4e, 0xc1, 0x9d, 0x19, 0xba, 0xcf, 0xd3, 0x9e, 0xeb, 0xc6, 0xb7, 0xae, 0xa6, 0x4a, + 0x6d, 0x42, 0xac, 0x47, 0x1f, 0x39, 0x3c, 0x54, 0xd6, 0xed, 0xff, 0xd8, 0x84, 0xce, 0x93, 0x93, + 0x12, 0x8d, 0xcf, 0x9d, 0x0e, 0xa6, 0xb0, 0x1e, 0x98, 0x58, 0x94, 0x74, 0xbf, 0xc6, 0xf8, 0xd6, + 0x01, 0xca, 0x66, 0x4c, 0x01, 0x47, 0xb7, 0xa8, 0x7b, 0x78, 0x85, 0xa2, 0x8c, 0x54, 0x5f, 0xa0, + 0xb0, 0xce, 0xb1, 0x48, 0x53, 0xbd, 0x76, 0x25, 0xfa, 0x57, 0xd9, 0xd9, 0xc1, 0xa9, 0xcc, 0xc4, + 0xbd, 0x3c, 0x93, 0x9e, 0x7a, 0x1d, 0x95, 0x67, 0x24, 0x61, 0x81, 0xac, 0xa6, 0x35, 0xd6, 0x8b, + 0x8b, 0x8a, 0xfe, 0x4c, 0x49, 0x36, 0x97, 0x0b, 0x8d, 0x8c, 0x81, 0x0e, 0x0a, 0x0e, 0x9d, 0xff, + 0xc5, 0x42, 0x2e, 0xd4, 0xd5, 0xf8, 0xef, 0x8a, 0xaa, 0xa8, 0x26, 0x80, 0x83, 0x77, 0x2a, 0x60, + 0xe9, 0x10, 0x92, 0x4d, 0x79, 0x55, 0xa9, 0xea, 0x87, 0x8f, 0x91, 0x2f, 0x92, 0x32, 0xdb, 0x31, + 0x42, 0x59, 0x92, 0x2f, 0x08, 0x15, 0x65, 0xd1, 0xc2, 0x39, 0x30, 0xef, 0x86, 0xae, 0xed, 0x5a, + 0x32, 0x1e, 0x12, 0x7c, 0x86, 0x18, 0x4c, 0x99, 0x9a, 0x3d, 0x4e, 0xbd, 0xc1, 0xdf, 0x13, 0xd0, + 0x45, 0x5f, 0x2a, 0x08, 0xf8, 0x0c, 0x78, 0xf8, 0x33, 0x37, 0x2b, 0xe8, 0xac, 0x99, 0x81, 0x3d, + 0x6c, 0xd2, 0x52, 0x0f, 0x10, 0x85, 0x6d, 0x1e, 0x6a, 0xfd, 0x7c, 0x03, 0xf8, 0x37, 0xee, 0xf5, + 0x47, 0xe1, 0xb7, 0xe8, 0xb7, 0xe3, 0xe0, 0xa0, 0x65, 0x9f, 0x92, 0x9c, 0x48, 0x77, 0xc9, 0x10, + 0x10, 0xd9, 0x0f, 0x36, 0xcb, 0x01, 0xf6, 0xa8, 0xa1, 0x4d, 0xc3, 0x7e, 0xa0, 0x05, 0x0d, 0x86, + 0xb7, 0xe7, 0xcb, 0x7e, 0xb7, 0x9b, 0x0b, 0x38, 0x7e, 0x32, 0xf1, 0x63, 0x63, 0x91, 0x46, 0xa0, + 0x63, 0x0f, 0x0b, 0xd5, 0xc8, 0xdf, 0x20, 0xf6, 0x08, 0xf9, 0x4f, 0xb4, 0xcd, 0xb8, 0xaf, 0x5f, + 0x15, 0x6f, 0x77, 0x72, 0xb0, 0x19, 0x33, 0x6a, 0xab, 0x83, 0xbd, 0x60, 0xea, 0x90, 0x0d, 0x6c, + 0xe9, 0x53, 0x6b, 0xd9, 0x2f, 0x27, 0x87, 0x19, 0x48, 0x39, 0xc6, 0x60, 0x6f, 0x74, 0x58, 0x17, + 0x7b, 0xac, 0x29, 0x14, 0x9e, 0x44, 0x1d, 0x88, 0x04, 0xfe, 0x0d, 0xfe, 0x7b, 0x50, 0x78, 0x7b, + 0xff, 0x4c, 0x3a, 0x6b, 0x66, 0xc9, 0x73, 0xf4, 0xd8, 0x93, 0xc3, 0xe0, 0x99, 0x66, 0x73, 0x87, + 0x1c, 0xdc, 0x62, 0xe7, 0x43, 0x9d, 0xeb, 0xeb, 0x7d, 0x6b, 0x3f, 0x78, 0xf7, 0x5f, 0x94, 0xf1, + 0xb1, 0x3a, 0xbc, 0x65, 0x50, 0x18, 0x7b, 0x10, 0x7b, 0xfc, 0xd9, 0x38, 0xca, 0x07, 0x00, 0x68, + 0xed, 0x92, 0x83, 0xcf, 0x16, 0x21, 0x52, 0xd7, 0x23, 0x0f, 0x74, 0xec, 0x55, 0x2a, 0x15, 0x47, + 0x06, 0x64, 0x04, 0x5e, 0x2a, 0xa4, 0x6b, 0x6a, 0xa6, 0x60, 0x1f, 0x8b, 0xb3, 0xa7, 0x6d, 0xdb, + 0x6b, 0x39, 0x73, 0x02, 0x3e, 0x43, 0xcf, 0xeb, 0x62, 0xba, 0x30, 0x5a, 0xf6, 0x4f, 0x1e, 0x3f, + 0xa2, 0x2b, 0xe7, 0xe0, 0x9f, 0x71, 0xb2, 0x2b, 0x9d, 0x34, 0x16, 0x85, 0x54, 0x28, 0x55, 0xac, + 0xcf, 0xc0, 0x9d, 0x3d, 0x82, 0x34, 0xf1, 0x42, 0xc9, 0xb8, 0x91, 0xe4, 0xa8, 0xab, 0x7f, 0x59, + 0x65, 0x84, 0x74, 0xaf, 0x55, 0xa8, 0xf8, 0x05, 0xfc, 0xd7, 0x23, 0xee, 0x19, 0xc3, 0x03, 0x08, + 0x60, 0xcf, 0x00, 0xa3, 0xbd, 0xb5, 0x80, 0x8a, 0x68, 0xd1, 0x1c, 0x78, 0xbe, 0xed, 0xe0, 0x3d, + 0xba, 0x07, 0x30, 0x11, 0xfb, 0x2f, 0x3e, 0x9f, 0xce, 0xcb, 0x90, 0xa2, 0xa5, 0x19, 0xb0, 0x51, + 0x48, 0x1a, 0xe1, 0xbf, 0x80, 0x65, 0x40, 0x62, 0x11, 0x39, 0x18, 0x91, 0x3d, 0x5b, 0xa3, 0x39, + 0x33, 0xa8, 0xd9, 0x8f, 0x1b, 0x3d, 0x72, 0xc3, 0xba, 0x35, 0xf0, 0x35, 0x58, 0x30, 0x77, 0xf6, + 0x57, 0x5f, 0x7e, 0xa1, 0x1e, 0x68, 0xc8, 0x1f, 0x3f, 0x76, 0x0c, 0x83, 0x2d, 0x4d, 0x9d, 0x28, + 0x22, 0x18, 0xb1, 0x74, 0x0c, 0xbd, 0x4d, 0x0e, 0x63, 0x0a, 0xf6, 0xc2, 0xa0, 0x61, 0x1f, 0xae, + 0x63, 0x8f, 0xf7, 0x1e, 0x20, 0x58, 0x34, 0xfb, 0x7a, 0x67, 0x47, 0x78, 0x4e, 0x97, 0xf9, 0x00, + 0xcf, 0x88, 0x6b, 0x25, 0x28, 0xbc, 0xd8, 0x63, 0xa7, 0x21, 0x31, 0x1a, 0x93, 0xbd, 0x78, 0x8f, + 0x2b, 0xa1, 0x62, 0xa1, 0xf9, 0x4c, 0xfa, 0x65, 0x9c, 0xb9, 0x29, 0x0a, 0x4c, 0x2c, 0x82, 0xff, + 0x1e, 0xbc, 0xae, 0xa5, 0x5e, 0xb9, 0xe2, 0x5b, 0xee, 0xbd, 0x09, 0x74, 0x30, 0x72, 0x49, 0xa1, + 0x31, 0xd0, 0x1b, 0xaf, 0x5b, 0xd0, 0x81, 0xf0, 0x29, 0x15, 0x0c, 0xbd, 0x92, 0x42, 0x79, 0x39, + 0x7b, 0xaf, 0x0d, 0x17, 0x80, 0xef, 0x08, 0xe4, 0x57, 0xf3, 0xdb, 0xda, 0xee, 0xc2, 0xe7, 0xea, + 0x81, 0xa6, 0xc4, 0xe6, 0x13, 0x87, 0xd1, 0x87, 0xc6, 0x28, 0xb1, 0xa8, 0x4d, 0x50, 0x4a, 0xeb, + 0xef, 0x93, 0xf7, 0x96, 0xbc, 0xea, 0xab, 0xab, 0x1d, 0x0a, 0xe3, 0x66, 0x68, 0x53, 0x20, 0x43, + 0x2c, 0xed, 0x79, 0x51, 0xd3, 0x01, 0x0a, 0x1a, 0xbc, 0xee, 0x1a, 0x81, 0x5a, 0x85, 0x2e, 0x5d, + 0xbc, 0x60, 0xe2, 0x76, 0xa8, 0xa8, 0x98, 0x78, 0xd8, 0x0e, 0xe5, 0xe0, 0xf9, 0xa7, 0x80, 0xe2, + 0xaa, 0x5e, 0x8a, 0xe7, 0xa7, 0x95, 0x61, 0x40, 0x44, 0x83, 0x12, 0x8b, 0x3a, 0x7a, 0x14, 0xfd, + 0xfd, 0xfd, 0xaf, 0xea, 0x3a, 0xdc, 0x8e, 0xe5, 0x41, 0x4f, 0x07, 0xbf, 0x74, 0x56, 0x0b, 0xba, + 0x2e, 0x59, 0xe0, 0x40, 0x01, 0x73, 0x88, 0x09, 0x6b, 0x01, 0xf9, 0x3d, 0x2e, 0xa3, 0x1e, 0x1a, + 0xb2, 0xfb, 0xe4, 0x13, 0x2e, 0xc5, 0x6c, 0x9d, 0xea, 0xf7, 0xef, 0xdd, 0x33, 0x26, 0x3b, 0x7a, + 0x40, 0x5a, 0xbd, 0x7d, 0x4c, 0x29, 0x7b, 0xdf, 0x95, 0xd7, 0x20, 0xcc, 0xae, 0xa3, 0xf7, 0x19, + 0xc2, 0x98, 0x9a, 0x3a, 0x1c, 0x30, 0x87, 0xfe, 0xed, 0xba, 0xff, 0x37, 0x5e, 0x46, 0x2f, 0x9b, + 0x31, 0x19, 0x5d, 0xda, 0xbe, 0xff, 0x2e, 0xb3, 0xf0, 0xa6, 0xa6, 0x3e, 0xf0, 0xad, 0xd5, 0xd6, + 0xa9, 0xdb, 0x52, 0x12, 0x20, 0xe3, 0xa6, 0xc3, 0x91, 0x5d, 0x0f, 0xfe, 0x46, 0xdf, 0x04, 0x3c, + 0xb0, 0xd3, 0xbe, 0x5b, 0x74, 0xa6, 0x4c, 0x4a, 0x5d, 0xda, 0xd5, 0x07, 0xd8, 0x14, 0xd5, 0x6a, + 0x3b, 0xfb, 0x09, 0x44, 0xdb, 0xa4, 0x52, 0x65, 0x7b, 0xdb, 0x40, 0xaf, 0xd9, 0x76, 0xe8, 0x03, + 0xab, 0xad, 0x74, 0xd6, 0x4c, 0x4a, 0x7d, 0xdf, 0x95, 0x57, 0x88, 0x4a, 0xf7, 0xd3, 0xc7, 0x80, + 0xa5, 0xaa, 0x5b, 0x33, 0xb4, 0xae, 0xb7, 0xa7, 0x47, 0x22, 0x91, 0x40, 0x7f, 0xfc, 0x79, 0x02, + 0x2e, 0xbf, 0xb4, 0x14, 0xea, 0x7e, 0x17, 0x0b, 0x11, 0x15, 0xc9, 0xfe, 0x7d, 0x88, 0xa2, 0x97, + 0xc7, 0xae, 0x0f, 0x47, 0xbe, 0x0b, 0xcf, 0xeb, 0xb6, 0xd9, 0x21, 0xff, 0xe3, 0x37, 0xca, 0x2d, + 0x93, 0xfa, 0x5e, 0xca, 0x22, 0x4d, 0xdd, 0xf6, 0x2d, 0xc8, 0xff, 0x84, 0xe5, 0x53, 0x3f, 0x7a, + 0x28, 0xaa, 0xb5, 0xa5, 0x05, 0x9e, 0x1b, 0x4a, 0x1d, 0xfc, 0x7c, 0x43, 0xf1, 0x71, 0x65, 0xa0, + 0x8e, 0xc2, 0x18, 0x4a, 0x3d, 0x74, 0x6f, 0xf0, 0xdd, 0x9c, 0x1c, 0x23, 0x92, 0x86, 0xe0, 0x46, + 0xdd, 0x5e, 0x38, 0xf5, 0xaa, 0xca, 0x4a, 0xd9, 0x00, 0xf6, 0xec, 0x72, 0x73, 0x77, 0x71, 0xfe, + 0x61, 0xf9, 0xd2, 0x69, 0x93, 0x27, 0x28, 0x14, 0x8a, 0x98, 0xe3, 0xd1, 0xe0, 0x64, 0x28, 0xa8, + 0xe3, 0x30, 0x88, 0x3a, 0x4a, 0x2a, 0xe0, 0x64, 0x7f, 0x78, 0xd8, 0xfa, 0x9f, 0x57, 0x03, 0xc6, + 0x53, 0x27, 0x8d, 0x77, 0xb0, 0xdb, 0x0c, 0x3c, 0x95, 0x4a, 0xa5, 0xe5, 0x52, 0x1f, 0x3a, 0xd0, + 0x65, 0x8e, 0x38, 0x86, 0xa9, 0x1b, 0x1b, 0x74, 0xd4, 0x9d, 0xb7, 0x3a, 0xa9, 0x07, 0x47, 0xc5, + 0xeb, 0x51, 0xcf, 0xb2, 0x60, 0xea, 0x79, 0x0f, 0x1f, 0x10, 0xba, 0x40, 0xc4, 0x1e, 0x3b, 0x11, + 0xf5, 0xf8, 0xbb, 0x55, 0x96, 0x4b, 0x1d, 0x9c, 0x38, 0xda, 0xdb, 0x22, 0xea, 0x40, 0xf8, 0xa6, + 0xa8, 0x70, 0x42, 0xe1, 0x31, 0xf4, 0xca, 0x2b, 0x4a, 0x6b, 0xe6, 0xa7, 0x4e, 0x80, 0x76, 0x1c, + 0xd5, 0x4d, 0x6d, 0xc1, 0x18, 0xd6, 0x4b, 0xe4, 0x0a, 0x8a, 0x7a, 0x89, 0x5e, 0x05, 0x8f, 0xfc, + 0x05, 0x05, 0xb5, 0x74, 0x7c, 0xe4, 0x9a, 0xd6, 0xf9, 0x65, 0x80, 0x7a, 0x00, 0x9d, 0x18, 0x02, + 0xa8, 0x4f, 0x9f, 0x32, 0xc9, 0xd5, 0x79, 0x3b, 0x0a, 0x46, 0x2e, 0xb5, 0x43, 0xa7, 0x19, 0xf2, + 0x3f, 0x30, 0xea, 0x5f, 0x37, 0x08, 0x0e, 0x60, 0x7f, 0x44, 0x18, 0xe5, 0x97, 0x5f, 0xa1, 0xec, + 0x67, 0xed, 0x6f, 0x0a, 0xbe, 0x44, 0x9c, 0xc8, 0xc3, 0x97, 0xfa, 0x36, 0xc7, 0x2d, 0x63, 0x47, + 0xbd, 0x87, 0x82, 0x35, 0x1f, 0x3d, 0x00, 0x2e, 0xb5, 0x9e, 0xd7, 0xf5, 0x40, 0x85, 0x24, 0x14, + 0x92, 0xe3, 0xd5, 0x25, 0x98, 0xf1, 0x63, 0x47, 0x73, 0x64, 0x80, 0x70, 0x7e, 0xe0, 0x35, 0x82, + 0xee, 0x6a, 0x1e, 0x7b, 0x3b, 0x11, 0x1d, 0x75, 0xa8, 0x9a, 0xdb, 0xce, 0x1d, 0x28, 0x24, 0x14, + 0x5e, 0x56, 0xf0, 0x84, 0xc1, 0x9a, 0x8e, 0xba, 0x87, 0xbb, 0x2b, 0x5f, 0xea, 0x10, 0xdd, 0x72, + 0x25, 0x64, 0xef, 0x1c, 0xc9, 0x32, 0xe4, 0xdc, 0x9f, 0x43, 0x5a, 0x47, 0xd0, 0x36, 0x00, 0x6e, + 0xfa, 0x85, 0x2e, 0x80, 0x6e, 0x52, 0x19, 0x65, 0x82, 0x01, 0xb5, 0x98, 0x81, 0x79, 0x1d, 0x4e, + 0x68, 0xb0, 0x23, 0x70, 0x62, 0x4f, 0xd7, 0xe6, 0xe8, 0x83, 0x84, 0x90, 0xee, 0x31, 0x8f, 0x35, + 0xf5, 0x4e, 0xaf, 0x54, 0xb2, 0x11, 0x04, 0x2e, 0xaf, 0x29, 0x8e, 0x8a, 0xef, 0xbe, 0xd6, 0xf5, + 0x8a, 0xad, 0x5f, 0xd5, 0xe0, 0xb3, 0x0b, 0x3a, 0xb1, 0xb7, 0xbb, 0x6e, 0xd0, 0x24, 0x7c, 0x47, + 0xe1, 0x74, 0x1e, 0x02, 0x75, 0xe6, 0x2e, 0xbe, 0xd6, 0xf3, 0xb1, 0x28, 0xb0, 0xff, 0xb9, 0x02, + 0xc0, 0xcc, 0xf7, 0xd2, 0x0b, 0x63, 0x51, 0x87, 0xa8, 0xf9, 0x6d, 0x2d, 0x65, 0xd4, 0xba, 0x04, + 0x83, 0x06, 0x3f, 0x70, 0x44, 0x6b, 0xfc, 0x19, 0x72, 0xfb, 0x2d, 0xa8, 0xed, 0x33, 0x7c, 0x44, + 0x84, 0x51, 0xa7, 0x83, 0x70, 0xea, 0x5a, 0x06, 0xe1, 0x41, 0x94, 0x79, 0x19, 0x65, 0x60, 0xcb, + 0xa2, 0x0e, 0xd0, 0x71, 0x23, 0x0d, 0x90, 0xa8, 0x73, 0xda, 0x0c, 0xff, 0xf5, 0xb9, 0xf4, 0x82, + 0x96, 0x3a, 0x76, 0xc9, 0x22, 0xa8, 0xab, 0x07, 0x66, 0x1b, 0x11, 0x84, 0xf7, 0x1e, 0xec, 0xfd, + 0xc2, 0x61, 0x89, 0xd4, 0xd5, 0x70, 0xd0, 0x4b, 0x90, 0x0f, 0x3c, 0xa7, 0x4b, 0x33, 0xa6, 0xa0, + 0xde, 0xdb, 0xd3, 0xf3, 0xf5, 0x57, 0xf3, 0x78, 0x19, 0xc2, 0x53, 0xfc, 0x8e, 0xa8, 0x5c, 0xb3, + 0x51, 0x07, 0x19, 0xe5, 0xc6, 0x0d, 0xb4, 0xdf, 0x02, 0x4a, 0x88, 0x16, 0xce, 0x46, 0x54, 0x7c, + 0x69, 0x92, 0xbb, 0xbf, 0x09, 0xa8, 0x2f, 0xff, 0xcf, 0xe2, 0x0d, 0xeb, 0xd6, 0x88, 0xeb, 0xeb, + 0x57, 0x2e, 0x5b, 0x7a, 0x20, 0x22, 0xfc, 0x97, 0xb5, 0xab, 0x1f, 0xe5, 0x3d, 0xfc, 0x7c, 0xda, + 0x14, 0x06, 0x43, 0x30, 0xf7, 0x85, 0xe7, 0x61, 0x58, 0x03, 0x9d, 0x49, 0xa9, 0xfb, 0x78, 0x7a, + 0xc0, 0x13, 0xa0, 0x3d, 0x48, 0x36, 0xe0, 0xf8, 0xf1, 0xd8, 0xd1, 0x80, 0x3a, 0xb3, 0x21, 0x9c, + 0x7a, 0xf8, 0x40, 0xeb, 0xb8, 0x19, 0xa8, 0x0b, 0x43, 0xcd, 0x46, 0xdd, 0xd4, 0xcc, 0xf0, 0xab, + 0x6f, 0x16, 0xf5, 0x4d, 0xbf, 0x20, 0x2a, 0x11, 0xd7, 0xa8, 0xa9, 0x5b, 0xdc, 0x27, 0x09, 0xa2, + 0x31, 0xc8, 0x1b, 0x51, 0x29, 0xac, 0x6e, 0x07, 0x14, 0x1b, 0xdb, 0x7a, 0x09, 0x61, 0xec, 0xfd, + 0x75, 0xc5, 0x04, 0xf1, 0x6e, 0x67, 0x4b, 0xa1, 0xde, 0xfd, 0xf2, 0x1f, 0x40, 0xa5, 0x7f, 0x70, + 0x90, 0x19, 0x39, 0x6b, 0xaf, 0x6a, 0x92, 0x01, 0x1f, 0xd7, 0x28, 0x6d, 0x35, 0xd2, 0xf0, 0xce, + 0x6b, 0xa3, 0x51, 0x87, 0x6c, 0x2a, 0xbf, 0x5f, 0x0c, 0xcf, 0x25, 0xd2, 0x6e, 0xc8, 0xde, 0xf7, + 0xd2, 0xcb, 0xd8, 0x9b, 0x22, 0xc7, 0xb0, 0x1c, 0xc2, 0xc3, 0x30, 0x97, 0xc5, 0xb9, 0xc0, 0x98, + 0xd4, 0x45, 0xf3, 0xf5, 0x8a, 0x03, 0x2f, 0x6b, 0x3a, 0xf0, 0xfa, 0x98, 0x23, 0x36, 0x5a, 0xbf, + 0x64, 0xfc, 0x68, 0x63, 0x0e, 0xd1, 0x30, 0x9c, 0xba, 0x9a, 0x5b, 0x32, 0x68, 0x3a, 0x10, 0xaa, + 0xe9, 0x30, 0x72, 0xdb, 0xce, 0x1c, 0x8c, 0x15, 0x7a, 0x55, 0x8d, 0xd4, 0xbf, 0xae, 0x19, 0x68, + 0x0e, 0xf6, 0x63, 0x01, 0x27, 0xaf, 0xa9, 0xa2, 0x0c, 0x50, 0xb3, 0x61, 0xf5, 0x90, 0x0c, 0x2d, + 0x31, 0xdc, 0x1c, 0x04, 0xaa, 0x82, 0x34, 0x1d, 0xd9, 0xaf, 0xea, 0xd6, 0x74, 0xf8, 0xf7, 0x56, + 0x8a, 0x50, 0x65, 0xa7, 0x62, 0xf1, 0x02, 0xa3, 0xc4, 0xa2, 0x9b, 0xc7, 0x73, 0xe2, 0x58, 0x34, + 0x8f, 0x39, 0x3d, 0x6c, 0xee, 0x4a, 0xd4, 0x7e, 0x38, 0xe9, 0x07, 0xba, 0x14, 0x27, 0x7b, 0xe3, + 0x8e, 0x87, 0x51, 0x9b, 0x60, 0x50, 0x49, 0x5f, 0x83, 0xb8, 0xb7, 0xe4, 0x95, 0xaa, 0x97, 0x98, + 0xc7, 0x1b, 0x0e, 0x8b, 0x18, 0x0f, 0x63, 0x46, 0xfc, 0x95, 0x5f, 0x1f, 0x78, 0xf9, 0xa5, 0x43, + 0x70, 0x36, 0xb9, 0x89, 0xca, 0xce, 0x37, 0xdd, 0xeb, 0x4c, 0xfe, 0xf1, 0x2c, 0x91, 0x52, 0xc5, + 0x63, 0x61, 0x16, 0x8e, 0xa0, 0xd0, 0xbd, 0xe0, 0xe9, 0xd3, 0x4f, 0x27, 0x4f, 0x34, 0x7a, 0x4c, + 0x96, 0x83, 0xd4, 0xfc, 0x7a, 0x5b, 0x2f, 0xe2, 0xd8, 0x73, 0x9d, 0xf3, 0xbc, 0x4e, 0x77, 0x29, + 0x34, 0x99, 0x62, 0x24, 0xad, 0x30, 0x10, 0x75, 0x8f, 0x3f, 0x1b, 0x07, 0xf3, 0x79, 0xbc, 0x0d, + 0xd3, 0x3a, 0xd0, 0x23, 0x57, 0x6e, 0x0d, 0xce, 0xc2, 0x75, 0xf4, 0x8a, 0x2b, 0x90, 0x76, 0xf5, + 0x31, 0xdf, 0xa5, 0x52, 0xf5, 0x07, 0x25, 0x15, 0x13, 0x7e, 0x80, 0x17, 0xd5, 0xed, 0x06, 0x92, + 0xd1, 0xd3, 0x7d, 0x97, 0xeb, 0x4e, 0xd4, 0xdc, 0x6e, 0xca, 0x89, 0x89, 0x26, 0xc0, 0xae, 0x63, + 0x0f, 0x91, 0x6a, 0x1e, 0xb1, 0x05, 0xc2, 0x8c, 0x04, 0x27, 0x63, 0x3f, 0x80, 0x27, 0x53, 0x1b, + 0x2b, 0x2b, 0xa8, 0xf3, 0x77, 0x93, 0x8d, 0x07, 0x33, 0x01, 0xaa, 0x9a, 0xbb, 0x91, 0x58, 0x3b, + 0xf5, 0xd7, 0xef, 0x42, 0xe8, 0xbc, 0x95, 0x25, 0xde, 0xe5, 0x5c, 0x3e, 0x6b, 0xaa, 0xa6, 0x68, + 0x6b, 0x33, 0xaa, 0xec, 0xf3, 0x29, 0xa0, 0x46, 0xd4, 0x9e, 0x7a, 0x95, 0x32, 0x70, 0x48, 0xe2, + 0x4b, 0x64, 0x30, 0x31, 0xb7, 0x5a, 0x18, 0x2b, 0x2b, 0xd7, 0x5d, 0xd2, 0xde, 0xab, 0xeb, 0x42, + 0x4a, 0x21, 0x76, 0x83, 0xb5, 0xc6, 0x9d, 0x64, 0x6e, 0x8c, 0x87, 0xae, 0xf9, 0xf8, 0x21, 0xc2, + 0x8d, 0xe5, 0x0d, 0x9d, 0xc8, 0xec, 0xa1, 0x74, 0x21, 0x03, 0xa3, 0xad, 0x5c, 0x77, 0x3b, 0xbf, + 0x0c, 0xa8, 0x8e, 0x5f, 0x82, 0x5e, 0xe7, 0x85, 0xb2, 0x4d, 0xaa, 0x53, 0xd6, 0x66, 0x54, 0x7b, + 0x1a, 0x45, 0xa5, 0xa5, 0x2a, 0x23, 0x15, 0x57, 0xbf, 0xbf, 0x4f, 0xef, 0x4b, 0x90, 0x57, 0xda, + 0x82, 0xa4, 0xef, 0xea, 0x55, 0xf0, 0x25, 0x66, 0xcd, 0xba, 0x5f, 0x7e, 0x50, 0x4b, 0x97, 0x17, + 0xa3, 0x29, 0x5d, 0x92, 0xb0, 0x20, 0x66, 0x23, 0x4d, 0x87, 0x23, 0x75, 0xd2, 0xcb, 0xe5, 0xf8, + 0x25, 0xd7, 0xc1, 0xf1, 0xc8, 0x01, 0x09, 0xb4, 0x3d, 0x52, 0x74, 0xb0, 0x66, 0xdd, 0x83, 0x06, + 0x27, 0x8f, 0xb8, 0x1d, 0xcb, 0xc3, 0xfd, 0x5b, 0x62, 0x8e, 0x40, 0x1d, 0xcb, 0xe7, 0x7c, 0x86, + 0xfb, 0xaf, 0x5b, 0xbd, 0x8a, 0xb2, 0x34, 0x51, 0xb9, 0xfc, 0x1b, 0x6d, 0xfd, 0xf5, 0x50, 0x04, + 0xee, 0x7f, 0xe0, 0xaf, 0xd7, 0xd0, 0xfe, 0x96, 0x60, 0xea, 0xa5, 0x0a, 0x18, 0x60, 0xcd, 0xba, + 0xc3, 0x46, 0x4f, 0x4d, 0x7f, 0x51, 0x9c, 0x5e, 0x01, 0x06, 0x8e, 0xe6, 0x02, 0xae, 0x6a, 0xcd, + 0x0a, 0xc2, 0x2d, 0xa5, 0x25, 0xaf, 0xc9, 0x76, 0xe0, 0xb0, 0xc0, 0x12, 0x6c, 0xe6, 0x38, 0x04, + 0x1c, 0x7b, 0xb4, 0x99, 0x71, 0x26, 0x33, 0x1d, 0xde, 0x6e, 0xdd, 0x57, 0xeb, 0xe9, 0x7e, 0x21, + 0xfe, 0x5c, 0xce, 0xed, 0x5b, 0x1f, 0x8f, 0x1d, 0xed, 0xbc, 0xcd, 0x09, 0xf7, 0x37, 0xbf, 0xee, + 0xd9, 0x59, 0x37, 0xe6, 0xcc, 0x9c, 0xb1, 0x3f, 0x3c, 0x8c, 0x6f, 0x34, 0x66, 0x01, 0xd2, 0xdd, + 0x8b, 0x9b, 0xee, 0x47, 0x0f, 0x45, 0xad, 0xff, 0x79, 0x35, 0xd9, 0x8e, 0xf9, 0x75, 0x87, 0x79, + 0x9f, 0xcd, 0x98, 0x51, 0x95, 0x15, 0x15, 0x7c, 0x63, 0x32, 0x3d, 0x04, 0xe8, 0x8e, 0x2f, 0x49, + 0x81, 0x60, 0x66, 0xdd, 0x81, 0xe8, 0x1b, 0xd6, 0xad, 0x81, 0x0e, 0x7d, 0x7c, 0xc0, 0x2b, 0xb9, + 0x60, 0xee, 0xec, 0xcc, 0xf4, 0xb4, 0x45, 0xf3, 0xbe, 0x3c, 0x17, 0x17, 0xab, 0x52, 0xa9, 0xc0, + 0x7b, 0x3a, 0x7d, 0xca, 0xa4, 0x36, 0xa9, 0xf4, 0xeb, 0xf9, 0x73, 0xd5, 0x83, 0x2b, 0xd2, 0x9a, + 0x05, 0x7c, 0x75, 0xa7, 0x03, 0x1c, 0x94, 0x69, 0x1e, 0xdd, 0x67, 0x7d, 0x36, 0xed, 0xda, 0x95, + 0x3f, 0xd1, 0xbf, 0x32, 0x99, 0x0c, 0x4a, 0x0f, 0xf3, 0x1c, 0xf8, 0x7a, 0x4e, 0x9b, 0x3c, 0x21, + 0x38, 0xc0, 0xaf, 0xa5, 0xa5, 0x19, 0x9c, 0x47, 0x1f, 0xd6, 0xd4, 0x35, 0xec, 0xff, 0xd8, 0x74, + 0xfe, 0x5c, 0x9c, 0xda, 0x4c, 0xc0, 0xf2, 0x77, 0xbd, 0x71, 0x18, 0x98, 0xee, 0x14, 0x2b, 0x50, + 0x90, 0x61, 0x4e, 0xdd, 0xdf, 0x44, 0xd0, 0xeb, 0xbe, 0x4f, 0xa0, 0xee, 0x7b, 0x87, 0x75, 0xe7, + 0x80, 0x61, 0xdd, 0xcd, 0x83, 0x21, 0xd7, 0x3d, 0x6b, 0x58, 0x77, 0x2a, 0x70, 0xd7, 0xfd, 0xd4, + 0x89, 0xe3, 0x78, 0x4d, 0x15, 0x9e, 0xa3, 0xe5, 0xd5, 0x87, 0x75, 0xe7, 0x07, 0x76, 0xdd, 0x7f, + 0x5a, 0x1e, 0x75, 0x20, 0x12, 0xef, 0x6f, 0x80, 0xd3, 0xb6, 0x70, 0x9f, 0x5f, 0xd7, 0xad, 0xad, + 0x0f, 0xf6, 0x85, 0xe1, 0xeb, 0x9d, 0x1d, 0x70, 0x3b, 0xb9, 0xaf, 0x75, 0x4d, 0x63, 0xbd, 0x7d, + 0xfc, 0x66, 0x46, 0xbd, 0x15, 0xba, 0x7b, 0xd1, 0xeb, 0x8e, 0xfb, 0x2f, 0x9c, 0xf7, 0x25, 0x3c, + 0x19, 0x37, 0x7a, 0xa4, 0xb4, 0x55, 0x37, 0xb5, 0xbd, 0xf3, 0xee, 0x2d, 0xf2, 0x28, 0x67, 0x08, + 0x9f, 0xf8, 0xe7, 0x5a, 0xe9, 0xb1, 0xa5, 0x6a, 0xb9, 0x60, 0x58, 0x77, 0x22, 0x28, 0xd7, 0xf5, + 0xaa, 0xfc, 0x7e, 0x09, 0xbc, 0x05, 0xe4, 0x39, 0x84, 0x4b, 0xc1, 0x29, 0x7a, 0xbd, 0x80, 0x41, + 0x49, 0xc5, 0x92, 0x76, 0xf6, 0xf1, 0x07, 0x44, 0xdd, 0xf1, 0x57, 0x2c, 0x23, 0x8d, 0xbd, 0x2b, + 0x8b, 0xcb, 0x9c, 0x15, 0x06, 0xe7, 0x7a, 0xe4, 0xfe, 0xb1, 0xcc, 0x72, 0x60, 0x84, 0x35, 0x22, + 0x01, 0xe0, 0xab, 0x3b, 0xca, 0xdf, 0x6f, 0x66, 0x67, 0xe1, 0xe9, 0x1d, 0xa2, 0xc4, 0x66, 0x94, + 0x56, 0xfa, 0xad, 0xb6, 0xe4, 0xb8, 0xf6, 0xfd, 0xf9, 0x8a, 0xcf, 0x53, 0x3f, 0xa0, 0x48, 0xef, + 0x50, 0xf4, 0x0a, 0x91, 0x88, 0xcb, 0xb3, 0xf5, 0x29, 0x54, 0x97, 0x73, 0x6b, 0xb8, 0xb8, 0xf8, + 0x9c, 0xca, 0x23, 0xe9, 0x65, 0x81, 0x89, 0x45, 0xde, 0x67, 0x0b, 0xb6, 0x04, 0x66, 0x51, 0x12, + 0x0a, 0x4e, 0x28, 0xec, 0xe1, 0x99, 0x51, 0x32, 0x80, 0x83, 0xee, 0x14, 0x6b, 0x80, 0xd5, 0xd6, + 0xd6, 0xcc, 0x9c, 0x3e, 0x15, 0x9f, 0xdc, 0x83, 0x20, 0x5a, 0xa4, 0x5b, 0xd6, 0xb5, 0xeb, 0xd1, + 0x03, 0xba, 0x78, 0x2b, 0x9b, 0x64, 0x77, 0x8a, 0x9b, 0x33, 0x0a, 0x1a, 0x90, 0x4b, 0x2f, 0x68, + 0x48, 0x7b, 0x2a, 0x4e, 0xcd, 0x1f, 0x74, 0x4f, 0xc5, 0x23, 0x3a, 0x3a, 0x3a, 0xea, 0x48, 0xc8, + 0xb9, 0x7d, 0x8b, 0xec, 0x69, 0x20, 0xda, 0xda, 0xa8, 0x97, 0xcb, 0x95, 0xca, 0xfa, 0x82, 0x93, + 0x8a, 0x08, 0x3f, 0x80, 0xff, 0x05, 0xae, 0xd3, 0xba, 0x18, 0xa0, 0xd3, 0x3d, 0x96, 0x93, 0xee, + 0x0f, 0xee, 0xe7, 0xc2, 0x34, 0xb7, 0xea, 0x7b, 0xda, 0xf2, 0x65, 0x47, 0x66, 0x1a, 0xde, 0x09, + 0xd5, 0x1a, 0x1b, 0x23, 0x8c, 0x1b, 0x45, 0x7a, 0x9f, 0x35, 0x7d, 0x9a, 0xb9, 0x46, 0x12, 0x88, + 0x1a, 0x3a, 0x6d, 0xf7, 0xe8, 0xd4, 0xdf, 0xe2, 0xcb, 0xbe, 0xae, 0x0c, 0x03, 0xf8, 0xea, 0xce, + 0x1d, 0xf8, 0x7c, 0xa2, 0x92, 0xc1, 0xd5, 0xa2, 0xda, 0x92, 0x2e, 0xf6, 0x2b, 0xb8, 0x76, 0xf8, + 0x11, 0x75, 0x1f, 0x3b, 0xea, 0x3d, 0x94, 0xbf, 0x73, 0xd9, 0xc0, 0x8a, 0x75, 0x9e, 0x16, 0x9d, + 0xab, 0x75, 0xf8, 0xbd, 0x23, 0x93, 0xf6, 0xfb, 0xe1, 0x73, 0xee, 0x99, 0x2e, 0x37, 0x8c, 0x66, + 0x19, 0x6e, 0x4f, 0x87, 0xa1, 0xd3, 0x1d, 0xa1, 0x35, 0xee, 0x64, 0xe9, 0x27, 0x36, 0x7c, 0x9f, + 0x9d, 0xb8, 0x46, 0xe4, 0xf3, 0x67, 0x05, 0xd0, 0x25, 0x5c, 0xbc, 0x00, 0x4f, 0x58, 0x23, 0x06, + 0xba, 0x37, 0x06, 0xfb, 0x70, 0x71, 0x62, 0x2f, 0xf7, 0x9a, 0xdf, 0xd7, 0x8b, 0x16, 0xcc, 0x26, + 0xf3, 0xa8, 0x5a, 0xbd, 0x82, 0xd0, 0x6b, 0x0c, 0xe1, 0x7e, 0x3c, 0x0f, 0xa9, 0x9f, 0xfe, 0x54, + 0xcc, 0x57, 0x14, 0x13, 0xe8, 0x4e, 0x40, 0xf7, 0xf3, 0xa7, 0xcd, 0x31, 0x47, 0x81, 0xfd, 0xc6, + 0x20, 0x1f, 0x34, 0xcf, 0x90, 0xc2, 0x05, 0x78, 0x51, 0x97, 0x23, 0x8d, 0x32, 0xa4, 0x99, 0x15, + 0xf2, 0xca, 0x8a, 0x8a, 0x25, 0x0b, 0xf1, 0x1f, 0x40, 0x96, 0x4f, 0x5c, 0x7f, 0xaa, 0x12, 0x1b, + 0x31, 0x11, 0x48, 0xb5, 0xe0, 0x24, 0x03, 0x4c, 0xaf, 0x3b, 0x77, 0x98, 0x53, 0x77, 0x84, 0x8e, + 0xb4, 0x6b, 0xe8, 0x6d, 0x2d, 0x9d, 0x32, 0x8e, 0x1c, 0x00, 0x49, 0x1f, 0x70, 0x99, 0x87, 0xf4, + 0x70, 0xee, 0xd7, 0xb0, 0xee, 0x2c, 0x68, 0x0c, 0xf1, 0xd3, 0x95, 0xd2, 0xfe, 0xd6, 0x5b, 0x1e, + 0x46, 0xae, 0x50, 0x21, 0xe9, 0x2f, 0xde, 0x63, 0xd9, 0xc9, 0x10, 0x61, 0x58, 0x77, 0xae, 0xe8, + 0xc8, 0xce, 0xa0, 0xcb, 0x73, 0xe0, 0xe6, 0x59, 0x9b, 0x35, 0x6b, 0x11, 0x70, 0x1d, 0x98, 0x68, + 0x55, 0xba, 0xa7, 0x24, 0x27, 0x76, 0x75, 0x75, 0x0d, 0x19, 0x1f, 0xed, 0x24, 0x16, 0xe0, 0xca, + 0xa6, 0x13, 0xc7, 0x82, 0xdb, 0xf9, 0xa6, 0x43, 0x1d, 0xcf, 0xe6, 0x54, 0x72, 0x31, 0xc5, 0xae, + 0xbb, 0x61, 0x2b, 0xe0, 0x1a, 0x02, 0x7e, 0xba, 0xaf, 0x5d, 0xf5, 0x03, 0xac, 0x5c, 0x0c, 0x25, + 0x25, 0x75, 0xe9, 0xe4, 0x8f, 0xa0, 0x2e, 0xed, 0x19, 0x7a, 0x8d, 0x4d, 0x9e, 0x67, 0xb5, 0x85, + 0x4b, 0x9f, 0xb3, 0x9c, 0x06, 0xf4, 0xfa, 0x5b, 0x87, 0xee, 0x77, 0x73, 0x72, 0xe0, 0xd2, 0xd1, + 0x72, 0xb9, 0x9c, 0x41, 0xfa, 0xaa, 0x4a, 0x4e, 0x89, 0x91, 0x01, 0xe0, 0xf5, 0x87, 0xba, 0x80, + 0xb4, 0x8f, 0xfb, 0x87, 0x0c, 0x0e, 0x83, 0x76, 0x0a, 0xe7, 0xb4, 0x38, 0x98, 0x95, 0xe8, 0x8e, + 0x9a, 0xa7, 0x01, 0x8e, 0x47, 0x1f, 0x85, 0xb3, 0x9e, 0xa7, 0x8c, 0x1f, 0xa7, 0x1e, 0x6c, 0x51, + 0x1a, 0x37, 0x7a, 0x24, 0x38, 0x3e, 0xca, 0x7b, 0x08, 0x37, 0xe7, 0xbc, 0x10, 0x7f, 0x4e, 0x18, + 0x27, 0x34, 0x85, 0x0b, 0xad, 0xfb, 0x0d, 0x01, 0x67, 0x4f, 0x6f, 0xa6, 0x59, 0x03, 0x9c, 0x0c, + 0x6b, 0xd0, 0x1d, 0x28, 0xdb, 0xa7, 0x5f, 0xb5, 0x99, 0xf5, 0xd9, 0xb4, 0x40, 0x3f, 0x5f, 0x38, + 0xf7, 0x1f, 0xea, 0xfe, 0xf1, 0xc0, 0x4a, 0x35, 0x48, 0x77, 0xc2, 0xc6, 0x61, 0xdc, 0x01, 0xb7, + 0xb3, 0x2d, 0xc1, 0x56, 0x2c, 0x87, 0x80, 0xf3, 0xa7, 0x35, 0xba, 0x53, 0xad, 0x5e, 0x4e, 0x86, + 0x35, 0xe8, 0x6e, 0x4a, 0xd4, 0x6c, 0x5c, 0xc7, 0xac, 0x3b, 0xe5, 0xaa, 0xf1, 0x64, 0x0c, 0xeb, + 0xce, 0x0f, 0xf5, 0x2e, 0x5b, 0xb5, 0xfd, 0x99, 0x41, 0xde, 0xb8, 0xff, 0x89, 0x2c, 0x91, 0xb6, + 0x3f, 0x33, 0x80, 0x76, 0x23, 0x47, 0x1c, 0x6e, 0xc7, 0x1f, 0x69, 0x5b, 0x37, 0xf5, 0x37, 0x40, + 0x93, 0x84, 0x06, 0x68, 0xdb, 0x88, 0x36, 0xff, 0x6a, 0x44, 0xda, 0xbc, 0x60, 0x89, 0xba, 0x37, + 0x47, 0x47, 0x41, 0x5d, 0xca, 0x67, 0x13, 0xf7, 0xb2, 0xd0, 0x35, 0x14, 0x9f, 0x7f, 0xce, 0x6c, + 0xe4, 0x50, 0x7a, 0x19, 0x0a, 0x5c, 0xdf, 0xda, 0x83, 0x5f, 0x42, 0xcd, 0xe8, 0x4d, 0x51, 0xe1, + 0x46, 0xa6, 0xce, 0x19, 0x96, 0xa8, 0xbb, 0x1a, 0xeb, 0xdc, 0x81, 0x9b, 0xf5, 0xe2, 0xc0, 0x9b, + 0xe9, 0x41, 0xce, 0x43, 0xbe, 0xf7, 0x7e, 0x51, 0x23, 0x1e, 0xa6, 0xa0, 0xa2, 0x0d, 0xbf, 0xda, + 0x12, 0x1b, 0x83, 0xaa, 0x66, 0x5c, 0x1a, 0x5c, 0x87, 0x08, 0x16, 0xaa, 0x7b, 0xf7, 0xf3, 0x02, + 0xa4, 0x4e, 0xc7, 0x0d, 0xe2, 0x46, 0x4d, 0xa7, 0x6f, 0x57, 0x72, 0xe9, 0x4e, 0x3b, 0x34, 0xb8, + 0x57, 0x05, 0x82, 0xec, 0xf1, 0x43, 0x64, 0xb6, 0xed, 0x6a, 0x92, 0xa9, 0x9e, 0x86, 0x02, 0x16, + 0xaa, 0x3b, 0x40, 0xd7, 0xc3, 0x5c, 0xa4, 0x91, 0xd8, 0xcb, 0x9d, 0x32, 0xcc, 0xd3, 0x0a, 0xe9, + 0xde, 0xe4, 0xa2, 0x6d, 0x91, 0x77, 0xec, 0xfd, 0x33, 0xed, 0xfc, 0x32, 0x1c, 0xc3, 0x6e, 0xfb, + 0x5e, 0x7c, 0xf1, 0xac, 0xb2, 0x8d, 0x32, 0x30, 0x30, 0x82, 0x0c, 0xb6, 0xa7, 0xb3, 0x6f, 0x29, + 0x35, 0xa4, 0xd0, 0xd3, 0x7d, 0xe5, 0xb2, 0xa5, 0x96, 0x36, 0x7f, 0xb5, 0xe2, 0x9b, 0xf9, 0x48, + 0xac, 0x86, 0x40, 0x2f, 0x61, 0x46, 0x1a, 0x83, 0x7c, 0x74, 0xad, 0xcd, 0xe3, 0x47, 0xf7, 0x1b, + 0xb0, 0x0a, 0xb0, 0xb1, 0x40, 0x4c, 0xef, 0xde, 0x7b, 0x76, 0x5b, 0x8e, 0xe8, 0x10, 0x40, 0x26, + 0x42, 0x9f, 0x4e, 0x63, 0xa0, 0xb7, 0xb2, 0xb3, 0x93, 0xf9, 0x2e, 0x4d, 0x87, 0x0c, 0xd6, 0xc0, + 0xa9, 0x71, 0x36, 0xa3, 0x54, 0x54, 0xbd, 0x2b, 0x66, 0x01, 0x45, 0x3e, 0x93, 0x98, 0x70, 0x49, + 0xc0, 0x5a, 0x9d, 0x26, 0x40, 0xd3, 0x91, 0xfd, 0xc2, 0xfa, 0x14, 0x9b, 0x8f, 0x45, 0xb1, 0x5b, + 0x37, 0x2d, 0xde, 0xd4, 0xf5, 0x38, 0xa4, 0xc9, 0x97, 0xc4, 0x5e, 0x6e, 0x65, 0x9f, 0x4e, 0x20, + 0xab, 0x5c, 0x36, 0x63, 0xb2, 0xd8, 0x7d, 0xbb, 0xf4, 0xf2, 0x79, 0x73, 0x73, 0x64, 0xc2, 0x9b, + 0xaa, 0xbb, 0xd1, 0xd1, 0xd9, 0xa3, 0x28, 0x6f, 0xec, 0x2a, 0xac, 0x6e, 0x2f, 0xae, 0xeb, 0x6c, + 0xe9, 0x94, 0xb3, 0xdf, 0x60, 0x18, 0xde, 0x6a, 0xdd, 0x81, 0xd6, 0x07, 0xaf, 0x97, 0xee, 0x89, + 0x79, 0x64, 0xeb, 0x95, 0x4a, 0x2e, 0x86, 0x3a, 0x85, 0xe7, 0x84, 0x24, 0x15, 0x15, 0xd0, 0x94, + 0x8e, 0x0c, 0xc4, 0x08, 0xf2, 0x1e, 0x4f, 0xa7, 0x4f, 0x9d, 0x34, 0xe3, 0x4e, 0xe7, 0xa6, 0x71, + 0xf1, 0x17, 0x13, 0x0e, 0x1c, 0x8d, 0x45, 0xbb, 0xaa, 0x93, 0xf7, 0x56, 0xc7, 0x9d, 0x63, 0x48, + 0xf6, 0xb1, 0x1b, 0x9c, 0x46, 0xcf, 0xf1, 0xd0, 0x9d, 0xec, 0x05, 0x4a, 0x32, 0x3d, 0xdd, 0x5c, + 0x77, 0x7d, 0x7d, 0x13, 0xe1, 0x1f, 0x9b, 0xcf, 0xa5, 0xda, 0x45, 0x54, 0x3f, 0x30, 0xb3, 0xac, + 0x81, 0xa5, 0x10, 0xc5, 0x1d, 0x44, 0xdd, 0x6f, 0x64, 0x66, 0x00, 0xdd, 0x27, 0xd9, 0x8c, 0xa5, + 0x0c, 0xfd, 0xa6, 0xe3, 0x48, 0xa6, 0x88, 0xa0, 0xa6, 0xad, 0x77, 0x9a, 0xe7, 0xd9, 0x67, 0x67, + 0x6f, 0x55, 0xd4, 0xb4, 0x74, 0xc3, 0x8d, 0xe7, 0x14, 0xca, 0xfe, 0xfa, 0xd6, 0x9e, 0x94, 0x87, + 0x75, 0x7e, 0x97, 0x5e, 0xd8, 0x07, 0xdc, 0x20, 0x84, 0x3f, 0x96, 0x4a, 0xd1, 0x32, 0x21, 0x00, + 0xb4, 0xe3, 0x81, 0x45, 0xe5, 0xe5, 0x46, 0x89, 0xc0, 0x72, 0x70, 0x34, 0xa3, 0x0c, 0x57, 0xd0, + 0x21, 0xe4, 0x66, 0xfc, 0x2d, 0xf6, 0xdc, 0x23, 0xeb, 0x79, 0xe3, 0xce, 0x43, 0xf7, 0xf1, 0x1b, + 0x83, 0xcf, 0x3f, 0x33, 0x9c, 0x8c, 0x9e, 0xee, 0x91, 0x61, 0xa1, 0x48, 0x77, 0xca, 0x9d, 0xa9, + 0xdf, 0x5c, 0x84, 0x5d, 0x2b, 0xc1, 0xb5, 0xf3, 0xe7, 0xb9, 0x82, 0x46, 0x4c, 0x76, 0x85, 0x9e, + 0xf4, 0xe7, 0x28, 0x16, 0xc8, 0xe6, 0x05, 0x3d, 0xdd, 0x09, 0x8d, 0x04, 0x69, 0xd7, 0xcd, 0xdc, + 0x88, 0x61, 0x2c, 0x3c, 0x29, 0x6b, 0xc5, 0x55, 0xab, 0x69, 0x14, 0x92, 0x4d, 0x97, 0x88, 0xbb, + 0xec, 0xb0, 0x9d, 0xc8, 0xf7, 0x26, 0xd3, 0xee, 0xee, 0xcd, 0x05, 0x14, 0xdf, 0xd5, 0xbd, 0xc1, + 0x81, 0x86, 0x58, 0xb4, 0x40, 0xd8, 0xfa, 0xa4, 0x23, 0xbd, 0x24, 0x6d, 0x3d, 0xec, 0x37, 0xd0, + 0x40, 0xa5, 0xea, 0xb7, 0xc3, 0x56, 0xdb, 0xbb, 0x57, 0xdc, 0x24, 0xd8, 0x94, 0xf5, 0xeb, 0x0e, + 0x37, 0x8b, 0xd0, 0x2a, 0x55, 0x24, 0x21, 0x07, 0x50, 0x75, 0xcb, 0x9a, 0x0e, 0x86, 0x56, 0xaf, + 0xf9, 0xbe, 0x74, 0xea, 0xc7, 0x25, 0xe3, 0x46, 0x96, 0x4e, 0xfc, 0xb0, 0x62, 0xe9, 0xd7, 0x4d, + 0x07, 0x42, 0x95, 0x52, 0xea, 0xdd, 0x3b, 0x6d, 0x07, 0x53, 0xbd, 0x43, 0x08, 0xef, 0x65, 0x67, + 0x10, 0xac, 0x5c, 0xf7, 0xaa, 0x26, 0xdd, 0xa2, 0x6e, 0x94, 0xfb, 0x74, 0x48, 0x42, 0x03, 0x19, + 0x1a, 0x76, 0xd0, 0xce, 0x01, 0x38, 0xb2, 0x9f, 0x89, 0x91, 0xcd, 0xa8, 0xd4, 0x52, 0x61, 0xc4, + 0xac, 0x5c, 0x77, 0xef, 0xb3, 0xba, 0x71, 0xf4, 0xe4, 0xab, 0xa2, 0x6f, 0xe6, 0xb1, 0xb6, 0xa9, + 0x95, 0xcd, 0x9c, 0xda, 0x5b, 0x46, 0xec, 0x3f, 0x71, 0x3f, 0xa1, 0xed, 0xb9, 0xb5, 0x15, 0xba, + 0x9a, 0xa1, 0x35, 0xeb, 0xae, 0x54, 0xe9, 0xe6, 0xbc, 0x1d, 0xbe, 0x4e, 0x2c, 0x77, 0xe3, 0x2d, + 0xfb, 0x20, 0x7b, 0x69, 0xf0, 0xf7, 0x6c, 0xbb, 0x9a, 0xd4, 0xf3, 0xf2, 0x9f, 0xf6, 0xd4, 0xab, + 0x70, 0x19, 0x78, 0xe4, 0x4a, 0xa7, 0x8e, 0x27, 0xdc, 0x5b, 0x8d, 0xad, 0x8d, 0x98, 0xca, 0x7f, + 0x60, 0xbe, 0xda, 0xba, 0x75, 0x3f, 0x83, 0x75, 0x07, 0x12, 0xd6, 0xf8, 0x95, 0x84, 0x07, 0x23, + 0x59, 0x6b, 0x6d, 0x7f, 0x23, 0xdf, 0xdb, 0xdf, 0xd7, 0x97, 0xb2, 0x7e, 0x35, 0x43, 0x97, 0xcb, + 0xf6, 0x03, 0x7f, 0x6b, 0xb3, 0xaf, 0x0b, 0x85, 0xe4, 0xdb, 0x59, 0x61, 0xcd, 0xba, 0xfb, 0x5f, + 0xf8, 0x07, 0x4a, 0xe3, 0xa6, 0x3f, 0x53, 0xa7, 0x4f, 0x5c, 0xa7, 0x13, 0x9d, 0x66, 0x28, 0xc7, + 0x86, 0x75, 0x6b, 0xfb, 0x95, 0xca, 0x06, 0x3f, 0x0f, 0x14, 0x92, 0xf0, 0x99, 0x8d, 0x18, 0x1c, + 0xbc, 0x66, 0xef, 0x9f, 0x29, 0x80, 0x9b, 0x35, 0xeb, 0x8e, 0x6a, 0xf9, 0xfb, 0x52, 0xf4, 0xca, + 0xda, 0x68, 0xdc, 0x52, 0x09, 0xcd, 0xaa, 0xe8, 0x2b, 0x96, 0x2e, 0x46, 0xe7, 0x68, 0x90, 0xac, + 0x24, 0x22, 0x04, 0x0f, 0x53, 0x39, 0xb0, 0x6d, 0x03, 0x74, 0x32, 0x39, 0xef, 0x8e, 0x43, 0x6b, + 0xd6, 0x7d, 0xf3, 0xe0, 0xd4, 0xc0, 0xbf, 0xf5, 0x0b, 0xda, 0x95, 0x2b, 0x97, 0xa0, 0xfe, 0x42, + 0xdc, 0xbf, 0xbd, 0xad, 0x6d, 0xc7, 0x56, 0xc7, 0xb5, 0x3f, 0xfd, 0x80, 0x7b, 0xa2, 0x41, 0x4e, + 0x65, 0x33, 0x3f, 0xc1, 0xfd, 0xf1, 0x8f, 0xc7, 0xf3, 0x2a, 0xde, 0xcb, 0x34, 0x5b, 0xad, 0xee, + 0xf8, 0x14, 0x11, 0x91, 0x44, 0x86, 0x5f, 0x2a, 0x9d, 0x32, 0x6e, 0x70, 0x28, 0x47, 0x32, 0xee, + 0x0f, 0x6b, 0xe9, 0x0b, 0xe7, 0xcd, 0xc1, 0x3d, 0x65, 0xf9, 0x8f, 0xd0, 0xb7, 0x97, 0x10, 0x05, + 0x2a, 0xc8, 0xa7, 0x15, 0x34, 0xf0, 0xa5, 0x67, 0xb5, 0xba, 0x77, 0xf5, 0x2a, 0x90, 0xee, 0x0d, + 0xfa, 0x9b, 0xd2, 0xa0, 0x4c, 0xa6, 0xa7, 0xf8, 0x25, 0xee, 0x0f, 0xe7, 0x90, 0x6e, 0xfc, 0x75, + 0x3d, 0xee, 0xd9, 0x57, 0x5f, 0xab, 0x1b, 0xe7, 0xa4, 0xdf, 0x2d, 0x6e, 0xe7, 0xab, 0x5d, 0x04, + 0xf7, 0x72, 0x2e, 0xd7, 0xa9, 0x3f, 0x08, 0xc3, 0xba, 0xeb, 0xe1, 0x45, 0x21, 0x71, 0x9e, 0x78, + 0x5f, 0x7d, 0x1d, 0xab, 0xee, 0x09, 0xf7, 0x78, 0xaf, 0x8a, 0xfd, 0x96, 0xeb, 0xce, 0xde, 0x2a, + 0xc9, 0x25, 0xbd, 0x0f, 0xeb, 0xae, 0x83, 0x00, 0xdd, 0x17, 0xcc, 0x9d, 0xbd, 0x3f, 0x3c, 0x6c, + 0xf4, 0x7b, 0xff, 0x8b, 0x7b, 0x5a, 0x84, 0xee, 0x8f, 0xf3, 0xf2, 0x6e, 0x66, 0xf3, 0x5e, 0xd3, + 0xc9, 0x2c, 0x10, 0xa0, 0x3b, 0xc8, 0xdc, 0x3d, 0xdc, 0xdd, 0x4a, 0xf4, 0x97, 0x08, 0xb6, 0x08, + 0xdd, 0x2d, 0x6a, 0x1c, 0x19, 0x33, 0x84, 0xe9, 0x4e, 0xb6, 0x63, 0x7e, 0xdd, 0x9b, 0x9b, 0x9b, + 0xa6, 0x4d, 0x9e, 0xf0, 0xf3, 0x4f, 0x3f, 0xa6, 0x73, 0x58, 0x0f, 0xc8, 0xec, 0xb0, 0x1e, 0xdd, + 0xbf, 0x9e, 0x3f, 0xf7, 0xde, 0xdd, 0x3b, 0xed, 0xed, 0xed, 0x6f, 0x44, 0x17, 0xa0, 0xac, 0x57, + 0x69, 0x25, 0xba, 0xe3, 0xcb, 0xfc, 0xf5, 0x0e, 0xc1, 0x16, 0x5e, 0xc6, 0x85, 0x95, 0xe8, 0x9e, + 0x9c, 0x94, 0xf8, 0xd1, 0x07, 0xef, 0xc3, 0x45, 0x99, 0x3f, 0xfb, 0x64, 0xf2, 0xca, 0x65, 0x4b, + 0x81, 0xe7, 0xc6, 0x0d, 0xbf, 0x7c, 0x3a, 0x79, 0xa2, 0xcd, 0x87, 0x1f, 0x7c, 0xbb, 0x68, 0xc1, + 0x98, 0xf7, 0xdf, 0x01, 0x3e, 0xae, 0xce, 0xdb, 0x57, 0x2c, 0x5d, 0x02, 0xde, 0x8c, 0xde, 0x9e, + 0x1e, 0x77, 0x17, 0x67, 0x99, 0x4c, 0xb6, 0x2f, 0x84, 0x65, 0x23, 0x87, 0x21, 0x82, 0x00, 0xdd, + 0x29, 0x61, 0x66, 0xdd, 0x41, 0xde, 0x52, 0x5b, 0x5b, 0x83, 0xe6, 0xaf, 0xc2, 0xa4, 0x01, 0x77, + 0x21, 0x86, 0x4b, 0x33, 0xc3, 0x72, 0x4e, 0x5f, 0x5f, 0xdf, 0xeb, 0x57, 0xc5, 0xff, 0x9e, 0xf1, + 0x29, 0x38, 0x8f, 0x3e, 0x72, 0x18, 0xce, 0x6e, 0x35, 0x0b, 0x70, 0xdd, 0xc5, 0x52, 0xbd, 0x3e, + 0xd5, 0x37, 0x46, 0x77, 0x95, 0x4a, 0x45, 0x78, 0x07, 0x27, 0x7c, 0x34, 0x26, 0xfe, 0x6c, 0x1c, + 0xd4, 0x3d, 0xea, 0x40, 0x24, 0x38, 0xde, 0xb9, 0x7d, 0x1b, 0x1c, 0x41, 0xc2, 0x07, 0xc7, 0x2f, + 0x67, 0x7d, 0xae, 0x1e, 0x58, 0x24, 0x7b, 0xc6, 0xd4, 0xc9, 0x7c, 0x09, 0x19, 0x0b, 0xd6, 0xa0, + 0xfb, 0x96, 0xcd, 0xbf, 0xbb, 0xec, 0xd8, 0x86, 0xfb, 0xe4, 0x3f, 0x79, 0x8c, 0x76, 0xdd, 0xc6, + 0x75, 0x07, 0x29, 0x7d, 0xe6, 0xf4, 0xa9, 0x3b, 0x9c, 0x1c, 0x4b, 0x5e, 0xbf, 0xca, 0xbe, 0xa1, + 0x69, 0x98, 0x5e, 0xb6, 0xe4, 0x5b, 0xbe, 0x9c, 0x8c, 0x02, 0x6b, 0xd0, 0xfd, 0x4d, 0x04, 0x93, + 0xee, 0x83, 0x9b, 0x08, 0x0d, 0xeb, 0x6e, 0x7c, 0x0c, 0xeb, 0x6e, 0x1e, 0xc8, 0xe4, 0xc3, 0xba, + 0x9b, 0x03, 0xc3, 0xba, 0x9b, 0x07, 0xc3, 0xba, 0x9b, 0x07, 0x7c, 0x75, 0x07, 0xb5, 0x93, 0x45, + 0xf3, 0x35, 0xeb, 0x90, 0x5f, 0x88, 0x3f, 0xf7, 0xd7, 0x35, 0xdd, 0x0e, 0xa0, 0xc3, 0xba, 0xf3, + 0x03, 0x77, 0xdd, 0xe5, 0x72, 0xf9, 0xd4, 0x89, 0xe3, 0x41, 0xb1, 0x78, 0xc1, 0x5c, 0x4d, 0xcf, + 0x2a, 0xd0, 0x1d, 0x36, 0xbb, 0x96, 0x97, 0x6b, 0x36, 0xf8, 0xe4, 0xa2, 0xfb, 0xa5, 0x61, 0xdd, + 0x11, 0x38, 0xe9, 0x5e, 0xf4, 0x62, 0xc5, 0xd2, 0xc5, 0x68, 0xdc, 0x39, 0x41, 0x77, 0xe0, 0x26, + 0x8e, 0xfb, 0xb0, 0xbd, 0xa2, 0x5c, 0xa7, 0xbb, 0xfe, 0x7e, 0x94, 0xf6, 0xfe, 0x99, 0xd0, 0xfe, + 0xa9, 0x6c, 0xde, 0xb3, 0x9f, 0xde, 0x6a, 0xdd, 0xeb, 0x1f, 0xe4, 0x4e, 0x19, 0x3f, 0x0e, 0xa9, + 0xfc, 0xd5, 0x97, 0x5f, 0xc8, 0x64, 0xb2, 0xd8, 0xd3, 0xa7, 0xf0, 0x49, 0x00, 0x05, 0xb9, 0xf7, + 0x90, 0xee, 0xca, 0xd6, 0x16, 0xdc, 0xce, 0x8e, 0xc8, 0xbb, 0xd0, 0xbe, 0x1f, 0xd5, 0x88, 0x57, + 0x66, 0xbc, 0xd5, 0xba, 0x83, 0xf4, 0x0e, 0xfe, 0xad, 0xae, 0xaa, 0xfa, 0xe0, 0xdd, 0x7f, 0x91, + 0xd3, 0xfb, 0x95, 0x14, 0xed, 0x28, 0x0f, 0xa4, 0x7b, 0xe7, 0x9d, 0x9b, 0xb8, 0x1d, 0xdd, 0x7e, + 0xe7, 0x9e, 0xfc, 0x36, 0x99, 0x50, 0x0f, 0xeb, 0x8e, 0x3c, 0x6f, 0x64, 0x66, 0x20, 0xdd, 0x03, + 0x7c, 0x7d, 0xf0, 0xf0, 0x68, 0x04, 0x6b, 0xe3, 0x3e, 0xbd, 0xdd, 0xfb, 0xda, 0xbb, 0xfb, 0x50, + 0x14, 0x7c, 0xb7, 0xbe, 0x1d, 0xd6, 0x9d, 0x1d, 0x92, 0x88, 0x10, 0x18, 0xbe, 0xe2, 0xff, 0xe6, + 0x12, 0x2e, 0xed, 0x89, 0x7d, 0x8a, 0x62, 0x09, 0x4e, 0xe1, 0x31, 0xf3, 0x66, 0x58, 0x77, 0x3d, + 0xb4, 0x49, 0x29, 0x36, 0x65, 0x90, 0x3d, 0xd2, 0xad, 0x16, 0xa4, 0x18, 0xd8, 0x7d, 0x10, 0x07, + 0x8a, 0x05, 0xb8, 0x9d, 0x47, 0x1f, 0xa6, 0xe5, 0x73, 0x1a, 0x96, 0xcd, 0x34, 0xaf, 0x2c, 0xee, + 0xcc, 0x69, 0xd6, 0xfb, 0xfd, 0x13, 0x5e, 0x82, 0xe2, 0x14, 0x17, 0x07, 0xbe, 0xfe, 0x0e, 0x21, + 0x37, 0x3d, 0x62, 0x1e, 0x81, 0x5b, 0xce, 0xdd, 0xa9, 0x6a, 0xe4, 0xb0, 0xe9, 0x8b, 0x21, 0xe0, + 0xab, 0x3b, 0x28, 0xbf, 0x83, 0x5c, 0xde, 0xcf, 0xdb, 0x73, 0xca, 0x04, 0x9b, 0x2d, 0xb6, 0x7f, + 0x10, 0xac, 0x95, 0xcf, 0x9e, 0x0e, 0x6f, 0x11, 0xef, 0x71, 0x21, 0x5c, 0xea, 0x53, 0x28, 0x71, + 0xe9, 0xa1, 0xb3, 0xf5, 0x4a, 0xd3, 0x3a, 0x6f, 0x0a, 0x57, 0x54, 0xdb, 0xa1, 0xa7, 0xfb, 0x6e, + 0x37, 0x17, 0xbe, 0x8b, 0xfe, 0x00, 0x11, 0xc9, 0xb1, 0x72, 0x74, 0xe0, 0x97, 0xf0, 0xbf, 0xf4, + 0xe2, 0x79, 0xd5, 0x90, 0x2c, 0x00, 0xc0, 0x57, 0x77, 0xb7, 0x9d, 0x3b, 0x4e, 0x9f, 0xd4, 0x6e, + 0xd6, 0x41, 0xee, 0xb8, 0x6f, 0x3a, 0x14, 0x81, 0x92, 0xbc, 0xbc, 0xba, 0x8a, 0x70, 0xb5, 0xb7, + 0x4f, 0xb5, 0x3d, 0x3c, 0x87, 0xfb, 0x83, 0x13, 0x75, 0x57, 0x63, 0x49, 0x9e, 0xe3, 0x52, 0x57, + 0x86, 0xe8, 0x8e, 0x9c, 0x43, 0x50, 0xd6, 0xe5, 0x5c, 0xde, 0x55, 0x0f, 0x66, 0xe0, 0xba, 0xd7, + 0x73, 0xd0, 0x5d, 0xa9, 0x54, 0xc2, 0x07, 0xdf, 0xb0, 0x6e, 0x0d, 0xe5, 0x32, 0x01, 0x48, 0x77, + 0xd1, 0xc2, 0x39, 0xe4, 0xab, 0x6a, 0xcd, 0x36, 0x89, 0xa2, 0x9d, 0x07, 0xef, 0x09, 0xd4, 0xfd, + 0xfc, 0xb9, 0xb3, 0x20, 0xee, 0x8f, 0x3e, 0xa0, 0x1e, 0x18, 0x4e, 0x46, 0x4a, 0x5e, 0x1d, 0x97, + 0x4d, 0x84, 0x40, 0x4d, 0xfa, 0x74, 0xb6, 0x28, 0xe2, 0xea, 0x6b, 0x50, 0xd4, 0x75, 0x8e, 0xba, + 0x67, 0x8b, 0x4d, 0x04, 0x45, 0xce, 0xce, 0x37, 0x3d, 0xe1, 0x3e, 0xef, 0x01, 0x9e, 0x74, 0xe0, + 0xab, 0x3b, 0x42, 0xcc, 0xf1, 0x68, 0xca, 0x77, 0xbd, 0xed, 0x4a, 0x12, 0x92, 0xbe, 0x66, 0xe3, + 0x3a, 0xba, 0x78, 0xe5, 0x0a, 0xd5, 0x13, 0x91, 0xf4, 0xc6, 0xf3, 0x46, 0xc2, 0x26, 0x42, 0xf8, + 0x3e, 0x42, 0x75, 0xad, 0x3d, 0xd4, 0xeb, 0x42, 0xb4, 0x90, 0xbe, 0x1e, 0x46, 0x07, 0xf8, 0xcd, + 0xf7, 0x26, 0x17, 0xdb, 0xf9, 0x65, 0x12, 0xd4, 0xf7, 0x3d, 0x49, 0xdc, 0x6a, 0x42, 0x18, 0xf8, + 0xea, 0xbe, 0x79, 0xd3, 0x7f, 0xc3, 0xf6, 0x6a, 0x67, 0x16, 0xd0, 0xe5, 0xb1, 0x0d, 0xde, 0xbb, + 0x90, 0xf4, 0xd5, 0xeb, 0x29, 0x76, 0xe2, 0xe6, 0x8e, 0x11, 0xe4, 0x8d, 0x96, 0x22, 0xc2, 0x42, + 0x8d, 0xbe, 0x79, 0x13, 0x00, 0x1d, 0x83, 0x5b, 0x85, 0x8d, 0x3b, 0x22, 0x72, 0xf4, 0x13, 0x7e, + 0x46, 0x41, 0x05, 0xf5, 0x66, 0x4f, 0xdc, 0x21, 0x20, 0xbd, 0x2f, 0x5b, 0xf2, 0x2d, 0x5c, 0x20, + 0xa0, 0xf0, 0x1f, 0xda, 0xdd, 0xa3, 0xaa, 0x7e, 0x5c, 0x8a, 0xa4, 0xaf, 0x5a, 0xbd, 0x9c, 0x5c, + 0xbc, 0xe1, 0x08, 0x8a, 0xf4, 0x3e, 0x75, 0x12, 0x71, 0xfa, 0x9a, 0x09, 0x90, 0xf3, 0xa2, 0xd1, + 0xde, 0x2f, 0x03, 0x57, 0x5f, 0x40, 0xa3, 0x07, 0x0e, 0xc1, 0xf9, 0x0c, 0x2b, 0x44, 0xf3, 0x67, + 0x21, 0xe9, 0x81, 0x6b, 0x3a, 0x18, 0x26, 0xc0, 0x08, 0x51, 0x77, 0xf0, 0x49, 0x01, 0xbf, 0xb9, + 0x97, 0xc7, 0x2e, 0x01, 0xb6, 0x0c, 0x47, 0x64, 0x62, 0x21, 0x2e, 0x3d, 0xe5, 0x72, 0xa8, 0x1c, + 0xd1, 0x3d, 0x64, 0xba, 0x03, 0x54, 0xad, 0x5d, 0x89, 0x4b, 0x5f, 0x32, 0x61, 0x8c, 0x24, 0x34, + 0xb0, 0xe7, 0xb5, 0x01, 0xf5, 0xa6, 0x49, 0x36, 0x63, 0x79, 0x0d, 0x3e, 0x95, 0x84, 0x07, 0xd7, + 0xbb, 0x38, 0x11, 0x9d, 0xeb, 0xd6, 0x41, 0xb7, 0x4d, 0xeb, 0xdc, 0xb7, 0x37, 0xf8, 0x7a, 0x48, + 0x22, 0xf7, 0x4a, 0x13, 0xe2, 0x15, 0xcd, 0x4c, 0xd3, 0xfa, 0xcf, 0xdc, 0xd2, 0x5b, 0x0b, 0x35, + 0xe2, 0x1a, 0x71, 0xce, 0x2e, 0x47, 0x0c, 0xa9, 0xee, 0x00, 0x4d, 0x51, 0xe1, 0x7a, 0xd2, 0x0f, + 0xb8, 0xd2, 0x69, 0xe3, 0x2b, 0x97, 0x2e, 0xaa, 0x73, 0xda, 0x2c, 0xf6, 0x76, 0xc7, 0x37, 0x6c, + 0x12, 0x7b, 0x03, 0xe7, 0x8e, 0x5c, 0x6f, 0x49, 0xb1, 0x9e, 0xee, 0xe5, 0xe5, 0x65, 0xa8, 0x1c, + 0xf9, 0xfd, 0x77, 0xff, 0xe1, 0x12, 0x7d, 0x43, 0x80, 0x17, 0x39, 0x7a, 0x56, 0x57, 0xfe, 0xc5, + 0xa7, 0xa0, 0xf2, 0xdd, 0xf7, 0xff, 0xec, 0x9d, 0x89, 0x5f, 0x13, 0xd7, 0x16, 0xc7, 0xfb, 0x5f, + 0xbc, 0xf7, 0xda, 0x5a, 0x14, 0x77, 0xad, 0x5b, 0x15, 0xad, 0xf5, 0xa9, 0x7d, 0xad, 0xda, 0xd6, + 0x7d, 0xa9, 0xd6, 0x3e, 0x6b, 0xfb, 0xac, 0x56, 0x16, 0x51, 0xeb, 0xc6, 0xbe, 0x2f, 0x82, 0xec, + 0x82, 0x80, 0x80, 0x28, 0xe0, 0x02, 0x88, 0x0b, 0x0a, 0x88, 0x82, 0x08, 0xa8, 0xb8, 0x20, 0x04, + 0x65, 0x87, 0x04, 0x42, 0x20, 0x40, 0x16, 0x08, 0x7b, 0xf6, 0xc4, 0x77, 0x71, 0x70, 0x98, 0xcc, + 0x4c, 0x26, 0x93, 0x98, 0x15, 0xe7, 0xfb, 0x39, 0x1f, 0x3f, 0x71, 0x32, 0x73, 0xb9, 0x73, 0xf2, + 0xcb, 0xcd, 0xbd, 0x73, 0xef, 0x3d, 0x87, 0xd3, 0x85, 0x5b, 0x66, 0x45, 0x8b, 0x4a, 0xf8, 0x8c, + 0x4a, 0xba, 0x2e, 0x6d, 0xa8, 0xa1, 0xfd, 0x0e, 0x50, 0x0c, 0x0f, 0x75, 0x9d, 0x70, 0xd4, 0xe1, + 0xf6, 0xc5, 0x4d, 0xaa, 0x7e, 0x87, 0x1e, 0xcb, 0xc1, 0x26, 0x25, 0x11, 0xe5, 0x52, 0x37, 0xbf, + 0xc3, 0xc6, 0xf1, 0x76, 0x95, 0x0f, 0x0e, 0x62, 0x8b, 0xa5, 0x77, 0x0d, 0x21, 0x5d, 0xaf, 0x43, + 0x00, 0x65, 0x23, 0xf8, 0x1d, 0x42, 0xca, 0xe9, 0x06, 0x8d, 0x0c, 0x50, 0xba, 0x8e, 0x7e, 0x07, + 0x5e, 0x86, 0x72, 0xc3, 0x1d, 0x76, 0xb0, 0x83, 0x5e, 0x30, 0x18, 0x9a, 0x83, 0x1e, 0x80, 0xaf, + 0x1b, 0x99, 0x24, 0x71, 0xe0, 0xe3, 0xe9, 0x3a, 0x71, 0xb8, 0x6d, 0xf3, 0x0f, 0xa0, 0x29, 0xc4, + 0xd6, 0x03, 0x37, 0xae, 0x66, 0x35, 0x73, 0x5c, 0xf5, 0xc7, 0x23, 0x4a, 0xb5, 0x75, 0x87, 0x8a, + 0xdf, 0x05, 0x06, 0xf4, 0x3b, 0x0c, 0xe8, 0xdb, 0xf4, 0x65, 0x5d, 0x03, 0x23, 0x5b, 0x5e, 0x68, + 0x20, 0xc7, 0xc7, 0x95, 0x20, 0x4f, 0x1c, 0xba, 0x9d, 0x81, 0xf0, 0xf5, 0xd6, 0x31, 0x0c, 0x2f, + 0x49, 0xa4, 0x5d, 0x9d, 0xdc, 0x20, 0x1f, 0xb4, 0xf0, 0xfd, 0xdc, 0xb1, 0x67, 0xc6, 0xe4, 0x34, + 0x21, 0x1a, 0x7a, 0xed, 0x7e, 0x63, 0x8d, 0xef, 0x77, 0xad, 0x30, 0x81, 0xdf, 0x21, 0x40, 0xd3, + 0x81, 0x0c, 0x12, 0x00, 0x8c, 0x6d, 0xff, 0x27, 0xf6, 0x34, 0xa7, 0xa4, 0x57, 0x63, 0xee, 0xd3, + 0x32, 0x81, 0x35, 0x39, 0xbf, 0xeb, 0x12, 0x5a, 0x40, 0x2f, 0x98, 0xcc, 0xef, 0x10, 0x52, 0x2e, + 0x67, 0x34, 0xda, 0xce, 0x7b, 0xd7, 0x83, 0x9e, 0x00, 0xea, 0x84, 0x11, 0xc4, 0xb6, 0x0d, 0xdf, + 0x4c, 0xf4, 0xb6, 0x47, 0x02, 0x28, 0xbf, 0x6b, 0x86, 0xb1, 0x64, 0xde, 0xf8, 0x30, 0x24, 0x26, + 0x1c, 0xf5, 0xae, 0xe7, 0xd5, 0xf1, 0x4e, 0x3d, 0xf9, 0x32, 0x29, 0xbf, 0x93, 0x82, 0xb5, 0x7b, + 0x1b, 0xec, 0x7a, 0x51, 0x23, 0x3a, 0xe9, 0x24, 0xec, 0xc1, 0xd0, 0x6c, 0xb2, 0xad, 0xbc, 0x88, + 0xf2, 0x3b, 0x19, 0x14, 0x42, 0x21, 0xec, 0x77, 0xd6, 0xcf, 0xe8, 0xf4, 0x3e, 0xae, 0x29, 0x63, + 0x31, 0xc2, 0x1c, 0xfc, 0xc9, 0x06, 0x1d, 0xa1, 0xfc, 0x4e, 0x96, 0xbe, 0x8c, 0xcb, 0xb0, 0xeb, + 0x51, 0x79, 0x20, 0x68, 0x88, 0x91, 0x14, 0xbb, 0x97, 0x54, 0x0c, 0x5d, 0xca, 0xef, 0x5a, 0xc0, + 0x5c, 0xff, 0x1d, 0xe4, 0x91, 0xf6, 0xdd, 0xdb, 0x50, 0x6f, 0xc1, 0x8b, 0xb3, 0xa2, 0x30, 0xd9, + 0x52, 0x70, 0x41, 0xfa, 0xbd, 0x93, 0xf2, 0x3b, 0x31, 0xfd, 0xb7, 0xb3, 0x60, 0xc9, 0x2b, 0xc4, + 0x2a, 0xce, 0x72, 0x49, 0x1e, 0x0b, 0xa6, 0xec, 0x9e, 0x5c, 0x41, 0xa6, 0xa8, 0x09, 0xe5, 0xf7, + 0x4e, 0x36, 0xfb, 0xd6, 0x4d, 0x1d, 0xb3, 0xee, 0x91, 0x84, 0xfe, 0xe5, 0x34, 0xc8, 0x29, 0xbd, + 0x97, 0x12, 0x91, 0xc7, 0xa3, 0xee, 0x8e, 0x8d, 0xa1, 0x48, 0xc6, 0x95, 0x9a, 0x50, 0x7e, 0x9f, + 0x37, 0x6b, 0xba, 0xa1, 0x37, 0x0d, 0x77, 0x9d, 0x3c, 0x0c, 0x39, 0xa5, 0xdb, 0xc3, 0x09, 0x79, + 0xbc, 0xae, 0x63, 0x50, 0xab, 0xc7, 0x35, 0x13, 0xca, 0xef, 0x56, 0x9f, 0xfe, 0xe3, 0x72, 0x6a, + 0xca, 0x51, 0x47, 0x07, 0xc3, 0x55, 0x08, 0x7e, 0xbe, 0xda, 0xb2, 0x72, 0x29, 0xf2, 0xf8, 0x90, + 0x48, 0xed, 0xbe, 0x77, 0x5c, 0x26, 0x8e, 0xdf, 0x23, 0x42, 0x43, 0xdc, 0x9c, 0x47, 0x35, 0x68, + 0xd0, 0xd0, 0x10, 0x83, 0x0f, 0xf2, 0x20, 0xa7, 0xd0, 0xe7, 0x4e, 0x45, 0xbd, 0x05, 0xfb, 0xb1, + 0xba, 0x5d, 0x73, 0x3c, 0xaf, 0x89, 0xe3, 0x77, 0xd8, 0xdd, 0x0b, 0xe6, 0xce, 0x82, 0x76, 0x4d, + 0x62, 0xf1, 0xf3, 0xf6, 0xc2, 0x3d, 0x4e, 0x1e, 0x51, 0x53, 0x3d, 0xfc, 0xd3, 0x8a, 0x7a, 0xeb, + 0xa0, 0xfb, 0x58, 0x4c, 0xe4, 0x17, 0x74, 0xfc, 0xc8, 0xbd, 0x2a, 0xe5, 0x4c, 0x0c, 0xbf, 0xf7, + 0xf7, 0xf5, 0x41, 0x6b, 0x4b, 0x80, 0xfd, 0xb4, 0x76, 0x6c, 0x57, 0x7c, 0x56, 0x66, 0xc6, 0xc6, + 0x1f, 0xd7, 0xce, 0xb4, 0xb6, 0x3a, 0x7e, 0xc4, 0x71, 0xf6, 0x34, 0x6b, 0x70, 0x04, 0xbc, 0x1e, + 0x2d, 0xc1, 0xcb, 0x63, 0xc5, 0xd2, 0x25, 0x8f, 0x4b, 0x48, 0x65, 0x63, 0x46, 0x21, 0xa6, 0x37, + 0xa9, 0xf5, 0xfb, 0xfb, 0x58, 0xd4, 0x4f, 0x1a, 0x34, 0xcf, 0x84, 0x4c, 0x10, 0xbf, 0xaf, 0x5f, + 0xf7, 0x7d, 0x5a, 0xca, 0x25, 0xe4, 0x3e, 0x79, 0xb9, 0x5c, 0x0e, 0xfc, 0x0e, 0xde, 0x6a, 0x6c, + 0xa8, 0xe7, 0xf1, 0x46, 0xe3, 0x4c, 0x97, 0xbf, 0x7c, 0x01, 0xf9, 0xfd, 0xce, 0xed, 0x5b, 0xe0, + 0x5f, 0x28, 0x15, 0xb1, 0xb6, 0x90, 0xf1, 0xfb, 0xe3, 0x7a, 0xcd, 0x01, 0xc0, 0x27, 0x88, 0xdf, + 0x51, 0x6d, 0xba, 0xfd, 0x5f, 0xfb, 0xf7, 0xfc, 0xb2, 0x13, 0xf2, 0x3b, 0x9d, 0xde, 0x2c, 0x14, + 0x8e, 0x06, 0x0a, 0x7c, 0xf9, 0xe2, 0x39, 0xe4, 0x77, 0x48, 0xe9, 0xa8, 0x80, 0x80, 0x24, 0x11, + 0x33, 0x9a, 0x35, 0xfa, 0xbd, 0x54, 0x4b, 0xbf, 0xb3, 0x2d, 0xd4, 0xef, 0x39, 0x77, 0xb2, 0x51, + 0x8b, 0x3b, 0xa0, 0x88, 0x05, 0x94, 0xdf, 0x75, 0xc6, 0xbc, 0xc6, 0xab, 0x6f, 0x49, 0xfa, 0xbd, + 0x8e, 0xf2, 0xbb, 0xbe, 0x11, 0xb7, 0xd0, 0xd5, 0xfb, 0x7d, 0x2c, 0xab, 0x58, 0x49, 0x1d, 0x4e, + 0xda, 0x02, 0x14, 0xa4, 0xfc, 0x5e, 0x47, 0xf9, 0xfd, 0x3d, 0x64, 0xfc, 0x5e, 0x54, 0xc3, 0xd5, + 0x58, 0x0e, 0xa5, 0x77, 0xed, 0x90, 0xb2, 0xdb, 0x61, 0xbf, 0x2b, 0x65, 0x32, 0xe4, 0x5b, 0x76, + 0x3e, 0x63, 0xe9, 0x51, 0x92, 0x1e, 0x30, 0x34, 0x96, 0xd3, 0xd1, 0x3b, 0x1e, 0x1a, 0xbf, 0x7f, + 0x44, 0x65, 0x41, 0xca, 0xf8, 0x7a, 0x0a, 0xba, 0x7e, 0x92, 0x60, 0xe9, 0x80, 0xd9, 0xf9, 0x5d, + 0x21, 0x1c, 0x81, 0xfd, 0x22, 0xe5, 0xa8, 0xec, 0x59, 0x71, 0x8e, 0x7b, 0x0e, 0xf9, 0xd1, 0xed, + 0x62, 0xa5, 0xc6, 0x72, 0x62, 0xf3, 0xde, 0x27, 0x6c, 0x52, 0x9d, 0x10, 0x97, 0xf5, 0xf0, 0xe1, + 0xf2, 0x65, 0x3c, 0xcd, 0xdf, 0x1b, 0x03, 0x61, 0x76, 0x7e, 0x07, 0xd0, 0xe7, 0x4e, 0x85, 0xfc, + 0xd2, 0x97, 0x75, 0x0d, 0x79, 0xfc, 0x4c, 0xf6, 0xf8, 0xb2, 0x0e, 0xae, 0xa6, 0x47, 0x34, 0xb6, + 0x9e, 0x63, 0x4b, 0xec, 0xbd, 0x53, 0xab, 0x90, 0xc7, 0x07, 0x1f, 0xde, 0x1f, 0xf3, 0xfb, 0x4c, + 0x2b, 0xbd, 0xd7, 0x9c, 0x3c, 0xe6, 0xe8, 0x77, 0xd6, 0x7f, 0x77, 0x40, 0xae, 0xc1, 0xa6, 0x93, + 0x81, 0x43, 0xba, 0x1f, 0x0b, 0x7d, 0x44, 0x50, 0x82, 0xe7, 0xe5, 0xf1, 0x74, 0x2a, 0xcf, 0x1a, + 0x55, 0x36, 0xfb, 0x72, 0x4f, 0x8f, 0x2d, 0xdd, 0x61, 0xae, 0xff, 0x4e, 0xef, 0x35, 0x27, 0x8f, + 0x39, 0xfa, 0x9d, 0x17, 0x15, 0x32, 0xf6, 0x48, 0xf2, 0x9b, 0xaf, 0x50, 0x6f, 0x05, 0xdf, 0x6e, + 0x84, 0x1d, 0x7a, 0x22, 0xfe, 0x25, 0x07, 0x2f, 0x09, 0x96, 0x4b, 0xca, 0x78, 0xc2, 0x26, 0x4f, + 0xcc, 0x2e, 0x06, 0xc6, 0xe2, 0xb9, 0x50, 0xe1, 0xbc, 0x88, 0x60, 0x43, 0xdd, 0x00, 0x09, 0xcc, + 0xd1, 0xef, 0xf2, 0x3e, 0x01, 0xdc, 0x04, 0x0f, 0x3d, 0x2a, 0x40, 0xbd, 0xeb, 0x72, 0x71, 0x7c, + 0xcb, 0x28, 0x30, 0xd7, 0xa4, 0x57, 0xe1, 0x77, 0x9b, 0x32, 0x9e, 0xb6, 0x9f, 0xcd, 0x69, 0xf2, + 0x48, 0xa1, 0xc1, 0xcf, 0xce, 0x80, 0xd9, 0x79, 0xdf, 0x43, 0x5d, 0x3b, 0x54, 0xfa, 0x68, 0x7c, + 0xd5, 0x42, 0xcd, 0x1b, 0x63, 0xdd, 0x10, 0x0e, 0xe6, 0xe8, 0x77, 0x40, 0xfb, 0x6f, 0x3b, 0xc7, + 0x5a, 0x83, 0x8d, 0x6b, 0xb0, 0xef, 0xfa, 0xc6, 0x3e, 0x41, 0xba, 0x1e, 0xd7, 0x0e, 0xf9, 0x17, + 0x74, 0x60, 0x66, 0xc0, 0x59, 0xbb, 0xb7, 0xbe, 0x7f, 0xb8, 0x6f, 0x63, 0x94, 0xfb, 0x50, 0x8b, + 0x99, 0xfa, 0x7d, 0x20, 0xe7, 0x16, 0x2c, 0xcc, 0x9e, 0xb8, 0xb3, 0xd8, 0x13, 0x42, 0xee, 0x34, + 0x11, 0x38, 0x3d, 0x38, 0x0b, 0x67, 0xe1, 0x63, 0x4f, 0xfc, 0x59, 0xb8, 0xcc, 0xbe, 0x1b, 0xe9, + 0x86, 0xbf, 0x09, 0x22, 0xcc, 0xd4, 0xef, 0x80, 0x76, 0xc4, 0x4a, 0x26, 0xdc, 0xb5, 0xda, 0x0a, + 0xa5, 0xf2, 0x62, 0x51, 0xab, 0x4f, 0x4a, 0xa5, 0x7d, 0x40, 0xc1, 0xe8, 0xbe, 0xe4, 0x80, 0x42, + 0xb7, 0x0b, 0xa0, 0xcd, 0x69, 0x46, 0xa5, 0x6a, 0x82, 0x40, 0x76, 0x1f, 0x99, 0x3f, 0xfd, 0xc7, + 0xf0, 0xd5, 0xd7, 0x80, 0xf9, 0xfa, 0x5d, 0x21, 0x11, 0xc3, 0x9e, 0xa2, 0xcf, 0x9f, 0x21, 0xac, + 0xae, 0xd2, 0x7c, 0x8d, 0x1a, 0x24, 0x6d, 0x4c, 0xd0, 0xb0, 0x98, 0xc3, 0x70, 0x09, 0x66, 0xdc, + 0xef, 0x4a, 0xa5, 0x12, 0xb5, 0x4f, 0xfe, 0x52, 0xf2, 0x05, 0x13, 0xd6, 0x0c, 0x00, 0xfa, 0xef, + 0xb0, 0xb3, 0x9a, 0xf1, 0xd6, 0xef, 0x91, 0x41, 0x31, 0x32, 0xd2, 0x3c, 0x6b, 0xf2, 0x78, 0xab, + 0x85, 0xb7, 0xd6, 0xde, 0xf8, 0xa8, 0xe8, 0xdd, 0xee, 0xaf, 0xfd, 0xda, 0xee, 0x93, 0x37, 0x34, + 0xfc, 0xf7, 0x7d, 0x4a, 0xc8, 0xf8, 0xd1, 0x61, 0x5a, 0x5d, 0xde, 0x93, 0x70, 0x0e, 0x79, 0x39, + 0x2f, 0xd4, 0x34, 0x41, 0xa2, 0xb1, 0xa8, 0xdd, 0x27, 0xff, 0xaa, 0xfc, 0xa5, 0x49, 0x2a, 0x84, + 0x42, 0xa9, 0x50, 0xf0, 0x11, 0xe9, 0xc5, 0x80, 0x31, 0xbe, 0x5e, 0x88, 0xca, 0xbb, 0x84, 0xcb, + 0x40, 0xde, 0x5d, 0xe6, 0xda, 0x55, 0x2a, 0x4e, 0x0f, 0x0b, 0x54, 0xca, 0xb5, 0x4e, 0x2c, 0x66, + 0x20, 0xd0, 0x7e, 0x8f, 0x8d, 0x3e, 0x0b, 0x9c, 0x3e, 0xcd, 0xea, 0x73, 0x93, 0xd4, 0x46, 0x1d, + 0x3d, 0x09, 0x31, 0x48, 0x0f, 0x8e, 0x7a, 0xdf, 0x66, 0x1e, 0x18, 0x79, 0xf6, 0xdf, 0xcc, 0x90, + 0x71, 0x39, 0xe0, 0xb3, 0x79, 0xfb, 0xee, 0x13, 0x02, 0x1d, 0xff, 0x81, 0xbc, 0x3b, 0x1c, 0x7f, + 0x4f, 0x86, 0xcd, 0x7c, 0xd4, 0xf9, 0xbd, 0xc9, 0xf1, 0xa6, 0xbe, 0x09, 0x15, 0xf0, 0xf7, 0xc9, + 0xf7, 0x10, 0x6e, 0x75, 0x34, 0x09, 0xe2, 0x16, 0x3a, 0x6b, 0xc7, 0x46, 0x94, 0x37, 0xc9, 0x18, + 0x73, 0xf3, 0x3a, 0x31, 0xbd, 0xd1, 0xd4, 0xd5, 0x47, 0xf3, 0x49, 0xfe, 0xbd, 0x7b, 0x28, 0xb3, + 0x3d, 0xb0, 0x1f, 0x7b, 0xd0, 0x4c, 0x2c, 0x27, 0x2d, 0xe5, 0xa6, 0x87, 0x6b, 0xd6, 0xb1, 0xc3, + 0xea, 0x0c, 0xe9, 0xf1, 0xb6, 0xad, 0x3f, 0x0d, 0x95, 0x14, 0x69, 0xf6, 0x81, 0x29, 0xc0, 0xd1, + 0xbb, 0xf9, 0x23, 0x65, 0x77, 0xf0, 0x22, 0xcf, 0xb4, 0x6d, 0x5a, 0x07, 0xcf, 0x60, 0x8c, 0xdb, + 0x8c, 0x2f, 0xda, 0x36, 0xaf, 0xe3, 0x45, 0x85, 0x80, 0xef, 0x87, 0xa9, 0xab, 0x49, 0x84, 0x45, + 0xfa, 0x1d, 0x09, 0x68, 0xd3, 0x25, 0xad, 0x0c, 0x71, 0x53, 0xbd, 0x84, 0xd9, 0x82, 0x3b, 0xbc, + 0x32, 0x4f, 0x2c, 0xde, 0xef, 0x14, 0x1f, 0x8e, 0x50, 0x22, 0x6f, 0xe8, 0x1c, 0xcc, 0x2e, 0xef, + 0x8c, 0xcc, 0x69, 0xf6, 0xcf, 0xaa, 0xf7, 0xcf, 0xa8, 0xf1, 0x4e, 0xab, 0xf2, 0x48, 0x7e, 0xe5, + 0x92, 0xf0, 0xf2, 0xe4, 0xb9, 0x67, 0xce, 0xf1, 0xcf, 0xdd, 0x93, 0xca, 0xbd, 0x53, 0x68, 0x3e, + 0x57, 0xde, 0xf8, 0x67, 0xd6, 0x05, 0xdd, 0x6a, 0x4c, 0x2a, 0x6c, 0x2d, 0x6b, 0xec, 0x69, 0xef, + 0x11, 0x8a, 0xa5, 0xe6, 0xd2, 0x3f, 0x24, 0x09, 0x25, 0xf7, 0x8f, 0x91, 0x4a, 0x66, 0x7f, 0x78, + 0x0e, 0xdd, 0xe7, 0x6a, 0xf5, 0xa1, 0xa0, 0x22, 0x5b, 0xcf, 0x3c, 0x8d, 0xcf, 0x76, 0x09, 0xcc, + 0xd6, 0x3b, 0xdf, 0x29, 0xf6, 0x79, 0x40, 0x56, 0xfd, 0xed, 0x97, 0x9d, 0x03, 0x42, 0xcd, 0x71, + 0x15, 0x4c, 0xcb, 0x27, 0x4a, 0x25, 0x18, 0xc2, 0x69, 0x66, 0xcd, 0xb7, 0x2b, 0x83, 0x02, 0xfc, + 0xc9, 0x9c, 0x49, 0x61, 0x9e, 0xbc, 0x66, 0xf6, 0x85, 0x67, 0x37, 0x38, 0xc7, 0x3d, 0x3b, 0xe8, + 0x76, 0x97, 0x84, 0xe9, 0xa8, 0x7e, 0x3b, 0xef, 0x7b, 0x41, 0x19, 0xd5, 0x29, 0x25, 0xac, 0xde, + 0x21, 0x89, 0x66, 0xf5, 0x19, 0x1d, 0x52, 0xad, 0xfb, 0x2f, 0x3b, 0xb6, 0x41, 0x4f, 0x6c, 0x62, + 0xa3, 0x71, 0xe6, 0x1f, 0x28, 0xcc, 0x99, 0x56, 0xee, 0xf0, 0xe9, 0x9b, 0x0d, 0xa4, 0x62, 0x5b, + 0xba, 0xe7, 0xda, 0x07, 0x14, 0x1e, 0x8d, 0x7c, 0xec, 0x7a, 0xe1, 0x95, 0x47, 0xda, 0x6b, 0xaf, + 0x6b, 0x35, 0x3e, 0x19, 0xb5, 0xfe, 0xd7, 0xeb, 0xfd, 0xae, 0xd7, 0xf9, 0x66, 0xd4, 0xfa, 0x5c, + 0xab, 0xf1, 0x4a, 0xa5, 0x9d, 0x38, 0xf7, 0xcc, 0x21, 0xb0, 0xd0, 0xce, 0x3b, 0x9f, 0x8c, 0xf4, + 0xdd, 0x93, 0x2b, 0xe2, 0x1e, 0xb4, 0x98, 0xda, 0x01, 0x2a, 0x68, 0x90, 0xbb, 0x4c, 0x26, 0xfb, + 0x7e, 0xf5, 0x4a, 0xe4, 0x83, 0x61, 0x2f, 0x77, 0x57, 0xe3, 0xd4, 0x8c, 0xe2, 0x03, 0x49, 0x29, + 0x6e, 0x73, 0x3a, 0xf3, 0x90, 0x68, 0xfa, 0x39, 0xb8, 0xc8, 0xe5, 0x22, 0x2d, 0xe2, 0x4e, 0xe3, + 0xf3, 0xa6, 0xde, 0x41, 0x91, 0x4c, 0x73, 0x89, 0x08, 0xe4, 0x0a, 0x25, 0x83, 0x33, 0x7c, 0xa5, + 0xb4, 0x0d, 0x7c, 0x25, 0x8e, 0x84, 0x15, 0x13, 0xfc, 0x15, 0x87, 0xc0, 0x87, 0xbe, 0x99, 0x75, + 0x8d, 0x9d, 0x43, 0x06, 0xba, 0x4d, 0xad, 0x20, 0x92, 0xfb, 0xf0, 0xf0, 0xf0, 0x92, 0x85, 0xf3, + 0x50, 0xf3, 0x4f, 0xc0, 0xec, 0xfe, 0xda, 0x6f, 0xb4, 0xfa, 0x51, 0xe8, 0xc0, 0xe5, 0xe2, 0x56, + 0xc7, 0xc0, 0x42, 0x75, 0x4d, 0xb8, 0x73, 0xdc, 0xf3, 0xf4, 0x52, 0x26, 0x7f, 0x50, 0xcf, 0x9d, + 0x0d, 0x5a, 0x8b, 0xc0, 0x2f, 0xb3, 0xce, 0xc1, 0xef, 0xbe, 0x3a, 0xdd, 0xbb, 0x5f, 0xa9, 0x16, + 0x4b, 0xb4, 0xfb, 0x52, 0xe9, 0x1d, 0xb5, 0x72, 0xe7, 0x72, 0x38, 0xb3, 0xa7, 0x4d, 0xc1, 0x6a, + 0x1d, 0xb2, 0xed, 0x98, 0xf7, 0xe3, 0xca, 0x00, 0x00, 0x15, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x9b, + 0x37, 0xea, 0x10, 0x65, 0x8d, 0xc2, 0xd0, 0x94, 0x56, 0x73, 0x8e, 0x45, 0x97, 0xe1, 0xaa, 0xcd, + 0x29, 0xb9, 0xf2, 0x5a, 0x09, 0xd3, 0x08, 0x75, 0x60, 0x72, 0x87, 0x42, 0x33, 0x6b, 0xd4, 0x89, + 0xde, 0x3f, 0xa3, 0x76, 0x60, 0xc4, 0x64, 0x23, 0x5a, 0x7c, 0xb9, 0x83, 0x3e, 0x4c, 0x72, 0x62, + 0x42, 0x42, 0x7c, 0x2c, 0x6c, 0xbb, 0x77, 0x6e, 0x77, 0x73, 0x3a, 0x85, 0x3c, 0x92, 0x97, 0x73, + 0xd7, 0xc8, 0x75, 0xa5, 0x20, 0x00, 0xf4, 0x16, 0xfc, 0xd3, 0xaa, 0x70, 0x15, 0xe6, 0x9b, 0x4a, + 0x13, 0x0c, 0x9a, 0x20, 0x21, 0x77, 0x54, 0x4e, 0xb3, 0x63, 0x60, 0x01, 0xb6, 0x3e, 0x87, 0x43, + 0x8a, 0xb3, 0x9f, 0xeb, 0x2d, 0xe2, 0xb9, 0x56, 0x90, 0x7d, 0x10, 0x19, 0x7c, 0x3a, 0xe0, 0xd9, + 0xd3, 0xa7, 0x06, 0xad, 0x0a, 0x85, 0xce, 0xe4, 0x55, 0x74, 0xe1, 0x0e, 0x46, 0x3d, 0x92, 0xca, + 0x69, 0xad, 0x9a, 0xf7, 0xb4, 0x23, 0x91, 0x76, 0xb1, 0x45, 0x75, 0x35, 0x7d, 0x59, 0xe9, 0xbd, + 0x17, 0xe2, 0xf9, 0xe7, 0x22, 0xf9, 0x51, 0x21, 0xfc, 0x73, 0x11, 0xbd, 0x17, 0xe2, 0xfa, 0xb2, + 0xae, 0x0d, 0xbf, 0x28, 0x43, 0xed, 0x00, 0x21, 0x43, 0xc8, 0xed, 0x46, 0x78, 0x23, 0x20, 0xd2, + 0x7c, 0xb4, 0x4f, 0x76, 0xf5, 0xe1, 0x50, 0x72, 0xb7, 0x78, 0xe2, 0xee, 0x33, 0xb0, 0x69, 0x23, + 0x6c, 0xdd, 0x73, 0x42, 0x49, 0x47, 0xb2, 0x1e, 0xc8, 0xcd, 0xe6, 0x06, 0x78, 0xc1, 0xd9, 0xa9, + 0x34, 0x5a, 0xeb, 0xea, 0x65, 0x1c, 0x6f, 0x17, 0x41, 0x7a, 0x9a, 0x8c, 0xaf, 0x79, 0x3f, 0x25, + 0x60, 0x70, 0x44, 0xea, 0x96, 0xfa, 0x1a, 0xab, 0x78, 0xaf, 0xb4, 0xaa, 0x1e, 0x7d, 0x0f, 0x21, + 0x88, 0xa1, 0xe4, 0x6e, 0xd9, 0xc4, 0x03, 0xad, 0x7b, 0xa3, 0xb5, 0xee, 0x94, 0x54, 0xc1, 0xe6, + 0x8f, 0x68, 0xbc, 0xb6, 0x3f, 0xfb, 0x46, 0xc7, 0x81, 0xbd, 0xcd, 0xef, 0xf7, 0x90, 0xe9, 0x66, + 0x6d, 0x1b, 0xd6, 0x08, 0xd2, 0x92, 0xc9, 0x54, 0x35, 0xf8, 0x66, 0x03, 0xb6, 0x99, 0xf7, 0x48, + 0xae, 0x60, 0x70, 0x86, 0x3f, 0xd8, 0x0d, 0x64, 0xa1, 0xe4, 0x6e, 0xc1, 0x5c, 0x2f, 0xeb, 0xb0, + 0x0f, 0x40, 0x3f, 0x81, 0x71, 0x4e, 0x2c, 0x6f, 0xd1, 0x24, 0x20, 0xc1, 0xd5, 0x14, 0xe4, 0x6a, + 0x74, 0xac, 0xd1, 0xe7, 0x4e, 0x6d, 0x5d, 0xb5, 0x0c, 0x48, 0xb9, 0x6d, 0xdb, 0x7a, 0xe6, 0xfa, + 0xef, 0x5b, 0xbf, 0x5f, 0x41, 0x5f, 0x30, 0x93, 0x68, 0x25, 0xde, 0x86, 0xef, 0x05, 0x29, 0x9a, + 0x97, 0x8c, 0x47, 0xe7, 0x36, 0x63, 0x9f, 0xd9, 0xfb, 0xa4, 0xd7, 0x48, 0x64, 0x0a, 0x3d, 0xb9, + 0x44, 0x03, 0x94, 0xdc, 0x2d, 0x95, 0x3a, 0xf6, 0xa0, 0x7b, 0xe2, 0x4b, 0x94, 0x74, 0x4e, 0xc4, + 0x94, 0x55, 0xb6, 0x12, 0xa5, 0xff, 0x91, 0xb0, 0xda, 0x3a, 0x8f, 0xda, 0xe1, 0xb7, 0xd3, 0x9b, + 0x7f, 0xe0, 0x85, 0xf8, 0x0f, 0x97, 0x3d, 0x56, 0x08, 0xf1, 0x7f, 0x19, 0x14, 0x42, 0xa1, 0xa8, + 0xe6, 0x0d, 0x2f, 0x3c, 0x08, 0xb9, 0xfd, 0x46, 0xa5, 0x84, 0x2d, 0x3f, 0x0e, 0x16, 0xa0, 0xf7, + 0xef, 0xa1, 0x18, 0x4f, 0x98, 0x0a, 0xf7, 0xbb, 0x3c, 0xef, 0x45, 0x6a, 0x19, 0x58, 0x5e, 0x67, + 0x28, 0xb9, 0x5b, 0x24, 0x0a, 0xa5, 0x12, 0xab, 0x1b, 0x7b, 0xbf, 0x07, 0x17, 0x8b, 0x98, 0x04, + 0x57, 0x0d, 0xe4, 0xde, 0x46, 0x6d, 0x03, 0x80, 0x8c, 0x6d, 0xb7, 0x4f, 0x54, 0xfd, 0x9a, 0xe4, + 0x9f, 0x66, 0xb3, 0x3b, 0x1c, 0x0e, 0x1e, 0x90, 0x72, 0xba, 0x38, 0x3e, 0x6e, 0x38, 0x3f, 0x0b, + 0x8b, 0x66, 0xa3, 0x62, 0x7d, 0xa2, 0x10, 0x4b, 0x15, 0x9e, 0x57, 0xaa, 0x51, 0x35, 0x3f, 0x76, + 0xf6, 0x29, 0x8d, 0xf0, 0x5b, 0xaa, 0x2f, 0x28, 0xb9, 0x5b, 0x24, 0xcf, 0xe9, 0x02, 0xe7, 0x73, + 0xe8, 0xe7, 0xeb, 0xa0, 0x57, 0x40, 0xb0, 0x44, 0xb1, 0x3f, 0xe7, 0x56, 0xcb, 0xaa, 0xa5, 0x68, + 0x81, 0x2e, 0x98, 0xd9, 0x9b, 0x92, 0x44, 0xf2, 0x8f, 0x8a, 0xc5, 0xe2, 0x5d, 0xdb, 0xb7, 0x22, + 0x8f, 0x0c, 0x3e, 0xc8, 0x03, 0x1d, 0x1e, 0x54, 0x99, 0x2d, 0xcb, 0x17, 0xf5, 0xdf, 0xcc, 0x24, + 0x28, 0xe7, 0xd6, 0x0b, 0xb6, 0x43, 0x20, 0x7a, 0xba, 0x37, 0x48, 0x9b, 0x3c, 0xc1, 0x3a, 0x43, + 0xc9, 0xdd, 0x22, 0x89, 0xbe, 0x47, 0x47, 0xad, 0x64, 0xb4, 0x0f, 0x28, 0x48, 0x2b, 0x66, 0xaa, + 0x3b, 0x1f, 0xf4, 0x61, 0xba, 0x9d, 0xff, 0x46, 0x3f, 0x60, 0x59, 0xbb, 0x52, 0x63, 0xdf, 0x03, + 0x66, 0xc7, 0x96, 0x4d, 0x32, 0x19, 0xce, 0x9c, 0xe8, 0xf0, 0xcb, 0x67, 0xac, 0x9d, 0x9b, 0x50, + 0x25, 0x83, 0x11, 0xb0, 0xa8, 0x41, 0x6d, 0x16, 0x90, 0x21, 0x91, 0xcc, 0xeb, 0xf2, 0x1b, 0xf4, + 0x53, 0x9a, 0x14, 0x5a, 0x7b, 0x0f, 0xa9, 0x90, 0xf2, 0x1f, 0x02, 0x25, 0x77, 0xcb, 0x43, 0xae, + 0x50, 0x9e, 0xbe, 0x89, 0xee, 0xc9, 0x1c, 0x8b, 0x29, 0x6b, 0xec, 0x52, 0xbb, 0x2e, 0x45, 0x70, + 0x2d, 0x95, 0x61, 0x33, 0x4f, 0xa5, 0xd7, 0xb1, 0x70, 0x56, 0x4f, 0xbc, 0xda, 0x05, 0x7f, 0x22, + 0x91, 0x68, 0xd1, 0xbc, 0x39, 0xd0, 0x0c, 0xfa, 0x34, 0xab, 0xcf, 0xdb, 0xdb, 0x89, 0xb2, 0x10, + 0xf7, 0x81, 0xc2, 0x97, 0x2d, 0x50, 0x29, 0x7c, 0xfe, 0x8c, 0xde, 0xe4, 0xf3, 0x04, 0x97, 0x04, + 0xdf, 0x6a, 0x44, 0x46, 0xec, 0x80, 0xe6, 0x9e, 0x1e, 0x93, 0x08, 0xbf, 0xfa, 0x81, 0x50, 0x72, + 0xb7, 0x3c, 0x46, 0x24, 0xf2, 0x80, 0xcc, 0x5a, 0x94, 0xdc, 0xdd, 0x92, 0x2b, 0x51, 0xd9, 0xef, + 0x90, 0x8c, 0xa6, 0x03, 0x9f, 0x69, 0x85, 0x1a, 0x98, 0x8e, 0xd0, 0xd4, 0x66, 0xee, 0x5e, 0xb1, + 0x74, 0x09, 0x72, 0xcd, 0xc8, 0x72, 0x1b, 0x74, 0xdc, 0x1f, 0x24, 0x92, 0x0e, 0x56, 0xc7, 0xfe, + 0x3d, 0xa8, 0x06, 0x9e, 0x17, 0x11, 0xac, 0xc4, 0xfb, 0x35, 0x80, 0x88, 0xcd, 0xa7, 0xc3, 0xc1, + 0xe1, 0x0e, 0x8e, 0xad, 0x24, 0x2b, 0xbc, 0xfd, 0x52, 0x6d, 0x4e, 0x5e, 0x7d, 0x41, 0xc9, 0xdd, + 0xf2, 0x18, 0x16, 0xcb, 0x7c, 0xd3, 0xd1, 0x8b, 0x52, 0xbc, 0x52, 0xab, 0x08, 0x82, 0xe0, 0xf3, + 0x22, 0x83, 0x51, 0x72, 0x64, 0xed, 0xde, 0x4a, 0xd0, 0xdf, 0x00, 0x1c, 0x39, 0x64, 0xbf, 0xdc, + 0x66, 0xf1, 0x8a, 0x65, 0x4b, 0xfe, 0xfc, 0x7d, 0x2f, 0x71, 0x7d, 0xa4, 0x5d, 0x9d, 0x9d, 0x7f, + 0x3b, 0xa0, 0xca, 0xe7, 0x06, 0xf9, 0x2a, 0xd5, 0x67, 0xd1, 0x4c, 0x2c, 0x68, 0x81, 0xd3, 0xb3, + 0xbc, 0xef, 0x8c, 0x15, 0x66, 0x3e, 0xd5, 0x73, 0x26, 0x7b, 0x2c, 0x94, 0xdc, 0x2d, 0x0f, 0xfd, + 0xc8, 0xfd, 0x17, 0x20, 0x77, 0xfd, 0x4c, 0xe3, 0x53, 0x72, 0xa7, 0x30, 0x20, 0x46, 0x96, 0xbb, + 0x58, 0x2c, 0x96, 0x48, 0x88, 0xa6, 0xfa, 0xa5, 0x5d, 0x6c, 0x4a, 0xee, 0x14, 0x86, 0x02, 0x57, + 0xee, 0x9e, 0x7a, 0x95, 0x7b, 0x5c, 0x4c, 0x34, 0xe8, 0xb2, 0x3b, 0xda, 0xdb, 0x4e, 0xfe, 0xec, + 0x9f, 0x50, 0xa2, 0x6f, 0x57, 0xa7, 0x93, 0xea, 0x4e, 0xa6, 0xe4, 0x3e, 0x8a, 0x5c, 0x2e, 0xb7, + 0x79, 0xb7, 0x3b, 0xc4, 0x7a, 0xd2, 0xa7, 0xdd, 0x5d, 0xf8, 0x49, 0xe2, 0x29, 0x74, 0xc0, 0x68, + 0x72, 0x5f, 0xba, 0x68, 0x3e, 0x99, 0x2c, 0xf6, 0x94, 0xdc, 0x47, 0x39, 0xb8, 0x7f, 0x1f, 0x70, + 0xd9, 0xc3, 0xc2, 0x82, 0x29, 0x9f, 0xff, 0x6b, 0xe9, 0x57, 0x0b, 0xe4, 0x66, 0x13, 0xc4, 0xcb, + 0xd2, 0x31, 0x9a, 0xdc, 0x3d, 0xdd, 0x5c, 0xc8, 0xd4, 0x87, 0x92, 0xfb, 0xdb, 0xa4, 0x84, 0x78, + 0xe0, 0xaf, 0xe3, 0x47, 0x1c, 0xc1, 0xeb, 0x6b, 0x57, 0x2e, 0x83, 0xd7, 0x7b, 0x76, 0xef, 0xd2, + 0xa5, 0x82, 0x14, 0x18, 0x46, 0xc4, 0x72, 0xe3, 0xc8, 0x3d, 0x28, 0xc0, 0x8f, 0x4c, 0x7d, 0x3e, + 0x76, 0xb9, 0x57, 0xd1, 0x2a, 0x81, 0xb3, 0xbe, 0x5e, 0xb2, 0x08, 0xde, 0xe0, 0x77, 0xd8, 0xc1, + 0x0e, 0x1c, 0x09, 0xf4, 0xf3, 0xd5, 0xa5, 0x8e, 0x14, 0xaa, 0x50, 0x72, 0xd7, 0x19, 0xfd, 0xcb, + 0x5d, 0x24, 0x14, 0x7e, 0x39, 0x73, 0x1a, 0x18, 0xdf, 0xb4, 0xb6, 0x8c, 0x07, 0x5d, 0x50, 0x28, + 0x14, 0xcb, 0x16, 0x2f, 0x04, 0x1e, 0xbc, 0x79, 0x63, 0x3c, 0x29, 0xb1, 0xa0, 0xb7, 0x17, 0x9c, + 0x0c, 0xac, 0xfa, 0xcd, 0x6b, 0xf0, 0x2f, 0x74, 0x5a, 0x6d, 0x4d, 0x4d, 0x47, 0x87, 0xca, 0x6d, + 0x83, 0xd3, 0x68, 0x95, 0x15, 0x0c, 0x3a, 0x1d, 0xea, 0x0e, 0x49, 0x24, 0x12, 0x30, 0x12, 0x80, + 0x9f, 0x15, 0x0c, 0x0d, 0x0d, 0x71, 0x39, 0x1c, 0x92, 0x77, 0x31, 0x31, 0x30, 0x4b, 0xb9, 0xdb, + 0x7f, 0xa4, 0x72, 0x87, 0x83, 0xd2, 0xa8, 0xb3, 0x86, 0xfa, 0xb1, 0xd9, 0x8d, 0x3f, 0x7f, 0xff, + 0x0d, 0xfc, 0x02, 0xf4, 0xf6, 0x8e, 0x4e, 0x1d, 0xff, 0xb1, 0xe7, 0xd7, 0x99, 0xd6, 0x56, 0x2d, + 0x8c, 0xd1, 0xec, 0x4b, 0xe7, 0xa2, 0xa3, 0xd6, 0x7e, 0xbb, 0x0a, 0xbc, 0x78, 0x54, 0xf4, 0x70, + 0xfe, 0xec, 0x19, 0x40, 0xee, 0xe0, 0xf5, 0xc8, 0xc8, 0xc8, 0x9c, 0xe9, 0xd6, 0x99, 0xe9, 0xa3, + 0x69, 0x6c, 0xea, 0x6a, 0x6b, 0xa7, 0x4f, 0x9e, 0xf4, 0xf4, 0xc9, 0x63, 0xe7, 0x93, 0xc7, 0xb7, + 0x6d, 0xda, 0xf0, 0xb1, 0x8d, 0x0a, 0x8c, 0x20, 0x77, 0xad, 0xf8, 0x78, 0xe5, 0x1e, 0x1a, 0x1c, + 0x04, 0x04, 0xbd, 0x6f, 0xef, 0x1e, 0xdc, 0x77, 0xaf, 0x67, 0xa4, 0x83, 0x77, 0x81, 0x6a, 0x87, + 0x87, 0x47, 0xf7, 0x1f, 0x00, 0xb9, 0x87, 0x87, 0x9c, 0x81, 0xde, 0x8a, 0x8e, 0x8a, 0xd8, 0xfb, + 0xdf, 0x5f, 0xa0, 0xd7, 0xa5, 0xc5, 0xc5, 0x8b, 0xe6, 0xcd, 0x79, 0xfb, 0xae, 0xe5, 0x76, 0x38, + 0x78, 0x00, 0x28, 0x7b, 0xcd, 0xea, 0x95, 0xae, 0x4e, 0x27, 0x57, 0x2c, 0x5d, 0x92, 0x78, 0x3e, + 0x0e, 0x3a, 0x07, 0x34, 0xf0, 0xd6, 0x93, 0x3e, 0xfd, 0x75, 0xe7, 0x0e, 0x92, 0xf5, 0x9f, 0x48, + 0xe0, 0xca, 0xdd, 0x2b, 0x95, 0xd6, 0xad, 0x7e, 0x11, 0x01, 0x9e, 0xdc, 0xb7, 0x50, 0x72, 0x57, + 0x0b, 0x19, 0xb9, 0x97, 0x14, 0x3f, 0x02, 0x6a, 0x9e, 0x3b, 0x63, 0xaa, 0x58, 0xa4, 0xd6, 0xef, + 0x4e, 0x27, 0x8e, 0x81, 0x73, 0x7e, 0x5c, 0x33, 0x9a, 0x96, 0x0a, 0xc8, 0x3d, 0x32, 0x2c, 0x14, + 0x3a, 0x8e, 0x2b, 0xf7, 0xe3, 0x47, 0x0f, 0xef, 0xd8, 0xb2, 0x11, 0x6a, 0xbc, 0xc1, 0x57, 0x05, + 0x74, 0x90, 0x22, 0x42, 0x43, 0xc0, 0xeb, 0x8b, 0x17, 0x92, 0x6c, 0x16, 0xce, 0x1b, 0xe8, 0xef, + 0x2f, 0xb8, 0x9f, 0x3f, 0x6b, 0xda, 0x14, 0x64, 0xaf, 0xe9, 0x63, 0xc0, 0x32, 0xe4, 0x1e, 0x3c, + 0xd1, 0xe5, 0x6e, 0x08, 0x40, 0x6f, 0xbe, 0x93, 0xcd, 0x16, 0x8b, 0x4d, 0x10, 0x37, 0xc2, 0x6c, + 0xd1, 0x51, 0xee, 0xaa, 0xd1, 0xc1, 0x29, 0xb9, 0x13, 0x41, 0xcd, 0xaa, 0x9a, 0x0f, 0x3a, 0xc9, + 0xfd, 0x0c, 0x25, 0xf7, 0xb7, 0x94, 0xdc, 0x2d, 0x11, 0x4a, 0xee, 0x3a, 0x43, 0xc9, 0xdd, 0xf2, + 0x18, 0x91, 0x50, 0x72, 0xd7, 0x11, 0x4a, 0xee, 0x96, 0xc7, 0x44, 0x90, 0x7b, 0x21, 0x25, 0x77, + 0x0a, 0x72, 0x18, 0x47, 0xee, 0xed, 0x2c, 0x16, 0xfc, 0x1a, 0x39, 0xaf, 0x87, 0x85, 0x92, 0x3b, + 0x85, 0x01, 0x31, 0x9c, 0xdc, 0x07, 0xfa, 0xfb, 0x83, 0x02, 0xfc, 0x66, 0x58, 0x5b, 0x59, 0x7d, + 0xfa, 0x8f, 0xef, 0x56, 0xfd, 0x1b, 0x3e, 0x0e, 0xad, 0x7a, 0x02, 0xb6, 0x6d, 0xd3, 0x06, 0x6c, + 0x12, 0x52, 0x4a, 0xee, 0x14, 0x06, 0x44, 0xbf, 0x72, 0x57, 0x2a, 0x95, 0x39, 0x77, 0xef, 0xac, + 0xfa, 0x66, 0x19, 0x6a, 0xf2, 0x1b, 0x57, 0xee, 0xb0, 0x4d, 0xb3, 0xfa, 0xdc, 0xc3, 0xd5, 0x99, + 0xcf, 0x1f, 0x4d, 0x49, 0x2a, 0xed, 0x64, 0x77, 0x1d, 0x3f, 0x84, 0x99, 0x66, 0xf2, 0x21, 0x90, + 0x7b, 0x52, 0x61, 0x2b, 0x56, 0xee, 0xe9, 0x4f, 0x28, 0xb9, 0x53, 0x60, 0xd0, 0x8b, 0xdc, 0xe9, + 0x3f, 0x6f, 0x5a, 0xb6, 0xe0, 0x4b, 0x82, 0xb5, 0x1e, 0xb3, 0xa6, 0x4e, 0xfe, 0x75, 0xe7, 0x0e, + 0xc8, 0xbe, 0x5b, 0xb9, 0x82, 0xe0, 0xcc, 0x19, 0x93, 0x27, 0x45, 0xfe, 0xbc, 0x05, 0x25, 0xf7, + 0x6e, 0xf7, 0x93, 0xf2, 0x21, 0xb5, 0x91, 0x11, 0xf2, 0x68, 0xdd, 0x0e, 0xa7, 0x55, 0x42, 0xcd, + 0xd8, 0x7a, 0xe4, 0x85, 0xdd, 0x31, 0x78, 0x2c, 0x31, 0x4a, 0xee, 0x96, 0x07, 0xae, 0xdc, 0x3d, + 0xb5, 0x6d, 0xdd, 0x77, 0x6d, 0x11, 0xd5, 0x8f, 0xb6, 0xee, 0x7d, 0x02, 0x81, 0xbf, 0x8f, 0xf7, + 0x8c, 0x29, 0x5f, 0x68, 0xd5, 0xba, 0x03, 0xdb, 0xf8, 0xe3, 0x3a, 0x48, 0x12, 0x4a, 0xa9, 0x84, + 0x17, 0x81, 0x9e, 0xb5, 0x6d, 0xdf, 0xbb, 0x93, 0x20, 0x7f, 0x73, 0xa7, 0x40, 0xe4, 0x7b, 0x05, + 0x1d, 0x13, 0xf8, 0x54, 0x42, 0x79, 0x1b, 0xcf, 0xb0, 0xe1, 0x51, 0x29, 0xb9, 0x5b, 0x1e, 0xfa, + 0x95, 0x3b, 0x92, 0x2a, 0x1a, 0x6d, 0xd7, 0xf6, 0xad, 0x04, 0x72, 0x5f, 0x30, 0x67, 0x56, 0x52, + 0x42, 0x3c, 0x76, 0x92, 0xbb, 0x37, 0x25, 0x91, 0xbe, 0x70, 0x16, 0xb2, 0x7c, 0x86, 0xcd, 0xbc, + 0xde, 0xa4, 0x58, 0x82, 0xbb, 0xb8, 0x50, 0xc4, 0xb4, 0xc3, 0xc4, 0x2e, 0x76, 0x4d, 0x7a, 0x45, + 0x57, 0x1f, 0x2d, 0xe7, 0xc3, 0xa1, 0xe4, 0x6e, 0x79, 0x18, 0x4e, 0xee, 0x30, 0x32, 0x99, 0xac, + 0xb0, 0xe0, 0x01, 0xfc, 0xdf, 0xda, 0x9a, 0x6a, 0xe4, 0x83, 0x1a, 0x2c, 0x92, 0xb6, 0xd6, 0xae, + 0x93, 0x87, 0x51, 0x0d, 0x3c, 0x18, 0xbf, 0x12, 0xa7, 0x3f, 0xb8, 0x00, 0x7a, 0xf0, 0xbe, 0xe8, + 0x5c, 0x4e, 0x76, 0x3e, 0xf9, 0xd1, 0xb9, 0x64, 0x23, 0xd3, 0x6b, 0x0b, 0x25, 0x77, 0xcb, 0xc3, + 0x08, 0x72, 0xd7, 0x81, 0xde, 0xe4, 0xf3, 0xf4, 0x79, 0xd3, 0x51, 0x8a, 0xe7, 0x85, 0x07, 0x11, + 0x5f, 0x75, 0xa5, 0x94, 0x75, 0xf8, 0x34, 0x26, 0x6b, 0xda, 0xbb, 0x00, 0x63, 0x7e, 0x19, 0xb5, + 0xf5, 0x1d, 0xfd, 0x7a, 0xac, 0xe1, 0x5b, 0x82, 0xdc, 0x4c, 0x25, 0x8f, 0x8a, 0x90, 0xe6, 0x60, + 0xfb, 0x57, 0xfc, 0xb9, 0x18, 0xe4, 0x11, 0x5a, 0x65, 0xe5, 0x87, 0xff, 0x79, 0x89, 0x4c, 0x91, + 0x52, 0xc2, 0x4a, 0x2c, 0x68, 0xc5, 0x58, 0x0b, 0xca, 0x12, 0x80, 0x3d, 0xd0, 0x6c, 0xe0, 0xda, + 0xe4, 0x22, 0xe6, 0xe5, 0xd2, 0xb6, 0xac, 0x67, 0x1d, 0xf7, 0x5f, 0x73, 0xca, 0x5b, 0xfa, 0x9a, + 0xbb, 0x87, 0xf9, 0x83, 0x12, 0x99, 0xdc, 0x48, 0x11, 0xc4, 0x8d, 0x80, 0x11, 0xe4, 0xde, 0xdc, + 0xd4, 0x68, 0x7b, 0x60, 0xdf, 0xec, 0x69, 0xd6, 0xa0, 0x03, 0x33, 0xd3, 0xda, 0xea, 0xa7, 0xb5, + 0xdf, 0x85, 0x87, 0x9c, 0x21, 0x58, 0xe8, 0x0a, 0x50, 0xca, 0x64, 0xdc, 0x20, 0x5f, 0x94, 0xdc, + 0x41, 0x0f, 0xa7, 0xf7, 0x42, 0xbc, 0xc6, 0x3b, 0xf2, 0xba, 0x86, 0xbe, 0x1d, 0xa4, 0x39, 0x06, + 0x17, 0x79, 0xa5, 0x55, 0xf9, 0x66, 0xd6, 0x9d, 0xb9, 0xd5, 0x10, 0x99, 0xd3, 0x14, 0x95, 0xd3, + 0xac, 0xd6, 0x72, 0x9b, 0xcf, 0xa2, 0x8d, 0x0e, 0x59, 0xcc, 0x3d, 0x3a, 0x9d, 0x33, 0xac, 0xb6, + 0x75, 0xa7, 0x37, 0x37, 0x4d, 0xfd, 0xe2, 0x33, 0x75, 0x83, 0xf1, 0xff, 0xfc, 0xfb, 0x1b, 0x32, + 0x7b, 0xd4, 0x35, 0x22, 0x93, 0x2b, 0xfd, 0x32, 0xeb, 0x08, 0x6e, 0x55, 0x9f, 0xe6, 0x9e, 0x6b, + 0xef, 0xf7, 0xe0, 0x68, 0xe4, 0x63, 0xcf, 0xd4, 0x2a, 0xff, 0xac, 0xfa, 0x94, 0x47, 0xcc, 0x6a, + 0xd6, 0x00, 0x41, 0xc8, 0x5c, 0xb3, 0xc5, 0xd0, 0x72, 0x8f, 0x0a, 0x0f, 0x03, 0x1f, 0x31, 0x68, + 0xdd, 0xe0, 0x23, 0x9c, 0xee, 0xee, 0x05, 0x73, 0x67, 0x4d, 0xf9, 0xfc, 0x5f, 0xc4, 0x1b, 0xc7, + 0x64, 0x82, 0xde, 0xae, 0x53, 0x47, 0xd0, 0x8a, 0x9f, 0x3b, 0x95, 0x1f, 0x17, 0xa5, 0xf1, 0xa6, + 0x3a, 0x7a, 0x84, 0xfe, 0x99, 0xb5, 0xb8, 0x59, 0x9c, 0xf4, 0x62, 0xa7, 0x62, 0x9f, 0xd7, 0xb3, + 0x07, 0x89, 0x3a, 0x33, 0x3c, 0x2e, 0x77, 0xce, 0x74, 0x6b, 0xac, 0xd6, 0x77, 0x6c, 0xd9, 0xa4, + 0xb1, 0xf6, 0x24, 0x31, 0xaa, 0xdc, 0xd5, 0x98, 0x9d, 0x77, 0xbe, 0x4b, 0xfc, 0x8b, 0xc0, 0x1b, + 0xf5, 0x99, 0x65, 0x1d, 0x5d, 0x02, 0xa2, 0x06, 0xcc, 0x4c, 0x50, 0x27, 0x77, 0x82, 0x18, 0x91, + 0x5a, 0xc9, 0xfd, 0xf6, 0xcd, 0x1b, 0xe0, 0x53, 0x06, 0xe2, 0x3e, 0xea, 0xe8, 0x70, 0x37, 0xfb, + 0xf6, 0xc0, 0xc0, 0x00, 0xf9, 0xba, 0x49, 0xbb, 0x3b, 0xbb, 0x30, 0xfb, 0x56, 0x9b, 0x67, 0x4d, + 0xe6, 0x06, 0x93, 0xdd, 0xa6, 0x9c, 0x4f, 0xeb, 0x0e, 0xc8, 0xa8, 0xb1, 0xf7, 0x21, 0x95, 0x98, + 0x5b, 0x9f, 0x72, 0x7f, 0xfb, 0x2e, 0x93, 0xb0, 0xcd, 0xa2, 0xf9, 0x48, 0xad, 0xdb, 0x1f, 0x3c, + 0x40, 0xfe, 0xe6, 0x35, 0x02, 0xfa, 0x18, 0xa3, 0xb9, 0x67, 0x03, 0x0a, 0xf5, 0x68, 0xf6, 0xfe, + 0x05, 0xa0, 0x15, 0xb7, 0xf5, 0xce, 0x47, 0x85, 0x84, 0x26, 0x69, 0x87, 0x4e, 0x17, 0xfa, 0x5f, + 0x79, 0x9d, 0x58, 0xd8, 0xca, 0x55, 0xbf, 0x17, 0xce, 0xb4, 0xe8, 0x49, 0xee, 0x9b, 0x89, 0xfb, + 0xee, 0x0c, 0x3a, 0xfd, 0x5c, 0x74, 0xd4, 0xc6, 0x1f, 0xd7, 0x41, 0x61, 0x95, 0x80, 0x81, 0x2e, + 0x4d, 0x57, 0xa7, 0xe6, 0xa8, 0xa5, 0xd2, 0xce, 0x0e, 0x6c, 0x1b, 0x0f, 0x8c, 0x6d, 0xfb, 0x3f, + 0x61, 0x55, 0x05, 0xf9, 0xdb, 0x04, 0xb7, 0x53, 0xce, 0x10, 0x80, 0x4e, 0x88, 0x5f, 0x66, 0xad, + 0x6f, 0x1a, 0xcd, 0xed, 0xfc, 0xf3, 0xa3, 0x61, 0x25, 0x87, 0x82, 0x8b, 0xc6, 0x2c, 0x48, 0x3b, + 0x3b, 0x95, 0x50, 0xae, 0x59, 0xee, 0x6f, 0xdf, 0x45, 0x47, 0x5a, 0xf3, 0xed, 0x58, 0x9e, 0x78, + 0x1f, 0x4f, 0x77, 0xf2, 0xd5, 0x35, 0x13, 0xa4, 0x72, 0x05, 0x77, 0x40, 0xfc, 0xba, 0xad, 0xff, + 0x7a, 0x59, 0x07, 0xe8, 0xde, 0x81, 0x5f, 0x4c, 0xe7, 0xf8, 0xe7, 0xe0, 0x2b, 0x71, 0xd0, 0x43, + 0xf3, 0x97, 0xe1, 0x48, 0xd0, 0xc3, 0xe0, 0x9b, 0x0d, 0x65, 0x4d, 0xbd, 0xa6, 0xbe, 0x09, 0x15, + 0x0c, 0x2d, 0x77, 0x2f, 0x77, 0xd7, 0x9f, 0xb7, 0x6e, 0xea, 0x13, 0xa8, 0x64, 0xa8, 0xcc, 0xb9, + 0x93, 0x0d, 0x04, 0x00, 0x8e, 0x93, 0xac, 0x24, 0x3f, 0x2a, 0x04, 0x34, 0xea, 0x58, 0xd1, 0x77, + 0x39, 0xff, 0x4d, 0x32, 0x75, 0x99, 0x21, 0x20, 0xfb, 0x64, 0x66, 0xb9, 0xcd, 0x57, 0xce, 0x27, + 0x8f, 0x1b, 0xb4, 0x2a, 0xc6, 0x07, 0x74, 0x5d, 0x2e, 0x16, 0x31, 0x03, 0x33, 0x6b, 0x8f, 0x86, + 0x97, 0x12, 0xf7, 0x1a, 0x8f, 0x84, 0x16, 0x47, 0xdd, 0x69, 0xe4, 0x9b, 0x22, 0x19, 0x2f, 0x16, + 0x7c, 0xb9, 0xa7, 0xe8, 0x4d, 0xee, 0x35, 0xd5, 0xd5, 0x33, 0xa7, 0x4e, 0x86, 0xf6, 0x1c, 0x27, + 0xc4, 0xc7, 0x5d, 0x48, 0x3c, 0x0f, 0x86, 0xad, 0xa0, 0x8d, 0xff, 0x72, 0xe6, 0x34, 0x68, 0xef, + 0x3c, 0x49, 0x06, 0xef, 0xe7, 0xb2, 0xb6, 0x6f, 0xc0, 0x2a, 0x7e, 0xb4, 0xa5, 0x3f, 0xf8, 0xc7, + 0x50, 0xf1, 0x43, 0xad, 0xef, 0xfc, 0x83, 0xf9, 0xa4, 0xa3, 0xbd, 0xbd, 0xac, 0xec, 0xa9, 0x46, + 0x03, 0xdd, 0xb8, 0x6b, 0x57, 0xaf, 0x90, 0x39, 0xd3, 0xe4, 0xd6, 0xd2, 0xa2, 0xc5, 0x47, 0x82, + 0x24, 0xbf, 0x8a, 0x13, 0x74, 0xb3, 0xfe, 0xef, 0xc8, 0xc7, 0x04, 0xba, 0xf7, 0x48, 0x2a, 0xcf, + 0x7d, 0x65, 0xe2, 0x00, 0x80, 0x40, 0xee, 0x7e, 0x86, 0x94, 0x3b, 0x4c, 0x4f, 0x0f, 0xbf, 0xfa, + 0xcd, 0x6b, 0x5a, 0x65, 0x05, 0x78, 0xa1, 0x73, 0x6d, 0x7b, 0x12, 0x62, 0x18, 0x8b, 0xe7, 0xe2, + 0xb6, 0xf4, 0x2d, 0xab, 0x96, 0x72, 0xfc, 0x3d, 0x45, 0xf5, 0x35, 0x3a, 0x17, 0xae, 0x2d, 0xa4, + 0x5a, 0xf7, 0xac, 0xcc, 0x0c, 0xf0, 0x5d, 0x9f, 0x3d, 0x6d, 0xca, 0x87, 0xdc, 0xb6, 0x05, 0xc1, + 0x1f, 0x94, 0x24, 0x16, 0xb4, 0xb8, 0x24, 0xbd, 0x52, 0x27, 0x7a, 0xc7, 0x80, 0xc2, 0xe8, 0x3c, + 0xba, 0xa9, 0xaa, 0x27, 0x34, 0x70, 0xeb, 0x6e, 0x08, 0xfa, 0xd2, 0xd3, 0x88, 0x53, 0x5b, 0xb2, + 0xed, 0xf6, 0xf1, 0xe3, 0xa2, 0x44, 0x8d, 0xf5, 0x06, 0xad, 0x86, 0x66, 0xb9, 0xc7, 0x46, 0x9f, + 0x45, 0xae, 0x83, 0xd3, 0xb9, 0xed, 0xc4, 0x45, 0x29, 0x95, 0x4a, 0x39, 0xdd, 0xba, 0x99, 0x8c, + 0xcb, 0xc1, 0xb7, 0x1e, 0xbe, 0x7c, 0xa0, 0x5f, 0xa1, 0x8f, 0xdd, 0xdc, 0x35, 0xed, 0x03, 0xa1, + 0x77, 0x9a, 0x8e, 0x60, 0xe7, 0x41, 0xa0, 0x47, 0x3a, 0x9e, 0x79, 0xe7, 0xf3, 0xe9, 0x46, 0xc8, + 0x28, 0x84, 0xc2, 0x12, 0xe5, 0x0e, 0x31, 0x54, 0x52, 0xc4, 0xf1, 0x72, 0x46, 0xe5, 0x11, 0x41, + 0xdb, 0x8c, 0x2f, 0x5a, 0x56, 0x2c, 0xee, 0xf8, 0xfd, 0x17, 0xd0, 0xf0, 0xf3, 0xa3, 0xc3, 0xfa, + 0x6f, 0x64, 0x8c, 0xbc, 0x7a, 0x21, 0x61, 0xb6, 0x80, 0x4f, 0x5c, 0xde, 0x27, 0x00, 0x9f, 0xac, + 0xce, 0xa6, 0x10, 0x09, 0x35, 0xc8, 0x1d, 0x8c, 0x5a, 0xb0, 0x0f, 0x22, 0xb1, 0x2b, 0x9e, 0x75, + 0x46, 0x21, 0x1c, 0x01, 0x77, 0x45, 0x74, 0xf3, 0x1f, 0x68, 0x73, 0xa7, 0xb6, 0x7c, 0xbd, 0x90, + 0xb5, 0x63, 0x63, 0xb7, 0xfb, 0x29, 0x5e, 0x78, 0x50, 0x5f, 0xe6, 0x55, 0x09, 0xab, 0x4d, 0x87, + 0x7a, 0x36, 0xb3, 0x07, 0x7d, 0x2e, 0x55, 0xe0, 0x8a, 0x1e, 0x74, 0x7e, 0xf2, 0x5e, 0x19, 0x3c, + 0xcb, 0x0a, 0x12, 0xcb, 0x95, 0x3b, 0xcc, 0xe0, 0x83, 0x3c, 0x8e, 0xb7, 0x2b, 0x63, 0xc9, 0x97, + 0x06, 0xfc, 0xe8, 0x55, 0xad, 0xfd, 0xb7, 0x9d, 0xe2, 0xa6, 0x06, 0x22, 0xb9, 0xdb, 0xfd, 0xb5, + 0x5f, 0xdd, 0x34, 0x53, 0x5e, 0xce, 0x5d, 0xbd, 0xdc, 0xb6, 0xc1, 0xe5, 0xae, 0xc6, 0x98, 0xeb, + 0x56, 0x77, 0x7b, 0xb9, 0xf4, 0x5e, 0x4a, 0x54, 0x8c, 0x68, 0xb1, 0x04, 0x8f, 0x23, 0x10, 0x62, + 0xd7, 0xf1, 0x41, 0xe6, 0x76, 0x89, 0xc6, 0xe9, 0x33, 0x52, 0x33, 0x3f, 0x01, 0xe4, 0x0e, 0x23, + 0xed, 0xee, 0x04, 0x9d, 0xfb, 0x6e, 0x97, 0x63, 0x8c, 0xa5, 0xf3, 0x4d, 0x26, 0x77, 0xa5, 0x52, + 0xb9, 0x7d, 0xf3, 0x46, 0xe2, 0xd8, 0x77, 0x97, 0x92, 0x35, 0x27, 0x05, 0xd7, 0x88, 0xa9, 0xe4, + 0x8e, 0x34, 0x86, 0xcd, 0x3c, 0x5e, 0x48, 0xc0, 0xf0, 0x93, 0x12, 0x38, 0x80, 0x2b, 0x31, 0xbc, + 0x7e, 0x91, 0x5b, 0x4a, 0x15, 0x56, 0xf1, 0xb6, 0x5e, 0xf7, 0x8c, 0xd3, 0xa1, 0x57, 0x2b, 0x77, + 0xf5, 0x73, 0x64, 0x66, 0x2b, 0x77, 0x24, 0x40, 0x0c, 0x22, 0x7a, 0x93, 0xe0, 0x6a, 0x0a, 0xff, + 0x6c, 0x08, 0xc7, 0xc7, 0xad, 0x7d, 0xf7, 0x36, 0xc6, 0xb2, 0x05, 0xa3, 0x0b, 0x2d, 0x55, 0x6b, + 0xae, 0x7f, 0xb9, 0x63, 0xf1, 0xf5, 0xf6, 0xac, 0xac, 0x50, 0x9b, 0xa8, 0x4d, 0x67, 0x94, 0x0a, + 0x05, 0xe8, 0x64, 0x2b, 0x24, 0x08, 0x13, 0x13, 0x98, 0x48, 0xb3, 0x89, 0x44, 0xc0, 0x6b, 0xa0, + 0x93, 0x27, 0x65, 0xb7, 0x8f, 0xd0, 0x2a, 0x06, 0x72, 0x6f, 0xf3, 0x63, 0xc2, 0xb9, 0x81, 0xde, + 0x9d, 0x0e, 0xfb, 0x5b, 0x96, 0x7f, 0xa5, 0xc1, 0x29, 0x33, 0xad, 0x78, 0x11, 0xc1, 0x72, 0x31, + 0xa9, 0x89, 0xd5, 0x7b, 0x15, 0x5d, 0x47, 0x23, 0x4a, 0xb1, 0xa2, 0xf7, 0xbc, 0xf2, 0x66, 0x44, + 0x62, 0xd8, 0x85, 0x09, 0x13, 0x55, 0xee, 0x04, 0x28, 0xe5, 0x72, 0x85, 0x50, 0x28, 0x1f, 0x1c, + 0x30, 0x6c, 0xdf, 0x1d, 0xc6, 0x40, 0x72, 0x37, 0x32, 0xc0, 0x65, 0xa2, 0xc6, 0x3a, 0xa0, 0x69, + 0xb6, 0xdd, 0x3e, 0xdc, 0x47, 0x63, 0x63, 0x2d, 0xc1, 0xde, 0x5d, 0x04, 0x49, 0x18, 0x61, 0x7a, + 0x06, 0xc5, 0xbe, 0x57, 0xd1, 0xe9, 0x70, 0x81, 0x39, 0x9d, 0x7d, 0x52, 0x58, 0xcd, 0x35, 0xdc, + 0x5d, 0xe8, 0x4f, 0xee, 0xc6, 0x7b, 0x02, 0x68, 0x26, 0x7c, 0x5c, 0x72, 0x47, 0x31, 0x98, 0x9f, + 0xdb, 0xe5, 0x72, 0x0c, 0x57, 0xf1, 0xe0, 0x37, 0x94, 0x6d, 0xff, 0x27, 0x19, 0xd1, 0xc7, 0xdf, + 0xa3, 0xdb, 0xfb, 0x3d, 0x40, 0x4f, 0x4b, 0x9d, 0x79, 0x74, 0xbb, 0xdc, 0x50, 0xe3, 0x57, 0x4a, + 0xee, 0x3a, 0xf3, 0x51, 0xcb, 0x1d, 0x02, 0x8c, 0x56, 0x7b, 0x12, 0x63, 0x59, 0x3b, 0x37, 0xe3, + 0xea, 0x9e, 0xe3, 0xeb, 0x2e, 0x61, 0x31, 0x89, 0x4b, 0xb8, 0xf1, 0x94, 0x75, 0xe8, 0xcc, 0x23, + 0x94, 0xfe, 0x8e, 0x86, 0x97, 0x16, 0xd7, 0x18, 0xa4, 0x8d, 0x1f, 0x95, 0x7b, 0x06, 0x3a, 0x8d, + 0x30, 0x25, 0x77, 0x32, 0x50, 0x72, 0x1f, 0xa7, 0x27, 0x29, 0x96, 0xf9, 0xc3, 0xb7, 0x58, 0xc5, + 0xb3, 0xb6, 0xad, 0x1f, 0x7c, 0x90, 0x47, 0x7c, 0x6d, 0x41, 0x55, 0xf7, 0xe1, 0x30, 0x74, 0x57, + 0xfe, 0x64, 0x4c, 0xd9, 0x2b, 0x86, 0x80, 0xf8, 0x42, 0x1d, 0x10, 0x51, 0x72, 0xd7, 0x15, 0x4a, + 0xee, 0x68, 0x40, 0x4b, 0xdf, 0xba, 0x7a, 0x19, 0x5a, 0xf4, 0x73, 0xac, 0xf9, 0xd1, 0x61, 0xc4, + 0x17, 0xa6, 0x16, 0xb7, 0x61, 0x7b, 0x35, 0xde, 0xa9, 0x34, 0x96, 0xbe, 0xe7, 0xa1, 0x28, 0xb9, + 0xeb, 0x0c, 0x25, 0x77, 0x1c, 0xa4, 0x7c, 0x2e, 0x76, 0xe7, 0x25, 0x30, 0x5e, 0x88, 0xbf, 0x42, + 0x42, 0x34, 0x59, 0x1b, 0x75, 0xa7, 0x11, 0xbd, 0xf9, 0xd2, 0x3d, 0x37, 0xf8, 0x56, 0x83, 0x7e, + 0xab, 0x47, 0xc9, 0x5d, 0x67, 0x28, 0xb9, 0xe3, 0xa3, 0x94, 0xcb, 0xb9, 0x81, 0xde, 0x68, 0xc5, + 0xcf, 0xf8, 0x82, 0x17, 0x41, 0xb4, 0xf9, 0x52, 0x26, 0x57, 0x62, 0xf7, 0xa1, 0x1d, 0x0a, 0x2c, + 0xd4, 0xef, 0xb0, 0x95, 0x92, 0xbb, 0xce, 0x50, 0x72, 0x57, 0x0b, 0xae, 0xe2, 0x19, 0x8b, 0xe7, + 0x12, 0x6f, 0xbe, 0x7c, 0x52, 0xcf, 0x77, 0xc4, 0x74, 0xe2, 0xfd, 0x32, 0xeb, 0xa4, 0xfa, 0xdb, + 0x2c, 0xab, 0x4e, 0xee, 0x9d, 0x94, 0xdc, 0x35, 0x41, 0xc9, 0x9d, 0x08, 0x79, 0x9f, 0xa0, 0xdb, + 0xf5, 0x38, 0x7a, 0xe4, 0xfa, 0xeb, 0x36, 0x61, 0xf5, 0x6b, 0x82, 0xab, 0xbc, 0xd3, 0xd1, 0x5a, + 0x3c, 0x12, 0x56, 0x52, 0xd6, 0xd8, 0xa3, 0xaf, 0x5a, 0x51, 0x72, 0xd7, 0x19, 0xc3, 0xca, 0xdd, + 0xdd, 0xc5, 0x09, 0x5a, 0x71, 0x90, 0x7a, 0xe9, 0xa2, 0xb6, 0xd7, 0x9a, 0x09, 0x03, 0x79, 0xd9, + 0xad, 0xab, 0xbf, 0x46, 0x77, 0xe2, 0xc3, 0x4e, 0x13, 0xac, 0x38, 0xc8, 0x7c, 0xda, 0xee, 0x10, + 0xa8, 0x12, 0x11, 0xee, 0xa0, 0x5e, 0x23, 0xc2, 0xe9, 0x47, 0xee, 0x3b, 0x37, 0x51, 0x72, 0x57, + 0x8b, 0x0e, 0x72, 0x87, 0x76, 0xf8, 0x06, 0x07, 0xfa, 0xef, 0xdc, 0xb6, 0x65, 0x74, 0x1d, 0xe5, + 0x4b, 0xbd, 0xad, 0xa3, 0x34, 0x26, 0x40, 0xd6, 0xdc, 0x20, 0x1f, 0xf4, 0xb4, 0xeb, 0x9e, 0x9f, + 0x45, 0x35, 0x6f, 0xd4, 0x5d, 0xd2, 0xdd, 0x27, 0x72, 0x4b, 0xae, 0x44, 0xf7, 0x67, 0xd2, 0x6b, + 0x86, 0xc5, 0x32, 0xbd, 0x54, 0x89, 0x92, 0xbb, 0xce, 0x18, 0x4a, 0xee, 0xed, 0xed, 0xac, 0xc9, + 0x9f, 0xfd, 0x73, 0xfe, 0xec, 0x19, 0x32, 0x99, 0xac, 0xa7, 0x87, 0x6f, 0x3d, 0xe9, 0xd3, 0xe9, + 0x93, 0x27, 0x41, 0x29, 0x54, 0x2d, 0x8e, 0xd1, 0xad, 0x09, 0x2b, 0x16, 0xab, 0xf4, 0xe0, 0x97, + 0x2d, 0x10, 0x5c, 0x49, 0x51, 0x77, 0x3e, 0xee, 0x80, 0xd5, 0x35, 0xb1, 0x9c, 0xc1, 0xd1, 0x4f, + 0x00, 0x44, 0x20, 0x77, 0x3f, 0x4a, 0xee, 0x3a, 0x61, 0x10, 0xb9, 0x83, 0x16, 0x71, 0xb9, 0xcd, + 0x57, 0xa0, 0x45, 0xa7, 0x55, 0x8e, 0xed, 0x3c, 0xbf, 0x97, 0x97, 0x0b, 0xfe, 0xbb, 0x72, 0xf9, + 0x32, 0x92, 0xab, 0x0e, 0x61, 0xb6, 0x6c, 0xf8, 0xa9, 0xb6, 0xc6, 0xc4, 0x9f, 0xca, 0x48, 0x45, + 0x79, 0xdb, 0x96, 0x1f, 0x50, 0x8b, 0xc9, 0xf8, 0xe7, 0x22, 0x08, 0x2e, 0xf1, 0xbf, 0x5e, 0x8f, + 0x92, 0xe3, 0xb1, 0xc8, 0x27, 0x15, 0xad, 0x7d, 0x7a, 0xa9, 0x0f, 0x25, 0x77, 0x9d, 0x31, 0x88, + 0xdc, 0x1d, 0xed, 0x6d, 0x81, 0xb8, 0xe3, 0x62, 0xa2, 0x91, 0x07, 0xbd, 0x3d, 0xdc, 0xc0, 0xc1, + 0x03, 0xfb, 0xfe, 0x80, 0x8f, 0x08, 0x85, 0x23, 0x82, 0xde, 0x5e, 0xf0, 0x05, 0x68, 0x6c, 0xa8, + 0xe7, 0x74, 0x8f, 0x05, 0x13, 0xec, 0xe8, 0x68, 0xaf, 0xa9, 0xae, 0x56, 0x28, 0xc6, 0x9e, 0x63, + 0x80, 0xe3, 0x50, 0xde, 0x08, 0x2e, 0x87, 0x23, 0x97, 0xcb, 0x07, 0xfa, 0xfb, 0xab, 0x68, 0x95, + 0x43, 0xea, 0x23, 0x29, 0x1b, 0x02, 0x31, 0xbd, 0xa9, 0xfd, 0xf7, 0x5d, 0xe8, 0xee, 0x3b, 0x61, + 0x38, 0xb8, 0x90, 0xec, 0x46, 0xd4, 0x5e, 0x6f, 0xc7, 0x90, 0xe2, 0x27, 0x0d, 0xfa, 0xf9, 0x71, + 0xfb, 0x7f, 0x7b, 0x67, 0xfe, 0xd4, 0xc4, 0x19, 0xc6, 0xf1, 0xfe, 0x21, 0x1d, 0x1c, 0x5a, 0x0a, + 0x85, 0xaa, 0x48, 0x6d, 0x47, 0x66, 0xac, 0x62, 0xc7, 0xe3, 0x17, 0xb5, 0xc7, 0x54, 0x64, 0x14, + 0xe8, 0x28, 0xc3, 0x08, 0x72, 0xd4, 0x82, 0x65, 0x38, 0x0c, 0x10, 0xae, 0x10, 0x2e, 0x47, 0xa0, + 0x2d, 0x08, 0x16, 0x19, 0x3a, 0x9c, 0xc2, 0xa0, 0x23, 0x11, 0x4a, 0xa0, 0xc4, 0x58, 0x20, 0x81, + 0x8e, 0x22, 0x02, 0x53, 0xc9, 0x01, 0xe4, 0x30, 0x27, 0x77, 0x0e, 0x48, 0x08, 0xf4, 0x8d, 0xb1, + 0x14, 0xde, 0xdd, 0x6c, 0xb2, 0x99, 0x25, 0x10, 0xd8, 0xef, 0xbc, 0x3f, 0x2c, 0x9b, 0x3d, 0x9e, + 0x30, 0x9f, 0x7d, 0xf3, 0xbc, 0xef, 0x3e, 0xef, 0xf3, 0x90, 0xb8, 0x3b, 0x2c, 0xe2, 0x71, 0xaf, + 0xae, 0xfa, 0x0d, 0x3b, 0x50, 0xde, 0x52, 0x0a, 0x78, 0xed, 0xbf, 0x25, 0xb0, 0xdd, 0x5d, 0x4c, + 0xb0, 0xdd, 0x50, 0x57, 0x0b, 0xb6, 0xef, 0x55, 0x94, 0x83, 0x6d, 0x01, 0x9f, 0x0f, 0xb6, 0xf9, + 0x3c, 0x73, 0xec, 0xb8, 0xd7, 0x07, 0xfb, 0x06, 0xb8, 0x1c, 0xb0, 0x71, 0xd0, 0xc7, 0xeb, 0x6a, + 0x68, 0x30, 0x70, 0x8d, 0xc0, 0x76, 0x5c, 0x6c, 0xcc, 0xe5, 0x8b, 0x17, 0xf0, 0x7f, 0x59, 0x07, + 0x05, 0x70, 0x17, 0x5f, 0xb9, 0x84, 0xc0, 0x9d, 0x86, 0x71, 0x4a, 0x01, 0x1a, 0xee, 0xec, 0x31, + 0x62, 0x56, 0xfa, 0x92, 0xb8, 0x3b, 0x2c, 0x82, 0x71, 0x07, 0x8e, 0x87, 0x39, 0xbf, 0xbd, 0xbb, + 0x1b, 0x6a, 0xea, 0x29, 0xd0, 0x97, 0x7b, 0xec, 0x7b, 0x1f, 0x1c, 0xd0, 0xfe, 0xc4, 0x1c, 0x82, + 0x02, 0x70, 0x3f, 0x15, 0x70, 0xcc, 0xf2, 0x11, 0x8f, 0x37, 0x0e, 0xf6, 0x83, 0xfe, 0xde, 0xf2, + 0xe7, 0xc7, 0x1e, 0xee, 0x5c, 0x4e, 0xff, 0xda, 0x66, 0xdc, 0xd9, 0x2c, 0x96, 0xe5, 0xd3, 0x96, + 0xe6, 0x07, 0x27, 0x03, 0xbe, 0x40, 0x5e, 0x7f, 0x8b, 0xb4, 0xc4, 0x1f, 0xc7, 0x8b, 0x7b, 0xe1, + 0xc3, 0xd7, 0x24, 0xee, 0x3b, 0x50, 0x44, 0xe2, 0x0e, 0xbc, 0x0e, 0x00, 0x25, 0xa0, 0x96, 0xf9, + 0x47, 0x87, 0xb5, 0x63, 0x7a, 0xfe, 0xec, 0x06, 0x07, 0x80, 0x51, 0xec, 0x84, 0x50, 0x08, 0x70, + 0x3f, 0xfd, 0x65, 0x80, 0x65, 0xff, 0x4e, 0xc7, 0xfd, 0xea, 0x65, 0xe4, 0x5c, 0x24, 0xc6, 0x29, + 0x28, 0xb8, 0xe7, 0xf5, 0x3c, 0xdd, 0x62, 0xdc, 0x25, 0x24, 0xee, 0xb6, 0x44, 0xbe, 0x66, 0xb2, + 0x2d, 0x47, 0x70, 0x7f, 0x04, 0xe3, 0x1e, 0x0d, 0x70, 0x1f, 0x25, 0x71, 0xdf, 0x66, 0x91, 0xb8, + 0xdb, 0xd6, 0x92, 0x80, 0x27, 0x0e, 0x0b, 0xc6, 0x8f, 0x3b, 0x03, 0xc2, 0x9d, 0x45, 0xe2, 0xbe, + 0xdd, 0x22, 0x71, 0xb7, 0x2d, 0xe2, 0x70, 0x57, 0x12, 0x62, 0x0f, 0x61, 0xb8, 0x8f, 0x92, 0xb8, + 0x5b, 0xd1, 0x5e, 0xc6, 0x7d, 0x79, 0x42, 0x20, 0x8d, 0x0e, 0x87, 0x70, 0x57, 0xe4, 0x65, 0x62, + 0xbc, 0x43, 0x28, 0x66, 0xf0, 0xa0, 0xfc, 0xc3, 0xd1, 0xf4, 0xee, 0xd6, 0x7e, 0x31, 0x21, 0xf6, + 0x2c, 0xe8, 0x8d, 0xa9, 0x35, 0x70, 0xfe, 0x0f, 0xea, 0xef, 0x43, 0x72, 0xeb, 0x29, 0x8b, 0xc1, + 0xc3, 0x09, 0xbf, 0x18, 0x0e, 0x09, 0x24, 0xaa, 0x6a, 0xb6, 0x0b, 0x89, 0xc4, 0xdd, 0xb6, 0x8c, + 0x6a, 0x95, 0x39, 0xf7, 0xd5, 0x66, 0x5c, 0xe4, 0xe9, 0x49, 0x18, 0x39, 0x6a, 0x1e, 0x0d, 0x4a, + 0xa1, 0xb0, 0x99, 0x08, 0x0a, 0x83, 0xa8, 0xc0, 0x77, 0x30, 0xe4, 0x8d, 0xc9, 0xef, 0x81, 0x70, + 0xcf, 0x7e, 0x30, 0x66, 0x5c, 0x41, 0x7f, 0xfc, 0x4c, 0x7a, 0x9d, 0x82, 0x06, 0x87, 0x76, 0x4a, + 0xe3, 0xa3, 0x0d, 0x12, 0x62, 0x1e, 0x3f, 0x17, 0x12, 0x89, 0xbb, 0x6d, 0x81, 0x5e, 0x5c, 0x59, + 0x98, 0x03, 0xc7, 0x45, 0x7e, 0x77, 0x4e, 0xf7, 0xf2, 0x85, 0xb5, 0x53, 0x40, 0x07, 0x9c, 0x51, + 0x3f, 0x0c, 0x11, 0x09, 0x1e, 0x80, 0x5a, 0x96, 0x23, 0x39, 0xcc, 0x36, 0x6a, 0x46, 0x63, 0x48, + 0xb9, 0xff, 0x1c, 0xbe, 0x72, 0x76, 0x67, 0x53, 0xbf, 0xc4, 0xda, 0x29, 0x60, 0xa8, 0x2d, 0xfa, + 0x3e, 0x08, 0xfe, 0x75, 0xa2, 0x67, 0x10, 0x92, 0x57, 0xd0, 0xb5, 0x44, 0xe2, 0x6e, 0x97, 0xe6, + 0x9a, 0xeb, 0xf9, 0x9f, 0x1f, 0x80, 0xe3, 0x08, 0x30, 0x97, 0xf3, 0xf5, 0xbd, 0x9e, 0x8e, 0xbf, + 0xf3, 0x0c, 0xe6, 0x92, 0xd6, 0x75, 0x9f, 0xe9, 0x78, 0x92, 0xcd, 0x57, 0x93, 0xb3, 0x89, 0x77, + 0xb9, 0xd0, 0x35, 0xaf, 0xdd, 0x6a, 0xcb, 0x6b, 0xb5, 0x5a, 0xc1, 0x74, 0xcd, 0x5c, 0x24, 0xac, + 0x8c, 0x7f, 0xc4, 0x77, 0xa3, 0xf1, 0x3c, 0x5f, 0xaf, 0xe9, 0xea, 0x4a, 0x87, 0xcd, 0x70, 0x5d, + 0x91, 0xb8, 0xdb, 0x25, 0xe0, 0x0f, 0xc8, 0xa9, 0xc9, 0x70, 0x07, 0x1f, 0xf4, 0xb5, 0x6e, 0x08, + 0xab, 0x1e, 0x9b, 0x40, 0xb6, 0x70, 0xb3, 0x1c, 0x41, 0x67, 0xca, 0xe3, 0x84, 0x72, 0x2e, 0x77, + 0x0c, 0x5f, 0x92, 0x82, 0xb9, 0xc5, 0x25, 0x5a, 0xdd, 0x50, 0x44, 0x1a, 0x5c, 0x88, 0xf4, 0x7a, + 0x76, 0xe7, 0x2f, 0x6d, 0x58, 0xa1, 0xc5, 0xfa, 0x91, 0x61, 0x51, 0xf0, 0x05, 0xd8, 0x93, 0xf9, + 0x31, 0x6a, 0x59, 0x48, 0x64, 0x6a, 0x5b, 0x57, 0x11, 0x89, 0xbb, 0xbd, 0x5a, 0xe8, 0xea, 0x10, + 0x9e, 0x39, 0x0e, 0x7b, 0xf0, 0x59, 0x94, 0xd5, 0x15, 0xac, 0x9c, 0x61, 0xa8, 0xa5, 0x07, 0xde, + 0x79, 0xf3, 0xa9, 0x8c, 0xb4, 0x9a, 0xa1, 0x8a, 0x4e, 0xc1, 0x94, 0x4a, 0x8b, 0x7a, 0x2e, 0x18, + 0x7a, 0x3e, 0x19, 0x94, 0x66, 0x36, 0x8c, 0xc4, 0x95, 0xf6, 0xa1, 0x5e, 0x21, 0x36, 0xb7, 0xab, + 0xf1, 0x2f, 0x11, 0xb6, 0xd9, 0x0a, 0x1a, 0x1c, 0xbd, 0x0c, 0xba, 0xf6, 0x99, 0x5a, 0xab, 0xe1, + 0x9c, 0xbb, 0x5b, 0x24, 0xee, 0x38, 0x04, 0xbc, 0x17, 0x08, 0x9d, 0xb7, 0xc4, 0xa7, 0x9a, 0x74, + 0xe8, 0xbc, 0xae, 0xab, 0xaa, 0x67, 0x92, 0x72, 0x87, 0x85, 0x8a, 0xec, 0xff, 0x8d, 0xc2, 0xb8, + 0x9e, 0xd5, 0x69, 0xae, 0x2d, 0x95, 0xdd, 0x19, 0x49, 0xed, 0xb0, 0xd4, 0x16, 0xb5, 0xd6, 0xa2, + 0x72, 0x98, 0x65, 0x98, 0x9d, 0xfa, 0xda, 0xdb, 0x84, 0x84, 0x8a, 0xbc, 0x2c, 0xa4, 0xc1, 0xca, + 0xa2, 0xdc, 0x3d, 0xe8, 0xb5, 0x5b, 0x44, 0xe2, 0x8e, 0x4f, 0xc8, 0x19, 0x3d, 0x33, 0xf1, 0xd4, + 0x14, 0x7b, 0x00, 0xaa, 0x61, 0x8b, 0xf2, 0xea, 0x51, 0x92, 0xec, 0xe1, 0x6a, 0x49, 0x25, 0xec, + 0x4a, 0xa6, 0xd0, 0xe6, 0xbd, 0x8c, 0x0a, 0xb9, 0x3c, 0x1d, 0xf6, 0xbe, 0xcc, 0xac, 0xe7, 0x65, + 0xad, 0x12, 0x51, 0x21, 0xd4, 0x45, 0x45, 0xe2, 0x8e, 0x4f, 0x26, 0xbd, 0x1e, 0x95, 0x78, 0x51, + 0x48, 0xa0, 0x96, 0xdb, 0x67, 0xe7, 0x45, 0x58, 0xa3, 0x2a, 0x7a, 0xeb, 0x3f, 0x94, 0xbb, 0x5c, + 0x64, 0x5e, 0x1a, 0xb4, 0x5e, 0xbf, 0x2d, 0xae, 0xa4, 0x37, 0xa3, 0x71, 0xb4, 0xb9, 0x5f, 0xa2, + 0x5e, 0x5c, 0xb6, 0xe7, 0xfa, 0x9a, 0x5e, 0xf6, 0x54, 0xd0, 0x37, 0x48, 0x23, 0x15, 0x39, 0x69, + 0x2b, 0x73, 0xc4, 0xc4, 0xdc, 0xbb, 0xa8, 0x48, 0xdc, 0x1d, 0x91, 0xba, 0xe2, 0x67, 0xde, 0x41, + 0x4f, 0xd4, 0x6e, 0xde, 0x88, 0x73, 0xc5, 0x96, 0x66, 0xc9, 0x38, 0x2e, 0x5b, 0xe4, 0xf0, 0x66, + 0x5a, 0x38, 0xd2, 0x1a, 0xd6, 0x24, 0x70, 0xe5, 0xab, 0xba, 0x27, 0x9a, 0xfa, 0xc4, 0xec, 0x31, + 0xd5, 0xa4, 0x4a, 0xeb, 0x40, 0xb1, 0x6f, 0x73, 0xe9, 0x6a, 0xb4, 0xf2, 0x18, 0xaa, 0xd2, 0xdb, + 0xab, 0xa6, 0xdd, 0x53, 0x3a, 0xdc, 0x31, 0xa1, 0xe3, 0x6e, 0x30, 0x18, 0x5e, 0x0e, 0xbd, 0xd8, + 0xd8, 0x62, 0xa3, 0x22, 0x1b, 0xeb, 0xeb, 0x36, 0xee, 0xe1, 0xf3, 0xb7, 0xad, 0x38, 0xd1, 0x4e, + 0x90, 0x7e, 0x64, 0x58, 0x1c, 0x1e, 0x8a, 0xa4, 0x6a, 0xf2, 0xdc, 0x29, 0x25, 0x8d, 0x6a, 0x72, + 0xba, 0xc3, 0x60, 0x7e, 0x39, 0x50, 0x94, 0x3b, 0xee, 0xed, 0x8e, 0x34, 0x49, 0x78, 0xfc, 0xc8, + 0x6c, 0x4b, 0x83, 0x93, 0xed, 0xd9, 0x99, 0xb2, 0xda, 0xbb, 0xff, 0x3d, 0x38, 0xb0, 0x5e, 0x3f, + 0x16, 0xd9, 0x02, 0x8e, 0xfa, 0x13, 0x52, 0x24, 0xde, 0xd5, 0xf5, 0xae, 0xac, 0x1c, 0x82, 0x30, + 0xf3, 0x64, 0x5f, 0x5c, 0x94, 0xa6, 0xef, 0x99, 0x13, 0x6c, 0xd0, 0x3e, 0x1f, 0x94, 0x53, 0x93, + 0xcd, 0x69, 0xff, 0x91, 0x66, 0x78, 0xba, 0xa9, 0x8a, 0x0b, 0x9c, 0x60, 0x83, 0xab, 0x08, 0xcb, + 0x99, 0x11, 0x08, 0xf8, 0x96, 0xd5, 0x18, 0x50, 0xfb, 0xf6, 0xfc, 0x59, 0xbc, 0x4b, 0x4e, 0x77, + 0xb1, 0x80, 0x87, 0xa0, 0xcc, 0x47, 0x99, 0x00, 0x59, 0x6f, 0xb2, 0xe4, 0x9b, 0xb3, 0x4d, 0xb5, + 0x26, 0x0d, 0x91, 0x0b, 0x0e, 0xc1, 0x70, 0x73, 0xbe, 0xa3, 0x0d, 0xf8, 0x4e, 0x7c, 0x3f, 0x1f, + 0x6b, 0xf7, 0x55, 0x80, 0x1f, 0x99, 0x65, 0xbb, 0x7c, 0xfd, 0xbd, 0x23, 0x1b, 0xbe, 0xbb, 0x5a, + 0xad, 0xda, 0xef, 0xe5, 0xb1, 0x91, 0xf5, 0x88, 0xf0, 0x30, 0xe7, 0x58, 0xe6, 0x5a, 0x5a, 0x99, + 0x9d, 0x51, 0x97, 0x15, 0xf3, 0x7c, 0x3e, 0xc4, 0xe0, 0x5e, 0x70, 0xc2, 0x5f, 0x9e, 0x71, 0x6b, + 0xfa, 0xde, 0xaf, 0x4b, 0xbc, 0x71, 0xbc, 0xfd, 0x85, 0x49, 0xa7, 0x5b, 0xe2, 0x8f, 0x4f, 0x57, + 0x57, 0xca, 0xb3, 0x28, 0xc2, 0xd3, 0xc7, 0x30, 0xee, 0xc2, 0x3b, 0xfc, 0x89, 0xaa, 0xa4, 0x70, + 0x0f, 0xc6, 0xc3, 0xd8, 0x23, 0xdb, 0x43, 0x55, 0xbd, 0x4e, 0xe7, 0x7f, 0xd8, 0xcf, 0xc2, 0x7a, + 0x6a, 0x4a, 0x92, 0x13, 0x6c, 0x72, 0x69, 0x69, 0x07, 0x38, 0xb2, 0x54, 0x38, 0x9e, 0x0c, 0x9d, + 0xcb, 0x03, 0x1f, 0x09, 0x8e, 0x7e, 0x36, 0x75, 0xf1, 0xab, 0x37, 0x09, 0x37, 0xc0, 0x63, 0xa0, + 0xc8, 0xa5, 0x2a, 0xf3, 0xb3, 0x81, 0xff, 0xad, 0x2c, 0xc8, 0x51, 0xd0, 0x33, 0x15, 0xd9, 0x69, + 0xb2, 0xe4, 0x78, 0xf1, 0x95, 0x4b, 0xc2, 0x13, 0xfe, 0xf6, 0x54, 0xa8, 0xe3, 0xf9, 0x79, 0xcb, + 0x12, 0xe3, 0xe6, 0xdb, 0x1f, 0x6f, 0xf7, 0x3f, 0x60, 0x47, 0xcb, 0xae, 0x99, 0x19, 0x93, 0xc9, + 0x74, 0x68, 0xbf, 0x77, 0x4a, 0x62, 0xc2, 0x56, 0x5b, 0xb3, 0x9b, 0xa4, 0x61, 0xf7, 0x28, 0x0b, + 0x73, 0x26, 0xce, 0x9e, 0xb4, 0x07, 0x7d, 0x87, 0xdb, 0xe4, 0xf9, 0x33, 0x0a, 0x7a, 0xc6, 0x02, + 0xb3, 0x7d, 0xbb, 0xbf, 0xae, 0x6b, 0xe8, 0x3d, 0x83, 0x61, 0x59, 0x43, 0x6a, 0x2b, 0x35, 0x2f, + 0x95, 0xc8, 0x3b, 0x18, 0xa2, 0xd2, 0x22, 0x41, 0x52, 0xfc, 0x48, 0x80, 0xff, 0xab, 0x43, 0xde, + 0x38, 0x9a, 0xef, 0xe6, 0x01, 0xa8, 0xa7, 0x1b, 0xff, 0x53, 0x1f, 0x69, 0xcc, 0x35, 0xe5, 0x6d, + 0xba, 0xa6, 0xf7, 0x29, 0x39, 0xb1, 0x88, 0x57, 0xf6, 0xce, 0xbb, 0x93, 0x22, 0x50, 0x26, 0xf0, + 0x10, 0x70, 0x7a, 0x67, 0xea, 0x6b, 0x54, 0xa5, 0x45, 0x60, 0x98, 0x0b, 0x3c, 0x19, 0xe0, 0xb7, + 0x48, 0x6f, 0x44, 0x4a, 0xc2, 0x43, 0x45, 0x21, 0x81, 0xe2, 0xb0, 0x60, 0x69, 0x74, 0xf8, 0x9b, + 0x9f, 0x7e, 0x90, 0xa7, 0x27, 0x81, 0x4f, 0xc1, 0x31, 0x33, 0xb5, 0xd5, 0xda, 0x81, 0x7e, 0x83, + 0xcc, 0xa9, 0xc5, 0x8a, 0x77, 0xa5, 0xfe, 0x05, 0x34, 0x91, 0x5b, 0x5a, 0x71, 0xf0, 0xe8, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, +}; + +const BITMAP_OPAQUE tune_diff_pair_length_legend_xpm[1] = {{ png, sizeof( png ), "tune_diff_pair_length_legend_xpm" }}; + +//EOF diff --git a/bitmaps_png/cpp_other/tune_diff_pair_skew_legend.cpp b/bitmaps_png/cpp_other/tune_diff_pair_skew_legend.cpp new file mode 100644 index 0000000000..212be2465f --- /dev/null +++ b/bitmaps_png/cpp_other/tune_diff_pair_skew_legend.cpp @@ -0,0 +1,362 @@ + +/* Do not modify this file, it was automatically generated by the + * PNG2cpp CMake script, using a *.png file as input. + */ + +#include + +static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x62, 0x08, 0x02, 0x00, 0x00, 0x01, 0x81, 0xbc, 0x69, + 0xd2, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x1e, 0xc2, 0x00, 0x00, 0x1e, + 0xc2, 0x01, 0x6e, 0xd0, 0x75, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x89, 0x2a, 0x8d, 0x06, 0x00, 0x00, 0x15, 0x65, 0x49, + 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x5d, 0x89, 0x5f, 0x13, 0xd7, 0x1a, 0xed, 0x7f, 0xf1, 0x6c, + 0x5d, 0x00, 0x37, 0xac, 0x56, 0xad, 0x6d, 0xad, 0xb6, 0xd5, 0xda, 0x45, 0x5f, 0xad, 0x4f, 0xfb, + 0xac, 0xaf, 0x8b, 0xad, 0xd6, 0xf7, 0x6c, 0x1b, 0x54, 0x04, 0x91, 0x55, 0x14, 0x10, 0x41, 0x14, + 0x14, 0x14, 0x5b, 0x15, 0x5c, 0xd9, 0x41, 0x01, 0xc1, 0x8d, 0x4d, 0x76, 0x64, 0x47, 0x05, 0x64, + 0x0b, 0x88, 0x0a, 0x84, 0x7d, 0xdf, 0x03, 0x01, 0x02, 0xef, 0x9b, 0xdc, 0x38, 0x0c, 0x59, 0x27, + 0xc9, 0x4c, 0x26, 0x81, 0x39, 0xbf, 0x43, 0x7e, 0x93, 0xc9, 0xcc, 0xbd, 0x5f, 0x0e, 0x27, 0x77, + 0xee, 0xdc, 0xb9, 0xcb, 0x5b, 0x13, 0xe4, 0x30, 0x32, 0x32, 0x42, 0xf2, 0x48, 0x09, 0xbc, 0x45, + 0xe6, 0x20, 0xb3, 0x03, 0xfb, 0x0c, 0xde, 0xf9, 0x07, 0xf5, 0x19, 0x38, 0x1e, 0x3d, 0x22, 0xbd, + 0x73, 0xfe, 0xdc, 0x77, 0x28, 0xcb, 0x80, 0x12, 0xbc, 0x55, 0x59, 0x59, 0xf9, 0xe0, 0xfe, 0x7d, + 0x99, 0x0c, 0x0c, 0x8b, 0xf4, 0x38, 0x77, 0x83, 0x48, 0xc7, 0xd3, 0x21, 0x4e, 0x7e, 0x4f, 0x55, + 0xcb, 0x00, 0xfe, 0xc8, 0xeb, 0xab, 0xc6, 0x7f, 0x82, 0xac, 0x44, 0x5b, 0x37, 0x6f, 0x1a, 0x1c, + 0x1c, 0x44, 0xdb, 0x39, 0xd5, 0x5d, 0x6a, 0x66, 0x10, 0x17, 0x1b, 0x03, 0xaf, 0xa1, 0xc1, 0x81, + 0x03, 0x03, 0x03, 0x12, 0xc7, 0xf5, 0xf7, 0xf7, 0xe3, 0xdb, 0xdc, 0xa6, 0xfe, 0x09, 0xd2, 0x90, + 0x2b, 0x11, 0xc7, 0x25, 0x41, 0xde, 0x39, 0x26, 0xc7, 0x1e, 0xaa, 0x96, 0x01, 0x11, 0x76, 0xa1, + 0xa5, 0x1c, 0x87, 0x18, 0xce, 0xf1, 0x38, 0xc5, 0xa7, 0x71, 0x5c, 0x13, 0x39, 0x4e, 0xb1, 0x4a, + 0x29, 0x23, 0x03, 0xca, 0xa1, 0xf5, 0x0c, 0x5a, 0x4f, 0x1f, 0xaf, 0xfb, 0xe5, 0x7b, 0xaa, 0x48, + 0xf6, 0x1b, 0x50, 0x5f, 0x10, 0xb5, 0xb5, 0xb5, 0xa9, 0x97, 0x22, 0xa9, 0xd4, 0x73, 0x72, 0xb2, + 0xa5, 0x43, 0x56, 0xf5, 0x4b, 0x28, 0x4a, 0x5d, 0xa5, 0x84, 0x64, 0xa7, 0x2e, 0xaf, 0x74, 0x0b, + 0x0e, 0x0a, 0x94, 0x28, 0xdd, 0x80, 0x2a, 0xfd, 0xac, 0x26, 0x14, 0xfc, 0x74, 0x9d, 0x3d, 0x82, + 0xa4, 0x77, 0xc2, 0x91, 0xea, 0xfc, 0x6e, 0x3d, 0x4e, 0xbb, 0x49, 0x7c, 0x20, 0x91, 0x0a, 0xaf, + 0xae, 0xf6, 0xc2, 0x79, 0x2f, 0xe9, 0xfd, 0xa4, 0x52, 0x07, 0x58, 0x9a, 0x9b, 0x75, 0x76, 0x76, + 0x18, 0xce, 0x9e, 0x95, 0x9d, 0x95, 0xa9, 0x20, 0x15, 0x95, 0x53, 0x97, 0xa9, 0x8c, 0xf9, 0xc5, + 0x1c, 0x99, 0x27, 0x5c, 0x4f, 0x7e, 0xad, 0x5a, 0xea, 0x44, 0x60, 0xc5, 0x99, 0x43, 0x8c, 0x53, + 0x64, 0x85, 0x82, 0x73, 0x62, 0x8a, 0x5a, 0xc8, 0x14, 0x67, 0x40, 0x7a, 0x4b, 0x1b, 0xed, 0xa6, + 0x4e, 0x61, 0x29, 0x06, 0xa4, 0x2c, 0x76, 0xdf, 0x4b, 0x17, 0xd1, 0xa5, 0x54, 0x9b, 0x50, 0x27, + 0x7a, 0x79, 0x85, 0x50, 0x51, 0xe1, 0x33, 0xcd, 0x82, 0x51, 0x19, 0x6a, 0x46, 0xbf, 0x72, 0xe9, + 0x12, 0x32, 0x25, 0x32, 0x1c, 0xa3, 0xf6, 0xd5, 0x87, 0x0c, 0xa8, 0xd4, 0x5e, 0xfb, 0x10, 0x47, + 0xbf, 0x7a, 0xd5, 0x0a, 0x1b, 0x4b, 0x0b, 0x92, 0xe7, 0x5c, 0x08, 0x8a, 0x81, 0x12, 0xf3, 0x55, + 0xab, 0x64, 0x3d, 0x51, 0x26, 0xe0, 0x48, 0xb3, 0x93, 0x8f, 0xd4, 0x8c, 0x4e, 0x19, 0x64, 0x68, + 0x6f, 0x34, 0xe7, 0x6d, 0xc5, 0xe7, 0xc8, 0xbc, 0x80, 0x49, 0x63, 0xef, 0x6f, 0xbb, 0x90, 0x6d, + 0xe0, 0x0b, 0xa4, 0x71, 0x3b, 0xd4, 0x08, 0x4e, 0x29, 0x24, 0xa3, 0x87, 0xfc, 0x76, 0xfd, 0xfc, + 0x23, 0x5c, 0xad, 0xa0, 0x00, 0x59, 0xba, 0x68, 0xfe, 0xaa, 0xe5, 0x4b, 0x53, 0x53, 0x92, 0x17, + 0x1a, 0xcc, 0x31, 0x5e, 0x60, 0x08, 0xdb, 0xe8, 0x18, 0x05, 0x97, 0xaa, 0xd6, 0xd6, 0x56, 0x78, + 0x5d, 0xb7, 0x66, 0xf5, 0xba, 0xb5, 0xab, 0xf1, 0x9d, 0x70, 0x7c, 0x61, 0x5d, 0x0f, 0x0d, 0xc1, + 0x8b, 0xa2, 0x0f, 0xbf, 0x15, 0xf6, 0xd9, 0x9a, 0x8f, 0x80, 0x8d, 0x8d, 0x0d, 0x64, 0xce, 0x51, + 0xb5, 0x16, 0x02, 0xc7, 0x07, 0x3f, 0xae, 0x53, 0x27, 0x3a, 0x65, 0x10, 0x6b, 0xdf, 0x26, 0xd2, + 0x4c, 0x1a, 0x91, 0xf9, 0x8d, 0x01, 0x19, 0x75, 0x88, 0x17, 0x62, 0xab, 0x21, 0x0e, 0x55, 0x43, + 0x47, 0x80, 0x5b, 0x11, 0x38, 0xd1, 0x29, 0xbc, 0xdc, 0x37, 0xf1, 0x15, 0x55, 0x9c, 0xd0, 0xc2, + 0x5d, 0x03, 0xad, 0x98, 0xd6, 0xd1, 0xb7, 0x5d, 0x38, 0xd3, 0xe2, 0xe6, 0xa8, 0x9b, 0x54, 0x1e, + 0x3d, 0x79, 0xec, 0xf8, 0x6e, 0xeb, 0xc6, 0x0d, 0xeb, 0xa9, 0x4a, 0x8d, 0x0c, 0x28, 0x0b, 0x7d, + 0xc1, 0xbc, 0xd9, 0x54, 0x25, 0x45, 0x12, 0x94, 0x85, 0x3e, 0x36, 0x36, 0x26, 0xef, 0x23, 0x3e, + 0x9f, 0x4f, 0x55, 0x2e, 0x44, 0xa8, 0x1f, 0xba, 0x74, 0xeb, 0x66, 0x77, 0xd7, 0x94, 0xd6, 0x29, + 0xbc, 0xa5, 0xa9, 0xa7, 0xa7, 0x5b, 0xed, 0x5c, 0x14, 0x40, 0xcd, 0xd0, 0xc9, 0x54, 0x18, 0x8b, + 0x8b, 0x0a, 0xe1, 0x98, 0xe6, 0xa6, 0x26, 0x1d, 0x0a, 0x7d, 0x78, 0x78, 0x98, 0x7c, 0xe8, 0x3e, + 0x17, 0xff, 0xd6, 0xa1, 0xd0, 0x11, 0xb2, 0x32, 0x1f, 0x2b, 0x3e, 0x80, 0x57, 0x27, 0xae, 0x0b, + 0xe8, 0x5c, 0xe8, 0xe4, 0x41, 0x57, 0xe8, 0xa8, 0xed, 0xe7, 0x82, 0xf7, 0x39, 0x79, 0xcd, 0x42, + 0x32, 0xe9, 0xe1, 0xed, 0x27, 0xdd, 0x56, 0x24, 0xdd, 0x74, 0x04, 0x1c, 0x14, 0x8c, 0xd1, 0xab, + 0xba, 0x4a, 0x37, 0x69, 0x10, 0x90, 0xa9, 0x67, 0x3a, 0x99, 0x23, 0x2d, 0xfc, 0x0a, 0xe0, 0x60, + 0x1a, 0x43, 0x9f, 0x3f, 0xf7, 0x1d, 0x08, 0xfd, 0x9b, 0xaf, 0xbf, 0x20, 0x73, 0xc2, 0xa9, 0x7b, + 0x55, 0x64, 0x2a, 0x92, 0x28, 0x4d, 0xa0, 0xed, 0xcd, 0x67, 0x07, 0x4f, 0xdc, 0xd7, 0x34, 0x4c, + 0x59, 0x10, 0xab, 0xfe, 0xfb, 0x9e, 0xdd, 0x68, 0x03, 0x6e, 0x38, 0x14, 0x9f, 0xc0, 0x71, 0x4b, + 0xb2, 0x0f, 0x2b, 0x25, 0x93, 0xf4, 0xc7, 0x1f, 0xac, 0x74, 0x77, 0x73, 0x1d, 0x1e, 0x15, 0x9a, + 0x39, 0x45, 0x6b, 0x12, 0xa2, 0x3c, 0x48, 0x86, 0xee, 0x74, 0xcc, 0x5e, 0xb1, 0x79, 0x38, 0xae, + 0x89, 0x4e, 0x11, 0xe5, 0x32, 0x3f, 0x32, 0x9e, 0x6f, 0x80, 0xaa, 0x03, 0xb6, 0x56, 0x87, 0xf1, + 0x9d, 0x23, 0x63, 0x42, 0xf5, 0xaa, 0xfb, 0x4a, 0x31, 0x25, 0xf4, 0x8e, 0x8e, 0x76, 0xb8, 0xdf, + 0xdb, 0xbc, 0xf1, 0xab, 0x09, 0x51, 0x75, 0xca, 0xf1, 0xe8, 0x11, 0x81, 0x40, 0xf0, 0xcd, 0xd7, + 0x5f, 0x92, 0x0f, 0x1d, 0x6d, 0x10, 0xbf, 0x3c, 0xfc, 0x4c, 0xb5, 0x11, 0x3a, 0x9e, 0xe5, 0xf7, + 0xdb, 0xfe, 0x05, 0xaf, 0xf5, 0xf5, 0xbc, 0x07, 0xf7, 0xee, 0xa2, 0x3d, 0x47, 0xed, 0x6c, 0xd1, + 0x06, 0x99, 0xd0, 0x89, 0xe8, 0x1e, 0x1c, 0xa1, 0x31, 0x74, 0xb8, 0x49, 0x85, 0x5c, 0xe1, 0x95, + 0xcc, 0x09, 0x9c, 0x63, 0x0f, 0xaf, 0xa7, 0xd6, 0xa8, 0x94, 0x07, 0x8d, 0xa1, 0x67, 0x67, 0x66, + 0x82, 0xde, 0xf8, 0x33, 0x3e, 0xca, 0xe3, 0x80, 0x53, 0xae, 0xa6, 0xd4, 0xa8, 0x7a, 0x96, 0x52, + 0x28, 0x29, 0xd7, 0xf1, 0xfb, 0x6b, 0xa0, 0xd5, 0x8d, 0xa7, 0x10, 0x04, 0x14, 0x8e, 0x6a, 0x64, + 0x03, 0x27, 0xee, 0x77, 0x4f, 0xf1, 0xa1, 0xee, 0xfe, 0xfa, 0x66, 0x7a, 0xad, 0x92, 0x8a, 0x00, + 0x6a, 0x94, 0xc7, 0xe8, 0x1c, 0x7f, 0xf0, 0x42, 0x96, 0x1a, 0x41, 0xe3, 0x70, 0x08, 0x2c, 0x24, + 0xd9, 0x76, 0x4f, 0x86, 0xb6, 0x21, 0xa5, 0x7a, 0x7c, 0x73, 0xcd, 0x86, 0xce, 0x04, 0xa6, 0x6f, + 0xe8, 0x8c, 0xb7, 0xb7, 0xc8, 0x63, 0xbb, 0x8f, 0xb7, 0x92, 0xd0, 0xa9, 0x7d, 0xb8, 0x45, 0x21, + 0xdb, 0xbc, 0xdd, 0x75, 0xce, 0x30, 0x56, 0x16, 0xe6, 0xb1, 0x0f, 0x1f, 0xc0, 0x46, 0x5d, 0x6d, + 0xad, 0xcc, 0x9a, 0xc5, 0xf4, 0x80, 0xce, 0xe9, 0x0e, 0xe0, 0x56, 0x94, 0x7f, 0xbb, 0xe9, 0x2b, + 0xb8, 0xc4, 0x7f, 0xb7, 0x65, 0x33, 0xd3, 0xb1, 0xd0, 0x05, 0x2d, 0xe9, 0x4e, 0xfe, 0x99, 0x60, + 0x7a, 0x5a, 0xaa, 0xe1, 0xec, 0x59, 0xd7, 0xaf, 0xfa, 0xee, 0xd9, 0xb5, 0xf3, 0xc3, 0x15, 0xef, + 0x91, 0xcf, 0x82, 0xa6, 0xbb, 0x60, 0x9a, 0xc0, 0x80, 0xee, 0x70, 0x17, 0xa6, 0xf9, 0xb3, 0x62, + 0xd4, 0xc0, 0x96, 0x93, 0x35, 0x59, 0x2f, 0x64, 0x75, 0x97, 0x81, 0xbd, 0x7b, 0x76, 0xa3, 0x36, + 0x0e, 0x9c, 0xfb, 0x39, 0x7f, 0x68, 0xc2, 0x9d, 0x3f, 0xfe, 0x87, 0x98, 0xda, 0x22, 0xc3, 0xb9, + 0xac, 0xee, 0x32, 0x80, 0xfb, 0xbd, 0xa1, 0xa1, 0xde, 0x68, 0xce, 0xdb, 0x54, 0xf9, 0xfd, 0xd0, + 0xc1, 0x03, 0xf8, 0x1e, 0x56, 0x77, 0x19, 0xd0, 0x42, 0x9f, 0x0f, 0x56, 0x77, 0x19, 0x20, 0xea, + 0x1e, 0xf5, 0xa4, 0xc9, 0x36, 0xb4, 0xd4, 0xca, 0xbf, 0xd0, 0xfa, 0xfa, 0x13, 0xab, 0x6b, 0x18, + 0x2d, 0xaf, 0x16, 0x58, 0x5d, 0x2d, 0xb0, 0xbc, 0x92, 0x0f, 0x3c, 0xec, 0x0b, 0xcc, 0xb3, 0xf0, + 0xc9, 0xb3, 0xb8, 0x9c, 0x7b, 0x08, 0x78, 0x09, 0x98, 0x63, 0x7e, 0x31, 0xc7, 0xec, 0xef, 0x6c, + 0xb3, 0xbf, 0xb2, 0xe0, 0x46, 0xff, 0xa0, 0x77, 0x26, 0xd0, 0xf6, 0xe6, 0x53, 0xc7, 0x88, 0x72, + 0x62, 0x47, 0x68, 0x3d, 0xd6, 0x7d, 0x6c, 0x6c, 0x8c, 0xa6, 0xde, 0x51, 0xa0, 0xbb, 0xeb, 0x9d, + 0x0a, 0xf4, 0xf0, 0x00, 0xc8, 0xf1, 0x48, 0xb5, 0xbc, 0xf6, 0xc4, 0xda, 0xaf, 0xd0, 0xc6, 0x5f, + 0xc4, 0x00, 0x78, 0x2d, 0xb2, 0x09, 0x10, 0x31, 0xb0, 0x18, 0x68, 0x8b, 0x18, 0x04, 0x7c, 0x2e, + 0x66, 0x30, 0x62, 0x09, 0xa2, 0xe5, 0x8d, 0x67, 0x1c, 0x87, 0x18, 0x94, 0xda, 0x3e, 0x87, 0x87, + 0xe3, 0xe3, 0xe3, 0xfa, 0xaa, 0x7b, 0x6b, 0x4b, 0x0b, 0x7e, 0x99, 0xa2, 0x3c, 0x1b, 0x67, 0x8f, + 0x20, 0xec, 0xe9, 0xc8, 0xa5, 0xbc, 0xae, 0x01, 0x35, 0x47, 0x97, 0x10, 0x11, 0x1a, 0x1c, 0xb4, + 0xd0, 0x60, 0x0e, 0x0a, 0x35, 0x30, 0x55, 0xdc, 0x11, 0xe6, 0x54, 0x84, 0xb6, 0xbb, 0x08, 0x6a, + 0x02, 0xb1, 0xee, 0x99, 0x8f, 0x33, 0x24, 0xea, 0x1b, 0x78, 0x8b, 0x2a, 0xdc, 0x37, 0x86, 0x04, + 0x05, 0x6a, 0x92, 0x87, 0xa5, 0x6f, 0x3e, 0xe8, 0x7e, 0xc8, 0x27, 0x4f, 0xd3, 0x60, 0xdf, 0x60, + 0xe9, 0xa2, 0xf9, 0x28, 0x48, 0x34, 0xb0, 0xe6, 0xe9, 0xeb, 0x6e, 0xac, 0x23, 0x9d, 0x53, 0x74, + 0x47, 0xbf, 0x80, 0xaa, 0x2c, 0xe8, 0x86, 0x64, 0xf9, 0x8e, 0x3f, 0xaf, 0xc1, 0x01, 0x5f, 0xef, + 0x56, 0x68, 0xc8, 0xbe, 0x3f, 0xf7, 0xaa, 0x9d, 0x07, 0xc7, 0x35, 0x11, 0x74, 0x97, 0xf7, 0x98, + 0x41, 0x31, 0x5a, 0xa5, 0xfa, 0x7e, 0xd9, 0xdb, 0x5a, 0xa3, 0x8d, 0xcd, 0x1b, 0xbf, 0x44, 0x9d, + 0x13, 0x84, 0xc2, 0x71, 0xa4, 0xfb, 0xe3, 0x4a, 0x5a, 0xba, 0x00, 0xd2, 0x01, 0x25, 0xba, 0xe3, + 0x65, 0xce, 0x47, 0x2b, 0x97, 0x27, 0xc4, 0x29, 0x19, 0x29, 0x23, 0x0f, 0xa0, 0x3b, 0xd6, 0xaf, + 0x4d, 0x45, 0xdd, 0x8d, 0xe7, 0x1b, 0xf8, 0xdf, 0xbc, 0x81, 0xbf, 0x7d, 0x7f, 0x19, 0xd6, 0x81, + 0xf7, 0x83, 0xe5, 0xcb, 0xa4, 0x8f, 0x1c, 0x1e, 0x11, 0xa2, 0xa2, 0xa6, 0xe0, 0xb5, 0xde, 0x14, + 0xf1, 0x8a, 0x74, 0xdf, 0xb8, 0x61, 0xfd, 0xed, 0xb0, 0xd0, 0xe1, 0x37, 0x80, 0xaf, 0x0d, 0xaf, + 0x71, 0xb1, 0x31, 0x42, 0xa1, 0x10, 0x6c, 0x58, 0xc9, 0xc5, 0xba, 0xf7, 0x3f, 0xb8, 0x77, 0x17, + 0xae, 0x69, 0x2d, 0xcd, 0xcd, 0xd6, 0x87, 0x0f, 0xc1, 0xdb, 0x9e, 0xee, 0xee, 0xf7, 0xdf, 0x7b, + 0x57, 0x22, 0x4d, 0xb5, 0x75, 0x27, 0x8e, 0xe1, 0x9a, 0x10, 0xd5, 0xd9, 0x65, 0x1e, 0xd9, 0x37, + 0x34, 0x8a, 0x74, 0x2f, 0xad, 0xef, 0x53, 0x29, 0x0b, 0x06, 0x21, 0x57, 0xf7, 0xc8, 0xf0, 0xdb, + 0xd2, 0xcd, 0x23, 0x20, 0x3d, 0xea, 0x9f, 0xdf, 0xd9, 0xd9, 0x51, 0x5f, 0xcf, 0x9b, 0x10, 0xe9, + 0x6e, 0x67, 0x6d, 0xf9, 0xc5, 0xba, 0x4f, 0xc2, 0x42, 0x82, 0x79, 0xbc, 0xba, 0xed, 0x5b, 0xb7, + 0xc0, 0x4e, 0xb8, 0x7b, 0x24, 0x9e, 0x85, 0x74, 0x3f, 0x71, 0x47, 0xd1, 0x30, 0x0c, 0x69, 0x48, + 0xeb, 0x2e, 0x0f, 0x50, 0xac, 0x23, 0xdd, 0x5f, 0xb4, 0x90, 0xea, 0x55, 0xad, 0x0b, 0x98, 0xd4, + 0x9d, 0x78, 0x51, 0x5d, 0xb6, 0x78, 0x01, 0x55, 0x19, 0x84, 0x65, 0xf1, 0x90, 0x28, 0x94, 0xd4, + 0x64, 0xe4, 0x61, 0xbf, 0x67, 0x3a, 0x64, 0x71, 0xd0, 0x27, 0x9f, 0xbe, 0x2c, 0xa8, 0xc5, 0x14, + 0xbf, 0xa3, 0x9e, 0x22, 0x70, 0xbd, 0xa2, 0x24, 0xe9, 0x86, 0xae, 0x21, 0x53, 0xd7, 0x04, 0x24, + 0x7a, 0x43, 0x27, 0x2d, 0xfd, 0x09, 0x89, 0x30, 0x75, 0x4f, 0x41, 0x79, 0xf9, 0x88, 0x7a, 0x35, + 0xeb, 0x38, 0x26, 0x75, 0x2f, 0x17, 0x61, 0xef, 0x9e, 0xdd, 0xe5, 0xa4, 0xe1, 0xea, 0x97, 0x68, + 0xef, 0x16, 0x26, 0xcd, 0xc9, 0xfb, 0x23, 0x87, 0x98, 0xf8, 0xa2, 0x66, 0x6d, 0x7e, 0x1f, 0x6b, + 0xcf, 0x54, 0x3c, 0x77, 0xdd, 0xa4, 0x6d, 0x48, 0xe9, 0x84, 0x6e, 0x3e, 0xf7, 0x98, 0x09, 0x60, + 0x75, 0x67, 0x06, 0xac, 0xee, 0xcc, 0x80, 0xd5, 0x9d, 0x19, 0xb0, 0xba, 0x33, 0x03, 0x8d, 0x74, + 0x6f, 0x71, 0x73, 0x7c, 0xb1, 0x68, 0x2e, 0x4b, 0x95, 0xd8, 0x76, 0xfe, 0xb4, 0xa6, 0xba, 0xd3, + 0x81, 0xbc, 0xdc, 0x1c, 0xc3, 0xd9, 0xb3, 0x16, 0xcc, 0x9b, 0x7d, 0xde, 0xf3, 0x2c, 0xd3, 0xb1, + 0xd0, 0x08, 0x9d, 0xd3, 0x1d, 0x6f, 0x89, 0x5b, 0xb2, 0xd0, 0xa8, 0xaf, 0x4f, 0x6f, 0xda, 0x5b, + 0x54, 0x85, 0x2e, 0xea, 0x6e, 0x63, 0x69, 0x41, 0xb2, 0x65, 0x46, 0x7f, 0xa1, 0x73, 0xba, 0x03, + 0xbc, 0xbd, 0x3c, 0x51, 0x33, 0x51, 0x7b, 0x3b, 0x05, 0xd3, 0xf7, 0xe8, 0x26, 0xb4, 0xa1, 0x3b, + 0xc9, 0xc1, 0x00, 0x80, 0xe1, 0xa1, 0xa1, 0x1f, 0xb6, 0x6f, 0x43, 0xdb, 0x81, 0xfe, 0x7e, 0x7f, + 0xee, 0xfd, 0x2f, 0xc9, 0x13, 0x2b, 0xb9, 0x5c, 0x35, 0x02, 0x63, 0x10, 0xda, 0xd0, 0xbd, 0xb1, + 0x81, 0xd4, 0x3c, 0x07, 0x08, 0x46, 0x73, 0xde, 0xde, 0xff, 0xe7, 0xef, 0xbe, 0x97, 0x2f, 0x81, + 0xdf, 0x5b, 0x9a, 0xc9, 0xb6, 0xed, 0x24, 0x25, 0x25, 0xaa, 0x15, 0x1a, 0x63, 0x60, 0x46, 0x77, + 0xc5, 0xc5, 0x77, 0x6b, 0x4b, 0x4b, 0xe1, 0x33, 0x25, 0xf3, 0xf9, 0x0d, 0x0f, 0x0f, 0x13, 0xdf, + 0xb2, 0xba, 0xcb, 0x00, 0x51, 0xf7, 0x27, 0x05, 0xf9, 0x60, 0xe4, 0x5c, 0x8d, 0xbb, 0x31, 0x41, + 0x22, 0xdb, 0xbe, 0xfd, 0x06, 0x7f, 0xcb, 0xea, 0x2e, 0x03, 0x48, 0xf7, 0xb6, 0xb6, 0x36, 0xa8, + 0x95, 0xa3, 0x0b, 0x26, 0x25, 0xba, 0x8b, 0x07, 0x95, 0x8a, 0x86, 0x3a, 0xb2, 0xba, 0xcb, 0x00, + 0xe8, 0xbe, 0xd8, 0x68, 0x1e, 0xf1, 0x79, 0xd6, 0x4f, 0x3b, 0xb6, 0x6b, 0xd8, 0x2f, 0x55, 0xa2, + 0xd7, 0xc9, 0xcf, 0x3f, 0xec, 0xd0, 0xc2, 0x17, 0xa1, 0x10, 0xda, 0xf3, 0xfb, 0xf5, 0xab, 0xbe, + 0xb8, 0x4c, 0x14, 0xfa, 0x7d, 0xf9, 0xbb, 0x8b, 0x87, 0xf8, 0x7c, 0xd6, 0xef, 0x32, 0x40, 0x2c, + 0xdf, 0xad, 0x0e, 0x99, 0x53, 0xa5, 0xbb, 0xe1, 0xec, 0x59, 0xf8, 0x5c, 0x0d, 0xac, 0xee, 0x32, + 0x20, 0x5d, 0x9f, 0x79, 0xf5, 0xea, 0xa5, 0x86, 0x69, 0xa6, 0x26, 0x27, 0x11, 0xdf, 0xb2, 0xba, + 0xcb, 0x80, 0x4a, 0xf5, 0x77, 0xf5, 0xc0, 0xea, 0x2e, 0x03, 0xac, 0xee, 0xd2, 0xd0, 0xb6, 0xee, + 0x1d, 0xfd, 0x82, 0x33, 0x0f, 0xaa, 0x8e, 0x04, 0x3f, 0xc7, 0x3a, 0xbf, 0xbf, 0xe9, 0xff, 0x8e, + 0x75, 0x7e, 0x17, 0xf5, 0x7f, 0x3f, 0x2c, 0xea, 0xff, 0x8e, 0x75, 0x7e, 0xf7, 0xc9, 0x3b, 0x24, + 0xea, 0xff, 0x6e, 0x7e, 0x29, 0xe7, 0x10, 0xea, 0xfc, 0xfe, 0x77, 0x36, 0xd6, 0xf9, 0xfd, 0x42, + 0x96, 0xa9, 0x77, 0xa6, 0xe5, 0xe5, 0x5c, 0xfb, 0xa0, 0xe2, 0x9b, 0xe9, 0x93, 0x93, 0xf2, 0xe9, + 0x9f, 0xee, 0xc4, 0x09, 0x70, 0xee, 0x46, 0x47, 0xa9, 0x34, 0x61, 0x0e, 0x49, 0x46, 0x46, 0x84, + 0xa3, 0x0d, 0xaf, 0x2b, 0x21, 0x4a, 0x27, 0xd8, 0x21, 0xc3, 0xc9, 0x7e, 0x22, 0xc7, 0x1e, 0xde, + 0xca, 0xc2, 0xba, 0xad, 0xe9, 0x9f, 0xee, 0xc4, 0x37, 0x5f, 0x6f, 0x58, 0xef, 0x75, 0xc6, 0x83, + 0xf2, 0x3c, 0xc0, 0xef, 0x7d, 0x43, 0xa3, 0xfb, 0x9c, 0xc4, 0xc3, 0x04, 0x38, 0x8e, 0xb1, 0x66, + 0x17, 0x73, 0xb0, 0x41, 0x07, 0xc4, 0x71, 0x07, 0x01, 0x93, 0xe3, 0x0e, 0xf0, 0x41, 0x07, 0x36, + 0xf8, 0xb8, 0x83, 0x60, 0xf4, 0xfa, 0x66, 0xd0, 0x41, 0x40, 0xf1, 0x01, 0xcf, 0x0c, 0x5c, 0xfd, + 0x63, 0xb7, 0xcb, 0xf4, 0x58, 0xf7, 0x81, 0x81, 0x01, 0x9a, 0x06, 0x1d, 0x80, 0xee, 0x07, 0x5d, + 0xc4, 0x1d, 0xc7, 0x9c, 0x23, 0xd5, 0xe9, 0x8d, 0x2d, 0x13, 0x05, 0x2f, 0x5a, 0x38, 0xc7, 0xc5, + 0xd2, 0x5f, 0x0c, 0x8c, 0xa2, 0x2a, 0x59, 0xed, 0x60, 0x52, 0x77, 0xbc, 0x33, 0xff, 0xee, 0x9d, + 0x3f, 0x51, 0x9b, 0x87, 0x6b, 0x48, 0x36, 0x52, 0x27, 0x8b, 0x4b, 0x41, 0x7b, 0x7a, 0x7b, 0x7b, + 0xfb, 0x6f, 0xbf, 0xfc, 0x8c, 0x42, 0x35, 0x5e, 0xb2, 0xd4, 0xdc, 0x2b, 0x0d, 0x52, 0x76, 0xf3, + 0xf2, 0xd7, 0x3c, 0x65, 0x6d, 0x42, 0xac, 0x7b, 0x25, 0x97, 0x4b, 0xbc, 0xed, 0x56, 0x30, 0x73, + 0xa2, 0x1a, 0xb0, 0x74, 0xbd, 0x03, 0xd2, 0x58, 0x04, 0x14, 0x6b, 0x9e, 0x54, 0xf8, 0xad, 0x30, + 0x62, 0x9c, 0xae, 0xce, 0xc7, 0x79, 0x9d, 0x7c, 0x4c, 0x77, 0x4f, 0xff, 0xf3, 0xf1, 0x9a, 0xde, + 0x13, 0x68, 0x13, 0x93, 0xf3, 0xfd, 0x10, 0xf9, 0xf1, 0x07, 0x2b, 0xf1, 0x23, 0x42, 0x82, 0x02, + 0x7b, 0x7b, 0xd4, 0x9f, 0x8c, 0x98, 0xdb, 0xd4, 0x6f, 0x79, 0x22, 0x12, 0xa4, 0x51, 0x69, 0x11, + 0x12, 0x05, 0x20, 0x0e, 0x09, 0xea, 0xed, 0xed, 0x85, 0x3d, 0x50, 0xc3, 0x01, 0xdd, 0xad, 0xfd, + 0x65, 0xf7, 0x8e, 0xd7, 0x4d, 0x4c, 0xb9, 0xae, 0x76, 0x74, 0xb4, 0x4b, 0x7c, 0xcc, 0xe7, 0x0f, + 0xae, 0x5f, 0xfb, 0xf1, 0x86, 0xcf, 0xd6, 0xaa, 0x9d, 0xc1, 0x9d, 0x82, 0x46, 0xd0, 0x9d, 0x43, + 0xe9, 0x04, 0x57, 0x05, 0xf9, 0x79, 0xc4, 0x4b, 0x91, 0x75, 0xd0, 0x73, 0xd0, 0xdd, 0x54, 0xb3, + 0xb9, 0x94, 0xb4, 0x0c, 0x25, 0xba, 0xff, 0xf0, 0xfd, 0x77, 0xf9, 0x79, 0xb9, 0x9a, 0x5c, 0x6c, + 0xfd, 0xd3, 0x6b, 0x31, 0xdd, 0x1d, 0xd4, 0x5c, 0x4d, 0x40, 0xba, 0xc4, 0xab, 0x28, 0xc7, 0xae, + 0xcc, 0x6d, 0xad, 0xad, 0x0b, 0x0d, 0xe6, 0xa0, 0x3d, 0xb6, 0x21, 0x25, 0xa0, 0x3b, 0xc7, 0x23, + 0x4d, 0xed, 0x20, 0xb5, 0x0f, 0x25, 0xba, 0x23, 0xc5, 0xf7, 0xfd, 0xb9, 0xf7, 0xc2, 0x39, 0x2f, + 0xf5, 0x32, 0x00, 0xdd, 0x51, 0x87, 0x6c, 0x55, 0x4f, 0xfc, 0xf4, 0xe3, 0x0f, 0x51, 0xe3, 0x17, + 0x7a, 0x9b, 0x98, 0x90, 0x10, 0xf3, 0xe0, 0xbe, 0x44, 0xb3, 0x0c, 0x02, 0xd4, 0x2c, 0xb1, 0x51, + 0xac, 0x9e, 0x19, 0xea, 0x45, 0xc8, 0x08, 0x14, 0xe9, 0x9e, 0x9c, 0x94, 0xb8, 0xe9, 0x8b, 0xcf, + 0x27, 0x34, 0x1b, 0x4f, 0xac, 0xb6, 0xee, 0xc4, 0x1c, 0x6b, 0x6b, 0x6a, 0x50, 0xc1, 0x72, 0x37, + 0xea, 0x8e, 0xf4, 0x91, 0x36, 0x41, 0xcf, 0xb1, 0xc1, 0xb1, 0xe7, 0x95, 0x4c, 0x34, 0xab, 0x53, + 0x50, 0xa4, 0xfb, 0x82, 0x79, 0xb3, 0xb7, 0x7d, 0xfb, 0xcd, 0xae, 0x9f, 0x7f, 0x04, 0xc2, 0x77, + 0xae, 0x79, 0x8d, 0x2d, 0x35, 0xb3, 0x79, 0xe3, 0x57, 0xff, 0xfc, 0xea, 0x0b, 0x07, 0x7b, 0x3b, + 0xf8, 0x97, 0xa0, 0xe9, 0x24, 0x57, 0x2d, 0x5f, 0xba, 0x7d, 0xeb, 0x96, 0xb0, 0x90, 0xa0, 0x3b, + 0x11, 0xe1, 0x20, 0x50, 0x70, 0x60, 0x40, 0x6b, 0x4b, 0x0b, 0x9e, 0x08, 0x25, 0xba, 0x37, 0x36, + 0x36, 0x20, 0xdd, 0x4b, 0x4b, 0x9e, 0x4b, 0x1f, 0x89, 0x74, 0xd7, 0x70, 0xae, 0x3c, 0x2d, 0x43, + 0x91, 0xee, 0x68, 0x00, 0x1f, 0x42, 0xa0, 0xbf, 0xdf, 0xca, 0x65, 0x4b, 0x60, 0x27, 0x2a, 0x55, + 0x91, 0x28, 0xeb, 0xd6, 0x60, 0x6b, 0x30, 0x8c, 0x8f, 0x8f, 0xc3, 0x2f, 0x03, 0x2d, 0xde, 0x00, + 0x15, 0xa1, 0x53, 0xae, 0x2e, 0xc4, 0x44, 0xfc, 0xa8, 0xd0, 0x7d, 0x42, 0x34, 0xd1, 0x36, 0xd4, + 0xdc, 0x65, 0x1e, 0x09, 0xb7, 0xb8, 0x90, 0x85, 0xbc, 0x95, 0x89, 0x74, 0x13, 0x72, 0x75, 0xb7, + 0xb7, 0xb5, 0x36, 0x37, 0xdd, 0x4f, 0xfc, 0x14, 0x09, 0xb1, 0xf6, 0xa3, 0x55, 0xf8, 0x36, 0xd4, + 0x73, 0x9a, 0x1a, 0x1b, 0xa1, 0xd8, 0x85, 0xed, 0xe5, 0x4b, 0x16, 0xc1, 0xab, 0xf1, 0x02, 0xc3, + 0xf5, 0x9f, 0xac, 0x21, 0x9e, 0x45, 0x95, 0xee, 0x0a, 0x60, 0x13, 0x50, 0x84, 0xdd, 0x1f, 0x5c, + 0xce, 0x55, 0x35, 0x0b, 0x06, 0x21, 0x57, 0x77, 0xe9, 0xbb, 0x27, 0x10, 0xf4, 0xa8, 0x9d, 0xad, + 0x84, 0xee, 0x13, 0xa2, 0x1e, 0x2f, 0x9f, 0x7f, 0xba, 0x06, 0x2e, 0x80, 0x07, 0xf7, 0x9b, 0x08, + 0x85, 0xc2, 0x17, 0x55, 0x95, 0xc4, 0x11, 0xc6, 0xd7, 0x53, 0x6a, 0xe8, 0xd6, 0xdd, 0x36, 0x10, + 0xd3, 0xdd, 0xec, 0x92, 0x1e, 0xea, 0x8e, 0x16, 0x52, 0xf9, 0x64, 0xf5, 0x07, 0x68, 0x43, 0x93, + 0x0a, 0xbb, 0x04, 0x8e, 0x84, 0x95, 0x61, 0xba, 0xcb, 0x5f, 0x73, 0x51, 0x73, 0xd8, 0x85, 0x96, + 0x62, 0x59, 0xb8, 0xc9, 0xa8, 0xea, 0xe8, 0x2c, 0xc4, 0xba, 0xc3, 0x25, 0x91, 0x78, 0xbf, 0x2a, + 0x6f, 0x45, 0x18, 0x35, 0x60, 0x72, 0x2a, 0x09, 0x1b, 0xc4, 0x16, 0x48, 0x41, 0x23, 0x81, 0x3c, + 0xa4, 0x57, 0xb4, 0x6b, 0x6d, 0xb4, 0x26, 0x55, 0x90, 0x31, 0x6e, 0x98, 0xd8, 0x48, 0xa0, 0x21, + 0xce, 0x3f, 0xac, 0x42, 0x8a, 0x94, 0xd4, 0xf5, 0x52, 0x95, 0xa6, 0x4c, 0x70, 0x4e, 0x62, 0x43, + 0xc2, 0xcd, 0x4e, 0x27, 0x0f, 0x0c, 0x8f, 0xd2, 0x9a, 0x11, 0x55, 0x98, 0xd4, 0xbd, 0xaa, 0xb2, + 0x92, 0xda, 0x46, 0x31, 0xa7, 0x88, 0x0a, 0x8e, 0x63, 0x2c, 0xc8, 0x71, 0xf8, 0xda, 0x13, 0x4a, + 0x12, 0x54, 0x80, 0xd0, 0x37, 0xa3, 0xc2, 0x0f, 0x5f, 0xc8, 0xec, 0x1b, 0xd2, 0x03, 0xe9, 0xa7, + 0x5c, 0x57, 0xdf, 0x5d, 0x68, 0xb4, 0xe7, 0xd7, 0x9d, 0xe4, 0x4f, 0x26, 0xce, 0x92, 0x8d, 0xd3, + 0x3f, 0xbd, 0xe6, 0xe8, 0xad, 0x32, 0x93, 0x37, 0x0d, 0xee, 0x26, 0xbe, 0xb4, 0x8b, 0x8e, 0x60, + 0x1f, 0x56, 0x8a, 0x3f, 0x09, 0xb1, 0xf2, 0x2f, 0x3c, 0x7b, 0xbf, 0x8a, 0xc2, 0x65, 0xad, 0x28, + 0xa4, 0x50, 0x38, 0x3e, 0x81, 0xeb, 0x5e, 0x55, 0x55, 0x59, 0x5e, 0x5e, 0x9e, 0x95, 0xf9, 0x98, + 0xfc, 0x60, 0x6d, 0x80, 0x9c, 0xc1, 0xda, 0x0f, 0xf0, 0xef, 0x7f, 0xe4, 0x2a, 0x65, 0x73, 0xfd, + 0x90, 0xc1, 0xe9, 0x7b, 0x55, 0x8c, 0x0f, 0xc7, 0x56, 0x4a, 0xb8, 0xdd, 0x99, 0xd0, 0xf0, 0xb9, + 0x36, 0x36, 0x8f, 0x39, 0x3e, 0xbb, 0x3a, 0x4e, 0xc7, 0x18, 0x8e, 0xcb, 0x23, 0xdb, 0xa0, 0xe2, + 0xac, 0x2a, 0x06, 0x66, 0xe1, 0x19, 0x1d, 0x13, 0x1e, 0x8f, 0xac, 0xd8, 0x7f, 0x26, 0x95, 0x73, + 0x3c, 0x8e, 0xe3, 0x1c, 0x47, 0xe1, 0x74, 0xed, 0x54, 0x91, 0x02, 0xdd, 0x59, 0xa8, 0x0d, 0x56, + 0x77, 0x66, 0xc0, 0xea, 0xce, 0x0c, 0x58, 0xdd, 0x99, 0x01, 0xab, 0x3b, 0x33, 0x60, 0x75, 0x67, + 0x06, 0xac, 0xee, 0xcc, 0x80, 0xd5, 0x9d, 0x19, 0xb0, 0xba, 0x33, 0x03, 0xf5, 0x75, 0x17, 0x0a, + 0x04, 0x8c, 0xaf, 0x25, 0xa4, 0x8f, 0xd4, 0x54, 0xf7, 0x71, 0x81, 0x80, 0xf1, 0xb9, 0x5c, 0xf4, + 0x8f, 0xc6, 0x06, 0x14, 0xf8, 0x9d, 0xf1, 0x05, 0xa8, 0xf4, 0x8e, 0xbc, 0x5f, 0x77, 0x68, 0xaa, + 0xfb, 0x0c, 0x41, 0x51, 0xe1, 0x33, 0xe3, 0xf9, 0x06, 0x8b, 0x8d, 0xe6, 0x99, 0x1d, 0xd8, 0x77, + 0xc6, 0xfd, 0x94, 0xbd, 0xad, 0xf5, 0xf2, 0x25, 0x8b, 0x0c, 0xde, 0xf9, 0x07, 0x3e, 0x2d, 0x37, + 0x0b, 0x3d, 0x02, 0x6b, 0x77, 0x25, 0xd8, 0xb5, 0xf3, 0x27, 0x30, 0x37, 0xea, 0xaa, 0x82, 0xe3, + 0x51, 0x7c, 0x5c, 0x6a, 0x4a, 0x32, 0x9a, 0x7c, 0x9e, 0x85, 0x1e, 0x81, 0xb5, 0xbb, 0x12, 0x0c, + 0xf1, 0xf9, 0x7b, 0x7f, 0xdb, 0x85, 0x3f, 0xf2, 0x5f, 0x68, 0x30, 0x67, 0xcf, 0xae, 0x9d, 0x21, + 0x41, 0x81, 0x12, 0xd3, 0xb0, 0xb0, 0xd0, 0x0b, 0xb0, 0x76, 0x57, 0x0d, 0xbc, 0xba, 0x5a, 0xdf, + 0xcb, 0x97, 0x56, 0x2d, 0x5f, 0x0a, 0xd6, 0x97, 0xe8, 0x06, 0xca, 0x42, 0xf7, 0x31, 0x7d, 0xec, + 0xde, 0xd8, 0xd0, 0x40, 0xc7, 0x4a, 0x74, 0x5b, 0x37, 0x6f, 0x02, 0x67, 0x07, 0x07, 0x06, 0x10, + 0x77, 0xda, 0x58, 0x5a, 0xc0, 0x4e, 0x8f, 0x53, 0x27, 0x29, 0xcf, 0x2e, 0x29, 0x29, 0x51, 0xbf, + 0x16, 0xff, 0xd2, 0x2f, 0xb0, 0x76, 0x57, 0x8e, 0x84, 0xb8, 0xb8, 0xaf, 0x37, 0xac, 0xc3, 0xeb, + 0x33, 0x46, 0x73, 0xde, 0x86, 0xfa, 0xcc, 0xeb, 0x57, 0xb4, 0x2c, 0x64, 0xc1, 0xda, 0x9d, 0x56, + 0xcc, 0x08, 0xbb, 0x8f, 0x8f, 0x8f, 0xc7, 0xc7, 0xc6, 0x7c, 0xb9, 0xee, 0x53, 0xcd, 0x67, 0x78, + 0xd2, 0x10, 0xc5, 0x45, 0x85, 0xeb, 0xd6, 0xae, 0xbe, 0x17, 0x1d, 0x85, 0xfa, 0x2d, 0x49, 0x83, + 0xb5, 0x3b, 0xad, 0x98, 0xce, 0x76, 0x7f, 0xf9, 0xb2, 0x7a, 0xdf, 0x9f, 0xbf, 0x13, 0x3b, 0xf4, + 0xeb, 0x82, 0xdd, 0x89, 0xf1, 0xfc, 0xef, 0xb7, 0x5f, 0x25, 0xa6, 0xd6, 0x65, 0xed, 0x4e, 0x2b, + 0xa6, 0x9b, 0xdd, 0x07, 0x07, 0x07, 0x2f, 0x9c, 0xf7, 0x5a, 0xb6, 0x78, 0x81, 0xc4, 0x4c, 0x0b, + 0xba, 0x69, 0x77, 0x9c, 0x4b, 0x16, 0x18, 0x9e, 0xf5, 0x38, 0xdd, 0xd7, 0xd7, 0xc7, 0xda, 0x9d, + 0x56, 0x4c, 0x2b, 0xbb, 0xc7, 0xc5, 0xc5, 0x06, 0xdc, 0xbc, 0xf1, 0xc9, 0x47, 0x1f, 0xc8, 0xb4, + 0x14, 0x30, 0xf6, 0xe1, 0x83, 0xa6, 0xc6, 0x46, 0x06, 0x99, 0x9c, 0x98, 0x28, 0x2f, 0xb6, 0xd5, + 0xef, 0xaf, 0xb8, 0xea, 0xeb, 0x73, 0x27, 0x32, 0x82, 0xb5, 0x3b, 0x7d, 0x98, 0x56, 0x76, 0x27, + 0x56, 0x66, 0x7a, 0x7b, 0x7a, 0xdc, 0xdd, 0x5c, 0x17, 0xcf, 0x37, 0xd0, 0xe5, 0xd2, 0x7d, 0xb1, + 0xd1, 0xbc, 0x93, 0x27, 0x9c, 0xbb, 0xba, 0x3a, 0xf1, 0x03, 0xd8, 0xd2, 0x9d, 0x56, 0x4c, 0x5b, + 0xbb, 0x13, 0x51, 0x5e, 0x56, 0xb6, 0x67, 0xd7, 0x2f, 0xba, 0x63, 0xf7, 0x5f, 0x7e, 0xfc, 0x4f, + 0xc9, 0x73, 0xd9, 0xa3, 0x78, 0x59, 0xbb, 0xd3, 0x8a, 0x19, 0x61, 0x77, 0x3d, 0x02, 0x6b, 0x77, + 0x5a, 0xc1, 0xda, 0x5d, 0xb7, 0xc0, 0xda, 0x9d, 0x56, 0xcc, 0x2c, 0xbb, 0xf7, 0x0d, 0x8d, 0x96, + 0x35, 0xf4, 0xf2, 0x3a, 0xf9, 0x75, 0x1d, 0x18, 0x6b, 0x81, 0xed, 0xfc, 0x9a, 0xf6, 0x41, 0xe0, + 0xeb, 0xb6, 0xc1, 0x57, 0x22, 0xbe, 0x6c, 0x1d, 0x00, 0x56, 0xb7, 0x0c, 0xbc, 0x10, 0xb1, 0xaa, + 0x19, 0xb1, 0xbf, 0xb2, 0xb9, 0x9f, 0xdb, 0x24, 0x66, 0x45, 0x23, 0xc6, 0xf2, 0xc6, 0xbe, 0xb2, + 0x06, 0x8c, 0xa5, 0xc0, 0xfa, 0xbe, 0x92, 0xfa, 0xde, 0xe7, 0x3c, 0x8c, 0xc5, 0xc0, 0xba, 0xde, + 0xa2, 0xba, 0xde, 0xc2, 0xba, 0x9e, 0xc2, 0xda, 0x9e, 0x67, 0xc0, 0x9a, 0x9e, 0xa7, 0x35, 0xd8, + 0x36, 0xa4, 0xdf, 0xd6, 0x27, 0x50, 0x10, 0x21, 0x6b, 0x77, 0x5a, 0xf1, 0xd6, 0xd8, 0xd8, 0x98, + 0x60, 0x5a, 0xa0, 0xb6, 0xb6, 0x36, 0x2b, 0xf3, 0x31, 0x71, 0x4f, 0xdf, 0xe0, 0x90, 0xef, 0xa3, + 0x2a, 0xfb, 0xc0, 0xa7, 0xe6, 0x67, 0x92, 0xf6, 0x39, 0xc7, 0xec, 0x77, 0xb8, 0xcf, 0x20, 0xf7, + 0x11, 0xe6, 0x69, 0xe0, 0x38, 0x3c, 0x34, 0x71, 0x49, 0xb0, 0xbb, 0xf1, 0xe4, 0x44, 0x14, 0xb7, + 0xe0, 0xf5, 0x14, 0x73, 0xb3, 0x76, 0xa7, 0x15, 0x8a, 0x4a, 0xf7, 0xfb, 0xf7, 0xa2, 0x17, 0x19, + 0xce, 0xd5, 0x97, 0x25, 0x38, 0x89, 0xa5, 0xbb, 0x4b, 0x54, 0xa5, 0xa9, 0x77, 0x16, 0xe3, 0x53, + 0x6d, 0x90, 0xe4, 0xc1, 0x33, 0xa9, 0xae, 0xd1, 0x95, 0x28, 0x72, 0xd6, 0xee, 0xb4, 0x42, 0xae, + 0xdd, 0x6f, 0x85, 0x86, 0xe0, 0x4f, 0x40, 0x9a, 0x9b, 0x9a, 0xb4, 0x19, 0x93, 0x7a, 0x40, 0x76, + 0x3f, 0x19, 0xc5, 0x35, 0x39, 0x1e, 0x47, 0x34, 0x13, 0xc7, 0x31, 0xc6, 0xe2, 0x4a, 0x81, 0x73, + 0x44, 0x79, 0x5c, 0x61, 0x33, 0xd4, 0x43, 0x1a, 0xba, 0x86, 0x5a, 0x7a, 0x87, 0x5b, 0x7b, 0x87, + 0xa1, 0x52, 0x01, 0x6c, 0x07, 0xf6, 0x0b, 0x3a, 0xde, 0xb0, 0x73, 0x40, 0xd0, 0x35, 0x30, 0x02, + 0xec, 0x1e, 0x14, 0xb3, 0x87, 0x3f, 0xd2, 0x2b, 0xe6, 0x28, 0xd4, 0x85, 0x10, 0xfb, 0x87, 0x46, + 0x07, 0x86, 0x81, 0x63, 0xc0, 0x41, 0x81, 0x98, 0x7c, 0xc1, 0xd8, 0xd0, 0x88, 0x98, 0xc3, 0x23, + 0x42, 0x8c, 0xa3, 0x18, 0x05, 0xa3, 0xc2, 0x91, 0x31, 0x8c, 0x70, 0x22, 0xe4, 0x9b, 0x56, 0xd1, + 0xee, 0x12, 0xc5, 0xb5, 0xbb, 0xfe, 0x44, 0xd2, 0xf7, 0xce, 0xf1, 0x67, 0xee, 0x57, 0xb1, 0x76, + 0xa7, 0x15, 0xb2, 0xed, 0xee, 0x7d, 0xce, 0x93, 0xd8, 0x3c, 0x6c, 0x34, 0xe7, 0xed, 0xf2, 0xb2, + 0x32, 0x2d, 0x47, 0xa6, 0x2a, 0x4a, 0xab, 0x6a, 0x4e, 0xfa, 0x46, 0x11, 0x0d, 0x64, 0xfd, 0x57, + 0x66, 0x74, 0x7e, 0x3d, 0xd3, 0x71, 0x4d, 0x41, 0x57, 0x57, 0x67, 0xf8, 0xad, 0xb0, 0xdf, 0xf7, + 0xec, 0x46, 0xcb, 0x13, 0x6e, 0x3d, 0x74, 0xde, 0xcc, 0x2b, 0x95, 0x18, 0xb3, 0x87, 0xef, 0xed, + 0x6a, 0x1e, 0x65, 0x53, 0x17, 0xb2, 0x90, 0x80, 0x0c, 0xbb, 0x1f, 0xb1, 0xb1, 0x92, 0xf9, 0xd8, + 0x2f, 0x3d, 0x35, 0x45, 0xfb, 0xf1, 0x91, 0x44, 0x72, 0x79, 0xfb, 0xd1, 0xbf, 0xe2, 0x9d, 0x3d, + 0x82, 0xc4, 0x25, 0xba, 0x5b, 0xb2, 0x7f, 0xca, 0x6b, 0xa6, 0x83, 0xc2, 0x26, 0x0d, 0xf7, 0xbf, + 0x79, 0xe3, 0xa7, 0x1d, 0xdb, 0xe7, 0xcf, 0x7d, 0x47, 0xa6, 0xa4, 0xdf, 0x6e, 0xfa, 0x7a, 0x02, + 0xab, 0x7a, 0x71, 0x39, 0x0e, 0xe2, 0x95, 0x7d, 0xdc, 0x3c, 0xfd, 0x8f, 0xf8, 0x66, 0xc0, 0xed, + 0x2f, 0xd3, 0xb1, 0x4f, 0x4f, 0x48, 0xda, 0xfd, 0xbf, 0xbb, 0x7f, 0x95, 0xf7, 0x94, 0x1b, 0x78, + 0x3b, 0x2c, 0x94, 0x91, 0x28, 0x15, 0x63, 0x4c, 0x38, 0x6e, 0x13, 0x5c, 0x62, 0x79, 0x22, 0x12, + 0xd9, 0x9d, 0x73, 0x3a, 0x25, 0x32, 0x97, 0xc7, 0x74, 0x50, 0x93, 0x88, 0x8b, 0x79, 0x28, 0xb1, + 0xd4, 0x2c, 0xce, 0xa4, 0xc4, 0x47, 0xe8, 0x98, 0xb3, 0x0f, 0xaa, 0x38, 0xa2, 0x3a, 0x18, 0xd8, + 0xdd, 0xcc, 0x29, 0xda, 0x2e, 0xac, 0x94, 0xd9, 0x98, 0xa7, 0x2b, 0xa6, 0xd8, 0xfd, 0xe5, 0xcb, + 0xea, 0xdc, 0xec, 0x6c, 0x9c, 0x09, 0xf1, 0x71, 0xdf, 0x6f, 0xdb, 0x42, 0xdc, 0x03, 0xec, 0xee, + 0xea, 0x92, 0x48, 0x02, 0xbf, 0x1a, 0x5c, 0xbb, 0xe2, 0xa3, 0xc5, 0xc8, 0x27, 0xf1, 0xa8, 0xb4, + 0xcd, 0xf4, 0x6c, 0x1a, 0x6e, 0x77, 0xdb, 0xe0, 0xe7, 0x50, 0x93, 0x66, 0x24, 0x12, 0x05, 0x28, + 0x2a, 0x2c, 0xc4, 0x57, 0xb4, 0x46, 0xfc, 0x6e, 0xcb, 0xe4, 0x52, 0xe0, 0x70, 0x63, 0x60, 0xe5, + 0x57, 0x88, 0xdb, 0xdd, 0xca, 0x37, 0xbf, 0xa2, 0x51, 0x3f, 0x5a, 0x08, 0xf4, 0x0b, 0x8a, 0x5a, + 0x66, 0x3a, 0x3a, 0xda, 0xa1, 0x96, 0xa9, 0xf8, 0xfc, 0xc8, 0xf0, 0xdb, 0xf0, 0x9f, 0x3b, 0xe3, + 0x7e, 0x0a, 0xad, 0x3a, 0x91, 0x99, 0x91, 0x4e, 0x69, 0x78, 0xa4, 0x10, 0x90, 0x51, 0xcb, 0x71, + 0x4d, 0x44, 0x76, 0x87, 0x5a, 0x81, 0x53, 0x04, 0x65, 0x8b, 0xce, 0x51, 0x05, 0xb3, 0x03, 0xfb, + 0xd0, 0x22, 0xc8, 0xf5, 0x3c, 0xde, 0x86, 0xcf, 0xd6, 0x4a, 0x57, 0x0e, 0x85, 0xe3, 0xe3, 0xb6, + 0x21, 0x25, 0xb8, 0xdd, 0x39, 0xee, 0xa9, 0x69, 0x15, 0x0c, 0xcc, 0x6f, 0x3a, 0xed, 0xa1, 0x91, + 0xdd, 0x5f, 0xbf, 0x7a, 0x65, 0x38, 0x7b, 0xd6, 0x8a, 0xa5, 0xc6, 0xa3, 0xa3, 0xa3, 0x3d, 0xdd, + 0xdd, 0x0b, 0x0d, 0xe6, 0x40, 0x25, 0xb5, 0xa5, 0xb9, 0x99, 0xea, 0x20, 0x95, 0xc0, 0x3f, 0x1d, + 0xb3, 0x3b, 0xb8, 0xc4, 0xc6, 0x35, 0x5c, 0x0b, 0x76, 0xff, 0xfc, 0xd3, 0x35, 0x3f, 0x7e, 0xff, + 0x6f, 0x1e, 0xaf, 0x0e, 0x19, 0x17, 0xbe, 0x7e, 0x56, 0xa6, 0xdc, 0x35, 0x73, 0xdc, 0x5c, 0x4e, + 0x14, 0xe4, 0x4b, 0xce, 0x86, 0xdc, 0xdb, 0xd3, 0x73, 0xfa, 0xe4, 0x94, 0x71, 0xae, 0xa3, 0x50, + 0x1f, 0x13, 0xd9, 0x1d, 0x7e, 0xb4, 0xfb, 0x1d, 0xee, 0x9b, 0x9c, 0x49, 0xcb, 0x7a, 0xd1, 0x39, + 0xc1, 0x82, 0x6a, 0xa8, 0x6f, 0x77, 0xb8, 0x0f, 0x5b, 0xfd, 0xfe, 0x72, 0xf8, 0x7f, 0x3f, 0x2f, + 0x2e, 0x42, 0x7b, 0x92, 0x13, 0x1f, 0xa1, 0xe9, 0xf9, 0xa9, 0x5d, 0x3e, 0x51, 0x29, 0x90, 0xdd, + 0xdf, 0x3c, 0xc1, 0xa1, 0xdd, 0xee, 0xc6, 0xa2, 0x5e, 0x96, 0x2b, 0x97, 0x2d, 0x29, 0x2a, 0x7c, + 0x26, 0x10, 0x08, 0x0a, 0x9f, 0x3d, 0x25, 0x7e, 0x7a, 0xcd, 0xd7, 0xe7, 0x3d, 0xe3, 0x85, 0x68, + 0xce, 0x82, 0x1f, 0xb6, 0x7f, 0x47, 0x32, 0x4d, 0xc1, 0xa8, 0xd0, 0x46, 0xb4, 0xca, 0x17, 0xe2, + 0x01, 0xaf, 0x8c, 0xbc, 0x97, 0x6c, 0x73, 0x24, 0xf5, 0x50, 0xdf, 0xee, 0x26, 0x7f, 0xec, 0x85, + 0x7f, 0xea, 0x15, 0x9f, 0xcb, 0xc4, 0x9d, 0x50, 0x98, 0xc1, 0xce, 0x5d, 0x84, 0x85, 0x5a, 0x87, + 0xf8, 0xfc, 0xb6, 0xb6, 0xb6, 0xf1, 0xf1, 0xf1, 0xf2, 0xb2, 0xb2, 0x97, 0xd5, 0xd5, 0x68, 0x27, + 0xaf, 0xae, 0xf6, 0x49, 0x7e, 0x3e, 0x78, 0x85, 0x78, 0x58, 0x69, 0x49, 0x49, 0x7e, 0x5e, 0x2e, + 0xbe, 0x74, 0x4e, 0x6b, 0x6b, 0x2b, 0x9c, 0x88, 0x1f, 0x50, 0x5f, 0xcf, 0x93, 0xf7, 0xc0, 0x8b, + 0x11, 0xbb, 0x43, 0xfc, 0xd2, 0x1f, 0xdd, 0x89, 0x08, 0xc7, 0x57, 0xab, 0x05, 0xc2, 0xb5, 0xee, + 0xc6, 0xb5, 0x2b, 0x64, 0xd2, 0x1c, 0x1a, 0x19, 0x43, 0x8b, 0x7c, 0x89, 0x1f, 0x3c, 0x79, 0x67, + 0x3e, 0xad, 0x51, 0x7f, 0xa9, 0x4f, 0x16, 0xf2, 0xa0, 0xa6, 0xdd, 0xe1, 0xae, 0x54, 0x41, 0x03, + 0x0e, 0x10, 0x7c, 0x8f, 0x8e, 0x8c, 0x8b, 0x8d, 0xc1, 0xa7, 0x25, 0x4a, 0x4c, 0x88, 0x87, 0x6d, + 0xb4, 0x50, 0x77, 0x57, 0x67, 0xe7, 0x62, 0xa3, 0x79, 0xa8, 0x1a, 0xf0, 0xe5, 0xfa, 0x4f, 0x71, + 0x5b, 0x78, 0x7a, 0xb8, 0x43, 0x6d, 0x01, 0x6d, 0x1f, 0xe0, 0xfc, 0xf1, 0xd3, 0x8e, 0xed, 0x2f, + 0xaa, 0x2a, 0x8d, 0x17, 0x18, 0xa6, 0xa6, 0x24, 0xcb, 0x8b, 0x93, 0x11, 0xbb, 0xcb, 0xfb, 0xed, + 0xf1, 0xf9, 0x83, 0x6b, 0x3f, 0x5c, 0xb5, 0x7a, 0xd5, 0x8a, 0x8f, 0x56, 0x2e, 0x47, 0x8b, 0xc0, + 0x92, 0xc1, 0xc0, 0xf0, 0x28, 0x5a, 0x5b, 0x0d, 0xd1, 0xec, 0xef, 0xec, 0x62, 0x1e, 0xbd, 0xeb, + 0xcd, 0xcc, 0x4c, 0xa8, 0x63, 0x77, 0xb8, 0x7c, 0xc3, 0xff, 0x1b, 0x2c, 0x28, 0x73, 0x1a, 0xad, + 0xbe, 0xbe, 0x3e, 0xf8, 0x08, 0x0e, 0x88, 0x8a, 0x8c, 0x98, 0x10, 0xd9, 0x1d, 0x5f, 0x7d, 0xa8, + 0xb3, 0xb3, 0x03, 0xf6, 0x43, 0x39, 0x8d, 0xde, 0x42, 0xdd, 0xf7, 0xc1, 0xbd, 0xbb, 0xb0, 0x11, + 0x71, 0xfb, 0xd6, 0x87, 0x2b, 0xde, 0x7b, 0xff, 0xbd, 0x77, 0xff, 0xf8, 0xdf, 0x1e, 0x73, 0xd3, + 0xfd, 0xb0, 0x81, 0xa7, 0x86, 0x9a, 0x7d, 0xf2, 0x72, 0x15, 0x2d, 0xb0, 0xe7, 0xa7, 0x4b, 0x76, + 0x57, 0x0f, 0xbd, 0xfc, 0x11, 0xb4, 0xa4, 0x1d, 0xe2, 0xa1, 0x4b, 0xb9, 0x6c, 0xd3, 0x3b, 0x1d, + 0x50, 0xd9, 0xee, 0x50, 0x7a, 0xa1, 0x91, 0xa0, 0x69, 0xf2, 0x9f, 0x3a, 0xe5, 0xe6, 0x64, 0xa3, + 0x32, 0x1e, 0x2a, 0x30, 0x60, 0x77, 0xb4, 0x6c, 0xdf, 0x84, 0x1c, 0xbb, 0xc3, 0x31, 0x58, 0xdd, + 0xa0, 0xa0, 0x60, 0x02, 0x5b, 0x0f, 0xbe, 0x6d, 0xd3, 0x17, 0x9f, 0xa3, 0x65, 0x2d, 0xe1, 0x7e, + 0x0e, 0x4e, 0xbc, 0xea, 0xeb, 0x23, 0x14, 0x0a, 0xb7, 0x7d, 0xfb, 0x8d, 0xad, 0xd5, 0x61, 0x79, + 0xd9, 0x4d, 0xb1, 0xbb, 0x73, 0xfc, 0x91, 0x30, 0x7a, 0x1f, 0x00, 0xd3, 0x61, 0xf7, 0xce, 0x01, + 0x81, 0x8d, 0xff, 0xa4, 0xdd, 0x0f, 0xfb, 0xe6, 0x55, 0x36, 0xb3, 0x0d, 0x91, 0xd4, 0x43, 0xd3, + 0x86, 0x48, 0xaa, 0x00, 0xe6, 0x6e, 0x55, 0x77, 0xdd, 0x3f, 0xec, 0x19, 0x8d, 0x73, 0xbc, 0xd8, + 0xee, 0x4e, 0xb1, 0xee, 0xf7, 0xab, 0xa8, 0x8d, 0x4d, 0x0b, 0xe8, 0x1b, 0x1a, 0xb5, 0x0b, 0x9e, + 0xac, 0xbb, 0x9b, 0x9c, 0x4d, 0xcf, 0xac, 0x64, 0x1b, 0x22, 0xa9, 0xc7, 0x14, 0xbb, 0xc3, 0xfd, + 0xa2, 0x82, 0x71, 0xcd, 0xc0, 0x63, 0x47, 0x6c, 0x99, 0x0a, 0x54, 0x1e, 0x06, 0x86, 0xc7, 0x2c, + 0x6e, 0x16, 0xe2, 0x46, 0x31, 0xf5, 0xca, 0xc8, 0xe0, 0xea, 0xa5, 0x51, 0xf0, 0x07, 0xab, 0xe8, + 0x47, 0xeb, 0x74, 0x5b, 0xd7, 0x3b, 0x29, 0xe9, 0x23, 0x24, 0x4b, 0x77, 0xa8, 0x39, 0x6c, 0xf9, + 0xe7, 0x46, 0x99, 0x5e, 0xff, 0xcb, 0xfb, 0x1c, 0x23, 0x21, 0x2a, 0x40, 0x7b, 0x9f, 0xc0, 0x8e, + 0x50, 0xe5, 0xe5, 0x38, 0xc5, 0x9d, 0x8a, 0xe6, 0x2a, 0x3f, 0x4d, 0x27, 0x31, 0x3c, 0x2a, 0xb4, + 0x0a, 0x28, 0x26, 0x7e, 0x97, 0x93, 0x51, 0xfa, 0xfa, 0x5d, 0x74, 0x16, 0xb2, 0x2b, 0x33, 0xc4, + 0x39, 0x6f, 0x11, 0xe1, 0x6e, 0x52, 0xcb, 0x91, 0x29, 0x85, 0x73, 0x54, 0xa5, 0xa9, 0x4b, 0x3c, + 0xa1, 0xa3, 0x6f, 0xac, 0xcb, 0x9d, 0x0a, 0xa6, 0x83, 0xd2, 0x08, 0x43, 0x23, 0x63, 0x16, 0x7e, + 0x93, 0xbf, 0x5e, 0xac, 0x53, 0xe7, 0xe5, 0xdc, 0xb8, 0x62, 0x6d, 0x3f, 0xb6, 0x9b, 0xc6, 0x90, + 0x5b, 0x77, 0x3f, 0x6a, 0x67, 0x83, 0x7b, 0x3d, 0x23, 0x3d, 0x4d, 0x8b, 0x21, 0x29, 0x42, 0x53, + 0xf7, 0xd0, 0xd5, 0x94, 0x1a, 0x7b, 0x28, 0xd1, 0x1d, 0xa6, 0x74, 0x16, 0xb7, 0xf0, 0x4a, 0xbf, + 0x9d, 0xa3, 0x5b, 0x7d, 0x7d, 0xd5, 0xc3, 0xc8, 0x98, 0xd0, 0x31, 0xbc, 0x5c, 0xa2, 0x2b, 0xfc, + 0x81, 0x93, 0x89, 0x0e, 0xb7, 0x4a, 0xa3, 0x9f, 0x34, 0xf5, 0xf2, 0x47, 0x98, 0x0e, 0x50, 0xbf, + 0xa1, 0xe8, 0x56, 0xd5, 0xdd, 0xcd, 0xd5, 0x70, 0xf6, 0x2c, 0x6e, 0x05, 0x2d, 0x45, 0xa6, 0x5d, + 0x68, 0x29, 0xc7, 0x2d, 0x89, 0xe3, 0x9a, 0x48, 0x8a, 0x27, 0x13, 0x39, 0x27, 0x12, 0x38, 0x53, + 0x2d, 0x8e, 0x68, 0xee, 0xfd, 0x38, 0xe1, 0x69, 0xe3, 0xeb, 0xb6, 0x41, 0x3a, 0x82, 0x64, 0x0a, + 0x1d, 0xfd, 0x02, 0x97, 0x88, 0x72, 0x93, 0xe3, 0xb1, 0xd2, 0xdf, 0x17, 0x5b, 0x34, 0xf8, 0x78, + 0x3c, 0xc7, 0xe5, 0x11, 0xc7, 0x25, 0x81, 0x25, 0x19, 0xda, 0x86, 0x94, 0xe2, 0x33, 0x72, 0x4a, + 0xda, 0x1d, 0xad, 0xa2, 0xad, 0x05, 0xb8, 0xfa, 0x25, 0xca, 0x5c, 0x7b, 0x5b, 0xe9, 0x82, 0xdc, + 0xd8, 0xbf, 0xfc, 0xd8, 0xc3, 0xc3, 0x7f, 0x67, 0x1f, 0x8f, 0xac, 0xc8, 0xa9, 0x96, 0xec, 0x9e, + 0x39, 0xcd, 0x70, 0x2d, 0xad, 0xd6, 0x2e, 0xa4, 0xc4, 0xf4, 0x6c, 0x1a, 0xde, 0x21, 0x9e, 0xa5, + 0xaa, 0x54, 0x64, 0x77, 0xad, 0xc1, 0x2b, 0xb6, 0x1a, 0xfc, 0x4a, 0x92, 0x2e, 0x51, 0x5c, 0xaf, + 0x98, 0xea, 0x9b, 0xe9, 0xb5, 0xcf, 0x6a, 0xba, 0xfb, 0x87, 0x46, 0x99, 0x8a, 0x99, 0x59, 0x54, + 0xb7, 0x0c, 0x3c, 0x2a, 0x69, 0x0b, 0xce, 0xe4, 0x9d, 0x8b, 0xad, 0x3e, 0x75, 0xb7, 0xd2, 0xe5, + 0x0e, 0xd7, 0x2d, 0xba, 0x92, 0xa5, 0x52, 0x7a, 0xc6, 0x56, 0x0b, 0x85, 0x4c, 0xdb, 0x9d, 0x05, + 0x0b, 0xed, 0x83, 0xb5, 0x3b, 0x8b, 0x19, 0x04, 0xd6, 0xee, 0x2c, 0x66, 0x10, 0x58, 0xbb, 0xb3, + 0x98, 0x41, 0x60, 0xed, 0xce, 0x62, 0x06, 0x81, 0xb5, 0x3b, 0x8b, 0x19, 0x04, 0xd6, 0xee, 0x2c, + 0x66, 0x10, 0x58, 0xbb, 0xb3, 0x98, 0x41, 0x60, 0xc6, 0xee, 0xe3, 0x00, 0x81, 0x80, 0x25, 0x4b, + 0x2d, 0x50, 0xc8, 0xe7, 0x33, 0x6d, 0x77, 0x81, 0xa0, 0xc5, 0xcd, 0xf1, 0xc5, 0xa2, 0xb9, 0x2c, + 0x59, 0xd2, 0x4b, 0x63, 0x83, 0xb6, 0xf3, 0xa7, 0x59, 0xbb, 0xb3, 0x9c, 0x19, 0xd4, 0x09, 0xbb, + 0x8f, 0x8c, 0x0c, 0x71, 0xcb, 0x87, 0x2a, 0x59, 0xb2, 0xa4, 0x99, 0xdc, 0xf2, 0xe1, 0xaa, 0xc9, + 0x51, 0x32, 0xff, 0x07, 0xaa, 0x57, 0x6f, 0xac, 0x69, 0xfa, 0xc1, 0x9f, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, +}; + +const BITMAP_OPAQUE tune_diff_pair_skew_legend_xpm[1] = {{ png, sizeof( png ), "tune_diff_pair_skew_legend_xpm" }}; + +//EOF diff --git a/bitmaps_png/cpp_other/tune_single_track_length_legend.cpp b/bitmaps_png/cpp_other/tune_single_track_length_legend.cpp new file mode 100644 index 0000000000..4c6cf7a2e5 --- /dev/null +++ b/bitmaps_png/cpp_other/tune_single_track_length_legend.cpp @@ -0,0 +1,655 @@ + +/* Do not modify this file, it was automatically generated by the + * PNG2cpp CMake script, using a *.png file as input. + */ + +#include + +static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xa2, 0x08, 0x02, 0x00, 0x00, 0x01, 0x90, 0x54, 0x77, + 0x66, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x1e, 0xc2, 0x00, 0x00, 0x1e, + 0xc2, 0x01, 0x6e, 0xd0, 0x75, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x89, 0x2a, 0x8d, 0x06, 0x00, 0x00, 0x20, 0x00, 0x49, + 0x44, 0x41, 0x54, 0x78, 0x9c, 0xec, 0x5d, 0x87, 0x5f, 0x14, 0x47, 0xfb, 0xf7, 0xbf, 0xf8, 0x25, + 0xaf, 0x89, 0xd1, 0x18, 0x45, 0x45, 0x40, 0x63, 0x09, 0x56, 0x14, 0x03, 0xaf, 0xbd, 0xc5, 0x82, + 0x05, 0x15, 0x45, 0x2c, 0x09, 0x28, 0x16, 0x90, 0x2e, 0x28, 0x0a, 0x8a, 0xd1, 0x68, 0x6c, 0x49, + 0x34, 0x18, 0xa3, 0xd1, 0xe4, 0x35, 0x89, 0x46, 0xd4, 0x20, 0xbd, 0x88, 0x20, 0x20, 0xed, 0x80, + 0xa3, 0x2b, 0x45, 0x3d, 0x3a, 0x07, 0x47, 0xbb, 0xf2, 0x9b, 0xbb, 0x81, 0x61, 0xbd, 0xdd, 0xdb, + 0x9d, 0xbd, 0x9b, 0xbb, 0x83, 0x83, 0xef, 0x67, 0x3e, 0x7c, 0xf6, 0x86, 0xd9, 0x67, 0x9e, 0xfd, + 0xee, 0xec, 0xd4, 0x67, 0x9e, 0x19, 0xa6, 0xd0, 0x0d, 0x0d, 0x09, 0x71, 0xec, 0x09, 0x86, 0xe1, + 0xcb, 0xfa, 0xe4, 0x3f, 0xff, 0x47, 0xfd, 0x19, 0x39, 0x6e, 0x6c, 0xa1, 0xcf, 0x11, 0x70, 0x51, + 0x1c, 0xe8, 0x07, 0xae, 0x09, 0x64, 0xa0, 0x26, 0x1d, 0x5e, 0x4c, 0x34, 0xfb, 0x0c, 0xe6, 0xad, + 0x29, 0x0f, 0x2d, 0x33, 0xc8, 0x72, 0x76, 0x42, 0xd7, 0x36, 0xb3, 0xac, 0xc1, 0xdf, 0xca, 0xf0, + 0x6b, 0xc4, 0x32, 0x68, 0x2d, 0x2c, 0x40, 0xd7, 0x40, 0xf7, 0xd6, 0x5e, 0x14, 0x1d, 0xf5, 0x25, + 0x93, 0x81, 0x38, 0x2f, 0x87, 0x31, 0x5e, 0xe8, 0xef, 0x83, 0x9b, 0x81, 0xd9, 0xa7, 0x9f, 0x68, + 0x95, 0x81, 0x37, 0x6e, 0x06, 0x00, 0xe6, 0x63, 0x47, 0x8b, 0xc5, 0xe2, 0xe5, 0x8b, 0x17, 0x82, + 0x0b, 0x5a, 0x06, 0xb9, 0x8c, 0xb7, 0x14, 0xfa, 0x7a, 0xf1, 0xc8, 0x80, 0x05, 0x30, 0x03, 0x7b, + 0xdb, 0x79, 0x28, 0x66, 0xc7, 0xb6, 0x2d, 0xe0, 0xaf, 0xd0, 0xf7, 0x08, 0xa1, 0x0c, 0x04, 0xca, + 0x0c, 0xa8, 0x9f, 0xc5, 0x26, 0x87, 0x75, 0xe0, 0xaf, 0xc0, 0xdd, 0x8d, 0x54, 0x06, 0x79, 0x8c, + 0xf1, 0x8c, 0x9f, 0x02, 0xc9, 0x0c, 0xb2, 0x76, 0x6c, 0xad, 0xb9, 0x7b, 0x5b, 0x3d, 0x83, 0xd6, + 0x02, 0x41, 0xd5, 0xcd, 0x1b, 0x3d, 0x21, 0xfc, 0x1a, 0x0c, 0xb5, 0x4f, 0x1e, 0xd1, 0xef, 0x5f, + 0x64, 0x67, 0xdb, 0x93, 0x41, 0x3e, 0x73, 0x06, 0x00, 0x99, 0x9b, 0x37, 0x80, 0xe7, 0x00, 0x1f, + 0x44, 0x49, 0x70, 0x20, 0x0c, 0x1a, 0x9f, 0x20, 0xc9, 0xd6, 0x46, 0xd3, 0xd7, 0xcf, 0x92, 0x01, + 0x1d, 0xec, 0x14, 0xc9, 0xa3, 0x27, 0x59, 0x30, 0x65, 0x20, 0x20, 0x95, 0x01, 0xf3, 0x7b, 0x23, + 0x99, 0x41, 0xea, 0xca, 0x65, 0xf4, 0x48, 0xf0, 0xda, 0xd4, 0x62, 0xe4, 0x72, 0xb9, 0x96, 0x19, + 0xbc, 0xf9, 0xe3, 0x2e, 0x3d, 0x32, 0xc3, 0x71, 0x23, 0xf5, 0xa7, 0xeb, 0xde, 0xdd, 0xcd, 0xcd, + 0xcd, 0xbb, 0x9d, 0xb7, 0x6b, 0x93, 0x81, 0x82, 0x89, 0x25, 0x96, 0xe6, 0x45, 0x9b, 0x0c, 0xa8, + 0x12, 0x9b, 0xd2, 0x9e, 0xab, 0x49, 0x6f, 0x6b, 0x6b, 0x23, 0x90, 0x01, 0x40, 0xf5, 0x6f, 0xbf, + 0x66, 0x38, 0x6e, 0xe8, 0xa8, 0xae, 0xc2, 0x4c, 0xcf, 0x3b, 0x03, 0x46, 0x74, 0xd5, 0xd5, 0x4a, + 0xca, 0x4a, 0xc8, 0x48, 0x17, 0xe4, 0xf5, 0x7d, 0x5c, 0x25, 0x27, 0x82, 0x00, 0x51, 0x5d, 0x0d, + 0xf5, 0xf2, 0xee, 0x6e, 0x70, 0x91, 0xe7, 0xb6, 0x57, 0x57, 0xe9, 0x54, 0xc4, 0xcf, 0xb4, 0x46, + 0xd7, 0xa0, 0x42, 0x15, 0xfa, 0x79, 0xd5, 0xc7, 0xc5, 0x90, 0x91, 0xce, 0x58, 0x78, 0x88, 0xd5, + 0xa0, 0x54, 0x41, 0xa8, 0x95, 0xd7, 0x8b, 0x74, 0xf6, 0x48, 0x66, 0xe9, 0x4d, 0x8d, 0x8d, 0xfa, + 0x92, 0x5e, 0x5d, 0xa5, 0x2c, 0xd7, 0x09, 0x71, 0xca, 0xfe, 0x25, 0xec, 0xa3, 0x91, 0x94, 0xce, + 0x09, 0xbd, 0x4b, 0x6f, 0x97, 0x48, 0xa8, 0x31, 0xe0, 0x53, 0x20, 0xaf, 0x7b, 0x4d, 0x75, 0x35, + 0xea, 0x3d, 0x64, 0xbb, 0x38, 0x13, 0x96, 0xce, 0x19, 0x3f, 0x8c, 0xde, 0x9a, 0x83, 0x20, 0x97, + 0x76, 0x6b, 0x21, 0x1d, 0xfe, 0x2b, 0xd9, 0xce, 0x96, 0xa3, 0x35, 0x6f, 0xce, 0x78, 0xc1, 0x2e, + 0x02, 0x5e, 0xa8, 0x8d, 0x35, 0xe8, 0x60, 0x63, 0x86, 0x93, 0x81, 0xc2, 0x82, 0x7c, 0xed, 0xa5, + 0x03, 0xa4, 0x3b, 0xac, 0xd5, 0xa3, 0x74, 0xf6, 0xa2, 0x6d, 0x20, 0xe9, 0x57, 0x2e, 0x5d, 0x9c, + 0xc6, 0xd4, 0x1d, 0xe2, 0x90, 0x9e, 0xb3, 0xc7, 0xa5, 0xab, 0x56, 0x44, 0x8d, 0xc9, 0xd8, 0xe4, + 0x20, 0x97, 0x4a, 0xd5, 0xa4, 0x6b, 0x02, 0x56, 0xe7, 0x20, 0x7b, 0x97, 0x33, 0xba, 0xce, 0xdb, + 0xef, 0x8a, 0xfe, 0xa5, 0x53, 0x99, 0xa1, 0x42, 0xb0, 0xdf, 0x95, 0x71, 0x9c, 0x46, 0x46, 0x3a, + 0x27, 0xae, 0x5c, 0xbe, 0x84, 0x1b, 0x2e, 0x5d, 0x8c, 0xb3, 0x9e, 0x06, 0x68, 0x50, 0x0b, 0x6d, + 0xc5, 0x42, 0xa3, 0x69, 0x4f, 0x05, 0x78, 0x23, 0x8c, 0x2f, 0xa5, 0x34, 0x34, 0x18, 0x68, 0x99, + 0x68, 0x33, 0x87, 0xf1, 0xae, 0xec, 0xc3, 0xee, 0x4f, 0xcc, 0xc6, 0xe4, 0xec, 0x62, 0xa8, 0x0f, + 0x35, 0x41, 0x2f, 0xda, 0x33, 0xe2, 0xd9, 0x22, 0x7b, 0x96, 0xfa, 0xcb, 0x65, 0x87, 0x13, 0x7c, + 0x60, 0xf8, 0x1e, 0x30, 0x65, 0x1a, 0x4e, 0x7b, 0xa0, 0x53, 0x4b, 0x4e, 0x36, 0x3d, 0x7e, 0xd2, + 0xc4, 0xf1, 0xf4, 0x94, 0x15, 0x17, 0xce, 0xe2, 0xc8, 0x34, 0x90, 0xf6, 0xe2, 0xdc, 0x1c, 0x7c, + 0x46, 0x41, 0x4a, 0xc6, 0x89, 0x10, 0x3a, 0xf8, 0x69, 0xcf, 0x59, 0xc5, 0x68, 0x82, 0x38, 0x8f, + 0xaf, 0xf6, 0x0c, 0xb3, 0x2c, 0x74, 0xf0, 0xd0, 0xde, 0xd9, 0x69, 0x6b, 0x60, 0x80, 0x5f, 0x80, + 0xaf, 0xf7, 0xf7, 0xe7, 0xcf, 0x65, 0x67, 0xbd, 0x84, 0x91, 0x0d, 0xf5, 0xf5, 0x8d, 0x0d, 0x0d, + 0x9c, 0xf7, 0x8a, 0xf3, 0x72, 0xf9, 0x69, 0xef, 0xc7, 0x30, 0x85, 0x43, 0x87, 0xa1, 0x4a, 0xce, + 0xc0, 0xd6, 0x5e, 0xa0, 0xd4, 0xfe, 0xc7, 0xab, 0x97, 0x61, 0x65, 0xfa, 0xe7, 0xbd, 0x3f, 0xe8, + 0xc1, 0x6e, 0xbe, 0x0d, 0xf8, 0xd7, 0x8e, 0x6d, 0x5b, 0x94, 0xda, 0xfb, 0x30, 0xcc, 0x6e, 0xd1, + 0x61, 0x50, 0xed, 0xd5, 0x22, 0x85, 0xaa, 0xc9, 0xd1, 0x92, 0xe2, 0x62, 0xb5, 0x78, 0x90, 0x32, + 0x66, 0xb2, 0x25, 0x8e, 0x58, 0x83, 0x69, 0xcf, 0xdc, 0xe9, 0x2f, 0x60, 0x9e, 0xb2, 0x91, 0x83, + 0xc4, 0x05, 0x1e, 0x07, 0x39, 0xc5, 0x1a, 0xa8, 0xad, 0xd5, 0xa4, 0x3d, 0x0b, 0xa2, 0x2c, 0xcc, + 0x39, 0x3f, 0x80, 0x61, 0xf5, 0x71, 0xd1, 0xf4, 0x2e, 0x07, 0x7b, 0x28, 0xf0, 0xf1, 0xcc, 0xcd, + 0xc9, 0xe1, 0x15, 0x04, 0x8f, 0x23, 0xc0, 0x8d, 0x6a, 0x91, 0x59, 0x59, 0x2f, 0xb9, 0xef, 0xcd, + 0xcc, 0x48, 0x5d, 0xb9, 0x8c, 0x51, 0x8d, 0xf4, 0xf5, 0x6b, 0xb4, 0xe1, 0xbe, 0xab, 0xae, 0x96, + 0x57, 0x7b, 0xae, 0x50, 0x4d, 0x4b, 0xaa, 0xa5, 0x8f, 0x8f, 0x8d, 0xd5, 0xd4, 0x1d, 0xc2, 0x87, + 0xf6, 0x25, 0xa7, 0x2c, 0x2c, 0x04, 0x28, 0xd4, 0xf1, 0xa6, 0x06, 0x27, 0xb1, 0x38, 0x5f, 0x40, + 0x7f, 0x5a, 0xce, 0xce, 0x3b, 0x27, 0x74, 0x2a, 0xf7, 0x51, 0x96, 0x13, 0x31, 0xdf, 0x40, 0x6b, + 0x01, 0x87, 0xf6, 0x23, 0x87, 0x7f, 0xa0, 0x85, 0x02, 0x3a, 0x69, 0x2f, 0x70, 0x77, 0xc3, 0xd4, + 0xfe, 0xcd, 0xdd, 0xdb, 0x2c, 0xda, 0x7f, 0x69, 0x33, 0x07, 0x96, 0x22, 0xd0, 0xf5, 0x37, 0x1f, + 0x3b, 0x7a, 0xfa, 0xe7, 0x56, 0x20, 0xf2, 0xcc, 0xa9, 0x50, 0x4e, 0xb1, 0xba, 0xd6, 0x39, 0x40, + 0xa7, 0x2c, 0xa7, 0x2d, 0x38, 0xc9, 0x9e, 0x2d, 0xb4, 0x53, 0x8b, 0x34, 0x72, 0xc9, 0x81, 0x80, + 0x5f, 0x70, 0x57, 0x7d, 0x1d, 0xe3, 0x7f, 0x0b, 0xbd, 0x3c, 0x94, 0x8b, 0x11, 0xb4, 0x3e, 0xe3, + 0xb9, 0x6f, 0xc3, 0x8c, 0xf9, 0xd5, 0xaa, 0x21, 0x7b, 0xe7, 0x76, 0xc6, 0x7a, 0xed, 0xdd, 0xfd, + 0xbf, 0x34, 0xdd, 0x52, 0x53, 0x5d, 0xad, 0x63, 0xa6, 0x86, 0x1b, 0x9d, 0xd0, 0xd1, 0x92, 0x95, + 0xd9, 0xf4, 0x22, 0x55, 0xeb, 0xdb, 0xc9, 0xa8, 0xae, 0x36, 0xe8, 0x3e, 0x77, 0xf6, 0x5b, 0x96, + 0x21, 0x79, 0xbe, 0xbf, 0x37, 0x43, 0xf3, 0xe7, 0xed, 0x61, 0x1c, 0xd5, 0xd5, 0xc0, 0x52, 0x8e, + 0xa1, 0xa2, 0xd1, 0x96, 0x13, 0xe1, 0x0a, 0x4f, 0x57, 0x57, 0x17, 0x20, 0x3e, 0xd9, 0x7e, 0x01, + 0x8c, 0x97, 0x75, 0x74, 0xe0, 0xe7, 0x42, 0x5e, 0x75, 0xf8, 0x09, 0xde, 0xb9, 0x7d, 0x8b, 0xfe, + 0x2f, 0xa8, 0x5f, 0x5d, 0x4c, 0x14, 0x8a, 0xe9, 0xee, 0xea, 0x82, 0x17, 0xb2, 0x8e, 0x76, 0x87, + 0x4f, 0x3e, 0x22, 0xbf, 0x76, 0xc4, 0x17, 0x97, 0x2f, 0x7e, 0x4f, 0x8f, 0x7c, 0xb1, 0x7e, 0x8d, + 0xb2, 0x3d, 0xae, 0xe9, 0xfb, 0x3a, 0x51, 0x3d, 0x93, 0xfa, 0x3c, 0x05, 0x5c, 0x80, 0x21, 0xb9, + 0xf1, 0x27, 0x11, 0x18, 0x55, 0x8f, 0x54, 0x1a, 0x7e, 0x78, 0x52, 0x63, 0x80, 0xba, 0x52, 0xd5, + 0x1c, 0x1f, 0xf8, 0x5b, 0x57, 0x57, 0x0b, 0x2e, 0x44, 0x11, 0x0f, 0x40, 0x32, 0xd1, 0xe3, 0x08, + 0x9c, 0x5c, 0x0c, 0xa4, 0x7a, 0xd1, 0x51, 0x5f, 0x3a, 0x9d, 0x40, 0x75, 0x99, 0x4c, 0xa6, 0x16, + 0x09, 0x92, 0xc5, 0x4e, 0x9d, 0x8c, 0x93, 0x8b, 0x81, 0x54, 0x8f, 0xb6, 0x62, 0xee, 0xfc, 0xd0, + 0x17, 0x72, 0xd3, 0x56, 0xaf, 0xc0, 0x2c, 0x33, 0x06, 0x52, 0x5d, 0x59, 0xab, 0x30, 0x4d, 0x24, + 0x53, 0xad, 0x62, 0x7a, 0x6c, 0x63, 0x02, 0x7c, 0xfa, 0x9d, 0xea, 0x98, 0xc5, 0x80, 0xb1, 0x68, + 0x31, 0x62, 0x70, 0xa8, 0x8e, 0xdf, 0x61, 0xd2, 0x45, 0x75, 0x76, 0xc3, 0x33, 0x2a, 0xf8, 0xb1, + 0x3e, 0xc5, 0x72, 0x22, 0x4e, 0x32, 0x66, 0xd5, 0xa7, 0xe0, 0xa9, 0x4e, 0x9c, 0xf5, 0xa3, 0x7e, + 0x3e, 0x81, 0x01, 0x7e, 0x0e, 0x6b, 0x56, 0x2b, 0x54, 0x6b, 0xb3, 0x4f, 0xff, 0x7d, 0x92, 0x18, + 0x1f, 0x07, 0x62, 0x4e, 0x1e, 0x0f, 0xa2, 0x27, 0xd6, 0x4d, 0x75, 0xd2, 0xac, 0xa3, 0xd9, 0xe7, + 0xec, 0xac, 0x97, 0xa0, 0xe3, 0x91, 0xf2, 0x2c, 0xd9, 0x62, 0xdc, 0x98, 0x75, 0xab, 0x57, 0x32, + 0x26, 0xee, 0x5f, 0xac, 0xf3, 0x02, 0xa3, 0xea, 0x31, 0x03, 0x43, 0xf5, 0xef, 0x2f, 0xa8, 0xc5, + 0xe0, 0xa8, 0xde, 0xd2, 0xd2, 0xa2, 0x30, 0x7e, 0xe5, 0xa8, 0x41, 0x75, 0x96, 0xf9, 0x54, 0x10, + 0xe0, 0x7f, 0xfb, 0xa9, 0xea, 0x0a, 0x95, 0x61, 0xa5, 0xa6, 0xbb, 0x60, 0xe5, 0x5b, 0x7c, 0x2c, + 0xa0, 0x1f, 0xaa, 0x3e, 0x49, 0x2d, 0x72, 0xdb, 0xe6, 0x8d, 0x0a, 0x1a, 0x1a, 0x53, 0x92, 0x95, + 0xaa, 0x6b, 0x36, 0x52, 0x43, 0x30, 0xa6, 0xea, 0x55, 0x55, 0x95, 0x12, 0x09, 0x83, 0xa9, 0x98, + 0x72, 0x02, 0x95, 0xc9, 0xc2, 0x54, 0x0d, 0xc6, 0x54, 0x5d, 0x13, 0x12, 0xe7, 0xcf, 0xc5, 0x29, + 0x33, 0xfd, 0x51, 0x75, 0x98, 0xfe, 0xe9, 0x84, 0x71, 0xec, 0x69, 0xc8, 0xab, 0x0e, 0x3e, 0x44, + 0xf0, 0xc1, 0xa9, 0x95, 0x04, 0xa5, 0xea, 0x9f, 0xf3, 0x50, 0xbd, 0x2e, 0x2a, 0x12, 0x0e, 0xf6, + 0xa4, 0xaa, 0x1a, 0x93, 0x11, 0x14, 0x6b, 0x1d, 0x6a, 0xa0, 0x58, 0xee, 0xf4, 0x84, 0x9b, 0xe1, + 0xf8, 0x46, 0xb1, 0xf4, 0x8e, 0x1a, 0x5f, 0xd5, 0x01, 0x24, 0xe5, 0x65, 0x7d, 0x53, 0x1d, 0x1e, + 0x07, 0x41, 0xcd, 0x83, 0x8c, 0x80, 0x7a, 0x4c, 0x81, 0xf8, 0xae, 0x17, 0x80, 0xf7, 0x98, 0x97, + 0x98, 0xc0, 0x77, 0xc9, 0x00, 0xaa, 0xce, 0xf7, 0x2e, 0x10, 0x84, 0x41, 0xfe, 0x9a, 0x34, 0xe1, + 0x57, 0x60, 0x8a, 0x7a, 0x05, 0x15, 0x7a, 0x7b, 0x72, 0xa7, 0xa6, 0x80, 0xce, 0xfa, 0x9b, 0x9a, + 0x1a, 0x23, 0x4c, 0x3b, 0xe6, 0xec, 0x71, 0xe1, 0xab, 0x3d, 0x5d, 0x75, 0xd8, 0x76, 0x72, 0xda, + 0xd1, 0xb2, 0x40, 0xcb, 0xcf, 0x14, 0x6a, 0xdf, 0xf9, 0xee, 0x2d, 0x66, 0x7a, 0x2d, 0xca, 0x3a, + 0x27, 0xb4, 0xaf, 0x61, 0x70, 0xea, 0x2f, 0x6a, 0xe2, 0x7e, 0xa4, 0x3a, 0x2c, 0xf7, 0x98, 0x89, + 0x55, 0xaa, 0x5b, 0x69, 0x9d, 0x17, 0x23, 0x74, 0xaa, 0xd7, 0x81, 0x42, 0x2d, 0xb9, 0x0c, 0x56, + 0x31, 0x8c, 0x29, 0xd9, 0x55, 0x7f, 0x91, 0x96, 0xc6, 0x37, 0x77, 0x5d, 0x55, 0xaf, 0xfc, 0xf9, + 0x27, 0xcc, 0x94, 0x2c, 0xaa, 0x83, 0xef, 0x75, 0xf4, 0x88, 0xe1, 0x7c, 0x73, 0xd7, 0x55, 0x75, + 0x30, 0x80, 0xc7, 0x4c, 0x99, 0xdc, 0xbb, 0xa1, 0x84, 0x0e, 0x34, 0x6f, 0xea, 0xb2, 0xc3, 0x29, + 0x38, 0x28, 0x30, 0x23, 0xfd, 0xc5, 0x02, 0x9b, 0xd9, 0xa0, 0x07, 0xcf, 0x2e, 0x53, 0x57, 0xd5, + 0xe3, 0xac, 0xa7, 0x61, 0xa6, 0x2c, 0x0e, 0xf2, 0x67, 0xfc, 0xd7, 0x1f, 0x77, 0xef, 0xc0, 0x0b, + 0xb4, 0x1c, 0x09, 0x54, 0xf7, 0xf3, 0x3e, 0xa2, 0x69, 0xe3, 0x04, 0x82, 0x4e, 0xaa, 0xe7, 0x1f, + 0xdc, 0x8f, 0xf3, 0xa5, 0xe2, 0x0f, 0x37, 0x79, 0x81, 0xc0, 0x2a, 0x64, 0x9c, 0xf5, 0x74, 0xd6, + 0x24, 0x4a, 0x23, 0x0c, 0xd0, 0x8f, 0xd5, 0x31, 0x23, 0x3a, 0x74, 0x55, 0xbd, 0x34, 0xf4, 0x04, + 0xd0, 0x2c, 0xd3, 0x91, 0x61, 0xbc, 0xa3, 0x84, 0x4c, 0xaa, 0x69, 0xb6, 0x1f, 0x96, 0x6f, 0x5d, + 0xd6, 0x50, 0x09, 0x74, 0x7a, 0x61, 0x79, 0x50, 0x2e, 0x35, 0xfe, 0x73, 0x9f, 0x1a, 0x0f, 0x7a, + 0x0a, 0x30, 0x5e, 0xde, 0xcd, 0x60, 0x35, 0x1e, 0x1b, 0x13, 0xdd, 0x2f, 0x96, 0x4e, 0xa1, 0xf5, + 0x1d, 0x3d, 0x3c, 0x5f, 0xb2, 0x88, 0x88, 0x7c, 0x46, 0x90, 0x1c, 0x6a, 0x80, 0x61, 0x01, 0xa8, + 0x2b, 0x33, 0xb7, 0x6e, 0xce, 0x75, 0xdd, 0xf3, 0xea, 0x92, 0xfa, 0x40, 0x89, 0x38, 0x8c, 0xb9, + 0xe4, 0x6b, 0x68, 0xc8, 0x64, 0x95, 0xd7, 0x7f, 0xcc, 0x3f, 0xec, 0x1e, 0x3f, 0xd3, 0x5a, 0xad, + 0x74, 0x44, 0x5b, 0x4e, 0xcc, 0xd8, 0xe4, 0x00, 0x46, 0x33, 0x5a, 0x6c, 0xe1, 0xd2, 0x0e, 0x03, + 0x86, 0x77, 0x50, 0x1b, 0xb1, 0xef, 0x1e, 0xd6, 0x84, 0xda, 0xc7, 0x11, 0xcf, 0x16, 0xda, 0xd1, + 0xbf, 0xc4, 0xb8, 0x2f, 0xa6, 0x25, 0xce, 0x9b, 0x0b, 0xde, 0xc1, 0xd3, 0xf1, 0x66, 0xea, 0x63, + 0x41, 0xf3, 0xf1, 0xe0, 0x1d, 0x10, 0x7e, 0x80, 0xf7, 0x31, 0x30, 0x78, 0xff, 0xdf, 0xef, 0x77, + 0x61, 0x5b, 0xc0, 0xab, 0x4e, 0x2d, 0x7e, 0x7f, 0x6c, 0x0b, 0xaa, 0x91, 0xee, 0xa6, 0x26, 0xb5, + 0x34, 0x5d, 0xbd, 0x4b, 0xe6, 0x10, 0xaf, 0xaf, 0x5c, 0x4c, 0x98, 0x33, 0x0b, 0xdd, 0x92, 0xbe, + 0x61, 0x9d, 0xac, 0x5d, 0xa2, 0xd0, 0x03, 0x06, 0x00, 0xef, 0x8d, 0x0d, 0x0d, 0x39, 0xd9, 0x59, + 0x20, 0x04, 0xf8, 0x7a, 0xc3, 0x0b, 0xee, 0x5b, 0x52, 0x92, 0xc1, 0x38, 0xae, 0xa7, 0x85, 0x59, + 0xb6, 0xb8, 0x53, 0xf4, 0x4e, 0x53, 0xca, 0x6e, 0x4a, 0xa3, 0x29, 0x16, 0x8b, 0x77, 0x39, 0x3b, + 0xa1, 0x17, 0x4c, 0x7d, 0x61, 0x64, 0x9e, 0x84, 0x82, 0x01, 0xc0, 0x3b, 0x02, 0xa3, 0x09, 0x02, + 0x1d, 0xe5, 0x67, 0xc3, 0x10, 0x65, 0x6f, 0xef, 0xfd, 0xae, 0x29, 0x19, 0x9c, 0x97, 0x90, 0xf6, + 0x6e, 0x48, 0x82, 0x10, 0xe4, 0xe5, 0x41, 0xd2, 0x7f, 0x09, 0xff, 0x59, 0x2e, 0x95, 0xa6, 0x2e, + 0x5f, 0x02, 0xe5, 0x68, 0xec, 0xac, 0x69, 0x0b, 0x53, 0xe3, 0xbd, 0x3e, 0xb6, 0xcf, 0x12, 0xb8, + 0xad, 0x88, 0x6d, 0xcf, 0x11, 0xac, 0xb2, 0xa8, 0x96, 0x16, 0xab, 0x96, 0x2d, 0x81, 0x17, 0xd4, + 0x8d, 0x96, 0xd9, 0x2e, 0x3b, 0x7a, 0xa6, 0x11, 0xbd, 0x0e, 0x6b, 0xa9, 0x37, 0x13, 0x4c, 0x8d, + 0xf7, 0xe7, 0xcb, 0x7a, 0x4a, 0x68, 0xe9, 0xa9, 0x13, 0x38, 0x32, 0x21, 0xef, 0x8c, 0xfb, 0xf9, + 0x20, 0xe4, 0x9d, 0x9d, 0x51, 0xe6, 0x3d, 0xf6, 0x46, 0x4d, 0xa9, 0x29, 0xf8, 0xda, 0xb2, 0xc3, + 0xa4, 0x78, 0x07, 0xbd, 0x40, 0x54, 0xd8, 0x71, 0xec, 0xe1, 0x30, 0x1b, 0xea, 0xc2, 0x23, 0x1e, + 0xc4, 0x2b, 0x7a, 0x93, 0xe2, 0x1d, 0x6e, 0xfc, 0x8a, 0xc4, 0xb6, 0x0a, 0x01, 0x60, 0x5c, 0x97, + 0x53, 0x43, 0x91, 0xca, 0x78, 0x24, 0x92, 0xc9, 0xe8, 0x57, 0x6b, 0x98, 0x16, 0xef, 0x79, 0xbc, + 0x79, 0xc7, 0x41, 0x51, 0xef, 0x4c, 0x02, 0xe6, 0x06, 0x3d, 0x1c, 0xe8, 0x8b, 0xf7, 0x33, 0xa7, + 0x42, 0xff, 0xfe, 0xf3, 0x1e, 0x59, 0x99, 0xc6, 0xe7, 0xdd, 0x0f, 0x6b, 0x6b, 0x21, 0x0e, 0xf4, + 0xc2, 0x7b, 0x52, 0x62, 0x82, 0xb7, 0xa7, 0xc7, 0x8a, 0x25, 0x8b, 0x2a, 0x2b, 0x5f, 0x13, 0x14, + 0xcb, 0x83, 0x77, 0x3c, 0x8b, 0x1c, 0x4c, 0x14, 0xf7, 0x95, 0xf7, 0xfe, 0xcd, 0xfb, 0xc8, 0xe1, + 0x1f, 0x48, 0x55, 0x40, 0xad, 0x96, 0x48, 0x24, 0xba, 0xfd, 0xeb, 0x2f, 0xe0, 0xef, 0xdd, 0xdf, + 0x94, 0xbe, 0xa0, 0x8a, 0x8b, 0x8b, 0x7e, 0xfa, 0xe1, 0x0a, 0xb8, 0x80, 0x93, 0xeb, 0x7f, 0xdd, + 0xfb, 0x1f, 0x8e, 0x58, 0xe3, 0xf3, 0x8e, 0xb7, 0x9d, 0x13, 0x07, 0x7a, 0xb1, 0x6c, 0xa7, 0xff, + 0x4c, 0x88, 0x8b, 0x03, 0x23, 0x72, 0x30, 0x20, 0x4c, 0x79, 0x96, 0x0c, 0x7e, 0x6e, 0xdf, 0xb2, + 0xb9, 0xb5, 0xb5, 0xd5, 0xe7, 0x88, 0x72, 0x0f, 0x01, 0xd5, 0x9b, 0x19, 0x3b, 0x30, 0x78, 0xcf, + 0xd5, 0x0b, 0xef, 0xbd, 0xed, 0x6a, 0xbf, 0xe6, 0x5d, 0x7f, 0x30, 0x1a, 0xef, 0x03, 0xa2, 0xbc, + 0xeb, 0x0f, 0x74, 0xfb, 0x21, 0x35, 0x20, 0xde, 0x31, 0x2d, 0x2e, 0x31, 0xd1, 0xc7, 0x3b, 0x93, + 0xdf, 0x42, 0xed, 0x60, 0x5a, 0xbc, 0x0b, 0xd4, 0x79, 0xdf, 0xef, 0xfa, 0xb5, 0x16, 0x9b, 0xea, + 0x36, 0x39, 0xac, 0x03, 0xb7, 0xcc, 0x99, 0xf1, 0x05, 0xfc, 0xd9, 0xd7, 0x9f, 0xc1, 0x30, 0xb6, + 0xc3, 0x84, 0x29, 0xf3, 0x0e, 0x5a, 0x0e, 0x2d, 0x66, 0x8f, 0x15, 0xbd, 0xbc, 0x83, 0x30, 0x76, + 0xd4, 0x88, 0x96, 0x96, 0x16, 0xc4, 0x3b, 0x5f, 0x13, 0x27, 0x16, 0x98, 0x32, 0xef, 0x08, 0x65, + 0xa5, 0xa5, 0xf4, 0xc4, 0x80, 0xd6, 0xbd, 0x2e, 0xce, 0xa3, 0x3e, 0xfa, 0x90, 0xea, 0x6a, 0x0f, + 0xe2, 0x65, 0x66, 0x06, 0xf5, 0x67, 0xc5, 0x85, 0x73, 0x50, 0x6c, 0xda, 0xea, 0x15, 0x5a, 0x29, + 0xce, 0x00, 0x53, 0xe5, 0x9d, 0xdb, 0x2e, 0x0a, 0x3a, 0xea, 0xb1, 0x1c, 0x3f, 0xb6, 0x45, 0xb3, + 0xc1, 0x25, 0x84, 0x5c, 0xda, 0x0d, 0xbd, 0x22, 0x80, 0x50, 0x17, 0x15, 0xc9, 0x43, 0x63, 0xcd, + 0x30, 0x31, 0xde, 0xf3, 0x30, 0x79, 0x6f, 0x97, 0x48, 0xc0, 0x20, 0x23, 0x3a, 0xea, 0xa9, 0x97, + 0xc7, 0xa1, 0xcd, 0x1b, 0xd6, 0x73, 0x66, 0xfd, 0xea, 0xca, 0xc5, 0xc8, 0x5e, 0x73, 0x50, 0x22, + 0x6b, 0xb0, 0x83, 0x94, 0x77, 0x2d, 0x50, 0x76, 0x26, 0x14, 0x4d, 0x76, 0x96, 0x9f, 0x3d, 0xad, + 0xa3, 0xb4, 0x01, 0xc0, 0x3b, 0xa8, 0x9d, 0x51, 0xf3, 0x08, 0xc2, 0xf8, 0xcf, 0x3e, 0xd5, 0x94, + 0xb2, 0x8f, 0x77, 0xd2, 0xf6, 0x97, 0x10, 0x1d, 0x35, 0xd5, 0xb1, 0xd3, 0xa6, 0xa0, 0x82, 0xff, + 0xea, 0xe2, 0x79, 0xad, 0x45, 0x0d, 0x00, 0xde, 0x01, 0x3a, 0xda, 0xdb, 0x21, 0xe9, 0xec, 0x83, + 0x5b, 0x7d, 0xf3, 0x0e, 0x51, 0x1b, 0xf9, 0x04, 0xb4, 0xdb, 0xa8, 0xec, 0xc7, 0x4c, 0xb6, 0x2a, + 0x0a, 0xf4, 0x6b, 0x2d, 0xe4, 0x67, 0x7c, 0xa5, 0x8d, 0x8b, 0x1c, 0xcc, 0x00, 0x4a, 0x44, 0xfa, + 0x86, 0x75, 0xc5, 0xc7, 0x8f, 0x76, 0xbe, 0x7d, 0x43, 0xe4, 0x81, 0x0f, 0xb8, 0x7d, 0xc3, 0x9e, + 0x00, 0xba, 0xb2, 0xd1, 0x37, 0xef, 0x08, 0x25, 0xc1, 0x41, 0xb1, 0x53, 0x3f, 0xd7, 0x82, 0x19, + 0xa5, 0x73, 0x1f, 0xc0, 0x7b, 0xea, 0xca, 0x65, 0x58, 0x61, 0xd5, 0x72, 0xac, 0xb0, 0x62, 0x69, + 0xb2, 0xfd, 0x82, 0x68, 0x95, 0xef, 0x19, 0x6a, 0x88, 0x9e, 0x64, 0x51, 0x1a, 0x8a, 0xb5, 0xf6, + 0xa6, 0x35, 0xf0, 0x79, 0xff, 0xdc, 0xc2, 0xdc, 0xdd, 0x95, 0xe3, 0x2d, 0xf2, 0x02, 0x68, 0x6c, + 0x5f, 0xff, 0x74, 0xb5, 0x38, 0xd0, 0x0f, 0x8c, 0x69, 0xf3, 0x0f, 0xee, 0x17, 0xb8, 0xbb, 0xb1, + 0x84, 0x42, 0x6f, 0x0f, 0x43, 0xd4, 0x33, 0x65, 0x61, 0xa1, 0xb1, 0xd3, 0xa7, 0xa0, 0x17, 0x20, + 0x70, 0x77, 0xe5, 0xbe, 0x47, 0x2b, 0x60, 0xf2, 0x0e, 0x7a, 0x32, 0xb0, 0xd6, 0xb2, 0x9b, 0x47, + 0xde, 0xd8, 0x14, 0x13, 0x86, 0xac, 0xdf, 0xe5, 0xd0, 0x45, 0x0e, 0x0c, 0xa5, 0xa1, 0xc1, 0xc4, + 0x33, 0x80, 0x4e, 0xa7, 0x70, 0xca, 0xbb, 0xee, 0xfe, 0x84, 0x74, 0x84, 0xa1, 0xdb, 0xd5, 0xae, + 0xba, 0x5a, 0x54, 0x27, 0x12, 0x9c, 0xde, 0x83, 0x18, 0xe2, 0x9d, 0x1d, 0xf2, 0xa4, 0xf9, 0x36, + 0x90, 0x20, 0xd0, 0xea, 0x12, 0x94, 0x4b, 0xe1, 0x9d, 0x63, 0x33, 0xcc, 0xe0, 0xe4, 0x5d, 0xd1, + 0x94, 0x9e, 0x86, 0xfa, 0x3c, 0xf2, 0xae, 0x4e, 0x52, 0x62, 0x87, 0x78, 0xe7, 0x46, 0xb2, 0xfd, + 0x97, 0x90, 0x23, 0x16, 0xcf, 0x62, 0x7c, 0x01, 0xdd, 0xf2, 0x69, 0xcd, 0x7b, 0xc8, 0x89, 0xe3, + 0x19, 0xe9, 0x2f, 0xc6, 0x8c, 0xfc, 0x98, 0x94, 0x3e, 0x2c, 0x30, 0x1a, 0xef, 0x19, 0x8e, 0x1b, + 0x7b, 0xc7, 0xdc, 0x61, 0xa4, 0x64, 0xa2, 0xcf, 0x28, 0x6e, 0x06, 0xfb, 0xce, 0x19, 0x06, 0xde, + 0x6b, 0x6b, 0x45, 0xb0, 0x7b, 0xf3, 0xe4, 0xd1, 0x23, 0x67, 0xa7, 0xad, 0xf4, 0x5b, 0xde, 0xbd, + 0xc5, 0xdd, 0x6b, 0x89, 0x03, 0xa3, 0xf1, 0x8e, 0x16, 0x71, 0x04, 0x07, 0x18, 0x8e, 0x6e, 0xd2, + 0x52, 0x66, 0xaf, 0xe1, 0x75, 0xce, 0x5e, 0x17, 0xf6, 0x94, 0x74, 0xde, 0xa9, 0x73, 0xf4, 0x4b, + 0x17, 0xda, 0x47, 0x3c, 0xfc, 0xe7, 0xca, 0xa5, 0x8b, 0xe0, 0x1a, 0xee, 0x0d, 0x9b, 0x36, 0xc9, + 0x02, 0x7c, 0x0a, 0xe0, 0xc2, 0xcb, 0xe3, 0x30, 0x8a, 0xd4, 0x05, 0x46, 0xe3, 0x5d, 0xda, 0xd6, + 0x86, 0xec, 0x0e, 0x19, 0x8f, 0x16, 0xe2, 0x0b, 0xc9, 0xab, 0x0a, 0xd4, 0x49, 0x6d, 0x7c, 0x96, + 0xc4, 0x9e, 0x78, 0xf0, 0xd6, 0xef, 0x00, 0x75, 0x4f, 0xff, 0x45, 0x4c, 0x55, 0x5e, 0xfb, 0x41, + 0x17, 0x51, 0x60, 0xc4, 0x84, 0x0c, 0xde, 0x4b, 0x43, 0x8e, 0x73, 0xa6, 0x1f, 0xd4, 0xbc, 0x2b, + 0x54, 0x2d, 0xe1, 0xd3, 0xde, 0x52, 0x9f, 0xb9, 0xd9, 0x41, 0xbb, 0xbe, 0x0d, 0xda, 0x79, 0x07, + 0x42, 0xd5, 0xf5, 0x1f, 0xb1, 0x6e, 0x19, 0xe4, 0xbc, 0x43, 0xa0, 0xba, 0x1e, 0x84, 0xf8, 0x99, + 0xd6, 0xd5, 0xbf, 0xde, 0xc0, 0xb9, 0xab, 0x31, 0x25, 0x39, 0x6d, 0xed, 0x6a, 0x74, 0x63, 0x9e, + 0xdb, 0xd7, 0x98, 0xd9, 0xa1, 0x29, 0xe5, 0x71, 0x9f, 0x8d, 0xd2, 0x41, 0x6b, 0x9d, 0xd0, 0x2f, + 0x78, 0x87, 0x28, 0x0d, 0x09, 0x46, 0x75, 0x05, 0x0c, 0x09, 0xb3, 0x67, 0x40, 0xa7, 0x21, 0xe5, + 0xe7, 0xce, 0x94, 0x7f, 0x77, 0xb6, 0xe4, 0xf8, 0x51, 0xa1, 0xef, 0x91, 0x64, 0xbb, 0x05, 0x6a, + 0x33, 0x6e, 0xc5, 0x47, 0x79, 0x9b, 0x47, 0x8f, 0x1c, 0xfe, 0xc1, 0x02, 0x9b, 0xd9, 0xfa, 0x78, + 0x0a, 0x4c, 0xf4, 0x23, 0xde, 0x11, 0x44, 0x0f, 0xef, 0xe7, 0xed, 0xfb, 0x46, 0xed, 0x1d, 0xa8, + 0x85, 0x4c, 0xc7, 0x8d, 0x65, 0xdf, 0x7f, 0xd7, 0xa2, 0x4f, 0xe8, 0xf5, 0x19, 0xfb, 0x23, 0xef, + 0x7a, 0x87, 0x4c, 0xd6, 0x2a, 0x2c, 0x68, 0x4c, 0x4d, 0x69, 0x48, 0x4a, 0x68, 0xc9, 0xc9, 0xea, + 0x6e, 0x69, 0x36, 0xbc, 0x0a, 0x83, 0x88, 0xf7, 0xd6, 0xc2, 0xfc, 0xa2, 0x40, 0xbf, 0xb4, 0xd5, + 0x2b, 0x51, 0x4b, 0x8e, 0x42, 0xe2, 0xbc, 0x39, 0x42, 0x1f, 0xcf, 0xb7, 0x7f, 0x13, 0x36, 0x1c, + 0x67, 0x41, 0x3f, 0xe2, 0x3d, 0x23, 0x23, 0x83, 0xc5, 0x3b, 0xf6, 0xe9, 0x53, 0xa1, 0x3c, 0x4e, + 0xb7, 0x7a, 0x3f, 0x3c, 0x3a, 0x1d, 0x9a, 0xb9, 0xcb, 0x19, 0x67, 0x25, 0x28, 0xf9, 0xcb, 0xf9, + 0x65, 0x67, 0xb8, 0x5d, 0xe2, 0xeb, 0x8e, 0x7e, 0xc4, 0x3b, 0x3b, 0x46, 0x7d, 0xf4, 0xa1, 0x36, + 0x8e, 0xe0, 0xe5, 0xf2, 0x22, 0x4a, 0x67, 0x09, 0x85, 0xa8, 0x89, 0x13, 0x40, 0xa3, 0x9d, 0x68, + 0x33, 0x87, 0x71, 0xa1, 0x2e, 0x7d, 0xe3, 0x7a, 0x4d, 0x67, 0x47, 0x93, 0xc2, 0xc0, 0xe0, 0x3d, + 0x29, 0x21, 0x1e, 0x74, 0xfb, 0xf8, 0x1e, 0x36, 0xd1, 0x59, 0x2b, 0x4a, 0x77, 0x58, 0x4b, 0x25, + 0x34, 0x6d, 0xd5, 0xf2, 0x92, 0x13, 0x41, 0xca, 0xc3, 0xa6, 0x55, 0x1e, 0x11, 0x7f, 0xb8, 0xaa, + 0xb4, 0xc1, 0xef, 0x7c, 0xfb, 0x46, 0xe9, 0xb7, 0xe0, 0xc0, 0x7e, 0xea, 0x86, 0xf9, 0x28, 0x4b, + 0xf3, 0x57, 0x97, 0xf5, 0xe8, 0x1d, 0x62, 0x60, 0xf0, 0x8e, 0x7a, 0xdc, 0xb1, 0x31, 0xd1, 0x98, + 0xb7, 0x74, 0x54, 0x57, 0x25, 0xd9, 0xce, 0x43, 0x3c, 0x3e, 0x5f, 0xb6, 0xf8, 0x2d, 0xcd, 0x81, + 0x10, 0xe4, 0x1d, 0xa1, 0xfd, 0xf5, 0xab, 0x42, 0x1f, 0x4f, 0xea, 0x7b, 0x2a, 0x0b, 0x0b, 0x21, + 0xf3, 0x00, 0x34, 0x0c, 0x00, 0xde, 0x2f, 0x9e, 0xff, 0x8e, 0x6a, 0x3f, 0x83, 0x73, 0x8b, 0xac, + 0xbd, 0x1d, 0x6d, 0xb5, 0x8e, 0x54, 0x9d, 0x04, 0x0e, 0x6a, 0x1c, 0x7a, 0xb2, 0xab, 0x57, 0x2e, + 0xd3, 0x23, 0xab, 0xc2, 0xaf, 0x9f, 0x31, 0x1f, 0x3f, 0x65, 0xf8, 0x87, 0x3d, 0x03, 0x60, 0x3c, + 0x1f, 0x58, 0x7c, 0x31, 0x00, 0x78, 0x87, 0x3e, 0x09, 0xf6, 0x7d, 0xb3, 0x17, 0x5e, 0x88, 0xc5, + 0x62, 0xce, 0x5b, 0x0a, 0x3c, 0x0f, 0x23, 0xd2, 0x4b, 0x82, 0x19, 0xbc, 0x43, 0x43, 0xa8, 0xf1, + 0xfe, 0xf7, 0x9f, 0xf7, 0xcc, 0x46, 0x8f, 0x84, 0x6f, 0xd7, 0xbb, 0xf7, 0x6c, 0x82, 0xd8, 0x29, + 0x93, 0xdb, 0xab, 0x2a, 0x09, 0x3c, 0xc6, 0xfb, 0x18, 0x00, 0xbc, 0x43, 0x1c, 0x3b, 0x1a, 0x80, + 0x99, 0x12, 0x54, 0xd6, 0x7d, 0x43, 0x59, 0x0d, 0x1e, 0xc1, 0x44, 0x22, 0xd1, 0x9e, 0x9d, 0x3b, + 0xd4, 0x4e, 0xba, 0x98, 0x68, 0xf6, 0x19, 0xfa, 0xaa, 0x9a, 0xd2, 0x52, 0xa3, 0x7a, 0x4d, 0x51, + 0xf2, 0xf6, 0x93, 0xb4, 0xf8, 0x80, 0x30, 0x41, 0xde, 0x93, 0xed, 0x6c, 0x7b, 0x66, 0xe1, 0x77, + 0x6b, 0x9c, 0x85, 0x07, 0xbc, 0x8f, 0x19, 0xf9, 0x31, 0xe8, 0x62, 0xaa, 0xc5, 0x8f, 0x1d, 0x35, + 0x02, 0xd5, 0x66, 0xe5, 0xe7, 0x28, 0xfe, 0x25, 0x48, 0x77, 0xed, 0x4d, 0x8d, 0xf7, 0x8a, 0x4b, + 0x17, 0x7a, 0x56, 0x6e, 0xc7, 0x9b, 0x89, 0x99, 0xcf, 0xca, 0x53, 0x02, 0xf0, 0xee, 0xb8, 0x71, + 0xbd, 0x1a, 0xef, 0xbb, 0x9c, 0x9d, 0xa4, 0x52, 0xe9, 0x62, 0xfb, 0x05, 0x53, 0xad, 0x7a, 0xdc, + 0x15, 0x64, 0xef, 0xda, 0x09, 0xa5, 0xbd, 0xdc, 0xe6, 0xa8, 0x83, 0xee, 0x0c, 0x30, 0x35, 0xde, + 0xb3, 0xb6, 0x6f, 0x81, 0x4c, 0xb1, 0xef, 0xcd, 0x00, 0xbc, 0x3b, 0x39, 0x6e, 0xba, 0xac, 0x5a, + 0x51, 0x82, 0x08, 0xf4, 0xf7, 0x45, 0xee, 0x5a, 0xb3, 0x5e, 0x66, 0xc2, 0x0b, 0xea, 0x0a, 0x41, + 0x5b, 0x49, 0x91, 0x96, 0xaa, 0x33, 0xc1, 0xa4, 0x78, 0xef, 0x6e, 0x6e, 0x42, 0x34, 0x35, 0x24, + 0xc4, 0xb1, 0xa4, 0x54, 0xe3, 0xfd, 0xda, 0x8f, 0x57, 0x6b, 0xdf, 0x3f, 0x2b, 0x1b, 0x21, 0x65, + 0xe9, 0xa2, 0x48, 0x3d, 0x98, 0x9c, 0x98, 0x14, 0xef, 0x35, 0x77, 0x6e, 0xf5, 0x4c, 0xe2, 0xcf, + 0x9a, 0x81, 0x23, 0xf3, 0x92, 0x6a, 0x63, 0xe6, 0xa3, 0x88, 0x87, 0xf4, 0x83, 0x47, 0x11, 0xd0, + 0xe6, 0xd5, 0x6c, 0x97, 0x1d, 0xd8, 0xca, 0x72, 0xc3, 0xa4, 0x78, 0x47, 0x1c, 0xe5, 0xed, 0xc3, + 0x5a, 0x03, 0x09, 0x3e, 0x16, 0xf4, 0x22, 0x2d, 0x2d, 0x2d, 0xf5, 0x39, 0x4b, 0x1a, 0x78, 0x5c, + 0x14, 0x9c, 0x3b, 0xc3, 0x54, 0x15, 0x07, 0x26, 0xc5, 0xbb, 0xd0, 0xf7, 0x48, 0xef, 0x4a, 0x08, + 0xf7, 0xd9, 0xf4, 0x33, 0xa7, 0x4f, 0x81, 0x67, 0x88, 0xb1, 0x27, 0x93, 0x54, 0x94, 0xa1, 0x86, + 0x9a, 0x71, 0xf0, 0xa5, 0x1d, 0x4c, 0x8a, 0x77, 0xc1, 0x81, 0x7d, 0xec, 0xdd, 0x76, 0x2a, 0x66, + 0x4d, 0x9f, 0x0a, 0x78, 0xb7, 0x9e, 0xfa, 0x79, 0x2b, 0x2b, 0x9a, 0xab, 0xab, 0x51, 0x9b, 0xd1, + 0xdd, 0x4c, 0x6c, 0xa6, 0xde, 0xa4, 0x78, 0xcf, 0x73, 0xdb, 0xdb, 0x33, 0x46, 0x3d, 0xa1, 0x71, + 0x8c, 0x4a, 0x05, 0x8e, 0xbb, 0x10, 0x69, 0x5b, 0x1b, 0xe2, 0x5d, 0xd3, 0x51, 0xa0, 0x5a, 0x60, + 0x50, 0xf3, 0x8e, 0x03, 0x99, 0x64, 0x88, 0x77, 0x2e, 0xe4, 0xb9, 0x7d, 0xad, 0x07, 0xde, 0x25, + 0x7d, 0xbc, 0xab, 0x0e, 0x66, 0x24, 0x82, 0x21, 0xde, 0x39, 0x20, 0x6b, 0x1f, 0x50, 0xbc, 0xef, + 0x77, 0xc5, 0xb5, 0x66, 0xc1, 0x84, 0xf1, 0x78, 0x6f, 0xef, 0xe3, 0x5d, 0xc3, 0xd8, 0x4a, 0x0b, + 0xe8, 0x85, 0xf7, 0x73, 0xdf, 0x86, 0x1d, 0xd8, 0xe7, 0x1a, 0x1d, 0xf5, 0x94, 0xa0, 0x4c, 0xa3, + 0xf1, 0xde, 0xd1, 0xc7, 0x7b, 0x67, 0x3f, 0xe7, 0x1d, 0xce, 0xe7, 0x8d, 0xfa, 0xe8, 0x43, 0x82, + 0x32, 0xf9, 0xf1, 0xae, 0x79, 0xce, 0x9d, 0x2f, 0x64, 0x1d, 0x1d, 0x7d, 0xbc, 0x6b, 0xf6, 0x33, + 0xcc, 0x17, 0xe4, 0x79, 0x6f, 0x6e, 0x6a, 0x9a, 0x3b, 0x53, 0xe9, 0xb9, 0x65, 0xcc, 0xc8, 0x8f, + 0xd5, 0xbc, 0x4d, 0xeb, 0x02, 0xa3, 0xf1, 0xde, 0x39, 0x40, 0x78, 0x5f, 0xba, 0xd0, 0xee, 0xf5, + 0xab, 0x0a, 0xa9, 0x54, 0x1a, 0xf5, 0x34, 0x12, 0x9e, 0xa8, 0x19, 0x13, 0x1d, 0xf5, 0xe7, 0xbd, + 0x3f, 0xea, 0xeb, 0xeb, 0x6e, 0xde, 0x08, 0xef, 0xec, 0x54, 0x5a, 0x9e, 0xfe, 0xfa, 0xcb, 0x8d, + 0xf4, 0x17, 0x2f, 0x5a, 0x5a, 0x5a, 0x9a, 0x9b, 0x9b, 0x3b, 0xda, 0xdb, 0x9b, 0x1a, 0x1b, 0x39, + 0xc5, 0x1a, 0x8b, 0x77, 0x79, 0x67, 0x67, 0x1f, 0xef, 0xd8, 0xc7, 0x3c, 0x71, 0x42, 0x2f, 0x7e, + 0xdd, 0x02, 0x03, 0xfc, 0x60, 0x80, 0x15, 0xce, 0x62, 0xfb, 0x05, 0x8a, 0xde, 0xca, 0x47, 0x69, + 0xd2, 0xff, 0xcf, 0x03, 0x70, 0xe1, 0xeb, 0xa5, 0x9c, 0xa7, 0x9d, 0x3e, 0xd9, 0xd2, 0x1a, 0xcf, + 0xd7, 0x23, 0x16, 0xef, 0xfb, 0xf4, 0xc0, 0x7b, 0xd7, 0x40, 0xe0, 0xfd, 0xe1, 0x83, 0xfb, 0x7b, + 0x5d, 0x9c, 0xd1, 0xcf, 0x35, 0xab, 0x96, 0xdf, 0xb9, 0x7d, 0x8b, 0xca, 0xbb, 0xbd, 0xed, 0x3c, + 0x90, 0x20, 0x21, 0x4e, 0x79, 0x2e, 0xae, 0x42, 0xe5, 0x58, 0x6f, 0x93, 0xc3, 0x3a, 0x1c, 0xc9, + 0xc6, 0xe3, 0xbd, 0x6b, 0x00, 0xf0, 0x3e, 0x72, 0xf8, 0x07, 0x54, 0x4f, 0xf6, 0x12, 0x49, 0x1b, + 0xa0, 0x5b, 0x8d, 0xf7, 0x1b, 0x3f, 0x5f, 0xff, 0x6a, 0xc5, 0xd2, 0xa3, 0x7e, 0x3e, 0xa5, 0x25, + 0x25, 0xb9, 0x39, 0x39, 0x05, 0xf9, 0x02, 0x61, 0x61, 0x01, 0xa7, 0x64, 0xa3, 0xf1, 0xde, 0x4d, + 0xe1, 0x9d, 0x90, 0xa3, 0x05, 0x85, 0xa9, 0x8d, 0x9b, 0xf4, 0xc2, 0x7b, 0xf7, 0x10, 0xef, 0x1c, + 0xd0, 0x0b, 0xef, 0xd2, 0x3e, 0xde, 0x3b, 0xde, 0xd4, 0x90, 0x12, 0x3b, 0xc4, 0x3b, 0x07, 0xe4, + 0x52, 0xe9, 0x10, 0xef, 0x1c, 0x60, 0xe4, 0x1d, 0xf4, 0x62, 0xf3, 0x05, 0x1a, 0x0d, 0x0b, 0x18, + 0x71, 0x2a, 0x84, 0xe2, 0xaf, 0x45, 0x46, 0xe1, 0xbd, 0x86, 0xbf, 0x61, 0xac, 0x06, 0x98, 0x18, + 0xef, 0xdf, 0x50, 0x79, 0xaf, 0xaa, 0xaa, 0x84, 0x2e, 0x4f, 0xf8, 0xf2, 0x0e, 0x4d, 0x68, 0x40, + 0xdf, 0x4c, 0xf9, 0x43, 0x26, 0x1b, 0xe2, 0x9d, 0x03, 0x14, 0xde, 0x03, 0x2d, 0x27, 0x98, 0x21, + 0xe3, 0xaf, 0xef, 0xcf, 0x9f, 0xd3, 0x74, 0x58, 0x3d, 0xcb, 0x09, 0xf6, 0x30, 0x14, 0x0b, 0x0b, + 0xfb, 0x78, 0x27, 0x77, 0x9a, 0x99, 0xa9, 0xf2, 0x1e, 0x04, 0xaa, 0x17, 0xc4, 0x9d, 0x76, 0xe5, + 0x1d, 0x84, 0x90, 0x13, 0xc7, 0x15, 0x72, 0x39, 0xe2, 0x9d, 0xa0, 0xa1, 0xa4, 0xc9, 0xf2, 0x0e, + 0x63, 0x40, 0x49, 0xd7, 0x8e, 0x77, 0xaa, 0x53, 0xc9, 0x98, 0xc9, 0x96, 0x50, 0x6c, 0x2b, 0xb9, + 0x5d, 0xaf, 0xa6, 0xca, 0x7b, 0x20, 0x35, 0xbe, 0x9e, 0xb6, 0x3e, 0xe7, 0xe7, 0x7d, 0x64, 0x81, + 0xcd, 0xec, 0x0d, 0x6b, 0xbf, 0xb2, 0x32, 0x67, 0x38, 0x9e, 0x5a, 0x2e, 0x7f, 0xcf, 0x6e, 0x20, + 0x71, 0xde, 0x5c, 0x28, 0x56, 0xf4, 0xf0, 0x01, 0x6f, 0xbd, 0x35, 0x60, 0x50, 0xf0, 0x4e, 0x07, + 0x28, 0xd1, 0x70, 0x5c, 0xfd, 0xf4, 0xdf, 0x27, 0x9c, 0x62, 0xb3, 0x9c, 0xb6, 0xe0, 0x9b, 0x29, + 0x60, 0x62, 0x90, 0xf2, 0x5e, 0x5b, 0xab, 0xb4, 0x07, 0x06, 0xec, 0x7b, 0x1e, 0x3a, 0xc0, 0x29, + 0x16, 0x99, 0x43, 0x65, 0x6e, 0xdd, 0x8c, 0xa9, 0x2d, 0x27, 0x06, 0x29, 0xef, 0x11, 0x0f, 0xff, + 0x81, 0x17, 0x8b, 0xed, 0x17, 0x54, 0x94, 0x97, 0xb3, 0x27, 0x6e, 0x48, 0x4e, 0x44, 0x4d, 0xab, + 0xa4, 0xa2, 0x0c, 0x4b, 0x5d, 0x2e, 0x0c, 0x18, 0xde, 0x8f, 0x07, 0x72, 0x9b, 0x85, 0xe2, 0xf3, + 0x3e, 0x7f, 0xce, 0x4c, 0x7f, 0x1f, 0xaf, 0xa8, 0xa7, 0x91, 0x98, 0x1b, 0x77, 0x9e, 0xfd, 0xb7, + 0xc7, 0x3b, 0x54, 0x51, 0x00, 0x99, 0x23, 0x9c, 0x06, 0x29, 0xef, 0x0a, 0xd5, 0xba, 0x18, 0x67, + 0x49, 0x47, 0x28, 0x3b, 0x75, 0x02, 0x15, 0xf9, 0xe6, 0xf4, 0x34, 0xcc, 0xbb, 0x58, 0x30, 0x78, + 0x79, 0xe7, 0x07, 0xb9, 0x0c, 0x39, 0x44, 0x4b, 0x5d, 0xbe, 0x44, 0xde, 0xad, 0xeb, 0xfa, 0xa5, + 0x69, 0xf1, 0xbe, 0xbf, 0x97, 0x77, 0xa2, 0xb6, 0xea, 0x10, 0x35, 0x77, 0x6e, 0xa3, 0x22, 0x2f, + 0x70, 0x77, 0x53, 0xc8, 0x75, 0xb2, 0x51, 0x1d, 0x00, 0xbc, 0x8f, 0x1e, 0x31, 0x9c, 0x3a, 0x70, + 0x17, 0x89, 0x34, 0x1a, 0x53, 0xe8, 0x95, 0x77, 0x05, 0xa5, 0x63, 0x03, 0x42, 0xee, 0xd7, 0xbb, + 0xa4, 0x62, 0xed, 0x7d, 0x76, 0x0c, 0x00, 0xde, 0xc1, 0xa8, 0x07, 0x91, 0x3e, 0x7d, 0xb2, 0x25, + 0x4b, 0x4a, 0x7d, 0xf3, 0xae, 0xa0, 0x9c, 0x09, 0x0a, 0x42, 0xc2, 0xdc, 0xd9, 0xd5, 0xbf, 0x84, + 0x6b, 0x27, 0x67, 0x00, 0xf0, 0x0e, 0x60, 0x3d, 0x75, 0x32, 0xe4, 0x9d, 0x7a, 0x3c, 0x30, 0x1d, + 0x02, 0xfd, 0xf3, 0x0e, 0x20, 0xf4, 0x39, 0x82, 0xa8, 0x87, 0x9d, 0xfa, 0xca, 0xf0, 0x6b, 0x0a, + 0x99, 0x94, 0xfb, 0x4e, 0x0a, 0x86, 0x55, 0xdd, 0xbc, 0x81, 0x15, 0x6e, 0x5c, 0xaf, 0x0a, 0xbf, + 0x86, 0x13, 0xde, 0xfe, 0xef, 0xf7, 0x86, 0xc4, 0x78, 0x82, 0xa6, 0x26, 0x0a, 0xd5, 0xc0, 0x1d, + 0x90, 0xbe, 0x69, 0xfd, 0x5a, 0xf6, 0x64, 0x86, 0xe1, 0x5d, 0xa1, 0xf2, 0xfc, 0x4e, 0x75, 0x66, + 0x00, 0x42, 0xb4, 0xd5, 0xc4, 0x97, 0xdb, 0x1c, 0x41, 0x2f, 0x13, 0xd4, 0x45, 0xa0, 0x55, 0x67, + 0x0f, 0x8d, 0x29, 0xc9, 0xc3, 0x5e, 0xac, 0xfb, 0x8a, 0x7a, 0x3f, 0xc1, 0x90, 0x68, 0x33, 0xbb, + 0xd0, 0xdb, 0x53, 0xf4, 0xf0, 0x3e, 0x91, 0x47, 0xdd, 0xba, 0x69, 0x03, 0x67, 0x1a, 0x83, 0xf1, + 0xae, 0x50, 0x9d, 0x9d, 0x93, 0xb3, 0x1b, 0xcb, 0xb7, 0x0a, 0x3d, 0xd4, 0xc7, 0xc5, 0xe8, 0x91, + 0x77, 0x14, 0x52, 0x96, 0x2c, 0x2c, 0x0c, 0x3b, 0x95, 0x9b, 0x93, 0xa3, 0xef, 0x90, 0xd3, 0x6b, + 0xff, 0x2e, 0x0c, 0xf2, 0x67, 0x4f, 0x79, 0xe6, 0x74, 0x28, 0x91, 0x1c, 0x0b, 0x7e, 0xff, 0x2d, + 0xdf, 0xeb, 0x70, 0xcc, 0x64, 0x2b, 0xde, 0xbc, 0xe7, 0xec, 0xd9, 0x49, 0xf2, 0xb0, 0x83, 0x55, + 0xcb, 0x01, 0xcb, 0x09, 0xb3, 0x67, 0xd0, 0x33, 0x03, 0xa5, 0x83, 0xe0, 0x7a, 0x3c, 0x23, 0x30, + 0xcb, 0xbb, 0x58, 0x2c, 0xe6, 0x7b, 0x82, 0x19, 0x07, 0xe4, 0x72, 0x50, 0xb5, 0x96, 0x84, 0x04, + 0x17, 0xf9, 0xfb, 0x14, 0x1e, 0x39, 0xc4, 0x7e, 0xd8, 0x01, 0x08, 0x4a, 0xde, 0x49, 0x66, 0x4f, + 0x41, 0x57, 0x43, 0x7d, 0x65, 0xf8, 0x75, 0x34, 0x90, 0x81, 0x21, 0x76, 0xda, 0x14, 0x51, 0x04, + 0xb1, 0xa9, 0x54, 0x3a, 0x30, 0x79, 0x87, 0xce, 0x1f, 0x36, 0xac, 0xfd, 0x4a, 0x7f, 0x9a, 0x70, + 0x42, 0xef, 0xfd, 0x99, 0x56, 0x61, 0x81, 0xe0, 0x80, 0x1b, 0xa2, 0x3e, 0xca, 0x7c, 0x7c, 0xcd, + 0x6f, 0xb7, 0xb8, 0x6f, 0xd3, 0x0a, 0x38, 0xbc, 0xe7, 0x0b, 0x04, 0xa8, 0x57, 0xca, 0xde, 0x3b, + 0xd2, 0x2b, 0x0c, 0xd4, 0x8f, 0x2c, 0xff, 0xf6, 0x34, 0xf2, 0xa6, 0x16, 0x6d, 0x39, 0xb1, 0x29, + 0x35, 0x45, 0x1f, 0xb9, 0x08, 0xf6, 0xbb, 0x72, 0xf2, 0x4e, 0x1d, 0x82, 0x4d, 0x9b, 0x64, 0xa1, + 0x0f, 0x35, 0x70, 0x60, 0xb8, 0xfe, 0xfb, 0xbb, 0x07, 0x7f, 0x21, 0xcf, 0x22, 0x29, 0x0b, 0xed, + 0xe4, 0x9d, 0xc4, 0xdc, 0xed, 0x23, 0xe0, 0xf0, 0x0e, 0x61, 0x3b, 0x77, 0x16, 0xf1, 0xdc, 0x79, + 0xc1, 0xa0, 0xe3, 0xa6, 0xea, 0x5b, 0xbf, 0xa0, 0x0a, 0x07, 0x67, 0x6b, 0x2f, 0x5f, 0x0c, 0xf1, + 0xae, 0x11, 0xc8, 0x45, 0x3b, 0x18, 0x77, 0x90, 0x5a, 0x43, 0x40, 0x18, 0xe2, 0x5d, 0x33, 0x64, + 0xb2, 0xa4, 0x2f, 0xe7, 0x43, 0x76, 0x48, 0xad, 0x21, 0x20, 0x0c, 0xf1, 0xce, 0x86, 0xb2, 0xb0, + 0x10, 0xd4, 0xad, 0x54, 0x10, 0xed, 0x51, 0x0c, 0xf1, 0xce, 0x06, 0x59, 0x47, 0x7b, 0xb4, 0x55, + 0x4f, 0x03, 0x2b, 0x7a, 0x1c, 0x41, 0x50, 0xf2, 0x10, 0xef, 0x1c, 0xc8, 0xd9, 0xe3, 0xa2, 0x8f, + 0xd6, 0x55, 0xe0, 0x3e, 0xc4, 0x3b, 0x2b, 0xf8, 0x3a, 0x8a, 0xc1, 0x84, 0x8e, 0xbc, 0xaf, 0x59, + 0xb5, 0x9c, 0xf0, 0xfc, 0x81, 0x66, 0x18, 0x87, 0xf7, 0xca, 0x6b, 0x3d, 0xae, 0x06, 0x53, 0x57, + 0x2c, 0x23, 0x28, 0x56, 0x47, 0xde, 0x01, 0xe9, 0x2b, 0x97, 0x2e, 0x6e, 0xa8, 0xaf, 0x27, 0xa8, + 0x92, 0x26, 0x18, 0x87, 0xf7, 0x77, 0x0f, 0xfe, 0x86, 0x04, 0x25, 0xdb, 0x7f, 0x49, 0x50, 0xac, + 0x2e, 0xbc, 0x47, 0x45, 0xfe, 0xeb, 0xeb, 0xe5, 0x59, 0x5b, 0x2b, 0x9a, 0x33, 0xe3, 0x0b, 0x82, + 0x2a, 0x69, 0x82, 0x71, 0x78, 0x47, 0x96, 0x40, 0x09, 0x73, 0x48, 0xd6, 0xb3, 0xd9, 0x2e, 0x3b, + 0xa0, 0xd8, 0xd2, 0xd3, 0x27, 0xd9, 0x53, 0xd2, 0x79, 0x1f, 0x3d, 0x62, 0x38, 0xbc, 0xd0, 0x54, + 0xd5, 0x50, 0x3d, 0x7c, 0xea, 0x0e, 0xe3, 0xf0, 0x8e, 0x0e, 0xd2, 0x8b, 0x9a, 0x38, 0x41, 0xc7, + 0x85, 0x79, 0x2a, 0x9e, 0x2f, 0x5b, 0x0c, 0xc5, 0xbe, 0xfe, 0xf1, 0x0a, 0x7b, 0x4a, 0x3a, 0xef, + 0xd4, 0x79, 0x9b, 0x33, 0xa7, 0x94, 0x2e, 0xe0, 0x6d, 0x66, 0x59, 0x07, 0x06, 0xf8, 0xed, 0xd9, + 0xb9, 0x63, 0xdf, 0x37, 0x7b, 0xbb, 0xbb, 0xbb, 0xe7, 0xce, 0xfc, 0xe2, 0xdc, 0x99, 0x30, 0x27, + 0xc7, 0x4d, 0x96, 0x13, 0xcc, 0x74, 0x57, 0xd5, 0x38, 0xbc, 0xcb, 0xa5, 0xdd, 0xe8, 0xf8, 0x0e, + 0x62, 0x9e, 0xd6, 0x65, 0x32, 0xd4, 0x3d, 0x6d, 0xce, 0x4c, 0x67, 0x4f, 0xab, 0xc6, 0xbb, 0xe7, + 0xa1, 0x03, 0x7f, 0xdc, 0xbd, 0x83, 0x7e, 0xc2, 0x22, 0xef, 0xba, 0x77, 0xb7, 0x42, 0xb5, 0xb5, + 0x1c, 0xfc, 0x2d, 0x12, 0x16, 0x42, 0xde, 0xc1, 0xf5, 0xad, 0x9b, 0x58, 0xc7, 0xed, 0xb0, 0xc3, + 0x68, 0xeb, 0xda, 0xa9, 0x2b, 0x97, 0xf5, 0xd4, 0xc5, 0x27, 0x8e, 0x11, 0x11, 0x58, 0x17, 0x15, + 0xd9, 0x33, 0xdf, 0x69, 0x65, 0xc1, 0x39, 0x1c, 0x53, 0xe3, 0x5d, 0xad, 0x6e, 0x31, 0xfb, 0xf4, + 0x93, 0xd2, 0x92, 0x92, 0x43, 0xee, 0xfb, 0x14, 0xbd, 0x2c, 0x9b, 0x0e, 0xef, 0xe8, 0x18, 0x82, + 0x17, 0x5f, 0xad, 0x24, 0x22, 0x50, 0xe8, 0xeb, 0x05, 0x05, 0x66, 0x53, 0x36, 0x8c, 0x6b, 0xc2, + 0x20, 0xed, 0xbf, 0x03, 0xb4, 0xe4, 0x66, 0xa3, 0xb9, 0x49, 0x51, 0xc4, 0x3f, 0x3a, 0x4a, 0xeb, + 0x7c, 0xf7, 0x16, 0xcd, 0xef, 0xbf, 0xba, 0x72, 0x91, 0x33, 0xfd, 0xe0, 0xe5, 0x1d, 0x20, 0x7b, + 0xe7, 0xf6, 0x9e, 0x22, 0xbf, 0x4e, 0xd7, 0x25, 0x37, 0x74, 0x54, 0x9c, 0xb2, 0x83, 0x24, 0xe7, + 0x9e, 0xf3, 0x19, 0xd4, 0xbc, 0xd7, 0x3e, 0x8e, 0xe8, 0x9b, 0x8e, 0xd7, 0x61, 0x2b, 0xc5, 0xeb, + 0x1f, 0x2e, 0x23, 0x39, 0xa5, 0x27, 0xb9, 0x0f, 0x45, 0x54, 0x0c, 0x72, 0xde, 0x15, 0x4a, 0xdb, + 0xab, 0xbe, 0xf3, 0x34, 0x2a, 0xce, 0x9f, 0xd5, 0x42, 0x42, 0x7d, 0x42, 0x1c, 0x5a, 0xc6, 0x4a, + 0xc7, 0x73, 0xed, 0xa1, 0x18, 0xe2, 0x5d, 0xde, 0xd9, 0x99, 0xb2, 0xc8, 0x1e, 0x51, 0x5f, 0x76, + 0x9a, 0xdf, 0x39, 0x26, 0x6f, 0xff, 0xba, 0x87, 0x36, 0xdb, 0x81, 0x6e, 0x4c, 0x5b, 0x91, 0x90, + 0xf3, 0x16, 0x6a, 0x3f, 0x9d, 0xac, 0x27, 0x2e, 0x5e, 0x30, 0xbe, 0x7d, 0x64, 0x5b, 0x71, 0x51, + 0xdc, 0xf4, 0xa9, 0x88, 0x7a, 0xd0, 0x2d, 0x91, 0x62, 0x9c, 0xe0, 0x01, 0x46, 0x5b, 0xc5, 0xc7, + 0x02, 0xd0, 0x5d, 0x4f, 0xc7, 0x9b, 0xd5, 0xdc, 0xfe, 0x15, 0x27, 0x3b, 0x30, 0xec, 0x44, 0xbc, + 0x93, 0x3d, 0xba, 0x99, 0x17, 0x8c, 0xcf, 0x3b, 0x40, 0x73, 0x66, 0x46, 0xfc, 0x2c, 0x6b, 0xaa, + 0x99, 0x0d, 0xe0, 0x54, 0x93, 0x91, 0x93, 0xac, 0x5d, 0x52, 0x76, 0x26, 0x14, 0x1d, 0x26, 0x01, + 0x6d, 0x43, 0x2a, 0xaf, 0xf3, 0x38, 0x75, 0x06, 0x92, 0x8e, 0x0e, 0x35, 0x30, 0x0a, 0xfa, 0x05, + 0xef, 0x00, 0x1d, 0x35, 0xd5, 0x68, 0xbb, 0x22, 0x0a, 0xa0, 0x9f, 0x03, 0xba, 0xf9, 0xa5, 0xa7, + 0x43, 0x2a, 0x2e, 0x5d, 0x28, 0x0b, 0x0b, 0x29, 0x3e, 0xea, 0x9b, 0xb5, 0x63, 0x5b, 0x94, 0xa5, + 0x39, 0x35, 0x4d, 0x92, 0xad, 0x4d, 0x7d, 0x7c, 0x2c, 0xaf, 0xbc, 0x04, 0x79, 0x79, 0x80, 0x77, + 0xa9, 0x94, 0x9f, 0x05, 0x2f, 0x59, 0xf4, 0x17, 0xde, 0x21, 0x4a, 0x82, 0x03, 0xa3, 0x27, 0x59, + 0xaa, 0xb1, 0xaf, 0x29, 0x80, 0xba, 0x05, 0xbc, 0x09, 0x59, 0x47, 0x87, 0x16, 0x19, 0xe1, 0x58, + 0xb9, 0xea, 0x15, 0xfd, 0x8b, 0x77, 0x00, 0x50, 0xb9, 0x17, 0x07, 0xfa, 0x51, 0xab, 0x11, 0x7a, + 0x88, 0xb3, 0x9e, 0x2e, 0x0c, 0xf0, 0xa9, 0xcb, 0x17, 0xe8, 0xef, 0xf0, 0x55, 0x89, 0x44, 0xa2, + 0xd7, 0xc7, 0xec, 0x77, 0xbc, 0x23, 0xb4, 0x64, 0xbf, 0x2c, 0x3d, 0x79, 0x4c, 0xe8, 0xe7, 0x95, + 0xbd, 0xdb, 0x39, 0xdd, 0x61, 0x6d, 0xd6, 0xce, 0xed, 0x85, 0x5e, 0x87, 0x41, 0xbd, 0xaf, 0x3c, + 0xb8, 0x83, 0xdc, 0x14, 0xa6, 0xb1, 0xd0, 0x7f, 0x79, 0x1f, 0x82, 0xee, 0x00, 0x95, 0x70, 0xab, + 0xb0, 0xe0, 0xdd, 0xfd, 0xbf, 0x4a, 0x4f, 0x9f, 0x04, 0xb5, 0x88, 0xd0, 0xdf, 0x27, 0xff, 0xe0, + 0xbe, 0xdc, 0xbd, 0xbb, 0x40, 0x33, 0x99, 0xb1, 0xd1, 0x21, 0xc3, 0x71, 0x03, 0x28, 0xcd, 0xb9, + 0xae, 0x7b, 0x0a, 0x3c, 0x0f, 0x81, 0x1a, 0x1b, 0x0c, 0x5d, 0x2b, 0x2e, 0x9c, 0xad, 0x8f, 0x89, + 0x6a, 0x7f, 0xfd, 0x8a, 0xac, 0x9d, 0x47, 0xff, 0xc1, 0x50, 0x71, 0x67, 0x86, 0x5c, 0x2e, 0x97, + 0x0e, 0x40, 0x74, 0xb7, 0x4b, 0xea, 0xe2, 0x63, 0x41, 0xef, 0x24, 0xdf, 0xe3, 0x40, 0xca, 0xe2, + 0x85, 0x51, 0x16, 0xe6, 0x98, 0x7d, 0x14, 0xb5, 0x10, 0x33, 0x65, 0x52, 0xfa, 0xfa, 0x35, 0x42, + 0x7f, 0xef, 0xf2, 0xb3, 0xa7, 0x5b, 0x0b, 0x89, 0x39, 0x7f, 0x31, 0x3a, 0x86, 0x8a, 0x3b, 0x79, + 0x78, 0x1c, 0x74, 0x0f, 0x3d, 0x19, 0x6c, 0xc8, 0x1c, 0xdb, 0x2b, 0x5f, 0x83, 0x91, 0xa4, 0xc0, + 0xdd, 0x2d, 0xee, 0x8b, 0xa9, 0xda, 0x95, 0x6f, 0xf6, 0x90, 0xb4, 0x60, 0x3e, 0xe8, 0xde, 0x54, + 0x85, 0x5f, 0x27, 0x78, 0xae, 0x8c, 0x51, 0x30, 0x54, 0xdc, 0x09, 0x63, 0xcb, 0x26, 0x07, 0x38, + 0x09, 0x71, 0x60, 0x9f, 0xab, 0xbe, 0xf3, 0x02, 0x03, 0x9d, 0x57, 0x97, 0x2e, 0x08, 0xdc, 0x5d, + 0xa3, 0xad, 0x2c, 0x58, 0xc7, 0x3a, 0xd3, 0x52, 0x57, 0x2c, 0x15, 0x1c, 0x70, 0xeb, 0xd9, 0xe3, + 0x19, 0x72, 0xbc, 0xec, 0xdb, 0x53, 0x15, 0x17, 0xbf, 0xcb, 0x50, 0x4d, 0x04, 0x94, 0x9c, 0x08, + 0x52, 0xf6, 0x73, 0x40, 0x67, 0x7d, 0xd7, 0xce, 0x67, 0x0b, 0xed, 0xd8, 0x07, 0xad, 0xf1, 0x33, + 0xad, 0x41, 0x4a, 0xd0, 0x3b, 0xe2, 0xbb, 0x59, 0xb7, 0x9f, 0x60, 0xa8, 0xb8, 0x13, 0x03, 0xe8, + 0xff, 0x2c, 0xb2, 0xb3, 0xa5, 0xce, 0x31, 0x73, 0x6e, 0x72, 0xd6, 0x1a, 0xed, 0x55, 0x95, 0x60, + 0xf8, 0x98, 0xb2, 0xe8, 0xbf, 0x8c, 0x85, 0x12, 0x94, 0xfe, 0x8c, 0x8d, 0xeb, 0x41, 0x21, 0xae, + 0xb9, 0x7d, 0x93, 0x65, 0x83, 0xc1, 0x0f, 0x57, 0xaf, 0xd0, 0x0f, 0x45, 0x90, 0x77, 0x77, 0xb5, + 0xe4, 0x64, 0x55, 0x5c, 0x3c, 0x5f, 0xe4, 0xef, 0xfd, 0x7c, 0xd9, 0x62, 0x64, 0xf2, 0xa1, 0x36, + 0x3b, 0x93, 0xb5, 0x7d, 0x6b, 0xf9, 0xb9, 0x30, 0x69, 0x6b, 0xab, 0x9e, 0x1e, 0x50, 0x4f, 0x18, + 0x2a, 0xee, 0x64, 0xd0, 0xd1, 0xde, 0x8e, 0xfc, 0x27, 0x50, 0x83, 0xbd, 0xed, 0x3c, 0xb2, 0x1b, + 0x06, 0xbb, 0x1a, 0xea, 0x8b, 0x8f, 0x1f, 0x4d, 0xee, 0xdd, 0xb6, 0xf1, 0x5e, 0x87, 0x7b, 0xb2, + 0x55, 0xfe, 0xa1, 0xfd, 0x15, 0xe7, 0xcf, 0x62, 0xba, 0xa8, 0xbf, 0x7a, 0xe5, 0x72, 0x37, 0xd7, + 0x19, 0x20, 0xe2, 0xfc, 0xbc, 0x92, 0xe0, 0xa0, 0x2c, 0xa7, 0x2d, 0xa8, 0xdc, 0x3f, 0x36, 0x1b, + 0xf3, 0xc4, 0x6c, 0x0c, 0xbc, 0xce, 0x74, 0xdc, 0x58, 0x71, 0xe1, 0x9c, 0xee, 0x8e, 0x78, 0x0c, + 0x86, 0xa1, 0xe2, 0x4e, 0x00, 0xf5, 0xf5, 0x75, 0xe6, 0x63, 0x47, 0xd3, 0xcb, 0x3a, 0xf2, 0xda, + 0x22, 0x91, 0xb4, 0x11, 0xc9, 0xa8, 0x2a, 0xfc, 0xda, 0xcb, 0x6d, 0x8e, 0xf4, 0x82, 0x9e, 0xb2, + 0xd0, 0x1e, 0x54, 0xf6, 0x92, 0xb2, 0x52, 0x5e, 0xd2, 0x94, 0xc5, 0x9d, 0x72, 0x3c, 0x02, 0x23, + 0xda, 0x25, 0x92, 0xc7, 0x8f, 0x22, 0x5c, 0xf7, 0xee, 0x1e, 0xff, 0xe9, 0x27, 0xf0, 0x71, 0x56, + 0x8c, 0x18, 0xfe, 0x5e, 0x4d, 0x3f, 0x61, 0x5c, 0x81, 0xe7, 0xc1, 0x86, 0xc4, 0x78, 0x1d, 0x1e, + 0xcb, 0x70, 0x18, 0x2a, 0xee, 0xe4, 0x71, 0xec, 0x68, 0xc0, 0x65, 0xd5, 0x11, 0xc6, 0x04, 0xd1, + 0xdd, 0xd8, 0x50, 0x1c, 0xe4, 0x1f, 0x3b, 0x6d, 0x8a, 0x5a, 0x41, 0x4f, 0xb6, 0xb3, 0x2d, 0x39, + 0x1e, 0x08, 0xaa, 0x7c, 0x4c, 0x39, 0x62, 0xb1, 0xd8, 0xdb, 0xd3, 0x23, 0xf2, 0xc9, 0xe3, 0xa4, + 0x84, 0xf8, 0xb9, 0x33, 0xad, 0x37, 0xae, 0x5f, 0x9b, 0x18, 0xaf, 0x7e, 0x12, 0x76, 0x79, 0x59, + 0x99, 0xc5, 0xb8, 0x31, 0x9a, 0xbe, 0xde, 0x27, 0xae, 0x7b, 0x18, 0xd4, 0xb0, 0x5f, 0xa0, 0x34, + 0x46, 0xe8, 0xf7, 0x1d, 0xfa, 0xa1, 0xe2, 0x4e, 0x1e, 0xc4, 0x8b, 0x7b, 0x5b, 0x71, 0x91, 0xd0, + 0xf7, 0x88, 0x5a, 0x37, 0x3a, 0xca, 0xc2, 0x5c, 0xe8, 0xeb, 0x25, 0xce, 0xcb, 0xe5, 0x25, 0x4a, + 0x24, 0x12, 0xc1, 0x52, 0xeb, 0xf6, 0xf5, 0x9e, 0x53, 0x21, 0x27, 0x9f, 0x25, 0x27, 0xfd, 0x7f, + 0x7b, 0x67, 0xe2, 0xd5, 0xc4, 0xb5, 0x06, 0xf0, 0xf7, 0x5f, 0xb4, 0xa7, 0x9e, 0x67, 0x6b, 0x6d, + 0xd5, 0x08, 0x22, 0x28, 0x22, 0x22, 0x8a, 0x88, 0x28, 0x22, 0xd5, 0xd7, 0xba, 0x80, 0xa2, 0xd6, + 0xdd, 0xa2, 0x80, 0x82, 0x82, 0x10, 0x08, 0x61, 0x71, 0x17, 0xc5, 0x15, 0x50, 0x5a, 0xdc, 0xb1, + 0xd6, 0x56, 0xc5, 0xad, 0x56, 0xb6, 0x10, 0x90, 0xdd, 0x05, 0x42, 0x02, 0x24, 0x10, 0x56, 0x45, + 0x40, 0x90, 0x35, 0x10, 0x48, 0xe0, 0x7d, 0x71, 0x34, 0x0d, 0x93, 0x41, 0x43, 0xe6, 0x4e, 0x12, + 0xc8, 0xfc, 0xce, 0x3d, 0x9e, 0x6c, 0xde, 0xf9, 0xa2, 0xbf, 0xb9, 0xb9, 0x77, 0xe6, 0xde, 0xfb, + 0x75, 0x0e, 0xd1, 0xff, 0xe6, 0x15, 0x15, 0x5a, 0x4c, 0x99, 0x8c, 0x73, 0xdd, 0x63, 0xab, 0x22, + 0xb9, 0x38, 0x0c, 0x55, 0x8b, 0xbd, 0x76, 0xe0, 0x8c, 0x4f, 0xb3, 0xb4, 0x80, 0x13, 0xd2, 0xc0, + 0x2f, 0xdd, 0xd0, 0xba, 0xa3, 0x07, 0xad, 0xee, 0x5d, 0xe5, 0x22, 0x65, 0xba, 0x70, 0x65, 0xc9, + 0xb0, 0xb3, 0x2d, 0x3f, 0x18, 0xd1, 0x3f, 0xfc, 0xec, 0x7b, 0x98, 0xee, 0xd8, 0x2c, 0xb9, 0xd8, + 0x98, 0x68, 0xd9, 0xd0, 0x73, 0x29, 0xa4, 0x52, 0xe9, 0xda, 0xd5, 0xae, 0xe0, 0xf7, 0x3c, 0xdb, + 0x59, 0x4a, 0xdd, 0x85, 0x1f, 0x27, 0x84, 0x49, 0x1b, 0x1b, 0x44, 0xa1, 0xc1, 0xb8, 0xcb, 0x38, + 0xf0, 0x14, 0xc6, 0xc7, 0x1a, 0xcd, 0x7a, 0xd2, 0x13, 0xb4, 0xee, 0xe8, 0x41, 0xa8, 0x3b, 0xf4, + 0x61, 0x84, 0xa1, 0xc1, 0xb8, 0x76, 0x3d, 0x6b, 0xd1, 0x02, 0x18, 0x20, 0x6a, 0x57, 0x21, 0xa6, + 0xfb, 0xc6, 0x75, 0xee, 0xf0, 0x38, 0x26, 0xfa, 0xdc, 0x50, 0xc3, 0x68, 0xdf, 0x5d, 0x5e, 0xee, + 0xae, 0x2b, 0xa5, 0x1f, 0x77, 0x4a, 0x69, 0x6f, 0x6f, 0x5f, 0xf1, 0xe3, 0x52, 0x4f, 0x8f, 0xed, + 0xaa, 0x9f, 0x91, 0x4b, 0x7b, 0x60, 0xc0, 0x80, 0xeb, 0xd8, 0x70, 0x66, 0x5a, 0x2a, 0xb6, 0xa8, + 0x35, 0xd4, 0xe9, 0x06, 0xb4, 0xee, 0xe8, 0x41, 0xa8, 0xbb, 0xf8, 0xe8, 0x41, 0xae, 0xad, 0x8d, + 0xaa, 0x4f, 0xdc, 0x39, 0xb3, 0xe1, 0x45, 0xad, 0x2b, 0xfc, 0xac, 0xee, 0x51, 0x91, 0xc7, 0x16, + 0x39, 0xd8, 0xb7, 0xb5, 0xb6, 0x6a, 0x52, 0x9b, 0x5c, 0x22, 0x11, 0x86, 0xb2, 0x70, 0xd3, 0xf6, + 0x72, 0x97, 0xb9, 0xbc, 0x4a, 0xb8, 0xaa, 0x75, 0x84, 0x94, 0x42, 0xeb, 0x8e, 0x1e, 0x54, 0xba, + 0xb7, 0x17, 0xbe, 0xe0, 0x79, 0x0f, 0xea, 0x22, 0x27, 0x31, 0x26, 0x82, 0x5e, 0x7d, 0x6d, 0x1a, + 0xb9, 0x48, 0xc8, 0x27, 0x74, 0xbf, 0x79, 0x23, 0xc1, 0xda, 0xd2, 0xa2, 0xb6, 0xb6, 0x66, 0x58, + 0x15, 0x76, 0x96, 0x0a, 0x4a, 0xfc, 0x7c, 0x71, 0x7d, 0x2d, 0x61, 0x08, 0x13, 0xed, 0x66, 0xad, + 0xa8, 0xa0, 0x75, 0x47, 0x0f, 0x2a, 0xdd, 0xc5, 0x91, 0x47, 0x70, 0x9b, 0x6f, 0xe6, 0x2f, 0xff, + 0xdf, 0x9b, 0xbb, 0xb7, 0xc9, 0xd7, 0x8c, 0x11, 0x7d, 0xee, 0x2c, 0x96, 0xac, 0x87, 0xcb, 0xe1, + 0x4c, 0x9b, 0x62, 0x52, 0xcc, 0x1b, 0xde, 0xa8, 0x57, 0x49, 0xe5, 0xa9, 0x13, 0xca, 0x2c, 0x3f, + 0x58, 0xc9, 0xf9, 0x61, 0x49, 0xfd, 0xad, 0x9b, 0xa8, 0xe2, 0x44, 0x08, 0xad, 0x3b, 0x7a, 0x90, + 0xe8, 0x2e, 0x6b, 0x6f, 0x57, 0x2e, 0xea, 0x55, 0x96, 0xd2, 0xe0, 0x00, 0x24, 0x59, 0x01, 0xa1, + 0x51, 0x9f, 0x35, 0x63, 0x9a, 0xe9, 0xc4, 0xef, 0x2c, 0xa7, 0x4e, 0x31, 0x37, 0x65, 0xa4, 0xa5, + 0xa6, 0x90, 0xa9, 0xad, 0xed, 0x59, 0x7e, 0xe1, 0xc7, 0x2d, 0x84, 0x94, 0x37, 0xbc, 0x44, 0xd4, + 0x6f, 0xca, 0xac, 0x05, 0xb4, 0xee, 0xe8, 0x41, 0xa2, 0xbb, 0xa4, 0xb2, 0xa2, 0x64, 0x9f, 0xdf, + 0xa0, 0x9e, 0x8c, 0x09, 0x43, 0x14, 0xc6, 0x22, 0x1f, 0x5e, 0x4d, 0x75, 0x95, 0xea, 0x0d, 0x60, + 0x90, 0x3e, 0xf2, 0xd8, 0x91, 0x4b, 0x17, 0xe3, 0xb5, 0x2e, 0x7f, 0x9c, 0x8f, 0xe1, 0x07, 0xf8, + 0xe1, 0xce, 0x4c, 0xad, 0xd7, 0x80, 0x50, 0x0a, 0xad, 0x3b, 0x7a, 0x90, 0xe8, 0xde, 0x51, 0x5c, + 0x54, 0xec, 0xbd, 0x73, 0xd0, 0x85, 0xed, 0xe9, 0x16, 0xa8, 0xf2, 0x26, 0x43, 0x1f, 0x66, 0xb6, + 0x95, 0x25, 0x48, 0x0f, 0x7f, 0x92, 0x9f, 0xe3, 0x20, 0xeb, 0xea, 0x14, 0xaa, 0x64, 0x3a, 0xf9, + 0xd0, 0x7d, 0x67, 0x07, 0x69, 0x7e, 0xf3, 0x4b, 0x67, 0xd0, 0xba, 0xa3, 0x07, 0x8d, 0xee, 0x3c, + 0xd0, 0x7d, 0xd0, 0x38, 0x35, 0xcd, 0xd2, 0xa2, 0xfc, 0x20, 0xb2, 0x34, 0xe1, 0x08, 0x91, 0x4b, + 0xba, 0xd4, 0xfb, 0x5d, 0x30, 0x5a, 0xed, 0x55, 0xcb, 0xfa, 0xa9, 0x77, 0x68, 0xdd, 0xd1, 0x83, + 0x4e, 0xf7, 0x9d, 0x23, 0x44, 0x77, 0x89, 0xba, 0xee, 0x65, 0x21, 0x41, 0xb4, 0xee, 0x46, 0x01, + 0x55, 0x9d, 0x19, 0x83, 0xd5, 0xbd, 0x7b, 0x08, 0xdd, 0xdf, 0x36, 0xe9, 0x3b, 0x34, 0x3c, 0xb4, + 0xee, 0xe8, 0x31, 0x3e, 0xdd, 0xbb, 0x09, 0x74, 0x67, 0xd1, 0xba, 0x93, 0xe3, 0x55, 0x5d, 0xdd, + 0x37, 0x63, 0xbe, 0x84, 0x02, 0x03, 0xac, 0x7e, 0x43, 0xbd, 0x4d, 0x3d, 0x60, 0x84, 0xba, 0xf7, + 0x74, 0xab, 0x0f, 0x55, 0xcb, 0x58, 0xcc, 0xde, 0xa6, 0x21, 0x93, 0x84, 0xea, 0x8b, 0x11, 0xa3, + 0x3b, 0xf8, 0x6d, 0x3b, 0x73, 0x06, 0x88, 0x5e, 0x53, 0x53, 0x0d, 0xc6, 0x6f, 0x5a, 0x8f, 0x2c, + 0x89, 0x3b, 0x72, 0x28, 0xd4, 0x1d, 0xd1, 0x95, 0x19, 0xb4, 0xc8, 0x7b, 0x7a, 0x44, 0x04, 0x9d, + 0x19, 0xa6, 0x94, 0xd6, 0x5d, 0x6b, 0xbc, 0x77, 0x7a, 0x7c, 0xfd, 0xd5, 0x17, 0xf9, 0xb9, 0xb9, + 0xf0, 0xf8, 0xf2, 0xc5, 0x78, 0x78, 0x7c, 0xf4, 0xb0, 0xf6, 0x53, 0x47, 0x28, 0xc5, 0xf0, 0x2f, + 0x44, 0xa2, 0x45, 0x31, 0x57, 0x8c, 0x50, 0x77, 0xc3, 0x9b, 0x47, 0x30, 0x32, 0x74, 0xbf, 0x72, + 0xe9, 0x22, 0xf8, 0x7d, 0xfa, 0xe4, 0x09, 0xe5, 0x2b, 0x3b, 0xb6, 0x6f, 0x85, 0x57, 0xee, 0x27, + 0xde, 0xd5, 0x63, 0x54, 0x43, 0x61, 0x6c, 0xba, 0xf7, 0x4b, 0xa5, 0x04, 0xba, 0xb3, 0x68, 0xdd, + 0xb5, 0x42, 0x35, 0x51, 0x24, 0xae, 0x40, 0xaf, 0x46, 0x39, 0x03, 0xdb, 0x79, 0xa1, 0xc3, 0x62, + 0xc7, 0xf9, 0x87, 0x0f, 0x44, 0xb8, 0xbb, 0xae, 0x74, 0x71, 0x5a, 0xb8, 0x6e, 0x8d, 0xeb, 0x99, + 0x53, 0x51, 0x0b, 0xe7, 0xcf, 0x0b, 0x0b, 0x51, 0x64, 0xc6, 0x49, 0x49, 0x4e, 0xb2, 0xb6, 0xb4, + 0x88, 0x8a, 0x3c, 0x76, 0x20, 0x3c, 0xcc, 0x8c, 0x31, 0xe1, 0xd1, 0xc3, 0x07, 0xf0, 0xe2, 0xb6, + 0xcd, 0x1b, 0xf7, 0xec, 0xf6, 0x86, 0x07, 0x21, 0x41, 0x81, 0x9b, 0x7f, 0x5e, 0x87, 0x2a, 0x60, + 0x64, 0xba, 0xef, 0x1a, 0xd1, 0xba, 0x07, 0x6a, 0xb8, 0x64, 0x56, 0x97, 0x18, 0xba, 0xee, 0x52, + 0xa9, 0x74, 0xaa, 0xc9, 0xa4, 0x09, 0xe3, 0xc6, 0xb6, 0xb7, 0xb7, 0xe3, 0xde, 0x12, 0x57, 0x54, + 0x80, 0xee, 0x53, 0x26, 0x7d, 0x8f, 0xad, 0x04, 0x05, 0xdd, 0x93, 0xfe, 0x79, 0x0c, 0x0f, 0x7a, + 0x7b, 0x7b, 0xe1, 0x4c, 0x68, 0x7b, 0xbf, 0xac, 0x26, 0x3b, 0xeb, 0x29, 0x18, 0x0f, 0x0f, 0xe0, + 0x33, 0xf1, 0x71, 0x17, 0xe0, 0x37, 0xc1, 0x71, 0xde, 0x5c, 0xa8, 0x90, 0xc5, 0x0c, 0xc0, 0x2a, + 0x81, 0xdf, 0x07, 0xf8, 0x30, 0x66, 0x3f, 0x2a, 0x10, 0xe9, 0xce, 0x1b, 0x31, 0xba, 0xf7, 0x4a, + 0x45, 0x04, 0x43, 0x55, 0x5a, 0xf7, 0xe1, 0xb3, 0x76, 0xb5, 0x2b, 0xe8, 0x98, 0xfc, 0xe4, 0x1f, + 0xc2, 0x77, 0xff, 0xfc, 0xe3, 0x26, 0xbc, 0xeb, 0xe2, 0xe4, 0x38, 0xf0, 0x5e, 0x77, 0x2e, 0x47, + 0xb1, 0xec, 0x12, 0xd3, 0xbd, 0xe3, 0xfd, 0x9a, 0x1a, 0xa5, 0xee, 0xb3, 0x66, 0x4c, 0x7b, 0x78, + 0x5f, 0x91, 0x47, 0xba, 0xf5, 0xdd, 0xbb, 0x79, 0xb6, 0xb3, 0xb0, 0x46, 0xfd, 0xea, 0xe5, 0x4b, + 0x8b, 0x1c, 0xec, 0xbb, 0x25, 0x12, 0xa8, 0xe1, 0xb7, 0xb8, 0xf3, 0xa8, 0x62, 0x36, 0x3e, 0xdd, + 0x7b, 0x89, 0x74, 0x67, 0x52, 0x9d, 0x33, 0x5d, 0x0b, 0x0c, 0x5d, 0x77, 0x84, 0x40, 0x03, 0xdf, + 0xa4, 0x93, 0x6b, 0x05, 0x46, 0xa7, 0x7b, 0x5f, 0x2f, 0x71, 0x67, 0x86, 0xd6, 0xdd, 0x18, 0x30, + 0x3e, 0xdd, 0xfb, 0x08, 0x75, 0xef, 0xa9, 0x7f, 0xad, 0xef, 0xd0, 0xf0, 0xd0, 0xba, 0xa3, 0x47, + 0xa1, 0xfb, 0xd9, 0x33, 0x24, 0x2b, 0x51, 0xd7, 0x3d, 0xd5, 0x60, 0x75, 0x97, 0x11, 0xe9, 0x1e, + 0x4c, 0xeb, 0x6e, 0x1c, 0xe8, 0x45, 0x77, 0xb9, 0x5c, 0xae, 0x5c, 0x49, 0x4d, 0x05, 0xdd, 0x43, + 0xef, 0x78, 0xdf, 0x2f, 0x93, 0x11, 0xe9, 0x8e, 0x66, 0x25, 0x0a, 0x5a, 0x68, 0xdd, 0xd1, 0x83, + 0x4e, 0x77, 0xcf, 0xcf, 0xea, 0xce, 0x2b, 0x2a, 0x5a, 0xb3, 0x6a, 0x05, 0x76, 0x59, 0x56, 0xc0, + 0xe7, 0x93, 0x3c, 0xe8, 0x27, 0x70, 0x77, 0x5b, 0x05, 0x87, 0x30, 0x37, 0x65, 0xc4, 0xff, 0x1a, + 0x87, 0xdf, 0x59, 0x52, 0x2e, 0x23, 0x98, 0x33, 0x43, 0xeb, 0x6e, 0x24, 0xa0, 0xd1, 0x9d, 0x3f, + 0xa4, 0xee, 0x6d, 0xad, 0xad, 0x87, 0xf6, 0x87, 0x4f, 0x18, 0x37, 0x16, 0x77, 0x17, 0x42, 0x07, + 0xba, 0xab, 0x96, 0xa5, 0xce, 0x4e, 0x39, 0xd9, 0x59, 0x8a, 0xf7, 0xe4, 0x72, 0x02, 0xdd, 0x83, + 0x02, 0x7a, 0x5e, 0xd5, 0x51, 0x17, 0x8f, 0x76, 0xd0, 0xba, 0xa3, 0x87, 0x3a, 0xdd, 0x85, 0x11, + 0x6c, 0x75, 0xed, 0x94, 0x65, 0xbd, 0xbb, 0x9b, 0xa7, 0xc7, 0x76, 0x8a, 0xca, 0x74, 0x33, 0x53, + 0xc2, 0x83, 0x42, 0x7b, 0x7f, 0xf5, 0x62, 0x3c, 0xad, 0xbb, 0xf1, 0x42, 0x75, 0xeb, 0x3e, 0xf0, + 0xbe, 0xa7, 0x7e, 0xf3, 0x46, 0xc2, 0xcc, 0xe9, 0xe6, 0x7a, 0x69, 0xdd, 0xbf, 0x19, 0xf3, 0xa5, + 0xaf, 0xb7, 0xe7, 0xab, 0xba, 0x7f, 0x6d, 0x16, 0x85, 0xb1, 0x92, 0x4d, 0x27, 0xab, 0x46, 0x5b, + 0xe2, 0xbf, 0x57, 0x22, 0x2e, 0xa7, 0x2e, 0x1e, 0xed, 0xa0, 0x75, 0x47, 0x0f, 0x95, 0xba, 0x87, + 0xa9, 0x7f, 0xb2, 0xb9, 0xf9, 0x6d, 0x28, 0x2b, 0x68, 0xfc, 0xd8, 0x31, 0x9a, 0xe8, 0x0e, 0xe7, + 0xc9, 0xed, 0xbf, 0x6e, 0x6d, 0xdf, 0xb2, 0x71, 0xc9, 0xa2, 0x05, 0x9b, 0xd6, 0xaf, 0x3d, 0x7c, + 0x20, 0x42, 0xc3, 0x84, 0x9b, 0xa0, 0xbb, 0xd3, 0x82, 0xf9, 0xd8, 0x8d, 0x3c, 0x75, 0xca, 0x0f, + 0x86, 0xe3, 0xb6, 0x13, 0x2b, 0xdc, 0xbe, 0xa5, 0xb5, 0x20, 0x4f, 0x93, 0x9a, 0x75, 0x09, 0xad, + 0x3b, 0x7a, 0x28, 0xd3, 0xdd, 0x9c, 0x50, 0x77, 0xcd, 0x69, 0x6a, 0x6a, 0x84, 0x86, 0x79, 0xdb, + 0xe6, 0x8d, 0xca, 0x57, 0x92, 0x93, 0x9e, 0x40, 0x6b, 0xed, 0xe7, 0xbb, 0x9b, 0x64, 0xb4, 0xf5, + 0xb7, 0x6e, 0xe6, 0x2c, 0x5d, 0xa2, 0x1a, 0x6d, 0xe6, 0x02, 0x7b, 0x4d, 0x72, 0xc7, 0xeb, 0x18, + 0x5a, 0x77, 0xf4, 0x18, 0xac, 0xee, 0x80, 0xfd, 0x1c, 0x1b, 0xf0, 0xdb, 0x76, 0xe6, 0x8c, 0x90, + 0xa0, 0x40, 0x68, 0xaa, 0x3f, 0xbb, 0xbf, 0xbb, 0x86, 0x48, 0x2a, 0xc5, 0xa5, 0x4c, 0x7f, 0x82, + 0x4b, 0xef, 0x06, 0x76, 0x71, 0x86, 0xd6, 0x1d, 0x3d, 0x86, 0xac, 0xfb, 0x87, 0xca, 0x3b, 0x3a, + 0xee, 0xdd, 0xbd, 0xb3, 0x63, 0xdb, 0x16, 0xc6, 0x77, 0xdf, 0x82, 0xfd, 0x8b, 0x1d, 0xe7, 0x93, + 0xaf, 0xb3, 0x2a, 0xfa, 0x4c, 0xa6, 0xc3, 0x3c, 0xd5, 0x80, 0xd3, 0x6d, 0xac, 0x2b, 0x0e, 0xed, + 0x27, 0x5f, 0x33, 0x42, 0x68, 0xdd, 0xd1, 0xb3, 0x3f, 0x2c, 0x14, 0x85, 0xee, 0xc5, 0xc8, 0x75, + 0x7f, 0x70, 0x2f, 0x11, 0xe4, 0x0e, 0x63, 0x0f, 0xda, 0x9b, 0x69, 0xdd, 0x1a, 0xc5, 0x24, 0x3c, + 0x71, 0xc5, 0xf0, 0x32, 0x7f, 0xa8, 0x23, 0xeb, 0x68, 0x17, 0xc2, 0x80, 0xd5, 0x84, 0xa1, 0x1a, + 0x73, 0xce, 0x0f, 0xce, 0xd5, 0x17, 0x62, 0x48, 0xd6, 0x8c, 0x10, 0x5a, 0x77, 0xf4, 0x18, 0xac, + 0xee, 0x03, 0xef, 0xb7, 0x10, 0xdb, 0xb0, 0x76, 0x0d, 0xf4, 0xe0, 0xb1, 0x6b, 0x2c, 0x26, 0x13, + 0xc6, 0xfb, 0xee, 0xf2, 0x6a, 0x43, 0x94, 0x83, 0xa0, 0x43, 0x50, 0x5c, 0x12, 0xb0, 0x17, 0xd7, + 0xa5, 0xc9, 0x71, 0x59, 0x5c, 0x75, 0x3a, 0x6a, 0x60, 0xc0, 0x20, 0xd6, 0x16, 0xd3, 0xba, 0xa3, + 0xc7, 0x90, 0x75, 0xa7, 0x9a, 0xf6, 0x97, 0xcf, 0x05, 0x7e, 0x3e, 0x38, 0xe3, 0x39, 0xd6, 0x56, + 0xa2, 0xf0, 0x10, 0x43, 0xd8, 0x76, 0x86, 0xd6, 0x1d, 0x3d, 0xc8, 0x74, 0xdf, 0x3d, 0xf2, 0x74, + 0x07, 0xba, 0x6b, 0xaa, 0x85, 0xec, 0x20, 0xf5, 0x84, 0xdd, 0x45, 0xbf, 0x6c, 0xad, 0x8d, 0x8f, + 0x1b, 0xe8, 0xd7, 0x67, 0xfa, 0x79, 0x5a, 0x77, 0x04, 0xe0, 0x32, 0xca, 0x87, 0xb3, 0x43, 0xce, + 0x9d, 0x3e, 0xa5, 0xfa, 0x8a, 0x16, 0x75, 0x12, 0xe8, 0x3e, 0xcd, 0xbc, 0xdc, 0x20, 0xb7, 0xd5, + 0x55, 0x47, 0xde, 0xd3, 0x53, 0x71, 0xf8, 0xc0, 0xd3, 0x45, 0x0b, 0x70, 0xc6, 0x27, 0x9b, 0x4e, + 0xe6, 0xef, 0xd9, 0x55, 0x77, 0x39, 0xbe, 0x5f, 0x86, 0xe6, 0x8a, 0xd0, 0x70, 0xa1, 0x75, 0x47, + 0x03, 0x8b, 0x19, 0x30, 0xd4, 0xbd, 0xfd, 0x93, 0x27, 0x22, 0xb5, 0xa8, 0x70, 0x44, 0xeb, 0x8e, + 0xd1, 0x9a, 0x9f, 0x57, 0xc6, 0x0a, 0x24, 0x4c, 0xc3, 0x9d, 0xef, 0xba, 0x1c, 0xbe, 0x4b, 0x97, + 0xa8, 0x4c, 0xc7, 0x21, 0xd1, 0xba, 0x23, 0x03, 0x5a, 0x74, 0x75, 0xd7, 0x7f, 0x4f, 0xb8, 0xae, + 0x5d, 0x6d, 0xa0, 0x3b, 0x7f, 0x84, 0xeb, 0x8e, 0xf1, 0xe6, 0xee, 0xed, 0x92, 0x7d, 0x7b, 0x53, + 0xcc, 0x09, 0xd2, 0xd8, 0x27, 0x99, 0x30, 0x0a, 0xdc, 0x56, 0x8a, 0xc2, 0x58, 0x0d, 0x89, 0x77, + 0x74, 0x93, 0xb2, 0x8f, 0xd6, 0x1d, 0x25, 0xd8, 0xda, 0x59, 0x65, 0x21, 0x93, 0x26, 0xa0, 0x43, + 0x30, 0x4a, 0x74, 0xcc, 0x4c, 0x34, 0x61, 0x00, 0x00, 0x07, 0xa9, 0x49, 0x44, 0x41, 0x54, 0xc7, + 0x78, 0x97, 0x95, 0x29, 0x0a, 0x0d, 0xce, 0xb4, 0xb7, 0x53, 0x97, 0xfe, 0x43, 0x3f, 0xc7, 0xcc, + 0x24, 0xdb, 0x65, 0x71, 0xc9, 0xbe, 0x3d, 0x30, 0xa8, 0xad, 0x8e, 0x3d, 0xd7, 0x92, 0x91, 0xde, + 0x55, 0x2e, 0xec, 0x7b, 0xd7, 0x82, 0x36, 0xab, 0xd9, 0x7f, 0x9a, 0x39, 0x29, 0x2f, 0xb7, 0x6e, + 0xcc, 0x72, 0x72, 0x34, 0xdc, 0xb2, 0x78, 0x61, 0xce, 0xd2, 0x25, 0x79, 0x3f, 0x2d, 0x7b, 0xe6, + 0xee, 0xc6, 0xf7, 0xf1, 0x2a, 0x63, 0x31, 0xe1, 0x1f, 0xae, 0x32, 0x2a, 0xb2, 0xe9, 0xc9, 0x63, + 0x45, 0x9e, 0x68, 0xbd, 0x0e, 0x7d, 0xd4, 0xc9, 0xe4, 0xa6, 0x63, 0x93, 0xa8, 0xa0, 0x33, 0x42, + 0xa6, 0x9e, 0x51, 0xa6, 0x3b, 0x86, 0xac, 0xab, 0xb3, 0x36, 0x2e, 0xb6, 0x94, 0xe9, 0xcf, 0x9d, + 0x33, 0x7b, 0x28, 0xef, 0x09, 0xce, 0x84, 0x29, 0x93, 0x53, 0x2d, 0xcc, 0x60, 0xa4, 0x4e, 0xa6, + 0x3c, 0x5f, 0xbb, 0xba, 0x99, 0x93, 0xaa, 0xd0, 0x3d, 0x7f, 0xd5, 0x72, 0xcd, 0x8f, 0x6d, 0x68, + 0x25, 0xcd, 0x6a, 0x7a, 0xc1, 0xea, 0x55, 0xa5, 0xc1, 0x81, 0xc5, 0x47, 0x0f, 0xe5, 0xde, 0xbf, + 0x9b, 0xc1, 0xe5, 0xea, 0xbd, 0x24, 0x5c, 0xbf, 0x76, 0xf7, 0xce, 0x6d, 0x92, 0x95, 0xe4, 0xfd, + 0xf9, 0x47, 0xa1, 0xa7, 0x07, 0x4e, 0xf7, 0x92, 0x30, 0x96, 0xde, 0xbf, 0x1d, 0x92, 0x92, 0x99, + 0x9a, 0xfa, 0x22, 0x3e, 0xae, 0x94, 0x1d, 0xfc, 0x72, 0xdb, 0x66, 0xce, 0x2c, 0x2b, 0x1d, 0x78, + 0x52, 0xe0, 0xba, 0x62, 0x34, 0xe8, 0xae, 0x5a, 0x92, 0x18, 0x13, 0x73, 0x97, 0x2e, 0x81, 0xb6, + 0xbf, 0xe1, 0x7e, 0x62, 0x3f, 0x95, 0x2b, 0xd9, 0x74, 0x00, 0x15, 0xad, 0xfb, 0x95, 0x4b, 0x17, + 0x27, 0x8c, 0x1b, 0xab, 0x3a, 0x71, 0xd7, 0x30, 0xe8, 0x97, 0x88, 0xcb, 0x5f, 0xdf, 0xb8, 0x26, + 0x8a, 0x60, 0xc3, 0xd0, 0xf6, 0xc5, 0x86, 0x75, 0x4f, 0x17, 0x3a, 0x70, 0xac, 0xad, 0x92, 0x06, + 0xdf, 0xa0, 0x45, 0xa3, 0x3b, 0xf4, 0x90, 0x1a, 0xee, 0xdd, 0x45, 0x58, 0x1a, 0x1f, 0x24, 0x36, + 0x3e, 0xbc, 0x8f, 0xb0, 0x34, 0x24, 0xde, 0x7e, 0x95, 0x70, 0xad, 0x36, 0x3e, 0x4e, 0x7c, 0xfc, + 0x28, 0x74, 0xec, 0x84, 0xec, 0xa0, 0xa2, 0x1d, 0xdb, 0xb2, 0x9d, 0x17, 0xa5, 0x4c, 0x35, 0xfd, + 0xc4, 0xd7, 0xcb, 0x76, 0x5a, 0x08, 0x63, 0xa0, 0xd6, 0xfc, 0x5c, 0x7d, 0xff, 0x5f, 0x6a, 0x09, + 0x72, 0xdd, 0x8f, 0x1d, 0x3e, 0xa4, 0x9c, 0xad, 0xce, 0x2b, 0x2a, 0x42, 0x18, 0x2a, 0x55, 0xc8, + 0xe5, 0xbd, 0x2d, 0xcd, 0x3d, 0xf5, 0xaf, 0x25, 0x55, 0xe2, 0xce, 0xb2, 0xd2, 0xce, 0x52, 0x01, + 0xc9, 0xd2, 0xfb, 0xb6, 0x69, 0x04, 0x0f, 0x55, 0xe5, 0xd2, 0x9e, 0xb6, 0x17, 0xcf, 0xc4, 0xc7, + 0x8f, 0x40, 0x5f, 0x30, 0x73, 0x81, 0x3d, 0xa1, 0xf4, 0x70, 0x4a, 0x94, 0xf8, 0xfb, 0xbe, 0xbe, + 0x71, 0x7d, 0x80, 0x74, 0x06, 0x22, 0x1d, 0x83, 0x56, 0xf7, 0x3d, 0xbb, 0xbd, 0x71, 0x97, 0x8c, + 0x52, 0x92, 0x93, 0xd0, 0x06, 0x3c, 0x22, 0x18, 0xc1, 0xba, 0x0f, 0x42, 0x2e, 0x6f, 0xe1, 0x72, + 0xa0, 0xed, 0xcf, 0x5d, 0xea, 0xa2, 0x2e, 0x7d, 0xb2, 0x09, 0x03, 0xa4, 0x6f, 0x7c, 0x70, 0x4f, + 0xdf, 0x51, 0x0e, 0x03, 0x84, 0xba, 0x63, 0x3b, 0xb1, 0xa9, 0x97, 0x84, 0x6b, 0x06, 0x9a, 0xdb, + 0x9a, 0x3a, 0x46, 0x8b, 0xee, 0x1f, 0xe9, 0xef, 0xeb, 0x7b, 0x75, 0xfd, 0x8a, 0x60, 0xaf, 0x0f, + 0x2e, 0x73, 0x39, 0x94, 0xb4, 0x19, 0xd3, 0xa1, 0x7b, 0x63, 0x80, 0x9b, 0x9f, 0x10, 0xd2, 0x21, + 0xe0, 0xf3, 0x77, 0x7b, 0x91, 0xd7, 0x7d, 0xf3, 0x86, 0xf5, 0xb3, 0xad, 0x2c, 0xb1, 0x62, 0x65, + 0x61, 0x36, 0x7e, 0xec, 0x18, 0xe5, 0x53, 0x28, 0xd7, 0xae, 0x5c, 0xa6, 0x22, 0x78, 0x83, 0x65, + 0xb4, 0xe9, 0xae, 0x04, 0x7a, 0xfc, 0x02, 0x3f, 0x1f, 0xf5, 0xe1, 0x4e, 0xd1, 0x2f, 0x5b, 0x1a, + 0xee, 0x1b, 0xe2, 0x36, 0xd9, 0x38, 0x50, 0xe9, 0xae, 0x4a, 0x69, 0x89, 0x60, 0xfe, 0xdc, 0xd9, + 0xa8, 0x22, 0x1c, 0x89, 0x8c, 0x5a, 0xdd, 0x07, 0xde, 0xb7, 0xf4, 0x95, 0xc7, 0x8f, 0xe5, 0x0e, + 0x5e, 0x54, 0x06, 0x05, 0x5e, 0xa9, 0x3a, 0x77, 0x5a, 0xdf, 0xd1, 0x7d, 0x06, 0x5a, 0x77, 0x2a, + 0x18, 0xcd, 0xba, 0x63, 0xb4, 0x64, 0xa4, 0xf3, 0x7d, 0xbc, 0x70, 0xc6, 0x67, 0x3b, 0x3b, 0x55, + 0xc7, 0x92, 0xdd, 0xc6, 0x91, 0x52, 0x68, 0xdd, 0xa9, 0x60, 0xf4, 0xeb, 0x0e, 0x74, 0x96, 0xf0, + 0x4b, 0x02, 0xf1, 0x59, 0xcc, 0x0b, 0xdc, 0x56, 0x35, 0xdc, 0xbb, 0xa3, 0xef, 0xd0, 0x86, 0x84, + 0xd6, 0x9d, 0x0a, 0x8c, 0x42, 0x77, 0xa0, 0xad, 0x20, 0x8f, 0xe7, 0xb5, 0x13, 0x67, 0x3c, 0x9c, + 0x03, 0x5d, 0x15, 0x22, 0x7d, 0x87, 0x46, 0x0c, 0x91, 0xee, 0x53, 0x69, 0xdd, 0x49, 0x62, 0x2c, + 0xba, 0x03, 0xb5, 0x17, 0x7f, 0xcd, 0x5a, 0xbc, 0x50, 0x55, 0x20, 0xee, 0x5c, 0x5b, 0xf1, 0x89, + 0xa3, 0xfa, 0x8e, 0x8b, 0x18, 0x5a, 0x77, 0x2a, 0x30, 0x22, 0xdd, 0x7b, 0x9b, 0xdf, 0x0a, 0xd9, + 0x41, 0xb8, 0x06, 0x5e, 0xb1, 0x0d, 0xb9, 0x81, 0x6d, 0x0e, 0x81, 0x01, 0x1d, 0x30, 0xdc, 0x90, + 0x43, 0xc7, 0xba, 0xa7, 0xa5, 0xa6, 0xec, 0xf6, 0xda, 0xc9, 0x0e, 0x66, 0x92, 0x39, 0xa2, 0xa1, + 0x61, 0x44, 0xba, 0x03, 0xe2, 0xc8, 0xc3, 0xe9, 0xb3, 0x67, 0x0d, 0xee, 0xc1, 0xaf, 0x6c, 0x4e, + 0xd3, 0x7e, 0x9a, 0x2e, 0x75, 0xe8, 0x57, 0x77, 0x2c, 0xef, 0x95, 0xaf, 0xb7, 0x27, 0xfc, 0x09, + 0xd2, 0x93, 0x39, 0xa8, 0x41, 0x61, 0x5c, 0xba, 0xbf, 0xfe, 0x3d, 0x21, 0x7b, 0x89, 0xd3, 0xa0, + 0x4b, 0x34, 0x4b, 0x9c, 0x14, 0x53, 0x0c, 0x0c, 0x0f, 0x3d, 0xea, 0x2e, 0x93, 0xc9, 0x66, 0x98, + 0x4f, 0x99, 0x6a, 0x32, 0x49, 0x2e, 0x97, 0xc7, 0xc7, 0x5d, 0xf8, 0xfa, 0xab, 0x2f, 0x62, 0xa3, + 0x0d, 0x6e, 0x3f, 0x30, 0xed, 0x30, 0x2e, 0xdd, 0xdf, 0xa6, 0x24, 0xe5, 0xaf, 0xf8, 0x51, 0xd5, + 0xa1, 0xcc, 0xf9, 0x76, 0xd5, 0x31, 0x64, 0x97, 0x51, 0x53, 0x41, 0x7b, 0x51, 0x61, 0xb1, 0xd7, + 0x8e, 0x41, 0x77, 0x85, 0x2d, 0xa7, 0x91, 0x4c, 0x12, 0xaf, 0xa1, 0xee, 0x5b, 0x37, 0x6d, 0x00, + 0xc5, 0x0b, 0x5f, 0xbe, 0xc0, 0x9e, 0x6e, 0xde, 0xb0, 0x1e, 0x9e, 0xa6, 0xa7, 0xa5, 0x69, 0x7e, + 0x14, 0x8f, 0xad, 0x9b, 0xb5, 0x0e, 0x92, 0x52, 0x8c, 0x4b, 0xf7, 0xd6, 0x82, 0xbc, 0xc2, 0x6d, + 0x9b, 0x54, 0x1d, 0xe2, 0x58, 0x5b, 0x95, 0x1f, 0x39, 0xa0, 0xef, 0xb8, 0x08, 0x68, 0xc9, 0xe4, + 0x3e, 0x73, 0x77, 0x1b, 0x34, 0xb0, 0x9e, 0x63, 0x53, 0x19, 0xa5, 0xcd, 0xb2, 0x57, 0x25, 0x9a, + 0xe8, 0x7e, 0x3e, 0x26, 0x1a, 0xe4, 0x8e, 0x39, 0x7b, 0x46, 0xb9, 0xae, 0xbc, 0x5b, 0x22, 0x31, + 0x37, 0x65, 0x7c, 0xfb, 0xdf, 0xaf, 0xea, 0x5f, 0x7f, 0x98, 0x7f, 0x21, 0x14, 0x96, 0x95, 0x08, + 0xf8, 0x79, 0xb9, 0x39, 0xd0, 0xf6, 0x17, 0xf3, 0x78, 0xfd, 0xfd, 0xfd, 0x8f, 0x1e, 0x3e, 0x88, + 0x3b, 0x1f, 0x53, 0x5b, 0x5b, 0xa3, 0x88, 0xbc, 0xb9, 0xf9, 0xc9, 0xe3, 0xbf, 0xe1, 0x01, 0x7c, + 0x46, 0x58, 0x56, 0x9a, 0x93, 0x9d, 0x75, 0x21, 0x36, 0x3a, 0xeb, 0x69, 0x26, 0x99, 0xc8, 0x51, + 0x61, 0x5c, 0xba, 0x4b, 0x1b, 0xde, 0x94, 0xb1, 0x98, 0xb8, 0xd1, 0x2a, 0x8c, 0x5f, 0x7b, 0x5b, + 0x9a, 0xf5, 0x1d, 0x1a, 0x9e, 0xca, 0x53, 0x27, 0x32, 0xec, 0x6c, 0x55, 0xe3, 0x84, 0xdf, 0xa5, + 0xc6, 0x47, 0x0f, 0xc9, 0xd4, 0xf9, 0x59, 0xdd, 0x9f, 0x15, 0xe4, 0x83, 0xeb, 0x0e, 0x76, 0xb6, + 0x61, 0x6c, 0x96, 0x6a, 0x09, 0xf4, 0xf7, 0x83, 0xd7, 0xad, 0x2c, 0xcc, 0xb0, 0x3d, 0x25, 0xa1, + 0x6f, 0xb3, 0xc8, 0xc1, 0x1e, 0xfb, 0x2b, 0xcb, 0x97, 0xb9, 0x44, 0x84, 0xb2, 0xb1, 0xc7, 0x93, + 0xbe, 0x1b, 0x57, 0x29, 0x16, 0x43, 0x25, 0x73, 0x6d, 0x66, 0xc2, 0xd3, 0x93, 0xc7, 0x23, 0x57, + 0xfc, 0xb8, 0x14, 0x7b, 0xeb, 0x54, 0xd4, 0xf1, 0x5d, 0x9e, 0x3b, 0xc8, 0x04, 0x8f, 0x04, 0xe3, + 0xd2, 0x1d, 0xa8, 0x38, 0xbc, 0x1f, 0xb7, 0x7c, 0x26, 0x77, 0x99, 0x4b, 0xfd, 0xad, 0x9b, 0xfa, + 0x8e, 0x6b, 0x10, 0xdd, 0x35, 0xd5, 0xa5, 0x41, 0xfb, 0x70, 0xa7, 0x65, 0x69, 0x70, 0x40, 0x77, + 0x5d, 0x2d, 0x99, 0x6a, 0x3f, 0xad, 0xbb, 0x44, 0xd2, 0x35, 0xf9, 0xfb, 0x6f, 0x27, 0x8e, 0xff, + 0xa6, 0xb3, 0xb3, 0x53, 0xfd, 0xdd, 0xab, 0x97, 0x2f, 0x81, 0xf1, 0x6b, 0x56, 0xad, 0x18, 0x78, + 0xaf, 0xfb, 0x5e, 0x9f, 0x5d, 0xd8, 0xeb, 0xbf, 0x6c, 0xd9, 0x74, 0xfd, 0xea, 0x87, 0x79, 0x66, + 0xd0, 0xe3, 0x87, 0xe6, 0x5c, 0x55, 0x77, 0x65, 0xba, 0x66, 0xf8, 0x0c, 0x7c, 0x92, 0x4c, 0xf0, + 0x48, 0x30, 0x3a, 0xdd, 0x3b, 0x8a, 0x79, 0x7c, 0x5f, 0x6f, 0xfc, 0xe5, 0xc8, 0xe0, 0xc0, 0xee, + 0xea, 0x2a, 0x7d, 0x87, 0xf6, 0x2f, 0x70, 0x4e, 0xa6, 0xdb, 0x58, 0xab, 0x46, 0xf8, 0xd4, 0xd1, + 0xa1, 0xe6, 0x7c, 0x34, 0xc9, 0x6a, 0x3f, 0xad, 0x3b, 0xb4, 0xc4, 0x20, 0x74, 0x6a, 0x4a, 0xf2, + 0x50, 0x1f, 0x80, 0xe6, 0x19, 0x3e, 0x10, 0xce, 0x0e, 0xa1, 0x75, 0x1f, 0x49, 0x54, 0xc7, 0x9e, + 0xcb, 0x72, 0x72, 0x54, 0x95, 0x29, 0xc5, 0xdc, 0x4c, 0x14, 0xc6, 0x92, 0x75, 0x76, 0xe8, 0x3b, + 0x34, 0x05, 0xb5, 0xf1, 0x71, 0xf0, 0x83, 0xa3, 0x1a, 0x5e, 0xb2, 0x09, 0x43, 0x08, 0xe1, 0x75, + 0xb4, 0x93, 0xac, 0x99, 0xbe, 0xcd, 0x64, 0x8c, 0xba, 0x2b, 0xb2, 0x3c, 0x47, 0xb0, 0x71, 0xd9, + 0x26, 0x52, 0xa7, 0x99, 0x8b, 0xc2, 0x43, 0x14, 0x3b, 0x3d, 0xe8, 0x95, 0x9a, 0xb8, 0xd8, 0xbc, + 0x9f, 0x96, 0xe1, 0x7e, 0x7c, 0x04, 0xfe, 0xbe, 0x1d, 0xc5, 0x08, 0x96, 0xdb, 0xd1, 0xba, 0x1b, + 0xa3, 0xee, 0x80, 0x5c, 0x22, 0x01, 0xb9, 0x41, 0x71, 0x55, 0xab, 0x92, 0x26, 0x4f, 0x2a, 0x65, + 0xee, 0x6b, 0x7f, 0xf9, 0x5c, 0x2f, 0x21, 0xc9, 0x3a, 0x3b, 0xcb, 0xf7, 0x87, 0x72, 0xe7, 0xe2, + 0x77, 0xa4, 0xe0, 0xfb, 0x78, 0xb7, 0x21, 0xca, 0xfa, 0x42, 0xeb, 0x6e, 0xa4, 0xba, 0x03, 0xfd, + 0xbd, 0xd2, 0xf2, 0x83, 0xe1, 0x19, 0x76, 0x73, 0x70, 0x7a, 0xe5, 0xb8, 0x38, 0x57, 0x1c, 0x3d, + 0x28, 0xeb, 0xea, 0xd2, 0x65, 0x30, 0x8d, 0x0f, 0x12, 0x05, 0x7b, 0x77, 0x27, 0x31, 0x26, 0xe2, + 0x4e, 0xbf, 0xb2, 0xe0, 0x80, 0xce, 0xb2, 0x52, 0x54, 0x47, 0xa1, 0x75, 0x37, 0x5e, 0xdd, 0x31, + 0x5e, 0x5d, 0xbb, 0x5c, 0xb8, 0x75, 0x13, 0xce, 0x78, 0x28, 0x2f, 0xb7, 0x6c, 0xa8, 0x3a, 0x1d, + 0x25, 0x97, 0x50, 0x2e, 0xfd, 0xdb, 0x94, 0x24, 0x70, 0x3a, 0x75, 0xda, 0x54, 0x5c, 0x00, 0xdc, + 0x39, 0xb3, 0x45, 0xfb, 0x43, 0xfb, 0xda, 0xc9, 0x6e, 0x25, 0x17, 0x1f, 0x77, 0xe1, 0xf4, 0xc9, + 0x13, 0x58, 0x09, 0x09, 0x0a, 0x34, 0x37, 0x65, 0x28, 0x9f, 0x42, 0xd1, 0xfc, 0xe6, 0xd1, 0xe8, + 0xc0, 0xd8, 0x75, 0x07, 0xa4, 0x6f, 0xea, 0x45, 0x61, 0x21, 0x5c, 0x5b, 0x1b, 0x75, 0xe9, 0x61, + 0xc8, 0x08, 0x7d, 0x9e, 0x0e, 0x3e, 0x0f, 0xf9, 0x41, 0xfb, 0xda, 0x5a, 0xe1, 0x74, 0x2a, 0xde, + 0xb5, 0x53, 0x7d, 0x4d, 0x6d, 0x92, 0x09, 0x43, 0xe0, 0xe7, 0xdb, 0xf8, 0x37, 0xa9, 0x4b, 0xec, + 0x4a, 0x24, 0x92, 0x2e, 0x2b, 0x0b, 0x33, 0xc2, 0xa5, 0xd9, 0xfe, 0x7b, 0x7c, 0x90, 0x1c, 0x62, + 0x04, 0x41, 0xeb, 0xfe, 0x81, 0xb6, 0xe7, 0xcf, 0x84, 0x21, 0x4c, 0x8e, 0x95, 0xa5, 0xba, 0xf4, + 0xe0, 0xdf, 0xf3, 0xb5, 0x6e, 0x30, 0xba, 0x85, 0x96, 0x58, 0xde, 0xd3, 0x4d, 0xe6, 0x28, 0x9d, + 0x65, 0x25, 0x95, 0x27, 0x8e, 0x09, 0xf6, 0xfa, 0x70, 0x66, 0x12, 0x1d, 0x68, 0xf2, 0xa4, 0x22, + 0x8f, 0x6d, 0x35, 0x17, 0x62, 0x06, 0xe4, 0xda, 0xec, 0x91, 0x3d, 0x14, 0x72, 0xb9, 0xdc, 0xd1, + 0xde, 0x0e, 0xe7, 0xfa, 0xf1, 0xa3, 0x47, 0x10, 0x1e, 0x62, 0xa4, 0x40, 0xeb, 0x3e, 0x08, 0xe8, + 0x28, 0x8b, 0xc2, 0x58, 0x59, 0x6a, 0x1b, 0x93, 0xff, 0x3b, 0x71, 0x65, 0xba, 0x45, 0x81, 0xdb, + 0x2a, 0x38, 0x31, 0xc4, 0xc7, 0x0e, 0x35, 0x3e, 0xbc, 0xd7, 0x25, 0x2a, 0x1b, 0xea, 0xf2, 0x65, + 0xbf, 0x54, 0xda, 0x5d, 0x57, 0xdb, 0x92, 0xc9, 0xad, 0x8e, 0x39, 0x2b, 0x0c, 0x0f, 0xe1, 0x79, + 0x79, 0x64, 0xd8, 0xcf, 0x1d, 0xaa, 0xda, 0xd4, 0xe9, 0xe6, 0x25, 0xfb, 0xf6, 0xbc, 0xfe, 0xfd, + 0x3a, 0x75, 0x5b, 0x5e, 0xba, 0xbb, 0xae, 0x54, 0xba, 0xae, 0xbc, 0x52, 0x6e, 0x6c, 0xd0, 0xba, + 0x13, 0x20, 0xef, 0xe9, 0xa9, 0xbb, 0x14, 0x5f, 0x1a, 0xb8, 0x8f, 0x3b, 0x87, 0xa0, 0x87, 0xa3, + 0x5e, 0x52, 0xa6, 0x9a, 0x72, 0x66, 0x59, 0x41, 0x6f, 0x1b, 0x84, 0xce, 0xb0, 0xb3, 0x4d, 0xb7, + 0xb1, 0x06, 0x7d, 0x35, 0xfc, 0x8b, 0x30, 0x72, 0x28, 0x3f, 0x18, 0xd1, 0x5d, 0x53, 0xad, 0x83, + 0xef, 0xe5, 0xeb, 0xed, 0x09, 0xae, 0x27, 0x3f, 0xf9, 0x47, 0x07, 0xc7, 0x32, 0x4c, 0x68, 0xdd, + 0x3f, 0x85, 0x5c, 0xda, 0xd3, 0x70, 0x3f, 0x11, 0xda, 0xfb, 0x17, 0x1b, 0xd6, 0xa5, 0x5a, 0xe0, + 0x47, 0x93, 0xda, 0x95, 0x24, 0xc6, 0xc4, 0x6c, 0x67, 0x27, 0x01, 0xd3, 0xff, 0x79, 0x04, 0xfb, + 0xaf, 0x0b, 0xe7, 0xaf, 0x5c, 0xbe, 0xa4, 0xcb, 0xf2, 0xdb, 0xaf, 0x71, 0x24, 0x6b, 0x48, 0x25, + 0xb1, 0x8b, 0xb7, 0xde, 0xa1, 0x75, 0xd7, 0x14, 0xc5, 0x1e, 0x7d, 0xcf, 0x0b, 0x2a, 0x4f, 0x47, + 0x09, 0x43, 0x59, 0x3c, 0xef, 0x1d, 0x39, 0x2e, 0xce, 0xd0, 0xff, 0xc6, 0x5d, 0x3a, 0x24, 0x68, + 0xbf, 0xcd, 0xcd, 0x9e, 0x2e, 0xb0, 0x7f, 0xb9, 0x71, 0x7d, 0x59, 0x30, 0xb3, 0xfc, 0x40, 0x58, + 0xd3, 0xe3, 0x47, 0xbd, 0x6f, 0x9b, 0xf4, 0xfd, 0x55, 0x8c, 0x17, 0x5a, 0x77, 0x52, 0xf4, 0xf7, + 0xf5, 0x49, 0xdf, 0xd4, 0x77, 0x08, 0xf8, 0x6d, 0x2f, 0x9e, 0xbd, 0xcb, 0xc9, 0x6a, 0xe6, 0x72, + 0x5a, 0x9e, 0x66, 0xb4, 0x16, 0xe4, 0x75, 0xf0, 0x8a, 0x24, 0xd5, 0x55, 0x3a, 0xb8, 0x8e, 0x49, + 0x33, 0x2c, 0xfe, 0x0f, 0x35, 0xf0, 0x0d, 0xe1, 0x1b, 0xb4, 0xe3, 0xaf, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, +}; + +const BITMAP_OPAQUE tune_single_track_length_legend_xpm[1] = {{ png, sizeof( png ), "tune_single_track_length_legend_xpm" }}; + +//EOF diff --git a/bitmaps_png/sources/tune_diff_pair_length_legend.png b/bitmaps_png/sources/tune_diff_pair_length_legend.png new file mode 100644 index 0000000000000000000000000000000000000000..8eee166a7c2a80dc4e541d5e385c9324176791ea GIT binary patch literal 13724 zcmV;NHDk(&P)|Kdp6Gz|ozj&Xw zhgNH)p4D2bPqk{*zO6o1t*upSwSBY|5b!__Meb9%R6J1e0L242s#Y#RMJp;QqD4VD z!c8C?;R+Cvkaxm_$z<={gd|43pZP4y?Cfv8`_1g^+%rOL3{*DB=q`kBt_A zV^|K10316yI{Fm~X>tNMcR7@6oCv(*3c#^y^$O(E7~%(x_JLWn5%l->bC1AFKm;x>}!L$+B{=N};)w?*=yKJp@-PRc5i#*A3;1M7wnw!9Ll+XFB!DpA) z+r1&cljR9&{`)h0a7`SZsjLx@!RbeaaS$HDm=TD+`ZqYXbjqunyN4tKfac?e!O`XL zePRTwz7rC`lnFKjA4zyHI6CgTZJY?mkc0<;qXRhtV@X8#o#6?{eYph6@{PfO$Il6G!O+~EWq7w&pbUSDDuO5AH|WaC1;>_C(c}mOT1O=x0j}PC2Q2U~ z>8|SS1wlJ+XOSbIvrfUC8M@EYp6kZ9uBJ+DLaaw0IXqO>?f=+>&Xbc8jnAD9rm!BE zSd?_X#`x9&%4SRfN4KbZc!i>jR9~R5&ap^Sy>=z~SJ~OYsm#Q^Jd>V!9hGM!VS%is zHP(xZivCPVHkS*HjDZdc4xRtSLN3(R`0t9Us3w4ecPe1%5Ry%KRjKNSkC88uGTSji zS&}aZ6=l)FIWX^ruI*Yf9uj4>c{d@!XH}3UE;kW3w-6({tf}RKr)}G7IdcL& zL(l7Cx-eSyPaZ#_E9c;!ak49&G!}(aC{?V_z@0sUH1R^oxRKW zTcbHMsM(JjJ#xdkHSjf9Fn9J>Uw)w;XviNwb_|0pO`Rwr7_oE=y-f~d3iiUFVIQtz zkM|xRSTy^3XGeHWm-ztCh-)P%yx3!>Au$@0y?Bo+p<OE?(1GwN6%4(SLU}oRuMHP~?+D~q^V{0)!sqINro`qGhtY?| zD6yzbP)h6XllPXq>Z_|A3gc#IQy@bu?Rint0SX$t?iztwg)UvZVB&VDsF--z4&~ta zr-0(BUW(_Zm0>_cgA$86dKCTr{jcge+>YfzPY1trRtvf=S>QkcbBGCR0r@>HqaGTv z`{WZY#cZAG_wU^^COdjSTD^TtDSO|Q*C5QUqxTuYn3_5qFo*u_y8ky`MlYK&8C}}G z|1Puerlvmdt<~14+fouB&0QO~kq>Uj?z z5V}Cb9y<~B_`6k>OC6jz+S?-PK=`Jpa6;iR^vWwrYv!j;fOZ_!O>My#)=T6Hih7A& z1&{m%1+{d1L>T3lU!m-0 z?QaUcM4ZUOm-;rxEn`Q$hk`X9JpeAXp4at2g(MV`RJZjL6mtJWnjyq4$yHU4UnjF+6@2ox%7gTI(Eq-sH+EN8xe%}9_;d1D#2!`*?c56QDgvHsJX2*wKJG zvmu;%_(1Ep8K?_G%|_kS%{(7oX4(@!T)Gk9`MWv-GBNbP_zfbQ=kXPD*r0?og z@Fix=x?g@!OP3d;DP5AVAZ8;?ha+{;%jNhb*TM0~0SUA{QgpCp-Gc@vkGLJn!~I)g zjzAsD=X{3yuUox}vNTb-{2Oik^-u)vf8ejz(EgTS>ZJ-8V9mP2Mo&$DQJh`@29D+e zu4>H+!Y!pGugP}cu)q>*<~Rf#d$gHxCNmx0ZrxYw>3$*pT+Z!VACDdFyv+&sH^1)L zSvTg)oUuPVjBhk%0n*)zo9;&sMXmpNHQA2&b%%MM&6rV@6%~AAGCc(7jxR}pU}oKc z=o{9pfew9qz$>|6?(EF;v_-;nz^|pH8JtHS*3>oZ|JZc?T%6iW!18y!aTu8H z6f01WVNTuOM9}NLPoVC5hjr(GVcpGxA=f=?Sa&LL*ZtIq<9JOKo}=Z}hjr%%cHMtk z9(5oR?{9$9ws4{C)|%1>`w|OTj66y?{YU#gcaR@drfR z@mDM(jlC<2%bXPk=X&J+vCMK{gf$`o;Hx{z-*0AT;prWs#AcLM`mMI)xc2?|iqBI& zph)jf^a_!P%d_<FFfPAKf*nNc!;gYFb-fYsL4 z%$zIXx_B#_WOs_2GYT4zOD||hdn!)NA9PQ}BRV=d>PX1BeT(dA zAlllfm&=vP`ht^+2tR=T1+LS&7@*TVmXq!e?&rcZx9WS^@?}S68r})j8XF^w8%27b zHGP`7MiPh`I&Jsp)ZgOEzOD=d`0CCb_}b@;s_llJ@JbMBcgH;iT(Zcm4y(;cBT?qumFHhiC*xJKmjX9dtDT)Y5JSR)3y zHwOD~abhp`n%~!p7R)B|s9L>(&}$6gemoDUpZ-+LR}>TIPC)nbr_C`(f&IoHA2iR9 z!UcFymm`fbq?r}+%8H653-KR7mQP%NsuCM95lFS*Bm+#ZJ9n5|G%u23QAFWzI>$q->!cdqEj&Y;V4;O1GIHER)Y z9hhiUx~C*3c6D_P86WK=7U0UJ6UTzv`KCi1&*oHeF~zRCVJqMo0)D!$UG)R3Tnr^8 zb?M}fpf2qhdW}t^!i(e?ss!?;L_1@xtu}zs!C3YkpbZKhq{2YkNbxV z4uf_I=d?JOmFSL|rvZ*fABD4?r;Hz`9&Aw>H+m#EKFWItH|M+%e@+-DG=&ST`wanS zPj9AK1Dp(N&>bk-r(d<1_1UyQKVLZaAL{<`z)Cepcf!VD+yS?=P;+0PJ>6V)eSH(*ADhpm+C@}9FteW&qtM*^H$O{ifqcrih@Xt#_K|*=J{ORn)X}!;R+@%KrM+o|K1mewSX@ z2izcpKbA_-G9du8kw=O`A)<^?_735^74*Uj9BVJti;YsFQoX%v!8 zmx#OUu${>FCe!Zj%>@+S)xE)ihFG*f*!rX+y(Dct>^IOrrRulCR@=K*+$7kP_3I8d zi_j`nBq0Y-b<3I#hE}inzI5uxCF4exPW-T9>DNsMLX}eL-8*duQ@uk7?`3BYtX%i1 zCf%ZLl>2l@LIW8ZcF@iNII^FKkM(jUv zKcVfpwH3OWp*8ESRO#lt9llO1cjGPlAbV->_iVeG)bsM6_SCCz8F=JMr;aDwTaB%a zn96@(zS_EVKZA7#64v;Yga;#8Yi)lc-`n5Um$H5}Lzm0;1Al9?uM36b+gV}Fy8B=F z2TJ3nKU1eqT&EMAW+=yob!+>T$_76V6q4|njTjufX78UVfSWbzj%xY)QuNB&Xxvf> z&8p}tmM%u;XppQVA_NapIk0U5bTT>bjzeqKee>Ydz`yki+LbGpp#DPKzrC$($5zL+ zKmCAvqCrk&Ge5!o@sG#zD&EU9TdnT+6cLd`hF>b3GH!4vM>6gYYv~K;&A~lo`H#@I zmk5 zaxT}YKM2FR>)}Nqah`ZzeI2Xr3HNxfiv5=B&fY4?CA|;pu7d#G7tEc#KRj&od;g1j zT7>S8^YU(H^Ip@*ED)eO$lN{L-AeSA2(}2_EovMYGlc0*wqt(Xo12@aO`h=cPd}z} zSP#hTupZsNou!7u>uw&% zc3rmX~Wb_~fGdrD5F>IO$&WV#U(MXxuqLci<+D`>?&DT&KJKew6n9nb7{JY~Hh< z-fG?JALLFMKMtw<)t6t$WU|=Pr|?Mt1-bW-?#k8{+|G{3yU@NL)rePSyw$pc^bY>5 zuB!Ur-G7nO`;`>!C=aB2=bf9l9o>HCp8PhMP!H>lJa1%XAl(Ceeem#T1Z(3yz1{oT zyZcZSe7C+G)}0-ah!7aQ;{WCnF71hZied>);W6`OSa&_NNhvmEkUi3^7Ni*1eGmtV z1-P9@AExDV8kWs8uPpA&Y1aGw6JCPi6c-1+{th8GJz^e#Th867YUHr#iy`2vJ1D<{ zT;9*ybIJspEw+CUtd-B64sQ|faUoplQz&uip|kZ$(>iYoS5(`fr~7U<7ru-B01?Tt za&+LA@W1rpdDW0C0Kivwx1BpqpVV&FLGHM3IuwDDyu7-KaJ9EjwLLtC`-2m8S7S+@ z<5E|K=#HF2P}b#K-c=7~;JVjy&|Rri!Ux~5ZVlx!0Z4bz!a3xtYRxu@qMZlt3Do`k zxw9bdk3OIt7*0k?ULBWBgg{ODbhaqs>T6Kcb&k4ci%kSY&dxVI;XdyHo^;@=J3`Fy zXv%lJ?Mf1ozGmY(x_IRZ)f18Q#`8wPCPMf=LUpY@)aydDkiH&92l&nRCKucJWfIi) zJxSbZLKyh!zIoGs!}e-t7SQFf4c@zu^wsMrcH-ua5#)`QBEmwAzIhV>9fMnijXNT8 z^b>wYK?U_@Puw9Oy)RqxEnFa=@E_XUqpE&filnbvy_{UU;RuTKK6Mgt`kD!l^P49rH7$(37QFri30l&GI$1VZ33`b;QAuc`Ta;O~9J!HBA zRIOc!OJ6c!j3hL$=d}U#rb#wqc?~|5ga_BVI1!!e))f|D_moBPv+AQ{V$2V*edjsc=TyIISp6=!4 zWvCqa{dfQ25`9B}7dd)XSN_GPpz_`K|LmQKUlZ3B$NOKr_u5(%cdc6$t@WvWt=iUo zsn$Mg`>a+LQR~LOFM{lXfPg6A0*DI=h=K^HxF7^&hXg_(Ko$sl_QZE_aG1U9Up`Wh3|k?W(FPO~l5K=B@G}_L4*Mpt_>Vy%*whiA*^tML=D8Fll zv1H!(FeD}%^{(gD@lHMYGAX~4g0*`a?0QinI_V_r!O(27t-OfxI~f#0A?$b7&*=0% zt|?f}3#ROzTtTL&3FY@rHv8619kcF{g#P6;$SJ*-5|PKF z?v9P2NXC_#P=22`Yr3H~4R@V93^}FS!wGr3u47QE$2Akm?^d7w<8o@sQAY>ERS15* z+Ol#f^7xQQ?Y?(hCXU}DLPOk~M>S~B&=7+U@*te=Jx(4`Q$76CihApy`&dlm7j*o{y(;BQ48QmH^+9V(fc>;~Y*&0%X2!-J z*Uq%II)21)_B3m71iT(C!OLUC(j|{eNM&P2A*MH}_51r+)K3~T&xA}6zpr2SeOk&T z9=kZ44OqaiW0r~yT?OWhqC>61`kn#KDdd&gACy3usZMywm`}h2^ z6Y@Kq-YgW31`2%n;yL7ZNa?76fFuz!nl<{pR7=0JE!6Khcd}87JD`XKl;3s6yvD0< zN&3Bx^1Hqfx6sx5eJrb3NgYnw0u-eDUPt-;J!Je|RKwL+4yAYPkh0rhzbj=jeh1L!PKEr^mvs$!{7m-vvJS4MM>MvcV@vG4Q>&22 z2Or)a^ZQIIz1N&P=ID3Ue|JEx!KRaeL%JUeeMC@#=jHKqD$g2KHv4ibIj9eN`EB?m7FmP^Wb!X{75E(XTpxlrM}h+sqA013>| z@A5tY+yoCjDnPyKa&dgiC@|NgSK)V?GM=`d&1v#Tp~272fZ2K9LtQ&m`e=OBLd_dv z-4G7u=yyQ-Z#&0YgNW`%sIS`h6hh7A(x3 zxU<+3LhdvXI6XKEXW?T{{8_lnz8mR=zX>AD)bD_H#7ZXIwb}}$@?ue|PfDeIK*8v~ z)z^Ue`duLr!=9qgpCPQS(tM2?ByCL4u$aSe31-~y zN~IFDPySN!1ryc`0Q&E+vzqbN?~y?BWFCzFvsRyM)U?-d*O}RVq#o z3slOrPAq01(0-4NJ`0>a&FXWL)J7dW2{A|yj(Xo_9vFG{-^`G4IpDK-`|cA09shy6 zI~;#chRuA``Mt^UroIUk@b}605N>re3E~zyYsW^EH^~@t^ExrT(bUyP^GW`_dnmI# zupfKSOe`lY<)(*g*0ICt4C(QDZtUY`6Fd_@FLH&ZCVGI^)Dr_xl>}l^2ilye#KO_ky_m7cE zW`B4N-RElcp`apL&peIKb_vYZJKrhxc|cbE?U$VcLd|g%Ov@)qB^bhKX3e)Ng97}? zoJnDxyk_==XE!*<>FSyz(RFRxO3d|^in2&P|uwWT8qFhv(CZqzB=8zU#S*LwEI%& z9kp`jayYZ6O~Gm%vhA4nJVj(!qAjfbB;xq;i}Ckx$;^G(+G87 za)&}QYt)I}KcjYF#AG8{e7S=@OmbpELVPT2yLWDPb2^1Ql9zMW$aSS40Q468)2eV4 z=9@|r44NPzcT`TZV_*TcK8Hh!v!ClN;<;9keGnOZI^fyUrv|MGh0f$vbm0z0J(9|4 zt(y0=BawEoMRhfOS?RqO;`!$y`B5SKa}m84;`*|#4ZkQu?EoP|$n8dWBOuazv`=>R z;ZSn7c;fCeuxTS~-E%@oN3tHs&E^Jp!P%)aTI=d%9B&svdYX){c|Rp!a75~s`WmZv zue7QjeGegsq2zAa!~?B+qqXjoRKeztXuP&R`$orsz0L3Ukm+V^8`cQYlF3vx_+|sP znfFMpU~q;%*bQW%dgl7? zTfbjHUoewsCEkYb1u2@Bj7R4-W1rdkq}NDf3O%_*1C-n?l{)sId*Vx!bWX&SRkjkP z|B= zI6n)EW}{+#q7X|Jo>!_-H9vOtDUI-3sxK(HTO`lv0_St+=j)(XK(IuyKj&74ipAnx+qWW*3_i#M9UfGfEz1}6-^?T^=hh3hLm+y(H%Oa2!8$|9-6Dy; zM@Ow>v=1mqD`u)YAM|0mo&QEZU|G9TW8VX2$Cgbp8P1&O@XKecotsc4gAuT(L2VY0 zA(71M@*DJ1niN`l52=vy9|9$J%R{bEp1z6h$sCI*YwS|HE=6!Hm0>earPr}=R!_Xz z1%D!uXwkem&%H5s0N-F z5v;`fHGqiCr^CVF4vwuPE4=+uZBAZ&LCM|n7#7QX)6t7kyi%(Og5dKagHdv1?cPez z-vAsrWWU^I@rq?j{``F}aebs+ot=L>pvvb4`6|_C(M&98fzz|R?~D~@KGkz3dn}aP zEf4+3{TCp2{Y>Lia;GpLMwYu+ES5-!ruwB_Y)bAFh5}dao_dvgTue0RvOC(_PX6ql zP@->Fr<3YVrsO_~TrRhHw>!jo(x=^B_(|d^biinGU%F^MnJo5{+($XMe;;t!!@`0o zpZ{y=R}1836U58XF`C>x-CW4jhm!l-q=b0juj5A?!Ru>RE`!&5cJI=qf)p4=#B$@v zJt)ABOnp9fxmVFDfwR6|vIySbci6!W90~OE)uoOUs!(#*8U4#$Boux*a~c@mw6=@~ zT~H_#%N8#L9=v&DJSnlDw-=lYtoqGs@Go>)ZB0!_hste((`c0y3_2a^4oM^uFcN^D z6$}jxaXB24cQG+AOS#*Bq;iLY(x|hB`mx!KKY#xX`~vj$j!qr_vFF#B)>bWy(d={7r;PuGJ$eiicndzfxZ0c%jr%#^r^vPrAlgGDh+VHWB3XC9k zt@wE59vU131if$X9^7}YXQYF7fog|`NB189xrc|Gf!>OairD+#U!d2e#l?%}&3XH- z<#srD04RIS>XoieCs!<8l6XE2ItMiH){{Q{b>|L}^`A)K%H1oK)~$XK0iN8qP;yrb z8M&7fKLTo=J7cO?q}K0FCys%0eq1w}mI}x{GAtB2jw|=$M-T7VvJq;$!B+)zkRn1u z!0U?_l57^v8|d#ZxSv03+7x83>0`h$~H^OYuQSPeI!6~^D zLCva~4?4;H3?=usl-w;5O71#C$=&i8kx+8i5lZfs$3&2OAtiSTau`SM?JO4j8ac0r zg_1jk0WqB12m1Si0{muJTUmYjkMCCf8$J%LdIGj>(*|r3QcCU=21LJdS1Oe`ckitF zW*KVo8&~eIO|$yk!_}G3A5BRr?PPZyKZKcP@*$9WQei7r?&(h`xl>@!i`?lyZ(6qC zOM|MqzFWD1;LI75Cq@3e1ts@x_mlD=wUH6>Xx$E{RYJ|!dgO)OF?cL7 zO74~iuG~GfZQXZm5!H{j?tKD*zmNBfDPL&Sx&zzz<2pzZN~wewfu6N(-@B6_e{-im zFa@T?0 zY~b4DBIf1Nwyb9z_g{0$Tl$*2hxvmNncPSb#EpOv}l4Z12faw>Zi5e zg@>FWSm+8+%4FOiUzFTI52yD+yv957x`w_Tq&Wr`d8JkPX4aj#)exD}6qVDg)^eNA zqKyt&%so1tGpx3Cr#ClE{o*rqgYp0T`x`QQ)HNcLEB!L-2yRuM=ALWs_uy#cW6#to z|E&6yN6c#0071xHv&GPIj|vY1A2Dd%;3J&w?gevaP5Jy^#2d$Cg5IuEN6?C&JCz?7 zrSYaZdW8O&wYXWF^kS!CpVzYoi8?bpE_cp!Ypm9HY}ur-_9QW?+|`(!cfL#fi@+Q8 znPnYa0-^@YOi(9xf*6rn$^G`t8{kt0;y&u=a5ww*z`y|cx=Fh`yDU zoKNcx$f&XRA(fb0pK^cuE|aj$qWMUz+aEkY{^m6T`WU0RX9EiLX!iaEpcS|E&PRoW zCTWLG7y4g$omkk)RlgU`wCG9hn~D4G3_AT>bkxQl*Fj;GfPpSeSEuHvrP9t0Y#R@Z zZTmlARR#Im1h-Sp5P(jIUuLau8qMwe^P^!Uhk}d7EJ!;$l~Ar(?r+~kM_TjkSe|$v zPj~XwH4~(A1$RLFx~>0uSqJFefnQAL_~+m&anM8am*Ggz!{D0@Wlg=Nz6li!Eq5<> z*Ppj;>JzABsLZ*O4Fmv=ldL2^Dg-p@SkZSm|4lM=nIRziWM;X|SI#Go8?-9M2XtL7 z7BK@eYmbJP689R9gce8LY2=$C87~%mxu@t&?lslbGpA05_8cd~$6ZJ~4~DIvjsJ4y zG-&TUNe1udvbJx)Dt@%3KlsN`@k6ce{Db+VqrJVX?5Rcr-MDL4uaG&@`d zWQ@FeAz`+FPh8$70H3VRrVt4=$Q_JYun!`!E1q>mAshjBMRfBYXmh8we7%shV`I1b zDPDL`U*=T_t4)V`HnRtPE>+-)9&~>4UKu>g3KGkeJIvsNJdU?3W675W{ODD!{kNUs zrUoLp+x@j)-855P&RxCSw!!7D#+d6?cYC??UP@GqXt4y3BM@TO@j>QxiN@(OQZqjR zrSnZDccoIfee*`**mswbH75nvh^gd`G=|MQUP!?3lM*<9D>1x& zky}a?R`Ir8_l(n_S1Wh*b7W>KcO*azB6^eHY6|~s2*<~*efKuTvIV0HEmdo-f4O7v z_4cf+P@AYtXOs#B=wvG-2on>SNVADVz-yqBCuO&f&?*LUZ}Vfqxq;rD4*Oe{f2F}G zGp%?L!E!OFiPd`*T}LBIv7-09@@7P0*o6rbRqg~R<#L5kC?6a!Y~LNmKyo)Sz-6Mw zI-qH`-9Fq$V`DAB-dzMq7-4z_#lBb3>2QHLoqbYR%{AOz=uhs(dje=Cd|YxzF_@p* z<#G&H@!&U9RiG2dlF+=J2&I%p5yB- zVKIqIxbc*A=*%OO{*H#17S|Z0jUSbJ20D!}C3iAVav!HBDVF)ew^+rqwyht0kVkxN zK~?wRFmzY`WK7vBhJg4&9S~7+*A+_cXh2Kfx_TK}^mDBF(P6|FrWUthdo|vvG?u>S zp(wfQ3?+9Qqo#HaYl5r1)6rTy5>`^y*rTsnQF7NA!^+*=#R*z*kb3E& zw%3{o19{o4tG`Bf;=@i8tT@Pg+U^jj5)tm8UL(TkNA5c}QF2#{4swTf_y!01@7%U! zbRFeOy{)4(CP3EQARqL!>zC@?xCqXGxEsoKx2`d(>^x&5*5L`)7cRucb)itr4!O>3uL?CxR zO71#g5V?aEakLV!|0x`X*{r6qy?mJ;P zxRC5d)Lw7Lkm4r|`uTDDe|u;C)WjLa@%|wl99jy6sz_}|W~^ez;}^BZRAdzBD8mSH z)PiL=3=pmmE=Qm(2o@PSoWh_Z5lW!MSRjFpA_7y%0pu_zcMeDh^o_9;-ra1nnI#a| z@4P=On?0T|pMCSZ?>_JIkhnW6;&HF8`VBi!-cky9?Y||k-Cazu-B4Exw(nJxgKYty z54QO{bL_a+2m1!N9I$cF$LnfnFmR2)c3f=C<%<{ae_00wa2H>>gutDKaY_Li?(8vQ zR{D~-J1l~62abn1zrDK~YU(M_mwW7c9~{vB#2kVGa6c7r%<>VBHxBlL{@(KE#~$un zPXF3w+}SLa<Sg3yB*rNyxaaje-D2D&B<{9EzGkv5M{s`x;~ougA0=_$ zW|6qt){=lH4hzPQI|IU@skCM1s(O$-Vc|stK4u^18hjvQiqYV;b9zPcn ziMwrqUR+t21II;vcTV^6g|$;a2b@tq3=s()fLfL#Im|X{Mq^01{~W$@c4t$+#M&uf zs4ex}VXAqKC(6vP3ZkOho>-nD_fa3@-m-F?#o{qos4Ca#7b)V^YlFe6>vx#@P z&^52!YRhZ2TETS9TqLZFf5dmA@jPFz>FP>{&2U|jxZ5S*56G#>a0egswQdNj9-Bb6 zaI+jiXUgM*axQlaUy_2k#U)zZP(&JBi1d1P=Pzwop~d=G2%WdYrETSVfHPskZPGx5|EdjP6o zi}LDGlI-DXNhRz`rqJfSj0(9t9rnJ=tmkE|5>X-4MMdI{PbR${m3UD|pqATb=S5hf zDthZbl)GGHUK+Gszb&q$H=}X1xnH7QT(;->nqKx)&^JgU6**}ubHv2lyQoOq9g(`? zXWl_i)NbC0bH$cs$v7@s+3e|;q$kxIMGg!eq>l29*U%D^4uvUjcRhb!(e_n zP?S6F?T$1_c>Kt0OM{c`*_pE1yZ=2nuwFkF*#eIG6H+AJ)%C8d9D*?OWM5pArtg^( zY|uU*lv9(I3!Gqss|d@P5eWE})fiCw_WW7AOHOyOfQO*WN0|UwZ?fc@ zvrV-o4Ur2D!EkfFqYd~@d_Ny+_f>!&nPt0t{k3bn z+e1~oPUnBv&%%0YN|F<7a%pJ?II>hYo(!GK10M;Fel~USt2YTZz+<4ur7H8Yf&Z;6 z$WhQU71?RBW~b$U7LK(jq}p{78WRt3%#6 zn(yWTsHYqMQy*!}HRWx(ruQj1v4~gp&byN$P$uvYaC&FzYgDC0V3-R$8Q`}_Z$wJM zLq#Eh;;>+8boiT}evqdpflt9PGqu&)fqsL`sl|$SrTzspky~1E@aP8s00002jOG zcPQU!TY?A(xcdGRLNAn`%725t&tCd!czb#}dHE6$d=^R|BOtiz^!%xsX+YkQ?Poj2 zdA6f)tcNXuY@IpO6WTtz^vn)wcvaUB2c5%tu$z*km@xs=n3$NX@7gS?5%wnN`#Wlp zI#Pe4`WU)KOh|N`yCO$p2^`VmhsYx|!qP^@zS+?M!I+h=qt=YS9!W~7pJ-EdJ=?zD zLVQKDdO?21D#xY#;2Y@Q3Rqw?;!c;DrRBx?ztC(Nnz&Or@CR+=G><`;q1h9V^8ee5vWE(gn~FLN|5%OxM2o%8_N@zLfoIFJ%Mx^N{-~R1Nii z`vS%HZpvPezs$+?^Y_0uQIL_JQGNezhDm01{KX(gHqgc}3~IIi)P68qBi_U@DiZW2 z)@qo^5ycO8?Hr z&{WO5x&mk+f@Z1Mb*WQ#Y$#$Ocm9~wIw~9UuWPrYCC$VeusXVWKi=^i+!^kQcezne;4xFmY%jZu7nc7o8#57-T(#Z=sNe)}U*n(BV@tV6 zAY}FX#PX(=ht5nxE5e#V?uTI4iY)f7Sstp-mKd5f_oKsBZu;kTRjw(Qa^T^)*TE3& zLA6c-jR19MZ`YzJ-?KaEQ7SSr{Kvd1g@$HgPpi0Lz6Z|W`Sdx#uJY>2O6wyVrYGa5 z5z~8daa0>w+ZFtrRG|R@Ss}YBEVpyTD28T9Zef)O3t&C+5N-Yt?MuSJ6#t_ZrX%YHNUnBK$mSKjrdqdW(0&4$V6`);-z2uk*dwg`8>4o{yPLbSozF-h1*WDcXXYO}Ol(eHU zzGJVN0_EyI8!&81s!A4kN7N9vo5x`Dc^%ZxYOZu7_)ZfO{X5r|yRfyC#(v+iy9|&g zzsKk8Qt3H80SKjQy*37gf-T(gKhlP?vo3NRrbJom$m0iDHtO>(7e}##Z|CzUn~jVy z$~*`9hRV6Bbn=8^7Z>Nq)pIG8@0$@O^%XN!L0?`72+m`#+>2%tDgh)+iEkZ=ff%qM zwixs8(m4p48cXmt9l6U9{#*SEo7(0(3XzA4{)W-*JmoPWY2Y6CP zDyllP^BK=_7us*)kva2r6Fqm2rmZJ*ENAdEVq%YO-8?-Uz9-x{5Z>V=HQj_F72PxV zmu(+pRkLwuIp1)JS#0~$fA=_LGO_}0pVJe8dB;+5(eh@d=S!NjrMRPCCgfYNf2j;z z-j#f~YhS+VznHA02mN2`Fp?2h--?S@T_=`JFK$r1#OGY*U{;iRAw6E*-{(3j8+Ssyr9!;Spc4YFq?A$fr8}O)!krZtMCxu+)GWvKt@>5N)OeNHpGajk`w@ zBIf+)4Q0tzf(sr-(w9_XVm3E7FKdF`b*aO$OO)7MlI|bw4VQP-6H04k0vOmhT2c0N zRML;kRv5NTKeodu-V!xovXi79?z0EP39ZORlaRhmjVbq5*$o>88cy4<+3%HH2xvcU z+}=Czs^iT!@zp{^)QIdxJ6c%a|r2Ta_^0n9EsaV^R|j`bCX9-9bKlkr&KhJP~J}nJ0M| zqyZGYq5S;F&rmJ!;!}|HfgHb|ILqtf0`ykd#(t*jF*E=8$Q5r))_IAuXBfBpq^S}Z zUFNC1_t8rQmqlss=R#J88HjoamK zEmj=qC5YH4F6M6c)>wx83k%2Gh>tJ|f3=Y&asVu$zBNH+l*lPGL945`JICFb;*d4# zoRRjUhkSfBci9~5HNk^}V0T^J4Jp1q7qs;BjBCxXQ37Keko3a-mrVj(LhZqF_YGP2 z=)M@SHm<#0rYfV9nx79AN1hQIt?=L6-R=cfE^OeOp<=uHg1A}9{K%y0A*zq17_ju` z>a4cAQ;+E~^a36ia~?8xEcrxa4N8}7QVz%a@VN~w-Wl)P76zW}mq)u*@B5mdjO8p`Rb>Ca7H&lG;r^{xnBWdz|N0+T zX71uf{Yy2tVr$Fhs_19#URv78ULj_H@*PG~tNQV4y62jjA4_Q)gn4v;3q1WJVGod8 ztKa)z(EldM+Ihb`_8a;4&@p=Y5(j}0=8$nlV90F;IFWh0vwI1mjHKdLa>&6cJDT_sA8UHVn?%!)AW3;#bS^GZ&h>UF_mF(h^JnXFu50)o;AK03Z}h+y!6h!xJlq+cEh@M%m9bG`&*;l_pkGq4`oQ&p38K<1ftwb$*Zb7u!HVaZMSBk| zMD1Xq2VWYKixe3)?i;kXeer!JNJOqxhtxesN;aRf4<4CiP+iPp_*`q3Vx+$jq!baZz@3CP#H;eD-C0 z@7K}MCL@bByk??o`deytE;9qlVPh{|h&tNRW$vxT67`=I*6|cP%fL|CGa7wFbK6Xq zN&g3B;5|4Ha9WiQ{fJ>K;Sw(lhmnazkmGVGqWW0OG6ooi=1t!2&Y@)h)9AxguKh&j z7Z;9acx($geOQJsQg5g=pZuebH2o=bH_9SC0p7@Z#R6%K1IA&X=AZw>)N_Apa08{etp2mKMX`-5Qr@&ut#7O4)QGt`v-j?Q?<(lo`pXKn`A+nOVMiRgiI!b#3n%k=MIK z|NA)nmyi?aCb@Sn*esqNX|B_W&PM(IDkGC5uL4&vK;BCn{px9q#-h<^L#96)oEgv9oV(zibf3|4sTwN#U*TKb1r~~ZqmO&&rbN_{>vd$L}jU! ziQK__3vGXZk7W02A~%ggY~Jcf=7bbPaY5SPcWAH|!QsnMswZ}?k6b3}^Lf-DccvQ~ zQPhq87PMV3tF_Tgb5T30xy)U%@9H>-(8JXQ)DxtRFFw~Gav>)t1Av!aTJ;ztnE(YR z#RLV75zMz!;`p_RA3Hl6Wb675r101seK~eu(JJEDyOeJ}MgdPsN4(95+SvaFEMW26YQ-o$s_=jIK2dxz%7!^+sBGI3**T)@pd=+y}M+U+bxoC27 za`8NzReJzrK#v;c2F}xEzE^N2hn}BD;tl8t!;yo7WGh|R5iRcFR;EXPH$GGhX_95< zWeJG4&mK2)?jL}Fl96qSp;_ksKy&Ay;Gh+>4a=k~YHKRA=|@)@Fb@t>z!EP^;Wx8} zGaA1#Z+Dp&hdJQv!mbTRK#QdTmhkCV*4Njy>ur?u@zZNb(bbiJ=bTZW4Ocr0>bJ?AGxw@ki zKiC6XErG4}!3z483S4?}3M!=+WXjg&fJOiwyd~`1!a|n4RS}-Xg#SqR7_O}+AD0SU z^;B-Vr2dsh9)de3@8cM@-PYxl9{W6Rgkyg_W$IWzV*<7KSKf`)!Cm1>SXd`!Gx_8` zm&0{U%d5f6nwjbjyr09gs@J2vqoUUhpXB7`w6dlJJ@Hp%9h8>m(t6B@ zloW0>bxL?!U?vK1 z6{ATW4RPpEgJgyDE}%YT_4BI7m);{S?Msn}fA`>5uK5qloxwKvzo%2U39Jjoq6vS} z<|9n#MB0Lq$K#!&lV(X#tqLKX+P4Omnhdm#Hx|ymVan4!`f3&yF6Yq3HQb@*D5ICM z@9LOv#=Vx9Hiv@9I>1S8il&9|luYMqY;uF*XKA3fL_;>e; z4}JW!I7HxPCFkSz6$>|8qx&m|9(j~lpEd7g^%den%zmmi5rWMI{KQE9Y6J8^8zog z?-->yKfFUKAS5zi(W-gvHTvtt`a1{vEsIaf=ic{)XD`y3TrQ$Eu=hyhy z@^_))W*8MzAtgJ-z%8H*kZe5aqyN-D#tLFW;uJSwOo}fppdJjLDXroeQ^$fXYI76M zdYx!_OtsrxnlW#Mqv8~_9U{m{E_g1se5kavR2hxNlj9S<;bSI)$mZw3NztVl`OO3c07dgXPuQ)Ne zdCy0Ke#rMmzOC{GchXzm{Cj^Mt|~639-PX^UA%WuZL4A|n2cUi>McfNhDu(25zZ79 z6bj)7P*4>r^MwVC&+jO2M!8Nza<_+TN$U4jp)^~+v-~7%i0{hu06jc2TEp;%A4Y}m z-z^*+$T!OBov{5FWfgON-QM1g#bQsIn=@x;U4i(5#PcwffT)0%ZqJ{Gy%Ov8HE?$q z&ilk|WH*_H>xpB4Yg|upqd!w1Eow>o+Au?H!j4lMY^)k_A)mRG0$o&~#^Ke5%qK+^ z=#6?)HDWqINK#^aTtaUppN`(A7|&KCu!YOco6^84w%=QqhCbE-L7f_&gr3~%*VyUA zBk>xc1eSXh6%R+_(iq^QS4Y^35ALcqZ9%iKN#w;2%Q$})>wfi^R^&8V#25t?rxdxJ z6e?_OJC;gv2|cn0w|cC7%c|*COGIiwwQVNTLYp$9F&(X4L$K{-21ctMvL=AK7BB`) z7+h^tfGuhc%>3rj<+MYX+&I3nO9jqjz>`41c#bUXA2hi!CB$U-0@onkzZ;Z z8amrQoQ0C;vMCY1hNOL_>(D7Je0+AIl|^TSDBd-nMUT(E`zzu_D*CL#)>RNG`gt=) zI~K?&54GU$KMmu`WfY z|CD;Kv&0E4fs%G!@_n}nw%&_eSwLJb^!JCma3|FbSARJykRN|13Y`-x8^GhpDo;Uq zjj1CT+AG}7cCC{tW^B`twV%7!Hu)BYhvw|qY)jJ)8YLk&>WN?ZaZnY%j;SrWc~Mwu z`HP?-bLuF)<$O}=BRnO?v69STM4SOH;VoHe_D2(M$RPheIE2|GfJE@=iW&{?NO^)G zMT6tm!IG~cmQ%V8AKL#^TEbiMSZ65VN%1s3qcK93&1KmuCmS^*#*(+>H5T4=ZkN4< R_$n;H^JfN6>(%We{|7*w7q$QZ literal 0 HcmV?d00001 diff --git a/bitmaps_png/sources/tune_single_track_length_legend.png b/bitmaps_png/sources/tune_single_track_length_legend.png new file mode 100644 index 0000000000000000000000000000000000000000..7530620c0c0521800ad165d75557ff47c0e56904 GIT binary patch literal 10264 zcmV+zDCgISP)|KXn6i55_zxXAu ziP0EEML=T-RuluTy~TnB6-6uwC>D?|C<=Z|o4bKwz1`cLy_>s(gYRcPeD;RfXP*7;?9^wT8K%$;4GD4V35Maz`s6?VNBtQ& zZfv2?5pYo)=m)L|WS}M;UQ9Im4CbvV4=ppua&|)3HnXh3-^%c7#4>0tEI`*l_tst% z9rY!XfjBRRF<$8JgPVcbr=Mt*fj4dj0On&yi^byQix+|mS_Zj{w-ow%@yLJ$Favwr zc_?Pbwk_bV(Dw+T3F}jGqF@46=4?t+{(!J%iQ)LDkJ0 zJt6!W47E=l(eGbmXWNrOK63^DnVUC&=Kvo>NpK(x8lND^)<)CU&yoQh>=enPCs{CM zARv_i^LrziLF&q7^hog9)MDgvxt1Bc`Qt74psIBw{uuEI>uI|D{^)zwPMO2|kT|EoSLsy5&$LF@ph6Y;dDX|okde+0LUZ{;V=wM@plYzp5eC?$Jq&uwDqjdJ7Z6N7aE?u0))E(lGp0mfLt5!sf z$=Ku|mrB*7YXVm1AbXcHy3X70ivFcjnV~|k-<5HkMn*a(u3Wx^8!lapvz`WMPz!Cv zLZfL<1$ZNjFQqgz7-*SjGl%i6?8EL)%*N#GVyF)_K`+`f;@Kj5mio(OhZB5Y_#QB2 z8cutlQ%g=ZJ$}-}@${4x7tZ3yG?4b<+#GyHK}yDn5IXp2&soK2f;f+__6)NubnwvL z*=cKFfM0;G_xI<|WoNyFkq!0rjSUT)_lom!`DyRRFoi>hp-Rrc)?T30{>Q7AVP*Q~ zy+7!|ZoUop*N$yll-m0+%x=+PQ0>(sg{sNXlHy{uc#tw?vL%jKgK5v)=`UcOvXO(t z1s(@E#Tuxs)ucTOqAbigKY(HNanbZH2YV>+@yyN1;S~grBfyPnky%+Ux$n))NL{&% zQH}KVYqa6MtFD$;d#+GTORA-hkB!yT9m0q9C8sPb1Sr(;rUoamIA1`2TF%ZpCv+Vg-tj&_GnJ|e$%#21$@ zeov2lv3`xRJ+A5dI#E57`aA_(fFZf@ClMG`k5n3dcv544x>D5~ANX5WR|_sg5f4Bz z(c=i5Tnwao(NSMIoj`S&Or{nIlEqG)jFXFjRFAe|?)=afa?@6?z$`NcQe9cAFij*= ztzvp?V*-5oo$8pyfU#&XVsNOA-(k{4b#}uuD)_NJ#d0D}GG^7M;HgfW^`m}1fdPIF zYgQ{%YqL-PeUca-2Vzbh527d5O?A?&quJ-|te2qUk@76rV%(T@t5-56?q96)0;B3N z14H%iFQ~=fsNT}jqA-5ts6lm>`BV_#fBUKG3YB4{rn_L}TYM~_AF4h{EpprDjS3nX zQ<9acYc^6tFsABNRh1G6gQ=Ku0+q?aR1L;dT@w=L&&4S-{ZVz8{^^8q>}klW4n9Qi z!Ksx5rRtyaP`xfH5)SsHsv46K6l)!7pjhtogqz{`MzQpc8ei1`B;{p&Qym@$LCu4V zfO<@U_^ua#_n4QMz<0?2s?PT=5QIVgnl#~8V2XML6?%Jer>20;`kR^>BTPHy>~Z0% zJzaI!c5>R$vOvqv6l&l3?k#3|Ey_A4w69@s>Mv^Iexy1q_n3)Qs#|HD7bA44*MUMU zxeQh@j49bwf035PH+NlCul)HZ%#@a#R8kzpa;(`Q&-jFtfyh7EDrK#{MR3M@4ySR90^qS^FE?!;{<|Es^=fvkMpJC z4>x&%z$#>%^>o%GN+S%=kJT|FI&@XNH1q_}EYp!;yrYCns%f?#mTz6wPziK;VR=w4 zHU4v-8V`C3FkarxU^N~a6WuSCPNDT3Jv?8sh=_bfkQ{1&VF9QsGq-Neb=~volKMc2 zIE=aEYiP)1mDhjFKkObq(^{=`L|abG*yI34Gg@rn(hdWLcTgL#?;h5K+Q$*k7TVFj z#JDe}CC-}*-oexHX6j=>^YP#v5PpF7F)(=l-|u%}TfnPMEq;G&3#yUsrY5yCUA;@@ z5U;OXOqeqZ-IBgxovdA=&;tel?~M%&IoVkt1o(Qx3+`J|lEFBxr-fOzxKs2_Q_5~i zqbU}PcR4$u7fgL&WS)eA0l+%~qX_~XldZrP*4r{456HJZw z=gWFZXz8gFI5HvcjQjZ@cn7^eRM>Is;V>KO!XqBUD|(aS z9d7)J#I_0nU|g3|Ly^jOB$CPKS8JFS?|Hm=$3ao=OakTxJsjwZ_cNzL|NiqHS((P? z-4APPArADyds1S8x2MO7C5tL6UlSC|gLgcO9847VmG}P5`^e!RNL4_smPjPJ{p&B_ z@7>>&zMzVWi+=jy3b=ri>wn$*AC6e#^NzQj69;;+Y^VQBh>HUwaxfrFd6o=*Zr`%G zwYAmfh;k1B)tebRFnG_^3-7({YQN@Pe=r*F1ERd^4|Mw>H6Y$GEiN(9$2*hXLhWE$ zybIKM-|zah7MtoeIjjS>%$e~8{Mpx^!7#SNgemh5S`IB{j}^VVgD`f~h?bTX#5-RT zCl;78?+9h3rS!yr*1ayyqdxkO>S_<-Wo8ETXT^ncP;A=j6aiR@ zwnekSC4^ks4ZR|OP!|=+Lu1V_G2Zhqd2g3Uz#tZzBFk4Bee(`c8~FsZ+o zdIwUVbyZ1uwrSl{eozf?-^={o@7xP zinaEpHSl@=+``=5mE$e)0%&Ys|8%uD&<~7h^AGM9xVy20LT?X4)H7vap|R7apcf!; zcjdlED`4^tdNQ!qvYSWV*c20ntl#C(MGg$5p~1v6fKI1y%De9Vgmi?V+tseRT2vN;+-Axr1>_GAkgX(luO~AV>8U)NV; zd<$@^7UB!Zs|wUfZG4u*o_O%q?*MgA|3yqyUi(28QDDS` z4Bksaj&r6T)VwQHE#cGNQlGimLA$;U+Ia^;)%72-ZW-jfL!i1Ig!q}()xX}rxvMcH zIc@D~bYq^|*O=L%DdlmWjnYADozO3MhbRpRMs)=Y3A1NFry=F%&Xj+5w&eIxq3@Ao zy9H`9ZpBA=n@5iv{=ov9+4^`2O!On(5kwE~=k5DO?H#CvOvjC7-+$MlPw4d-`y=mq zhfLNgENDzkX-G_O;=DORAJ4ac6E+-YK|kU> zBO`;wJND^Qp*&8vdOtim9h$kz8D}LZ`OEobXSiMB>yCcJJ3B^w^r1G6;N|inN@od$ zsEHFmqn&6ohjF1UedBsfXGfF5z~DV8As%%5_#QUVSu09+SW6`|ZPoIU6G6(urd1vh zf4Hi&!S8(gM(MZUz<%n6`6x^CSC{qZ9b#bcj(Xg&G0~W}bW~R*+0H{eK3}%@EzN-t z(cGLs<ufG|PclkIGKX5n{hoP`Ixj~V$f=whnHj~z7v)n?`ADE=i#ckNA$_lipw zdRA`7n~9mv%2NXH?znNi8t=QDoupFfV*3SCt$N%QWbfJurM=wdsDthdFg4z@wr_z< zvG2_QygNB=x~y7Jf(Z2YMebU&US`4z>Iy+yNs*SSGr^>I?{02FG&Ll|v7}Vv{o0RL zYu`UB8zE)sqDVcMoR}2vHFs|HOybX)fg|&hYGdZ3h==rpM-kBG)ohm?*vfLlqw+4M7~Pl0EMu_u#Ml%a;2 zaqy)bOp15Gfqm@Vb}D8~p9*-lp89z!E1IjTQJc}-Ol+p!qg(%n-U#pPR9c??`pb><7cW{`TAG`iJKEcu8XGyq8jE*%XJ;Sp*vC9^LN9*Z0t5VD zfECVS`vr>L%13F^|IY((;p?TGr=338(i+d#BNp%b^uT-9K;Zr1gZq13oYBuUtCrun zeT&Mwz3n`ZAR$h9F0Ml5SZ|ZVIvmNy>S^ zouHwl$?^_kKuOn*cdAp#n8}t0Fw znL}l6-HfR%Ck83+5fA@?7mMu|RFs#qCvHeiL`|!tq6|x2E({pnj|Xy_h2rx*f6h#Q zAFrsVk(e8Ip8dDSJ5*5snIoJADenr^x)^6kM<_dW0u}k@^fb)7STJ~b=LfkAIYdic zzC_-w>-wc>@xH&8ccQlH5H)vhqarVGcT>o9vQZrXypJ9+oH}q9i8LBh=#_T`rDFp^ z?$^7dV(oo)3;^E2s0WcgeX=D>N`3RLpqvQ`Lc-kH)xU&mCuacg4q!cXGUT0lJTM&s z{qqhW^f`j4hn@P$@M{X0l>1H!hE?6Xffa6CuL{406W;#s_lCrHf~F=4)xaH)zG?kh z_GE_PU7_;)PIYDgLbTPym)jgcFB8;7pjBrNjVZ~)Uab3ydOyLCXfwOe+f(%LK9NV= zx@iMv8iVn!P@SEVvm48|3O&@v#pscD6jGKfEDSr9o0FsOkkf1bE)4Q#PkH8aD3Kfs ze*Z1s>u}6uE8e{4?Ab~3u!B|00m})qXV5bPrGwylJR>m6yI3sddx9AU|K{`gVyhla;>+9uNTPvC~;|qc+X@YThN0vYd zb4b>+*)BVv*wWJ{*;CSaA3b6?ywFtDP(6I=4&(5S4$_O7I6=pSc`BYSTMWg%{_zTX zN;>bySuyR&ivxsnJ_2EO_mePbXV0lyvwEC==cs| zp4MeD)IDv^OlME4#=GaC1ApATgMPvy@49!lLbbIV{4Ej|Lf*mkt(#cK?XbgW>)NR+ zm-W=eCyo&jSQi!9Gv8@t!8sgL<6W(8G5hqB(vp%x?)wzIESnDR=oo?*U#%n}Q0VIg z1!hw=jBCOm?Y{%G_MRfYPS+(jbX1(O zgCysk^BL5<*FKKun~v9EE5+*{E+aXmC%F$rR19+76-wKyzVkFH&Y#snLVZFUTE6|>_ohiJ-V3}jL$njb7n^TENiNn4d7Ihk&~=l zQg$X39VP*7Ln^QHICTb+jt(_23i<`_039{eXuBc`pq~S}`K6~rDlT0p3kxYe>YKG= zTa=|aHBFMOO?`YUue=0#d4PARl%EAJS@aj)AxeS+qbFIav9BqBx&^!mSx1K!8R1yD z>J|NqcK}ei7YF)Ls}XvLvz{&t@Ttoe=85zwTRH)C;#BS+`YR%Gnui` zA;WP4D9yR9dkQ=cff^eOT`Mk}t&fRnfBlNAok#z{P;qC5TrQUmKyf&QT?hPabTaTzViYDomZDG2;5zxtt?o_ zI@3~DEEODZ>)GQOa=h%@QxzA#%TP@Ol$;1s_H#gIeb>%s3+>nkt?@IhK}yg&;=5V5 zpJ1rC69ee~EV8qu&M|Xta@HE{Rh3})n6l`-j4hyP=megJhB@G zyBg|?j~`9$-L~;whkLSB{-OO9=g(rgsK0vUayQo*AmaSIlHi~$r!A=5KQXGi__;H!H?Cis7_WX3c6nKu z#ket=zTPLUdl=NPU!XKb==UA^q2f*+#EW}dagosXh*~!~%EDae>m|<1iGWwh)lr1wsNO5LQJ%kTnoU;C*p44U<7b=1vmG{LVd|Y~J~zzqz@0 z=HB~t4$=SS6%|@cnT&JYW2+*$I1E*by>{S?PqVau6Vkvh-O#$D2d(a1A+SRV$_dMHKO5KGYCxl5G8$_YOxXU>36voFI z&3e)kwC?CZs5|swgrUK>c0Fs+0vI4_S0SeR#&z!SI41hsP{U~7U0&|4E2STIN@;Iz zU-9EoPmk@YpOH&@V8DRu*l=cADz>OK)aeGa?&v|NyZGoquC0x#Puw}P;YF=0{H*R# zk;fJ}*tfN|YEqkAA`ynNaMSj3m$|%3xTo4dEk z*NhQ;?ktw9hs)tin_^PT8{Vi_N#&^%$}B%v$@yVP{jHm*;zS6oJ9?1lE^BXBF6vd5 z(%=9jSplI@pEYBe>BR3Wr%o|9Wu&F1kg2WhS$^TiErgUeyhPM*%B%&n?&v|HyQH$B zWS`%lo{R}Y6viSSUQKnC>J4C!KJwU+OBds{E`OYl;RpEP&P=V>fKUppJ9?1l-cejs z?7ef)h3)AUsPZO5A7-|dB}fl{lAq%s>*^G$WIFlKeP;)0e)CIb(7K}sjqW_qeb6{H z&C;U$AhI;!2$4&=)caj9TJ2TK`l)wl-O+(Yll4RbAaTW4?p}1FU{Sy-ht}gu3^1s}EJnSj^t0A(Mpa zixHzc_-#9L28do$Qw_#%T8}J=J8~%09nqB;w8(pULCPK5y7x*&1VdF?_u;d4wJYeD{Nx|PcmMq3 zCcNw7Y<>=M(x_}>g7v|9PGO#5~$&~ zxbvuDHa^{ZiF9XDoikkv3|)7GKm*^TlWPS=r+Z&7ac73s-54-F-TMf2@2P*S@6hnj zx}!&-``I%jD^b@y)nIj(5$PUG>uwzAMR&Peu3Sk?1>HmMc;7FR5$TR*B??+--O+uw~V(Vah}?rp8D zhxUh07&jJo7eWWRtCpqCPC40GiudGl0^NfGdS2C07ms$(x}%3W-Gvcsb?ua8y}O&I z$99U!bTd=JgF<_M^pt+lr+)KB!p!OBdTHIi8S|yDx96+6e{B|pv64+E zt43SmzgHqIr!F4tpmj$NmAZ$if3msxZ73^f{Ma#?=nm(}?Z0kq-?DMZq6M4QuRVMq zLc@fcpu5w8`Phv-b;=Kh>%}o z-9^7_t&NWx=+|fZd0KY_;4;dGvqR3EKBfAK7IhNnKFz$`Ah*?3N8Zy@arnT~MGJ7o zC!0>@@7Yy%Ilf;xnx9w33M5R!o$tCFzDt*= zOvfS7x+4QxbamH%Pq?mKZJ;}UgzJv+=I-s1eS1^P3DVdnnJ^06R*J${4T*Pjld_N2 z9VOV>S!E%UCZIzwN_5OjG+_V$2dPO!K~%?hmz60B4bHT;QvUp+6(j|F6Eqmtf#`p0mV=>_$t}-gJ z>B(b7o@l)eebmY1rel++pff_Io>8VdhODczHZHc5>Cc@rdnoS-&V(tGQ!UJ3q)w(h zU%R@Qld8}?f7No$k8Nlr&1!nV>Q$w|fyGA;<=(%W!R6|`BwW9C_s(sSmE`^TN1>+& zPWO^9mfpV|l9HL4`XWBAlpXwX+h)!zD;;=J;JRWo=&o9l7!z}sE`hec;eKL2l`GkF z02QtKl}i^Vj2o*uan~^Dmx#+>-?%1^{*vW;?A#&&0=%KwmI( zfjy!0a7vW;`@X($eSmZZA{~QP_dUD4ahHrzl9SK|JR%sux(`AwZ{c#F?ay86qAq>1 z2?L~Wd~i?SQ4Rxyx??-Bsh5On2AbQNI!24`AL;Mwdv*PaV6P7@b2*f>8PlPAV}P5V z5Yi#w^LKlZ*M0Mb^|P%kv0`OmHh%0F8=EN`~p88_2Ev@FIyV! z8{#(EI8f=XN@c~THOcUxAc|AkL3 zWTf+byl}>6J3Cd!lHJCUQfS?&VD#$_be8Z-0`XbQ3*1&U+`FUi(1wK8oeGRXcc85x zkLR@$XFQw(T@@mIheiyM?o(;qNn$Lz1GN`_&04%rRUqzMTk(mb`i_ejT6ZciBHeqN z-wN45xCUOa4Y`4B4uJt3Fx-$s$GWGbrtJ3G$qr_cIijIqM7jgw$iwNgXASPbuWU}! zewr?I=vQ|v@0G8&C;SQ0lR2nCVO+Yu{yiakiPNALeM!BxMTOu(xWqkYJuj*fan13M@mX!$j zdAT{z_80Sb{r&xq9zKXWA5&Xfqlmn@`N`wI;Q@R`SXP>oopm8LI_qgBnaELLT)Ime z-juPJxX~(%Uwd1c^&J|X%2OvY>}*xzgx{scM-R!=`B~kc7372K4tBO-Y?f*X^!J0; ztt`y2Jtd)Uv&g|7`zywHthk0hu&4Rd;2&X7~(zl1%VOFgo2k zig|orZ~W!R;K1(cDt(9cFK|w#+gPhc_|(y%=6p2CYCo+zw8S8EYD)4@AAsf=J`m0h zp>-cgRL7pna&lCaDaG7O6vmQucIZ1a1-0>U@PnfoUa|>82;p_KldPG(&18(aE3!OC zuyNTYQm2`V!b220J?NF1xY)d(mf?PU1pdAq#R!($(YhO>?tok(0l7hORjZOFPby{Z zYk&D%FCob~JInWna_8cAq~QB_w;{^*~^F zFpUoq1$%cVF(%?pzp~(f&azTeN1=5$UfnTXUAtVkbra5bC@;5cs5%`bmrySK+ms}5 zI(6DqTmalTvqk$u``XEFB^Mue;q=K9SP2OVG&f}^pF+|6=F#ZD*mVb_Z|X&1AzWJ< zb?ITq2z{OoJ`edp``TLJbSmDpQ+-Wsk_kiL=iB%4mCc! z*Ci?&>hfj3RN7rv+mgwxjyWp~58-)vWZ2Igs@l})<|X^~y#D<}yV z8xACjry{c?A2f3+Jy~ zzNE|Y+plpXYe*%ri?`mPb=MTd9(~UXDo;lVLs>lU9XT$}(Er9=IwWYn&CQ-Juz$I6 zeOWNG{6JXK<43)3oAmuvj2BvWQuO!rN#E3W2>5L;p1sS-YUXlUo@TTb Date: Wed, 18 Feb 2015 00:51:40 +0100 Subject: [PATCH 10/23] undo should work on pads too (GAL view) --- pcbnew/board_undo_redo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 6bef956fc1..c999b37da7 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -387,7 +387,7 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, BOARD_ITEM* item = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii ); // For texts belonging to modules, we need to save state of the parent module - if( item->Type() == PCB_MODULE_TEXT_T ) + if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_PAD_T ) { item = item->GetParent(); wxASSERT( item->Type() == PCB_MODULE_T ); From 5d78a007cc6befad5fbfc9155beecb226c4266db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:53:57 +0100 Subject: [PATCH 11/23] added ClassOf() for DRAWSEGMENTs, PADs and PCB_TEXTs --- pcbnew/class_drawsegment.h | 5 +++++ pcbnew/class_pad.h | 5 +++++ pcbnew/class_pcb_text.h | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 7316b4e554..3c5667ebd6 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -69,6 +69,11 @@ public: /// skip the linked list stuff, and parent const DRAWSEGMENT& operator = ( const DRAWSEGMENT& rhs ); + static inline bool ClassOf( const EDA_ITEM *aItem ) + { + return aItem && PCB_LINE_T == aItem->Type(); + } + void SetWidth( int aWidth ) { m_Width = aWidth; } int GetWidth() const { return m_Width; } diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index c68596bd29..339b4dc65b 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -94,6 +94,11 @@ public: ///< used for edge board connectors static LSET UnplatedHoleMask(); ///< layer set for a mechanical unplated through hole pad + static inline bool ClassOf( const EDA_ITEM *aItem ) + { + return aItem && PCB_PAD_T == aItem->Type(); + } + void Copy( D_PAD* source ); D_PAD* Next() const { return static_cast( Pnext ); } diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index 7a6d853704..9bdcd2a720 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -49,6 +49,11 @@ public: ~TEXTE_PCB(); + static inline bool ClassOf( const EDA_ITEM *aItem ) + { + return aItem && PCB_TEXT_T == aItem->Type(); + } + virtual const wxPoint& GetPosition() const { return m_Pos; From da9fc844217547e0054d527b3b08fbed1dc26d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 00:58:14 +0100 Subject: [PATCH 12/23] improved module locking: lock pads only/lock whole module mode added --- pcbnew/class_module.cpp | 28 ++++++++++++++----- pcbnew/class_module.h | 18 ++++++++++++ pcbnew/class_pad.cpp | 1 - .../dialog_edit_module_for_BoardEditor.cpp | 16 ++++++++--- ...ialog_edit_module_for_BoardEditor_base.cpp | 4 +-- ...ialog_edit_module_for_BoardEditor_base.fbp | 4 +-- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index c6e0b5d5e5..1f9462da5c 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -57,7 +57,7 @@ MODULE::MODULE( BOARD* parent ) : m_Attributs = MOD_DEFAULT; m_Layer = F_Cu; m_Orient = 0; - m_ModuleStatus = 0; + m_ModuleStatus = MODULE_PADS_LOCKED; flag = 0; m_CntRot90 = m_CntRot180 = 0; m_Surface = 0.0; @@ -815,6 +815,11 @@ void MODULE::RunOnChildren( boost::function aFunction ) } } +const BOX2I MODULE::ViewBBox() const +{ + return BOX2I( VECTOR2I( GetFootprintRect().GetOrigin() ), + VECTOR2I( GetFootprintRect().GetSize() ) ); +} void MODULE::ViewUpdate( int aUpdateFlags ) { @@ -867,12 +872,6 @@ unsigned int MODULE::ViewGetLOD( int aLayer ) const return 30; } -const BOX2I MODULE::ViewBBox() const -{ - EDA_RECT fpRect = GetFootprintRect(); - - return BOX2I( VECTOR2I( fpRect.GetOrigin() ), VECTOR2I( fpRect.GetSize() ) ); -} /* Test for validity of the name in a library of the footprint * ( no spaces, dir separators ... ) @@ -1116,3 +1115,18 @@ void MODULE::SetOrientation( double newangle ) CalculateBoundingBox(); } +double MODULE::PadCoverageRatio() const +{ + double padArea = 0.0; + double moduleArea = GetFootprintRect().GetArea(); + + for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) + padArea += pad->GetBoundingBox().GetArea(); + + if(moduleArea == 0.0) + return 1.0; + + double ratio = padArea / moduleArea; + + return std::min(ratio, 1.0); +} diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 266b033e3f..e8ae7e6946 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -223,6 +223,7 @@ public: #define MODULE_is_LOCKED 0x01 ///< module LOCKED: no autoplace allowed #define MODULE_is_PLACED 0x02 ///< In autoplace: module automatically placed #define MODULE_to_PLACE 0x04 ///< In autoplace: module waiting for autoplace +#define MODULE_PADS_LOCKED 0x08 ///< In autoplace: module waiting for autoplace bool IsLocked() const @@ -261,6 +262,15 @@ public: m_ModuleStatus &= ~MODULE_to_PLACE; } + bool PadsLocked() const { return (m_ModuleStatus & MODULE_PADS_LOCKED ); } + void SetPadsLocked( bool aPadsLocked ) + { + if( aPadsLocked ) + m_ModuleStatus |= MODULE_PADS_LOCKED; + else + m_ModuleStatus &= ~MODULE_PADS_LOCKED; + } + void SetLastEditTime( time_t aTime ) { m_LastEditTime = aTime; } void SetLastEditTime( ) { m_LastEditTime = time( NULL ); } time_t GetLastEditTime() const { return m_LastEditTime; } @@ -559,6 +569,14 @@ public: m_initial_comments = aInitialComments; } + /** + * Function PadCoverageRatio + * Calculates the ratio of total area of the footprint pads to the area of the + * footprint. Used by selection tool heuristics. + * @return the ratio + */ + double PadCoverageRatio() const; + /// Return the initial comments block or NULL if none, without transfer of ownership. const wxArrayString* GetInitialComments() const { return m_initial_comments; } diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 4abd48edcf..7ec4f88fbc 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -177,7 +177,6 @@ const EDA_RECT D_PAD::GetBoundingBox() const area.SetOrigin( m_Pos.x-dx, m_Pos.y-dy ); area.SetSize( 2*dx, 2*dy ); break; - break; case PAD_RECT: //Use two corners and track their rotation diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp index f7430f96fb..7c7d9ba7ea 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp @@ -313,12 +313,19 @@ void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties() break; } - m_AutoPlaceCtrl->SetSelection( (m_CurrentModule->IsLocked()) ? 1 : 0 ); + if (m_CurrentModule->IsLocked() ) + m_AutoPlaceCtrl->SetSelection( 2 ); + else if (m_CurrentModule->PadsLocked() ) + m_AutoPlaceCtrl->SetSelection( 1 ); + else + m_AutoPlaceCtrl->SetSelection( 0 ); m_AutoPlaceCtrl->SetItemToolTip( 0, - _( "Enable hotkey move commands and Auto Placement" ) ); + _( "Component can be freely moved and auto placed. User can arbitrarily select and edit component's pads." ) ); m_AutoPlaceCtrl->SetItemToolTip( 1, - _( "Disable hotkey move commands and Auto Placement" ) ); + _( "Component can be freely moved and auto placed, but its pads cannot be selected or edited." ) ); + m_AutoPlaceCtrl->SetItemToolTip( 2, + _( "Component is locked: it cannot be freely moved or auto placed." ) ); m_CostRot90Ctrl->SetValue( m_CurrentModule->GetPlacementCost90() ); @@ -583,7 +590,8 @@ void DIALOG_MODULE_BOARD_EDITOR::OnOkClick( wxCommandEvent& event ) modpos.x = ValueFromTextCtrl( *m_ModPositionX ); modpos.y = ValueFromTextCtrl( *m_ModPositionY ); m_CurrentModule->SetPosition( modpos ); - m_CurrentModule->SetLocked( m_AutoPlaceCtrl->GetSelection() == 1 ); + m_CurrentModule->SetLocked( m_AutoPlaceCtrl->GetSelection() == 2 ); + m_CurrentModule->SetPadsLocked( m_AutoPlaceCtrl->GetSelection() == 1 ); switch( m_AttributsCtrl->GetSelection() ) { diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp index d47946603b..f47642935a 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp @@ -143,10 +143,10 @@ DIALOG_MODULE_BOARD_EDITOR_BASE::DIALOG_MODULE_BOARD_EDITOR_BASE( wxWindow* pare m_AttributsCtrl->SetSelection( 0 ); bSizerAttrib->Add( m_AttributsCtrl, 1, wxALL|wxEXPAND, 5 ); - wxString m_AutoPlaceCtrlChoices[] = { _("Free"), _("Locked") }; + wxString m_AutoPlaceCtrlChoices[] = { _("Free"), _("Lock pads"), _("Lock module") }; int m_AutoPlaceCtrlNChoices = sizeof( m_AutoPlaceCtrlChoices ) / sizeof( wxString ); m_AutoPlaceCtrl = new wxRadioBox( m_PanelProperties, wxID_ANY, _("Move and Place"), wxDefaultPosition, wxDefaultSize, m_AutoPlaceCtrlNChoices, m_AutoPlaceCtrlChoices, 1, wxRA_SPECIFY_COLS ); - m_AutoPlaceCtrl->SetSelection( 0 ); + m_AutoPlaceCtrl->SetSelection( 1 ); bSizerAttrib->Add( m_AutoPlaceCtrl, 1, wxALL|wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp index 80a6083222..86a87cfef9 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp @@ -2260,7 +2260,7 @@ 1 0 - "Free" "Locked" + "Free" "Lock pads" "Lock module" 1 1 @@ -2292,7 +2292,7 @@ 1 Resizable - 0 + 1 1 wxRA_SPECIFY_COLS From 4da839f30f44a682b40d20ab6bde01814eb3ea86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 01:01:02 +0100 Subject: [PATCH 13/23] groundwork for invoking module editor on selected footprint in GAL mode --- pcbnew/loadcmp.cpp | 11 +++++++++-- pcbnew/modedit.cpp | 4 ++++ pcbnew/xchgmod.cpp | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pcbnew/loadcmp.cpp b/pcbnew/loadcmp.cpp index 63034f561c..39c6449428 100644 --- a/pcbnew/loadcmp.cpp +++ b/pcbnew/loadcmp.cpp @@ -28,6 +28,8 @@ * @brief Footprints selection and loading functions. */ +#include + #include #include #include @@ -61,6 +63,10 @@ static void DisplayCmpDoc( wxString& aName, void* aData ); static FOOTPRINT_LIST MList; +static void clearModuleItemFlags ( BOARD_ITEM *aItem ) +{ + aItem->ClearFlags(); +} bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule ) { @@ -92,9 +98,10 @@ bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule ) aModule = newModule; - GetBoard()->Add( newModule ); - newModule->ClearFlags(); + newModule->RunOnChildren( boost::bind( &clearModuleItemFlags, _1 ) ); + + GetBoard()->Add( newModule ); // Clear references to any net info, because the footprint editor // does know any thing about nets handled by the current edited board. diff --git a/pcbnew/modedit.cpp b/pcbnew/modedit.cpp index 61951c2795..615a6d9343 100644 --- a/pcbnew/modedit.cpp +++ b/pcbnew/modedit.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -428,6 +429,8 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; } + m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); + // Create the "new" module MODULE* newmodule = new MODULE( *module_in_edit ); newmodule->SetParent( mainpcb ); @@ -480,6 +483,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) RN_DATA* ratsnest = pcbframe->GetBoard()->GetRatsnest(); ratsnest->Update( newmodule ); ratsnest->Recalculate(); + GetGalCanvas()->ForceRefresh(); } } break; diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index dcaea360dd..19c896be4b 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -45,6 +45,8 @@ #include #include +#include +#include static bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName ); @@ -481,6 +483,10 @@ void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, aNewModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( aNewModule ); + + m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); + GetGalCanvas()->ForceRefresh(); + } } else From 9f0b02268b36551f8232027df380bf535b8ae1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 01:04:47 +0100 Subject: [PATCH 14/23] tools: moved tools registration outside pcbframe.cpp --- pcbnew/CMakeLists.txt | 1 + pcbnew/pcbframe.cpp | 20 +++----------------- pcbnew/tools/common_actions.h | 8 ++++++++ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 0e916943cf..d4980a7d6a 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -275,6 +275,7 @@ set( PCBNEW_CLASS_SRCS tools/module_tools.cpp tools/placement_tool.cpp tools/common_actions.cpp + tools/tools_common.cpp ) set( PCBNEW_SRCS ${PCBNEW_AUTOROUTER_SRCS} ${PCBNEW_CLASS_SRCS} ${PCBNEW_DIALOGS} ) diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 1ccc128d66..e4a8d42612 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -68,17 +68,9 @@ #include #include - -#include -#include -#include -#include -#include -#include -#include -#include #include + #include #if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON) @@ -545,14 +537,8 @@ void PCB_EDIT_FRAME::setupTools() m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager ); // 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->RegisterTool( new PCB_EDITOR_CONTROL ); - m_toolManager->RegisterTool( new PLACEMENT_TOOL ); + registerAllTools ( m_toolManager ); + m_toolManager->ResetTools( TOOL_BASE::RUN ); // Run the selection tool, it is supposed to be always active diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 73849a755e..1c3b690eab 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -22,10 +22,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifndef __COMMON_ACTIONS_H +#define __COMMON_ACTIONS_H + #include #include class TOOL_EVENT; +class TOOL_MANAGER; /** * Class COMMON_ACTIONS @@ -241,3 +245,7 @@ public: */ static boost::optional TranslateLegacyId( int aId ); }; + +void registerAllTools ( TOOL_MANAGER *aToolManager ); + +#endif From a46a92f918c66d620713459edbaca56cd8a96477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 01:06:14 +0100 Subject: [PATCH 15/23] new IDs for diff pair & length tuning tools --- pcbnew/pcbnew_id.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index 830df53a88..caf8d0965c 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -39,6 +39,16 @@ enum pcbnew_ids ID_PCB_DELETE_ITEM_BUTT, ID_PCB_PLACE_OFFSET_COORD_BUTT, ID_PCB_PLACE_GRID_COORD_BUTT, + ID_DIFF_PAIR_BUTT, + ID_TUNE_SINGLE_TRACK_LEN_BUTT, + ID_TUNE_DIFF_PAIR_LEN_BUTT, + ID_TUNE_DIFF_PAIR_SKEW_BUTT, + ID_MENU_REMOVE_MEANDERS, + ID_MENU_MITER_TRACES, + ID_MENU_ADD_TEARDROPS, + ID_MENU_DIFF_PAIR_DIMENSIONS, + ID_MENU_INTERACTIVE_ROUTER_SETTINGS, + ID_PCB_MASK_CLEARANCE, ID_PCB_LAYERS_SETUP, From e5deafb4bb3067f10c20d02f492d11634c0d356f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 01:10:20 +0100 Subject: [PATCH 16/23] bulk improvements for selection and edit tools (GAL) disambiguatin heuristics and smarter grid alignment --- pcbnew/tools/common_actions.cpp | 21 +- pcbnew/tools/common_actions.h | 7 + pcbnew/tools/edit_tool.cpp | 223 ++++++++++++----- pcbnew/tools/edit_tool.h | 17 +- pcbnew/tools/grid_helper.cpp | 334 ++++++++++++++++++++++++++ pcbnew/tools/grid_helper.h | 105 ++++++++ pcbnew/tools/selection_tool.cpp | 409 +++++++++++++++++++++++++++----- pcbnew/tools/selection_tool.h | 27 ++- pcbnew/tools/tools_common.cpp | 28 +++ 9 files changed, 1046 insertions(+), 125 deletions(-) create mode 100644 pcbnew/tools/grid_helper.cpp create mode 100644 pcbnew/tools/grid_helper.h create mode 100644 pcbnew/tools/tools_common.cpp diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index c35372ea27..759dae77f5 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -58,8 +58,27 @@ TOOL_ACTION COMMON_ACTIONS::findDummy( "pcbnew.Find.Dummy", // only block the ho TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", AS_GLOBAL, 'T'); - // Edit tool actions +TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor", + AS_CONTEXT, MD_CTRL + 'E', + "Open in Footprint Editor", + "Opens the selected footprint in the Footprint Editor" ); + +TOOL_ACTION COMMON_ACTIONS::copyPadToSettings ( "pcbnew.InteractiveEdit.copyPadToSettings", + AS_CONTEXT, 0, + "Copy pad settings to Current Settings", + "Copies the properties of selected pad to the current template pad settings." ); + +TOOL_ACTION COMMON_ACTIONS::copySettingsToPads ( "pcbnew.InteractiveEdit.copySettingsToPads", + AS_CONTEXT, 0, + "Copy Current Settings to pads", + "Copies the current template pad settings to the selected pad(s)." ); + +TOOL_ACTION COMMON_ACTIONS::globalEditPads ( "pcbnew.InteractiveEdit.globalPadEdit", + AS_CONTEXT, 0, + "Global Pad Edition", + "Changes pad properties globally." ); + TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', "Move", "Moves the selected item(s)", AF_ACTIVATE ); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 1c3b690eab..850459bad7 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -236,6 +236,13 @@ public: /// Blocks CTRL+F, it is handled by wxWidgets static TOOL_ACTION findDummy; + + static TOOL_ACTION editFootprintInFpEditor; + static TOOL_ACTION copyPadToSettings; + static TOOL_ACTION copySettingsToPads; + static TOOL_ACTION globalEditPads; + + /** * Function TranslateLegacyId() * Translates legacy tool ids to the corresponding TOOL_ACTION name. diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 1747a8be71..1c772b0944 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -22,11 +22,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + #include #include #include #include #include +#include +#include #include #include @@ -41,6 +45,7 @@ #include "common_actions.h" #include "selection_tool.h" #include "edit_tool.h" +#include "grid_helper.h" EDIT_TOOL::EDIT_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), @@ -74,6 +79,11 @@ bool EDIT_TOOL::Init() m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); + // Footprint actions + m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, + SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && + SELECTION_CONDITIONS::Count ( 1 ) ); + m_offset.x = 0; m_offset.y = 0; @@ -82,6 +92,20 @@ bool EDIT_TOOL::Init() return true; } +bool EDIT_TOOL::invokeInlineRouter() +{ + TRACK *track = uniqueSelected (); + VIA *via = uniqueSelected (); + + if( track || via ) + { + printf("Calling interactive drag\n"); + m_toolMgr->RunAction( COMMON_ACTIONS::routerInlineDrag, true ); + return true; + } + + return false; +} int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) { @@ -90,11 +114,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - // Be sure that there is at least one item that we can modify - if( !makeSelection( selection ) ) + // Be sure that there is at least one item that we can modify. If nothing was selected before, + // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) + if( !hoverSelection( selection ) ) { setTransitions(); - return 0; } @@ -102,6 +126,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? + bool lockOverride = false; + bool isDragAndDrop = false; // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; @@ -109,9 +135,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); controls->ShowCursor( true ); - controls->SetSnapping( true ); + //controls->SetSnapping( true ); controls->ForceCursorPosition( false ); + GRID_HELPER grid ( editFrame ); + // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { @@ -151,10 +179,22 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { - m_cursor = controls->GetCursorPosition(); + //if ( invokeInlineRouter ( ) ) + // break; + VECTOR2I mousePos = evt->Position(); + + m_cursor = grid.Align ( evt->Position() ); + isDragAndDrop = evt->IsDrag( BUT_LEFT ); + + if( m_dragging ) { + + + m_cursor = grid.BestSnapAnchor ( evt->Position(), selection.Item( 0 ) ); + getViewControls()->ForceCursorPosition ( true, m_cursor ); + wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - selection.Item( 0 )->GetPosition(); @@ -166,33 +206,52 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } else // Prepare to start dragging { - if( m_selectionTool->CheckLock() || selection.Empty() ) + m_selectionTool->SanitizeSelection( ); + + if ( selection.Empty() ) break; + // deal with locked items (override lock or abort the operation) + SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock(); + + if ( lockFlags == SELECTION_LOCKED ) + break; + else if ( lockFlags == SELECTION_LOCK_OVERRIDE ) + lockOverride = true; + // Save items, so changes can be undone editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + VECTOR2I origin; + + + if( evt->IsDrag( BUT_LEFT ) ) + mousePos = evt->DragOrigin(); + + // origin = grid.Align ( evt->DragOrigin() ); + //else + origin = grid.Align ( mousePos ); + if( selection.Size() == 1 ) { // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later - m_cursor = VECTOR2I( selection.Item( 0 )->GetPosition() ); - m_offset.x = 0; - m_offset.y = 0; + m_cursor = grid.BestDragOrigin ( mousePos, selection.Item( 0 ) ); + getViewControls()->ForceCursorPosition ( true, m_cursor ); + grid.SetAuxAxes ( true, m_cursor ); + + VECTOR2I o = VECTOR2I( selection.Item( 0 )->GetPosition() ); + m_offset.x = o.x - m_cursor.x; + m_offset.y = o.y - m_cursor.y; } else { - VECTOR2D origin; - - if( evt->IsDrag( BUT_LEFT ) ) - origin = getView()->GetGAL()->GetGridPoint( evt->DragOrigin() ); - else - origin = getViewControls()->GetCursorPosition(); - - // Update dragging offset (distance between cursor and the first dragged item) m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - wxPoint( origin.x, origin.y ); + + getViewControls()->ForceCursorPosition ( true, origin ); + } controls->SetAutoPan( true ); @@ -204,7 +263,12 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) - break; // Finish + { + if (!isDragAndDrop || !lockOverride ) + break; // Finish + + lockOverride = false; + } } m_dragging = false; @@ -231,7 +295,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) ratsnest->Recalculate(); controls->ShowCursor( false ); - controls->SetSnapping( false ); + //controls->SetSnapping( false ); controls->SetAutoPan( false ); setTransitions(); @@ -245,7 +309,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - if( !makeSelection( selection ) ) + if( !hoverSelection( selection, false ) ) { setTransitions(); @@ -258,22 +322,6 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) // Display properties dialog BOARD_ITEM* item = selection.Item( 0 ); - // Check if user wants to edit pad or module properties - if( item->Type() == PCB_MODULE_T ) - { - VECTOR2D cursor = getViewControls()->GetCursorPosition(); - - for( D_PAD* pad = static_cast( item )->Pads(); pad; pad = pad->Next() ) - { - if( pad->ViewBBox().Contains( cursor ) ) - { - // Turns out that user wants to edit a pad properties - item = pad; - break; - } - } - } - std::vector& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; // Some of properties dialogs alter pointers, so we should deselect them @@ -317,7 +365,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) + if( !hoverSelection( selection ) ) { setTransitions(); @@ -371,7 +419,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) + if( !hoverSelection( selection ) ) { setTransitions(); @@ -421,7 +469,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) + if( !hoverSelection( selection ) ) { setTransitions(); @@ -477,40 +525,58 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) // Default removal procedure case PCB_MODULE_TEXT_T: { - if( m_editModules ) - { - TEXTE_MODULE* text = static_cast( aItem ); + TEXTE_MODULE* text = static_cast( aItem ); - switch( text->GetType() ) - { + switch( text->GetType() ) + { case TEXTE_MODULE::TEXT_is_REFERENCE: - DisplayError( getEditFrame(), _( "Cannot delete REFERENCE!" ) ); + DisplayError( getEditFrame(), _( "Cannot delete component reference." ) ); return; case TEXTE_MODULE::TEXT_is_VALUE: - DisplayError( getEditFrame(), _( "Cannot delete VALUE!" ) ); + DisplayError( getEditFrame(), _( "Cannot delete component value." ) ); return; case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings break; - } } - } - /* no break */ - case PCB_PAD_T: - case PCB_MODULE_EDGE_T: if( m_editModules ) { + MODULE* module = static_cast( aItem->GetParent() ); module->SetLastEditTime(); - board->m_Status_Pcb = 0; // it is done in the legacy view aItem->DeleteStructure(); } return; - break; + } + + case PCB_PAD_T: + case PCB_MODULE_EDGE_T: + { + MODULE* module = static_cast( aItem->GetParent() ); + module->SetLastEditTime(); + + board->m_Status_Pcb = 0; // it is done in the legacy view + + + if(!m_editModules) + { + if(aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1) + { + DisplayError( getEditFrame(), _( "Cannot delete the only remaining pad of the module (modules on PCB must have at least one pad)." ) ); + return; + } + getView()->Remove( aItem ); + board->Remove( aItem ); + } + + aItem->DeleteStructure(); + + return; + } case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer @@ -526,7 +592,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) default: // other types do not need to (or should not) be handled assert( false ); return; - break; } getView()->Remove( aItem ); @@ -541,6 +606,8 @@ void EDIT_TOOL::setTransitions() Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); + + Go( &EDIT_TOOL::editFootprintInFpEditor, COMMON_ACTIONS::editFootprintInFpEditor.MakeEvent() ); } @@ -550,6 +617,7 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw ) RN_DATA* ratsnest = getModel()->GetRatsnest(); ratsnest->ClearSimple(); + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item( i ); @@ -579,16 +647,28 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) } } - -bool EDIT_TOOL::makeSelection( const SELECTION& aSelection ) +bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) { if( aSelection.Empty() ) // Try to find an item that could be modified + { m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); + if ( m_selectionTool->CheckLock() == SELECTION_LOCKED ) + { + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + return false; + } + } + + if ( aSanitize ) + m_selectionTool->SanitizeSelection(); + + if ( aSelection.Empty() ) + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + return !aSelection.Empty(); } - void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) { for( unsigned int i = 0; i < aList->GetCount(); ++i ) @@ -626,3 +706,32 @@ void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) } } } + +int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) +{ + MODULE *mod = uniqueSelected (); + + if( !mod ) + return 0; + + PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); + + editFrame-> SetCurItem( mod ); + + if( editFrame->GetCurItem()->GetTimeStamp() == 0 ) // Module Editor needs a non null timestamp + { + editFrame->GetCurItem()->SetTimeStamp( GetNewTimeStamp() ); + editFrame->OnModify(); + } + + FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) editFrame->Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); + + editor->Load_Module_From_BOARD( (MODULE*)editFrame->GetCurItem() ); + editFrame->SetCurItem( NULL ); // the current module could be deleted by + + editor->Show( true ); + editor->Raise(); // Iconize( false ); + + setTransitions(); + return 0; +} diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index ca50fc01ec..c2ded9a84a 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -147,10 +147,25 @@ private: ///> If there are no items currently selected, it tries to choose the item that is under ///> the cursor or displays a disambiguation menu if there are multpile items. - bool makeSelection( const SELECTION& aSelection ); + bool hoverSelection( const SELECTION& aSelection, bool aSanitize = true ); ///> Updates view with the changes in the list. void processChanges( const PICKED_ITEMS_LIST* aList ); + + int editFootprintInFpEditor( const TOOL_EVENT& aEvent ); + + bool invokeInlineRouter(); + + template T* uniqueSelected() + { + const SELECTION& selection = m_selectionTool->GetSelection(); + + if(selection.items.GetCount() > 1) + return NULL; + + BOARD_ITEM *item = selection.Item( 0 ); + return dyn_cast (item); + } }; #endif diff --git a/pcbnew/tools/grid_helper.cpp b/pcbnew/tools/grid_helper.cpp new file mode 100644 index 0000000000..271aae5462 --- /dev/null +++ b/pcbnew/tools/grid_helper.cpp @@ -0,0 +1,334 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 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 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 +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "grid_helper.h" + +GRID_HELPER::GRID_HELPER ( PCB_BASE_FRAME *aFrame ) : + m_frame ( aFrame ) +{ + +} + +GRID_HELPER::~GRID_HELPER () +{ + +} + +void GRID_HELPER::SetGrid ( int aSize ) +{ + assert ( false ); +} + +void GRID_HELPER::SetOrigin ( const VECTOR2I& aOrigin ) +{ +} + +VECTOR2I GRID_HELPER::GetGrid () +{ + PCB_SCREEN *screen = m_frame->GetScreen(); + + const wxRealPoint& size = screen->GetGridSize(); + + return VECTOR2I ( KiROUND ( size.x ), KiROUND ( size.y ) ); +} + +VECTOR2I GRID_HELPER::GetOrigin () +{ + return VECTOR2I ( 0, 0 ); +} + +void GRID_HELPER::SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal) +{ + if( aEnable ) + m_auxAxis = aOrigin; + else + m_auxAxis = boost::optional (); + + m_diagonalAuxAxesEnable = aEnable; +} + +VECTOR2I GRID_HELPER::Align ( const VECTOR2I& aPoint ) +{ + const VECTOR2D gridOffset ( GetOrigin () ); + const VECTOR2D gridSize ( GetGrid() ); + + VECTOR2I nearest ( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x, + round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y ); + + if ( !m_auxAxis ) + return nearest; + + if ( std::abs ( m_auxAxis->x - aPoint.x) < std::abs ( nearest.x - aPoint.x ) ) + nearest.x = m_auxAxis->x; + + if ( std::abs ( m_auxAxis->y - aPoint.y) < std::abs ( nearest.y - aPoint.y ) ) + nearest.y = m_auxAxis->y; + + return nearest; +} + +VECTOR2I GRID_HELPER::BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ) +{ + clearAnchors(); + computeAnchors( aItem, aMousePos ); + + double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); + double lineSnapMinCornerDistance = 50.0 / worldScale; + + ANCHOR* nearestOutline = nearestAnchor ( aMousePos, OUTLINE, LSET::AllLayersMask() ); + ANCHOR* nearestCorner = nearestAnchor ( aMousePos, CORNER, LSET::AllLayersMask() ); + ANCHOR* nearestOrigin = nearestAnchor ( aMousePos, ORIGIN, LSET::AllLayersMask() ); + ANCHOR* best = NULL; + double minDist = std::numeric_limits::max(); + + if (nearestOrigin) + { + minDist = nearestOrigin->Distance(aMousePos); + best = nearestOrigin; + } + + if (nearestCorner) + { + double dist = nearestCorner->Distance(aMousePos); + if (dist < minDist) + { + minDist = dist; + best = nearestCorner; + } + } + + if (nearestOutline) + { + double dist = nearestOutline->Distance(aMousePos); + if (minDist > lineSnapMinCornerDistance && dist < minDist) + best = nearestOutline; + } + + return best ? best->pos : aMousePos; +} + +std::set GRID_HELPER::queryVisible ( const BOX2I& aArea ) +{ + std::set items; + + std::vector selectedItems; + std::vector::iterator it, it_end; + + m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items + + for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) + { + BOARD_ITEM* item = static_cast( it->first ); + if( item->ViewIsVisible() ) + items.insert ( item ); + } + + return items; +} + +VECTOR2I GRID_HELPER::BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ) +{ + double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); + int snapRange = (int) (100.0 / worldScale); + + BOX2I bb ( VECTOR2I ( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2) , VECTOR2I (snapRange, snapRange) ); + + clearAnchors(); + + BOOST_FOREACH ( BOARD_ITEM *item, queryVisible ( bb ) ) + { + computeAnchors(item, aOrigin); + } + + LSET layers ( aDraggedItem->GetLayer() ); + ANCHOR *nearest = nearestAnchor ( aOrigin, CORNER | SNAPPABLE, layers ); + + VECTOR2I nearestGrid = Align ( aOrigin ); + double gridDist = (nearestGrid - aOrigin).EuclideanNorm(); + if (nearest) + { + double snapDist = nearest->Distance ( aOrigin ); + + if(nearest && snapDist < gridDist) + return nearest->pos; + } + + return nearestGrid; +} + +void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ) +{ + VECTOR2I origin; + + + switch ( aItem->Type() ) + { + case PCB_MODULE_T: + { + MODULE *mod = static_cast (aItem); + addAnchor ( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); + + for (D_PAD *pad = mod->Pads(); pad; pad = pad->Next() ) + addAnchor ( pad->GetPosition(), CORNER | SNAPPABLE, pad ); + + break; + } + + case PCB_MODULE_EDGE_T: + case PCB_LINE_T: + { + DRAWSEGMENT *dseg = static_cast (aItem); + VECTOR2I start = dseg->GetStart(); + VECTOR2I end = dseg->GetEnd(); + //LAYER_ID layer = dseg->GetLayer(); + + + switch( dseg->GetShape() ) + { + case S_CIRCLE: + { + int r = (start - end).EuclideanNorm(); + + addAnchor ( start, ORIGIN | SNAPPABLE, dseg ); + addAnchor ( start + VECTOR2I ( -r, 0 ) , OUTLINE | SNAPPABLE, dseg ); + addAnchor ( start + VECTOR2I ( r, 0 ) , OUTLINE | SNAPPABLE, dseg ); + addAnchor ( start + VECTOR2I ( 0, -r ) , OUTLINE | SNAPPABLE, dseg); + addAnchor ( start + VECTOR2I ( 0, r ) , OUTLINE | SNAPPABLE, dseg ); + break; + } + + case S_ARC: + { + origin = dseg->GetCenter(); + addAnchor ( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); + addAnchor ( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); + addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); + break; + } + + case S_SEGMENT: + { + origin.x = start.x + ( start.x - end.x ) / 2; + origin.y = start.y + ( start.y - end.y ) / 2; + addAnchor ( start, CORNER | SNAPPABLE, dseg ); + addAnchor ( end, CORNER | SNAPPABLE, dseg ); + addAnchor ( origin, ORIGIN, dseg ); + break; + } + + default: + { + origin = dseg->GetStart(); + addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); + break; + } + } + break; + } + + case PCB_TRACE_T: + { + TRACK *track = static_cast (aItem); + VECTOR2I start = track->GetStart(); + VECTOR2I end = track->GetEnd(); + origin.x = start.x + ( start.x - end.x ) / 2; + origin.y = start.y + ( start.y - end.y ) / 2; + addAnchor ( start, CORNER | SNAPPABLE, track ); + addAnchor ( end, CORNER | SNAPPABLE, track ); + addAnchor ( origin, ORIGIN, track); + break; + } + + case PCB_ZONE_AREA_T: + { + const CPolyLine* outline = static_cast( aItem )->Outline(); + int cornersCount = outline->GetCornersCount(); + + SHAPE_LINE_CHAIN lc; + lc.SetClosed ( true ); + + for( int i = 0; i < cornersCount; ++i ) + { + const VECTOR2I p ( outline->GetPos( i ) ); + addAnchor ( p, CORNER, aItem ); + lc.Append ( p ); + } + + addAnchor( lc.NearestPoint ( aRefPos ), OUTLINE, aItem ); + + break; + } + + case PCB_MODULE_TEXT_T: + case PCB_TEXT_T: + addAnchor ( aItem->GetPosition(), ORIGIN, aItem ); + default: + + + break; + } + +} + +GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ) +{ + double minDist = std::numeric_limits::max(); + ANCHOR *best = NULL; + + BOOST_FOREACH( ANCHOR& a, m_anchors ) + { + if ( !aMatchLayers [ a.item->GetLayer() ] ) + continue; + + if ( ( aFlags & a.flags ) != aFlags ) + continue; + + double dist = a.Distance(aPos); + + if(dist < minDist) + { + minDist = dist; + best = &a; + } + } + + return best; + +} \ No newline at end of file diff --git a/pcbnew/tools/grid_helper.h b/pcbnew/tools/grid_helper.h new file mode 100644 index 0000000000..11e9c7ce47 --- /dev/null +++ b/pcbnew/tools/grid_helper.h @@ -0,0 +1,105 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 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 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 __GRID_HELPER_H +#define __GRID_HELPER_H + +#include + +#include +#include + +#include + +class PCB_BASE_FRAME; + +class GRID_HELPER { +public: + + GRID_HELPER ( PCB_BASE_FRAME *aFrame ); + ~GRID_HELPER (); + + void SetGrid ( int aSize ); + void SetOrigin ( const VECTOR2I& aOrigin ); + + VECTOR2I GetGrid (); + VECTOR2I GetOrigin (); + + void SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin = VECTOR2I(0, 0), bool aEnableDiagonal = false ); + + VECTOR2I Align ( const VECTOR2I& aPoint ); + + VECTOR2I BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ); + VECTOR2I BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ); + +private: + + enum ANCHOR_FLAGS { + CORNER = 0x1, + OUTLINE = 0x2, + SNAPPABLE = 0x4, + ORIGIN = 0x8 + }; + + struct ANCHOR + { + ANCHOR ( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM *aItem = NULL ): + pos (aPos), flags (aFlags), item (aItem) {} ; + + VECTOR2I pos; + int flags; + BOARD_ITEM *item; + + double Distance ( const VECTOR2I& aP ) + { + return (aP - pos).EuclideanNorm(); + } + + bool CanSnapItem ( const BOARD_ITEM *aItem ); + }; + + std::vector m_anchors; + + std::set queryVisible ( const BOX2I& aArea ); + + void addAnchor( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM *aItem = NULL ) + { + m_anchors.push_back( ANCHOR( aPos, aFlags, aItem ) ); + } + + ANCHOR* nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ); + + void computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ); + + void clearAnchors () + { + m_anchors.clear(); + } + + PCB_BASE_FRAME* m_frame; + boost::optional m_auxAxis; + bool m_diagonalAuxAxesEnable; +}; + +#endif diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index fbbec3e43f..ae66146ce4 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.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-2015 CERN * @author Tomasz Wlostowski * @author Maciej Suminski * @@ -22,14 +22,20 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include +#include + #include #include #include #include +#include +#include + #include #include @@ -69,9 +75,12 @@ SELECTION_TOOL::~SELECTION_TOOL() void SELECTION_TOOL::Reset( RESET_REASON aReason ) { if( aReason == TOOL_BASE::MODEL_RELOAD ) + { // Remove pointers to the selected items from containers // without changing their properties (as they are already deleted) + m_selection.group->Clear(); m_selection.clear(); + } else // Restore previous properties of selected items and remove them from containers clearSelection(); @@ -250,16 +259,12 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) } -bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aAllowDisambiguation ) +bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aOnDrag ) { BOARD_ITEM* item; GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); GENERAL_COLLECTOR collector; - // Preferred types (they have the priority when if they are covered by a bigger item) - const KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_LINE_T, - PCB_MODULE_EDGE_T, PCB_MODULE_TEXT_T, EOT }; - if( m_editModules ) collector.Collect( getModel(), GENERAL_COLLECTOR::ModuleItems, wxPoint( aWhere.x, aWhere.y ), guide ); @@ -267,10 +272,19 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aAllowDisambigua collector.Collect( getModel(), GENERAL_COLLECTOR::AllBoardItems, wxPoint( aWhere.x, aWhere.y ), guide ); + bool anyCollected = collector.GetCount() != 0; + + // Remove unselectable items + for( int i = collector.GetCount() - 1; i >= 0; --i ) + { + if( !selectable( collector[i] ) || ( aOnDrag && collector[i]->IsLocked() )) + collector.Remove( i ); + } + switch( collector.GetCount() ) { case 0: - if( !m_additive ) + if( !m_additive && anyCollected ) clearSelection(); return false; @@ -281,21 +295,9 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aAllowDisambigua return true; default: - // Remove unselectable items - for( int i = collector.GetCount() - 1; i >= 0; --i ) - { - if( !selectable( collector[i] ) ) - 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; - } + + // Apply some ugly heuristics to avoid disambiguation menus whenever possible + guessSelectionCandidates( collector ); // Let's see if there is still disambiguation in selection.. if( collector.GetCount() == 1 ) @@ -304,9 +306,11 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aAllowDisambigua return true; } - - else if( aAllowDisambiguation && collector.GetCount() > 1 ) + else if( collector.GetCount() > 1 ) { + if( aOnDrag ) + Wait ( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); + item = disambiguationMenu( &collector ); if( item ) @@ -354,6 +358,9 @@ bool SELECTION_TOOL::selectMultiple() if( evt->IsMouseUp( BUT_LEFT ) ) { + // End drawing the selection box + m_selArea->ViewSetVisible( false ); + // Mark items within the selection box as selected std::vector selectedItems; BOX2I selectionBox = m_selArea->ViewBBox(); @@ -407,11 +414,10 @@ void SELECTION_TOOL::setTransitions() Go( &SELECTION_TOOL::findMove, COMMON_ACTIONS::findMove.MakeEvent() ); } - -bool SELECTION_TOOL::CheckLock() +SELECTION_LOCK_FLAGS SELECTION_TOOL::CheckLock() { if( !m_locked || m_editModules ) - return false; + return SELECTION_UNLOCKED; bool containsLocked = false; @@ -438,18 +444,22 @@ bool SELECTION_TOOL::CheckLock() } } - if( containsLocked && - !IsOK( m_frame, _( "Selection contains locked items. Do you want to continue?" ) ) ) + if( containsLocked ) { - return true; + if ( IsOK( m_frame, _( "Selection contains locked items. Do you want to continue?" ) ) ) + { + m_locked = false; + return SELECTION_LOCK_OVERRIDE; + } + else + return SELECTION_LOCKED; } - + m_locked = false; - return false; + return SELECTION_UNLOCKED; } - int SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent ) { selectCursor( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); @@ -511,7 +521,6 @@ void SELECTION_TOOL::findCallback( BOARD_ITEM* aItem ) { clearSelection(); select( aItem ); - getView()->SetCenter( VECTOR2D( aItem->GetPosition() ) ); // Inform other potentially interested tools m_toolMgr->ProcessEvent( SelectedEvent ); @@ -562,8 +571,9 @@ void SELECTION_TOOL::clearSelection() { BOARD_ITEM* item = static_cast( *it ); - item->ViewSetVisible( true ); + item->ViewHide ( false ); item->ClearSelected(); + item->ViewUpdate ( KIGFX::VIEW_ITEM::GEOMETRY ) ; } m_selection.clear(); @@ -732,12 +742,21 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const case PCB_MODULE_TEXT_T: if( m_multiple && !m_editModules ) return false; - break; + return aItem->ViewIsVisible() && board->IsLayerVisible( aItem->GetLayer() ); // These are not selectable case PCB_MODULE_EDGE_T: case PCB_PAD_T: - return m_editModules; + { + if( m_multiple && !m_editModules ) + return false; + + MODULE *mod = static_cast (aItem) -> GetParent(); + if( mod && mod->IsLocked() ) + return false; + + break; + } case NOT_USED: case TYPE_NOT_INIT: @@ -762,6 +781,14 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) module->RunOnChildren( boost::bind( &SELECTION_TOOL::selectVisually, this, _1 ) ); } + if ( aItem->Type() == PCB_PAD_T ) + { + MODULE* module = static_cast( aItem->GetParent() ); + + if( m_selection.items.FindItem( module ) >= 0 ) + return; + } + selectVisually( aItem ); ITEM_PICKER picker( aItem ); m_selection.items.PushItem( picker ); @@ -811,7 +838,7 @@ void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const m_selection.group->Add( aItem ); // Hide the original item, so it is shown only on overlay - aItem->ViewSetVisible( false ); + aItem->ViewHide (true); aItem->SetSelected(); } @@ -821,8 +848,9 @@ void SELECTION_TOOL::unselectVisually( BOARD_ITEM* aItem ) const m_selection.group->Remove( aItem ); // Restore original item visibility - aItem->ViewSetVisible( true ); + aItem->ViewHide (false); aItem->ClearSelected(); + aItem->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } @@ -869,38 +897,304 @@ void SELECTION_TOOL::highlightNet( const VECTOR2I& aPoint ) } } - -BOARD_ITEM* SELECTION_TOOL::prefer( GENERAL_COLLECTOR& aCollector, const KICAD_T aTypes[] ) const +static double calcArea ( BOARD_ITEM *aItem ) { - 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 ) + switch (aItem -> Type() ) { - KICAD_T type = aCollector[i]->Type(); + case PCB_MODULE_T: + return static_cast (aItem)->GetFootprintRect().GetArea(); - for( int j = 0; j < typesNr - 1; ++j ) // Check if the item's type is in our list + case PCB_TRACE_T: { - if( aTypes[j] == type ) + TRACK *t = static_cast (aItem); + return ( t->GetWidth() + t->GetLength() ) * t->GetWidth(); + } + + default: + return aItem->GetBoundingBox().GetArea(); + } +} + +static double calcMinArea ( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) +{ + double best = std::numeric_limits::max(); + + if(!aCollector.GetCount()) + return 0.0; + + for(int i = 0; i < aCollector.GetCount(); i++) + { + BOARD_ITEM *item = aCollector[i]; + if(item->Type() == aType) + best = std::min(best, calcArea ( item )); + + } + + return best; +} + +static double calcMaxArea ( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) +{ + double best = 0.0; + + for(int i = 0; i < aCollector.GetCount(); i++) + { + BOARD_ITEM *item = aCollector[i]; + if(item->Type() == aType) + best = std::max(best, calcArea ( item )); + + } + + return best; +} + +double calcRatio ( double a, double b ) +{ + if ( a == 0.0 && b == 0.0 ) + return 1.0; + if ( b == 0.0 ) + return 10000000.0; // something arbitrarily big for the moment + + return a / b; +} + +// todo: explain the selection heuristics +void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) const +{ + std::set rejected; + + const double footprintAreaRatio = 0.2; + const double modulePadMinCoverRatio = 0.45; + const double padViaAreaRatio = 0.5; + const double trackViaLengthRatio = 2.0; + const double trackTrackLengthRatio = 0.3; + const double textToFeatureMinRatio = 0.2; + const double textToFootprintMinRatio = 0.4; + + LAYER_ID actLayer = m_frame->GetActiveLayer(); + + LSET silkLayers(2, B_SilkS, F_SilkS ); + + if( silkLayers[ actLayer ] ) + { + std::set preferred; + + for( int i = 0; i < aCollector.GetCount(); ++i ) + { + BOARD_ITEM *item = aCollector[i]; + + if ( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_LINE_T ) + if ( silkLayers[item->GetLayer() ] ) + preferred.insert ( item ); + } + + if( preferred.size() != 0) + { + aCollector.Empty(); + + BOOST_FOREACH( BOARD_ITEM *item, preferred ) + aCollector.Append( item ); + return; + } + } + + if (aCollector.CountType ( PCB_MODULE_TEXT_T ) > 0 ) + { + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( TEXTE_MODULE *txt = dyn_cast ( aCollector[i] ) ) { - if( preferred == NULL ) + double textArea = calcArea ( txt ); + + for( int j = 0; j < aCollector.GetCount(); ++j ) { - preferred = aCollector[i]; // save the first matching item - break; + BOARD_ITEM *item = aCollector[j]; + double areaRatio = calcRatio ( textArea, calcArea ( item ) ); + + if (item->Type () == PCB_MODULE_T && areaRatio < textToFootprintMinRatio ) + { + printf("rejectModuleN\n"); + + rejected.insert ( item ); + } + switch (item->Type()) + { + case PCB_TRACE_T: + case PCB_PAD_T: + case PCB_LINE_T: + case PCB_VIA_T: + case PCB_MODULE_T: + if ( areaRatio > textToFeatureMinRatio ) + { + printf("t after moduleRejected\n"); + rejected.insert ( txt ); + } + break; + default: + break; + } } - else + } + } + + if( aCollector.CountType ( PCB_MODULE_T ) > 0 ) + { + double minArea = calcMinArea ( aCollector, PCB_MODULE_T ); + double maxArea = calcMaxArea ( aCollector, PCB_MODULE_T ); + + + if( calcRatio(minArea, maxArea) <= footprintAreaRatio ) + { + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( MODULE *mod = dyn_cast ( aCollector[i] ) ) { - return NULL; // there is more than one preferred item, so there is no clear choice + double normalizedArea = calcRatio ( calcArea(mod), maxArea ); + + if(normalizedArea > footprintAreaRatio) + { + printf("rejectModule1\n"); + + rejected.insert( mod ); + } } + } + } + + if( aCollector.CountType ( PCB_PAD_T ) > 0 ) + { + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( D_PAD *pad = dyn_cast ( aCollector[i] ) ) + { + double ratio = pad->GetParent()->PadCoverageRatio(); + + if(ratio < modulePadMinCoverRatio) + rejected.insert( pad->GetParent() ); + } + } + + if( aCollector.CountType ( PCB_VIA_T ) > 0 ) + { + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( VIA *via = dyn_cast ( aCollector[i] ) ) + { + double viaArea = calcArea ( via ); + + for( int j = 0; j < aCollector.GetCount(); ++j ) + { + BOARD_ITEM *item = aCollector[j]; + double areaRatio = calcRatio ( viaArea, calcArea ( item ) ); + + if( item->Type() == PCB_MODULE_T && areaRatio < modulePadMinCoverRatio ) + rejected.insert( item ); + + if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio ) + rejected.insert( item ); + + if ( TRACK *track = dyn_cast ( item ) ) + { + if( track->GetNetCode() != via->GetNetCode() ) + continue; + + double lenRatio = (double) ( track->GetLength() + track->GetWidth()) / (double) via->GetWidth(); + + if( lenRatio > trackViaLengthRatio ) + rejected.insert( track ); + } + } + } + } + + int nTracks = aCollector.CountType ( PCB_TRACE_T ); + + if( nTracks > 0 ) + { + double maxLength = 0.0; + double minLength = std::numeric_limits::max(); + double maxArea = 0.0; + + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( TRACK *track = dyn_cast ( aCollector[i] ) ) + { + maxLength = std::max( track->GetLength(), maxLength ); + maxLength = std::max( (double)track->GetWidth(), maxLength ); + + minLength = std::min( std::max ( track->GetLength(), (double)track->GetWidth() ), minLength ); + + double area = ( track->GetLength() + track->GetWidth() * track->GetWidth() ); + maxArea = std::max(area, maxArea); + } + + if(maxLength > 0.0 && minLength/maxLength < trackTrackLengthRatio && nTracks > 1 ) + for( int i = 0; i < aCollector.GetCount(); ++i ) + if ( TRACK *track = dyn_cast ( aCollector[i] ) ) + { + double ratio = std::max( (double) track->GetWidth(), track->GetLength()) / maxLength; + if( ratio > trackTrackLengthRatio) + rejected.insert(track); + } + + + for( int j = 0; j < aCollector.GetCount(); ++j ) + { + if ( MODULE *mod = dyn_cast ( aCollector[j] ) ) + { + double ratio = maxArea / mod->GetFootprintRect().GetArea(); + + if( ratio < modulePadMinCoverRatio ) + { + printf("rejectModule\n"); + rejected.insert( mod ); + } + } + } + + } + + BOOST_FOREACH(BOARD_ITEM *item, rejected) + { + aCollector.Remove(item); + } + printf("Post-selection: %d\n", aCollector.GetCount() ); +} + +bool SELECTION_TOOL::SanitizeSelection() +{ + std::set rejected; + + if ( !m_editModules ) + { + + for( unsigned int i = 0; i < m_selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = m_selection.Item( i ); + + if( item->Type() == PCB_PAD_T ) + { + MODULE *mod = static_cast ( item->GetParent( ) ); + + // case 1: module (or its pads) are locked + if( mod && ( mod->PadsLocked( ) || mod->IsLocked( ) ) ) + rejected.insert ( item ); + + // case 2: multi-item selection contains both the module and its pads - remove the pads + if (mod && m_selection.items.FindItem ( mod ) >= 0 ) + rejected.insert ( item ); } } } - return preferred; -} + while ( !rejected.empty () ) + { + BOARD_ITEM *item = *rejected.begin(); + + int itemIdx = m_selection.items.FindItem( item ); + if( itemIdx >= 0 ) + m_selection.items.RemovePicker( itemIdx ); + rejected.erase(item); + } + + return true; +} void SELECTION_TOOL::generateMenu() { @@ -931,6 +1225,7 @@ void SELECTION::clear() } + const TOOL_EVENT SELECTION_TOOL::SelectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.selected" ); const TOOL_EVENT SELECTION_TOOL::UnselectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.unselected" ); const TOOL_EVENT SELECTION_TOOL::ClearedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.cleared" ); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index b90ff268e9..5a900d5a31 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.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-2015 CERN * @author Tomasz Wlostowski * @author Maciej Suminski * @@ -78,6 +78,13 @@ private: friend class SELECTION_TOOL; }; +enum SELECTION_LOCK_FLAGS +{ + SELECTION_UNLOCKED = 0, + SELECTION_LOCK_OVERRIDE = 1, + SELECTION_LOCKED = 2 +}; + /** * Class SELECTION_TOOL * @@ -149,7 +156,7 @@ public: } ///> Checks if the user has agreed to modify locked items for the given selection. - bool CheckLock(); + SELECTION_LOCK_FLAGS CheckLock(); ///> Select a single item under cursor event handler. int CursorSelection( const TOOL_EVENT& aEvent ); @@ -157,6 +164,10 @@ public: ///> Clear current selection event handler. int ClearSelection( const TOOL_EVENT& aEvent ); + ///> Makes sure a group selection does not contain items that would cause + ///> conflicts when moving/rotating together (e.g. a footprint and one of the same footprint's pads) + bool SanitizeSelection( ); + ///> Item selection event handler. int SelectItem( const TOOL_EVENT& aEvent ); @@ -183,7 +194,7 @@ private: * a menu is shown, otherise function finishes without selecting anything. * @return True if an item was selected, false otherwise. */ - bool selectCursor( const VECTOR2I& aWhere, bool aAllowDisambiguation = true ); + bool selectCursor( const VECTOR2I& aWhere, bool aOnDrag = false); /** * Function selectMultiple() @@ -291,14 +302,12 @@ 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. + * Function guessSelectionCandidates() + * Tries to guess best selection candidates in case multiple items are clicked, by + * doing some braindead heuristics. * @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; + void guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) const; /** * Function generateMenu() diff --git a/pcbnew/tools/tools_common.cpp b/pcbnew/tools/tools_common.cpp new file mode 100644 index 0000000000..338f900e49 --- /dev/null +++ b/pcbnew/tools/tools_common.cpp @@ -0,0 +1,28 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void registerAllTools ( TOOL_MANAGER *aToolManager ) +{ + aToolManager->RegisterTool( new SELECTION_TOOL ); + aToolManager->RegisterTool( new ROUTER_TOOL ); + aToolManager->RegisterTool( new LENGTH_TUNER_TOOL ); + aToolManager->RegisterTool( new EDIT_TOOL ); + aToolManager->RegisterTool( new DRAWING_TOOL ); + aToolManager->RegisterTool( new POINT_EDITOR ); + aToolManager->RegisterTool( new PCBNEW_CONTROL ); + aToolManager->RegisterTool( new PCB_EDITOR_CONTROL ); + aToolManager->RegisterTool( new PLACEMENT_TOOL ); +} \ No newline at end of file From 112adccbcb81e99b2918031292407577ab78f4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Wed, 18 Feb 2015 01:29:54 +0100 Subject: [PATCH 17/23] router: differential pairs & length tuning support --- pcbnew/CMakeLists.txt | 5 + .../dialog_pns_diff_pair_dimensions.cpp | 91 + .../dialogs/dialog_pns_diff_pair_dimensions.h | 55 + .../dialog_pns_diff_pair_dimensions_base.cpp | 102 + .../dialog_pns_diff_pair_dimensions_base.fbp | 1002 ++++++++ .../dialog_pns_diff_pair_dimensions_base.h | 68 + .../dialog_pns_length_tuning_settings.cpp | 122 + .../dialog_pns_length_tuning_settings.h | 56 + ...dialog_pns_length_tuning_settings_base.cpp | 183 ++ ...dialog_pns_length_tuning_settings_base.fbp | 2253 +++++++++++++++++ .../dialog_pns_length_tuning_settings_base.h | 86 + .../dialogs/dialog_pns_settings_base.fbp.bak | 1334 ++++++++++ pcbnew/dialogs/dialog_track_via_size.cpp | 27 +- pcbnew/dialogs/dialog_track_via_size.h | 7 + pcbnew/dialogs/dialog_track_via_size_base.cpp | 44 +- pcbnew/dialogs/dialog_track_via_size_base.fbp | 1034 ++++++-- pcbnew/dialogs/dialog_track_via_size_base.h | 17 +- pcbnew/menubar_pcbframe.cpp | 55 + pcbnew/router/CMakeLists.txt | 11 + pcbnew/router/direction.h | 11 +- pcbnew/router/length_tuner_tool.cpp | 319 +++ pcbnew/router/length_tuner_tool.h | 52 + pcbnew/router/pns_algo_base.h | 3 + pcbnew/router/pns_diff_pair.cpp | 825 ++++++ pcbnew/router/pns_diff_pair.h | 457 ++++ pcbnew/router/pns_diff_pair_placer.cpp | 778 ++++++ pcbnew/router/pns_diff_pair_placer.h | 303 +++ pcbnew/router/pns_dp_meander_placer.cpp | 459 ++++ pcbnew/router/pns_dp_meander_placer.h | 148 ++ pcbnew/router/pns_item.h | 4 +- pcbnew/router/pns_itemset.cpp | 27 +- pcbnew/router/pns_itemset.h | 21 +- pcbnew/router/pns_joint.h | 18 +- pcbnew/router/pns_line.cpp | 91 + pcbnew/router/pns_line.h | 19 +- pcbnew/router/pns_line_placer.cpp | 82 +- pcbnew/router/pns_line_placer.h | 19 +- pcbnew/router/pns_meander.cpp | 580 +++++ pcbnew/router/pns_meander.h | 498 ++++ pcbnew/router/pns_meander_placer.cpp | 262 ++ pcbnew/router/pns_meander_placer.h | 115 + pcbnew/router/pns_meander_placer_base.cpp | 167 ++ pcbnew/router/pns_meander_placer_base.h | 167 ++ pcbnew/router/pns_meander_skew_placer.cpp | 157 ++ pcbnew/router/pns_meander_skew_placer.h | 66 + pcbnew/router/pns_node.cpp | 83 +- pcbnew/router/pns_node.h | 55 +- pcbnew/router/pns_optimizer.cpp | 367 ++- pcbnew/router/pns_optimizer.h | 17 +- pcbnew/router/pns_placement_algo.h | 189 ++ pcbnew/router/pns_router.cpp | 192 +- pcbnew/router/pns_router.h | 30 +- pcbnew/router/pns_routing_settings.cpp | 2 +- pcbnew/router/pns_segment.h | 5 + pcbnew/router/pns_shove.cpp | 375 ++- pcbnew/router/pns_shove.h | 45 +- pcbnew/router/pns_sizes_settings.h | 30 +- pcbnew/router/pns_solid.h | 7 +- pcbnew/router/pns_tool_base.cpp | 273 ++ pcbnew/router/pns_tool_base.h | 74 + pcbnew/router/pns_topology.cpp | 360 +++ pcbnew/router/pns_topology.h | 75 + pcbnew/router/pns_tune_status_popup.cpp | 69 + pcbnew/router/pns_tune_status_popup.h | 45 + pcbnew/router/pns_utils.cpp | 81 + pcbnew/router/pns_utils.h | 11 + pcbnew/router/pns_via.cpp | 12 + pcbnew/router/pns_via.h | 8 + pcbnew/router/pns_walkaround.cpp | 26 +- pcbnew/router/pns_walkaround.h | 15 +- pcbnew/router/ranged_num.h | 53 + pcbnew/router/router_menus.h | 981 +++++++ pcbnew/router/router_preview_item.cpp | 110 +- pcbnew/router/router_tool.cpp | 439 ++-- pcbnew/router/router_tool.h | 48 +- pcbnew/tools/common_actions.cpp | 55 +- pcbnew/tools/common_actions.h | 23 +- 77 files changed, 15413 insertions(+), 942 deletions(-) create mode 100644 pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp create mode 100644 pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h create mode 100644 pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.cpp create mode 100644 pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.fbp create mode 100644 pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.h create mode 100644 pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp create mode 100644 pcbnew/dialogs/dialog_pns_length_tuning_settings.h create mode 100644 pcbnew/dialogs/dialog_pns_length_tuning_settings_base.cpp create mode 100644 pcbnew/dialogs/dialog_pns_length_tuning_settings_base.fbp create mode 100644 pcbnew/dialogs/dialog_pns_length_tuning_settings_base.h create mode 100644 pcbnew/dialogs/dialog_pns_settings_base.fbp.bak create mode 100644 pcbnew/router/length_tuner_tool.cpp create mode 100644 pcbnew/router/length_tuner_tool.h create mode 100644 pcbnew/router/pns_diff_pair.cpp create mode 100644 pcbnew/router/pns_diff_pair.h create mode 100644 pcbnew/router/pns_diff_pair_placer.cpp create mode 100644 pcbnew/router/pns_diff_pair_placer.h create mode 100644 pcbnew/router/pns_dp_meander_placer.cpp create mode 100644 pcbnew/router/pns_dp_meander_placer.h create mode 100644 pcbnew/router/pns_meander.cpp create mode 100644 pcbnew/router/pns_meander.h create mode 100644 pcbnew/router/pns_meander_placer.cpp create mode 100644 pcbnew/router/pns_meander_placer.h create mode 100644 pcbnew/router/pns_meander_placer_base.cpp create mode 100644 pcbnew/router/pns_meander_placer_base.h create mode 100644 pcbnew/router/pns_meander_skew_placer.cpp create mode 100644 pcbnew/router/pns_meander_skew_placer.h create mode 100644 pcbnew/router/pns_placement_algo.h create mode 100644 pcbnew/router/pns_tool_base.cpp create mode 100644 pcbnew/router/pns_tool_base.h create mode 100644 pcbnew/router/pns_topology.cpp create mode 100644 pcbnew/router/pns_topology.h create mode 100644 pcbnew/router/pns_tune_status_popup.cpp create mode 100644 pcbnew/router/pns_tune_status_popup.h create mode 100644 pcbnew/router/ranged_num.h create mode 100644 pcbnew/router/router_menus.h diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index d4980a7d6a..99e4212082 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -104,6 +104,10 @@ set( PCBNEW_DIALOGS dialogs/dialog_pcb_text_properties_base.cpp dialogs/dialog_pns_settings.cpp dialogs/dialog_pns_settings_base.cpp + dialogs/dialog_pns_diff_pair_dimensions.cpp + dialogs/dialog_pns_diff_pair_dimensions_base.cpp + dialogs/dialog_pns_length_tuning_settings.cpp + dialogs/dialog_pns_length_tuning_settings_base.cpp dialogs/dialog_non_copper_zones_properties.cpp dialogs/dialog_non_copper_zones_properties_base.cpp dialogs/dialog_pad_properties.cpp @@ -275,6 +279,7 @@ set( PCBNEW_CLASS_SRCS tools/module_tools.cpp tools/placement_tool.cpp tools/common_actions.cpp + tools/grid_helper.cpp tools/tools_common.cpp ) diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp new file mode 100644 index 0000000000..6704edc70a --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp @@ -0,0 +1,91 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014-2015 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 . + */ + +/** + * Push and Shove diff pair dimensions (gap) settings dialog. + */ + +#include "dialog_pns_diff_pair_dimensions.h" +#include + +DIALOG_PNS_DIFF_PAIR_DIMENSIONS::DIALOG_PNS_DIFF_PAIR_DIMENSIONS( wxWindow* aParent, PNS_SIZES_SETTINGS& aSizes ) : + DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE( aParent ), + m_traceWidth ( this, m_traceWidthText, m_traceWidthUnit ), + m_traceGap (this, m_traceGapText, m_traceGapUnit ), + m_viaGap ( this, m_viaGapText, m_viaGapUnit ), + m_sizes( aSizes ) + +{ + m_traceWidth.SetValue ( aSizes.DiffPairWidth() ); + m_traceGap.SetValue ( aSizes.DiffPairGap() ); + m_viaGap.SetValue ( aSizes.DiffPairViaGap() ); + m_viaTraceGapEqual->SetValue ( m_sizes.DiffPairViaGapSameAsTraceGap() ); + + updateCheckbox(); +} + +void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::updateCheckbox() +{ + printf("Checked: %d", m_viaTraceGapEqual->GetValue()); + if( m_viaTraceGapEqual->GetValue() ) + { + m_sizes.SetDiffPairViaGapSameAsTraceGap( true ); + m_viaGapText->Disable(); + m_viaGapLabel->Disable(); + m_viaGapUnit->Disable(); + } else { + m_sizes.SetDiffPairViaGapSameAsTraceGap( false ); + m_viaGapText->Enable(); + m_viaGapLabel->Enable(); + m_viaGapUnit->Enable(); + } +} + +void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnClose( wxCloseEvent& aEvent ) +{ + // Do nothing, it is result of ESC pressing + EndModal( 0 ); +} + + +void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnOkClick( wxCommandEvent& aEvent ) +{ + // Save widgets' values to settings + m_sizes.SetDiffPairGap ( m_traceGap.GetValue() ); + m_sizes.SetDiffPairViaGap ( m_viaGap.GetValue() ); + m_sizes.SetDiffPairWidth ( m_traceWidth.GetValue() ); + + // todo: verify against design rules + EndModal( 1 ); +} + + +void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnCancelClick( wxCommandEvent& aEvent ) +{ + // Do nothing + EndModal( 0 ); +} + +void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnViaTraceGapEqualCheck( wxCommandEvent& event ) +{ + event.Skip(); + updateCheckbox(); +} + \ No newline at end of file diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h new file mode 100644 index 0000000000..1ea6318fc8 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h @@ -0,0 +1,55 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014-2015 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 . + */ + +/** + * Push and Shove diff pair dimensions (gap) settings dialog. + */ + +#ifndef __dialog_diff_pair_dimensions_settings__ +#define __dialog_diff_pair_dimensions_settings__ + +#include + +#include "dialog_pns_diff_pair_dimensions_base.h" + +class PNS_SIZES_SETTINGS; + +class DIALOG_PNS_DIFF_PAIR_DIMENSIONS : public DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE +{ + public: + DIALOG_PNS_DIFF_PAIR_DIMENSIONS( wxWindow* aParent, PNS_SIZES_SETTINGS& aSizes ); + + virtual void OnClose( wxCloseEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); + virtual void OnViaTraceGapEqualCheck( wxCommandEvent& event ); + + + private: + void updateCheckbox( ); + + WX_UNIT_BINDER m_traceWidth; + WX_UNIT_BINDER m_traceGap; + WX_UNIT_BINDER m_viaGap; + + PNS_SIZES_SETTINGS& m_sizes; +}; + +#endif // __dialog_pns_settings__ diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.cpp b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.cpp new file mode 100644 index 0000000000..a74a8b0b1b --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.cpp @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_pns_diff_pair_dimensions_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( 400,-1 ), wxDefaultSize ); + + wxBoxSizer* bSizer7; + bSizer7 = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer1->AddGrowableCol( 1 ); + fgSizer1->SetFlexibleDirection( wxBOTH ); + fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_traceWidthLabel = new wxStaticText( this, wxID_ANY, _("Width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_traceWidthLabel->Wrap( -1 ); + fgSizer1->Add( m_traceWidthLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 ); + + m_traceWidthText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_traceWidthText, 0, wxALL|wxEXPAND, 5 ); + + m_traceWidthUnit = new wxStaticText( this, wxID_ANY, _("u"), wxDefaultPosition, wxDefaultSize, 0 ); + m_traceWidthUnit->Wrap( -1 ); + fgSizer1->Add( m_traceWidthUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_traceGapLabel = new wxStaticText( this, wxID_ANY, _("Trace gap:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_traceGapLabel->Wrap( -1 ); + fgSizer1->Add( m_traceGapLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 ); + + m_traceGapText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_traceGapText, 0, wxALL|wxEXPAND, 5 ); + + m_traceGapUnit = new wxStaticText( this, wxID_ANY, _("u"), wxDefaultPosition, wxDefaultSize, 0 ); + m_traceGapUnit->Wrap( -1 ); + m_traceGapUnit->SetMaxSize( wxSize( 40,-1 ) ); + + fgSizer1->Add( m_traceGapUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_viaGapLabel = new wxStaticText( this, wxID_ANY, _("Via gap:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_viaGapLabel->Wrap( -1 ); + m_viaGapLabel->Enable( false ); + + fgSizer1->Add( m_viaGapLabel, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + + m_viaGapText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_viaGapText->Enable( false ); + + fgSizer1->Add( m_viaGapText, 0, wxALL|wxEXPAND, 5 ); + + m_viaGapUnit = new wxStaticText( this, wxID_ANY, _("u"), wxDefaultPosition, wxDefaultSize, 0 ); + m_viaGapUnit->Wrap( -1 ); + m_viaGapUnit->Enable( false ); + m_viaGapUnit->SetMaxSize( wxSize( 40,-1 ) ); + + fgSizer1->Add( m_viaGapUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + bSizer7->Add( fgSizer1, 0, wxEXPAND, 5 ); + + m_viaTraceGapEqual = new wxCheckBox( this, wxID_ANY, _("Via gap same as trace gap"), wxDefaultPosition, wxDefaultSize, 0 ); + m_viaTraceGapEqual->SetValue(true); + bSizer7->Add( m_viaTraceGapEqual, 0, wxALL|wxEXPAND, 5 ); + + m_stdButtons = new wxStdDialogButtonSizer(); + m_stdButtonsOK = new wxButton( this, wxID_OK ); + m_stdButtons->AddButton( m_stdButtonsOK ); + m_stdButtonsCancel = new wxButton( this, wxID_CANCEL ); + m_stdButtons->AddButton( m_stdButtonsCancel ); + m_stdButtons->Realize(); + + bSizer7->Add( m_stdButtons, 0, wxEXPAND, 5 ); + + + this->SetSizer( bSizer7 ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnClose ) ); + m_viaTraceGapEqual->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::onViaTraceGapEqualCheck ), NULL, this ); + m_stdButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnCancelClick ), NULL, this ); + m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::~DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnClose ) ); + m_viaTraceGapEqual->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::onViaTraceGapEqualCheck ), NULL, this ); + m_stdButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnCancelClick ), NULL, this ); + m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE::OnOkClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.fbp b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.fbp new file mode 100644 index 0000000000..d87bb97fa9 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.fbp @@ -0,0 +1,1002 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_pns_diff_pair_dimensions_base + 1000 + none + 1 + DIALOG_PNS_SETTINGS_BASE + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 400,-1 + DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE + + 400,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Differential Pair Dimensions + + + + + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer7 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 3 + wxBOTH + 1 + + 0 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Width: + + 0 + + + 0 + + 1 + m_traceWidthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_traceWidthText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + u + + 0 + + + 0 + + 1 + m_traceWidthUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Trace gap: + + 0 + + + 0 + + 1 + m_traceGapLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_traceGapText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + u + + 0 + 40,-1 + + 0 + + 1 + m_traceGapUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + Via gap: + + 0 + + + 0 + + 1 + m_viaGapLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_viaGapText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + u + + 0 + 40,-1 + + 0 + + 1 + m_viaGapUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via gap same as trace gap + + 0 + + + 0 + + 1 + m_viaTraceGapEqual + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnViaTraceGapEqualCheck + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdButtons + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.h b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.h new file mode 100644 index 0000000000..4300d7f697 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions_base.h @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE_H__ +#define __DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_traceWidthLabel; + wxTextCtrl* m_traceWidthText; + wxStaticText* m_traceWidthUnit; + wxStaticText* m_traceGapLabel; + wxTextCtrl* m_traceGapText; + wxStaticText* m_traceGapUnit; + wxStaticText* m_viaGapLabel; + wxTextCtrl* m_viaGapText; + wxStaticText* m_viaGapUnit; + wxCheckBox* m_viaTraceGapEqual; + wxStdDialogButtonSizer* m_stdButtons; + wxButton* m_stdButtonsOK; + wxButton* m_stdButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void onViaTraceGapEqualCheck( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Differential Pair Dimensions"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 400,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE(); + +}; + +#endif //__DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE_H__ diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp b/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp new file mode 100644 index 0000000000..1b5524db8b --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp @@ -0,0 +1,122 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2014-2015 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 . + */ + +/** + * Length tuner settings dialog. + */ + +#include "dialog_pns_length_tuning_settings.h" +#include + +DIALOG_PNS_LENGTH_TUNING_SETTINGS::DIALOG_PNS_LENGTH_TUNING_SETTINGS( wxWindow* aParent, PNS_MEANDER_SETTINGS& aSettings, PNS_ROUTER_MODE aMode ) : + DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE( aParent ), + m_minAmpl ( this, m_minAmplText, m_minAmplUnit ), + m_maxAmpl (this, m_maxAmplText, m_maxAmplUnit ), + m_spacing ( this, m_spacingText, m_spacingUnit ), + m_targetLength ( this, m_targetLengthText, m_targetLengthUnit ), + m_settings( aSettings ), + m_mode ( aMode ) +{ + + m_miterStyle->Enable ( false ); + m_radiusText->Enable ( aMode != PNS_MODE_TUNE_DIFF_PAIR ); + //m_minAmpl.Enable ( aMode != PNS_MODE_TUNE_DIFF_PAIR_SKEW ); + + m_minAmpl.SetValue ( m_settings.m_minAmplitude ); + m_maxAmpl.SetValue ( m_settings.m_maxAmplitude ); + + m_spacing.SetValue ( m_settings.m_spacing ); + m_radiusText->SetValue ( wxString::Format(wxT("%i"), m_settings.m_cornerRadiusPercentage) ); + + + m_miterStyle->SetSelection ( m_settings.m_cornerType == PNS_MEANDER_SETTINGS::ROUND ? 1 : 0 ); + + switch( aMode ) + { + case PNS_MODE_TUNE_SINGLE: + SetTitle ( _("Single track length tuning") ); + m_legend->SetBitmap( KiBitmap( tune_single_track_length_legend_xpm ) ); + m_targetLength.SetValue ( m_settings.m_targetLength ); + + break; + + case PNS_MODE_TUNE_DIFF_PAIR: + SetTitle ( _("Differential pair length tuning") ); + m_legend->SetBitmap( KiBitmap( tune_diff_pair_length_legend_xpm ) ); + m_targetLength.SetValue ( m_settings.m_targetLength ); + + break; + + case PNS_MODE_TUNE_DIFF_PAIR_SKEW: + SetTitle ( _("Differential pair skew tuning") ); + m_legend->SetBitmap( KiBitmap( tune_diff_pair_skew_legend_xpm ) ); + m_targetLengthLabel->SetLabel( _("Target skew: ") ); + m_targetLength.SetValue ( m_settings.m_targetSkew ); + break; + + default: + break; + } + + m_stdButtonsOK->SetDefault(); + m_targetLengthText->SetSelection(-1, -1); + m_targetLengthText->SetFocus(); +} + + +void DIALOG_PNS_LENGTH_TUNING_SETTINGS::OnClose( wxCloseEvent& aEvent ) +{ + // Do nothing, it is result of ESC pressing + EndModal( 0 ); +} + + +void DIALOG_PNS_LENGTH_TUNING_SETTINGS::OnOkClick( wxCommandEvent& aEvent ) +{ + + // fixme: use validators and TransferDataFromWindow + m_settings.m_minAmplitude = m_minAmpl.GetValue(); + m_settings.m_maxAmplitude = m_maxAmpl.GetValue(); + m_settings.m_spacing = m_spacing.GetValue(); + + m_settings.m_cornerRadiusPercentage = wxAtoi( m_radiusText->GetValue() ); + + if (m_mode == PNS_MODE_TUNE_DIFF_PAIR_SKEW) + m_settings.m_targetSkew = m_targetLength.GetValue(); + else + m_settings.m_targetLength = m_targetLength.GetValue(); + + if ( m_settings.m_maxAmplitude < m_settings.m_minAmplitude ) + m_settings.m_maxAmplitude = m_settings.m_maxAmplitude; + + + m_settings.m_cornerType = m_miterStyle->GetSelection( ) ? PNS_MEANDER_SETTINGS::CHAMFER : PNS_MEANDER_SETTINGS::ROUND; + + + + EndModal( 1 ); +} + + +void DIALOG_PNS_LENGTH_TUNING_SETTINGS::OnCancelClick( wxCommandEvent& aEvent ) +{ + // Do nothing + EndModal( 0 ); +} diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings.h b/pcbnew/dialogs/dialog_pns_length_tuning_settings.h new file mode 100644 index 0000000000..ae83c36125 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings.h @@ -0,0 +1,56 @@ +/* + * 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_length_tuning_settings__ +#define __dialog_pns_length_tuning_settings__ + +#include "dialog_pns_length_tuning_settings_base.h" + +#include + +#include + +class PNS_MEANDER_SETTINGS; + +class DIALOG_PNS_LENGTH_TUNING_SETTINGS : public DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE +{ + public: + DIALOG_PNS_LENGTH_TUNING_SETTINGS( wxWindow* aParent, PNS_MEANDER_SETTINGS& aSettings, PNS_ROUTER_MODE aMode ); + + virtual void OnClose( wxCloseEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); + + private: + + WX_UNIT_BINDER m_minAmpl; + WX_UNIT_BINDER m_maxAmpl; + WX_UNIT_BINDER m_spacing; + WX_UNIT_BINDER m_targetLength; + + PNS_MEANDER_SETTINGS& m_settings; + PNS_ROUTER_MODE m_mode; +}; + +#endif // __dialog_pns_settings__ diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.cpp b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.cpp new file mode 100644 index 0000000000..5cb8aa03da --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.cpp @@ -0,0 +1,183 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_pns_length_tuning_settings_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( 345,668 ), wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* sbSizer1; + sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Length/skew") ), wxVERTICAL ); + + wxFlexGridSizer* fgSizer4; + fgSizer4 = new wxFlexGridSizer( 0, 2, 0, 0 ); + fgSizer4->AddGrowableCol( 1 ); + fgSizer4->SetFlexibleDirection( wxBOTH ); + fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText4 = new wxStaticText( this, wxID_ANY, _("Tune from:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + fgSizer4->Add( m_staticText4, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choicePathFromChoices; + m_choicePathFrom = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePathFromChoices, 0 ); + m_choicePathFrom->SetSelection( 0 ); + fgSizer4->Add( m_choicePathFrom, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText15 = new wxStaticText( this, wxID_ANY, _("Tune to:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText15->Wrap( -1 ); + fgSizer4->Add( m_staticText15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choice4Choices; + m_choice4 = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choice4Choices, 0 ); + m_choice4->SetSelection( 0 ); + fgSizer4->Add( m_choice4, 0, wxALL, 5 ); + + m_staticText3 = new wxStaticText( this, wxID_ANY, _("Constraint:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + fgSizer4->Add( m_staticText3, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxString m_constraintSourceChoices[] = { _("from Design Rules"), _("manual") }; + int m_constraintSourceNChoices = sizeof( m_constraintSourceChoices ) / sizeof( wxString ); + m_constraintSource = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_constraintSourceNChoices, m_constraintSourceChoices, 0 ); + m_constraintSource->SetSelection( 1 ); + m_constraintSource->Enable( false ); + + fgSizer4->Add( m_constraintSource, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_targetLengthLabel = new wxStaticText( this, wxID_ANY, _("Target length:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_targetLengthLabel->Wrap( -1 ); + fgSizer4->Add( m_targetLengthLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxGridSizer* gSizer2; + gSizer2 = new wxGridSizer( 0, 2, 0, 0 ); + + m_targetLengthText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + gSizer2->Add( m_targetLengthText, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_targetLengthUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_targetLengthUnit->Wrap( -1 ); + gSizer2->Add( m_targetLengthUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + + fgSizer4->Add( gSizer2, 1, wxEXPAND, 5 ); + + + sbSizer1->Add( fgSizer4, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( sbSizer1, 0, wxEXPAND|wxALL, 5 ); + + wxStaticBoxSizer* sbSizer2; + sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Meandering") ), wxVERTICAL ); + + m_legend = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + sbSizer2->Add( m_legend, 1, wxALL|wxEXPAND, 5 ); + + wxFlexGridSizer* fgSizer3; + fgSizer3 = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer3->AddGrowableCol( 2 ); + fgSizer3->SetFlexibleDirection( wxBOTH ); + fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText9 = new wxStaticText( this, wxID_ANY, _("Min amplitude (Amin):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText9->Wrap( -1 ); + fgSizer3->Add( m_staticText9, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_minAmplText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer3->Add( m_minAmplText, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_minAmplUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_minAmplUnit->Wrap( -1 ); + fgSizer3->Add( m_minAmplUnit, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_staticText91 = new wxStaticText( this, wxID_ANY, _("Max amplitude (Amax):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText91->Wrap( -1 ); + fgSizer3->Add( m_staticText91, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_maxAmplText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer3->Add( m_maxAmplText, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_maxAmplUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_maxAmplUnit->Wrap( -1 ); + fgSizer3->Add( m_maxAmplUnit, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_staticText11 = new wxStaticText( this, wxID_ANY, _("Spacing (s):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText11->Wrap( -1 ); + fgSizer3->Add( m_staticText11, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_spacingText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer3->Add( m_spacingText, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_spacingUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_spacingUnit->Wrap( -1 ); + fgSizer3->Add( m_spacingUnit, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_staticText13 = new wxStaticText( this, wxID_ANY, _("Miter radius (r):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText13->Wrap( -1 ); + fgSizer3->Add( m_staticText13, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_radiusText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer3->Add( m_radiusText, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_radiusUnit = new wxStaticText( this, wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radiusUnit->Wrap( -1 ); + fgSizer3->Add( m_radiusUnit, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_staticText14 = new wxStaticText( this, wxID_ANY, _("Miter style:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText14->Wrap( -1 ); + m_staticText14->Enable( false ); + + fgSizer3->Add( m_staticText14, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxString m_miterStyleChoices[] = { _("45 degree"), _("arc") }; + int m_miterStyleNChoices = sizeof( m_miterStyleChoices ) / sizeof( wxString ); + m_miterStyle = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_miterStyleNChoices, m_miterStyleChoices, 0 ); + m_miterStyle->SetSelection( 0 ); + m_miterStyle->Enable( false ); + + fgSizer3->Add( m_miterStyle, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + + sbSizer2->Add( fgSizer3, 1, wxEXPAND, 5 ); + + + bMainSizer->Add( sbSizer2, 1, wxALL|wxEXPAND, 5 ); + + m_stdButtons = new wxStdDialogButtonSizer(); + m_stdButtonsOK = new wxButton( this, wxID_OK ); + m_stdButtons->AddButton( m_stdButtonsOK ); + m_stdButtonsCancel = new wxButton( this, wxID_CANCEL ); + m_stdButtons->AddButton( m_stdButtonsCancel ); + m_stdButtons->Realize(); + + bMainSizer->Add( m_stdButtons, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnClose ) ); + m_stdButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnCancelClick ), NULL, this ); + m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::~DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnClose ) ); + m_stdButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnCancelClick ), NULL, this ); + m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE::OnOkClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.fbp b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.fbp new file mode 100644 index 0000000000..2727188e68 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.fbp @@ -0,0 +1,2253 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + /home/twl/Kicad-dev/kicad-git/bitmaps_png/cpp_other + UTF-8 + connect + dialog_pns_length_tuning_settings_base + 1000 + none + 1 + DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 345,668 + DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE + + 345,668 + wxDEFAULT_DIALOG_STYLE + DIALOG_SHIM; dialog_shim.h + Trace length tuning + + + + + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 0 + + wxID_ANY + Length/skew + + sbSizer1 + wxVERTICAL + none + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 0 + + fgSizer4 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Tune from: + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choicePathFrom + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Tune to: + + 0 + + + 0 + + 1 + m_staticText15 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choice4 + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Constraint: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "from Design Rules" "manual" + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_constraintSource + 1 + + + protected + 1 + + Resizable + 1 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Target length: + + 0 + + + 0 + + 1 + m_targetLengthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 2 + 0 + + gSizer2 + none + 0 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_targetLengthText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_targetLengthUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Meandering + + sbSizer2 + wxVERTICAL + none + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + Load From Resource; + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_legend + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 3 + wxBOTH + 2 + + 0 + + fgSizer3 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Min amplitude (Amin): + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_minAmplText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_minAmplUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Max amplitude (Amax): + + 0 + + + 0 + + 1 + m_staticText91 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_maxAmplText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_maxAmplUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Spacing (s): + + 0 + + + 0 + + 1 + m_staticText11 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_spacingText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_spacingUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Miter radius (r): + + 0 + + + 0 + + 1 + m_staticText13 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_radiusText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + % + + 0 + + + 0 + + 1 + m_radiusUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + Miter style: + + 0 + + + 0 + + 1 + m_staticText14 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "45 degree" "arc" + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_miterStyle + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdButtons + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.h b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.h new file mode 100644 index 0000000000..f0e8217ac7 --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings_base.h @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Jun 6 2014) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE_H__ +#define __DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticText4; + wxChoice* m_choicePathFrom; + wxStaticText* m_staticText15; + wxChoice* m_choice4; + wxStaticText* m_staticText3; + wxChoice* m_constraintSource; + wxStaticText* m_targetLengthLabel; + wxTextCtrl* m_targetLengthText; + wxStaticText* m_targetLengthUnit; + wxStaticBitmap* m_legend; + wxStaticText* m_staticText9; + wxTextCtrl* m_minAmplText; + wxStaticText* m_minAmplUnit; + wxStaticText* m_staticText91; + wxTextCtrl* m_maxAmplText; + wxStaticText* m_maxAmplUnit; + wxStaticText* m_staticText11; + wxTextCtrl* m_spacingText; + wxStaticText* m_spacingUnit; + wxStaticText* m_staticText13; + wxTextCtrl* m_radiusText; + wxStaticText* m_radiusUnit; + wxStaticText* m_staticText14; + wxChoice* m_miterStyle; + wxStdDialogButtonSizer* m_stdButtons; + wxButton* m_stdButtonsOK; + wxButton* m_stdButtonsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Trace length tuning"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 345,668 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE(); + +}; + +#endif //__DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE_H__ diff --git a/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak b/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak new file mode 100644 index 0000000000..fdda4f1fef --- /dev/null +++ b/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak @@ -0,0 +1,1334 @@ + + + + + + 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 + + 279,481 + wxDEFAULT_DIALOG_STYLE + DIALOG_SHIM; dialog_shim.h + Interactive Router settings + + + + + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 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 + 0 + 1 + + wxRA_SPECIFY_COLS + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 1 + + wxID_ANY + Options + + bOptions + wxVERTICAL + none + + + 5 + wxTOP|wxRIGHT|wxLEFT + 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 + wxTOP|wxRIGHT|wxLEFT + 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 + wxTOP|wxRIGHT|wxLEFT + 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 + wxTOP|wxRIGHT|wxLEFT + 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 + wxTOP|wxRIGHT|wxLEFT + 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 + wxTOP|wxRIGHT|wxLEFT + 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 + wxEXPAND + 0 + + + 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 | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_stdButtons + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_track_via_size.cpp b/pcbnew/dialogs/dialog_track_via_size.cpp index ab9e1cac37..82abe58169 100644 --- a/pcbnew/dialogs/dialog_track_via_size.cpp +++ b/pcbnew/dialogs/dialog_track_via_size.cpp @@ -31,15 +31,20 @@ DIALOG_TRACK_VIA_SIZE::DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, BOARD_DESIGN_SETTINGS& aSettings ) : DIALOG_TRACK_VIA_SIZE_BASE( aParent ), + m_trackWidth( aParent, m_trackWidthText, m_trackWidthLabel ), + m_viaDiameter( aParent, m_viaDiameterText, m_viaDiameterLabel ), + m_viaDrill( aParent, m_viaDrillText, m_viaDrillLabel ), m_settings( aSettings ) { // Load router settings to dialog fields - m_trackWidth->SetValue( To_User_Unit( m_trackWidth->GetUnits(), m_settings.GetCustomTrackWidth() ) ); - m_viaDiameter->SetValue( To_User_Unit( m_viaDiameter->GetUnits(), m_settings.GetCustomViaSize() ) ); - m_viaDrill->SetValue( To_User_Unit( m_viaDrill->GetUnits(), m_settings.GetCustomViaDrill() ) ); - - m_trackWidth->SetFocus(); + m_trackWidth.SetValue( m_settings.GetCustomTrackWidth() ); + m_viaDiameter.SetValue( m_settings.GetCustomViaSize() ); + m_viaDrill.SetValue( m_settings.GetCustomViaDrill() ); + m_trackWidthText->SetFocus(); + m_trackWidthText->SetSelection(-1, -1); + m_stdButtonsOK->SetDefault(); + // 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 ); @@ -54,11 +59,11 @@ DIALOG_TRACK_VIA_SIZE::DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, BOARD_DESIGN_SE bool DIALOG_TRACK_VIA_SIZE::check() { // Wrong input - if( !m_trackWidth->GetValue() || !m_viaDiameter->GetValue() || !m_viaDrill->GetValue() ) + if( m_trackWidth.GetValue() < 0 || m_viaDiameter.GetValue() < 0 || m_viaDrill.GetValue() < 0 ) return false; // Via drill should be smaller than via diameter - if( m_viaDrill->GetValue() >= m_viaDiameter->GetValue() ) + if( m_viaDrill.GetValue() >= m_viaDiameter.GetValue() ) return false; return true; @@ -76,15 +81,15 @@ void DIALOG_TRACK_VIA_SIZE::onOkClick( wxCommandEvent& aEvent ) if( check() ) { // Store dialog values to the router settings - m_settings.SetCustomTrackWidth( From_User_Unit( m_trackWidth->GetUnits(), *m_trackWidth->GetValue() ) ); - m_settings.SetCustomViaSize( From_User_Unit( m_viaDiameter->GetUnits(), *m_viaDiameter->GetValue() ) ); - m_settings.SetCustomViaDrill( From_User_Unit( m_viaDrill->GetUnits(), *m_viaDrill->GetValue() ) ); + m_settings.SetCustomTrackWidth( m_trackWidth.GetValue() ); + m_settings.SetCustomViaSize( m_viaDiameter.GetValue() ); + m_settings.SetCustomViaDrill( m_viaDrill.GetValue() ); EndModal( 1 ); } else { DisplayError( GetParent(), _( "Settings are incorrect" ) ); - m_trackWidth->SetFocus(); + m_trackWidthText->SetFocus(); } } diff --git a/pcbnew/dialogs/dialog_track_via_size.h b/pcbnew/dialogs/dialog_track_via_size.h index 5db003d7de..c265e53311 100644 --- a/pcbnew/dialogs/dialog_track_via_size.h +++ b/pcbnew/dialogs/dialog_track_via_size.h @@ -25,6 +25,8 @@ #ifndef __dialog_track_via_size__ #define __dialog_track_via_size__ +#include + #include "dialog_track_via_size_base.h" class BOARD_DESIGN_SETTINGS; @@ -37,6 +39,11 @@ class DIALOG_TRACK_VIA_SIZE : public DIALOG_TRACK_VIA_SIZE_BASE DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, BOARD_DESIGN_SETTINGS& aSettings ); protected: + + WX_UNIT_BINDER m_trackWidth; + WX_UNIT_BINDER m_viaDiameter; + WX_UNIT_BINDER m_viaDrill; + // Routings settings that are modified by the dialog. BOARD_DESIGN_SETTINGS& m_settings; diff --git a/pcbnew/dialogs/dialog_track_via_size_base.cpp b/pcbnew/dialogs/dialog_track_via_size_base.cpp index a1bfad0ce4..1c963f6bae 100644 --- a/pcbnew/dialogs/dialog_track_via_size_base.cpp +++ b/pcbnew/dialogs/dialog_track_via_size_base.cpp @@ -16,14 +16,46 @@ DIALOG_TRACK_VIA_SIZE_BASE::DIALOG_TRACK_VIA_SIZE_BASE( wxWindow* parent, wxWind wxBoxSizer* bSizes; bSizes = new wxBoxSizer( wxVERTICAL ); - m_trackWidth = new WX_UNIT_TEXT( this, _("Track width:") ); - bSizes->Add( m_trackWidth, 0, wxALL|wxEXPAND, 5 ); + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer1->SetFlexibleDirection( wxBOTH ); + fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - m_viaDiameter = new WX_UNIT_TEXT( this, _("Via diameter:") ); - bSizes->Add( m_viaDiameter, 0, wxALL|wxEXPAND, 5 ); + m_staticText3 = new wxStaticText( this, wxID_ANY, _("Track width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + fgSizer1->Add( m_staticText3, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_viaDrill = new WX_UNIT_TEXT( this, _("Via drill:") ); - bSizes->Add( m_viaDrill, 0, wxALL|wxEXPAND, 5 ); + m_trackWidthText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_trackWidthText, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_trackWidthLabel = new wxStaticText( this, wxID_ANY, _("inch"), wxDefaultPosition, wxDefaultSize, 0 ); + m_trackWidthLabel->Wrap( -1 ); + fgSizer1->Add( m_trackWidthLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText5 = new wxStaticText( this, wxID_ANY, _("Via diameter:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + fgSizer1->Add( m_staticText5, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_viaDiameterText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_viaDiameterText, 1, wxALL|wxEXPAND, 5 ); + + m_viaDiameterLabel = new wxStaticText( this, wxID_ANY, _("u"), wxDefaultPosition, wxDefaultSize, 0 ); + m_viaDiameterLabel->Wrap( -1 ); + fgSizer1->Add( m_viaDiameterLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText7 = new wxStaticText( this, wxID_ANY, _("Via drill:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText7->Wrap( -1 ); + fgSizer1->Add( m_staticText7, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_viaDrillText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_viaDrillText, 1, wxALL|wxEXPAND, 5 ); + + m_viaDrillLabel = new wxStaticText( this, wxID_ANY, _("u"), wxDefaultPosition, wxDefaultSize, 0 ); + m_viaDrillLabel->Wrap( -1 ); + fgSizer1->Add( m_viaDrillLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizes->Add( fgSizer1, 1, wxEXPAND|wxALL, 5 ); m_stdButtons = new wxStdDialogButtonSizer(); m_stdButtonsOK = new wxButton( this, wxID_OK ); diff --git a/pcbnew/dialogs/dialog_track_via_size_base.fbp b/pcbnew/dialogs/dialog_track_via_size_base.fbp index c2e3325af7..6f660994ad 100644 --- a/pcbnew/dialogs/dialog_track_via_size_base.fbp +++ b/pcbnew/dialogs/dialog_track_via_size_base.fbp @@ -95,257 +95,791 @@ none 5 - wxALL|wxEXPAND - 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 + wxEXPAND|wxALL + 1 + + 3 + wxBOTH + + + 0 - 1 - m_trackWidth - 1 - - - protected - 1 - - Resizable - - 1 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL|wxEXPAND - 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|wxEXPAND - 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Track width: + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_trackWidthText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + inch + + 0 + + + 0 + + 1 + m_trackWidthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via diameter: + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_viaDiameterText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + u + + 0 + + + 0 + + 1 + m_viaDiameterLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via drill: + + 0 + + + 0 + + 1 + m_staticText7 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_viaDrillText + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + u + + 0 + + + 0 + + 1 + m_viaDrillLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_track_via_size_base.h b/pcbnew/dialogs/dialog_track_via_size_base.h index 3f62c01588..8cff008abf 100644 --- a/pcbnew/dialogs/dialog_track_via_size_base.h +++ b/pcbnew/dialogs/dialog_track_via_size_base.h @@ -11,12 +11,13 @@ #include #include #include -#include +#include +#include #include #include #include #include -#include +#include #include #include #include @@ -32,9 +33,15 @@ 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; + wxStaticText* m_staticText3; + wxTextCtrl* m_trackWidthText; + wxStaticText* m_trackWidthLabel; + wxStaticText* m_staticText5; + wxTextCtrl* m_viaDiameterText; + wxStaticText* m_viaDiameterLabel; + wxStaticText* m_staticText7; + wxTextCtrl* m_viaDrillText; + wxStaticText* m_viaDrillLabel; wxStdDialogButtonSizer* m_stdButtons; wxButton* m_stdButtonsOK; wxButton* m_stdButtonsCancel; diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 92008ca165..4c86dbceef 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -433,6 +433,49 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Set the origin point for the grid" ), KiBitmap( grid_select_axis_xpm ) ); + wxMenu* routeMenu = new wxMenu; + + AddMenuItem( routeMenu, ID_TRACK_BUTT, + _( "Single Track" ), + _( "Interactively route a single track" ), + KiBitmap( add_tracks_xpm ) ); + + AddMenuItem( routeMenu, ID_DIFF_PAIR_BUTT, + _( "Differential Pair" ), + _( "Interactively route a differential pair" ), + KiBitmap( add_tracks_xpm ) ); + + routeMenu->AppendSeparator(); + + AddMenuItem( routeMenu, ID_TUNE_SINGLE_TRACK_LEN_BUTT, + _( "Tune Track Length" ), + _( "Tune length of a single track" ), + KiBitmap( add_tracks_xpm ) ); + + AddMenuItem( routeMenu, ID_TUNE_DIFF_PAIR_LEN_BUTT, + _( "Tune Differential Pair Length" ), + _( "Tune length of a differential pair" ), + KiBitmap( add_tracks_xpm ) ); + + AddMenuItem( routeMenu, ID_TUNE_DIFF_PAIR_SKEW_BUTT, + _( "Tune Differential Pair Skew/Phase" ), + _( "Tune skew/phase of a differential pair" ), + KiBitmap( add_tracks_xpm ) ); + +/* Fixme: add icons & missing menu entries! + routeMenu->AppendSeparator(); + + AddMenuItem( routeMenu, ID_MENU_MITER_TRACES, + _( "Miter traces..." ), + _( "Miter trace corners with arcs" ), + KiBitmap( grid_select_axis_xpm ) ); + + AddMenuItem( routeMenu, ID_MENU_ADD_TEARDROPS, + _( "Teardrops..." ), + _( "Add teardrops to pads/vias" ), + KiBitmap( grid_select_axis_xpm ) ); +*/ + //----- Preferences and configuration menu------------------------------------ wxMenu* configmenu = new wxMenu; @@ -467,6 +510,12 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Select how items (pads, tracks texts ... ) are displayed" ), KiBitmap( display_options_xpm ) ); + AddMenuItem( configmenu, ID_MENU_INTERACTIVE_ROUTER_SETTINGS, + _( "Interactive Routing" ), + _( "Configure Interactive Routing." ), + KiBitmap( add_tracks_xpm ) ); // fixme: icon + + //--- dimensions submenu ------------------------------------------------------ wxMenu* dimensionsMenu = new wxMenu; @@ -488,6 +537,11 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Adjust the global clearance between pads and the solder resist mask" ), KiBitmap( pads_mask_layers_xpm ) ); + AddMenuItem( dimensionsMenu, ID_MENU_DIFF_PAIR_DIMENSIONS, + _( "Differential Pairs" ), + _( "Define the global gap/width for differential pairs." ), + KiBitmap( add_tracks_xpm ) ); // fixme: icon + dimensionsMenu->AppendSeparator(); AddMenuItem( dimensionsMenu, ID_CONFIG_SAVE, _( "&Save" ), _( "Save dimension preferences" ), @@ -592,6 +646,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() menuBar->Append( editMenu, _( "&Edit" ) ); menuBar->Append( viewMenu, _( "&View" ) ); menuBar->Append( placeMenu, _( "&Place" ) ); + menuBar->Append( routeMenu, _( "&Route" ) ); menuBar->Append( configmenu, _( "P&references" ) ); menuBar->Append( dimensionsMenu, _( "D&imensions" ) ); menuBar->Append( toolsMenu, _( "&Tools" ) ); diff --git a/pcbnew/router/CMakeLists.txt b/pcbnew/router/CMakeLists.txt index a69b09118f..2f324def01 100644 --- a/pcbnew/router/CMakeLists.txt +++ b/pcbnew/router/CMakeLists.txt @@ -13,12 +13,19 @@ set( PCBNEW_PNS_SRCS time_limit.cpp pns_algo_base.cpp + pns_diff_pair.cpp + pns_diff_pair_placer.cpp + pns_dp_meander_placer.cpp pns_dragger.cpp pns_item.cpp pns_itemset.cpp pns_line.cpp pns_line_placer.cpp pns_logger.cpp + pns_meander.cpp + pns_meander_placer.cpp + pns_meander_placer_base.cpp + pns_meander_skew_placer.cpp pns_node.cpp pns_optimizer.cpp pns_router.cpp @@ -26,11 +33,15 @@ set( PCBNEW_PNS_SRCS pns_shove.cpp pns_sizes_settings.cpp pns_solid.cpp + pns_tool_base.cpp + pns_topology.cpp + pns_tune_status_popup.cpp pns_utils.cpp pns_via.cpp pns_walkaround.cpp router_preview_item.cpp router_tool.cpp + length_tuner_tool.cpp ) add_library( pnsrouter STATIC ${PCBNEW_PNS_SRCS} ) diff --git a/pcbnew/router/direction.h b/pcbnew/router/direction.h index eb37a14988..44f137e68d 100644 --- a/pcbnew/router/direction.h +++ b/pcbnew/router/direction.h @@ -73,7 +73,7 @@ public: */ DIRECTION_45( const VECTOR2I& aVec ) { - construct( aVec ); + construct_( aVec ); } /** @@ -82,7 +82,7 @@ public: */ DIRECTION_45( const SEG& aSeg ) { - construct( aSeg.B - aSeg.A ); + construct_( aSeg.B - aSeg.A ); } /** @@ -309,6 +309,11 @@ public: } } + int Mask() const + { + return 1 << ( (int) m_dir ); + } + private: /** @@ -316,7 +321,7 @@ private: * 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 */ - void construct( const VECTOR2I& aVec ) + void construct_( const VECTOR2I& aVec ) { m_dir = UNDEFINED; diff --git a/pcbnew/router/length_tuner_tool.cpp b/pcbnew/router/length_tuner_tool.cpp new file mode 100644 index 0000000000..3bfe403cc9 --- /dev/null +++ b/pcbnew/router/length_tuner_tool.cpp @@ -0,0 +1,319 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 + +#include "class_draw_panel_gal.h" +#include "class_board.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "pns_segment.h" +#include "pns_router.h" +#include "pns_meander_placer.h" // fixme: move settings to separate header +#include "pns_tune_status_popup.h" + +#include "length_tuner_tool.h" + +#include "trace.h" + +using namespace KIGFX; +using boost::optional; + +static TOOL_ACTION ACT_StartTuning( "pcbnew.LengthTuner.StartTuning", + AS_CONTEXT, 'X', + "New Track", "Starts laying a new track."); +static TOOL_ACTION ACT_EndTuning( "pcbnew.LengthTuner.EndTuning", + AS_CONTEXT, WXK_END, + "End Track", "Stops laying the current meander."); + +static TOOL_ACTION ACT_Settings( "pcbnew.LengthTuner.Settings", + AS_CONTEXT, 'L', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + +static TOOL_ACTION ACT_SpacingIncrease( "pcbnew.LengthTuner.SpacingIncrease", + AS_CONTEXT, '1', + "Increase spacing", "Increase meander spacing by one step."); + +static TOOL_ACTION ACT_SpacingDecrease( "pcbnew.LengthTuner.SpacingDecrease", + AS_CONTEXT, '2', + "Decrease spacing ", "Decrease meander spacing by one step."); + +static TOOL_ACTION ACT_AmplIncrease( "pcbnew.LengthTuner.AmplIncrease", + AS_CONTEXT, '3', + "Increase amplitude", "Increase meander amplitude by one step."); + +static TOOL_ACTION ACT_AmplDecrease( "pcbnew.LengthTuner.AmplDecrease", + AS_CONTEXT, '4', + "Decrease amplitude", "Decrease meander amplitude by one step."); + + +LENGTH_TUNER_TOOL::LENGTH_TUNER_TOOL() : + PNS_TOOL_BASE( "pcbnew.LengthTuner" ) +{ +} + + +class TUNER_TOOL_MENU: public CONTEXT_MENU +{ +public: + TUNER_TOOL_MENU( BOARD* aBoard ) + { + SetTitle( wxT( "Length Tuner" ) ); + + //Add( ACT_StartTuning ); + //Add( ACT_EndTuning ); + + //AppendSeparator(); + + Add( ACT_SpacingIncrease ); + Add( ACT_SpacingDecrease ); + Add( ACT_AmplIncrease ); + Add( ACT_AmplDecrease ); + Add( ACT_Settings ); + } +}; + + +LENGTH_TUNER_TOOL::~LENGTH_TUNER_TOOL() +{ + delete m_router; +} + +void LENGTH_TUNER_TOOL::Reset( RESET_REASON aReason ) +{ + PNS_TOOL_BASE::Reset( aReason ); + + Go( &LENGTH_TUNER_TOOL::TuneSingleTrace, COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent() ); + Go( &LENGTH_TUNER_TOOL::TuneDiffPair, COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent() ); + Go( &LENGTH_TUNER_TOOL::TuneDiffPairSkew, COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent() ); +} + + +void LENGTH_TUNER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) +{ + if( aEvent.IsAction( &ACT_RouterOptions ) ) + { + DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() ); + + if( settingsDlg.ShowModal() ) + { + // FIXME: do we need an explicit update? + } + } + + PNS_MEANDER_PLACER_BASE *placer = static_cast ( m_router->Placer() ); + + if (!placer) + return; + + if( aEvent.IsAction( &ACT_Settings ) ) + { + PNS_MEANDER_SETTINGS settings = placer->MeanderSettings(); + DIALOG_PNS_LENGTH_TUNING_SETTINGS settingsDlg( m_frame, settings, m_router->Mode() ); + + if( settingsDlg.ShowModal() ) + { + placer->UpdateSettings ( settings ); + } + + m_savedMeanderSettings = placer->MeanderSettings( ); + } +} + +void LENGTH_TUNER_TOOL::performTuning() +{ + bool saveUndoBuffer = true; + + if(m_startItem) + { + m_frame->SetActiveLayer( ToLAYER_ID ( m_startItem->Layers().Start() ) ); + + if( m_startItem->Net() >= 0 ) + highlightNet( true, m_startItem->Net() ); + } + + m_ctls->ForceCursorPosition( false ); + m_ctls->SetAutoPan( true ); + + if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, 0 ) ) + { + wxMessageBox ( m_router->FailureReason(), _("Error") ); + highlightNet ( false ); + return; + } + + PNS_TUNE_STATUS_POPUP statusPopup ( m_frame ); + statusPopup.Popup(); + + PNS_MEANDER_PLACER *placer = static_cast ( m_router->Placer() ); + VECTOR2I end; + + placer->UpdateSettings( m_savedMeanderSettings ); + + + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( evt->IsCancel() || evt->IsActivate() ) + break; + else if( evt->Action() == TA_UNDO_REDO ) + { + saveUndoBuffer = false; + break; + } + else if( evt->IsMotion() ) + { + end = evt->Position(); + m_router->Move( end, NULL ); + + wxPoint p = wxGetMousePosition(); + + p.x+=20; + p.y+=20; + + statusPopup.Update ( m_router ); + statusPopup.Move( p ); + } + else if( evt->IsClick( BUT_LEFT ) ) + { + if( m_router->FixRoute( evt->Position(), NULL ) ) + break; + } + else if( evt->IsAction( &ACT_EndTuning ) ) + { + if( m_router->FixRoute( end, NULL ) ) + break; + } else if (evt->IsAction ( &ACT_AmplDecrease ) ) { + placer->AmplitudeStep( -1 ); + m_router->Move( end, NULL ); + } else if (evt->IsAction ( &ACT_AmplIncrease ) ) { + placer->AmplitudeStep( 1 ); + m_router->Move( end, NULL ); + } else if (evt->IsAction ( &ACT_SpacingDecrease ) ) { + placer->SpacingStep( -1 ); + m_router->Move( end, NULL ); + } else if (evt->IsAction ( &ACT_SpacingIncrease ) ) { + placer->SpacingStep( 1 ); + m_router->Move( end, NULL ); + } + + handleCommonEvents( *evt ); + } + + m_router->StopRouting(); + + if( saveUndoBuffer ) + { + // Save the recent changes in the undo buffer + m_frame->SaveCopyInUndoList( m_router->GetUndoBuffer(), UR_UNSPECIFIED ); + m_router->ClearUndoBuffer(); + m_frame->OnModify(); + } + else + { + // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now + m_needsSync = true; + } + + m_ctls->SetAutoPan( false ); + m_ctls->ForceCursorPosition( false ); + highlightNet( false ); + +} + +int LENGTH_TUNER_TOOL::TuneSingleTrace ( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Trace Length" ) ); + return mainLoop( PNS_MODE_TUNE_SINGLE ); +} + +int LENGTH_TUNER_TOOL::TuneDiffPair ( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Diff Pair Length" ) ); + return mainLoop( PNS_MODE_TUNE_DIFF_PAIR ); +} + +int LENGTH_TUNER_TOOL::TuneDiffPairSkew ( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Diff Pair Skew" ) ); + return mainLoop( PNS_MODE_TUNE_DIFF_PAIR_SKEW ); +} + + +int LENGTH_TUNER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) +{ + // Deselect all items + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + + Activate(); + + m_router->SetMode ( aMode ); + + m_ctls->SetSnapping( true ); + m_ctls->ShowCursor( true ); + + std::auto_ptr ctxMenu ( new TUNER_TOOL_MENU( m_board ) ); + SetContextMenu ( ctxMenu.get() ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( m_needsSync ) + { + m_router->SyncWorld(); + m_router->SetView( getView() ); + m_needsSync = false; + } + + if( evt->IsCancel() || evt->IsActivate() ) + break; // Finish + else if( evt->Action() == TA_UNDO_REDO ) + m_needsSync = true; + else if( evt->IsMotion() ) + updateStartItem( *evt ); + else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_StartTuning ) ) + { + updateStartItem( *evt ); + performTuning( ); + } + + handleCommonEvents( *evt ); + } + + // Restore the default settings + m_ctls->SetAutoPan( false ); + m_ctls->ShowCursor( false ); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + // Store routing settings till the next invocation + m_savedSettings = m_router->Settings(); + m_savedSizes = m_router->Sizes(); + + return 0; +} \ No newline at end of file diff --git a/pcbnew/router/length_tuner_tool.h b/pcbnew/router/length_tuner_tool.h new file mode 100644 index 0000000000..79a2cd39ab --- /dev/null +++ b/pcbnew/router/length_tuner_tool.h @@ -0,0 +1,52 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 + * 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 __LENGTH_TUNER_TOOL_H +#define __LENGTH_TUNER_TOOL_H + +#include "pns_tool_base.h" +#include "pns_meander.h" + +class PNS_TUNE_STATUS_POPUP; + +class APIEXPORT LENGTH_TUNER_TOOL : public PNS_TOOL_BASE +{ +public: + LENGTH_TUNER_TOOL(); + ~LENGTH_TUNER_TOOL(); + + void Reset( RESET_REASON aReason ); + + int TuneSingleTrace ( const TOOL_EVENT& aEvent ); + int TuneDiffPair ( const TOOL_EVENT& aEvent ); + int TuneDiffPairSkew ( const TOOL_EVENT& aEvent ); + int ClearMeanders ( const TOOL_EVENT& aEvent ); + +private: + + void performTuning( ); + int mainLoop( PNS_ROUTER_MODE aMode ); + void handleCommonEvents( const TOOL_EVENT& evt ); + + PNS_MEANDER_SETTINGS m_savedMeanderSettings; +}; + +#endif diff --git a/pcbnew/router/pns_algo_base.h b/pcbnew/router/pns_algo_base.h index 1aa94333fc..e48fcf8137 100644 --- a/pcbnew/router/pns_algo_base.h +++ b/pcbnew/router/pns_algo_base.h @@ -21,6 +21,8 @@ #ifndef __PNS_ALGO_BASE_H #define __PNS_ALGO_BASE_H +#include // for wxString + #include "pns_routing_settings.h" class PNS_ROUTER; @@ -53,6 +55,7 @@ public: ///> Returns the logger object, allowing to dump geometry to a file. virtual PNS_LOGGER* Logger(); + private: PNS_ROUTER* m_router; diff --git a/pcbnew/router/pns_diff_pair.cpp b/pcbnew/router/pns_diff_pair.cpp new file mode 100644 index 0000000000..dba1e3153a --- /dev/null +++ b/pcbnew/router/pns_diff_pair.cpp @@ -0,0 +1,825 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 +#include +#include + +#include +#include +#include +#include + +#include "direction.h" + +#include "pns_diff_pair.h" +#include "pns_router.h" +#include "pns_solid.h" +#include "pns_utils.h" + + +class PNS_LINE; + +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( PNS_ITEM *aPrimP, PNS_ITEM *aPrimN ) +{ + m_primP = aPrimP->Clone(); + m_primN = aPrimN->Clone(); + + m_anchorP = m_primP->Anchor(0); + m_anchorN = m_primN->Anchor(0); +} + +void PNS_DP_PRIMITIVE_PAIR::SetAnchors( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ) +{ + m_anchorP = aAnchorP; + m_anchorN = aAnchorN; +} + +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ) +{ + m_anchorP = aAnchorP; + m_anchorN = aAnchorN; + m_primP = m_primN = NULL; +} + +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( const PNS_DP_PRIMITIVE_PAIR& aOther ) +{ + if(aOther.m_primP) + m_primP = aOther.m_primP->Clone(); + if(aOther.m_primN) + m_primN = aOther.m_primN->Clone(); + + m_anchorP = aOther.m_anchorP; + m_anchorN = aOther.m_anchorN; +} + +PNS_DP_PRIMITIVE_PAIR& PNS_DP_PRIMITIVE_PAIR::operator= ( const PNS_DP_PRIMITIVE_PAIR& aOther ) +{ + if(aOther.m_primP) + m_primP = aOther.m_primP->Clone(); + if(aOther.m_primN) + m_primN = aOther.m_primN->Clone(); + + m_anchorP = aOther.m_anchorP; + m_anchorN = aOther.m_anchorN; + + return *this; +} + + +PNS_DP_PRIMITIVE_PAIR::~PNS_DP_PRIMITIVE_PAIR() +{ + delete m_primP; + delete m_primN; +} + +bool PNS_DP_PRIMITIVE_PAIR::Directional() const +{ + if (!m_primP) + return false; + + return m_primP->OfKind(PNS_ITEM::SEGMENT); +} + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::anchorDirection ( PNS_ITEM *aItem, const VECTOR2I& aP ) const +{ + if( !aItem->OfKind ( PNS_ITEM::SEGMENT ) ) + return DIRECTION_45(); + + PNS_SEGMENT *s = static_cast (aItem); + + if(s->Seg().A == aP) + return DIRECTION_45 ( s->Seg().A - s->Seg().B ); + else + return DIRECTION_45 ( s->Seg().B - s->Seg().A ); +} + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirP () const +{ + return anchorDirection ( m_primP, m_anchorP ); +} + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirN () const +{ + return anchorDirection ( m_primN, m_anchorN ); +} + +static void drawGw ( VECTOR2I p, int color ) +{ + SHAPE_LINE_CHAIN l; + + l.Append ( p - VECTOR2I(-50000, -50000) ); + l.Append ( p + VECTOR2I(-50000, -50000) ); + + //printf("router @ %p\n", PNS_ROUTER::GetInstance()); +// PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + + l.Clear(); + l.Append ( p - VECTOR2I(50000, -50000) ); + l.Append ( p + VECTOR2I(50000, -50000) ); + +// PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + + +} + + +static DIRECTION_45::AngleType angle ( const VECTOR2I &a, const VECTOR2I &b ) +{ + DIRECTION_45 dir_a(a); + DIRECTION_45 dir_b(b); + + return dir_a.Angle(dir_b); + +} + +static bool checkGap ( const SHAPE_LINE_CHAIN &p, const SHAPE_LINE_CHAIN &n, int gap ) +{ + int i, j; + + for (i = 0; i < p.SegmentCount() ;i++) + for (j = 0; j < n.SegmentCount() ; j++) + { + int dist = p.CSegment(i).Distance (n.CSegment(j)); + if (dist < gap - 100) + return false; + } + return true; +} + +void PNS_DP_GATEWAY::Reverse() +{ + m_entryN = m_entryN.Reverse(); + m_entryP = m_entryP.Reverse(); +} + +bool PNS_DIFF_PAIR::BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarget, bool aPrefDiagonal ) +{ + SHAPE_LINE_CHAIN p = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorP(), aTarget.AnchorP(), aPrefDiagonal ); + SHAPE_LINE_CHAIN n = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorN(), aTarget.AnchorN(), aPrefDiagonal ); + + if(!checkGap ( p, n, m_gapConstraint )) + return false; + + if (p.SelfIntersecting() || n.SelfIntersecting() ) + return false; + + if(p.Intersects(n)) + return false; + + int mask = aEntry.AllowedAngles() | DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_OBTUSE; + + SHAPE_LINE_CHAIN sum_n, sum_p; + m_p = p; + m_n = n; + + if( aEntry.HasEntryLines() ) + { + if ( !aEntry.Entry().CheckConnectionAngle( *this, mask ) ) + return false; + sum_p = aEntry.Entry().CP(); + sum_n = aEntry.Entry().CN(); + sum_p.Append(p); + sum_n.Append(n); + } else { + sum_p = p; + sum_n = n; + } + + mask = aTarget.AllowedAngles() | DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_OBTUSE; + + m_p = sum_p; + m_n = sum_n; + + if( aTarget.HasEntryLines() ) + { + PNS_DP_GATEWAY t(aTarget) ; + t.Reverse(); + + if( !CheckConnectionAngle( t.Entry(), mask ) ) + return false; + + sum_p.Append( t.Entry().CP() ); + sum_n.Append( t.Entry().CN() ); + + } + + m_p = sum_p; + m_n = sum_n; + + return true; +} + +bool PNS_DIFF_PAIR::CheckConnectionAngle ( const PNS_DIFF_PAIR &aOther, int allowedAngles ) const +{ + bool checkP, checkN; + + + if( m_p.SegmentCount() == 0 || aOther.m_p.SegmentCount() == 0) + checkP = true; + else { + DIRECTION_45 p0 ( m_p.CSegment(-1) ); + DIRECTION_45 p1 ( aOther.m_p.CSegment(0) ); + + checkP = (p0.Angle(p1) & allowedAngles) != 0; + } + + + if( m_n.SegmentCount() == 0 || aOther.m_n.SegmentCount() == 0) + checkN = true; + else { + DIRECTION_45 n0 ( m_n.CSegment(-1) ); + DIRECTION_45 n1 ( aOther.m_n.CSegment(0) ); + + checkN = (n0.Angle(n1) & allowedAngles) != 0; + } + + return checkP && checkN; +} + +const PNS_DIFF_PAIR PNS_DP_GATEWAY::Entry() const +{ + return PNS_DIFF_PAIR(m_entryP, m_entryN, 0); +} + +void PNS_DP_GATEWAYS::BuildOrthoProjections ( PNS_DP_GATEWAYS& aEntries, const VECTOR2I& aCursorPos, int aOrthoScore ) +{ + BOOST_FOREACH(PNS_DP_GATEWAY g, aEntries.Gateways()) + { + VECTOR2I dir = (g.AnchorP() - g.AnchorN()).Perpendicular(); + VECTOR2I midpoint ( ( g.AnchorP() + g.AnchorN() ) / 2); + SEG guide ( midpoint, midpoint + dir ); + VECTOR2I proj = guide.LineProject(aCursorPos); + + + PNS_DP_GATEWAYS targets(m_gap); + + targets.m_viaGap = m_viaGap; + targets.m_viaDiameter = m_viaDiameter; + targets.m_fitVias = m_fitVias; + + targets.BuildForCursor ( proj ); + + BOOST_FOREACH ( PNS_DP_GATEWAY t, targets.Gateways() ) + { + t.SetPriority ( aOrthoScore ); + m_gateways.push_back ( t ); + } + } +} + + +bool PNS_DP_GATEWAYS::FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ) +{ + std::vector candidates; + + BOOST_FOREACH( PNS_DP_GATEWAY g_entry, aEntry.Gateways() ) + { + BOOST_FOREACH ( PNS_DP_GATEWAY g_target, aTarget.Gateways() ) + { + for(int attempt = 0; attempt < 2; attempt ++) + { + PNS_DIFF_PAIR l ( m_gap ); + + if ( l.BuildInitial( g_entry, g_target, aPrefDiagonal ^ (attempt ? true : false) ) ) + { + int score = (attempt == 1 ? -3 : 0); + score +=g_entry.Priority(); + score +=g_target.Priority(); + + + DP_CANDIDATE c; + c.score = score; + c.p = l.CP(); + c.n = l.CN(); + candidates.push_back(c); + } + } + } + } + + int bestScore = -1000; + DP_CANDIDATE best; + bool found; + + BOOST_FOREACH( DP_CANDIDATE c, candidates ) + { + if ( c.score > bestScore ) + { + bestScore = c.score; + best = c; + found = true; + } + } + + if ( found ) + { + aDp.SetGap ( m_gap ); + aDp.SetShape( best.p, best.n ); + return true; + } + + return false; +} + +bool PNS_DP_GATEWAYS::checkDiagonalAlignment ( const VECTOR2I& a, const VECTOR2I& b) const +{ + VECTOR2I dir ( std::abs (a.x - b.x), std::abs ( a.y - b.y )); + + return (dir.x == 0 && dir.y != 0) || (dir.x == dir.y) || (dir.y == 0 && dir.x != 0); +} + + +void PNS_DP_GATEWAYS::BuildFromPrimitivePair( PNS_DP_PRIMITIVE_PAIR aPair, bool aPreferDiagonal ) +{ + VECTOR2I majorDirection; + VECTOR2I p0_p, p0_n; + int orthoFanDistance; + int diagFanDistance; + const SHAPE *shP = NULL; + + if( aPair.PrimP() == NULL) + { + BuildGeneric ( aPair.AnchorP(), aPair.AnchorN(), true ); + return; + } + + const int pvMask = PNS_ITEM::SOLID | PNS_ITEM::VIA; + + if ( aPair.PrimP()->OfKind ( pvMask ) && aPair.PrimN()->OfKind ( pvMask ) ) + { + p0_p = aPair.AnchorP(); + p0_n = aPair.AnchorN(); + + shP = aPair.PrimP()->Shape(); + + } else if ( aPair.PrimP()->OfKind ( PNS_ITEM::SEGMENT ) && aPair.PrimN()->OfKind ( PNS_ITEM::SEGMENT ) ) { + buildDpContinuation ( aPair, aPreferDiagonal ); + + return; + } + + majorDirection = (p0_p - p0_n).Perpendicular(); + + switch( shP->Type() ) + { + case SH_RECT: + { + int w = static_cast ( shP )->GetWidth(); + int h = static_cast ( shP )->GetHeight(); + + if(w < h) + std::swap(w,h); + + orthoFanDistance = w * 3/4; + diagFanDistance = (w - h) / 2; + break; + } + + case SH_SEGMENT: + { + int w = static_cast ( shP )->GetWidth(); + SEG s = static_cast ( shP )->GetSeg(); + + orthoFanDistance = w + (s.B - s.A).EuclideanNorm() / 2; + diagFanDistance = (s.B - s.A).EuclideanNorm() / 2; + break; + } + + default: + BuildGeneric ( p0_p, p0_n, true ); + return; + } + + if(checkDiagonalAlignment ( p0_p, p0_n )) + { + int padDist = (p0_p - p0_n).EuclideanNorm(); + + for(int k = 0; k < 2; k++ ) + { + VECTOR2I dir, dp, dv; + + if(k == 0) + { + + dir = majorDirection.Resize(orthoFanDistance); + int d = (padDist - m_gap) / 2; + + dp = dir.Resize( d ); + dv = (p0_n - p0_p).Resize( d ); + } else { + dir = majorDirection.Resize(diagFanDistance); + int d = (padDist - m_gap) / 2; + dp = dir.Resize( d ); + dv = (p0_n - p0_p).Resize( d ); + } + + for(int i = 0; i < 2; i++) + { + int sign = i ? -1 : 1; + + VECTOR2I gw_p ( p0_p + sign * (dir + dp) + dv ); + VECTOR2I gw_n ( p0_n + sign * (dir + dp) - dv ); + + SHAPE_LINE_CHAIN entryP (p0_p, p0_p + sign * dir, gw_p); + SHAPE_LINE_CHAIN entryN (p0_n, p0_n + sign * dir, gw_n); + + PNS_DP_GATEWAY gw ( gw_p, gw_n, false ); + + gw.SetEntryLines ( entryP, entryN ); + gw.SetPriority(100 - k); + m_gateways.push_back( gw ); + } + } + } + + BuildGeneric ( p0_p, p0_n, true ); +} + + +void PNS_DP_GATEWAYS::BuildForCursor( const VECTOR2I& aCursorPos ) +{ + int gap = m_fitVias ? m_viaGap + m_viaDiameter : m_gap; + + for (int attempt = 0; attempt < 2; attempt ++) + { + for(int i = 0; i < 4; i++ ) + { + VECTOR2I dir; + + + if( !attempt ) + { + dir = VECTOR2I( gap, gap ).Resize( gap / 2 ); + + if( i % 2 == 0 ) + dir.x = -dir.x; + if( i / 2 == 0 ) + dir.y = -dir.y; + } + else + { + if( i /2 == 0) + dir = VECTOR2I( gap / 2 * ( (i % 2) ? -1 : 1), 0 ); + else + dir = VECTOR2I( 0, gap / 2 * ( (i % 2) ? -1 : 1) ); + } + + if( m_fitVias ) + BuildGeneric ( aCursorPos + dir, aCursorPos - dir, true, true ); + else + m_gateways.push_back( PNS_DP_GATEWAY( aCursorPos + dir, aCursorPos - dir, attempt ? true : false ) ); + + drawGw ( aCursorPos + dir, 2 ); + drawGw ( aCursorPos - dir, 3 ); + } + } +} + + +void PNS_DP_GATEWAYS::buildEntries ( const VECTOR2I& p0_p, const VECTOR2I& p0_n ) +{ + BOOST_FOREACH (PNS_DP_GATEWAY &g, m_gateways ) + { + if ( !g.HasEntryLines() ) + { + SHAPE_LINE_CHAIN lead_p = DIRECTION_45().BuildInitialTrace ( g.AnchorP(), p0_p, g.IsDiagonal() ).Reverse(); + SHAPE_LINE_CHAIN lead_n = DIRECTION_45().BuildInitialTrace ( g.AnchorN(), p0_n, g.IsDiagonal() ).Reverse(); + g.SetEntryLines(lead_p, lead_n); + } + } +} + + +void PNS_DP_GATEWAYS::buildDpContinuation ( PNS_DP_PRIMITIVE_PAIR aPair, bool aIsDiagonal ) +{ + PNS_DP_GATEWAY gw ( aPair.AnchorP(), aPair.AnchorN(), aIsDiagonal ); + gw.SetPriority( 100 ); + m_gateways.push_back ( gw ); + + if ( !aPair.Directional() ) + return; + + DIRECTION_45 dP = aPair.DirP(); + DIRECTION_45 dN = aPair.DirN(); + + int gap = (aPair.AnchorP() - aPair.AnchorN()).EuclideanNorm(); + + VECTOR2I vdP = aPair.AnchorP() + dP.Left().ToVector(); + VECTOR2I vdN = aPair.AnchorN() + dN.Left().ToVector(); + + PNS_SEGMENT *sP = static_cast (aPair.PrimP()); + + VECTOR2I t1, t2; + + if( sP->Seg().Side(vdP) == sP->Seg().Side(vdN )) + { + t1 = aPair.AnchorP() + dP.Left().ToVector().Resize( gap ); + t2 = aPair.AnchorN() + dP.Right().ToVector().Resize( gap ); + } + else + { + t1 = aPair.AnchorP() + dP.Right().ToVector().Resize( gap ); + t2 = aPair.AnchorN() + dP.Left().ToVector().Resize( gap ); + } + + + PNS_DP_GATEWAY gwL ( t2, aPair.AnchorN(), !aIsDiagonal ); + SHAPE_LINE_CHAIN ep = dP.BuildInitialTrace ( aPair.AnchorP(), t2, !aIsDiagonal ); + + gwL.SetPriority(10); + gwL.SetEntryLines ( ep , SHAPE_LINE_CHAIN( ) ); + + m_gateways.push_back(gwL); + + PNS_DP_GATEWAY gwR (aPair.AnchorP(), t1, !aIsDiagonal ); + SHAPE_LINE_CHAIN en = dP.BuildInitialTrace ( aPair.AnchorN(), t1, !aIsDiagonal ); + gwR.SetPriority(10); + gwR.SetEntryLines ( SHAPE_LINE_CHAIN( ), en ); + + m_gateways.push_back(gwR); +} + + +void PNS_DP_GATEWAYS::BuildGeneric( const VECTOR2I& p0_p, const VECTOR2I& p0_n, bool aBuildEntries, bool aViaMode ) +{ + SEG st_p[2], st_n[2]; + SEG d_n[2], d_p[2]; + + const int padToGapThreshold = 3; + int padDist = ( p0_p - p0_p ).EuclideanNorm( ); + + st_p[0] = SEG(p0_p + VECTOR2I(-100, 0), p0_p + VECTOR2I(100, 0) ); + st_n[0] = SEG(p0_n + VECTOR2I(-100, 0), p0_n + VECTOR2I(100, 0) ); + st_p[1] = SEG(p0_p + VECTOR2I(0, -100), p0_p + VECTOR2I(0, 100) ); + st_n[1] = SEG(p0_n + VECTOR2I(0, -100), p0_n + VECTOR2I(0, 100) ); + d_p[0] = SEG ( p0_p + VECTOR2I (-100, -100), p0_p + VECTOR2I(100, 100)); + d_p[1] = SEG ( p0_p + VECTOR2I (100, -100), p0_p + VECTOR2I(-100, 100)); + d_n[0] = SEG ( p0_n + VECTOR2I (-100, -100), p0_n + VECTOR2I(100, 100)); + d_n[1] = SEG ( p0_n + VECTOR2I (100, -100), p0_n + VECTOR2I(-100, 100)); + + // midpoint exit & side-by exits + for(int i = 0; i < 2; i++) + { + bool straightColl = st_p[i].Collinear ( st_n[i] ); + bool diagColl = d_p[i].Collinear( d_n[i] ); + + if( straightColl || diagColl ) + { + VECTOR2I dir = ( p0_n - p0_p ).Resize( m_gap / 2 ); + VECTOR2I m = ( p0_p + p0_n ) / 2; + int prio = ( padDist > padToGapThreshold * m_gap ? 2 : 1); + + if(!aViaMode) + { + m_gateways.push_back( PNS_DP_GATEWAY( m - dir, m + dir, diagColl, DIRECTION_45::ANG_RIGHT, prio ) ); + + dir = ( p0_n - p0_p ).Resize( m_gap ); + m_gateways.push_back( PNS_DP_GATEWAY( p0_p - dir, p0_p - dir + dir.Perpendicular(), diagColl ) ); + m_gateways.push_back( PNS_DP_GATEWAY( p0_p - dir, p0_p - dir - dir.Perpendicular(), diagColl ) ); + m_gateways.push_back( PNS_DP_GATEWAY( p0_n + dir + dir.Perpendicular(), p0_n + dir, diagColl ) ); + m_gateways.push_back( PNS_DP_GATEWAY( p0_n + dir - dir.Perpendicular(), p0_n + dir, diagColl ) ); + } + } + } + + + for (int i = 0; i < 2; i++) + for(int j = 0; j < 2; j++) + { + OPT_VECTOR2I ips[2], m; + + ips[0] = d_n[i].IntersectLines( d_p[j] ); + ips[1] = st_p[i].IntersectLines( st_n[j] ); + + if ( d_n[i].Collinear (d_p[j]) ) + ips [0] = OPT_VECTOR2I(); + if ( st_p[i].Collinear (st_p[j]) ) + ips [1] = OPT_VECTOR2I(); + + // diagonal-diagonal and straight-straight cases - the most typical case if the pads + // are on the same straight/diagonal line + for ( int k = 0; k < 2; k++ ) + { + m = ips [ k ]; + if(m && *m != p0_p && *m != p0_n ) + { + int prio = ( padDist > padToGapThreshold * m_gap ? 10 : 20); + VECTOR2I g_p ( ( p0_p - *m ).Resize ( ( double ) m_gap * M_SQRT1_2 ) ); + VECTOR2I g_n ( ( p0_n - *m ).Resize ( ( double ) m_gap * M_SQRT1_2 ) ); + + m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, k == 0 ? true : false, DIRECTION_45::ANG_OBTUSE, prio ) ); + } + } + + ips[0] = st_n[i].IntersectLines( d_p[j] ); + ips[1] = st_p[i].IntersectLines( d_n[j] ); + + // diagonal-straight cases: 8 possibilities of "weirder" exists + for ( int k = 0; k < 2; k++ ) + { + m = ips[k]; + + if(!aViaMode && m && *m != p0_p && *m != p0_n ) + { + VECTOR2I g_p, g_n; + + g_p = ( p0_p - *m ).Resize ((double)m_gap * M_SQRT2 ); + g_n = ( p0_n - *m ).Resize ((double)m_gap ); + + if ( angle ( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) + m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, true ) ); + + g_p = ( p0_p - *m ).Resize ( m_gap ); + g_n = ( p0_n - *m ).Resize ( (double)m_gap * M_SQRT2 ); + + if ( angle ( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) + m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, true ) ); + + } + } + } + + if (aBuildEntries) + buildEntries(p0_p, p0_n); +} + + +PNS_DP_PRIMITIVE_PAIR PNS_DIFF_PAIR::EndingPrimitives() +{ + if (m_hasVias) + return PNS_DP_PRIMITIVE_PAIR ( &m_via_p, &m_via_n ); + else + { + const PNS_LINE lP ( PLine() ); + const PNS_LINE lN ( NLine() ); + + PNS_SEGMENT sP ( lP, lP.CSegment(-1) ); + PNS_SEGMENT sN ( lN, lN.CSegment(-1) ); + + PNS_DP_PRIMITIVE_PAIR dpair ( &sP, &sN ); + dpair.SetAnchors ( sP.Seg().B, sN.Seg().B ); + return dpair; + } +} + +bool commonParallelProjection ( SEG n, SEG p, SEG &pClip, SEG& nClip ) +{ + SEG n_proj_p ( p.LineProject(n.A), p.LineProject(n.B) ); + + int64_t t_a = 0; + int64_t t_b = p.TCoef(p.B); + + int64_t tproj_a = p.TCoef(n_proj_p.A); + int64_t tproj_b = p.TCoef(n_proj_p.B); + + if(t_b < t_a) + std::swap ( t_b, t_a ); + + if(tproj_b < tproj_a) + std::swap ( tproj_b, tproj_a ); + + + if(t_b <= tproj_a) + return false; + + if(t_a >= tproj_b) + return false; + + + int64_t t[4] = { 0, p.TCoef ( p.B ), p.TCoef ( n_proj_p.A ), p.TCoef ( n_proj_p.B ) }; + std::vector tv(t, t+4); + std::sort(tv.begin(), tv.end()); // fixme: awful and disgusting way of finding 2 midpoints + + int64_t pLenSq = p.SquaredLength(); + + VECTOR2I dp = p.B - p.A; + pClip.A.x = p.A.x + rescale ( (int64_t)dp.x, tv[1], pLenSq ); + pClip.A.y = p.A.y + rescale ( (int64_t)dp.y, tv[1], pLenSq ); + + pClip.B.x = p.A.x + rescale ( (int64_t)dp.x, tv[2], pLenSq ); + pClip.B.y = p.A.y + rescale ( (int64_t)dp.y, tv[2], pLenSq ); + + nClip.A = n.LineProject(pClip.A); + nClip.B = n.LineProject(pClip.B); + + return true; + +} + +double PNS_DIFF_PAIR::Skew () const +{ + return m_p.Length() - m_n.Length(); +} + +void PNS_DIFF_PAIR::CoupledSegmentPairs ( COUPLED_SEGMENTS_VEC& aPairs ) const +{ + SHAPE_LINE_CHAIN p ( m_p ); + SHAPE_LINE_CHAIN n ( m_n ); + + p.Simplify(); + n.Simplify(); + + for(int i = 0; i < p.SegmentCount(); i++ ) + { + for (int j = 0; j < n.SegmentCount(); j++ ) + { + SEG sp = p.CSegment(i); + SEG sn = n.CSegment(j); + + SEG p_clip, n_clip; + + int64_t dist = std::abs ( sp.Distance(sn) - m_width ); + + if( sp.ApproxParallel(sn) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( sp, sn, p_clip, n_clip )) + { + const COUPLED_SEGMENTS spair ( p_clip, sp, i, n_clip, sn, j); + aPairs.push_back( spair ); + } + } + } +} + +int64_t PNS_DIFF_PAIR::CoupledLength ( const SHAPE_LINE_CHAIN& aP, const SHAPE_LINE_CHAIN& aN ) const +{ + int64_t total = 0; + + for(int i = 0; i < aP.SegmentCount(); i++ ) + { + for (int j = 0; j < aN.SegmentCount(); j++ ) + { + SEG sp = aP.CSegment(i); + SEG sn = aN.CSegment(j); + + SEG p_clip, n_clip; + + int64_t dist = std::abs ( sp.Distance(sn) - m_width ); + + if( sp.ApproxParallel(sn) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( sp, sn, p_clip, n_clip )) + total += p_clip.Length(); + } + } + return total; +} + + + +double PNS_DIFF_PAIR::CoupledLength() const +{ + COUPLED_SEGMENTS_VEC pairs; + + CoupledSegmentPairs(pairs); + + double l = 0.0; + for(unsigned int i = 0; i < pairs.size();i++) + l += pairs[i].coupledP.Length(); + + return l; +} + +double PNS_DIFF_PAIR::CoupledLengthFactor() const +{ + double t = TotalLength(); + if( t == 0.0 ) + return 0.0; + return CoupledLength() / t; +} + +double PNS_DIFF_PAIR::TotalLength() const +{ + double lenP = m_p.Length(); + double lenN = m_n.Length(); + + return (lenN + lenP ) / 2.0; +} + +int PNS_DIFF_PAIR::CoupledLength ( const SEG& aP, const SEG& aN ) const +{ + SEG p_clip, n_clip; + int64_t dist = std::abs ( aP.Distance(aN) - m_width ); + + if( aP.ApproxParallel(aN) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( aP, aN, p_clip, n_clip )) + return p_clip.Length(); + + return 0; +} + diff --git a/pcbnew/router/pns_diff_pair.h b/pcbnew/router/pns_diff_pair.h new file mode 100644 index 0000000000..d680adf166 --- /dev/null +++ b/pcbnew/router/pns_diff_pair.h @@ -0,0 +1,457 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_DIFF_PAIR_H +#define __PNS_DIFF_PAIR_H + +#include + +#include +#include + +#include "pns_line.h" +#include "pns_via.h" + +#include "ranged_num.h" + +class PNS_DIFF_PAIR; + +/** + * Class PNS_DP_GATEWAY + * + * Defines a "gateway" for routing a differential pair - e.g. a pair of points (anchors) with certain + * orientation, spacing and (optionally) predefined entry paths. The routing algorithm connects such + * gateways with parallel lines, thus creating a difrerential pair. + **/ +class PNS_DP_GATEWAY { +public: + PNS_DP_GATEWAY ( const VECTOR2I& aAnchorP, + const VECTOR2I& aAnchorN, + bool aIsDiagonal, + int aAllowedEntryAngles = DIRECTION_45::ANG_OBTUSE, + int aPriority = 0 ) + : m_anchorP(aAnchorP), + m_anchorN (aAnchorN), + m_isDiagonal( aIsDiagonal ), + m_allowedEntryAngles (aAllowedEntryAngles), + m_priority(aPriority) + { + m_hasEntryLines = false; + } + + ~PNS_DP_GATEWAY () + { + + } + + /** + * Function IsDiagonal() + * + * @return true, if the gateway anchors lie on a diagonal line + */ + + bool IsDiagonal() const + { + return m_isDiagonal; + } + + const VECTOR2I& AnchorP () const { return m_anchorP; } + const VECTOR2I& AnchorN () const { return m_anchorN; } + + /** + * Function AllowedAngles() + * + * @return a mask of 45-degree entry directoins allowed for the + * gateway. + */ + int AllowedAngles () const { return m_allowedEntryAngles; } + + /** + * Function Priority() + * + * @return priority/score value for gateway matching + */ + int Priority() const + { + return m_priority; + } + + void SetPriority(int aPriority) + { + m_priority = aPriority; + } + + void SetEntryLines ( const SHAPE_LINE_CHAIN& aEntryP, const SHAPE_LINE_CHAIN& aEntryN ) + { + m_entryP = aEntryP; + m_entryN = aEntryN; + m_hasEntryLines = true; + } + + const SHAPE_LINE_CHAIN& EntryP () const { return m_entryP; } + const SHAPE_LINE_CHAIN& EntryN () const { return m_entryN; } + const PNS_DIFF_PAIR Entry() const ; + + void Reverse(); + + bool HasEntryLines () const + { + return m_hasEntryLines; + } + +private: + + SHAPE_LINE_CHAIN m_entryP, m_entryN; + bool m_hasEntryLines; + VECTOR2I m_anchorP, m_anchorN; + bool m_isDiagonal; + int m_allowedEntryAngles; + int m_priority; +}; + +/** + * Class PNS_DP_PRIMITIVE_PAIR + * + * Stores staring/ending primitives (pads, vias or segments) for a differential pair. + **/ +class PNS_DP_PRIMITIVE_PAIR +{ + +public: + PNS_DP_PRIMITIVE_PAIR(): + m_primP (NULL), m_primN ( NULL ) {}; + + PNS_DP_PRIMITIVE_PAIR ( const PNS_DP_PRIMITIVE_PAIR& aOther ); + PNS_DP_PRIMITIVE_PAIR ( PNS_ITEM *aPrimP, PNS_ITEM *aPrimN ); + PNS_DP_PRIMITIVE_PAIR ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); + + ~PNS_DP_PRIMITIVE_PAIR(); + + void SetAnchors ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); + + const VECTOR2I& AnchorP () const { return m_anchorP; } + const VECTOR2I& AnchorN () const { return m_anchorN; } + + PNS_DP_PRIMITIVE_PAIR& operator= ( const PNS_DP_PRIMITIVE_PAIR& aOther ); + + PNS_ITEM* PrimP () const { return m_primP; } + PNS_ITEM* PrimN () const { return m_primN; } + + bool Directional() const; + + DIRECTION_45 DirP () const; + DIRECTION_45 DirN () const; + +private: + + DIRECTION_45 anchorDirection ( PNS_ITEM *aItem, const VECTOR2I& aP) const; + + PNS_ITEM *m_primP, *m_primN; + VECTOR2I m_anchorP, m_anchorN; +}; + +/** + * Class PNS_GATEWAYS + * + * A set of gateways calculated for the cursor or starting/ending primitive pair. + **/ + +class PNS_DP_GATEWAYS +{ + + public: + PNS_DP_GATEWAYS ( int aGap ): + m_gap(aGap), m_viaGap( aGap ) {}; + + void SetGap ( int aGap ) { + m_gap = aGap; + m_viaGap = aGap; + } + + void Clear() + { + m_gateways.clear(); + } + + void SetFitVias ( bool aEnable, int aDiameter = 0, int aViaGap = -1 ) + { + m_fitVias = aEnable; + m_viaDiameter = aDiameter; + if(aViaGap < 0) + m_viaGap = m_gap; + else + m_viaGap = aViaGap; + } + + + void BuildForCursor ( const VECTOR2I& aCursorPos ); + void BuildOrthoProjections ( PNS_DP_GATEWAYS &aEntries, const VECTOR2I& aCursorPos, int aOrthoScore ); + void BuildGeneric ( const VECTOR2I& p0_p, const VECTOR2I& p0_n, bool aBuildEntries = false, bool aViaMode = false ); + void BuildFromPrimitivePair( PNS_DP_PRIMITIVE_PAIR aPair, bool aPreferDiagonal ); + + bool FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ); + + std::vector& Gateways() + { + return m_gateways; + } + + private: + + struct DP_CANDIDATE + { + SHAPE_LINE_CHAIN p, n; + VECTOR2I gw_p, gw_n; + int score; + }; + + bool checkDiagonalAlignment ( const VECTOR2I& a, const VECTOR2I& b) const; + void buildDpContinuation ( PNS_DP_PRIMITIVE_PAIR aPair, bool aIsDiagonal ); + void buildEntries ( const VECTOR2I& p0_p, const VECTOR2I& p0_n ); + + int m_gap; + int m_viaGap; + int m_viaDiameter; + bool m_fitVias; + + std::vector m_gateways; +}; + + +/** + * Class PNS_DIFF_PAIR + * + * Basic class for a differential pair. Stores two PNS_LINEs (for positive and negative nets, respectively), + * the gap and coupling constraints. + **/ +class PNS_DIFF_PAIR : public PNS_ITEM { + +public: + struct COUPLED_SEGMENTS { + COUPLED_SEGMENTS ( const SEG& aCoupledP, const SEG& aParentP, int aIndexP, + const SEG& aCoupledN, const SEG& aParentN, int aIndexN ) : + coupledP ( aCoupledP ), + coupledN ( aCoupledN ), + parentP ( aParentP ), + parentN ( aParentN ), + indexP ( aIndexP ), + indexN ( aIndexN ) + {} + + SEG coupledP; + SEG coupledN; + SEG parentP; + SEG parentN; + int indexP; + int indexN; + }; + + typedef std::vector COUPLED_SEGMENTS_VEC; + + PNS_DIFF_PAIR ( ) : PNS_ITEM ( DIFF_PAIR ), m_hasVias (false) {} + + PNS_DIFF_PAIR ( int aGap ) : + PNS_ITEM ( DIFF_PAIR ), + m_hasVias (false) + { + m_gapConstraint = aGap; + } + + PNS_DIFF_PAIR ( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, int aGap = 0 ): + PNS_ITEM ( DIFF_PAIR ), + m_n (aN), + m_p (aP), + m_hasVias (false) + { + m_gapConstraint = aGap; + } + + PNS_DIFF_PAIR ( const PNS_LINE &aLineP, const PNS_LINE &aLineN, int aGap = 0 ): + PNS_ITEM ( DIFF_PAIR ), + m_line_p ( aLineP ), + m_line_n ( aLineN ), + m_hasVias (false) + { + m_gapConstraint = aGap; + m_net_p = aLineP.Net(); + m_net_n = aLineN.Net(); + m_p = aLineP.CLine(); + m_n = aLineN.CLine(); + } + + static inline bool ClassOf( const PNS_ITEM* aItem ) + { + return aItem && DIFF_PAIR == aItem->Kind(); + } + + PNS_DIFF_PAIR * Clone() const { assert(false); return NULL; } + + static PNS_DIFF_PAIR* AssembleDp ( PNS_LINE *aLine ); + + void SetShape ( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, bool aSwapLanes = false) + { + if (aSwapLanes) + { + m_p = aN; + m_n = aP; + } else { + m_p = aP; + m_n = aN; + } + } + + void SetShape ( const PNS_DIFF_PAIR& aPair ) + { + m_p = aPair.m_p; + m_n = aPair.m_n; + } + + void SetNets ( int aP, int aN ) + { + m_net_p = aP; + m_net_n = aN; + } + + void SetWidth ( int aWidth ) + { + m_width = aWidth; + } + + int Width() const { return m_width; } + + void SetGap ( int aGap) + { + m_gap = aGap; + m_gapConstraint = RANGED_NUM ( m_gap, 10000, 10000 ); + } + + int Gap() const { + return m_gap; + } + + void AppendVias ( const PNS_VIA &aViaP, const PNS_VIA& aViaN ) + { + m_hasVias = true; + m_via_p = aViaP; + m_via_n = aViaN; + } + + void RemoveVias () + { + m_hasVias = false; + } + + bool EndsWithVias() const + { + return m_hasVias; + } + + int NetP() const + { + return m_net_p; + } + + int NetN() const + { + return m_net_n; + } + + PNS_LINE& PLine() + { + if ( !m_line_p.IsLinked ( ) ) + updateLine(m_line_p, m_p, m_net_p, m_via_p ); + return m_line_p; + } + + PNS_LINE& NLine() + { + if ( !m_line_n.IsLinked ( ) ) + updateLine(m_line_n, m_n, m_net_n, m_via_n ); + return m_line_n; + } + + PNS_DP_PRIMITIVE_PAIR EndingPrimitives(); + + double CoupledLength() const; + double TotalLength() const; + double CoupledLengthFactor () const; + double Skew () const; + + void CoupledSegmentPairs ( COUPLED_SEGMENTS_VEC& aPairs ) const; + + void Clear() + { + m_n.Clear(); + m_p.Clear(); + } + + void Append (const PNS_DIFF_PAIR& aOther ) + { + m_n.Append ( aOther.m_n ); + m_p.Append ( aOther.m_p ); + } + + bool Empty() const + { + return (m_n.SegmentCount() == 0) || (m_p.SegmentCount() == 0); + } + const SHAPE_LINE_CHAIN& CP() const { return m_p; } + const SHAPE_LINE_CHAIN& CN() const { return m_n; } + + bool BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY& aTarget, bool aPrefDiagonal ); + bool CheckConnectionAngle ( const PNS_DIFF_PAIR &aOther, int allowedAngles ) const; + int CoupledLength ( const SEG& aP, const SEG& aN ) const; + + int64_t CoupledLength ( const SHAPE_LINE_CHAIN& aP, const SHAPE_LINE_CHAIN& aN ) const; + + const RANGED_NUM GapConstraint() const { + return m_gapConstraint; + } + +private: + + void updateLine( PNS_LINE &aLine, const SHAPE_LINE_CHAIN& aShape, int aNet, PNS_VIA& aVia ) + { + aLine.SetShape( aShape ); + aLine.SetWidth( m_width ); + aLine.SetNet(aNet); + aLine.SetLayer (Layers().Start()); + + if(m_hasVias) + aLine.AppendVia ( aVia ); + } + + SHAPE_LINE_CHAIN m_n, m_p; + PNS_LINE m_line_p, m_line_n; + PNS_VIA m_via_p, m_via_n; + + bool m_hasVias; + int m_net_p, m_net_n; + int m_width; + int m_gap; + int m_viaGap; + int m_maxUncoupledLength; + int m_chamferLimit; + RANGED_NUM m_gapConstraint; +}; + + +#endif diff --git a/pcbnew/router/pns_diff_pair_placer.cpp b/pcbnew/router/pns_diff_pair_placer.cpp new file mode 100644 index 0000000000..ff1d7f3f49 --- /dev/null +++ b/pcbnew/router/pns_diff_pair_placer.cpp @@ -0,0 +1,778 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 + +#include +#include +#include +#include + +#include "trace.h" + +#include "pns_node.h" +#include "pns_walkaround.h" +#include "pns_shove.h" +#include "pns_utils.h" +#include "pns_router.h" +#include "pns_diff_pair_placer.h" +#include "pns_solid.h" +#include "pns_topology.h" + +using boost::optional; + +PNS_DIFF_PAIR_PLACER::PNS_DIFF_PAIR_PLACER( PNS_ROUTER* aRouter ) : + PNS_PLACEMENT_ALGO ( aRouter ) +{ + m_initialDiagonal = false; + m_startDiagonal = false; + m_world = NULL; + m_shove = NULL; + m_currentNode = NULL; + m_idle = true; +} + +PNS_DIFF_PAIR_PLACER::~PNS_DIFF_PAIR_PLACER() +{ + if( m_shove ) + delete m_shove; +} + + +void PNS_DIFF_PAIR_PLACER::setWorld ( PNS_NODE* aWorld ) +{ + m_world = aWorld; +} + +const PNS_VIA PNS_DIFF_PAIR_PLACER::makeVia ( const VECTOR2I& aP, int aNet ) +{ + const PNS_LAYERSET layers( m_sizes.GetLayerTop(), m_sizes.GetLayerBottom() ); + + PNS_VIA v( aP, layers, m_sizes.ViaDiameter(), m_sizes.ViaDrill(), -1, m_sizes.ViaType() ); + v.SetNet (aNet); + return v; +} + +void PNS_DIFF_PAIR_PLACER::SetOrthoMode ( bool aOrthoMode ) +{ + m_orthoMode = aOrthoMode; + if(!m_idle) + Move ( m_currentEnd, NULL ); +} + +bool PNS_DIFF_PAIR_PLACER::ToggleVia( bool aEnabled ) +{ + m_placingVia = aEnabled; + if(!m_idle) + Move ( m_currentEnd, NULL ); + + return true; +} + +bool PNS_DIFF_PAIR_PLACER::rhMarkObstacles( const VECTOR2I& aP ) +{ + if( !routeHead ( aP ) ) + return false; + + bool collP = m_currentNode->CheckColliding( &m_currentTrace.PLine() ); + bool collN = m_currentNode->CheckColliding( &m_currentTrace.NLine() ); + + m_fitOk = !(collP || collN); + return m_fitOk; +} + +bool PNS_DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP ) +{ + PNS_VIA virtHead = makeVia ( aP, -1 ); + + if ( m_placingVia ) + virtHead.SetDiameter ( viaGap() + 2 * virtHead.Diameter() ); + else + { + virtHead.SetLayer ( m_currentLayer ); + virtHead.SetDiameter ( m_sizes.DiffPairGap() + 2 * m_sizes.TrackWidth() ); + } + + VECTOR2I lead(0, 0);// = aP - m_currentStart ; + VECTOR2I force; + bool solidsOnly = true; + + + if(m_currentMode == RM_MarkObstacles ) + { + aNewP = aP; + return true; + } else if (m_currentMode == RM_Walkaround ) + { + solidsOnly = false; + } + + // fixme: I'm too lazy to do it well. Circular approximaton will do for the moment. + if( virtHead.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) ) + { + aNewP = aP + force; + return true; + } + + return false; +} + + +bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE *aNode, PNS_DIFF_PAIR *aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ) +{ + PNS_WALKAROUND walkaround( aNode, Router() ); + PNS_WALKAROUND::WALKAROUND_STATUS wf1; + + Router()->GetClearanceFunc()->OverrideClearance ( true, aCurrent->NetP(), aCurrent->NetN(), aCurrent->Gap() - 20 ); + + walkaround.SetSolidsOnly( aSolidsOnly ); + walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); + + PNS_SHOVE shove(aNode, Router()); + PNS_LINE walkP, walkN; + + aWalk = *aCurrent; + + int iter = 0; + + PNS_DIFF_PAIR cur (*aCurrent); + + bool currentIsP = aPFirst; + + int mask = aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY; + + //Router()->DisplayDebugLine( aCurrent->CP(), 4, 10000 ); + //Router()->DisplayDebugLine( aCurrent->CN(), 5, 10000 ); + + do { + PNS_LINE preWalk = (currentIsP ? cur.PLine() : cur.NLine() ); + PNS_LINE preShove = (currentIsP ? cur.NLine() : cur.PLine() ); + PNS_LINE postWalk; + + if (!aNode->CheckColliding ( &preWalk, mask ) ) + { + + currentIsP = !currentIsP; + + if (!aNode->CheckColliding ( &preShove, mask ) ) + break; + else + continue; + } + + wf1 = walkaround.Route( preWalk, postWalk, false ); + + if(wf1 != PNS_WALKAROUND::DONE) + return false; + + PNS_LINE postShove ( preShove ); + + shove.ForceClearance(true, cur.Gap() - 12); + + PNS_SHOVE::SHOVE_STATUS sh1; + + sh1 = shove.ProcessSingleLine( &postWalk, &preShove, &postShove ); + + if(sh1 != PNS_SHOVE::SH_OK) + return false; + + postWalk.Line().Simplify(); + postShove.Line().Simplify(); + + + cur.SetShape ( postWalk.CLine(), postShove.CLine(), !currentIsP ); + + currentIsP = !currentIsP; + + if (!aNode->CheckColliding ( &postShove, mask ) ) + break; + + + iter++; + } while (iter < 3); + + if(iter == 3) + return false; + + + + aWalk.SetShape(cur.CP(), cur.CN() ); + Router()->GetClearanceFunc()->OverrideClearance ( false ); + + return true; +} + +bool PNS_DIFF_PAIR_PLACER::tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bool aSolidsOnly ) +{ + PNS_DIFF_PAIR best; + double bestScore = 100000000000000.0; + + for(int attempt = 0; attempt <= 1; attempt ++) + { + PNS_DIFF_PAIR p; + PNS_NODE *tmp = m_currentNode->Branch(); + + bool pfirst = attempt % 2 ? true : false; + bool wind_cw = attempt / 2 ? true : false; + + if ( attemptWalk ( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) ) + { + // double len = p.TotalLength(); + double cl = p.CoupledLength(); + double skew = p.Skew(); + + double score = cl + fabs(skew) * 3.0; + + if(score < bestScore) + { + bestScore = score; + best = p; + } + } + + delete tmp; + } + + if(bestScore > 0.0) + { + PNS_OPTIMIZER optimizer( m_currentNode ); + + aPair.SetShape ( best ); + + optimizer.Optimize ( &aPair ); + return true; + } + + return false; +} + +bool PNS_DIFF_PAIR_PLACER::rhWalkOnly( const VECTOR2I& aP ) +{ + if ( !routeHead ( aP ) ) + return false; + + m_fitOk = tryWalkDp ( m_currentNode, m_currentTrace, false ); + + return m_fitOk; +} + + +bool PNS_DIFF_PAIR_PLACER::route ( const VECTOR2I& aP ) +{ + switch( m_currentMode ) + { + case RM_MarkObstacles: + return rhMarkObstacles( aP ); + case RM_Walkaround: + return rhWalkOnly ( aP ); + case RM_Shove: + return rhShoveOnly ( aP ); + default: + break; + } + + return false; +} + +bool PNS_DIFF_PAIR_PLACER::rhShoveOnly ( const VECTOR2I& aP ) +{ + m_currentNode = m_shove->CurrentNode(); + + bool ok = routeHead ( aP ); + + m_fitOk = false; + + if(!ok) + return false; + + if (!tryWalkDp ( m_currentNode, m_currentTrace, true ) ) + return false; + + PNS_LINE pLine ( m_currentTrace.PLine() ); + PNS_LINE nLine ( m_currentTrace.NLine() ); + PNS_ITEMSET head; + + head.Add ( &pLine ); + head.Add ( &nLine ); + + PNS_SHOVE::SHOVE_STATUS status = m_shove->ShoveMultiLines( head ); + + m_currentNode = m_shove->CurrentNode(); + + if( status == PNS_SHOVE::SH_OK ) + { + m_currentNode = m_shove->CurrentNode(); + + if( !m_currentNode->CheckColliding ( &m_currentTrace.PLine() ) && + !m_currentNode->CheckColliding ( &m_currentTrace.NLine() ) ) + { + m_fitOk = true; + } + } + + return m_fitOk; +} + + + +const PNS_ITEMSET PNS_DIFF_PAIR_PLACER::Traces() +{ + PNS_ITEMSET t; + + t.Add( const_cast ( &m_currentTrace.PLine( ) ) ); + t.Add( const_cast ( &m_currentTrace.NLine( ) ) ); + + return t; +} + + +void PNS_DIFF_PAIR_PLACER::FlipPosture() +{ + m_startDiagonal = !m_startDiagonal; + + if(!m_idle) + Move ( m_currentEnd, NULL ); +} + + +PNS_NODE* PNS_DIFF_PAIR_PLACER::CurrentNode( bool aLoopsRemoved ) const +{ + if( m_lastNode ) + return m_lastNode; + + return m_currentNode; +} + + +bool PNS_DIFF_PAIR_PLACER::SetLayer( int aLayer ) +{ + if( m_idle ) + { + m_currentLayer = aLayer; + return true; + } else if( m_chainedPlacement ) + return false; + else if( !m_prevPair ) + return false; + else if( m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( PNS_ITEM::VIA ) && m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) ) { + m_currentLayer = aLayer; + m_start = *m_prevPair; + initPlacement ( false ); + Move ( m_currentEnd, NULL ); + return true; + } + + return false; +} + +int PNS_DIFF_PAIR_PLACER::matchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) +{ + int rv = 0; + if (aNetName.EndsWith("+")) + { + aComplementNet = "-"; + rv = 1; + } else if (aNetName.EndsWith("_P")) + { + aComplementNet = "_N"; + rv = 1; + } else if (aNetName.EndsWith("-")) + { + aComplementNet = "+"; + rv = -1; + } else if (aNetName.EndsWith("_N")) + { + aComplementNet = "_P"; + rv = -1; + } + + if (rv != 0) { + aBaseDpName = aNetName.Left ( aNetName.Length() - aComplementNet.Length() ); + } + + return rv; +} + +OPT_VECTOR2I PNS_DIFF_PAIR_PLACER::getDanglingAnchor ( PNS_NODE *aNode, PNS_ITEM *aItem ) +{ + switch(aItem->Kind()) + { + case PNS_ITEM::VIA: + case PNS_ITEM::SOLID: + return aItem->Anchor(0); + + case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT *s =static_cast ( aItem ); + + PNS_JOINT *jA = aNode->FindJoint( s->Seg().A, s ); + PNS_JOINT *jB = aNode->FindJoint( s->Seg().B, s ); + + if(jA->LinkCount() == 1) + return s->Seg().A; + else if (jB->LinkCount() == 1) + return s->Seg().B; + else + return OPT_VECTOR2I(); + } + default: + return OPT_VECTOR2I(); + break; + } +} + +bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair ( const VECTOR2I& aP, PNS_ITEM *aItem, PNS_DP_PRIMITIVE_PAIR& aPair ) +{ + + if(!aItem || !aItem->Parent() || !aItem->Parent()->GetNet() ) + return false; + + wxString netNameP = aItem->Parent()->GetNet()->GetNetname(); + wxString netNameN, netNameBase; + + + BOARD *brd = Router()->GetBoard(); + PNS_ITEM *primRef = NULL, *primP = NULL, *primN = NULL; + + // printf("Current %p\n", m_currentNode); + int refNet; + + wxString suffix; + + int r = matchDpSuffix ( netNameP, suffix, netNameBase ); + + if(r == 0) + return false; + else if(r == 1) + { + primRef = primP = static_cast (aItem); + netNameN = netNameBase + suffix; + } else { + primRef = primN = static_cast (aItem); + netNameN = netNameP; + netNameP = netNameBase + suffix; + } + + int netP = brd->FindNet ( netNameP )->GetNet(); + int netN = brd->FindNet ( netNameN )->GetNet(); + + if ( primP ) + refNet = netN; + else + refNet = netP; + +// printf("Net: P: %s N: %s\n", (const char *)(netNameP.c_str()), (const char *)(netNameN.c_str())); + + std::set items; + + OPT_VECTOR2I refAnchor = getDanglingAnchor ( m_currentNode, primRef ); + + if(!refAnchor) + return false; + + m_currentNode->AllItemsInNet( refNet, items ); + double bestDist = std::numeric_limits::max(); + bool found = false; + + BOOST_FOREACH (PNS_ITEM *item, items) + { + if ( item->Kind() == aItem->Kind() ) + { + OPT_VECTOR2I anchor = getDanglingAnchor ( m_currentNode, item ); + if(!anchor) + continue; + + double dist = (*anchor - *refAnchor).EuclideanNorm(); + + if (dist < bestDist) + { + found = true; + bestDist = dist; + + if (refNet == netP) + { + aPair = PNS_DP_PRIMITIVE_PAIR ( item, primRef ); + aPair.SetAnchors ( *anchor, *refAnchor ); + } else { + aPair = PNS_DP_PRIMITIVE_PAIR ( primRef, item ); + aPair.SetAnchors ( *refAnchor, *anchor ); + } + } + } + } + + return found; +} + + +int PNS_DIFF_PAIR_PLACER::viaGap() const +{ + return m_sizes.DiffPairViaGap(); +} + +int PNS_DIFF_PAIR_PLACER::gap() const +{ + return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth(); +} + +bool PNS_DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + VECTOR2I p( aP ); + + bool split; + + if( Router()->SnappingEnabled() ) + p = Router()->SnapToItem( aStartItem, aP, split ); + + if(!aStartItem) + { + Router()->SetFailureReason( _( "Can't start a differential pair " + " in the middle of nowhere." ) ); + return false; + } + + PNS_DP_PRIMITIVE_PAIR start; + + m_currentNode = Router()->GetWorld(); + + if (!findDpPrimitivePair(aP, aStartItem, m_start ) ) + { + Router()->SetFailureReason( _( "Unable to find complementary differential pair " + "net. Make sure the names of the nets belonging " + "to a differential pair end with either _N/_P or +/-." ) ); + return false; + } + + m_netP = m_start.PrimP()->Net(); + m_netN = m_start.PrimN()->Net(); + + m_currentStart = p; + m_currentEnd = p; + m_placingVia = false; + m_chainedPlacement = false; + + initPlacement( false ); + return true; +} + +void PNS_DIFF_PAIR_PLACER::initPlacement( bool aSplitSeg ) +{ + m_idle = false; + m_orthoMode = false; + m_currentEndItem = NULL; + m_startDiagonal = m_initialDiagonal; + + PNS_NODE* world = Router()->GetWorld(); + + world->KillChildren(); + PNS_NODE* rootNode = world->Branch(); + + setWorld( rootNode ); + + TRACE( 1, "world %p, intitial-direction %s layer %d\n", + m_world % m_direction.Format().c_str() % aLayer ); + + m_lastNode = NULL; + m_currentNode = rootNode; + 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_currentNode, Router() ); + } +} + +bool PNS_DIFF_PAIR_PLACER::routeHead( const VECTOR2I& aP ) +{ + m_fitOk = false; + + PNS_DP_GATEWAYS gwsEntry ( gap() ); + PNS_DP_GATEWAYS gwsTarget ( gap() ); + + + if(!m_prevPair) + m_prevPair = m_start; + + gwsEntry.BuildFromPrimitivePair ( *m_prevPair, m_startDiagonal ); + + PNS_DP_PRIMITIVE_PAIR target; + + if (findDpPrimitivePair ( aP, m_currentEndItem, target )) + { + gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal ); + m_snapOnTarget = true; + } else { + VECTOR2I fp; + + if( !propagateDpHeadForces ( aP, fp ) ) + return false; + + gwsTarget.SetFitVias ( m_placingVia, m_sizes.ViaDiameter(), viaGap() ); + gwsTarget.BuildForCursor ( fp ); + gwsTarget.BuildOrthoProjections ( gwsEntry, fp, m_orthoMode ? 200 : -200 ); + m_snapOnTarget = false; + } + + m_currentTrace = PNS_DIFF_PAIR(); + m_currentTrace.SetGap ( gap() ); + m_currentTrace.SetLayer( m_currentLayer ); + + + if ( gwsEntry.FitGateways(gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace ) ) + { + m_currentTrace.SetNets ( m_netP, m_netN ); + m_currentTrace.SetWidth ( m_sizes.DiffPairWidth() ); + m_currentTrace.SetGap ( m_sizes.DiffPairGap() ); + + if(m_placingVia) + { + m_currentTrace.AppendVias ( makeVia ( m_currentTrace.CP().CPoint(-1), m_netP ), + makeVia ( m_currentTrace.CN().CPoint(-1), m_netN ) ); + } + return true; + } + + return false; + +} + +bool PNS_DIFF_PAIR_PLACER::Move(const VECTOR2I& aP , PNS_ITEM* aEndItem ) +{ + m_currentEndItem = aEndItem; + m_fitOk = false; + + delete m_lastNode; + m_lastNode = NULL; + + if ( !route( aP ) ) + return false; + + PNS_NODE* latestNode = m_currentNode; + m_lastNode = latestNode->Branch(); + + assert (m_lastNode != NULL); + m_currentEnd = aP; + + updateLeadingRatLine(); + + return true; +} + +void PNS_DIFF_PAIR_PLACER::UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ) +{ + m_sizes = aSizes; + if( !m_idle ) + { + initPlacement ( ); + Move ( m_currentEnd, NULL ); + } +} + +bool PNS_DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + if (!m_fitOk) + return false; + + if (m_currentTrace.CP().SegmentCount() < 1 || + m_currentTrace.CN().SegmentCount() < 1 ) + return false; + + if( m_currentTrace.CP().SegmentCount() > 1) + m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment(-2) ).IsDiagonal(); + + PNS_TOPOLOGY topo ( m_lastNode ); + + if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() ) + { + SHAPE_LINE_CHAIN newP ( m_currentTrace.CP() ); + SHAPE_LINE_CHAIN newN ( m_currentTrace.CN() ); + + if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1) + { + newP.Remove(-1, -1); + newN.Remove(-1, -1); + } + + m_currentTrace.SetShape ( newP, newN ); + } + + if( m_currentTrace.EndsWithVias() ) + { + m_lastNode->Add( m_currentTrace.PLine().Via().Clone() ); + m_lastNode->Add( m_currentTrace.NLine().Via().Clone() ); + m_chainedPlacement = false; + } else + m_chainedPlacement = !m_snapOnTarget; + + PNS_LINE lineP ( m_currentTrace.PLine() ); + PNS_LINE lineN ( m_currentTrace.NLine() ); + + m_lastNode->Add ( &lineP ); + m_lastNode->Add ( &lineN ); + + topo.SimplifyLine( &lineP ); + topo.SimplifyLine( &lineN ); + + m_prevPair = m_currentTrace.EndingPrimitives(); + + Router()->CommitRouting( m_lastNode ); + + m_lastNode = NULL; + m_placingVia = false; + + if(m_snapOnTarget) + { + m_idle = true; + return true; + } else { + initPlacement(); + return false; + } +} + + +void PNS_DIFF_PAIR_PLACER::GetModifiedNets( std::vector &aNets ) const +{ + aNets.push_back( m_netP ); + aNets.push_back( m_netN ); +} + +void PNS_DIFF_PAIR_PLACER::updateLeadingRatLine() +{ + SHAPE_LINE_CHAIN ratLineN, ratLineP; + PNS_TOPOLOGY topo ( m_lastNode ); + + if( topo.LeadingRatLine ( &m_currentTrace.PLine(), ratLineP )) + { + Router()->DisplayDebugLine( ratLineP, 1, 10000 ); + } + + if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN )) + { + Router()->DisplayDebugLine( ratLineN, 3, 10000 ); + } + +} diff --git a/pcbnew/router/pns_diff_pair_placer.h b/pcbnew/router/pns_diff_pair_placer.h new file mode 100644 index 0000000000..87b8001484 --- /dev/null +++ b/pcbnew/router/pns_diff_pair_placer.h @@ -0,0 +1,303 @@ +/* + * 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_DIFF_PLACER_H +#define __PNS_DIFF_PLACER_H + +#include + +#include +#include + +#include "pns_sizes_settings.h" +#include "pns_node.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_algo_base.h" +#include "pns_diff_pair.h" + +#include "pns_placement_algo.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; +class PNS_VIA; +class PNS_SIZES_SETTINGS; + + +/** + * Class PNS_LINE_PLACER + * + * Single track placement algorithm. Interactively routes a track. + * Applies shove and walkaround algorithms when needed. + */ + +class PNS_DIFF_PAIR_PLACER : public PNS_PLACEMENT_ALGO +{ +public: + PNS_DIFF_PAIR_PLACER( PNS_ROUTER* aRouter ); + ~PNS_DIFF_PAIR_PLACER(); + + /** + * Function Start() + * + * Starts routing a single track at point aP, taking item aStartItem as anchor + * (unless NULL). + */ + bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + + /** + * Function Move() + * + * Moves the end of the currently routed trace to the point aP, taking + * aEndItem as anchor (if not NULL). + * (unless NULL). + */ + bool 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 ToggleVia() + * + * Enables/disables a via at the end of currently routed trace. + */ + bool ToggleVia( bool aEnabled ); + + /** + * Function SetLayer() + * + * Sets the current routing layer. + */ + bool SetLayer( int aLayer ); + + /** + * 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_SIZES_SETTINGS& aSizes ); + + bool IsPlacingVia() const { return m_placingVia; } + + void SetOrthoMode ( bool aOrthoMode ); + + void GetModifiedNets( std::vector &aNets ) const; +private: + + int viaGap() const; + int gap() const; + + /** + * 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 + * if the trace was stuck somewhere on the way. May call routeStep() + * repetitively due to mouse smoothing. + * @param aP ending point of current route. + * @return true, if the routing is complete. + */ + bool route( const VECTOR2I& aP ); + + /** + * 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 initPlacement( bool aSplitSeg = false ); + + /** + * 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 ); + + + bool routeHead( const VECTOR2I& aP ); + bool tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bool aSolidsOnly ); + + ///> route step, walkaround mode + bool rhWalkOnly( const VECTOR2I& aP ); + + ///> route step, shove mode + bool rhShoveOnly ( const VECTOR2I& aP ); + + ///> route step, mark obstacles mode + bool rhMarkObstacles( const VECTOR2I& aP ); + + const PNS_VIA makeVia ( const VECTOR2I& aP, int aNet ); + + bool findDpPrimitivePair ( const VECTOR2I& aP, PNS_ITEM *aItem, PNS_DP_PRIMITIVE_PAIR& aPair ); + OPT_VECTOR2I getDanglingAnchor ( PNS_NODE *aNode, PNS_ITEM *aItem ); + int matchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); + bool attemptWalk ( PNS_NODE *aNode, PNS_DIFF_PAIR *aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ); + bool propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP ); + + enum State { + RT_START = 0, + RT_ROUTE = 1, + RT_FINISH = 2 + }; + + State m_state; + + bool m_chainedPlacement; + bool m_initialDiagonal; + bool m_startDiagonal; + bool m_fitOk; + + int m_netP, m_netN; + + PNS_DP_PRIMITIVE_PAIR m_start; + boost::optional m_prevPair; + + + ///> current algorithm iteration + int m_iteration; + + ///> pointer to world to search colliding items + PNS_NODE* m_world; + + ///> current routing start point (end of tail, beginning of head) + VECTOR2I m_p_start; + + ///> The shove engine + PNS_SHOVE* m_shove; + + ///> Current world state + PNS_NODE* m_currentNode; + + ///> Postprocessed world state (including marked collisions & removed loops) + PNS_NODE* m_lastNode; + + PNS_SIZES_SETTINGS m_sizes; + + ///> Are we placing a via? + bool m_placingVia; + + ///> current via diameter + int m_viaDiameter; + + ///> current via drill + int m_viaDrill; + + ///> current track width + int m_currentWidth; + + int m_currentNet; + int m_currentLayer; + + bool m_startsOnVia; + bool m_orthoMode; + bool m_snapOnTarget; + + VECTOR2I m_currentEnd, m_currentStart; + PNS_DIFF_PAIR m_currentTrace; + + PNS_ITEM *m_currentEndItem; + PNS_MODE m_currentMode; + + bool m_idle; +}; + +#endif // __PNS_LINE_PLACER_H diff --git a/pcbnew/router/pns_dp_meander_placer.cpp b/pcbnew/router/pns_dp_meander_placer.cpp new file mode 100644 index 0000000000..8f36dde975 --- /dev/null +++ b/pcbnew/router/pns_dp_meander_placer.cpp @@ -0,0 +1,459 @@ +/* + * 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 + +#include // God forgive me doing this... +#include + +#include "trace.h" + +#include "pns_node.h" +#include "pns_itemset.h" +#include "pns_topology.h" +#include "pns_dp_meander_placer.h" +#include "pns_diff_pair.h" +#include "pns_router.h" +#include "pns_utils.h" + + +using boost::optional; + + + +PNS_DP_MEANDER_PLACER::PNS_DP_MEANDER_PLACER( PNS_ROUTER* aRouter ) : + PNS_MEANDER_PLACER_BASE ( aRouter ) +{ + m_world = NULL; + m_currentNode = NULL; +} + + +PNS_DP_MEANDER_PLACER::~PNS_DP_MEANDER_PLACER() +{ + +} + +const PNS_LINE PNS_DP_MEANDER_PLACER::Trace() const +{ + return m_currentTraceP; +} + +PNS_NODE* PNS_DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const +{ + if(!m_currentNode) + return m_world; + return m_currentNode; +} + +bool PNS_DP_MEANDER_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + VECTOR2I p; + if(!aStartItem || !aStartItem->OfKind ( PNS_ITEM::SEGMENT )) + { + Router()->SetFailureReason( _("Please select a track whose length you want to tune.") ); + return false; + } + + m_initialSegment = static_cast(aStartItem); + + p = m_initialSegment->Seg().NearestPoint( aP ); + + m_currentNode=NULL; + m_currentStart = p; + + m_world = Router()->GetWorld()->Branch(); + + PNS_TOPOLOGY topo ( m_world ); + + if( !topo.AssembleDiffPair ( m_initialSegment, m_originPair ) ) + { + Router()->SetFailureReason( _( "Unable to find complementary differential pair " + "net for length tuning. Make sure the names of the nets belonging " + "to a differential pair end with either _N/_P or +/-." ) ); + return false; + } + + + m_originPair.SetGap ( Router()->Sizes().DiffPairGap() ); + + if( !m_originPair.PLine().SegmentCount() || + !m_originPair.NLine().SegmentCount() ) + return false; + + m_tunedPathP = topo.AssembleTrivialPath ( m_originPair.PLine().GetLink(0) ); + m_tunedPathN = topo.AssembleTrivialPath ( m_originPair.NLine().GetLink(0) ); + + m_world->Remove ( m_originPair.PLine() ); + m_world->Remove ( m_originPair.NLine() ); + + m_currentWidth = m_originPair.Width(); + + return true; +} + + +void PNS_DP_MEANDER_PLACER::release() +{ + #if 0 + BOOST_FOREACH(PNS_MEANDER *m, m_meanders) + { + delete m; + } + + m_meanders.clear(); + #endif +} + +int PNS_DP_MEANDER_PLACER::origPathLength () const +{ + int totalP = 0; + int totalN = 0; + + BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathP.CItems() ) + { + if ( const PNS_LINE *l = dyn_cast (item) ) + totalP += l->CLine( ).Length( ); + + } + BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathN.CItems() ) + { + if ( const PNS_LINE *l = dyn_cast (item) ) + totalN += l->CLine( ).Length( ); + + } + + return std::max(totalP, totalN); +} + +const SEG PNS_DP_MEANDER_PLACER::baselineSegment ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ) +{ + const VECTOR2I a( ( aCoupledSegs.coupledP.A + aCoupledSegs.coupledN.A ) / 2 ); + const VECTOR2I b( ( aCoupledSegs.coupledP.B + aCoupledSegs.coupledN.B ) / 2 ); + + return SEG (a, b); +} + + +#if 0 +PNS_MEANDER_PLACER_BASE::TUNING_STATUS PNS_DP_MEANDER_PLACER::tuneLineLength ( PNS_MEANDERED_LINE& aTuned, int aElongation ) +{ + int remaining = aElongation; + bool finished = false; + + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + + if(m->Type() != MT_CORNER ) + { + + if(remaining >= 0) + remaining -= m->MaxTunableLength() - m->BaselineLength(); + + if(remaining < 0) + { + if(!finished) + { + PNS_MEANDER_TYPE newType; + + if ( m->Type() == MT_START || m->Type() == MT_SINGLE) + newType = MT_SINGLE; + else + newType = MT_FINISH; + + m->SetType ( newType ); + m->Recalculate( ); + + finished = true; + } else { + m->MakeEmpty(); + } + } + } + } + + remaining = aElongation; + int meanderCount = 0; + + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + if( m->Type() != MT_CORNER && m->Type() != MT_EMPTY ) + { + if(remaining >= 0) + { + remaining -= m->MaxTunableLength() - m->BaselineLength(); + meanderCount ++; + } + } + } + + int balance = 0; + + + if( meanderCount ) + balance = -remaining / meanderCount; + + if (balance >= 0) + { + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + if(m->Type() != MT_CORNER && m->Type() != MT_EMPTY) + { +// int pre = m->MaxTunableLength(); + m->Resize ( std::max( m->Amplitude() - balance / 2, m_settings.m_minAmplitude ) ); + } + } + + } + return TUNED; +} +#endif + + + +bool pairOrientation( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aPair ) +{ + VECTOR2I midp = ( aPair.coupledP.A + aPair.coupledN.A ) / 2; + + //DrawDebugPoint (midp, 6); + + return aPair.coupledP.Side ( midp ) > 0; +} + +bool PNS_DP_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + + + +// return false; + + if(m_currentNode) + delete m_currentNode; + + m_currentNode = m_world->Branch(); + + SHAPE_LINE_CHAIN preP, tunedP, postP; + SHAPE_LINE_CHAIN preN, tunedN, postN; + + cutTunedLine ( m_originPair.CP(), m_currentStart, aP, preP, tunedP, postP ); + cutTunedLine ( m_originPair.CN(), m_currentStart, aP, preN, tunedN, postN ); + + PNS_DIFF_PAIR tuned ( m_originPair ); + + tuned.SetShape ( tunedP, tunedN ); + + m_coupledSegments.clear(); + + tuned.CoupledSegmentPairs ( m_coupledSegments ); + + if (m_coupledSegments.size() == 0) + return false; + + //Router()->DisplayDebugLine ( tuned.CP(), 5, 20000 ); + //Router()->DisplayDebugLine ( tuned.CN(), 4, 20000 ); + + //Router()->DisplayDebugLine ( m_originPair.CP(), 5, 20000 ); + //Router()->DisplayDebugLine ( m_originPair.CN(), 4, 20000 ); + + m_result = PNS_MEANDERED_LINE (this, true ); + m_result.SetWidth ( tuned.Width() ); + + int offset = ( tuned.Gap() + tuned.Width() ) / 2; + + if ( !pairOrientation ( m_coupledSegments[0] ) ) + offset *= -1; + + + m_result.SetBaselineOffset ( offset ); + + + BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathP.CItems() ) + { + if ( const PNS_LINE *l = dyn_cast (item) ) + Router()->DisplayDebugLine ( l->CLine(), 5, 10000 ); + + } + + BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathN.CItems() ) + { + if ( const PNS_LINE *l = dyn_cast (item) ) + Router()->DisplayDebugLine ( l->CLine(), 5, 10000 ); + } + + + BOOST_FOREACH ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& sp, m_coupledSegments ) + { + SEG base = baselineSegment ( sp ); + + // DrawDebugSeg ( base, 3 ); + + m_result.AddCorner ( sp.parentP.A, sp.parentN.A ); + m_result.MeanderSegment ( base ); + m_result.AddCorner ( sp.parentP.B, sp.parentN.B ); + } + + int dpLen = origPathLength(); + + m_lastStatus = TUNED; + + if (dpLen - m_settings.m_targetLength > m_settings.m_lengthTollerance) + { + m_lastStatus = TOO_LONG; + m_lastLength = dpLen; + } else { + + m_lastLength = dpLen - std::max ( tunedP.Length(), tunedN.Length() ); + tuneLineLength(m_result, m_settings.m_targetLength - dpLen ); + } + + if (m_lastStatus != TOO_LONG) + { + tunedP.Clear(); + tunedN.Clear(); + + BOOST_FOREACH ( PNS_MEANDER_SHAPE *m, m_result.Meanders() ) + { + if( m->Type() != MT_EMPTY ) + { + tunedP.Append ( m->CLine(0) ); + tunedN.Append ( m->CLine(1) ); + } + } + + m_lastLength += std::max ( tunedP.Length(), tunedN.Length() ); + + int comp = compareWithTollerance( m_lastLength - m_settings.m_targetLength, 0, m_settings.m_lengthTollerance ); + + if( comp > 0 ) + m_lastStatus = TOO_LONG; + else if( comp < 0 ) + m_lastStatus = TOO_SHORT; + else + m_lastStatus = TUNED; + + } + + m_finalShapeP.Clear( ); + m_finalShapeP.Append( preP ); + m_finalShapeP.Append( tunedP ); + m_finalShapeP.Append( postP ); + m_finalShapeP.Simplify(); + + m_finalShapeN.Clear( ); + m_finalShapeN.Append( preN ); + m_finalShapeN.Append( tunedN ); + m_finalShapeN.Append( postN ); + m_finalShapeN.Simplify(); + + return true; +} + + +bool PNS_DP_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + PNS_LINE lP ( m_originPair.PLine(), m_finalShapeP ); + PNS_LINE lN ( m_originPair.NLine(), m_finalShapeN ); + + m_currentNode->Add ( &lP ); + m_currentNode->Add ( &lN ); + + Router()->CommitRouting( m_currentNode ); + + return true; +} + +bool PNS_DP_MEANDER_PLACER::CheckFit ( PNS_MEANDER_SHAPE *aShape ) +{ + PNS_LINE l1 ( m_originPair.PLine(), aShape->CLine(0) ); + PNS_LINE l2 ( m_originPair.NLine(), aShape->CLine(1) ); + + if( m_currentNode->CheckColliding( &l1 ) ) + return false; + + if( m_currentNode->CheckColliding( &l2 ) ) + return false; + + int w = aShape->Width(); + int clearance = w + m_settings.m_spacing; + + return m_result.CheckSelfIntersections( aShape, clearance ); +} + + +const PNS_ITEMSET PNS_DP_MEANDER_PLACER::Traces() +{ + + m_currentTraceP = PNS_LINE ( m_originPair.PLine(), m_finalShapeP ); + m_currentTraceN = PNS_LINE ( m_originPair.NLine(), m_finalShapeN ); + + PNS_ITEMSET traces; + + traces.Add (&m_currentTraceP); + traces.Add (&m_currentTraceN); + + return traces; +} + +const VECTOR2I& PNS_DP_MEANDER_PLACER::CurrentEnd() const +{ + return m_currentEnd; +} + +int PNS_DP_MEANDER_PLACER::CurrentNet() const +{ + return m_initialSegment->Net(); +} + +int PNS_DP_MEANDER_PLACER::CurrentLayer() const +{ + return m_initialSegment->Layers().Start(); +} + +const wxString PNS_DP_MEANDER_PLACER::TuningInfo() const +{ + wxString status; + + switch (m_lastStatus) + { + case TOO_LONG: + status = _("Too long: "); + break; + case TOO_SHORT: + status = _("Too short: "); + break; + case TUNED: + status = _("Tuned: "); + break; + default: + return _("?"); + } + + status += LengthDoubleToString( (double) m_lastLength, false ); + status += "/"; + status += LengthDoubleToString( (double) m_settings.m_targetLength, false ); + + return status; +} + +PNS_DP_MEANDER_PLACER::TUNING_STATUS PNS_DP_MEANDER_PLACER::TuningStatus() const +{ + return m_lastStatus; +} diff --git a/pcbnew/router/pns_dp_meander_placer.h b/pcbnew/router/pns_dp_meander_placer.h new file mode 100644 index 0000000000..5f2f54f500 --- /dev/null +++ b/pcbnew/router/pns_dp_meander_placer.h @@ -0,0 +1,148 @@ +/* + * 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_DP_MEANDER_PLACER_H +#define __PNS_DP_MEANDER_PLACER_H + +#include + +#include +#include + +#include "pns_node.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_placement_algo.h" +#include "pns_meander.h" +#include "pns_meander_placer_base.h" +#include "pns_diff_pair.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; + +/** + * Class PNS_DP_MEANDER_PLACER + * + * Differential Pair length-matching/meandering tool. + */ + +class PNS_DP_MEANDER_PLACER : public PNS_MEANDER_PLACER_BASE +{ +public: + + PNS_DP_MEANDER_PLACER( PNS_ROUTER* aRouter ); + ~PNS_DP_MEANDER_PLACER(); + + /** + * Function Start() + * + * Starts routing a single track at point aP, taking item aStartItem as anchor + * (unless NULL). + */ + bool Start ( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + + /** + * Function Move() + * + * Moves the end of the currently routed trace to the point aP, taking + * aEndItem as anchor (if not NULL). + * (unless NULL). + */ + bool 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 ); + + const PNS_LINE Trace() const; + + /** + * Function CurrentNode() + * + * Returns the most recent world state. + */ + PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const; + + const PNS_ITEMSET Traces(); + + const VECTOR2I& CurrentEnd() const; + + int CurrentNet() const; + int CurrentLayer() const; + + + int totalLength(); + + const wxString TuningInfo() const; + TUNING_STATUS TuningStatus() const; + + bool CheckFit ( PNS_MEANDER_SHAPE* aShape ); + + +private: + friend class PNS_MEANDER_SHAPE; + + void meanderSegment ( const SEG& aBase ); + + + +// void addMeander ( PNS_MEANDER *aM ); +// void addCorner ( const VECTOR2I& aP ); + + const SEG baselineSegment ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ); + + void setWorld ( PNS_NODE* aWorld ); + void release(); + + int origPathLength () const; + + ///> pointer to world to search colliding items + PNS_NODE* m_world; + + ///> current routing start point (end of tail, beginning of head) + VECTOR2I m_currentStart; + + ///> Current world state + PNS_NODE* m_currentNode; + + PNS_DIFF_PAIR m_originPair; + PNS_DIFF_PAIR::COUPLED_SEGMENTS_VEC m_coupledSegments; + + PNS_LINE m_currentTraceN, m_currentTraceP; + PNS_ITEMSET m_tunedPath, m_tunedPathP, m_tunedPathN; + + SHAPE_LINE_CHAIN m_finalShapeP, m_finalShapeN; + PNS_MEANDERED_LINE m_result; + PNS_SEGMENT *m_initialSegment; + + int m_lastLength; + TUNING_STATUS m_lastStatus; +}; + +#endif // __PNS_DP_MEANDER_PLACER_H diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h index 7e4333052e..cd53b76b61 100644 --- a/pcbnew/router/pns_item.h +++ b/pcbnew/router/pns_item.h @@ -36,7 +36,8 @@ class PNS_NODE; enum LineMarker { MK_HEAD = ( 1 << 0 ), MK_VIOLATION = ( 1 << 3 ), - MK_LOCKED = ( 1 << 4 ) + MK_LOCKED = ( 1 << 4 ), + MK_DP_COUPLED = ( 1 << 5 ) }; /** @@ -58,6 +59,7 @@ public: JOINT = 4, SEGMENT = 8, VIA = 16, + DIFF_PAIR = 32, ANY = 0xff }; diff --git a/pcbnew/router/pns_itemset.cpp b/pcbnew/router/pns_itemset.cpp index 837f5e4ee5..9c41b2eb66 100644 --- a/pcbnew/router/pns_itemset.cpp +++ b/pcbnew/router/pns_itemset.cpp @@ -22,12 +22,22 @@ #include "pns_itemset.h" -PNS_ITEMSET::PNS_ITEMSET( PNS_ITEM* aInitialItem ) +PNS_ITEMSET::PNS_ITEMSET( PNS_ITEM* aInitialItem ) : + m_owner ( false ) { if( aInitialItem ) m_items.push_back( aInitialItem ); } +PNS_ITEMSET::~PNS_ITEMSET() +{ + if (m_owner) + { + BOOST_FOREACH ( PNS_ITEM *item, m_items ) + delete item; + } +} + PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd, bool aInvert ) { ITEMS newItems; @@ -64,6 +74,21 @@ PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask, bool aInvert ) return *this; } +PNS_ITEMSET& PNS_ITEMSET::FilterMarker( int aMarker, bool aInvert ) +{ + ITEMS newItems; + + BOOST_FOREACH( PNS_ITEM* item, m_items ) + { + if( item->Marker() & aMarker ) + newItems.push_back( item ); + } + + m_items = newItems; + + return *this; +} + PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet, bool aInvert ) { diff --git a/pcbnew/router/pns_itemset.h b/pcbnew/router/pns_itemset.h index d229fc017c..278714db77 100644 --- a/pcbnew/router/pns_itemset.h +++ b/pcbnew/router/pns_itemset.h @@ -21,7 +21,7 @@ #ifndef __PNS_ITEMSET_H #define __PNS_ITEMSET_H -#include +#include #include #include "pns_item.h" @@ -36,15 +36,23 @@ class PNS_ITEMSET { public: - typedef std::vector ITEMS; + typedef std::deque ITEMS; PNS_ITEMSET( PNS_ITEM* aInitialItem = NULL ); - PNS_ITEMSET( const PNS_ITEMSET& aOther ) + PNS_ITEMSET( const PNS_ITEMSET& aOther ): + m_owner ( false ) { m_items = aOther.m_items; } + ~PNS_ITEMSET(); + + void MakeOwner ( ) + { + m_owner = true; + } + const PNS_ITEMSET& operator=( const PNS_ITEMSET& aOther ) { m_items = aOther.m_items; @@ -68,6 +76,7 @@ public: PNS_ITEMSET& FilterLayers( int aStart, int aEnd = -1, bool aInvert = false ); PNS_ITEMSET& FilterKinds( int aKindMask, bool aInvert = false ); PNS_ITEMSET& FilterNet( int aNet, bool aInvert = false ); + PNS_ITEMSET& FilterMarker( int aMarker, bool aInvert = false ); PNS_ITEMSET& ExcludeLayers( int aStart, int aEnd = -1 ) { @@ -96,6 +105,11 @@ public: m_items.push_back( aItem ); } + void Prepend ( PNS_ITEM *aItem ) + { + m_items.push_front ( aItem ); + } + PNS_ITEM* Get( int index ) const { return m_items[index]; @@ -126,6 +140,7 @@ public: private: ITEMS m_items; + bool m_owner; }; #endif diff --git a/pcbnew/router/pns_joint.h b/pcbnew/router/pns_joint.h index 43ca70daf0..566ade3bd0 100644 --- a/pcbnew/router/pns_joint.h +++ b/pcbnew/router/pns_joint.h @@ -41,7 +41,7 @@ class PNS_JOINT : public PNS_ITEM { public: - typedef std::vector LINKED_ITEMS; + typedef std::deque LINKED_ITEMS; ///> Joints are hashed by their position, layers and net. /// Linked items are, obviously, not hashed @@ -95,6 +95,22 @@ public: return seg1->Width() == seg2->Width(); } + bool IsNonFanoutVia () const + { + if ( m_linkedItems.Size() != 3 ) + return false; + + int vias = 0, segs = 0; + + for(int i = 0; i < 3; i++) + { + vias += m_linkedItems[i]->Kind() == VIA ? 1 : 0; + segs += m_linkedItems[i]->Kind() == SEGMENT ? 1 : 0; + } + + return (vias == 1 && segs == 2); + } + ///> Links the joint to a given board item (when it's added to the PNS_NODE) void Link( PNS_ITEM* aItem ) { diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index c391f31a9e..bf02010bfe 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -701,6 +701,9 @@ void PNS_LINE::Reverse() void PNS_LINE::AppendVia( const PNS_VIA& aVia ) { + if(m_line.PointCount() == 0) + return; + if( aVia.Pos() == m_line.CPoint( 0 ) ) { Reverse(); @@ -781,3 +784,91 @@ void PNS_LINE::ClearSegmentLinks() m_segmentRefs = NULL; } + +static void extendBox( BOX2I& aBox, bool &aDefined, const VECTOR2I& aP ) +{ + if( aDefined ) + aBox.Merge ( aP ); + else { + aBox = BOX2I ( aP, VECTOR2I (0, 0 ) ); + aDefined = true; + } +} + +OPT_BOX2I PNS_LINE::ChangedArea ( const PNS_LINE *aOther ) const +{ + BOX2I area; + bool areaDefined = false; + + + int i_start = -1; + int i_end_self = -1, i_end_other = -1; + + SHAPE_LINE_CHAIN self ( m_line ); + self.Simplify(); + SHAPE_LINE_CHAIN other ( aOther->m_line ); + other.Simplify(); + + int np_self = self.PointCount(); + int np_other = other.PointCount(); + + int n = std::min ( np_self, np_other ); + + for( int i = 0; i < n; i++) + { + const VECTOR2I p1 = self.CPoint(i); + const VECTOR2I p2 = other.CPoint(i); + if (p1 != p2) + { + if (i != n - 1) + { + SEG s = self.CSegment(i); + if( !s.Contains( p2 ) ) + { + i_start = i; + break; + } + } else { + i_start = i; + break; + } + + } + } + + for( int i = 0; i < n; i++) + { + + const VECTOR2I p1 = self.CPoint( np_self - 1 - i ); + const VECTOR2I p2 = other.CPoint( np_other - 1 - i ); + if (p1 != p2) + { + i_end_self = np_self - 1 - i; + i_end_other = np_other - 1 - i; + break; + } + } + + if( i_start < 0 ) + i_start = n; + + if( i_end_self < 0 ) + i_end_self = np_self - 1; + + if( i_end_other < 0 ) + i_end_other = np_other - 1; + + for (int i = i_start; i <= i_end_self; i++ ) + extendBox ( area, areaDefined, self.CPoint(i) ); + + for (int i = i_start; i <= i_end_other; i++ ) + extendBox ( area, areaDefined, other.CPoint(i) ); + + if( areaDefined ) + { + area.Inflate ( std::max( Width(), aOther->Width() ) ); + return area; + } + + return OPT_BOX2I ( ); +} diff --git a/pcbnew/router/pns_line.h b/pcbnew/router/pns_line.h index d77c37ec96..5a12fab96f 100644 --- a/pcbnew/router/pns_line.h +++ b/pcbnew/router/pns_line.h @@ -88,7 +88,12 @@ public: } ~PNS_LINE(); - + + static inline bool ClassOf( const PNS_ITEM* aItem ) + { + return aItem && LINE == aItem->Kind(); + } + /// @copydoc PNS_ITEM::Clone() virtual PNS_LINE* Clone() const; @@ -179,6 +184,11 @@ public: return m_segmentRefs; } + bool IsLinked () const + { + return m_segmentRefs != NULL; + } + ///> Checks if the segment aSeg is a part of the line. bool ContainsSegment( PNS_SEGMENT* aSeg ) const { @@ -189,6 +199,11 @@ public: aSeg ) != m_segmentRefs->end(); } + PNS_SEGMENT* GetLink ( int aIndex ) const + { + return (*m_segmentRefs) [ aIndex ]; + } + ///> Erases the linking information. Used to detach the line from the owning node. void ClearSegmentLinks(); @@ -251,6 +266,8 @@ public: bool HasLoops() const; + OPT_BOX2I ChangedArea ( const PNS_LINE *aOther ) const; + private: VECTOR2I snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, int aIndex, int aThreshold) const; diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 093fbe6218..2d6014784e 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -31,13 +31,14 @@ #include "pns_shove.h" #include "pns_utils.h" #include "pns_router.h" +#include "pns_topology.h" #include using boost::optional; PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_ROUTER* aRouter ) : - PNS_ALGO_BASE ( aRouter ) + PNS_PLACEMENT_ALGO ( aRouter ) { m_initial_direction = DIRECTION_45::N; m_world = NULL; @@ -67,11 +68,13 @@ const PNS_VIA PNS_LINE_PLACER::makeVia ( const VECTOR2I& aP ) } -void PNS_LINE_PLACER::ToggleVia( bool aEnabled ) +bool PNS_LINE_PLACER::ToggleVia( bool aEnabled ) { m_placingVia = aEnabled; if(!m_idle) Move ( m_currentEnd, NULL ); + + return true; } @@ -225,8 +228,6 @@ bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) VECTOR2I new_start; int reduce_index = -1; - DIRECTION_45 head_dir( head.CSegment( 0 ) ); - for( int i = tail.SegmentCount() - 1; i >= 0; i-- ) { const SEG s = tail.CSegment( i ); @@ -376,7 +377,7 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead ) bool PNS_LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP ); + SHAPE_LINE_CHAIN line = buildInitialLine ( aP ); PNS_LINE initTrack( m_head, line ), walkFull; int effort = 0; bool viaOk = handleViaPlacement( initTrack ); @@ -430,7 +431,7 @@ bool PNS_LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, PNS_LINE& aNewHead ) bool PNS_LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - m_head.SetShape( m_direction.BuildInitialTrace( m_p_start, aP ) ); + m_head.SetShape( buildInitialLine ( aP ) ); if( m_placingVia ) { @@ -445,7 +446,7 @@ bool PNS_LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ) bool PNS_LINE_PLACER::rhShoveOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP ); + SHAPE_LINE_CHAIN line = buildInitialLine ( aP ); PNS_LINE initTrack( m_head, line ); PNS_LINE walkSolids, l2; @@ -744,7 +745,7 @@ bool PNS_LINE_PLACER::SetLayer( int aLayer ) return false; } -void PNS_LINE_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +bool PNS_LINE_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p( aP ); @@ -772,6 +773,7 @@ void PNS_LINE_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) setInitialDirection( Settings().InitialDirection() ); initPlacement( m_splitSeg ); + return true; } void PNS_LINE_PLACER::initPlacement( bool aSplitSeg ) @@ -819,7 +821,7 @@ void PNS_LINE_PLACER::initPlacement( bool aSplitSeg ) } -void PNS_LINE_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +bool PNS_LINE_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { PNS_LINE current; VECTOR2I p = aP; @@ -856,6 +858,7 @@ void PNS_LINE_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) } updateLeadingRatLine(); + return true; } @@ -962,11 +965,6 @@ void PNS_LINE_PLACER::removeLoops( PNS_NODE* aNode, PNS_LINE* aLatest ) 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 ++; } @@ -1012,27 +1010,39 @@ void PNS_LINE_PLACER::UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ) void PNS_LINE_PLACER::updateLeadingRatLine() { PNS_LINE current = Trace(); + SHAPE_LINE_CHAIN ratLine; + PNS_TOPOLOGY topo ( m_lastNode ); - 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 ); - } + if( topo.LeadingRatLine ( ¤t, ratLine )) + Router()->DisplayDebugLine( ratLine, 5, 10000 ); +} + +void PNS_LINE_PLACER::SetOrthoMode ( bool aOrthoMode ) +{ + m_orthoMode = aOrthoMode; + if(!m_idle) + Move ( m_currentEnd, NULL ); +} + +const SHAPE_LINE_CHAIN PNS_LINE_PLACER::buildInitialLine ( const VECTOR2I& aP ) +{ + SHAPE_LINE_CHAIN l (m_direction.BuildInitialTrace( m_p_start, aP ) ); + + if( l.SegmentCount() <= 1 ) + return l; + + if (m_orthoMode) + { + VECTOR2I newLast = l.CSegment(0).LineProject ( l.CPoint(-1) ); + + l.Remove(-1, -1); + l.Point(1) = newLast; + } + + return l; +} + +void PNS_LINE_PLACER::GetModifiedNets( std::vector &aNets ) const +{ + aNets.push_back( m_currentNet ); } diff --git a/pcbnew/router/pns_line_placer.h b/pcbnew/router/pns_line_placer.h index 1d603bd9b6..ec7ace7412 100644 --- a/pcbnew/router/pns_line_placer.h +++ b/pcbnew/router/pns_line_placer.h @@ -30,7 +30,7 @@ #include "pns_node.h" #include "pns_via.h" #include "pns_line.h" -#include "pns_algo_base.h" +#include "pns_placement_algo.h" class PNS_ROUTER; class PNS_SHOVE; @@ -40,6 +40,7 @@ class PNS_VIA; class PNS_SIZES_SETTINGS; + /** * Class PNS_LINE_PLACER * @@ -47,7 +48,7 @@ class PNS_SIZES_SETTINGS; * Applies shove and walkaround algorithms when needed. */ -class PNS_LINE_PLACER : public PNS_ALGO_BASE +class PNS_LINE_PLACER : public PNS_PLACEMENT_ALGO { public: PNS_LINE_PLACER( PNS_ROUTER* aRouter ); @@ -59,7 +60,7 @@ public: * Starts routing a single track at point aP, taking item aStartItem as anchor * (unless NULL). */ - void Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); /** * Function Move() @@ -68,7 +69,7 @@ public: * aEndItem as anchor (if not NULL). * (unless NULL). */ - void Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + bool Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ); /** * Function FixRoute() @@ -86,7 +87,7 @@ public: * * Enables/disables a via at the end of currently routed trace. */ - void ToggleVia( bool aEnabled ); + bool ToggleVia( bool aEnabled ); /** * Function SetLayer() @@ -180,7 +181,11 @@ public: */ void UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ); + void SetOrthoMode ( bool aOrthoMode ); + bool IsPlacingVia() const { return m_placingVia; } + + void GetModifiedNets( std::vector &aNets ) const; private: /** * Function route() @@ -343,7 +348,8 @@ private: bool rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ); const PNS_VIA makeVia ( const VECTOR2I& aP ); - + const SHAPE_LINE_CHAIN buildInitialLine ( const VECTOR2I& aP ); + ///> current routing direction DIRECTION_45 m_direction; @@ -403,6 +409,7 @@ private: bool m_idle; bool m_chainedPlacement; bool m_splitSeg; + bool m_orthoMode; }; #endif // __PNS_LINE_PLACER_H diff --git a/pcbnew/router/pns_meander.cpp b/pcbnew/router/pns_meander.cpp new file mode 100644 index 0000000000..952a27e403 --- /dev/null +++ b/pcbnew/router/pns_meander.cpp @@ -0,0 +1,580 @@ +/* + * 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 // God forgive me doing this... +#include + +#include "trace.h" + +#include "pns_node.h" +#include "pns_itemset.h" +#include "pns_topology.h" +#include "pns_meander.h" +#include "pns_meander_placer_base.h" +#include "pns_router.h" + +const PNS_MEANDER_SETTINGS& PNS_MEANDER_SHAPE::Settings( ) const +{ + return m_placer->MeanderSettings( ); +} + +const PNS_MEANDER_SETTINGS& PNS_MEANDERED_LINE::Settings( ) const +{ + return m_placer->MeanderSettings( ); +} + +void PNS_MEANDERED_LINE::MeanderSegment( const SEG &aBase, int aBaseIndex ) +{ + double base_len = aBase.Length( ); + + SHAPE_LINE_CHAIN lc; + + bool side = true; + VECTOR2D dir( aBase.B - aBase.A ); + + if(!m_dual) + AddCorner( aBase.A ); + + bool turning = false; + bool started = false; + + m_last = aBase.A; + + do + { + PNS_MEANDER_SHAPE *m = new PNS_MEANDER_SHAPE( m_placer, m_width, m_dual ); + m->SetBaselineOffset( m_baselineOffset ); + m->SetBaseIndex( aBaseIndex ); + + double thr = (double) m->spacing( ); + + bool fail = false; + double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( ); + + if( remaining < Settings( ).m_step ) + break; + + if( remaining > 3.0 * thr ) + { + + if( !turning ) + { + for( int i = 0; i < 2; i++ ) + { + if ( m->Fit( MT_CHECK_START, aBase, m_last, i ) ) + { + turning = true; + AddMeander( m ); + side = !i; + started = true; + break; + } + } + + if( !turning ) + { + fail = true; + + for( int i = 0; i < 2; i++ ) + { + if ( m->Fit ( MT_SINGLE, aBase, m_last, i ) ) + { + AddMeander( m ); + fail = false; + started = false; + side = !i; + break; + } + } + } + + } else { + bool rv = m->Fit( MT_CHECK_FINISH, aBase, m_last, side ); + + if( rv ) + { + m->Fit( MT_TURN, aBase, m_last, side ); + AddMeander( m ); + started = true; + } else { + m->Fit( MT_FINISH, aBase, m_last, side ); + started = false; + AddMeander( m ); + turning = false; + } + + side = !side; + } + + } else if( started ) + { + bool rv = m->Fit( MT_FINISH, aBase, m_last, side ); + if( rv ) + AddMeander(m); + + break; + + } else { + fail = true; + } + + remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( ); + + if( remaining < Settings( ).m_step ) + break; + + + if( fail ) + { + PNS_MEANDER_SHAPE tmp( m_placer, m_width, m_dual ); + tmp.SetBaselineOffset( m_baselineOffset ); + tmp.SetBaseIndex( aBaseIndex ); + + int nextP = tmp.spacing( ) - 2 * tmp.cornerRadius( ) + Settings( ).m_step; + VECTOR2I pn = m_last + dir.Resize ( nextP ); + + if (aBase.Contains( pn ) && !m_dual) + { + AddCorner ( pn ); + } else + break; + } + + + } while( true ); + + if( !m_dual ) + AddCorner( aBase.B ); +} + + +int PNS_MEANDER_SHAPE::cornerRadius( ) const +{ + int cr = (int64_t) spacing( ) * Settings( ).m_cornerRadiusPercentage / 200; + + return cr; +} + +int PNS_MEANDER_SHAPE::spacing( ) const +{ + if ( !m_dual ) + return std::max ( 2 * m_width, Settings( ).m_spacing ); + else + { + int sp = 2 * ( m_width + std::abs( m_baselineOffset ) ); + return std::max ( sp, Settings( ).m_spacing ); + } +} + + +SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool side ) +{ + SHAPE_LINE_CHAIN lc; + + if( aDir.EuclideanNorm( ) == 0.0f ) + { + lc.Append( aP ); + return lc; + } + + VECTOR2D dir_u( aDir ); + VECTOR2D dir_v( aDir.Perpendicular( ) ); + + const int ArcSegments = Settings( ).m_cornerArcSegments; + + for(int i = ArcSegments - 1; i >= 0; i--) + { + VECTOR2D p; + double alpha = (double) i / (double) (ArcSegments - 1) * M_PI / 2.0; + p = aP + dir_u * cos( alpha ) + dir_v * ( side ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) ); + lc.Append( ( int ) p.x, ( int ) p.y ); + } + return lc; +} + +VECTOR2I PNS_MEANDER_SHAPE::reflect( VECTOR2I p, const SEG& line ) +{ + typedef int64_t ecoord; + VECTOR2I d = line.B - line.A; + ecoord l_squared = d.Dot( d ); + ecoord t = d.Dot( p - line.A ); + VECTOR2I c, rv; + + if(!l_squared) + c = p; + else { + c.x = line.A.x + rescale( t, (ecoord)d.x, l_squared ); + c.y = line.A.y + rescale( t, (ecoord)d.y, l_squared ); + } + + return 2 * c - p; +} + +void PNS_MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir ) +{ + m_currentTarget = aTarget; + m_currentTarget->Clear( ); + m_currentTarget->Append( aWhere ); + m_currentDir = aDir; + m_currentPos = aWhere; +} + +void PNS_MEANDER_SHAPE::forward( int aLength ) +{ + m_currentPos += m_currentDir.Resize( aLength ); + m_currentTarget->Append( m_currentPos ); +} + +void PNS_MEANDER_SHAPE::turn( int aAngle ) +{ + m_currentDir = m_currentDir.Rotate( (double)aAngle * M_PI / 180.0 ); +} + +void PNS_MEANDER_SHAPE::arc( int aRadius, bool aSide ) +{ + if( aRadius <= 0 ) + { + turn ( aSide ? -90 : 90 ); + return; + } + + VECTOR2D dir = m_currentDir.Resize( (double) aRadius ); + SHAPE_LINE_CHAIN arc = circleQuad( m_currentPos, dir, aSide ); + m_currentPos = arc.CPoint( -1 ); + m_currentDir = dir.Rotate( aSide ? -M_PI/2.0 : M_PI/2.0 ); + + m_currentTarget->Append ( arc ); +} + +void PNS_MEANDER_SHAPE::uShape ( int aSides, int aCorner, int aTop ) +{ + forward( aSides ); + arc( aCorner, true ); + forward( aTop ); + arc( aCorner, true ); + forward( aSides ); +} + +SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset ) +{ + const PNS_MEANDER_SETTINGS& st = Settings(); + int cr = cornerRadius(); + int offset = aBaselineOffset; + int spc = spacing(); + + if (aSide) + offset *= -1; + + VECTOR2D dir_u_b ( aDir.Resize( offset ) ); + VECTOR2D dir_v_b (dir_u_b.Perpendicular()); + + if (2 * cr > aAmpl) + { + cr = aAmpl / 2; + } + + if (2 * cr > spc) + { + cr = spc / 2; + } + + + SHAPE_LINE_CHAIN lc; + + start ( &lc, aP + dir_v_b, aDir ); + + switch (aType) + { + case MT_EMPTY: + { + lc.Append( aP + dir_v_b + aDir ); + break; + } + case MT_START: + { + arc( cr - offset, false ); + uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); + forward( std::min(cr - offset, cr + offset) ); + forward( std::abs( offset ) ); + + break; + } + + case MT_FINISH: + { + start( &lc, aP - dir_u_b, aDir ); + turn ( 90 ); + forward( std::min(cr - offset, cr + offset) ); + forward( std::abs( offset ) ); + uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); + arc( cr - offset, false ); + break; + } + + case MT_TURN: + { + + start( &lc, aP - dir_u_b, aDir ); + turn( 90 ); + forward( std::abs( offset ) ); + uShape ( aAmpl - cr, cr + offset, spc - 2 * cr ); + forward( std::abs( offset ) ); + + break; + } + + case MT_SINGLE: + { + arc( cr - offset, false ); + uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); + arc( cr - offset, false ); + lc.Append ( aP + dir_v_b + aDir.Resize ( 2 * st.m_spacing) ); + break; + } + + default: + break; + } + + if( aSide ) + { + SEG axis ( aP, aP + aDir ); + for(int i = 0; i < lc.PointCount(); i++ ) + lc.Point(i) = reflect ( lc.CPoint(i), axis ); + } + + return lc; +} + +bool PNS_MEANDERED_LINE::CheckSelfIntersections ( PNS_MEANDER_SHAPE *aShape, int aClearance ) +{ + for (int i = m_meanders.size() - 1; i >= 0; i--) + { + PNS_MEANDER_SHAPE *m = m_meanders[i]; + + if (m->Type() == MT_EMPTY || m->Type() == MT_CORNER ) + continue; + + const SEG& b1 = aShape->BaseSegment(); + const SEG& b2 = m->BaseSegment(); + + if (b1.ApproxParallel(b2)) + continue; + + int n = m->CLine(0).SegmentCount(); + + for (int j = n - 1; j >= 0; j--) + if ( aShape->CLine(0).Collide ( m->CLine(0).CSegment(j), aClearance ) ) + return false; + } + + return true; +} + +bool PNS_MEANDER_SHAPE::Fit ( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ) +{ + const PNS_MEANDER_SETTINGS& st = Settings(); + + bool checkMode = false; + PNS_MEANDER_TYPE prim1, prim2; + + if(aType == MT_CHECK_START) + { + prim1 = MT_START; + prim2 = MT_TURN; + checkMode = true; + } else if (aType == MT_CHECK_FINISH ) { + prim1 = MT_TURN; + prim2 = MT_FINISH; + checkMode = true; + } + + if(checkMode) + { + PNS_MEANDER_SHAPE m1 ( m_placer, m_width, m_dual ); + PNS_MEANDER_SHAPE m2 ( m_placer, m_width, m_dual ); + + m1.SetBaselineOffset ( m_baselineOffset ); + m2.SetBaselineOffset ( m_baselineOffset ); + + bool c1 = m1.Fit ( prim1, aSeg, aP, aSide ); + bool c2 = false; + + if(c1) + c2 = m2.Fit ( prim2, aSeg, m1.End(), !aSide ); + + if(c1 && c2) + { + m_type = prim1; + m_shapes[0] = m1.m_shapes[0]; + m_shapes[1] = m1.m_shapes[1]; + m_baseSeg =aSeg; + m_p0 = aP; + m_side = aSide; + m_amplitude = m1.Amplitude(); + m_dual = m1.m_dual; + m_baseSeg = m1.m_baseSeg; + m_baseIndex = m1.m_baseIndex; + updateBaseSegment (); + m_baselineOffset = m1.m_baselineOffset; + return true; + } else + return false; + + } + + int minAmpl = st.m_minAmplitude; + int maxAmpl = st.m_maxAmplitude; + + if (m_dual) + { + minAmpl = std::max( minAmpl, 2 * std::abs(m_baselineOffset) ); + maxAmpl = std::max( maxAmpl, 2 * std::abs(m_baselineOffset) ); + } + + for(int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step) + { + if (m_dual) + { + m_shapes[0] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, m_baselineOffset ); + m_shapes[1] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, -m_baselineOffset ); + } else { + m_shapes[0] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, 0); + } + + m_type = aType; + m_baseSeg =aSeg; + m_p0 = aP; + m_side = aSide; + m_amplitude = ampl; + + updateBaseSegment(); + + if( m_placer->CheckFit ( this ) ) + return true; + } + + return false; +} + +void PNS_MEANDER_SHAPE::Recalculate ( ) +{ + + m_shapes[0] = genMeanderShape ( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, m_dual ? m_baselineOffset : 0); + + if (m_dual) + m_shapes[1] = genMeanderShape ( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, -m_baselineOffset ); + + updateBaseSegment(); + +} + +void PNS_MEANDER_SHAPE::Resize ( int aAmpl ) +{ + if(aAmpl < 0) + return; + + m_amplitude = aAmpl; + + Recalculate(); +} + +void PNS_MEANDER_SHAPE::MakeEmpty() +{ + updateBaseSegment(); + + VECTOR2I dir = m_clippedBaseSeg.B - m_clippedBaseSeg.A; + + m_type = MT_EMPTY; + + m_shapes[0] = genMeanderShape ( m_p0, dir, m_side, m_type, 0, m_dual ? m_baselineOffset : 0); + + if(m_dual) + m_shapes[1] = genMeanderShape ( m_p0, dir, m_side, m_type, 0, -m_baselineOffset ); + + +} + + +void PNS_MEANDERED_LINE::AddCorner ( const VECTOR2I& aA, const VECTOR2I& aB ) +{ + PNS_MEANDER_SHAPE *m = new PNS_MEANDER_SHAPE ( m_placer, m_width, m_dual ); + + m->MakeCorner ( aA, aB ); + m_last = aA; + + m_meanders.push_back( m ); +} + +void PNS_MEANDER_SHAPE::MakeCorner ( VECTOR2I aP1, VECTOR2I aP2 ) +{ + SetType( MT_CORNER ); + m_shapes[ 0 ].Clear( ); + m_shapes[ 1 ].Clear( ); + m_shapes[ 0 ].Append( aP1 ); + m_shapes[ 1 ].Append( aP2 ); + m_clippedBaseSeg.A = aP1; + m_clippedBaseSeg.B = aP1; + +} + +void PNS_MEANDERED_LINE::AddMeander ( PNS_MEANDER_SHAPE *aShape ) +{ + m_last = aShape->BaseSegment( ).B; + m_meanders.push_back( aShape ); +} + + +void PNS_MEANDERED_LINE::Clear( ) +{ + BOOST_FOREACH( PNS_MEANDER_SHAPE *m, m_meanders ) + { + delete m; + } + + m_meanders.clear( ); +} + +int PNS_MEANDER_SHAPE::BaselineLength( ) const +{ + return m_clippedBaseSeg.Length( ); +} + +int PNS_MEANDER_SHAPE::MaxTunableLength( ) const +{ + return CLine( 0 ).Length( ); +} + +void PNS_MEANDER_SHAPE::updateBaseSegment( ) +{ + if( m_dual ) + { + VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2; + VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2; + + m_clippedBaseSeg.A = m_baseSeg.LineProject( midpA ); + m_clippedBaseSeg.B = m_baseSeg.LineProject( midpB ); + } else { + m_clippedBaseSeg.A = m_baseSeg.LineProject( CLine( 0 ).CPoint( 0 ) ); + m_clippedBaseSeg.B = m_baseSeg.LineProject( CLine( 0 ).CPoint( -1 ) ); + } +} diff --git a/pcbnew/router/pns_meander.h b/pcbnew/router/pns_meander.h new file mode 100644 index 0000000000..0abcbaaa13 --- /dev/null +++ b/pcbnew/router/pns_meander.h @@ -0,0 +1,498 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_MEANDER_H +#define __PNS_MEANDER_H + +#include + +#include +#include + +class PNS_MEANDER_PLACER_BASE; + +///< Shapes of available meanders +enum PNS_MEANDER_TYPE { + MT_SINGLE, // _|^|_, single-sided + MT_START, // _|^| + MT_FINISH, // |^|_ + MT_TURN, // |^| or |_| + MT_CHECK_START, // try fitting a start type, but don't produce a line + MT_CHECK_FINISH, // try fitting a finish type, but don't produce a line + MT_CORNER, // line corner + MT_EMPTY // no meander (straight line) +}; + +/** + * Class PNS_MEANDER_SETTINGS + * + * Holds dimensions for the meandering algorithm. + */ +class PNS_MEANDER_SETTINGS +{ +public: + + ///> meander corner shape + enum CornerType { + ROUND = 1, // rounded (90 degree arc) + CHAMFER // chamfered (45 degree segment) + }; + + PNS_MEANDER_SETTINGS () + { + m_minAmplitude = 100000; + m_maxAmplitude = 1000000; + m_step = 50000; + m_spacing = 600000; + m_targetLength = 100000000; + m_targetSkew = 0; + m_cornerType = ROUND; + m_cornerRadiusPercentage = 100; + m_lengthTollerance = 100000; + m_cornerArcSegments = 8; + } + + ///> minimum meandering amplitude + int m_minAmplitude; + ///> maximum meandering amplitude + int m_maxAmplitude; + ///> meandering period/spacing (see dialog picture for explanation) + int m_spacing; + ///> amplitude/spacing adjustment step + int m_step; + ///> desired length of the tuned line/diff pair + int m_targetLength; + ///> type of corners for the meandered line + CornerType m_cornerType; + ///> rounding percentage (0 - 100) + int m_cornerRadiusPercentage; + ///> allowable tuning error + int m_lengthTollerance; + ///> number of line segments for arc approximation + int m_cornerArcSegments; + ///> target skew value for diff pair de-skewing + int m_targetSkew; +}; + +class PNS_MEANDERED_LINE; + +/** + * Class PNS_MEANDER_SETTINGS + * + * Holds the geometry of a single meander. + */ +class PNS_MEANDER_SHAPE +{ + public: + + /** + * Constructor + * + * @param aPlacer the meander placer instance + * @param aWidth width of the meandered line + * @param aIsDual when true, the shape contains two meandered + * lines at a given offset (diff pairs) + */ + PNS_MEANDER_SHAPE( PNS_MEANDER_PLACER_BASE *aPlacer, int aWidth, bool aIsDual = false ) : + m_placer( aPlacer ), + m_dual( aIsDual ), + m_width( aWidth ), + m_baselineOffset( 0 ) + { + + } + + /** + * Function SetType() + * + * Sets the type of the meander. + */ + void SetType( PNS_MEANDER_TYPE aType ) + { + m_type = aType; + } + + /** + * Function Type() + * + * @return the type of the meander. + */ + PNS_MEANDER_TYPE Type( ) const + { + return m_type; + } + + /** + * Function SetBaseIndex() + * + * Sets an auxillary index of the segment being meandered in its original PNS_LINE. + */ + void SetBaseIndex( int aIndex ) + { + m_baseIndex = aIndex; + } + + /** + * Function BaseIndex() + * + * @return auxillary index of the segment being meandered in its original PNS_LINE. + */ + int BaseIndex( ) const + { + return m_baseIndex; + } + + /** + * Function Amplitude() + * + * @return the amplitude of the meander shape. + */ + int Amplitude( ) const + { + return m_amplitude; + } + + /** + * Function MakeCorner() + * + * Creates a dummy meander shape representing a line corner. Used to define + * the starts/ends of meandered segments. + * @param aP1 corner point of the 1st line + * @param aP2 corner point of the 2nd line (if m_dual == true) + */ + void MakeCorner( VECTOR2I aP1, VECTOR2I aP2 = VECTOR2I ( 0, 0 ) ); + + /** + * Function Resize() + * + * Changes the amplitude of the meander shape to aAmpl and recalculates + * the resulting line chain. + * @param aAmpl new amplitude. + */ + void Resize( int aAmpl ); + + /** + * Function Recalculate() + * + * Recalculates the line chain representing the meanders's shape. + */ + void Recalculate ( ); + + /** + * Function IsDual() + * + * @return true if the shape represents 2 parallel lines (diff pair). + */ + bool IsDual( ) const + { + return m_dual; + } + + /** + * Function Side() + * + * @return true if the meander is to the right of its base segment. + */ + bool Side( ) const + { + return m_side; + } + + /** + * Function End() + * + * @return end vertex of the base segment of the meander shape. + */ + VECTOR2I End( ) const + { + return m_clippedBaseSeg.B; + } + + /** + * Function CLine() + * + * @return the line chain representing the shape of the meander. + */ + const SHAPE_LINE_CHAIN& CLine( int aShape ) const + { + return m_shapes[ aShape ]; + } + + /** + * Function MakeEmpty() + * + * Replaces the meander with straight bypass line(s), effectively + * clearing it. + */ + void MakeEmpty( ); + + /** + * Function Fit() + * + * Attempts to fit a meander of a given type onto a segment, avoiding + * collisions with other board features. + * @param aType type of meander shape + * @param aSeg base segment for meandering + * @param aP start point of the meander + * @param aSide side of aSeg to put the meander on (true = right) + * @return true on success. + */ + bool Fit( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ); + + /** + * Function BaseSegment() + * + * Returns the base segment the meadner was fitted to. + * @return the base segment. + */ + const SEG& BaseSegment( ) const + { + return m_clippedBaseSeg; + } + + /** + * Function BaselineLength() + * + * @return length of the base segment for the meander (i.e. + * the minimim tuned length. + */ + int BaselineLength( ) const; + + /** + * Function MaxTunableLength() + * + * @return the length of the fitted line chain. + */ + int MaxTunableLength( ) const; + + /** + * Function Settings() + * + * @return the current meandering settings. + */ + const PNS_MEANDER_SETTINGS& Settings( ) const; + + /** + * Function Width() + * + * @return width of the meandered line. + */ + int Width() const + { + return m_width; + } + + /** + * Function SetBaselineOffset() + * + * Sets the parallel offset between the base segment and the meandered + * line. Used for dual menaders (diff pair) only. + * @param aOffset the offset + */ + void SetBaselineOffset ( int aOffset ) + { + m_baselineOffset = aOffset; + } + + private: + friend class PNS_MEANDERED_LINE; + + ///> starts turtle drawing + void start ( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir ); + ///> moves turtle forward by aLength + void forward ( int aLength ); + ///> turns the turtle by aAngle + void turn ( int aAngle ); + ///> tells the turtle to draw an arc of given radius and turn direction + void arc ( int aRadius, bool aSide ); + ///> tells the turtle to draw an U-like shape + void uShape ( int aSides, int aCorner, int aTop ); + + ///> generates a 90-degree circular arc + SHAPE_LINE_CHAIN circleQuad ( VECTOR2D aP, VECTOR2D aDir, bool side ); + + ///> reflects a point onto other side of a given segment + VECTOR2I reflect ( VECTOR2I p, const SEG& line ); + + ///> produces a meander shape of given type + SHAPE_LINE_CHAIN genMeanderShape ( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset = 0); + + ///> recalculates the clipped baseline after the parameters of + ///> the meander have been changed. + void updateBaseSegment(); + + ///> returns sanitized corner radius value + int cornerRadius ( ) const; + + ///> returns sanitized spacing value + int spacing ( ) const; + + ///> the type + PNS_MEANDER_TYPE m_type; + ///> the placer that placed this meander + PNS_MEANDER_PLACER_BASE *m_placer; + ///> dual or single line + bool m_dual; + ///> width of the line + int m_width; + ///> amplitude of the meander + int m_amplitude; + ///> offset wrs the base segment (dual only) + int m_baselineOffset; + ///> first point of the meandered line + VECTOR2I m_p0; + ///> base segment (unclipped) + SEG m_baseSeg; + ///> base segment (clipped) + SEG m_clippedBaseSeg; + ///> side (true = right) + bool m_side; + ///> the actual shapes (0 used for single, both for dual) + SHAPE_LINE_CHAIN m_shapes[2]; + ///> index of the meandered segment in the base line + int m_baseIndex; + ///> current turtle direction + VECTOR2D m_currentDir; + ///> current turtle position + VECTOR2D m_currentPos; + ///> the line the turtle is drawing on + SHAPE_LINE_CHAIN* m_currentTarget; +}; + + +/** + * Class PNS_MEANDERED_LINE + * + * Represents a set of meanders fitted over a single or two lines. + */ +class PNS_MEANDERED_LINE +{ + public: + PNS_MEANDERED_LINE( ) + { + + } + + /** + * Constructor + * + * @param aPlacer the meander placer instance + * @param aIsDual when true, the meanders are generated for two coupled lines + */ + PNS_MEANDERED_LINE( PNS_MEANDER_PLACER_BASE *aPlacer, bool aIsDual = false ) : + m_placer( aPlacer ), + m_dual( aIsDual ) + { + + } + + /** + * Function AddCorner() + * + * Creates a dummy meander shape representing a line corner. Used to define + * the starts/ends of meandered segments. + * @param aA corner point of the 1st line + * @param aB corner point of the 2nd line (if m_dual == true) + */ + void AddCorner( const VECTOR2I& aA, const VECTOR2I& aB = VECTOR2I( 0, 0 ) ); + + /** + * Function AddMeander() + * + * Adds a new meander shape the the meandered line. + * @param aShape the meander shape to add + */ + void AddMeander( PNS_MEANDER_SHAPE *aShape ); + + /** + * Function Clear() + * + * Clears the line geometry, removing all corners and meanders. + */ + void Clear( ); + + /** + * Function SetWidth() + * + * Sets the line width. + */ + void SetWidth( int aWidth ) + { + m_width = aWidth; + } + + /** + * Function MeanderSegment() + * + * Fits maximum amplitude meanders on a given segment and adds to the + * current line. + * @param aSeg the base segment to meander + * @param aBaseIndex index of the base segment in the original line + */ + void MeanderSegment( const SEG& aSeg, int aBaseIndex = 0 ); + + /// @copydoc PNS_MEANDER_SHAPE::SetBaselineOffset() + void SetBaselineOffset( int aOffset ) + { + m_baselineOffset = aOffset; + } + + /** + * Function Meanders() + * + * @return set of meander shapes for this line + */ + std::vector & Meanders() + { + return m_meanders; + } + + + /** + * Function CheckSelfIntersections() + * + * Checks if the given shape is intersecting with any other meander in + * the current line. + * @param aShape the shape to check + * @param aClearance clearance value + * @return true, if the meander shape is not colliding + */ + bool CheckSelfIntersections ( PNS_MEANDER_SHAPE *aShape, int aClearance ); + + /** + * Function Settings() + * + * @return the current meandering settings. + */ + const PNS_MEANDER_SETTINGS& Settings() const; + + private: + + VECTOR2I m_last; + + PNS_MEANDER_PLACER_BASE *m_placer; + std::vector m_meanders; + + bool m_dual; + int m_width; + int m_baselineOffset; +}; + +#endif // __PNS_MEANDER_H diff --git a/pcbnew/router/pns_meander_placer.cpp b/pcbnew/router/pns_meander_placer.cpp new file mode 100644 index 0000000000..e0875309d1 --- /dev/null +++ b/pcbnew/router/pns_meander_placer.cpp @@ -0,0 +1,262 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 // God forgive me doing this... +#include + +#include "trace.h" + +#include "pns_node.h" +#include "pns_itemset.h" +#include "pns_topology.h" +#include "pns_meander_placer.h" +#include "pns_router.h" + + +PNS_MEANDER_PLACER::PNS_MEANDER_PLACER( PNS_ROUTER* aRouter ) : + PNS_MEANDER_PLACER_BASE ( aRouter ) +{ + m_world = NULL; + m_currentNode = NULL; + m_originLine = NULL; +} + + +PNS_MEANDER_PLACER::~PNS_MEANDER_PLACER( ) +{ + +} + +PNS_NODE* PNS_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const +{ + if( !m_currentNode ) + return m_world; + + return m_currentNode; +} + +bool PNS_MEANDER_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + VECTOR2I p; + + if( !aStartItem || !aStartItem->OfKind( PNS_ITEM::SEGMENT ) ) + { + Router( )->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); + return false; + } + + m_initialSegment = static_cast( aStartItem ); + + p = m_initialSegment->Seg( ).NearestPoint( aP ); + + m_originLine = NULL; + m_currentNode = NULL; + m_currentStart = p; + + m_world = Router( )->GetWorld( )->Branch( ); + m_originLine = m_world->AssembleLine( m_initialSegment ); + + PNS_TOPOLOGY topo( m_world ); + m_tunedPath = topo.AssembleTrivialPath( m_initialSegment ); + + m_world->Remove( m_originLine ); + + m_currentWidth = m_originLine->Width( ); + m_currentEnd = VECTOR2I( 0, 0 ); + + return true; +} + + +int PNS_MEANDER_PLACER::origPathLength( ) const +{ + int total = 0; + BOOST_FOREACH( const PNS_ITEM *item, m_tunedPath.CItems( ) ) + { + if( const PNS_LINE *l = dyn_cast( item ) ) + { + total += l->CLine( ).Length( ); + } + } + + return total; +} + +bool PNS_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + return doMove ( aP, aEndItem, m_settings.m_targetLength ); +} + +bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTargetLength ) +{ + SHAPE_LINE_CHAIN pre, tuned, post; + + if(m_currentNode) + delete m_currentNode; + + m_currentNode = m_world->Branch( ); + + cutTunedLine ( m_originLine->CLine( ), m_currentStart, aP, pre, tuned, post ); + + m_result = PNS_MEANDERED_LINE( this, false ); + m_result.SetWidth( m_originLine->Width() ); + m_result.SetBaselineOffset( 0 ); + + for( int i = 0; i < tuned.SegmentCount(); i++ ) + { + const SEG s = tuned.CSegment( i ); + m_result.AddCorner( s.A ); + m_result.MeanderSegment( s ); + m_result.AddCorner( s.B ); + } + + int lineLen = origPathLength( ); + + m_lastLength = lineLen; + m_lastStatus = TUNED; + + if( compareWithTollerance ( lineLen, aTargetLength, m_settings.m_lengthTollerance ) > 0 ) + { + m_lastStatus = TOO_LONG; + } else { + m_lastLength = lineLen - tuned.Length( ); + tuneLineLength( m_result, aTargetLength - lineLen ); + } + + BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPath.CItems( ) ) + { + if ( const PNS_LINE *l = dyn_cast( item ) ) + { + Router( )->DisplayDebugLine( l->CLine( ), 5, 10000 ); + } + } + + if (m_lastStatus != TOO_LONG) + { + tuned.Clear( ); + + BOOST_FOREACH ( PNS_MEANDER_SHAPE *m, m_result.Meanders() ) + { + if( m->Type() != MT_EMPTY ) + { + tuned.Append ( m->CLine(0) ); + } + } + + m_lastLength += tuned.Length( ); + + int comp = compareWithTollerance( m_lastLength - aTargetLength, 0, m_settings.m_lengthTollerance ); + + if( comp > 0 ) + m_lastStatus = TOO_LONG; + else if( comp < 0 ) + m_lastStatus = TOO_SHORT; + else + m_lastStatus = TUNED; + + } + + m_finalShape.Clear( ); + m_finalShape.Append( pre ); + m_finalShape.Append( tuned ); + m_finalShape.Append( post ); + m_finalShape.Simplify( ); + + return true; +} + + +bool PNS_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + m_currentTrace = PNS_LINE( *m_originLine, m_finalShape ); + m_currentNode->Add ( &m_currentTrace ); + + Router( )->CommitRouting( m_currentNode ); + return true; +} + +bool PNS_MEANDER_PLACER::CheckFit( PNS_MEANDER_SHAPE *aShape ) +{ + PNS_LINE l( *m_originLine, aShape->CLine( 0 ) ); + + if( m_currentNode->CheckColliding( &l ) ) + return false; + + int w = aShape->Width( ); + int clearance = w + m_settings.m_spacing; + + return m_result.CheckSelfIntersections( aShape, clearance ); +} + + +const PNS_ITEMSET PNS_MEANDER_PLACER::Traces() +{ + m_currentTrace = PNS_LINE( *m_originLine, m_finalShape ); + return PNS_ITEMSET( &m_currentTrace ); +} + +const VECTOR2I& PNS_MEANDER_PLACER::CurrentEnd() const +{ + return m_currentEnd; +} + +int PNS_MEANDER_PLACER::CurrentNet() const +{ + return m_initialSegment->Net( ); +} + +int PNS_MEANDER_PLACER::CurrentLayer() const +{ + return m_initialSegment->Layers( ).Start( ); +} + + +const wxString PNS_MEANDER_PLACER::TuningInfo( ) const +{ + wxString status; + + switch ( m_lastStatus ) + { + case TOO_LONG: + status = _( "Too long: " ); + break; + case TOO_SHORT: + status = _(" Too short: " ); + break; + case TUNED: + status = _(" Tuned: " ); + break; + default: + return _( "?" ); + } + + status += LengthDoubleToString( (double) m_lastLength, false ); + status += "/"; + status += LengthDoubleToString( (double) m_settings.m_targetLength, false ); + + return status; +} + +PNS_MEANDER_PLACER::TUNING_STATUS PNS_MEANDER_PLACER::TuningStatus( ) const +{ + return m_lastStatus; +} diff --git a/pcbnew/router/pns_meander_placer.h b/pcbnew/router/pns_meander_placer.h new file mode 100644 index 0000000000..98c6670629 --- /dev/null +++ b/pcbnew/router/pns_meander_placer.h @@ -0,0 +1,115 @@ +/* + * 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_MEANDER_PLACER_H +#define __PNS_MEANDER_PLACER_H + +#include + +#include +#include + +#include "pns_node.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_placement_algo.h" +#include "pns_meander.h" +#include "pns_meander_placer_base.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; + +/** + * Class PNS_MEANDER_PLACER + * + * Single track length matching/meandering tool. + */ +class PNS_MEANDER_PLACER : public PNS_MEANDER_PLACER_BASE +{ +public: + + PNS_MEANDER_PLACER( PNS_ROUTER* aRouter ); + virtual ~PNS_MEANDER_PLACER(); + + /// @copydoc PNS_PLACEMENT_ALGO::Start() + virtual bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + + /// @copydoc PNS_PLACEMENT_ALGO::Move() + virtual bool Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + + /// @copydoc PNS_PLACEMENT_ALGO::FixRoute() + virtual bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + + /// @copydoc PNS_PLACEMENT_ALGO::CurrentNode() + PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const; + + /// @copydoc PNS_PLACEMENT_ALGO::Traces() + const PNS_ITEMSET Traces(); + + /// @copydoc PNS_PLACEMENT_ALGO::CurrentEnd() + const VECTOR2I& CurrentEnd() const; + + /// @copydoc PNS_PLACEMENT_ALGO::CurrentNet() + int CurrentNet() const; + + /// @copydoc PNS_PLACEMENT_ALGO::CurrentLayer() + int CurrentLayer() const; + + /// @copydoc PNS_MEANDER_PLACER_BASE::TuningInfo() + virtual const wxString TuningInfo() const; + + /// @copydoc PNS_MEANDER_PLACER_BASE::TuningStatus() + virtual TUNING_STATUS TuningStatus() const; + + /// @copydoc PNS_MEANDER_PLACER_BASE::CheckFit() + bool CheckFit ( PNS_MEANDER_SHAPE* aShape ); + +protected: + + bool doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTargetLength ); + + void setWorld ( PNS_NODE* aWorld ); + + virtual int origPathLength () const; + + ///> pointer to world to search colliding items + PNS_NODE* m_world; + + ///> current routing start point (end of tail, beginning of head) + VECTOR2I m_currentStart; + + ///> Current world state + PNS_NODE* m_currentNode; + + PNS_LINE* m_originLine; + PNS_LINE m_currentTrace; + PNS_ITEMSET m_tunedPath; + + SHAPE_LINE_CHAIN m_finalShape; + PNS_MEANDERED_LINE m_result; + PNS_SEGMENT *m_initialSegment; + + int m_lastLength; + TUNING_STATUS m_lastStatus; +}; + +#endif // __PNS_MEANDER_PLACER_H diff --git a/pcbnew/router/pns_meander_placer_base.cpp b/pcbnew/router/pns_meander_placer_base.cpp new file mode 100644 index 0000000000..c35204a9d6 --- /dev/null +++ b/pcbnew/router/pns_meander_placer_base.cpp @@ -0,0 +1,167 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_router.h" +#include "pns_meander.h" +#include "pns_meander_placer_base.h" + +PNS_MEANDER_PLACER_BASE::PNS_MEANDER_PLACER_BASE( PNS_ROUTER* aRouter ) : + PNS_PLACEMENT_ALGO( aRouter ) +{ + +}; + +PNS_MEANDER_PLACER_BASE::~PNS_MEANDER_PLACER_BASE( ) +{ + +}; + +void PNS_MEANDER_PLACER_BASE::AmplitudeStep( int aSign ) +{ + int a = m_settings.m_maxAmplitude + aSign * m_settings.m_step; + a = std::max( a, m_settings.m_minAmplitude ); + + m_settings.m_maxAmplitude = a; +} + +void PNS_MEANDER_PLACER_BASE::SpacingStep( int aSign ) +{ + int s = m_settings.m_spacing + aSign * m_settings.m_step; + s = std::max( s, 2 * m_currentWidth ); + + m_settings.m_spacing = s; +} + +void PNS_MEANDER_PLACER_BASE::UpdateSettings( const PNS_MEANDER_SETTINGS& aSettings ) +{ + m_settings = aSettings; +} + +void PNS_MEANDER_PLACER_BASE::cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, + const VECTOR2I& aTuneStart, + const VECTOR2I& aCursorPos, + SHAPE_LINE_CHAIN& aPre, + SHAPE_LINE_CHAIN& aTuned, + SHAPE_LINE_CHAIN& aPost ) +{ + VECTOR2I n = aOrigin.NearestPoint( aCursorPos ); + VECTOR2I m = aOrigin.NearestPoint( aTuneStart ); + + SHAPE_LINE_CHAIN l( aOrigin ); + l.Split( n ); + l.Split( m ); + + int i_start = l.Find( m ); + int i_end = l.Find( n ); + + if( i_start > i_end ) + { + l = l.Reverse( ); + i_start = l.Find( m ); + i_end = l.Find( n ); + } + + aPre = l.Slice( 0, i_start ); + aPost = l.Slice( i_end, -1 ); + aTuned = l.Slice( i_start, i_end ); + aTuned.Simplify( ); +} + +void PNS_MEANDER_PLACER_BASE::tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aElongation ) +{ + int remaining = aElongation; + bool finished = false; + + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + if(m->Type() != MT_CORNER ) + { + if(remaining >= 0) + remaining -= m->MaxTunableLength() - m->BaselineLength(); + + if(remaining < 0) + { + if(!finished) + { + PNS_MEANDER_TYPE newType; + + if ( m->Type() == MT_START || m->Type() == MT_SINGLE) + newType = MT_SINGLE; + else + newType = MT_FINISH; + + m->SetType ( newType ); + m->Recalculate( ); + + finished = true; + } else { + m->MakeEmpty(); + } + } + } + } + + remaining = aElongation; + int meanderCount = 0; + + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + if( m->Type() != MT_CORNER && m->Type() != MT_EMPTY ) + { + if(remaining >= 0) + { + remaining -= m->MaxTunableLength() - m->BaselineLength(); + meanderCount ++; + } + } + } + + int balance = 0; + + if( meanderCount ) + balance = -remaining / meanderCount; + + if (balance >= 0) + { + BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + { + if(m->Type() != MT_CORNER && m->Type() != MT_EMPTY) + { + m->Resize ( std::max( m->Amplitude() - balance / 2, m_settings.m_minAmplitude ) ); + } + } + + } +} + +const PNS_MEANDER_SETTINGS& PNS_MEANDER_PLACER_BASE::MeanderSettings( ) const +{ + return m_settings; +} + +int PNS_MEANDER_PLACER_BASE::compareWithTollerance ( int aValue, int aExpected, int aTollerance ) const +{ + if( aValue < aExpected - aTollerance ) + return -1; + else if( aValue > aExpected + aTollerance ) + return 1; + else + return 0; +} \ No newline at end of file diff --git a/pcbnew/router/pns_meander_placer_base.h b/pcbnew/router/pns_meander_placer_base.h new file mode 100644 index 0000000000..ac94b97a67 --- /dev/null +++ b/pcbnew/router/pns_meander_placer_base.h @@ -0,0 +1,167 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_MEANDER_PLACER_BASE_H +#define __PNS_MEANDER_PLACER_BASE_H + +#include + +#include +#include + +#include "pns_node.h" +#include "pns_via.h" +#include "pns_line.h" +#include "pns_placement_algo.h" +#include "pns_meander.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; + +/** + * Class PNS_MEANDER_PLACER_BASE + * + * Base class for Single trace & Differenial pair meandering tools, as + * both of them share a lot of code. + */ +class PNS_MEANDER_PLACER_BASE : public PNS_PLACEMENT_ALGO +{ +public: + ///> Result of the length tuning operation + enum TUNING_STATUS { + TOO_SHORT = 0, + TOO_LONG, + TUNED + }; + + PNS_MEANDER_PLACER_BASE( PNS_ROUTER* aRouter ); + virtual ~PNS_MEANDER_PLACER_BASE( ); + + /** + * Function TuningInfo() + * + * Returns a string describing the status and length of the + * tuned traces. + */ + virtual const wxString TuningInfo( ) const = 0; + + /** + * Function TuningStatus() + * + * Returns the tuning status (too short, too long, etc.) + * of the trace(s) being tuned. + */ + virtual TUNING_STATUS TuningStatus( ) const = 0; + + /** + * Function AmplitudeStep() + * + * Increases/decreases the current meandering amplitude by one step. + * @param aSign direction (negative = decrease, positive = increase). + */ + virtual void AmplitudeStep( int aSign ); + + /** + * Function SpacingStep() + * + * Increases/decreases the current meandering spcing by one step. + * @param aSign direction (negative = decrease, positive = increase). + */ + virtual void SpacingStep( int aSign ); + + /** + * Function MeanderSettings() + * + * Returns the current meandering configuration. + * @return the settings + */ + virtual const PNS_MEANDER_SETTINGS& MeanderSettings() const; + + /* + * Function UpdateSettings() + * + * Sets the current meandering configuration. + * @param aSettings the settings + */ + virtual void UpdateSettings( const PNS_MEANDER_SETTINGS& aSettings); + + /** + * Function CheckFit() + * + * Checks if it's ok to place the shape aShape (i.e. + * if it doesn't cause DRC violations or collide with + * other meanders). + * @param aShape the shape to check + * @return true if the shape fits + */ + virtual bool CheckFit ( PNS_MEANDER_SHAPE* aShape ) + { + return false; + } + + + +protected: + + /** + * Function cutTunedLine() + * + * Extracts the part of a track to be meandered, depending on the + * starting point and the cursor position. + * @param aOrigin the original line + * @param aTuneStart point where we start meandering (start click coorinates) + * @param aCursorPos current cursor position + * @param aPre part before the beginning of meanders + * @param aTuned part to be meandered + * @param aPost part after the end of meanders + */ + void cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, + const VECTOR2I& aTuneStart, + const VECTOR2I& aCursorPos, + SHAPE_LINE_CHAIN& aPre, + SHAPE_LINE_CHAIN& aTuned, + SHAPE_LINE_CHAIN& aPost ); + + /** + * Function tuneLineLength() + * + * Takes a set of meanders in aTuned and tunes their length to + * extend the original line length by aElongation. + */ + void tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aElongation ); + + /** + * Function compareWithTollerance() + * + * Compares aValue against aExpected with given tollerance. + */ + int compareWithTollerance ( int aValue, int aExpected, int aTollerance = 0 ) const; + + ///> width of the meandered trace(s) + int m_currentWidth; + ///> meandering settings + PNS_MEANDER_SETTINGS m_settings; + ///> current end point + VECTOR2I m_currentEnd; +}; + +#endif // __PNS_MEANDER_PLACER_BASE_H diff --git a/pcbnew/router/pns_meander_skew_placer.cpp b/pcbnew/router/pns_meander_skew_placer.cpp new file mode 100644 index 0000000000..5904dcd07d --- /dev/null +++ b/pcbnew/router/pns_meander_skew_placer.cpp @@ -0,0 +1,157 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 // God forgive me doing this... +#include + +#include "trace.h" + +#include "pns_node.h" +#include "pns_itemset.h" +#include "pns_topology.h" +#include "pns_meander_skew_placer.h" + +#include "pns_router.h" + + +PNS_MEANDER_SKEW_PLACER::PNS_MEANDER_SKEW_PLACER ( PNS_ROUTER* aRouter ) : + PNS_MEANDER_PLACER ( aRouter ) +{ +} + +PNS_MEANDER_SKEW_PLACER::~PNS_MEANDER_SKEW_PLACER( ) +{ + +} + +bool PNS_MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) +{ + VECTOR2I p; + + if( !aStartItem || !aStartItem->OfKind( PNS_ITEM::SEGMENT ) ) + { + Router( )->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) ); + return false; + } + + m_initialSegment = static_cast( aStartItem ); + + p = m_initialSegment->Seg( ).NearestPoint( aP ); + + m_originLine = NULL; + m_currentNode = NULL; + m_currentStart = p; + + m_world = Router( )->GetWorld( )->Branch( ); + m_originLine = m_world->AssembleLine( m_initialSegment ); + + PNS_TOPOLOGY topo( m_world ); + m_tunedPath = topo.AssembleTrivialPath( m_initialSegment ); + + if( !topo.AssembleDiffPair ( m_initialSegment, m_originPair ) ) + { + Router()->SetFailureReason( _( "Unable to find complementary differential pair " + "net for skew tuning. Make sure the names of the nets belonging " + "to a differential pair end with either _N/_P or +/-." ) ); + return false; + } + + + m_originPair.SetGap ( Router()->Sizes().DiffPairGap() ); + + if( !m_originPair.PLine().SegmentCount() || + !m_originPair.NLine().SegmentCount() ) + return false; + + m_tunedPathP = topo.AssembleTrivialPath ( m_originPair.PLine().GetLink(0) ); + m_tunedPathN = topo.AssembleTrivialPath ( m_originPair.NLine().GetLink(0) ); + + m_world->Remove( m_originLine ); + + m_currentWidth = m_originLine->Width( ); + m_currentEnd = VECTOR2I( 0, 0 ); + + if ( m_originPair.PLine().Net () == m_originLine->Net() ) + m_coupledLength = itemsetLength ( m_tunedPathN ); + else + m_coupledLength = itemsetLength ( m_tunedPathP ); + + return true; +} + + +int PNS_MEANDER_SKEW_PLACER::origPathLength( ) const +{ + return itemsetLength ( m_tunedPath ); +} + +int PNS_MEANDER_SKEW_PLACER::itemsetLength( const PNS_ITEMSET& aSet ) const +{ + int total = 0; + BOOST_FOREACH( const PNS_ITEM *item, aSet.CItems( ) ) + { + if( const PNS_LINE *l = dyn_cast( item ) ) + { + total += l->CLine( ).Length( ); + } + } + + return total; +} + +int PNS_MEANDER_SKEW_PLACER::currentSkew () const +{ + return m_lastLength - m_coupledLength; +} + +bool PNS_MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + return doMove ( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew ); +} + + +const wxString PNS_MEANDER_SKEW_PLACER::TuningInfo( ) const +{ + wxString status; + + switch ( m_lastStatus ) + { + case TOO_LONG: + status = _( "Too long: skew " ); + break; + case TOO_SHORT: + status = _(" Too short: skew " ); + break; + case TUNED: + status = _(" Tuned: skew " ); + break; + default: + return _( "?" ); + } + + status += LengthDoubleToString( (double) m_lastLength - m_coupledLength, false ); + status += "/"; + status += LengthDoubleToString( (double) m_settings.m_targetSkew, false ); + + return status; +} + diff --git a/pcbnew/router/pns_meander_skew_placer.h b/pcbnew/router/pns_meander_skew_placer.h new file mode 100644 index 0000000000..a7f3a90773 --- /dev/null +++ b/pcbnew/router/pns_meander_skew_placer.h @@ -0,0 +1,66 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_MEANDER_SKEW_PLACER_H +#define __PNS_MEANDER_SKEW_PLACER_H + +#include "pns_meander_placer.h" +#include "pns_diff_pair.h" + +class PNS_ROUTER; +class PNS_SHOVE; +class PNS_OPTIMIZER; +class PNS_ROUTER_BASE; + +/** + * Class PNS_MEANDER_SKEW_PLACER + * + * Differential pair skew adjustment algorithm. + */ +class PNS_MEANDER_SKEW_PLACER : public PNS_MEANDER_PLACER +{ +public: + + PNS_MEANDER_SKEW_PLACER( PNS_ROUTER* aRouter ); + ~PNS_MEANDER_SKEW_PLACER(); + + /// @copydoc PNS_PLACEMENT_ALGO::Start() + bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ); + + /// @copydoc PNS_PLACEMENT_ALGO::Move() + bool Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ); + + /// @copydoc PNS_MEANDER_PLACER_BASE::TuningInfo() + const wxString TuningInfo() const; + +private: + + int currentSkew( ) const; + int itemsetLength( const PNS_ITEMSET& aSet ) const; + + int origPathLength () const; + + PNS_DIFF_PAIR m_originPair; + PNS_ITEMSET m_tunedPath, m_tunedPathP, m_tunedPathN; + + int m_coupledLength; +}; + +#endif // __PNS_MEANDER_SKEW_PLACER_H diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 8ee7feeb3d..a553871d7f 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -53,6 +53,7 @@ PNS_NODE::PNS_NODE() m_parent = NULL; m_maxClearance = 800000; // fixme: depends on how thick traces are. m_index = new PNS_INDEX; + m_collisionFilter = NULL; #ifdef DEBUG allocNodes.insert( this ); @@ -109,6 +110,7 @@ PNS_NODE* PNS_NODE::Branch() child->m_parent = this; child->m_clearanceFunctor = m_clearanceFunctor; child->m_root = isRoot() ? this : m_root; + child->m_collisionFilter = m_collisionFilter; // immmediate offspring of the root branch needs not copy anything. // For the rest, deep-copy joints, overridden item map and pointers @@ -211,6 +213,9 @@ struct PNS_NODE::OBSTACLE_VISITOR int clearance = m_extraClearance + m_node->GetClearance( aItem, m_item ); + if( m_node->m_collisionFilter && (*m_node->m_collisionFilter)(aItem, m_item)) + return true; + if( aItem->Kind() == PNS_ITEM::LINE ) clearance += static_cast(aItem)->Width() / 2; @@ -220,6 +225,7 @@ struct PNS_NODE::OBSTACLE_VISITOR PNS_OBSTACLE obs; obs.m_item = aItem; + obs.m_head = m_item; m_tab.push_back( obs ); m_matchCount++; @@ -414,10 +420,14 @@ PNS_NODE::OPT_OBSTACLE PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKi } -bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, int aKindMask ) +bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, int aKindMask, int aForceClearance ) { assert( aItemB ); - int clearance = GetClearance( aItemA, aItemB ); + int clearance; + if( aForceClearance >= 0 ) + clearance = aForceClearance; + else + clearance = GetClearance( aItemA, aItemB ); // fixme: refactor if( aItemA->Kind() == PNS_ITEM::LINE ) @@ -713,6 +723,11 @@ void PNS_NODE::Remove( PNS_ITEM* aItem ) } } +void PNS_NODE::Remove ( PNS_LINE& aLine ) +{ + removeLine ( &aLine ); +} + void PNS_NODE::followLine( PNS_SEGMENT* aCurrent, bool aScanDirection, int& aPos, int aLimit, VECTOR2I* aCorners, PNS_SEGMENT** aSegments, bool& aGuardHit ) @@ -755,7 +770,7 @@ void PNS_NODE::followLine( PNS_SEGMENT* aCurrent, bool aScanDirection, int& aPos PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex) { - const int MaxVerts = 1024; + const int MaxVerts = 1024 * 16; VECTOR2I corners[MaxVerts + 1]; PNS_SEGMENT* segs[MaxVerts + 1]; @@ -812,6 +827,7 @@ void PNS_NODE::FindLineEnds( PNS_LINE* aLine, PNS_JOINT& aA, PNS_JOINT& aB ) } +#if 0 void PNS_NODE::MapConnectivity ( PNS_JOINT* aStart, std::vector& aFoundJoints ) { std::deque searchQueue; @@ -846,51 +862,9 @@ void PNS_NODE::MapConnectivity ( PNS_JOINT* aStart, std::vector& aFo BOOST_FOREACH(PNS_JOINT* jt, processed) aFoundJoints.push_back( jt ); } +#endif -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 ) @@ -1192,13 +1166,13 @@ void PNS_NODE::AllItemsInNet( int aNet, std::set& aItems ) } -void PNS_NODE::ClearRanks() +void PNS_NODE::ClearRanks( int aMarkerMask ) { - for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) - { - (*i)->SetRank( -1 ); - (*i)->Mark( 0 ); - } + for( PNS_INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i ) + { + (*i)->SetRank( -1 ); + (*i)->Mark( (*i)->Marker() & (~aMarkerMask) ); + } } @@ -1262,3 +1236,8 @@ PNS_SEGMENT* PNS_NODE::findRedundantSegment ( PNS_SEGMENT *aSeg ) return NULL; } + +void PNS_NODE::SetCollisionFilter ( PNS_COLLISION_FILTER *aFilter ) +{ + m_collisionFilter = aFilter; +} diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index 13e1672f6a..eb7b8b503e 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -52,8 +52,28 @@ class PNS_INDEX; class PNS_CLEARANCE_FUNC { public: - virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) = 0; virtual ~PNS_CLEARANCE_FUNC() {} + virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) = 0; + virtual void OverrideClearance (bool aEnable, int aNetA = 0, int aNetB = 0, int aClearance = 0) = 0; + +}; + +class PNS_PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC +{ +public: + PNS_PCBNEW_CLEARANCE_FUNC( BOARD *aBoard ); + virtual ~PNS_PCBNEW_CLEARANCE_FUNC(); + + virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ); + virtual void OverrideClearance (bool aEnable, int aNetA = 0, int aNetB = 0, int aClearance = 0); + +private: + int localPadClearance( const PNS_ITEM* aItem ) const; + std::vector m_clearanceCache; + int m_defaultClearance; + bool m_overrideEnabled; + int m_overrideNetA, m_overrideNetB; + int m_overrideClearance; }; /** @@ -65,7 +85,7 @@ public: struct PNS_OBSTACLE { ///> Item we search collisions with - PNS_ITEM* m_head; + const PNS_ITEM* m_head; ///> Item found to be colliding with m_head PNS_ITEM* m_item; @@ -81,6 +101,15 @@ struct PNS_OBSTACLE int m_distFirst, m_distLast; }; +/** + * Struct PNS_COLLISION_FILTER + * Used to override the decision of the collision search algorithm whether two + * items collide. + **/ +struct PNS_COLLISION_FILTER { + virtual bool operator()( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB ) const = 0; +}; + /** * Class PNS_NODE * @@ -201,7 +230,8 @@ public: */ bool CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, - int aKindMask = PNS_ITEM::ANY ); + int aKindMask = PNS_ITEM::ANY, + int aForceClearance = -1 ); /** * Function HitTest() @@ -230,6 +260,15 @@ public: */ void Remove( PNS_ITEM* aItem ); + /** + * Function Remove() + * + * Just as the name says, removes a line from this branch. + * @param aItem item to remove + */ + void Remove( PNS_LINE& aLine ); + + /** * Function Replace() * @@ -296,16 +335,18 @@ public: * 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 ) + PNS_JOINT* FindJoint( const VECTOR2I& aPos, const PNS_ITEM* aItem ) { return FindJoint( aPos, aItem->Layers().Start(), aItem->Net() ); } +#if 0 void MapConnectivity( PNS_JOINT* aStart, std::vector & aFoundJoints ); PNS_ITEM* NearestUnconnectedItem( PNS_JOINT* aStart, int *aAnchor = NULL, int aKindMask = PNS_ITEM::ANY); +#endif ///> finds all lines between a pair of joints. Used by the loop removal procedure. int FindLinesBetweenJoints( PNS_JOINT& aA, @@ -320,10 +361,11 @@ public: void AllItemsInNet( int aNet, std::set& aItems ); - void ClearRanks(); + void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION ); int FindByMarker( int aMarker, PNS_ITEMSET& aItems ); int RemoveByMarker( int aMarker ); + void SetCollisionFilter ( PNS_COLLISION_FILTER *aFilter ); private: struct OBSTACLE_VISITOR; @@ -411,6 +453,9 @@ private: ///> depth of the node (number of parent nodes in the inheritance chain) int m_depth; + + ///> optional collision filtering object + PNS_COLLISION_FILTER *m_collisionFilter; }; #endif diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index 6451bca600..f6b6def28c 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -24,6 +24,7 @@ #include #include "pns_line.h" +#include "pns_diff_pair.h" #include "pns_node.h" #include "pns_optimizer.h" #include "pns_utils.h" @@ -121,6 +122,7 @@ PNS_OPTIMIZER::PNS_OPTIMIZER( PNS_NODE* aWorld ) : m_world( aWorld ), m_collisionKindMask( PNS_ITEM::ANY ), m_effortLevel( MERGE_SEGMENTS ) { // m_cache = new SHAPE_INDEX_LIST(); + m_restrictAreaActive = false; } @@ -222,6 +224,154 @@ void PNS_OPTIMIZER::ClearCache( bool aStaticOnly ) } } +class LINE_RESTRICTIONS +{ + public: + LINE_RESTRICTIONS( ) {}; + ~LINE_RESTRICTIONS( ) {}; + + void Build( PNS_NODE *aWorld, PNS_LINE *aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ); + bool Check ( int aVertex1, int aVertex2, const SHAPE_LINE_CHAIN& aReplacement ); + void Dump(); + + + private: + int allowedAngles ( PNS_NODE *aWorld, const PNS_LINE *aLine, const VECTOR2I& aP, bool aFirst ); + + struct RVERTEX + { + RVERTEX ( bool aRestricted, int aAllowedAngles ) : + restricted ( aRestricted ), + allowedAngles ( aAllowedAngles ) + { + + } + + bool restricted; + int allowedAngles; + }; + + std::vector m_rs; +}; + +// fixme: use later +int LINE_RESTRICTIONS::allowedAngles ( PNS_NODE *aWorld, const PNS_LINE *aLine, const VECTOR2I& aP, bool aFirst ) +{ + PNS_JOINT* jt = aWorld->FindJoint( aP , aLine ); + + if( !jt ) + return 0xff; + + + DIRECTION_45 dirs [8]; + + int n_dirs = 0; + + BOOST_FOREACH ( const PNS_ITEM *item, jt->Links().CItems() ) + { + if (item->OfKind (PNS_ITEM::VIA) || item->OfKind (PNS_ITEM::SOLID)) + return 0xff; + else if ( const PNS_SEGMENT *seg = dyn_cast ( item ) ) + { + SEG s = seg->Seg(); + if (s.A != aP) + s.Reverse(); + + if (n_dirs < 8) + dirs [ n_dirs++ ] = aFirst ? DIRECTION_45 ( s ) : DIRECTION_45 ( s ).Opposite(); + } + } + + + + const int angleMask = DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_STRAIGHT; + int outputMask = 0xff; + + for (int d = 0; d < 8; d ++) + { + DIRECTION_45 refDir( (DIRECTION_45::Directions) d ); + for (int i = 0; i < n_dirs; i++ ) + { + if (! (refDir.Angle(dirs [ i ] ) & angleMask) ) + outputMask &= ~refDir.Mask(); + } + } + + DrawDebugDirs ( aP, outputMask, 3 ); + return 0xff; +} + + +void LINE_RESTRICTIONS::Build( PNS_NODE *aWorld, PNS_LINE *aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ) +{ + const SHAPE_LINE_CHAIN& l = aLine; + VECTOR2I v_prev; + int n = l.PointCount( ); + + m_rs.reserve( n ); + + for (int i = 0; i < n; i++) + { + const VECTOR2I &v = l.CPoint(i), v_next; + RVERTEX r ( false, 0xff ); + + if ( aRestrictedAreaEnable ) + { + bool exiting = ( i > 0 && aRestrictedArea.Contains( v_prev ) && !aRestrictedArea.Contains(v) ); + bool entering = false; + + if( i != l.PointCount() - 1) + { + const VECTOR2I& v_next = l.CPoint(i + 1); + entering = ( !aRestrictedArea.Contains( v ) && aRestrictedArea.Contains( v_next ) ); + } + + if(entering) + { + const SEG& sp = l.CSegment(i); + r.allowedAngles = DIRECTION_45(sp).Mask(); + } else if (exiting) { + const SEG& sp = l.CSegment(i - 1); + r.allowedAngles = DIRECTION_45(sp).Mask(); + } else { + r.allowedAngles = (! aRestrictedArea.Contains ( v ) ) ? 0 : 0xff; + r.restricted = r.allowedAngles ? false : true; + } + } + v_prev = v; + m_rs.push_back(r); + } +} + +void LINE_RESTRICTIONS::Dump() +{ +} + +bool LINE_RESTRICTIONS::Check ( int aVertex1, int aVertex2, const SHAPE_LINE_CHAIN& aReplacement ) +{ + if( m_rs.empty( ) ) + return true; + + for(int i = aVertex1; i <= aVertex2; i++) + if ( m_rs[i].restricted ) + return false; + + const RVERTEX& v1 = m_rs[ aVertex1 ]; + const RVERTEX& v2 = m_rs[ aVertex2 ]; + + int m1 = DIRECTION_45( aReplacement.CSegment( 0 ) ).Mask(); + int m2; + if (aReplacement.SegmentCount() == 1) + m2 = m1; + else + m2 = DIRECTION_45 ( aReplacement.CSegment( 1 ) ).Mask(); + + + return ((v1.allowedAngles & m1) != 0) && + ((v2.allowedAngles & m2) != 0); +} + + bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache ) { @@ -391,7 +541,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 ) { if( !aResult ) aResult = aLine; @@ -425,12 +575,16 @@ bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int cost_orig = PNS_COST_ESTIMATOR::CornerCost( aCurrentPath ); + LINE_RESTRICTIONS restr; + if( aLine->SegmentCount() < 4 ) return false; DIRECTION_45 orig_start( aLine->CSegment( 0 ) ); DIRECTION_45 orig_end( aLine->CSegment( -1 ) ); + restr.Build( m_world, aLine, aCurrentPath, m_restrictArea, m_restrictAreaActive ); + while( n < n_segs - step ) { const SEG s1 = aCurrentPath.CSegment( n ); @@ -446,13 +600,14 @@ bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace( s1.A, s2.B, i ); cost[i] = INT_MAX; + bool restrictionsOK = restr.Check ( n, n + step + 1, bypass ); if( n == 0 && orig_start != DIRECTION_45( bypass.CSegment( 0 ) ) ) postureMatch = false; else if( n == n_segs - step && orig_end != DIRECTION_45( bypass.CSegment( -1 ) ) ) postureMatch = false; - if( (postureMatch || !m_keepPostures) && !checkColliding( aLine, bypass ) ) + if( restrictionsOK && (postureMatch || !m_keepPostures) && !checkColliding( aLine, bypass ) ) { path[i] = aCurrentPath; path[i].Replace( s1.Index(), s2.Index(), bypass ); @@ -782,7 +937,6 @@ bool PNS_OPTIMIZER::fanoutCleanup( PNS_LINE* aLine ) 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 ); @@ -796,3 +950,210 @@ bool PNS_OPTIMIZER::fanoutCleanup( PNS_LINE* aLine ) return false; } + +int findCoupledVertices ( const VECTOR2I& aVertex, const SEG& aOrigSeg, const SHAPE_LINE_CHAIN& aCoupled, PNS_DIFF_PAIR *aPair, int *aIndices ) +{ + int count = 0; + for ( int i = 0; i < aCoupled.SegmentCount(); i++ ) + { + SEG s = aCoupled.CSegment(i); + VECTOR2I projOverCoupled = s.LineProject ( aVertex ); + + + if( s.ApproxParallel ( aOrigSeg ) ) + { + int64_t dist = ( projOverCoupled - aVertex ).EuclideanNorm() - aPair->Width(); + + if( aPair->GapConstraint().Matches(dist) ) + { + *aIndices++ = i; + count++; + } + } + } + + return count; +} + +bool verifyDpBypass ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aNewRef, const SHAPE_LINE_CHAIN& aNewCoupled ) +{ + PNS_LINE refLine ( aRefIsP ? aPair->PLine() : aPair->NLine(), aNewRef ); + PNS_LINE coupledLine ( aRefIsP ? aPair->NLine() : aPair->PLine(), aNewCoupled ); + + if ( aNode->CheckColliding( &refLine, &coupledLine, PNS_ITEM::ANY, aPair->Gap() - 10 ) ) + return false; + + if ( aNode->CheckColliding ( &refLine ) ) + return false; + + if ( aNode->CheckColliding ( &coupledLine ) ) + return false; + + return true; +} + +bool coupledBypass ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aRef, const SHAPE_LINE_CHAIN& aRefBypass, const SHAPE_LINE_CHAIN& aCoupled, SHAPE_LINE_CHAIN& aNewCoupled ) +{ + int vStartIdx[1024]; // fixme: possible overflow + + int nStarts = findCoupledVertices ( aRefBypass.CPoint(0), aRefBypass.CSegment(0), aCoupled, aPair, vStartIdx ); + DIRECTION_45 dir( aRefBypass.CSegment(0) ); + + int64_t bestLength = -1; + bool found = false; + SHAPE_LINE_CHAIN bestBypass; + int si, ei; + + for(int i=0; i< nStarts ;i++) + for ( int j = 1; j < aCoupled.PointCount() - 1; j++) + { + int delta = std::abs ( vStartIdx[i] - j ); + if(delta > 1) + { + const VECTOR2I& vs = aCoupled.CPoint( vStartIdx[i] ); + SHAPE_LINE_CHAIN bypass = dir.BuildInitialTrace( vs, aCoupled.CPoint(j), dir.IsDiagonal() ); + + int64_t coupledLength = aPair->CoupledLength ( aRef, bypass ); + + SHAPE_LINE_CHAIN newCoupled = aCoupled; + + si = vStartIdx[i]; + ei = j; + + if(si < ei) + newCoupled.Replace( si, ei, bypass ); + else + newCoupled.Replace( ei, si, bypass.Reverse() ); + + if(coupledLength > bestLength && verifyDpBypass ( aNode, aPair, aRefIsP, aRef, newCoupled) ) + { + bestBypass = newCoupled; + bestLength = coupledLength; + found = true; + } + } + } + + + if(found) + aNewCoupled = bestBypass; + + return found; +} + +bool checkDpColliding ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aIsP, const SHAPE_LINE_CHAIN& aPath ) +{ + PNS_LINE tmp ( aIsP ? aPair->PLine() : aPair->NLine(), aPath ); + + return aNode->CheckColliding( &tmp ); +} + + +bool PNS_OPTIMIZER::mergeDpStep( PNS_DIFF_PAIR *aPair, bool aTryP, int step ) +{ + int n = 1; + + SHAPE_LINE_CHAIN currentPath = aTryP ? aPair->CP() : aPair->CN(); + SHAPE_LINE_CHAIN coupledPath = aTryP ? aPair->CN() : aPair->CP(); + + int n_segs = currentPath.SegmentCount() - 1; + + int64_t clenPre = aPair->CoupledLength ( currentPath, coupledPath ); + int64_t budget = clenPre / 10; // fixme: come up with somethig more intelligent here... + + while( n < n_segs - step ) + { + const SEG s1 = currentPath.CSegment( n ); + const SEG s2 = currentPath.CSegment( n + step ); + + DIRECTION_45 dir1 (s1); + DIRECTION_45 dir2 (s2); + + if( dir1.IsObtuse(dir2 ) ) + { + SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace( s1.A, s2.B, dir1.IsDiagonal() ); + SHAPE_LINE_CHAIN newRef; + SHAPE_LINE_CHAIN newCoup; + int64_t deltaCoupled = -1, deltaUni = -1; + + + newRef = currentPath; + newRef.Replace( s1.Index(), s2.Index(), bypass ); + + deltaUni = aPair->CoupledLength ( newRef, coupledPath ) - clenPre + budget; + + if ( coupledBypass ( m_world, aPair, aTryP, newRef, bypass, coupledPath, newCoup ) ) + { + deltaCoupled = aPair->CoupledLength ( newRef, newCoup ) - clenPre + budget; + + if(deltaCoupled >= 0) + { + newRef.Simplify(); + newCoup.Simplify(); + + aPair->SetShape ( newRef, newCoup, !aTryP ); + return true; + } + } + else if( deltaUni >= 0 && verifyDpBypass ( m_world, aPair, aTryP, newRef, coupledPath ) ) + { + newRef.Simplify(); + coupledPath.Simplify(); + + aPair->SetShape ( newRef, coupledPath, !aTryP ); + return true; + } + } + + n++; + } + + return false; +} + +bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR *aPair ) +{ + int step_p = aPair->CP().SegmentCount() - 2; + int step_n = aPair->CN().SegmentCount() - 2; + + while( 1 ) + { + int n_segs_p = aPair->CP().SegmentCount(); + int n_segs_n = aPair->CN().SegmentCount(); + + int max_step_p = n_segs_p - 2; + int max_step_n = n_segs_n - 2; + + if( step_p > max_step_p ) + step_p = max_step_p; + + if( step_n > max_step_n ) + step_n = max_step_n; + + if( step_p < 1 && step_n < 1) + break; + + bool found_anything_p = false; + bool found_anything_n = false; + + if(step_p > 1) + found_anything_p = mergeDpStep( aPair, true, step_p ); + + if(step_n > 1) + found_anything_n = mergeDpStep( aPair, false, step_n ); + + if( !found_anything_n && !found_anything_p ) + { + step_n--; + step_p--; + } + } + return true; +} + +bool PNS_OPTIMIZER::Optimize( PNS_DIFF_PAIR* aPair ) +{ + + + return mergeDpSegments ( aPair ); +} \ No newline at end of file diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index fb75b41a53..f48d6ec632 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -30,8 +30,9 @@ #include "range.h" class PNS_NODE; -class PNS_LINE; class PNS_ROUTER; +class PNS_LINE; +class PNS_DIFF_PAIR; /** * Class PNS_COST_ESTIMATOR @@ -101,6 +102,8 @@ public: static bool Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld); bool Optimize( PNS_LINE* aLine, PNS_LINE* aResult = NULL ); + bool Optimize( PNS_DIFF_PAIR* aPair ); + void SetWorld( PNS_NODE* aNode ) { m_world = aNode; } void CacheStaticItem( PNS_ITEM* aItem ); @@ -117,6 +120,13 @@ public: m_effortLevel = aEffort; } + + void SetRestrictArea( const BOX2I& aArea ) + { + m_restrictArea = aArea; + m_restrictAreaActive = true; + } + private: static const int MaxCachedItems = 256; @@ -136,6 +146,8 @@ private: bool runSmartPads( PNS_LINE* aLine ); bool mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step ); bool fanoutCleanup( PNS_LINE * aLine ); + bool mergeDpSegments( PNS_DIFF_PAIR *aPair ); + bool mergeDpStep( PNS_DIFF_PAIR *aPair, bool aTryP, int step ); bool checkColliding( PNS_ITEM* aItem, bool aUpdateCache = true ); bool checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath ); @@ -160,6 +172,9 @@ private: int m_collisionKindMask; int m_effortLevel; bool m_keepPostures; + + BOX2I m_restrictArea; + bool m_restrictAreaActive; }; #endif diff --git a/pcbnew/router/pns_placement_algo.h b/pcbnew/router/pns_placement_algo.h new file mode 100644 index 0000000000..7de571692e --- /dev/null +++ b/pcbnew/router/pns_placement_algo.h @@ -0,0 +1,189 @@ +/* + * 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_PLACEMENT_ALGO_H +#define __PNS_PLACEMENT_ALGO_H + +#include + +#include "pns_algo_base.h" +#include "pns_sizes_settings.h" +#include "pns_itemset.h" + +class PNS_ROUTER; +class PNS_ITEM; +class PNS_NODE; + +/** + * Class PNS_PLACEMENT_ALGO + * + * Abstract class for a P&S placement/dragging algorithm. + * All subtools (drag, single/diff pair routing and meandering) + * are derived from it. + */ + +class PNS_PLACEMENT_ALGO : public PNS_ALGO_BASE +{ +public: + PNS_PLACEMENT_ALGO( PNS_ROUTER* aRouter ) : + PNS_ALGO_BASE( aRouter ) {}; + + virtual ~PNS_PLACEMENT_ALGO () {}; + + /** + * Function Start() + * + * Starts placement/drag operation at point aP, taking item aStartItem as anchor + * (unless NULL). + */ + virtual bool Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) = 0; + + /** + * Function Move() + * + * Moves the end of the currently routed primtive(s) to the point aP, taking + * aEndItem as the anchor (if not NULL). + * (unless NULL). + */ + virtual bool Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) = 0; + + /** + * Function FixRoute() + * + * Commits the currently routed items 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. + */ + virtual bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) = 0; + + /** + * Function ToggleVia() + * + * Enables/disables a via at the end of currently routed trace. + */ + virtual bool ToggleVia( bool aEnabled ) + { + return false; + } + + /** + * Function IsPlacingVia() + * + * Returns true if the placer is placing a via (or more vias). + */ + virtual bool IsPlacingVia() const + { + return false; + } + + /** + * Function SetLayer() + * + * Sets the current routing layer. + */ + virtual bool SetLayer( int aLayer ) + { + return false; + } + + /** + * Function Traces() + * + * Returns all routed/tuned traces. + */ + virtual const PNS_ITEMSET Traces() = 0; + + /** + * Function CurrentEnd() + * + * Returns the current end of the line being placed/tuned. It may not be equal + * to the cursor position due to collisions. + */ + virtual const VECTOR2I& CurrentEnd() const = 0; + + /** + * Function CurrentNet() + * + * Returns the net code of currently routed track. + */ + virtual int CurrentNet() const = 0; + + /** + * Function CurrentLayer() + * + * Returns the layer of currently routed track. + */ + virtual int CurrentLayer() const = 0; + + /** + * Function CurrentNode() + * + * Returns the most recent board state. + */ + virtual PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const = 0; + + /** + * Function FlipPosture() + * + * Toggles the current posture (straight/diagonal) of the trace head. + */ + virtual 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. + */ + virtual void UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ) + { + + } + + /** + * Function SetOrthoMode() + * + * Forces the router to place a straight 90/45 degree trace (with the end + * as near to the cursor as possible) instead of a standard 135 degree + * two-segment bend. + */ + virtual void SetOrthoMode ( bool aOrthoMode ) + { + + } + + /** + * Function GetModifiedNets + * + * Returns the net codes of all currently routed trace(s) + */ + virtual void GetModifiedNets( std::vector &aNets ) const + { + + } +}; + +#endif diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index d8c9f23678..c1a78c97e6 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -44,6 +44,12 @@ #include "pns_router.h" #include "pns_shove.h" #include "pns_dragger.h" +#include "pns_diff_pair_placer.h" +#include "pns_meander_placer.h" +#include "pns_meander_skew_placer.h" +#include "pns_dp_meander_placer.h" + + #include @@ -58,66 +64,85 @@ // To be fixed sometime in the future. static PNS_ROUTER* theRouter; -class PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC + +PNS_PCBNEW_CLEARANCE_FUNC::PNS_PCBNEW_CLEARANCE_FUNC( BOARD* aBoard ) { -public: - PCBNEW_CLEARANCE_FUNC( BOARD* aBoard ) + m_clearanceCache.resize( aBoard->GetNetCount() ); + + for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ ) { - m_clearanceCache.resize( aBoard->GetNetCount() ); + NETINFO_ITEM* ni = aBoard->FindNet( i ); + if( ni == NULL ) + continue; - for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ ) - { - NETINFO_ITEM* ni = aBoard->FindNet( i ); - if( ni == NULL ) - continue; - - wxString netClassName = ni->GetClassName(); - NETCLASSPTR 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() % - clearance ); - } - - m_defaultClearance = 254000; // aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); + wxString netClassName = ni->GetClassName(); + NETCLASSPTR 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() % + clearance ); } - int localPadClearance( const PNS_ITEM* aItem ) const + m_overrideEnabled = false; + m_defaultClearance = 254000; // aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); +} + +PNS_PCBNEW_CLEARANCE_FUNC::~PNS_PCBNEW_CLEARANCE_FUNC() +{ + +} + +int PNS_PCBNEW_CLEARANCE_FUNC::localPadClearance( const PNS_ITEM* aItem ) const +{ + if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T ) + return 0; + + const D_PAD* pad = static_cast( aItem->Parent() ); + return pad->GetLocalClearance(); +} + +int PNS_PCBNEW_CLEARANCE_FUNC::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 ); + + if(m_overrideEnabled && aA->OfKind(PNS_ITEM::SEGMENT) && aB->OfKind(PNS_ITEM::SEGMENT)) { - if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T ) - return 0; - - const D_PAD* pad = static_cast( aItem->Parent() ); - - return pad->GetLocalClearance(); + if( net_a == m_overrideNetA && net_b == m_overrideNetB ) + return m_overrideClearance; + else if( net_a == m_overrideNetB && net_b == m_overrideNetA ) + return m_overrideClearance; } - 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 ); - 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 ); - cl_a = std::max( cl_a, pad_a ); - cl_b = std::max( cl_b, pad_b ); - - return std::max( cl_a, cl_b ); - } - -private: - std::vector m_clearanceCache; - int m_defaultClearance; + return std::max( cl_a, cl_b ); }; +// fixme: ugly hack to make the optimizer respect gap width for currently routed differential pair. +void PNS_PCBNEW_CLEARANCE_FUNC::OverrideClearance (bool aEnable, int aNetA , int aNetB , int aClearance ) +{ + m_overrideEnabled = aEnable; + m_overrideNetA = aNetA; + m_overrideNetB = aNetB; + m_overrideClearance = aClearance; +} + PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) { PNS_LAYERSET layers( 0, MAX_CU_LAYERS - 1 ); + // ignore non-copper pads + if ( (aPad->GetLayerSet() & LSET::AllCuMask()).none() ) + return NULL; + switch( aPad->GetAttribute() ) { case PAD_STANDARD: @@ -222,6 +247,8 @@ PNS_ITEM* PNS_ROUTER::syncTrack( TRACK* aTrack ) PNS_SEGMENT* s = new PNS_SEGMENT( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNetCode() ); + if( aTrack->GetFlags( ) & DP_COUPLED ) + s->Mark ( MK_DP_COUPLED ); s->SetWidth( aTrack->GetWidth() ); s->SetLayers( PNS_LAYERSET( aTrack->GetLayer() ) ); s->SetParent( aTrack ); @@ -265,7 +292,7 @@ void PNS_ROUTER::SyncWorld() int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue(); - m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC( m_board ); + m_clearanceFunc = new PNS_PCBNEW_CLEARANCE_FUNC( m_board ); m_world = new PNS_NODE(); m_world->SetClearanceFunctor( m_clearanceFunc ); m_world->SetMaxClearance( 4 * worstClearance ); @@ -309,6 +336,7 @@ PNS_ROUTER::PNS_ROUTER() m_previewItems = NULL; m_board = NULL; m_dragger = NULL; + m_mode = PNS_MODE_ROUTE_SINGLE; } @@ -460,17 +488,45 @@ bool PNS_ROUTER::StartDragging( const VECTOR2I& aP, PNS_ITEM* aStartItem ) bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem, int aLayer ) { - m_placer = new PNS_LINE_PLACER( this ); + switch (m_mode) + { + case PNS_MODE_ROUTE_SINGLE: + m_placer = new PNS_LINE_PLACER( this ); + break; + case PNS_MODE_ROUTE_DIFF_PAIR: + m_placer = new PNS_DIFF_PAIR_PLACER( this ); + break; + case PNS_MODE_TUNE_SINGLE: + m_placer = new PNS_MEANDER_PLACER( this ); + break; + case PNS_MODE_TUNE_DIFF_PAIR: + m_placer = new PNS_DP_MEANDER_PLACER( this ); + break; + case PNS_MODE_TUNE_DIFF_PAIR_SKEW: + m_placer = new PNS_MEANDER_SKEW_PLACER( this ); + break; + + default: + return false; + } m_placer->UpdateSizes ( m_sizes ); m_placer->SetLayer( aLayer ); - m_placer->Start( aP, aStartItem ); + + bool rv = m_placer->Start( aP, aStartItem ); + + if(!rv) + return false; m_currentEnd = aP; m_currentEndItem = NULL; m_state = ROUTE_TRACK; + return rv; +} - return true; +BOARD *PNS_ROUTER::GetBoard() +{ + return m_board; } void PNS_ROUTER::eraseView() @@ -652,15 +708,25 @@ void PNS_ROUTER::movePlacing( const VECTOR2I& aP, PNS_ITEM* aEndItem ) eraseView(); m_placer->Move( aP, aEndItem ); - PNS_LINE current = m_placer->Trace(); + PNS_ITEMSET current = m_placer->Traces(); - DisplayItem( ¤t ); - if( current.EndsWithVia() ) - DisplayItem( ¤t.Via() ); + BOOST_FOREACH( const PNS_ITEM* item, current.CItems() ) + { + if( !item->OfKind ( PNS_ITEM::LINE ) ) + continue; - PNS_ITEMSET tmp( ¤t ); - updateView( m_placer->CurrentNode( true ), tmp ); + const PNS_LINE *l = static_cast (item); + DisplayItem(l); + + if( l->EndsWithVia() ) + DisplayItem( &l->Via() ); + } + + + //PNS_ITEMSET tmp( ¤t ); + + updateView( m_placer->CurrentNode( true ), current ); } @@ -765,11 +831,13 @@ bool PNS_ROUTER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) void PNS_ROUTER::StopRouting() { // Update the ratsnest with new changes + if( m_placer ) { - int n = m_placer->CurrentNet(); + std::vector nets; + m_placer->GetModifiedNets( nets ); - if( n >= 0) + BOOST_FOREACH ( int n, nets ) { // Update the ratsnest with new changes m_board->GetRatsnest()->Recalculate( n ); @@ -871,3 +939,17 @@ bool PNS_ROUTER::IsPlacingVia() const return m_placer->IsPlacingVia(); } +void PNS_ROUTER::SetOrthoMode( bool aEnable ) +{ + if(!m_placer) + return; + + m_placer->SetOrthoMode ( aEnable ); +} + +void PNS_ROUTER::SetMode ( PNS_ROUTER_MODE aMode ) +{ + m_mode = aMode; +} + + diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 0969bade68..48fed80321 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -41,6 +41,8 @@ class D_PAD; class TRACK; class VIA; class PNS_NODE; +class PNS_DIFF_PAIR_PLACER; +class PNS_PLACEMENT_ALGO; class PNS_LINE_PLACER; class PNS_ITEM; class PNS_LINE; @@ -59,6 +61,14 @@ namespace KIGFX }; +enum PNS_ROUTER_MODE { + PNS_MODE_ROUTE_SINGLE = 1, + PNS_MODE_ROUTE_DIFF_PAIR, + PNS_MODE_TUNE_SINGLE, + PNS_MODE_TUNE_DIFF_PAIR, + PNS_MODE_TUNE_DIFF_PAIR_SKEW +}; + /** * Class PNS_ROUTER * @@ -78,6 +88,9 @@ public: PNS_ROUTER(); ~PNS_ROUTER(); + void SetMode ( PNS_ROUTER_MODE aMode ); + PNS_ROUTER_MODE Mode() const { return m_mode; } + static PNS_ROUTER* GetInstance(); void ClearWorld(); @@ -113,6 +126,7 @@ public: void SwitchLayer( int layer ); void ToggleViaPlacement(); + void SetOrthoMode ( bool aEnable ); int GetCurrentLayer() const; int GetCurrentNet() const; @@ -193,6 +207,15 @@ public: return m_sizes; } + PNS_ITEM *QueryItemByParent ( const BOARD_ITEM *aItem ) const; + + BOARD *GetBoard(); + + void SetFailureReason ( const wxString& aReason ) { m_failureReason = aReason; } + const wxString& FailureReason() const { return m_failureReason; } + + PNS_PLACEMENT_ALGO *Placer() { return m_placer; } + private: void movePlacing( const VECTOR2I& aP, PNS_ITEM* aItem ); void moveDragging( const VECTOR2I& aP, PNS_ITEM* aItem ); @@ -225,7 +248,7 @@ private: BOARD* m_board; PNS_NODE* m_world; PNS_NODE* m_lastNode; - PNS_LINE_PLACER* m_placer; + PNS_PLACEMENT_ALGO * m_placer; PNS_DRAGGER* m_dragger; PNS_SHOVE* m_shove; int m_iterLimit; @@ -250,6 +273,11 @@ private: ///> Stores list of modified items in the current operation PICKED_ITEMS_LIST m_undoBuffer; PNS_SIZES_SETTINGS m_sizes; + PNS_ROUTER_MODE m_mode; + + wxString m_toolStatusbarName; + wxString m_failureReason; + }; #endif diff --git a/pcbnew/router/pns_routing_settings.cpp b/pcbnew/router/pns_routing_settings.cpp index bb67840fbe..81ae5f7b5f 100644 --- a/pcbnew/router/pns_routing_settings.cpp +++ b/pcbnew/router/pns_routing_settings.cpp @@ -24,7 +24,7 @@ PNS_ROUTING_SETTINGS::PNS_ROUTING_SETTINGS() { m_routingMode = RM_Walkaround; - m_optimizerEffort = OE_FULL; + m_optimizerEffort = OE_MEDIUM; m_removeLoops = true; m_smartPads = true; m_shoveVias = true; diff --git a/pcbnew/router/pns_segment.h b/pcbnew/router/pns_segment.h index 2550526c2e..dc9e870cdd 100644 --- a/pcbnew/router/pns_segment.h +++ b/pcbnew/router/pns_segment.h @@ -55,6 +55,11 @@ public: m_rank = aParentLine.Rank(); }; + static inline bool ClassOf( const PNS_ITEM* aItem ) + { + return aItem && SEGMENT == aItem->Kind(); + } + PNS_SEGMENT* Clone( ) const; const SHAPE* Shape() const diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 1338557f1a..48a3227088 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -36,11 +36,36 @@ #include "pns_utils.h" #include "pns_router.h" #include "pns_shove.h" +#include "pns_utils.h" #include "time_limit.h" #include +void PNS_SHOVE::replaceItems ( PNS_ITEM *aOld, PNS_ITEM *aNew ) +{ + OPT_BOX2I changed_area = ChangedArea( aOld, aNew ); + + + if(changed_area) + { + assert ( !changed_area->Contains ( VECTOR2I (0, 0 ) ) ); + + m_affectedAreaSum = m_affectedAreaSum ? m_affectedAreaSum->Merge ( *changed_area ) : *changed_area; + } + + m_currentNode->Replace( aOld, aNew ); +} + + +int PNS_SHOVE::getClearance( PNS_ITEM *aA, PNS_ITEM *aB ) const +{ + if(m_forceClearance >= 0) + return m_forceClearance; + + return m_currentNode->GetClearance( aA, aB ); +} + static void sanityCheck( PNS_LINE* aOld, PNS_LINE* aNew ) { assert( aOld->CPoint( 0 ) == aNew->CPoint( 0 ) ); @@ -51,6 +76,7 @@ static void sanityCheck( PNS_LINE* aOld, PNS_LINE* aNew ) PNS_SHOVE::PNS_SHOVE( PNS_NODE* aWorld, PNS_ROUTER* aRouter ) : PNS_ALGO_BASE ( aRouter ) { + m_forceClearance = -1; m_root = aWorld; } @@ -59,7 +85,7 @@ PNS_SHOVE::~PNS_SHOVE() { // free all the stuff we've created during routing/dragging operation. BOOST_FOREACH( PNS_ITEM* item, m_gcItems ) - delete item; + delete item; } @@ -73,17 +99,6 @@ PNS_LINE* PNS_SHOVE::assembleLine( const PNS_SEGMENT* aSeg, int* aIndex ) return l; } - -// garbage-collected line cloning -PNS_LINE* PNS_SHOVE::cloneLine ( const PNS_LINE* aLine ) -{ - PNS_LINE* l = aLine->Clone(); - - m_gcItems.push_back( l ); - return l; -} - - // 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: @@ -92,7 +107,7 @@ bool PNS_SHOVE::checkBumpDirection( PNS_LINE* aCurrent, PNS_LINE* aShoved ) cons { const SEG ss = aCurrent->CSegment( 0 ); - int dist = m_currentNode->GetClearance( aCurrent, aShoved ) + PNS_HULL_MARGIN; + int dist = getClearance( aCurrent, aShoved ) + PNS_HULL_MARGIN; dist += aCurrent->Width() / 2; dist += aShoved->Width() / 2; @@ -106,7 +121,7 @@ bool PNS_SHOVE::checkBumpDirection( PNS_LINE* aCurrent, PNS_LINE* aShoved ) cons PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::walkaroundLoneVia( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ) { - int clearance = m_currentNode->GetClearance( aCurrent, aObstacle ); + int clearance = getClearance( aCurrent, aObstacle ); const SHAPE_LINE_CHAIN hull = aCurrent->Via().Hull( clearance, aObstacle->Width() ); SHAPE_LINE_CHAIN path_cw, path_ccw; @@ -204,7 +219,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processHullSet( PNS_LINE* aCurrent, PNS_LINE* continue; } - bool colliding = m_currentNode->CheckColliding( &l, aCurrent ); + bool colliding = m_currentNode->CheckColliding( &l, aCurrent, PNS_ITEM::ANY, m_forceClearance ); if( ( aCurrent->Marker() & MK_HEAD ) && !colliding ) { @@ -232,7 +247,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processHullSet( PNS_LINE* aCurrent, PNS_LINE* } -PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ProcessSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ) { aShoved->ClearSegmentLinks(); @@ -262,7 +277,8 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::processSingleLine( PNS_LINE* aCurrent, PNS_LI { int w = aObstacle->Width(); int n_segs = aCurrent->SegmentCount(); - int clearance = m_currentNode->GetClearance( aCurrent, aObstacle ); + + int clearance = getClearance( aCurrent, aObstacle ); HULL_SET hulls; @@ -291,19 +307,24 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE* aCurrent, PNS_S { int segIndex; PNS_LINE* obstacleLine = assembleLine( aObstacleSeg, &segIndex ); - PNS_LINE* shovedLine = cloneLine( obstacleLine ); + PNS_LINE* shovedLine = clone( obstacleLine ); - SHOVE_STATUS rv = processSingleLine( aCurrent, obstacleLine, shovedLine ); + SHOVE_STATUS rv = ProcessSingleLine( aCurrent, obstacleLine, shovedLine ); assert ( obstacleLine->LayersOverlap( shovedLine ) ); if( rv == SH_OK ) { if( shovedLine->Marker() & MK_HEAD ) + { + if( m_multiLineMode ) + return SH_INCOMPLETE; + m_newHead = *shovedLine; + } sanityCheck( obstacleLine, shovedLine ); - m_currentNode->Replace( obstacleLine, shovedLine ); + replaceItems ( obstacleLine, shovedLine ); sanityCheck( obstacleLine, shovedLine ); int rank = aCurrent->Rank(); @@ -326,17 +347,24 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE* aCurrent, PNS_S PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle ) { - PNS_LINE* shovedLine = cloneLine( aObstacle ); + PNS_LINE* shovedLine = clone( aObstacle ); + + SHOVE_STATUS rv = ProcessSingleLine( aCurrent, aObstacle, shovedLine ); + - SHOVE_STATUS rv = processSingleLine( aCurrent, aObstacle, shovedLine ); if( rv == SH_OK ) { if( shovedLine->Marker() & MK_HEAD ) + { + if (m_multiLineMode) + return SH_INCOMPLETE; + m_newHead = *shovedLine; + } sanityCheck( aObstacle, shovedLine ); - m_currentNode->Replace( aObstacle, shovedLine ); + replaceItems( aObstacle, shovedLine ); sanityCheck( aObstacle, shovedLine ); int rank = aObstacle->Rank(); @@ -358,8 +386,10 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE* aCurrent, PNS_LINE PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE* aCurrent, PNS_SOLID* aObstacleSolid ) { + //printf("pre2-v %d\n", aCurrent->EndsWithVia()); + PNS_WALKAROUND walkaround( m_currentNode, Router() ); - PNS_LINE* walkaroundLine = cloneLine( aCurrent ); + PNS_LINE* walkaroundLine = clone( aCurrent ); if( aCurrent->EndsWithVia() ) { @@ -413,10 +443,14 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE* aCurrent, PNS_SOL if( aCurrent->Marker() & MK_HEAD ) { walkaroundLine->Mark( MK_HEAD ); + + if(m_multiLineMode) + return SH_INCOMPLETE; + m_newHead = *walkaroundLine; } - m_currentNode->Replace( aCurrent, walkaroundLine ); + replaceItems ( aCurrent, walkaroundLine ); walkaroundLine->SetRank( nextRank ); #ifdef DEBUG @@ -447,7 +481,7 @@ bool PNS_SHOVE::reduceSpringback( const PNS_ITEMSET& aHeadSet ) delete spTag.m_node; m_nodeStack.pop_back(); - } + } else break; } @@ -457,32 +491,59 @@ bool PNS_SHOVE::reduceSpringback( const PNS_ITEMSET& aHeadSet ) bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET& aHeadItems, - const PNS_COST_ESTIMATOR& aCost ) + const PNS_COST_ESTIMATOR& aCost, const OPT_BOX2I& aAffectedArea ) { SPRINGBACK_TAG st; + OPT_BOX2I prev_area; + + if(!m_nodeStack.empty()) + prev_area = m_nodeStack.back().m_affectedArea; + st.m_node = aNode; st.m_cost = aCost; st.m_headItems = aHeadItems; + + if( aAffectedArea ) + { + if( prev_area ) + st.m_affectedArea = prev_area->Merge ( *aAffectedArea ); + else + st.m_affectedArea = aAffectedArea; + } else + st.m_affectedArea = prev_area; + m_nodeStack.push_back( st ); return true; } -PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank ) +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun ) { LINE_PAIR_VEC draggedLines; VECTOR2I p0 ( aVia->Pos() ); - PNS_JOINT* jt = m_currentNode->FindJoint( p0, 1, aVia->Net() ); - PNS_VIA* pushedVia = aVia -> Clone(); + PNS_JOINT* jt = m_currentNode->FindJoint( p0, aVia ); + VECTOR2I p0_pushed( p0 + aForce ); - pushedVia->SetPos( p0 + aForce ); + while (aForce.x != 0 || aForce.y != 0) + { + PNS_JOINT *jt_next = m_currentNode->FindJoint ( p0_pushed, aVia ); + + if(!jt_next) + break; + + p0_pushed += aForce.Resize ( 2 ); // make sure pushed via does not overlap with any existing joint + } + + PNS_VIA* pushedVia = aVia->Clone(); + pushedVia->SetPos( p0_pushed ); pushedVia->Mark( aVia->Marker() ); if( aVia->Marker() & MK_HEAD ) { m_draggedVia = pushedVia; + m_draggedViaHeadSet.Clear(); } if( !jt ) @@ -493,9 +554,8 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) { - if( item->OfKind( PNS_ITEM::SEGMENT ) ) + if( PNS_SEGMENT *seg = dyn_cast( item ) ) { - PNS_SEGMENT* seg = (PNS_SEGMENT*) item; LINE_PAIR lp; int segIndex; @@ -506,19 +566,27 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc if( segIndex == 0 ) lp.first->Reverse(); - lp.second = cloneLine( lp.first ); + lp.second = clone( lp.first ); lp.second->ClearSegmentLinks(); - lp.second->DragCorner( p0 + aForce, lp.second->CLine().Find( p0 ) ); + lp.second->DragCorner( p0_pushed, lp.second->CLine().Find( p0 ) ); lp.second->AppendVia ( *pushedVia ); draggedLines.push_back( lp ); + + if (aVia->Marker() & MK_HEAD ) + m_draggedViaHeadSet.Add ( clone ( lp.second ) ); + } } - m_currentNode->Remove( aVia ); - m_currentNode->Add ( pushedVia ); + m_draggedViaHeadSet.Add ( pushedVia ); + if ( aDryRun ) + return SH_OK; + + replaceItems ( aVia, pushedVia ); + if( aVia->BelongsTo( m_currentNode ) ) - delete aVia; + delete aVia; pushedVia->SetRank( aCurrentRank - 1 ); @@ -532,6 +600,10 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc if( lp.first->Marker() & MK_HEAD ) { lp.second->Mark( MK_HEAD ); + + if ( m_multiLineMode ) + return SH_INCOMPLETE; + m_newHead = *lp.second; } @@ -539,7 +611,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc if( lp.second->SegmentCount() ) { - m_currentNode->Replace( lp.first, lp.second ); + replaceItems( lp.first, lp.second ); lp.second->SetRank( aCurrentRank - 1 ); pushLine( lp.second ); } @@ -558,7 +630,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingVia( PNS_ITEM* aCurrent, PNS_VIA* aObstacleVia ) { - int clearance = m_currentNode->GetClearance( aCurrent, aObstacleVia ) ; + int clearance = getClearance( aCurrent, aObstacleVia ) ; LINE_PAIR_VEC draggedLines; bool colLine = false, colVia = false; PNS_LINE* currentLine = NULL; @@ -609,11 +681,11 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onReverseCollidingVia( PNS_LINE* aCurrent, PN { std::vector steps; int n = 0; - PNS_LINE* cur = cloneLine( aCurrent ); + PNS_LINE* cur = clone( aCurrent ); cur->ClearSegmentLinks(); PNS_JOINT* jt = m_currentNode->FindJoint( aObstacleVia->Pos(), aObstacleVia ); - PNS_LINE* shoved = cloneLine( aCurrent ); + PNS_LINE* shoved = clone( aCurrent ); shoved->ClearSegmentLinks(); cur->RemoveVia(); @@ -628,7 +700,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onReverseCollidingVia( PNS_LINE* aCurrent, PN head->AppendVia( *aObstacleVia ); - SHOVE_STATUS st = processSingleLine( head, cur, shoved ); + SHOVE_STATUS st = ProcessSingleLine( head, cur, shoved ); if( st != SH_OK ) { @@ -660,7 +732,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onReverseCollidingVia( PNS_LINE* aCurrent, PN head.AppendVia( *aObstacleVia ); head.ClearSegmentLinks(); - SHOVE_STATUS st = processSingleLine( &head, aCurrent, shoved ); + SHOVE_STATUS st = ProcessSingleLine( &head, aCurrent, shoved ); if( st != SH_OK ) return st; @@ -678,7 +750,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onReverseCollidingVia( PNS_LINE* aCurrent, PN m_logger.Log( shoved, 3, "shoved-line" ); #endif int currentRank = aCurrent->Rank(); - m_currentNode->Replace( aCurrent, shoved ); + replaceItems( aCurrent, shoved ); pushLine( shoved ); shoved->SetRank( currentRank ); @@ -727,7 +799,15 @@ void PNS_SHOVE::unwindStack( PNS_ITEM* aItem ) void PNS_SHOVE::pushLine( PNS_LINE* aL ) { if( aL->LinkCount() >= 0 && ( aL->LinkCount() != aL->SegmentCount() ) ) + { + printf("LC: %d SC %d\n", aL->LinkCount(), aL->SegmentCount() ); + for(int i=0;iSegmentCount();i++) + { + SEG s = aL->CLine().CSegment(i); + printf("s %d: %d %d %d %d\n", i, s.A.x, s.A.y, s.B.x, s.B.y ); + } assert( false ); + } m_lineStack.push_back( aL ); m_optimizerQueue.push_back( aL ); @@ -847,6 +927,8 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveMainLoop() { SHOVE_STATUS st = SH_OK; + m_affectedAreaSum = OPT_BOX2I(); + TRACE( 1, "ShoveStart [root: %d jts, current: %d jts]", m_root->JointCount() % m_currentNode->JointCount() ); @@ -873,16 +955,34 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveMainLoop() return st; } +OPT_BOX2I PNS_SHOVE::totalAffectedArea ( ) const +{ + OPT_BOX2I area; + if(!m_nodeStack.empty()) + area = m_nodeStack.back().m_affectedArea; + + if( area ) + { + if ( m_affectedAreaSum ) + area->Merge ( *m_affectedAreaSum ); + } else + area = m_affectedAreaSum; + + return area; +} + PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) { SHOVE_STATUS st = SH_OK; + m_multiLineMode = false; + // empty head? nothing to shove... if( !aCurrentHead.SegmentCount() ) return SH_INCOMPLETE; - PNS_LINE* head = cloneLine( &aCurrentHead ); + PNS_LINE* head = clone( &aCurrentHead ); head->ClearSegmentLinks(); m_lineStack.clear(); @@ -890,7 +990,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) m_newHead = OPT_LINE(); m_logger.Clear(); - PNS_ITEMSET headSet( cloneLine( &aCurrentHead ) ); + PNS_ITEMSET headSet( clone( &aCurrentHead ) ); reduceSpringback( headSet ); @@ -924,7 +1024,6 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) if( m_newHead && st == SH_OK ) { st = SH_HEAD_MODIFIED; - //Router()->DisplayDebugLine( m_newHead->CLine(), 3, 20000 ); } m_currentNode->RemoveByMarker( MK_HEAD ); @@ -934,7 +1033,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) if( st == SH_OK || st == SH_HEAD_MODIFIED ) { - pushSpringback( m_currentNode, headSet, PNS_COST_ESTIMATOR() ); + pushSpringback( m_currentNode, headSet, PNS_COST_ESTIMATOR(), m_affectedAreaSum); } else { @@ -948,19 +1047,107 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) } + +PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveMultiLines( const PNS_ITEMSET& aHeadSet ) +{ + SHOVE_STATUS st = SH_OK; + + m_multiLineMode = true; + + PNS_ITEMSET headSet; + + BOOST_FOREACH ( const PNS_ITEM *item, aHeadSet.CItems() ) + { + const PNS_LINE *headOrig = static_cast (item); + + // empty head? nothing to shove... + if( !headOrig->SegmentCount() ) + return SH_INCOMPLETE; + + headSet.Add ( clone ( headOrig ) ); + } + + + m_lineStack.clear(); + m_optimizerQueue.clear(); + m_logger.Clear(); + + reduceSpringback( headSet ); + + PNS_NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; + + m_currentNode = parent->Branch(); + m_currentNode->ClearRanks(); + int n = 0; + BOOST_FOREACH ( const PNS_ITEM *item, aHeadSet.CItems() ) + { + const PNS_LINE *headOrig = static_cast (item); + PNS_LINE *head = clone ( headOrig ); + head->ClearSegmentLinks(); + + m_currentNode->Add( head ); + + head->Mark( MK_HEAD ); + head->SetRank( 100000 ); + n++; + pushLine( head ); + + PNS_VIA* headVia = NULL; + + if( head->EndsWithVia() ) + { + headVia = head->Via().Clone(); // fixme: leak + m_currentNode->Add( headVia ); + headVia->Mark( MK_HEAD ); + headVia->SetRank( 100000 ); + m_logger.Log( headVia, 0, "head-via" ); + } + } + + m_logger.NewGroup( "initial", 0 ); + //m_logger.Log( head, 0, "head" ); + + st = shoveMainLoop(); + runOptimizer( m_currentNode, NULL ); + + m_currentNode->RemoveByMarker( MK_HEAD ); + + TRACE( 1, "Shove status : %s after %d iterations", + ( st == SH_OK ? "OK" : "FAILURE") % m_iter ); + + if( st == SH_OK ) + { + pushSpringback( m_currentNode, PNS_ITEMSET(), PNS_COST_ESTIMATOR(), m_affectedAreaSum ); + } + else + { + delete m_currentNode; + m_currentNode = parent; + } + + 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 ); + m_draggedViaHeadSet.Clear(); PNS_NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; + + m_currentNode = parent; + //st = pushVia( aVia, ( aWhere - aVia->Pos() ), 0, true ); + //reduceSpringback( m_draggedViaHeadSet ); + + parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; + m_currentNode = parent->Branch(); m_currentNode->ClearRanks(); @@ -969,10 +1156,11 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveDraggingVia( PNS_VIA* aVia, const VECTOR st = pushVia( aVia, ( aWhere - aVia->Pos() ), 0 ); st = shoveMainLoop(); runOptimizer( m_currentNode, NULL ); + //m_currentNode->RemoveByMarker( MK_HEAD ); if( st == SH_OK || st == SH_HEAD_MODIFIED ) { - pushSpringback( m_currentNode, PNS_ITEMSET(), PNS_COST_ESTIMATOR() ); + pushSpringback( m_currentNode, m_draggedViaHeadSet, PNS_COST_ESTIMATOR(), m_affectedAreaSum); } else { @@ -981,8 +1169,9 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveDraggingVia( PNS_VIA* aVia, const VECTOR } if( aNewVia ) + { *aNewVia = m_draggedVia; - + } return st; } @@ -990,22 +1179,39 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveDraggingVia( PNS_VIA* aVia, const VECTOR void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) { PNS_OPTIMIZER optimizer( aNode ); - int optFlags = 0, n_passes = 0, extend = 0; + int optFlags = 0, n_passes = 0; PNS_OPTIMIZATION_EFFORT effort = Settings().OptimizerEffort(); + OPT_BOX2I area = totalAffectedArea(); + + int maxWidth = 0; + + for( std::vector::iterator i = m_optimizerQueue.begin(); + i != m_optimizerQueue.end(); ++i ) + { + maxWidth = std::max ( (*i)->Width(), maxWidth ); + } + + if(area) + { + area->Inflate ( 10 * maxWidth ); + } + switch( effort ) { case OE_LOW: optFlags = PNS_OPTIMIZER::MERGE_OBTUSE; n_passes = 1; - extend = 0; break; case OE_MEDIUM: - optFlags = PNS_OPTIMIZER::MERGE_OBTUSE; + optFlags = PNS_OPTIMIZER::MERGE_SEGMENTS; + + if( area ) + optimizer.SetRestrictArea ( *area ); + n_passes = 2; - extend = 1; break; case OE_FULL: @@ -1017,6 +1223,7 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) break; } + if( Settings().SmartPads() ) optFlags |= PNS_OPTIMIZER::SMART_PADS ; @@ -1034,18 +1241,6 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) 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 ) ) @@ -1059,48 +1254,6 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) } } - -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; diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index 2b4f32729f..d9fbeb9cee 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -61,7 +61,19 @@ public: } SHOVE_STATUS ShoveLines( const PNS_LINE& aCurrentHead ); + SHOVE_STATUS ShoveMultiLines( const PNS_ITEMSET& aHeadSet ); + SHOVE_STATUS ShoveDraggingVia( PNS_VIA*aVia, const VECTOR2I& aWhere, PNS_VIA** aNewVia ); + SHOVE_STATUS ProcessSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_LINE* aShoved ); + + void ForceClearance ( bool aEnabled, int aClearance ) + { + if( aEnabled ) + m_forceClearance = aClearance; + else + m_forceClearance = -1; + } PNS_NODE* CurrentNode(); @@ -83,15 +95,15 @@ private: PNS_NODE* m_node; PNS_ITEMSET m_headItems; PNS_COST_ESTIMATOR m_cost; + OPT_BOX2I m_affectedArea; }; - 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 ); + bool pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET& aHeadItems, + const PNS_COST_ESTIMATOR& aCost, const OPT_BOX2I& aAffectedArea ); SHOVE_STATUS walkaroundLoneVia( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ); bool checkBumpDirection( PNS_LINE* aCurrent, PNS_LINE* aShoved ) const; @@ -101,8 +113,11 @@ private: 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 ); + SHOVE_STATUS pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun = false ); + OPT_BOX2I totalAffectedArea ( ) const; + + void unwindStack( PNS_SEGMENT* aSeg ); void unwindStack( PNS_ITEM* aItem ); @@ -111,14 +126,26 @@ private: 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 ); + + void replaceItems ( PNS_ITEM *aOld, PNS_ITEM *aNew ); + + template T* clone ( const T* aItem ) + { + T *cloned = aItem->Clone(); + + m_gcItems.push_back( cloned ); + return cloned; + } + + OPT_BOX2I m_affectedAreaSum; + SHOVE_STATUS shoveIteration( int aIter ); SHOVE_STATUS shoveMainLoop(); + int getClearance( PNS_ITEM *aA, PNS_ITEM *aB ) const; + std::vector m_nodeStack; std::vector m_lineStack; std::vector m_optimizerQueue; @@ -131,8 +158,12 @@ private: PNS_LOGGER m_logger; PNS_VIA* m_draggedVia; + PNS_ITEMSET m_draggedViaHeadSet; int m_iter; + int m_forceClearance; + bool m_multiLineMode; + bool m_headModified; }; #endif // __PNS_SHOVE_H diff --git a/pcbnew/router/pns_sizes_settings.h b/pcbnew/router/pns_sizes_settings.h index 2cd0dae9a1..8c84256215 100644 --- a/pcbnew/router/pns_sizes_settings.h +++ b/pcbnew/router/pns_sizes_settings.h @@ -34,11 +34,13 @@ class PNS_SIZES_SETTINGS { public: PNS_SIZES_SETTINGS() : - m_trackWidth( 100000 ), - m_diffPairWidth( 100000 ), - m_diffPairGap( 125000 ), - m_viaDiameter( 500000 ), - m_viaDrill( 200000 ), + m_trackWidth( 155000 ), + m_diffPairWidth( 125000 ), + m_diffPairGap( 180000 ), + m_diffPairViaGap ( 180000 ), + m_viaDiameter( 600000 ), + m_viaDrill( 250000 ), + m_diffPairViaGapSameAsTraceGap ( true ), m_viaType( VIA_THROUGH ) {}; @@ -54,8 +56,21 @@ public: void SetTrackWidth( int aWidth ) { m_trackWidth = aWidth; } int DiffPairWidth() const { return m_diffPairWidth; } - int DiffPairGap() const { return m_diffPairGap; } + + int DiffPairViaGap() const { + if(m_diffPairViaGapSameAsTraceGap) + return m_diffPairGap; + else + return m_diffPairViaGap; + } + + bool DiffPairViaGapSameAsTraceGap() const { return m_diffPairViaGapSameAsTraceGap; } + + void SetDiffPairWidth( int aWidth ) { m_diffPairWidth = aWidth; } + void SetDiffPairGap( int aGap ) { m_diffPairGap = aGap; } + void SetDiffPairViaGapSameAsTraceGap ( bool aEnable ) { m_diffPairViaGapSameAsTraceGap = aEnable; } + void SetDiffPairViaGap( int aGap ) { m_diffPairViaGap = aGap; } int ViaDiameter() const { return m_viaDiameter; } void SetViaDiameter( int aDiameter) { m_viaDiameter = aDiameter; } @@ -84,9 +99,12 @@ private: int m_trackWidth; int m_diffPairWidth; int m_diffPairGap; + int m_diffPairViaGap; int m_viaDiameter; int m_viaDrill; + bool m_diffPairViaGapSameAsTraceGap; + VIATYPE_T m_viaType; std::map m_layerPairs; diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index 88f8431d24..527a08142f 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -48,7 +48,12 @@ public: m_shape = aSolid.m_shape->Clone(); m_pos = aSolid.m_pos; } - + + static inline bool ClassOf( const PNS_ITEM* aItem ) + { + return aItem && SOLID == aItem->Kind(); + } + PNS_ITEM* Clone() const; const SHAPE* Shape() const { return m_shape; } diff --git a/pcbnew/router/pns_tool_base.cpp b/pcbnew/router/pns_tool_base.cpp new file mode 100644 index 0000000000..0e83041791 --- /dev/null +++ b/pcbnew/router/pns_tool_base.cpp @@ -0,0 +1,273 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * 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 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 +#include +#include + +#include "class_draw_panel_gal.h" +#include "class_board.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "pns_tool_base.h" +#include "pns_segment.h" +#include "pns_router.h" +#include "pns_meander_placer.h" // fixme: move settings to separate header +#include "pns_tune_status_popup.h" +#include "trace.h" + +using namespace KIGFX; +using boost::optional; + +TOOL_ACTION PNS_TOOL_BASE::ACT_RouterOptions( "pcbnew.InteractiveRouter.RouterOptions", + AS_CONTEXT, 'E', + "Routing Options...", "Shows a dialog containing router options."); + + +PNS_TOOL_BASE::PNS_TOOL_BASE( const std::string& aToolName ) : + TOOL_INTERACTIVE( aToolName ) +{ + m_router = NULL; +} + + +PNS_TOOL_BASE::~PNS_TOOL_BASE() +{ + delete m_router; +} + + +void PNS_TOOL_BASE::Reset( RESET_REASON aReason ) +{ + if( m_router ) + delete m_router; + + m_frame = getEditFrame(); + m_ctls = getViewControls(); + m_board = getModel(); + + m_router = new PNS_ROUTER; + + m_router->ClearWorld(); + m_router->SetBoard( m_board ); + m_router->SyncWorld(); + m_router->LoadSettings( m_savedSettings ); + m_router->UpdateSizes( m_savedSizes ); + m_needsSync = false; + + if( getView() ) + m_router->SetView( getView() ); +} + +PNS_ITEM* PNS_TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) +{ + int tl = getView()->GetTopLayer(); + + if( aLayer > 0 ) + tl = aLayer; + + 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->Layers().Start() ) ) + continue; + + // fixme: this causes flicker with live loop removal... + //if( item->Parent() && !item->Parent()->ViewIsVisible() ) + // continue; + + if( aNet < 0 || item->Net() == aNet ) + { + if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) + { + if( !prioritized[2] ) + prioritized[2] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[0] = item; + } + else + { + if( !prioritized[3] ) + prioritized[3] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[1] = item; + } + } + } + + PNS_ITEM* rv = NULL; + PCB_EDIT_FRAME* frame = getEditFrame (); + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions(); + + for( int i = 0; i < 4; i++ ) + { + PNS_ITEM* item = prioritized[i]; + + if( displ_opts->m_ContrastModeDisplay ) + if( item && !item->Layers().Overlaps( tl ) ) + item = NULL; + + if( item ) + { + rv = item; + break; + } + } + + if( rv && aLayer >= 0 && !rv->Layers().Overlaps( aLayer ) ) + rv = NULL; + + if( rv ) + TRACE( 0, "%s, layer : %d, tl: %d", rv->KindStr().c_str() % rv->Layers().Start() % tl ); + + return rv; +} + + +void PNS_TOOL_BASE::highlightNet( bool aEnabled, int aNetcode ) +{ + RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings(); + + if( aNetcode >= 0 && aEnabled ) + rs->SetHighlight( true, aNetcode ); + else + rs->SetHighlight( false ); + + getView()->UpdateAllLayersColor(); +} + +void PNS_TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent ) +{ + int tl = getView()->GetTopLayer(); + VECTOR2I cp = m_ctls->GetCursorPosition(); + PNS_ITEM* startItem = NULL; + + if( aEvent.IsMotion() || aEvent.IsClick() ) + { + bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); + + VECTOR2I p( aEvent.Position() ); + startItem = pickSingleItem( p ); + m_router->EnableSnapping ( snapEnabled ); + + if( !snapEnabled && startItem && !startItem->Layers().Overlaps( tl ) ) + startItem = NULL; + + if( startItem && startItem->Net() >= 0 ) + { + bool dummy; + VECTOR2I psnap = m_router->SnapToItem( startItem, p, dummy ); + + if( snapEnabled ) + { + m_startSnapPoint = psnap; + m_ctls->ForceCursorPosition( true, psnap ); + } + else + { + m_startSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + +// if( startItem->Layers().IsMultilayer() ) +// m_startLayer = tl; +// else +// m_startLayer = startItem->Layers().Start(); + + m_startItem = startItem; + } + else + { + m_startItem = NULL; + m_startSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + } +} + +void PNS_TOOL_BASE::updateEndItem( TOOL_EVENT& aEvent ) +{ + VECTOR2I mp = m_ctls->GetMousePosition(); + VECTOR2I p = getView()->ToWorld( mp ); + VECTOR2I cp = m_ctls->GetCursorPosition(); + int layer; + bool snapEnabled = !aEvent.Modifier( MD_CTRL ); + + m_router->EnableSnapping( snapEnabled ); + + if( !snapEnabled || m_router->GetCurrentNet() < 0 || !m_startItem ) + { + m_endItem = NULL; + m_endSnapPoint = cp; + return; + } + + bool dummy; + + if( m_router->IsPlacingVia() ) + layer = -1; + else + layer = m_router->GetCurrentLayer(); + + PNS_ITEM* endItem = pickSingleItem( p, m_startItem->Net(), layer ); + + if( endItem ) + { + VECTOR2I cursorPos = m_router->SnapToItem( endItem, p, dummy ); + m_ctls->ForceCursorPosition( true, cursorPos ); + m_endItem = endItem; + m_endSnapPoint = cursorPos; + } + else + { + m_endItem = NULL; + m_endSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + + if( m_endItem ) + TRACE( 0, "%s, layer : %d", m_endItem->KindStr().c_str() % m_endItem->Layers().Start() ); +} + diff --git a/pcbnew/router/pns_tool_base.h b/pcbnew/router/pns_tool_base.h new file mode 100644 index 0000000000..9778b0e999 --- /dev/null +++ b/pcbnew/router/pns_tool_base.h @@ -0,0 +1,74 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * 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 + * 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_TOOL_BASE_H +#define __PNS_TOOL_BASE_H + +#include + +#include +#include + +#include + +#include "pns_router.h" + +class PNS_TUNE_STATUS_POPUP; + +class APIEXPORT PNS_TOOL_BASE : public TOOL_INTERACTIVE +{ +public: + static TOOL_ACTION ACT_RouterOptions; + + PNS_TOOL_BASE( const std::string& aToolName ); + virtual ~PNS_TOOL_BASE(); + + virtual void Reset( RESET_REASON aReason ); + +protected: + + virtual PNS_ITEM* pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); + virtual void highlightNet( bool aEnabled, int aNetcode = -1 ); + virtual void updateStartItem( TOOL_EVENT& aEvent ); + virtual void updateEndItem( TOOL_EVENT& aEvent ); + + MSG_PANEL_ITEMS m_panelItems; + + PNS_ROUTER* m_router; + PNS_ROUTING_SETTINGS m_savedSettings; ///< Stores routing settings between router invocations + PNS_SIZES_SETTINGS m_savedSizes; ///< Stores sizes settings between router invocations + PNS_ITEM* m_startItem; + int m_startLayer; + VECTOR2I m_startSnapPoint; + + PNS_ITEM* m_endItem; + VECTOR2I m_endSnapPoint; + + ///> Flag marking that the router's world needs syncing. + bool m_needsSync; + + PCB_EDIT_FRAME *m_frame; + KIGFX::VIEW_CONTROLS *m_ctls; + BOARD *m_board; + +}; + +#endif diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp new file mode 100644 index 0000000000..8fdc9a4770 --- /dev/null +++ b/pcbnew/router/pns_topology.cpp @@ -0,0 +1,360 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_line.h" +#include "pns_segment.h" +#include "pns_node.h" +#include "pns_joint.h" +#include "pns_solid.h" +#include "pns_router.h" + +#include "pns_diff_pair.h" +#include "pns_topology.h" + +#include + +bool PNS_TOPOLOGY::SimplifyLine ( PNS_LINE *aLine ) +{ + + if( !aLine->LinkedSegments() || !aLine->SegmentCount() ) + return false; + + PNS_SEGMENT *root = (*aLine->LinkedSegments())[0]; + std::auto_ptr l ( m_world->AssembleLine( root ) ); + SHAPE_LINE_CHAIN simplified ( l->CLine() ); + + simplified.Simplify(); + + if( simplified.PointCount() != l->PointCount() ) + { + std::auto_ptr lnew ( l->Clone() ); + m_world -> Remove( l.get() ); + lnew->SetShape( simplified ); + m_world -> Add( lnew.get() ); + return true; + } + + return false; +} + +const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints ( PNS_JOINT* aStart ) +{ + std::deque searchQueue; + JOINT_SET processed; + + searchQueue.push_back( aStart ); + processed.insert( aStart ); + + while( !searchQueue.empty() ) + { + PNS_JOINT* current = searchQueue.front(); + searchQueue.pop_front(); + + BOOST_FOREACH( PNS_ITEM* item, current->LinkList() ) + { + if ( item->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_SEGMENT* seg = static_cast( item ); + PNS_JOINT* a = m_world->FindJoint( seg->Seg().A, seg ); + PNS_JOINT* b = m_world->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 ); + } + } + } + } + + return processed; +} + + +bool PNS_TOPOLOGY::LeadingRatLine( const PNS_LINE *aTrack, SHAPE_LINE_CHAIN& aRatLine ) +{ + PNS_LINE track ( *aTrack ); + VECTOR2I end; + + if( !track.PointCount() ) + return false; + + std::auto_ptr tmpNode ( m_world->Branch() ); + tmpNode->Add( &track ); + + PNS_JOINT* jt = tmpNode->FindJoint( track.CPoint( -1 ), &track ); + + if ( !jt ) + return false; + + if( (!track.EndsWithVia() && jt->LinkCount() >= 2) || (track.EndsWithVia() && jt->LinkCount() >= 3 )) // we got something connected + { + end = jt->Pos(); + } else { + int anchor; + + PNS_TOPOLOGY topo ( tmpNode.get() ); + PNS_ITEM* it = topo.NearestUnconnectedItem( jt, &anchor ); + + if( !it ) + return false; + + end = it->Anchor( anchor ); + } + + aRatLine.Clear(); + aRatLine.Append ( track.CPoint( -1 ) ); + aRatLine.Append ( end ); + return true; +} + +PNS_ITEM* PNS_TOPOLOGY::NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor, int aKindMask ) +{ + std::set disconnected; + + m_world->AllItemsInNet( aStart->Net(), disconnected ); + + BOOST_FOREACH( const PNS_JOINT *jt, ConnectedJoints ( aStart ) ) + { + 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; +} + + +bool PNS_TOPOLOGY::followTrivialPath ( PNS_LINE *aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ) +{ + VECTOR2I anchor = aLeft ? aLine->CPoint(0) : aLine->CPoint(-1); + PNS_SEGMENT *last = aLeft ? aLine->LinkedSegments()->front() : aLine->LinkedSegments()->back(); + PNS_JOINT *jt = m_world->FindJoint ( anchor, aLine ); + + assert (jt != NULL); + + aVisited.insert( last ); + + if( jt->IsNonFanoutVia() ) + { + PNS_ITEM *via = NULL; + PNS_SEGMENT *next_seg = NULL; + + BOOST_FOREACH ( PNS_ITEM *link, jt->Links().Items() ) + { + if( link->OfKind ( PNS_ITEM::VIA ) ) + via = link; + else if( aVisited.find(link) == aVisited.end() ) + next_seg = static_cast (link); + } + + if(!next_seg) + return false; + + PNS_LINE *l = m_world->AssembleLine ( next_seg ); + + VECTOR2I nextAnchor = (aLeft ? l->CLine().CPoint(-1) : l->CLine().CPoint(0) ); + + if (nextAnchor != anchor) + { + l->Reverse(); + } + + if (aLeft) + { + aSet.Prepend ( via ); + aSet.Prepend ( l ); + } else { + aSet.Add ( via ); + aSet.Add ( l ); + } + + return followTrivialPath ( l, aLeft, aSet, aVisited ); + } + return false; +} + +const PNS_ITEMSET PNS_TOPOLOGY::AssembleTrivialPath ( PNS_SEGMENT *aStart ) +{ + PNS_ITEMSET path; + std::set visited; + + PNS_LINE *l = m_world->AssembleLine ( aStart ); + + path.Add ( l ); + + followTrivialPath( l, false, path, visited ); + followTrivialPath( l, true, path, visited ); + + return path; +} + +const PNS_ITEMSET PNS_TOPOLOGY::ConnectedItems( PNS_JOINT* aStart, int aKindMask ) +{ + return PNS_ITEMSET(); +} + +const PNS_ITEMSET PNS_TOPOLOGY::ConnectedItems( PNS_ITEM* aStart, int aKindMask ) +{ + return PNS_ITEMSET(); +} + +int PNS_TOPOLOGY::MatchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) +{ + int rv = 0; + if (aNetName.EndsWith("+")) + { + aComplementNet = "-"; + rv = 1; + } else if (aNetName.EndsWith("_P")) + { + aComplementNet = "_N"; + rv = 1; + } else if (aNetName.EndsWith("-")) + { + aComplementNet = "+"; + rv = -1; + } else if (aNetName.EndsWith("_N")) + { + aComplementNet = "_P"; + rv = -1; + } + + if (rv != 0) { + aBaseDpName = aNetName.Left ( aNetName.Length() - aComplementNet.Length() ); + aComplementNet = aBaseDpName + aComplementNet; + } + + return rv; +} + + +int PNS_TOPOLOGY::DpCoupledNet( int aNet ) +{ + BOARD *brd = PNS_ROUTER::GetInstance()->GetBoard(); + + wxString refName = brd->FindNet ( aNet )->GetNetname(); + wxString dummy, coupledNetName; + + if ( MatchDpSuffix ( refName, coupledNetName, dummy ) ) + { + NETINFO_ITEM *net = brd->FindNet ( coupledNetName ); + + if(!net) + return -1; + + return net->GetNet(); + + } + + return -1; +} + + +int PNS_TOPOLOGY::DpNetPolarity( int aNet ) +{ + BOARD *brd = PNS_ROUTER::GetInstance()->GetBoard(); + + wxString refName = brd->FindNet ( aNet )->GetNetname(); + wxString dummy1, dummy2; + + return MatchDpSuffix ( refName, dummy1, dummy2 ); +} + + +bool PNS_TOPOLOGY::AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ) +{ + int refNet = aStart->Net(); + int coupledNet = DpCoupledNet ( refNet ); + + if(coupledNet < 0) + return false; + + std::set coupledItems; + + m_world->AllItemsInNet( coupledNet, coupledItems ); + + PNS_SEGMENT *coupledSeg = NULL, *refSeg; + int minDist = std::numeric_limits::max(); + + if( ( refSeg = dyn_cast( aStart ) ) != NULL ) + { + BOOST_FOREACH ( PNS_ITEM *item, coupledItems ) + { + if ( PNS_SEGMENT *s = dyn_cast(item) ) + { + if( s->Layers().Start() == refSeg->Layers().Start() && s->Width() == refSeg->Width() ) + { + int dist = s->Seg().Distance( refSeg->Seg() ); + + if(dist < minDist) + { + minDist = dist; + coupledSeg = s; + } + } + } + } + } else + return false; + + if(!coupledSeg) + return false; + + std::auto_ptr lp ( m_world->AssembleLine ( refSeg ) ); + std::auto_ptr ln ( m_world->AssembleLine ( coupledSeg ) ); + + if(DpNetPolarity(refNet) < 0) + { + std::swap (lp, ln); + } + + aPair = PNS_DIFF_PAIR ( *lp, *ln ); + aPair.SetWidth ( lp->Width() ); + aPair.SetLayers ( lp->Layers() ); + return true; +} diff --git a/pcbnew/router/pns_topology.h b/pcbnew/router/pns_topology.h new file mode 100644 index 0000000000..5233cb71c0 --- /dev/null +++ b/pcbnew/router/pns_topology.h @@ -0,0 +1,75 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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_TOPOLOGY_H +#define __PNS_TOPOLOGY_H + +#include +#include + +#include "pns_itemset.h" + +class PNS_NODE; +class PNS_SEGMENT; +class PNS_JOINT; +class PNS_ITEM; +class PNS_SOLID; +class PNS_DIFF_PAIR; + +class PNS_TOPOLOGY +{ + public: + typedef std::set JOINT_SET; + + PNS_TOPOLOGY ( PNS_NODE *aNode ): + m_world ( aNode ) {}; + + ~PNS_TOPOLOGY ( ) {}; + + bool SimplifyLine ( PNS_LINE *aLine ); + PNS_ITEM* NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor = NULL, int aKindMask = PNS_ITEM::ANY ); + bool LeadingRatLine( const PNS_LINE *aTrack, SHAPE_LINE_CHAIN& aRatLine ); + + const JOINT_SET ConnectedJoints ( PNS_JOINT* aStart ); + const PNS_ITEMSET ConnectedItems ( PNS_JOINT* aStart, int aKindMask = PNS_ITEM::ANY ); + const PNS_ITEMSET ConnectedItems ( PNS_ITEM* aStart, int aKindMask = PNS_ITEM::ANY ); + int64_t ShortestConnectionLength ( PNS_ITEM *aFrom, PNS_ITEM *aTo ); + + + + const PNS_ITEMSET AssembleTrivialPath ( PNS_SEGMENT *aStart ); + const PNS_DIFF_PAIR AssembleDiffPair ( PNS_SEGMENT *aStart ); + + int MatchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); + int DpCoupledNet( int aNet ); + int DpNetPolarity( int aNet ); + const PNS_LINE DpCoupledLine( PNS_LINE *aLine ); + bool AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ); + + + + private: + + bool followTrivialPath ( PNS_LINE *aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ); + + PNS_NODE *m_world; +}; + +#endif diff --git a/pcbnew/router/pns_tune_status_popup.cpp b/pcbnew/router/pns_tune_status_popup.cpp new file mode 100644 index 0000000000..924169af97 --- /dev/null +++ b/pcbnew/router/pns_tune_status_popup.cpp @@ -0,0 +1,69 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014-2015 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, see . + */ + +#include "pns_tune_status_popup.h" +#include "pns_router.h" +#include "pns_meander_placer.h" + +PNS_TUNE_STATUS_POPUP::PNS_TUNE_STATUS_POPUP ( PCB_EDIT_FRAME *parent ) : + WX_STATUS_POPUP ( parent ) +{ + m_panel->SetBackgroundColour( wxColour(64,64,64) ); + m_statusLine = new wxStaticText( m_panel, wxID_ANY, + wxT("Status text 1\n") ) ; + m_topSizer->Add( m_statusLine, 1, wxALL | wxEXPAND, 5 ); + + updateSize(); +} + +PNS_TUNE_STATUS_POPUP::~PNS_TUNE_STATUS_POPUP() +{ + +} + +void PNS_TUNE_STATUS_POPUP::Update( PNS_ROUTER *aRouter ) +{ + PNS_MEANDER_PLACER_BASE *placer = dynamic_cast ( aRouter->Placer() ); + + if(!placer) + return; + + m_statusLine->SetLabel ( placer->TuningInfo() ); + + wxColour color; + + switch ( placer->TuningStatus() ) + { + case PNS_MEANDER_PLACER::TUNED: + color = wxColour ( 0, 255, 0 ); + break; + case PNS_MEANDER_PLACER::TOO_SHORT: + color = wxColour ( 255, 128, 128 ); + break; + case PNS_MEANDER_PLACER::TOO_LONG: + color = wxColour ( 128, 128, 255 ); + break; + } + + m_statusLine->SetForegroundColour (color); + + updateSize(); +} + diff --git a/pcbnew/router/pns_tune_status_popup.h b/pcbnew/router/pns_tune_status_popup.h new file mode 100644 index 0000000000..9a894f3ed4 --- /dev/null +++ b/pcbnew/router/pns_tune_status_popup.h @@ -0,0 +1,45 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 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 __PNS_TUNE_STATUS_POPUP_H_ +#define __PNS_TUNE_STATUS_POPUP_H_ + +#include + +class PNS_ROUTER; + +class PNS_TUNE_STATUS_POPUP : public WX_STATUS_POPUP +{ +public: + PNS_TUNE_STATUS_POPUP ( PCB_EDIT_FRAME *parent ); + ~PNS_TUNE_STATUS_POPUP(); + + + void Update( PNS_ROUTER *aRouter ); + +private: + wxStaticText *m_statusLine; +}; + +#endif /* __PNS_TUNE_STATUS_POPUP_H_*/ diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index 5a69e673d8..5635893e10 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -20,6 +20,7 @@ #include "pns_utils.h" #include "pns_line.h" +#include "pns_via.h" #include "pns_router.h" #include @@ -91,3 +92,83 @@ SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ) 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 ) ); } + +void DrawDebugPoint ( VECTOR2I p, int color ) +{ + SHAPE_LINE_CHAIN l; + + l.Append ( p - VECTOR2I(-50000, -50000) ); + l.Append ( p + VECTOR2I(-50000, -50000) ); + + //printf("router @ %p\n", PNS_ROUTER::GetInstance()); + PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + + l.Clear(); + l.Append ( p - VECTOR2I(50000, -50000) ); + l.Append ( p + VECTOR2I(50000, -50000) ); + + PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); +} + +void DrawDebugBox ( BOX2I b, int color ) +{ + SHAPE_LINE_CHAIN l; + + VECTOR2I o = b.GetOrigin(); + VECTOR2I s = b.GetSize(); + + l.Append ( o ); + l.Append ( o.x + s.x, o.y ); + l.Append ( o.x + s.x, o.y + s.y ); + l.Append ( o.x, o.y + s.y ); + l.Append ( o ); + + //printf("router @ %p\n", PNS_ROUTER::GetInstance()); + PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); +} + +void DrawDebugSeg ( SEG s, int color ) +{ + SHAPE_LINE_CHAIN l; + + l.Append ( s.A ); + l.Append ( s.B ); + + PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); +} + +void DrawDebugDirs ( VECTOR2D p, int mask, int color ) +{ + BOX2I b ( p - VECTOR2I ( 10000, 10000 ), VECTOR2I ( 20000, 20000 ) ); + + DrawDebugBox ( b, color ); + for (int i = 0; i < 8; i++) + { + if ( (1<OfKind ( PNS_ITEM::VIA ) && aItemB->OfKind ( PNS_ITEM::VIA ) ) + { + const PNS_VIA *va = static_cast (aItemA); + const PNS_VIA *vb = static_cast (aItemB); + + return va->ChangedArea (vb); + } else if ( aItemA->OfKind ( PNS_ITEM::LINE ) && aItemB->OfKind ( PNS_ITEM::LINE ) ) + { + const PNS_LINE *la = static_cast (aItemA); + const PNS_LINE *lb = static_cast (aItemB); + + return la->ChangedArea (lb); + } + return OPT_BOX2I(); +} \ No newline at end of file diff --git a/pcbnew/router/pns_utils.h b/pcbnew/router/pns_utils.h index 5bf6d9313b..01f1f0bb6f 100644 --- a/pcbnew/router/pns_utils.h +++ b/pcbnew/router/pns_utils.h @@ -22,12 +22,15 @@ #define __PNS_UTILS_H #include +#include #include #include #include #define HULL_MARGIN 10 +class PNS_ITEM; + /** Various utility functions */ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize, @@ -38,4 +41,12 @@ const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ); +void DrawDebugPoint ( VECTOR2I p, int color ); +void DrawDebugBox ( BOX2I b, int color ); +void DrawDebugSeg ( SEG s, int color ); +void DrawDebugDirs ( VECTOR2D p, int mask, int color ); + +OPT_BOX2I ChangedArea ( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB ); + + #endif // __PNS_UTILS_H diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index 1b5c369bf2..06acf533ea 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -95,3 +95,15 @@ PNS_VIA* PNS_VIA::Clone ( ) const return v; } + +OPT_BOX2I PNS_VIA::ChangedArea ( const PNS_VIA *aOther ) const +{ + if ( aOther->Pos() != Pos() ) + { + BOX2I tmp = Shape()->BBox( ); + tmp.Merge ( aOther->Shape()->BBox( ) ); + return tmp; + } + + return OPT_BOX2I(); +} diff --git a/pcbnew/router/pns_via.h b/pcbnew/router/pns_via.h index b7637e9f13..1a2dc1d7e8 100644 --- a/pcbnew/router/pns_via.h +++ b/pcbnew/router/pns_via.h @@ -73,6 +73,12 @@ public: m_viaType = aB.m_viaType; } + static inline bool ClassOf( const PNS_ITEM* aItem ) + { + return aItem && VIA == aItem->Kind(); + } + + const VECTOR2I& Pos() const { return m_pos; @@ -140,6 +146,8 @@ public: return 1; } + OPT_BOX2I ChangedArea ( const PNS_VIA *aOther ) const; + private: int m_diameter; int m_drill; diff --git a/pcbnew/router/pns_walkaround.cpp b/pcbnew/router/pns_walkaround.cpp index bbe8d2bca3..9c81860551 100644 --- a/pcbnew/router/pns_walkaround.cpp +++ b/pcbnew/router/pns_walkaround.cpp @@ -136,7 +136,7 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia PNS_LINE& aWalkPath, bool aOptimize ) { PNS_LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); - WALKAROUND_STATUS s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; + WALKAROUND_STATUS s_cw, s_ccw; // = IN_PROGRESS, s_ccw = IN_PROGRESS; SHAPE_LINE_CHAIN best_path; start( aInitialPath ); @@ -146,6 +146,17 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia aWalkPath = aInitialPath; + if(m_forceWinding) + { + s_cw = m_forceCw ? IN_PROGRESS : STUCK; + s_ccw = m_forceCw ? STUCK : IN_PROGRESS; + m_forceSingleDirection = true; + + } else { + + m_forceSingleDirection = false; + } + while( m_iteration < m_iterationLimit ) { if( s_cw != STUCK ) @@ -229,17 +240,20 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia 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 ); + if( st == DONE ) + { + if( aOptimize ) + 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 95c2079b61..939ba426d0 100644 --- a/pcbnew/router/pns_walkaround.h +++ b/pcbnew/router/pns_walkaround.h @@ -39,6 +39,7 @@ public: { m_forceSingleDirection = false; m_forceLongerPath = false; + m_forceWinding = false; m_cursorApproachMode = false; m_itemMask = PNS_ITEM::ANY; } @@ -79,7 +80,11 @@ public: { m_forceSingleDirection = aForceSingleDirection; m_forceLongerPath = aForceSingleDirection; - //printf("FSD %d FPD %d\n", m_forceSingleDirection?1:0, m_forceLongerPath ? 1: 0); + } + + void SetSingleDirection2( bool aForceSingleDirection ) + { + m_forceSingleDirection = aForceSingleDirection; } void SetApproachCursor( bool aEnabled, const VECTOR2I& aPos ) @@ -88,6 +93,12 @@ public: m_cursorApproachMode = aEnabled; } + void SetForceWinding ( bool aEnabled, bool aCw ) + { + m_forceCw = aCw; + m_forceWinding = aEnabled; + } + WALKAROUND_STATUS Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize = true ); @@ -110,6 +121,8 @@ private: int m_itemMask; bool m_forceSingleDirection, m_forceLongerPath; bool m_cursorApproachMode; + bool m_forceWinding; + bool m_forceCw; VECTOR2I m_cursorPos; PNS_NODE::OPT_OBSTACLE m_currentObstacle[2]; bool m_recursiveCollision[2]; diff --git a/pcbnew/router/ranged_num.h b/pcbnew/router/ranged_num.h new file mode 100644 index 0000000000..99a5940e71 --- /dev/null +++ b/pcbnew/router/ranged_num.h @@ -0,0 +1,53 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2015 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 __RANGED_NUM_H +#define __RANGED_NUM_H + +template class RANGED_NUM { + public: + RANGED_NUM ( T aValue = 0, T aTollerancePlus = 0, T aTolleranceMinus = 0) : + m_value (aValue), + m_tollerancePlus ( aTollerancePlus ), + m_tolleranceMinus ( aTolleranceMinus ) + {} + + operator T() + { + return m_value; + } + + RANGED_NUM& operator= ( const T aValue ) + { + m_value = aValue; + return *this; + } + + bool Matches ( const T& aOther ) const + { + return ( aOther >= m_value - m_tolleranceMinus && aOther <= m_value + m_tollerancePlus ); + } + + private: + T m_value, m_tollerancePlus, m_tolleranceMinus; + +}; + +#endif diff --git a/pcbnew/router/router_menus.h b/pcbnew/router/router_menus.h new file mode 100644 index 0000000000..bafd7360ca --- /dev/null +++ b/pcbnew/router/router_menus.h @@ -0,0 +1,981 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * 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 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 +#include +#include + +#include "class_draw_panel_gal.h" +#include "class_board.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "router_tool.h" +#include "pns_segment.h" +#include "pns_router.h" +#include "pns_meander_placer.h" // fixme: move settings to separate header +#include "pns_tune_status_popup.h" +#include "trace.h" + +using namespace KIGFX; +using boost::optional; + +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_PlaceBlindVia( "pcbnew.InteractiveRouter.PlaceBlindVia", + AS_CONTEXT, 'Z', + "Place Blind/Buried Via", "Adds a blind or buried via at the end of currently routed track." ); +static TOOL_ACTION ACT_PlaceMicroVia( "pcbnew.InteractiveRouter.PlaceMicroVia", + AS_CONTEXT, 'Q', + "Place Microvia", "Adds a microvia 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."); + +static TOOL_ACTION ACT_SetDpDimensions( "pcbnew.InteractiveRouter.SetDpDimensions", + AS_CONTEXT, 'D', + "Differential Pair Dimensions...", "Sets the width and gap of the currently routed differential pair."); + +static TOOL_ACTION ACT_SetLengthTune( "pcbnew.InteractiveRouter.LengthTunerSettings", + AS_CONTEXT, 'L', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + +static TOOL_ACTION ACT_LengthTuneSpacingIncrease( "pcbnew.InteractiveRouter.LengthTunerSpacingIncrease", + AS_CONTEXT, '1', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + +static TOOL_ACTION ACT_LengthTuneSpacingDecrease( "pcbnew.InteractiveRouter.LengthTunerSpacingDecrease", + AS_CONTEXT, '2', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + +static TOOL_ACTION ACT_SetLengthTuneAmplIncrease( "pcbnew.InteractiveRouter.LengthTunerAmplIncrease", + AS_CONTEXT, '3', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + +static TOOL_ACTION ACT_SetLengthTuneAmplDecrease( "pcbnew.InteractiveRouter.LengthTunerAmplDecrease", + AS_CONTEXT, '4', + "Length Tuning Settings", "Sets the length tuning parameters for currently routed item."); + + +ROUTER_TOOL::ROUTER_TOOL() : + TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) +{ + m_router = NULL; +} + + +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, PNS_ROUTER_MODE aMode ) + { + 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_PlaceBlindVia ); + Add( ACT_PlaceMicroVia ); + 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 ); + + if ( aMode == PNS_MODE_ROUTE_DIFF_PAIR ) + Add( ACT_SetDpDimensions ); + + AppendSeparator(); + Add( ACT_RouterOptions ); + } +}; + + +ROUTER_TOOL::~ROUTER_TOOL() +{ + delete m_router; +} + + +void ROUTER_TOOL::Reset( RESET_REASON aReason ) +{ + printf("RESET\n"); + if( m_router ) + delete m_router; + + m_frame = getEditFrame(); + m_ctls = getViewControls(); + m_board = getModel(); + + m_router = new PNS_ROUTER; + + m_router->ClearWorld(); + m_router->SetBoard( m_board ); + m_router->SyncWorld(); + m_router->LoadSettings( m_savedSettings ); + m_router->UpdateSizes( m_savedSizes ); + m_needsSync = false; + + if( getView() ) + m_router->SetView( getView() ); + + Go( &ROUTER_TOOL::RouteSingleTrace, COMMON_ACTIONS::routerActivateSingle.MakeEvent() ); + Go( &ROUTER_TOOL::RouteDiffPair, COMMON_ACTIONS::routerActivateDiffPair.MakeEvent() ); + Go( &ROUTER_TOOL::TuneSingleTrace, COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent() ); +} + +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 ) +{ + BOARD_DESIGN_SETTINGS &bds = m_board->GetDesignSettings(); + + NETCLASSPTR netClass; + NETINFO_ITEM* ni = m_board->FindNet( aNetCode ); + + if( ni ) + { + wxString netClassName = ni->GetClassName(); + netClass = bds.m_NetClasses.Find( netClassName ); + } + + if( !netClass ) + netClass = bds.GetDefault(); + + aWidth = netClass->GetTrackWidth(); + aViaDiameter = netClass->GetViaDiameter(); + aViaDrill = netClass->GetViaDrill(); +} + + +PNS_ITEM* ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) +{ + int tl = getView()->GetTopLayer(); + + if( aLayer > 0 ) + tl = aLayer; + + 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->Layers().Start() ) ) + continue; + + // fixme: this causes flicker with live loop removal... + //if( item->Parent() && !item->Parent()->ViewIsVisible() ) + // continue; + + if( aNet < 0 || item->Net() == aNet ) + { + if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) + { + if( !prioritized[2] ) + prioritized[2] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[0] = item; + } + else + { + if( !prioritized[3] ) + prioritized[3] = item; + if( item->Layers().Overlaps( tl ) ) + prioritized[1] = item; + } + } + } + + PNS_ITEM* rv = NULL; + PCB_EDIT_FRAME* frame = getEditFrame (); + DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions(); + + for( int i = 0; i < 4; i++ ) + { + PNS_ITEM* item = prioritized[i]; + + if( displ_opts->m_ContrastModeDisplay ) + if( item && !item->Layers().Overlaps( tl ) ) + item = NULL; + + if( item ) + { + rv = item; + break; + } + } + + if( rv && aLayer >= 0 && !rv->Layers().Overlaps( aLayer ) ) + rv = NULL; + + if( rv ) + TRACE( 0, "%s, layer : %d, tl: %d", rv->KindStr().c_str() % rv->Layers().Start() % tl ); + + return rv; +} + + +void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode ) +{ + RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings(); + + if( aNetcode >= 0 && aEnabled ) + rs->SetHighlight( true, aNetcode ); + else + rs->SetHighlight( false ); + + getView()->UpdateAllLayersColor(); +} + + +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_frame, m_router->Settings() ); + + if( settingsDlg.ShowModal() ) + { + // FIXME: do we need an explicit update? + } + } + else if( aEvent.IsAction( &ACT_SetDpDimensions ) ) + { + PNS_SIZES_SETTINGS sizes = m_router->Sizes(); + DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( m_frame, sizes ); + + if( settingsDlg.ShowModal() ) + { + m_router->UpdateSizes( sizes ); + } + } + else if( aEvent.IsAction( &ACT_SetLengthTune ) ) + { + PNS_MEANDER_PLACER *placer = dynamic_cast ( m_router->Placer() ); + + if(!placer) + return; + + PNS_MEANDER_SETTINGS settings = placer->Settings(); + DIALOG_PNS_LENGTH_TUNING_SETTINGS settingsDlg( m_frame, settings, m_router->Mode() ); + + if( settingsDlg.ShowModal() ) + { + placer->UpdateSettings ( settings ); + } + } + else if( aEvent.IsAction( &ACT_CustomTrackWidth ) ) + { + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + DIALOG_TRACK_VIA_SIZE sizeDlg( m_frame, bds ); + + if( sizeDlg.ShowModal() ) + { + bds.UseCustomTrackViaSize( true ); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); + } + } + + else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) + { + + PNS_SIZES_SETTINGS sizes ( m_savedSizes ); + sizes.ImportCurrent ( m_board->GetDesignSettings() ); + m_router->UpdateSizes ( sizes ); + } +} + + +void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) +{ + int tl = getView()->GetTopLayer(); + VECTOR2I cp = m_ctls->GetCursorPosition(); + PNS_ITEM* startItem = NULL; + + if( aEvent.IsMotion() || aEvent.IsClick() ) + { + bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); + + VECTOR2I p( aEvent.Position() ); + startItem = pickSingleItem( p ); + m_router->EnableSnapping ( snapEnabled ); + + if( !snapEnabled && startItem && !startItem->Layers().Overlaps( tl ) ) + startItem = NULL; + + if( startItem && startItem->Net() >= 0 ) + { + bool dummy; + VECTOR2I psnap = m_router->SnapToItem( startItem, p, dummy ); + + if( snapEnabled ) + { + m_startSnapPoint = psnap; + m_ctls->ForceCursorPosition( true, psnap ); + } + else + { + m_startSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + +// if( startItem->Layers().IsMultilayer() ) +// m_startLayer = tl; +// else +// m_startLayer = startItem->Layers().Start(); + + m_startItem = startItem; + } + else + { + m_startItem = NULL; + m_startSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + } +} + + +void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) +{ + VECTOR2I mp = m_ctls->GetMousePosition(); + VECTOR2I p = getView()->ToWorld( mp ); + VECTOR2I cp = m_ctls->GetCursorPosition(); + int layer; + bool snapEnabled = !aEvent.Modifier( MD_CTRL ); + + m_router->EnableSnapping( snapEnabled ); + + if( !snapEnabled || m_router->GetCurrentNet() < 0 || !m_startItem ) + { + m_endItem = NULL; + m_endSnapPoint = cp; + return; + } + + bool dummy; + + if( m_router->IsPlacingVia() ) + layer = -1; + else + layer = m_router->GetCurrentLayer(); + + PNS_ITEM* endItem = pickSingleItem( p, m_startItem->Net(), layer ); + + if( endItem ) + { + VECTOR2I cursorPos = m_router->SnapToItem( endItem, p, dummy ); + m_ctls->ForceCursorPosition( true, cursorPos ); + m_endItem = endItem; + m_endSnapPoint = cursorPos; + } + else + { + m_endItem = NULL; + m_endSnapPoint = cp; + m_ctls->ForceCursorPosition( false ); + } + + if( m_endItem ) + TRACE( 0, "%s, layer : %d", m_endItem->KindStr().c_str() % m_endItem->Layers().Start() ); +} + +int ROUTER_TOOL::getStartLayer( const PNS_ITEM* aItem ) +{ + int tl = getView()->GetTopLayer(); + + if( m_startItem ) + { + const PNS_LAYERSET& ls = m_startItem->Layers(); + + if( ls.Overlaps( tl ) ) + return tl; + else + return ls.Start(); + } + + return tl; +} +void ROUTER_TOOL::switchLayerOnViaPlacement() +{ + int al = m_frame->GetActiveLayer(); + int cl = m_router->GetCurrentLayer(); + + if( cl != al ) + { + m_router->SwitchLayer( al ); + } + + optional newLayer = m_router->Sizes().PairedLayer( cl ); + + if( newLayer ) + { + m_router->SwitchLayer ( *newLayer ); + m_frame->SetActiveLayer ( ToLAYER_ID( *newLayer ) ); + } +} + +bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) +{ + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + + const int layerCount = bds.GetCopperLayerCount(); + int currentLayer = m_router->GetCurrentLayer(); + + PNS_SIZES_SETTINGS sizes = m_router->Sizes(); + + // fixme: P&S supports more than one fixed layer pair. Update the dialog? + sizes.ClearLayerPairs(); + sizes.AddLayerPair( m_frame->GetScreen()->m_Route_Layer_TOP, + m_frame->GetScreen()->m_Route_Layer_BOTTOM ); + + if( !m_router->IsPlacingVia() ) + { + // Cannot place microvias or blind vias if not allowed (obvious) + if( ( aType == VIA_BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) ) + return false; + if( ( aType == VIA_MICROVIA ) && ( !bds.m_MicroViasAllowed ) ) + return false; + + //Can only place through vias on 2-layer boards + if( ( aType != VIA_THROUGH ) && ( layerCount <= 2 ) ) + return false; + + //Can only place microvias if we're on an outer layer, or directly adjacent to one + if( ( aType == VIA_MICROVIA ) && ( currentLayer > In1_Cu ) && ( currentLayer < layerCount-2 ) ) + return false; + + //Cannot place blind vias with front/back as the layer pair, this doesn't make sense + if( ( aType == VIA_BLIND_BURIED ) && ( sizes.GetLayerTop() == F_Cu ) && ( sizes.GetLayerBottom() == B_Cu ) ) + return false; + } + + + sizes.SetViaType ( aType ); + m_router->ToggleViaPlacement( ); + m_router->UpdateSizes( sizes ); + + m_router->Move( m_endSnapPoint, m_endItem ); // refresh + + return false; +} + +//void ROUTER_TOOL::prepareRouting() +//{} + +void ROUTER_TOOL::performRouting() +{ + bool saveUndoBuffer = true; + + int routingLayer = getStartLayer ( m_startItem ); + m_frame->SetActiveLayer( ToLAYER_ID ( routingLayer ) ); + // fixme: switch on invisible layer + + if( m_startItem && m_startItem->Net() >= 0 ) + { + highlightNet( true, m_startItem->Net() ); + // Update track width and via size shown in main toolbar comboboxes + m_frame->SetCurrentNetClass( m_startItem->Parent()->GetNetClass()->GetName() ); + } + else + m_frame->SetCurrentNetClass( NETCLASS::Default ); + + m_ctls->ForceCursorPosition( false ); + m_ctls->SetAutoPan( true ); + + PNS_SIZES_SETTINGS sizes ( m_savedSizes ); + sizes.Init ( m_board, m_startItem ); + sizes.AddLayerPair ( m_frame->GetScreen()->m_Route_Layer_TOP, + m_frame->GetScreen()->m_Route_Layer_BOTTOM ); + m_router->UpdateSizes( sizes ); + + if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) ) + { + wxMessageBox ( m_router->FailureReason(), _("Error") ); + highlightNet ( false ); + return; + } + + + m_tuneStatusPopup = new PNS_TUNE_STATUS_POPUP ( m_frame ); + m_tuneStatusPopup->Popup(); + + m_endItem = NULL; + m_endSnapPoint = m_startSnapPoint; + + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( evt->IsCancel() || evt->IsActivate() ) + break; + else if( evt->Action() == TA_UNDO_REDO ) + { + saveUndoBuffer = false; + break; + } + else if( evt->IsMotion() ) + { + + wxPoint p = wxGetMousePosition(); + p.x+=20; + p.y+=20; + m_tuneStatusPopup->Update (m_router); + m_tuneStatusPopup->Move(p); + + + updateEndItem( *evt ); + m_router->SetOrthoMode ( evt->Modifier ( MD_CTRL ) ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsClick( BUT_LEFT ) ) + { + updateEndItem( *evt ); + bool needLayerSwitch = m_router->IsPlacingVia(); + + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) + break; + + if( needLayerSwitch ) + switchLayerOnViaPlacement(); + + // Synchronize the indicated layer + m_frame->SetActiveLayer( ToLAYER_ID( m_router->GetCurrentLayer() ) ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsAction( &ACT_PlaceThroughVia ) ) + { + onViaCommand ( VIA_THROUGH ); + } + else if( evt->IsAction( &ACT_PlaceBlindVia ) ) + { + onViaCommand ( VIA_BLIND_BURIED ); + } + else if( evt->IsAction( &ACT_PlaceMicroVia ) ) + { + onViaCommand ( VIA_MICROVIA ); + } + else if( evt->IsAction( &ACT_SwitchPosture ) ) + { + m_router->FlipPosture(); + m_router->Move( m_endSnapPoint, m_endItem ); // refresh + } + else if( evt->IsAction( &COMMON_ACTIONS::layerChanged ) ) + { + updateEndItem( *evt ); + m_router->SwitchLayer( m_frame->GetActiveLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); // refresh + } + else if( evt->IsAction( &ACT_EndTrack ) ) + { + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) + break; + } + + handleCommonEvents( *evt ); + } + + m_router->StopRouting(); + + if( saveUndoBuffer ) + { + // Save the recent changes in the undo buffer + m_frame->SaveCopyInUndoList( m_router->GetUndoBuffer(), UR_UNSPECIFIED ); + m_router->ClearUndoBuffer(); + m_frame->OnModify(); + } + else + { + // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now + m_needsSync = true; + } + + delete m_tuneStatusPopup; + + m_ctls->SetAutoPan( false ); + m_ctls->ForceCursorPosition( false ); + highlightNet( false ); +} + +int ROUTER_TOOL::RouteSingleTrace( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Route Track" ) ); + return mainLoop( PNS_MODE_ROUTE_SINGLE ); +} + +int ROUTER_TOOL::RouteDiffPair( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Router Differential Pair" ) ); + return mainLoop( PNS_MODE_ROUTE_DIFF_PAIR ); +} + +int ROUTER_TOOL::TuneSingleTrace( TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Track Length" ) ); + return mainLoop( PNS_MODE_TUNE_SINGLE ); +} + +int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) +{ + PCB_EDIT_FRAME* frame = getEditFrame(); + BOARD* board = getModel(); + + // Deselect all items + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + + Activate(); + + m_router->SetMode ( aMode ); + + m_ctls->SetSnapping( true ); + m_ctls->ShowCursor( true ); + + std::auto_ptr ctxMenu ( new ROUTER_TOOL_MENU( board, aMode ) ); + SetContextMenu ( ctxMenu.get() ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( m_needsSync ) + { + m_router->SyncWorld(); + m_router->SetView( getView() ); + m_needsSync = false; + } + + if( evt->IsCancel() || evt->IsActivate() ) + break; // Finish + else if( evt->Action() == TA_UNDO_REDO ) + m_needsSync = true; + else if( evt->IsMotion() ) + updateStartItem( *evt ); + else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_NewTrack ) ) + { + updateStartItem( *evt ); + + if( evt->Modifier( MD_CTRL ) ) + performDragging(); + else + performRouting(); + } + else if( evt->IsAction( &ACT_Drag ) ) + performDragging(); + + handleCommonEvents( *evt ); + } + + // Restore the default settings + m_ctls->SetAutoPan( false ); + m_ctls->ShowCursor( false ); + frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + // Store routing settings till the next invocation + m_savedSettings = m_router->Settings(); + m_savedSizes = m_router->Sizes(); + + return 0; +} + +int ROUTER_TOOL::InlineDrag ( TOOL_EVENT& aEvent ) +{ + return 0; + + #if 0 + VIEW_CONTROLS* ctls = getViewControls(); + PCB_EDIT_FRAME* frame = getEditFrame(); + BOARD* board = getModel(); + + printf("RouterTool::InlineDrag!\n"); + Reset(); + + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + ctls->SetSnapping( true ); + ctls->ShowCursor( true ); + + m_startItem = m_router->QueryItemByParent ( ) + + bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem ); + + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( evt->IsCancel() ) + break; + else if( evt->IsMotion() ) + { + updateEndItem( *evt ); + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsUp( BUT_LEFT ) ) + { + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) + break; + } + } + + if( m_router->RoutingInProgress() ) + m_router->StopRouting(); + + return 0; + #endif + +} + +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() || evt->IsActivate() ) + 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_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index c51c91c18c..a3a44baf5a 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -57,8 +57,16 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS_ITEM* aItem ) { m_originLayer = aItem->Layers().Start(); - assert( m_originLayer >= 0 ); + if (aItem->OfKind ( PNS_ITEM::LINE )) + { + const PNS_LINE *l=static_cast (aItem); + if(!l->SegmentCount()) + return; + } + + assert( m_originLayer >= 0 ); + m_layer = m_originLayer; m_color = getLayerColor( m_originLayer ); m_color.a = 0.8; @@ -159,65 +167,65 @@ void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const 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 ) + case SH_LINE_CHAIN: { - aGal->SetLayerDepth( ClearanceOverlayDepth ); - aGal->SetStrokeColor( COLOR4D( DARKDARKGRAY ) ); - aGal->SetLineWidth( m_width + 2 * m_clearance ); + 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; } - break; - } - - case SH_CIRCLE: - { - const SHAPE_CIRCLE* c = (const SHAPE_CIRCLE*) m_shape; - aGal->DrawCircle( c->GetCenter(), c->GetRadius() ); - - if( m_clearance > 0 ) + case SH_CIRCLE: { - aGal->SetLayerDepth( ClearanceOverlayDepth ); - aGal->SetFillColor( COLOR4D( DARKDARKGRAY ) ); - aGal->SetIsStroke( false ); - aGal->DrawCircle( c->GetCenter(), c->GetRadius() + m_clearance ); + 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; } - 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 ) + case SH_RECT: { - 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 ) ); - } + const SHAPE_RECT* r = (const SHAPE_RECT*) m_shape; + aGal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() ); - break; - } + 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; + } case SH_CONVEX: case SH_POLYGON: diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index a36bc83da4..09f30942d5 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -75,17 +76,18 @@ static TOOL_ACTION ACT_PlaceMicroVia( "pcbnew.InteractiveRouter.PlaceMicroVia", 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."); +static TOOL_ACTION ACT_SetDpDimensions( "pcbnew.InteractiveRouter.SetDpDimensions", + AS_CONTEXT, 'D', + "Differential Pair Dimensions...", "Sets the width and gap of the currently routed differential pair."); + + ROUTER_TOOL::ROUTER_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) -{ - m_router = NULL; + PNS_TOOL_BASE( "pcbnew.InteractiveRouter" ) +{ } @@ -208,7 +210,7 @@ protected: class ROUTER_TOOL_MENU: public CONTEXT_MENU { public: - ROUTER_TOOL_MENU( BOARD* aBoard ) + ROUTER_TOOL_MENU( BOARD* aBoard, PNS_ROUTER_MODE aMode ) { SetTitle( wxT( "Interactive Router" ) ); Add( ACT_NewTrack ); @@ -227,40 +229,33 @@ public: AppendSubMenu( trackMenu, wxT( "Select Track Width" ) ); Add( ACT_CustomTrackWidth ); - + + if ( aMode == PNS_MODE_ROUTE_DIFF_PAIR ) + Add( ACT_SetDpDimensions ); + AppendSeparator(); - Add( ACT_RouterOptions ); + Add( PNS_TOOL_BASE::ACT_RouterOptions ); } }; ROUTER_TOOL::~ROUTER_TOOL() { - delete m_router; + } void ROUTER_TOOL::Reset( RESET_REASON aReason ) { - if( m_router ) - delete m_router; - - m_router = new PNS_ROUTER; - - TRACEn( 0, "Reset" ); - m_router->ClearWorld(); - m_router->SetBoard( getModel() ); - m_router->SyncWorld(); - m_router->LoadSettings( m_settings ); - m_needsSync = false; - - if( getView() ) - m_router->SetView( getView() ); - - Go( &ROUTER_TOOL::Main, COMMON_ACTIONS::routerActivate.MakeEvent() ); + PNS_TOOL_BASE::Reset( aReason ); + + Go( &ROUTER_TOOL::RouteSingleTrace, COMMON_ACTIONS::routerActivateSingle.MakeEvent() ); + Go( &ROUTER_TOOL::RouteDiffPair, COMMON_ACTIONS::routerActivateDiffPair.MakeEvent() ); + Go( &ROUTER_TOOL::DpDimensionsDialog, COMMON_ACTIONS::routerActivateDpDimensionsDialog.MakeEvent() ); + Go( &ROUTER_TOOL::SettingsDialog, COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent() ); + } - int ROUTER_TOOL::getDefaultWidth( int aNetCode ) { int w, d1, d2; @@ -274,11 +269,10 @@ int ROUTER_TOOL::getDefaultWidth( int aNetCode ) void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill ) { - BOARD* board = getModel(); - BOARD_DESIGN_SETTINGS &bds = board->GetDesignSettings(); + BOARD_DESIGN_SETTINGS &bds = m_board->GetDesignSettings(); NETCLASSPTR netClass; - NETINFO_ITEM* ni = board->FindNet( aNetCode ); + NETINFO_ITEM* ni = m_board->FindNet( aNetCode ); if( ni ) { @@ -294,96 +288,8 @@ void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth, aViaDrill = netClass->GetViaDrill(); } - -PNS_ITEM* ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) +void ROUTER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) { - int tl = getView()->GetTopLayer(); - - if( aLayer > 0 ) - tl = aLayer; - - 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->Layers().Start() ) ) - continue; - - // fixme: this causes flicker with live loop removal... - //if( item->Parent() && !item->Parent()->ViewIsVisible() ) - // continue; - - if( aNet < 0 || item->Net() == aNet ) - { - if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) - { - if( !prioritized[2] ) - prioritized[2] = item; - if( item->Layers().Overlaps( tl ) ) - prioritized[0] = item; - } - else - { - if( !prioritized[3] ) - prioritized[3] = item; - if( item->Layers().Overlaps( tl ) ) - prioritized[1] = item; - } - } - } - - PNS_ITEM* rv = NULL; - PCB_EDIT_FRAME* frame = getEditFrame (); - DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions(); - - for( int i = 0; i < 4; i++ ) - { - PNS_ITEM* item = prioritized[i]; - - if( displ_opts->m_ContrastModeDisplay ) - if( item && !item->Layers().Overlaps( tl ) ) - item = NULL; - - if( item ) - { - rv = item; - break; - } - } - - if( rv && aLayer >= 0 && !rv->Layers().Overlaps( aLayer ) ) - rv = NULL; - - if( rv ) - TRACE( 0, "%s, layer : %d, tl: %d", rv->KindStr().c_str() % rv->Layers().Start() % tl ); - - return rv; -} - - -void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode ) -{ - RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings(); - - if( aNetcode >= 0 && aEnabled ) - rs->SetHighlight( true, aNetcode ); - else - rs->SetHighlight( false ); - - getView()->UpdateAllLayersColor(); -} - - -void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) -{ - PCB_EDIT_FRAME* frame = getEditFrame (); - BOARD* board = getModel (); - #ifdef DEBUG if( aEvent.IsKeyPressed() ) { @@ -399,18 +305,27 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) #endif if( aEvent.IsAction( &ACT_RouterOptions ) ) { - DIALOG_PNS_SETTINGS settingsDlg( frame, m_router->Settings() ); + DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() ); if( settingsDlg.ShowModal() ) { // FIXME: do we need an explicit update? } } + else if( aEvent.IsAction( &ACT_SetDpDimensions ) ) + { + PNS_SIZES_SETTINGS sizes = m_router->Sizes(); + DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( m_frame, sizes ); + if( settingsDlg.ShowModal() ) + { + m_router->UpdateSizes( sizes ); + } + } else if( aEvent.IsAction( &ACT_CustomTrackWidth ) ) { - BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); - DIALOG_TRACK_VIA_SIZE sizeDlg( frame, bds ); + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + DIALOG_TRACK_VIA_SIZE sizeDlg( m_frame, bds ); if( sizeDlg.ShowModal() ) { @@ -422,107 +337,12 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) { - PNS_SIZES_SETTINGS sizes; - sizes.ImportCurrent ( board->GetDesignSettings() ); + PNS_SIZES_SETTINGS sizes ( m_router->Sizes() ); + sizes.ImportCurrent ( m_board->GetDesignSettings() ); m_router->UpdateSizes ( sizes ); } } - -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( !snapEnabled && startItem && !startItem->Layers().Overlaps( tl ) ) - startItem = NULL; - - if( startItem && startItem->Net() >= 0 ) - { - bool dummy; - VECTOR2I psnap = m_router->SnapToItem( startItem, p, dummy ); - - if( snapEnabled ) - { - m_startSnapPoint = psnap; - ctls->ForceCursorPosition( true, psnap ); - } - else - { - m_startSnapPoint = cp; - ctls->ForceCursorPosition( false ); - } - -// if( startItem->Layers().IsMultilayer() ) -// m_startLayer = tl; -// else -// m_startLayer = startItem->Layers().Start(); - - m_startItem = startItem; - } - else - { - m_startItem = NULL; - m_startSnapPoint = cp; - ctls->ForceCursorPosition( false ); - } - } -} - - -void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) -{ - VIEW_CONTROLS* ctls = getViewControls(); - VECTOR2I p = getView()->ToWorld( ctls->GetMousePosition() ); - VECTOR2I cp = ctls->GetCursorPosition(); - int layer; - bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); - - m_router->EnableSnapping( snapEnabled ); - - if( !snapEnabled || m_router->GetCurrentNet() < 0 || !m_startItem ) - { - m_endItem = NULL; - m_endSnapPoint = cp; - return; - } - - bool dummy; - - if( m_router->IsPlacingVia() ) - layer = -1; - else - layer = m_router->GetCurrentLayer(); - - PNS_ITEM* endItem = pickSingleItem( p, m_startItem->Net(), layer ); - - if( endItem ) - { - VECTOR2I cursorPos = m_router->SnapToItem( endItem, p, dummy ); - ctls->ForceCursorPosition( true, cursorPos ); - m_endItem = endItem; - m_endSnapPoint = cursorPos; - } - else - { - m_endItem = NULL; - m_endSnapPoint = cp; - ctls->ForceCursorPosition( false ); - } - - if( m_endItem ) - TRACE( 0, "%s, layer : %d", m_endItem->KindStr().c_str() % m_endItem->Layers().Start() ); -} - int ROUTER_TOOL::getStartLayer( const PNS_ITEM* aItem ) { int tl = getView()->GetTopLayer(); @@ -541,9 +361,7 @@ int ROUTER_TOOL::getStartLayer( const PNS_ITEM* aItem ) } void ROUTER_TOOL::switchLayerOnViaPlacement() { - PCB_EDIT_FRAME* frame = getEditFrame(); - - int al = frame->GetActiveLayer(); + int al = m_frame->GetActiveLayer(); int cl = m_router->GetCurrentLayer(); if( cl != al ) @@ -556,24 +374,23 @@ void ROUTER_TOOL::switchLayerOnViaPlacement() if( newLayer ) { m_router->SwitchLayer ( *newLayer ); - frame->SetActiveLayer ( ToLAYER_ID( *newLayer ) ); + m_frame->SetActiveLayer ( ToLAYER_ID( *newLayer ) ); } } bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) { - BOARD* board = getModel (); - BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); - PCB_EDIT_FRAME* frame = getEditFrame(); - + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + const int layerCount = bds.GetCopperLayerCount(); int currentLayer = m_router->GetCurrentLayer(); PNS_SIZES_SETTINGS sizes = m_router->Sizes(); + // fixme: P&S supports more than one fixed layer pair. Update the dialog? sizes.ClearLayerPairs(); - sizes.AddLayerPair( frame->GetScreen()->m_Route_Layer_TOP, - frame->GetScreen()->m_Route_Layer_BOTTOM ); + sizes.AddLayerPair( m_frame->GetScreen()->m_Route_Layer_TOP, + m_frame->GetScreen()->m_Route_Layer_BOTTOM ); if( !m_router->IsPlacingVia() ) { @@ -606,40 +423,77 @@ bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) return false; } -void ROUTER_TOOL::performRouting() -{ - PCB_EDIT_FRAME* frame = getEditFrame(); - bool saveUndoBuffer = true; - VIEW_CONTROLS* ctls = getViewControls(); - BOARD* board = getModel(); - int routingLayer = getStartLayer ( m_startItem ); - frame->SetActiveLayer( ToLAYER_ID ( routingLayer ) ); +bool ROUTER_TOOL::prepareInteractive() +{ + int routingLayer = getStartLayer ( m_startItem ); + m_frame->SetActiveLayer( ToLAYER_ID ( routingLayer ) ); + // fixme: switch on invisible layer if( m_startItem && m_startItem->Net() >= 0 ) { highlightNet( true, m_startItem->Net() ); // Update track width and via size shown in main toolbar comboboxes - frame->SetCurrentNetClass( m_startItem->Parent()->GetNetClass()->GetName() ); + m_frame->SetCurrentNetClass( m_startItem->Parent()->GetNetClass()->GetName() ); } else - frame->SetCurrentNetClass( NETCLASS::Default ); + m_frame->SetCurrentNetClass( NETCLASS::Default ); - ctls->ForceCursorPosition( false ); - ctls->SetAutoPan( true ); + m_ctls->ForceCursorPosition( false ); + m_ctls->SetAutoPan( true ); - PNS_SIZES_SETTINGS sizes; - sizes.Init ( board, m_startItem ); - sizes.AddLayerPair ( frame->GetScreen()->m_Route_Layer_TOP, - frame->GetScreen()->m_Route_Layer_BOTTOM ); + PNS_SIZES_SETTINGS sizes ( m_router->Sizes() ); + + sizes.Init ( m_board, m_startItem ); + sizes.AddLayerPair ( m_frame->GetScreen()->m_Route_Layer_TOP, + m_frame->GetScreen()->m_Route_Layer_BOTTOM ); m_router->UpdateSizes( sizes ); - - m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ); + + if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) ) + { + wxMessageBox ( m_router->FailureReason(), _("Error") ); + highlightNet ( false ); + return false; + } m_endItem = NULL; m_endSnapPoint = m_startSnapPoint; + return true; +} + +bool ROUTER_TOOL::finishInteractive( bool aSaveUndoBuffer ) +{ + m_router->StopRouting(); + + if( aSaveUndoBuffer ) + { + // Save the recent changes in the undo buffer + m_frame->SaveCopyInUndoList( m_router->GetUndoBuffer(), UR_UNSPECIFIED ); + m_router->ClearUndoBuffer(); + m_frame->OnModify(); + } + else + { + // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now + m_needsSync = true; + } + + m_ctls->SetAutoPan( false ); + m_ctls->ForceCursorPosition( false ); + highlightNet( false ); + + return true; +} + +void ROUTER_TOOL::performRouting() +{ + bool saveUndoBuffer = true; + + if ( !prepareInteractive( ) ) + return; + while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() || evt->IsActivate() ) @@ -652,6 +506,7 @@ void ROUTER_TOOL::performRouting() else if( evt->IsMotion() ) { updateEndItem( *evt ); + m_router->SetOrthoMode ( evt->Modifier ( MD_CTRL ) ); m_router->Move( m_endSnapPoint, m_endItem ); } else if( evt->IsClick( BUT_LEFT ) ) @@ -663,13 +518,10 @@ void ROUTER_TOOL::performRouting() break; if( needLayerSwitch ) - { switchLayerOnViaPlacement(); - } // Synchronize the indicated layer - frame->SetActiveLayer( ToLAYER_ID( m_router->GetCurrentLayer() ) ); - + m_frame->SetActiveLayer( ToLAYER_ID( m_router->GetCurrentLayer() ) ); m_router->Move( m_endSnapPoint, m_endItem ); } else if( evt->IsAction( &ACT_PlaceThroughVia ) ) @@ -692,7 +544,7 @@ void ROUTER_TOOL::performRouting() else if( evt->IsAction( &COMMON_ACTIONS::layerChanged ) ) { updateEndItem( *evt ); - m_router->SwitchLayer( frame->GetActiveLayer() ); + m_router->SwitchLayer( m_frame->GetActiveLayer() ); m_router->Move( m_endSnapPoint, m_endItem ); // refresh } else if( evt->IsAction( &ACT_EndTrack ) ) @@ -704,42 +556,67 @@ void ROUTER_TOOL::performRouting() handleCommonEvents( *evt ); } - m_router->StopRouting(); + finishInteractive ( saveUndoBuffer ); +} - 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; - } +int ROUTER_TOOL::DpDimensionsDialog( const TOOL_EVENT& aEvent ) +{ + Activate(); - ctls->SetAutoPan( false ); - ctls->ForceCursorPosition( false ); - highlightNet( false ); + PNS_SIZES_SETTINGS sizes = m_router->Sizes(); + DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( m_frame, sizes ); + + if( settingsDlg.ShowModal() ) + { + m_router->UpdateSizes( sizes ); + m_savedSizes = sizes; + } + + return 0; +} + +int ROUTER_TOOL::SettingsDialog( const TOOL_EVENT& aEvent ) +{ + Activate(); + + DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() ); + + if( settingsDlg.ShowModal() ) + { + m_savedSettings = m_router->Settings(); + } + return 0; } -int ROUTER_TOOL::Main( const TOOL_EVENT& aEvent ) +int ROUTER_TOOL::RouteSingleTrace( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Route Track" ) ); + return mainLoop( PNS_MODE_ROUTE_SINGLE ); +} + +int ROUTER_TOOL::RouteDiffPair( const TOOL_EVENT& aEvent ) +{ + m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Router Differential Pair" ) ); + return mainLoop( PNS_MODE_ROUTE_DIFF_PAIR ); +} + +int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) { - VIEW_CONTROLS* ctls = getViewControls(); PCB_EDIT_FRAME* frame = getEditFrame(); BOARD* board = getModel(); // Deselect all items m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Interactive Router" ) ); + Activate(); - ctls->SetSnapping( true ); - ctls->ShowCursor( true ); + m_router->SetMode ( aMode ); + + m_ctls->SetSnapping( true ); + m_ctls->ShowCursor( true ); - std::auto_ptr ctxMenu ( new ROUTER_TOOL_MENU( board ) ); + std::auto_ptr ctxMenu ( new ROUTER_TOOL_MENU( board, aMode ) ); SetContextMenu ( ctxMenu.get() ); // Main loop: keep receiving events @@ -774,17 +651,17 @@ int ROUTER_TOOL::Main( const TOOL_EVENT& aEvent ) } // Restore the default settings - ctls->SetAutoPan( false ); - ctls->ShowCursor( false ); + m_ctls->SetAutoPan( false ); + m_ctls->ShowCursor( false ); frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); // Store routing settings till the next invocation - m_settings = m_router->Settings(); + m_savedSettings = m_router->Settings(); + m_savedSizes = m_router->Sizes(); return 0; } - void ROUTER_TOOL::performDragging() { PCB_EDIT_FRAME* frame = getEditFrame(); @@ -845,3 +722,9 @@ void ROUTER_TOOL::performDragging() ctls->ForceCursorPosition( false ); highlightNet( false ); } + +int ROUTER_TOOL::InlineDrag ( const TOOL_EVENT& aEvent ) +{ + return 0; +} + diff --git a/pcbnew/router/router_tool.h b/pcbnew/router/router_tool.h index 314e844ae5..73c4ea917f 100644 --- a/pcbnew/router/router_tool.h +++ b/pcbnew/router/router_tool.h @@ -22,61 +22,41 @@ #ifndef __ROUTER_TOOL_H #define __ROUTER_TOOL_H -#include +#include "pns_tool_base.h" -#include -#include - -#include - -#include "pns_routing_settings.h" - -class PNS_ROUTER; -class PNS_ITEM; - -class APIEXPORT ROUTER_TOOL : public TOOL_INTERACTIVE +class APIEXPORT ROUTER_TOOL : public PNS_TOOL_BASE { public: ROUTER_TOOL(); ~ROUTER_TOOL(); void Reset( RESET_REASON aReason ); - int Main( const TOOL_EVENT& aEvent ); + + int RouteSingleTrace ( const TOOL_EVENT& aEvent ); + int RouteDiffPair ( const TOOL_EVENT& aEvent ); + int InlineDrag ( const TOOL_EVENT& aEvent ); + + int DpDimensionsDialog ( const TOOL_EVENT& aEvent ); + int SettingsDialog ( const TOOL_EVENT& aEvent ); private: - PNS_ITEM* pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); + + int mainLoop( PNS_ROUTER_MODE aMode ); int getDefaultWidth( int aNetCode ); 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 ); + void handleCommonEvents( const TOOL_EVENT& evt ); int getStartLayer( const PNS_ITEM* aItem ); void switchLayerOnViaPlacement(); bool onViaCommand( VIATYPE_T aType ); - 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; - VECTOR2I m_startSnapPoint; - - PNS_ITEM* m_endItem; - VECTOR2I m_endSnapPoint; - - ///> Flag marking that the router's world needs syncing. - bool m_needsSync; + bool prepareInteractive( ); + bool finishInteractive( bool aSaveUndoBuffer ); }; #endif diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 759dae77f5..2a5f4e84ea 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -390,11 +390,41 @@ TOOL_ACTION COMMON_ACTIONS::toBeDone( "pcbnew.Control.toBeDone", AS_GLOBAL, 0, // dialog saying it is not implemented yet "", "" ); // so users are aware of that -TOOL_ACTION COMMON_ACTIONS::routerActivate( "pcbnew.InteractiveRouter", +TOOL_ACTION COMMON_ACTIONS::routerActivateSingle( "pcbnew.InteractiveRouter.SingleTrack", AS_GLOBAL, 'X', - "Run push & shove router", "Run push & shove router", AF_ACTIVATE ); + "Run push & shove router (single tracks)", "Run push & shove router (single tracks)", AF_ACTIVATE ); +TOOL_ACTION COMMON_ACTIONS::routerActivateDiffPair( "pcbnew.InteractiveRouter.DiffPair", + AS_GLOBAL, '6', + "Run push & shove router (differential pairs)", "Run push & shove router (differential pairs)", AF_ACTIVATE ); + +TOOL_ACTION COMMON_ACTIONS::routerActivateSettingsDialog( "pcbnew.InteractiveRouter.SettingsDialog", + AS_GLOBAL, 0, + "Open Interactive Router settings", "Open Interactive Router settings", AF_ACTIVATE ); + +TOOL_ACTION COMMON_ACTIONS::routerActivateDpDimensionsDialog( "pcbnew.InteractiveRouter.DpDimensionsDialog", + AS_GLOBAL, 0, + "Open Differential Pair Dimension settings", "Open Differential Pair Dimension settings", AF_ACTIVATE ); + +TOOL_ACTION COMMON_ACTIONS::routerActivateTuneSingleTrace( "pcbnew.LengthTuner.TuneSingleTrack", + AS_GLOBAL, '7', + "Tune length of a single track", "", AF_ACTIVATE ); + + +TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPair( "pcbnew.LengthTuner.TuneDiffPair", + AS_GLOBAL, '8', + "Tune length of a differential pair", "", AF_ACTIVATE ); + + +TOOL_ACTION COMMON_ACTIONS::routerActivateTuneDiffPairSkew( "pcbnew.LengthTuner.TuneDiffPairSkew", + AS_GLOBAL, '9', + "Tune skew of a differential pair", "", AF_ACTIVATE ); + +TOOL_ACTION COMMON_ACTIONS::routerInlineDrag( "pcbnew.InteractiveRouter.InlineDrag", + AS_GLOBAL, 0, + "", "" ); + // Point editor TOOL_ACTION COMMON_ACTIONS::pointEditorUpdate( "pcbnew.PointEditor.update", AS_GLOBAL, 0, @@ -404,7 +434,6 @@ TOOL_ACTION COMMON_ACTIONS::pointEditorBreakOutline( "pcbnew.PointEditor.breakOu AS_GLOBAL, 0, "Create corner", "Create corner" ); - // Placement tool TOOL_ACTION COMMON_ACTIONS::alignTop( "pcbnew.Place.alignTop", AS_GLOBAL, 0, @@ -445,7 +474,25 @@ boost::optional COMMON_ACTIONS::TranslateLegacyId( int aId ) return COMMON_ACTIONS::placeModule.MakeEvent(); case ID_TRACK_BUTT: - return COMMON_ACTIONS::routerActivate.MakeEvent(); + return COMMON_ACTIONS::routerActivateSingle.MakeEvent(); + + case ID_DIFF_PAIR_BUTT: + return COMMON_ACTIONS::routerActivateDiffPair.MakeEvent(); + + case ID_TUNE_SINGLE_TRACK_LEN_BUTT: + return COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent(); + + case ID_TUNE_DIFF_PAIR_LEN_BUTT: + return COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent(); + + case ID_TUNE_DIFF_PAIR_SKEW_BUTT: + return COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent(); + + case ID_MENU_INTERACTIVE_ROUTER_SETTINGS: + return COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent(); + + case ID_MENU_DIFF_PAIR_DIMENSIONS: + return COMMON_ACTIONS::routerActivateDpDimensionsDialog.MakeEvent(); case ID_PCB_ZONES_BUTT: return COMMON_ACTIONS::drawZone.MakeEvent(); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 850459bad7..5efe6e9515 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -116,8 +116,29 @@ public: static TOOL_ACTION arcPosture; // Push and Shove Router Tool + /// Activation of the Push and Shove router - static TOOL_ACTION routerActivate; + static TOOL_ACTION routerActivateSingle; + + /// Activation of the Push and Shove router (differential pair mode) + static TOOL_ACTION routerActivateDiffPair; + + /// Activation of the Push and Shove router (tune single line mode) + static TOOL_ACTION routerActivateTuneSingleTrace; + + /// Activation of the Push and Shove router (diff pair tuning mode) + static TOOL_ACTION routerActivateTuneDiffPair; + + /// Activation of the Push and Shove router (skew tuning mode) + static TOOL_ACTION routerActivateTuneDiffPairSkew; + + /// Activation of the Push and Shove settings dialogs + static TOOL_ACTION routerActivateSettingsDialog; + static TOOL_ACTION routerActivateDpDimensionsDialog; + + + /// Activation of the Push and Shove router (inline dragging mode) + static TOOL_ACTION routerInlineDrag; // Point Editor /// Update edit points From 4fb9bce354a79e5f569e411732e1f52e86402404 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Feb 2015 17:53:46 +0100 Subject: [PATCH 18/23] Code formatting. --- common/geometry/seg.cpp | 2 +- common/wx_status_popup.cpp | 16 +- common/wx_unit_binder.cpp | 21 +- include/base_struct.h | 2 +- include/class_collector.h | 3 +- include/gal/opengl/vertex_item.h | 2 +- include/geometry/seg.h | 37 +- include/view/view_item.h | 22 +- include/wx_status_popup.h | 8 +- include/wx_unit_binder.h | 10 +- pcbnew/class_drawsegment.h | 2 +- pcbnew/class_module.cpp | 7 +- pcbnew/class_module.h | 9 +- pcbnew/class_pad.h | 2 +- pcbnew/class_pcb_text.h | 2 +- .../dialog_edit_module_for_BoardEditor.cpp | 4 +- .../dialog_pns_diff_pair_dimensions.cpp | 25 +- .../dialogs/dialog_pns_diff_pair_dimensions.h | 25 +- .../dialog_pns_length_tuning_settings.cpp | 64 +- .../dialog_pns_length_tuning_settings.h | 25 +- .../dialogs/dialog_pns_settings_base.fbp.bak | 1334 ----------------- pcbnew/dialogs/dialog_track_via_size.cpp | 6 +- pcbnew/dialogs/dialog_track_via_size.h | 31 +- pcbnew/loadcmp.cpp | 2 +- pcbnew/menubar_pcbframe.cpp | 1 - pcbnew/pcbframe.cpp | 3 +- pcbnew/pcbnew_id.h | 1 - pcbnew/router/direction.h | 45 +- pcbnew/router/length_tuner_tool.cpp | 75 +- pcbnew/router/length_tuner_tool.h | 11 +- pcbnew/router/pns_algo_base.cpp | 8 +- pcbnew/router/pns_algo_base.h | 34 +- pcbnew/router/pns_diff_pair.cpp | 646 ++++---- pcbnew/router/pns_diff_pair.h | 163 +- pcbnew/router/pns_diff_pair_placer.cpp | 425 +++--- pcbnew/router/pns_diff_pair_placer.h | 27 +- pcbnew/router/pns_dp_meander_placer.cpp | 242 +-- pcbnew/router/pns_dp_meander_placer.h | 32 +- pcbnew/router/pns_dragger.h | 48 +- pcbnew/router/pns_index.h | 10 - pcbnew/router/pns_itemset.cpp | 10 +- pcbnew/router/pns_itemset.h | 8 +- pcbnew/router/pns_joint.h | 14 +- pcbnew/router/pns_line.cpp | 53 +- pcbnew/router/pns_line.h | 78 +- pcbnew/router/pns_line_placer.cpp | 53 +- pcbnew/router/pns_line_placer.h | 11 +- pcbnew/router/pns_logger.cpp | 193 +-- pcbnew/router/pns_logger.h | 26 +- pcbnew/router/pns_meander.cpp | 308 ++-- pcbnew/router/pns_meander.h | 708 +++++---- pcbnew/router/pns_meander_placer.cpp | 113 +- pcbnew/router/pns_meander_placer.h | 16 +- pcbnew/router/pns_meander_placer_base.cpp | 83 +- pcbnew/router/pns_meander_placer_base.h | 34 +- pcbnew/router/pns_meander_skew_placer.cpp | 47 +- pcbnew/router/pns_meander_skew_placer.h | 5 +- pcbnew/router/pns_node.cpp | 81 +- pcbnew/router/pns_node.h | 7 +- pcbnew/router/pns_optimizer.cpp | 242 +-- pcbnew/router/pns_optimizer.h | 2 +- pcbnew/router/pns_placement_algo.h | 22 +- pcbnew/router/pns_router.cpp | 58 +- pcbnew/router/pns_router.h | 1 - pcbnew/router/pns_routing_settings.h | 1 - pcbnew/router/pns_segment.h | 12 +- pcbnew/router/pns_shove.cpp | 100 +- pcbnew/router/pns_shove.h | 10 +- pcbnew/router/pns_sizes_settings.cpp | 6 + pcbnew/router/pns_sizes_settings.h | 10 +- pcbnew/router/pns_solid.cpp | 2 +- pcbnew/router/pns_solid.h | 6 +- pcbnew/router/pns_tool_base.cpp | 7 +- pcbnew/router/pns_tool_base.h | 10 +- pcbnew/router/pns_topology.cpp | 201 +-- pcbnew/router/pns_topology.h | 49 +- pcbnew/router/pns_tune_status_popup.cpp | 48 +- pcbnew/router/pns_tune_status_popup.h | 7 +- pcbnew/router/pns_utils.cpp | 94 +- pcbnew/router/pns_utils.h | 10 +- pcbnew/router/pns_via.cpp | 7 +- pcbnew/router/pns_via.h | 4 +- pcbnew/router/pns_walkaround.cpp | 16 +- pcbnew/router/range.h | 106 +- pcbnew/router/ranged_num.h | 45 +- pcbnew/router/router_menus.h | 74 +- pcbnew/router/router_preview_item.cpp | 11 +- pcbnew/router/router_preview_item.h | 8 +- pcbnew/router/router_tool.cpp | 18 +- pcbnew/router/time_limit.h | 14 +- pcbnew/tools/common_actions.cpp | 14 +- pcbnew/tools/common_actions.h | 8 +- pcbnew/tools/edit_tool.cpp | 77 +- pcbnew/tools/edit_tool.h | 8 +- pcbnew/tools/grid_helper.cpp | 327 ++-- pcbnew/tools/grid_helper.h | 93 +- pcbnew/tools/selection_tool.cpp | 204 +-- pcbnew/tools/selection_tool.h | 4 +- pcbnew/tools/tools_common.cpp | 26 +- pcbnew/xchgmod.cpp | 1 - 100 files changed, 3005 insertions(+), 4238 deletions(-) delete mode 100644 pcbnew/dialogs/dialog_pns_settings_base.fbp.bak diff --git a/common/geometry/seg.cpp b/common/geometry/seg.cpp index 8ec1565fb5..ceb279d489 100644 --- a/common/geometry/seg.cpp +++ b/common/geometry/seg.cpp @@ -35,7 +35,7 @@ bool SEG::PointCloserThan( const VECTOR2I& aP, int aDist ) const { VECTOR2I d = B - A; ecoord dist_sq = (ecoord) aDist * aDist; - ecoord dist_sq_thr = (ecoord) (aDist + 1) * (aDist + 1); + ecoord dist_sq_thr = (ecoord) ( aDist + 1 ) * ( aDist + 1 ); SEG::ecoord l_squared = d.Dot( d ); SEG::ecoord t = d.Dot( aP - A ); diff --git a/common/wx_status_popup.cpp b/common/wx_status_popup.cpp index 5daa877def..9679b3e0da 100644 --- a/common/wx_status_popup.cpp +++ b/common/wx_status_popup.cpp @@ -29,35 +29,37 @@ #include #include -WX_STATUS_POPUP::WX_STATUS_POPUP ( PCB_EDIT_FRAME *parent ) : - wxPopupWindow ( parent ) +WX_STATUS_POPUP::WX_STATUS_POPUP( PCB_EDIT_FRAME* aParent ) : + wxPopupWindow( aParent ) { m_panel = new wxPanel( this, wxID_ANY ); m_panel->SetBackgroundColour( *wxLIGHT_GREY ); m_topSizer = new wxBoxSizer( wxVERTICAL ); m_panel->SetSizer( m_topSizer ); - } + void WX_STATUS_POPUP::updateSize() { m_topSizer->Fit( m_panel ); - SetClientSize( m_panel->GetSize( ) ); + SetClientSize( m_panel->GetSize() ); } + WX_STATUS_POPUP::~WX_STATUS_POPUP() { } -void WX_STATUS_POPUP::Popup(wxWindow *focus) + +void WX_STATUS_POPUP::Popup( wxWindow* ) { - Show(true); + Show( true ); Raise(); } + void WX_STATUS_POPUP::Move( const wxPoint& aWhere ) { SetPosition ( aWhere ); } - \ No newline at end of file diff --git a/common/wx_unit_binder.cpp b/common/wx_unit_binder.cpp index 14883d7cff..90a66ae12e 100644 --- a/common/wx_unit_binder.cpp +++ b/common/wx_unit_binder.cpp @@ -35,14 +35,14 @@ #include "wx_unit_binder.h" -WX_UNIT_BINDER::WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl *aTextInput, wxStaticText *aUnitLabel, wxSpinButton *aSpinButton ) +WX_UNIT_BINDER::WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl* aTextInput, wxStaticText* aUnitLabel, wxSpinButton* aSpinButton ) { // Use the currently selected units m_units = g_UserUnit; m_textCtrl = aTextInput; - m_textCtrl->SetValue ( wxT("0") ); + m_textCtrl->SetValue( wxT( "0" ) ); m_unitLabel = aUnitLabel; - m_unitLabel->SetLabel ( GetAbbreviatedUnitsLabel (m_units)); + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units ) ); } @@ -50,15 +50,17 @@ WX_UNIT_BINDER::~WX_UNIT_BINDER() { } + void WX_UNIT_BINDER::SetValue( int aValue ) { wxString s = StringFromValue( m_units, aValue, false ); - m_textCtrl->SetValue ( s ); + m_textCtrl->SetValue( s ); - m_unitLabel->SetLabel ( GetAbbreviatedUnitsLabel (m_units)); + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units ) ); } + int WX_UNIT_BINDER::GetValue() const { wxString s = m_textCtrl->GetValue(); @@ -66,8 +68,9 @@ int WX_UNIT_BINDER::GetValue() const return ValueFromString( m_units, s ); } -void WX_UNIT_BINDER::Enable ( bool aEnable ) + +void WX_UNIT_BINDER::Enable( bool aEnable ) { - m_textCtrl->Enable ( aEnable ); - m_unitLabel->Enable ( aEnable ); -} + m_textCtrl->Enable( aEnable ); + m_unitLabel->Enable( aEnable ); +} \ No newline at end of file diff --git a/include/base_struct.h b/include/base_struct.h index 84500d2cca..647f77f792 100644 --- a/include/base_struct.h +++ b/include/base_struct.h @@ -147,7 +147,7 @@ public: #define BRIGHTENED (1 << 26) ///< item is drawn with a bright contour #define DP_COUPLED (1 << 27) ///< item is coupled with another item making a differential pair - ///< (applies to segments only) + ///< (applies to segments only) #define EDA_ITEM_ALL_FLAGS -1 diff --git a/include/class_collector.h b/include/class_collector.h index f8c90a6582..04f7010e9d 100644 --- a/include/class_collector.h +++ b/include/class_collector.h @@ -134,7 +134,7 @@ public: * removes the item aItem (if exists in the collector). * @param aItem the item to be removed. */ - void Remove( const EDA_ITEM *aItem ) + void Remove( const EDA_ITEM* aItem ) { for( size_t i = 0; i < m_List.size(); i++ ) { @@ -257,7 +257,6 @@ public: return cnt; } - /** * Function Collect * scans an EDA_ITEM using this class's Inspector method, which does diff --git a/include/gal/opengl/vertex_item.h b/include/gal/opengl/vertex_item.h index 1905b9511e..c5bf962172 100644 --- a/include/gal/opengl/vertex_item.h +++ b/include/gal/opengl/vertex_item.h @@ -50,7 +50,7 @@ public: /** * Function GetSize() * Returns information about number of vertices stored. - * @param Number of vertices. + * @return Number of vertices. */ inline unsigned int GetSize() const { diff --git a/include/geometry/seg.h b/include/geometry/seg.h index 855271a512..06adfef52d 100644 --- a/include/geometry/seg.h +++ b/include/geometry/seg.h @@ -206,7 +206,7 @@ public: return sqrt( SquaredDistance( aP ) ); } - void CanonicalCoefs ( ecoord& qA, ecoord& qB, ecoord& qC) const + void CanonicalCoefs( ecoord& qA, ecoord& qB, ecoord& qC ) const { qA = A.y - B.y; qB = B.x - A.x; @@ -223,8 +223,8 @@ public: bool Collinear( const SEG& aSeg ) const { ecoord qa, qb, qc; - CanonicalCoefs ( qa, qb, qc ); - + CanonicalCoefs( qa, qb, qc ); + 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 ); @@ -234,23 +234,23 @@ public: bool ApproxCollinear( const SEG& aSeg ) const { ecoord p, q, r; - CanonicalCoefs ( p, q, r ); - - ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); - ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + CanonicalCoefs( p, q, r ); - return std::abs(dist1) <= 1 && std::abs(dist2) <= 1; + ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); + ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + + return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1; } bool ApproxParallel ( const SEG& aSeg ) const { ecoord p, q, r; - CanonicalCoefs ( p, q, r ); - - ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); - ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + CanonicalCoefs( p, q, r ); - return std::abs(dist1 - dist2) <= 1; + ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q ); + ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q ); + + return std::abs( dist1 - dist2 ) <= 1; } @@ -291,7 +291,7 @@ public: return ( A - B ).SquaredEuclideanNorm(); } - ecoord TCoef ( const VECTOR2I& aP ) const; + ecoord TCoef( const VECTOR2I& aP ) const; /** * Function Index() @@ -310,7 +310,7 @@ public: void Reverse() { - std::swap ( A, B ); + std::swap( A, B ); } private: @@ -320,7 +320,6 @@ private: int m_index; }; - inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const { VECTOR2I d = B - A; @@ -337,7 +336,6 @@ inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const return A + VECTOR2I( xp, yp ); } - inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const { ecoord p = A.y - B.y; @@ -349,10 +347,10 @@ inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const return aDetermineSide ? dist : abs( dist ); } -inline SEG::ecoord SEG::TCoef ( const VECTOR2I& aP ) const +inline SEG::ecoord SEG::TCoef( const VECTOR2I& aP ) const { VECTOR2I d = B - A; - return d.Dot ( aP - A); + return d.Dot( aP - A); } inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const @@ -376,7 +374,6 @@ inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const return A + VECTOR2I( xp, yp ); } - inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg ) { aStream << "[ " << aSeg.A << " - " << aSeg.B << " ]"; diff --git a/include/view/view_item.h b/include/view/view_item.h index be28c9230f..4e6f97572d 100644 --- a/include/view/view_item.h +++ b/include/view/view_item.h @@ -76,16 +76,15 @@ public: ALL = 0xff }; - /** - * Enum VIEW_VISIBILITY_FLAGS. - * Defines the visibility of the item (temporarily hidden, invisible, etc). + /** + * Enum VIEW_VISIBILITY_FLAGS. + * Defines the visibility of the item (temporarily hidden, invisible, etc). */ enum VIEW_VISIBILITY_FLAGS { VISIBLE = 0x01, /// Item is visible (in general) HIDDEN = 0x02 /// Item is temporarily hidden (e.g. being used by a tool). Overrides VISIBLE flag. }; - VIEW_ITEM() : m_view( NULL ), m_flags( VISIBLE ), m_requiredUpdate( ALL ), m_groups( NULL ), m_groupsSize( 0 ) {} @@ -141,13 +140,14 @@ public: void ViewSetVisible( bool aIsVisible = true ) { bool cur_visible = m_flags & VISIBLE; - + if( cur_visible != aIsVisible ) { - if(aIsVisible) + if( aIsVisible ) m_flags |= VISIBLE; else m_flags &= ~VISIBLE; + ViewUpdate( APPEARANCE | COLOR ); } } @@ -158,12 +158,12 @@ public: * * @param aHide: whether the item is hidden (on all layers), or not. */ - void ViewHide ( bool aHide = true ) + void ViewHide( bool aHide = true ) { - if(! (m_flags & VISIBLE) ) + if( !( m_flags & VISIBLE ) ) return; - if(aHide) + if( aHide ) m_flags |= HIDDEN; else m_flags &= ~HIDDEN; @@ -242,7 +242,7 @@ protected: } VIEW* m_view; ///< Current dynamic view the item is assigned to. - int m_flags; ///< Visibility flags + int m_flags; ///< Visibility flags int m_requiredUpdate; ///< Flag required for updating ///* Helper for storing cached items group ids @@ -341,7 +341,7 @@ protected: * Function isRenderable() * Returns if the item should be drawn or not. */ - bool isRenderable() const + bool isRenderable() const { return m_flags == VISIBLE; } diff --git a/include/wx_status_popup.h b/include/wx_status_popup.h index a050704006..93e8e7f9aa 100644 --- a/include/wx_status_popup.h +++ b/include/wx_status_popup.h @@ -41,18 +41,18 @@ class PCB_EDIT_FRAME; class WX_STATUS_POPUP: public wxPopupWindow { public: - WX_STATUS_POPUP ( PCB_EDIT_FRAME *parent ); + WX_STATUS_POPUP( PCB_EDIT_FRAME* aParent ); virtual ~WX_STATUS_POPUP(); - virtual void Popup(wxWindow *focus = NULL); + virtual void Popup(wxWindow* aFocus = NULL); virtual void Move( const wxPoint &aWhere ); protected: void updateSize(); - wxPanel *m_panel; - wxBoxSizer *m_topSizer; + wxPanel* m_panel; + wxBoxSizer* m_topSizer; }; #endif /* __WX_STATUS_POPUP_H_*/ diff --git a/include/wx_unit_binder.h b/include/wx_unit_binder.h index 34d092ee18..be4e39d39d 100644 --- a/include/wx_unit_binder.h +++ b/include/wx_unit_binder.h @@ -43,7 +43,7 @@ public: * @param aUnitLabel is the units label displayed next to the text field. * @param aSpinButton is an optional spin button (for adjusting the input value) */ - WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl *aTextInput, wxStaticText *aUnitLabel, wxSpinButton *aSpinButton = NULL ); + WX_UNIT_BINDER( wxWindow* aParent, wxTextCtrl* aTextInput, wxStaticText* aUnitLabel, wxSpinButton* aSpinButton = NULL ); virtual ~WX_UNIT_BINDER(); @@ -64,20 +64,20 @@ public: * Function Enable * Enables/diasables the binded widgets */ - void Enable ( bool aEnable ); + void Enable( bool aEnable ); protected: - void onTextChanged ( wxEvent& aEvent ); + void onTextChanged( wxEvent& aEvent ); ///> Text input control. wxTextCtrl* m_textCtrl; ///> Label showing currently used units. - wxStaticText* m_unitLabel; + wxStaticText* m_unitLabel; ///> Currently used units. - EDA_UNITS_T m_units; + EDA_UNITS_T m_units; ///> Step size (added/subtracted difference if spin buttons are used). int m_step; diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 3c5667ebd6..433fceee34 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -69,7 +69,7 @@ public: /// skip the linked list stuff, and parent const DRAWSEGMENT& operator = ( const DRAWSEGMENT& rhs ); - static inline bool ClassOf( const EDA_ITEM *aItem ) + static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_LINE_T == aItem->Type(); } diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 1f9462da5c..aec9d6565a 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -815,12 +815,14 @@ void MODULE::RunOnChildren( boost::function aFunction ) } } + const BOX2I MODULE::ViewBBox() const { return BOX2I( VECTOR2I( GetFootprintRect().GetOrigin() ), - VECTOR2I( GetFootprintRect().GetSize() ) ); + VECTOR2I( GetFootprintRect().GetSize() ) ); } + void MODULE::ViewUpdate( int aUpdateFlags ) { if( !m_view ) @@ -1115,6 +1117,7 @@ void MODULE::SetOrientation( double newangle ) CalculateBoundingBox(); } + double MODULE::PadCoverageRatio() const { double padArea = 0.0; @@ -1128,5 +1131,5 @@ double MODULE::PadCoverageRatio() const double ratio = padArea / moduleArea; - return std::min(ratio, 1.0); + return std::min( ratio, 1.0 ); } diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index e8ae7e6946..45e71556c7 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -262,7 +262,8 @@ public: m_ModuleStatus &= ~MODULE_to_PLACE; } - bool PadsLocked() const { return (m_ModuleStatus & MODULE_PADS_LOCKED ); } + bool PadsLocked() const { return ( m_ModuleStatus & MODULE_PADS_LOCKED ); } + void SetPadsLocked( bool aPadsLocked ) { if( aPadsLocked ) @@ -569,9 +570,9 @@ public: m_initial_comments = aInitialComments; } - /** - * Function PadCoverageRatio - * Calculates the ratio of total area of the footprint pads to the area of the + /** + * Function PadCoverageRatio + * Calculates the ratio of total area of the footprint pads to the area of the * footprint. Used by selection tool heuristics. * @return the ratio */ diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 339b4dc65b..c60e1d464b 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -94,7 +94,7 @@ public: ///< used for edge board connectors static LSET UnplatedHoleMask(); ///< layer set for a mechanical unplated through hole pad - static inline bool ClassOf( const EDA_ITEM *aItem ) + static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_PAD_T == aItem->Type(); } diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index 9bdcd2a720..e1aeee7e4d 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -49,7 +49,7 @@ public: ~TEXTE_PCB(); - static inline bool ClassOf( const EDA_ITEM *aItem ) + static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_TEXT_T == aItem->Type(); } diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp index 7c7d9ba7ea..cf9f15161f 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp @@ -313,9 +313,9 @@ void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties() break; } - if (m_CurrentModule->IsLocked() ) + if( m_CurrentModule->IsLocked() ) m_AutoPlaceCtrl->SetSelection( 2 ); - else if (m_CurrentModule->PadsLocked() ) + else if( m_CurrentModule->PadsLocked() ) m_AutoPlaceCtrl->SetSelection( 1 ); else m_AutoPlaceCtrl->SetSelection( 0 ); diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp index 6704edc70a..6438c6600d 100644 --- a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.cpp @@ -27,23 +27,22 @@ DIALOG_PNS_DIFF_PAIR_DIMENSIONS::DIALOG_PNS_DIFF_PAIR_DIMENSIONS( wxWindow* aParent, PNS_SIZES_SETTINGS& aSizes ) : DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE( aParent ), - m_traceWidth ( this, m_traceWidthText, m_traceWidthUnit ), - m_traceGap (this, m_traceGapText, m_traceGapUnit ), - m_viaGap ( this, m_viaGapText, m_viaGapUnit ), + m_traceWidth( this, m_traceWidthText, m_traceWidthUnit ), + m_traceGap( this, m_traceGapText, m_traceGapUnit ), + m_viaGap( this, m_viaGapText, m_viaGapUnit ), m_sizes( aSizes ) - { - m_traceWidth.SetValue ( aSizes.DiffPairWidth() ); - m_traceGap.SetValue ( aSizes.DiffPairGap() ); - m_viaGap.SetValue ( aSizes.DiffPairViaGap() ); - m_viaTraceGapEqual->SetValue ( m_sizes.DiffPairViaGapSameAsTraceGap() ); - + m_traceWidth.SetValue( aSizes.DiffPairWidth() ); + m_traceGap.SetValue( aSizes.DiffPairGap() ); + m_viaGap.SetValue( aSizes.DiffPairViaGap() ); + m_viaTraceGapEqual->SetValue( m_sizes.DiffPairViaGapSameAsTraceGap() ); + updateCheckbox(); } + void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::updateCheckbox() { - printf("Checked: %d", m_viaTraceGapEqual->GetValue()); if( m_viaTraceGapEqual->GetValue() ) { m_sizes.SetDiffPairViaGapSameAsTraceGap( true ); @@ -58,6 +57,7 @@ void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::updateCheckbox() } } + void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnClose( wxCloseEvent& aEvent ) { // Do nothing, it is result of ESC pressing @@ -71,7 +71,7 @@ void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnOkClick( wxCommandEvent& aEvent ) m_sizes.SetDiffPairGap ( m_traceGap.GetValue() ); m_sizes.SetDiffPairViaGap ( m_viaGap.GetValue() ); m_sizes.SetDiffPairWidth ( m_traceWidth.GetValue() ); - + // todo: verify against design rules EndModal( 1 ); } @@ -83,9 +83,10 @@ void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnCancelClick( wxCommandEvent& aEvent ) EndModal( 0 ); } + void DIALOG_PNS_DIFF_PAIR_DIMENSIONS::OnViaTraceGapEqualCheck( wxCommandEvent& event ) { event.Skip(); updateCheckbox(); } - \ No newline at end of file + diff --git a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h index 1ea6318fc8..c40d9db1e6 100644 --- a/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h +++ b/pcbnew/dialogs/dialog_pns_diff_pair_dimensions.h @@ -33,23 +33,22 @@ class PNS_SIZES_SETTINGS; class DIALOG_PNS_DIFF_PAIR_DIMENSIONS : public DIALOG_PNS_DIFF_PAIR_DIMENSIONS_BASE { - public: - DIALOG_PNS_DIFF_PAIR_DIMENSIONS( wxWindow* aParent, PNS_SIZES_SETTINGS& aSizes ); +public: + DIALOG_PNS_DIFF_PAIR_DIMENSIONS( wxWindow* aParent, PNS_SIZES_SETTINGS& aSizes ); - virtual void OnClose( wxCloseEvent& aEvent ); - virtual void OnOkClick( wxCommandEvent& aEvent ); - virtual void OnCancelClick( wxCommandEvent& aEvent ); - virtual void OnViaTraceGapEqualCheck( wxCommandEvent& event ); - + virtual void OnClose( wxCloseEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); + virtual void OnViaTraceGapEqualCheck( wxCommandEvent& event ); - private: - void updateCheckbox( ); +private: + void updateCheckbox(); - WX_UNIT_BINDER m_traceWidth; - WX_UNIT_BINDER m_traceGap; - WX_UNIT_BINDER m_viaGap; + WX_UNIT_BINDER m_traceWidth; + WX_UNIT_BINDER m_traceGap; + WX_UNIT_BINDER m_viaGap; - PNS_SIZES_SETTINGS& m_sizes; + PNS_SIZES_SETTINGS& m_sizes; }; #endif // __dialog_pns_settings__ diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp b/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp index 1b5524db8b..b817a0b1a4 100644 --- a/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings.cpp @@ -20,63 +20,59 @@ /** * Length tuner settings dialog. - */ + */ #include "dialog_pns_length_tuning_settings.h" #include DIALOG_PNS_LENGTH_TUNING_SETTINGS::DIALOG_PNS_LENGTH_TUNING_SETTINGS( wxWindow* aParent, PNS_MEANDER_SETTINGS& aSettings, PNS_ROUTER_MODE aMode ) : DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE( aParent ), - m_minAmpl ( this, m_minAmplText, m_minAmplUnit ), - m_maxAmpl (this, m_maxAmplText, m_maxAmplUnit ), - m_spacing ( this, m_spacingText, m_spacingUnit ), - m_targetLength ( this, m_targetLengthText, m_targetLengthUnit ), + m_minAmpl( this, m_minAmplText, m_minAmplUnit ), + m_maxAmpl( this, m_maxAmplText, m_maxAmplUnit ), + m_spacing( this, m_spacingText, m_spacingUnit ), + m_targetLength( this, m_targetLengthText, m_targetLengthUnit ), m_settings( aSettings ), - m_mode ( aMode ) + m_mode( aMode ) { - - m_miterStyle->Enable ( false ); - m_radiusText->Enable ( aMode != PNS_MODE_TUNE_DIFF_PAIR ); + m_miterStyle->Enable( false ); + m_radiusText->Enable( aMode != PNS_MODE_TUNE_DIFF_PAIR ); //m_minAmpl.Enable ( aMode != PNS_MODE_TUNE_DIFF_PAIR_SKEW ); - m_minAmpl.SetValue ( m_settings.m_minAmplitude ); - m_maxAmpl.SetValue ( m_settings.m_maxAmplitude ); - - m_spacing.SetValue ( m_settings.m_spacing ); - m_radiusText->SetValue ( wxString::Format(wxT("%i"), m_settings.m_cornerRadiusPercentage) ); + m_minAmpl.SetValue( m_settings.m_minAmplitude ); + m_maxAmpl.SetValue( m_settings.m_maxAmplitude ); - - m_miterStyle->SetSelection ( m_settings.m_cornerType == PNS_MEANDER_SETTINGS::ROUND ? 1 : 0 ); + m_spacing.SetValue( m_settings.m_spacing ); + m_radiusText->SetValue( wxString::Format( wxT( "%i" ), m_settings.m_cornerRadiusPercentage ) ); + + m_miterStyle->SetSelection( m_settings.m_cornerType == PNS_MEANDER_SETTINGS::ROUND ? 1 : 0 ); switch( aMode ) { case PNS_MODE_TUNE_SINGLE: - SetTitle ( _("Single track length tuning") ); + SetTitle( _( "Single track length tuning" ) ); m_legend->SetBitmap( KiBitmap( tune_single_track_length_legend_xpm ) ); - m_targetLength.SetValue ( m_settings.m_targetLength ); - + m_targetLength.SetValue( m_settings.m_targetLength ); break; - + case PNS_MODE_TUNE_DIFF_PAIR: - SetTitle ( _("Differential pair length tuning") ); + SetTitle( _( "Differential pair length tuning" ) ); m_legend->SetBitmap( KiBitmap( tune_diff_pair_length_legend_xpm ) ); - m_targetLength.SetValue ( m_settings.m_targetLength ); - + m_targetLength.SetValue( m_settings.m_targetLength ); break; - + case PNS_MODE_TUNE_DIFF_PAIR_SKEW: - SetTitle ( _("Differential pair skew tuning") ); + SetTitle( _( "Differential pair skew tuning" ) ); m_legend->SetBitmap( KiBitmap( tune_diff_pair_skew_legend_xpm ) ); - m_targetLengthLabel->SetLabel( _("Target skew: ") ); + m_targetLengthLabel->SetLabel( _( "Target skew: " ) ); m_targetLength.SetValue ( m_settings.m_targetSkew ); break; - + default: break; } m_stdButtonsOK->SetDefault(); - m_targetLengthText->SetSelection(-1, -1); + m_targetLengthText->SetSelection( -1, -1 ); m_targetLengthText->SetFocus(); } @@ -90,26 +86,22 @@ void DIALOG_PNS_LENGTH_TUNING_SETTINGS::OnClose( wxCloseEvent& aEvent ) void DIALOG_PNS_LENGTH_TUNING_SETTINGS::OnOkClick( wxCommandEvent& aEvent ) { - // fixme: use validators and TransferDataFromWindow m_settings.m_minAmplitude = m_minAmpl.GetValue(); m_settings.m_maxAmplitude = m_maxAmpl.GetValue(); m_settings.m_spacing = m_spacing.GetValue(); m_settings.m_cornerRadiusPercentage = wxAtoi( m_radiusText->GetValue() ); - - if (m_mode == PNS_MODE_TUNE_DIFF_PAIR_SKEW) + + if( m_mode == PNS_MODE_TUNE_DIFF_PAIR_SKEW ) m_settings.m_targetSkew = m_targetLength.GetValue(); else m_settings.m_targetLength = m_targetLength.GetValue(); - if ( m_settings.m_maxAmplitude < m_settings.m_minAmplitude ) + if( m_settings.m_maxAmplitude < m_settings.m_minAmplitude ) m_settings.m_maxAmplitude = m_settings.m_maxAmplitude; - - m_settings.m_cornerType = m_miterStyle->GetSelection( ) ? PNS_MEANDER_SETTINGS::CHAMFER : PNS_MEANDER_SETTINGS::ROUND; - - + m_settings.m_cornerType = m_miterStyle->GetSelection() ? PNS_MEANDER_SETTINGS::CHAMFER : PNS_MEANDER_SETTINGS::ROUND; EndModal( 1 ); } diff --git a/pcbnew/dialogs/dialog_pns_length_tuning_settings.h b/pcbnew/dialogs/dialog_pns_length_tuning_settings.h index ae83c36125..f65d9503bf 100644 --- a/pcbnew/dialogs/dialog_pns_length_tuning_settings.h +++ b/pcbnew/dialogs/dialog_pns_length_tuning_settings.h @@ -35,22 +35,21 @@ class PNS_MEANDER_SETTINGS; class DIALOG_PNS_LENGTH_TUNING_SETTINGS : public DIALOG_PNS_LENGTH_TUNING_SETTINGS_BASE { - public: - DIALOG_PNS_LENGTH_TUNING_SETTINGS( wxWindow* aParent, PNS_MEANDER_SETTINGS& aSettings, PNS_ROUTER_MODE aMode ); +public: + DIALOG_PNS_LENGTH_TUNING_SETTINGS( wxWindow* aParent, PNS_MEANDER_SETTINGS& aSettings, PNS_ROUTER_MODE aMode ); - virtual void OnClose( wxCloseEvent& aEvent ); - virtual void OnOkClick( wxCommandEvent& aEvent ); - virtual void OnCancelClick( wxCommandEvent& aEvent ); - - private: + virtual void OnClose( wxCloseEvent& aEvent ); + virtual void OnOkClick( wxCommandEvent& aEvent ); + virtual void OnCancelClick( wxCommandEvent& aEvent ); - WX_UNIT_BINDER m_minAmpl; - WX_UNIT_BINDER m_maxAmpl; - WX_UNIT_BINDER m_spacing; - WX_UNIT_BINDER m_targetLength; +private: + WX_UNIT_BINDER m_minAmpl; + WX_UNIT_BINDER m_maxAmpl; + WX_UNIT_BINDER m_spacing; + WX_UNIT_BINDER m_targetLength; - PNS_MEANDER_SETTINGS& m_settings; - PNS_ROUTER_MODE m_mode; + PNS_MEANDER_SETTINGS& m_settings; + PNS_ROUTER_MODE m_mode; }; #endif // __dialog_pns_settings__ diff --git a/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak b/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak deleted file mode 100644 index fdda4f1fef..0000000000 --- a/pcbnew/dialogs/dialog_pns_settings_base.fbp.bak +++ /dev/null @@ -1,1334 +0,0 @@ - - - - - - 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 - - 279,481 - wxDEFAULT_DIALOG_STYLE - DIALOG_SHIM; dialog_shim.h - Interactive Router settings - - - - - - - - - - - - - - OnClose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bMainSizer - wxVERTICAL - none - - 5 - wxALL|wxEXPAND - 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 - 0 - 1 - - wxRA_SPECIFY_COLS - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxEXPAND|wxALL - 1 - - wxID_ANY - Options - - bOptions - wxVERTICAL - none - - - 5 - wxTOP|wxRIGHT|wxLEFT - 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 - wxTOP|wxRIGHT|wxLEFT - 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 - wxTOP|wxRIGHT|wxLEFT - 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 - wxTOP|wxRIGHT|wxLEFT - 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 - wxTOP|wxRIGHT|wxLEFT - 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 - wxTOP|wxRIGHT|wxLEFT - 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 - wxEXPAND - 0 - - - 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 | wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - m_staticline1 - 1 - - - protected - 1 - - Resizable - 1 - - wxLI_HORIZONTAL - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxEXPAND - 0 - - 0 - 1 - 0 - 0 - 0 - 1 - 0 - 0 - - m_stdButtons - protected - - OnCancelClick - - - - OnOkClick - - - - - - - - - - diff --git a/pcbnew/dialogs/dialog_track_via_size.cpp b/pcbnew/dialogs/dialog_track_via_size.cpp index 82abe58169..d8f025bad0 100644 --- a/pcbnew/dialogs/dialog_track_via_size.cpp +++ b/pcbnew/dialogs/dialog_track_via_size.cpp @@ -42,16 +42,16 @@ DIALOG_TRACK_VIA_SIZE::DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, BOARD_DESIGN_SE m_viaDrill.SetValue( m_settings.GetCustomViaDrill() ); m_trackWidthText->SetFocus(); - m_trackWidthText->SetSelection(-1, -1); + m_trackWidthText->SetSelection( -1, -1 ); m_stdButtonsOK->SetDefault(); - + // 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 - + Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_TRACK_VIA_SIZE::onClose ) ); } diff --git a/pcbnew/dialogs/dialog_track_via_size.h b/pcbnew/dialogs/dialog_track_via_size.h index c265e53311..b84d77f109 100644 --- a/pcbnew/dialogs/dialog_track_via_size.h +++ b/pcbnew/dialogs/dialog_track_via_size.h @@ -34,26 +34,25 @@ class BOARD_DESIGN_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, BOARD_DESIGN_SETTINGS& aSettings ); +public: + /** Constructor */ + DIALOG_TRACK_VIA_SIZE( wxWindow* aParent, BOARD_DESIGN_SETTINGS& aSettings ); - protected: +protected: + WX_UNIT_BINDER m_trackWidth; + WX_UNIT_BINDER m_viaDiameter; + WX_UNIT_BINDER m_viaDrill; - WX_UNIT_BINDER m_trackWidth; - WX_UNIT_BINDER m_viaDiameter; - WX_UNIT_BINDER m_viaDrill; + // Routings settings that are modified by the dialog. + BOARD_DESIGN_SETTINGS& m_settings; - // Routings settings that are modified by the dialog. - BOARD_DESIGN_SETTINGS& m_settings; + ///> Checks if values given in the dialog are sensible. + bool check(); - ///> 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 ); + // 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/loadcmp.cpp b/pcbnew/loadcmp.cpp index 39c6449428..866b5c384f 100644 --- a/pcbnew/loadcmp.cpp +++ b/pcbnew/loadcmp.cpp @@ -63,7 +63,7 @@ static void DisplayCmpDoc( wxString& aName, void* aData ); static FOOTPRINT_LIST MList; -static void clearModuleItemFlags ( BOARD_ITEM *aItem ) +static void clearModuleItemFlags( BOARD_ITEM* aItem ) { aItem->ClearFlags(); } diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 4c86dbceef..0062d6ea48 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -515,7 +515,6 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Configure Interactive Routing." ), KiBitmap( add_tracks_xpm ) ); // fixme: icon - //--- dimensions submenu ------------------------------------------------------ wxMenu* dimensionsMenu = new wxMenu; diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index e4a8d42612..c16e125501 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -70,7 +70,6 @@ #include #include - #include #if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON) @@ -537,7 +536,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager ); // Register tools - registerAllTools ( m_toolManager ); + registerAllTools( m_toolManager ); m_toolManager->ResetTools( TOOL_BASE::RUN ); diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index caf8d0965c..8078ae088d 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -48,7 +48,6 @@ enum pcbnew_ids ID_MENU_ADD_TEARDROPS, ID_MENU_DIFF_PAIR_DIMENSIONS, ID_MENU_INTERACTIVE_ROUTER_SETTINGS, - ID_PCB_MASK_CLEARANCE, ID_PCB_LAYERS_SETUP, diff --git a/pcbnew/router/direction.h b/pcbnew/router/direction.h index 44f137e68d..402d4c991e 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-2014 CERN + * Copyright (C) 2013-2015 CERN * Author: Tomasz Wlostowski * * This program is free software: you can redistribute it and/or modify it @@ -180,7 +180,7 @@ public: return ( m_dir % 2 ) == 1; } - bool IsDefined() const + bool IsDefined() const { return m_dir != UNDEFINED; } @@ -282,7 +282,7 @@ public: l.m_dir = NW; else l.m_dir = static_cast( m_dir - 1 ); - + return l; } @@ -303,10 +303,10 @@ public: case NW: return VECTOR2I( -1, 1 ); case SE: return VECTOR2I( 1, -1 ); case SW: return VECTOR2I( -1, -1 ); - + default: return VECTOR2I( 0, 0 ); - } + } } int Mask() const @@ -320,7 +320,8 @@ 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; @@ -343,40 +344,14 @@ private: if( dir < 0 ) dir = dir + 8; - + m_dir = (Directions) dir; return; - - if( aVec.y < 0 ) - { - if( aVec.x > 0 ) - m_dir = NE; - else if( aVec.x < 0 ) - m_dir = NW; - else - m_dir = N; - } - else if( aVec.y == 0 ) - { - if( aVec.x > 0 ) - m_dir = E; - else - m_dir = W; - } - else // aVec.y>0 - { - if( aVec.x > 0 ) - m_dir = SE; - else if( aVec.x < 0 ) - m_dir = SW; - else - m_dir = S; - } } - + ///> our actual direction - Directions m_dir; + Directions m_dir; }; #endif // __DIRECTION_H diff --git a/pcbnew/router/length_tuner_tool.cpp b/pcbnew/router/length_tuner_tool.cpp index 3bfe403cc9..79df24cfa5 100644 --- a/pcbnew/router/length_tuner_tool.cpp +++ b/pcbnew/router/length_tuner_tool.cpp @@ -86,7 +86,7 @@ public: TUNER_TOOL_MENU( BOARD* aBoard ) { SetTitle( wxT( "Length Tuner" ) ); - + //Add( ACT_StartTuning ); //Add( ACT_EndTuning ); @@ -96,7 +96,7 @@ public: Add( ACT_SpacingDecrease ); Add( ACT_AmplIncrease ); Add( ACT_AmplDecrease ); - Add( ACT_Settings ); + Add( ACT_Settings ); } }; @@ -106,10 +106,11 @@ LENGTH_TUNER_TOOL::~LENGTH_TUNER_TOOL() delete m_router; } + void LENGTH_TUNER_TOOL::Reset( RESET_REASON aReason ) { PNS_TOOL_BASE::Reset( aReason ); - + Go( &LENGTH_TUNER_TOOL::TuneSingleTrace, COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent() ); Go( &LENGTH_TUNER_TOOL::TuneDiffPair, COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent() ); Go( &LENGTH_TUNER_TOOL::TuneDiffPairSkew, COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent() ); @@ -128,9 +129,9 @@ void LENGTH_TUNER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) } } - PNS_MEANDER_PLACER_BASE *placer = static_cast ( m_router->Placer() ); + PNS_MEANDER_PLACER_BASE* placer = static_cast( m_router->Placer() ); - if (!placer) + if( !placer ) return; if( aEvent.IsAction( &ACT_Settings ) ) @@ -143,15 +144,16 @@ void LENGTH_TUNER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) placer->UpdateSettings ( settings ); } - m_savedMeanderSettings = placer->MeanderSettings( ); + m_savedMeanderSettings = placer->MeanderSettings(); } } + void LENGTH_TUNER_TOOL::performTuning() { bool saveUndoBuffer = true; - - if(m_startItem) + + if( m_startItem ) { m_frame->SetActiveLayer( ToLAYER_ID ( m_startItem->Layers().Start() ) ); @@ -162,22 +164,21 @@ void LENGTH_TUNER_TOOL::performTuning() m_ctls->ForceCursorPosition( false ); m_ctls->SetAutoPan( true ); - if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, 0 ) ) + if( !m_router->StartRouting( m_startSnapPoint, m_startItem, 0 ) ) { - wxMessageBox ( m_router->FailureReason(), _("Error") ); - highlightNet ( false ); + wxMessageBox( m_router->FailureReason(), _( "Error" ) ); + highlightNet( false ); return; } - PNS_TUNE_STATUS_POPUP statusPopup ( m_frame ); + PNS_TUNE_STATUS_POPUP statusPopup( m_frame ); statusPopup.Popup(); - PNS_MEANDER_PLACER *placer = static_cast ( m_router->Placer() ); + PNS_MEANDER_PLACER* placer = static_cast( m_router->Placer() ); VECTOR2I end; placer->UpdateSettings( m_savedMeanderSettings ); - while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() || evt->IsActivate() ) @@ -194,10 +195,10 @@ void LENGTH_TUNER_TOOL::performTuning() wxPoint p = wxGetMousePosition(); - p.x+=20; - p.y+=20; + p.x += 20; + p.y += 20; - statusPopup.Update ( m_router ); + statusPopup.Update( m_router ); statusPopup.Move( p ); } else if( evt->IsClick( BUT_LEFT ) ) @@ -209,16 +210,24 @@ void LENGTH_TUNER_TOOL::performTuning() { if( m_router->FixRoute( end, NULL ) ) break; - } else if (evt->IsAction ( &ACT_AmplDecrease ) ) { + } + else if( evt->IsAction( &ACT_AmplDecrease ) ) + { placer->AmplitudeStep( -1 ); m_router->Move( end, NULL ); - } else if (evt->IsAction ( &ACT_AmplIncrease ) ) { + } + else if( evt->IsAction( &ACT_AmplIncrease ) ) + { placer->AmplitudeStep( 1 ); m_router->Move( end, NULL ); - } else if (evt->IsAction ( &ACT_SpacingDecrease ) ) { + } + else if(evt->IsAction( &ACT_SpacingDecrease ) ) + { placer->SpacingStep( -1 ); m_router->Move( end, NULL ); - } else if (evt->IsAction ( &ACT_SpacingIncrease ) ) { + } + else if( evt->IsAction( &ACT_SpacingIncrease ) ) + { placer->SpacingStep( 1 ); m_router->Move( end, NULL ); } @@ -244,27 +253,29 @@ void LENGTH_TUNER_TOOL::performTuning() m_ctls->SetAutoPan( false ); m_ctls->ForceCursorPosition( false ); highlightNet( false ); - } -int LENGTH_TUNER_TOOL::TuneSingleTrace ( const TOOL_EVENT& aEvent ) + +int LENGTH_TUNER_TOOL::TuneSingleTrace( const TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Trace Length" ) ); return mainLoop( PNS_MODE_TUNE_SINGLE ); } -int LENGTH_TUNER_TOOL::TuneDiffPair ( const TOOL_EVENT& aEvent ) + +int LENGTH_TUNER_TOOL::TuneDiffPair( const TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Diff Pair Length" ) ); return mainLoop( PNS_MODE_TUNE_DIFF_PAIR ); } -int LENGTH_TUNER_TOOL::TuneDiffPairSkew ( const TOOL_EVENT& aEvent ) + +int LENGTH_TUNER_TOOL::TuneDiffPairSkew( const TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Diff Pair Skew" ) ); return mainLoop( PNS_MODE_TUNE_DIFF_PAIR_SKEW ); } - + int LENGTH_TUNER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) { @@ -273,13 +284,13 @@ int LENGTH_TUNER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) Activate(); - m_router->SetMode ( aMode ); - + m_router->SetMode( aMode ); + m_ctls->SetSnapping( true ); m_ctls->ShowCursor( true ); - std::auto_ptr ctxMenu ( new TUNER_TOOL_MENU( m_board ) ); - SetContextMenu ( ctxMenu.get() ); + std::auto_ptr ctxMenu( new TUNER_TOOL_MENU( m_board ) ); + SetContextMenu( ctxMenu.get() ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) @@ -300,7 +311,7 @@ int LENGTH_TUNER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_StartTuning ) ) { updateStartItem( *evt ); - performTuning( ); + performTuning( ); } handleCommonEvents( *evt ); @@ -316,4 +327,4 @@ int LENGTH_TUNER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) m_savedSizes = m_router->Sizes(); return 0; -} \ No newline at end of file +} diff --git a/pcbnew/router/length_tuner_tool.h b/pcbnew/router/length_tuner_tool.h index 79a2cd39ab..ed6ebf8fc1 100644 --- a/pcbnew/router/length_tuner_tool.h +++ b/pcbnew/router/length_tuner_tool.h @@ -35,16 +35,15 @@ public: void Reset( RESET_REASON aReason ); - int TuneSingleTrace ( const TOOL_EVENT& aEvent ); - int TuneDiffPair ( const TOOL_EVENT& aEvent ); - int TuneDiffPairSkew ( const TOOL_EVENT& aEvent ); - int ClearMeanders ( const TOOL_EVENT& aEvent ); + int TuneSingleTrace( const TOOL_EVENT& aEvent ); + int TuneDiffPair( const TOOL_EVENT& aEvent ); + int TuneDiffPairSkew( const TOOL_EVENT& aEvent ); + int ClearMeanders( const TOOL_EVENT& aEvent ); private: - void performTuning( ); int mainLoop( PNS_ROUTER_MODE aMode ); - void handleCommonEvents( const TOOL_EVENT& evt ); + void handleCommonEvents( const TOOL_EVENT& aEvent ); PNS_MEANDER_SETTINGS m_savedMeanderSettings; }; diff --git a/pcbnew/router/pns_algo_base.cpp b/pcbnew/router/pns_algo_base.cpp index 7008665428..b72243b223 100644 --- a/pcbnew/router/pns_algo_base.cpp +++ b/pcbnew/router/pns_algo_base.cpp @@ -23,10 +23,10 @@ PNS_ROUTING_SETTINGS& PNS_ALGO_BASE::Settings() const { - return m_router->Settings(); + return m_router->Settings(); } -PNS_LOGGER *PNS_ALGO_BASE::Logger() +PNS_LOGGER *PNS_ALGO_BASE::Logger() { - return NULL; -} \ No newline at end of file + return NULL; +} diff --git a/pcbnew/router/pns_algo_base.h b/pcbnew/router/pns_algo_base.h index e48fcf8137..a6429ea602 100644 --- a/pcbnew/router/pns_algo_base.h +++ b/pcbnew/router/pns_algo_base.h @@ -22,7 +22,7 @@ #define __PNS_ALGO_BASE_H #include // for wxString - + #include "pns_routing_settings.h" class PNS_ROUTER; @@ -33,32 +33,30 @@ class PNS_LOGGER; * * 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 ) - {} + PNS_ALGO_BASE( PNS_ROUTER* aRouter ) : + m_router( aRouter ) + {} - virtual ~PNS_ALGO_BASE() {} + virtual ~PNS_ALGO_BASE() {} - ///> Returns the instance of our router - PNS_ROUTER* Router() const - { - return m_router; - } + ///> Returns the instance of our router + PNS_ROUTER* Router() const + { + return m_router; + } - ///> Returns current router settings - PNS_ROUTING_SETTINGS& Settings() const; + ///> Returns current router settings + PNS_ROUTING_SETTINGS& Settings() const; - ///> Returns the logger object, allowing to dump geometry to a file. - virtual PNS_LOGGER* Logger(); + ///> Returns the logger object, allowing to dump geometry to a file. + virtual PNS_LOGGER* Logger(); - private: - PNS_ROUTER* m_router; + PNS_ROUTER* m_router; }; #endif diff --git a/pcbnew/router/pns_diff_pair.cpp b/pcbnew/router/pns_diff_pair.cpp index dba1e3153a..a352d79ef5 100644 --- a/pcbnew/router/pns_diff_pair.cpp +++ b/pcbnew/router/pns_diff_pair.cpp @@ -39,44 +39,48 @@ class PNS_LINE; -PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( PNS_ITEM *aPrimP, PNS_ITEM *aPrimN ) +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR( PNS_ITEM* aPrimP, PNS_ITEM* aPrimN ) { m_primP = aPrimP->Clone(); m_primN = aPrimN->Clone(); - - m_anchorP = m_primP->Anchor(0); - m_anchorN = m_primN->Anchor(0); + + m_anchorP = m_primP->Anchor( 0 ); + m_anchorN = m_primN->Anchor( 0 ); } + void PNS_DP_PRIMITIVE_PAIR::SetAnchors( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ) { m_anchorP = aAnchorP; m_anchorN = aAnchorN; } -PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ) + +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ) { m_anchorP = aAnchorP; m_anchorN = aAnchorN; m_primP = m_primN = NULL; } -PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR ( const PNS_DP_PRIMITIVE_PAIR& aOther ) + +PNS_DP_PRIMITIVE_PAIR::PNS_DP_PRIMITIVE_PAIR( const PNS_DP_PRIMITIVE_PAIR& aOther ) { - if(aOther.m_primP) + if( aOther.m_primP ) m_primP = aOther.m_primP->Clone(); - if(aOther.m_primN) + if( aOther.m_primN ) m_primN = aOther.m_primN->Clone(); m_anchorP = aOther.m_anchorP; m_anchorN = aOther.m_anchorN; } -PNS_DP_PRIMITIVE_PAIR& PNS_DP_PRIMITIVE_PAIR::operator= ( const PNS_DP_PRIMITIVE_PAIR& aOther ) + +PNS_DP_PRIMITIVE_PAIR& PNS_DP_PRIMITIVE_PAIR::operator=( const PNS_DP_PRIMITIVE_PAIR& aOther ) { - if(aOther.m_primP) + if( aOther.m_primP ) m_primP = aOther.m_primP->Clone(); - if(aOther.m_primN) + if( aOther.m_primN ) m_primN = aOther.m_primN->Clone(); m_anchorP = aOther.m_anchorP; @@ -85,105 +89,114 @@ PNS_DP_PRIMITIVE_PAIR& PNS_DP_PRIMITIVE_PAIR::operator= ( const PNS_DP_PRIMITIVE return *this; } - + PNS_DP_PRIMITIVE_PAIR::~PNS_DP_PRIMITIVE_PAIR() { delete m_primP; delete m_primN; } -bool PNS_DP_PRIMITIVE_PAIR::Directional() const + +bool PNS_DP_PRIMITIVE_PAIR::Directional() const { - if (!m_primP) + if( !m_primP ) return false; - return m_primP->OfKind(PNS_ITEM::SEGMENT); + return m_primP->OfKind( PNS_ITEM::SEGMENT ); } -DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::anchorDirection ( PNS_ITEM *aItem, const VECTOR2I& aP ) const + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::anchorDirection( PNS_ITEM* aItem, const VECTOR2I& aP ) const { if( !aItem->OfKind ( PNS_ITEM::SEGMENT ) ) return DIRECTION_45(); - PNS_SEGMENT *s = static_cast (aItem); + PNS_SEGMENT* s = static_cast( aItem ); - if(s->Seg().A == aP) - return DIRECTION_45 ( s->Seg().A - s->Seg().B ); + if( s->Seg().A == aP ) + return DIRECTION_45( s->Seg().A - s->Seg().B ); else - return DIRECTION_45 ( s->Seg().B - s->Seg().A ); + return DIRECTION_45( s->Seg().B - s->Seg().A ); } -DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirP () const + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirP() const { - return anchorDirection ( m_primP, m_anchorP ); + return anchorDirection( m_primP, m_anchorP ); } -DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirN () const + +DIRECTION_45 PNS_DP_PRIMITIVE_PAIR::DirN() const { - return anchorDirection ( m_primN, m_anchorN ); + return anchorDirection( m_primN, m_anchorN ); } -static void drawGw ( VECTOR2I p, int color ) + +static void drawGw( VECTOR2I p, int color ) { SHAPE_LINE_CHAIN l; - l.Append ( p - VECTOR2I(-50000, -50000) ); - l.Append ( p + VECTOR2I(-50000, -50000) ); - + l.Append( p - VECTOR2I( -50000, -50000 ) ); + l.Append( p + VECTOR2I( -50000, -50000 ) ); + //printf("router @ %p\n", PNS_ROUTER::GetInstance()); // PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); l.Clear(); - l.Append ( p - VECTOR2I(50000, -50000) ); - l.Append ( p + VECTOR2I(50000, -50000) ); + l.Append( p - VECTOR2I( 50000, -50000 ) ); + l.Append( p + VECTOR2I( 50000, -50000 ) ); // PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); - - } -static DIRECTION_45::AngleType angle ( const VECTOR2I &a, const VECTOR2I &b ) +static DIRECTION_45::AngleType angle( const VECTOR2I &a, const VECTOR2I &b ) { - DIRECTION_45 dir_a(a); - DIRECTION_45 dir_b(b); - - return dir_a.Angle(dir_b); - + DIRECTION_45 dir_a( a ); + DIRECTION_45 dir_b( b ); + + return dir_a.Angle( dir_b ); } -static bool checkGap ( const SHAPE_LINE_CHAIN &p, const SHAPE_LINE_CHAIN &n, int gap ) + +static bool checkGap( const SHAPE_LINE_CHAIN &p, const SHAPE_LINE_CHAIN &n, int gap ) { int i, j; - for (i = 0; i < p.SegmentCount() ;i++) - for (j = 0; j < n.SegmentCount() ; j++) + for( i = 0; i < p.SegmentCount(); i++ ) + { + for( j = 0; j < n.SegmentCount() ; j++ ) { - int dist = p.CSegment(i).Distance (n.CSegment(j)); - if (dist < gap - 100) + int dist = p.CSegment( i ).Distance( n.CSegment( j ) ); + + if( dist < gap - 100 ) return false; } + } + return true; } + void PNS_DP_GATEWAY::Reverse() { m_entryN = m_entryN.Reverse(); m_entryP = m_entryP.Reverse(); } -bool PNS_DIFF_PAIR::BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarget, bool aPrefDiagonal ) + +bool PNS_DIFF_PAIR::BuildInitial( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarget, bool aPrefDiagonal ) { SHAPE_LINE_CHAIN p = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorP(), aTarget.AnchorP(), aPrefDiagonal ); SHAPE_LINE_CHAIN n = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorN(), aTarget.AnchorN(), aPrefDiagonal ); - if(!checkGap ( p, n, m_gapConstraint )) + if( !checkGap ( p, n, m_gapConstraint ) ) return false; - if (p.SelfIntersecting() || n.SelfIntersecting() ) + if( p.SelfIntersecting() || n.SelfIntersecting() ) return false; - - if(p.Intersects(n)) + + if( p.Intersects( n ) ) return false; int mask = aEntry.AllowedAngles() | DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_OBTUSE; @@ -194,17 +207,20 @@ bool PNS_DIFF_PAIR::BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarg if( aEntry.HasEntryLines() ) { - if ( !aEntry.Entry().CheckConnectionAngle( *this, mask ) ) - return false; + if( !aEntry.Entry().CheckConnectionAngle( *this, mask ) ) + return false; + sum_p = aEntry.Entry().CP(); sum_n = aEntry.Entry().CN(); - sum_p.Append(p); - sum_n.Append(n); - } else { + sum_p.Append( p ); + sum_n.Append( n ); + } + else + { sum_p = p; sum_n = n; } - + mask = aTarget.AllowedAngles() | DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_OBTUSE; m_p = sum_p; @@ -220,98 +236,100 @@ bool PNS_DIFF_PAIR::BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarg sum_p.Append( t.Entry().CP() ); sum_n.Append( t.Entry().CN() ); - } m_p = sum_p; m_n = sum_n; - + return true; } -bool PNS_DIFF_PAIR::CheckConnectionAngle ( const PNS_DIFF_PAIR &aOther, int allowedAngles ) const + +bool PNS_DIFF_PAIR::CheckConnectionAngle( const PNS_DIFF_PAIR& aOther, int aAllowedAngles ) const { bool checkP, checkN; - - if( m_p.SegmentCount() == 0 || aOther.m_p.SegmentCount() == 0) + if( m_p.SegmentCount() == 0 || aOther.m_p.SegmentCount() == 0 ) checkP = true; - else { - DIRECTION_45 p0 ( m_p.CSegment(-1) ); - DIRECTION_45 p1 ( aOther.m_p.CSegment(0) ); + else + { + DIRECTION_45 p0( m_p.CSegment( -1 ) ); + DIRECTION_45 p1( aOther.m_p.CSegment( 0 ) ); - checkP = (p0.Angle(p1) & allowedAngles) != 0; + checkP = ( p0.Angle( p1 ) & aAllowedAngles ) != 0; } - - if( m_n.SegmentCount() == 0 || aOther.m_n.SegmentCount() == 0) + if( m_n.SegmentCount() == 0 || aOther.m_n.SegmentCount() == 0 ) checkN = true; - else { - DIRECTION_45 n0 ( m_n.CSegment(-1) ); - DIRECTION_45 n1 ( aOther.m_n.CSegment(0) ); + else + { + DIRECTION_45 n0( m_n.CSegment( -1 ) ); + DIRECTION_45 n1( aOther.m_n.CSegment( 0 ) ); - checkN = (n0.Angle(n1) & allowedAngles) != 0; + checkN = ( n0.Angle( n1 ) & aAllowedAngles ) != 0; } return checkP && checkN; } + const PNS_DIFF_PAIR PNS_DP_GATEWAY::Entry() const { - return PNS_DIFF_PAIR(m_entryP, m_entryN, 0); + return PNS_DIFF_PAIR( m_entryP, m_entryN, 0 ); } -void PNS_DP_GATEWAYS::BuildOrthoProjections ( PNS_DP_GATEWAYS& aEntries, const VECTOR2I& aCursorPos, int aOrthoScore ) + +void PNS_DP_GATEWAYS::BuildOrthoProjections( PNS_DP_GATEWAYS& aEntries, + const VECTOR2I& aCursorPos, int aOrthoScore ) { - BOOST_FOREACH(PNS_DP_GATEWAY g, aEntries.Gateways()) + BOOST_FOREACH( PNS_DP_GATEWAY g, aEntries.Gateways() ) { - VECTOR2I dir = (g.AnchorP() - g.AnchorN()).Perpendicular(); - VECTOR2I midpoint ( ( g.AnchorP() + g.AnchorN() ) / 2); - SEG guide ( midpoint, midpoint + dir ); - VECTOR2I proj = guide.LineProject(aCursorPos); - - - PNS_DP_GATEWAYS targets(m_gap); - + VECTOR2I dir = ( g.AnchorP() - g.AnchorN() ).Perpendicular(); + VECTOR2I midpoint( ( g.AnchorP() + g.AnchorN() ) / 2 ); + SEG guide( midpoint, midpoint + dir ); + VECTOR2I proj = guide.LineProject( aCursorPos ); + + PNS_DP_GATEWAYS targets( m_gap ); + targets.m_viaGap = m_viaGap; targets.m_viaDiameter = m_viaDiameter; targets.m_fitVias = m_fitVias; - - targets.BuildForCursor ( proj ); - BOOST_FOREACH ( PNS_DP_GATEWAY t, targets.Gateways() ) + targets.BuildForCursor( proj ); + + BOOST_FOREACH( PNS_DP_GATEWAY t, targets.Gateways() ) { - t.SetPriority ( aOrthoScore ); - m_gateways.push_back ( t ); + t.SetPriority( aOrthoScore ); + m_gateways.push_back( t ); } } } - -bool PNS_DP_GATEWAYS::FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ) + +bool PNS_DP_GATEWAYS::FitGateways( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, + bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ) { std::vector candidates; - + BOOST_FOREACH( PNS_DP_GATEWAY g_entry, aEntry.Gateways() ) { - BOOST_FOREACH ( PNS_DP_GATEWAY g_target, aTarget.Gateways() ) + BOOST_FOREACH( PNS_DP_GATEWAY g_target, aTarget.Gateways() ) { - for(int attempt = 0; attempt < 2; attempt ++) + for( int attempt = 0; attempt < 2; attempt++ ) { - PNS_DIFF_PAIR l ( m_gap ); + PNS_DIFF_PAIR l( m_gap ); - if ( l.BuildInitial( g_entry, g_target, aPrefDiagonal ^ (attempt ? true : false) ) ) + if( l.BuildInitial( g_entry, g_target, aPrefDiagonal ^ ( attempt ? true : false ) ) ) { - int score = (attempt == 1 ? -3 : 0); + int score = ( attempt == 1 ? -3 : 0 ); score +=g_entry.Priority(); - score +=g_target.Priority(); + score +=g_target.Priority(); - DP_CANDIDATE c; c.score = score; c.p = l.CP(); c.n = l.CN(); - candidates.push_back(c); + candidates.push_back( c ); } } } @@ -323,7 +341,7 @@ bool PNS_DP_GATEWAYS::FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& a BOOST_FOREACH( DP_CANDIDATE c, candidates ) { - if ( c.score > bestScore ) + if( c.score > bestScore ) { bestScore = c.score; best = c; @@ -331,9 +349,9 @@ bool PNS_DP_GATEWAYS::FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& a } } - if ( found ) + if( found ) { - aDp.SetGap ( m_gap ); + aDp.SetGap( m_gap ); aDp.SetShape( best.p, best.n ); return true; } @@ -341,7 +359,8 @@ bool PNS_DP_GATEWAYS::FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& a return false; } -bool PNS_DP_GATEWAYS::checkDiagonalAlignment ( const VECTOR2I& a, const VECTOR2I& b) const + +bool PNS_DP_GATEWAYS::checkDiagonalAlignment( const VECTOR2I& a, const VECTOR2I& b ) const { VECTOR2I dir ( std::abs (a.x - b.x), std::abs ( a.y - b.y )); @@ -355,104 +374,107 @@ void PNS_DP_GATEWAYS::BuildFromPrimitivePair( PNS_DP_PRIMITIVE_PAIR aPair, bool VECTOR2I p0_p, p0_n; int orthoFanDistance; int diagFanDistance; - const SHAPE *shP = NULL; + const SHAPE* shP = NULL; - if( aPair.PrimP() == NULL) + if( aPair.PrimP() == NULL ) { - BuildGeneric ( aPair.AnchorP(), aPair.AnchorN(), true ); + BuildGeneric( aPair.AnchorP(), aPair.AnchorN(), true ); return; } const int pvMask = PNS_ITEM::SOLID | PNS_ITEM::VIA; - if ( aPair.PrimP()->OfKind ( pvMask ) && aPair.PrimN()->OfKind ( pvMask ) ) + if( aPair.PrimP()->OfKind( pvMask ) && aPair.PrimN()->OfKind( pvMask ) ) { p0_p = aPair.AnchorP(); p0_n = aPair.AnchorN(); - + shP = aPair.PrimP()->Shape(); - } else if ( aPair.PrimP()->OfKind ( PNS_ITEM::SEGMENT ) && aPair.PrimN()->OfKind ( PNS_ITEM::SEGMENT ) ) { - buildDpContinuation ( aPair, aPreferDiagonal ); + } + else if( aPair.PrimP()->OfKind( PNS_ITEM::SEGMENT ) && aPair.PrimN()->OfKind( PNS_ITEM::SEGMENT ) ) + { + buildDpContinuation( aPair, aPreferDiagonal ); return; } - majorDirection = (p0_p - p0_n).Perpendicular(); + majorDirection = ( p0_p - p0_n ).Perpendicular(); switch( shP->Type() ) { case SH_RECT: { - int w = static_cast ( shP )->GetWidth(); - int h = static_cast ( shP )->GetHeight(); + int w = static_cast( shP )->GetWidth(); + int h = static_cast( shP )->GetHeight(); - if(w < h) - std::swap(w,h); + if( w < h ) + std::swap( w, h ); orthoFanDistance = w * 3/4; - diagFanDistance = (w - h) / 2; + diagFanDistance = ( w - h ) / 2; break; } - + case SH_SEGMENT: { - int w = static_cast ( shP )->GetWidth(); - SEG s = static_cast ( shP )->GetSeg(); + int w = static_cast( shP )->GetWidth(); + SEG s = static_cast( shP )->GetSeg(); - orthoFanDistance = w + (s.B - s.A).EuclideanNorm() / 2; - diagFanDistance = (s.B - s.A).EuclideanNorm() / 2; + orthoFanDistance = w + ( s.B - s.A ).EuclideanNorm() / 2; + diagFanDistance = ( s.B - s.A ).EuclideanNorm() / 2; break; } default: - BuildGeneric ( p0_p, p0_n, true ); - return; + BuildGeneric ( p0_p, p0_n, true ); + return; } - if(checkDiagonalAlignment ( p0_p, p0_n )) + if( checkDiagonalAlignment( p0_p, p0_n ) ) { - int padDist = (p0_p - p0_n).EuclideanNorm(); - - for(int k = 0; k < 2; k++ ) + int padDist = ( p0_p - p0_n ).EuclideanNorm(); + + for( int k = 0; k < 2; k++ ) { VECTOR2I dir, dp, dv; - if(k == 0) + if( k == 0 ) { - - dir = majorDirection.Resize(orthoFanDistance); - int d = (padDist - m_gap) / 2; + dir = majorDirection.Resize( orthoFanDistance ); + int d = ( padDist - m_gap ) / 2; dp = dir.Resize( d ); - dv = (p0_n - p0_p).Resize( d ); - } else { - dir = majorDirection.Resize(diagFanDistance); - int d = (padDist - m_gap) / 2; + dv = ( p0_n - p0_p ).Resize( d ); + } + else + { + dir = majorDirection.Resize( diagFanDistance ); + int d = ( padDist - m_gap ) / 2; dp = dir.Resize( d ); - dv = (p0_n - p0_p).Resize( d ); + dv = ( p0_n - p0_p ).Resize( d ); } - for(int i = 0; i < 2; i++) + for( int i = 0; i < 2; i++ ) { int sign = i ? -1 : 1; - VECTOR2I gw_p ( p0_p + sign * (dir + dp) + dv ); - VECTOR2I gw_n ( p0_n + sign * (dir + dp) - dv ); + VECTOR2I gw_p( p0_p + sign * ( dir + dp ) + dv ); + VECTOR2I gw_n( p0_n + sign * ( dir + dp ) - dv ); - SHAPE_LINE_CHAIN entryP (p0_p, p0_p + sign * dir, gw_p); - SHAPE_LINE_CHAIN entryN (p0_n, p0_n + sign * dir, gw_n); + SHAPE_LINE_CHAIN entryP( p0_p, p0_p + sign * dir, gw_p ); + SHAPE_LINE_CHAIN entryN( p0_n, p0_n + sign * dir, gw_n ); - PNS_DP_GATEWAY gw ( gw_p, gw_n, false ); - - gw.SetEntryLines ( entryP, entryN ); - gw.SetPriority(100 - k); + PNS_DP_GATEWAY gw( gw_p, gw_n, false ); + + gw.SetEntryLines( entryP, entryN ); + gw.SetPriority( 100 - k ); m_gateways.push_back( gw ); } } - } + } - BuildGeneric ( p0_p, p0_n, true ); + BuildGeneric( p0_p, p0_n, true ); } @@ -460,103 +482,103 @@ void PNS_DP_GATEWAYS::BuildForCursor( const VECTOR2I& aCursorPos ) { int gap = m_fitVias ? m_viaGap + m_viaDiameter : m_gap; - for (int attempt = 0; attempt < 2; attempt ++) + for( int attempt = 0; attempt < 2; attempt++ ) { - for(int i = 0; i < 4; i++ ) - { - VECTOR2I dir; - - - if( !attempt ) - { - dir = VECTOR2I( gap, gap ).Resize( gap / 2 ); - - if( i % 2 == 0 ) - dir.x = -dir.x; - if( i / 2 == 0 ) - dir.y = -dir.y; - } - else - { - if( i /2 == 0) - dir = VECTOR2I( gap / 2 * ( (i % 2) ? -1 : 1), 0 ); - else - dir = VECTOR2I( 0, gap / 2 * ( (i % 2) ? -1 : 1) ); - } - - if( m_fitVias ) - BuildGeneric ( aCursorPos + dir, aCursorPos - dir, true, true ); - else - m_gateways.push_back( PNS_DP_GATEWAY( aCursorPos + dir, aCursorPos - dir, attempt ? true : false ) ); - - drawGw ( aCursorPos + dir, 2 ); - drawGw ( aCursorPos - dir, 3 ); - } - } -} - - -void PNS_DP_GATEWAYS::buildEntries ( const VECTOR2I& p0_p, const VECTOR2I& p0_n ) -{ - BOOST_FOREACH (PNS_DP_GATEWAY &g, m_gateways ) - { - if ( !g.HasEntryLines() ) + for( int i = 0; i < 4; i++ ) { - SHAPE_LINE_CHAIN lead_p = DIRECTION_45().BuildInitialTrace ( g.AnchorP(), p0_p, g.IsDiagonal() ).Reverse(); - SHAPE_LINE_CHAIN lead_n = DIRECTION_45().BuildInitialTrace ( g.AnchorN(), p0_n, g.IsDiagonal() ).Reverse(); - g.SetEntryLines(lead_p, lead_n); + VECTOR2I dir; + + if( !attempt ) + { + dir = VECTOR2I( gap, gap ).Resize( gap / 2 ); + + if( i % 2 == 0 ) + dir.x = -dir.x; + + if( i / 2 == 0 ) + dir.y = -dir.y; + } + else + { + if( i /2 == 0 ) + dir = VECTOR2I( gap / 2 * ( ( i % 2 ) ? -1 : 1 ), 0 ); + else + dir = VECTOR2I( 0, gap / 2 * ( ( i % 2 ) ? -1 : 1) ); + } + + if( m_fitVias ) + BuildGeneric( aCursorPos + dir, aCursorPos - dir, true, true ); + else + m_gateways.push_back( PNS_DP_GATEWAY( aCursorPos + dir, + aCursorPos - dir, attempt ? true : false ) ); + + drawGw ( aCursorPos + dir, 2 ); + drawGw ( aCursorPos - dir, 3 ); } } } -void PNS_DP_GATEWAYS::buildDpContinuation ( PNS_DP_PRIMITIVE_PAIR aPair, bool aIsDiagonal ) +void PNS_DP_GATEWAYS::buildEntries( const VECTOR2I& p0_p, const VECTOR2I& p0_n ) { - PNS_DP_GATEWAY gw ( aPair.AnchorP(), aPair.AnchorN(), aIsDiagonal ); - gw.SetPriority( 100 ); - m_gateways.push_back ( gw ); + BOOST_FOREACH( PNS_DP_GATEWAY &g, m_gateways ) + { + if( !g.HasEntryLines() ) + { + SHAPE_LINE_CHAIN lead_p = DIRECTION_45().BuildInitialTrace ( g.AnchorP(), p0_p, g.IsDiagonal() ).Reverse(); + SHAPE_LINE_CHAIN lead_n = DIRECTION_45().BuildInitialTrace ( g.AnchorN(), p0_n, g.IsDiagonal() ).Reverse(); + g.SetEntryLines( lead_p, lead_n ); + } + } +} - if ( !aPair.Directional() ) + +void PNS_DP_GATEWAYS::buildDpContinuation( PNS_DP_PRIMITIVE_PAIR aPair, bool aIsDiagonal ) +{ + PNS_DP_GATEWAY gw( aPair.AnchorP(), aPair.AnchorN(), aIsDiagonal ); + gw.SetPriority( 100 ); + m_gateways.push_back( gw ); + + if( !aPair.Directional() ) return; DIRECTION_45 dP = aPair.DirP(); DIRECTION_45 dN = aPair.DirN(); - int gap = (aPair.AnchorP() - aPair.AnchorN()).EuclideanNorm(); + int gap = ( aPair.AnchorP() - aPair.AnchorN() ).EuclideanNorm(); VECTOR2I vdP = aPair.AnchorP() + dP.Left().ToVector(); VECTOR2I vdN = aPair.AnchorN() + dN.Left().ToVector(); - - PNS_SEGMENT *sP = static_cast (aPair.PrimP()); - + + PNS_SEGMENT* sP = static_cast( aPair.PrimP() ); + VECTOR2I t1, t2; - if( sP->Seg().Side(vdP) == sP->Seg().Side(vdN )) + if( sP->Seg().Side( vdP ) == sP->Seg().Side( vdN ) ) { t1 = aPair.AnchorP() + dP.Left().ToVector().Resize( gap ); t2 = aPair.AnchorN() + dP.Right().ToVector().Resize( gap ); - } - else + } + else { t1 = aPair.AnchorP() + dP.Right().ToVector().Resize( gap ); t2 = aPair.AnchorN() + dP.Left().ToVector().Resize( gap ); } + PNS_DP_GATEWAY gwL( t2, aPair.AnchorN(), !aIsDiagonal ); + SHAPE_LINE_CHAIN ep = dP.BuildInitialTrace( aPair.AnchorP(), t2, !aIsDiagonal ); - PNS_DP_GATEWAY gwL ( t2, aPair.AnchorN(), !aIsDiagonal ); - SHAPE_LINE_CHAIN ep = dP.BuildInitialTrace ( aPair.AnchorP(), t2, !aIsDiagonal ); - - gwL.SetPriority(10); - gwL.SetEntryLines ( ep , SHAPE_LINE_CHAIN( ) ); + gwL.SetPriority( 10 ); + gwL.SetEntryLines( ep , SHAPE_LINE_CHAIN() ); - m_gateways.push_back(gwL); + m_gateways.push_back( gwL ); - PNS_DP_GATEWAY gwR (aPair.AnchorP(), t1, !aIsDiagonal ); - SHAPE_LINE_CHAIN en = dP.BuildInitialTrace ( aPair.AnchorN(), t1, !aIsDiagonal ); - gwR.SetPriority(10); - gwR.SetEntryLines ( SHAPE_LINE_CHAIN( ), en ); + PNS_DP_GATEWAY gwR( aPair.AnchorP(), t1, !aIsDiagonal ); + SHAPE_LINE_CHAIN en = dP.BuildInitialTrace( aPair.AnchorN(), t1, !aIsDiagonal ); + gwR.SetPriority( 10) ; + gwR.SetEntryLines( SHAPE_LINE_CHAIN(), en ); - m_gateways.push_back(gwR); + m_gateways.push_back( gwR ); } @@ -566,32 +588,32 @@ void PNS_DP_GATEWAYS::BuildGeneric( const VECTOR2I& p0_p, const VECTOR2I& p0_n, SEG d_n[2], d_p[2]; const int padToGapThreshold = 3; - int padDist = ( p0_p - p0_p ).EuclideanNorm( ); + int padDist = ( p0_p - p0_p ).EuclideanNorm(); - st_p[0] = SEG(p0_p + VECTOR2I(-100, 0), p0_p + VECTOR2I(100, 0) ); - st_n[0] = SEG(p0_n + VECTOR2I(-100, 0), p0_n + VECTOR2I(100, 0) ); - st_p[1] = SEG(p0_p + VECTOR2I(0, -100), p0_p + VECTOR2I(0, 100) ); - st_n[1] = SEG(p0_n + VECTOR2I(0, -100), p0_n + VECTOR2I(0, 100) ); - d_p[0] = SEG ( p0_p + VECTOR2I (-100, -100), p0_p + VECTOR2I(100, 100)); - d_p[1] = SEG ( p0_p + VECTOR2I (100, -100), p0_p + VECTOR2I(-100, 100)); - d_n[0] = SEG ( p0_n + VECTOR2I (-100, -100), p0_n + VECTOR2I(100, 100)); - d_n[1] = SEG ( p0_n + VECTOR2I (100, -100), p0_n + VECTOR2I(-100, 100)); + st_p[0] = SEG(p0_p + VECTOR2I( -100, 0 ), p0_p + VECTOR2I( 100, 0 ) ); + st_n[0] = SEG(p0_n + VECTOR2I( -100, 0 ), p0_n + VECTOR2I( 100, 0 ) ); + st_p[1] = SEG(p0_p + VECTOR2I( 0, -100 ), p0_p + VECTOR2I( 0, 100 ) ); + st_n[1] = SEG(p0_n + VECTOR2I( 0, -100 ), p0_n + VECTOR2I( 0, 100 ) ); + d_p[0] = SEG( p0_p + VECTOR2I( -100, -100 ), p0_p + VECTOR2I( 100, 100 ) ); + d_p[1] = SEG( p0_p + VECTOR2I( 100, -100 ), p0_p + VECTOR2I( -100, 100 ) ); + d_n[0] = SEG( p0_n + VECTOR2I( -100, -100 ), p0_n + VECTOR2I( 100, 100 ) ); + d_n[1] = SEG( p0_n + VECTOR2I( 100, -100 ), p0_n + VECTOR2I( -100, 100 ) ); // midpoint exit & side-by exits - for(int i = 0; i < 2; i++) + for( int i = 0; i < 2; i++ ) { - bool straightColl = st_p[i].Collinear ( st_n[i] ); + bool straightColl = st_p[i].Collinear( st_n[i] ); bool diagColl = d_p[i].Collinear( d_n[i] ); - + if( straightColl || diagColl ) { VECTOR2I dir = ( p0_n - p0_p ).Resize( m_gap / 2 ); VECTOR2I m = ( p0_p + p0_n ) / 2; int prio = ( padDist > padToGapThreshold * m_gap ? 2 : 1); - if(!aViaMode) + if( !aViaMode ) { - m_gateways.push_back( PNS_DP_GATEWAY( m - dir, m + dir, diagColl, DIRECTION_45::ANG_RIGHT, prio ) ); + m_gateways.push_back( PNS_DP_GATEWAY( m - dir, m + dir, diagColl, DIRECTION_45::ANG_RIGHT, prio ) ); dir = ( p0_n - p0_p ).Resize( m_gap ); m_gateways.push_back( PNS_DP_GATEWAY( p0_p - dir, p0_p - dir + dir.Perpendicular(), diagColl ) ); @@ -602,30 +624,30 @@ void PNS_DP_GATEWAYS::BuildGeneric( const VECTOR2I& p0_p, const VECTOR2I& p0_n, } } - - for (int i = 0; i < 2; i++) - for(int j = 0; j < 2; j++) + for( int i = 0; i < 2; i++ ) + { + for( int j = 0; j < 2; j++ ) { OPT_VECTOR2I ips[2], m; ips[0] = d_n[i].IntersectLines( d_p[j] ); ips[1] = st_p[i].IntersectLines( st_n[j] ); - if ( d_n[i].Collinear (d_p[j]) ) + if( d_n[i].Collinear( d_p[j] ) ) ips [0] = OPT_VECTOR2I(); - if ( st_p[i].Collinear (st_p[j]) ) + if( st_p[i].Collinear( st_p[j] ) ) ips [1] = OPT_VECTOR2I(); // diagonal-diagonal and straight-straight cases - the most typical case if the pads // are on the same straight/diagonal line - for ( int k = 0; k < 2; k++ ) + for( int k = 0; k < 2; k++ ) { - m = ips [ k ]; - if(m && *m != p0_p && *m != p0_n ) + m = ips[k]; + if( m && *m != p0_p && *m != p0_n ) { - int prio = ( padDist > padToGapThreshold * m_gap ? 10 : 20); - VECTOR2I g_p ( ( p0_p - *m ).Resize ( ( double ) m_gap * M_SQRT1_2 ) ); - VECTOR2I g_n ( ( p0_n - *m ).Resize ( ( double ) m_gap * M_SQRT1_2 ) ); + int prio = ( padDist > padToGapThreshold * m_gap ? 10 : 20 ); + VECTOR2I g_p( ( p0_p - *m ).Resize( (double) m_gap * M_SQRT1_2 ) ); + VECTOR2I g_n( ( p0_n - *m ).Resize( (double) m_gap * M_SQRT1_2 ) ); m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, k == 0 ? true : false, DIRECTION_45::ANG_OBTUSE, prio ) ); } @@ -635,175 +657,182 @@ void PNS_DP_GATEWAYS::BuildGeneric( const VECTOR2I& p0_p, const VECTOR2I& p0_n, ips[1] = st_p[i].IntersectLines( d_n[j] ); // diagonal-straight cases: 8 possibilities of "weirder" exists - for ( int k = 0; k < 2; k++ ) + for( int k = 0; k < 2; k++ ) { m = ips[k]; - - if(!aViaMode && m && *m != p0_p && *m != p0_n ) + + if( !aViaMode && m && *m != p0_p && *m != p0_n ) { VECTOR2I g_p, g_n; - g_p = ( p0_p - *m ).Resize ((double)m_gap * M_SQRT2 ); - g_n = ( p0_n - *m ).Resize ((double)m_gap ); + g_p = ( p0_p - *m ).Resize( (double) m_gap * M_SQRT2 ); + g_n = ( p0_n - *m ).Resize( (double) m_gap ); - if ( angle ( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) + if( angle( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, true ) ); - - g_p = ( p0_p - *m ).Resize ( m_gap ); - g_n = ( p0_n - *m ).Resize ( (double)m_gap * M_SQRT2 ); - if ( angle ( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) + g_p = ( p0_p - *m ).Resize( m_gap ); + g_n = ( p0_n - *m ).Resize( (double) m_gap * M_SQRT2 ); + + if( angle( g_p, g_n ) != DIRECTION_45::ANG_ACUTE ) m_gateways.push_back( PNS_DP_GATEWAY( *m + g_p, *m + g_n, true ) ); - } } + } } - if (aBuildEntries) - buildEntries(p0_p, p0_n); + if( aBuildEntries ) + buildEntries( p0_p, p0_n ); } PNS_DP_PRIMITIVE_PAIR PNS_DIFF_PAIR::EndingPrimitives() { - if (m_hasVias) - return PNS_DP_PRIMITIVE_PAIR ( &m_via_p, &m_via_n ); + if( m_hasVias ) + return PNS_DP_PRIMITIVE_PAIR( &m_via_p, &m_via_n ); else { - const PNS_LINE lP ( PLine() ); - const PNS_LINE lN ( NLine() ); + const PNS_LINE lP( PLine() ); + const PNS_LINE lN( NLine() ); + + PNS_SEGMENT sP( lP, lP.CSegment( -1 ) ); + PNS_SEGMENT sN( lN, lN.CSegment( -1 ) ); + + PNS_DP_PRIMITIVE_PAIR dpair( &sP, &sN ); + dpair.SetAnchors( sP.Seg().B, sN.Seg().B ); - PNS_SEGMENT sP ( lP, lP.CSegment(-1) ); - PNS_SEGMENT sN ( lN, lN.CSegment(-1) ); - - PNS_DP_PRIMITIVE_PAIR dpair ( &sP, &sN ); - dpair.SetAnchors ( sP.Seg().B, sN.Seg().B ); return dpair; } } -bool commonParallelProjection ( SEG n, SEG p, SEG &pClip, SEG& nClip ) + +bool commonParallelProjection( SEG n, SEG p, SEG &pClip, SEG& nClip ) { - SEG n_proj_p ( p.LineProject(n.A), p.LineProject(n.B) ); - + SEG n_proj_p( p.LineProject( n.A ), p.LineProject( n.B ) ); + int64_t t_a = 0; - int64_t t_b = p.TCoef(p.B); + int64_t t_b = p.TCoef( p.B ); - int64_t tproj_a = p.TCoef(n_proj_p.A); - int64_t tproj_b = p.TCoef(n_proj_p.B); + int64_t tproj_a = p.TCoef( n_proj_p.A ); + int64_t tproj_b = p.TCoef( n_proj_p.B ); - if(t_b < t_a) - std::swap ( t_b, t_a ); + if( t_b < t_a ) + std::swap( t_b, t_a ); - if(tproj_b < tproj_a) - std::swap ( tproj_b, tproj_a ); - + if( tproj_b < tproj_a ) + std::swap( tproj_b, tproj_a ); - if(t_b <= tproj_a) + if( t_b <= tproj_a ) return false; - if(t_a >= tproj_b) + if( t_a >= tproj_b ) return false; - - int64_t t[4] = { 0, p.TCoef ( p.B ), p.TCoef ( n_proj_p.A ), p.TCoef ( n_proj_p.B ) }; - std::vector tv(t, t+4); - std::sort(tv.begin(), tv.end()); // fixme: awful and disgusting way of finding 2 midpoints + int64_t t[4] = { 0, p.TCoef( p.B ), p.TCoef( n_proj_p.A ), p.TCoef( n_proj_p.B ) }; + std::vector tv( t, t + 4 ); + std::sort( tv.begin(), tv.end() ); // fixme: awful and disgusting way of finding 2 midpoints int64_t pLenSq = p.SquaredLength(); VECTOR2I dp = p.B - p.A; - pClip.A.x = p.A.x + rescale ( (int64_t)dp.x, tv[1], pLenSq ); - pClip.A.y = p.A.y + rescale ( (int64_t)dp.y, tv[1], pLenSq ); + pClip.A.x = p.A.x + rescale( (int64_t)dp.x, tv[1], pLenSq ); + pClip.A.y = p.A.y + rescale( (int64_t)dp.y, tv[1], pLenSq ); - pClip.B.x = p.A.x + rescale ( (int64_t)dp.x, tv[2], pLenSq ); - pClip.B.y = p.A.y + rescale ( (int64_t)dp.y, tv[2], pLenSq ); + pClip.B.x = p.A.x + rescale( (int64_t)dp.x, tv[2], pLenSq ); + pClip.B.y = p.A.y + rescale( (int64_t)dp.y, tv[2], pLenSq ); - nClip.A = n.LineProject(pClip.A); - nClip.B = n.LineProject(pClip.B); + nClip.A = n.LineProject( pClip.A ); + nClip.B = n.LineProject( pClip.B ); return true; - } -double PNS_DIFF_PAIR::Skew () const + +double PNS_DIFF_PAIR::Skew() const { return m_p.Length() - m_n.Length(); } -void PNS_DIFF_PAIR::CoupledSegmentPairs ( COUPLED_SEGMENTS_VEC& aPairs ) const + +void PNS_DIFF_PAIR::CoupledSegmentPairs( COUPLED_SEGMENTS_VEC& aPairs ) const { - SHAPE_LINE_CHAIN p ( m_p ); - SHAPE_LINE_CHAIN n ( m_n ); + SHAPE_LINE_CHAIN p( m_p ); + SHAPE_LINE_CHAIN n( m_n ); p.Simplify(); n.Simplify(); - for(int i = 0; i < p.SegmentCount(); i++ ) + for( int i = 0; i < p.SegmentCount(); i++ ) { - for (int j = 0; j < n.SegmentCount(); j++ ) + for( int j = 0; j < n.SegmentCount(); j++ ) { - SEG sp = p.CSegment(i); - SEG sn = n.CSegment(j); - + SEG sp = p.CSegment( i ); + SEG sn = n.CSegment( j ); + SEG p_clip, n_clip; - int64_t dist = std::abs ( sp.Distance(sn) - m_width ); + int64_t dist = std::abs( sp.Distance( sn ) - m_width ); - if( sp.ApproxParallel(sn) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( sp, sn, p_clip, n_clip )) + if( sp.ApproxParallel( sn ) && m_gapConstraint.Matches( dist ) && commonParallelProjection( sp, sn, p_clip, n_clip ) ) { - const COUPLED_SEGMENTS spair ( p_clip, sp, i, n_clip, sn, j); + const COUPLED_SEGMENTS spair( p_clip, sp, i, n_clip, sn, j ); aPairs.push_back( spair ); } } } } -int64_t PNS_DIFF_PAIR::CoupledLength ( const SHAPE_LINE_CHAIN& aP, const SHAPE_LINE_CHAIN& aN ) const + +int64_t PNS_DIFF_PAIR::CoupledLength( const SHAPE_LINE_CHAIN& aP, const SHAPE_LINE_CHAIN& aN ) const { int64_t total = 0; - for(int i = 0; i < aP.SegmentCount(); i++ ) + for( int i = 0; i < aP.SegmentCount(); i++ ) { - for (int j = 0; j < aN.SegmentCount(); j++ ) + for( int j = 0; j < aN.SegmentCount(); j++ ) { - SEG sp = aP.CSegment(i); - SEG sn = aN.CSegment(j); - + SEG sp = aP.CSegment( i ); + SEG sn = aN.CSegment( j ); + SEG p_clip, n_clip; - int64_t dist = std::abs ( sp.Distance(sn) - m_width ); + int64_t dist = std::abs( sp.Distance(sn) - m_width ); - if( sp.ApproxParallel(sn) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( sp, sn, p_clip, n_clip )) + if( sp.ApproxParallel( sn ) && m_gapConstraint.Matches( dist ) && + commonParallelProjection( sp, sn, p_clip, n_clip ) ) total += p_clip.Length(); } } + return total; } - double PNS_DIFF_PAIR::CoupledLength() const { COUPLED_SEGMENTS_VEC pairs; - CoupledSegmentPairs(pairs); + CoupledSegmentPairs( pairs ); double l = 0.0; - for(unsigned int i = 0; i < pairs.size();i++) + for( unsigned int i = 0; i < pairs.size(); i++ ) l += pairs[i].coupledP.Length(); return l; } + double PNS_DIFF_PAIR::CoupledLengthFactor() const { double t = TotalLength(); - if( t == 0.0 ) + + if( t == 0.0 ) return 0.0; + return CoupledLength() / t; } + double PNS_DIFF_PAIR::TotalLength() const { double lenP = m_p.Length(); @@ -812,14 +841,15 @@ double PNS_DIFF_PAIR::TotalLength() const return (lenN + lenP ) / 2.0; } + int PNS_DIFF_PAIR::CoupledLength ( const SEG& aP, const SEG& aN ) const { SEG p_clip, n_clip; - int64_t dist = std::abs ( aP.Distance(aN) - m_width ); + int64_t dist = std::abs( aP.Distance( aN ) - m_width ); - if( aP.ApproxParallel(aN) && m_gapConstraint.Matches ( dist ) && commonParallelProjection ( aP, aN, p_clip, n_clip )) + if( aP.ApproxParallel( aN ) && m_gapConstraint.Matches( dist ) && + commonParallelProjection ( aP, aN, p_clip, n_clip ) ) return p_clip.Length(); return 0; } - diff --git a/pcbnew/router/pns_diff_pair.h b/pcbnew/router/pns_diff_pair.h index d680adf166..3b6a591839 100644 --- a/pcbnew/router/pns_diff_pair.h +++ b/pcbnew/router/pns_diff_pair.h @@ -43,23 +43,22 @@ class PNS_DIFF_PAIR; **/ class PNS_DP_GATEWAY { public: - PNS_DP_GATEWAY ( const VECTOR2I& aAnchorP, - const VECTOR2I& aAnchorN, - bool aIsDiagonal, - int aAllowedEntryAngles = DIRECTION_45::ANG_OBTUSE, - int aPriority = 0 ) - : m_anchorP(aAnchorP), - m_anchorN (aAnchorN), - m_isDiagonal( aIsDiagonal ), - m_allowedEntryAngles (aAllowedEntryAngles), - m_priority(aPriority) + PNS_DP_GATEWAY( const VECTOR2I& aAnchorP, + const VECTOR2I& aAnchorN, + bool aIsDiagonal, + int aAllowedEntryAngles = DIRECTION_45::ANG_OBTUSE, + int aPriority = 0 ) + : m_anchorP( aAnchorP ), + m_anchorN( aAnchorN ), + m_isDiagonal( aIsDiagonal ), + m_allowedEntryAngles( aAllowedEntryAngles ), + m_priority( aPriority ) { m_hasEntryLines = false; } - ~PNS_DP_GATEWAY () + ~PNS_DP_GATEWAY() { - } /** @@ -67,15 +66,15 @@ public: * * @return true, if the gateway anchors lie on a diagonal line */ - bool IsDiagonal() const { - return m_isDiagonal; + return m_isDiagonal; } - const VECTOR2I& AnchorP () const { return m_anchorP; } - const VECTOR2I& AnchorN () const { return m_anchorN; } - + const VECTOR2I& AnchorP() const { return m_anchorP; } + + const VECTOR2I& AnchorN() const { return m_anchorN; } + /** * Function AllowedAngles() * @@ -89,36 +88,35 @@ public: * * @return priority/score value for gateway matching */ - int Priority() const - { + int Priority() const + { return m_priority; } - - void SetPriority(int aPriority) + + void SetPriority(int aPriority) { m_priority = aPriority; } - void SetEntryLines ( const SHAPE_LINE_CHAIN& aEntryP, const SHAPE_LINE_CHAIN& aEntryN ) - { + void SetEntryLines( const SHAPE_LINE_CHAIN& aEntryP, const SHAPE_LINE_CHAIN& aEntryN ) + { m_entryP = aEntryP; m_entryN = aEntryN; m_hasEntryLines = true; } - const SHAPE_LINE_CHAIN& EntryP () const { return m_entryP; } - const SHAPE_LINE_CHAIN& EntryN () const { return m_entryN; } + const SHAPE_LINE_CHAIN& EntryP() const { return m_entryP; } + const SHAPE_LINE_CHAIN& EntryN() const { return m_entryN; } const PNS_DIFF_PAIR Entry() const ; - - void Reverse(); - - bool HasEntryLines () const - { - return m_hasEntryLines; - } - -private: + void Reverse(); + + bool HasEntryLines () const + { + return m_hasEntryLines; + } + +private: SHAPE_LINE_CHAIN m_entryP, m_entryN; bool m_hasEntryLines; VECTOR2I m_anchorP, m_anchorN; @@ -134,37 +132,36 @@ private: **/ class PNS_DP_PRIMITIVE_PAIR { - public: PNS_DP_PRIMITIVE_PAIR(): - m_primP (NULL), m_primN ( NULL ) {}; + m_primP( NULL ), m_primN( NULL ) {}; - PNS_DP_PRIMITIVE_PAIR ( const PNS_DP_PRIMITIVE_PAIR& aOther ); - PNS_DP_PRIMITIVE_PAIR ( PNS_ITEM *aPrimP, PNS_ITEM *aPrimN ); - PNS_DP_PRIMITIVE_PAIR ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); + PNS_DP_PRIMITIVE_PAIR( const PNS_DP_PRIMITIVE_PAIR& aOther ); + PNS_DP_PRIMITIVE_PAIR( PNS_ITEM* aPrimP, PNS_ITEM* aPrimN ); + PNS_DP_PRIMITIVE_PAIR( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); ~PNS_DP_PRIMITIVE_PAIR(); - void SetAnchors ( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); + void SetAnchors( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); - const VECTOR2I& AnchorP () const { return m_anchorP; } - const VECTOR2I& AnchorN () const { return m_anchorN; } + const VECTOR2I& AnchorP() const { return m_anchorP; } + const VECTOR2I& AnchorN() const { return m_anchorN; } - PNS_DP_PRIMITIVE_PAIR& operator= ( const PNS_DP_PRIMITIVE_PAIR& aOther ); + PNS_DP_PRIMITIVE_PAIR& operator=( const PNS_DP_PRIMITIVE_PAIR& aOther ); - PNS_ITEM* PrimP () const { return m_primP; } - PNS_ITEM* PrimN () const { return m_primN; } + PNS_ITEM* PrimP() const { return m_primP; } + PNS_ITEM* PrimN() const { return m_primN; } bool Directional() const; - DIRECTION_45 DirP () const; - DIRECTION_45 DirN () const; + DIRECTION_45 DirP() const; + DIRECTION_45 DirN() const; private: + DIRECTION_45 anchorDirection( PNS_ITEM* aItem, const VECTOR2I& aP ) const; - DIRECTION_45 anchorDirection ( PNS_ITEM *aItem, const VECTOR2I& aP) const; - - PNS_ITEM *m_primP, *m_primN; + PNS_ITEM* m_primP; + PNS_ITEM* m_primN; VECTOR2I m_anchorP, m_anchorN; }; @@ -174,21 +171,21 @@ private: * A set of gateways calculated for the cursor or starting/ending primitive pair. **/ -class PNS_DP_GATEWAYS +class PNS_DP_GATEWAYS { public: PNS_DP_GATEWAYS ( int aGap ): m_gap(aGap), m_viaGap( aGap ) {}; - void SetGap ( int aGap ) { - m_gap = aGap; + void SetGap ( int aGap ) { + m_gap = aGap; m_viaGap = aGap; } - - void Clear() - { - m_gateways.clear(); + + void Clear() + { + m_gateways.clear(); } void SetFitVias ( bool aEnable, int aDiameter = 0, int aViaGap = -1 ) @@ -201,12 +198,12 @@ class PNS_DP_GATEWAYS m_viaGap = aViaGap; } - + void BuildForCursor ( const VECTOR2I& aCursorPos ); void BuildOrthoProjections ( PNS_DP_GATEWAYS &aEntries, const VECTOR2I& aCursorPos, int aOrthoScore ); void BuildGeneric ( const VECTOR2I& p0_p, const VECTOR2I& p0_n, bool aBuildEntries = false, bool aViaMode = false ); void BuildFromPrimitivePair( PNS_DP_PRIMITIVE_PAIR aPair, bool aPreferDiagonal ); - + bool FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ); std::vector& Gateways() @@ -216,7 +213,7 @@ class PNS_DP_GATEWAYS private: - struct DP_CANDIDATE + struct DP_CANDIDATE { SHAPE_LINE_CHAIN p, n; VECTOR2I gw_p, gw_n; @@ -246,7 +243,7 @@ class PNS_DIFF_PAIR : public PNS_ITEM { public: struct COUPLED_SEGMENTS { - COUPLED_SEGMENTS ( const SEG& aCoupledP, const SEG& aParentP, int aIndexP, + COUPLED_SEGMENTS ( const SEG& aCoupledP, const SEG& aParentP, int aIndexP, const SEG& aCoupledN, const SEG& aParentN, int aIndexN ) : coupledP ( aCoupledP ), coupledN ( aCoupledN ), @@ -255,7 +252,7 @@ public: indexP ( aIndexP ), indexN ( aIndexN ) {} - + SEG coupledP; SEG coupledN; SEG parentP; @@ -266,17 +263,17 @@ public: typedef std::vector COUPLED_SEGMENTS_VEC; - PNS_DIFF_PAIR ( ) : PNS_ITEM ( DIFF_PAIR ), m_hasVias (false) {} + PNS_DIFF_PAIR ( ) : PNS_ITEM ( DIFF_PAIR ), m_hasVias (false) {} - PNS_DIFF_PAIR ( int aGap ) : - PNS_ITEM ( DIFF_PAIR ), + PNS_DIFF_PAIR ( int aGap ) : + PNS_ITEM ( DIFF_PAIR ), m_hasVias (false) { m_gapConstraint = aGap; } PNS_DIFF_PAIR ( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, int aGap = 0 ): - PNS_ITEM ( DIFF_PAIR ), + PNS_ITEM ( DIFF_PAIR ), m_n (aN), m_p (aP), m_hasVias (false) @@ -285,7 +282,7 @@ public: } PNS_DIFF_PAIR ( const PNS_LINE &aLineP, const PNS_LINE &aLineN, int aGap = 0 ): - PNS_ITEM ( DIFF_PAIR ), + PNS_ITEM ( DIFF_PAIR ), m_line_p ( aLineP ), m_line_n ( aLineN ), m_hasVias (false) @@ -301,8 +298,8 @@ public: { return aItem && DIFF_PAIR == aItem->Kind(); } - - PNS_DIFF_PAIR * Clone() const { assert(false); return NULL; } + + PNS_DIFF_PAIR * Clone() const { assert(false); return NULL; } static PNS_DIFF_PAIR* AssembleDp ( PNS_LINE *aLine ); @@ -317,7 +314,7 @@ public: m_n = aN; } } - + void SetShape ( const PNS_DIFF_PAIR& aPair ) { m_p = aPair.m_p; @@ -326,20 +323,20 @@ public: void SetNets ( int aP, int aN ) { - m_net_p = aP; - m_net_n = aN; + m_net_p = aP; + m_net_n = aN; } - + void SetWidth ( int aWidth ) { - m_width = aWidth; + m_width = aWidth; } int Width() const { return m_width; } - + void SetGap ( int aGap) { - m_gap = aGap; + m_gap = aGap; m_gapConstraint = RANGED_NUM ( m_gap, 10000, 10000 ); } @@ -364,24 +361,24 @@ public: return m_hasVias; } - int NetP() const + int NetP() const { return m_net_p; } - int NetN() const + int NetN() const { return m_net_n; } - PNS_LINE& PLine() + PNS_LINE& PLine() { if ( !m_line_p.IsLinked ( ) ) updateLine(m_line_p, m_p, m_net_p, m_via_p ); return m_line_p; - } + } - PNS_LINE& NLine() + PNS_LINE& NLine() { if ( !m_line_n.IsLinked ( ) ) updateLine(m_line_n, m_n, m_net_n, m_via_n ); @@ -415,7 +412,7 @@ public: } const SHAPE_LINE_CHAIN& CP() const { return m_p; } const SHAPE_LINE_CHAIN& CN() const { return m_n; } - + bool BuildInitial ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY& aTarget, bool aPrefDiagonal ); bool CheckConnectionAngle ( const PNS_DIFF_PAIR &aOther, int allowedAngles ) const; int CoupledLength ( const SEG& aP, const SEG& aN ) const; @@ -428,7 +425,7 @@ public: private: - void updateLine( PNS_LINE &aLine, const SHAPE_LINE_CHAIN& aShape, int aNet, PNS_VIA& aVia ) + void updateLine( PNS_LINE &aLine, const SHAPE_LINE_CHAIN& aShape, int aNet, PNS_VIA& aVia ) { aLine.SetShape( aShape ); aLine.SetWidth( m_width ); diff --git a/pcbnew/router/pns_diff_pair_placer.cpp b/pcbnew/router/pns_diff_pair_placer.cpp index ff1d7f3f49..d3c44a1472 100644 --- a/pcbnew/router/pns_diff_pair_placer.cpp +++ b/pcbnew/router/pns_diff_pair_placer.cpp @@ -57,74 +57,82 @@ PNS_DIFF_PAIR_PLACER::~PNS_DIFF_PAIR_PLACER() } -void PNS_DIFF_PAIR_PLACER::setWorld ( PNS_NODE* aWorld ) +void PNS_DIFF_PAIR_PLACER::setWorld( PNS_NODE* aWorld ) { m_world = aWorld; } -const PNS_VIA PNS_DIFF_PAIR_PLACER::makeVia ( const VECTOR2I& aP, int aNet ) + +const PNS_VIA PNS_DIFF_PAIR_PLACER::makeVia( const VECTOR2I& aP, int aNet ) { const PNS_LAYERSET layers( m_sizes.GetLayerTop(), m_sizes.GetLayerBottom() ); PNS_VIA v( aP, layers, m_sizes.ViaDiameter(), m_sizes.ViaDrill(), -1, m_sizes.ViaType() ); - v.SetNet (aNet); + v.SetNet( aNet ); + return v; } + void PNS_DIFF_PAIR_PLACER::SetOrthoMode ( bool aOrthoMode ) { m_orthoMode = aOrthoMode; - if(!m_idle) - Move ( m_currentEnd, NULL ); + + if( !m_idle ) + Move( m_currentEnd, NULL ); } + bool PNS_DIFF_PAIR_PLACER::ToggleVia( bool aEnabled ) { m_placingVia = aEnabled; - if(!m_idle) - Move ( m_currentEnd, NULL ); + + if( !m_idle ) + Move( m_currentEnd, NULL ); return true; } + bool PNS_DIFF_PAIR_PLACER::rhMarkObstacles( const VECTOR2I& aP ) { - if( !routeHead ( aP ) ) + if( !routeHead( aP ) ) return false; bool collP = m_currentNode->CheckColliding( &m_currentTrace.PLine() ); bool collN = m_currentNode->CheckColliding( &m_currentTrace.NLine() ); - - m_fitOk = !(collP || collN); + + m_fitOk = !( collP || collN ) ; return m_fitOk; } + bool PNS_DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP ) { - PNS_VIA virtHead = makeVia ( aP, -1 ); + PNS_VIA virtHead = makeVia( aP, -1 ); - if ( m_placingVia ) - virtHead.SetDiameter ( viaGap() + 2 * virtHead.Diameter() ); - else + if( m_placingVia ) + virtHead.SetDiameter( viaGap() + 2 * virtHead.Diameter() ); + else { - virtHead.SetLayer ( m_currentLayer ); - virtHead.SetDiameter ( m_sizes.DiffPairGap() + 2 * m_sizes.TrackWidth() ); + virtHead.SetLayer( m_currentLayer ); + virtHead.SetDiameter( m_sizes.DiffPairGap() + 2 * m_sizes.TrackWidth() ); } - VECTOR2I lead(0, 0);// = aP - m_currentStart ; + VECTOR2I lead( 0, 0 );// = aP - m_currentStart ; VECTOR2I force; - bool solidsOnly = true; - + bool solidsOnly = true; - if(m_currentMode == RM_MarkObstacles ) + if( m_currentMode == RM_MarkObstacles ) { aNewP = aP; - return true; - } else if (m_currentMode == RM_Walkaround ) + return true; + } + else if( m_currentMode == RM_Walkaround ) { solidsOnly = false; } - + // fixme: I'm too lazy to do it well. Circular approximaton will do for the moment. if( virtHead.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) ) { @@ -134,98 +142,96 @@ bool PNS_DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& return false; } - -bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE *aNode, PNS_DIFF_PAIR *aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ) + +bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ) { PNS_WALKAROUND walkaround( aNode, Router() ); PNS_WALKAROUND::WALKAROUND_STATUS wf1; - Router()->GetClearanceFunc()->OverrideClearance ( true, aCurrent->NetP(), aCurrent->NetN(), aCurrent->Gap() - 20 ); + Router()->GetClearanceFunc()->OverrideClearance( true, aCurrent->NetP(), aCurrent->NetN(), aCurrent->Gap() - 20 ); walkaround.SetSolidsOnly( aSolidsOnly ); walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); - PNS_SHOVE shove(aNode, Router()); + PNS_SHOVE shove( aNode, Router() ); PNS_LINE walkP, walkN; - + aWalk = *aCurrent; - + int iter = 0; - - PNS_DIFF_PAIR cur (*aCurrent); + + PNS_DIFF_PAIR cur( *aCurrent ); bool currentIsP = aPFirst; int mask = aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY; - + //Router()->DisplayDebugLine( aCurrent->CP(), 4, 10000 ); //Router()->DisplayDebugLine( aCurrent->CN(), 5, 10000 ); - do { - PNS_LINE preWalk = (currentIsP ? cur.PLine() : cur.NLine() ); - PNS_LINE preShove = (currentIsP ? cur.NLine() : cur.PLine() ); + do + { + PNS_LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() ); + PNS_LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() ); PNS_LINE postWalk; - if (!aNode->CheckColliding ( &preWalk, mask ) ) - { - + if( !aNode->CheckColliding ( &preWalk, mask ) ) + { currentIsP = !currentIsP; - - if (!aNode->CheckColliding ( &preShove, mask ) ) + + if( !aNode->CheckColliding( &preShove, mask ) ) break; else continue; } - + wf1 = walkaround.Route( preWalk, postWalk, false ); - if(wf1 != PNS_WALKAROUND::DONE) + if( wf1 != PNS_WALKAROUND::DONE ) return false; - PNS_LINE postShove ( preShove ); + PNS_LINE postShove( preShove ); + + shove.ForceClearance( true, cur.Gap() - 12 ); - shove.ForceClearance(true, cur.Gap() - 12); - PNS_SHOVE::SHOVE_STATUS sh1; - + sh1 = shove.ProcessSingleLine( &postWalk, &preShove, &postShove ); - if(sh1 != PNS_SHOVE::SH_OK) + if( sh1 != PNS_SHOVE::SH_OK ) return false; postWalk.Line().Simplify(); postShove.Line().Simplify(); + cur.SetShape( postWalk.CLine(), postShove.CLine(), !currentIsP ); - cur.SetShape ( postWalk.CLine(), postShove.CLine(), !currentIsP ); - currentIsP = !currentIsP; - - if (!aNode->CheckColliding ( &postShove, mask ) ) + + if( !aNode->CheckColliding( &postShove, mask ) ) break; - iter++; - } while (iter < 3); + } + while( iter < 3 ); - if(iter == 3) + if( iter == 3 ) return false; - - - aWalk.SetShape(cur.CP(), cur.CN() ); - Router()->GetClearanceFunc()->OverrideClearance ( false ); + aWalk.SetShape( cur.CP(), cur.CN() ); + Router()->GetClearanceFunc()->OverrideClearance( false ); return true; } -bool PNS_DIFF_PAIR_PLACER::tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bool aSolidsOnly ) + +bool PNS_DIFF_PAIR_PLACER::tryWalkDp( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bool aSolidsOnly ) { PNS_DIFF_PAIR best; double bestScore = 100000000000000.0; - for(int attempt = 0; attempt <= 1; attempt ++) + for( int attempt = 0; attempt <= 1; attempt++ ) { PNS_DIFF_PAIR p; PNS_NODE *tmp = m_currentNode->Branch(); @@ -233,7 +239,7 @@ bool PNS_DIFF_PAIR_PLACER::tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bo bool pfirst = attempt % 2 ? true : false; bool wind_cw = attempt / 2 ? true : false; - if ( attemptWalk ( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) ) + if( attemptWalk ( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) ) { // double len = p.TotalLength(); double cl = p.CoupledLength(); @@ -241,41 +247,42 @@ bool PNS_DIFF_PAIR_PLACER::tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bo double score = cl + fabs(skew) * 3.0; - if(score < bestScore) + if( score < bestScore ) { bestScore = score; best = p; } } - + delete tmp; } - - if(bestScore > 0.0) + + if( bestScore > 0.0 ) { PNS_OPTIMIZER optimizer( m_currentNode ); - aPair.SetShape ( best ); + aPair.SetShape( best ); + optimizer.Optimize( &aPair ); - optimizer.Optimize ( &aPair ); return true; } - + return false; } + bool PNS_DIFF_PAIR_PLACER::rhWalkOnly( const VECTOR2I& aP ) { - if ( !routeHead ( aP ) ) + if( !routeHead ( aP ) ) return false; - m_fitOk = tryWalkDp ( m_currentNode, m_currentTrace, false ); + m_fitOk = tryWalkDp( m_currentNode, m_currentTrace, false ); return m_fitOk; } -bool PNS_DIFF_PAIR_PLACER::route ( const VECTOR2I& aP ) +bool PNS_DIFF_PAIR_PLACER::route( const VECTOR2I& aP ) { switch( m_currentMode ) { @@ -292,7 +299,8 @@ bool PNS_DIFF_PAIR_PLACER::route ( const VECTOR2I& aP ) return false; } -bool PNS_DIFF_PAIR_PLACER::rhShoveOnly ( const VECTOR2I& aP ) + +bool PNS_DIFF_PAIR_PLACER::rhShoveOnly( const VECTOR2I& aP ) { m_currentNode = m_shove->CurrentNode(); @@ -300,18 +308,18 @@ bool PNS_DIFF_PAIR_PLACER::rhShoveOnly ( const VECTOR2I& aP ) m_fitOk = false; - if(!ok) + if( !ok ) return false; - if (!tryWalkDp ( m_currentNode, m_currentTrace, true ) ) + if( !tryWalkDp( m_currentNode, m_currentTrace, true ) ) return false; - - PNS_LINE pLine ( m_currentTrace.PLine() ); - PNS_LINE nLine ( m_currentTrace.NLine() ); + + PNS_LINE pLine( m_currentTrace.PLine() ); + PNS_LINE nLine( m_currentTrace.NLine() ); PNS_ITEMSET head; - head.Add ( &pLine ); - head.Add ( &nLine ); + head.Add( &pLine ); + head.Add( &nLine ); PNS_SHOVE::SHOVE_STATUS status = m_shove->ShoveMultiLines( head ); @@ -320,9 +328,9 @@ bool PNS_DIFF_PAIR_PLACER::rhShoveOnly ( const VECTOR2I& aP ) if( status == PNS_SHOVE::SH_OK ) { m_currentNode = m_shove->CurrentNode(); - - if( !m_currentNode->CheckColliding ( &m_currentTrace.PLine() ) && - !m_currentNode->CheckColliding ( &m_currentTrace.NLine() ) ) + + if( !m_currentNode->CheckColliding( &m_currentTrace.PLine() ) && + !m_currentNode->CheckColliding( &m_currentTrace.NLine() ) ) { m_fitOk = true; } @@ -332,14 +340,13 @@ bool PNS_DIFF_PAIR_PLACER::rhShoveOnly ( const VECTOR2I& aP ) } - const PNS_ITEMSET PNS_DIFF_PAIR_PLACER::Traces() { PNS_ITEMSET t; - t.Add( const_cast ( &m_currentTrace.PLine( ) ) ); - t.Add( const_cast ( &m_currentTrace.NLine( ) ) ); - + t.Add( const_cast( &m_currentTrace.PLine() ) ); + t.Add( const_cast( &m_currentTrace.NLine() ) ); + return t; } @@ -348,8 +355,8 @@ void PNS_DIFF_PAIR_PLACER::FlipPosture() { m_startDiagonal = !m_startDiagonal; - if(!m_idle) - Move ( m_currentEnd, NULL ); + if( !m_idle ) + Move( m_currentEnd, NULL ); } @@ -368,88 +375,97 @@ bool PNS_DIFF_PAIR_PLACER::SetLayer( int aLayer ) { m_currentLayer = aLayer; return true; - } else if( m_chainedPlacement ) + } else if( m_chainedPlacement ) return false; - else if( !m_prevPair ) + else if( !m_prevPair ) return false; - else if( m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( PNS_ITEM::VIA ) && m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) ) { + else if( m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( PNS_ITEM::VIA ) && + m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) ) + { m_currentLayer = aLayer; m_start = *m_prevPair; - initPlacement ( false ); - Move ( m_currentEnd, NULL ); + initPlacement( false ); + Move( m_currentEnd, NULL ); return true; } return false; } -int PNS_DIFF_PAIR_PLACER::matchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) + +int PNS_DIFF_PAIR_PLACER::matchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) { int rv = 0; - if (aNetName.EndsWith("+")) + + if( aNetName.EndsWith( "+" ) ) { aComplementNet = "-"; rv = 1; - } else if (aNetName.EndsWith("_P")) + } + else if( aNetName.EndsWith( "_P" ) ) { aComplementNet = "_N"; rv = 1; - } else if (aNetName.EndsWith("-")) + } + else if( aNetName.EndsWith( "-" ) ) { aComplementNet = "+"; rv = -1; - } else if (aNetName.EndsWith("_N")) + } + else if( aNetName.EndsWith( "_N" ) ) { aComplementNet = "_P"; rv = -1; } - if (rv != 0) { - aBaseDpName = aNetName.Left ( aNetName.Length() - aComplementNet.Length() ); + if( rv != 0 ) + { + aBaseDpName = aNetName.Left( aNetName.Length() - aComplementNet.Length() ); } return rv; } -OPT_VECTOR2I PNS_DIFF_PAIR_PLACER::getDanglingAnchor ( PNS_NODE *aNode, PNS_ITEM *aItem ) + +OPT_VECTOR2I PNS_DIFF_PAIR_PLACER::getDanglingAnchor( PNS_NODE* aNode, PNS_ITEM* aItem ) { - switch(aItem->Kind()) + switch( aItem->Kind() ) { case PNS_ITEM::VIA: case PNS_ITEM::SOLID: - return aItem->Anchor(0); + return aItem->Anchor( 0 ); case PNS_ITEM::SEGMENT: { - PNS_SEGMENT *s =static_cast ( aItem ); + PNS_SEGMENT* s =static_cast( aItem ); - PNS_JOINT *jA = aNode->FindJoint( s->Seg().A, s ); - PNS_JOINT *jB = aNode->FindJoint( s->Seg().B, s ); + PNS_JOINT* jA = aNode->FindJoint( s->Seg().A, s ); + PNS_JOINT* jB = aNode->FindJoint( s->Seg().B, s ); - if(jA->LinkCount() == 1) + if( jA->LinkCount() == 1 ) return s->Seg().A; - else if (jB->LinkCount() == 1) + else if( jB->LinkCount() == 1 ) return s->Seg().B; - else + else return OPT_VECTOR2I(); } + default: return OPT_VECTOR2I(); break; } } -bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair ( const VECTOR2I& aP, PNS_ITEM *aItem, PNS_DP_PRIMITIVE_PAIR& aPair ) -{ - - if(!aItem || !aItem->Parent() || !aItem->Parent()->GetNet() ) + +bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, PNS_ITEM* aItem, PNS_DP_PRIMITIVE_PAIR& aPair ) +{ + if( !aItem || !aItem->Parent() || !aItem->Parent()->GetNet() ) return false; wxString netNameP = aItem->Parent()->GetNet()->GetNetname(); wxString netNameN, netNameBase; - - BOARD *brd = Router()->GetBoard(); + BOARD* brd = Router()->GetBoard(); PNS_ITEM *primRef = NULL, *primP = NULL, *primN = NULL; // printf("Current %p\n", m_currentNode); @@ -459,61 +475,65 @@ bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair ( const VECTOR2I& aP, PNS_ITEM *a int r = matchDpSuffix ( netNameP, suffix, netNameBase ); - if(r == 0) + if( r == 0 ) return false; - else if(r == 1) + else if( r == 1 ) { - primRef = primP = static_cast (aItem); + primRef = primP = static_cast( aItem ); netNameN = netNameBase + suffix; - } else { - primRef = primN = static_cast (aItem); + } + else + { + primRef = primN = static_cast( aItem ); netNameN = netNameP; netNameP = netNameBase + suffix; } - int netP = brd->FindNet ( netNameP )->GetNet(); - int netN = brd->FindNet ( netNameN )->GetNet(); - - if ( primP ) + int netP = brd->FindNet( netNameP )->GetNet(); + int netN = brd->FindNet( netNameN )->GetNet(); + + if( primP ) refNet = netN; else refNet = netP; - + // printf("Net: P: %s N: %s\n", (const char *)(netNameP.c_str()), (const char *)(netNameN.c_str())); std::set items; - OPT_VECTOR2I refAnchor = getDanglingAnchor ( m_currentNode, primRef ); + OPT_VECTOR2I refAnchor = getDanglingAnchor( m_currentNode, primRef ); - if(!refAnchor) + if( !refAnchor ) return false; - + m_currentNode->AllItemsInNet( refNet, items ); double bestDist = std::numeric_limits::max(); bool found = false; - BOOST_FOREACH (PNS_ITEM *item, items) + BOOST_FOREACH(PNS_ITEM* item, items ) { - if ( item->Kind() == aItem->Kind() ) + if( item->Kind() == aItem->Kind() ) { - OPT_VECTOR2I anchor = getDanglingAnchor ( m_currentNode, item ); - if(!anchor) + OPT_VECTOR2I anchor = getDanglingAnchor( m_currentNode, item ); + if( !anchor ) continue; - double dist = (*anchor - *refAnchor).EuclideanNorm(); - - if (dist < bestDist) + double dist = ( *anchor - *refAnchor ).EuclideanNorm(); + + if( dist < bestDist ) { found = true; bestDist = dist; - - if (refNet == netP) + + if( refNet == netP ) { aPair = PNS_DP_PRIMITIVE_PAIR ( item, primRef ); - aPair.SetAnchors ( *anchor, *refAnchor ); - } else { - aPair = PNS_DP_PRIMITIVE_PAIR ( primRef, item ); - aPair.SetAnchors ( *refAnchor, *anchor ); + aPair.SetAnchors( *anchor, *refAnchor ); + } + else + { + aPair = PNS_DP_PRIMITIVE_PAIR( primRef, item ); + aPair.SetAnchors( *refAnchor, *anchor ); } } } @@ -528,11 +548,13 @@ int PNS_DIFF_PAIR_PLACER::viaGap() const return m_sizes.DiffPairViaGap(); } + int PNS_DIFF_PAIR_PLACER::gap() const { return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth(); } + bool PNS_DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p( aP ); @@ -542,7 +564,7 @@ bool PNS_DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) if( Router()->SnappingEnabled() ) p = Router()->SnapToItem( aStartItem, aP, split ); - if(!aStartItem) + if( !aStartItem ) { Router()->SetFailureReason( _( "Can't start a differential pair " " in the middle of nowhere." ) ); @@ -553,7 +575,7 @@ bool PNS_DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) m_currentNode = Router()->GetWorld(); - if (!findDpPrimitivePair(aP, aStartItem, m_start ) ) + if( !findDpPrimitivePair( aP, aStartItem, m_start ) ) { Router()->SetFailureReason( _( "Unable to find complementary differential pair " "net. Make sure the names of the nets belonging " @@ -573,6 +595,7 @@ bool PNS_DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) return true; } + void PNS_DIFF_PAIR_PLACER::initPlacement( bool aSplitSeg ) { m_idle = false; @@ -598,7 +621,7 @@ void PNS_DIFF_PAIR_PLACER::initPlacement( bool aSplitSeg ) delete m_shove; m_shove = NULL; - + if( m_currentMode == RM_Shove || m_currentMode == RM_Smart ) { m_shove = new PNS_SHOVE( m_currentNode, Router() ); @@ -609,57 +632,56 @@ bool PNS_DIFF_PAIR_PLACER::routeHead( const VECTOR2I& aP ) { m_fitOk = false; - PNS_DP_GATEWAYS gwsEntry ( gap() ); - PNS_DP_GATEWAYS gwsTarget ( gap() ); + PNS_DP_GATEWAYS gwsEntry( gap() ); + PNS_DP_GATEWAYS gwsTarget( gap() ); - - if(!m_prevPair) + if( !m_prevPair ) m_prevPair = m_start; - gwsEntry.BuildFromPrimitivePair ( *m_prevPair, m_startDiagonal ); + gwsEntry.BuildFromPrimitivePair( *m_prevPair, m_startDiagonal ); PNS_DP_PRIMITIVE_PAIR target; - - if (findDpPrimitivePair ( aP, m_currentEndItem, target )) + + if( findDpPrimitivePair ( aP, m_currentEndItem, target ) ) { gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal ); m_snapOnTarget = true; } else { VECTOR2I fp; - if( !propagateDpHeadForces ( aP, fp ) ) + if( !propagateDpHeadForces( aP, fp ) ) return false; - gwsTarget.SetFitVias ( m_placingVia, m_sizes.ViaDiameter(), viaGap() ); - gwsTarget.BuildForCursor ( fp ); - gwsTarget.BuildOrthoProjections ( gwsEntry, fp, m_orthoMode ? 200 : -200 ); + gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() ); + gwsTarget.BuildForCursor( fp ); + gwsTarget.BuildOrthoProjections( gwsEntry, fp, m_orthoMode ? 200 : -200 ); m_snapOnTarget = false; } m_currentTrace = PNS_DIFF_PAIR(); - m_currentTrace.SetGap ( gap() ); + m_currentTrace.SetGap( gap() ); m_currentTrace.SetLayer( m_currentLayer ); - - if ( gwsEntry.FitGateways(gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace ) ) + if ( gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace ) ) { - m_currentTrace.SetNets ( m_netP, m_netN ); - m_currentTrace.SetWidth ( m_sizes.DiffPairWidth() ); - m_currentTrace.SetGap ( m_sizes.DiffPairGap() ); - - if(m_placingVia) + m_currentTrace.SetNets( m_netP, m_netN ); + m_currentTrace.SetWidth( m_sizes.DiffPairWidth() ); + m_currentTrace.SetGap( m_sizes.DiffPairGap() ); + + if( m_placingVia ) { - m_currentTrace.AppendVias ( makeVia ( m_currentTrace.CP().CPoint(-1), m_netP ), + m_currentTrace.AppendVias ( makeVia ( m_currentTrace.CP().CPoint(-1), m_netP ), makeVia ( m_currentTrace.CN().CPoint(-1), m_netN ) ); } + return true; } return false; - } -bool PNS_DIFF_PAIR_PLACER::Move(const VECTOR2I& aP , PNS_ITEM* aEndItem ) + +bool PNS_DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , PNS_ITEM* aEndItem ) { m_currentEndItem = aEndItem; m_fitOk = false; @@ -667,13 +689,13 @@ bool PNS_DIFF_PAIR_PLACER::Move(const VECTOR2I& aP , PNS_ITEM* aEndItem ) delete m_lastNode; m_lastNode = NULL; - if ( !route( aP ) ) + if( !route( aP ) ) return false; PNS_NODE* latestNode = m_currentNode; m_lastNode = latestNode->Branch(); - assert (m_lastNode != NULL); + assert( m_lastNode != NULL ); m_currentEnd = aP; updateLeadingRatLine(); @@ -681,42 +703,45 @@ bool PNS_DIFF_PAIR_PLACER::Move(const VECTOR2I& aP , PNS_ITEM* aEndItem ) return true; } + void PNS_DIFF_PAIR_PLACER::UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ) { m_sizes = aSizes; + if( !m_idle ) { - initPlacement ( ); - Move ( m_currentEnd, NULL ); + initPlacement(); + Move( m_currentEnd, NULL ); } } + bool PNS_DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - if (!m_fitOk) + if( !m_fitOk ) return false; - if (m_currentTrace.CP().SegmentCount() < 1 || - m_currentTrace.CN().SegmentCount() < 1 ) + if( m_currentTrace.CP().SegmentCount() < 1 || + m_currentTrace.CN().SegmentCount() < 1 ) return false; - if( m_currentTrace.CP().SegmentCount() > 1) - m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment(-2) ).IsDiagonal(); - - PNS_TOPOLOGY topo ( m_lastNode ); - - if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() ) + if( m_currentTrace.CP().SegmentCount() > 1 ) + m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal(); + + PNS_TOPOLOGY topo( m_lastNode ); + + if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() ) { SHAPE_LINE_CHAIN newP ( m_currentTrace.CP() ); SHAPE_LINE_CHAIN newN ( m_currentTrace.CN() ); - - if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1) + + if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 ) { - newP.Remove(-1, -1); - newN.Remove(-1, -1); + newP.Remove( -1, -1 ); + newN.Remove( -1, -1 ); } - m_currentTrace.SetShape ( newP, newN ); + m_currentTrace.SetShape( newP, newN ); } if( m_currentTrace.EndsWithVias() ) @@ -727,11 +752,11 @@ bool PNS_DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) } else m_chainedPlacement = !m_snapOnTarget; - PNS_LINE lineP ( m_currentTrace.PLine() ); - PNS_LINE lineN ( m_currentTrace.NLine() ); - - m_lastNode->Add ( &lineP ); - m_lastNode->Add ( &lineN ); + PNS_LINE lineP( m_currentTrace.PLine() ); + PNS_LINE lineN( m_currentTrace.NLine() ); + + m_lastNode->Add( &lineP ); + m_lastNode->Add( &lineN ); topo.SimplifyLine( &lineP ); topo.SimplifyLine( &lineN ); @@ -742,12 +767,14 @@ bool PNS_DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) m_lastNode = NULL; m_placingVia = false; - - if(m_snapOnTarget) + + if( m_snapOnTarget ) { m_idle = true; - return true; - } else { + return true; + } + else + { initPlacement(); return false; } @@ -760,19 +787,19 @@ void PNS_DIFF_PAIR_PLACER::GetModifiedNets( std::vector &aNets ) const aNets.push_back( m_netN ); } + void PNS_DIFF_PAIR_PLACER::updateLeadingRatLine() { SHAPE_LINE_CHAIN ratLineN, ratLineP; - PNS_TOPOLOGY topo ( m_lastNode ); + PNS_TOPOLOGY topo( m_lastNode ); - if( topo.LeadingRatLine ( &m_currentTrace.PLine(), ratLineP )) + if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) ) { Router()->DisplayDebugLine( ratLineP, 1, 10000 ); - } + } - if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN )) + if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) ) { Router()->DisplayDebugLine( ratLineN, 3, 10000 ); - } - + } } diff --git a/pcbnew/router/pns_diff_pair_placer.h b/pcbnew/router/pns_diff_pair_placer.h index 87b8001484..19a43ccb6a 100644 --- a/pcbnew/router/pns_diff_pair_placer.h +++ b/pcbnew/router/pns_diff_pair_placer.h @@ -161,11 +161,11 @@ public: bool IsPlacingVia() const { return m_placingVia; } - void SetOrthoMode ( bool aOrthoMode ); + void SetOrthoMode( bool aOrthoMode ); + + void GetModifiedNets( std::vector& aNets ) const; - void GetModifiedNets( std::vector &aNets ) const; private: - int viaGap() const; int gap() const; @@ -212,10 +212,10 @@ private: */ void setInitialDirection( const DIRECTION_45& aDirection ); - + bool routeHead( const VECTOR2I& aP ); - bool tryWalkDp ( PNS_NODE* aNode, PNS_DIFF_PAIR &aPair, bool aSolidsOnly ); - + bool tryWalkDp( PNS_NODE* aNode, PNS_DIFF_PAIR& aPair, bool aSolidsOnly ); + ///> route step, walkaround mode bool rhWalkOnly( const VECTOR2I& aP ); @@ -227,10 +227,10 @@ private: const PNS_VIA makeVia ( const VECTOR2I& aP, int aNet ); - bool findDpPrimitivePair ( const VECTOR2I& aP, PNS_ITEM *aItem, PNS_DP_PRIMITIVE_PAIR& aPair ); - OPT_VECTOR2I getDanglingAnchor ( PNS_NODE *aNode, PNS_ITEM *aItem ); - int matchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); - bool attemptWalk ( PNS_NODE *aNode, PNS_DIFF_PAIR *aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ); + bool findDpPrimitivePair( const VECTOR2I& aP, PNS_ITEM* aItem, PNS_DP_PRIMITIVE_PAIR& aPair ); + OPT_VECTOR2I getDanglingAnchor( PNS_NODE* aNode, PNS_ITEM* aItem ); + int matchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); + bool attemptWalk( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurrent, PNS_DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly ); bool propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP ); enum State { @@ -247,11 +247,10 @@ private: bool m_fitOk; int m_netP, m_netN; - + PNS_DP_PRIMITIVE_PAIR m_start; boost::optional m_prevPair; - ///> current algorithm iteration int m_iteration; @@ -294,9 +293,9 @@ private: VECTOR2I m_currentEnd, m_currentStart; PNS_DIFF_PAIR m_currentTrace; - PNS_ITEM *m_currentEndItem; + PNS_ITEM* m_currentEndItem; PNS_MODE m_currentMode; - + bool m_idle; }; diff --git a/pcbnew/router/pns_dp_meander_placer.cpp b/pcbnew/router/pns_dp_meander_placer.cpp index 8f36dde975..d92821a46c 100644 --- a/pcbnew/router/pns_dp_meander_placer.cpp +++ b/pcbnew/router/pns_dp_meander_placer.cpp @@ -34,13 +34,10 @@ #include "pns_router.h" #include "pns_utils.h" - using boost::optional; - - PNS_DP_MEANDER_PLACER::PNS_DP_MEANDER_PLACER( PNS_ROUTER* aRouter ) : - PNS_MEANDER_PLACER_BASE ( aRouter ) + PNS_MEANDER_PLACER_BASE( aRouter ) { m_world = NULL; m_currentNode = NULL; @@ -49,42 +46,46 @@ PNS_DP_MEANDER_PLACER::PNS_DP_MEANDER_PLACER( PNS_ROUTER* aRouter ) : PNS_DP_MEANDER_PLACER::~PNS_DP_MEANDER_PLACER() { - } + const PNS_LINE PNS_DP_MEANDER_PLACER::Trace() const { return m_currentTraceP; } + PNS_NODE* PNS_DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const { - if(!m_currentNode) + if( !m_currentNode ) return m_world; + return m_currentNode; } + bool PNS_DP_MEANDER_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p; - if(!aStartItem || !aStartItem->OfKind ( PNS_ITEM::SEGMENT )) + + if( !aStartItem || !aStartItem->OfKind( PNS_ITEM::SEGMENT ) ) { - Router()->SetFailureReason( _("Please select a track whose length you want to tune.") ); + Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); return false; } - m_initialSegment = static_cast(aStartItem); + m_initialSegment = static_cast( aStartItem ); p = m_initialSegment->Seg().NearestPoint( aP ); m_currentNode=NULL; - m_currentStart = p; + m_currentStart = p; m_world = Router()->GetWorld()->Branch(); - PNS_TOPOLOGY topo ( m_world ); + PNS_TOPOLOGY topo( m_world ); - if( !topo.AssembleDiffPair ( m_initialSegment, m_originPair ) ) + if( !topo.AssembleDiffPair( m_initialSegment, m_originPair ) ) { Router()->SetFailureReason( _( "Unable to find complementary differential pair " "net for length tuning. Make sure the names of the nets belonging " @@ -92,21 +93,20 @@ bool PNS_DP_MEANDER_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) return false; } - - m_originPair.SetGap ( Router()->Sizes().DiffPairGap() ); + m_originPair.SetGap( Router()->Sizes().DiffPairGap() ); if( !m_originPair.PLine().SegmentCount() || !m_originPair.NLine().SegmentCount() ) return false; - - m_tunedPathP = topo.AssembleTrivialPath ( m_originPair.PLine().GetLink(0) ); - m_tunedPathN = topo.AssembleTrivialPath ( m_originPair.NLine().GetLink(0) ); - m_world->Remove ( m_originPair.PLine() ); - m_world->Remove ( m_originPair.NLine() ); + m_tunedPathP = topo.AssembleTrivialPath( m_originPair.PLine().GetLink( 0 ) ); + m_tunedPathN = topo.AssembleTrivialPath( m_originPair.NLine().GetLink( 0 ) ); + + m_world->Remove( m_originPair.PLine() ); + m_world->Remove( m_originPair.NLine() ); m_currentWidth = m_originPair.Width(); - + return true; } @@ -123,40 +123,42 @@ void PNS_DP_MEANDER_PLACER::release() #endif } -int PNS_DP_MEANDER_PLACER::origPathLength () const + +int PNS_DP_MEANDER_PLACER::origPathLength() const { int totalP = 0; int totalN = 0; - BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathP.CItems() ) + BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathP.CItems() ) { - if ( const PNS_LINE *l = dyn_cast (item) ) - totalP += l->CLine( ).Length( ); - - } - BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathN.CItems() ) - { - if ( const PNS_LINE *l = dyn_cast (item) ) - totalN += l->CLine( ).Length( ); - + if( const PNS_LINE* l = dyn_cast( item ) ) + totalP += l->CLine().Length(); + } - return std::max(totalP, totalN); + BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathN.CItems() ) + { + if( const PNS_LINE* l = dyn_cast( item ) ) + totalN += l->CLine().Length(); + } + + return std::max( totalP, totalN ); } -const SEG PNS_DP_MEANDER_PLACER::baselineSegment ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ) + +const SEG PNS_DP_MEANDER_PLACER::baselineSegment( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ) { const VECTOR2I a( ( aCoupledSegs.coupledP.A + aCoupledSegs.coupledN.A ) / 2 ); const VECTOR2I b( ( aCoupledSegs.coupledP.B + aCoupledSegs.coupledN.B ) / 2 ); - return SEG (a, b); + return SEG( a, b ); } #if 0 PNS_MEANDER_PLACER_BASE::TUNING_STATUS PNS_DP_MEANDER_PLACER::tuneLineLength ( PNS_MEANDERED_LINE& aTuned, int aElongation ) { - int remaining = aElongation; + int remaining = aElongation; bool finished = false; BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) @@ -181,7 +183,7 @@ PNS_MEANDER_PLACER_BASE::TUNING_STATUS PNS_DP_MEANDER_PLACER::tuneLineLength ( P m->SetType ( newType ); m->Recalculate( ); - + finished = true; } else { m->MakeEmpty(); @@ -210,7 +212,7 @@ PNS_MEANDER_PLACER_BASE::TUNING_STATUS PNS_DP_MEANDER_PLACER::tuneLineLength ( P if( meanderCount ) balance = -remaining / meanderCount; - + if (balance >= 0) { BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) @@ -221,50 +223,47 @@ PNS_MEANDER_PLACER_BASE::TUNING_STATUS PNS_DP_MEANDER_PLACER::tuneLineLength ( P m->Resize ( std::max( m->Amplitude() - balance / 2, m_settings.m_minAmplitude ) ); } } - + } return TUNED; } #endif - -bool pairOrientation( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aPair ) +bool pairOrientation( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aPair ) { VECTOR2I midp = ( aPair.coupledP.A + aPair.coupledN.A ) / 2; //DrawDebugPoint (midp, 6); - return aPair.coupledP.Side ( midp ) > 0; + return aPair.coupledP.Side( midp ) > 0; } + bool PNS_DP_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - - - // return false; - if(m_currentNode) + if( m_currentNode ) delete m_currentNode; m_currentNode = m_world->Branch(); - + SHAPE_LINE_CHAIN preP, tunedP, postP; SHAPE_LINE_CHAIN preN, tunedN, postN; - cutTunedLine ( m_originPair.CP(), m_currentStart, aP, preP, tunedP, postP ); - cutTunedLine ( m_originPair.CN(), m_currentStart, aP, preN, tunedN, postN ); - + cutTunedLine( m_originPair.CP(), m_currentStart, aP, preP, tunedP, postP ); + cutTunedLine( m_originPair.CN(), m_currentStart, aP, preN, tunedN, postN ); + PNS_DIFF_PAIR tuned ( m_originPair ); - tuned.SetShape ( tunedP, tunedN ); + tuned.SetShape( tunedP, tunedN ); m_coupledSegments.clear(); - tuned.CoupledSegmentPairs ( m_coupledSegments ); + tuned.CoupledSegmentPairs( m_coupledSegments ); - if (m_coupledSegments.size() == 0) + if( m_coupledSegments.size() == 0 ) return false; //Router()->DisplayDebugLine ( tuned.CP(), 5, 20000 ); @@ -273,74 +272,71 @@ bool PNS_DP_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) //Router()->DisplayDebugLine ( m_originPair.CP(), 5, 20000 ); //Router()->DisplayDebugLine ( m_originPair.CN(), 4, 20000 ); - m_result = PNS_MEANDERED_LINE (this, true ); - m_result.SetWidth ( tuned.Width() ); - - int offset = ( tuned.Gap() + tuned.Width() ) / 2; + m_result = PNS_MEANDERED_LINE( this, true ); + m_result.SetWidth( tuned.Width() ); - if ( !pairOrientation ( m_coupledSegments[0] ) ) + int offset = ( tuned.Gap() + tuned.Width() ) / 2; + + if( !pairOrientation( m_coupledSegments[0] ) ) offset *= -1; - - m_result.SetBaselineOffset ( offset ); + m_result.SetBaselineOffset( offset ); - - BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathP.CItems() ) + BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathP.CItems() ) { - if ( const PNS_LINE *l = dyn_cast (item) ) - Router()->DisplayDebugLine ( l->CLine(), 5, 10000 ); - - } - - BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPathN.CItems() ) - { - if ( const PNS_LINE *l = dyn_cast (item) ) - Router()->DisplayDebugLine ( l->CLine(), 5, 10000 ); + if( const PNS_LINE* l = dyn_cast( item ) ) + Router()->DisplayDebugLine( l->CLine(), 5, 10000 ); } - - BOOST_FOREACH ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& sp, m_coupledSegments ) + BOOST_FOREACH( const PNS_ITEM* item, m_tunedPathN.CItems() ) { - SEG base = baselineSegment ( sp ); - + if( const PNS_LINE* l = dyn_cast( item ) ) + Router()->DisplayDebugLine( l->CLine(), 5, 10000 ); + } + + BOOST_FOREACH( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& sp, m_coupledSegments ) + { + SEG base = baselineSegment( sp ); + // DrawDebugSeg ( base, 3 ); - - m_result.AddCorner ( sp.parentP.A, sp.parentN.A ); - m_result.MeanderSegment ( base ); - m_result.AddCorner ( sp.parentP.B, sp.parentN.B ); + + m_result.AddCorner( sp.parentP.A, sp.parentN.A ); + m_result.MeanderSegment( base ); + m_result.AddCorner( sp.parentP.B, sp.parentN.B ); } int dpLen = origPathLength(); m_lastStatus = TUNED; - if (dpLen - m_settings.m_targetLength > m_settings.m_lengthTollerance) + if( dpLen - m_settings.m_targetLength > m_settings.m_lengthTolerance ) { m_lastStatus = TOO_LONG; m_lastLength = dpLen; - } else { - - m_lastLength = dpLen - std::max ( tunedP.Length(), tunedN.Length() ); - tuneLineLength(m_result, m_settings.m_targetLength - dpLen ); + } + else + { + m_lastLength = dpLen - std::max( tunedP.Length(), tunedN.Length() ); + tuneLineLength( m_result, m_settings.m_targetLength - dpLen ); } - if (m_lastStatus != TOO_LONG) + if( m_lastStatus != TOO_LONG ) { tunedP.Clear(); tunedN.Clear(); - BOOST_FOREACH ( PNS_MEANDER_SHAPE *m, m_result.Meanders() ) + BOOST_FOREACH( PNS_MEANDER_SHAPE* m, m_result.Meanders() ) { if( m->Type() != MT_EMPTY ) { - tunedP.Append ( m->CLine(0) ); - tunedN.Append ( m->CLine(1) ); - } + tunedP.Append ( m->CLine( 0 ) ); + tunedN.Append ( m->CLine( 1 ) ); + } } - m_lastLength += std::max ( tunedP.Length(), tunedN.Length() ); - - int comp = compareWithTollerance( m_lastLength - m_settings.m_targetLength, 0, m_settings.m_lengthTollerance ); + m_lastLength += std::max( tunedP.Length(), tunedN.Length() ); + + int comp = compareWithTolerance( m_lastLength - m_settings.m_targetLength, 0, m_settings.m_lengthTolerance ); if( comp > 0 ) m_lastStatus = TOO_LONG; @@ -348,16 +344,15 @@ bool PNS_DP_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) m_lastStatus = TOO_SHORT; else m_lastStatus = TUNED; - } - m_finalShapeP.Clear( ); + m_finalShapeP.Clear(); m_finalShapeP.Append( preP ); m_finalShapeP.Append( tunedP ); m_finalShapeP.Append( postP ); m_finalShapeP.Simplify(); - - m_finalShapeN.Clear( ); + + m_finalShapeN.Clear(); m_finalShapeN.Append( preN ); m_finalShapeN.Append( tunedN ); m_finalShapeN.Append( postN ); @@ -369,22 +364,23 @@ bool PNS_DP_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) bool PNS_DP_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - PNS_LINE lP ( m_originPair.PLine(), m_finalShapeP ); - PNS_LINE lN ( m_originPair.NLine(), m_finalShapeN ); - - m_currentNode->Add ( &lP ); - m_currentNode->Add ( &lN ); + PNS_LINE lP( m_originPair.PLine(), m_finalShapeP ); + PNS_LINE lN( m_originPair.NLine(), m_finalShapeN ); + + m_currentNode->Add( &lP ); + m_currentNode->Add( &lN ); Router()->CommitRouting( m_currentNode ); - + return true; } - -bool PNS_DP_MEANDER_PLACER::CheckFit ( PNS_MEANDER_SHAPE *aShape ) + + +bool PNS_DP_MEANDER_PLACER::CheckFit( PNS_MEANDER_SHAPE* aShape ) { - PNS_LINE l1 ( m_originPair.PLine(), aShape->CLine(0) ); - PNS_LINE l2 ( m_originPair.NLine(), aShape->CLine(1) ); - + PNS_LINE l1( m_originPair.PLine(), aShape->CLine( 0 ) ); + PNS_LINE l2( m_originPair.NLine(), aShape->CLine( 1 ) ); + if( m_currentNode->CheckColliding( &l1 ) ) return false; @@ -397,62 +393,66 @@ bool PNS_DP_MEANDER_PLACER::CheckFit ( PNS_MEANDER_SHAPE *aShape ) return m_result.CheckSelfIntersections( aShape, clearance ); } - + const PNS_ITEMSET PNS_DP_MEANDER_PLACER::Traces() { - - m_currentTraceP = PNS_LINE ( m_originPair.PLine(), m_finalShapeP ); - m_currentTraceN = PNS_LINE ( m_originPair.NLine(), m_finalShapeN ); + m_currentTraceP = PNS_LINE( m_originPair.PLine(), m_finalShapeP ); + m_currentTraceN = PNS_LINE( m_originPair.NLine(), m_finalShapeN ); PNS_ITEMSET traces; - - traces.Add (&m_currentTraceP); - traces.Add (&m_currentTraceN); - + + traces.Add( &m_currentTraceP ); + traces.Add( &m_currentTraceN ); + return traces; } + const VECTOR2I& PNS_DP_MEANDER_PLACER::CurrentEnd() const { return m_currentEnd; } - + + int PNS_DP_MEANDER_PLACER::CurrentNet() const { return m_initialSegment->Net(); } + int PNS_DP_MEANDER_PLACER::CurrentLayer() const { return m_initialSegment->Layers().Start(); } + const wxString PNS_DP_MEANDER_PLACER::TuningInfo() const { wxString status; - switch (m_lastStatus) + switch( m_lastStatus ) { case TOO_LONG: - status = _("Too long: "); + status = _( "Too long: " ); break; case TOO_SHORT: - status = _("Too short: "); + status = _("Too short: " ); break; case TUNED: - status = _("Tuned: "); + status = _( "Tuned: " ); break; default: - return _("?"); + return _( "?" ); } status += LengthDoubleToString( (double) m_lastLength, false ); status += "/"; status += LengthDoubleToString( (double) m_settings.m_targetLength, false ); - + return status; } + PNS_DP_MEANDER_PLACER::TUNING_STATUS PNS_DP_MEANDER_PLACER::TuningStatus() const { return m_lastStatus; diff --git a/pcbnew/router/pns_dp_meander_placer.h b/pcbnew/router/pns_dp_meander_placer.h index 5f2f54f500..029c93ae8e 100644 --- a/pcbnew/router/pns_dp_meander_placer.h +++ b/pcbnew/router/pns_dp_meander_placer.h @@ -48,13 +48,12 @@ class PNS_ROUTER_BASE; class PNS_DP_MEANDER_PLACER : public PNS_MEANDER_PLACER_BASE { public: - PNS_DP_MEANDER_PLACER( PNS_ROUTER* aRouter ); ~PNS_DP_MEANDER_PLACER(); /** * Function Start() - * + * * Starts routing a single track at point aP, taking item aStartItem as anchor * (unless NULL). */ @@ -62,8 +61,8 @@ public: /** * Function Move() - * - * Moves the end of the currently routed trace to the point aP, taking + * + * Moves the end of the currently routed trace to the point aP, taking * aEndItem as anchor (if not NULL). * (unless NULL). */ @@ -71,7 +70,7 @@ public: /** * 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 @@ -79,7 +78,7 @@ public: * if Settings.CanViolateDRC() is on. */ bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ); - + const PNS_LINE Trace() const; /** @@ -88,39 +87,36 @@ public: * Returns the most recent world state. */ PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const; - + const PNS_ITEMSET Traces(); const VECTOR2I& CurrentEnd() const; - + int CurrentNet() const; int CurrentLayer() const; - int totalLength(); const wxString TuningInfo() const; TUNING_STATUS TuningStatus() const; - bool CheckFit ( PNS_MEANDER_SHAPE* aShape ); + bool CheckFit( PNS_MEANDER_SHAPE* aShape ); + - private: friend class PNS_MEANDER_SHAPE; - + void meanderSegment ( const SEG& aBase ); - - // void addMeander ( PNS_MEANDER *aM ); // void addCorner ( const VECTOR2I& aP ); - const SEG baselineSegment ( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ); + const SEG baselineSegment( const PNS_DIFF_PAIR::COUPLED_SEGMENTS& aCoupledSegs ); - void setWorld ( PNS_NODE* aWorld ); + void setWorld( PNS_NODE* aWorld ); void release(); - int origPathLength () const; + int origPathLength() const; ///> pointer to world to search colliding items PNS_NODE* m_world; @@ -139,7 +135,7 @@ private: SHAPE_LINE_CHAIN m_finalShapeP, m_finalShapeN; PNS_MEANDERED_LINE m_result; - PNS_SEGMENT *m_initialSegment; + PNS_SEGMENT* m_initialSegment; int m_lastLength; TUNING_STATUS m_lastStatus; diff --git a/pcbnew/router/pns_dragger.h b/pcbnew/router/pns_dragger.h index 171b8ac79e..ced82083d9 100644 --- a/pcbnew/router/pns_dragger.h +++ b/pcbnew/router/pns_dragger.h @@ -42,7 +42,7 @@ class PNS_ROUTER_BASE; class PNS_DRAGGER : public PNS_ALGO_BASE { public: - PNS_DRAGGER( PNS_ROUTER* aRouter ); + PNS_DRAGGER( PNS_ROUTER* aRouter ); ~PNS_DRAGGER(); /** @@ -54,7 +54,7 @@ public: /** * 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. */ @@ -67,24 +67,24 @@ public: * @return true, if dragging finished with success. */ bool Drag( const VECTOR2I& aP ); - + /** * Function FixRoute() * - * Checks if the result of current dragging operation is correct + * 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() * @@ -94,30 +94,30 @@ public: /// @copydoc PNS_ALGO_BASE::Logger() virtual PNS_LOGGER* Logger(); - + private: - typedef std::pair LinePair; + typedef std::pair LinePair; typedef std::vector LinePairVec; - enum DragMode { - CORNER = 0, - SEGMENT, - VIA - }; + 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 ); + 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; + 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; diff --git a/pcbnew/router/pns_index.h b/pcbnew/router/pns_index.h index 9e1ef37db0..6c895dc8a0 100644 --- a/pcbnew/router/pns_index.h +++ b/pcbnew/router/pns_index.h @@ -160,7 +160,6 @@ PNS_INDEX::PNS_INDEX() memset( m_subIndices, 0, sizeof( m_subIndices ) ); } - PNS_INDEX::ITEM_SHAPE_INDEX* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) { int idx_n = -1; @@ -201,7 +200,6 @@ PNS_INDEX::ITEM_SHAPE_INDEX* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) return m_subIndices[idx_n]; } - void PNS_INDEX::Add( PNS_ITEM* aItem ) { ITEM_SHAPE_INDEX* idx = getSubindex( aItem ); @@ -216,7 +214,6 @@ void PNS_INDEX::Add( PNS_ITEM* aItem ) } } - void PNS_INDEX::Remove( PNS_ITEM* aItem ) { ITEM_SHAPE_INDEX* idx = getSubindex( aItem ); @@ -230,14 +227,12 @@ void PNS_INDEX::Remove( PNS_ITEM* aItem ) m_netMap[net].remove( aItem ); } - void PNS_INDEX::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) { Remove( aOldItem ); Add( aNewItem ); } - template int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { @@ -247,7 +242,6 @@ int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Vi return m_subIndices[index]->Query( aShape, aMinDistance, aVisitor, false ); } - template int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& aVisitor ) { @@ -281,7 +275,6 @@ int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& aVisitor return total; } - template int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { @@ -293,7 +286,6 @@ int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) return total; } - void PNS_INDEX::Clear() { for( int i = 0; i < MaxSubIndices; ++i ) @@ -307,13 +299,11 @@ void PNS_INDEX::Clear() } } - PNS_INDEX::~PNS_INDEX() { Clear(); } - PNS_INDEX::NET_ITEMS_LIST* PNS_INDEX::GetItemsForNet( int aNet ) { if( m_netMap.find( aNet ) == m_netMap.end() ) diff --git a/pcbnew/router/pns_itemset.cpp b/pcbnew/router/pns_itemset.cpp index 9c41b2eb66..a21c645c57 100644 --- a/pcbnew/router/pns_itemset.cpp +++ b/pcbnew/router/pns_itemset.cpp @@ -23,21 +23,23 @@ #include "pns_itemset.h" PNS_ITEMSET::PNS_ITEMSET( PNS_ITEM* aInitialItem ) : - m_owner ( false ) + m_owner( false ) { if( aInitialItem ) m_items.push_back( aInitialItem ); } + PNS_ITEMSET::~PNS_ITEMSET() { - if (m_owner) + if( m_owner ) { - BOOST_FOREACH ( PNS_ITEM *item, m_items ) + BOOST_FOREACH( PNS_ITEM* item, m_items ) delete item; } } + PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd, bool aInvert ) { ITEMS newItems; @@ -74,6 +76,7 @@ PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask, bool aInvert ) return *this; } + PNS_ITEMSET& PNS_ITEMSET::FilterMarker( int aMarker, bool aInvert ) { ITEMS newItems; @@ -105,6 +108,7 @@ PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet, bool aInvert ) return *this; } + PNS_ITEMSET& PNS_ITEMSET::ExcludeItem( const PNS_ITEM* aItem ) { ITEMS newItems; diff --git a/pcbnew/router/pns_itemset.h b/pcbnew/router/pns_itemset.h index 278714db77..3f25f3d35d 100644 --- a/pcbnew/router/pns_itemset.h +++ b/pcbnew/router/pns_itemset.h @@ -41,14 +41,14 @@ public: PNS_ITEMSET( PNS_ITEM* aInitialItem = NULL ); PNS_ITEMSET( const PNS_ITEMSET& aOther ): - m_owner ( false ) + m_owner( false ) { m_items = aOther.m_items; } ~PNS_ITEMSET(); - void MakeOwner ( ) + void MakeOwner() { m_owner = true; } @@ -105,9 +105,9 @@ public: m_items.push_back( aItem ); } - void Prepend ( PNS_ITEM *aItem ) + void Prepend( PNS_ITEM* aItem ) { - m_items.push_front ( aItem ); + m_items.push_front( aItem ); } PNS_ITEM* Get( int index ) const diff --git a/pcbnew/router/pns_joint.h b/pcbnew/router/pns_joint.h index 566ade3bd0..78cb36e4d2 100644 --- a/pcbnew/router/pns_joint.h +++ b/pcbnew/router/pns_joint.h @@ -95,20 +95,20 @@ public: return seg1->Width() == seg2->Width(); } - bool IsNonFanoutVia () const + bool IsNonFanoutVia() const { - if ( m_linkedItems.Size() != 3 ) + if( m_linkedItems.Size() != 3 ) return false; int vias = 0, segs = 0; - for(int i = 0; i < 3; i++) + for( int i = 0; i < 3; i++ ) { vias += m_linkedItems[i]->Kind() == VIA ? 1 : 0; segs += m_linkedItems[i]->Kind() == SEGMENT ? 1 : 0; } - return (vias == 1 && segs == 2); + return ( vias == 1 && segs == 2 ); } ///> Links the joint to a given board item (when it's added to the PNS_NODE) @@ -209,15 +209,11 @@ private: PNS_ITEMSET m_linkedItems; }; - -// hash function & comparison operator for boost::unordered_map<> -inline bool operator==( PNS_JOINT::HASH_TAG const& aP1, - PNS_JOINT::HASH_TAG const& aP2 ) +inline bool operator==( PNS_JOINT::HASH_TAG const& aP1, PNS_JOINT::HASH_TAG const& aP2 ) { return aP1.pos == aP2.pos && aP1.net == aP2.net; } - inline std::size_t hash_value( PNS_JOINT::HASH_TAG const& aP ) { std::size_t seed = 0; diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index bf02010bfe..dd346e4cae 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -140,7 +140,7 @@ PNS_SEGMENT* PNS_SEGMENT::Clone( ) const { PNS_SEGMENT* s = new PNS_SEGMENT; - s->m_seg = m_seg; + s->m_seg = m_seg; s->m_net = m_net; s->m_layers = m_layers; s->m_marker = m_marker; @@ -348,7 +348,6 @@ SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECT { optional picked; int i; - int d = 2; if( aOrigin.CSegment( -1 ).Length() > 100000 * 30 ) // fixme: constant/parameter? @@ -701,7 +700,7 @@ void PNS_LINE::Reverse() void PNS_LINE::AppendVia( const PNS_VIA& aVia ) { - if(m_line.PointCount() == 0) + if( m_line.PointCount() == 0 ) return; if( aVia.Pos() == m_line.CPoint( 0 ) ) @@ -785,44 +784,47 @@ void PNS_LINE::ClearSegmentLinks() m_segmentRefs = NULL; } -static void extendBox( BOX2I& aBox, bool &aDefined, const VECTOR2I& aP ) + +static void extendBox( BOX2I& aBox, bool& aDefined, const VECTOR2I& aP ) { if( aDefined ) aBox.Merge ( aP ); else { - aBox = BOX2I ( aP, VECTOR2I (0, 0 ) ); + aBox = BOX2I( aP, VECTOR2I( 0, 0 ) ); aDefined = true; } } -OPT_BOX2I PNS_LINE::ChangedArea ( const PNS_LINE *aOther ) const + +OPT_BOX2I PNS_LINE::ChangedArea( const PNS_LINE* aOther ) const { BOX2I area; bool areaDefined = false; - int i_start = -1; int i_end_self = -1, i_end_other = -1; - SHAPE_LINE_CHAIN self ( m_line ); + SHAPE_LINE_CHAIN self( m_line ); self.Simplify(); - SHAPE_LINE_CHAIN other ( aOther->m_line ); + SHAPE_LINE_CHAIN other( aOther->m_line ); other.Simplify(); int np_self = self.PointCount(); int np_other = other.PointCount(); - int n = std::min ( np_self, np_other ); + int n = std::min( np_self, np_other ); - for( int i = 0; i < n; i++) + for( int i = 0; i < n; i++ ) { - const VECTOR2I p1 = self.CPoint(i); - const VECTOR2I p2 = other.CPoint(i); - if (p1 != p2) + const VECTOR2I p1 = self.CPoint( i ); + const VECTOR2I p2 = other.CPoint( i ); + + if( p1 != p2 ) { - if (i != n - 1) + if( i != n - 1 ) { - SEG s = self.CSegment(i); + SEG s = self.CSegment( i ); + if( !s.Contains( p2 ) ) { i_start = i; @@ -832,16 +834,15 @@ OPT_BOX2I PNS_LINE::ChangedArea ( const PNS_LINE *aOther ) const i_start = i; break; } - } } - for( int i = 0; i < n; i++) + for( int i = 0; i < n; i++ ) { - const VECTOR2I p1 = self.CPoint( np_self - 1 - i ); const VECTOR2I p2 = other.CPoint( np_other - 1 - i ); - if (p1 != p2) + + if( p1 != p2 ) { i_end_self = np_self - 1 - i; i_end_other = np_other - 1 - i; @@ -858,17 +859,17 @@ OPT_BOX2I PNS_LINE::ChangedArea ( const PNS_LINE *aOther ) const if( i_end_other < 0 ) i_end_other = np_other - 1; - for (int i = i_start; i <= i_end_self; i++ ) - extendBox ( area, areaDefined, self.CPoint(i) ); + for( int i = i_start; i <= i_end_self; i++ ) + extendBox( area, areaDefined, self.CPoint( i ) ); - for (int i = i_start; i <= i_end_other; i++ ) - extendBox ( area, areaDefined, other.CPoint(i) ); + for( int i = i_start; i <= i_end_other; i++ ) + extendBox( area, areaDefined, other.CPoint( i ) ); if( areaDefined ) { - area.Inflate ( std::max( Width(), aOther->Width() ) ); + area.Inflate( std::max( Width(), aOther->Width() ) ); return area; } - return OPT_BOX2I ( ); + return OPT_BOX2I(); } diff --git a/pcbnew/router/pns_line.h b/pcbnew/router/pns_line.h index 5a12fab96f..cf75e0ff1f 100644 --- a/pcbnew/router/pns_line.h +++ b/pcbnew/router/pns_line.h @@ -70,7 +70,7 @@ public: } PNS_LINE( const PNS_LINE& aOther ) ; - + /** * Constructor * Copies properties (net, layers, etc.) from a base line and replaces the shape @@ -88,12 +88,12 @@ public: } ~PNS_LINE(); - + static inline bool ClassOf( const PNS_ITEM* aItem ) { return aItem && LINE == aItem->Kind(); } - + /// @copydoc PNS_ITEM::Clone() virtual PNS_LINE* Clone() const; @@ -101,62 +101,62 @@ public: ///> Assigns a shape to the line (a polyline/line chain) void SetShape( const SHAPE_LINE_CHAIN& aLine ) - { + { m_line = aLine; } ///> Returns the shape of the line - const SHAPE* Shape() const - { - return &m_line; + const SHAPE* Shape() const + { + return &m_line; } ///> Modifiable accessor to the underlying shape - SHAPE_LINE_CHAIN& Line() - { - return m_line; + SHAPE_LINE_CHAIN& Line() + { + return m_line; } ///> Const accessor to the underlying shape - const SHAPE_LINE_CHAIN& CLine() const - { + const SHAPE_LINE_CHAIN& CLine() const + { return m_line; } ///> Returns the number of segments in the line - int SegmentCount() const + int SegmentCount() const { - return m_line.SegmentCount(); + return m_line.SegmentCount(); } ///> Returns the number of points in the line - int PointCount() const - { - return m_line.PointCount(); + int PointCount() const + { + return m_line.PointCount(); } ///> Returns the aIdx-th point of the line - const VECTOR2I& CPoint( int aIdx ) const - { + 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; + void SetWidth( int aWidth ) + { + m_width = aWidth; } - + ///> Returns line width - int Width() const - { - return m_width; + int Width() const + { + return m_width; } ///> Returns true if the line is geometrically identical as line aOther @@ -168,7 +168,7 @@ public: /* Linking functions */ - ///> Adds a reference to a segment registered in a PNS_NODE that is a part of this line. + ///> 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 ) @@ -184,7 +184,7 @@ public: return m_segmentRefs; } - bool IsLinked () const + bool IsLinked() const { return m_segmentRefs != NULL; } @@ -199,14 +199,14 @@ public: aSeg ) != m_segmentRefs->end(); } - PNS_SEGMENT* GetLink ( int aIndex ) const + PNS_SEGMENT* GetLink( int aIndex ) const { return (*m_segmentRefs) [ aIndex ]; } ///> 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 { @@ -220,9 +220,9 @@ public: ///> Returns the clipped line. const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const; - ///> Clips the line to a given range of vertices. + ///> 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 ); @@ -253,21 +253,21 @@ public: void RemoveVia() { m_hasVia = false; } 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 SetRank( int aRank ); int Rank() const; - + bool HasLoops() const; - OPT_BOX2I ChangedArea ( const PNS_LINE *aOther ) const; - + OPT_BOX2I ChangedArea( const PNS_LINE* aOther ) const; + private: VECTOR2I snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, int aIndex, int aThreshold) const; @@ -277,7 +277,7 @@ private: ///> 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; diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 2d6014784e..9a9ff9b1c1 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -38,7 +38,7 @@ using boost::optional; PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_ROUTER* aRouter ) : - PNS_PLACEMENT_ALGO ( aRouter ) + PNS_PLACEMENT_ALGO( aRouter ) { m_initial_direction = DIRECTION_45::N; m_world = NULL; @@ -71,8 +71,8 @@ const PNS_VIA PNS_LINE_PLACER::makeVia ( const VECTOR2I& aP ) bool PNS_LINE_PLACER::ToggleVia( bool aEnabled ) { m_placingVia = aEnabled; - if(!m_idle) - Move ( m_currentEnd, NULL ); + if( !m_idle ) + Move( m_currentEnd, NULL ); return true; } @@ -377,7 +377,7 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead ) bool PNS_LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - SHAPE_LINE_CHAIN line = buildInitialLine ( aP ); + SHAPE_LINE_CHAIN line = buildInitialLine( aP ); PNS_LINE initTrack( m_head, line ), walkFull; int effort = 0; bool viaOk = handleViaPlacement( initTrack ); @@ -431,7 +431,7 @@ bool PNS_LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, PNS_LINE& aNewHead ) bool PNS_LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - m_head.SetShape( buildInitialLine ( aP ) ); + m_head.SetShape( buildInitialLine( aP ) ); if( m_placingVia ) { @@ -446,7 +446,7 @@ bool PNS_LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ) bool PNS_LINE_PLACER::rhShoveOnly ( const VECTOR2I& aP, PNS_LINE& aNewHead ) { - SHAPE_LINE_CHAIN line = buildInitialLine ( aP ); + SHAPE_LINE_CHAIN line = buildInitialLine( aP ); PNS_LINE initTrack( m_head, line ); PNS_LINE walkSolids, l2; @@ -531,9 +531,9 @@ bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead ) case RM_MarkObstacles: return rhMarkObstacles( aP, aNewHead ); case RM_Walkaround: - return rhWalkOnly ( aP, aNewHead ); + return rhWalkOnly( aP, aNewHead ); case RM_Shove: - return rhShoveOnly ( aP, aNewHead ); + return rhShoveOnly( aP, aNewHead ); default: break; } @@ -732,9 +732,12 @@ bool PNS_LINE_PLACER::SetLayer( int aLayer ) { m_currentLayer = aLayer; return true; - } else if( m_chainedPlacement ) { + } + else if( m_chainedPlacement ) + { return false; - } else if( !m_startItem || ( m_startItem->OfKind( PNS_ITEM::VIA ) && m_startItem->Layers().Overlaps( aLayer ) ) ) { + } + else if( !m_startItem || ( m_startItem->OfKind( PNS_ITEM::VIA ) && m_startItem->Layers().Overlaps( aLayer ) ) ) { m_currentLayer = aLayer; m_splitSeg = false; initPlacement ( m_splitSeg ); @@ -745,6 +748,7 @@ bool PNS_LINE_PLACER::SetLayer( int aLayer ) return false; } + bool PNS_LINE_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p( aP ); @@ -1013,36 +1017,39 @@ void PNS_LINE_PLACER::updateLeadingRatLine() SHAPE_LINE_CHAIN ratLine; PNS_TOPOLOGY topo ( m_lastNode ); - if( topo.LeadingRatLine ( ¤t, ratLine )) + if( topo.LeadingRatLine( ¤t, ratLine ) ) Router()->DisplayDebugLine( ratLine, 5, 10000 ); } -void PNS_LINE_PLACER::SetOrthoMode ( bool aOrthoMode ) + +void PNS_LINE_PLACER::SetOrthoMode( bool aOrthoMode ) { m_orthoMode = aOrthoMode; - if(!m_idle) - Move ( m_currentEnd, NULL ); + + if( !m_idle ) + Move( m_currentEnd, NULL ); } -const SHAPE_LINE_CHAIN PNS_LINE_PLACER::buildInitialLine ( const VECTOR2I& aP ) +const SHAPE_LINE_CHAIN PNS_LINE_PLACER::buildInitialLine( const VECTOR2I& aP ) { - SHAPE_LINE_CHAIN l (m_direction.BuildInitialTrace( m_p_start, aP ) ); + SHAPE_LINE_CHAIN l( m_direction.BuildInitialTrace( m_p_start, aP ) ); if( l.SegmentCount() <= 1 ) return l; - - if (m_orthoMode) - { - VECTOR2I newLast = l.CSegment(0).LineProject ( l.CPoint(-1) ); - l.Remove(-1, -1); - l.Point(1) = newLast; + if( m_orthoMode ) + { + VECTOR2I newLast = l.CSegment( 0 ).LineProject( l.CPoint( -1 ) ); + + l.Remove( -1, -1 ); + l.Point( 1 ) = newLast; } return l; } -void PNS_LINE_PLACER::GetModifiedNets( std::vector &aNets ) const + +void PNS_LINE_PLACER::GetModifiedNets( std::vector& aNets ) const { aNets.push_back( m_currentNet ); } diff --git a/pcbnew/router/pns_line_placer.h b/pcbnew/router/pns_line_placer.h index ec7ace7412..cfa6228f66 100644 --- a/pcbnew/router/pns_line_placer.h +++ b/pcbnew/router/pns_line_placer.h @@ -40,7 +40,6 @@ class PNS_VIA; class PNS_SIZES_SETTINGS; - /** * Class PNS_LINE_PLACER * @@ -96,7 +95,6 @@ public: */ bool SetLayer( int aLayer ); - /** * Function Head() * @@ -181,11 +179,11 @@ public: */ void UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ); - void SetOrthoMode ( bool aOrthoMode ); + void SetOrthoMode( bool aOrthoMode ); bool IsPlacingVia() const { return m_placingVia; } - void GetModifiedNets( std::vector &aNets ) const; + void GetModifiedNets( std::vector& aNets ) const; private: /** * Function route() @@ -348,8 +346,9 @@ private: bool rhMarkObstacles( const VECTOR2I& aP, PNS_LINE& aNewHead ); const PNS_VIA makeVia ( const VECTOR2I& aP ); - const SHAPE_LINE_CHAIN buildInitialLine ( const VECTOR2I& aP ); - + + const SHAPE_LINE_CHAIN buildInitialLine( const VECTOR2I& aP ); + ///> current routing direction DIRECTION_45 m_direction; diff --git a/pcbnew/router/pns_logger.cpp b/pcbnew/router/pns_logger.cpp index b09578137c..47aab1687e 100644 --- a/pcbnew/router/pns_logger.cpp +++ b/pcbnew/router/pns_logger.cpp @@ -32,7 +32,7 @@ PNS_LOGGER::PNS_LOGGER( ) { - m_groupOpened = false; + m_groupOpened = false; } @@ -43,89 +43,89 @@ PNS_LOGGER::~PNS_LOGGER() void PNS_LOGGER::Clear() { - m_theLog.str( std::string() ); - m_groupOpened = false; + 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; + if( m_groupOpened ) + m_theLog << "endgroup" << std::endl; - m_theLog << "group " << aName << " " << aIter << std::endl; - m_groupOpened = true; + m_theLog << "group " << aName << " " << aIter << std::endl; + m_groupOpened = true; } void PNS_LOGGER::EndGroup() { - if( !m_groupOpened ) - return; + if( !m_groupOpened ) + return; - m_groupOpened = false; - m_theLog << "endgroup" << std::endl; + 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(); + 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; - } + 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::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::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; - } + 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; - } + 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; + 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; } @@ -137,54 +137,55 @@ void PNS_LOGGER::Log( const VECTOR2I& aStart, const VECTOR2I& aEnd, 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 ) << " "; + 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 << " "; + for( int i = 0; i < lc->PointCount(); i++ ) + m_theLog << lc->CPoint( i ).x << " " << lc->CPoint( i ).y << " "; - break; - } + 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_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_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; - } + 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; - } + default: + break; + } } + void PNS_LOGGER::Save( const std::string& aFilename ) { - EndGroup(); + 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 ); + 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 index 9120a43557..b38fd427c8 100644 --- a/pcbnew/router/pns_logger.h +++ b/pcbnew/router/pns_logger.h @@ -35,25 +35,25 @@ class SHAPE; class PNS_LOGGER { public: - PNS_LOGGER(); - ~PNS_LOGGER(); + PNS_LOGGER(); + ~PNS_LOGGER(); - void Save( const std::string& aFilename ); - void Clear(); + void Save( const std::string& aFilename ); + void Clear(); - void NewGroup( const std::string& aName, int aIter = 0 ); - void EndGroup(); + 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() ); + 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 ); + void dumpShape( const SHAPE* aSh ); - bool m_groupOpened; - std::stringstream m_theLog; + bool m_groupOpened; + std::stringstream m_theLog; }; #endif diff --git a/pcbnew/router/pns_meander.cpp b/pcbnew/router/pns_meander.cpp index 952a27e403..0577aad404 100644 --- a/pcbnew/router/pns_meander.cpp +++ b/pcbnew/router/pns_meander.cpp @@ -32,50 +32,49 @@ #include "pns_meander_placer_base.h" #include "pns_router.h" -const PNS_MEANDER_SETTINGS& PNS_MEANDER_SHAPE::Settings( ) const +const PNS_MEANDER_SETTINGS& PNS_MEANDER_SHAPE::Settings() const { - return m_placer->MeanderSettings( ); + return m_placer->MeanderSettings(); } -const PNS_MEANDER_SETTINGS& PNS_MEANDERED_LINE::Settings( ) const +const PNS_MEANDER_SETTINGS& PNS_MEANDERED_LINE::Settings() const { - return m_placer->MeanderSettings( ); + return m_placer->MeanderSettings(); } -void PNS_MEANDERED_LINE::MeanderSegment( const SEG &aBase, int aBaseIndex ) +void PNS_MEANDERED_LINE::MeanderSegment( const SEG& aBase, int aBaseIndex ) { - double base_len = aBase.Length( ); + double base_len = aBase.Length(); SHAPE_LINE_CHAIN lc; - + bool side = true; VECTOR2D dir( aBase.B - aBase.A ); - if(!m_dual) + if( !m_dual ) AddCorner( aBase.A ); bool turning = false; bool started = false; - + m_last = aBase.A; - + do { - PNS_MEANDER_SHAPE *m = new PNS_MEANDER_SHAPE( m_placer, m_width, m_dual ); + PNS_MEANDER_SHAPE* m = new PNS_MEANDER_SHAPE( m_placer, m_width, m_dual ); m->SetBaselineOffset( m_baselineOffset ); m->SetBaseIndex( aBaseIndex ); - double thr = (double) m->spacing( ); + double thr = (double) m->spacing(); bool fail = false; - double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( ); + double remaining = base_len - ( m_last - aBase.A ).EuclideanNorm(); if( remaining < Settings( ).m_step ) break; if( remaining > 3.0 * thr ) { - if( !turning ) { for( int i = 0; i < 2; i++ ) @@ -106,11 +105,10 @@ void PNS_MEANDERED_LINE::MeanderSegment( const SEG &aBase, int aBaseIndex ) } } } - } else { bool rv = m->Fit( MT_CHECK_FINISH, aBase, m_last, side ); - if( rv ) + if( rv ) { m->Fit( MT_TURN, aBase, m_last, side ); AddMeander( m ); @@ -124,37 +122,35 @@ void PNS_MEANDERED_LINE::MeanderSegment( const SEG &aBase, int aBaseIndex ) side = !side; } - } else if( started ) { bool rv = m->Fit( MT_FINISH, aBase, m_last, side ); - if( rv ) - AddMeander(m); - + if( rv ) + AddMeander( m ); + break; } else { fail = true; } - + remaining = base_len - ( m_last - aBase.A ).EuclideanNorm( ); if( remaining < Settings( ).m_step ) break; - if( fail ) { PNS_MEANDER_SHAPE tmp( m_placer, m_width, m_dual ); tmp.SetBaselineOffset( m_baselineOffset ); tmp.SetBaseIndex( aBaseIndex ); - int nextP = tmp.spacing( ) - 2 * tmp.cornerRadius( ) + Settings( ).m_step; - VECTOR2I pn = m_last + dir.Resize ( nextP ); - - if (aBase.Contains( pn ) && !m_dual) + int nextP = tmp.spacing() - 2 * tmp.cornerRadius() + Settings().m_step; + VECTOR2I pn = m_last + dir.Resize( nextP ); + + if( aBase.Contains( pn ) && !m_dual ) { - AddCorner ( pn ); + AddCorner( pn ); } else break; } @@ -167,26 +163,27 @@ void PNS_MEANDERED_LINE::MeanderSegment( const SEG &aBase, int aBaseIndex ) } -int PNS_MEANDER_SHAPE::cornerRadius( ) const +int PNS_MEANDER_SHAPE::cornerRadius() const { - int cr = (int64_t) spacing( ) * Settings( ).m_cornerRadiusPercentage / 200; + int cr = (int64_t) spacing() * Settings().m_cornerRadiusPercentage / 200; return cr; } + int PNS_MEANDER_SHAPE::spacing( ) const { if ( !m_dual ) - return std::max ( 2 * m_width, Settings( ).m_spacing ); + return std::max( 2 * m_width, Settings().m_spacing ); else { int sp = 2 * ( m_width + std::abs( m_baselineOffset ) ); - return std::max ( sp, Settings( ).m_spacing ); + return std::max ( sp, Settings().m_spacing ); } } -SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool side ) +SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide ) { SHAPE_LINE_CHAIN lc; @@ -195,22 +192,24 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool lc.Append( aP ); return lc; } - + VECTOR2D dir_u( aDir ); VECTOR2D dir_v( aDir.Perpendicular( ) ); - - const int ArcSegments = Settings( ).m_cornerArcSegments; - for(int i = ArcSegments - 1; i >= 0; i--) + const int ArcSegments = Settings().m_cornerArcSegments; + + for( int i = ArcSegments - 1; i >= 0; i-- ) { VECTOR2D p; - double alpha = (double) i / (double) (ArcSegments - 1) * M_PI / 2.0; - p = aP + dir_u * cos( alpha ) + dir_v * ( side ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) ); + double alpha = (double) i / (double) ( ArcSegments - 1 ) * M_PI / 2.0; + p = aP + dir_u * cos( alpha ) + dir_v * ( aSide ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) ); lc.Append( ( int ) p.x, ( int ) p.y ); } + return lc; } + VECTOR2I PNS_MEANDER_SHAPE::reflect( VECTOR2I p, const SEG& line ) { typedef int64_t ecoord; @@ -219,53 +218,58 @@ VECTOR2I PNS_MEANDER_SHAPE::reflect( VECTOR2I p, const SEG& line ) ecoord t = d.Dot( p - line.A ); VECTOR2I c, rv; - if(!l_squared) + if( !l_squared ) c = p; else { - c.x = line.A.x + rescale( t, (ecoord)d.x, l_squared ); - c.y = line.A.y + rescale( t, (ecoord)d.y, l_squared ); + c.x = line.A.x + rescale( t, (ecoord) d.x, l_squared ); + c.y = line.A.y + rescale( t, (ecoord) d.y, l_squared ); } - + return 2 * c - p; } + void PNS_MEANDER_SHAPE::start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir ) { m_currentTarget = aTarget; - m_currentTarget->Clear( ); + m_currentTarget->Clear(); m_currentTarget->Append( aWhere ); m_currentDir = aDir; m_currentPos = aWhere; } + void PNS_MEANDER_SHAPE::forward( int aLength ) { m_currentPos += m_currentDir.Resize( aLength ); m_currentTarget->Append( m_currentPos ); } + void PNS_MEANDER_SHAPE::turn( int aAngle ) { - m_currentDir = m_currentDir.Rotate( (double)aAngle * M_PI / 180.0 ); + m_currentDir = m_currentDir.Rotate( (double) aAngle * M_PI / 180.0 ); } + void PNS_MEANDER_SHAPE::arc( int aRadius, bool aSide ) { if( aRadius <= 0 ) { - turn ( aSide ? -90 : 90 ); + turn( aSide ? -90 : 90 ); return; } VECTOR2D dir = m_currentDir.Resize( (double) aRadius ); SHAPE_LINE_CHAIN arc = circleQuad( m_currentPos, dir, aSide ); m_currentPos = arc.CPoint( -1 ); - m_currentDir = dir.Rotate( aSide ? -M_PI/2.0 : M_PI/2.0 ); + m_currentDir = dir.Rotate( aSide ? -M_PI / 2.0 : M_PI / 2.0 ); m_currentTarget->Append ( arc ); } -void PNS_MEANDER_SHAPE::uShape ( int aSides, int aCorner, int aTop ) + +void PNS_MEANDER_SHAPE::uShape( int aSides, int aCorner, int aTop ) { forward( aSides ); arc( aCorner, true ); @@ -274,35 +278,36 @@ void PNS_MEANDER_SHAPE::uShape ( int aSides, int aCorner, int aTop ) forward( aSides ); } -SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset ) + +SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape( VECTOR2D aP, VECTOR2D aDir, + bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset ) { const PNS_MEANDER_SETTINGS& st = Settings(); int cr = cornerRadius(); int offset = aBaselineOffset; int spc = spacing(); - - if (aSide) + + if( aSide ) offset *= -1; - VECTOR2D dir_u_b ( aDir.Resize( offset ) ); - VECTOR2D dir_v_b (dir_u_b.Perpendicular()); + VECTOR2D dir_u_b( aDir.Resize( offset ) ); + VECTOR2D dir_v_b( dir_u_b.Perpendicular() ); - if (2 * cr > aAmpl) + if( 2 * cr > aAmpl ) { cr = aAmpl / 2; } - if (2 * cr > spc) + if( 2 * cr > spc ) { cr = spc / 2; } - SHAPE_LINE_CHAIN lc; - start ( &lc, aP + dir_v_b, aDir ); + start( &lc, aP + dir_v_b, aDir ); - switch (aType) + switch( aType ) { case MT_EMPTY: { @@ -313,7 +318,7 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir { arc( cr - offset, false ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); - forward( std::min(cr - offset, cr + offset) ); + forward( std::min( cr - offset, cr + offset ) ); forward( std::abs( offset ) ); break; @@ -323,8 +328,8 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir { start( &lc, aP - dir_u_b, aDir ); turn ( 90 ); - forward( std::min(cr - offset, cr + offset) ); - forward( std::abs( offset ) ); + forward( std::min( cr - offset, cr + offset ) ); + forward( std::abs( offset ) ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); arc( cr - offset, false ); break; @@ -332,13 +337,11 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir case MT_TURN: { - start( &lc, aP - dir_u_b, aDir ); turn( 90 ); forward( std::abs( offset ) ); uShape ( aAmpl - cr, cr + offset, spc - 2 * cr ); forward( std::abs( offset ) ); - break; } @@ -347,7 +350,7 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir arc( cr - offset, false ); uShape( aAmpl - 2 * cr + std::abs( offset ), cr + offset, spc - 2 * cr ); arc( cr - offset, false ); - lc.Append ( aP + dir_v_b + aDir.Resize ( 2 * st.m_spacing) ); + lc.Append( aP + dir_v_b + aDir.Resize ( 2 * st.m_spacing ) ); break; } @@ -358,71 +361,76 @@ SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::genMeanderShape ( VECTOR2D aP, VECTOR2D aDir if( aSide ) { SEG axis ( aP, aP + aDir ); - for(int i = 0; i < lc.PointCount(); i++ ) - lc.Point(i) = reflect ( lc.CPoint(i), axis ); + + for( int i = 0; i < lc.PointCount(); i++ ) + lc.Point( i ) = reflect( lc.CPoint( i ), axis ); } return lc; } -bool PNS_MEANDERED_LINE::CheckSelfIntersections ( PNS_MEANDER_SHAPE *aShape, int aClearance ) -{ - for (int i = m_meanders.size() - 1; i >= 0; i--) - { - PNS_MEANDER_SHAPE *m = m_meanders[i]; - if (m->Type() == MT_EMPTY || m->Type() == MT_CORNER ) +bool PNS_MEANDERED_LINE::CheckSelfIntersections( PNS_MEANDER_SHAPE* aShape, int aClearance ) +{ + for( int i = m_meanders.size() - 1; i >= 0; i-- ) + { + PNS_MEANDER_SHAPE* m = m_meanders[i]; + + if( m->Type() == MT_EMPTY || m->Type() == MT_CORNER ) continue; const SEG& b1 = aShape->BaseSegment(); const SEG& b2 = m->BaseSegment(); - if (b1.ApproxParallel(b2)) + if( b1.ApproxParallel( b2 ) ) continue; - - int n = m->CLine(0).SegmentCount(); - for (int j = n - 1; j >= 0; j--) - if ( aShape->CLine(0).Collide ( m->CLine(0).CSegment(j), aClearance ) ) + int n = m->CLine( 0 ).SegmentCount(); + + for( int j = n - 1; j >= 0; j-- ) + if( aShape->CLine( 0 ).Collide ( m->CLine( 0 ) .CSegment( j ), aClearance ) ) return false; } return true; } -bool PNS_MEANDER_SHAPE::Fit ( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ) + +bool PNS_MEANDER_SHAPE::Fit( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ) { const PNS_MEANDER_SETTINGS& st = Settings(); - + bool checkMode = false; PNS_MEANDER_TYPE prim1, prim2; - if(aType == MT_CHECK_START) + if( aType == MT_CHECK_START ) { prim1 = MT_START; prim2 = MT_TURN; checkMode = true; - } else if (aType == MT_CHECK_FINISH ) { + } + else if( aType == MT_CHECK_FINISH ) + { prim1 = MT_TURN; prim2 = MT_FINISH; checkMode = true; } - - if(checkMode) + + if( checkMode ) { - PNS_MEANDER_SHAPE m1 ( m_placer, m_width, m_dual ); - PNS_MEANDER_SHAPE m2 ( m_placer, m_width, m_dual ); + PNS_MEANDER_SHAPE m1( m_placer, m_width, m_dual ); + PNS_MEANDER_SHAPE m2( m_placer, m_width, m_dual ); - m1.SetBaselineOffset ( m_baselineOffset ); - m2.SetBaselineOffset ( m_baselineOffset ); + m1.SetBaselineOffset( m_baselineOffset ); + m2.SetBaselineOffset( m_baselineOffset ); - bool c1 = m1.Fit ( prim1, aSeg, aP, aSide ); + bool c1 = m1.Fit( prim1, aSeg, aP, aSide ); bool c2 = false; - if(c1) - c2 = m2.Fit ( prim2, aSeg, m1.End(), !aSide ); + if( c1 ) + c2 = m2.Fit( prim2, aSeg, m1.End(), !aSide ); - if(c1 && c2) + if( c1 && c2 ) { m_type = prim1; m_shapes[0] = m1.m_shapes[0]; @@ -434,63 +442,64 @@ bool PNS_MEANDER_SHAPE::Fit ( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VEC m_dual = m1.m_dual; m_baseSeg = m1.m_baseSeg; m_baseIndex = m1.m_baseIndex; - updateBaseSegment (); + updateBaseSegment(); m_baselineOffset = m1.m_baselineOffset; return true; } else return false; - - } + } int minAmpl = st.m_minAmplitude; int maxAmpl = st.m_maxAmplitude; - if (m_dual) + if( m_dual ) { - minAmpl = std::max( minAmpl, 2 * std::abs(m_baselineOffset) ); - maxAmpl = std::max( maxAmpl, 2 * std::abs(m_baselineOffset) ); + minAmpl = std::max( minAmpl, 2 * std::abs( m_baselineOffset ) ); + maxAmpl = std::max( maxAmpl, 2 * std::abs( m_baselineOffset ) ); } - for(int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step) + for( int ampl = maxAmpl; ampl >= minAmpl; ampl -= st.m_step ) { - if (m_dual) + if( m_dual ) { - m_shapes[0] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, m_baselineOffset ); - m_shapes[1] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, -m_baselineOffset ); - } else { - m_shapes[0] = genMeanderShape ( aP, aSeg.B - aSeg.A, aSide, aType, ampl, 0); + m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl, m_baselineOffset ); + m_shapes[1] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl, -m_baselineOffset ); + } + else + { + m_shapes[0] = genMeanderShape( aP, aSeg.B - aSeg.A, aSide, aType, ampl, 0 ); } m_type = aType; - m_baseSeg =aSeg; + m_baseSeg = aSeg; m_p0 = aP; m_side = aSide; m_amplitude = ampl; - + updateBaseSegment(); - - if( m_placer->CheckFit ( this ) ) + + if( m_placer->CheckFit( this ) ) return true; } return false; } -void PNS_MEANDER_SHAPE::Recalculate ( ) -{ - m_shapes[0] = genMeanderShape ( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, m_dual ? m_baselineOffset : 0); - - if (m_dual) - m_shapes[1] = genMeanderShape ( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, -m_baselineOffset ); - - updateBaseSegment(); - -} - -void PNS_MEANDER_SHAPE::Resize ( int aAmpl ) +void PNS_MEANDER_SHAPE::Recalculate() { - if(aAmpl < 0) + m_shapes[0] = genMeanderShape( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, m_dual ? m_baselineOffset : 0 ); + + if( m_dual ) + m_shapes[1] = genMeanderShape( m_p0, m_baseSeg.B - m_baseSeg.A, m_side, m_type, m_amplitude, -m_baselineOffset ); + + updateBaseSegment(); +} + + +void PNS_MEANDER_SHAPE::Resize( int aAmpl ) +{ + if( aAmpl < 0 ) return; m_amplitude = aAmpl; @@ -498,6 +507,7 @@ void PNS_MEANDER_SHAPE::Resize ( int aAmpl ) Recalculate(); } + void PNS_MEANDER_SHAPE::MakeEmpty() { updateBaseSegment(); @@ -506,47 +516,46 @@ void PNS_MEANDER_SHAPE::MakeEmpty() m_type = MT_EMPTY; - m_shapes[0] = genMeanderShape ( m_p0, dir, m_side, m_type, 0, m_dual ? m_baselineOffset : 0); - - if(m_dual) - m_shapes[1] = genMeanderShape ( m_p0, dir, m_side, m_type, 0, -m_baselineOffset ); + m_shapes[0] = genMeanderShape ( m_p0, dir, m_side, m_type, 0, m_dual ? m_baselineOffset : 0 ); - + if( m_dual ) + m_shapes[1] = genMeanderShape( m_p0, dir, m_side, m_type, 0, -m_baselineOffset ); } - -void PNS_MEANDERED_LINE::AddCorner ( const VECTOR2I& aA, const VECTOR2I& aB ) + +void PNS_MEANDERED_LINE::AddCorner( const VECTOR2I& aA, const VECTOR2I& aB ) { - PNS_MEANDER_SHAPE *m = new PNS_MEANDER_SHAPE ( m_placer, m_width, m_dual ); + PNS_MEANDER_SHAPE* m = new PNS_MEANDER_SHAPE( m_placer, m_width, m_dual ); - m->MakeCorner ( aA, aB ); + m->MakeCorner( aA, aB ); m_last = aA; m_meanders.push_back( m ); } - -void PNS_MEANDER_SHAPE::MakeCorner ( VECTOR2I aP1, VECTOR2I aP2 ) + + +void PNS_MEANDER_SHAPE::MakeCorner( VECTOR2I aP1, VECTOR2I aP2 ) { SetType( MT_CORNER ); - m_shapes[ 0 ].Clear( ); - m_shapes[ 1 ].Clear( ); - m_shapes[ 0 ].Append( aP1 ); - m_shapes[ 1 ].Append( aP2 ); + m_shapes[0].Clear(); + m_shapes[1].Clear(); + m_shapes[0].Append( aP1 ); + m_shapes[1].Append( aP2 ); m_clippedBaseSeg.A = aP1; m_clippedBaseSeg.B = aP1; - } -void PNS_MEANDERED_LINE::AddMeander ( PNS_MEANDER_SHAPE *aShape ) + +void PNS_MEANDERED_LINE::AddMeander( PNS_MEANDER_SHAPE* aShape ) { - m_last = aShape->BaseSegment( ).B; + m_last = aShape->BaseSegment().B; m_meanders.push_back( aShape ); } - - -void PNS_MEANDERED_LINE::Clear( ) + + +void PNS_MEANDERED_LINE::Clear() { - BOOST_FOREACH( PNS_MEANDER_SHAPE *m, m_meanders ) + BOOST_FOREACH( PNS_MEANDER_SHAPE* m, m_meanders ) { delete m; } @@ -554,26 +563,31 @@ void PNS_MEANDERED_LINE::Clear( ) m_meanders.clear( ); } -int PNS_MEANDER_SHAPE::BaselineLength( ) const + +int PNS_MEANDER_SHAPE::BaselineLength() const { - return m_clippedBaseSeg.Length( ); + return m_clippedBaseSeg.Length(); } -int PNS_MEANDER_SHAPE::MaxTunableLength( ) const + +int PNS_MEANDER_SHAPE::MaxTunableLength() const { - return CLine( 0 ).Length( ); + return CLine( 0 ).Length(); } + void PNS_MEANDER_SHAPE::updateBaseSegment( ) { if( m_dual ) { VECTOR2I midpA = ( CLine( 0 ).CPoint( 0 ) + CLine( 1 ).CPoint( 0 ) ) / 2; VECTOR2I midpB = ( CLine( 0 ).CPoint( -1 ) + CLine( 1 ).CPoint( -1 ) ) / 2; - + m_clippedBaseSeg.A = m_baseSeg.LineProject( midpA ); m_clippedBaseSeg.B = m_baseSeg.LineProject( midpB ); - } else { + } + else + { m_clippedBaseSeg.A = m_baseSeg.LineProject( CLine( 0 ).CPoint( 0 ) ); m_clippedBaseSeg.B = m_baseSeg.LineProject( CLine( 0 ).CPoint( -1 ) ); } diff --git a/pcbnew/router/pns_meander.h b/pcbnew/router/pns_meander.h index 0abcbaaa13..de08329ed7 100644 --- a/pcbnew/router/pns_meander.h +++ b/pcbnew/router/pns_meander.h @@ -55,7 +55,7 @@ public: CHAMFER // chamfered (45 degree segment) }; - PNS_MEANDER_SETTINGS () + PNS_MEANDER_SETTINGS() { m_minAmplitude = 100000; m_maxAmplitude = 1000000; @@ -65,26 +65,26 @@ public: m_targetSkew = 0; m_cornerType = ROUND; m_cornerRadiusPercentage = 100; - m_lengthTollerance = 100000; + m_lengthTolerance = 100000; m_cornerArcSegments = 8; } - + ///> minimum meandering amplitude int m_minAmplitude; ///> maximum meandering amplitude int m_maxAmplitude; - ///> meandering period/spacing (see dialog picture for explanation) + ///> meandering period/spacing (see dialog picture for explanation) int m_spacing; ///> amplitude/spacing adjustment step int m_step; ///> desired length of the tuned line/diff pair int m_targetLength; - ///> type of corners for the meandered line + ///> type of corners for the meandered line CornerType m_cornerType; ///> rounding percentage (0 - 100) int m_cornerRadiusPercentage; ///> allowable tuning error - int m_lengthTollerance; + int m_lengthTolerance; ///> number of line segments for arc approximation int m_cornerArcSegments; ///> target skew value for diff pair de-skewing @@ -100,280 +100,278 @@ class PNS_MEANDERED_LINE; */ class PNS_MEANDER_SHAPE { - public: - - /** - * Constructor - * - * @param aPlacer the meander placer instance - * @param aWidth width of the meandered line - * @param aIsDual when true, the shape contains two meandered - * lines at a given offset (diff pairs) - */ - PNS_MEANDER_SHAPE( PNS_MEANDER_PLACER_BASE *aPlacer, int aWidth, bool aIsDual = false ) : - m_placer( aPlacer ), - m_dual( aIsDual ), - m_width( aWidth ), - m_baselineOffset( 0 ) - { +public: + /** + * Constructor + * + * @param aPlacer the meander placer instance + * @param aWidth width of the meandered line + * @param aIsDual when true, the shape contains two meandered + * lines at a given offset (diff pairs) + */ + PNS_MEANDER_SHAPE( PNS_MEANDER_PLACER_BASE *aPlacer, int aWidth, bool aIsDual = false ) : + m_placer( aPlacer ), + m_dual( aIsDual ), + m_width( aWidth ), + m_baselineOffset( 0 ) + { + } - } + /** + * Function SetType() + * + * Sets the type of the meander. + */ + void SetType( PNS_MEANDER_TYPE aType ) + { + m_type = aType; + } - /** - * Function SetType() - * - * Sets the type of the meander. - */ - void SetType( PNS_MEANDER_TYPE aType ) - { - m_type = aType; - } - - /** - * Function Type() - * - * @return the type of the meander. - */ - PNS_MEANDER_TYPE Type( ) const - { - return m_type; - } + /** + * Function Type() + * + * @return the type of the meander. + */ + PNS_MEANDER_TYPE Type() const + { + return m_type; + } - /** - * Function SetBaseIndex() - * - * Sets an auxillary index of the segment being meandered in its original PNS_LINE. - */ - void SetBaseIndex( int aIndex ) - { - m_baseIndex = aIndex; - } + /** + * Function SetBaseIndex() + * + * Sets an auxillary index of the segment being meandered in its original PNS_LINE. + */ + void SetBaseIndex( int aIndex ) + { + m_baseIndex = aIndex; + } - /** - * Function BaseIndex() - * - * @return auxillary index of the segment being meandered in its original PNS_LINE. - */ - int BaseIndex( ) const - { - return m_baseIndex; - } + /** + * Function BaseIndex() + * + * @return auxillary index of the segment being meandered in its original PNS_LINE. + */ + int BaseIndex() const + { + return m_baseIndex; + } - /** - * Function Amplitude() - * - * @return the amplitude of the meander shape. - */ - int Amplitude( ) const - { - return m_amplitude; - } - - /** - * Function MakeCorner() - * - * Creates a dummy meander shape representing a line corner. Used to define - * the starts/ends of meandered segments. - * @param aP1 corner point of the 1st line - * @param aP2 corner point of the 2nd line (if m_dual == true) - */ - void MakeCorner( VECTOR2I aP1, VECTOR2I aP2 = VECTOR2I ( 0, 0 ) ); + /** + * Function Amplitude() + * + * @return the amplitude of the meander shape. + */ + int Amplitude() const + { + return m_amplitude; + } - /** - * Function Resize() - * - * Changes the amplitude of the meander shape to aAmpl and recalculates - * the resulting line chain. - * @param aAmpl new amplitude. - */ - void Resize( int aAmpl ); + /** + * Function MakeCorner() + * + * Creates a dummy meander shape representing a line corner. Used to define + * the starts/ends of meandered segments. + * @param aP1 corner point of the 1st line + * @param aP2 corner point of the 2nd line (if m_dual == true) + */ + void MakeCorner( VECTOR2I aP1, VECTOR2I aP2 = VECTOR2I( 0, 0 ) ); - /** - * Function Recalculate() - * - * Recalculates the line chain representing the meanders's shape. - */ - void Recalculate ( ); - - /** - * Function IsDual() - * - * @return true if the shape represents 2 parallel lines (diff pair). - */ - bool IsDual( ) const - { - return m_dual; - } + /** + * Function Resize() + * + * Changes the amplitude of the meander shape to aAmpl and recalculates + * the resulting line chain. + * @param aAmpl new amplitude. + */ + void Resize( int aAmpl ); - /** - * Function Side() - * - * @return true if the meander is to the right of its base segment. - */ - bool Side( ) const - { - return m_side; - } + /** + * Function Recalculate() + * + * Recalculates the line chain representing the meanders's shape. + */ + void Recalculate(); - /** - * Function End() - * - * @return end vertex of the base segment of the meander shape. - */ - VECTOR2I End( ) const - { - return m_clippedBaseSeg.B; - } + /** + * Function IsDual() + * + * @return true if the shape represents 2 parallel lines (diff pair). + */ + bool IsDual() const + { + return m_dual; + } - /** - * Function CLine() - * - * @return the line chain representing the shape of the meander. - */ - const SHAPE_LINE_CHAIN& CLine( int aShape ) const - { - return m_shapes[ aShape ]; - } + /** + * Function Side() + * + * @return true if the meander is to the right of its base segment. + */ + bool Side() const + { + return m_side; + } - /** - * Function MakeEmpty() - * - * Replaces the meander with straight bypass line(s), effectively - * clearing it. - */ - void MakeEmpty( ); + /** + * Function End() + * + * @return end vertex of the base segment of the meander shape. + */ + VECTOR2I End() const + { + return m_clippedBaseSeg.B; + } - /** - * Function Fit() - * - * Attempts to fit a meander of a given type onto a segment, avoiding - * collisions with other board features. - * @param aType type of meander shape - * @param aSeg base segment for meandering - * @param aP start point of the meander - * @param aSide side of aSeg to put the meander on (true = right) - * @return true on success. - */ - bool Fit( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ); + /** + * Function CLine() + * + * @return the line chain representing the shape of the meander. + */ + const SHAPE_LINE_CHAIN& CLine( int aShape ) const + { + return m_shapes[aShape]; + } - /** - * Function BaseSegment() - * - * Returns the base segment the meadner was fitted to. - * @return the base segment. - */ - const SEG& BaseSegment( ) const - { - return m_clippedBaseSeg; - } + /** + * Function MakeEmpty() + * + * Replaces the meander with straight bypass line(s), effectively + * clearing it. + */ + void MakeEmpty(); - /** - * Function BaselineLength() - * - * @return length of the base segment for the meander (i.e. - * the minimim tuned length. - */ - int BaselineLength( ) const; - - /** - * Function MaxTunableLength() - * - * @return the length of the fitted line chain. - */ - int MaxTunableLength( ) const; + /** + * Function Fit() + * + * Attempts to fit a meander of a given type onto a segment, avoiding + * collisions with other board features. + * @param aType type of meander shape + * @param aSeg base segment for meandering + * @param aP start point of the meander + * @param aSide side of aSeg to put the meander on (true = right) + * @return true on success. + */ + bool Fit( PNS_MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide ); - /** - * Function Settings() - * - * @return the current meandering settings. - */ - const PNS_MEANDER_SETTINGS& Settings( ) const; + /** + * Function BaseSegment() + * + * Returns the base segment the meadner was fitted to. + * @return the base segment. + */ + const SEG& BaseSegment() const + { + return m_clippedBaseSeg; + } - /** - * Function Width() - * - * @return width of the meandered line. - */ - int Width() const - { - return m_width; - } + /** + * Function BaselineLength() + * + * @return length of the base segment for the meander (i.e. + * the minimum tuned length. + */ + int BaselineLength() const; - /** - * Function SetBaselineOffset() - * - * Sets the parallel offset between the base segment and the meandered - * line. Used for dual menaders (diff pair) only. - * @param aOffset the offset - */ - void SetBaselineOffset ( int aOffset ) - { - m_baselineOffset = aOffset; - } + /** + * Function MaxTunableLength() + * + * @return the length of the fitted line chain. + */ + int MaxTunableLength() const; - private: - friend class PNS_MEANDERED_LINE; + /** + * Function Settings() + * + * @return the current meandering settings. + */ + const PNS_MEANDER_SETTINGS& Settings() const; - ///> starts turtle drawing - void start ( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir ); - ///> moves turtle forward by aLength - void forward ( int aLength ); - ///> turns the turtle by aAngle - void turn ( int aAngle ); - ///> tells the turtle to draw an arc of given radius and turn direction - void arc ( int aRadius, bool aSide ); - ///> tells the turtle to draw an U-like shape - void uShape ( int aSides, int aCorner, int aTop ); + /** + * Function Width() + * + * @return width of the meandered line. + */ + int Width() const + { + return m_width; + } - ///> generates a 90-degree circular arc - SHAPE_LINE_CHAIN circleQuad ( VECTOR2D aP, VECTOR2D aDir, bool side ); + /** + * Function SetBaselineOffset() + * + * Sets the parallel offset between the base segment and the meandered + * line. Used for dual menaders (diff pair) only. + * @param aOffset the offset + */ + void SetBaselineOffset( int aOffset ) + { + m_baselineOffset = aOffset; + } - ///> reflects a point onto other side of a given segment - VECTOR2I reflect ( VECTOR2I p, const SEG& line ); +private: + friend class PNS_MEANDERED_LINE; - ///> produces a meander shape of given type - SHAPE_LINE_CHAIN genMeanderShape ( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset = 0); - - ///> recalculates the clipped baseline after the parameters of - ///> the meander have been changed. - void updateBaseSegment(); - - ///> returns sanitized corner radius value - int cornerRadius ( ) const; - - ///> returns sanitized spacing value - int spacing ( ) const; - - ///> the type - PNS_MEANDER_TYPE m_type; - ///> the placer that placed this meander - PNS_MEANDER_PLACER_BASE *m_placer; - ///> dual or single line - bool m_dual; - ///> width of the line - int m_width; - ///> amplitude of the meander - int m_amplitude; - ///> offset wrs the base segment (dual only) - int m_baselineOffset; - ///> first point of the meandered line - VECTOR2I m_p0; - ///> base segment (unclipped) - SEG m_baseSeg; - ///> base segment (clipped) - SEG m_clippedBaseSeg; - ///> side (true = right) - bool m_side; - ///> the actual shapes (0 used for single, both for dual) - SHAPE_LINE_CHAIN m_shapes[2]; - ///> index of the meandered segment in the base line - int m_baseIndex; - ///> current turtle direction - VECTOR2D m_currentDir; - ///> current turtle position - VECTOR2D m_currentPos; - ///> the line the turtle is drawing on - SHAPE_LINE_CHAIN* m_currentTarget; + ///> starts turtle drawing + void start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir ); + ///> moves turtle forward by aLength + void forward( int aLength ); + ///> turns the turtle by aAngle + void turn( int aAngle ); + ///> tells the turtle to draw an arc of given radius and turn direction + void arc( int aRadius, bool aSide ); + ///> tells the turtle to draw an U-like shape + void uShape( int aSides, int aCorner, int aTop ); + + ///> generates a 90-degree circular arc + SHAPE_LINE_CHAIN circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide ); + + ///> reflects a point onto other side of a given segment + VECTOR2I reflect( VECTOR2I aP, const SEG& aLine ); + + ///> produces a meander shape of given type + SHAPE_LINE_CHAIN genMeanderShape( VECTOR2D aP, VECTOR2D aDir, bool aSide, PNS_MEANDER_TYPE aType, int aAmpl, int aBaselineOffset = 0 ); + + ///> recalculates the clipped baseline after the parameters of + ///> the meander have been changed. + void updateBaseSegment(); + + ///> returns sanitized corner radius value + int cornerRadius() const; + + ///> returns sanitized spacing value + int spacing() const; + + ///> the type + PNS_MEANDER_TYPE m_type; + ///> the placer that placed this meander + PNS_MEANDER_PLACER_BASE* m_placer; + ///> dual or single line + bool m_dual; + ///> width of the line + int m_width; + ///> amplitude of the meander + int m_amplitude; + ///> offset wrs the base segment (dual only) + int m_baselineOffset; + ///> first point of the meandered line + VECTOR2I m_p0; + ///> base segment (unclipped) + SEG m_baseSeg; + ///> base segment (clipped) + SEG m_clippedBaseSeg; + ///> side (true = right) + bool m_side; + ///> the actual shapes (0 used for single, both for dual) + SHAPE_LINE_CHAIN m_shapes[2]; + ///> index of the meandered segment in the base line + int m_baseIndex; + ///> current turtle direction + VECTOR2D m_currentDir; + ///> current turtle position + VECTOR2D m_currentPos; + ///> the line the turtle is drawing on + SHAPE_LINE_CHAIN* m_currentTarget; }; @@ -384,115 +382,111 @@ class PNS_MEANDER_SHAPE */ class PNS_MEANDERED_LINE { - public: - PNS_MEANDERED_LINE( ) - { +public: + PNS_MEANDERED_LINE() + { + } - } + /** + * Constructor + * + * @param aPlacer the meander placer instance + * @param aIsDual when true, the meanders are generated for two coupled lines + */ + PNS_MEANDERED_LINE( PNS_MEANDER_PLACER_BASE* aPlacer, bool aIsDual = false ) : + m_placer( aPlacer ), + m_dual( aIsDual ) + { + } - /** - * Constructor - * - * @param aPlacer the meander placer instance - * @param aIsDual when true, the meanders are generated for two coupled lines - */ - PNS_MEANDERED_LINE( PNS_MEANDER_PLACER_BASE *aPlacer, bool aIsDual = false ) : - m_placer( aPlacer ), - m_dual( aIsDual ) - { + /** + * Function AddCorner() + * + * Creates a dummy meander shape representing a line corner. Used to define + * the starts/ends of meandered segments. + * @param aA corner point of the 1st line + * @param aB corner point of the 2nd line (if m_dual == true) + */ + void AddCorner( const VECTOR2I& aA, const VECTOR2I& aB = VECTOR2I( 0, 0 ) ); - } - - /** - * Function AddCorner() - * - * Creates a dummy meander shape representing a line corner. Used to define - * the starts/ends of meandered segments. - * @param aA corner point of the 1st line - * @param aB corner point of the 2nd line (if m_dual == true) - */ - void AddCorner( const VECTOR2I& aA, const VECTOR2I& aB = VECTOR2I( 0, 0 ) ); - - /** - * Function AddMeander() - * - * Adds a new meander shape the the meandered line. - * @param aShape the meander shape to add - */ - void AddMeander( PNS_MEANDER_SHAPE *aShape ); - - /** - * Function Clear() - * - * Clears the line geometry, removing all corners and meanders. - */ - void Clear( ); + /** + * Function AddMeander() + * + * Adds a new meander shape the the meandered line. + * @param aShape the meander shape to add + */ + void AddMeander( PNS_MEANDER_SHAPE* aShape ); - /** - * Function SetWidth() - * - * Sets the line width. - */ - void SetWidth( int aWidth ) - { - m_width = aWidth; - } - - /** - * Function MeanderSegment() - * - * Fits maximum amplitude meanders on a given segment and adds to the - * current line. - * @param aSeg the base segment to meander - * @param aBaseIndex index of the base segment in the original line - */ - void MeanderSegment( const SEG& aSeg, int aBaseIndex = 0 ); + /** + * Function Clear() + * + * Clears the line geometry, removing all corners and meanders. + */ + void Clear(); - /// @copydoc PNS_MEANDER_SHAPE::SetBaselineOffset() - void SetBaselineOffset( int aOffset ) - { - m_baselineOffset = aOffset; - } + /** + * Function SetWidth() + * + * Sets the line width. + */ + void SetWidth( int aWidth ) + { + m_width = aWidth; + } - /** - * Function Meanders() - * - * @return set of meander shapes for this line - */ - std::vector & Meanders() - { - return m_meanders; - } + /** + * Function MeanderSegment() + * + * Fits maximum amplitude meanders on a given segment and adds to the + * current line. + * @param aSeg the base segment to meander + * @param aBaseIndex index of the base segment in the original line + */ + void MeanderSegment( const SEG& aSeg, int aBaseIndex = 0 ); + /// @copydoc PNS_MEANDER_SHAPE::SetBaselineOffset() + void SetBaselineOffset( int aOffset ) + { + m_baselineOffset = aOffset; + } - /** - * Function CheckSelfIntersections() - * - * Checks if the given shape is intersecting with any other meander in - * the current line. - * @param aShape the shape to check - * @param aClearance clearance value - * @return true, if the meander shape is not colliding - */ - bool CheckSelfIntersections ( PNS_MEANDER_SHAPE *aShape, int aClearance ); - - /** - * Function Settings() - * - * @return the current meandering settings. - */ - const PNS_MEANDER_SETTINGS& Settings() const; + /** + * Function Meanders() + * + * @return set of meander shapes for this line + */ + std::vector& Meanders() + { + return m_meanders; + } - private: + /** + * Function CheckSelfIntersections() + * + * Checks if the given shape is intersecting with any other meander in + * the current line. + * @param aShape the shape to check + * @param aClearance clearance value + * @return true, if the meander shape is not colliding + */ + bool CheckSelfIntersections ( PNS_MEANDER_SHAPE* aShape, int aClearance ); - VECTOR2I m_last; - - PNS_MEANDER_PLACER_BASE *m_placer; - std::vector m_meanders; - - bool m_dual; - int m_width; - int m_baselineOffset; + /** + * Function Settings() + * + * @return the current meandering settings. + */ + const PNS_MEANDER_SETTINGS& Settings() const; + +private: + VECTOR2I m_last; + + PNS_MEANDER_PLACER_BASE* m_placer; + std::vector m_meanders; + + bool m_dual; + int m_width; + int m_baselineOffset; }; #endif // __PNS_MEANDER_H diff --git a/pcbnew/router/pns_meander_placer.cpp b/pcbnew/router/pns_meander_placer.cpp index e0875309d1..6b421d2d65 100644 --- a/pcbnew/router/pns_meander_placer.cpp +++ b/pcbnew/router/pns_meander_placer.cpp @@ -33,7 +33,7 @@ PNS_MEANDER_PLACER::PNS_MEANDER_PLACER( PNS_ROUTER* aRouter ) : - PNS_MEANDER_PLACER_BASE ( aRouter ) + PNS_MEANDER_PLACER_BASE( aRouter ) { m_world = NULL; m_currentNode = NULL; @@ -41,11 +41,11 @@ PNS_MEANDER_PLACER::PNS_MEANDER_PLACER( PNS_ROUTER* aRouter ) : } -PNS_MEANDER_PLACER::~PNS_MEANDER_PLACER( ) +PNS_MEANDER_PLACER::~PNS_MEANDER_PLACER() { - } + PNS_NODE* PNS_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const { if( !m_currentNode ) @@ -54,73 +54,76 @@ PNS_NODE* PNS_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const return m_currentNode; } + bool PNS_MEANDER_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p; if( !aStartItem || !aStartItem->OfKind( PNS_ITEM::SEGMENT ) ) { - Router( )->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); + Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); return false; } - m_initialSegment = static_cast( aStartItem ); + m_initialSegment = static_cast( aStartItem ); - p = m_initialSegment->Seg( ).NearestPoint( aP ); + p = m_initialSegment->Seg().NearestPoint( aP ); m_originLine = NULL; m_currentNode = NULL; m_currentStart = p; - m_world = Router( )->GetWorld( )->Branch( ); + m_world = Router()->GetWorld()->Branch(); m_originLine = m_world->AssembleLine( m_initialSegment ); PNS_TOPOLOGY topo( m_world ); m_tunedPath = topo.AssembleTrivialPath( m_initialSegment ); m_world->Remove( m_originLine ); - - m_currentWidth = m_originLine->Width( ); + + m_currentWidth = m_originLine->Width(); m_currentEnd = VECTOR2I( 0, 0 ); - + return true; } -int PNS_MEANDER_PLACER::origPathLength( ) const +int PNS_MEANDER_PLACER::origPathLength() const { int total = 0; - BOOST_FOREACH( const PNS_ITEM *item, m_tunedPath.CItems( ) ) + BOOST_FOREACH( const PNS_ITEM* item, m_tunedPath.CItems() ) { - if( const PNS_LINE *l = dyn_cast( item ) ) + if( const PNS_LINE* l = dyn_cast( item ) ) { - total += l->CLine( ).Length( ); + total += l->CLine().Length(); } } return total; } + bool PNS_MEANDER_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - return doMove ( aP, aEndItem, m_settings.m_targetLength ); + return doMove( aP, aEndItem, m_settings.m_targetLength ); } + bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTargetLength ) { SHAPE_LINE_CHAIN pre, tuned, post; - if(m_currentNode) + if( m_currentNode ) delete m_currentNode; - m_currentNode = m_world->Branch( ); + m_currentNode = m_world->Branch(); - cutTunedLine ( m_originLine->CLine( ), m_currentStart, aP, pre, tuned, post ); + cutTunedLine( m_originLine->CLine(), m_currentStart, aP, pre, tuned, post ); m_result = PNS_MEANDERED_LINE( this, false ); m_result.SetWidth( m_originLine->Width() ); m_result.SetBaselineOffset( 0 ); - + for( int i = 0; i < tuned.SegmentCount(); i++ ) { const SEG s = tuned.CSegment( i ); @@ -128,43 +131,43 @@ bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTa m_result.MeanderSegment( s ); m_result.AddCorner( s.B ); } - - int lineLen = origPathLength( ); + + int lineLen = origPathLength(); m_lastLength = lineLen; m_lastStatus = TUNED; - if( compareWithTollerance ( lineLen, aTargetLength, m_settings.m_lengthTollerance ) > 0 ) + if( compareWithTolerance( lineLen, aTargetLength, m_settings.m_lengthTolerance ) > 0 ) { m_lastStatus = TOO_LONG; } else { - m_lastLength = lineLen - tuned.Length( ); - tuneLineLength( m_result, aTargetLength - lineLen ); + m_lastLength = lineLen - tuned.Length(); + tuneLineLength( m_result, aTargetLength - lineLen ); } - BOOST_FOREACH ( const PNS_ITEM *item, m_tunedPath.CItems( ) ) + BOOST_FOREACH ( const PNS_ITEM* item, m_tunedPath.CItems() ) { - if ( const PNS_LINE *l = dyn_cast( item ) ) + if( const PNS_LINE* l = dyn_cast( item ) ) { - Router( )->DisplayDebugLine( l->CLine( ), 5, 10000 ); + Router()->DisplayDebugLine( l->CLine(), 5, 10000 ); } } - if (m_lastStatus != TOO_LONG) + if( m_lastStatus != TOO_LONG ) { - tuned.Clear( ); + tuned.Clear(); - BOOST_FOREACH ( PNS_MEANDER_SHAPE *m, m_result.Meanders() ) + BOOST_FOREACH( PNS_MEANDER_SHAPE* m, m_result.Meanders() ) { if( m->Type() != MT_EMPTY ) { - tuned.Append ( m->CLine(0) ); - } + tuned.Append ( m->CLine( 0 ) ); + } } - m_lastLength += tuned.Length( ); + m_lastLength += tuned.Length(); - int comp = compareWithTollerance( m_lastLength - aTargetLength, 0, m_settings.m_lengthTollerance ); + int comp = compareWithTolerance( m_lastLength - aTargetLength, 0, m_settings.m_lengthTolerance ); if( comp > 0 ) m_lastStatus = TOO_LONG; @@ -172,14 +175,13 @@ bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTa m_lastStatus = TOO_SHORT; else m_lastStatus = TUNED; - } - m_finalShape.Clear( ); + m_finalShape.Clear(); m_finalShape.Append( pre ); m_finalShape.Append( tuned ); m_finalShape.Append( post ); - m_finalShape.Simplify( ); + m_finalShape.Simplify(); return true; } @@ -187,50 +189,54 @@ bool PNS_MEANDER_PLACER::doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTa bool PNS_MEANDER_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - m_currentTrace = PNS_LINE( *m_originLine, m_finalShape ); - m_currentNode->Add ( &m_currentTrace ); + m_currentTrace = PNS_LINE( *m_originLine, m_finalShape ); + m_currentNode->Add( &m_currentTrace ); - Router( )->CommitRouting( m_currentNode ); + Router()->CommitRouting( m_currentNode ); return true; } - -bool PNS_MEANDER_PLACER::CheckFit( PNS_MEANDER_SHAPE *aShape ) + + +bool PNS_MEANDER_PLACER::CheckFit( PNS_MEANDER_SHAPE* aShape ) { PNS_LINE l( *m_originLine, aShape->CLine( 0 ) ); - + if( m_currentNode->CheckColliding( &l ) ) return false; - int w = aShape->Width( ); + int w = aShape->Width(); int clearance = w + m_settings.m_spacing; return m_result.CheckSelfIntersections( aShape, clearance ); } - + const PNS_ITEMSET PNS_MEANDER_PLACER::Traces() { m_currentTrace = PNS_LINE( *m_originLine, m_finalShape ); return PNS_ITEMSET( &m_currentTrace ); } + const VECTOR2I& PNS_MEANDER_PLACER::CurrentEnd() const { return m_currentEnd; } - + + int PNS_MEANDER_PLACER::CurrentNet() const { - return m_initialSegment->Net( ); + return m_initialSegment->Net(); } + int PNS_MEANDER_PLACER::CurrentLayer() const { - return m_initialSegment->Layers( ).Start( ); + return m_initialSegment->Layers().Start(); } -const wxString PNS_MEANDER_PLACER::TuningInfo( ) const +const wxString PNS_MEANDER_PLACER::TuningInfo() const { wxString status; @@ -240,10 +246,10 @@ const wxString PNS_MEANDER_PLACER::TuningInfo( ) const status = _( "Too long: " ); break; case TOO_SHORT: - status = _(" Too short: " ); + status = _( "Too short: " ); break; case TUNED: - status = _(" Tuned: " ); + status = _( "Tuned: " ); break; default: return _( "?" ); @@ -252,11 +258,12 @@ const wxString PNS_MEANDER_PLACER::TuningInfo( ) const status += LengthDoubleToString( (double) m_lastLength, false ); status += "/"; status += LengthDoubleToString( (double) m_settings.m_targetLength, false ); - + return status; } -PNS_MEANDER_PLACER::TUNING_STATUS PNS_MEANDER_PLACER::TuningStatus( ) const + +PNS_MEANDER_PLACER::TUNING_STATUS PNS_MEANDER_PLACER::TuningStatus() const { return m_lastStatus; } diff --git a/pcbnew/router/pns_meander_placer.h b/pcbnew/router/pns_meander_placer.h index 98c6670629..227a0ce291 100644 --- a/pcbnew/router/pns_meander_placer.h +++ b/pcbnew/router/pns_meander_placer.h @@ -61,16 +61,16 @@ public: /// @copydoc PNS_PLACEMENT_ALGO::CurrentNode() PNS_NODE* CurrentNode( bool aLoopsRemoved = false ) const; - + /// @copydoc PNS_PLACEMENT_ALGO::Traces() const PNS_ITEMSET Traces(); /// @copydoc PNS_PLACEMENT_ALGO::CurrentEnd() const VECTOR2I& CurrentEnd() const; - + /// @copydoc PNS_PLACEMENT_ALGO::CurrentNet() int CurrentNet() const; - + /// @copydoc PNS_PLACEMENT_ALGO::CurrentLayer() int CurrentLayer() const; @@ -84,12 +84,12 @@ public: bool CheckFit ( PNS_MEANDER_SHAPE* aShape ); protected: - + bool doMove( const VECTOR2I& aP, PNS_ITEM* aEndItem, int aTargetLength ); - void setWorld ( PNS_NODE* aWorld ); - - virtual int origPathLength () const; + void setWorld( PNS_NODE* aWorld ); + + virtual int origPathLength() const; ///> pointer to world to search colliding items PNS_NODE* m_world; @@ -106,7 +106,7 @@ protected: SHAPE_LINE_CHAIN m_finalShape; PNS_MEANDERED_LINE m_result; - PNS_SEGMENT *m_initialSegment; + PNS_SEGMENT* m_initialSegment; int m_lastLength; TUNING_STATUS m_lastStatus; diff --git a/pcbnew/router/pns_meander_placer_base.cpp b/pcbnew/router/pns_meander_placer_base.cpp index c35204a9d6..291a33a763 100644 --- a/pcbnew/router/pns_meander_placer_base.cpp +++ b/pcbnew/router/pns_meander_placer_base.cpp @@ -25,35 +25,38 @@ PNS_MEANDER_PLACER_BASE::PNS_MEANDER_PLACER_BASE( PNS_ROUTER* aRouter ) : PNS_PLACEMENT_ALGO( aRouter ) { +} -}; -PNS_MEANDER_PLACER_BASE::~PNS_MEANDER_PLACER_BASE( ) +PNS_MEANDER_PLACER_BASE::~PNS_MEANDER_PLACER_BASE() { +} -}; void PNS_MEANDER_PLACER_BASE::AmplitudeStep( int aSign ) { int a = m_settings.m_maxAmplitude + aSign * m_settings.m_step; a = std::max( a, m_settings.m_minAmplitude ); - + m_settings.m_maxAmplitude = a; } + void PNS_MEANDER_PLACER_BASE::SpacingStep( int aSign ) { int s = m_settings.m_spacing + aSign * m_settings.m_step; s = std::max( s, 2 * m_currentWidth ); - + m_settings.m_spacing = s; } + void PNS_MEANDER_PLACER_BASE::UpdateSettings( const PNS_MEANDER_SETTINGS& aSettings ) { m_settings = aSettings; } + void PNS_MEANDER_PLACER_BASE::cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, const VECTOR2I& aTuneStart, const VECTOR2I& aCursorPos, @@ -73,47 +76,48 @@ void PNS_MEANDER_PLACER_BASE::cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, if( i_start > i_end ) { - l = l.Reverse( ); + l = l.Reverse(); i_start = l.Find( m ); i_end = l.Find( n ); } aPre = l.Slice( 0, i_start ); - aPost = l.Slice( i_end, -1 ); + aPost = l.Slice( i_end, -1 ); aTuned = l.Slice( i_start, i_end ); - aTuned.Simplify( ); + aTuned.Simplify(); } + void PNS_MEANDER_PLACER_BASE::tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aElongation ) { - int remaining = aElongation; + int remaining = aElongation; bool finished = false; - BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + BOOST_FOREACH( PNS_MEANDER_SHAPE* m, aTuned.Meanders() ) { - if(m->Type() != MT_CORNER ) + if( m->Type() != MT_CORNER ) { - if(remaining >= 0) + if( remaining >= 0 ) remaining -= m->MaxTunableLength() - m->BaselineLength(); - if(remaining < 0) + if( remaining < 0 ) { - if(!finished) - { - PNS_MEANDER_TYPE newType; + if( !finished ) + { + PNS_MEANDER_TYPE newType; - if ( m->Type() == MT_START || m->Type() == MT_SINGLE) - newType = MT_SINGLE; - else - newType = MT_FINISH; + if( m->Type() == MT_START || m->Type() == MT_SINGLE ) + newType = MT_SINGLE; + else + newType = MT_FINISH; - m->SetType ( newType ); - m->Recalculate( ); - - finished = true; - } else { - m->MakeEmpty(); - } + m->SetType( newType ); + m->Recalculate(); + + finished = true; + } else { + m->MakeEmpty(); + } } } } @@ -121,7 +125,7 @@ void PNS_MEANDER_PLACER_BASE::tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aE remaining = aElongation; int meanderCount = 0; - BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + BOOST_FOREACH(PNS_MEANDER_SHAPE* m, aTuned.Meanders()) { if( m->Type() != MT_CORNER && m->Type() != MT_EMPTY ) { @@ -137,31 +141,32 @@ void PNS_MEANDER_PLACER_BASE::tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aE if( meanderCount ) balance = -remaining / meanderCount; - - if (balance >= 0) + + if( balance >= 0 ) { - BOOST_FOREACH(PNS_MEANDER_SHAPE *m, aTuned.Meanders()) + BOOST_FOREACH( PNS_MEANDER_SHAPE* m, aTuned.Meanders() ) { - if(m->Type() != MT_CORNER && m->Type() != MT_EMPTY) + if( m->Type() != MT_CORNER && m->Type() != MT_EMPTY ) { - m->Resize ( std::max( m->Amplitude() - balance / 2, m_settings.m_minAmplitude ) ); + m->Resize( std::max( m->Amplitude() - balance / 2, m_settings.m_minAmplitude ) ); } } - } } -const PNS_MEANDER_SETTINGS& PNS_MEANDER_PLACER_BASE::MeanderSettings( ) const + +const PNS_MEANDER_SETTINGS& PNS_MEANDER_PLACER_BASE::MeanderSettings() const { return m_settings; } -int PNS_MEANDER_PLACER_BASE::compareWithTollerance ( int aValue, int aExpected, int aTollerance ) const + +int PNS_MEANDER_PLACER_BASE::compareWithTolerance( int aValue, int aExpected, int aTolerance ) const { - if( aValue < aExpected - aTollerance ) + if( aValue < aExpected - aTolerance ) return -1; - else if( aValue > aExpected + aTollerance ) + else if( aValue > aExpected + aTolerance ) return 1; else return 0; -} \ No newline at end of file +} diff --git a/pcbnew/router/pns_meander_placer_base.h b/pcbnew/router/pns_meander_placer_base.h index ac94b97a67..070e322d3f 100644 --- a/pcbnew/router/pns_meander_placer_base.h +++ b/pcbnew/router/pns_meander_placer_base.h @@ -54,7 +54,7 @@ public: }; PNS_MEANDER_PLACER_BASE( PNS_ROUTER* aRouter ); - virtual ~PNS_MEANDER_PLACER_BASE( ); + virtual ~PNS_MEANDER_PLACER_BASE(); /** * Function TuningInfo() @@ -62,15 +62,15 @@ public: * Returns a string describing the status and length of the * tuned traces. */ - virtual const wxString TuningInfo( ) const = 0; - + virtual const wxString TuningInfo() const = 0; + /** * Function TuningStatus() * * Returns the tuning status (too short, too long, etc.) * of the trace(s) being tuned. */ - virtual TUNING_STATUS TuningStatus( ) const = 0; + virtual TUNING_STATUS TuningStatus() const = 0; /** * Function AmplitudeStep() @@ -79,7 +79,7 @@ public: * @param aSign direction (negative = decrease, positive = increase). */ virtual void AmplitudeStep( int aSign ); - + /** * Function SpacingStep() * @@ -95,7 +95,7 @@ public: * @return the settings */ virtual const PNS_MEANDER_SETTINGS& MeanderSettings() const; - + /* * Function UpdateSettings() * @@ -103,7 +103,7 @@ public: * @param aSettings the settings */ virtual void UpdateSettings( const PNS_MEANDER_SETTINGS& aSettings); - + /** * Function CheckFit() * @@ -113,18 +113,16 @@ public: * @param aShape the shape to check * @return true if the shape fits */ - virtual bool CheckFit ( PNS_MEANDER_SHAPE* aShape ) - { + virtual bool CheckFit( PNS_MEANDER_SHAPE* aShape ) + { return false; } - - protected: - + /** * Function cutTunedLine() - * + * * Extracts the part of a track to be meandered, depending on the * starting point and the cursor position. * @param aOrigin the original line @@ -144,22 +142,22 @@ protected: /** * Function tuneLineLength() * - * Takes a set of meanders in aTuned and tunes their length to + * Takes a set of meanders in aTuned and tunes their length to * extend the original line length by aElongation. */ void tuneLineLength( PNS_MEANDERED_LINE& aTuned, int aElongation ); /** - * Function compareWithTollerance() + * Function compareWithTolerance() * - * Compares aValue against aExpected with given tollerance. + * Compares aValue against aExpected with given tolerance. */ - int compareWithTollerance ( int aValue, int aExpected, int aTollerance = 0 ) const; + int compareWithTolerance ( int aValue, int aExpected, int aTolerance = 0 ) const; ///> width of the meandered trace(s) int m_currentWidth; ///> meandering settings - PNS_MEANDER_SETTINGS m_settings; + PNS_MEANDER_SETTINGS m_settings; ///> current end point VECTOR2I m_currentEnd; }; diff --git a/pcbnew/router/pns_meander_skew_placer.cpp b/pcbnew/router/pns_meander_skew_placer.cpp index 5904dcd07d..2b670a5db9 100644 --- a/pcbnew/router/pns_meander_skew_placer.cpp +++ b/pcbnew/router/pns_meander_skew_placer.cpp @@ -38,30 +38,31 @@ PNS_MEANDER_SKEW_PLACER::PNS_MEANDER_SKEW_PLACER ( PNS_ROUTER* aRouter ) : { } + PNS_MEANDER_SKEW_PLACER::~PNS_MEANDER_SKEW_PLACER( ) { - } + bool PNS_MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { VECTOR2I p; if( !aStartItem || !aStartItem->OfKind( PNS_ITEM::SEGMENT ) ) { - Router( )->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) ); + Router()->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) ); return false; } - m_initialSegment = static_cast( aStartItem ); + m_initialSegment = static_cast( aStartItem ); - p = m_initialSegment->Seg( ).NearestPoint( aP ); + p = m_initialSegment->Seg().NearestPoint( aP ); m_originLine = NULL; m_currentNode = NULL; m_currentStart = p; - m_world = Router( )->GetWorld( )->Branch( ); + m_world = Router()->GetWorld( )->Branch(); m_originLine = m_world->AssembleLine( m_initialSegment ); PNS_TOPOLOGY topo( m_world ); @@ -75,18 +76,17 @@ bool PNS_MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) return false; } - m_originPair.SetGap ( Router()->Sizes().DiffPairGap() ); if( !m_originPair.PLine().SegmentCount() || !m_originPair.NLine().SegmentCount() ) return false; - - m_tunedPathP = topo.AssembleTrivialPath ( m_originPair.PLine().GetLink(0) ); - m_tunedPathN = topo.AssembleTrivialPath ( m_originPair.NLine().GetLink(0) ); + + m_tunedPathP = topo.AssembleTrivialPath ( m_originPair.PLine().GetLink( 0 ) ); + m_tunedPathN = topo.AssembleTrivialPath ( m_originPair.NLine().GetLink( 0 ) ); m_world->Remove( m_originLine ); - + m_currentWidth = m_originLine->Width( ); m_currentEnd = VECTOR2I( 0, 0 ); @@ -94,55 +94,58 @@ bool PNS_MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, PNS_ITEM* aStartItem ) m_coupledLength = itemsetLength ( m_tunedPathN ); else m_coupledLength = itemsetLength ( m_tunedPathP ); - + return true; } -int PNS_MEANDER_SKEW_PLACER::origPathLength( ) const +int PNS_MEANDER_SKEW_PLACER::origPathLength( ) const { return itemsetLength ( m_tunedPath ); } + int PNS_MEANDER_SKEW_PLACER::itemsetLength( const PNS_ITEMSET& aSet ) const { int total = 0; - BOOST_FOREACH( const PNS_ITEM *item, aSet.CItems( ) ) + BOOST_FOREACH( const PNS_ITEM* item, aSet.CItems() ) { - if( const PNS_LINE *l = dyn_cast( item ) ) + if( const PNS_LINE* l = dyn_cast( item ) ) { - total += l->CLine( ).Length( ); + total += l->CLine().Length(); } } return total; } -int PNS_MEANDER_SKEW_PLACER::currentSkew () const + +int PNS_MEANDER_SKEW_PLACER::currentSkew() const { return m_lastLength - m_coupledLength; } + bool PNS_MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { - return doMove ( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew ); + return doMove( aP, aEndItem, m_coupledLength + m_settings.m_targetSkew ); } -const wxString PNS_MEANDER_SKEW_PLACER::TuningInfo( ) const +const wxString PNS_MEANDER_SKEW_PLACER::TuningInfo() const { wxString status; - switch ( m_lastStatus ) + switch( m_lastStatus ) { case TOO_LONG: status = _( "Too long: skew " ); break; case TOO_SHORT: - status = _(" Too short: skew " ); + status = _( "Too short: skew " ); break; case TUNED: - status = _(" Tuned: skew " ); + status = _( "Tuned: skew " ); break; default: return _( "?" ); @@ -151,7 +154,7 @@ const wxString PNS_MEANDER_SKEW_PLACER::TuningInfo( ) const status += LengthDoubleToString( (double) m_lastLength - m_coupledLength, false ); status += "/"; status += LengthDoubleToString( (double) m_settings.m_targetSkew, false ); - + return status; } diff --git a/pcbnew/router/pns_meander_skew_placer.h b/pcbnew/router/pns_meander_skew_placer.h index a7f3a90773..7cb303c15d 100644 --- a/pcbnew/router/pns_meander_skew_placer.h +++ b/pcbnew/router/pns_meander_skew_placer.h @@ -37,7 +37,6 @@ class PNS_ROUTER_BASE; class PNS_MEANDER_SKEW_PLACER : public PNS_MEANDER_PLACER { public: - PNS_MEANDER_SKEW_PLACER( PNS_ROUTER* aRouter ); ~PNS_MEANDER_SKEW_PLACER(); @@ -51,13 +50,13 @@ public: const wxString TuningInfo() const; private: - + int currentSkew( ) const; int itemsetLength( const PNS_ITEMSET& aSet ) const; int origPathLength () const; - PNS_DIFF_PAIR m_originPair; + PNS_DIFF_PAIR m_originPair; PNS_ITEMSET m_tunedPath, m_tunedPathP, m_tunedPathN; int m_coupledLength; diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index a553871d7f..08e7d75a1c 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -64,7 +64,7 @@ PNS_NODE::PNS_NODE() 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" ); @@ -103,7 +103,7 @@ 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; @@ -175,8 +175,8 @@ struct PNS_NODE::OBSTACLE_VISITOR ///> number of items found so far int m_matchCount; - ///> additional clearance - int m_extraClearance; + ///> additional clearance + int m_extraClearance; OBSTACLE_VISITOR( PNS_NODE::OBSTACLES& aTab, const PNS_ITEM* aItem, int aKindMask ) : m_tab( aTab ), @@ -184,11 +184,11 @@ struct PNS_NODE::OBSTACLE_VISITOR m_kindMask( aKindMask ), m_limitCount( -1 ), m_matchCount( 0 ), - m_extraClearance( 0 ) + m_extraClearance( 0 ) { - if( aItem->Kind() == PNS_ITEM::LINE ) + if( aItem->Kind() == PNS_ITEM::LINE ) m_extraClearance += static_cast( aItem )->Width() / 2; - } + } void SetCountLimit( int aLimit ) { @@ -429,7 +429,7 @@ bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, i else clearance = GetClearance( aItemA, aItemB ); - // fixme: refactor + // fixme: refactor if( aItemA->Kind() == PNS_ITEM::LINE ) clearance += static_cast( aItemA )->Width() / 2; if( aItemB->Kind() == PNS_ITEM::LINE ) @@ -533,7 +533,7 @@ void PNS_NODE::addLine( PNS_LINE* aLine, bool aAllowRedundant ) m_index->Add( pseg ); } - } + } } } @@ -548,7 +548,7 @@ void PNS_NODE::addSegment( PNS_SEGMENT* aSeg, bool aAllowRedundant ) if( !aAllowRedundant && findRedundantSegment ( aSeg ) ) return; - + aSeg->SetOwner( this ); linkJoint( aSeg->Seg().A, aSeg->Layers(), aSeg->Net(), aSeg ); @@ -619,13 +619,13 @@ void PNS_NODE::removeLine( PNS_LINE* aLine ) { std::vector* segRefs = aLine->LinkedSegments(); - if(! aLine->SegmentCount() ) + if( !aLine->SegmentCount() ) return; - assert (segRefs != NULL); - assert (aLine->Owner()); - - if ( (int) segRefs->size() != aLine->SegmentCount() ) + 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()); } @@ -657,7 +657,7 @@ void PNS_NODE::removeVia( PNS_VIA* aVia ) tag.net = net; tag.pos = p; - bool split; + bool split; do { split = false; @@ -678,7 +678,7 @@ void PNS_NODE::removeVia( PNS_VIA* aVia ) } } } while( split ); - + // and re-link them, using the former via's link list BOOST_FOREACH(PNS_ITEM* item, links) { @@ -686,7 +686,7 @@ void PNS_NODE::removeVia( PNS_VIA* aVia ) linkJoint ( p, item->Layers(), net, item ); } - doRemove( aVia ); + doRemove( aVia ); } @@ -723,9 +723,10 @@ void PNS_NODE::Remove( PNS_ITEM* aItem ) } } -void PNS_NODE::Remove ( PNS_LINE& aLine ) + +void PNS_NODE::Remove( PNS_LINE& aLine ) { - removeLine ( &aLine ); + removeLine( &aLine ); } @@ -754,7 +755,7 @@ void PNS_NODE::followLine( PNS_SEGMENT* aCurrent, bool aScanDirection, int& aPos } aSegments[aPos] = aCurrent; - + aPos += ( aScanDirection ? 1 : -1 ); if( !jt->IsLineCorner() || aPos < 0 || aPos == aLimit ) @@ -763,7 +764,7 @@ void PNS_NODE::followLine( PNS_SEGMENT* aCurrent, bool aScanDirection, int& aPos aCurrent = jt->NextSegment( aCurrent ); prevReversed = - ( jt->Pos() == (aScanDirection ? aCurrent->Seg().B : aCurrent->Seg().A ) ); + ( jt->Pos() == ( aScanDirection ? aCurrent->Seg().B : aCurrent->Seg().A ) ); } } @@ -786,10 +787,10 @@ PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex) pl->SetOwner( this ); followLine( aSeg, false, i_start, MaxVerts, corners, segs, guardHit ); - + if( !guardHit ) followLine( aSeg, true, i_end, MaxVerts, corners, segs, guardHit ); - + int n = 0; PNS_SEGMENT* prev_seg = NULL; @@ -799,7 +800,7 @@ PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex) const VECTOR2I& p = corners[i]; pl->Line().Append( p ); - + if( segs[i] && prev_seg != segs[i] ) { pl->LinkSegment( segs[i] ); @@ -815,7 +816,7 @@ PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex) assert( pl->SegmentCount() != 0 ); assert( pl->SegmentCount() == (int) pl->LinkedSegments()->size() ); - + return pl; } @@ -855,7 +856,7 @@ void PNS_NODE::MapConnectivity ( PNS_JOINT* aStart, std::vector& aFo processed.insert( next ); searchQueue.push_back( next ); } - } + } } } @@ -865,8 +866,6 @@ void PNS_NODE::MapConnectivity ( PNS_JOINT* aStart, std::vector& aFo #endif - - int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& aA, PNS_JOINT& aB, std::vector& aLines ) { BOOST_FOREACH( PNS_ITEM* item, aA.LinkList() ) @@ -877,7 +876,7 @@ int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& aA, PNS_JOINT& aB, std::vector< PNS_LINE* line = AssembleLine( seg ); PNS_JOINT j_start, j_end; - + FindLineEnds( line, j_start, j_end ); int id_start = line->CLine().Find( aA.Pos() ); @@ -1020,13 +1019,13 @@ void PNS_NODE::Dump( bool aLong ) } if( !isRoot() ) - { + { for( i = m_root->m_items.begin(); i != m_root->m_items.end(); i++ ) { if( (*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides( *i ) ) all_segs.insert( static_cast(*i) ); } - } + } JOINT_MAP::iterator j; @@ -1153,7 +1152,7 @@ void PNS_NODE::AllItemsInNet( int aNet, std::set& aItems ) BOOST_FOREACH( PNS_ITEM*item, *l_cur ) aItems.insert( item ); } - + if( !isRoot() ) { PNS_INDEX::NET_ITEMS_LIST* l_root = m_root->m_index->GetItemsForNet( aNet ); @@ -1201,7 +1200,7 @@ int PNS_NODE::RemoveByMarker( int aMarker ) } for( std::list::const_iterator i = garbage.begin(), end = garbage.end(); i != end; ++i ) - { + { Remove( *i ); } @@ -1209,7 +1208,7 @@ int PNS_NODE::RemoveByMarker( int aMarker ) } -PNS_SEGMENT* PNS_NODE::findRedundantSegment ( PNS_SEGMENT *aSeg ) +PNS_SEGMENT* PNS_NODE::findRedundantSegment( PNS_SEGMENT* aSeg ) { PNS_JOINT* jtStart = FindJoint ( aSeg->Seg().A, aSeg ); @@ -1221,23 +1220,23 @@ PNS_SEGMENT* PNS_NODE::findRedundantSegment ( PNS_SEGMENT *aSeg ) 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() && + + if( seg2->Layers().Start() == aSeg->Layers().Start() && ( ( a1 == a2 && b1 == b2 ) || ( a1 == b2 && a2 == b1 ) ) ) return seg2; } } - + return NULL; } -void PNS_NODE::SetCollisionFilter ( PNS_COLLISION_FILTER *aFilter ) +void PNS_NODE::SetCollisionFilter( PNS_COLLISION_FILTER* aFilter ) { m_collisionFilter = aFilter; } diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index eb7b8b503e..fa3fcbba1c 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -55,10 +55,9 @@ public: virtual ~PNS_CLEARANCE_FUNC() {} virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) = 0; virtual void OverrideClearance (bool aEnable, int aNetA = 0, int aNetB = 0, int aClearance = 0) = 0; - }; -class PNS_PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC +class PNS_PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC { public: PNS_PCBNEW_CLEARANCE_FUNC( BOARD *aBoard ); @@ -297,7 +296,7 @@ public: * @param aOriginSegmentIndex index of aSeg in the resulting line * @return the line */ - PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg, int *aOriginSegmentIndex = NULL ); + PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg, int* aOriginSegmentIndex = NULL ); ///> Prints the contents and joints structure void Dump( bool aLong = false ); @@ -365,7 +364,7 @@ public: int FindByMarker( int aMarker, PNS_ITEMSET& aItems ); int RemoveByMarker( int aMarker ); - void SetCollisionFilter ( PNS_COLLISION_FILTER *aFilter ); + void SetCollisionFilter( PNS_COLLISION_FILTER* aFilter ); private: struct OBSTACLE_VISITOR; diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index f6b6def28c..0cebcd86ab 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -101,14 +101,14 @@ void PNS_COST_ESTIMATOR::Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ) bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, - double aLengthTollerance, - double aCornerTollerance ) const + double aLengthTolerance, + double aCornerTolerance ) const { 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 * aCornerTolerance && + aOther.m_lengthCost < m_lengthCost * aLengthTolerance ) return true; return false; @@ -224,27 +224,26 @@ void PNS_OPTIMIZER::ClearCache( bool aStaticOnly ) } } -class LINE_RESTRICTIONS + +class LINE_RESTRICTIONS { public: - LINE_RESTRICTIONS( ) {}; - ~LINE_RESTRICTIONS( ) {}; + LINE_RESTRICTIONS() {}; + ~LINE_RESTRICTIONS() {}; - void Build( PNS_NODE *aWorld, PNS_LINE *aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ); + void Build( PNS_NODE* aWorld, PNS_LINE* aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ); bool Check ( int aVertex1, int aVertex2, const SHAPE_LINE_CHAIN& aReplacement ); void Dump(); - private: - int allowedAngles ( PNS_NODE *aWorld, const PNS_LINE *aLine, const VECTOR2I& aP, bool aFirst ); + int allowedAngles( PNS_NODE* aWorld, const PNS_LINE* aLine, const VECTOR2I& aP, bool aFirst ); struct RVERTEX { - RVERTEX ( bool aRestricted, int aAllowedAngles ) : - restricted ( aRestricted ), - allowedAngles ( aAllowedAngles ) + RVERTEX ( bool aRestricted, int aAllowedAngles ) : + restricted( aRestricted ), + allowedAngles( aAllowedAngles ) { - } bool restricted; @@ -254,55 +253,54 @@ class LINE_RESTRICTIONS std::vector m_rs; }; + // fixme: use later -int LINE_RESTRICTIONS::allowedAngles ( PNS_NODE *aWorld, const PNS_LINE *aLine, const VECTOR2I& aP, bool aFirst ) +int LINE_RESTRICTIONS::allowedAngles( PNS_NODE* aWorld, const PNS_LINE* aLine, const VECTOR2I& aP, bool aFirst ) { PNS_JOINT* jt = aWorld->FindJoint( aP , aLine ); if( !jt ) return 0xff; - DIRECTION_45 dirs [8]; int n_dirs = 0; - BOOST_FOREACH ( const PNS_ITEM *item, jt->Links().CItems() ) + BOOST_FOREACH( const PNS_ITEM* item, jt->Links().CItems() ) { - if (item->OfKind (PNS_ITEM::VIA) || item->OfKind (PNS_ITEM::SOLID)) + if( item->OfKind( PNS_ITEM::VIA ) || item->OfKind( PNS_ITEM::SOLID ) ) return 0xff; - else if ( const PNS_SEGMENT *seg = dyn_cast ( item ) ) + else if( const PNS_SEGMENT* seg = dyn_cast( item ) ) { SEG s = seg->Seg(); - if (s.A != aP) + if( s.A != aP ) s.Reverse(); - if (n_dirs < 8) - dirs [ n_dirs++ ] = aFirst ? DIRECTION_45 ( s ) : DIRECTION_45 ( s ).Opposite(); + if( n_dirs < 8 ) + dirs[n_dirs++] = aFirst ? DIRECTION_45( s ) : DIRECTION_45( s ).Opposite(); } } - - const int angleMask = DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_STRAIGHT; int outputMask = 0xff; - - for (int d = 0; d < 8; d ++) + + for( int d = 0; d < 8; d++ ) { - DIRECTION_45 refDir( (DIRECTION_45::Directions) d ); - for (int i = 0; i < n_dirs; i++ ) + DIRECTION_45 refDir( ( DIRECTION_45::Directions ) d ); + + for( int i = 0; i < n_dirs; i++ ) { - if (! (refDir.Angle(dirs [ i ] ) & angleMask) ) + if( !(refDir.Angle( dirs[i] ) & angleMask ) ) outputMask &= ~refDir.Mask(); } } - DrawDebugDirs ( aP, outputMask, 3 ); + DrawDebugDirs( aP, outputMask, 3 ); return 0xff; } -void LINE_RESTRICTIONS::Build( PNS_NODE *aWorld, PNS_LINE *aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ) +void LINE_RESTRICTIONS::Build( PNS_NODE* aWorld, PNS_LINE* aOriginLine, const SHAPE_LINE_CHAIN& aLine, const BOX2I& aRestrictedArea, bool aRestrictedAreaEnable ) { const SHAPE_LINE_CHAIN& l = aLine; VECTOR2I v_prev; @@ -310,49 +308,56 @@ void LINE_RESTRICTIONS::Build( PNS_NODE *aWorld, PNS_LINE *aOriginLine, const SH m_rs.reserve( n ); - for (int i = 0; i < n; i++) + for( int i = 0; i < n; i++ ) { - const VECTOR2I &v = l.CPoint(i), v_next; - RVERTEX r ( false, 0xff ); + const VECTOR2I &v = l.CPoint( i ), v_next; + RVERTEX r( false, 0xff ); - if ( aRestrictedAreaEnable ) + if( aRestrictedAreaEnable ) { - bool exiting = ( i > 0 && aRestrictedArea.Contains( v_prev ) && !aRestrictedArea.Contains(v) ); - bool entering = false; + bool exiting = ( i > 0 && aRestrictedArea.Contains( v_prev ) && !aRestrictedArea.Contains( v ) ); + bool entering = false; - if( i != l.PointCount() - 1) + if( i != l.PointCount() - 1 ) { - const VECTOR2I& v_next = l.CPoint(i + 1); + const VECTOR2I& v_next = l.CPoint( i + 1 ); entering = ( !aRestrictedArea.Contains( v ) && aRestrictedArea.Contains( v_next ) ); } - if(entering) + if( entering ) { - const SEG& sp = l.CSegment(i); - r.allowedAngles = DIRECTION_45(sp).Mask(); - } else if (exiting) { - const SEG& sp = l.CSegment(i - 1); - r.allowedAngles = DIRECTION_45(sp).Mask(); - } else { - r.allowedAngles = (! aRestrictedArea.Contains ( v ) ) ? 0 : 0xff; + const SEG& sp = l.CSegment( i ); + r.allowedAngles = DIRECTION_45( sp ).Mask(); + } + else if( exiting ) + { + const SEG& sp = l.CSegment( i - 1 ); + r.allowedAngles = DIRECTION_45( sp ).Mask(); + } + else + { + r.allowedAngles = ( !aRestrictedArea.Contains( v ) ) ? 0 : 0xff; r.restricted = r.allowedAngles ? false : true; } } + v_prev = v; - m_rs.push_back(r); + m_rs.push_back( r ); } } + void LINE_RESTRICTIONS::Dump() { } -bool LINE_RESTRICTIONS::Check ( int aVertex1, int aVertex2, const SHAPE_LINE_CHAIN& aReplacement ) + +bool LINE_RESTRICTIONS::Check( int aVertex1, int aVertex2, const SHAPE_LINE_CHAIN& aReplacement ) { if( m_rs.empty( ) ) return true; - - for(int i = aVertex1; i <= aVertex2; i++) + + for( int i = aVertex1; i <= aVertex2; i++ ) if ( m_rs[i].restricted ) return false; @@ -361,18 +366,17 @@ bool LINE_RESTRICTIONS::Check ( int aVertex1, int aVertex2, const SHAPE_LINE_CHA int m1 = DIRECTION_45( aReplacement.CSegment( 0 ) ).Mask(); int m2; - if (aReplacement.SegmentCount() == 1) + + if( aReplacement.SegmentCount() == 1 ) m2 = m1; else - m2 = DIRECTION_45 ( aReplacement.CSegment( 1 ) ).Mask(); + m2 = DIRECTION_45( aReplacement.CSegment( 1 ) ).Mask(); - - return ((v1.allowedAngles & m1) != 0) && - ((v2.allowedAngles & m2) != 0); + return ( ( v1.allowedAngles & m1 ) != 0 ) && + ( ( v2.allowedAngles & m2 ) != 0 ); } - bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache ) { CACHE_VISITOR v( aItem, m_world, m_collisionKindMask ); @@ -464,7 +468,6 @@ bool PNS_OPTIMIZER::mergeObtuse( PNS_LINE* aLine ) s2opt = SEG( ip, s2.B ); } - if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) { SHAPE_LINE_CHAIN opt_path; @@ -802,7 +805,7 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, if(!connect.SegmentCount()) continue; - + int ang1 = dir_bkout.Angle( DIRECTION_45( connect.CSegment( 0 ) ) ); int ang2 = 0; @@ -872,7 +875,7 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, bool PNS_OPTIMIZER::runSmartPads( PNS_LINE* aLine ) { SHAPE_LINE_CHAIN& line = aLine->Line(); - + if( line.PointCount() < 3 ) return false; @@ -916,25 +919,27 @@ bool PNS_OPTIMIZER::fanoutCleanup( PNS_LINE* aLine ) 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 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; + bool endMatch = false; if(endPad) { endMatch = endPad->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ); - } else { + } + else + { endMatch = aLine->EndsWithVia(); } - + if( startMatch && endMatch && len < thr ) { - for(int i = 0; i < 2; i++ ) + for( int i = 0; i < 2; i++ ) { SHAPE_LINE_CHAIN l2 = DIRECTION_45().BuildInitialTrace( p_start, p_end, i ); PNS_LINE repl; @@ -951,97 +956,103 @@ bool PNS_OPTIMIZER::fanoutCleanup( PNS_LINE* aLine ) return false; } -int findCoupledVertices ( const VECTOR2I& aVertex, const SEG& aOrigSeg, const SHAPE_LINE_CHAIN& aCoupled, PNS_DIFF_PAIR *aPair, int *aIndices ) + +int findCoupledVertices( const VECTOR2I& aVertex, const SEG& aOrigSeg, const SHAPE_LINE_CHAIN& aCoupled, PNS_DIFF_PAIR* aPair, int* aIndices ) { - int count = 0; + int count = 0; for ( int i = 0; i < aCoupled.SegmentCount(); i++ ) { - SEG s = aCoupled.CSegment(i); + SEG s = aCoupled.CSegment( i ); VECTOR2I projOverCoupled = s.LineProject ( aVertex ); - if( s.ApproxParallel ( aOrigSeg ) ) { int64_t dist = ( projOverCoupled - aVertex ).EuclideanNorm() - aPair->Width(); - - if( aPair->GapConstraint().Matches(dist) ) + + if( aPair->GapConstraint().Matches( dist ) ) { *aIndices++ = i; count++; } } } - + return count; } -bool verifyDpBypass ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aNewRef, const SHAPE_LINE_CHAIN& aNewCoupled ) + +bool verifyDpBypass( PNS_NODE* aNode, PNS_DIFF_PAIR* aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aNewRef, const SHAPE_LINE_CHAIN& aNewCoupled ) { PNS_LINE refLine ( aRefIsP ? aPair->PLine() : aPair->NLine(), aNewRef ); PNS_LINE coupledLine ( aRefIsP ? aPair->NLine() : aPair->PLine(), aNewCoupled ); - - if ( aNode->CheckColliding( &refLine, &coupledLine, PNS_ITEM::ANY, aPair->Gap() - 10 ) ) + + if( aNode->CheckColliding( &refLine, &coupledLine, PNS_ITEM::ANY, aPair->Gap() - 10 ) ) return false; - if ( aNode->CheckColliding ( &refLine ) ) + if( aNode->CheckColliding ( &refLine ) ) return false; - if ( aNode->CheckColliding ( &coupledLine ) ) + if( aNode->CheckColliding ( &coupledLine ) ) return false; return true; } -bool coupledBypass ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aRef, const SHAPE_LINE_CHAIN& aRefBypass, const SHAPE_LINE_CHAIN& aCoupled, SHAPE_LINE_CHAIN& aNewCoupled ) + +bool coupledBypass( PNS_NODE* aNode, PNS_DIFF_PAIR* aPair, bool aRefIsP, const SHAPE_LINE_CHAIN& aRef, const SHAPE_LINE_CHAIN& aRefBypass, const SHAPE_LINE_CHAIN& aCoupled, SHAPE_LINE_CHAIN& aNewCoupled ) { int vStartIdx[1024]; // fixme: possible overflow - int nStarts = findCoupledVertices ( aRefBypass.CPoint(0), aRefBypass.CSegment(0), aCoupled, aPair, vStartIdx ); - DIRECTION_45 dir( aRefBypass.CSegment(0) ); - + int nStarts = findCoupledVertices( aRefBypass.CPoint( 0 ), aRefBypass.CSegment( 0 ), aCoupled, aPair, vStartIdx ); + DIRECTION_45 dir( aRefBypass.CSegment( 0 ) ); + int64_t bestLength = -1; bool found = false; SHAPE_LINE_CHAIN bestBypass; int si, ei; - for(int i=0; i< nStarts ;i++) - for ( int j = 1; j < aCoupled.PointCount() - 1; j++) + for( int i=0; i< nStarts; i++ ) + { + for( int j = 1; j < aCoupled.PointCount() - 1; j++ ) { int delta = std::abs ( vStartIdx[i] - j ); - if(delta > 1) + + if( delta > 1 ) { const VECTOR2I& vs = aCoupled.CPoint( vStartIdx[i] ); SHAPE_LINE_CHAIN bypass = dir.BuildInitialTrace( vs, aCoupled.CPoint(j), dir.IsDiagonal() ); - int64_t coupledLength = aPair->CoupledLength ( aRef, bypass ); - + int64_t coupledLength = aPair->CoupledLength( aRef, bypass ); + SHAPE_LINE_CHAIN newCoupled = aCoupled; si = vStartIdx[i]; ei = j; - + if(si < ei) newCoupled.Replace( si, ei, bypass ); else newCoupled.Replace( ei, si, bypass.Reverse() ); - if(coupledLength > bestLength && verifyDpBypass ( aNode, aPair, aRefIsP, aRef, newCoupled) ) + if(coupledLength > bestLength && verifyDpBypass( aNode, aPair, aRefIsP, aRef, newCoupled) ) { bestBypass = newCoupled; - bestLength = coupledLength; + bestLength = coupledLength; found = true; } } } + } - if(found) + if( found ) aNewCoupled = bestBypass; return found; } -bool checkDpColliding ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aIsP, const SHAPE_LINE_CHAIN& aPath ) + +bool checkDpColliding( PNS_NODE* aNode, PNS_DIFF_PAIR* aPair, bool aIsP, const SHAPE_LINE_CHAIN& aPath ) { PNS_LINE tmp ( aIsP ? aPair->PLine() : aPair->NLine(), aPath ); @@ -1049,16 +1060,16 @@ bool checkDpColliding ( PNS_NODE *aNode, PNS_DIFF_PAIR *aPair, bool aIsP, const } -bool PNS_OPTIMIZER::mergeDpStep( PNS_DIFF_PAIR *aPair, bool aTryP, int step ) +bool PNS_OPTIMIZER::mergeDpStep( PNS_DIFF_PAIR* aPair, bool aTryP, int step ) { int n = 1; - - SHAPE_LINE_CHAIN currentPath = aTryP ? aPair->CP() : aPair->CN(); - SHAPE_LINE_CHAIN coupledPath = aTryP ? aPair->CN() : aPair->CP(); + + SHAPE_LINE_CHAIN currentPath = aTryP ? aPair->CP() : aPair->CN(); + SHAPE_LINE_CHAIN coupledPath = aTryP ? aPair->CN() : aPair->CP(); int n_segs = currentPath.SegmentCount() - 1; - int64_t clenPre = aPair->CoupledLength ( currentPath, coupledPath ); + int64_t clenPre = aPair->CoupledLength( currentPath, coupledPath ); int64_t budget = clenPre / 10; // fixme: come up with somethig more intelligent here... while( n < n_segs - step ) @@ -1066,32 +1077,31 @@ bool PNS_OPTIMIZER::mergeDpStep( PNS_DIFF_PAIR *aPair, bool aTryP, int step ) const SEG s1 = currentPath.CSegment( n ); const SEG s2 = currentPath.CSegment( n + step ); - DIRECTION_45 dir1 (s1); - DIRECTION_45 dir2 (s2); + DIRECTION_45 dir1( s1 ); + DIRECTION_45 dir2( s2 ); - if( dir1.IsObtuse(dir2 ) ) + if( dir1.IsObtuse( dir2 ) ) { SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace( s1.A, s2.B, dir1.IsDiagonal() ); SHAPE_LINE_CHAIN newRef; SHAPE_LINE_CHAIN newCoup; int64_t deltaCoupled = -1, deltaUni = -1; - newRef = currentPath; newRef.Replace( s1.Index(), s2.Index(), bypass ); deltaUni = aPair->CoupledLength ( newRef, coupledPath ) - clenPre + budget; - if ( coupledBypass ( m_world, aPair, aTryP, newRef, bypass, coupledPath, newCoup ) ) + if ( coupledBypass( m_world, aPair, aTryP, newRef, bypass, coupledPath, newCoup ) ) { - deltaCoupled = aPair->CoupledLength ( newRef, newCoup ) - clenPre + budget; + deltaCoupled = aPair->CoupledLength( newRef, newCoup ) - clenPre + budget; - if(deltaCoupled >= 0) + if( deltaCoupled >= 0 ) { newRef.Simplify(); newCoup.Simplify(); - aPair->SetShape ( newRef, newCoup, !aTryP ); + aPair->SetShape( newRef, newCoup, !aTryP ); return true; } } @@ -1100,18 +1110,19 @@ bool PNS_OPTIMIZER::mergeDpStep( PNS_DIFF_PAIR *aPair, bool aTryP, int step ) newRef.Simplify(); coupledPath.Simplify(); - aPair->SetShape ( newRef, coupledPath, !aTryP ); + aPair->SetShape( newRef, coupledPath, !aTryP ); return true; } } - + n++; } - return false; + return false; } -bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR *aPair ) + +bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR* aPair ) { int step_p = aPair->CP().SegmentCount() - 2; int step_n = aPair->CN().SegmentCount() - 2; @@ -1120,7 +1131,7 @@ bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR *aPair ) { int n_segs_p = aPair->CP().SegmentCount(); int n_segs_n = aPair->CN().SegmentCount(); - + int max_step_p = n_segs_p - 2; int max_step_n = n_segs_n - 2; @@ -1136,12 +1147,12 @@ bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR *aPair ) bool found_anything_p = false; bool found_anything_n = false; - if(step_p > 1) + if( step_p > 1 ) found_anything_p = mergeDpStep( aPair, true, step_p ); - if(step_n > 1) + if( step_n > 1 ) found_anything_n = mergeDpStep( aPair, false, step_n ); - + if( !found_anything_n && !found_anything_p ) { step_n--; @@ -1151,9 +1162,8 @@ bool PNS_OPTIMIZER::mergeDpSegments( PNS_DIFF_PAIR *aPair ) return true; } + bool PNS_OPTIMIZER::Optimize( PNS_DIFF_PAIR* aPair ) { - - - return mergeDpSegments ( aPair ); -} \ No newline at end of file + return mergeDpSegments( aPair ); +} diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index f48d6ec632..84072693cb 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -62,7 +62,7 @@ public: void Remove( PNS_LINE& aLine ); void Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ); - bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, + bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTolerance, double aCornerTollerace ) const; double GetLengthCost() const { return m_lengthCost; } diff --git a/pcbnew/router/pns_placement_algo.h b/pcbnew/router/pns_placement_algo.h index 7de571692e..315ddc3813 100644 --- a/pcbnew/router/pns_placement_algo.h +++ b/pcbnew/router/pns_placement_algo.h @@ -34,7 +34,7 @@ class PNS_NODE; /** * Class PNS_PLACEMENT_ALGO * - * Abstract class for a P&S placement/dragging algorithm. + * Abstract class for a P&S placement/dragging algorithm. * All subtools (drag, single/diff pair routing and meandering) * are derived from it. */ @@ -44,7 +44,7 @@ class PNS_PLACEMENT_ALGO : public PNS_ALGO_BASE public: PNS_PLACEMENT_ALGO( PNS_ROUTER* aRouter ) : PNS_ALGO_BASE( aRouter ) {}; - + virtual ~PNS_PLACEMENT_ALGO () {}; /** @@ -90,8 +90,8 @@ public: * * Returns true if the placer is placing a via (or more vias). */ - virtual bool IsPlacingVia() const - { + virtual bool IsPlacingVia() const + { return false; } @@ -119,14 +119,14 @@ public: * to the cursor position due to collisions. */ virtual const VECTOR2I& CurrentEnd() const = 0; - + /** * Function CurrentNet() * * Returns the net code of currently routed track. */ virtual int CurrentNet() const = 0; - + /** * Function CurrentLayer() * @@ -146,9 +146,8 @@ public: * * Toggles the current posture (straight/diagonal) of the trace head. */ - virtual void FlipPosture() + virtual void FlipPosture() { - } /** @@ -160,19 +159,17 @@ public: */ virtual void UpdateSizes( const PNS_SIZES_SETTINGS& aSizes ) { - } /** * Function SetOrthoMode() - * + * * Forces the router to place a straight 90/45 degree trace (with the end * as near to the cursor as possible) instead of a standard 135 degree * two-segment bend. */ virtual void SetOrthoMode ( bool aOrthoMode ) { - } /** @@ -180,9 +177,8 @@ public: * * Returns the net codes of all currently routed trace(s) */ - virtual void GetModifiedNets( std::vector &aNets ) const + virtual void GetModifiedNets( std::vector &aNets ) const { - } }; diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index c1a78c97e6..29a284401f 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -49,8 +49,6 @@ #include "pns_meander_skew_placer.h" #include "pns_dp_meander_placer.h" - - #include #include @@ -87,11 +85,12 @@ PNS_PCBNEW_CLEARANCE_FUNC::PNS_PCBNEW_CLEARANCE_FUNC( BOARD* aBoard ) m_defaultClearance = 254000; // aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); } + PNS_PCBNEW_CLEARANCE_FUNC::~PNS_PCBNEW_CLEARANCE_FUNC() { - } + int PNS_PCBNEW_CLEARANCE_FUNC::localPadClearance( const PNS_ITEM* aItem ) const { if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T ) @@ -101,6 +100,7 @@ int PNS_PCBNEW_CLEARANCE_FUNC::localPadClearance( const PNS_ITEM* aItem ) const return pad->GetLocalClearance(); } + int PNS_PCBNEW_CLEARANCE_FUNC::operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ) { int net_a = aA->Net(); @@ -108,7 +108,7 @@ int PNS_PCBNEW_CLEARANCE_FUNC::operator()( const PNS_ITEM* aA, const PNS_ITEM* a int net_b = aB->Net(); int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance ); - if(m_overrideEnabled && aA->OfKind(PNS_ITEM::SEGMENT) && aB->OfKind(PNS_ITEM::SEGMENT)) + if( m_overrideEnabled && aA->OfKind( PNS_ITEM::SEGMENT ) && aB->OfKind( PNS_ITEM::SEGMENT ) ) { if( net_a == m_overrideNetA && net_b == m_overrideNetB ) return m_overrideClearance; @@ -123,10 +123,11 @@ int PNS_PCBNEW_CLEARANCE_FUNC::operator()( const PNS_ITEM* aA, const PNS_ITEM* a cl_b = std::max( cl_b, pad_b ); return std::max( cl_a, cl_b ); -}; +} + // fixme: ugly hack to make the optimizer respect gap width for currently routed differential pair. -void PNS_PCBNEW_CLEARANCE_FUNC::OverrideClearance (bool aEnable, int aNetA , int aNetB , int aClearance ) +void PNS_PCBNEW_CLEARANCE_FUNC::OverrideClearance( bool aEnable, int aNetA, int aNetB , int aClearance ) { m_overrideEnabled = aEnable; m_overrideNetA = aNetA; @@ -249,6 +250,7 @@ PNS_ITEM* PNS_ROUTER::syncTrack( TRACK* aTrack ) if( aTrack->GetFlags( ) & DP_COUPLED ) s->Mark ( MK_DP_COUPLED ); + s->SetWidth( aTrack->GetWidth() ); s->SetLayers( PNS_LAYERSET( aTrack->GetLayer() ) ); s->SetParent( aTrack ); @@ -280,6 +282,7 @@ void PNS_ROUTER::SetBoard( BOARD* aBoard ) TRACE( 1, "m_board = %p\n", m_board ); } + void PNS_ROUTER::SyncWorld() { if( !m_board ) @@ -488,7 +491,7 @@ bool PNS_ROUTER::StartDragging( const VECTOR2I& aP, PNS_ITEM* aStartItem ) bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem, int aLayer ) { - switch (m_mode) + switch( m_mode ) { case PNS_MODE_ROUTE_SINGLE: m_placer = new PNS_LINE_PLACER( this ); @@ -505,7 +508,7 @@ bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem, int aLa case PNS_MODE_TUNE_DIFF_PAIR_SKEW: m_placer = new PNS_MEANDER_SKEW_PLACER( this ); break; - + default: return false; } @@ -513,9 +516,9 @@ bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem, int aLa m_placer->UpdateSizes ( m_sizes ); m_placer->SetLayer( aLayer ); - bool rv = m_placer->Start( aP, aStartItem ); + bool rv = m_placer->Start( aP, aStartItem ); - if(!rv) + if( !rv ) return false; m_currentEnd = aP; @@ -524,11 +527,13 @@ bool PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem, int aLa return rv; } -BOARD *PNS_ROUTER::GetBoard() + +BOARD* PNS_ROUTER::GetBoard() { return m_board; } + void PNS_ROUTER::eraseView() { BOOST_FOREACH( BOARD_ITEM* item, m_hiddenItems ) @@ -710,22 +715,20 @@ void PNS_ROUTER::movePlacing( const VECTOR2I& aP, PNS_ITEM* aEndItem ) m_placer->Move( aP, aEndItem ); PNS_ITEMSET current = m_placer->Traces(); - BOOST_FOREACH( const PNS_ITEM* item, current.CItems() ) { - if( !item->OfKind ( PNS_ITEM::LINE ) ) + if( !item->OfKind( PNS_ITEM::LINE ) ) continue; - const PNS_LINE *l = static_cast (item); - DisplayItem(l); - + const PNS_LINE* l = static_cast (item); + DisplayItem( l ); + if( l->EndsWithVia() ) DisplayItem( &l->Via() ); } - //PNS_ITEMSET tmp( ¤t ); - + updateView( m_placer->CurrentNode( true ), current ); } @@ -844,7 +847,6 @@ void PNS_ROUTER::StopRouting() } } - if( !RoutingInProgress() ) return; @@ -890,9 +892,9 @@ void PNS_ROUTER::SwitchLayer( int aLayer ) void PNS_ROUTER::ToggleViaPlacement() { - if( m_state == ROUTE_TRACK ) + if( m_state == ROUTE_TRACK ) { - bool toggle = !m_placer->IsPlacingVia(); + bool toggle = !m_placer->IsPlacingVia(); m_placer->ToggleVia( toggle ); } } @@ -932,24 +934,26 @@ void PNS_ROUTER::DumpLog() logger->Save( "/tmp/shove.log" ); } + bool PNS_ROUTER::IsPlacingVia() const { - if(!m_placer) + if( !m_placer ) return NULL; + return m_placer->IsPlacingVia(); } + void PNS_ROUTER::SetOrthoMode( bool aEnable ) { - if(!m_placer) + if( !m_placer ) return; - m_placer->SetOrthoMode ( aEnable ); + m_placer->SetOrthoMode( aEnable ); } -void PNS_ROUTER::SetMode ( PNS_ROUTER_MODE aMode ) + +void PNS_ROUTER::SetMode( PNS_ROUTER_MODE aMode ) { m_mode = aMode; } - - diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 48fed80321..433372ebab 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -277,7 +277,6 @@ private: wxString m_toolStatusbarName; wxString m_failureReason; - }; #endif diff --git a/pcbnew/router/pns_routing_settings.h b/pcbnew/router/pns_routing_settings.h index 1e4e82bdff..7acd5d1ade 100644 --- a/pcbnew/router/pns_routing_settings.h +++ b/pcbnew/router/pns_routing_settings.h @@ -137,7 +137,6 @@ private: PNS_MODE m_routingMode; PNS_OPTIMIZATION_EFFORT m_optimizerEffort; - int m_walkaroundIterationLimit; int m_shoveIterationLimit; TIME_LIMIT m_shoveTimeLimit; diff --git a/pcbnew/router/pns_segment.h b/pcbnew/router/pns_segment.h index dc9e870cdd..ecd24bdd08 100644 --- a/pcbnew/router/pns_segment.h +++ b/pcbnew/router/pns_segment.h @@ -46,7 +46,7 @@ public: } PNS_SEGMENT( const PNS_LINE& aParentLine, const SEG& aSeg ) : - PNS_ITEM( SEGMENT ), + PNS_ITEM( SEGMENT ), m_seg( aSeg, aParentLine.Width() ) { m_net = aParentLine.Net(); @@ -59,7 +59,7 @@ public: { return aItem && SEGMENT == aItem->Kind(); } - + PNS_SEGMENT* Clone( ) const; const SHAPE* Shape() const @@ -100,7 +100,7 @@ public: void SetEnds( const VECTOR2I& a, const VECTOR2I& b ) { m_seg.SetSeg( SEG ( a, b ) ); - } + } void SwapEnds() { @@ -110,7 +110,7 @@ public: const SHAPE_LINE_CHAIN Hull( int aClearance, int aWalkaroundThickness ) const; - virtual VECTOR2I Anchor(int n) const + virtual VECTOR2I Anchor(int n) const { if( n == 0 ) return m_seg.GetSeg().A; @@ -118,9 +118,9 @@ public: return m_seg.GetSeg().B; } - virtual int AnchorCount() const + virtual int AnchorCount() const { - return 2; + return 2; } private: diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 48a3227088..31fad49bcc 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -42,14 +42,13 @@ #include -void PNS_SHOVE::replaceItems ( PNS_ITEM *aOld, PNS_ITEM *aNew ) +void PNS_SHOVE::replaceItems( PNS_ITEM* aOld, PNS_ITEM* aNew ) { OPT_BOX2I changed_area = ChangedArea( aOld, aNew ); - - if(changed_area) + if( changed_area ) { - assert ( !changed_area->Contains ( VECTOR2I (0, 0 ) ) ); + assert( !changed_area->Contains( VECTOR2I( 0, 0 ) ) ); m_affectedAreaSum = m_affectedAreaSum ? m_affectedAreaSum->Merge ( *changed_area ) : *changed_area; } @@ -60,12 +59,13 @@ void PNS_SHOVE::replaceItems ( PNS_ITEM *aOld, PNS_ITEM *aNew ) int PNS_SHOVE::getClearance( PNS_ITEM *aA, PNS_ITEM *aB ) const { - if(m_forceClearance >= 0) + if( m_forceClearance >= 0 ) return m_forceClearance; return m_currentNode->GetClearance( aA, aB ); } + static void sanityCheck( PNS_LINE* aOld, PNS_LINE* aNew ) { assert( aOld->CPoint( 0 ) == aNew->CPoint( 0 ) ); @@ -99,6 +99,7 @@ PNS_LINE* PNS_SHOVE::assembleLine( const PNS_SEGMENT* aSeg, int* aIndex ) return l; } + // 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: @@ -311,7 +312,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE* aCurrent, PNS_S SHOVE_STATUS rv = ProcessSingleLine( aCurrent, obstacleLine, shovedLine ); - assert ( obstacleLine->LayersOverlap( shovedLine ) ); + assert( obstacleLine->LayersOverlap( shovedLine ) ); if( rv == SH_OK ) { @@ -319,7 +320,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSegment( PNS_LINE* aCurrent, PNS_S { if( m_multiLineMode ) return SH_INCOMPLETE; - + m_newHead = *shovedLine; } @@ -351,13 +352,11 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE* aCurrent, PNS_LINE SHOVE_STATUS rv = ProcessSingleLine( aCurrent, aObstacle, shovedLine ); - - if( rv == SH_OK ) { if( shovedLine->Marker() & MK_HEAD ) { - if (m_multiLineMode) + if( m_multiLineMode ) return SH_INCOMPLETE; m_newHead = *shovedLine; @@ -444,7 +443,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE* aCurrent, PNS_SOL { walkaroundLine->Mark( MK_HEAD ); - if(m_multiLineMode) + if(m_multiLineMode) return SH_INCOMPLETE; m_newHead = *walkaroundLine; @@ -481,7 +480,7 @@ bool PNS_SHOVE::reduceSpringback( const PNS_ITEMSET& aHeadSet ) delete spTag.m_node; m_nodeStack.pop_back(); - } + } else break; } @@ -496,10 +495,9 @@ bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET& aHeadItems, SPRINGBACK_TAG st; OPT_BOX2I prev_area; - if(!m_nodeStack.empty()) + if( !m_nodeStack.empty() ) prev_area = m_nodeStack.back().m_affectedArea; - st.m_node = aNode; st.m_cost = aCost; st.m_headItems = aHeadItems; @@ -522,20 +520,20 @@ bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, const PNS_ITEMSET& aHeadItems, PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun ) { LINE_PAIR_VEC draggedLines; - VECTOR2I p0 ( aVia->Pos() ); + VECTOR2I p0( aVia->Pos() ); PNS_JOINT* jt = m_currentNode->FindJoint( p0, aVia ); VECTOR2I p0_pushed( p0 + aForce ); - while (aForce.x != 0 || aForce.y != 0) + while( aForce.x != 0 || aForce.y != 0 ) { - PNS_JOINT *jt_next = m_currentNode->FindJoint ( p0_pushed, aVia ); + PNS_JOINT* jt_next = m_currentNode->FindJoint( p0_pushed, aVia ); - if(!jt_next) + if( !jt_next ) break; - - p0_pushed += aForce.Resize ( 2 ); // make sure pushed via does not overlap with any existing joint + + p0_pushed += aForce.Resize( 2 ); // make sure pushed via does not overlap with any existing joint } - + PNS_VIA* pushedVia = aVia->Clone(); pushedVia->SetPos( p0_pushed ); pushedVia->Mark( aVia->Marker() ); @@ -554,7 +552,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc BOOST_FOREACH( PNS_ITEM* item, jt->LinkList() ) { - if( PNS_SEGMENT *seg = dyn_cast( item ) ) + if( PNS_SEGMENT* seg = dyn_cast( item ) ) { LINE_PAIR lp; int segIndex; @@ -569,12 +567,11 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc lp.second = clone( lp.first ); lp.second->ClearSegmentLinks(); lp.second->DragCorner( p0_pushed, lp.second->CLine().Find( p0 ) ); - lp.second->AppendVia ( *pushedVia ); + lp.second->AppendVia( *pushedVia ); draggedLines.push_back( lp ); - if (aVia->Marker() & MK_HEAD ) - m_draggedViaHeadSet.Add ( clone ( lp.second ) ); - + if( aVia->Marker() & MK_HEAD ) + m_draggedViaHeadSet.Add( clone ( lp.second ) ); } } @@ -584,9 +581,9 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc return SH_OK; replaceItems ( aVia, pushedVia ); - + if( aVia->BelongsTo( m_currentNode ) ) - delete aVia; + delete aVia; pushedVia->SetRank( aCurrentRank - 1 ); @@ -600,7 +597,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::pushVia( PNS_VIA* aVia, const VECTOR2I& aForc if( lp.first->Marker() & MK_HEAD ) { lp.second->Mark( MK_HEAD ); - + if ( m_multiLineMode ) return SH_INCOMPLETE; @@ -955,11 +952,12 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::shoveMainLoop() return st; } -OPT_BOX2I PNS_SHOVE::totalAffectedArea ( ) const + +OPT_BOX2I PNS_SHOVE::totalAffectedArea() const { OPT_BOX2I area; - if(!m_nodeStack.empty()) - area = m_nodeStack.back().m_affectedArea; + if( !m_nodeStack.empty() ) + area = m_nodeStack.back().m_affectedArea; if( area ) { @@ -977,7 +975,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) SHOVE_STATUS st = SH_OK; m_multiLineMode = false; - + // empty head? nothing to shove... if( !aCurrentHead.SegmentCount() ) return SH_INCOMPLETE; @@ -1047,7 +1045,6 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveLines( const PNS_LINE& aCurrentHead ) } - PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveMultiLines( const PNS_ITEMSET& aHeadSet ) { SHOVE_STATUS st = SH_OK; @@ -1056,22 +1053,21 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveMultiLines( const PNS_ITEMSET& aHeadSet PNS_ITEMSET headSet; - BOOST_FOREACH ( const PNS_ITEM *item, aHeadSet.CItems() ) + BOOST_FOREACH ( const PNS_ITEM* item, aHeadSet.CItems() ) { - const PNS_LINE *headOrig = static_cast (item); - + const PNS_LINE* headOrig = static_cast( item ); + // empty head? nothing to shove... if( !headOrig->SegmentCount() ) return SH_INCOMPLETE; - - headSet.Add ( clone ( headOrig ) ); - } + headSet.Add( clone( headOrig ) ); + } m_lineStack.clear(); m_optimizerQueue.clear(); m_logger.Clear(); - + reduceSpringback( headSet ); PNS_NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; @@ -1079,12 +1075,12 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveMultiLines( const PNS_ITEMSET& aHeadSet m_currentNode = parent->Branch(); m_currentNode->ClearRanks(); int n = 0; - BOOST_FOREACH ( const PNS_ITEM *item, aHeadSet.CItems() ) + BOOST_FOREACH ( const PNS_ITEM* item, aHeadSet.CItems() ) { - const PNS_LINE *headOrig = static_cast (item); - PNS_LINE *head = clone ( headOrig ); + const PNS_LINE* headOrig = static_cast( item ); + PNS_LINE* head = clone( headOrig ); head->ClearSegmentLinks(); - + m_currentNode->Add( head ); head->Mark( MK_HEAD ); @@ -1128,12 +1124,12 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveMultiLines( const PNS_ITEMSET& aHeadSet 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(); @@ -1160,7 +1156,7 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::ShoveDraggingVia( PNS_VIA* aVia, const VECTOR if( st == SH_OK || st == SH_HEAD_MODIFIED ) { - pushSpringback( m_currentNode, m_draggedViaHeadSet, PNS_COST_ESTIMATOR(), m_affectedAreaSum); + pushSpringback( m_currentNode, m_draggedViaHeadSet, PNS_COST_ESTIMATOR(), m_affectedAreaSum ); } else { @@ -1193,9 +1189,9 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) maxWidth = std::max ( (*i)->Width(), maxWidth ); } - if(area) + if( area ) { - area->Inflate ( 10 * maxWidth ); + area->Inflate( 10 * maxWidth ); } switch( effort ) @@ -1207,9 +1203,9 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) case OE_MEDIUM: optFlags = PNS_OPTIMIZER::MERGE_SEGMENTS; - + if( area ) - optimizer.SetRestrictArea ( *area ); + optimizer.SetRestrictArea( *area ); n_passes = 2; break; @@ -1223,7 +1219,6 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) break; } - if( Settings().SmartPads() ) optFlags |= PNS_OPTIMIZER::SMART_PADS ; @@ -1254,6 +1249,7 @@ void PNS_SHOVE::runOptimizer( PNS_NODE* aNode, PNS_LINE* aHead ) } } + PNS_NODE* PNS_SHOVE::CurrentNode() { return m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index d9fbeb9cee..cf8ae3f383 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -64,7 +64,7 @@ public: SHOVE_STATUS ShoveMultiLines( const PNS_ITEMSET& aHeadSet ); SHOVE_STATUS ShoveDraggingVia( PNS_VIA*aVia, const VECTOR2I& aWhere, PNS_VIA** aNewVia ); - SHOVE_STATUS ProcessSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, + SHOVE_STATUS ProcessSingleLine( PNS_LINE* aCurrent, PNS_LINE* aObstacle, PNS_LINE* aShoved ); void ForceClearance ( bool aEnabled, int aClearance ) @@ -115,9 +115,8 @@ private: SHOVE_STATUS onReverseCollidingVia( PNS_LINE* aCurrent, PNS_VIA* aObstacleVia ); SHOVE_STATUS pushVia( PNS_VIA* aVia, const VECTOR2I& aForce, int aCurrentRank, bool aDryRun = false ); - OPT_BOX2I totalAffectedArea ( ) const; + OPT_BOX2I totalAffectedArea() const; - void unwindStack( PNS_SEGMENT* aSeg ); void unwindStack( PNS_ITEM* aItem ); @@ -128,8 +127,8 @@ private: PNS_LINE* assembleLine( const PNS_SEGMENT* aSeg, int* aIndex = NULL ); - void replaceItems ( PNS_ITEM *aOld, PNS_ITEM *aNew ); - + void replaceItems( PNS_ITEM *aOld, PNS_ITEM *aNew ); + template T* clone ( const T* aItem ) { T *cloned = aItem->Clone(); @@ -140,7 +139,6 @@ private: OPT_BOX2I m_affectedAreaSum; - SHOVE_STATUS shoveIteration( int aIter ); SHOVE_STATUS shoveMainLoop(); diff --git a/pcbnew/router/pns_sizes_settings.cpp b/pcbnew/router/pns_sizes_settings.cpp index f2ab01a3be..94f12ac04a 100644 --- a/pcbnew/router/pns_sizes_settings.cpp +++ b/pcbnew/router/pns_sizes_settings.cpp @@ -66,6 +66,7 @@ int PNS_SIZES_SETTINGS::inheritTrackWidth( PNS_ITEM* aItem ) return ( mval == INT_MAX ? 0 : mval ); } + void PNS_SIZES_SETTINGS::Init( BOARD* aBoard, PNS_ITEM* aStartItem, int aNet ) { BOARD_DESIGN_SETTINGS &bds = aBoard->GetDesignSettings(); @@ -121,11 +122,13 @@ void PNS_SIZES_SETTINGS::Init( BOARD* aBoard, PNS_ITEM* aStartItem, int aNet ) m_layerPairs.clear(); } + void PNS_SIZES_SETTINGS::ClearLayerPairs() { m_layerPairs.clear(); } + void PNS_SIZES_SETTINGS::AddLayerPair( int aL1, int aL2 ) { int top = std::min( aL1, aL2 ); @@ -135,6 +138,7 @@ void PNS_SIZES_SETTINGS::AddLayerPair( int aL1, int aL2 ) m_layerPairs[top] = bottom; } + void PNS_SIZES_SETTINGS::ImportCurrent( BOARD_DESIGN_SETTINGS& aSettings ) { m_trackWidth = aSettings.GetCurrentTrackWidth(); @@ -142,6 +146,7 @@ void PNS_SIZES_SETTINGS::ImportCurrent( BOARD_DESIGN_SETTINGS& aSettings ) m_viaDrill = aSettings.GetCurrentViaDrill(); } + int PNS_SIZES_SETTINGS::GetLayerTop() const { if( m_layerPairs.empty() ) @@ -150,6 +155,7 @@ int PNS_SIZES_SETTINGS::GetLayerTop() const return m_layerPairs.begin()->first; } + int PNS_SIZES_SETTINGS::GetLayerBottom() const { if( m_layerPairs.empty() ) diff --git a/pcbnew/router/pns_sizes_settings.h b/pcbnew/router/pns_sizes_settings.h index 8c84256215..9e335cbbdf 100644 --- a/pcbnew/router/pns_sizes_settings.h +++ b/pcbnew/router/pns_sizes_settings.h @@ -47,7 +47,7 @@ public: ~PNS_SIZES_SETTINGS() {}; void Init( BOARD* aBoard, PNS_ITEM* aStartItem = NULL, int aNet = -1 ); - void ImportCurrent ( BOARD_DESIGN_SETTINGS& aSettings ); + void ImportCurrent( BOARD_DESIGN_SETTINGS& aSettings ); void ClearLayerPairs(); void AddLayerPair( int aL1, int aL2 ); @@ -57,12 +57,12 @@ public: int DiffPairWidth() const { return m_diffPairWidth; } int DiffPairGap() const { return m_diffPairGap; } - - int DiffPairViaGap() const { + + int DiffPairViaGap() const { if(m_diffPairViaGapSameAsTraceGap) return m_diffPairGap; else - return m_diffPairViaGap; + return m_diffPairViaGap; } bool DiffPairViaGapSameAsTraceGap() const { return m_diffPairViaGapSameAsTraceGap; } @@ -83,7 +83,7 @@ public: if( m_layerPairs.find(aLayerId) == m_layerPairs.end() ) return boost::optional(); - return m_layerPairs [ aLayerId ]; + return m_layerPairs[aLayerId]; } int GetLayerTop() const; diff --git a/pcbnew/router/pns_solid.cpp b/pcbnew/router/pns_solid.cpp index 6305ceabc4..9b0a048dab 100644 --- a/pcbnew/router/pns_solid.cpp +++ b/pcbnew/router/pns_solid.cpp @@ -62,7 +62,7 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness } -PNS_ITEM* PNS_SOLID::Clone ( ) const +PNS_ITEM* PNS_SOLID::Clone() const { PNS_ITEM* solid = new PNS_SOLID( *this ); return solid; diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index 527a08142f..e598409849 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -43,7 +43,7 @@ public: } PNS_SOLID( const PNS_SOLID& aSolid ) : - PNS_ITEM ( aSolid ) + PNS_ITEM( aSolid ) { m_shape = aSolid.m_shape->Clone(); m_pos = aSolid.m_pos; @@ -53,7 +53,7 @@ public: { return aItem && SOLID == aItem->Kind(); } - + PNS_ITEM* Clone() const; const SHAPE* Shape() const { return m_shape; } @@ -83,7 +83,7 @@ public: return m_pos; } - virtual int AnchorCount() const + virtual int AnchorCount() const { return 1; } diff --git a/pcbnew/router/pns_tool_base.cpp b/pcbnew/router/pns_tool_base.cpp index 0e83041791..9491d81a2c 100644 --- a/pcbnew/router/pns_tool_base.cpp +++ b/pcbnew/router/pns_tool_base.cpp @@ -95,6 +95,7 @@ void PNS_TOOL_BASE::Reset( RESET_REASON aReason ) m_router->SetView( getView() ); } + PNS_ITEM* PNS_TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) { int tl = getView()->GetTopLayer(); @@ -138,7 +139,7 @@ PNS_ITEM* PNS_TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int a } PNS_ITEM* rv = NULL; - PCB_EDIT_FRAME* frame = getEditFrame (); + PCB_EDIT_FRAME* frame = getEditFrame(); DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions(); for( int i = 0; i < 4; i++ ) @@ -178,6 +179,7 @@ void PNS_TOOL_BASE::highlightNet( bool aEnabled, int aNetcode ) getView()->UpdateAllLayersColor(); } + void PNS_TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent ) { int tl = getView()->GetTopLayer(); @@ -187,7 +189,7 @@ void PNS_TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent ) if( aEvent.IsMotion() || aEvent.IsClick() ) { bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); - + VECTOR2I p( aEvent.Position() ); startItem = pickSingleItem( p ); m_router->EnableSnapping ( snapEnabled ); @@ -227,6 +229,7 @@ void PNS_TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent ) } } + void PNS_TOOL_BASE::updateEndItem( TOOL_EVENT& aEvent ) { VECTOR2I mp = m_ctls->GetMousePosition(); diff --git a/pcbnew/router/pns_tool_base.h b/pcbnew/router/pns_tool_base.h index 9778b0e999..db8998561a 100644 --- a/pcbnew/router/pns_tool_base.h +++ b/pcbnew/router/pns_tool_base.h @@ -49,7 +49,7 @@ protected: virtual void highlightNet( bool aEnabled, int aNetcode = -1 ); virtual void updateStartItem( TOOL_EVENT& aEvent ); virtual void updateEndItem( TOOL_EVENT& aEvent ); - + MSG_PANEL_ITEMS m_panelItems; PNS_ROUTER* m_router; @@ -64,10 +64,10 @@ protected: ///> Flag marking that the router's world needs syncing. bool m_needsSync; - - PCB_EDIT_FRAME *m_frame; - KIGFX::VIEW_CONTROLS *m_ctls; - BOARD *m_board; + + PCB_EDIT_FRAME* m_frame; + KIGFX::VIEW_CONTROLS* m_ctls; + BOARD* m_board; }; diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp index 8fdc9a4770..f59a0fdb15 100644 --- a/pcbnew/router/pns_topology.cpp +++ b/pcbnew/router/pns_topology.cpp @@ -30,31 +30,31 @@ #include -bool PNS_TOPOLOGY::SimplifyLine ( PNS_LINE *aLine ) +bool PNS_TOPOLOGY::SimplifyLine( PNS_LINE* aLine ) { - - if( !aLine->LinkedSegments() || !aLine->SegmentCount() ) - return false; + if( !aLine->LinkedSegments() || !aLine->SegmentCount() ) + return false; - PNS_SEGMENT *root = (*aLine->LinkedSegments())[0]; - std::auto_ptr l ( m_world->AssembleLine( root ) ); - SHAPE_LINE_CHAIN simplified ( l->CLine() ); + PNS_SEGMENT* root = ( *aLine->LinkedSegments() )[0]; + std::auto_ptr l( m_world->AssembleLine( root ) ); + SHAPE_LINE_CHAIN simplified( l->CLine() ); simplified.Simplify(); if( simplified.PointCount() != l->PointCount() ) { - std::auto_ptr lnew ( l->Clone() ); - m_world -> Remove( l.get() ); + std::auto_ptr lnew( l->Clone() ); + m_world->Remove( l.get() ); lnew->SetShape( simplified ); - m_world -> Add( lnew.get() ); + m_world->Add( lnew.get() ); return true; } return false; } -const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints ( PNS_JOINT* aStart ) + +const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints( PNS_JOINT* aStart ) { std::deque searchQueue; JOINT_SET processed; @@ -69,9 +69,9 @@ const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints ( PNS_JOINT* aStart BOOST_FOREACH( PNS_ITEM* item, current->LinkList() ) { - if ( item->OfKind( PNS_ITEM::SEGMENT ) ) + if( item->OfKind( PNS_ITEM::SEGMENT ) ) { - PNS_SEGMENT* seg = static_cast( item ); + PNS_SEGMENT* seg = static_cast( item ); PNS_JOINT* a = m_world->FindJoint( seg->Seg().A, seg ); PNS_JOINT* b = m_world->FindJoint( seg->Seg().B, seg ); PNS_JOINT* next = ( *a == *current ) ? b : a; @@ -81,7 +81,7 @@ const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints ( PNS_JOINT* aStart processed.insert( next ); searchQueue.push_back( next ); } - } + } } } @@ -89,29 +89,31 @@ const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints ( PNS_JOINT* aStart } -bool PNS_TOPOLOGY::LeadingRatLine( const PNS_LINE *aTrack, SHAPE_LINE_CHAIN& aRatLine ) +bool PNS_TOPOLOGY::LeadingRatLine( const PNS_LINE* aTrack, SHAPE_LINE_CHAIN& aRatLine ) { - PNS_LINE track ( *aTrack ); + PNS_LINE track( *aTrack ); VECTOR2I end; if( !track.PointCount() ) return false; - std::auto_ptr tmpNode ( m_world->Branch() ); + std::auto_ptr tmpNode( m_world->Branch() ); tmpNode->Add( &track ); PNS_JOINT* jt = tmpNode->FindJoint( track.CPoint( -1 ), &track ); - if ( !jt ) + if( !jt ) return false; - if( (!track.EndsWithVia() && jt->LinkCount() >= 2) || (track.EndsWithVia() && jt->LinkCount() >= 3 )) // we got something connected + if( ( !track.EndsWithVia() && jt->LinkCount() >= 2 ) || ( track.EndsWithVia() && jt->LinkCount() >= 3 ) ) // we got something connected { end = jt->Pos(); - } else { + } + else + { int anchor; - - PNS_TOPOLOGY topo ( tmpNode.get() ); + + PNS_TOPOLOGY topo( tmpNode.get() ); PNS_ITEM* it = topo.NearestUnconnectedItem( jt, &anchor ); if( !it ) @@ -121,24 +123,24 @@ bool PNS_TOPOLOGY::LeadingRatLine( const PNS_LINE *aTrack, SHAPE_LINE_CHAIN& aRa } aRatLine.Clear(); - aRatLine.Append ( track.CPoint( -1 ) ); - aRatLine.Append ( end ); + aRatLine.Append( track.CPoint( -1 ) ); + aRatLine.Append( end ); return true; } PNS_ITEM* PNS_TOPOLOGY::NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor, int aKindMask ) { std::set disconnected; - + m_world->AllItemsInNet( aStart->Net(), disconnected ); - BOOST_FOREACH( const PNS_JOINT *jt, ConnectedJoints ( aStart ) ) + BOOST_FOREACH( const PNS_JOINT* jt, ConnectedJoints( aStart ) ) { BOOST_FOREACH( PNS_ITEM* link, jt->LinkList() ) { if( disconnected.find( link ) != disconnected.end() ) disconnected.erase( link ); - } + } } int best_dist = INT_MAX; @@ -148,7 +150,7 @@ PNS_ITEM* PNS_TOPOLOGY::NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor, { if( item->OfKind( aKindMask ) ) { - for(int i = 0; i < item->AnchorCount(); i++) + for(int i = 0; i < item->AnchorCount(); i++) { VECTOR2I p = item->Anchor( i ); int d = ( p - aStart->Pos() ).EuclideanNorm(); @@ -169,63 +171,67 @@ PNS_ITEM* PNS_TOPOLOGY::NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor, } -bool PNS_TOPOLOGY::followTrivialPath ( PNS_LINE *aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ) +bool PNS_TOPOLOGY::followTrivialPath( PNS_LINE* aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ) { - VECTOR2I anchor = aLeft ? aLine->CPoint(0) : aLine->CPoint(-1); - PNS_SEGMENT *last = aLeft ? aLine->LinkedSegments()->front() : aLine->LinkedSegments()->back(); - PNS_JOINT *jt = m_world->FindJoint ( anchor, aLine ); + VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 ); + PNS_SEGMENT* last = aLeft ? aLine->LinkedSegments()->front() : aLine->LinkedSegments()->back(); + PNS_JOINT* jt = m_world->FindJoint( anchor, aLine ); - assert (jt != NULL); + assert( jt != NULL ); aVisited.insert( last ); if( jt->IsNonFanoutVia() ) { - PNS_ITEM *via = NULL; - PNS_SEGMENT *next_seg = NULL; - - BOOST_FOREACH ( PNS_ITEM *link, jt->Links().Items() ) + PNS_ITEM* via = NULL; + PNS_SEGMENT* next_seg = NULL; + + BOOST_FOREACH( PNS_ITEM* link, jt->Links().Items() ) { - if( link->OfKind ( PNS_ITEM::VIA ) ) + if( link->OfKind( PNS_ITEM::VIA ) ) via = link; - else if( aVisited.find(link) == aVisited.end() ) - next_seg = static_cast (link); + else if( aVisited.find( link ) == aVisited.end() ) + next_seg = static_cast( link ); } - - if(!next_seg) + + if( !next_seg ) return false; - PNS_LINE *l = m_world->AssembleLine ( next_seg ); + PNS_LINE* l = m_world->AssembleLine( next_seg ); - VECTOR2I nextAnchor = (aLeft ? l->CLine().CPoint(-1) : l->CLine().CPoint(0) ); - - if (nextAnchor != anchor) + VECTOR2I nextAnchor = ( aLeft ? l->CLine().CPoint( -1 ) : l->CLine().CPoint( 0 ) ); + + if( nextAnchor != anchor ) { l->Reverse(); } - if (aLeft) + if( aLeft ) { - aSet.Prepend ( via ); - aSet.Prepend ( l ); - } else { - aSet.Add ( via ); - aSet.Add ( l ); + aSet.Prepend( via ); + aSet.Prepend( l ); + } + else + { + aSet.Add( via ); + aSet.Add( l ); } - return followTrivialPath ( l, aLeft, aSet, aVisited ); + return followTrivialPath( l, aLeft, aSet, aVisited ); } + return false; } -const PNS_ITEMSET PNS_TOPOLOGY::AssembleTrivialPath ( PNS_SEGMENT *aStart ) + +const PNS_ITEMSET PNS_TOPOLOGY::AssembleTrivialPath( PNS_SEGMENT* aStart ) { PNS_ITEMSET path; - std::set visited; + std::set visited; - PNS_LINE *l = m_world->AssembleLine ( aStart ); + PNS_LINE* l = m_world->AssembleLine( aStart ); - path.Add ( l ); + path.Add( l ); followTrivialPath( l, false, path, visited ); followTrivialPath( l, true, path, visited ); @@ -233,39 +239,47 @@ const PNS_ITEMSET PNS_TOPOLOGY::AssembleTrivialPath ( PNS_SEGMENT *aStart ) return path; } + const PNS_ITEMSET PNS_TOPOLOGY::ConnectedItems( PNS_JOINT* aStart, int aKindMask ) { return PNS_ITEMSET(); } + const PNS_ITEMSET PNS_TOPOLOGY::ConnectedItems( PNS_ITEM* aStart, int aKindMask ) { return PNS_ITEMSET(); } -int PNS_TOPOLOGY::MatchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) + +int PNS_TOPOLOGY::MatchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ) { int rv = 0; - if (aNetName.EndsWith("+")) + + if( aNetName.EndsWith( "+" ) ) { aComplementNet = "-"; rv = 1; - } else if (aNetName.EndsWith("_P")) + } + else if( aNetName.EndsWith( "_P" ) ) { aComplementNet = "_N"; rv = 1; - } else if (aNetName.EndsWith("-")) + } + else if( aNetName.EndsWith( "-" ) ) { aComplementNet = "+"; rv = -1; - } else if (aNetName.EndsWith("_N")) + } + else if( aNetName.EndsWith( "_N" ) ) { aComplementNet = "_P"; rv = -1; } - if (rv != 0) { - aBaseDpName = aNetName.Left ( aNetName.Length() - aComplementNet.Length() ); + if( rv != 0 ) + { + aBaseDpName = aNetName.Left( aNetName.Length() - aComplementNet.Length() ); aComplementNet = aBaseDpName + aComplementNet; } @@ -275,16 +289,16 @@ int PNS_TOPOLOGY::MatchDpSuffix ( wxString aNetName, wxString& aComplementNet, w int PNS_TOPOLOGY::DpCoupledNet( int aNet ) { - BOARD *brd = PNS_ROUTER::GetInstance()->GetBoard(); + BOARD* brd = PNS_ROUTER::GetInstance()->GetBoard(); - wxString refName = brd->FindNet ( aNet )->GetNetname(); + wxString refName = brd->FindNet( aNet )->GetNetname(); wxString dummy, coupledNetName; - - if ( MatchDpSuffix ( refName, coupledNetName, dummy ) ) - { - NETINFO_ITEM *net = brd->FindNet ( coupledNetName ); - if(!net) + if( MatchDpSuffix( refName, coupledNetName, dummy ) ) + { + NETINFO_ITEM* net = brd->FindNet( coupledNetName ); + + if( !net ) return -1; return net->GetNet(); @@ -297,24 +311,24 @@ int PNS_TOPOLOGY::DpCoupledNet( int aNet ) int PNS_TOPOLOGY::DpNetPolarity( int aNet ) { - BOARD *brd = PNS_ROUTER::GetInstance()->GetBoard(); + BOARD* brd = PNS_ROUTER::GetInstance()->GetBoard(); - wxString refName = brd->FindNet ( aNet )->GetNetname(); + wxString refName = brd->FindNet( aNet )->GetNetname(); wxString dummy1, dummy2; - return MatchDpSuffix ( refName, dummy1, dummy2 ); + return MatchDpSuffix( refName, dummy1, dummy2 ); } - -bool PNS_TOPOLOGY::AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ) + +bool PNS_TOPOLOGY::AssembleDiffPair( PNS_ITEM* aStart, PNS_DIFF_PAIR& aPair ) { int refNet = aStart->Net(); - int coupledNet = DpCoupledNet ( refNet ); - - if(coupledNet < 0) + int coupledNet = DpCoupledNet( refNet ); + + if( coupledNet < 0 ) return false; - std::set coupledItems; + std::set coupledItems; m_world->AllItemsInNet( coupledNet, coupledItems ); @@ -323,15 +337,15 @@ bool PNS_TOPOLOGY::AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ) if( ( refSeg = dyn_cast( aStart ) ) != NULL ) { - BOOST_FOREACH ( PNS_ITEM *item, coupledItems ) + BOOST_FOREACH( PNS_ITEM* item, coupledItems ) { - if ( PNS_SEGMENT *s = dyn_cast(item) ) + if( PNS_SEGMENT* s = dyn_cast( item ) ) { if( s->Layers().Start() == refSeg->Layers().Start() && s->Width() == refSeg->Width() ) { int dist = s->Seg().Distance( refSeg->Seg() ); - if(dist < minDist) + if( dist < minDist ) { minDist = dist; coupledSeg = s; @@ -339,22 +353,23 @@ bool PNS_TOPOLOGY::AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ) } } } - } else + } else return false; - if(!coupledSeg) + if( !coupledSeg ) return false; - std::auto_ptr lp ( m_world->AssembleLine ( refSeg ) ); - std::auto_ptr ln ( m_world->AssembleLine ( coupledSeg ) ); + std::auto_ptr lp ( m_world->AssembleLine( refSeg ) ); + std::auto_ptr ln ( m_world->AssembleLine( coupledSeg ) ); - if(DpNetPolarity(refNet) < 0) + if( DpNetPolarity( refNet ) < 0 ) { - std::swap (lp, ln); + std::swap( lp, ln ); } - - aPair = PNS_DIFF_PAIR ( *lp, *ln ); - aPair.SetWidth ( lp->Width() ); - aPair.SetLayers ( lp->Layers() ); + + aPair = PNS_DIFF_PAIR( *lp, *ln ); + aPair.SetWidth( lp->Width() ); + aPair.SetLayers( lp->Layers() ); + return true; } diff --git a/pcbnew/router/pns_topology.h b/pcbnew/router/pns_topology.h index 5233cb71c0..ebc4894b74 100644 --- a/pcbnew/router/pns_topology.h +++ b/pcbnew/router/pns_topology.h @@ -35,41 +35,36 @@ class PNS_DIFF_PAIR; class PNS_TOPOLOGY { - public: - typedef std::set JOINT_SET; +public: + typedef std::set JOINT_SET; - PNS_TOPOLOGY ( PNS_NODE *aNode ): - m_world ( aNode ) {}; + PNS_TOPOLOGY( PNS_NODE* aNode ): + m_world( aNode ) {}; - ~PNS_TOPOLOGY ( ) {}; + ~PNS_TOPOLOGY() {}; - bool SimplifyLine ( PNS_LINE *aLine ); - PNS_ITEM* NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor = NULL, int aKindMask = PNS_ITEM::ANY ); - bool LeadingRatLine( const PNS_LINE *aTrack, SHAPE_LINE_CHAIN& aRatLine ); + bool SimplifyLine( PNS_LINE *aLine ); + PNS_ITEM* NearestUnconnectedItem( PNS_JOINT* aStart, int* aAnchor = NULL, int aKindMask = PNS_ITEM::ANY ); + bool LeadingRatLine( const PNS_LINE* aTrack, SHAPE_LINE_CHAIN& aRatLine ); - const JOINT_SET ConnectedJoints ( PNS_JOINT* aStart ); - const PNS_ITEMSET ConnectedItems ( PNS_JOINT* aStart, int aKindMask = PNS_ITEM::ANY ); - const PNS_ITEMSET ConnectedItems ( PNS_ITEM* aStart, int aKindMask = PNS_ITEM::ANY ); - int64_t ShortestConnectionLength ( PNS_ITEM *aFrom, PNS_ITEM *aTo ); - + const JOINT_SET ConnectedJoints( PNS_JOINT* aStart ); + const PNS_ITEMSET ConnectedItems( PNS_JOINT* aStart, int aKindMask = PNS_ITEM::ANY ); + const PNS_ITEMSET ConnectedItems( PNS_ITEM* aStart, int aKindMask = PNS_ITEM::ANY ); + int64_t ShortestConnectionLength( PNS_ITEM* aFrom, PNS_ITEM* aTo ); + const PNS_ITEMSET AssembleTrivialPath( PNS_SEGMENT* aStart ); + const PNS_DIFF_PAIR AssembleDiffPair( PNS_SEGMENT* aStart ); - const PNS_ITEMSET AssembleTrivialPath ( PNS_SEGMENT *aStart ); - const PNS_DIFF_PAIR AssembleDiffPair ( PNS_SEGMENT *aStart ); + int MatchDpSuffix( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); + int DpCoupledNet( int aNet ); + int DpNetPolarity( int aNet ); + const PNS_LINE DpCoupledLine( PNS_LINE* aLine ); + bool AssembleDiffPair( PNS_ITEM* aStart, PNS_DIFF_PAIR& aPair ); - int MatchDpSuffix ( wxString aNetName, wxString& aComplementNet, wxString& aBaseDpName ); - int DpCoupledNet( int aNet ); - int DpNetPolarity( int aNet ); - const PNS_LINE DpCoupledLine( PNS_LINE *aLine ); - bool AssembleDiffPair ( PNS_ITEM *aStart, PNS_DIFF_PAIR& aPair ); +private: + bool followTrivialPath( PNS_LINE* aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ); - - - private: - - bool followTrivialPath ( PNS_LINE *aLine, bool aLeft, PNS_ITEMSET& aSet, std::set& aVisited ); - - PNS_NODE *m_world; + PNS_NODE *m_world; }; #endif diff --git a/pcbnew/router/pns_tune_status_popup.cpp b/pcbnew/router/pns_tune_status_popup.cpp index 924169af97..3250b2c56d 100644 --- a/pcbnew/router/pns_tune_status_popup.cpp +++ b/pcbnew/router/pns_tune_status_popup.cpp @@ -22,48 +22,48 @@ #include "pns_router.h" #include "pns_meander_placer.h" -PNS_TUNE_STATUS_POPUP::PNS_TUNE_STATUS_POPUP ( PCB_EDIT_FRAME *parent ) : - WX_STATUS_POPUP ( parent ) +PNS_TUNE_STATUS_POPUP::PNS_TUNE_STATUS_POPUP( PCB_EDIT_FRAME* aParent ) : + WX_STATUS_POPUP( aParent ) { - m_panel->SetBackgroundColour( wxColour(64,64,64) ); - m_statusLine = new wxStaticText( m_panel, wxID_ANY, - wxT("Status text 1\n") ) ; + m_panel->SetBackgroundColour( wxColour( 64, 64, 64 ) ); + m_statusLine = new wxStaticText( m_panel, wxID_ANY, wxT( "Status text 1\n" ) ) ; m_topSizer->Add( m_statusLine, 1, wxALL | wxEXPAND, 5 ); - + updateSize(); } + PNS_TUNE_STATUS_POPUP::~PNS_TUNE_STATUS_POPUP() { - } -void PNS_TUNE_STATUS_POPUP::Update( PNS_ROUTER *aRouter ) -{ - PNS_MEANDER_PLACER_BASE *placer = dynamic_cast ( aRouter->Placer() ); - if(!placer) +void PNS_TUNE_STATUS_POPUP::Update( PNS_ROUTER* aRouter ) +{ + PNS_MEANDER_PLACER_BASE* placer = dynamic_cast( aRouter->Placer() ); + + if( !placer ) return; - m_statusLine->SetLabel ( placer->TuningInfo() ); + m_statusLine->SetLabel( placer->TuningInfo() ); wxColour color; - switch ( placer->TuningStatus() ) + switch( placer->TuningStatus() ) { - case PNS_MEANDER_PLACER::TUNED: - color = wxColour ( 0, 255, 0 ); - break; - case PNS_MEANDER_PLACER::TOO_SHORT: - color = wxColour ( 255, 128, 128 ); - break; - case PNS_MEANDER_PLACER::TOO_LONG: - color = wxColour ( 128, 128, 255 ); - break; + case PNS_MEANDER_PLACER::TUNED: + color = wxColour( 0, 255, 0 ); + break; + case PNS_MEANDER_PLACER::TOO_SHORT: + color = wxColour( 255, 128, 128 ); + break; + case PNS_MEANDER_PLACER::TOO_LONG: + color = wxColour( 128, 128, 255 ); + break; } - m_statusLine->SetForegroundColour (color); + m_statusLine->SetForegroundColour( color ); - updateSize(); + updateSize(); } diff --git a/pcbnew/router/pns_tune_status_popup.h b/pcbnew/router/pns_tune_status_popup.h index 9a894f3ed4..3776882ad0 100644 --- a/pcbnew/router/pns_tune_status_popup.h +++ b/pcbnew/router/pns_tune_status_popup.h @@ -32,14 +32,13 @@ class PNS_ROUTER; class PNS_TUNE_STATUS_POPUP : public WX_STATUS_POPUP { public: - PNS_TUNE_STATUS_POPUP ( PCB_EDIT_FRAME *parent ); + PNS_TUNE_STATUS_POPUP( PCB_EDIT_FRAME* aParent ); ~PNS_TUNE_STATUS_POPUP(); - - void Update( PNS_ROUTER *aRouter ); + void Update( PNS_ROUTER* aRouter ); private: - wxStaticText *m_statusLine; + wxStaticText* m_statusLine; }; #endif /* __PNS_TUNE_STATUS_POPUP_H_*/ diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index 5635893e10..8ebd055dc5 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -93,82 +93,86 @@ SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ) std::abs( p1.x - p0.x ), std::abs( p1.y - p0.y ) ); } -void DrawDebugPoint ( VECTOR2I p, int color ) + +void DrawDebugPoint( VECTOR2I aP, int aColor ) { SHAPE_LINE_CHAIN l; - l.Append ( p - VECTOR2I(-50000, -50000) ); - l.Append ( p + VECTOR2I(-50000, -50000) ); - + l.Append( aP - VECTOR2I( -50000, -50000 ) ); + l.Append( aP + VECTOR2I( -50000, -50000 ) ); + //printf("router @ %p\n", PNS_ROUTER::GetInstance()); - PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, aColor, 10000 ); l.Clear(); - l.Append ( p - VECTOR2I(50000, -50000) ); - l.Append ( p + VECTOR2I(50000, -50000) ); + l.Append( aP - VECTOR2I( 50000, -50000 ) ); + l.Append( aP + VECTOR2I( 50000, -50000 ) ); - PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + PNS_ROUTER::GetInstance()->DisplayDebugLine( l, aColor, 10000 ); } -void DrawDebugBox ( BOX2I b, int color ) + +void DrawDebugBox( BOX2I aB, int aColor ) { SHAPE_LINE_CHAIN l; - VECTOR2I o = b.GetOrigin(); - VECTOR2I s = b.GetSize(); + VECTOR2I o = aB.GetOrigin(); + VECTOR2I s = aB.GetSize(); + + l.Append( o ); + l.Append( o.x + s.x, o.y ); + l.Append( o.x + s.x, o.y + s.y ); + l.Append( o.x, o.y + s.y ); + l.Append( o ); - l.Append ( o ); - l.Append ( o.x + s.x, o.y ); - l.Append ( o.x + s.x, o.y + s.y ); - l.Append ( o.x, o.y + s.y ); - l.Append ( o ); - //printf("router @ %p\n", PNS_ROUTER::GetInstance()); - PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + PNS_ROUTER::GetInstance()->DisplayDebugLine( l, aColor, 10000 ); } -void DrawDebugSeg ( SEG s, int color ) + +void DrawDebugSeg( SEG aS, int aColor ) { SHAPE_LINE_CHAIN l; - l.Append ( s.A ); - l.Append ( s.B ); - - PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); + l.Append( aS.A ); + l.Append( aS.B ); + + PNS_ROUTER::GetInstance()->DisplayDebugLine( l, aColor, 10000 ); } -void DrawDebugDirs ( VECTOR2D p, int mask, int color ) -{ - BOX2I b ( p - VECTOR2I ( 10000, 10000 ), VECTOR2I ( 20000, 20000 ) ); - DrawDebugBox ( b, color ); - for (int i = 0; i < 8; i++) +void DrawDebugDirs( VECTOR2D aP, int aMask, int aColor ) +{ + BOX2I b( aP - VECTOR2I( 10000, 10000 ), VECTOR2I( 20000, 20000 ) ); + + DrawDebugBox( b, aColor ); + for( int i = 0; i < 8; i++ ) { - if ( (1<OfKind ( PNS_ITEM::VIA ) && aItemB->OfKind ( PNS_ITEM::VIA ) ) + if( aItemA->OfKind( PNS_ITEM::VIA ) && aItemB->OfKind( PNS_ITEM::VIA ) ) { - const PNS_VIA *va = static_cast (aItemA); - const PNS_VIA *vb = static_cast (aItemB); - - return va->ChangedArea (vb); - } else if ( aItemA->OfKind ( PNS_ITEM::LINE ) && aItemB->OfKind ( PNS_ITEM::LINE ) ) - { - const PNS_LINE *la = static_cast (aItemA); - const PNS_LINE *lb = static_cast (aItemB); + const PNS_VIA* va = static_cast( aItemA ); + const PNS_VIA* vb = static_cast( aItemB ); - return la->ChangedArea (lb); + return va->ChangedArea( vb ); } + else if( aItemA->OfKind( PNS_ITEM::LINE ) && aItemB->OfKind( PNS_ITEM::LINE ) ) + { + const PNS_LINE* la = static_cast ( aItemA ); + const PNS_LINE* lb = static_cast ( aItemB ); + + return la->ChangedArea( lb ); + } + return OPT_BOX2I(); -} \ No newline at end of file +} diff --git a/pcbnew/router/pns_utils.h b/pcbnew/router/pns_utils.h index 01f1f0bb6f..bb02d9dbf6 100644 --- a/pcbnew/router/pns_utils.h +++ b/pcbnew/router/pns_utils.h @@ -41,12 +41,12 @@ const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg ); -void DrawDebugPoint ( VECTOR2I p, int color ); -void DrawDebugBox ( BOX2I b, int color ); -void DrawDebugSeg ( SEG s, int color ); -void DrawDebugDirs ( VECTOR2D p, int mask, int color ); +void DrawDebugPoint( VECTOR2I aP, int aColor ); +void DrawDebugBox( BOX2I aB, int aColor ); +void DrawDebugSeg( SEG aS, int aColor ); +void DrawDebugDirs( VECTOR2D aP, int aMask, int aColor ); -OPT_BOX2I ChangedArea ( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB ); +OPT_BOX2I ChangedArea( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB ); #endif // __PNS_UTILS_H diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index 06acf533ea..b038167d3d 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -96,12 +96,13 @@ PNS_VIA* PNS_VIA::Clone ( ) const return v; } -OPT_BOX2I PNS_VIA::ChangedArea ( const PNS_VIA *aOther ) const + +OPT_BOX2I PNS_VIA::ChangedArea ( const PNS_VIA* aOther ) const { if ( aOther->Pos() != Pos() ) { - BOX2I tmp = Shape()->BBox( ); - tmp.Merge ( aOther->Shape()->BBox( ) ); + BOX2I tmp = Shape()->BBox(); + tmp.Merge ( aOther->Shape()->BBox() ); return tmp; } diff --git a/pcbnew/router/pns_via.h b/pcbnew/router/pns_via.h index 1a2dc1d7e8..1417e59c21 100644 --- a/pcbnew/router/pns_via.h +++ b/pcbnew/router/pns_via.h @@ -146,8 +146,8 @@ public: return 1; } - OPT_BOX2I ChangedArea ( const PNS_VIA *aOther ) const; - + OPT_BOX2I ChangedArea( const PNS_VIA* aOther ) const; + private: int m_diameter; int m_drill; diff --git a/pcbnew/router/pns_walkaround.cpp b/pcbnew/router/pns_walkaround.cpp index 9c81860551..da965343ed 100644 --- a/pcbnew/router/pns_walkaround.cpp +++ b/pcbnew/router/pns_walkaround.cpp @@ -99,7 +99,7 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::singleStep( PNS_LINE& aPath, pnew.Append( path_walk[1] ); pnew.Append( path_post[1] ); - if(!path_post[1].PointCount() || !path_walk[1].PointCount()) + if( !path_post[1].PointCount() || !path_walk[1].PointCount() ) current_obs = nearestObstacle( PNS_LINE( aPath, path_pre[1] ) ); else current_obs = nearestObstacle( PNS_LINE( aPath, path_post[1] ) ); @@ -111,7 +111,7 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::singleStep( PNS_LINE& aPath, pnew.Append( path_walk[0] ); pnew.Append( path_post[0] ); - if(!path_post[0].PointCount() || !path_walk[0].PointCount()) + if( !path_post[0].PointCount() || !path_walk[0].PointCount() ) current_obs = nearestObstacle( PNS_LINE( aPath, path_pre[0] ) ); else current_obs = nearestObstacle( PNS_LINE( aPath, path_walk[0] ) ); @@ -146,14 +146,12 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia aWalkPath = aInitialPath; - if(m_forceWinding) + if( m_forceWinding ) { s_cw = m_forceCw ? IN_PROGRESS : STUCK; s_ccw = m_forceCw ? STUCK : IN_PROGRESS; m_forceSingleDirection = true; - } else { - m_forceSingleDirection = false; } @@ -171,9 +169,9 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia 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 ); break; } @@ -244,7 +242,7 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia return STUCK; if( aWalkPath.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) return STUCK; - + WALKAROUND_STATUS st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; if( st == DONE ) @@ -253,7 +251,5 @@ PNS_WALKAROUND::WALKAROUND_STATUS PNS_WALKAROUND::Route( const PNS_LINE& aInitia PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world ); } - - return st; } diff --git a/pcbnew/router/range.h b/pcbnew/router/range.h index 0778cf70e7..5b47c74f1d 100644 --- a/pcbnew/router/range.h +++ b/pcbnew/router/range.h @@ -24,70 +24,70 @@ template class RANGE { - public: - RANGE( T aMin, T aMax ) : - m_min( aMin ), - m_max( aMax ), - m_defined( true ) {} +public: + RANGE( T aMin, T aMax ) : + m_min( aMin ), + m_max( aMax ), + m_defined( true ) {} - RANGE(): - m_defined( false ) {} + RANGE(): + m_defined( false ) {} - T MinV() const - { - return m_min; - } + T MinV() const + { + return m_min; + } - T MaxV() const - { - return m_max; - } + T MaxV() const + { + return m_max; + } - void Set( T aMin, T aMax ) const - { - m_max = aMax; - m_min = aMin; - } + 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 ); - } - } + 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; + bool Inside( const T& aValue ) const + { + if( !m_defined ) + return true; - return aValue >= m_min && aValue <= m_max; - } + return aValue >= m_min && aValue <= m_max; + } - bool Overlaps ( const RANGE& aOther ) const - { - if( !m_defined || !aOther.m_defined ) - return true; + 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; - } + return m_max >= aOther.m_min && m_min <= aOther.m_max; + } - bool Defined() const - { - return m_defined; - } + bool Defined() const + { + return m_defined; + } - private: - T m_min, m_max; - bool m_defined; +private: + T m_min, m_max; + bool m_defined; }; #endif diff --git a/pcbnew/router/ranged_num.h b/pcbnew/router/ranged_num.h index 99a5940e71..5eadaf6879 100644 --- a/pcbnew/router/ranged_num.h +++ b/pcbnew/router/ranged_num.h @@ -17,37 +17,36 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ - + #ifndef __RANGED_NUM_H #define __RANGED_NUM_H template class RANGED_NUM { - public: - RANGED_NUM ( T aValue = 0, T aTollerancePlus = 0, T aTolleranceMinus = 0) : - m_value (aValue), - m_tollerancePlus ( aTollerancePlus ), - m_tolleranceMinus ( aTolleranceMinus ) - {} + public: + RANGED_NUM( T aValue = 0, T aTolerancePlus = 0, T aToleranceMinus = 0 ) : + m_value( aValue ), + m_tolerancePlus( aTolerancePlus ), + m_toleranceMinus( aToleranceMinus ) + {} - operator T() - { - return m_value; - } + operator T() + { + return m_value; + } - RANGED_NUM& operator= ( const T aValue ) - { - m_value = aValue; - return *this; - } + RANGED_NUM& operator=( const T aValue ) + { + m_value = aValue; + return *this; + } - bool Matches ( const T& aOther ) const - { - return ( aOther >= m_value - m_tolleranceMinus && aOther <= m_value + m_tollerancePlus ); - } + bool Matches( const T& aOther ) const + { + return ( aOther >= m_value - m_toleranceMinus && aOther <= m_value + m_tolerancePlus ); + } - private: - T m_value, m_tollerancePlus, m_tolleranceMinus; - + private: + T m_value, m_tolerancePlus, m_toleranceMinus; }; #endif diff --git a/pcbnew/router/router_menus.h b/pcbnew/router/router_menus.h index bafd7360ca..c52c5dab04 100644 --- a/pcbnew/router/router_menus.h +++ b/pcbnew/router/router_menus.h @@ -166,11 +166,11 @@ public: if( bds.m_ViasDimensionsList[i].m_Drill <= 0 ) { - msg << _ (", drill: default"); + msg << _(", drill: default"); } else { - msg << _ (", drill: ") << drill; + msg << _(", drill: ") << drill; } if( i == 0 ) @@ -256,10 +256,10 @@ public: AppendSubMenu( trackMenu, wxT( "Select Track Width" ) ); Add( ACT_CustomTrackWidth ); - + if ( aMode == PNS_MODE_ROUTE_DIFF_PAIR ) Add( ACT_SetDpDimensions ); - + AppendSeparator(); Add( ACT_RouterOptions ); } @@ -274,7 +274,7 @@ ROUTER_TOOL::~ROUTER_TOOL() void ROUTER_TOOL::Reset( RESET_REASON aReason ) { - printf("RESET\n"); + //printf("RESET\n"); if( m_router ) delete m_router; @@ -293,12 +293,13 @@ void ROUTER_TOOL::Reset( RESET_REASON aReason ) if( getView() ) m_router->SetView( getView() ); - + Go( &ROUTER_TOOL::RouteSingleTrace, COMMON_ACTIONS::routerActivateSingle.MakeEvent() ); Go( &ROUTER_TOOL::RouteDiffPair, COMMON_ACTIONS::routerActivateDiffPair.MakeEvent() ); Go( &ROUTER_TOOL::TuneSingleTrace, COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent() ); } + int ROUTER_TOOL::getDefaultWidth( int aNetCode ) { int w, d1, d2; @@ -452,9 +453,9 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) } else if( aEvent.IsAction( &ACT_SetLengthTune ) ) { - PNS_MEANDER_PLACER *placer = dynamic_cast ( m_router->Placer() ); + PNS_MEANDER_PLACER *placer = dynamic_cast ( m_router->Placer() ); - if(!placer) + if( !placer ) return; PNS_MEANDER_SETTINGS settings = placer->Settings(); @@ -479,10 +480,9 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) { - - PNS_SIZES_SETTINGS sizes ( m_savedSizes ); - sizes.ImportCurrent ( m_board->GetDesignSettings() ); - m_router->UpdateSizes ( sizes ); + PNS_SIZES_SETTINGS sizes( m_savedSizes ); + sizes.ImportCurrent( m_board->GetDesignSettings() ); + m_router->UpdateSizes( sizes ); } } @@ -496,7 +496,7 @@ void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) if( aEvent.IsMotion() || aEvent.IsClick() ) { bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); - + VECTOR2I p( aEvent.Position() ); startItem = pickSingleItem( p ); m_router->EnableSnapping ( snapEnabled ); @@ -581,6 +581,7 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) TRACE( 0, "%s, layer : %d", m_endItem->KindStr().c_str() % m_endItem->Layers().Start() ); } + int ROUTER_TOOL::getStartLayer( const PNS_ITEM* aItem ) { int tl = getView()->GetTopLayer(); @@ -597,6 +598,8 @@ int ROUTER_TOOL::getStartLayer( const PNS_ITEM* aItem ) return tl; } + + void ROUTER_TOOL::switchLayerOnViaPlacement() { int al = m_frame->GetActiveLayer(); @@ -616,10 +619,11 @@ void ROUTER_TOOL::switchLayerOnViaPlacement() } } + bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) { BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - + const int layerCount = bds.GetCopperLayerCount(); int currentLayer = m_router->GetCurrentLayer(); @@ -651,7 +655,6 @@ bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) return false; } - sizes.SetViaType ( aType ); m_router->ToggleViaPlacement( ); m_router->UpdateSizes( sizes ); @@ -667,9 +670,9 @@ bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) void ROUTER_TOOL::performRouting() { bool saveUndoBuffer = true; - - int routingLayer = getStartLayer ( m_startItem ); - m_frame->SetActiveLayer( ToLAYER_ID ( routingLayer ) ); + + int routingLayer = getStartLayer( m_startItem ); + m_frame->SetActiveLayer( ToLAYER_ID( routingLayer ) ); // fixme: switch on invisible layer if( m_startItem && m_startItem->Net() >= 0 ) @@ -686,19 +689,18 @@ void ROUTER_TOOL::performRouting() PNS_SIZES_SETTINGS sizes ( m_savedSizes ); sizes.Init ( m_board, m_startItem ); - sizes.AddLayerPair ( m_frame->GetScreen()->m_Route_Layer_TOP, - m_frame->GetScreen()->m_Route_Layer_BOTTOM ); + sizes.AddLayerPair( m_frame->GetScreen()->m_Route_Layer_TOP, + m_frame->GetScreen()->m_Route_Layer_BOTTOM ); m_router->UpdateSizes( sizes ); if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) ) { - wxMessageBox ( m_router->FailureReason(), _("Error") ); - highlightNet ( false ); + wxMessageBox( m_router->FailureReason(), _( "Error" ) ); + highlightNet( false ); return; } - - m_tuneStatusPopup = new PNS_TUNE_STATUS_POPUP ( m_frame ); + m_tuneStatusPopup = new PNS_TUNE_STATUS_POPUP( m_frame ); m_tuneStatusPopup->Popup(); m_endItem = NULL; @@ -715,16 +717,14 @@ void ROUTER_TOOL::performRouting() } else if( evt->IsMotion() ) { - wxPoint p = wxGetMousePosition(); - p.x+=20; - p.y+=20; - m_tuneStatusPopup->Update (m_router); - m_tuneStatusPopup->Move(p); - + p.x += 20; + p.y += 20; + m_tuneStatusPopup->Update( m_router ); + m_tuneStatusPopup->Move( p ); updateEndItem( *evt ); - m_router->SetOrthoMode ( evt->Modifier ( MD_CTRL ) ); + m_router->SetOrthoMode( evt->Modifier ( MD_CTRL ) ); m_router->Move( m_endSnapPoint, m_endItem ); } else if( evt->IsClick( BUT_LEFT ) ) @@ -796,24 +796,28 @@ void ROUTER_TOOL::performRouting() highlightNet( false ); } + int ROUTER_TOOL::RouteSingleTrace( TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Route Track" ) ); return mainLoop( PNS_MODE_ROUTE_SINGLE ); } + int ROUTER_TOOL::RouteDiffPair( TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Router Differential Pair" ) ); return mainLoop( PNS_MODE_ROUTE_DIFF_PAIR ); } + int ROUTER_TOOL::TuneSingleTrace( TOOL_EVENT& aEvent ) { m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Tune Track Length" ) ); return mainLoop( PNS_MODE_TUNE_SINGLE ); } + int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) { PCB_EDIT_FRAME* frame = getEditFrame(); @@ -825,7 +829,7 @@ int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) Activate(); m_router->SetMode ( aMode ); - + m_ctls->SetSnapping( true ); m_ctls->ShowCursor( true ); @@ -875,7 +879,8 @@ int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) return 0; } -int ROUTER_TOOL::InlineDrag ( TOOL_EVENT& aEvent ) + +int ROUTER_TOOL::InlineDrag( TOOL_EVENT& aEvent ) { return 0; @@ -903,7 +908,7 @@ int ROUTER_TOOL::InlineDrag ( TOOL_EVENT& aEvent ) { updateEndItem( *evt ); m_router->Move( m_endSnapPoint, m_endItem ); - } + } else if( evt->IsUp( BUT_LEFT ) ) { if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) @@ -919,6 +924,7 @@ int ROUTER_TOOL::InlineDrag ( TOOL_EVENT& aEvent ) } + void ROUTER_TOOL::performDragging() { PCB_EDIT_FRAME* frame = getEditFrame(); diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index a3a44baf5a..da9a0f0820 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -57,16 +57,15 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS_ITEM* aItem ) { m_originLayer = aItem->Layers().Start(); - - if (aItem->OfKind ( PNS_ITEM::LINE )) + if( aItem->OfKind ( PNS_ITEM::LINE ) ) { - const PNS_LINE *l=static_cast (aItem); - if(!l->SegmentCount()) + const PNS_LINE* l=static_cast( aItem ); + if( !l->SegmentCount() ) return; } assert( m_originLayer >= 0 ); - + m_layer = m_originLayer; m_color = getLayerColor( m_originLayer ); m_color.a = 0.8; @@ -139,7 +138,7 @@ const BOX2I ROUTER_PREVIEW_ITEM::ViewBBox() const } -void ROUTER_PREVIEW_ITEM::drawLineChain( const SHAPE_LINE_CHAIN &aL, KIGFX::GAL* aGal ) 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 ); diff --git a/pcbnew/router/router_preview_item.h b/pcbnew/router/router_preview_item.h index aeb5492979..a5b6759755 100644 --- a/pcbnew/router/router_preview_item.h +++ b/pcbnew/router/router_preview_item.h @@ -50,19 +50,19 @@ public: PR_POINT, PR_SHAPE }; - + 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 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 SetColor( const KIGFX::COLOR4D& aColor ) + void SetColor( const KIGFX::COLOR4D& aColor ) { m_color = aColor; } @@ -96,7 +96,7 @@ private: SHAPE* m_shape; ITEM_TYPE m_type; - + int m_style; int m_width; int m_layer; diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 09f30942d5..088695d8a9 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -87,7 +87,7 @@ static TOOL_ACTION ACT_SetDpDimensions( "pcbnew.InteractiveRouter.SetDpDimension ROUTER_TOOL::ROUTER_TOOL() : PNS_TOOL_BASE( "pcbnew.InteractiveRouter" ) -{ +{ } @@ -229,10 +229,10 @@ public: AppendSubMenu( trackMenu, wxT( "Select Track Width" ) ); Add( ACT_CustomTrackWidth ); - + if ( aMode == PNS_MODE_ROUTE_DIFF_PAIR ) Add( ACT_SetDpDimensions ); - + AppendSeparator(); Add( PNS_TOOL_BASE::ACT_RouterOptions ); } @@ -248,12 +248,12 @@ ROUTER_TOOL::~ROUTER_TOOL() void ROUTER_TOOL::Reset( RESET_REASON aReason ) { PNS_TOOL_BASE::Reset( aReason ); - + Go( &ROUTER_TOOL::RouteSingleTrace, COMMON_ACTIONS::routerActivateSingle.MakeEvent() ); Go( &ROUTER_TOOL::RouteDiffPair, COMMON_ACTIONS::routerActivateDiffPair.MakeEvent() ); Go( &ROUTER_TOOL::DpDimensionsDialog, COMMON_ACTIONS::routerActivateDpDimensionsDialog.MakeEvent() ); Go( &ROUTER_TOOL::SettingsDialog, COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent() ); - + } int ROUTER_TOOL::getDefaultWidth( int aNetCode ) @@ -381,7 +381,7 @@ void ROUTER_TOOL::switchLayerOnViaPlacement() bool ROUTER_TOOL::onViaCommand( VIATYPE_T aType ) { BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - + const int layerCount = bds.GetCopperLayerCount(); int currentLayer = m_router->GetCurrentLayer(); @@ -449,7 +449,7 @@ bool ROUTER_TOOL::prepareInteractive() sizes.AddLayerPair ( m_frame->GetScreen()->m_Route_Layer_TOP, m_frame->GetScreen()->m_Route_Layer_BOTTOM ); m_router->UpdateSizes( sizes ); - + if ( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) ) { wxMessageBox ( m_router->FailureReason(), _("Error") ); @@ -570,7 +570,7 @@ int ROUTER_TOOL::DpDimensionsDialog( const TOOL_EVENT& aEvent ) { m_router->UpdateSizes( sizes ); m_savedSizes = sizes; - } + } return 0; } @@ -612,7 +612,7 @@ int ROUTER_TOOL::mainLoop( PNS_ROUTER_MODE aMode ) Activate(); m_router->SetMode ( aMode ); - + m_ctls->SetSnapping( true ); m_ctls->ShowCursor( true ); diff --git a/pcbnew/router/time_limit.h b/pcbnew/router/time_limit.h index 8c7a07db5e..233fd96a1d 100644 --- a/pcbnew/router/time_limit.h +++ b/pcbnew/router/time_limit.h @@ -26,17 +26,17 @@ class TIME_LIMIT { public: - TIME_LIMIT( int aMilliseconds = 0 ); - ~TIME_LIMIT(); + TIME_LIMIT( int aMilliseconds = 0 ); + ~TIME_LIMIT(); - bool Expired() const; - void Restart(); + bool Expired() const; + void Restart(); - void Set( int aMilliseconds ); + void Set( int aMilliseconds ); private: - int m_limitMs; - int64_t m_startTics; + int m_limitMs; + int64_t m_startTics; }; #endif diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 2a5f4e84ea..47828f0d56 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -61,22 +61,22 @@ TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", // Edit tool actions TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor", AS_CONTEXT, MD_CTRL + 'E', - "Open in Footprint Editor", + "Open in Footprint Editor", "Opens the selected footprint in the Footprint Editor" ); TOOL_ACTION COMMON_ACTIONS::copyPadToSettings ( "pcbnew.InteractiveEdit.copyPadToSettings", AS_CONTEXT, 0, - "Copy pad settings to Current Settings", + "Copy pad settings to Current Settings", "Copies the properties of selected pad to the current template pad settings." ); TOOL_ACTION COMMON_ACTIONS::copySettingsToPads ( "pcbnew.InteractiveEdit.copySettingsToPads", AS_CONTEXT, 0, - "Copy Current Settings to pads", + "Copy Current Settings to pads", "Copies the current template pad settings to the selected pad(s)." ); TOOL_ACTION COMMON_ACTIONS::globalEditPads ( "pcbnew.InteractiveEdit.globalPadEdit", AS_CONTEXT, 0, - "Global Pad Edition", + "Global Pad Edition", "Changes pad properties globally." ); TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", @@ -481,13 +481,13 @@ boost::optional COMMON_ACTIONS::TranslateLegacyId( int aId ) case ID_TUNE_SINGLE_TRACK_LEN_BUTT: return COMMON_ACTIONS::routerActivateTuneSingleTrace.MakeEvent(); - + case ID_TUNE_DIFF_PAIR_LEN_BUTT: return COMMON_ACTIONS::routerActivateTuneDiffPair.MakeEvent(); - + case ID_TUNE_DIFF_PAIR_SKEW_BUTT: return COMMON_ACTIONS::routerActivateTuneDiffPairSkew.MakeEvent(); - + case ID_MENU_INTERACTIVE_ROUTER_SETTINGS: return COMMON_ACTIONS::routerActivateSettingsDialog.MakeEvent(); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 5efe6e9515..3e2c392598 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -116,10 +116,10 @@ public: static TOOL_ACTION arcPosture; // Push and Shove Router Tool - + /// Activation of the Push and Shove router static TOOL_ACTION routerActivateSingle; - + /// Activation of the Push and Shove router (differential pair mode) static TOOL_ACTION routerActivateDiffPair; @@ -128,14 +128,14 @@ public: /// Activation of the Push and Shove router (diff pair tuning mode) static TOOL_ACTION routerActivateTuneDiffPair; - + /// Activation of the Push and Shove router (skew tuning mode) static TOOL_ACTION routerActivateTuneDiffPairSkew; /// Activation of the Push and Shove settings dialogs static TOOL_ACTION routerActivateSettingsDialog; static TOOL_ACTION routerActivateDpDimensionsDialog; - + /// Activation of the Push and Shove router (inline dragging mode) static TOOL_ACTION routerInlineDrag; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 1c772b0944..bb017f42a8 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -80,8 +80,8 @@ bool EDIT_TOOL::Init() m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); // Footprint actions - m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, - SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && + m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, + SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && SELECTION_CONDITIONS::Count ( 1 ) ); m_offset.x = 0; @@ -94,12 +94,12 @@ bool EDIT_TOOL::Init() bool EDIT_TOOL::invokeInlineRouter() { - TRACK *track = uniqueSelected (); - VIA *via = uniqueSelected (); + TRACK *track = uniqueSelected(); + VIA *via = uniqueSelected(); if( track || via ) { - printf("Calling interactive drag\n"); + //printf("Calling interactive drag\n"); m_toolMgr->RunAction( COMMON_ACTIONS::routerInlineDrag, true ); return true; } @@ -115,7 +115,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) bool unselect = selection.Empty(); // Be sure that there is at least one item that we can modify. If nothing was selected before, - // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) + // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) if( !hoverSelection( selection ) ) { setTransitions(); @@ -184,15 +184,12 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) VECTOR2I mousePos = evt->Position(); - m_cursor = grid.Align ( evt->Position() ); - isDragAndDrop = evt->IsDrag( BUT_LEFT ); - + m_cursor = grid.Align( evt->Position() ); + isDragAndDrop = evt->IsDrag( BUT_LEFT ); if( m_dragging ) { - - - m_cursor = grid.BestSnapAnchor ( evt->Position(), selection.Item( 0 ) ); + m_cursor = grid.BestSnapAnchor( evt->Position(), selection.Item( 0 ) ); getViewControls()->ForceCursorPosition ( true, m_cursor ); wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - @@ -206,40 +203,39 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } else // Prepare to start dragging { - m_selectionTool->SanitizeSelection( ); - - if ( selection.Empty() ) + m_selectionTool->SanitizeSelection(); + + if( selection.Empty() ) break; - // deal with locked items (override lock or abort the operation) + // deal with locked items (override lock or abort the operation) SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock(); - - if ( lockFlags == SELECTION_LOCKED ) + + if( lockFlags == SELECTION_LOCKED ) break; - else if ( lockFlags == SELECTION_LOCK_OVERRIDE ) + else if( lockFlags == SELECTION_LOCK_OVERRIDE ) lockOverride = true; - + // Save items, so changes can be undone editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); VECTOR2I origin; - if( evt->IsDrag( BUT_LEFT ) ) mousePos = evt->DragOrigin(); // origin = grid.Align ( evt->DragOrigin() ); //else - origin = grid.Align ( mousePos ); + origin = grid.Align( mousePos ); if( selection.Size() == 1 ) { // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later - m_cursor = grid.BestDragOrigin ( mousePos, selection.Item( 0 ) ); + m_cursor = grid.BestDragOrigin( mousePos, selection.Item( 0 ) ); getViewControls()->ForceCursorPosition ( true, m_cursor ); - grid.SetAuxAxes ( true, m_cursor ); + grid.SetAuxAxes( true, m_cursor ); VECTOR2I o = VECTOR2I( selection.Item( 0 )->GetPosition() ); m_offset.x = o.x - m_cursor.x; @@ -249,9 +245,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) { m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - wxPoint( origin.x, origin.y ); - - getViewControls()->ForceCursorPosition ( true, origin ); - + getViewControls()->ForceCursorPosition( true, origin ); } controls->SetAutoPan( true ); @@ -263,8 +257,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) - { - if (!isDragAndDrop || !lockOverride ) + { + if( !isDragAndDrop || !lockOverride ) break; // Finish lockOverride = false; @@ -543,7 +537,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) if( m_editModules ) { - MODULE* module = static_cast( aItem->GetParent() ); module->SetLastEditTime(); board->m_Status_Pcb = 0; // it is done in the legacy view @@ -562,19 +555,20 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) board->m_Status_Pcb = 0; // it is done in the legacy view - if(!m_editModules) + if( !m_editModules ) { - if(aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1) + if( aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1 ) { DisplayError( getEditFrame(), _( "Cannot delete the only remaining pad of the module (modules on PCB must have at least one pad)." ) ); return; } + getView()->Remove( aItem ); board->Remove( aItem ); } - + aItem->DeleteStructure(); - + return; } @@ -653,19 +647,19 @@ bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) { m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); - if ( m_selectionTool->CheckLock() == SELECTION_LOCKED ) + if( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { - m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); return false; } } - if ( aSanitize ) + if( aSanitize ) m_selectionTool->SanitizeSelection(); - if ( aSelection.Empty() ) + if( aSelection.Empty() ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - + return !aSelection.Empty(); } @@ -707,9 +701,10 @@ void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) } } + int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) { - MODULE *mod = uniqueSelected (); + MODULE *mod = uniqueSelected(); if( !mod ) return 0; @@ -726,7 +721,7 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) editFrame->Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); - editor->Load_Module_From_BOARD( (MODULE*)editFrame->GetCurItem() ); + editor->Load_Module_From_BOARD( (MODULE*) editFrame->GetCurItem() ); editFrame->SetCurItem( NULL ); // the current module could be deleted by editor->Show( true ); diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index c2ded9a84a..2b333e49d4 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -156,15 +156,15 @@ private: bool invokeInlineRouter(); - template T* uniqueSelected() + template T* uniqueSelected() { const SELECTION& selection = m_selectionTool->GetSelection(); - if(selection.items.GetCount() > 1) + if( selection.items.GetCount() > 1 ) return NULL; - BOARD_ITEM *item = selection.Item( 0 ); - return dyn_cast (item); + BOARD_ITEM* item = selection.Item( 0 ); + return dyn_cast( item ); } }; diff --git a/pcbnew/tools/grid_helper.cpp b/pcbnew/tools/grid_helper.cpp index 271aae5462..c141d16aaa 100644 --- a/pcbnew/tools/grid_helper.cpp +++ b/pcbnew/tools/grid_helper.cpp @@ -40,223 +40,230 @@ #include "grid_helper.h" -GRID_HELPER::GRID_HELPER ( PCB_BASE_FRAME *aFrame ) : - m_frame ( aFrame ) -{ - -} - -GRID_HELPER::~GRID_HELPER () -{ - -} - -void GRID_HELPER::SetGrid ( int aSize ) -{ - assert ( false ); -} - -void GRID_HELPER::SetOrigin ( const VECTOR2I& aOrigin ) +GRID_HELPER::GRID_HELPER( PCB_BASE_FRAME* aFrame ) : + m_frame( aFrame ) { } -VECTOR2I GRID_HELPER::GetGrid () + +GRID_HELPER::~GRID_HELPER() { - PCB_SCREEN *screen = m_frame->GetScreen(); - - const wxRealPoint& size = screen->GetGridSize(); - - return VECTOR2I ( KiROUND ( size.x ), KiROUND ( size.y ) ); } -VECTOR2I GRID_HELPER::GetOrigin () + +void GRID_HELPER::SetGrid( int aSize ) { - return VECTOR2I ( 0, 0 ); + assert( false ); } -void GRID_HELPER::SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal) -{ - if( aEnable ) - m_auxAxis = aOrigin; - else - m_auxAxis = boost::optional (); - m_diagonalAuxAxesEnable = aEnable; +void GRID_HELPER::SetOrigin( const VECTOR2I& aOrigin ) +{ } -VECTOR2I GRID_HELPER::Align ( const VECTOR2I& aPoint ) -{ - const VECTOR2D gridOffset ( GetOrigin () ); - const VECTOR2D gridSize ( GetGrid() ); - VECTOR2I nearest ( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x, +VECTOR2I GRID_HELPER::GetGrid() +{ + PCB_SCREEN* screen = m_frame->GetScreen(); + + const wxRealPoint& size = screen->GetGridSize(); + + return VECTOR2I ( KiROUND( size.x ), KiROUND( size.y ) ); +} + + +VECTOR2I GRID_HELPER::GetOrigin() +{ + return VECTOR2I( 0, 0 ); +} + + +void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal ) +{ + if( aEnable ) + m_auxAxis = aOrigin; + else + m_auxAxis = boost::optional(); + + m_diagonalAuxAxesEnable = aEnable; +} + + +VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) +{ + const VECTOR2D gridOffset( GetOrigin () ); + const VECTOR2D gridSize( GetGrid() ); + + VECTOR2I nearest( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x, round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y ); - if ( !m_auxAxis ) - return nearest; + if( !m_auxAxis ) + return nearest; - if ( std::abs ( m_auxAxis->x - aPoint.x) < std::abs ( nearest.x - aPoint.x ) ) - nearest.x = m_auxAxis->x; + if( std::abs( m_auxAxis->x - aPoint.x) < std::abs( nearest.x - aPoint.x ) ) + nearest.x = m_auxAxis->x; - if ( std::abs ( m_auxAxis->y - aPoint.y) < std::abs ( nearest.y - aPoint.y ) ) - nearest.y = m_auxAxis->y; + if( std::abs( m_auxAxis->y - aPoint.y) < std::abs( nearest.y - aPoint.y ) ) + nearest.y = m_auxAxis->y; - return nearest; + return nearest; } -VECTOR2I GRID_HELPER::BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ) + +VECTOR2I GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, BOARD_ITEM* aItem ) { clearAnchors(); - computeAnchors( aItem, aMousePos ); - + computeAnchors( aItem, aMousePos ); + double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); double lineSnapMinCornerDistance = 50.0 / worldScale; - ANCHOR* nearestOutline = nearestAnchor ( aMousePos, OUTLINE, LSET::AllLayersMask() ); - ANCHOR* nearestCorner = nearestAnchor ( aMousePos, CORNER, LSET::AllLayersMask() ); - ANCHOR* nearestOrigin = nearestAnchor ( aMousePos, ORIGIN, LSET::AllLayersMask() ); - ANCHOR* best = NULL; - double minDist = std::numeric_limits::max(); + ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() ); + ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() ); + ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() ); + ANCHOR* best = NULL; + double minDist = std::numeric_limits::max(); - if (nearestOrigin) - { - minDist = nearestOrigin->Distance(aMousePos); - best = nearestOrigin; - } - - if (nearestCorner) - { - double dist = nearestCorner->Distance(aMousePos); - if (dist < minDist) - { - minDist = dist; - best = nearestCorner; - } - } - - if (nearestOutline) + if( nearestOrigin ) { - double dist = nearestOutline->Distance(aMousePos); - if (minDist > lineSnapMinCornerDistance && dist < minDist) - best = nearestOutline; + minDist = nearestOrigin->Distance( aMousePos ); + best = nearestOrigin; + } + + if( nearestCorner ) + { + double dist = nearestCorner->Distance( aMousePos ); + if( dist < minDist ) + { + minDist = dist; + best = nearestCorner; + } + } + + if( nearestOutline ) + { + double dist = nearestOutline->Distance( aMousePos ); + if( minDist > lineSnapMinCornerDistance && dist < minDist ) + best = nearestOutline; } return best ? best->pos : aMousePos; } -std::set GRID_HELPER::queryVisible ( const BOX2I& aArea ) + +std::set GRID_HELPER::queryVisible( const BOX2I& aArea ) { - std::set items; + std::set items; std::vector selectedItems; - std::vector::iterator it, it_end; + std::vector::iterator it, it_end; - m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items + m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items - for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) + for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { - BOARD_ITEM* item = static_cast( it->first ); - if( item->ViewIsVisible() ) - items.insert ( item ); + BOARD_ITEM* item = static_cast( it->first ); + if( item->ViewIsVisible() ) + items.insert ( item ); } return items; } -VECTOR2I GRID_HELPER::BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ) -{ - double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); - int snapRange = (int) (100.0 / worldScale); - BOX2I bb ( VECTOR2I ( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2) , VECTOR2I (snapRange, snapRange) ); +VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I &aOrigin, BOARD_ITEM* aDraggedItem ) +{ + double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); + int snapRange = (int) ( 100.0 / worldScale ); + + BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2 ), VECTOR2I( snapRange, snapRange ) ); clearAnchors(); - BOOST_FOREACH ( BOARD_ITEM *item, queryVisible ( bb ) ) + BOOST_FOREACH( BOARD_ITEM* item, queryVisible( bb ) ) { - computeAnchors(item, aOrigin); + computeAnchors( item, aOrigin ); } - LSET layers ( aDraggedItem->GetLayer() ); - ANCHOR *nearest = nearestAnchor ( aOrigin, CORNER | SNAPPABLE, layers ); + LSET layers( aDraggedItem->GetLayer() ); + ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers ); - VECTOR2I nearestGrid = Align ( aOrigin ); - double gridDist = (nearestGrid - aOrigin).EuclideanNorm(); - if (nearest) + VECTOR2I nearestGrid = Align( aOrigin ); + double gridDist = ( nearestGrid - aOrigin ).EuclideanNorm(); + if( nearest ) { - double snapDist = nearest->Distance ( aOrigin ); + double snapDist = nearest->Distance( aOrigin ); - if(nearest && snapDist < gridDist) - return nearest->pos; - } + if( nearest && snapDist < gridDist ) + return nearest->pos; + } - return nearestGrid; + return nearestGrid; } -void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ) -{ - VECTOR2I origin; - - switch ( aItem->Type() ) +void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos ) +{ + VECTOR2I origin; + + switch( aItem->Type() ) { case PCB_MODULE_T: { - MODULE *mod = static_cast (aItem); - addAnchor ( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); + MODULE* mod = static_cast( aItem ); + addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); + + for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() ) + addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); - for (D_PAD *pad = mod->Pads(); pad; pad = pad->Next() ) - addAnchor ( pad->GetPosition(), CORNER | SNAPPABLE, pad ); - break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { - DRAWSEGMENT *dseg = static_cast (aItem); + DRAWSEGMENT* dseg = static_cast( aItem ); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); - //LAYER_ID layer = dseg->GetLayer(); - + //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { - int r = (start - end).EuclideanNorm(); - - addAnchor ( start, ORIGIN | SNAPPABLE, dseg ); - addAnchor ( start + VECTOR2I ( -r, 0 ) , OUTLINE | SNAPPABLE, dseg ); - addAnchor ( start + VECTOR2I ( r, 0 ) , OUTLINE | SNAPPABLE, dseg ); - addAnchor ( start + VECTOR2I ( 0, -r ) , OUTLINE | SNAPPABLE, dseg); - addAnchor ( start + VECTOR2I ( 0, r ) , OUTLINE | SNAPPABLE, dseg ); + int r = ( start - end ).EuclideanNorm(); + + addAnchor( start, ORIGIN | SNAPPABLE, dseg ); + addAnchor( start + VECTOR2I ( -r, 0 ), OUTLINE | SNAPPABLE, dseg ); + addAnchor( start + VECTOR2I ( r, 0 ), OUTLINE | SNAPPABLE, dseg ); + addAnchor( start + VECTOR2I ( 0, -r ), OUTLINE | SNAPPABLE, dseg); + addAnchor( start + VECTOR2I ( 0, r ), OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); - addAnchor ( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); - addAnchor ( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); - addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); - break; + addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); + addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); + addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); + break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; - addAnchor ( start, CORNER | SNAPPABLE, dseg ); - addAnchor ( end, CORNER | SNAPPABLE, dseg ); - addAnchor ( origin, ORIGIN, dseg ); + addAnchor( start, CORNER | SNAPPABLE, dseg ); + addAnchor( end, CORNER | SNAPPABLE, dseg ); + addAnchor( origin, ORIGIN, dseg ); break; - } + } default: { origin = dseg->GetStart(); - addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); + addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } } @@ -265,70 +272,68 @@ void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ) case PCB_TRACE_T: { - TRACK *track = static_cast (aItem); + TRACK* track = static_cast( aItem ); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; - addAnchor ( start, CORNER | SNAPPABLE, track ); - addAnchor ( end, CORNER | SNAPPABLE, track ); - addAnchor ( origin, ORIGIN, track); + addAnchor( start, CORNER | SNAPPABLE, track ); + addAnchor( end, CORNER | SNAPPABLE, track ); + addAnchor( origin, ORIGIN, track); break; - } + } case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); - + SHAPE_LINE_CHAIN lc; - lc.SetClosed ( true ); - + lc.SetClosed( true ); + for( int i = 0; i < cornersCount; ++i ) { - const VECTOR2I p ( outline->GetPos( i ) ); - addAnchor ( p, CORNER, aItem ); - lc.Append ( p ); - } + const VECTOR2I p ( outline->GetPos( i ) ); + addAnchor( p, CORNER, aItem ); + lc.Append( p ); + } - addAnchor( lc.NearestPoint ( aRefPos ), OUTLINE, aItem ); + addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: - addAnchor ( aItem->GetPosition(), ORIGIN, aItem ); + addAnchor( aItem->GetPosition(), ORIGIN, aItem ); default: - break; } - } -GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ) + +GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor( VECTOR2I aPos, int aFlags, LSET aMatchLayers ) { - double minDist = std::numeric_limits::max(); - ANCHOR *best = NULL; + double minDist = std::numeric_limits::max(); + ANCHOR* best = NULL; - BOOST_FOREACH( ANCHOR& a, m_anchors ) - { - if ( !aMatchLayers [ a.item->GetLayer() ] ) - continue; + BOOST_FOREACH( ANCHOR& a, m_anchors ) + { + if( !aMatchLayers[a.item->GetLayer()] ) + continue; - if ( ( aFlags & a.flags ) != aFlags ) - continue; + if( ( aFlags & a.flags ) != aFlags ) + continue; - double dist = a.Distance(aPos); + double dist = a.Distance( aPos ); - if(dist < minDist) - { - minDist = dist; - best = &a; - } - } + if( dist < minDist ) + { + minDist = dist; + best = &a; + } + } - return best; - -} \ No newline at end of file + return best; +} diff --git a/pcbnew/tools/grid_helper.h b/pcbnew/tools/grid_helper.h index 11e9c7ce47..59435b5d1a 100644 --- a/pcbnew/tools/grid_helper.h +++ b/pcbnew/tools/grid_helper.h @@ -37,69 +37,68 @@ class PCB_BASE_FRAME; class GRID_HELPER { public: - GRID_HELPER ( PCB_BASE_FRAME *aFrame ); - ~GRID_HELPER (); + GRID_HELPER( PCB_BASE_FRAME* aFrame ); + ~GRID_HELPER(); - void SetGrid ( int aSize ); - void SetOrigin ( const VECTOR2I& aOrigin ); - - VECTOR2I GetGrid (); - VECTOR2I GetOrigin (); + void SetGrid( int aSize ); + void SetOrigin( const VECTOR2I& aOrigin ); - void SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin = VECTOR2I(0, 0), bool aEnableDiagonal = false ); - - VECTOR2I Align ( const VECTOR2I& aPoint ); + VECTOR2I GetGrid(); + VECTOR2I GetOrigin(); - VECTOR2I BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ); - VECTOR2I BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ); + void SetAuxAxes( bool aEnable, const VECTOR2I aOrigin = VECTOR2I( 0, 0 ), bool aEnableDiagonal = false ); + + VECTOR2I Align( const VECTOR2I& aPoint ); + + VECTOR2I BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM* aItem ); + VECTOR2I BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM* aDraggedItem ); private: + enum ANCHOR_FLAGS { + CORNER = 0x1, + OUTLINE = 0x2, + SNAPPABLE = 0x4, + ORIGIN = 0x8 + }; - enum ANCHOR_FLAGS { - CORNER = 0x1, - OUTLINE = 0x2, - SNAPPABLE = 0x4, - ORIGIN = 0x8 - }; + struct ANCHOR + { + ANCHOR( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM* aItem = NULL ): + pos( aPos ), flags( aFlags ), item( aItem ) {} ; - struct ANCHOR - { - ANCHOR ( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM *aItem = NULL ): - pos (aPos), flags (aFlags), item (aItem) {} ; + VECTOR2I pos; + int flags; + BOARD_ITEM* item; - VECTOR2I pos; - int flags; - BOARD_ITEM *item; - - double Distance ( const VECTOR2I& aP ) - { - return (aP - pos).EuclideanNorm(); - } + double Distance( const VECTOR2I& aP ) + { + return ( aP - pos ).EuclideanNorm(); + } - bool CanSnapItem ( const BOARD_ITEM *aItem ); - }; + bool CanSnapItem( const BOARD_ITEM* aItem ); + }; - std::vector m_anchors; + std::vector m_anchors; - std::set queryVisible ( const BOX2I& aArea ); + std::set queryVisible( const BOX2I& aArea ); - void addAnchor( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM *aItem = NULL ) - { - m_anchors.push_back( ANCHOR( aPos, aFlags, aItem ) ); - } + void addAnchor( VECTOR2I aPos, int aFlags = CORNER | SNAPPABLE, BOARD_ITEM* aItem = NULL ) + { + m_anchors.push_back( ANCHOR( aPos, aFlags, aItem ) ); + } - ANCHOR* nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ); + ANCHOR* nearestAnchor( VECTOR2I aPos, int aFlags, LSET aMatchLayers ); - void computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ); + void computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos ); - void clearAnchors () - { - m_anchors.clear(); - } + void clearAnchors () + { + m_anchors.clear(); + } - PCB_BASE_FRAME* m_frame; - boost::optional m_auxAxis; - bool m_diagonalAuxAxesEnable; + PCB_BASE_FRAME* m_frame; + boost::optional m_auxAxis; + bool m_diagonalAuxAxesEnable; }; #endif diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index ae66146ce4..cdb5e35c73 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -36,7 +36,6 @@ #include #include - #include #include #include @@ -277,7 +276,7 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aOnDrag ) // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0; --i ) { - if( !selectable( collector[i] ) || ( aOnDrag && collector[i]->IsLocked() )) + if( !selectable( collector[i] ) || ( aOnDrag && collector[i]->IsLocked() ) ) collector.Remove( i ); } @@ -294,8 +293,7 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aOnDrag ) return true; - default: - + default: // Apply some ugly heuristics to avoid disambiguation menus whenever possible guessSelectionCandidates( collector ); @@ -306,7 +304,7 @@ bool SELECTION_TOOL::selectCursor( const VECTOR2I& aWhere, bool aOnDrag ) return true; } - else if( collector.GetCount() > 1 ) + else if( collector.GetCount() > 1 ) { if( aOnDrag ) Wait ( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); @@ -414,6 +412,7 @@ void SELECTION_TOOL::setTransitions() Go( &SELECTION_TOOL::findMove, COMMON_ACTIONS::findMove.MakeEvent() ); } + SELECTION_LOCK_FLAGS SELECTION_TOOL::CheckLock() { if( !m_locked || m_editModules ) @@ -521,6 +520,7 @@ void SELECTION_TOOL::findCallback( BOARD_ITEM* aItem ) { clearSelection(); select( aItem ); + getView()->SetCenter( VECTOR2D( aItem->GetPosition() ) ); // Inform other potentially interested tools m_toolMgr->ProcessEvent( SelectedEvent ); @@ -571,9 +571,9 @@ void SELECTION_TOOL::clearSelection() { BOARD_ITEM* item = static_cast( *it ); - item->ViewHide ( false ); + item->ViewHide( false ); item->ClearSelected(); - item->ViewUpdate ( KIGFX::VIEW_ITEM::GEOMETRY ) ; + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ) ; } m_selection.clear(); @@ -742,6 +742,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const case PCB_MODULE_TEXT_T: if( m_multiple && !m_editModules ) return false; + return aItem->ViewIsVisible() && board->IsLayerVisible( aItem->GetLayer() ); // These are not selectable @@ -751,7 +752,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const if( m_multiple && !m_editModules ) return false; - MODULE *mod = static_cast (aItem) -> GetParent(); + MODULE* mod = static_cast( aItem )->GetParent(); if( mod && mod->IsLocked() ) return false; @@ -781,7 +782,7 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) module->RunOnChildren( boost::bind( &SELECTION_TOOL::selectVisually, this, _1 ) ); } - if ( aItem->Type() == PCB_PAD_T ) + if( aItem->Type() == PCB_PAD_T ) { MODULE* module = static_cast( aItem->GetParent() ); @@ -838,7 +839,7 @@ void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const m_selection.group->Add( aItem ); // Hide the original item, so it is shown only on overlay - aItem->ViewHide (true); + aItem->ViewHide( true ); aItem->SetSelected(); } @@ -848,7 +849,7 @@ void SELECTION_TOOL::unselectVisually( BOARD_ITEM* aItem ) const m_selection.group->Remove( aItem ); // Restore original item visibility - aItem->ViewHide (false); + aItem->ViewHide( false ); aItem->ClearSelected(); aItem->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } @@ -897,16 +898,17 @@ void SELECTION_TOOL::highlightNet( const VECTOR2I& aPoint ) } } -static double calcArea ( BOARD_ITEM *aItem ) + +static double calcArea( BOARD_ITEM* aItem ) { - switch (aItem -> Type() ) + switch( aItem -> Type() ) { case PCB_MODULE_T: - return static_cast (aItem)->GetFootprintRect().GetArea(); + return static_cast ( aItem )->GetFootprintRect().GetArea(); case PCB_TRACE_T: { - TRACK *t = static_cast (aItem); + TRACK* t = static_cast( aItem ); return ( t->GetWidth() + t->GetLength() ) * t->GetWidth(); } @@ -915,40 +917,43 @@ static double calcArea ( BOARD_ITEM *aItem ) } } -static double calcMinArea ( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) + +static double calcMinArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) { double best = std::numeric_limits::max(); - if(!aCollector.GetCount()) + if( !aCollector.GetCount() ) return 0.0; - for(int i = 0; i < aCollector.GetCount(); i++) + for( int i = 0; i < aCollector.GetCount(); i++ ) { - BOARD_ITEM *item = aCollector[i]; - if(item->Type() == aType) - best = std::min(best, calcArea ( item )); + BOARD_ITEM* item = aCollector[i]; + if( item->Type() == aType ) + best = std::min( best, calcArea( item ) ); } return best; } -static double calcMaxArea ( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) + +static double calcMaxArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType ) { double best = 0.0; - for(int i = 0; i < aCollector.GetCount(); i++) + for( int i = 0; i < aCollector.GetCount(); i++ ) { - BOARD_ITEM *item = aCollector[i]; - if(item->Type() == aType) - best = std::max(best, calcArea ( item )); + BOARD_ITEM* item = aCollector[i]; + if( item->Type() == aType ) + best = std::max(best, calcArea( item ) ); } return best; } -double calcRatio ( double a, double b ) + +double calcRatio( double a, double b ) { if ( a == 0.0 && b == 0.0 ) return 1.0; @@ -958,11 +963,12 @@ double calcRatio ( double a, double b ) return a / b; } + // todo: explain the selection heuristics void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) const { - std::set rejected; - + std::set rejected; + const double footprintAreaRatio = 0.2; const double modulePadMinCoverRatio = 0.45; const double padViaAreaRatio = 0.5; @@ -970,63 +976,64 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c const double trackTrackLengthRatio = 0.3; const double textToFeatureMinRatio = 0.2; const double textToFootprintMinRatio = 0.4; - + LAYER_ID actLayer = m_frame->GetActiveLayer(); - LSET silkLayers(2, B_SilkS, F_SilkS ); + LSET silkLayers( 2, B_SilkS, F_SilkS ); - if( silkLayers[ actLayer ] ) + if( silkLayers[actLayer] ) { - std::set preferred; + std::set preferred; for( int i = 0; i < aCollector.GetCount(); ++i ) { - BOARD_ITEM *item = aCollector[i]; - + BOARD_ITEM* item = aCollector[i]; + if ( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_TEXT_T || item->Type() == PCB_LINE_T ) - if ( silkLayers[item->GetLayer() ] ) + if ( silkLayers[item->GetLayer()] ) preferred.insert ( item ); } - if( preferred.size() != 0) + if( preferred.size() != 0 ) { aCollector.Empty(); - BOOST_FOREACH( BOARD_ITEM *item, preferred ) + BOOST_FOREACH( BOARD_ITEM* item, preferred ) aCollector.Append( item ); return; } } - - if (aCollector.CountType ( PCB_MODULE_TEXT_T ) > 0 ) + + if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) - if ( TEXTE_MODULE *txt = dyn_cast ( aCollector[i] ) ) + if( TEXTE_MODULE* txt = dyn_cast( aCollector[i] ) ) { - double textArea = calcArea ( txt ); + double textArea = calcArea( txt ); for( int j = 0; j < aCollector.GetCount(); ++j ) { - BOARD_ITEM *item = aCollector[j]; - double areaRatio = calcRatio ( textArea, calcArea ( item ) ); + BOARD_ITEM* item = aCollector[j]; + double areaRatio = calcRatio( textArea, calcArea( item ) ); - if (item->Type () == PCB_MODULE_T && areaRatio < textToFootprintMinRatio ) + if( item->Type() == PCB_MODULE_T && areaRatio < textToFootprintMinRatio ) { - printf("rejectModuleN\n"); + //printf("rejectModuleN\n"); - rejected.insert ( item ); + rejected.insert( item ); } - switch (item->Type()) + + switch( item->Type() ) { case PCB_TRACE_T: case PCB_PAD_T: case PCB_LINE_T: case PCB_VIA_T: case PCB_MODULE_T: - if ( areaRatio > textToFeatureMinRatio ) + if( areaRatio > textToFeatureMinRatio ) { - printf("t after moduleRejected\n"); - rejected.insert ( txt ); + //printf("t after moduleRejected\n"); + rejected.insert( txt ); } break; default: @@ -1035,53 +1042,55 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c } } } - - if( aCollector.CountType ( PCB_MODULE_T ) > 0 ) + + if( aCollector.CountType( PCB_MODULE_T ) > 0 ) { - double minArea = calcMinArea ( aCollector, PCB_MODULE_T ); - double maxArea = calcMaxArea ( aCollector, PCB_MODULE_T ); + double minArea = calcMinArea( aCollector, PCB_MODULE_T ); + double maxArea = calcMaxArea( aCollector, PCB_MODULE_T ); - - if( calcRatio(minArea, maxArea) <= footprintAreaRatio ) + if( calcRatio( minArea, maxArea ) <= footprintAreaRatio ) { for( int i = 0; i < aCollector.GetCount(); ++i ) - if ( MODULE *mod = dyn_cast ( aCollector[i] ) ) + if( MODULE* mod = dyn_cast( aCollector[i] ) ) { - double normalizedArea = calcRatio ( calcArea(mod), maxArea ); + double normalizedArea = calcRatio( calcArea(mod), maxArea ); - if(normalizedArea > footprintAreaRatio) + if( normalizedArea > footprintAreaRatio ) { - printf("rejectModule1\n"); + //printf("rejectModule1\n"); rejected.insert( mod ); } } } } - + if( aCollector.CountType ( PCB_PAD_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) - if ( D_PAD *pad = dyn_cast ( aCollector[i] ) ) + { + if ( D_PAD* pad = dyn_cast( aCollector[i] ) ) { double ratio = pad->GetParent()->PadCoverageRatio(); - if(ratio < modulePadMinCoverRatio) + if( ratio < modulePadMinCoverRatio ) rejected.insert( pad->GetParent() ); } + } } - if( aCollector.CountType ( PCB_VIA_T ) > 0 ) + if( aCollector.CountType( PCB_VIA_T ) > 0 ) { for( int i = 0; i < aCollector.GetCount(); ++i ) - if ( VIA *via = dyn_cast ( aCollector[i] ) ) + { + if( VIA* via = dyn_cast( aCollector[i] ) ) { - double viaArea = calcArea ( via ); + double viaArea = calcArea( via ); for( int j = 0; j < aCollector.GetCount(); ++j ) { - BOARD_ITEM *item = aCollector[j]; - double areaRatio = calcRatio ( viaArea, calcArea ( item ) ); + BOARD_ITEM* item = aCollector[j]; + double areaRatio = calcRatio ( viaArea, calcArea( item ) ); if( item->Type() == PCB_MODULE_T && areaRatio < modulePadMinCoverRatio ) rejected.insert( item ); @@ -1089,18 +1098,19 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio ) rejected.insert( item ); - if ( TRACK *track = dyn_cast ( item ) ) + if( TRACK* track = dyn_cast( item ) ) { if( track->GetNetCode() != via->GetNetCode() ) continue; - double lenRatio = (double) ( track->GetLength() + track->GetWidth()) / (double) via->GetWidth(); + double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) / (double) via->GetWidth(); if( lenRatio > trackViaLengthRatio ) rejected.insert( track ); } } } + } } int nTracks = aCollector.CountType ( PCB_TRACE_T ); @@ -1123,79 +1133,84 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c maxArea = std::max(area, maxArea); } - if(maxLength > 0.0 && minLength/maxLength < trackTrackLengthRatio && nTracks > 1 ) + if( maxLength > 0.0 && minLength/maxLength < trackTrackLengthRatio && nTracks > 1 ) + { for( int i = 0; i < aCollector.GetCount(); ++i ) - if ( TRACK *track = dyn_cast ( aCollector[i] ) ) + { + if( TRACK* track = dyn_cast( aCollector[i] ) ) { double ratio = std::max( (double) track->GetWidth(), track->GetLength()) / maxLength; - if( ratio > trackTrackLengthRatio) - rejected.insert(track); - } + if( ratio > trackTrackLengthRatio ) + rejected.insert( track) ; + } + } + } for( int j = 0; j < aCollector.GetCount(); ++j ) { - if ( MODULE *mod = dyn_cast ( aCollector[j] ) ) + if( MODULE* mod = dyn_cast( aCollector[j] ) ) { double ratio = maxArea / mod->GetFootprintRect().GetArea(); if( ratio < modulePadMinCoverRatio ) { - printf("rejectModule\n"); + //printf("rejectModule\n"); rejected.insert( mod ); } } } - } - BOOST_FOREACH(BOARD_ITEM *item, rejected) + BOOST_FOREACH( BOARD_ITEM* item, rejected ) { - aCollector.Remove(item); + aCollector.Remove( item ); } - printf("Post-selection: %d\n", aCollector.GetCount() ); + + //printf("Post-selection: %d\n", aCollector.GetCount() ); } + bool SELECTION_TOOL::SanitizeSelection() { - std::set rejected; + std::set rejected; - if ( !m_editModules ) + if( !m_editModules ) { - for( unsigned int i = 0; i < m_selection.items.GetCount(); ++i ) { BOARD_ITEM* item = m_selection.Item( i ); if( item->Type() == PCB_PAD_T ) { - MODULE *mod = static_cast ( item->GetParent( ) ); + MODULE* mod = static_cast ( item->GetParent() ); // case 1: module (or its pads) are locked - if( mod && ( mod->PadsLocked( ) || mod->IsLocked( ) ) ) - rejected.insert ( item ); + if( mod && ( mod->PadsLocked() || mod->IsLocked() ) ) + rejected.insert( item ); // case 2: multi-item selection contains both the module and its pads - remove the pads - if (mod && m_selection.items.FindItem ( mod ) >= 0 ) - rejected.insert ( item ); + if( mod && m_selection.items.FindItem( mod ) >= 0 ) + rejected.insert( item ); } } } - while ( !rejected.empty () ) + while( !rejected.empty () ) { - BOARD_ITEM *item = *rejected.begin(); - + BOARD_ITEM* item = *rejected.begin(); int itemIdx = m_selection.items.FindItem( item ); + if( itemIdx >= 0 ) m_selection.items.RemovePicker( itemIdx ); - rejected.erase(item); + rejected.erase( item ); } return true; } + void SELECTION_TOOL::generateMenu() { // Create a copy of the master context menu @@ -1225,7 +1240,6 @@ void SELECTION::clear() } - const TOOL_EVENT SELECTION_TOOL::SelectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.selected" ); const TOOL_EVENT SELECTION_TOOL::UnselectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.unselected" ); const TOOL_EVENT SELECTION_TOOL::ClearedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.cleared" ); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 5a900d5a31..b849bbff43 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -166,7 +166,7 @@ public: ///> Makes sure a group selection does not contain items that would cause ///> conflicts when moving/rotating together (e.g. a footprint and one of the same footprint's pads) - bool SanitizeSelection( ); + bool SanitizeSelection(); ///> Item selection event handler. int SelectItem( const TOOL_EVENT& aEvent ); @@ -194,7 +194,7 @@ private: * a menu is shown, otherise function finishes without selecting anything. * @return True if an item was selected, false otherwise. */ - bool selectCursor( const VECTOR2I& aWhere, bool aOnDrag = false); + bool selectCursor( const VECTOR2I& aWhere, bool aOnDrag = false ); /** * Function selectMultiple() diff --git a/pcbnew/tools/tools_common.cpp b/pcbnew/tools/tools_common.cpp index 338f900e49..e9af1bab65 100644 --- a/pcbnew/tools/tools_common.cpp +++ b/pcbnew/tools/tools_common.cpp @@ -1,3 +1,27 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2015 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 + */ + #include #include @@ -14,7 +38,7 @@ #include #include -void registerAllTools ( TOOL_MANAGER *aToolManager ) +void registerAllTools( TOOL_MANAGER *aToolManager ) { aToolManager->RegisterTool( new SELECTION_TOOL ); aToolManager->RegisterTool( new ROUTER_TOOL ); diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index 19c896be4b..9835d424fa 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -486,7 +486,6 @@ void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); GetGalCanvas()->ForceRefresh(); - } } else From 3f015705ac5e36560adde8606fe3338fff3d8399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Thu, 26 Feb 2015 16:34:10 +0100 Subject: [PATCH 19/23] working on shove fix for DPs --- pcbnew/router/pns_diff_pair.cpp | 18 ++++----- pcbnew/router/pns_diff_pair_placer.cpp | 17 ++++---- pcbnew/router/pns_node.h | 13 ++++-- pcbnew/router/pns_router.cpp | 56 ++++++++++++++++++-------- pcbnew/router/pns_shove.cpp | 2 + 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/pcbnew/router/pns_diff_pair.cpp b/pcbnew/router/pns_diff_pair.cpp index a352d79ef5..bc7376a11f 100644 --- a/pcbnew/router/pns_diff_pair.cpp +++ b/pcbnew/router/pns_diff_pair.cpp @@ -190,15 +190,6 @@ bool PNS_DIFF_PAIR::BuildInitial( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarge SHAPE_LINE_CHAIN p = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorP(), aTarget.AnchorP(), aPrefDiagonal ); SHAPE_LINE_CHAIN n = DIRECTION_45().BuildInitialTrace ( aEntry.AnchorN(), aTarget.AnchorN(), aPrefDiagonal ); - if( !checkGap ( p, n, m_gapConstraint ) ) - return false; - - if( p.SelfIntersecting() || n.SelfIntersecting() ) - return false; - - if( p.Intersects( n ) ) - return false; - int mask = aEntry.AllowedAngles() | DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_OBTUSE; SHAPE_LINE_CHAIN sum_n, sum_p; @@ -241,6 +232,15 @@ bool PNS_DIFF_PAIR::BuildInitial( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY &aTarge m_p = sum_p; m_n = sum_n; + if( !checkGap ( p, n, m_gapConstraint ) ) + return false; + + if( p.SelfIntersecting() || n.SelfIntersecting() ) + return false; + + if( p.Intersects( n ) ) + return false; + return true; } diff --git a/pcbnew/router/pns_diff_pair_placer.cpp b/pcbnew/router/pns_diff_pair_placer.cpp index d3c44a1472..7617fd5d73 100644 --- a/pcbnew/router/pns_diff_pair_placer.cpp +++ b/pcbnew/router/pns_diff_pair_placer.cpp @@ -149,7 +149,7 @@ bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurren PNS_WALKAROUND walkaround( aNode, Router() ); PNS_WALKAROUND::WALKAROUND_STATUS wf1; - Router()->GetClearanceFunc()->OverrideClearance( true, aCurrent->NetP(), aCurrent->NetN(), aCurrent->Gap() - 20 ); + Router()->GetClearanceFunc()->OverrideClearance( true, aCurrent->NetP(), aCurrent->NetN(), aCurrent->Gap() ); walkaround.SetSolidsOnly( aSolidsOnly ); walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() ); @@ -167,23 +167,29 @@ bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurren int mask = aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY; - //Router()->DisplayDebugLine( aCurrent->CP(), 4, 10000 ); - //Router()->DisplayDebugLine( aCurrent->CN(), 5, 10000 ); + Router()->DisplayDebugLine( aCurrent->CP(), 4, 10000 ); + Router()->DisplayDebugLine( aCurrent->CN(), 5, 10000 ); + printf("WStart\n"); do { PNS_LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() ); PNS_LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() ); PNS_LINE postWalk; + printf("iter %d\n", iter); if( !aNode->CheckColliding ( &preWalk, mask ) ) { + printf("PreWalkIsColl\n"); currentIsP = !currentIsP; if( !aNode->CheckColliding( &preShove, mask ) ) break; else + { + printf("PreShoveIsColl\n"); continue; + } } wf1 = walkaround.Route( preWalk, postWalk, false ); @@ -193,7 +199,7 @@ bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurren PNS_LINE postShove( preShove ); - shove.ForceClearance( true, cur.Gap() - 12 ); + shove.ForceClearance( true, cur.Gap() ); PNS_SHOVE::SHOVE_STATUS sh1; @@ -610,9 +616,6 @@ void PNS_DIFF_PAIR_PLACER::initPlacement( bool aSplitSeg ) setWorld( rootNode ); - TRACE( 1, "world %p, intitial-direction %s layer %d\n", - m_world % m_direction.Format().c_str() % aLayer ); - m_lastNode = NULL; m_currentNode = rootNode; m_currentMode = Settings().Mode(); diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index fa3fcbba1c..915d0b044d 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -42,7 +42,7 @@ class PNS_SOLID; class PNS_VIA; class PNS_RATSNEST; class PNS_INDEX; - +class PNS_ROUTER; /** * Class PNS_CLEARANCE_FUNC @@ -60,15 +60,22 @@ public: class PNS_PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC { public: - PNS_PCBNEW_CLEARANCE_FUNC( BOARD *aBoard ); + PNS_PCBNEW_CLEARANCE_FUNC( PNS_ROUTER *aRouter ); virtual ~PNS_PCBNEW_CLEARANCE_FUNC(); virtual int operator()( const PNS_ITEM* aA, const PNS_ITEM* aB ); virtual void OverrideClearance (bool aEnable, int aNetA = 0, int aNetB = 0, int aClearance = 0); private: + struct CLEARANCE_ENT { + int coupledNet; + int clearance; + }; + + PNS_ROUTER *m_router; + int localPadClearance( const PNS_ITEM* aItem ) const; - std::vector m_clearanceCache; + std::vector m_clearanceCache; int m_defaultClearance; bool m_overrideEnabled; int m_overrideNetA, m_overrideNetB; diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 29a284401f..b3dff4e1c2 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -44,6 +44,7 @@ #include "pns_router.h" #include "pns_shove.h" #include "pns_dragger.h" +#include "pns_topology.h" #include "pns_diff_pair_placer.h" #include "pns_meander_placer.h" #include "pns_meander_skew_placer.h" @@ -63,20 +64,33 @@ static PNS_ROUTER* theRouter; -PNS_PCBNEW_CLEARANCE_FUNC::PNS_PCBNEW_CLEARANCE_FUNC( BOARD* aBoard ) +PNS_PCBNEW_CLEARANCE_FUNC::PNS_PCBNEW_CLEARANCE_FUNC( PNS_ROUTER *aRouter ) : + m_router( aRouter ) { - m_clearanceCache.resize( aBoard->GetNetCount() ); + BOARD *brd = m_router->GetBoard(); + PNS_NODE *world = m_router->GetWorld(); - for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ ) + PNS_TOPOLOGY topo( world ); + m_clearanceCache.resize( brd->GetNetCount() ); + + for( unsigned int i = 0; i < brd->GetNetCount(); i++ ) { - NETINFO_ITEM* ni = aBoard->FindNet( i ); + NETINFO_ITEM* ni = brd->FindNet( i ); if( ni == NULL ) continue; + CLEARANCE_ENT ent; + ent.coupledNet = topo.DpCoupledNet( i ); + + printf("net %d coupled %d\n", i, ent.coupledNet); + wxString netClassName = ni->GetClassName(); - NETCLASSPTR nc = aBoard->GetDesignSettings().m_NetClasses.Find( netClassName ); + NETCLASSPTR nc = brd->GetDesignSettings().m_NetClasses.Find( netClassName ); + int clearance = nc->GetClearance(); - m_clearanceCache[i] = clearance; + ent.clearance = clearance; + m_clearanceCache[i] = ent; + TRACE( 1, "Add net %d netclass %s clearance %d", i % netClassName.mb_str() % clearance ); } @@ -104,11 +118,21 @@ int PNS_PCBNEW_CLEARANCE_FUNC::localPadClearance( const PNS_ITEM* aItem ) const int PNS_PCBNEW_CLEARANCE_FUNC::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 cl_a = ( net_a >= 0 ? m_clearanceCache[net_a].clearance : m_defaultClearance ); int net_b = aB->Net(); - int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance ); + int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b].clearance : m_defaultClearance ); - if( m_overrideEnabled && aA->OfKind( PNS_ITEM::SEGMENT ) && aB->OfKind( PNS_ITEM::SEGMENT ) ) + bool segsOnly = aA->OfKind( PNS_ITEM::SEGMENT ) && aB->OfKind( PNS_ITEM::SEGMENT ); + + #if 0 + if( segsOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b ) + { + cl_a = cl_b = m_router->Sizes().DiffPairGap() - 3 * PNS_HULL_MARGIN; + printf("Cl %d\n", cl_a); + } + #endif + + if( m_overrideEnabled && segsOnly ) { if( net_a == m_overrideNetA && net_b == m_overrideNetB ) return m_overrideClearance; @@ -248,9 +272,6 @@ PNS_ITEM* PNS_ROUTER::syncTrack( TRACK* aTrack ) PNS_SEGMENT* s = new PNS_SEGMENT( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNetCode() ); - if( aTrack->GetFlags( ) & DP_COUPLED ) - s->Mark ( MK_DP_COUPLED ); - s->SetWidth( aTrack->GetWidth() ); s->SetLayers( PNS_LAYERSET( aTrack->GetLayer() ) ); s->SetParent( aTrack ); @@ -293,12 +314,7 @@ void PNS_ROUTER::SyncWorld() ClearWorld(); - int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue(); - - m_clearanceFunc = new PNS_PCBNEW_CLEARANCE_FUNC( m_board ); m_world = new PNS_NODE(); - m_world->SetClearanceFunctor( m_clearanceFunc ); - m_world->SetMaxClearance( 4 * worstClearance ); for( MODULE* module = m_board->m_Modules; module; module = module->Next() ) { @@ -324,7 +340,13 @@ void PNS_ROUTER::SyncWorld() if( item ) m_world->Add( item ); } + + int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue(); + m_clearanceFunc = new PNS_PCBNEW_CLEARANCE_FUNC( this ); + m_world->SetClearanceFunctor( m_clearanceFunc ); + m_world->SetMaxClearance( 4 * worstClearance ); } + PNS_ROUTER::PNS_ROUTER() diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 31fad49bcc..7ed1a985c7 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -18,6 +18,8 @@ * with this program. If not, see . */ +#define PNS_DEBUG + #include #include From 0f9b72c0bf3d1bf99343478a534aae0951acb636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Mon, 2 Mar 2015 17:18:42 +0100 Subject: [PATCH 20/23] eeschema: fix assertions on debug messages caused by wxLogTrace argument size mismatch --- eeschema/class_libentry.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eeschema/class_libentry.cpp b/eeschema/class_libentry.cpp index bb3f9148c8..ce25334624 100644 --- a/eeschema/class_libentry.cpp +++ b/eeschema/class_libentry.cpp @@ -247,7 +247,7 @@ LIB_PART::~LIB_PART() wxLogTrace( traceSchLibMem, wxT( "%s: destroying part '%s' with alias list count of %u." ), GetChars( wxString::FromAscii( __WXFUNCTION__ ) ), GetChars( GetName() ), - m_aliases.size() ); + (unsigned int) m_aliases.size() ); // If the part is being deleted directly rather than through the library, // delete all of the aliases. @@ -1701,8 +1701,8 @@ LIB_ALIAS* LIB_PART::RemoveAlias( LIB_ALIAS* aAlias ) GetChars( wxString::FromAscii( __WXFUNCTION__ ) ), GetChars( m_name ), GetChars( aAlias->GetName() ), - m_aliases.size(), - m_me.use_count() ); + (unsigned int) m_aliases.size(), + (unsigned int) m_me.use_count() ); it = m_aliases.erase( it ); From bf3128c6834590e1fe550976a5f7f74eba310cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Mon, 2 Mar 2015 17:20:48 +0100 Subject: [PATCH 21/23] router: fix syntax error in PNS_LOGGER output files --- pcbnew/router/pns_logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/router/pns_logger.cpp b/pcbnew/router/pns_logger.cpp index 47aab1687e..e0f8d6ac4b 100644 --- a/pcbnew/router/pns_logger.cpp +++ b/pcbnew/router/pns_logger.cpp @@ -70,7 +70,7 @@ void PNS_LOGGER::EndGroup() void PNS_LOGGER::Log ( const PNS_ITEM* aItem, int aKind, const std::string aName ) { - m_theLog << "aItem " << aKind << " " << aName << " "; + m_theLog << "item " << aKind << " " << aName << " "; m_theLog << aItem->Net() << " " << aItem->Layers().Start() << " " << aItem->Layers().End() << " " << aItem->Marker() << " " << aItem->Rank(); From fe4056742644ab57180f4a7e96405cafad81c5aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Mon, 2 Mar 2015 17:21:04 +0100 Subject: [PATCH 22/23] router: shove now respects diff pair gap --- pcbnew/router/pns_diff_pair_placer.cpp | 13 +------------ pcbnew/router/pns_router.cpp | 19 +++---------------- pcbnew/router/pns_shove.cpp | 2 -- 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/pcbnew/router/pns_diff_pair_placer.cpp b/pcbnew/router/pns_diff_pair_placer.cpp index 7617fd5d73..e8a3d4f27f 100644 --- a/pcbnew/router/pns_diff_pair_placer.cpp +++ b/pcbnew/router/pns_diff_pair_placer.cpp @@ -167,29 +167,20 @@ bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurren int mask = aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY; - Router()->DisplayDebugLine( aCurrent->CP(), 4, 10000 ); - Router()->DisplayDebugLine( aCurrent->CN(), 5, 10000 ); - - printf("WStart\n"); do { PNS_LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() ); PNS_LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() ); PNS_LINE postWalk; - printf("iter %d\n", iter); if( !aNode->CheckColliding ( &preWalk, mask ) ) { - printf("PreWalkIsColl\n"); currentIsP = !currentIsP; if( !aNode->CheckColliding( &preShove, mask ) ) break; else - { - printf("PreShoveIsColl\n"); continue; - } } wf1 = walkaround.Route( preWalk, postWalk, false ); @@ -199,7 +190,7 @@ bool PNS_DIFF_PAIR_PLACER::attemptWalk ( PNS_NODE* aNode, PNS_DIFF_PAIR* aCurren PNS_LINE postShove( preShove ); - shove.ForceClearance( true, cur.Gap() ); + shove.ForceClearance( true, cur.Gap() - 2 * PNS_HULL_MARGIN ); PNS_SHOVE::SHOVE_STATUS sh1; @@ -474,7 +465,6 @@ bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, PNS_ITEM* aI BOARD* brd = Router()->GetBoard(); PNS_ITEM *primRef = NULL, *primP = NULL, *primN = NULL; - // printf("Current %p\n", m_currentNode); int refNet; wxString suffix; @@ -503,7 +493,6 @@ bool PNS_DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, PNS_ITEM* aI else refNet = netP; -// printf("Net: P: %s N: %s\n", (const char *)(netNameP.c_str()), (const char *)(netNameN.c_str())); std::set items; diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index b3dff4e1c2..d35973c878 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -82,8 +82,6 @@ PNS_PCBNEW_CLEARANCE_FUNC::PNS_PCBNEW_CLEARANCE_FUNC( PNS_ROUTER *aRouter ) : CLEARANCE_ENT ent; ent.coupledNet = topo.DpCoupledNet( i ); - printf("net %d coupled %d\n", i, ent.coupledNet); - wxString netClassName = ni->GetClassName(); NETCLASSPTR nc = brd->GetDesignSettings().m_NetClasses.Find( netClassName ); @@ -122,22 +120,11 @@ int PNS_PCBNEW_CLEARANCE_FUNC::operator()( const PNS_ITEM* aA, const PNS_ITEM* a int net_b = aB->Net(); int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b].clearance : m_defaultClearance ); - bool segsOnly = aA->OfKind( PNS_ITEM::SEGMENT ) && aB->OfKind( PNS_ITEM::SEGMENT ); + bool linesOnly = aA->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE ) && aB->OfKind( PNS_ITEM::SEGMENT | PNS_ITEM::LINE ); - #if 0 - if( segsOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b ) + if( linesOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b ) { - cl_a = cl_b = m_router->Sizes().DiffPairGap() - 3 * PNS_HULL_MARGIN; - printf("Cl %d\n", cl_a); - } - #endif - - if( m_overrideEnabled && segsOnly ) - { - if( net_a == m_overrideNetA && net_b == m_overrideNetB ) - return m_overrideClearance; - else if( net_a == m_overrideNetB && net_b == m_overrideNetA ) - return m_overrideClearance; + cl_a = cl_b = m_router->Sizes().DiffPairGap() - 2 * PNS_HULL_MARGIN; } int pad_a = localPadClearance( aA ); diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index 7ed1a985c7..8ee6ebfb76 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -387,8 +387,6 @@ PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingLine( PNS_LINE* aCurrent, PNS_LINE PNS_SHOVE::SHOVE_STATUS PNS_SHOVE::onCollidingSolid( PNS_LINE* aCurrent, PNS_SOLID* aObstacleSolid ) { - //printf("pre2-v %d\n", aCurrent->EndsWithVia()); - PNS_WALKAROUND walkaround( m_currentNode, Router() ); PNS_LINE* walkaroundLine = clone( aCurrent ); From 385d3648d6d064be3f8d7acd7240cae8517f5e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= Date: Tue, 3 Mar 2015 10:36:44 +0100 Subject: [PATCH 23/23] router: removed some printfs() --- pcbnew/router/pns_diff_pair.cpp | 5 ----- pcbnew/router/pns_utils.cpp | 2 -- 2 files changed, 7 deletions(-) diff --git a/pcbnew/router/pns_diff_pair.cpp b/pcbnew/router/pns_diff_pair.cpp index bc7376a11f..271a8f05de 100644 --- a/pcbnew/router/pns_diff_pair.cpp +++ b/pcbnew/router/pns_diff_pair.cpp @@ -139,14 +139,9 @@ static void drawGw( VECTOR2I p, int color ) l.Append( p - VECTOR2I( -50000, -50000 ) ); l.Append( p + VECTOR2I( -50000, -50000 ) ); - //printf("router @ %p\n", PNS_ROUTER::GetInstance()); -// PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); - l.Clear(); l.Append( p - VECTOR2I( 50000, -50000 ) ); l.Append( p + VECTOR2I( 50000, -50000 ) ); - -// PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, color, 10000 ); } diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index 8ebd055dc5..6046fa222d 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -101,7 +101,6 @@ void DrawDebugPoint( VECTOR2I aP, int aColor ) l.Append( aP - VECTOR2I( -50000, -50000 ) ); l.Append( aP + VECTOR2I( -50000, -50000 ) ); - //printf("router @ %p\n", PNS_ROUTER::GetInstance()); PNS_ROUTER::GetInstance()->DisplayDebugLine ( l, aColor, 10000 ); l.Clear(); @@ -125,7 +124,6 @@ void DrawDebugBox( BOX2I aB, int aColor ) l.Append( o.x, o.y + s.y ); l.Append( o ); - //printf("router @ %p\n", PNS_ROUTER::GetInstance()); PNS_ROUTER::GetInstance()->DisplayDebugLine( l, aColor, 10000 ); }