kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #37091
[patch] bring (back) the autoplacer to GAL
-
To:
Kicad Developers <kicad-developers@xxxxxxxxxxxxxxxxxxx>
-
From:
Tomasz Wlostowski <tomasz.wlostowski@xxxxxxx>
-
Date:
Thu, 9 Aug 2018 16:12:27 +0200
-
Authentication-results:
spf=pass (sender IP is 188.184.36.46) smtp.mailfrom=cern.ch; lists.launchpad.net; dkim=none (message not signed) header.d=none;lists.launchpad.net; dmarc=bestguesspass action=none header.from=cern.ch;
-
Autocrypt:
addr=tomasz.wlostowski@xxxxxxx; prefer-encrypt=mutual; keydata= xsFNBFRh3ssBEADmCSrn6qwXrSwI2/LcFSv0aXNHrUQ0MyOAHAW1Rn3LNXLcSCxep1w0iH8q M+ag0XxRVf87DGqjv8wKLGc8nIkGtrMSOuiF+hsrtjAiIrOyOipTABLapqGVj1Dm/26NCtiM /0ZU3XjKcSS5rrj4epKaTM0qW7xp6VceZgH79MbiSCjrt/r9Yhx4tGbWBaCSgTOUHwNB3/Oq 0E5VjU5SAQBQhwG71mES/xaIIUxtfxAPLxpvaq81cjTuT2VQ30T65fSDVikwXrc7M/a2hUG0 nyreo4CktY4pazofQpBA8f8gDPOY1CezY1o1or1Ey6Td/YM/G/Q2G9RZZTjPgD1KRdWIC+nG oCP0lcrMh8Ee+JgR2X7iAAfyVuKAeokxkGnCLon2qiuRG6yAGsEeunJDSd0XtBXzn71GqQH6 0NJzndNoI2PptbHMgc6bINbODkl/RFjVLVGMxDQbgxui2inpjayUZVCQ6SHiiY8BMJrpvTWK GvmgXllxGw+9IQ51u/I0W6hBdy0W/P2oXrP7V2GPDdvyIGJaecjvbkEnD1AbRvxlOjVTGFnC cW08ohzNHGfQK/MXaIpnZAWzRqJz8Wx13KkrdN1hT5quJtaHsvuxBclgHmzbqLlfvLnU7iOa tdN/JzL4L3czEFLJhnHOf9e5zd8yith9vGLUwPxjCzQvz5kBEQARAQABzS1Ub21hc3ogV2xv c3Rvd3NraSA8dG9tYXN6Lndsb3N0b3dza2lAY2Vybi5jaD7CwX4EEwECACgFAlRh3ssCGyMF CQlmAYAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMD02zLS2+sBdxkQAM3Nwk6cU8JT A0uR83NsQEUWjoGboIkVtO5amqWqWGLBguolhEt/NTuzQtmD6rFFhPcOpXDKRKdd6ySdlUB7 8XIgQQTEex6uQpWWV/cLACz6a0u0BONA+VPFzRpWSpOMKpCOcm7izGX9H4CZu4f+bqhL3zaC 38Ki5XxyyioGUzyWd/tw84nz2JgrP1zcYih0Qq82ooO1sRIUrJrm7onb4dH29p7d12uGiQZt go+xeYcDW3TlN4m2tmd7l/JqsD8F0CqtvWrGMsdbr1NE5Y2vyIpG3rkkCiTrlUs0SFyqAC7L qRswP6UZa7enNMhRtJN7eqyrya8J7deRTB6qubP8kTGTt+UTlIgivSqThEN9cJu4cWOsdr3X /D9h7aej1jDSerwKIm7UdmrjkOsgUiZhFMphdAgelmfcVdl7CjsqnnYa5eeeVfEMeT3Fv79V qUcg6LfwUGB56gO4OsnMLGCzCbn6kuwbtlCcV10MsTVzvKNFOrs3mm+yZ2msdLJSV2QMNtHW EVXJV2Tlye+XiYtljdyA6GthK+T/Z9qj8nblunMMN9TwCPkIzzKgyKPxIup/MV7CzN2y8nbp BqkFhApTlXt+NflNdqkfqrWcm+XDXbTwvUzFrKVc8QczpVOMuk7kS+MwxtGGEL6QuML/W8hb k1iEeeAQNiNorHshYTJzGb+lzsFNBFRh3ssBEADQpjP/NdQTZFh11UxsKAOM3KVPSjYxyOEO Gd65/klc3ZBTXJAaC2XmUhYU/kzhyJU7/dd+ywhsLYsWB21mVucAsANra1BkTFXPQFPQwsPP 15QnWQQwFdX7AoMZYceiXqNSWc48DvnXqlUB8TqzB3dSHys9tzfmc+2TDAlM/TpYKWTtY9Fc 2xsx3ZvOzHE1wi6KmdMuK5qc5QBWY16FJtcFA2D5scd24Zy2cO+QS7fDuQHVQpuV+y8unUQC l3VBdOb21WpYrkyUCJU5yRxTP7kbHOIaNyr6S05zArg0TtEfaqCSDOrljxzxSqLtgnD35enE G9/lvQbX8rG0nR1W4ZnhnEx0hAJk2eJ7v9X2Fiq+3rYiEhUsthfBexxoailNxrFIYFr1qBiG zj1HvzoEQZ0Mz/WU156JJBSKAg1IrWzKswIrcv1FoRVhISiEo4nfJslBthZbJjGJ5veYSU5V K4yUNEvcG98+Z4YKFLREXBq6V1AmiFUVbZ1FblK8TGvQaQ3YJlOWEtDA1yrHnujz5wgxtBSM pUsNApQOs2c0MaksfIgkM1McRDwTemup+wmPJ2U8Hvb5A6lI1G+iiUrXPYahdy8XRMxyM1aU xQz53A8Ex+YK/Qn/16k9BZYs/0k3tXb+WBFBcsq732oCo6n4hbfCoG4gYDn7jlEhnm/aQ1Vr eQARAQABwsFlBBgBAgAPBQJUYd7LAhsMBQkJZgGAAAoJEMD02zLS2+sB6kgQAM4V4jIUJo98 rbCU0Yy8YLahwQK5TynS8+zsQ/s9q+aYT8qWzdcjavfRKA3VArGP8qYBXRIQW7QbceSChTOG hhai+5nIJbWhGXVfEUtZ2txahcY2ecfsDEkvCOK7pLKsCq7eYQzMHV8ZPwGWPq+hZa+6msHh R2yUHo6NV2u2HjVJROaM2nUSZT6hOMhzp+zYwl1XEZKqo+QxDtLWJQ66MZIOAngyWN9/ePUJ 0dxG6V+r9MjgHS/OtVlgCKtvAYJCRGcGiSaL+wjhiaZ1/nwBAL0mwN2UaoP+oYjI09J5/Mff tbtQQHMQwRxy31b6N1ZFunnVkR0MeBlT8JtUI31zroRoQ/4u0+wXTYaeTANa0R73Y/m8aIhE sj2ZDD6NISA0Yxnm1rXUyJZosrcS5WjrpgjAjQvkFpm7Sx8Sx+QWpS+DcL8rJntzwL9cPHPA 3tutTbZ9vQrH20TT8Z4nFzTvytFKb5bydF92Fawph2NjFcwzMi/6i37tS1q1X93ky10vq2M4 MaTxIwyjENy6GT5mPh2YlKhWHN5K+8K7rf6QBsvud+SdN3T1AEJojZEYIvxXi0MMpfB4iqlu z+oUbkdDqZonG9QZIME1/BJ3y5oVp5h1r6+vs58a5p/lHjurNYMgbNmWUAcW3trFwXWJispd DhAcLoHO+yCvkKJabrfOZoa2
-
Openpgp:
preference=signencrypt
-
Spamdiagnosticmetadata:
NSPM
-
Spamdiagnosticoutput:
1:99
-
User-agent:
Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1
Hi all,
The patch set in the attachment brings back the legacy autoplacement
tool in a GALified version since many people were asking for it. Now it
can either place selected set of components or all off-board components
through Place->Autoplace menu.
Testing & feedback - as always - is more than welcome :)
Best,
Tom
>From 0b62ad598efca634c19eafd89b38b35860b4e498 Mon Sep 17 00:00:00 2001
From: Tomasz Wlostowski <tomasz.wlostowski@xxxxxxx>
Date: Thu, 9 Aug 2018 16:01:18 +0200
Subject: [PATCH 1/3] pcbnew: renaming of autorouter/autoplacer files
---
pcbnew/autorouter/ar_autoplacer.cpp | 1298 +++++++++++++++++++++++++++
pcbnew/autorouter/ar_cell.h | 116 +++
pcbnew/autorouter/ar_matrix.cpp | 547 +++++++++++
pcbnew/autorouter/auto_place_footprints.cpp | 1298 ---------------------------
pcbnew/autorouter/cell.h | 116 ---
pcbnew/autorouter/routing_matrix.cpp | 547 -----------
6 files changed, 1961 insertions(+), 1961 deletions(-)
create mode 100644 pcbnew/autorouter/ar_autoplacer.cpp
create mode 100644 pcbnew/autorouter/ar_cell.h
create mode 100644 pcbnew/autorouter/ar_matrix.cpp
delete mode 100644 pcbnew/autorouter/auto_place_footprints.cpp
delete mode 100644 pcbnew/autorouter/cell.h
delete mode 100644 pcbnew/autorouter/routing_matrix.cpp
diff --git a/pcbnew/autorouter/ar_autoplacer.cpp b/pcbnew/autorouter/ar_autoplacer.cpp
new file mode 100644
index 0000000..289c9db
--- /dev/null
+++ b/pcbnew/autorouter/ar_autoplacer.cpp
@@ -0,0 +1,1298 @@
+/**
+ * @file auto_place_footprints.cpp
+ * @brief Functions to automatically place Footprints on a board.
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
+ *
+ * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 <fctsys.h>
+#include <class_drawpanel.h>
+#include <confirm.h>
+#include <pcbnew.h>
+#include <pcb_edit_frame.h>
+#include <gr_basic.h>
+#include <macros.h>
+#include <msgpanel.h>
+
+#include <autorout.h>
+#include <cell.h>
+
+#include <class_board.h>
+#include <class_module.h>
+#include <class_track.h>
+#include <class_drawsegment.h>
+#include <convert_to_biu.h>
+#include <base_units.h>
+#include <protos.h>
+
+
+#define GAIN 16
+#define KEEP_OUT_MARGIN 500
+
+
+/* Penalty (cost) for CntRot90 and CntRot180:
+ * CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
+ */
+static const double OrientPenality[11] =
+{
+ 2.0, // CntRot = 0 rotation prohibited
+ 1.9, // CntRot = 1
+ 1.8, // CntRot = 2
+ 1.7, // CntRot = 3
+ 1.6, // CntRot = 4
+ 1.5, // CntRot = 5
+ 1.4, // CntRot = 5
+ 1.3, // CntRot = 7
+ 1.2, // CntRot = 8
+ 1.1, // CntRot = 9
+ 1.0 // CntRot = 10 rotation authorized, no penalty
+};
+
+// Cell states.
+#define OUT_OF_BOARD -2
+#define OCCUPED_By_MODULE -1
+#define FREE_CELL 0
+
+
+static wxPoint CurrPosition; // Current position of the current module placement
+double MinCout;
+
+
+/* generates the Routing matrix, used to fing the best placement
+ * of a footprint.
+ * Allocate a "bitmap" which is an image of the real board
+ * the bitmap handles:
+ * - The free areas
+ * - penalties (cell not occupied, but near occupied areas)
+ * - cells occupied by footprints, board cutout ...
+ */
+int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel );
+
+/* searches for the optimal position of aModule.
+ * return 1 if placement impossible or 0 if OK.
+ */
+static int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame,
+ MODULE* aModule, wxDC* aDC );
+
+/*
+ * Function compute_Ratsnest_PlaceModule
+ * displays the module's ratsnest during displacement, and assess the "cost"
+ * of the position.
+ *
+ * The cost is the longest ratsnest distance with penalty for connections
+ * approaching 45 degrees.
+ */
+static double compute_Ratsnest_PlaceModule( BOARD* aBrd );
+
+/* Place a footprint on the Routing matrix.
+ */
+void genModuleOnRoutingMatrix( MODULE* Module );
+/*
+ * Displays the Placement/Routing matrix on the screen
+ */
+static void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC );
+
+static int TstModuleOnBoard( BOARD* Pcb, MODULE* Module, bool TstOtherSide );
+
+static void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
+ int marge, int aKeepOut, LSET aLayerMask );
+
+static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC );
+static int propagate();
+
+void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
+{
+ MODULE* currModule = NULL;
+ wxPoint PosOK;
+ wxPoint memopos;
+ int error;
+ PCB_LAYER_ID lay_tmp_TOP, lay_tmp_BOTTOM;
+
+ // Undo: init list
+ PICKED_ITEMS_LIST newList;
+
+ newList.m_Status = UR_CHANGED;
+ ITEM_PICKER picker( NULL, UR_CHANGED );
+
+ if( GetBoard()->m_Modules == NULL )
+ return;
+
+ m_canvas->SetAbortRequest( false );
+
+ switch( place_mode )
+ {
+ case PLACE_1_MODULE:
+ currModule = Module;
+
+ if( currModule == NULL )
+ return;
+
+ currModule->SetIsPlaced( false );
+ currModule->SetNeedsPlaced( false );
+ break;
+
+ case PLACE_OUT_OF_BOARD:
+ break;
+
+ case PLACE_ALL:
+
+ if( !IsOK( this, _( "Footprints NOT LOCKED will be moved" ) ) )
+ return;
+
+ break;
+
+ case PLACE_INCREMENTAL:
+
+ if( !IsOK( this, _( "Footprints NOT PLACED will be moved" ) ) )
+ return;
+
+ break;
+ }
+
+ memopos = CurrPosition;
+ lay_tmp_BOTTOM = g_Route_Layer_BOTTOM;
+ lay_tmp_TOP = g_Route_Layer_TOP;
+
+ RoutingMatrix.m_GridRouting = (int) GetScreen()->GetGridSize().x;
+
+ // Ensure Board.m_GridRouting has a reasonable value:
+ if( RoutingMatrix.m_GridRouting < Millimeter2iu( 0.25 ) )
+ RoutingMatrix.m_GridRouting = Millimeter2iu( 0.25 );
+
+ // Compute module parameters used in auto place
+ if( genPlacementRoutingMatrix( GetBoard(), m_messagePanel ) == 0 )
+ return;
+
+ int moduleCount = 0;
+ Module = GetBoard()->m_Modules;
+
+ for( ; Module != NULL; Module = Module->Next() )
+ {
+ Module->SetNeedsPlaced( false );
+
+ switch( place_mode )
+ {
+ case PLACE_1_MODULE:
+
+ if( currModule == Module )
+ {
+ // Module will be placed, add to undo.
+ picker.SetItem( currModule );
+ newList.PushItem( picker );
+ Module->SetNeedsPlaced( true );
+ }
+
+ break;
+
+ case PLACE_OUT_OF_BOARD:
+ Module->SetIsPlaced( false );
+
+ if( Module->IsLocked() )
+ break;
+
+ if( !RoutingMatrix.m_BrdBox.Contains( Module->GetPosition() ) )
+ {
+ // Module will be placed, add to undo.
+ picker.SetItem( Module );
+ newList.PushItem( picker );
+ Module->SetNeedsPlaced( true );
+ }
+
+ break;
+
+ case PLACE_ALL:
+ Module->SetIsPlaced( false );
+
+ if( Module->IsLocked() )
+ break;
+
+ // Module will be placed, add to undo.
+ picker.SetItem( Module );
+ newList.PushItem( picker );
+ Module->SetNeedsPlaced( true );
+ break;
+
+ case PLACE_INCREMENTAL:
+
+ if( Module->IsLocked() )
+ {
+ Module->SetIsPlaced( false );
+ break;
+ }
+
+ if( !Module->NeedsPlaced() )
+ {
+ // Module will be placed, add to undo.
+ picker.SetItem( Module );
+ newList.PushItem( picker );
+ Module->SetNeedsPlaced( true );
+ }
+
+ break;
+ }
+
+ if( Module->NeedsPlaced() ) // Erase from screen
+ {
+ moduleCount++;
+ Module->Draw( m_canvas, DC, GR_XOR );
+ }
+ else
+ {
+ genModuleOnRoutingMatrix( Module );
+ }
+ }
+
+ // Undo command: prepare list
+ if( newList.GetCount() )
+ SaveCopyInUndoList( newList, UR_CHANGED );
+
+ int cnt = 0;
+ wxString msg;
+
+ while( ( Module = PickModule( this, DC ) ) != NULL )
+ {
+ // Display some info about activity, module placement can take a while:
+ msg.Printf( _( "Place footprint %d of %d" ), cnt, moduleCount );
+ SetStatusText( msg );
+
+ double initialOrient = Module->GetOrientation();
+ // Display fill area of interest, barriers, penalties.
+ drawPlacementRoutingMatrix( GetBoard(), DC );
+
+ error = getOptimalModulePlacement( this, Module, DC );
+ double bestScore = MinCout;
+ double bestRotation = 0.0;
+ int rotAllowed;
+ PosOK = CurrPosition;
+
+ if( error == ESC )
+ goto end_of_tst;
+
+ // Try orientations 90, 180, 270 degrees from initial orientation
+ rotAllowed = Module->GetPlacementCost180();
+
+ if( rotAllowed != 0 )
+ {
+ Rotate_Module( DC, Module, 1800.0, true );
+ error = getOptimalModulePlacement( this, Module, DC );
+ MinCout *= OrientPenality[rotAllowed];
+
+ if( bestScore > MinCout ) // This orientation is better.
+ {
+ PosOK = CurrPosition;
+ bestScore = MinCout;
+ bestRotation = 1800.0;
+ }
+ else
+ {
+ Rotate_Module( DC, Module, initialOrient, false );
+ }
+
+ if( error == ESC )
+ goto end_of_tst;
+ }
+
+ // Determine if the best orientation of a module is 90.
+ rotAllowed = Module->GetPlacementCost90();
+
+ if( rotAllowed != 0 )
+ {
+ Rotate_Module( DC, Module, 900.0, true );
+ error = getOptimalModulePlacement( this, Module, DC );
+ MinCout *= OrientPenality[rotAllowed];
+
+ if( bestScore > MinCout ) // This orientation is better.
+ {
+ PosOK = CurrPosition;
+ bestScore = MinCout;
+ bestRotation = 900.0;
+ }
+ else
+ {
+ Rotate_Module( DC, Module, initialOrient, false );
+ }
+
+ if( error == ESC )
+ goto end_of_tst;
+ }
+
+ // Determine if the best orientation of a module is -90.
+ if( rotAllowed != 0 )
+ {
+ Rotate_Module( DC, Module, 2700.0, true );
+ error = getOptimalModulePlacement( this, Module, DC );
+ MinCout *= OrientPenality[rotAllowed];
+
+ if( bestScore > MinCout ) // This orientation is better.
+ {
+ PosOK = CurrPosition;
+ bestScore = MinCout;
+ bestRotation = 2700.0;
+ }
+ else
+ {
+ Rotate_Module( DC, Module, initialOrient, false );
+ }
+
+ if( error == ESC )
+ goto end_of_tst;
+ }
+
+end_of_tst:
+
+ if( error == ESC )
+ break;
+
+ // Place module.
+ CurrPosition = GetCrossHairPosition();
+ SetCrossHairPosition( PosOK );
+
+ PlaceModule( Module, DC );
+
+ bestRotation += initialOrient;
+
+ if( bestRotation != Module->GetOrientation() )
+ Rotate_Module( DC, Module, bestRotation, false );
+
+ SetCrossHairPosition( CurrPosition );
+
+ Module->CalculateBoundingBox();
+
+ genModuleOnRoutingMatrix( Module );
+ Module->SetIsPlaced( true );
+ Module->SetNeedsPlaced( false );
+ }
+
+ CurrPosition = memopos;
+
+ RoutingMatrix.UnInitRoutingMatrix();
+
+ g_Route_Layer_TOP = lay_tmp_TOP;
+ g_Route_Layer_BOTTOM = lay_tmp_BOTTOM;
+
+ Module = GetBoard()->m_Modules;
+
+ for( ; Module != NULL; Module = Module->Next() )
+ {
+ Module->CalculateBoundingBox();
+ }
+
+ GetBoard()->m_Status_Pcb = 0;
+ Compile_Ratsnest( DC, true );
+ m_canvas->ReDraw( DC, true );
+}
+
+
+void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC )
+{
+ int ii, jj;
+ COLOR4D color;
+ int ox, oy;
+ MATRIX_CELL top_state, bottom_state;
+
+ GRSetDrawMode( DC, GR_COPY );
+
+ for( ii = 0; ii < RoutingMatrix.m_Nrows; ii++ )
+ {
+ oy = RoutingMatrix.m_BrdBox.GetY() + ( ii * RoutingMatrix.m_GridRouting );
+
+ for( jj = 0; jj < RoutingMatrix.m_Ncols; jj++ )
+ {
+ ox = RoutingMatrix.m_BrdBox.GetX() + (jj * RoutingMatrix.m_GridRouting);
+ color = COLOR4D::BLACK;
+
+ top_state = RoutingMatrix.GetCell( ii, jj, TOP );
+ bottom_state = RoutingMatrix.GetCell( ii, jj, BOTTOM );
+
+ if( top_state & CELL_is_ZONE )
+ color = COLOR4D( BLUE );
+
+ // obstacles
+ if( ( top_state & CELL_is_EDGE ) || ( bottom_state & CELL_is_EDGE ) )
+ color = COLOR4D::WHITE;
+ else if( top_state & ( HOLE | CELL_is_MODULE ) )
+ color = COLOR4D( LIGHTRED );
+ else if( bottom_state & (HOLE | CELL_is_MODULE) )
+ color = COLOR4D( LIGHTGREEN );
+ else // Display the filling and keep out regions.
+ {
+ if( RoutingMatrix.GetDist( ii, jj, TOP )
+ || RoutingMatrix.GetDist( ii, jj, BOTTOM ) )
+ color = DARKGRAY;
+ }
+
+ GRPutPixel( NULL, DC, ox, oy, color );
+ }
+ }
+}
+
+
+int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel )
+{
+ wxString msg;
+
+ RoutingMatrix.UnInitRoutingMatrix();
+
+ EDA_RECT bbox = aBrd->GetBoardEdgesBoundingBox();
+
+ if( bbox.GetWidth() == 0 || bbox.GetHeight() == 0 )
+ {
+ DisplayError( NULL, _( "No PCB edge found, unknown board size!" ) );
+ return 0;
+ }
+
+ RoutingMatrix.ComputeMatrixSize( aBrd, true );
+ int nbCells = RoutingMatrix.m_Ncols * RoutingMatrix.m_Nrows;
+
+ messagePanel->EraseMsgBox();
+ msg.Printf( wxT( "%d" ), RoutingMatrix.m_Ncols );
+ messagePanel->SetMessage( 1, _( "Cols" ), msg, GREEN );
+ msg.Printf( wxT( "%d" ), RoutingMatrix.m_Nrows );
+ messagePanel->SetMessage( 7, _( "Lines" ), msg, GREEN );
+ msg.Printf( wxT( "%d" ), nbCells );
+ messagePanel->SetMessage( 14, _( "Cells." ), msg, YELLOW );
+
+ // Choose the number of board sides.
+ RoutingMatrix.m_RoutingLayersCount = 2;
+
+ RoutingMatrix.InitRoutingMatrix();
+
+ // Display memory usage.
+ msg.Printf( wxT( "%d" ), RoutingMatrix.m_MemSize / 1024 );
+ messagePanel->SetMessage( 24, wxT( "Mem(Kb)" ), msg, CYAN );
+
+ g_Route_Layer_BOTTOM = F_Cu;
+
+ if( RoutingMatrix.m_RoutingLayersCount > 1 )
+ g_Route_Layer_BOTTOM = B_Cu;
+
+ g_Route_Layer_TOP = F_Cu;
+
+ // Place the edge layer segments
+ TRACK TmpSegm( NULL );
+
+ TmpSegm.SetLayer( UNDEFINED_LAYER );
+ TmpSegm.SetNetCode( -1 );
+ TmpSegm.SetWidth( RoutingMatrix.m_GridRouting / 2 );
+
+ for( auto PtStruct : aBrd->Drawings() )
+ {
+ DRAWSEGMENT* DrawSegm;
+
+ switch( PtStruct->Type() )
+ {
+ case PCB_LINE_T:
+ DrawSegm = (DRAWSEGMENT*) PtStruct;
+
+ if( DrawSegm->GetLayer() != Edge_Cuts )
+ break;
+
+ TraceSegmentPcb( DrawSegm, HOLE | CELL_is_EDGE,
+ RoutingMatrix.m_GridRouting, WRITE_CELL );
+ break;
+
+ case PCB_TEXT_T:
+ default:
+ break;
+ }
+ }
+
+ // Mark cells of the routing matrix to CELL_is_ZONE
+ // (i.e. availlable cell to place a module )
+ // Init a starting point of attachment to the area.
+ RoutingMatrix.OrCell( RoutingMatrix.m_Nrows / 2, RoutingMatrix.m_Ncols / 2,
+ BOTTOM, CELL_is_ZONE );
+
+ // find and mark all other availlable cells:
+ for( int ii = 1; ii != 0; )
+ ii = propagate();
+
+ // Initialize top layer. to the same value as the bottom layer
+ if( RoutingMatrix.m_BoardSide[TOP] )
+ memcpy( RoutingMatrix.m_BoardSide[TOP], RoutingMatrix.m_BoardSide[BOTTOM],
+ nbCells * sizeof(MATRIX_CELL) );
+
+ return 1;
+}
+
+
+/* Place module on Routing matrix.
+ */
+void genModuleOnRoutingMatrix( MODULE* Module )
+{
+ int ox, oy, fx, fy;
+ LSET layerMask;
+ D_PAD* Pad;
+
+ EDA_RECT fpBBox = Module->GetBoundingBox();
+
+ fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 );
+ ox = fpBBox.GetX();
+ fx = fpBBox.GetRight();
+ oy = fpBBox.GetY();
+ fy = fpBBox.GetBottom();
+
+ if( ox < RoutingMatrix.m_BrdBox.GetX() )
+ ox = RoutingMatrix.m_BrdBox.GetX();
+
+ if( ox > RoutingMatrix.m_BrdBox.GetRight() )
+ ox = RoutingMatrix.m_BrdBox.GetRight();
+
+ if( fx < RoutingMatrix.m_BrdBox.GetX() )
+ fx = RoutingMatrix.m_BrdBox.GetX();
+
+ if( fx > RoutingMatrix.m_BrdBox.GetRight() )
+ fx = RoutingMatrix.m_BrdBox.GetRight();
+
+ if( oy < RoutingMatrix.m_BrdBox.GetY() )
+ oy = RoutingMatrix.m_BrdBox.GetY();
+
+ if( oy > RoutingMatrix.m_BrdBox.GetBottom() )
+ oy = RoutingMatrix.m_BrdBox.GetBottom();
+
+ if( fy < RoutingMatrix.m_BrdBox.GetY() )
+ fy = RoutingMatrix.m_BrdBox.GetY();
+
+ if( fy > RoutingMatrix.m_BrdBox.GetBottom() )
+ fy = RoutingMatrix.m_BrdBox.GetBottom();
+
+ if( Module->GetLayer() == F_Cu )
+ layerMask.set( F_Cu );
+
+ if( Module->GetLayer() == B_Cu )
+ layerMask.set( B_Cu );
+
+ TraceFilledRectangle( ox, oy, fx, fy, layerMask,
+ CELL_is_MODULE, WRITE_OR_CELL );
+
+ // Trace pads + clearance areas.
+ for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() )
+ {
+ int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance();
+ ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL );
+ }
+
+ // Trace clearance.
+ int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN;
+ CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask );
+}
+
+
+// A minor helper function to draw a bounding box:
+inline void draw_FootprintRect( EDA_RECT* aClipBox, wxDC* aDC, EDA_RECT& fpBBox, COLOR4D aColor )
+{
+#ifndef USE_WX_OVERLAY
+ GRRect( aClipBox, aDC, fpBBox, 0, aColor );
+#endif
+}
+
+
+int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aDC )
+{
+ int error = 1;
+ wxPoint LastPosOK;
+ double min_cost, curr_cost, Score;
+ bool TstOtherSide;
+ auto displ_opts = (PCB_DISPLAY_OPTIONS*)aFrame->GetDisplayOptions();
+ BOARD* brd = aFrame->GetBoard();
+
+ aModule->CalculateBoundingBox();
+
+ bool showRats = displ_opts->m_Show_Module_Ratsnest;
+ displ_opts->m_Show_Module_Ratsnest = false;
+
+ brd->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
+ aFrame->SetMsgPanel( aModule );
+
+ LastPosOK = RoutingMatrix.m_BrdBox.GetOrigin();
+
+ wxPoint mod_pos = aModule->GetPosition();
+ EDA_RECT fpBBox = aModule->GetFootprintRect();
+
+ // Move fpBBox to have the footprint position at (0,0)
+ fpBBox.Move( -mod_pos );
+ wxPoint fpBBoxOrg = fpBBox.GetOrigin();
+
+ // Calculate the limit of the footprint position, relative
+ // to the routing matrix area
+ wxPoint xylimit = RoutingMatrix.m_BrdBox.GetEnd() - fpBBox.GetEnd();
+
+ wxPoint initialPos = RoutingMatrix.m_BrdBox.GetOrigin() - fpBBoxOrg;
+
+ // Stay on grid.
+ initialPos.x -= initialPos.x % RoutingMatrix.m_GridRouting;
+ initialPos.y -= initialPos.y % RoutingMatrix.m_GridRouting;
+
+ CurrPosition = initialPos;
+
+ // Undraw the current footprint
+ aModule->DrawOutlinesWhenMoving( aFrame->GetCanvas(), aDC, wxPoint( 0, 0 ) );
+
+ g_Offset_Module = mod_pos - CurrPosition;
+
+ /* Examine pads, and set TstOtherSide to true if a footprint
+ * has at least 1 pad through.
+ */
+ TstOtherSide = false;
+
+ if( RoutingMatrix.m_RoutingLayersCount > 1 )
+ {
+ LSET other( aModule->GetLayer() == B_Cu ? F_Cu : B_Cu );
+
+ for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
+ {
+ if( !( pad->GetLayerSet() & other ).any() )
+ continue;
+
+ TstOtherSide = true;
+ break;
+ }
+ }
+
+ // Draw the initial bounding box position
+ COLOR4D color = COLOR4D( BROWN );
+ fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
+ draw_FootprintRect(aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color);
+
+ min_cost = -1.0;
+ aFrame->SetStatusText( wxT( "Score ??, pos ??" ) );
+
+ for( ; CurrPosition.x < xylimit.x; CurrPosition.x += RoutingMatrix.m_GridRouting )
+ {
+ wxYield();
+
+ if( aFrame->GetCanvas()->GetAbortRequest() )
+ {
+ if( IsOK( aFrame, _( "OK to abort?" ) ) )
+ {
+ displ_opts->m_Show_Module_Ratsnest = showRats;
+ return ESC;
+ }
+ else
+ aFrame->GetCanvas()->SetAbortRequest( false );
+ }
+
+ CurrPosition.y = initialPos.y;
+
+ for( ; CurrPosition.y < xylimit.y; CurrPosition.y += RoutingMatrix.m_GridRouting )
+ {
+ // Erase traces.
+ draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
+
+ fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
+ g_Offset_Module = mod_pos - CurrPosition;
+ int keepOutCost = TstModuleOnBoard( brd, aModule, TstOtherSide );
+
+ // Draw at new place
+ color = keepOutCost >= 0 ? BROWN : RED;
+ draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
+
+ if( keepOutCost >= 0 ) // i.e. if the module can be put here
+ {
+ error = 0;
+ aFrame->build_ratsnest_module( aModule );
+ curr_cost = compute_Ratsnest_PlaceModule( brd );
+ Score = curr_cost + keepOutCost;
+
+ if( (min_cost >= Score ) || (min_cost < 0 ) )
+ {
+ LastPosOK = CurrPosition;
+ min_cost = Score;
+ wxString msg;
+ msg.Printf( wxT( "Score %g, pos %s, %s" ),
+ min_cost,
+ GetChars( ::CoordinateToString( LastPosOK.x ) ),
+ GetChars( ::CoordinateToString( LastPosOK.y ) ) );
+ aFrame->SetStatusText( msg );
+ }
+ }
+ }
+ }
+
+ // erasing the last traces
+ GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
+
+ displ_opts->m_Show_Module_Ratsnest = showRats;
+
+ // Regeneration of the modified variable.
+ CurrPosition = LastPosOK;
+
+ brd->m_Status_Pcb &= ~( RATSNEST_ITEM_LOCAL_OK | LISTE_PAD_OK );
+
+ MinCout = min_cost;
+ return error;
+}
+
+
+/* Test if the rectangular area (ux, ux .. y0, y1):
+ * - is a free zone (except OCCUPED_By_MODULE returns)
+ * - is on the working surface of the board (otherwise returns OUT_OF_BOARD)
+ *
+ * Returns OUT_OF_BOARD, or OCCUPED_By_MODULE or FREE_CELL if OK
+ */
+int TstRectangle( BOARD* Pcb, const EDA_RECT& aRect, int side )
+{
+ EDA_RECT rect = aRect;
+
+ rect.Inflate( RoutingMatrix.m_GridRouting / 2 );
+
+ wxPoint start = rect.GetOrigin();
+ wxPoint end = rect.GetEnd();
+
+ start -= RoutingMatrix.m_BrdBox.GetOrigin();
+ end -= RoutingMatrix.m_BrdBox.GetOrigin();
+
+ int row_min = start.y / RoutingMatrix.m_GridRouting;
+ int row_max = end.y / RoutingMatrix.m_GridRouting;
+ int col_min = start.x / RoutingMatrix.m_GridRouting;
+ int col_max = end.x / RoutingMatrix.m_GridRouting;
+
+ if( start.y > row_min * RoutingMatrix.m_GridRouting )
+ row_min++;
+
+ if( start.x > col_min * RoutingMatrix.m_GridRouting )
+ col_min++;
+
+ if( row_min < 0 )
+ row_min = 0;
+
+ if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
+ row_max = RoutingMatrix.m_Nrows - 1;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
+ col_max = RoutingMatrix.m_Ncols - 1;
+
+ for( int row = row_min; row <= row_max; row++ )
+ {
+ for( int col = col_min; col <= col_max; col++ )
+ {
+ unsigned int data = RoutingMatrix.GetCell( row, col, side );
+
+ if( ( data & CELL_is_ZONE ) == 0 )
+ return OUT_OF_BOARD;
+
+ if( (data & CELL_is_MODULE) )
+ return OCCUPED_By_MODULE;
+ }
+ }
+
+ return FREE_CELL;
+}
+
+
+/* Calculates and returns the clearance area of the rectangular surface
+ * aRect):
+ * (Sum of cells in terms of distance)
+ */
+unsigned int CalculateKeepOutArea( const EDA_RECT& aRect, int side )
+{
+ wxPoint start = aRect.GetOrigin();
+ wxPoint end = aRect.GetEnd();
+
+ start -= RoutingMatrix.m_BrdBox.GetOrigin();
+ end -= RoutingMatrix.m_BrdBox.GetOrigin();
+
+ int row_min = start.y / RoutingMatrix.m_GridRouting;
+ int row_max = end.y / RoutingMatrix.m_GridRouting;
+ int col_min = start.x / RoutingMatrix.m_GridRouting;
+ int col_max = end.x / RoutingMatrix.m_GridRouting;
+
+ if( start.y > row_min * RoutingMatrix.m_GridRouting )
+ row_min++;
+
+ if( start.x > col_min * RoutingMatrix.m_GridRouting )
+ col_min++;
+
+ if( row_min < 0 )
+ row_min = 0;
+
+ if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
+ row_max = RoutingMatrix.m_Nrows - 1;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
+ col_max = RoutingMatrix.m_Ncols - 1;
+
+ unsigned int keepOutCost = 0;
+
+ for( int row = row_min; row <= row_max; row++ )
+ {
+ for( int col = col_min; col <= col_max; col++ )
+ {
+ // RoutingMatrix.GetDist returns the "cost" of the cell
+ // at position (row, col)
+ // in autoplace this is the cost of the cell, if it is
+ // inside aRect
+ keepOutCost += RoutingMatrix.GetDist( row, col, side );
+ }
+ }
+
+ return keepOutCost;
+}
+
+
+/* Test if the module can be placed on the board.
+ * Returns the value TstRectangle().
+ * Module is known by its bounding box
+ */
+int TstModuleOnBoard( BOARD* Pcb, MODULE* aModule, bool TstOtherSide )
+{
+ int side = TOP;
+ int otherside = BOTTOM;
+
+ if( aModule->GetLayer() == B_Cu )
+ {
+ side = BOTTOM; otherside = TOP;
+ }
+
+ EDA_RECT fpBBox = aModule->GetFootprintRect();
+ fpBBox.Move( -g_Offset_Module );
+
+ int diag = TstRectangle( Pcb, fpBBox, side );
+
+ if( diag != FREE_CELL )
+ return diag;
+
+ if( TstOtherSide )
+ {
+ diag = TstRectangle( Pcb, fpBBox, otherside );
+
+ if( diag != FREE_CELL )
+ return diag;
+ }
+
+ int marge = ( RoutingMatrix.m_GridRouting * aModule->GetPadCount() ) / GAIN;
+
+ fpBBox.Inflate( marge );
+ return CalculateKeepOutArea( fpBBox, side );
+}
+
+
+double compute_Ratsnest_PlaceModule( BOARD* aBrd )
+{
+ double curr_cost;
+ wxPoint start; // start point of a ratsnest
+ wxPoint end; // end point of a ratsnest
+ int dx, dy;
+
+ if( ( aBrd->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
+ return -1;
+
+ curr_cost = 0;
+
+ for( unsigned ii = 0; ii < aBrd->m_LocalRatsnest.size(); ii++ )
+ {
+ RATSNEST_ITEM* pt_local_rats_nest = &aBrd->m_LocalRatsnest[ii];
+
+ if( ( pt_local_rats_nest->m_Status & LOCAL_RATSNEST_ITEM ) )
+ continue; // Skip ratsnest between 2 pads of the current module
+
+ // Skip modules not inside the board area
+ MODULE* module = pt_local_rats_nest->m_PadEnd->GetParent();
+
+ if( !RoutingMatrix.m_BrdBox.Contains( module->GetPosition() ) )
+ continue;
+
+ start = pt_local_rats_nest->m_PadStart->GetPosition() - g_Offset_Module;
+ end = pt_local_rats_nest->m_PadEnd->GetPosition();
+
+ // Cost of the ratsnest.
+ dx = end.x - start.x;
+ dy = end.y - start.y;
+
+ dx = abs( dx );
+ dy = abs( dy );
+
+ // ttry to have always dx >= dy to calculate the cost of the rastsnet
+ if( dx < dy )
+ std::swap( dx, dy );
+
+ // Cost of the connection = length + penalty due to the slope
+ // dx is the biggest length relative to the X or Y axis
+ // the penalty is max for 45 degrees ratsnests,
+ // and 0 for horizontal or vertical ratsnests.
+ // For Horizontal and Vertical ratsnests, dy = 0;
+ double conn_cost = hypot( dx, dy * 2.0 );
+ curr_cost += conn_cost; // Total cost = sum of costs of each connection
+ }
+
+ return curr_cost;
+}
+
+
+/**
+ * Function CreateKeepOutRectangle
+ * builds the cost map:
+ * Cells ( in Dist map ) inside the rect x0,y0 a x1,y1 are
+ * incremented by value aKeepOut
+ * Cell outside this rectangle, but inside the rectangle
+ * x0,y0 -marge to x1,y1 + marge are incremented by a decreasing value
+ * (aKeepOut ... 0). The decreasing value depends on the distance to the first rectangle
+ * Therefore the cost is high in rect x0,y0 to x1,y1, and decrease outside this rectangle
+ */
+void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
+ int marge, int aKeepOut, LSET aLayerMask )
+{
+ int row, col;
+ int row_min, row_max, col_min, col_max, pmarge;
+ int trace = 0;
+ DIST_CELL data, LocalKeepOut;
+ int lgain, cgain;
+
+ if( aLayerMask[g_Route_Layer_BOTTOM] )
+ trace = 1; // Trace on bottom layer.
+
+ if( aLayerMask[g_Route_Layer_TOP] && RoutingMatrix.m_RoutingLayersCount )
+ trace |= 2; // Trace on top layer.
+
+ if( trace == 0 )
+ return;
+
+ ux0 -= RoutingMatrix.m_BrdBox.GetX();
+ uy0 -= RoutingMatrix.m_BrdBox.GetY();
+ ux1 -= RoutingMatrix.m_BrdBox.GetX();
+ uy1 -= RoutingMatrix.m_BrdBox.GetY();
+
+ ux0 -= marge; ux1 += marge;
+ uy0 -= marge; uy1 += marge;
+
+ pmarge = marge / RoutingMatrix.m_GridRouting;
+
+ if( pmarge < 1 )
+ pmarge = 1;
+
+ // Calculate the coordinate limits of the rectangle.
+ row_max = uy1 / RoutingMatrix.m_GridRouting;
+ col_max = ux1 / RoutingMatrix.m_GridRouting;
+ row_min = uy0 / RoutingMatrix.m_GridRouting;
+
+ if( uy0 > row_min * RoutingMatrix.m_GridRouting )
+ row_min++;
+
+ col_min = ux0 / RoutingMatrix.m_GridRouting;
+
+ if( ux0 > col_min * RoutingMatrix.m_GridRouting )
+ col_min++;
+
+ if( row_min < 0 )
+ row_min = 0;
+
+ if( row_max >= (RoutingMatrix.m_Nrows - 1) )
+ row_max = RoutingMatrix.m_Nrows - 1;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ if( col_max >= (RoutingMatrix.m_Ncols - 1) )
+ col_max = RoutingMatrix.m_Ncols - 1;
+
+ for( row = row_min; row <= row_max; row++ )
+ {
+ lgain = 256;
+
+ if( row < pmarge )
+ lgain = ( 256 * row ) / pmarge;
+ else if( row > row_max - pmarge )
+ lgain = ( 256 * ( row_max - row ) ) / pmarge;
+
+ for( col = col_min; col <= col_max; col++ )
+ {
+ // RoutingMatrix Dist map containt the "cost" of the cell
+ // at position (row, col)
+ // in autoplace this is the cost of the cell, when
+ // a footprint overlaps it, near a "master" footprint
+ // this cost is hight near the "master" footprint
+ // and decrease with the distance
+ cgain = 256;
+ LocalKeepOut = aKeepOut;
+
+ if( col < pmarge )
+ cgain = ( 256 * col ) / pmarge;
+ else if( col > col_max - pmarge )
+ cgain = ( 256 * ( col_max - col ) ) / pmarge;
+
+ cgain = ( cgain * lgain ) / 256;
+
+ if( cgain != 256 )
+ LocalKeepOut = ( LocalKeepOut * cgain ) / 256;
+
+ if( trace & 1 )
+ {
+ data = RoutingMatrix.GetDist( row, col, BOTTOM ) + LocalKeepOut;
+ RoutingMatrix.SetDist( row, col, BOTTOM, data );
+ }
+
+ if( trace & 2 )
+ {
+ data = RoutingMatrix.GetDist( row, col, TOP );
+ data = std::max( data, LocalKeepOut );
+ RoutingMatrix.SetDist( row, col, TOP, data );
+ }
+ }
+ }
+}
+
+
+// Sort routines
+static bool Tri_PlaceModules( MODULE* ref, MODULE* compare )
+{
+ double ff1, ff2;
+
+ ff1 = ref->GetArea() * ref->GetPadCount();
+ ff2 = compare->GetArea() * compare->GetPadCount();
+
+ return ff2 < ff1;
+}
+
+
+static bool sortFootprintsByRatsnestSize( MODULE* ref, MODULE* compare )
+{
+ double ff1, ff2;
+
+ ff1 = ref->GetArea() * ref->GetFlag();
+ ff2 = compare->GetArea() * compare->GetFlag();
+ return ff2 < ff1;
+}
+
+
+/**
+ * Function PickModule
+ * find the "best" module place
+ * The criteria are:
+ * - Maximum ratsnest with modules already placed
+ * - Max size, and number of pads max
+ */
+static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
+{
+ MODULE* Module;
+ std::vector <MODULE*> moduleList;
+
+ // Build sorted footprints list (sort by decreasing size )
+ Module = pcbframe->GetBoard()->m_Modules;
+
+ for( ; Module != NULL; Module = Module->Next() )
+ {
+ Module->CalculateBoundingBox();
+ moduleList.push_back( Module );
+ }
+
+ sort( moduleList.begin(), moduleList.end(), Tri_PlaceModules );
+
+ for( unsigned kk = 0; kk < moduleList.size(); kk++ )
+ {
+ Module = moduleList[kk];
+ Module->SetFlag( 0 );
+
+ if( !Module->NeedsPlaced() )
+ continue;
+
+ pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
+ pcbframe->SetMsgPanel( Module );
+ pcbframe->build_ratsnest_module( Module );
+
+ // Calculate external ratsnest.
+ for( unsigned ii = 0; ii < pcbframe->GetBoard()->m_LocalRatsnest.size(); ii++ )
+ {
+ if( ( pcbframe->GetBoard()->m_LocalRatsnest[ii].m_Status &
+ LOCAL_RATSNEST_ITEM ) == 0 )
+ Module->IncrementFlag();
+ }
+ }
+
+ pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
+
+ sort( moduleList.begin(), moduleList.end(), sortFootprintsByRatsnestSize );
+
+ // Search for "best" module.
+ MODULE* bestModule = NULL;
+ MODULE* altModule = NULL;
+
+ for( unsigned ii = 0; ii < moduleList.size(); ii++ )
+ {
+ Module = moduleList[ii];
+
+ if( !Module->NeedsPlaced() )
+ continue;
+
+ altModule = Module;
+
+ if( Module->GetFlag() == 0 )
+ continue;
+
+ bestModule = Module;
+ break;
+ }
+
+ if( bestModule )
+ return bestModule;
+ else
+ return altModule;
+}
+
+
+/**
+ * Function propagate
+ * Used only in autoplace calculations
+ * Uses the routing matrix to fill the cells within the zone
+ * Search and mark cells within the zone, and agree with DRC options.
+ * Requirements:
+ * Start from an initial point, to fill zone
+ * The zone must have no "copper island"
+ * Algorithm:
+ * If the current cell has a neighbor flagged as "cell in the zone", it
+ * become a cell in the zone
+ * The first point in the zone is the starting point
+ * 4 searches within the matrix are made:
+ * 1 - Left to right and top to bottom
+ * 2 - Right to left and top to bottom
+ * 3 - bottom to top and Right to left
+ * 4 - bottom to top and Left to right
+ * Given the current cell, for each search, we consider the 2 neighbor cells
+ * the previous cell on the same line and the previous cell on the same column.
+ *
+ * This function can request some iterations
+ * Iterations are made until no cell is added to the zone.
+ * @return added cells count (i.e. which the attribute CELL_is_ZONE is set)
+ */
+int propagate()
+{
+ int row, col;
+ long current_cell, old_cell_H;
+ std::vector<long> pt_cell_V;
+ int nbpoints = 0;
+
+#define NO_CELL_ZONE (HOLE | CELL_is_EDGE | CELL_is_ZONE)
+
+ pt_cell_V.reserve( std::max( RoutingMatrix.m_Nrows, RoutingMatrix.m_Ncols ) );
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+
+ // Search from left to right and top to bottom.
+ for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
+ {
+ old_cell_H = 0;
+
+ for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
+ {
+ current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+
+ if( current_cell == 0 ) // a free cell is found
+ {
+ if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
+ {
+ RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
+ current_cell = CELL_is_ZONE;
+ nbpoints++;
+ }
+ }
+
+ pt_cell_V[col] = old_cell_H = current_cell;
+ }
+ }
+
+ // Search from right to left and top to bottom/
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+
+ for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
+ {
+ old_cell_H = 0;
+
+ for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
+ {
+ current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+
+ if( current_cell == 0 ) // a free cell is found
+ {
+ if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
+ {
+ RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
+ current_cell = CELL_is_ZONE;
+ nbpoints++;
+ }
+ }
+
+ pt_cell_V[col] = old_cell_H = current_cell;
+ }
+ }
+
+ // Search from bottom to top and right to left.
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+
+ for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
+ {
+ old_cell_H = 0;
+
+ for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
+ {
+ current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+
+ if( current_cell == 0 ) // a free cell is found
+ {
+ if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
+ {
+ RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
+ current_cell = CELL_is_ZONE;
+ nbpoints++;
+ }
+ }
+
+ pt_cell_V[row] = old_cell_H = current_cell;
+ }
+ }
+
+ // Search from bottom to top and left to right.
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+
+ for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
+ {
+ old_cell_H = 0;
+
+ for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
+ {
+ current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+
+ if( current_cell == 0 ) // a free cell is found
+ {
+ if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
+ {
+ RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
+ current_cell = CELL_is_ZONE;
+ nbpoints++;
+ }
+ }
+
+ pt_cell_V[row] = old_cell_H = current_cell;
+ }
+ }
+
+ return nbpoints;
+}
diff --git a/pcbnew/autorouter/ar_cell.h b/pcbnew/autorouter/ar_cell.h
new file mode 100644
index 0000000..63b76ae
--- /dev/null
+++ b/pcbnew/autorouter/ar_cell.h
@@ -0,0 +1,116 @@
+/**
+ * @file cell.h
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
+ *
+ * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
+ *
+ * First copyright (C) Randy Nevin, 1989 (see PCBCA package)
+ *
+ * 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 _CELL_H_
+#define _CELL_H_
+
+
+/* Bits characterizing cell */
+#define HOLE 0x01 /* a conducting hole or obstacle */
+#define CELL_is_MODULE 0x02 /* auto placement occupied by a module */
+#define CELL_is_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
+#define CELL_is_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
+#define CELL_is_ZONE 0x80 /* Area and auto-placement: cell available */
+
+/* Bit masks for presence of obstacles to autorouting */
+#define OCCUPE 1 /* Autorouting: obstacle tracks and vias. */
+#define VIA_IMPOSSIBLE 2 /* Autorouting: obstacle for vias. */
+#define CURRENT_PAD 4
+
+
+/* traces radiating outward from a hole to a side or corner */
+#define HOLE_NORTH 0x00000002L /* upward */
+#define HOLE_NORTHEAST 0x00000004L /* upward and right */
+#define HOLE_EAST 0x00000008L /* to the right */
+#define HOLE_SOUTHEAST 0x00000010L /* downward and right */
+#define HOLE_SOUTH 0x00000020L /* downward */
+#define HOLE_SOUTHWEST 0x00000040L /* downward and left */
+#define HOLE_WEST 0x00000080L /* to the left */
+#define HOLE_NORTHWEST 0x00000100L /* upward and left */
+
+/* straight lines through the center */
+#define LINE_HORIZONTAL 0x00000002L /* left-to-right line */
+#define LINE_VERTICAL 0x00000004L /* top-to-bottom line */
+
+/* lines cutting across a corner, connecting adjacent sides */
+#define CORNER_NORTHEAST 0x00000008L /* upper right corner */
+#define CORNER_SOUTHEAST 0x00000010L /* lower right corner */
+#define CORNER_SOUTHWEST 0x00000020L /* lower left corner */
+#define CORNER_NORTHWEST 0x00000040L /* upper left corner */
+
+/* diagonal lines through the center */
+#define DIAG_NEtoSW 0x00000080L /* northeast to southwest */
+#define DIAG_SEtoNW 0x00000100L /* southeast to northwest */
+
+/* 135 degree angle side-to-far-corner lines */
+#define BENT_NtoSE 0x00000200L /* north to southeast */
+#define BENT_NtoSW 0x00000400L /* north to southwest */
+#define BENT_EtoSW 0x00000800L /* east to southwest */
+#define BENT_EtoNW 0x00001000L /* east to northwest */
+#define BENT_StoNW 0x00002000L /* south to northwest */
+#define BENT_StoNE 0x00004000L /* south to northeast */
+#define BENT_WtoNE 0x00008000L /* west to northeast */
+#define BENT_WtoSE 0x00010000L /* west to southeast */
+
+/* 90 degree corner-to-adjacent-corner lines */
+#define ANGLE_NEtoSE 0x00020000L /* northeast to southeast */
+#define ANGLE_SEtoSW 0x00040000L /* southeast to southwest */
+#define ANGLE_SWtoNW 0x00080000L /* southwest to northwest */
+#define ANGLE_NWtoNE 0x00100000L /* northwest to northeast */
+
+/* 45 degree angle side-to-near-corner lines */
+#define SHARP_NtoNE 0x00200000L /* north to northeast */
+#define SHARP_EtoNE 0x00400000L /* east to northeast */
+#define SHARP_EtoSE 0x00800000L /* east to southeast */
+#define SHARP_StoSE 0x01000000L /* south to southeast */
+#define SHARP_StoSW 0x02000000L /* south to southwest */
+#define SHARP_WtoSW 0x04000000L /* west to southwest */
+#define SHARP_WtoNW 0x08000000L /* west to northwest */
+#define SHARP_NtoNW 0x10000000L /* north to northwest */
+
+/* directions the cell can be reached from (point to previous cell) */
+#define FROM_NOWHERE 0
+#define FROM_NORTH 1
+#define FROM_NORTHEAST 2
+#define FROM_EAST 3
+#define FROM_SOUTHEAST 4
+#define FROM_SOUTH 5
+#define FROM_SOUTHWEST 6
+#define FROM_WEST 7
+#define FROM_NORTHWEST 8
+#define FROM_OTHERSIDE 9
+
+
+#endif // _CELL_H_
+
diff --git a/pcbnew/autorouter/ar_matrix.cpp b/pcbnew/autorouter/ar_matrix.cpp
new file mode 100644
index 0000000..856dead
--- /dev/null
+++ b/pcbnew/autorouter/ar_matrix.cpp
@@ -0,0 +1,547 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
+ *
+ * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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
+ */
+
+/**
+ * @file routing_matrix.cpp
+ * @brief Functions to create autorouting maps
+ */
+
+#include <fctsys.h>
+#include <common.h>
+
+#include <pcbnew.h>
+#include <cell.h>
+#include <autorout.h>
+
+#include <class_eda_rect.h>
+#include <class_board.h>
+#include <class_module.h>
+#include <class_track.h>
+#include <class_drawsegment.h>
+#include <class_edge_mod.h>
+#include <class_pcb_text.h>
+
+
+MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
+{
+ m_BoardSide[0] = m_BoardSide[1] = NULL;
+ m_DistSide[0] = m_DistSide[1] = NULL;
+ m_DirSide[0] = m_DirSide[1] = NULL;
+ m_opWriteCell = NULL;
+ m_InitMatrixDone = false;
+ m_Nrows = 0;
+ m_Ncols = 0;
+ m_MemSize = 0;
+ m_RoutingLayersCount = 1;
+ m_GridRouting = 0;
+ m_RouteCount = 0;
+}
+
+
+MATRIX_ROUTING_HEAD::~MATRIX_ROUTING_HEAD()
+{
+}
+
+
+bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
+{
+ // The boundary box must have its start point on routing grid:
+ m_BrdBox = aUseBoardEdgesOnly ? aPcb->GetBoardEdgesBoundingBox() : aPcb->GetBoundingBox();
+
+ m_BrdBox.SetX( m_BrdBox.GetX() - ( m_BrdBox.GetX() % m_GridRouting ) );
+ m_BrdBox.SetY( m_BrdBox.GetY() - ( m_BrdBox.GetY() % m_GridRouting ) );
+
+ // The boundary box must have its end point on routing grid:
+ wxPoint end = m_BrdBox.GetEnd();
+
+ end.x -= end.x % m_GridRouting;
+ end.x += m_GridRouting;
+
+ end.y -= end.y % m_GridRouting;
+ end.y += m_GridRouting;
+
+ m_BrdBox.SetEnd( end );
+
+ m_Nrows = m_BrdBox.GetHeight() / m_GridRouting;
+ m_Ncols = m_BrdBox.GetWidth() / m_GridRouting;
+
+ // gives a small margin
+ m_Ncols += 1;
+ m_Nrows += 1;
+
+ return true;
+}
+
+
+int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
+{
+ if( m_Nrows <= 0 || m_Ncols <= 0 )
+ return 0;
+
+ m_InitMatrixDone = true; // we have been called
+
+ // give a small margin for memory allocation:
+ int ii = (RoutingMatrix.m_Nrows + 1) * (RoutingMatrix.m_Ncols + 1);
+
+ int side = BOTTOM;
+ for( int jj = 0; jj < m_RoutingLayersCount; jj++ ) // m_RoutingLayersCount = 1 or 2
+ {
+ m_BoardSide[side] = NULL;
+ m_DistSide[side] = NULL;
+ m_DirSide[side] = NULL;
+
+ // allocate matrix & initialize everything to empty
+ m_BoardSide[side] = (MATRIX_CELL*) operator new( ii * sizeof(MATRIX_CELL) );
+ memset( m_BoardSide[side], 0, ii * sizeof(MATRIX_CELL) );
+
+ if( m_BoardSide[side] == NULL )
+ return -1;
+
+ // allocate Distances
+ m_DistSide[side] = (DIST_CELL*) operator new( ii * sizeof(DIST_CELL) );
+ memset( m_DistSide[side], 0, ii * sizeof(DIST_CELL) );
+
+ if( m_DistSide[side] == NULL )
+ return -1;
+
+ // allocate Dir (chars)
+ m_DirSide[side] = (char*) operator new( ii );
+ memset( m_DirSide[side], 0, ii );
+
+ if( m_DirSide[side] == NULL )
+ return -1;
+
+ side = TOP;
+ }
+
+ m_MemSize = m_RouteCount * ii * ( sizeof(MATRIX_CELL)
+ + sizeof(DIST_CELL) + sizeof(char) );
+
+ return m_MemSize;
+}
+
+
+void MATRIX_ROUTING_HEAD::UnInitRoutingMatrix()
+{
+ int ii;
+
+ m_InitMatrixDone = false;
+
+ for( ii = 0; ii < MAX_ROUTING_LAYERS_COUNT; ii++ )
+ {
+ // de-allocate Dir matrix
+ if( m_DirSide[ii] )
+ {
+ delete m_DirSide[ii];
+ m_DirSide[ii] = NULL;
+ }
+
+ // de-allocate Distances matrix
+ if( m_DistSide[ii] )
+ {
+ delete m_DistSide[ii];
+ m_DistSide[ii] = NULL;
+ }
+
+ // de-allocate cells matrix
+ if( m_BoardSide[ii] )
+ {
+ delete m_BoardSide[ii];
+ m_BoardSide[ii] = NULL;
+ }
+ }
+
+ m_Nrows = m_Ncols = 0;
+}
+
+
+/**
+ * Function PlaceCells
+ * Initialize the matrix routing by setting obstacles for each occupied cell
+ * a cell set to HOLE is an obstacle for tracks and vias
+ * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only.
+ * a cell set to CELL_is_EDGE is a frontier.
+ * Tracks and vias having the same net code as net_code are skipped
+ * (htey do not are obstacles)
+ *
+ * For single-sided Routing 1:
+ * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
+ *
+ * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
+ */
+void PlaceCells( BOARD* aPcb, int net_code, int flag )
+{
+ int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
+ int marge, via_marge;
+ LSET layerMask;
+
+ // use the default NETCLASS?
+ NETCLASSPTR nc = aPcb->GetDesignSettings().GetDefault();
+
+ int trackWidth = nc->GetTrackWidth();
+ int clearance = nc->GetClearance();
+ int viaSize = nc->GetViaDiameter();
+
+ marge = clearance + (trackWidth / 2);
+ via_marge = clearance + (viaSize / 2);
+
+ // Place PADS on matrix routing:
+ for( unsigned i = 0; i < aPcb->GetPadCount(); ++i )
+ {
+ D_PAD* pad = aPcb->GetPad( i );
+
+ if( net_code != pad->GetNetCode() || (flag & FORCE_PADS) )
+ {
+ ::PlacePad( pad, HOLE, marge, WRITE_CELL );
+ }
+
+ ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ }
+
+ // Place outlines of modules on matrix routing, if they are on a copper layer
+ // or on the edge layer
+
+ for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
+ {
+ for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() )
+ {
+ switch( item->Type() )
+ {
+ case PCB_MODULE_EDGE_T:
+ {
+ EDGE_MODULE* edge = (EDGE_MODULE*) item;
+ EDGE_MODULE tmpEdge( *edge );
+
+ if( tmpEdge.GetLayer() == Edge_Cuts )
+ tmpEdge.SetLayer( UNDEFINED_LAYER );
+
+ TraceSegmentPcb( &tmpEdge, HOLE, marge, WRITE_CELL );
+ TraceSegmentPcb( &tmpEdge, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // Place board outlines and texts on copper layers:
+ for( auto item : aPcb->Drawings() )
+ {
+ switch( item->Type() )
+ {
+ case PCB_LINE_T:
+ {
+ DRAWSEGMENT* DrawSegm;
+
+ int type_cell = HOLE;
+ DrawSegm = (DRAWSEGMENT*) item;
+ DRAWSEGMENT tmpSegm( DrawSegm );
+
+ if( DrawSegm->GetLayer() == Edge_Cuts )
+ {
+ tmpSegm.SetLayer( UNDEFINED_LAYER );
+ type_cell |= CELL_is_EDGE;
+ }
+
+ TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
+ }
+ break;
+
+ case PCB_TEXT_T:
+ {
+ TEXTE_PCB* PtText = (TEXTE_PCB*) item;
+
+ if( PtText->GetText().Length() == 0 )
+ break;
+
+ EDA_RECT textbox = PtText->GetTextBox( -1 );
+ ux0 = textbox.GetX();
+ uy0 = textbox.GetY();
+ dx = textbox.GetWidth();
+ dy = textbox.GetHeight();
+
+ // Put bounding box (rectangle) on matrix
+ dx /= 2;
+ dy /= 2;
+
+ ux1 = ux0 + dx;
+ uy1 = uy0 + dy;
+
+ ux0 -= dx;
+ uy0 -= dy;
+
+ layerMask = LSET( PtText->GetLayer() );
+
+ TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
+ uy1 + marge, PtText->GetTextAngle(),
+ layerMask, HOLE, WRITE_CELL );
+
+ TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
+ ux1 + via_marge, uy1 + via_marge,
+ PtText->GetTextAngle(),
+ layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Put tracks and vias on matrix
+ for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
+ {
+ if( net_code == track->GetNetCode() )
+ continue;
+
+ TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
+ TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ }
+}
+
+
+int Build_Work( BOARD* Pcb )
+{
+ RATSNEST_ITEM* pt_rats;
+ D_PAD* pt_pad;
+ int r1, r2, c1, c2, current_net_code;
+ RATSNEST_ITEM* pt_ch;
+ int demi_pas = RoutingMatrix.m_GridRouting / 2;
+ wxString msg;
+
+ InitWork(); // clear work list
+ int cellCount = 0;
+
+ for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
+ {
+ pt_rats = &Pcb->m_FullRatsnest[ii];
+
+ /* We consider here only ratsnest that are active ( obviously not yet routed)
+ * and routables (that are not yet attempt to be routed and fail
+ */
+ if( (pt_rats->m_Status & CH_ACTIF) == 0 )
+ continue;
+
+ if( pt_rats->m_Status & CH_UNROUTABLE )
+ continue;
+
+ if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
+ continue;
+
+ pt_pad = pt_rats->m_PadStart;
+
+ current_net_code = pt_pad->GetNetCode();
+ pt_ch = pt_rats;
+
+ r1 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY() + demi_pas )
+ / RoutingMatrix.m_GridRouting;
+
+ if( r1 < 0 || r1 >= RoutingMatrix.m_Nrows )
+ {
+ msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
+ pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
+ wxMessageBox( msg );
+ return 0;
+ }
+
+ c1 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas ) / RoutingMatrix.m_GridRouting;
+
+ if( c1 < 0 || c1 >= RoutingMatrix.m_Ncols )
+ {
+ msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
+ pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
+ wxMessageBox( msg );
+ return 0;
+ }
+
+ pt_pad = pt_rats->m_PadEnd;
+
+ r2 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY()
+ + demi_pas ) / RoutingMatrix.m_GridRouting;
+
+ if( r2 < 0 || r2 >= RoutingMatrix.m_Nrows )
+ {
+ msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
+ pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
+ wxMessageBox( msg );
+ return 0;
+ }
+
+ c2 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas )
+ / RoutingMatrix.m_GridRouting;
+
+ if( c2 < 0 || c2 >= RoutingMatrix.m_Ncols )
+ {
+ msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
+ pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
+ wxMessageBox( msg );
+ return 0;
+ }
+
+ SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
+ cellCount++;
+ }
+
+ SortWork();
+ return cellCount;
+}
+
+// Initialize m_opWriteCell member to make the aLogicOp
+void MATRIX_ROUTING_HEAD::SetCellOperation( int aLogicOp )
+{
+ switch( aLogicOp )
+ {
+ default:
+ case WRITE_CELL:
+ m_opWriteCell = &MATRIX_ROUTING_HEAD::SetCell;
+ break;
+
+ case WRITE_OR_CELL:
+ m_opWriteCell = &MATRIX_ROUTING_HEAD::OrCell;
+ break;
+
+ case WRITE_XOR_CELL:
+ m_opWriteCell = &MATRIX_ROUTING_HEAD::XorCell;
+ break;
+
+ case WRITE_AND_CELL:
+ m_opWriteCell = &MATRIX_ROUTING_HEAD::AndCell;
+ break;
+
+ case WRITE_ADD_CELL:
+ m_opWriteCell = &MATRIX_ROUTING_HEAD::AddCell;
+ break;
+ }
+}
+
+
+/* return the value stored in a cell
+ */
+MATRIX_CELL MATRIX_ROUTING_HEAD::GetCell( int aRow, int aCol, int aSide )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ return p[aRow * m_Ncols + aCol];
+}
+
+
+/* basic cell operation : WRITE operation
+ */
+void MATRIX_ROUTING_HEAD::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] = x;
+}
+
+
+/* basic cell operation : OR operation
+ */
+void MATRIX_ROUTING_HEAD::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] |= x;
+}
+
+
+/* basic cell operation : XOR operation
+ */
+void MATRIX_ROUTING_HEAD::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] ^= x;
+}
+
+
+/* basic cell operation : AND operation
+ */
+void MATRIX_ROUTING_HEAD::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] &= x;
+}
+
+
+/* basic cell operation : ADD operation
+ */
+void MATRIX_ROUTING_HEAD::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = RoutingMatrix.m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] += x;
+}
+
+
+// fetch distance cell
+DIST_CELL MATRIX_ROUTING_HEAD::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
+{
+ DIST_CELL* p;
+
+ p = RoutingMatrix.m_DistSide[aSide];
+ return p[aRow * m_Ncols + aCol];
+}
+
+
+// store distance cell
+void MATRIX_ROUTING_HEAD::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
+{
+ DIST_CELL* p;
+
+ p = RoutingMatrix.m_DistSide[aSide];
+ p[aRow * m_Ncols + aCol] = x;
+}
+
+
+// fetch direction cell
+int MATRIX_ROUTING_HEAD::GetDir( int aRow, int aCol, int aSide )
+{
+ DIR_CELL* p;
+
+ p = RoutingMatrix.m_DirSide[aSide];
+ return (int) (p[aRow * m_Ncols + aCol]);
+}
+
+
+// store direction cell
+void MATRIX_ROUTING_HEAD::SetDir( int aRow, int aCol, int aSide, int x )
+{
+ DIR_CELL* p;
+
+ p = RoutingMatrix.m_DirSide[aSide];
+ p[aRow * m_Ncols + aCol] = (char) x;
+}
diff --git a/pcbnew/autorouter/auto_place_footprints.cpp b/pcbnew/autorouter/auto_place_footprints.cpp
deleted file mode 100644
index 289c9db..0000000
--- a/pcbnew/autorouter/auto_place_footprints.cpp
+++ /dev/null
@@ -1,1298 +0,0 @@
-/**
- * @file auto_place_footprints.cpp
- * @brief Functions to automatically place Footprints on a board.
- */
-
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
- * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
- * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- *
- * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * 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 <fctsys.h>
-#include <class_drawpanel.h>
-#include <confirm.h>
-#include <pcbnew.h>
-#include <pcb_edit_frame.h>
-#include <gr_basic.h>
-#include <macros.h>
-#include <msgpanel.h>
-
-#include <autorout.h>
-#include <cell.h>
-
-#include <class_board.h>
-#include <class_module.h>
-#include <class_track.h>
-#include <class_drawsegment.h>
-#include <convert_to_biu.h>
-#include <base_units.h>
-#include <protos.h>
-
-
-#define GAIN 16
-#define KEEP_OUT_MARGIN 500
-
-
-/* Penalty (cost) for CntRot90 and CntRot180:
- * CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
- */
-static const double OrientPenality[11] =
-{
- 2.0, // CntRot = 0 rotation prohibited
- 1.9, // CntRot = 1
- 1.8, // CntRot = 2
- 1.7, // CntRot = 3
- 1.6, // CntRot = 4
- 1.5, // CntRot = 5
- 1.4, // CntRot = 5
- 1.3, // CntRot = 7
- 1.2, // CntRot = 8
- 1.1, // CntRot = 9
- 1.0 // CntRot = 10 rotation authorized, no penalty
-};
-
-// Cell states.
-#define OUT_OF_BOARD -2
-#define OCCUPED_By_MODULE -1
-#define FREE_CELL 0
-
-
-static wxPoint CurrPosition; // Current position of the current module placement
-double MinCout;
-
-
-/* generates the Routing matrix, used to fing the best placement
- * of a footprint.
- * Allocate a "bitmap" which is an image of the real board
- * the bitmap handles:
- * - The free areas
- * - penalties (cell not occupied, but near occupied areas)
- * - cells occupied by footprints, board cutout ...
- */
-int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel );
-
-/* searches for the optimal position of aModule.
- * return 1 if placement impossible or 0 if OK.
- */
-static int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame,
- MODULE* aModule, wxDC* aDC );
-
-/*
- * Function compute_Ratsnest_PlaceModule
- * displays the module's ratsnest during displacement, and assess the "cost"
- * of the position.
- *
- * The cost is the longest ratsnest distance with penalty for connections
- * approaching 45 degrees.
- */
-static double compute_Ratsnest_PlaceModule( BOARD* aBrd );
-
-/* Place a footprint on the Routing matrix.
- */
-void genModuleOnRoutingMatrix( MODULE* Module );
-/*
- * Displays the Placement/Routing matrix on the screen
- */
-static void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC );
-
-static int TstModuleOnBoard( BOARD* Pcb, MODULE* Module, bool TstOtherSide );
-
-static void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
- int marge, int aKeepOut, LSET aLayerMask );
-
-static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC );
-static int propagate();
-
-void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
-{
- MODULE* currModule = NULL;
- wxPoint PosOK;
- wxPoint memopos;
- int error;
- PCB_LAYER_ID lay_tmp_TOP, lay_tmp_BOTTOM;
-
- // Undo: init list
- PICKED_ITEMS_LIST newList;
-
- newList.m_Status = UR_CHANGED;
- ITEM_PICKER picker( NULL, UR_CHANGED );
-
- if( GetBoard()->m_Modules == NULL )
- return;
-
- m_canvas->SetAbortRequest( false );
-
- switch( place_mode )
- {
- case PLACE_1_MODULE:
- currModule = Module;
-
- if( currModule == NULL )
- return;
-
- currModule->SetIsPlaced( false );
- currModule->SetNeedsPlaced( false );
- break;
-
- case PLACE_OUT_OF_BOARD:
- break;
-
- case PLACE_ALL:
-
- if( !IsOK( this, _( "Footprints NOT LOCKED will be moved" ) ) )
- return;
-
- break;
-
- case PLACE_INCREMENTAL:
-
- if( !IsOK( this, _( "Footprints NOT PLACED will be moved" ) ) )
- return;
-
- break;
- }
-
- memopos = CurrPosition;
- lay_tmp_BOTTOM = g_Route_Layer_BOTTOM;
- lay_tmp_TOP = g_Route_Layer_TOP;
-
- RoutingMatrix.m_GridRouting = (int) GetScreen()->GetGridSize().x;
-
- // Ensure Board.m_GridRouting has a reasonable value:
- if( RoutingMatrix.m_GridRouting < Millimeter2iu( 0.25 ) )
- RoutingMatrix.m_GridRouting = Millimeter2iu( 0.25 );
-
- // Compute module parameters used in auto place
- if( genPlacementRoutingMatrix( GetBoard(), m_messagePanel ) == 0 )
- return;
-
- int moduleCount = 0;
- Module = GetBoard()->m_Modules;
-
- for( ; Module != NULL; Module = Module->Next() )
- {
- Module->SetNeedsPlaced( false );
-
- switch( place_mode )
- {
- case PLACE_1_MODULE:
-
- if( currModule == Module )
- {
- // Module will be placed, add to undo.
- picker.SetItem( currModule );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- }
-
- break;
-
- case PLACE_OUT_OF_BOARD:
- Module->SetIsPlaced( false );
-
- if( Module->IsLocked() )
- break;
-
- if( !RoutingMatrix.m_BrdBox.Contains( Module->GetPosition() ) )
- {
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- }
-
- break;
-
- case PLACE_ALL:
- Module->SetIsPlaced( false );
-
- if( Module->IsLocked() )
- break;
-
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- break;
-
- case PLACE_INCREMENTAL:
-
- if( Module->IsLocked() )
- {
- Module->SetIsPlaced( false );
- break;
- }
-
- if( !Module->NeedsPlaced() )
- {
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- }
-
- break;
- }
-
- if( Module->NeedsPlaced() ) // Erase from screen
- {
- moduleCount++;
- Module->Draw( m_canvas, DC, GR_XOR );
- }
- else
- {
- genModuleOnRoutingMatrix( Module );
- }
- }
-
- // Undo command: prepare list
- if( newList.GetCount() )
- SaveCopyInUndoList( newList, UR_CHANGED );
-
- int cnt = 0;
- wxString msg;
-
- while( ( Module = PickModule( this, DC ) ) != NULL )
- {
- // Display some info about activity, module placement can take a while:
- msg.Printf( _( "Place footprint %d of %d" ), cnt, moduleCount );
- SetStatusText( msg );
-
- double initialOrient = Module->GetOrientation();
- // Display fill area of interest, barriers, penalties.
- drawPlacementRoutingMatrix( GetBoard(), DC );
-
- error = getOptimalModulePlacement( this, Module, DC );
- double bestScore = MinCout;
- double bestRotation = 0.0;
- int rotAllowed;
- PosOK = CurrPosition;
-
- if( error == ESC )
- goto end_of_tst;
-
- // Try orientations 90, 180, 270 degrees from initial orientation
- rotAllowed = Module->GetPlacementCost180();
-
- if( rotAllowed != 0 )
- {
- Rotate_Module( DC, Module, 1800.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
-
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 1800.0;
- }
- else
- {
- Rotate_Module( DC, Module, initialOrient, false );
- }
-
- if( error == ESC )
- goto end_of_tst;
- }
-
- // Determine if the best orientation of a module is 90.
- rotAllowed = Module->GetPlacementCost90();
-
- if( rotAllowed != 0 )
- {
- Rotate_Module( DC, Module, 900.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
-
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 900.0;
- }
- else
- {
- Rotate_Module( DC, Module, initialOrient, false );
- }
-
- if( error == ESC )
- goto end_of_tst;
- }
-
- // Determine if the best orientation of a module is -90.
- if( rotAllowed != 0 )
- {
- Rotate_Module( DC, Module, 2700.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
-
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 2700.0;
- }
- else
- {
- Rotate_Module( DC, Module, initialOrient, false );
- }
-
- if( error == ESC )
- goto end_of_tst;
- }
-
-end_of_tst:
-
- if( error == ESC )
- break;
-
- // Place module.
- CurrPosition = GetCrossHairPosition();
- SetCrossHairPosition( PosOK );
-
- PlaceModule( Module, DC );
-
- bestRotation += initialOrient;
-
- if( bestRotation != Module->GetOrientation() )
- Rotate_Module( DC, Module, bestRotation, false );
-
- SetCrossHairPosition( CurrPosition );
-
- Module->CalculateBoundingBox();
-
- genModuleOnRoutingMatrix( Module );
- Module->SetIsPlaced( true );
- Module->SetNeedsPlaced( false );
- }
-
- CurrPosition = memopos;
-
- RoutingMatrix.UnInitRoutingMatrix();
-
- g_Route_Layer_TOP = lay_tmp_TOP;
- g_Route_Layer_BOTTOM = lay_tmp_BOTTOM;
-
- Module = GetBoard()->m_Modules;
-
- for( ; Module != NULL; Module = Module->Next() )
- {
- Module->CalculateBoundingBox();
- }
-
- GetBoard()->m_Status_Pcb = 0;
- Compile_Ratsnest( DC, true );
- m_canvas->ReDraw( DC, true );
-}
-
-
-void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC )
-{
- int ii, jj;
- COLOR4D color;
- int ox, oy;
- MATRIX_CELL top_state, bottom_state;
-
- GRSetDrawMode( DC, GR_COPY );
-
- for( ii = 0; ii < RoutingMatrix.m_Nrows; ii++ )
- {
- oy = RoutingMatrix.m_BrdBox.GetY() + ( ii * RoutingMatrix.m_GridRouting );
-
- for( jj = 0; jj < RoutingMatrix.m_Ncols; jj++ )
- {
- ox = RoutingMatrix.m_BrdBox.GetX() + (jj * RoutingMatrix.m_GridRouting);
- color = COLOR4D::BLACK;
-
- top_state = RoutingMatrix.GetCell( ii, jj, TOP );
- bottom_state = RoutingMatrix.GetCell( ii, jj, BOTTOM );
-
- if( top_state & CELL_is_ZONE )
- color = COLOR4D( BLUE );
-
- // obstacles
- if( ( top_state & CELL_is_EDGE ) || ( bottom_state & CELL_is_EDGE ) )
- color = COLOR4D::WHITE;
- else if( top_state & ( HOLE | CELL_is_MODULE ) )
- color = COLOR4D( LIGHTRED );
- else if( bottom_state & (HOLE | CELL_is_MODULE) )
- color = COLOR4D( LIGHTGREEN );
- else // Display the filling and keep out regions.
- {
- if( RoutingMatrix.GetDist( ii, jj, TOP )
- || RoutingMatrix.GetDist( ii, jj, BOTTOM ) )
- color = DARKGRAY;
- }
-
- GRPutPixel( NULL, DC, ox, oy, color );
- }
- }
-}
-
-
-int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel )
-{
- wxString msg;
-
- RoutingMatrix.UnInitRoutingMatrix();
-
- EDA_RECT bbox = aBrd->GetBoardEdgesBoundingBox();
-
- if( bbox.GetWidth() == 0 || bbox.GetHeight() == 0 )
- {
- DisplayError( NULL, _( "No PCB edge found, unknown board size!" ) );
- return 0;
- }
-
- RoutingMatrix.ComputeMatrixSize( aBrd, true );
- int nbCells = RoutingMatrix.m_Ncols * RoutingMatrix.m_Nrows;
-
- messagePanel->EraseMsgBox();
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_Ncols );
- messagePanel->SetMessage( 1, _( "Cols" ), msg, GREEN );
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_Nrows );
- messagePanel->SetMessage( 7, _( "Lines" ), msg, GREEN );
- msg.Printf( wxT( "%d" ), nbCells );
- messagePanel->SetMessage( 14, _( "Cells." ), msg, YELLOW );
-
- // Choose the number of board sides.
- RoutingMatrix.m_RoutingLayersCount = 2;
-
- RoutingMatrix.InitRoutingMatrix();
-
- // Display memory usage.
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_MemSize / 1024 );
- messagePanel->SetMessage( 24, wxT( "Mem(Kb)" ), msg, CYAN );
-
- g_Route_Layer_BOTTOM = F_Cu;
-
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
- g_Route_Layer_BOTTOM = B_Cu;
-
- g_Route_Layer_TOP = F_Cu;
-
- // Place the edge layer segments
- TRACK TmpSegm( NULL );
-
- TmpSegm.SetLayer( UNDEFINED_LAYER );
- TmpSegm.SetNetCode( -1 );
- TmpSegm.SetWidth( RoutingMatrix.m_GridRouting / 2 );
-
- for( auto PtStruct : aBrd->Drawings() )
- {
- DRAWSEGMENT* DrawSegm;
-
- switch( PtStruct->Type() )
- {
- case PCB_LINE_T:
- DrawSegm = (DRAWSEGMENT*) PtStruct;
-
- if( DrawSegm->GetLayer() != Edge_Cuts )
- break;
-
- TraceSegmentPcb( DrawSegm, HOLE | CELL_is_EDGE,
- RoutingMatrix.m_GridRouting, WRITE_CELL );
- break;
-
- case PCB_TEXT_T:
- default:
- break;
- }
- }
-
- // Mark cells of the routing matrix to CELL_is_ZONE
- // (i.e. availlable cell to place a module )
- // Init a starting point of attachment to the area.
- RoutingMatrix.OrCell( RoutingMatrix.m_Nrows / 2, RoutingMatrix.m_Ncols / 2,
- BOTTOM, CELL_is_ZONE );
-
- // find and mark all other availlable cells:
- for( int ii = 1; ii != 0; )
- ii = propagate();
-
- // Initialize top layer. to the same value as the bottom layer
- if( RoutingMatrix.m_BoardSide[TOP] )
- memcpy( RoutingMatrix.m_BoardSide[TOP], RoutingMatrix.m_BoardSide[BOTTOM],
- nbCells * sizeof(MATRIX_CELL) );
-
- return 1;
-}
-
-
-/* Place module on Routing matrix.
- */
-void genModuleOnRoutingMatrix( MODULE* Module )
-{
- int ox, oy, fx, fy;
- LSET layerMask;
- D_PAD* Pad;
-
- EDA_RECT fpBBox = Module->GetBoundingBox();
-
- fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 );
- ox = fpBBox.GetX();
- fx = fpBBox.GetRight();
- oy = fpBBox.GetY();
- fy = fpBBox.GetBottom();
-
- if( ox < RoutingMatrix.m_BrdBox.GetX() )
- ox = RoutingMatrix.m_BrdBox.GetX();
-
- if( ox > RoutingMatrix.m_BrdBox.GetRight() )
- ox = RoutingMatrix.m_BrdBox.GetRight();
-
- if( fx < RoutingMatrix.m_BrdBox.GetX() )
- fx = RoutingMatrix.m_BrdBox.GetX();
-
- if( fx > RoutingMatrix.m_BrdBox.GetRight() )
- fx = RoutingMatrix.m_BrdBox.GetRight();
-
- if( oy < RoutingMatrix.m_BrdBox.GetY() )
- oy = RoutingMatrix.m_BrdBox.GetY();
-
- if( oy > RoutingMatrix.m_BrdBox.GetBottom() )
- oy = RoutingMatrix.m_BrdBox.GetBottom();
-
- if( fy < RoutingMatrix.m_BrdBox.GetY() )
- fy = RoutingMatrix.m_BrdBox.GetY();
-
- if( fy > RoutingMatrix.m_BrdBox.GetBottom() )
- fy = RoutingMatrix.m_BrdBox.GetBottom();
-
- if( Module->GetLayer() == F_Cu )
- layerMask.set( F_Cu );
-
- if( Module->GetLayer() == B_Cu )
- layerMask.set( B_Cu );
-
- TraceFilledRectangle( ox, oy, fx, fy, layerMask,
- CELL_is_MODULE, WRITE_OR_CELL );
-
- // Trace pads + clearance areas.
- for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() )
- {
- int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance();
- ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL );
- }
-
- // Trace clearance.
- int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN;
- CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask );
-}
-
-
-// A minor helper function to draw a bounding box:
-inline void draw_FootprintRect( EDA_RECT* aClipBox, wxDC* aDC, EDA_RECT& fpBBox, COLOR4D aColor )
-{
-#ifndef USE_WX_OVERLAY
- GRRect( aClipBox, aDC, fpBBox, 0, aColor );
-#endif
-}
-
-
-int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aDC )
-{
- int error = 1;
- wxPoint LastPosOK;
- double min_cost, curr_cost, Score;
- bool TstOtherSide;
- auto displ_opts = (PCB_DISPLAY_OPTIONS*)aFrame->GetDisplayOptions();
- BOARD* brd = aFrame->GetBoard();
-
- aModule->CalculateBoundingBox();
-
- bool showRats = displ_opts->m_Show_Module_Ratsnest;
- displ_opts->m_Show_Module_Ratsnest = false;
-
- brd->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
- aFrame->SetMsgPanel( aModule );
-
- LastPosOK = RoutingMatrix.m_BrdBox.GetOrigin();
-
- wxPoint mod_pos = aModule->GetPosition();
- EDA_RECT fpBBox = aModule->GetFootprintRect();
-
- // Move fpBBox to have the footprint position at (0,0)
- fpBBox.Move( -mod_pos );
- wxPoint fpBBoxOrg = fpBBox.GetOrigin();
-
- // Calculate the limit of the footprint position, relative
- // to the routing matrix area
- wxPoint xylimit = RoutingMatrix.m_BrdBox.GetEnd() - fpBBox.GetEnd();
-
- wxPoint initialPos = RoutingMatrix.m_BrdBox.GetOrigin() - fpBBoxOrg;
-
- // Stay on grid.
- initialPos.x -= initialPos.x % RoutingMatrix.m_GridRouting;
- initialPos.y -= initialPos.y % RoutingMatrix.m_GridRouting;
-
- CurrPosition = initialPos;
-
- // Undraw the current footprint
- aModule->DrawOutlinesWhenMoving( aFrame->GetCanvas(), aDC, wxPoint( 0, 0 ) );
-
- g_Offset_Module = mod_pos - CurrPosition;
-
- /* Examine pads, and set TstOtherSide to true if a footprint
- * has at least 1 pad through.
- */
- TstOtherSide = false;
-
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
- {
- LSET other( aModule->GetLayer() == B_Cu ? F_Cu : B_Cu );
-
- for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
- {
- if( !( pad->GetLayerSet() & other ).any() )
- continue;
-
- TstOtherSide = true;
- break;
- }
- }
-
- // Draw the initial bounding box position
- COLOR4D color = COLOR4D( BROWN );
- fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
- draw_FootprintRect(aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color);
-
- min_cost = -1.0;
- aFrame->SetStatusText( wxT( "Score ??, pos ??" ) );
-
- for( ; CurrPosition.x < xylimit.x; CurrPosition.x += RoutingMatrix.m_GridRouting )
- {
- wxYield();
-
- if( aFrame->GetCanvas()->GetAbortRequest() )
- {
- if( IsOK( aFrame, _( "OK to abort?" ) ) )
- {
- displ_opts->m_Show_Module_Ratsnest = showRats;
- return ESC;
- }
- else
- aFrame->GetCanvas()->SetAbortRequest( false );
- }
-
- CurrPosition.y = initialPos.y;
-
- for( ; CurrPosition.y < xylimit.y; CurrPosition.y += RoutingMatrix.m_GridRouting )
- {
- // Erase traces.
- draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
-
- fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
- g_Offset_Module = mod_pos - CurrPosition;
- int keepOutCost = TstModuleOnBoard( brd, aModule, TstOtherSide );
-
- // Draw at new place
- color = keepOutCost >= 0 ? BROWN : RED;
- draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
-
- if( keepOutCost >= 0 ) // i.e. if the module can be put here
- {
- error = 0;
- aFrame->build_ratsnest_module( aModule );
- curr_cost = compute_Ratsnest_PlaceModule( brd );
- Score = curr_cost + keepOutCost;
-
- if( (min_cost >= Score ) || (min_cost < 0 ) )
- {
- LastPosOK = CurrPosition;
- min_cost = Score;
- wxString msg;
- msg.Printf( wxT( "Score %g, pos %s, %s" ),
- min_cost,
- GetChars( ::CoordinateToString( LastPosOK.x ) ),
- GetChars( ::CoordinateToString( LastPosOK.y ) ) );
- aFrame->SetStatusText( msg );
- }
- }
- }
- }
-
- // erasing the last traces
- GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
-
- displ_opts->m_Show_Module_Ratsnest = showRats;
-
- // Regeneration of the modified variable.
- CurrPosition = LastPosOK;
-
- brd->m_Status_Pcb &= ~( RATSNEST_ITEM_LOCAL_OK | LISTE_PAD_OK );
-
- MinCout = min_cost;
- return error;
-}
-
-
-/* Test if the rectangular area (ux, ux .. y0, y1):
- * - is a free zone (except OCCUPED_By_MODULE returns)
- * - is on the working surface of the board (otherwise returns OUT_OF_BOARD)
- *
- * Returns OUT_OF_BOARD, or OCCUPED_By_MODULE or FREE_CELL if OK
- */
-int TstRectangle( BOARD* Pcb, const EDA_RECT& aRect, int side )
-{
- EDA_RECT rect = aRect;
-
- rect.Inflate( RoutingMatrix.m_GridRouting / 2 );
-
- wxPoint start = rect.GetOrigin();
- wxPoint end = rect.GetEnd();
-
- start -= RoutingMatrix.m_BrdBox.GetOrigin();
- end -= RoutingMatrix.m_BrdBox.GetOrigin();
-
- int row_min = start.y / RoutingMatrix.m_GridRouting;
- int row_max = end.y / RoutingMatrix.m_GridRouting;
- int col_min = start.x / RoutingMatrix.m_GridRouting;
- int col_max = end.x / RoutingMatrix.m_GridRouting;
-
- if( start.y > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- if( start.x > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( int row = row_min; row <= row_max; row++ )
- {
- for( int col = col_min; col <= col_max; col++ )
- {
- unsigned int data = RoutingMatrix.GetCell( row, col, side );
-
- if( ( data & CELL_is_ZONE ) == 0 )
- return OUT_OF_BOARD;
-
- if( (data & CELL_is_MODULE) )
- return OCCUPED_By_MODULE;
- }
- }
-
- return FREE_CELL;
-}
-
-
-/* Calculates and returns the clearance area of the rectangular surface
- * aRect):
- * (Sum of cells in terms of distance)
- */
-unsigned int CalculateKeepOutArea( const EDA_RECT& aRect, int side )
-{
- wxPoint start = aRect.GetOrigin();
- wxPoint end = aRect.GetEnd();
-
- start -= RoutingMatrix.m_BrdBox.GetOrigin();
- end -= RoutingMatrix.m_BrdBox.GetOrigin();
-
- int row_min = start.y / RoutingMatrix.m_GridRouting;
- int row_max = end.y / RoutingMatrix.m_GridRouting;
- int col_min = start.x / RoutingMatrix.m_GridRouting;
- int col_max = end.x / RoutingMatrix.m_GridRouting;
-
- if( start.y > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- if( start.x > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- unsigned int keepOutCost = 0;
-
- for( int row = row_min; row <= row_max; row++ )
- {
- for( int col = col_min; col <= col_max; col++ )
- {
- // RoutingMatrix.GetDist returns the "cost" of the cell
- // at position (row, col)
- // in autoplace this is the cost of the cell, if it is
- // inside aRect
- keepOutCost += RoutingMatrix.GetDist( row, col, side );
- }
- }
-
- return keepOutCost;
-}
-
-
-/* Test if the module can be placed on the board.
- * Returns the value TstRectangle().
- * Module is known by its bounding box
- */
-int TstModuleOnBoard( BOARD* Pcb, MODULE* aModule, bool TstOtherSide )
-{
- int side = TOP;
- int otherside = BOTTOM;
-
- if( aModule->GetLayer() == B_Cu )
- {
- side = BOTTOM; otherside = TOP;
- }
-
- EDA_RECT fpBBox = aModule->GetFootprintRect();
- fpBBox.Move( -g_Offset_Module );
-
- int diag = TstRectangle( Pcb, fpBBox, side );
-
- if( diag != FREE_CELL )
- return diag;
-
- if( TstOtherSide )
- {
- diag = TstRectangle( Pcb, fpBBox, otherside );
-
- if( diag != FREE_CELL )
- return diag;
- }
-
- int marge = ( RoutingMatrix.m_GridRouting * aModule->GetPadCount() ) / GAIN;
-
- fpBBox.Inflate( marge );
- return CalculateKeepOutArea( fpBBox, side );
-}
-
-
-double compute_Ratsnest_PlaceModule( BOARD* aBrd )
-{
- double curr_cost;
- wxPoint start; // start point of a ratsnest
- wxPoint end; // end point of a ratsnest
- int dx, dy;
-
- if( ( aBrd->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
- return -1;
-
- curr_cost = 0;
-
- for( unsigned ii = 0; ii < aBrd->m_LocalRatsnest.size(); ii++ )
- {
- RATSNEST_ITEM* pt_local_rats_nest = &aBrd->m_LocalRatsnest[ii];
-
- if( ( pt_local_rats_nest->m_Status & LOCAL_RATSNEST_ITEM ) )
- continue; // Skip ratsnest between 2 pads of the current module
-
- // Skip modules not inside the board area
- MODULE* module = pt_local_rats_nest->m_PadEnd->GetParent();
-
- if( !RoutingMatrix.m_BrdBox.Contains( module->GetPosition() ) )
- continue;
-
- start = pt_local_rats_nest->m_PadStart->GetPosition() - g_Offset_Module;
- end = pt_local_rats_nest->m_PadEnd->GetPosition();
-
- // Cost of the ratsnest.
- dx = end.x - start.x;
- dy = end.y - start.y;
-
- dx = abs( dx );
- dy = abs( dy );
-
- // ttry to have always dx >= dy to calculate the cost of the rastsnet
- if( dx < dy )
- std::swap( dx, dy );
-
- // Cost of the connection = length + penalty due to the slope
- // dx is the biggest length relative to the X or Y axis
- // the penalty is max for 45 degrees ratsnests,
- // and 0 for horizontal or vertical ratsnests.
- // For Horizontal and Vertical ratsnests, dy = 0;
- double conn_cost = hypot( dx, dy * 2.0 );
- curr_cost += conn_cost; // Total cost = sum of costs of each connection
- }
-
- return curr_cost;
-}
-
-
-/**
- * Function CreateKeepOutRectangle
- * builds the cost map:
- * Cells ( in Dist map ) inside the rect x0,y0 a x1,y1 are
- * incremented by value aKeepOut
- * Cell outside this rectangle, but inside the rectangle
- * x0,y0 -marge to x1,y1 + marge are incremented by a decreasing value
- * (aKeepOut ... 0). The decreasing value depends on the distance to the first rectangle
- * Therefore the cost is high in rect x0,y0 to x1,y1, and decrease outside this rectangle
- */
-void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
- int marge, int aKeepOut, LSET aLayerMask )
-{
- int row, col;
- int row_min, row_max, col_min, col_max, pmarge;
- int trace = 0;
- DIST_CELL data, LocalKeepOut;
- int lgain, cgain;
-
- if( aLayerMask[g_Route_Layer_BOTTOM] )
- trace = 1; // Trace on bottom layer.
-
- if( aLayerMask[g_Route_Layer_TOP] && RoutingMatrix.m_RoutingLayersCount )
- trace |= 2; // Trace on top layer.
-
- if( trace == 0 )
- return;
-
- ux0 -= RoutingMatrix.m_BrdBox.GetX();
- uy0 -= RoutingMatrix.m_BrdBox.GetY();
- ux1 -= RoutingMatrix.m_BrdBox.GetX();
- uy1 -= RoutingMatrix.m_BrdBox.GetY();
-
- ux0 -= marge; ux1 += marge;
- uy0 -= marge; uy1 += marge;
-
- pmarge = marge / RoutingMatrix.m_GridRouting;
-
- if( pmarge < 1 )
- pmarge = 1;
-
- // Calculate the coordinate limits of the rectangle.
- row_max = uy1 / RoutingMatrix.m_GridRouting;
- col_max = ux1 / RoutingMatrix.m_GridRouting;
- row_min = uy0 / RoutingMatrix.m_GridRouting;
-
- if( uy0 > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- col_min = ux0 / RoutingMatrix.m_GridRouting;
-
- if( ux0 > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= (RoutingMatrix.m_Nrows - 1) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= (RoutingMatrix.m_Ncols - 1) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( row = row_min; row <= row_max; row++ )
- {
- lgain = 256;
-
- if( row < pmarge )
- lgain = ( 256 * row ) / pmarge;
- else if( row > row_max - pmarge )
- lgain = ( 256 * ( row_max - row ) ) / pmarge;
-
- for( col = col_min; col <= col_max; col++ )
- {
- // RoutingMatrix Dist map containt the "cost" of the cell
- // at position (row, col)
- // in autoplace this is the cost of the cell, when
- // a footprint overlaps it, near a "master" footprint
- // this cost is hight near the "master" footprint
- // and decrease with the distance
- cgain = 256;
- LocalKeepOut = aKeepOut;
-
- if( col < pmarge )
- cgain = ( 256 * col ) / pmarge;
- else if( col > col_max - pmarge )
- cgain = ( 256 * ( col_max - col ) ) / pmarge;
-
- cgain = ( cgain * lgain ) / 256;
-
- if( cgain != 256 )
- LocalKeepOut = ( LocalKeepOut * cgain ) / 256;
-
- if( trace & 1 )
- {
- data = RoutingMatrix.GetDist( row, col, BOTTOM ) + LocalKeepOut;
- RoutingMatrix.SetDist( row, col, BOTTOM, data );
- }
-
- if( trace & 2 )
- {
- data = RoutingMatrix.GetDist( row, col, TOP );
- data = std::max( data, LocalKeepOut );
- RoutingMatrix.SetDist( row, col, TOP, data );
- }
- }
- }
-}
-
-
-// Sort routines
-static bool Tri_PlaceModules( MODULE* ref, MODULE* compare )
-{
- double ff1, ff2;
-
- ff1 = ref->GetArea() * ref->GetPadCount();
- ff2 = compare->GetArea() * compare->GetPadCount();
-
- return ff2 < ff1;
-}
-
-
-static bool sortFootprintsByRatsnestSize( MODULE* ref, MODULE* compare )
-{
- double ff1, ff2;
-
- ff1 = ref->GetArea() * ref->GetFlag();
- ff2 = compare->GetArea() * compare->GetFlag();
- return ff2 < ff1;
-}
-
-
-/**
- * Function PickModule
- * find the "best" module place
- * The criteria are:
- * - Maximum ratsnest with modules already placed
- * - Max size, and number of pads max
- */
-static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
-{
- MODULE* Module;
- std::vector <MODULE*> moduleList;
-
- // Build sorted footprints list (sort by decreasing size )
- Module = pcbframe->GetBoard()->m_Modules;
-
- for( ; Module != NULL; Module = Module->Next() )
- {
- Module->CalculateBoundingBox();
- moduleList.push_back( Module );
- }
-
- sort( moduleList.begin(), moduleList.end(), Tri_PlaceModules );
-
- for( unsigned kk = 0; kk < moduleList.size(); kk++ )
- {
- Module = moduleList[kk];
- Module->SetFlag( 0 );
-
- if( !Module->NeedsPlaced() )
- continue;
-
- pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
- pcbframe->SetMsgPanel( Module );
- pcbframe->build_ratsnest_module( Module );
-
- // Calculate external ratsnest.
- for( unsigned ii = 0; ii < pcbframe->GetBoard()->m_LocalRatsnest.size(); ii++ )
- {
- if( ( pcbframe->GetBoard()->m_LocalRatsnest[ii].m_Status &
- LOCAL_RATSNEST_ITEM ) == 0 )
- Module->IncrementFlag();
- }
- }
-
- pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
-
- sort( moduleList.begin(), moduleList.end(), sortFootprintsByRatsnestSize );
-
- // Search for "best" module.
- MODULE* bestModule = NULL;
- MODULE* altModule = NULL;
-
- for( unsigned ii = 0; ii < moduleList.size(); ii++ )
- {
- Module = moduleList[ii];
-
- if( !Module->NeedsPlaced() )
- continue;
-
- altModule = Module;
-
- if( Module->GetFlag() == 0 )
- continue;
-
- bestModule = Module;
- break;
- }
-
- if( bestModule )
- return bestModule;
- else
- return altModule;
-}
-
-
-/**
- * Function propagate
- * Used only in autoplace calculations
- * Uses the routing matrix to fill the cells within the zone
- * Search and mark cells within the zone, and agree with DRC options.
- * Requirements:
- * Start from an initial point, to fill zone
- * The zone must have no "copper island"
- * Algorithm:
- * If the current cell has a neighbor flagged as "cell in the zone", it
- * become a cell in the zone
- * The first point in the zone is the starting point
- * 4 searches within the matrix are made:
- * 1 - Left to right and top to bottom
- * 2 - Right to left and top to bottom
- * 3 - bottom to top and Right to left
- * 4 - bottom to top and Left to right
- * Given the current cell, for each search, we consider the 2 neighbor cells
- * the previous cell on the same line and the previous cell on the same column.
- *
- * This function can request some iterations
- * Iterations are made until no cell is added to the zone.
- * @return added cells count (i.e. which the attribute CELL_is_ZONE is set)
- */
-int propagate()
-{
- int row, col;
- long current_cell, old_cell_H;
- std::vector<long> pt_cell_V;
- int nbpoints = 0;
-
-#define NO_CELL_ZONE (HOLE | CELL_is_EDGE | CELL_is_ZONE)
-
- pt_cell_V.reserve( std::max( RoutingMatrix.m_Nrows, RoutingMatrix.m_Ncols ) );
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
-
- // Search from left to right and top to bottom.
- for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
- {
- old_cell_H = 0;
-
- for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
- {
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
-
- if( current_cell == 0 ) // a free cell is found
- {
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
- }
-
- pt_cell_V[col] = old_cell_H = current_cell;
- }
- }
-
- // Search from right to left and top to bottom/
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
-
- for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
- {
- old_cell_H = 0;
-
- for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
- {
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
-
- if( current_cell == 0 ) // a free cell is found
- {
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
- }
-
- pt_cell_V[col] = old_cell_H = current_cell;
- }
- }
-
- // Search from bottom to top and right to left.
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
-
- for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
- {
- old_cell_H = 0;
-
- for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
- {
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
-
- if( current_cell == 0 ) // a free cell is found
- {
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
- }
-
- pt_cell_V[row] = old_cell_H = current_cell;
- }
- }
-
- // Search from bottom to top and left to right.
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
-
- for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
- {
- old_cell_H = 0;
-
- for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
- {
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
-
- if( current_cell == 0 ) // a free cell is found
- {
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
- }
-
- pt_cell_V[row] = old_cell_H = current_cell;
- }
- }
-
- return nbpoints;
-}
diff --git a/pcbnew/autorouter/cell.h b/pcbnew/autorouter/cell.h
deleted file mode 100644
index 63b76ae..0000000
--- a/pcbnew/autorouter/cell.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file cell.h
- */
-
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
- * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
- * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- *
- * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
- *
- * First copyright (C) Randy Nevin, 1989 (see PCBCA package)
- *
- * 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 _CELL_H_
-#define _CELL_H_
-
-
-/* Bits characterizing cell */
-#define HOLE 0x01 /* a conducting hole or obstacle */
-#define CELL_is_MODULE 0x02 /* auto placement occupied by a module */
-#define CELL_is_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
-#define CELL_is_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
-#define CELL_is_ZONE 0x80 /* Area and auto-placement: cell available */
-
-/* Bit masks for presence of obstacles to autorouting */
-#define OCCUPE 1 /* Autorouting: obstacle tracks and vias. */
-#define VIA_IMPOSSIBLE 2 /* Autorouting: obstacle for vias. */
-#define CURRENT_PAD 4
-
-
-/* traces radiating outward from a hole to a side or corner */
-#define HOLE_NORTH 0x00000002L /* upward */
-#define HOLE_NORTHEAST 0x00000004L /* upward and right */
-#define HOLE_EAST 0x00000008L /* to the right */
-#define HOLE_SOUTHEAST 0x00000010L /* downward and right */
-#define HOLE_SOUTH 0x00000020L /* downward */
-#define HOLE_SOUTHWEST 0x00000040L /* downward and left */
-#define HOLE_WEST 0x00000080L /* to the left */
-#define HOLE_NORTHWEST 0x00000100L /* upward and left */
-
-/* straight lines through the center */
-#define LINE_HORIZONTAL 0x00000002L /* left-to-right line */
-#define LINE_VERTICAL 0x00000004L /* top-to-bottom line */
-
-/* lines cutting across a corner, connecting adjacent sides */
-#define CORNER_NORTHEAST 0x00000008L /* upper right corner */
-#define CORNER_SOUTHEAST 0x00000010L /* lower right corner */
-#define CORNER_SOUTHWEST 0x00000020L /* lower left corner */
-#define CORNER_NORTHWEST 0x00000040L /* upper left corner */
-
-/* diagonal lines through the center */
-#define DIAG_NEtoSW 0x00000080L /* northeast to southwest */
-#define DIAG_SEtoNW 0x00000100L /* southeast to northwest */
-
-/* 135 degree angle side-to-far-corner lines */
-#define BENT_NtoSE 0x00000200L /* north to southeast */
-#define BENT_NtoSW 0x00000400L /* north to southwest */
-#define BENT_EtoSW 0x00000800L /* east to southwest */
-#define BENT_EtoNW 0x00001000L /* east to northwest */
-#define BENT_StoNW 0x00002000L /* south to northwest */
-#define BENT_StoNE 0x00004000L /* south to northeast */
-#define BENT_WtoNE 0x00008000L /* west to northeast */
-#define BENT_WtoSE 0x00010000L /* west to southeast */
-
-/* 90 degree corner-to-adjacent-corner lines */
-#define ANGLE_NEtoSE 0x00020000L /* northeast to southeast */
-#define ANGLE_SEtoSW 0x00040000L /* southeast to southwest */
-#define ANGLE_SWtoNW 0x00080000L /* southwest to northwest */
-#define ANGLE_NWtoNE 0x00100000L /* northwest to northeast */
-
-/* 45 degree angle side-to-near-corner lines */
-#define SHARP_NtoNE 0x00200000L /* north to northeast */
-#define SHARP_EtoNE 0x00400000L /* east to northeast */
-#define SHARP_EtoSE 0x00800000L /* east to southeast */
-#define SHARP_StoSE 0x01000000L /* south to southeast */
-#define SHARP_StoSW 0x02000000L /* south to southwest */
-#define SHARP_WtoSW 0x04000000L /* west to southwest */
-#define SHARP_WtoNW 0x08000000L /* west to northwest */
-#define SHARP_NtoNW 0x10000000L /* north to northwest */
-
-/* directions the cell can be reached from (point to previous cell) */
-#define FROM_NOWHERE 0
-#define FROM_NORTH 1
-#define FROM_NORTHEAST 2
-#define FROM_EAST 3
-#define FROM_SOUTHEAST 4
-#define FROM_SOUTH 5
-#define FROM_SOUTHWEST 6
-#define FROM_WEST 7
-#define FROM_NORTHWEST 8
-#define FROM_OTHERSIDE 9
-
-
-#endif // _CELL_H_
-
diff --git a/pcbnew/autorouter/routing_matrix.cpp b/pcbnew/autorouter/routing_matrix.cpp
deleted file mode 100644
index 856dead..0000000
--- a/pcbnew/autorouter/routing_matrix.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
- * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
- * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
- *
- * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * 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
- */
-
-/**
- * @file routing_matrix.cpp
- * @brief Functions to create autorouting maps
- */
-
-#include <fctsys.h>
-#include <common.h>
-
-#include <pcbnew.h>
-#include <cell.h>
-#include <autorout.h>
-
-#include <class_eda_rect.h>
-#include <class_board.h>
-#include <class_module.h>
-#include <class_track.h>
-#include <class_drawsegment.h>
-#include <class_edge_mod.h>
-#include <class_pcb_text.h>
-
-
-MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
-{
- m_BoardSide[0] = m_BoardSide[1] = NULL;
- m_DistSide[0] = m_DistSide[1] = NULL;
- m_DirSide[0] = m_DirSide[1] = NULL;
- m_opWriteCell = NULL;
- m_InitMatrixDone = false;
- m_Nrows = 0;
- m_Ncols = 0;
- m_MemSize = 0;
- m_RoutingLayersCount = 1;
- m_GridRouting = 0;
- m_RouteCount = 0;
-}
-
-
-MATRIX_ROUTING_HEAD::~MATRIX_ROUTING_HEAD()
-{
-}
-
-
-bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
-{
- // The boundary box must have its start point on routing grid:
- m_BrdBox = aUseBoardEdgesOnly ? aPcb->GetBoardEdgesBoundingBox() : aPcb->GetBoundingBox();
-
- m_BrdBox.SetX( m_BrdBox.GetX() - ( m_BrdBox.GetX() % m_GridRouting ) );
- m_BrdBox.SetY( m_BrdBox.GetY() - ( m_BrdBox.GetY() % m_GridRouting ) );
-
- // The boundary box must have its end point on routing grid:
- wxPoint end = m_BrdBox.GetEnd();
-
- end.x -= end.x % m_GridRouting;
- end.x += m_GridRouting;
-
- end.y -= end.y % m_GridRouting;
- end.y += m_GridRouting;
-
- m_BrdBox.SetEnd( end );
-
- m_Nrows = m_BrdBox.GetHeight() / m_GridRouting;
- m_Ncols = m_BrdBox.GetWidth() / m_GridRouting;
-
- // gives a small margin
- m_Ncols += 1;
- m_Nrows += 1;
-
- return true;
-}
-
-
-int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
-{
- if( m_Nrows <= 0 || m_Ncols <= 0 )
- return 0;
-
- m_InitMatrixDone = true; // we have been called
-
- // give a small margin for memory allocation:
- int ii = (RoutingMatrix.m_Nrows + 1) * (RoutingMatrix.m_Ncols + 1);
-
- int side = BOTTOM;
- for( int jj = 0; jj < m_RoutingLayersCount; jj++ ) // m_RoutingLayersCount = 1 or 2
- {
- m_BoardSide[side] = NULL;
- m_DistSide[side] = NULL;
- m_DirSide[side] = NULL;
-
- // allocate matrix & initialize everything to empty
- m_BoardSide[side] = (MATRIX_CELL*) operator new( ii * sizeof(MATRIX_CELL) );
- memset( m_BoardSide[side], 0, ii * sizeof(MATRIX_CELL) );
-
- if( m_BoardSide[side] == NULL )
- return -1;
-
- // allocate Distances
- m_DistSide[side] = (DIST_CELL*) operator new( ii * sizeof(DIST_CELL) );
- memset( m_DistSide[side], 0, ii * sizeof(DIST_CELL) );
-
- if( m_DistSide[side] == NULL )
- return -1;
-
- // allocate Dir (chars)
- m_DirSide[side] = (char*) operator new( ii );
- memset( m_DirSide[side], 0, ii );
-
- if( m_DirSide[side] == NULL )
- return -1;
-
- side = TOP;
- }
-
- m_MemSize = m_RouteCount * ii * ( sizeof(MATRIX_CELL)
- + sizeof(DIST_CELL) + sizeof(char) );
-
- return m_MemSize;
-}
-
-
-void MATRIX_ROUTING_HEAD::UnInitRoutingMatrix()
-{
- int ii;
-
- m_InitMatrixDone = false;
-
- for( ii = 0; ii < MAX_ROUTING_LAYERS_COUNT; ii++ )
- {
- // de-allocate Dir matrix
- if( m_DirSide[ii] )
- {
- delete m_DirSide[ii];
- m_DirSide[ii] = NULL;
- }
-
- // de-allocate Distances matrix
- if( m_DistSide[ii] )
- {
- delete m_DistSide[ii];
- m_DistSide[ii] = NULL;
- }
-
- // de-allocate cells matrix
- if( m_BoardSide[ii] )
- {
- delete m_BoardSide[ii];
- m_BoardSide[ii] = NULL;
- }
- }
-
- m_Nrows = m_Ncols = 0;
-}
-
-
-/**
- * Function PlaceCells
- * Initialize the matrix routing by setting obstacles for each occupied cell
- * a cell set to HOLE is an obstacle for tracks and vias
- * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only.
- * a cell set to CELL_is_EDGE is a frontier.
- * Tracks and vias having the same net code as net_code are skipped
- * (htey do not are obstacles)
- *
- * For single-sided Routing 1:
- * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
- *
- * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
- */
-void PlaceCells( BOARD* aPcb, int net_code, int flag )
-{
- int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
- int marge, via_marge;
- LSET layerMask;
-
- // use the default NETCLASS?
- NETCLASSPTR nc = aPcb->GetDesignSettings().GetDefault();
-
- int trackWidth = nc->GetTrackWidth();
- int clearance = nc->GetClearance();
- int viaSize = nc->GetViaDiameter();
-
- marge = clearance + (trackWidth / 2);
- via_marge = clearance + (viaSize / 2);
-
- // Place PADS on matrix routing:
- for( unsigned i = 0; i < aPcb->GetPadCount(); ++i )
- {
- D_PAD* pad = aPcb->GetPad( i );
-
- if( net_code != pad->GetNetCode() || (flag & FORCE_PADS) )
- {
- ::PlacePad( pad, HOLE, marge, WRITE_CELL );
- }
-
- ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
- }
-
- // Place outlines of modules on matrix routing, if they are on a copper layer
- // or on the edge layer
-
- for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
- {
- for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() )
- {
- switch( item->Type() )
- {
- case PCB_MODULE_EDGE_T:
- {
- EDGE_MODULE* edge = (EDGE_MODULE*) item;
- EDGE_MODULE tmpEdge( *edge );
-
- if( tmpEdge.GetLayer() == Edge_Cuts )
- tmpEdge.SetLayer( UNDEFINED_LAYER );
-
- TraceSegmentPcb( &tmpEdge, HOLE, marge, WRITE_CELL );
- TraceSegmentPcb( &tmpEdge, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- // Place board outlines and texts on copper layers:
- for( auto item : aPcb->Drawings() )
- {
- switch( item->Type() )
- {
- case PCB_LINE_T:
- {
- DRAWSEGMENT* DrawSegm;
-
- int type_cell = HOLE;
- DrawSegm = (DRAWSEGMENT*) item;
- DRAWSEGMENT tmpSegm( DrawSegm );
-
- if( DrawSegm->GetLayer() == Edge_Cuts )
- {
- tmpSegm.SetLayer( UNDEFINED_LAYER );
- type_cell |= CELL_is_EDGE;
- }
-
- TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
- }
- break;
-
- case PCB_TEXT_T:
- {
- TEXTE_PCB* PtText = (TEXTE_PCB*) item;
-
- if( PtText->GetText().Length() == 0 )
- break;
-
- EDA_RECT textbox = PtText->GetTextBox( -1 );
- ux0 = textbox.GetX();
- uy0 = textbox.GetY();
- dx = textbox.GetWidth();
- dy = textbox.GetHeight();
-
- // Put bounding box (rectangle) on matrix
- dx /= 2;
- dy /= 2;
-
- ux1 = ux0 + dx;
- uy1 = uy0 + dy;
-
- ux0 -= dx;
- uy0 -= dy;
-
- layerMask = LSET( PtText->GetLayer() );
-
- TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
- uy1 + marge, PtText->GetTextAngle(),
- layerMask, HOLE, WRITE_CELL );
-
- TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
- ux1 + via_marge, uy1 + via_marge,
- PtText->GetTextAngle(),
- layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
- }
- break;
-
- default:
- break;
- }
- }
-
- // Put tracks and vias on matrix
- for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
- {
- if( net_code == track->GetNetCode() )
- continue;
-
- TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
- TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
- }
-}
-
-
-int Build_Work( BOARD* Pcb )
-{
- RATSNEST_ITEM* pt_rats;
- D_PAD* pt_pad;
- int r1, r2, c1, c2, current_net_code;
- RATSNEST_ITEM* pt_ch;
- int demi_pas = RoutingMatrix.m_GridRouting / 2;
- wxString msg;
-
- InitWork(); // clear work list
- int cellCount = 0;
-
- for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
- {
- pt_rats = &Pcb->m_FullRatsnest[ii];
-
- /* We consider here only ratsnest that are active ( obviously not yet routed)
- * and routables (that are not yet attempt to be routed and fail
- */
- if( (pt_rats->m_Status & CH_ACTIF) == 0 )
- continue;
-
- if( pt_rats->m_Status & CH_UNROUTABLE )
- continue;
-
- if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
- continue;
-
- pt_pad = pt_rats->m_PadStart;
-
- current_net_code = pt_pad->GetNetCode();
- pt_ch = pt_rats;
-
- r1 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY() + demi_pas )
- / RoutingMatrix.m_GridRouting;
-
- if( r1 < 0 || r1 >= RoutingMatrix.m_Nrows )
- {
- msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
- pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
- wxMessageBox( msg );
- return 0;
- }
-
- c1 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas ) / RoutingMatrix.m_GridRouting;
-
- if( c1 < 0 || c1 >= RoutingMatrix.m_Ncols )
- {
- msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
- pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
- wxMessageBox( msg );
- return 0;
- }
-
- pt_pad = pt_rats->m_PadEnd;
-
- r2 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY()
- + demi_pas ) / RoutingMatrix.m_GridRouting;
-
- if( r2 < 0 || r2 >= RoutingMatrix.m_Nrows )
- {
- msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
- pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
- wxMessageBox( msg );
- return 0;
- }
-
- c2 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas )
- / RoutingMatrix.m_GridRouting;
-
- if( c2 < 0 || c2 >= RoutingMatrix.m_Ncols )
- {
- msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
- pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
- wxMessageBox( msg );
- return 0;
- }
-
- SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
- cellCount++;
- }
-
- SortWork();
- return cellCount;
-}
-
-// Initialize m_opWriteCell member to make the aLogicOp
-void MATRIX_ROUTING_HEAD::SetCellOperation( int aLogicOp )
-{
- switch( aLogicOp )
- {
- default:
- case WRITE_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::SetCell;
- break;
-
- case WRITE_OR_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::OrCell;
- break;
-
- case WRITE_XOR_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::XorCell;
- break;
-
- case WRITE_AND_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::AndCell;
- break;
-
- case WRITE_ADD_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::AddCell;
- break;
- }
-}
-
-
-/* return the value stored in a cell
- */
-MATRIX_CELL MATRIX_ROUTING_HEAD::GetCell( int aRow, int aCol, int aSide )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- return p[aRow * m_Ncols + aCol];
-}
-
-
-/* basic cell operation : WRITE operation
- */
-void MATRIX_ROUTING_HEAD::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] = x;
-}
-
-
-/* basic cell operation : OR operation
- */
-void MATRIX_ROUTING_HEAD::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] |= x;
-}
-
-
-/* basic cell operation : XOR operation
- */
-void MATRIX_ROUTING_HEAD::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] ^= x;
-}
-
-
-/* basic cell operation : AND operation
- */
-void MATRIX_ROUTING_HEAD::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] &= x;
-}
-
-
-/* basic cell operation : ADD operation
- */
-void MATRIX_ROUTING_HEAD::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
-
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] += x;
-}
-
-
-// fetch distance cell
-DIST_CELL MATRIX_ROUTING_HEAD::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
-{
- DIST_CELL* p;
-
- p = RoutingMatrix.m_DistSide[aSide];
- return p[aRow * m_Ncols + aCol];
-}
-
-
-// store distance cell
-void MATRIX_ROUTING_HEAD::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
-{
- DIST_CELL* p;
-
- p = RoutingMatrix.m_DistSide[aSide];
- p[aRow * m_Ncols + aCol] = x;
-}
-
-
-// fetch direction cell
-int MATRIX_ROUTING_HEAD::GetDir( int aRow, int aCol, int aSide )
-{
- DIR_CELL* p;
-
- p = RoutingMatrix.m_DirSide[aSide];
- return (int) (p[aRow * m_Ncols + aCol]);
-}
-
-
-// store direction cell
-void MATRIX_ROUTING_HEAD::SetDir( int aRow, int aCol, int aSide, int x )
-{
- DIR_CELL* p;
-
- p = RoutingMatrix.m_DirSide[aSide];
- p[aRow * m_Ncols + aCol] = (char) x;
-}
--
2.7.4
>From 307bf79d8fee4b693ab8ec199571c7d920fca6b1 Mon Sep 17 00:00:00 2001
From: Tomasz Wlostowski <tomasz.wlostowski@xxxxxxx>
Date: Thu, 9 Aug 2018 16:02:05 +0200
Subject: [PATCH 2/3] VIEW: added support for VIEW_OVERLAYS (temporary overlays
for drawing debug graphics)
---
common/CMakeLists.txt | 1 +
common/view/view.cpp | 10 ++
common/view/view_overlay.cpp | 249 +++++++++++++++++++++++++++++++++++++++++++
include/view/view.h | 4 +
include/view/view_overlay.h | 62 +++++++++++
5 files changed, 326 insertions(+)
create mode 100644 common/view/view_overlay.cpp
create mode 100644 include/view/view_overlay.h
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index ca31d61..3d5d509 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -43,6 +43,7 @@ set( GAL_SRCS
gal/stroke_font.cpp
geometry/hetriang.cpp
view/view_controls.cpp
+ view/view_overlay.cpp
view/wx_view_controls.cpp
# OpenGL GAL
diff --git a/common/view/view.cpp b/common/view/view.cpp
index df44d5c..4ea11dd 100644
--- a/common/view/view.cpp
+++ b/common/view/view.cpp
@@ -31,6 +31,8 @@
#include <view/view_group.h>
#include <view/view_item.h>
#include <view/view_rtree.h>
+#include <view/view_overlay.h>
+
#include <gal/definitions.h>
#include <gal/graphics_abstraction_layer.h>
#include <painter.h>
@@ -1546,6 +1548,14 @@ void VIEW::Update( VIEW_ITEM* aItem, int aUpdateFlags )
}
+std::shared_ptr<VIEW_OVERLAY> VIEW::MakeOverlay()
+{
+ std::shared_ptr<VIEW_OVERLAY> overlay( new VIEW_OVERLAY );
+
+ Add ( overlay.get() );
+ return overlay;
+}
+
const int VIEW::TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS;
}
diff --git a/common/view/view_overlay.cpp b/common/view/view_overlay.cpp
new file mode 100644
index 0000000..0eb8f17
--- /dev/null
+++ b/common/view/view_overlay.cpp
@@ -0,0 +1,249 @@
+#include <view/view.h>
+#include <view/view_item.h>
+#include <view/view_overlay.h>
+#include <gal/graphics_abstraction_layer.h>
+#include <painter.h>
+
+#include <layers_id_colors_and_visibility.h>
+#include <geometry/seg.h>
+
+namespace KIGFX {
+struct VIEW_OVERLAY::COMMAND
+{
+ virtual ~COMMAND() {};
+ virtual void Execute( VIEW* aView ) const = 0;
+};
+
+struct VIEW_OVERLAY::COMMAND_LINE : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_LINE( const VECTOR2D& aP0, const VECTOR2D& aP1 ) :
+ m_p0( aP0 ),
+ m_p1( aP1 ) {};
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->DrawLine( m_p0, m_p1 );
+ }
+
+ VECTOR2D m_p0, m_p1;
+};
+
+struct VIEW_OVERLAY::COMMAND_CIRCLE : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_CIRCLE( const VECTOR2D& aCenter, double aRadius ) :
+ m_center(aCenter),
+ m_radius(aRadius)
+ {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->DrawCircle( m_center, m_radius
+ );
+ }
+
+ VECTOR2D m_center;
+ double m_radius;
+};
+
+struct VIEW_OVERLAY::COMMAND_ARC : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_ARC( const VECTOR2D& aCenter, double aRadius, double aStartAngle, double aEndAngle ) :
+ m_center(aCenter),
+ m_radius(aRadius),
+ m_startAngle( aStartAngle ),
+ m_endAngle( aEndAngle )
+ {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->DrawArc( m_center, m_radius, m_startAngle, m_endAngle );
+ }
+
+ VECTOR2D m_center;
+ double m_startAngle, m_endAngle;
+ double m_radius;
+};
+
+struct VIEW_OVERLAY::COMMAND_SET_STROKE : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_SET_STROKE( bool aIsStroke ) :
+ m_isStroke( aIsStroke ) {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->SetIsStroke( m_isStroke );
+ }
+
+ bool m_isStroke;
+};
+
+struct VIEW_OVERLAY::COMMAND_SET_FILL : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_SET_FILL( bool aIsFill ) :
+ m_isFill( aIsFill ) {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->SetIsFill( m_isFill );
+ }
+
+ bool m_isFill;
+};
+
+struct VIEW_OVERLAY::COMMAND_SET_COLOR : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_SET_COLOR( bool aIsStroke, const COLOR4D& aColor ) :
+ m_isStroke( aIsStroke ),
+ m_color( aColor )
+ {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ if( m_isStroke )
+ aView->GetGAL()->SetStrokeColor( m_color );
+ else
+ aView->GetGAL()->SetFillColor( m_color );
+ }
+
+ bool m_isStroke;
+ COLOR4D m_color;
+};
+
+struct VIEW_OVERLAY::COMMAND_SET_WIDTH : public VIEW_OVERLAY::COMMAND
+{
+ COMMAND_SET_WIDTH( double aWidth ) :
+ m_width( aWidth )
+ {}
+
+ virtual void Execute( VIEW* aView ) const override
+ {
+ aView->GetGAL()->SetLineWidth( m_width );
+ }
+
+ double m_width;
+};
+
+VIEW_OVERLAY::VIEW_OVERLAY()
+{
+}
+
+
+VIEW_OVERLAY::~VIEW_OVERLAY()
+{
+ releaseCommands();
+}
+
+
+void VIEW_OVERLAY::releaseCommands()
+{
+ for( auto cmd : m_commands )
+ delete cmd;
+
+ m_commands.clear();
+}
+
+
+void VIEW_OVERLAY::Clear()
+{
+ releaseCommands();
+}
+
+
+const BOX2I VIEW_OVERLAY::ViewBBox() const
+{
+ BOX2I maxBox;
+
+ maxBox.SetMaximum();
+ return maxBox;
+}
+
+
+void VIEW_OVERLAY::ViewDraw( int aLayer, VIEW* aView ) const
+{
+ for( const auto& cmd : m_commands )
+ cmd->Execute( aView );
+}
+
+
+void VIEW_OVERLAY::ViewGetLayers( int aLayers[], int& aCount ) const
+{
+ aLayers[0] = LAYER_GP_OVERLAY;
+ aCount = 1;
+}
+
+
+void VIEW_OVERLAY::Line( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
+{
+ m_commands.push_back( new COMMAND_LINE( aStartPoint, aEndPoint ) );
+}
+
+void VIEW_OVERLAY::Line( const SEG& aSeg )
+{
+ Line( aSeg.A, aSeg.B );
+}
+
+
+void VIEW_OVERLAY::Segment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth )
+{
+}
+
+
+void VIEW_OVERLAY::Polyline( std::deque<VECTOR2D>& aPointList )
+{
+}
+
+
+void VIEW_OVERLAY::Circle( const VECTOR2D& aCenterPoint, double aRadius )
+{
+ m_commands.push_back( new COMMAND_CIRCLE( aCenterPoint, aRadius ) );
+}
+
+
+void VIEW_OVERLAY::Arc( const VECTOR2D& aCenterPoint,
+ double aRadius,
+ double aStartAngle,
+ double aEndAngle )
+{
+ m_commands.push_back( new COMMAND_ARC( aCenterPoint, aRadius, aStartAngle, aEndAngle ) );
+}
+
+
+void VIEW_OVERLAY::Rectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
+{
+}
+
+
+void VIEW_OVERLAY::Polygon( const std::deque<VECTOR2D>& aPointList )
+{
+}
+
+
+void VIEW_OVERLAY::SetIsFill( bool aIsFillEnabled )
+{
+ m_commands.push_back( new COMMAND_SET_FILL( aIsFillEnabled ) );
+}
+
+
+void VIEW_OVERLAY::SetIsStroke( bool aIsStrokeEnabled )
+{
+ m_commands.push_back( new COMMAND_SET_STROKE( aIsStrokeEnabled ) );
+}
+
+
+void VIEW_OVERLAY::SetFillColor( const COLOR4D& aColor )
+{
+ m_commands.push_back( new COMMAND_SET_COLOR( false, aColor ) );
+}
+
+
+void VIEW_OVERLAY::SetStrokeColor( const COLOR4D& aColor )
+{
+ m_commands.push_back( new COMMAND_SET_COLOR( true, aColor ) );
+}
+
+void VIEW_OVERLAY::SetLineWidth( double aLineWidth )
+{
+ m_commands.push_back( new COMMAND_SET_WIDTH( aLineWidth ) );
+}
+
+}
diff --git a/include/view/view.h b/include/view/view.h
index ad8635f..7bc78a5 100644
--- a/include/view/view.h
+++ b/include/view/view.h
@@ -28,10 +28,13 @@
#include <vector>
#include <set>
#include <unordered_map>
+#include <memory>
#include <math/box2.h>
#include <gal/definitions.h>
+#include <view/view_overlay.h> // fixme
+
namespace KIGFX
{
class PAINTER;
@@ -683,6 +686,7 @@ public:
static const int VIEW_MAX_LAYERS = 512; ///< maximum number of layers that may be shown
+ std::shared_ptr<VIEW_OVERLAY> MakeOverlay();
private:
struct VIEW_LAYER
diff --git a/include/view/view_overlay.h b/include/view/view_overlay.h
new file mode 100644
index 0000000..9fd83c8
--- /dev/null
+++ b/include/view/view_overlay.h
@@ -0,0 +1,62 @@
+#ifndef __VIEW_OVERLAY_H
+#define __VIEW_OVERLAY_H
+
+//#include <view/view.h>
+#include <view/view_item.h>
+#include <gal/graphics_abstraction_layer.h>
+
+#include <vector>
+#include <deque>
+
+class SEG;
+
+namespace KIGFX
+{
+
+ class VIEW;
+
+class VIEW_OVERLAY : public VIEW_ITEM
+{
+public:
+ VIEW_OVERLAY();
+ virtual ~VIEW_OVERLAY();
+
+ struct COMMAND;
+ struct COMMAND_ARC;
+ struct COMMAND_LINE;
+ struct COMMAND_CIRCLE;
+ struct COMMAND_SET_STROKE;
+ struct COMMAND_SET_FILL;
+ struct COMMAND_SET_COLOR;
+ struct COMMAND_SET_WIDTH;
+
+ void Clear();
+
+ virtual const BOX2I ViewBBox() const override;
+ virtual void ViewDraw( int aLayer, VIEW *aView ) const override;
+ virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
+
+ void Line( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
+ void Line( const SEG& aSeg );
+ void Segment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth );
+ void Polyline( std::deque<VECTOR2D>& aPointList );
+ void Circle( const VECTOR2D& aCenterPoint, double aRadius );
+ void Arc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle );
+ void Rectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
+ void Polygon( const std::deque<VECTOR2D>& aPointList );
+ void SetIsFill( bool aIsFillEnabled );
+ void SetIsStroke( bool aIsStrokeEnabled );
+ void SetFillColor( const COLOR4D& aColor );
+ void SetStrokeColor( const COLOR4D& aColor );
+
+ void SetLineWidth( double aLineWidth );
+
+private:
+ void releaseCommands();
+
+ std::vector<COMMAND*> m_commands;
+};
+} // namespace KIGFX
+
+
+#endif
--
2.7.4
>From 39ee9f5f14a8b59cfeebfa10be6ad71b514920cd Mon Sep 17 00:00:00 2001
From: Tomasz Wlostowski <tomasz.wlostowski@xxxxxxx>
Date: Thu, 9 Aug 2018 16:04:51 +0200
Subject: [PATCH 3/3] pcbnew: bring back the autoplacer tool to GAL
---
pcbnew/CMakeLists.txt | 3 +
pcbnew/autorouter/ar_autoplacer.cpp | 1540 +++++++++-----------
pcbnew/autorouter/ar_autoplacer.h | 121 ++
pcbnew/autorouter/ar_cell.h | 20 +-
pcbnew/autorouter/ar_matrix.cpp | 1351 +++++++++++++----
pcbnew/autorouter/ar_matrix.h | 178 +++
pcbnew/autorouter/autoplacer_tool.cpp | 126 ++
pcbnew/autorouter/autoplacer_tool.h | 52 +
pcbnew/autorouter/graphpcb.cpp | 689 +--------
.../autorouter/move_and_route_event_functions.cpp | 2 +
pcbnew/autorouter/solve.cpp | 305 ++--
pcbnew/autorouter/work.cpp | 43 +-
pcbnew/connectivity_data.cpp | 39 +
pcbnew/connectivity_data.h | 4 +
pcbnew/edit.cpp | 43 +-
pcbnew/menubar_pcb_editor.cpp | 17 +
pcbnew/onrightclick.cpp | 20 +-
pcbnew/pcb_edit_frame.cpp | 6 -
pcbnew/pcbnew_id.h | 27 +-
pcbnew/tools/pcb_actions.cpp | 7 +
pcbnew/tools/pcb_actions.h | 2 +
pcbnew/tools/tools_common.cpp | 2 +
22 files changed, 2473 insertions(+), 2124 deletions(-)
create mode 100644 pcbnew/autorouter/ar_autoplacer.h
create mode 100644 pcbnew/autorouter/ar_matrix.h
create mode 100644 pcbnew/autorouter/autoplacer_tool.cpp
create mode 100644 pcbnew/autorouter/autoplacer_tool.h
diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index d9f55dd..a77f8eb 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -205,6 +205,9 @@ set( PCBNEW_CLASS_SRCS
autorouter/rect_placement/rect_placement.cpp
autorouter/spread_footprints.cpp
+ autorouter/ar_autoplacer.cpp
+ autorouter/ar_matrix.cpp
+ autorouter/autoplacer_tool.cpp
action_plugin.cpp
append_board_to_current.cpp
diff --git a/pcbnew/autorouter/ar_autoplacer.cpp b/pcbnew/autorouter/ar_autoplacer.cpp
index 289c9db..39ed071 100644
--- a/pcbnew/autorouter/ar_autoplacer.cpp
+++ b/pcbnew/autorouter/ar_autoplacer.cpp
@@ -1,8 +1,3 @@
-/**
- * @file auto_place_footprints.cpp
- * @brief Functions to automatically place Footprints on a board.
- */
-
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
@@ -39,26 +34,31 @@
#include <macros.h>
#include <msgpanel.h>
-#include <autorout.h>
-#include <cell.h>
-
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_drawsegment.h>
-#include <convert_to_biu.h>
-#include <base_units.h>
-#include <protos.h>
+#include <class_pad.h>
+#include <board_commit.h>
-#define GAIN 16
-#define KEEP_OUT_MARGIN 500
+#include <connectivity_data.h>
+#include <ratsnest_data.h>
+#include <widgets/progress_reporter.h>
+
+#include "ar_matrix.h"
+#include "ar_cell.h"
+#include "ar_autoplacer.h"
+
+#define AR_GAIN 16
+#define AR_KEEPOUT_MARGIN 500
+#define AR_ABORT_PLACEMENT -1
/* Penalty (cost) for CntRot90 and CntRot180:
* CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
*/
-static const double OrientPenality[11] =
+static const double OrientationPenalty[11] =
{
2.0, // CntRot = 0 rotation prohibited
1.9, // CntRot = 1
@@ -73,563 +73,471 @@ static const double OrientPenality[11] =
1.0 // CntRot = 10 rotation authorized, no penalty
};
-// Cell states.
-#define OUT_OF_BOARD -2
-#define OCCUPED_By_MODULE -1
-#define FREE_CELL 0
-
-
-static wxPoint CurrPosition; // Current position of the current module placement
-double MinCout;
-
-
-/* generates the Routing matrix, used to fing the best placement
- * of a footprint.
- * Allocate a "bitmap" which is an image of the real board
- * the bitmap handles:
- * - The free areas
- * - penalties (cell not occupied, but near occupied areas)
- * - cells occupied by footprints, board cutout ...
- */
-int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel );
-
-/* searches for the optimal position of aModule.
- * return 1 if placement impossible or 0 if OK.
- */
-static int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame,
- MODULE* aModule, wxDC* aDC );
-
-/*
- * Function compute_Ratsnest_PlaceModule
- * displays the module's ratsnest during displacement, and assess the "cost"
- * of the position.
- *
- * The cost is the longest ratsnest distance with penalty for connections
- * approaching 45 degrees.
- */
-static double compute_Ratsnest_PlaceModule( BOARD* aBrd );
-
-/* Place a footprint on the Routing matrix.
- */
-void genModuleOnRoutingMatrix( MODULE* Module );
-/*
- * Displays the Placement/Routing matrix on the screen
- */
-static void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC );
-
-static int TstModuleOnBoard( BOARD* Pcb, MODULE* Module, bool TstOtherSide );
-
-static void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
- int marge, int aKeepOut, LSET aLayerMask );
-
-static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC );
-static int propagate();
+AR_AUTOPLACER::AR_AUTOPLACER( BOARD* aBoard )
+{
+ m_board = aBoard;
+ m_connectivity.reset( new CONNECTIVITY_DATA );
+
+ for( auto mod : m_board->Modules() )
+ m_connectivity->Add( mod );
+
+ m_gridSize = Millimeter2iu( 0.5 );
+ m_progressReporter = nullptr;
+ m_refreshCallback = nullptr;
+}
-void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
+void AR_AUTOPLACER::placeModule( MODULE* aModule, bool aDoNotRecreateRatsnest, const wxPoint& aPos )
{
- MODULE* currModule = NULL;
- wxPoint PosOK;
- wxPoint memopos;
- int error;
- PCB_LAYER_ID lay_tmp_TOP, lay_tmp_BOTTOM;
+ if( !aModule )
+ return;
- // Undo: init list
- PICKED_ITEMS_LIST newList;
+ aModule->SetPosition( aPos );
+ m_connectivity->Update( aModule );
+}
- newList.m_Status = UR_CHANGED;
- ITEM_PICKER picker( NULL, UR_CHANGED );
- if( GetBoard()->m_Modules == NULL )
- return;
+int AR_AUTOPLACER::genPlacementRoutingMatrix()
+{
+ m_matrix.UnInitRoutingMatrix();
- m_canvas->SetAbortRequest( false );
+ EDA_RECT bbox = m_board->GetBoardEdgesBoundingBox();
- switch( place_mode )
+ if( bbox.GetWidth() == 0 || bbox.GetHeight() == 0 )
{
- case PLACE_1_MODULE:
- currModule = Module;
+ //DisplayError( NULL, _( "No PCB edge found, unknown board size!" ) );
+ // fixme: no wx here
+ return 0;
+ }
- if( currModule == NULL )
- return;
+ m_matrix.ComputeMatrixSize( bbox );
+ int nbCells = m_matrix.m_Ncols * m_matrix.m_Nrows;
- currModule->SetIsPlaced( false );
- currModule->SetNeedsPlaced( false );
- break;
+ // Choose the number of board sides.
+ m_matrix.m_RoutingLayersCount = 2;
+ m_matrix.InitRoutingMatrix();
- case PLACE_OUT_OF_BOARD:
- break;
+ m_matrix.m_routeLayerBottom = F_Cu;
- case PLACE_ALL:
+ if( m_matrix.m_RoutingLayersCount > 1 )
+ m_matrix.m_routeLayerBottom = B_Cu;
- if( !IsOK( this, _( "Footprints NOT LOCKED will be moved" ) ) )
- return;
+ m_matrix.m_routeLayerTop = F_Cu;
- break;
+ // Place the edge layer segments
+ TRACK tmp( NULL );
- case PLACE_INCREMENTAL:
+ tmp.SetLayer( UNDEFINED_LAYER );
+ tmp.SetNetCode( -1 );
+ tmp.SetWidth( m_matrix.m_GridRouting / 2 );
- if( !IsOK( this, _( "Footprints NOT PLACED will be moved" ) ) )
- return;
+ for( auto drawing : m_board->Drawings() )
+ {
+ DRAWSEGMENT* DrawSegm;
- break;
- }
+ switch( drawing->Type() )
+ {
+ case PCB_LINE_T:
+ DrawSegm = (DRAWSEGMENT*) drawing;
- memopos = CurrPosition;
- lay_tmp_BOTTOM = g_Route_Layer_BOTTOM;
- lay_tmp_TOP = g_Route_Layer_TOP;
+ if( DrawSegm->GetLayer() != Edge_Cuts )
+ break;
- RoutingMatrix.m_GridRouting = (int) GetScreen()->GetGridSize().x;
- // Ensure Board.m_GridRouting has a reasonable value:
- if( RoutingMatrix.m_GridRouting < Millimeter2iu( 0.25 ) )
- RoutingMatrix.m_GridRouting = Millimeter2iu( 0.25 );
+ //printf("addSeg %p grid %d\n", DrawSegm, m_matrix.m_GridRouting );
+ m_matrix.TraceSegmentPcb( DrawSegm, CELL_IS_HOLE | CELL_IS_EDGE,
+ m_matrix.m_GridRouting, AR_MATRIX::WRITE_CELL );
+ break;
- // Compute module parameters used in auto place
- if( genPlacementRoutingMatrix( GetBoard(), m_messagePanel ) == 0 )
- return;
+ case PCB_TEXT_T:
+ default:
+ break;
+ }
+ }
- int moduleCount = 0;
- Module = GetBoard()->m_Modules;
+ // Mark cells of the routing matrix to CELL_IS_ZONE
+ // (i.e. availlable cell to place a module )
+ // Init a starting point of attachment to the area.
+ m_matrix.OrCell( m_matrix.m_Nrows / 2, m_matrix.m_Ncols / 2,
+ AR_SIDE_BOTTOM, CELL_IS_ZONE );
- for( ; Module != NULL; Module = Module->Next() )
- {
- Module->SetNeedsPlaced( false );
+ // find and mark all other availlable cells:
+ for( int ii = 1; ii != 0; )
+ ii = propagate();
- switch( place_mode )
- {
- case PLACE_1_MODULE:
+ // Initialize top layer. to the same value as the bottom layer
+ if( m_matrix.m_BoardSide[AR_SIDE_TOP] )
+ memcpy( m_matrix.m_BoardSide[AR_SIDE_TOP], m_matrix.m_BoardSide[AR_SIDE_BOTTOM],
+ nbCells * sizeof(AR_MATRIX::MATRIX_CELL) );
- if( currModule == Module )
- {
- // Module will be placed, add to undo.
- picker.SetItem( currModule );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- }
+ return 1;
+}
- break;
+void AR_AUTOPLACER::rotateModule( MODULE* module, double angle, bool incremental )
+{
+ if( module == NULL )
+ return;
- case PLACE_OUT_OF_BOARD:
- Module->SetIsPlaced( false );
+ if( incremental )
+ module->SetOrientation( module->GetOrientation() + angle );
+ else
+ module->SetOrientation( angle );
- if( Module->IsLocked() )
- break;
- if( !RoutingMatrix.m_BrdBox.Contains( Module->GetPosition() ) )
- {
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- }
+ m_board->GetConnectivity()->Update( module );
+}
- break;
+/**
+ * Function propagate
+ * Used only in autoplace calculations
+ * Uses the routing matrix to fill the cells within the zone
+ * Search and mark cells within the zone, and agree with DRC options.
+ * Requirements:
+ * Start from an initial point, to fill zone
+ * The zone must have no "copper island"
+ * Algorithm:
+ * If the current cell has a neighbor flagged as "cell in the zone", it
+ * become a cell in the zone
+ * The first point in the zone is the starting point
+ * 4 searches within the matrix are made:
+ * 1 - Left to right and top to bottom
+ * 2 - Right to left and top to bottom
+ * 3 - bottom to top and Right to left
+ * 4 - bottom to top and Left to right
+ * Given the current cell, for each search, we consider the 2 neighbor cells
+ * the previous cell on the same line and the previous cell on the same column.
+ *
+ * This function can request some iterations
+ * Iterations are made until no cell is added to the zone.
+ * @return added cells count (i.e. which the attribute CELL_IS_ZONE is set)
+ */
- case PLACE_ALL:
- Module->SetIsPlaced( false );
+int AR_AUTOPLACER::propagate()
+{
+ int row, col;
+ long current_cell, old_cell_H;
+ std::vector<int> pt_cell_V;
+ int nbpoints = 0;
- if( Module->IsLocked() )
- break;
+ const uint32_t NO_CELL_ZONE = CELL_IS_HOLE | CELL_IS_EDGE | CELL_IS_ZONE;
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
- break;
+ pt_cell_V.reserve( std::max( m_matrix.m_Nrows, m_matrix.m_Ncols ) );
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
- case PLACE_INCREMENTAL:
+ // Search from left to right and top to bottom.
+ for( row = 0; row < m_matrix.m_Nrows; row++ )
+ {
+ old_cell_H = 0;
- if( Module->IsLocked() )
- {
- Module->SetIsPlaced( false );
- break;
- }
+ for( col = 0; col < m_matrix.m_Ncols; col++ )
+ {
+ current_cell = m_matrix.GetCell( row, col, AR_SIDE_BOTTOM ) & NO_CELL_ZONE;
- if( !Module->NeedsPlaced() )
+ if( current_cell == 0 ) // a free cell is found
{
- // Module will be placed, add to undo.
- picker.SetItem( Module );
- newList.PushItem( picker );
- Module->SetNeedsPlaced( true );
+ if( (old_cell_H & CELL_IS_ZONE) || (pt_cell_V[col] & CELL_IS_ZONE) )
+ {
+ m_matrix.OrCell( row, col, AR_SIDE_BOTTOM, CELL_IS_ZONE );
+ current_cell = CELL_IS_ZONE;
+ nbpoints++;
+ }
}
- break;
- }
-
- if( Module->NeedsPlaced() ) // Erase from screen
- {
- moduleCount++;
- Module->Draw( m_canvas, DC, GR_XOR );
- }
- else
- {
- genModuleOnRoutingMatrix( Module );
+ pt_cell_V[col] = old_cell_H = current_cell;
}
}
- // Undo command: prepare list
- if( newList.GetCount() )
- SaveCopyInUndoList( newList, UR_CHANGED );
-
- int cnt = 0;
- wxString msg;
+ // Search from right to left and top to bottom/
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
- while( ( Module = PickModule( this, DC ) ) != NULL )
+ for( row = 0; row < m_matrix.m_Nrows; row++ )
{
- // Display some info about activity, module placement can take a while:
- msg.Printf( _( "Place footprint %d of %d" ), cnt, moduleCount );
- SetStatusText( msg );
-
- double initialOrient = Module->GetOrientation();
- // Display fill area of interest, barriers, penalties.
- drawPlacementRoutingMatrix( GetBoard(), DC );
-
- error = getOptimalModulePlacement( this, Module, DC );
- double bestScore = MinCout;
- double bestRotation = 0.0;
- int rotAllowed;
- PosOK = CurrPosition;
-
- if( error == ESC )
- goto end_of_tst;
-
- // Try orientations 90, 180, 270 degrees from initial orientation
- rotAllowed = Module->GetPlacementCost180();
+ old_cell_H = 0;
- if( rotAllowed != 0 )
+ for( col = m_matrix.m_Ncols - 1; col >= 0; col-- )
{
- Rotate_Module( DC, Module, 1800.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
+ current_cell = m_matrix.GetCell( row, col, AR_SIDE_BOTTOM ) & NO_CELL_ZONE;
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 1800.0;
- }
- else
+ if( current_cell == 0 ) // a free cell is found
{
- Rotate_Module( DC, Module, initialOrient, false );
+ if( (old_cell_H & CELL_IS_ZONE) || (pt_cell_V[col] & CELL_IS_ZONE) )
+ {
+ m_matrix.OrCell( row, col, AR_SIDE_BOTTOM, CELL_IS_ZONE );
+ current_cell = CELL_IS_ZONE;
+ nbpoints++;
+ }
}
- if( error == ESC )
- goto end_of_tst;
+ pt_cell_V[col] = old_cell_H = current_cell;
}
+ }
- // Determine if the best orientation of a module is 90.
- rotAllowed = Module->GetPlacementCost90();
+ // Search from bottom to top and right to left.
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
- if( rotAllowed != 0 )
+ for( col = m_matrix.m_Ncols - 1; col >= 0; col-- )
+ {
+ old_cell_H = 0;
+
+ for( row = m_matrix.m_Nrows - 1; row >= 0; row-- )
{
- Rotate_Module( DC, Module, 900.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
+ current_cell = m_matrix.GetCell( row, col, AR_SIDE_BOTTOM ) & NO_CELL_ZONE;
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 900.0;
- }
- else
+ if( current_cell == 0 ) // a free cell is found
{
- Rotate_Module( DC, Module, initialOrient, false );
+ if( (old_cell_H & CELL_IS_ZONE) || (pt_cell_V[row] & CELL_IS_ZONE) )
+ {
+ m_matrix.OrCell( row, col, AR_SIDE_BOTTOM, CELL_IS_ZONE );
+ current_cell = CELL_IS_ZONE;
+ nbpoints++;
+ }
}
- if( error == ESC )
- goto end_of_tst;
+ pt_cell_V[row] = old_cell_H = current_cell;
}
+ }
- // Determine if the best orientation of a module is -90.
- if( rotAllowed != 0 )
+ // Search from bottom to top and left to right.
+ fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+
+ for( col = 0; col < m_matrix.m_Ncols; col++ )
+ {
+ old_cell_H = 0;
+
+ for( row = m_matrix.m_Nrows - 1; row >= 0; row-- )
{
- Rotate_Module( DC, Module, 2700.0, true );
- error = getOptimalModulePlacement( this, Module, DC );
- MinCout *= OrientPenality[rotAllowed];
+ current_cell = m_matrix.GetCell( row, col, AR_SIDE_BOTTOM ) & NO_CELL_ZONE;
- if( bestScore > MinCout ) // This orientation is better.
- {
- PosOK = CurrPosition;
- bestScore = MinCout;
- bestRotation = 2700.0;
- }
- else
+ if( current_cell == 0 ) // a free cell is found
{
- Rotate_Module( DC, Module, initialOrient, false );
+ if( (old_cell_H & CELL_IS_ZONE) || (pt_cell_V[row] & CELL_IS_ZONE) )
+ {
+ m_matrix.OrCell( row, col, AR_SIDE_BOTTOM, CELL_IS_ZONE );
+ current_cell = CELL_IS_ZONE;
+ nbpoints++;
+ }
}
- if( error == ESC )
- goto end_of_tst;
+ pt_cell_V[row] = old_cell_H = current_cell;
}
+ }
-end_of_tst:
+ return nbpoints;
+}
- if( error == ESC )
- break;
+void AR_AUTOPLACER::genModuleOnRoutingMatrix( MODULE* Module )
+{
+ int ox, oy, fx, fy;
+ LSET layerMask;
+
+ EDA_RECT fpBBox = Module->GetBoundingBox();
- // Place module.
- CurrPosition = GetCrossHairPosition();
- SetCrossHairPosition( PosOK );
+ fpBBox.Inflate( m_matrix.m_GridRouting / 2 );
+ ox = fpBBox.GetX();
+ fx = fpBBox.GetRight();
+ oy = fpBBox.GetY();
+ fy = fpBBox.GetBottom();
- PlaceModule( Module, DC );
+ if( ox < m_matrix.m_BrdBox.GetX() )
+ ox = m_matrix.m_BrdBox.GetX();
- bestRotation += initialOrient;
+ if( ox > m_matrix.m_BrdBox.GetRight() )
+ ox = m_matrix.m_BrdBox.GetRight();
- if( bestRotation != Module->GetOrientation() )
- Rotate_Module( DC, Module, bestRotation, false );
+ if( fx < m_matrix.m_BrdBox.GetX() )
+ fx = m_matrix.m_BrdBox.GetX();
- SetCrossHairPosition( CurrPosition );
+ if( fx > m_matrix.m_BrdBox.GetRight() )
+ fx = m_matrix.m_BrdBox.GetRight();
- Module->CalculateBoundingBox();
+ if( oy < m_matrix.m_BrdBox.GetY() )
+ oy = m_matrix.m_BrdBox.GetY();
- genModuleOnRoutingMatrix( Module );
- Module->SetIsPlaced( true );
- Module->SetNeedsPlaced( false );
- }
+ if( oy > m_matrix.m_BrdBox.GetBottom() )
+ oy = m_matrix.m_BrdBox.GetBottom();
- CurrPosition = memopos;
+ if( fy < m_matrix.m_BrdBox.GetY() )
+ fy = m_matrix.m_BrdBox.GetY();
- RoutingMatrix.UnInitRoutingMatrix();
+ if( fy > m_matrix.m_BrdBox.GetBottom() )
+ fy = m_matrix.m_BrdBox.GetBottom();
+
+ if( Module->GetLayer() == F_Cu )
+ layerMask.set( F_Cu );
- g_Route_Layer_TOP = lay_tmp_TOP;
- g_Route_Layer_BOTTOM = lay_tmp_BOTTOM;
+ if( Module->GetLayer() == B_Cu )
+ layerMask.set( B_Cu );
- Module = GetBoard()->m_Modules;
+ m_matrix.TraceFilledRectangle( ox, oy, fx, fy, layerMask,
+ CELL_IS_MODULE, AR_MATRIX::WRITE_OR_CELL );
- for( ; Module != NULL; Module = Module->Next() )
+ // Trace pads + clearance areas.
+ for( auto pad : Module->Pads() )
{
- Module->CalculateBoundingBox();
+ int margin = (m_matrix.m_GridRouting / 2) + pad->GetClearance();
+ m_matrix.PlacePad( pad, CELL_IS_MODULE, margin, AR_MATRIX::WRITE_OR_CELL );
}
- GetBoard()->m_Status_Pcb = 0;
- Compile_Ratsnest( DC, true );
- m_canvas->ReDraw( DC, true );
+ // Trace clearance.
+ int margin = ( m_matrix.m_GridRouting * Module->GetPadCount() ) / AR_GAIN;
+ m_matrix.CreateKeepOutRectangle( ox, oy, fx, fy, margin, AR_KEEPOUT_MARGIN , layerMask );
}
-
-void drawPlacementRoutingMatrix( BOARD* aBrd, wxDC* DC )
+/* Test if the rectangular area (ux, ux .. y0, y1):
+ * - is a free zone (except OCCUPED_By_MODULE returns)
+ * - is on the working surface of the board (otherwise returns OUT_OF_BOARD)
+ *
+ * Returns OUT_OF_BOARD, or OCCUPED_By_MODULE or FREE_CELL if OK
+ */
+int AR_AUTOPLACER::testRectangle( const EDA_RECT& aRect, int side )
{
- int ii, jj;
- COLOR4D color;
- int ox, oy;
- MATRIX_CELL top_state, bottom_state;
-
- GRSetDrawMode( DC, GR_COPY );
+ EDA_RECT rect = aRect;
- for( ii = 0; ii < RoutingMatrix.m_Nrows; ii++ )
- {
- oy = RoutingMatrix.m_BrdBox.GetY() + ( ii * RoutingMatrix.m_GridRouting );
+ rect.Inflate( m_matrix.m_GridRouting / 2 );
- for( jj = 0; jj < RoutingMatrix.m_Ncols; jj++ )
- {
- ox = RoutingMatrix.m_BrdBox.GetX() + (jj * RoutingMatrix.m_GridRouting);
- color = COLOR4D::BLACK;
+ wxPoint start = rect.GetOrigin();
+ wxPoint end = rect.GetEnd();
- top_state = RoutingMatrix.GetCell( ii, jj, TOP );
- bottom_state = RoutingMatrix.GetCell( ii, jj, BOTTOM );
+ start -= m_matrix.m_BrdBox.GetOrigin();
+ end -= m_matrix.m_BrdBox.GetOrigin();
- if( top_state & CELL_is_ZONE )
- color = COLOR4D( BLUE );
+ int row_min = start.y / m_matrix.m_GridRouting;
+ int row_max = end.y / m_matrix.m_GridRouting;
+ int col_min = start.x / m_matrix.m_GridRouting;
+ int col_max = end.x / m_matrix.m_GridRouting;
- // obstacles
- if( ( top_state & CELL_is_EDGE ) || ( bottom_state & CELL_is_EDGE ) )
- color = COLOR4D::WHITE;
- else if( top_state & ( HOLE | CELL_is_MODULE ) )
- color = COLOR4D( LIGHTRED );
- else if( bottom_state & (HOLE | CELL_is_MODULE) )
- color = COLOR4D( LIGHTGREEN );
- else // Display the filling and keep out regions.
- {
- if( RoutingMatrix.GetDist( ii, jj, TOP )
- || RoutingMatrix.GetDist( ii, jj, BOTTOM ) )
- color = DARKGRAY;
- }
+ if( start.y > row_min * m_matrix.m_GridRouting )
+ row_min++;
- GRPutPixel( NULL, DC, ox, oy, color );
- }
- }
-}
+ if( start.x > col_min * m_matrix.m_GridRouting )
+ col_min++;
+ if( row_min < 0 )
+ row_min = 0;
-int genPlacementRoutingMatrix( BOARD* aBrd, EDA_MSG_PANEL* messagePanel )
-{
- wxString msg;
+ if( row_max >= ( m_matrix.m_Nrows - 1 ) )
+ row_max = m_matrix.m_Nrows - 1;
- RoutingMatrix.UnInitRoutingMatrix();
+ if( col_min < 0 )
+ col_min = 0;
- EDA_RECT bbox = aBrd->GetBoardEdgesBoundingBox();
+ if( col_max >= ( m_matrix.m_Ncols - 1 ) )
+ col_max = m_matrix.m_Ncols - 1;
- if( bbox.GetWidth() == 0 || bbox.GetHeight() == 0 )
+ for( int row = row_min; row <= row_max; row++ )
{
- DisplayError( NULL, _( "No PCB edge found, unknown board size!" ) );
- return 0;
- }
-
- RoutingMatrix.ComputeMatrixSize( aBrd, true );
- int nbCells = RoutingMatrix.m_Ncols * RoutingMatrix.m_Nrows;
+ for( int col = col_min; col <= col_max; col++ )
+ {
+ unsigned int data = m_matrix.GetCell( row, col, side );
- messagePanel->EraseMsgBox();
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_Ncols );
- messagePanel->SetMessage( 1, _( "Cols" ), msg, GREEN );
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_Nrows );
- messagePanel->SetMessage( 7, _( "Lines" ), msg, GREEN );
- msg.Printf( wxT( "%d" ), nbCells );
- messagePanel->SetMessage( 14, _( "Cells." ), msg, YELLOW );
+ if( ( data & CELL_IS_ZONE ) == 0 )
+ return AR_OUT_OF_BOARD;
- // Choose the number of board sides.
- RoutingMatrix.m_RoutingLayersCount = 2;
+ if( (data & CELL_IS_MODULE) )
+ return AR_OCCUIPED_BY_MODULE;
+ }
+ }
- RoutingMatrix.InitRoutingMatrix();
+ return AR_FREE_CELL;
+}
- // Display memory usage.
- msg.Printf( wxT( "%d" ), RoutingMatrix.m_MemSize / 1024 );
- messagePanel->SetMessage( 24, wxT( "Mem(Kb)" ), msg, CYAN );
+/* Calculates and returns the clearance area of the rectangular surface
+ * aRect):
+ * (Sum of cells in terms of distance)
+ */
+unsigned int AR_AUTOPLACER::calculateKeepOutArea( const EDA_RECT& aRect, int side )
+{
+ wxPoint start = aRect.GetOrigin();
+ wxPoint end = aRect.GetEnd();
- g_Route_Layer_BOTTOM = F_Cu;
+ start -= m_matrix.m_BrdBox.GetOrigin();
+ end -= m_matrix.m_BrdBox.GetOrigin();
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
- g_Route_Layer_BOTTOM = B_Cu;
+ int row_min = start.y / m_matrix.m_GridRouting;
+ int row_max = end.y / m_matrix.m_GridRouting;
+ int col_min = start.x / m_matrix.m_GridRouting;
+ int col_max = end.x / m_matrix.m_GridRouting;
- g_Route_Layer_TOP = F_Cu;
+ if( start.y > row_min * m_matrix.m_GridRouting )
+ row_min++;
- // Place the edge layer segments
- TRACK TmpSegm( NULL );
+ if( start.x > col_min * m_matrix.m_GridRouting )
+ col_min++;
- TmpSegm.SetLayer( UNDEFINED_LAYER );
- TmpSegm.SetNetCode( -1 );
- TmpSegm.SetWidth( RoutingMatrix.m_GridRouting / 2 );
+ if( row_min < 0 )
+ row_min = 0;
- for( auto PtStruct : aBrd->Drawings() )
- {
- DRAWSEGMENT* DrawSegm;
+ if( row_max >= ( m_matrix.m_Nrows - 1 ) )
+ row_max = m_matrix.m_Nrows - 1;
- switch( PtStruct->Type() )
- {
- case PCB_LINE_T:
- DrawSegm = (DRAWSEGMENT*) PtStruct;
+ if( col_min < 0 )
+ col_min = 0;
- if( DrawSegm->GetLayer() != Edge_Cuts )
- break;
+ if( col_max >= ( m_matrix.m_Ncols - 1 ) )
+ col_max = m_matrix.m_Ncols - 1;
- TraceSegmentPcb( DrawSegm, HOLE | CELL_is_EDGE,
- RoutingMatrix.m_GridRouting, WRITE_CELL );
- break;
+ unsigned int keepOutCost = 0;
- case PCB_TEXT_T:
- default:
- break;
+ for( int row = row_min; row <= row_max; row++ )
+ {
+ for( int col = col_min; col <= col_max; col++ )
+ {
+ // m_matrix.GetDist returns the "cost" of the cell
+ // at position (row, col)
+ // in autoplace this is the cost of the cell, if it is
+ // inside aRect
+ keepOutCost += m_matrix.GetDist( row, col, side );
}
}
- // Mark cells of the routing matrix to CELL_is_ZONE
- // (i.e. availlable cell to place a module )
- // Init a starting point of attachment to the area.
- RoutingMatrix.OrCell( RoutingMatrix.m_Nrows / 2, RoutingMatrix.m_Ncols / 2,
- BOTTOM, CELL_is_ZONE );
-
- // find and mark all other availlable cells:
- for( int ii = 1; ii != 0; )
- ii = propagate();
-
- // Initialize top layer. to the same value as the bottom layer
- if( RoutingMatrix.m_BoardSide[TOP] )
- memcpy( RoutingMatrix.m_BoardSide[TOP], RoutingMatrix.m_BoardSide[BOTTOM],
- nbCells * sizeof(MATRIX_CELL) );
-
- return 1;
+ return keepOutCost;
}
-
-/* Place module on Routing matrix.
+/* Test if the module can be placed on the board.
+ * Returns the value TstRectangle().
+ * Module is known by its bounding box
*/
-void genModuleOnRoutingMatrix( MODULE* Module )
+int AR_AUTOPLACER::testModuleOnBoard( MODULE* aModule, bool TstOtherSide, const wxPoint& aOffset )
{
- int ox, oy, fx, fy;
- LSET layerMask;
- D_PAD* Pad;
-
- EDA_RECT fpBBox = Module->GetBoundingBox();
-
- fpBBox.Inflate( RoutingMatrix.m_GridRouting / 2 );
- ox = fpBBox.GetX();
- fx = fpBBox.GetRight();
- oy = fpBBox.GetY();
- fy = fpBBox.GetBottom();
-
- if( ox < RoutingMatrix.m_BrdBox.GetX() )
- ox = RoutingMatrix.m_BrdBox.GetX();
-
- if( ox > RoutingMatrix.m_BrdBox.GetRight() )
- ox = RoutingMatrix.m_BrdBox.GetRight();
-
- if( fx < RoutingMatrix.m_BrdBox.GetX() )
- fx = RoutingMatrix.m_BrdBox.GetX();
-
- if( fx > RoutingMatrix.m_BrdBox.GetRight() )
- fx = RoutingMatrix.m_BrdBox.GetRight();
-
- if( oy < RoutingMatrix.m_BrdBox.GetY() )
- oy = RoutingMatrix.m_BrdBox.GetY();
+ int side = AR_SIDE_TOP;
+ int otherside = AR_SIDE_BOTTOM;
- if( oy > RoutingMatrix.m_BrdBox.GetBottom() )
- oy = RoutingMatrix.m_BrdBox.GetBottom();
-
- if( fy < RoutingMatrix.m_BrdBox.GetY() )
- fy = RoutingMatrix.m_BrdBox.GetY();
-
- if( fy > RoutingMatrix.m_BrdBox.GetBottom() )
- fy = RoutingMatrix.m_BrdBox.GetBottom();
+ if( aModule->GetLayer() == B_Cu )
+ {
+ side = AR_SIDE_BOTTOM; otherside = AR_SIDE_TOP;
+ }
- if( Module->GetLayer() == F_Cu )
- layerMask.set( F_Cu );
+ EDA_RECT fpBBox = aModule->GetFootprintRect();
+ fpBBox.Move( -aOffset );
- if( Module->GetLayer() == B_Cu )
- layerMask.set( B_Cu );
+ int diag = testRectangle( fpBBox, side );
- TraceFilledRectangle( ox, oy, fx, fy, layerMask,
- CELL_is_MODULE, WRITE_OR_CELL );
+ if( diag != AR_FREE_CELL )
+ return diag;
- // Trace pads + clearance areas.
- for( Pad = Module->Pads(); Pad != NULL; Pad = Pad->Next() )
+ if( TstOtherSide )
{
- int margin = (RoutingMatrix.m_GridRouting / 2) + Pad->GetClearance();
- ::PlacePad( Pad, CELL_is_MODULE, margin, WRITE_OR_CELL );
- }
+ diag = testRectangle( fpBBox, otherside );
- // Trace clearance.
- int margin = ( RoutingMatrix.m_GridRouting * Module->GetPadCount() ) / GAIN;
- CreateKeepOutRectangle( ox, oy, fx, fy, margin, KEEP_OUT_MARGIN, layerMask );
-}
+ if( diag != AR_FREE_CELL )
+ return diag;
+ }
+ int marge = ( m_matrix.m_GridRouting * aModule->GetPadCount() ) / AR_GAIN;
-// A minor helper function to draw a bounding box:
-inline void draw_FootprintRect( EDA_RECT* aClipBox, wxDC* aDC, EDA_RECT& fpBBox, COLOR4D aColor )
-{
-#ifndef USE_WX_OVERLAY
- GRRect( aClipBox, aDC, fpBBox, 0, aColor );
-#endif
+ fpBBox.Inflate( marge );
+ return calculateKeepOutArea( fpBBox, side );
}
-
-int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aDC )
+int AR_AUTOPLACER::getOptimalModulePlacement(MODULE* aModule)
{
int error = 1;
wxPoint LastPosOK;
double min_cost, curr_cost, Score;
bool TstOtherSide;
- auto displ_opts = (PCB_DISPLAY_OPTIONS*)aFrame->GetDisplayOptions();
- BOARD* brd = aFrame->GetBoard();
-
+
aModule->CalculateBoundingBox();
- bool showRats = displ_opts->m_Show_Module_Ratsnest;
- displ_opts->m_Show_Module_Ratsnest = false;
-
- brd->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
- aFrame->SetMsgPanel( aModule );
-
- LastPosOK = RoutingMatrix.m_BrdBox.GetOrigin();
+ LastPosOK = m_matrix.m_BrdBox.GetOrigin();
wxPoint mod_pos = aModule->GetPosition();
EDA_RECT fpBBox = aModule->GetFootprintRect();
@@ -640,31 +548,27 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD
// Calculate the limit of the footprint position, relative
// to the routing matrix area
- wxPoint xylimit = RoutingMatrix.m_BrdBox.GetEnd() - fpBBox.GetEnd();
+ wxPoint xylimit = m_matrix.m_BrdBox.GetEnd() - fpBBox.GetEnd();
- wxPoint initialPos = RoutingMatrix.m_BrdBox.GetOrigin() - fpBBoxOrg;
+ wxPoint initialPos = m_matrix.m_BrdBox.GetOrigin() - fpBBoxOrg;
// Stay on grid.
- initialPos.x -= initialPos.x % RoutingMatrix.m_GridRouting;
- initialPos.y -= initialPos.y % RoutingMatrix.m_GridRouting;
-
- CurrPosition = initialPos;
+ initialPos.x -= initialPos.x % m_matrix.m_GridRouting;
+ initialPos.y -= initialPos.y % m_matrix.m_GridRouting;
- // Undraw the current footprint
- aModule->DrawOutlinesWhenMoving( aFrame->GetCanvas(), aDC, wxPoint( 0, 0 ) );
-
- g_Offset_Module = mod_pos - CurrPosition;
+ m_curPosition = initialPos;
+ auto moduleOffset = mod_pos - m_curPosition;
/* Examine pads, and set TstOtherSide to true if a footprint
* has at least 1 pad through.
*/
TstOtherSide = false;
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
+ if( m_matrix.m_RoutingLayersCount > 1 )
{
LSET other( aModule->GetLayer() == B_Cu ? F_Cu : B_Cu );
- for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
+ for( auto pad : aModule->Pads() )
{
if( !( pad->GetLayerSet() & other ).any() )
continue;
@@ -674,257 +578,121 @@ int getOptimalModulePlacement( PCB_EDIT_FRAME* aFrame, MODULE* aModule, wxDC* aD
}
}
- // Draw the initial bounding box position
- COLOR4D color = COLOR4D( BROWN );
- fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
- draw_FootprintRect(aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color);
+ fpBBox.SetOrigin( fpBBoxOrg + m_curPosition );
min_cost = -1.0;
- aFrame->SetStatusText( wxT( "Score ??, pos ??" ) );
+// m_frame->SetStatusText( wxT( "Score ??, pos ??" ) );
- for( ; CurrPosition.x < xylimit.x; CurrPosition.x += RoutingMatrix.m_GridRouting )
- {
- wxYield();
- if( aFrame->GetCanvas()->GetAbortRequest() )
+ for( ; m_curPosition.x < xylimit.x; m_curPosition.x += m_matrix.m_GridRouting )
+ {
+ if ( m_refreshCallback )
{
- if( IsOK( aFrame, _( "OK to abort?" ) ) )
- {
- displ_opts->m_Show_Module_Ratsnest = showRats;
- return ESC;
- }
- else
- aFrame->GetCanvas()->SetAbortRequest( false );
+ if ( m_refreshCallback() == AR_ABORT_PLACEMENT )
+ return AR_ABORT_PLACEMENT;
}
- CurrPosition.y = initialPos.y;
+ m_curPosition.y = initialPos.y;
- for( ; CurrPosition.y < xylimit.y; CurrPosition.y += RoutingMatrix.m_GridRouting )
+ for( ; m_curPosition.y < xylimit.y; m_curPosition.y += m_matrix.m_GridRouting )
{
- // Erase traces.
- draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
-
- fpBBox.SetOrigin( fpBBoxOrg + CurrPosition );
- g_Offset_Module = mod_pos - CurrPosition;
- int keepOutCost = TstModuleOnBoard( brd, aModule, TstOtherSide );
- // Draw at new place
- color = keepOutCost >= 0 ? BROWN : RED;
- draw_FootprintRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, color );
+ fpBBox.SetOrigin( fpBBoxOrg + m_curPosition );
+ moduleOffset = mod_pos - m_curPosition;
+ int keepOutCost = testModuleOnBoard( aModule, TstOtherSide, moduleOffset );
if( keepOutCost >= 0 ) // i.e. if the module can be put here
{
error = 0;
- aFrame->build_ratsnest_module( aModule );
- curr_cost = compute_Ratsnest_PlaceModule( brd );
+ // m_frame->build_ratsnest_module( aModule ); // fixme
+ curr_cost = computePlacementRatsnestCost( aModule, moduleOffset );
Score = curr_cost + keepOutCost;
if( (min_cost >= Score ) || (min_cost < 0 ) )
{
- LastPosOK = CurrPosition;
+ LastPosOK = m_curPosition;
min_cost = Score;
wxString msg;
- msg.Printf( wxT( "Score %g, pos %s, %s" ),
+/* msg.Printf( wxT( "Score %g, pos %s, %s" ),
min_cost,
GetChars( ::CoordinateToString( LastPosOK.x ) ),
GetChars( ::CoordinateToString( LastPosOK.y ) ) );
- aFrame->SetStatusText( msg );
+ m_frame->SetStatusText( msg );*/
}
}
}
}
- // erasing the last traces
- GRRect( aFrame->GetCanvas()->GetClipBox(), aDC, fpBBox, 0, BROWN );
-
- displ_opts->m_Show_Module_Ratsnest = showRats;
-
// Regeneration of the modified variable.
- CurrPosition = LastPosOK;
-
- brd->m_Status_Pcb &= ~( RATSNEST_ITEM_LOCAL_OK | LISTE_PAD_OK );
+ m_curPosition = LastPosOK;
- MinCout = min_cost;
+ m_minCost = min_cost;
return error;
}
-/* Test if the rectangular area (ux, ux .. y0, y1):
- * - is a free zone (except OCCUPED_By_MODULE returns)
- * - is on the working surface of the board (otherwise returns OUT_OF_BOARD)
- *
- * Returns OUT_OF_BOARD, or OCCUPED_By_MODULE or FREE_CELL if OK
- */
-int TstRectangle( BOARD* Pcb, const EDA_RECT& aRect, int side )
+const D_PAD* AR_AUTOPLACER::nearestPad( MODULE *aRefModule, D_PAD* aRefPad, const wxPoint& aOffset)
{
- EDA_RECT rect = aRect;
-
- rect.Inflate( RoutingMatrix.m_GridRouting / 2 );
-
- wxPoint start = rect.GetOrigin();
- wxPoint end = rect.GetEnd();
-
- start -= RoutingMatrix.m_BrdBox.GetOrigin();
- end -= RoutingMatrix.m_BrdBox.GetOrigin();
-
- int row_min = start.y / RoutingMatrix.m_GridRouting;
- int row_max = end.y / RoutingMatrix.m_GridRouting;
- int col_min = start.x / RoutingMatrix.m_GridRouting;
- int col_max = end.x / RoutingMatrix.m_GridRouting;
-
- if( start.y > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- if( start.x > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
+ const D_PAD* nearest = nullptr;
+ int64_t nearestDist = INT64_MAX;
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( int row = row_min; row <= row_max; row++ )
+ for ( auto mod : m_board->Modules() )
{
- for( int col = col_min; col <= col_max; col++ )
- {
- unsigned int data = RoutingMatrix.GetCell( row, col, side );
-
- if( ( data & CELL_is_ZONE ) == 0 )
- return OUT_OF_BOARD;
-
- if( (data & CELL_is_MODULE) )
- return OCCUPED_By_MODULE;
- }
- }
-
- return FREE_CELL;
-}
-
-
-/* Calculates and returns the clearance area of the rectangular surface
- * aRect):
- * (Sum of cells in terms of distance)
- */
-unsigned int CalculateKeepOutArea( const EDA_RECT& aRect, int side )
-{
- wxPoint start = aRect.GetOrigin();
- wxPoint end = aRect.GetEnd();
-
- start -= RoutingMatrix.m_BrdBox.GetOrigin();
- end -= RoutingMatrix.m_BrdBox.GetOrigin();
-
- int row_min = start.y / RoutingMatrix.m_GridRouting;
- int row_max = end.y / RoutingMatrix.m_GridRouting;
- int col_min = start.x / RoutingMatrix.m_GridRouting;
- int col_max = end.x / RoutingMatrix.m_GridRouting;
-
- if( start.y > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- if( start.x > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
+ if ( mod == aRefModule )
+ continue;
- unsigned int keepOutCost = 0;
+ if( !m_matrix.m_BrdBox.Contains( mod->GetPosition() ) )
+ continue;
- for( int row = row_min; row <= row_max; row++ )
- {
- for( int col = col_min; col <= col_max; col++ )
+ for ( auto pad: mod->Pads() )
{
- // RoutingMatrix.GetDist returns the "cost" of the cell
- // at position (row, col)
- // in autoplace this is the cost of the cell, if it is
- // inside aRect
- keepOutCost += RoutingMatrix.GetDist( row, col, side );
- }
- }
-
- return keepOutCost;
-}
-
-
-/* Test if the module can be placed on the board.
- * Returns the value TstRectangle().
- * Module is known by its bounding box
- */
-int TstModuleOnBoard( BOARD* Pcb, MODULE* aModule, bool TstOtherSide )
-{
- int side = TOP;
- int otherside = BOTTOM;
-
- if( aModule->GetLayer() == B_Cu )
- {
- side = BOTTOM; otherside = TOP;
- }
-
- EDA_RECT fpBBox = aModule->GetFootprintRect();
- fpBBox.Move( -g_Offset_Module );
-
- int diag = TstRectangle( Pcb, fpBBox, side );
+
+ if ( pad->GetNetCode() != aRefPad->GetNetCode() || pad->GetNetCode() <= 0 )
+ continue;
- if( diag != FREE_CELL )
- return diag;
+ auto dist = (VECTOR2I( aRefPad->GetPosition() - aOffset ) - VECTOR2I( pad->GetPosition() ) ).EuclideanNorm();
- if( TstOtherSide )
- {
- diag = TstRectangle( Pcb, fpBBox, otherside );
+ //printf("Dist %lld pad %p\n", dist, pad );
- if( diag != FREE_CELL )
- return diag;
+ if ( dist < nearestDist )
+ {
+ nearestDist = dist;
+ nearest = pad;
+ }
+ }
}
- int marge = ( RoutingMatrix.m_GridRouting * aModule->GetPadCount() ) / GAIN;
-
- fpBBox.Inflate( marge );
- return CalculateKeepOutArea( fpBBox, side );
+ return nearest;
}
-
-double compute_Ratsnest_PlaceModule( BOARD* aBrd )
+double AR_AUTOPLACER::computePlacementRatsnestCost( MODULE *aModule, const wxPoint& aOffset )
{
double curr_cost;
- wxPoint start; // start point of a ratsnest
- wxPoint end; // end point of a ratsnest
+ VECTOR2I start; // start point of a ratsnest
+ VECTOR2I end; // end point of a ratsnest
int dx, dy;
- if( ( aBrd->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
- return -1;
-
curr_cost = 0;
- for( unsigned ii = 0; ii < aBrd->m_LocalRatsnest.size(); ii++ )
- {
- RATSNEST_ITEM* pt_local_rats_nest = &aBrd->m_LocalRatsnest[ii];
+
+ // m_overlay->Clear();
- if( ( pt_local_rats_nest->m_Status & LOCAL_RATSNEST_ITEM ) )
- continue; // Skip ratsnest between 2 pads of the current module
- // Skip modules not inside the board area
- MODULE* module = pt_local_rats_nest->m_PadEnd->GetParent();
+ for ( auto pad : aModule->Pads() )
+ {
+ auto nearest = nearestPad( aModule, pad, aOffset );
- if( !RoutingMatrix.m_BrdBox.Contains( module->GetPosition() ) )
+ if( !nearest )
continue;
- start = pt_local_rats_nest->m_PadStart->GetPosition() - g_Offset_Module;
- end = pt_local_rats_nest->m_PadEnd->GetPosition();
+ //printf("pad %s nearest %s\n", (const char *)aModule->GetReference().c_str(), (const char *)nearest->GetParent()->GetReference().c_str());
+
+ start = VECTOR2I( pad->GetPosition() ) - VECTOR2I(aOffset);
+ end = VECTOR2I( nearest->GetPosition() );
+
+ //m_overlay->SetIsStroke( true );
+ //m_overlay->SetStrokeColor( COLOR4D(0.0, 1.0, 0.0, 1.0) );
+ //m_overlay->Line( start, end );
// Cost of the ratsnest.
dx = end.x - start.x;
@@ -949,122 +717,8 @@ double compute_Ratsnest_PlaceModule( BOARD* aBrd )
return curr_cost;
}
-
-/**
- * Function CreateKeepOutRectangle
- * builds the cost map:
- * Cells ( in Dist map ) inside the rect x0,y0 a x1,y1 are
- * incremented by value aKeepOut
- * Cell outside this rectangle, but inside the rectangle
- * x0,y0 -marge to x1,y1 + marge are incremented by a decreasing value
- * (aKeepOut ... 0). The decreasing value depends on the distance to the first rectangle
- * Therefore the cost is high in rect x0,y0 to x1,y1, and decrease outside this rectangle
- */
-void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
- int marge, int aKeepOut, LSET aLayerMask )
-{
- int row, col;
- int row_min, row_max, col_min, col_max, pmarge;
- int trace = 0;
- DIST_CELL data, LocalKeepOut;
- int lgain, cgain;
-
- if( aLayerMask[g_Route_Layer_BOTTOM] )
- trace = 1; // Trace on bottom layer.
-
- if( aLayerMask[g_Route_Layer_TOP] && RoutingMatrix.m_RoutingLayersCount )
- trace |= 2; // Trace on top layer.
-
- if( trace == 0 )
- return;
-
- ux0 -= RoutingMatrix.m_BrdBox.GetX();
- uy0 -= RoutingMatrix.m_BrdBox.GetY();
- ux1 -= RoutingMatrix.m_BrdBox.GetX();
- uy1 -= RoutingMatrix.m_BrdBox.GetY();
-
- ux0 -= marge; ux1 += marge;
- uy0 -= marge; uy1 += marge;
-
- pmarge = marge / RoutingMatrix.m_GridRouting;
-
- if( pmarge < 1 )
- pmarge = 1;
-
- // Calculate the coordinate limits of the rectangle.
- row_max = uy1 / RoutingMatrix.m_GridRouting;
- col_max = ux1 / RoutingMatrix.m_GridRouting;
- row_min = uy0 / RoutingMatrix.m_GridRouting;
-
- if( uy0 > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- col_min = ux0 / RoutingMatrix.m_GridRouting;
-
- if( ux0 > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= (RoutingMatrix.m_Nrows - 1) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= (RoutingMatrix.m_Ncols - 1) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( row = row_min; row <= row_max; row++ )
- {
- lgain = 256;
-
- if( row < pmarge )
- lgain = ( 256 * row ) / pmarge;
- else if( row > row_max - pmarge )
- lgain = ( 256 * ( row_max - row ) ) / pmarge;
-
- for( col = col_min; col <= col_max; col++ )
- {
- // RoutingMatrix Dist map containt the "cost" of the cell
- // at position (row, col)
- // in autoplace this is the cost of the cell, when
- // a footprint overlaps it, near a "master" footprint
- // this cost is hight near the "master" footprint
- // and decrease with the distance
- cgain = 256;
- LocalKeepOut = aKeepOut;
-
- if( col < pmarge )
- cgain = ( 256 * col ) / pmarge;
- else if( col > col_max - pmarge )
- cgain = ( 256 * ( col_max - col ) ) / pmarge;
-
- cgain = ( cgain * lgain ) / 256;
-
- if( cgain != 256 )
- LocalKeepOut = ( LocalKeepOut * cgain ) / 256;
-
- if( trace & 1 )
- {
- data = RoutingMatrix.GetDist( row, col, BOTTOM ) + LocalKeepOut;
- RoutingMatrix.SetDist( row, col, BOTTOM, data );
- }
-
- if( trace & 2 )
- {
- data = RoutingMatrix.GetDist( row, col, TOP );
- data = std::max( data, LocalKeepOut );
- RoutingMatrix.SetDist( row, col, TOP, data );
- }
- }
- }
-}
-
-
// Sort routines
-static bool Tri_PlaceModules( MODULE* ref, MODULE* compare )
+static bool sortFootprintsByComplexity( MODULE* ref, MODULE* compare )
{
double ff1, ff2;
@@ -1074,7 +728,6 @@ static bool Tri_PlaceModules( MODULE* ref, MODULE* compare )
return ff2 < ff1;
}
-
static bool sortFootprintsByRatsnestSize( MODULE* ref, MODULE* compare )
{
double ff1, ff2;
@@ -1086,70 +739,67 @@ static bool sortFootprintsByRatsnestSize( MODULE* ref, MODULE* compare )
/**
- * Function PickModule
+ * Function Module
* find the "best" module place
* The criteria are:
* - Maximum ratsnest with modules already placed
* - Max size, and number of pads max
*/
-static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
+MODULE* AR_AUTOPLACER::pickModule( )
{
- MODULE* Module;
+ MODULE* module;
std::vector <MODULE*> moduleList;
- // Build sorted footprints list (sort by decreasing size )
- Module = pcbframe->GetBoard()->m_Modules;
-
- for( ; Module != NULL; Module = Module->Next() )
+
+ for( auto m : m_board->Modules() )
{
- Module->CalculateBoundingBox();
- moduleList.push_back( Module );
+ m->CalculateBoundingBox();
+ moduleList.push_back( m );
}
- sort( moduleList.begin(), moduleList.end(), Tri_PlaceModules );
+ sort( moduleList.begin(), moduleList.end(), sortFootprintsByComplexity );
for( unsigned kk = 0; kk < moduleList.size(); kk++ )
{
- Module = moduleList[kk];
- Module->SetFlag( 0 );
+ module = moduleList[kk];
+ module->SetFlag( 0 );
- if( !Module->NeedsPlaced() )
+ if( !module->NeedsPlaced() )
continue;
- pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
- pcbframe->SetMsgPanel( Module );
- pcbframe->build_ratsnest_module( Module );
-
- // Calculate external ratsnest.
- for( unsigned ii = 0; ii < pcbframe->GetBoard()->m_LocalRatsnest.size(); ii++ )
- {
- if( ( pcbframe->GetBoard()->m_LocalRatsnest[ii].m_Status &
- LOCAL_RATSNEST_ITEM ) == 0 )
- Module->IncrementFlag();
- }
+ m_connectivity->Update( module );
}
- pcbframe->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
+ m_connectivity->RecalculateRatsnest();
+
+ for( unsigned kk = 0; kk < moduleList.size(); kk++ )
+ {
+ module = moduleList[kk];
+
+ auto edges = m_connectivity->GetRatsnestForComponent( module, true );
+
+ module->SetFlag( edges.size() ) ;
+ }
sort( moduleList.begin(), moduleList.end(), sortFootprintsByRatsnestSize );
// Search for "best" module.
- MODULE* bestModule = NULL;
- MODULE* altModule = NULL;
+ MODULE* bestModule = nullptr;
+ MODULE* altModule = nullptr;
for( unsigned ii = 0; ii < moduleList.size(); ii++ )
{
- Module = moduleList[ii];
+ module = moduleList[ii];
- if( !Module->NeedsPlaced() )
+ if( !module->NeedsPlaced() )
continue;
- altModule = Module;
+ altModule = module;
- if( Module->GetFlag() == 0 )
+ if( module->GetFlag() == 0 )
continue;
- bestModule = Module;
+ bestModule = module;
break;
}
@@ -1160,139 +810,269 @@ static MODULE* PickModule( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
}
-/**
- * Function propagate
- * Used only in autoplace calculations
- * Uses the routing matrix to fill the cells within the zone
- * Search and mark cells within the zone, and agree with DRC options.
- * Requirements:
- * Start from an initial point, to fill zone
- * The zone must have no "copper island"
- * Algorithm:
- * If the current cell has a neighbor flagged as "cell in the zone", it
- * become a cell in the zone
- * The first point in the zone is the starting point
- * 4 searches within the matrix are made:
- * 1 - Left to right and top to bottom
- * 2 - Right to left and top to bottom
- * 3 - bottom to top and Right to left
- * 4 - bottom to top and Left to right
- * Given the current cell, for each search, we consider the 2 neighbor cells
- * the previous cell on the same line and the previous cell on the same column.
- *
- * This function can request some iterations
- * Iterations are made until no cell is added to the zone.
- * @return added cells count (i.e. which the attribute CELL_is_ZONE is set)
- */
-int propagate()
+void AR_AUTOPLACER::drawPlacementRoutingMatrix( )
{
- int row, col;
- long current_cell, old_cell_H;
- std::vector<long> pt_cell_V;
- int nbpoints = 0;
-
-#define NO_CELL_ZONE (HOLE | CELL_is_EDGE | CELL_is_ZONE)
-
- pt_cell_V.reserve( std::max( RoutingMatrix.m_Nrows, RoutingMatrix.m_Ncols ) );
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+ int ii, jj;
+ COLOR4D color;
+ int ox, oy;
+ AR_MATRIX::MATRIX_CELL top_state, bottom_state;
- // Search from left to right and top to bottom.
- for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
+
+ for( ii = 0; ii < m_matrix.m_Nrows; ii++ )
{
- old_cell_H = 0;
+ oy = m_matrix.m_BrdBox.GetY() + ( ii * m_matrix.m_GridRouting );
- for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
+ for( jj = 0; jj < m_matrix.m_Ncols; jj++ )
{
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+ ox = m_matrix.m_BrdBox.GetX() + (jj * m_matrix.m_GridRouting);
+ color = COLOR4D::BLACK;
- if( current_cell == 0 ) // a free cell is found
+ top_state = m_matrix.GetCell( ii, jj, AR_SIDE_TOP );
+ bottom_state = m_matrix.GetCell( ii, jj, AR_SIDE_BOTTOM );
+
+ if(top_state || bottom_state)
{
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
+ // printf("[%d, %d] [%d, %d] TS %x BS %x\n",ii,jj, ox, oy, top_state, bottom_state );
}
- pt_cell_V[col] = old_cell_H = current_cell;
+ if( top_state & CELL_IS_ZONE )
+ color = COLOR4D( BLUE );
+
+ // obstacles
+ if( ( top_state & CELL_IS_EDGE ) || ( bottom_state & CELL_IS_EDGE ) )
+ color = COLOR4D::WHITE;
+ else if( top_state & ( CELL_IS_HOLE | CELL_IS_MODULE ) )
+ color = COLOR4D( LIGHTRED );
+ else if( bottom_state & ( CELL_IS_HOLE | CELL_IS_MODULE) )
+ color = COLOR4D( LIGHTGREEN );
+ else // Display the filling and keep out regions.
+ {
+ if( m_matrix.GetDist( ii, jj, AR_SIDE_TOP )
+ || m_matrix.GetDist( ii, jj, AR_SIDE_BOTTOM ) )
+ color = DARKGRAY;
+ }
+
+ m_overlay->SetIsFill(true);
+ m_overlay->SetFillColor( color );
+
+ VECTOR2D p(ox, oy);
+ m_overlay->Circle(p, m_matrix.m_GridRouting/4 );
}
}
+}
- // Search from right to left and top to bottom/
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+AR_RESULT AR_AUTOPLACER::AutoplaceModules( std::vector<MODULE*> aModules, BOARD_COMMIT* aCommit, bool aPlaceOffboardModules )
+{
+ wxPoint PosOK;
+ wxPoint memopos;
+ int error;
+ MODULE* module = nullptr;
+ bool cancelled = false;
+
+ memopos = m_curPosition;
+
+ //printf("set grid: %d\n", m_gridSize);
+
+ m_matrix.m_GridRouting = m_gridSize; //(int) m_frame->GetScreen()->GetGridSize().x;
- for( row = 0; row < RoutingMatrix.m_Nrows; row++ )
+ // Ensure Board.m_GridRouting has a reasonable value:
+ if( m_matrix.m_GridRouting < Millimeter2iu( 0.25 ) )
+ m_matrix.m_GridRouting = Millimeter2iu( 0.25 );
+
+ // Compute module parameters used in auto place
+ if( genPlacementRoutingMatrix( ) == 0 )
+ return AR_FAILURE;
+
+ int moduleCount = 0;
+
+
+ for ( auto m : m_board->Modules() )
{
- old_cell_H = 0;
+ m->SetNeedsPlaced( false );
+ }
- for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
- {
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+
+ std::vector<MODULE *> offboardMods;
- if( current_cell == 0 ) // a free cell is found
+ if( aPlaceOffboardModules )
+ {
+ for ( auto m : m_board->Modules() )
+ {
+ if( !m_matrix.m_BrdBox.Contains( m->GetPosition() ) )
{
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[col] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
+ offboardMods.push_back( m );
}
+ }
+ }
- pt_cell_V[col] = old_cell_H = current_cell;
+ for ( auto m : aModules )
+ {
+ m->SetNeedsPlaced( true );
+ aCommit->Modify(m);
+ }
+
+ for ( auto m : offboardMods )
+ {
+ m->SetNeedsPlaced( true );
+ aCommit->Modify(m);
+ }
+
+ for ( auto m : m_board->Modules() )
+ {
+ if( m->NeedsPlaced() ) // Erase from screen
+ {
+ moduleCount++;
+ }
+ else
+ {
+ genModuleOnRoutingMatrix( m );
}
}
- // Search from bottom to top and right to left.
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+ drawPlacementRoutingMatrix();
+
+ int cnt = 0;
+ wxString msg;
- for( col = RoutingMatrix.m_Ncols - 1; col >= 0; col-- )
+ if( m_progressReporter )
{
- old_cell_H = 0;
+ m_progressReporter->Report( _( "Autoplacing components..." ) );
+ m_progressReporter->SetMaxProgress( moduleCount );
+ }
+
+ while( ( module = pickModule( ) ) != nullptr )
+ {
+ // Display some info about activity, module placement can take a while:
+ //printf( _( "Place footprint %d of %d [%s]\n" ), cnt, moduleCount, (const char *)module->GetReference().c_str() );
+ //m_frame->SetStatusText( msg );
+
+ double initialOrient = module->GetOrientation();
+ // Display fill area of interest, barriers, penalties.
+ //drawPlacementRoutingMatrix( );
+
+ error = getOptimalModulePlacement( module );
+ double bestScore = m_minCost;
+ double bestRotation = 0.0;
+ int rotAllowed;
+ PosOK = m_curPosition;
+
+ if( error == AR_ABORT_PLACEMENT )
+ goto end_of_tst;
+
+ // Try orientations 90, 180, 270 degrees from initial orientation
+ rotAllowed = module->GetPlacementCost180();
- for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
+ //printf("rotAllowed %d\n", rotAllowed);
+
+ if( rotAllowed != 0 )
{
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+ rotateModule( module, 1800.0, true );
+ error = getOptimalModulePlacement( module );
+ m_minCost *= OrientationPenalty[rotAllowed];
- if( current_cell == 0 ) // a free cell is found
+ if( bestScore > m_minCost ) // This orientation is better.
{
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
+ PosOK = m_curPosition;
+ bestScore = m_minCost;
+ bestRotation = 1800.0;
+ }
+ else
+ {
+ rotateModule( module, initialOrient, false );
}
- pt_cell_V[row] = old_cell_H = current_cell;
+ if( error == AR_ABORT_PLACEMENT )
+ goto end_of_tst;
}
- }
- // Search from bottom to top and left to right.
- fill( pt_cell_V.begin(), pt_cell_V.end(), 0 );
+ // Determine if the best orientation of a module is 90.
+ rotAllowed = module->GetPlacementCost90();
+ if( rotAllowed != 0 )
+ {
+ rotateModule( module, 900.0, true );
+ error = getOptimalModulePlacement( module );
+ m_minCost *= OrientationPenalty[rotAllowed];
- for( col = 0; col < RoutingMatrix.m_Ncols; col++ )
- {
- old_cell_H = 0;
+ if( bestScore > m_minCost ) // This orientation is better.
+ {
+ PosOK = m_curPosition;
+ bestScore = m_minCost;
+ bestRotation = 900.0;
+ }
+ else
+ {
+ rotateModule( module, initialOrient, false );
+ }
- for( row = RoutingMatrix.m_Nrows - 1; row >= 0; row-- )
+ if( error == AR_ABORT_PLACEMENT )
+ goto end_of_tst;
+ }
+
+ // Determine if the best orientation of a module is -90.
+ if( rotAllowed != 0 )
{
- current_cell = RoutingMatrix.GetCell( row, col, BOTTOM ) & NO_CELL_ZONE;
+ rotateModule( module, 2700.0, true );
+ error = getOptimalModulePlacement( module );
+ m_minCost *= OrientationPenalty[rotAllowed];
- if( current_cell == 0 ) // a free cell is found
+ if( bestScore > m_minCost ) // This orientation is better.
{
- if( (old_cell_H & CELL_is_ZONE) || (pt_cell_V[row] & CELL_is_ZONE) )
- {
- RoutingMatrix.OrCell( row, col, BOTTOM, CELL_is_ZONE );
- current_cell = CELL_is_ZONE;
- nbpoints++;
- }
+ PosOK = m_curPosition;
+ bestScore = m_minCost;
+ bestRotation = 2700.0;
+ }
+ else
+ {
+ rotateModule( module, initialOrient, false );
}
- pt_cell_V[row] = old_cell_H = current_cell;
+ if( error == AR_ABORT_PLACEMENT )
+ goto end_of_tst;
+ }
+
+end_of_tst:
+
+ if( error == AR_ABORT_PLACEMENT )
+ break;
+
+
+ bestRotation += initialOrient;
+
+ if( bestRotation != module->GetOrientation() )
+ {
+ //printf("best rotation %d\n", bestRotation );
+ rotateModule( module, bestRotation, false );
}
+
+ // Place module.
+ placeModule( module, true, m_curPosition );
+
+ module->CalculateBoundingBox();
+ genModuleOnRoutingMatrix( module );
+ module->SetIsPlaced( true );
+ module->SetNeedsPlaced( false );
+
+
+ if( m_progressReporter )
+ {
+ m_progressReporter->AdvanceProgress();
+ if ( !m_progressReporter->KeepRefreshing( false ) )
+ {
+ cancelled = true;
+ break;
+ }
+ }
+ cnt++;
}
- return nbpoints;
+ m_curPosition = memopos;
+
+ m_matrix.UnInitRoutingMatrix();
+
+ for ( auto m : m_board->Modules() )
+ {
+ m->CalculateBoundingBox();
+ }
+
+ return cancelled ? AR_CANCELLED : AR_COMPLETED;
}
diff --git a/pcbnew/autorouter/ar_autoplacer.h b/pcbnew/autorouter/ar_autoplacer.h
new file mode 100644
index 0000000..552962b
--- /dev/null
+++ b/pcbnew/autorouter/ar_autoplacer.h
@@ -0,0 +1,121 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
+ *
+ * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 __AR_AUTOPLACER_H
+#define __AR_AUTOPLACER_H
+
+#include "ar_matrix.h"
+#include "ar_cell.h"
+
+#include <class_board.h>
+#include <class_module.h>
+
+#include <connectivity_data.h>
+
+#include <view/view_overlay.h>
+
+enum AR_CELL_STATE
+{
+ AR_OUT_OF_BOARD = -2,
+ AR_OCCUIPED_BY_MODULE = -1,
+ AR_FREE_CELL = 0
+};
+
+enum AR_RESULT
+{
+ AR_COMPLETED = 1,
+ AR_CANCELLED,
+ AR_FAILURE
+};
+
+class PROGRESS_REPORTER;
+
+class AR_AUTOPLACER
+{
+
+public:
+
+ AR_AUTOPLACER( BOARD* aBoard );
+
+ AR_RESULT AutoplaceModules( std::vector<MODULE*> aModules, BOARD_COMMIT* aCommit, bool aPlaceOffboardModules = false );
+
+
+ const std::vector<MODULE*> QueryOffboardModules();
+
+ void SetPlacementGrid( int aGrid )
+ {
+ m_gridSize = aGrid;
+ }
+
+ void SetOverlay( std::shared_ptr<KIGFX::VIEW_OVERLAY> aOverlay )
+ {
+ m_overlay = aOverlay;
+ }
+
+ void SetRefreshCallback( std::function<int()> aCallback )
+ {
+ m_refreshCallback = aCallback;
+ }
+
+ void SetProgressReporter( PROGRESS_REPORTER* aReporter )
+ {
+ m_progressReporter = aReporter;
+ }
+
+
+private:
+ void drawPlacementRoutingMatrix( );
+ void rotateModule( MODULE* module, double angle, bool incremental );
+ int genPlacementRoutingMatrix();
+ void genModuleOnRoutingMatrix( MODULE* Module );
+ int propagate();
+ int testRectangle( const EDA_RECT& aRect, int side );
+ unsigned int calculateKeepOutArea( const EDA_RECT& aRect, int side );
+ int testModuleOnBoard( MODULE* aModule, bool TstOtherSide, const wxPoint& aOffset );
+ int getOptimalModulePlacement(MODULE* aModule);
+ double computePlacementRatsnestCost( MODULE *aModule, const wxPoint& aOffset );
+ MODULE* pickModule( );
+ void placeModule( MODULE* aModule, bool aDoNotRecreateRatsnest, const wxPoint& aPos );
+ const D_PAD* nearestPad( MODULE *aRefModule, D_PAD* aRefPad, const wxPoint& aOffset);
+
+ AR_MATRIX m_matrix;
+
+ BOARD* m_board;
+
+ wxPoint m_curPosition;
+ wxPoint m_moduleOffset;
+ double m_minCost;
+ int m_gridSize;
+
+ std::shared_ptr<KIGFX::VIEW_OVERLAY> m_overlay;
+ std::unique_ptr<CONNECTIVITY_DATA> m_connectivity;
+ std::function<int()> m_refreshCallback;
+ PROGRESS_REPORTER* m_progressReporter;
+};
+
+#endif
diff --git a/pcbnew/autorouter/ar_cell.h b/pcbnew/autorouter/ar_cell.h
index 63b76ae..2dbaafe 100644
--- a/pcbnew/autorouter/ar_cell.h
+++ b/pcbnew/autorouter/ar_cell.h
@@ -1,7 +1,3 @@
-/**
- * @file cell.h
- */
-
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
@@ -32,16 +28,16 @@
*/
-#ifndef _CELL_H_
-#define _CELL_H_
-
+#ifndef _AR_CELL_H_
+#define _AR_CELL_H_
/* Bits characterizing cell */
-#define HOLE 0x01 /* a conducting hole or obstacle */
-#define CELL_is_MODULE 0x02 /* auto placement occupied by a module */
-#define CELL_is_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
-#define CELL_is_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
-#define CELL_is_ZONE 0x80 /* Area and auto-placement: cell available */
+#define CELL_IS_EMPTY 0x00
+#define CELL_IS_HOLE 0x01 /* a conducting hole or obstacle */
+#define CELL_IS_MODULE 0x02 /* auto placement occupied by a module */
+#define CELL_IS_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
+#define CELL_IS_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
+#define CELL_IS_ZONE 0x80 /* Area and auto-placement: cell available */
/* Bit masks for presence of obstacles to autorouting */
#define OCCUPE 1 /* Autorouting: obstacle tracks and vias. */
diff --git a/pcbnew/autorouter/ar_matrix.cpp b/pcbnew/autorouter/ar_matrix.cpp
index 856dead..dfc7b68 100644
--- a/pcbnew/autorouter/ar_matrix.cpp
+++ b/pcbnew/autorouter/ar_matrix.cpp
@@ -25,33 +25,23 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-/**
- * @file routing_matrix.cpp
- * @brief Functions to create autorouting maps
- */
+#include "ar_matrix.h"
+#include "ar_cell.h"
-#include <fctsys.h>
+#include <trigo.h>
+#include <math_for_graphics.h>
#include <common.h>
-#include <pcbnew.h>
-#include <cell.h>
-#include <autorout.h>
-
-#include <class_eda_rect.h>
-#include <class_board.h>
-#include <class_module.h>
-#include <class_track.h>
#include <class_drawsegment.h>
-#include <class_edge_mod.h>
-#include <class_pcb_text.h>
-
+#include <class_track.h>
+#include <class_pad.h>
-MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
+AR_MATRIX::AR_MATRIX()
{
- m_BoardSide[0] = m_BoardSide[1] = NULL;
- m_DistSide[0] = m_DistSide[1] = NULL;
- m_DirSide[0] = m_DirSide[1] = NULL;
- m_opWriteCell = NULL;
+ m_BoardSide[0] = m_BoardSide[1] = nullptr;
+ m_DistSide[0] = m_DistSide[1] = nullptr;
+ m_DirSide[0] = m_DirSide[1] = nullptr;
+ m_opWriteCell = nullptr;
m_InitMatrixDone = false;
m_Nrows = 0;
m_Ncols = 0;
@@ -62,15 +52,17 @@ MATRIX_ROUTING_HEAD::MATRIX_ROUTING_HEAD()
}
-MATRIX_ROUTING_HEAD::~MATRIX_ROUTING_HEAD()
+AR_MATRIX::~AR_MATRIX()
{
}
+// was: bool AR_MATRIX::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
+// aUseBoardEdgesOnly ? aPcb->GetBoardEdgesBoundingBox() : aPcb->GetBoundingBox();
-bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnly )
+bool AR_MATRIX::ComputeMatrixSize( const EDA_RECT& aBoundingBox )
{
// The boundary box must have its start point on routing grid:
- m_BrdBox = aUseBoardEdgesOnly ? aPcb->GetBoardEdgesBoundingBox() : aPcb->GetBoundingBox();
+ m_BrdBox = aBoundingBox;
m_BrdBox.SetX( m_BrdBox.GetX() - ( m_BrdBox.GetX() % m_GridRouting ) );
m_BrdBox.SetY( m_BrdBox.GetY() - ( m_BrdBox.GetY() % m_GridRouting ) );
@@ -97,7 +89,7 @@ bool MATRIX_ROUTING_HEAD::ComputeMatrixSize( BOARD* aPcb, bool aUseBoardEdgesOnl
}
-int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
+int AR_MATRIX::InitRoutingMatrix()
{
if( m_Nrows <= 0 || m_Ncols <= 0 )
return 0;
@@ -105,37 +97,37 @@ int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
m_InitMatrixDone = true; // we have been called
// give a small margin for memory allocation:
- int ii = (RoutingMatrix.m_Nrows + 1) * (RoutingMatrix.m_Ncols + 1);
+ int ii = (m_Nrows + 1) * (m_Ncols + 1);
- int side = BOTTOM;
+ int side = AR_SIDE_BOTTOM;
for( int jj = 0; jj < m_RoutingLayersCount; jj++ ) // m_RoutingLayersCount = 1 or 2
{
- m_BoardSide[side] = NULL;
- m_DistSide[side] = NULL;
- m_DirSide[side] = NULL;
+ m_BoardSide[side] = nullptr;
+ m_DistSide[side] = nullptr;
+ m_DirSide[side] = nullptr;
// allocate matrix & initialize everything to empty
m_BoardSide[side] = (MATRIX_CELL*) operator new( ii * sizeof(MATRIX_CELL) );
memset( m_BoardSide[side], 0, ii * sizeof(MATRIX_CELL) );
- if( m_BoardSide[side] == NULL )
+ if( m_BoardSide[side] == nullptr )
return -1;
// allocate Distances
m_DistSide[side] = (DIST_CELL*) operator new( ii * sizeof(DIST_CELL) );
memset( m_DistSide[side], 0, ii * sizeof(DIST_CELL) );
- if( m_DistSide[side] == NULL )
+ if( m_DistSide[side] == nullptr )
return -1;
// allocate Dir (chars)
m_DirSide[side] = (char*) operator new( ii );
memset( m_DirSide[side], 0, ii );
- if( m_DirSide[side] == NULL )
+ if( m_DirSide[side] == nullptr )
return -1;
- side = TOP;
+ side = AR_SIDE_TOP;
}
m_MemSize = m_RouteCount * ii * ( sizeof(MATRIX_CELL)
@@ -145,403 +137,1196 @@ int MATRIX_ROUTING_HEAD::InitRoutingMatrix()
}
-void MATRIX_ROUTING_HEAD::UnInitRoutingMatrix()
+void AR_MATRIX::UnInitRoutingMatrix()
{
int ii;
m_InitMatrixDone = false;
- for( ii = 0; ii < MAX_ROUTING_LAYERS_COUNT; ii++ )
+ for( ii = 0; ii < AR_MAX_ROUTING_LAYERS_COUNT; ii++ )
{
// de-allocate Dir matrix
if( m_DirSide[ii] )
{
delete m_DirSide[ii];
- m_DirSide[ii] = NULL;
+ m_DirSide[ii] = nullptr;
}
// de-allocate Distances matrix
if( m_DistSide[ii] )
{
delete m_DistSide[ii];
- m_DistSide[ii] = NULL;
+ m_DistSide[ii] = nullptr;
}
// de-allocate cells matrix
if( m_BoardSide[ii] )
{
delete m_BoardSide[ii];
- m_BoardSide[ii] = NULL;
+ m_BoardSide[ii] = nullptr;
}
}
m_Nrows = m_Ncols = 0;
}
+// Initialize m_opWriteCell member to make the aLogicOp
+void AR_MATRIX::SetCellOperation( AR_MATRIX::CELL_OP aLogicOp )
+{
+ switch( aLogicOp )
+ {
+ default:
+ case WRITE_CELL:
+ m_opWriteCell = &AR_MATRIX::SetCell;
+ break;
-/**
- * Function PlaceCells
- * Initialize the matrix routing by setting obstacles for each occupied cell
- * a cell set to HOLE is an obstacle for tracks and vias
- * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only.
- * a cell set to CELL_is_EDGE is a frontier.
- * Tracks and vias having the same net code as net_code are skipped
- * (htey do not are obstacles)
- *
- * For single-sided Routing 1:
- * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
- *
- * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
+ case WRITE_OR_CELL:
+ m_opWriteCell = &AR_MATRIX::OrCell;
+ break;
+
+ case WRITE_XOR_CELL:
+ m_opWriteCell = &AR_MATRIX::XorCell;
+ break;
+
+ case WRITE_AND_CELL:
+ m_opWriteCell = &AR_MATRIX::AndCell;
+ break;
+
+ case WRITE_ADD_CELL:
+ m_opWriteCell = &AR_MATRIX::AddCell;
+ break;
+ }
+}
+
+
+/* return the value stored in a cell
*/
-void PlaceCells( BOARD* aPcb, int net_code, int flag )
+AR_MATRIX::MATRIX_CELL AR_MATRIX::GetCell( int aRow, int aCol, int aSide )
{
- int ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
- int marge, via_marge;
- LSET layerMask;
+ MATRIX_CELL* p;
+
+ p = m_BoardSide[aSide];
+ return p[aRow * m_Ncols + aCol];
+}
- // use the default NETCLASS?
- NETCLASSPTR nc = aPcb->GetDesignSettings().GetDefault();
- int trackWidth = nc->GetTrackWidth();
- int clearance = nc->GetClearance();
- int viaSize = nc->GetViaDiameter();
+/* basic cell operation : WRITE operation
+ */
+void AR_MATRIX::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
- marge = clearance + (trackWidth / 2);
- via_marge = clearance + (viaSize / 2);
+ p = m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] = x;
+}
+
+
+/* basic cell operation : OR operation
+ */
+void AR_MATRIX::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] |= x;
+}
+
+
+/* basic cell operation : XOR operation
+ */
+void AR_MATRIX::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] ^= x;
+}
+
+
+/* basic cell operation : AND operation
+ */
+void AR_MATRIX::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] &= x;
+}
+
+
+/* basic cell operation : ADD operation
+ */
+void AR_MATRIX::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+{
+ MATRIX_CELL* p;
+
+ p = m_BoardSide[aSide];
+ p[aRow * m_Ncols + aCol] += x;
+}
+
+
+// fetch distance cell
+AR_MATRIX::DIST_CELL AR_MATRIX::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
+{
+ DIST_CELL* p;
+
+ p = m_DistSide[aSide];
+ return p[aRow * m_Ncols + aCol];
+}
+
+
+// store distance cell
+void AR_MATRIX::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
+{
+ DIST_CELL* p;
+
+ p = m_DistSide[aSide];
+ p[aRow * m_Ncols + aCol] = x;
+}
+
+
+// fetch direction cell
+int AR_MATRIX::GetDir( int aRow, int aCol, int aSide )
+{
+ DIR_CELL* p;
+
+ p = m_DirSide[aSide];
+ return (int) (p[aRow * m_Ncols + aCol]);
+}
+
+
+// store direction cell
+void AR_MATRIX::SetDir( int aRow, int aCol, int aSide, int x )
+{
+ DIR_CELL* p;
- // Place PADS on matrix routing:
- for( unsigned i = 0; i < aPcb->GetPadCount(); ++i )
+ p = m_DirSide[aSide];
+ p[aRow * m_Ncols + aCol] = (char) x;
+}
+
+/* The tables of distances and keep out areas are established on the basis of a
+ * 50 units grid size (the pitch between the cells is 50 units).
+ * The actual distance could be computed by a scaling factor, but this is
+ * not needed, we can use only reduced values
+ */
+
+ /* calculate approximate distance (manhattan distance)
+ */
+int AR_MATRIX::GetApxDist( int r1, int c1, int r2, int c2 )
+{
+ int d1, d2; /* row and column deltas */
+
+ if( ( d1 = r1 - r2 ) < 0 ) /* get absolute row delta */
+ d1 = -d1;
+
+ if( ( d2 = c1 - c2 ) < 0 ) /* get absolute column delta */
+ d2 = -d2;
+
+ return ( d1+d2 ) * 50;
+}
+
+
+/* distance to go thru a cell (en mils) */
+static const int dist[10][10] =
+{ /* OT=Otherside, OR=Origin (source) cell */
+/*..........N, NE, E, SE, S, SW, W, NW, OT, OR */
+/* N */ { 50, 60, 35, 60, 99, 60, 35, 60, 12, 12 },
+/* NE */ { 60, 71, 60, 71, 60, 99, 60, 71, 23, 23 },
+/* E */ { 35, 60, 50, 60, 35, 60, 99, 60, 12, 12 },
+/* SE */ { 60, 71, 60, 71, 60, 71, 60, 99, 23, 23 },
+/* S */ { 99, 60, 35, 60, 50, 60, 35, 60, 12, 12 },
+/* SW */ { 60, 99, 60, 71, 60, 71, 60, 71, 23, 23 },
+/* W */ { 35, 60, 99, 60, 35, 60, 50, 60, 12, 12 },
+/* NW */ { 60, 71, 60, 99, 60, 71, 60, 71, 23, 23 },
+
+/* OT */ { 12, 23, 12, 23, 12, 23, 12, 23, 99, 99 },
+/* OR */ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }
+};
+
+/* penalty for extraneous holes and corners, scaled by sharpness of turn */
+static const int penalty[10][10] =
+{ /* OT=Otherside, OR=Origin (source) cell */
+/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
+/* N */ { 0, 5, 10, 15, 20, 15, 10, 5, 50, 0 },
+/* NE */ { 5, 0, 5, 10, 15, 20, 15, 10, 50, 0 },
+/* E */ { 10, 5, 0, 5, 10, 15, 20, 15, 50, 0 },
+/* SE */ { 15, 10, 5, 0, 5, 10, 15, 20, 50, 0 },
+/* S */ { 20, 15, 10, 5, 0, 5, 10, 15, 50, 0 },
+/* SW */ { 15, 20, 15, 10, 5, 0, 5, 10, 50, 0 },
+/* W */ { 10, 15, 20, 15, 10, 5, 0, 5, 50, 0 },
+/* NW */ { 5, 10, 15, 20, 15, 10, 5, 0, 50, 0 },
+
+/* OT */ { 50, 50, 50, 50, 50, 50, 50, 50, 100, 0 },
+/* OR */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+/* penalty pour directions preferencielles */
+#define PN 20
+static const int dir_penalty_TOP[10][10] =
+{
+/* OT=Otherside, OR=Origin (source) cell */
+/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
+/* N */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* NE */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* E */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* SE */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* S */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* SW */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* W */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* NW */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+
+/* OT */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
+/* OR */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 }
+};
+
+static int dir_penalty_BOTTOM[10][10] =
+{
+/* OT=Otherside, OR=Origin (source) cell */
+/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
+/* N */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* NE */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* E */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* SE */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* S */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* SW */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* W */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* NW */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+
+/* OT */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
+/* OR */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 }
+};
+
+/*
+** x is the direction to enter the cell of interest.
+** y is the direction to exit the cell of interest.
+** z is the direction to really exit the cell, if y=FROM_OTHERSIDE.
+**
+** return the distance of the trace through the cell of interest.
+** the calculation is driven by the tables above.
+*/
+
+
+/* calculate distance (with penalty) of a trace through a cell
+*/
+int AR_MATRIX::CalcDist(int x,int y,int z ,int side )
+{
+ int adjust, ldist;
+
+ adjust = 0; /* set if hole is encountered */
+
+ if( x == CELL_IS_EMPTY )
+ x = 10;
+
+ if( y == CELL_IS_EMPTY )
{
- D_PAD* pad = aPcb->GetPad( i );
+ y = 10;
+ }
+ else if( y == FROM_OTHERSIDE )
+ {
+ if( z == CELL_IS_EMPTY )
+ z = 10;
- if( net_code != pad->GetNetCode() || (flag & FORCE_PADS) )
- {
- ::PlacePad( pad, HOLE, marge, WRITE_CELL );
- }
+ adjust = penalty[x-1][z-1];
+ }
+
+ ldist = dist[x-1][y-1] + penalty[x-1][y-1] + adjust;
+
+ if( m_RouteCount > 1 )
+ {
+ if( side == AR_SIDE_BOTTOM )
+ ldist += dir_penalty_TOP[x-1][y-1];
+
+ if( side == AR_SIDE_TOP )
+ ldist += dir_penalty_BOTTOM[x-1][y-1];
+ }
+
+ return ldist * 10;
+}
+
+#define OP_CELL( layer, dy, dx ) \
+ { \
+ if( layer == UNDEFINED_LAYER ) \
+ { \
+ WriteCell( dy, dx, AR_SIDE_BOTTOM, color ); \
+ if( m_RoutingLayersCount > 1 ) \
+ WriteCell( dy, dx, AR_SIDE_TOP, color ); \
+ } \
+ else \
+ { \
+ if( layer == m_routeLayerBottom ) \
+ WriteCell( dy, dx, AR_SIDE_BOTTOM, color ); \
+ if( m_RoutingLayersCount > 1 ) \
+ if( layer == m_routeLayerTop ) \
+ WriteCell( dy, dx, AR_SIDE_TOP, color ); \
+ } \
+ }
+
+/* Fills all cells inside a segment
+ * half-width = lg, org = ux0,uy0 end = ux1,uy1
+ * coordinates are in PCB units
+ */
+void AR_MATRIX::drawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
+ int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int64_t row, col;
+ int64_t inc;
+ int64_t row_max, col_max, row_min, col_min;
+ int64_t demi_pas;
+
+ int cx, cy, dx, dy;
+
+
+ //printf("segmQcq %d %d %d %d\n", ux0, uy0, ux1, uy1);
+
+ SetCellOperation( op_logic );
+
+ // Make coordinate ux1 tj > ux0 to simplify calculations
+ if( ux1 < ux0 )
+ {
+ std::swap( ux1, ux0 );
+ std::swap( uy1, uy0 );
+ }
+
+ // Calculating the incrementing the Y axis
+ inc = 1;
+
+ if( uy1 < uy0 )
+ inc = -1;
+
+ demi_pas = m_GridRouting / 2;
+
+ col_min = ( ux0 - lg ) / m_GridRouting;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ col_max = ( ux1 + lg + demi_pas ) / m_GridRouting;
+
+ if( col_max > ( m_Ncols - 1 ) )
+ col_max = m_Ncols - 1;
+
+ if( inc > 0 )
+ {
+ row_min = ( uy0 - lg ) / m_GridRouting;
+ row_max = ( uy1 + lg + demi_pas ) / m_GridRouting;
+ }
+ else
+ {
+ row_min = ( uy1 - lg ) / m_GridRouting;
+ row_max = ( uy0 + lg + demi_pas ) / m_GridRouting;
+ }
+
+ if( row_min < 0 )
+ row_min = 0;
+
+ if( row_min > ( m_Nrows - 1 ) )
+ row_min = m_Nrows - 1;
+
+ if( row_max < 0 )
+ row_max = 0;
- ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ if( row_max > ( m_Nrows - 1 ) )
+ row_max = m_Nrows - 1;
+
+ dx = ux1 - ux0;
+ dy = uy1 - uy0;
+
+ double angle;
+ if( dx )
+ {
+ angle = ArcTangente( dy, dx );
}
+ else
+ {
+ angle = 900;
+
+ if( dy < 0 )
+ angle = -900;
+ }
+
+ RotatePoint( &dx, &dy, angle ); // dx = length, dy = 0
- // Place outlines of modules on matrix routing, if they are on a copper layer
- // or on the edge layer
- for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
+ //printf("col_min %d max %d row_min %d max %d\n", col_min, col_max, row_min, row_max);
+
+ for( col = col_min; col <= col_max; col++ )
{
- for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() )
+ int64_t cxr;
+ cxr = ( col * m_GridRouting ) - ux0;
+
+ for( row = row_min; row <= row_max; row++ )
{
- switch( item->Type() )
- {
- case PCB_MODULE_EDGE_T:
+ cy = (row * m_GridRouting) - uy0;
+ cx = cxr;
+ RotatePoint( &cx, &cy, angle );
+
+ if( abs( cy ) > lg )
+ continue; // The point is too far on the Y axis.
+
+ /* This point a test is close to the segment: the position
+ * along the X axis must be tested.
+ */
+ if( ( cx >= 0 ) && ( cx <= dx ) )
{
- EDGE_MODULE* edge = (EDGE_MODULE*) item;
- EDGE_MODULE tmpEdge( *edge );
+ OP_CELL( layer, row, col );
+ continue;
+ }
- if( tmpEdge.GetLayer() == Edge_Cuts )
- tmpEdge.SetLayer( UNDEFINED_LAYER );
+ // Examination of extremities are rounded.
+ if( ( cx < 0 ) && ( cx >= -lg ) )
+ {
+ if( ( ( cx * cx ) + ( cy * cy ) ) <= ( lg * lg ) )
+ OP_CELL( layer, row, col );
- TraceSegmentPcb( &tmpEdge, HOLE, marge, WRITE_CELL );
- TraceSegmentPcb( &tmpEdge, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ continue;
}
- break;
- default:
- break;
+ if( ( cx > dx ) && ( cx <= ( dx + lg ) ) )
+ {
+ if( ( ( ( cx - dx ) * ( cx - dx ) ) + ( cy * cy ) ) <= ( lg * lg ) )
+ OP_CELL( layer, row, col );
+
+ continue;
}
}
}
+}
- // Place board outlines and texts on copper layers:
- for( auto item : aPcb->Drawings() )
+/* Fills all cells of the routing matrix contained in the circle
+ * half-width = lg, center = ux0, uy0, ux1,uy1 is a point on the circle.
+ * coord are in PCB units.
+ */
+void AR_MATRIX::traceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
+ int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int radius, nb_segm;
+ int x0, y0, // Starting point of the current segment trace.
+ x1, y1; // End point.
+ int ii;
+ int angle;
+
+ radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
+
+ x0 = x1 = radius;
+ y0 = y1 = 0;
+
+ if( lg < 1 )
+ lg = 1;
+
+ nb_segm = ( 2 * radius ) / lg;
+
+ if( nb_segm < 5 )
+ nb_segm = 5;
+
+ if( nb_segm > 100 )
+ nb_segm = 100;
+
+ for( ii = 1; ii < nb_segm; ii++ )
{
- switch( item->Type() )
- {
- case PCB_LINE_T:
- {
- DRAWSEGMENT* DrawSegm;
+ angle = (3600 * ii) / nb_segm;
+ x1 = KiROUND( cosdecideg( radius, angle ) );
+ y1 = KiROUND( sindecideg( radius, angle ) );
+ drawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
+ x0 = x1;
+ y0 = y1;
+ }
- int type_cell = HOLE;
- DrawSegm = (DRAWSEGMENT*) item;
- DRAWSEGMENT tmpSegm( DrawSegm );
+ drawSegmentQcq( x1 + ux0, y1 + uy0, ux0 + radius, uy0, lg, layer, color, op_logic );
+}
- if( DrawSegm->GetLayer() == Edge_Cuts )
- {
- tmpSegm.SetLayer( UNDEFINED_LAYER );
- type_cell |= CELL_is_EDGE;
- }
+void AR_MATRIX::traceFilledCircle( int cx, int cy, int radius,
+ LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int row, col;
+ int ux0, uy0, ux1, uy1;
+ int row_max, col_max, row_min, col_min;
+ int trace = 0;
+ double fdistmin, fdistx, fdisty;
+ int tstwrite = 0;
+ int distmin;
- TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
- }
- break;
+ if( aLayerMask[m_routeLayerBottom] )
+ trace = 1; // Trace on BOTTOM
- case PCB_TEXT_T:
- {
- TEXTE_PCB* PtText = (TEXTE_PCB*) item;
+ if( aLayerMask[m_routeLayerTop] )
+ if( m_RoutingLayersCount > 1 )
+ trace |= 2; // Trace on TOP
- if( PtText->GetText().Length() == 0 )
- break;
+ if( trace == 0 )
+ return;
- EDA_RECT textbox = PtText->GetTextBox( -1 );
- ux0 = textbox.GetX();
- uy0 = textbox.GetY();
- dx = textbox.GetWidth();
- dy = textbox.GetHeight();
+ SetCellOperation( op_logic );
- // Put bounding box (rectangle) on matrix
- dx /= 2;
- dy /= 2;
+ cx -= GetBrdCoordOrigin().x;
+ cy -= GetBrdCoordOrigin().y;
- ux1 = ux0 + dx;
- uy1 = uy0 + dy;
+ distmin = radius;
- ux0 -= dx;
- uy0 -= dy;
+ // Calculate the bounding rectangle of the circle.
+ ux0 = cx - radius;
+ uy0 = cy - radius;
+ ux1 = cx + radius;
+ uy1 = cy + radius;
- layerMask = LSET( PtText->GetLayer() );
+ // Calculate limit coordinates of cells belonging to the rectangle.
+ row_max = uy1 / m_GridRouting;
+ col_max = ux1 / m_GridRouting;
+ row_min = uy0 / m_GridRouting; // if (uy0 > row_min*Board.m_GridRouting) row_min++;
+ col_min = ux0 / m_GridRouting; // if (ux0 > col_min*Board.m_GridRouting) col_min++;
- TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
- uy1 + marge, PtText->GetTextAngle(),
- layerMask, HOLE, WRITE_CELL );
+ if( row_min < 0 )
+ row_min = 0;
- TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
- ux1 + via_marge, uy1 + via_marge,
- PtText->GetTextAngle(),
- layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
- }
- break;
+ if( row_max >= (m_Nrows - 1) )
+ row_max = m_Nrows - 1;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ if( col_max >= (m_Ncols - 1) )
+ col_max = m_Ncols - 1;
+
+ // Calculate coordinate limits of cell belonging to the rectangle.
+ if( row_min > row_max )
+ row_max = row_min;
+
+ if( col_min > col_max )
+ col_max = col_min;
+
+ fdistmin = (double) distmin * distmin;
+
+ for( row = row_min; row <= row_max; row++ )
+ {
+ fdisty = (double) ( cy - ( row * m_GridRouting ) );
+ fdisty *= fdisty;
+
+ for( col = col_min; col <= col_max; col++ )
+ {
+ fdistx = (double) ( cx - ( col * m_GridRouting ) );
+ fdistx *= fdistx;
+
+ if( fdistmin <= ( fdistx + fdisty ) )
+ continue;
+
+ if( trace & 1 )
+ WriteCell( row, col, AR_SIDE_BOTTOM, color );
- default:
- break;
+ if( trace & 2 )
+ WriteCell( row, col, AR_SIDE_TOP, color );
+
+ tstwrite = 1;
}
}
- // Put tracks and vias on matrix
- for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
+ if( tstwrite )
+ return;
+
+ /* If no cell has been written, it affects the 4 neighboring diagonal
+ * (Adverse event: pad off grid in the center of the 4 neighboring
+ * diagonal) */
+ distmin = m_GridRouting / 2 + 1;
+ fdistmin = ( (double) distmin * distmin ) * 2; // Distance to center point diagonally
+
+ for( row = row_min; row <= row_max; row++ )
{
- if( net_code == track->GetNetCode() )
- continue;
+ fdisty = (double) ( cy - ( row * m_GridRouting ) );
+ fdisty *= fdisty;
+
+ for( col = col_min; col <= col_max; col++ )
+ {
+ fdistx = (double) ( cx - ( col * m_GridRouting ) );
+ fdistx *= fdistx;
+
+ if( fdistmin <= ( fdistx + fdisty ) )
+ continue;
+
+ if( trace & 1 )
+ WriteCell( row, col, AR_SIDE_BOTTOM, color );
- TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
- TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
+ if( trace & 2 )
+ WriteCell( row, col, AR_SIDE_TOP, color );
+ }
}
}
-int Build_Work( BOARD* Pcb )
+/* Fills all routing matrix cells contained in the arc
+ * angle = ArcAngle, half-width lg
+ * center = ux0,uy0, starting at ux1, uy1. Coordinates are in
+ * PCB units.
+ */
+void AR_MATRIX::traceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
+ LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic )
{
- RATSNEST_ITEM* pt_rats;
- D_PAD* pt_pad;
- int r1, r2, c1, c2, current_net_code;
- RATSNEST_ITEM* pt_ch;
- int demi_pas = RoutingMatrix.m_GridRouting / 2;
- wxString msg;
+ int radius, nb_segm;
+ int x0, y0, // Starting point of the current segment trace
+ x1, y1; // End point
+ int ii;
+ double angle, StAngle;
+
+
+ radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
+
+ x0 = ux1 - ux0;
+ y0 = uy1 - uy0;
+ StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );
+
+ if( lg < 1 )
+ lg = 1;
- InitWork(); // clear work list
- int cellCount = 0;
+ nb_segm = ( 2 * radius ) / lg;
+ nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;
- for( unsigned ii = 0; ii < Pcb->GetRatsnestsCount(); ii++ )
+ if( nb_segm < 5 )
+ nb_segm = 5;
+
+ if( nb_segm > 100 )
+ nb_segm = 100;
+
+ for( ii = 1; ii <= nb_segm; ii++ )
{
- pt_rats = &Pcb->m_FullRatsnest[ii];
+ angle = ( ArcAngle * ii ) / nb_segm;
+ angle += StAngle;
+
+ NORMALIZE_ANGLE_POS( angle );
+
+ x1 = KiROUND( cosdecideg( radius, angle ) );
+ y1 = KiROUND( cosdecideg( radius, angle ) );
+ drawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
+ x0 = x1;
+ y0 = y1;
+ }
+}
+
+
+void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
+ double angle, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int row, col;
+ int cx, cy; // Center of rectangle
+ int radius; // Radius of the circle
+ int row_min, row_max, col_min, col_max;
+ int rotrow, rotcol;
+ int trace = 0;
+
+ if( aLayerMask[m_routeLayerBottom] )
+ trace = 1; // Trace on BOTTOM
+
+ if( aLayerMask[m_routeLayerTop] )
+ {
+ if( m_RoutingLayersCount > 1 )
+ trace |= 2; // Trace on TOP
+ }
+
+ if( trace == 0 )
+ return;
+
+ SetCellOperation( op_logic );
+
+ ux0 -= GetBrdCoordOrigin().x;
+ uy0 -= GetBrdCoordOrigin().y;
+ ux1 -= GetBrdCoordOrigin().x;
+ uy1 -= GetBrdCoordOrigin().y;
+
+ cx = (ux0 + ux1) / 2;
+ cy = (uy0 + uy1) / 2;
+ radius = KiROUND( Distance( ux0, uy0, cx, cy ) );
+
+ // Calculating coordinate limits belonging to the rectangle.
+ row_max = ( cy + radius ) / m_GridRouting;
+ col_max = ( cx + radius ) / m_GridRouting;
+ row_min = ( cy - radius ) / m_GridRouting;
+
+ if( uy0 > row_min * m_GridRouting )
+ row_min++;
+
+ col_min = ( cx - radius ) / m_GridRouting;
+
+ if( ux0 > col_min * m_GridRouting )
+ col_min++;
+
+ if( row_min < 0 )
+ row_min = 0;
+
+ if( row_max >= ( m_Nrows - 1 ) )
+ row_max = m_Nrows - 1;
+
+ if( col_min < 0 )
+ col_min = 0;
+
+ if( col_max >= ( m_Ncols - 1 ) )
+ col_max = m_Ncols - 1;
+
+ for( row = row_min; row <= row_max; row++ )
+ {
+ for( col = col_min; col <= col_max; col++ )
+ {
+ rotrow = row * m_GridRouting;
+ rotcol = col * m_GridRouting;
+ RotatePoint( &rotcol, &rotrow, cx, cy, -angle );
+
+ if( rotrow <= uy0 )
+ continue;
+
+ if( rotrow >= uy1 )
+ continue;
+
+ if( rotcol <= ux0 )
+ continue;
+
+ if( rotcol >= ux1 )
+ continue;
+
+ if( trace & 1 )
+ WriteCell( row, col, AR_SIDE_BOTTOM, color );
+
+ if( trace & 2 )
+ WriteCell( row, col, AR_SIDE_TOP, color );
+ }
+ }
+}
+
+
+void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
+ LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int row, col;
+ int row_min, row_max, col_min, col_max;
+ int trace = 0;
+
+ if( aLayerMask[m_routeLayerBottom] )
+ trace = 1; // Trace on BOTTOM
+
+ if( aLayerMask[m_routeLayerTop] && m_RoutingLayersCount > 1 )
+ trace |= 2; // Trace on TOP
+
+ if( trace == 0 )
+ return;
+
+ SetCellOperation( op_logic );
+
+ ux0 -= GetBrdCoordOrigin().x;
+ uy0 -= GetBrdCoordOrigin().y;
+ ux1 -= GetBrdCoordOrigin().x;
+ uy1 -= GetBrdCoordOrigin().y;
+
+ // Calculating limits coord cells belonging to the rectangle.
+ row_max = uy1 / m_GridRouting;
+ col_max = ux1 / m_GridRouting;
+ row_min = uy0 / m_GridRouting;
- /* We consider here only ratsnest that are active ( obviously not yet routed)
- * and routables (that are not yet attempt to be routed and fail
- */
- if( (pt_rats->m_Status & CH_ACTIF) == 0 )
- continue;
+ if( uy0 > row_min * m_GridRouting )
+ row_min++;
- if( pt_rats->m_Status & CH_UNROUTABLE )
- continue;
+ col_min = ux0 / m_GridRouting;
- if( (pt_rats->m_Status & CH_ROUTE_REQ) == 0 )
- continue;
+ if( ux0 > col_min * m_GridRouting )
+ col_min++;
- pt_pad = pt_rats->m_PadStart;
+ if( row_min < 0 )
+ row_min = 0;
- current_net_code = pt_pad->GetNetCode();
- pt_ch = pt_rats;
+ if( row_max >= ( m_Nrows - 1 ) )
+ row_max = m_Nrows - 1;
- r1 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY() + demi_pas )
- / RoutingMatrix.m_GridRouting;
+ if( col_min < 0 )
+ col_min = 0;
- if( r1 < 0 || r1 >= RoutingMatrix.m_Nrows )
+ if( col_max >= ( m_Ncols - 1 ) )
+ col_max = m_Ncols - 1;
+
+ for( row = row_min; row <= row_max; row++ )
+ {
+ for( col = col_min; col <= col_max; col++ )
{
- msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r1,
- pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
- wxMessageBox( msg );
- return 0;
+ if( trace & 1 )
+ WriteCell( row, col, AR_SIDE_BOTTOM, color );
+
+ if( trace & 2 )
+ WriteCell( row, col, AR_SIDE_TOP, color );
}
+ }
+}
- c1 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas ) / RoutingMatrix.m_GridRouting;
- if( c1 < 0 || c1 >= RoutingMatrix.m_Ncols )
+/* Draws a line, if layer = -1 on all layers
+ */
+void AR_MATRIX::tracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic )
+{
+ int dx, dy, lim;
+ int cumul, inc, il, delta;
+
+ SetCellOperation( op_logic );
+
+ if( x0 == x1 ) // Vertical.
+ {
+ if( y1 < y0 )
+ std::swap( y0, y1 );
+
+ dy = y0 / m_GridRouting;
+ lim = y1 / m_GridRouting;
+ dx = x0 / m_GridRouting;
+
+ // Clipping limits of board.
+ if( ( dx < 0 ) || ( dx >= m_Ncols ) )
+ return;
+
+ if( dy < 0 )
+ dy = 0;
+
+ if( lim >= m_Nrows )
+ lim = m_Nrows - 1;
+
+ for( ; dy <= lim; dy++ )
{
- msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c1,
- pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
- wxMessageBox( msg );
- return 0;
+ OP_CELL( layer, dy, dx );
}
- pt_pad = pt_rats->m_PadEnd;
+ return;
+ }
+
+ if( y0 == y1 ) // Horizontal
+ {
+ if( x1 < x0 )
+ std::swap( x0, x1 );
+
+ dx = x0 / m_GridRouting;
+ lim = x1 / m_GridRouting;
+ dy = y0 / m_GridRouting;
+
+ // Clipping limits of board.
+ if( ( dy < 0 ) || ( dy >= m_Nrows ) )
+ return;
- r2 = ( pt_pad->GetPosition().y - RoutingMatrix.m_BrdBox.GetY()
- + demi_pas ) / RoutingMatrix.m_GridRouting;
+ if( dx < 0 )
+ dx = 0;
- if( r2 < 0 || r2 >= RoutingMatrix.m_Nrows )
+ if( lim >= m_Ncols )
+ lim = m_Ncols - 1;
+
+ for( ; dx <= lim; dx++ )
{
- msg.Printf( wxT( "error : row = %d ( padY %d pcbY %d) " ), r2,
- pt_pad->GetPosition().y, RoutingMatrix.m_BrdBox.GetY() );
- wxMessageBox( msg );
- return 0;
+ OP_CELL( layer, dy, dx );
}
- c2 = ( pt_pad->GetPosition().x - RoutingMatrix.m_BrdBox.GetX() + demi_pas )
- / RoutingMatrix.m_GridRouting;
+ return;
+ }
- if( c2 < 0 || c2 >= RoutingMatrix.m_Ncols )
+ // Here is some perspective: using the algorithm LUCAS.
+ if( abs( x1 - x0 ) >= abs( y1 - y0 ) ) // segment slightly inclined/
+ {
+ if( x1 < x0 )
{
- msg.Printf( wxT( "error : col = %d ( padX %d pcbX %d) " ), c2,
- pt_pad->GetPosition().x, RoutingMatrix.m_BrdBox.GetX() );
- wxMessageBox( msg );
- return 0;
+ std::swap( x1, x0 );
+ std::swap( y1, y0 );
}
- SetWork( r1, c1, current_net_code, r2, c2, pt_ch, 0 );
- cellCount++;
+ dx = x0 / m_GridRouting;
+ lim = x1 / m_GridRouting;
+ dy = y0 / m_GridRouting;
+ inc = 1;
+
+ if( y1 < y0 )
+ inc = -1;
+
+ il = lim - dx; cumul = il / 2;
+ delta = abs( y1 - y0 ) / m_GridRouting;
+
+ for( ; dx <= lim; )
+ {
+ if( ( dx >= 0 ) && ( dy >= 0 ) &&
+ ( dx < m_Ncols ) &&
+ ( dy < m_Nrows ) )
+ {
+ OP_CELL( layer, dy, dx );
+ }
+
+ dx++;
+ cumul += delta;
+
+ if( cumul > il )
+ {
+ cumul -= il;
+ dy += inc;
+ }
+ }
}
+ else
+ {
+ if( y1 < y0 )
+ {
+ std::swap( x1, x0 );
+ std::swap( y1, y0 );
+ }
+
+ dy = y0 / m_GridRouting;
+ lim = y1 / m_GridRouting;
+ dx = x0 / m_GridRouting;
+ inc = 1;
+
+ if( x1 < x0 )
+ inc = -1;
+
+ il = lim - dy;
+ cumul = il / 2;
+ delta = abs( x1 - x0 ) / m_GridRouting;
- SortWork();
- return cellCount;
+ for( ; dy <= lim; )
+ {
+ if( ( dx >= 0 ) && ( dy >= 0 ) && ( dx < m_Ncols ) && ( dy < m_Nrows ) )
+ {
+ OP_CELL( layer, dy, dx );
+ }
+
+ dy++;
+ cumul += delta;
+
+ if( cumul > il )
+ {
+ cumul -= il;
+ dx += inc;
+ }
+ }
+ }
}
-// Initialize m_opWriteCell member to make the aLogicOp
-void MATRIX_ROUTING_HEAD::SetCellOperation( int aLogicOp )
+void AR_MATRIX::TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, AR_MATRIX::CELL_OP op_logic )
{
- switch( aLogicOp )
- {
- default:
- case WRITE_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::SetCell;
- break;
+ int half_width = ( pt_segm->GetWidth() / 2 ) + marge;
- case WRITE_OR_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::OrCell;
- break;
+ // Calculate the bounding rectangle of the segment (if H, V or Via)
+ int ux0 = pt_segm->GetStart().x - GetBrdCoordOrigin().x;
+ int uy0 = pt_segm->GetStart().y - GetBrdCoordOrigin().y;
+ int ux1 = pt_segm->GetEnd().x - GetBrdCoordOrigin().x;
+ int uy1 = pt_segm->GetEnd().y - GetBrdCoordOrigin().y;
- case WRITE_XOR_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::XorCell;
+ //printf("traceSegm %d %d %d %d\n", ux0, uy0, ux1, uy1);
+
+ LAYER_NUM layer = pt_segm->GetLayer();
+
+ //if( color == VIA_IMPOSSIBLE )
+ layer = UNDEFINED_LAYER;
+
+
+ switch( pt_segm->GetShape() )
+ {
+ // The segment is here a straight line or a circle or an arc.:
+ case S_CIRCLE:
+ traceCircle( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
- case WRITE_AND_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::AndCell;
+ case S_ARC:
+ traceArc( ux0, uy0, ux1, uy1, pt_segm->GetAngle(), half_width, layer, color, op_logic );
break;
- case WRITE_ADD_CELL:
- m_opWriteCell = &MATRIX_ROUTING_HEAD::AddCell;
+ // The segment is here a line segment.
+ default:
+ drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
}
}
-
-/* return the value stored in a cell
- */
-MATRIX_CELL MATRIX_ROUTING_HEAD::GetCell( int aRow, int aCol, int aSide )
+void AR_MATRIX::TraceSegmentPcb( TRACK* aTrack, int color, int marge, AR_MATRIX::CELL_OP op_logic )
{
- MATRIX_CELL* p;
+ int half_width = ( aTrack->GetWidth() / 2 ) + marge;
- p = RoutingMatrix.m_BoardSide[aSide];
- return p[aRow * m_Ncols + aCol];
-}
+ // Test if VIA (filled circle need to be drawn)
+ if( aTrack->Type() == PCB_VIA_T )
+ {
+ LSET layer_mask;
+ if( aTrack->IsOnLayer( m_routeLayerBottom ) )
+ layer_mask.set( m_routeLayerBottom );
-/* basic cell operation : WRITE operation
- */
-void MATRIX_ROUTING_HEAD::SetCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
+ if( aTrack->IsOnLayer( m_routeLayerTop ) )
+ {
+ if( !layer_mask.any() )
+ layer_mask = LSET( m_routeLayerTop );
+ else
+ layer_mask.set();
+ }
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] = x;
-}
+ if( color == VIA_IMPOSSIBLE )
+ layer_mask.set();
+ if( layer_mask.any() )
+ traceFilledCircle( aTrack->GetStart().x, aTrack->GetStart().y,
+ half_width, layer_mask, color, op_logic );
+ }
+ else
+ {
+ // Calculate the bounding rectangle of the segment
+ int ux0 = aTrack->GetStart().x - GetBrdCoordOrigin().x;
+ int uy0 = aTrack->GetStart().y - GetBrdCoordOrigin().y;
+ int ux1 = aTrack->GetEnd().x - GetBrdCoordOrigin().x;
+ int uy1 = aTrack->GetEnd().y - GetBrdCoordOrigin().y;
-/* basic cell operation : OR operation
- */
-void MATRIX_ROUTING_HEAD::OrCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
+ // Ordinary track
+ PCB_LAYER_ID layer = aTrack->GetLayer();
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] |= x;
+ if( color == VIA_IMPOSSIBLE )
+ layer = UNDEFINED_LAYER;
+
+ drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
+ }
}
-/* basic cell operation : XOR operation
+
+/**
+ * Function CreateKeepOutRectangle
+ * builds the cost map:
+ * Cells ( in Dist map ) inside the rect x0,y0 a x1,y1 are
+ * incremented by value aKeepOut
+ * Cell outside this rectangle, but inside the rectangle
+ * x0,y0 -marge to x1,y1 + marge are incremented by a decreasing value
+ * (aKeepOut ... 0). The decreasing value depends on the distance to the first rectangle
+ * Therefore the cost is high in rect x0,y0 to x1,y1, and decrease outside this rectangle
*/
-void MATRIX_ROUTING_HEAD::XorCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
+void AR_MATRIX::CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
+ int marge, int aKeepOut, LSET aLayerMask )
{
- MATRIX_CELL* p;
+ int row, col;
+ int row_min, row_max, col_min, col_max, pmarge;
+ int trace = 0;
+ DIST_CELL data, LocalKeepOut;
+ int lgain, cgain;
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] ^= x;
-}
+ if( aLayerMask[m_routeLayerBottom] )
+ trace = 1; // Trace on bottom layer.
+ if( aLayerMask[m_routeLayerTop] && m_RoutingLayersCount )
+ trace |= 2; // Trace on top layer.
-/* basic cell operation : AND operation
- */
-void MATRIX_ROUTING_HEAD::AndCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
+ if( trace == 0 )
+ return;
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] &= x;
-}
+ ux0 -= m_BrdBox.GetX();
+ uy0 -= m_BrdBox.GetY();
+ ux1 -= m_BrdBox.GetX();
+ uy1 -= m_BrdBox.GetY();
+ ux0 -= marge; ux1 += marge;
+ uy0 -= marge; uy1 += marge;
-/* basic cell operation : ADD operation
- */
-void MATRIX_ROUTING_HEAD::AddCell( int aRow, int aCol, int aSide, MATRIX_CELL x )
-{
- MATRIX_CELL* p;
+ pmarge = marge / m_GridRouting;
- p = RoutingMatrix.m_BoardSide[aSide];
- p[aRow * m_Ncols + aCol] += x;
-}
+ if( pmarge < 1 )
+ pmarge = 1;
+ // Calculate the coordinate limits of the rectangle.
+ row_max = uy1 / m_GridRouting;
+ col_max = ux1 / m_GridRouting;
+ row_min = uy0 / m_GridRouting;
-// fetch distance cell
-DIST_CELL MATRIX_ROUTING_HEAD::GetDist( int aRow, int aCol, int aSide ) // fetch distance cell
-{
- DIST_CELL* p;
+ if( uy0 > row_min * m_GridRouting )
+ row_min++;
- p = RoutingMatrix.m_DistSide[aSide];
- return p[aRow * m_Ncols + aCol];
-}
+ col_min = ux0 / m_GridRouting;
+ if( ux0 > col_min * m_GridRouting )
+ col_min++;
-// store distance cell
-void MATRIX_ROUTING_HEAD::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
-{
- DIST_CELL* p;
+ if( row_min < 0 )
+ row_min = 0;
- p = RoutingMatrix.m_DistSide[aSide];
- p[aRow * m_Ncols + aCol] = x;
-}
+ if( row_max >= (m_Nrows - 1) )
+ row_max = m_Nrows - 1;
+ if( col_min < 0 )
+ col_min = 0;
-// fetch direction cell
-int MATRIX_ROUTING_HEAD::GetDir( int aRow, int aCol, int aSide )
-{
- DIR_CELL* p;
+ if( col_max >= (m_Ncols - 1) )
+ col_max = m_Ncols - 1;
- p = RoutingMatrix.m_DirSide[aSide];
- return (int) (p[aRow * m_Ncols + aCol]);
-}
+ for( row = row_min; row <= row_max; row++ )
+ {
+ lgain = 256;
+ if( row < pmarge )
+ lgain = ( 256 * row ) / pmarge;
+ else if( row > row_max - pmarge )
+ lgain = ( 256 * ( row_max - row ) ) / pmarge;
-// store direction cell
-void MATRIX_ROUTING_HEAD::SetDir( int aRow, int aCol, int aSide, int x )
+ for( col = col_min; col <= col_max; col++ )
+ {
+ // RoutingMatrix Dist map containt the "cost" of the cell
+ // at position (row, col)
+ // in autoplace this is the cost of the cell, when
+ // a footprint overlaps it, near a "master" footprint
+ // this cost is hight near the "master" footprint
+ // and decrease with the distance
+ cgain = 256;
+ LocalKeepOut = aKeepOut;
+
+ if( col < pmarge )
+ cgain = ( 256 * col ) / pmarge;
+ else if( col > col_max - pmarge )
+ cgain = ( 256 * ( col_max - col ) ) / pmarge;
+
+ cgain = ( cgain * lgain ) / 256;
+
+ if( cgain != 256 )
+ LocalKeepOut = ( LocalKeepOut * cgain ) / 256;
+
+ if( trace & 1 )
+ {
+ data = GetDist( row, col, AR_SIDE_BOTTOM ) + LocalKeepOut;
+ SetDist( row, col, AR_SIDE_BOTTOM, data );
+ }
+
+ if( trace & 2 )
+ {
+ data = GetDist( row, col, AR_SIDE_TOP );
+ data = std::max( data, LocalKeepOut );
+ SetDist( row, col, AR_SIDE_TOP, data );
+ }
+ }
+ }
+}
+
+void AR_MATRIX::PlacePad( D_PAD* aPad, int color, int marge, AR_MATRIX::CELL_OP op_logic )
{
- DIR_CELL* p;
+ int dx, dy;
+ wxPoint shape_pos = aPad->ShapePos();
- p = RoutingMatrix.m_DirSide[aSide];
- p[aRow * m_Ncols + aCol] = (char) x;
+ dx = aPad->GetSize().x / 2;
+ dx += marge;
+
+ if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
+ {
+ traceFilledCircle( shape_pos.x, shape_pos.y, dx,
+ aPad->GetLayerSet(), color, op_logic );
+ return;
+ }
+
+ dy = aPad->GetSize().y / 2;
+ dy += marge;
+
+ if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID )
+ {
+ dx += abs( aPad->GetDelta().y ) / 2;
+ dy += abs( aPad->GetDelta().x ) / 2;
+ }
+
+ // The pad is a rectangle ( horizontal or vertical )
+ if( int( aPad->GetOrientation() ) % 900 == 0 )
+ {
+ // Orientation turned 90 deg.
+ if( aPad->GetOrientation() == 900 || aPad->GetOrientation() == 2700 )
+ {
+ std::swap( dx, dy );
+ }
+
+ TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy,
+ shape_pos.x + dx, shape_pos.y + dy,
+ aPad->GetLayerSet(), color, op_logic );
+ }
+ else
+ {
+ TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy,
+ shape_pos.x + dx, shape_pos.y + dy,
+ aPad->GetOrientation(),
+ aPad->GetLayerSet(), color, op_logic );
+ }
}
diff --git a/pcbnew/autorouter/ar_matrix.h b/pcbnew/autorouter/ar_matrix.h
new file mode 100644
index 0000000..c453fa3
--- /dev/null
+++ b/pcbnew/autorouter/ar_matrix.h
@@ -0,0 +1,178 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@xxxxxxxxxxxxxxx
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2011 Wayne Stambaugh <stambaughw@xxxxxxxxxxx>
+ *
+ * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 __AR_MATRIX_H
+#define __AR_MATRIX_H
+
+#include <eda_rect.h>
+#include <layers_id_colors_and_visibility.h>
+
+class DRAWSEGMENT;
+class TRACK;
+class D_PAD;
+class MODULE;
+
+#define AR_MAX_ROUTING_LAYERS_COUNT 2
+
+#define AR_SIDE_TOP 0
+#define AR_SIDE_BOTTOM 1
+
+/**
+ * class AR_MATRIX
+ * handle the matrix routing that describes the actual board
+ */
+class AR_MATRIX
+{
+public:
+ typedef unsigned char MATRIX_CELL;
+ typedef int DIST_CELL;
+ typedef char DIR_CELL;
+
+ MATRIX_CELL* m_BoardSide[AR_MAX_ROUTING_LAYERS_COUNT]; // the image map of 2 board sides
+ DIST_CELL* m_DistSide[AR_MAX_ROUTING_LAYERS_COUNT]; // the image map of 2 board sides:
+ // distance to cells
+ DIR_CELL* m_DirSide[AR_MAX_ROUTING_LAYERS_COUNT]; // the image map of 2 board sides:
+ // pointers back to source
+ bool m_InitMatrixDone;
+ int m_RoutingLayersCount; // Number of layers for autorouting (0 or 1)
+ int m_GridRouting; // Size of grid for autoplace/autoroute
+ EDA_RECT m_BrdBox; // Actual board bounding box
+ int m_Nrows, m_Ncols; // Matrix size
+ int m_MemSize; // Memory requirement, just for statistics
+ int m_RouteCount; // Number of routes
+
+ PCB_LAYER_ID m_routeLayerTop;
+ PCB_LAYER_ID m_routeLayerBottom;
+
+
+private:
+ // a pointer to the current selected cell operation
+ void (AR_MATRIX::* m_opWriteCell)( int aRow, int aCol,
+ int aSide, MATRIX_CELL aCell);
+
+public:
+
+ enum CELL_OP
+ {
+ WRITE_CELL = 0,
+ WRITE_OR_CELL = 1,
+ WRITE_XOR_CELL = 2,
+ WRITE_AND_CELL = 3,
+ WRITE_ADD_CELL = 4
+ };
+
+ AR_MATRIX();
+ ~AR_MATRIX();
+
+ void WriteCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell)
+ {
+ (*this.*m_opWriteCell)( aRow, aCol, aSide, aCell );
+ }
+
+ /**
+ * function GetBrdCoordOrigin
+ * @return the board coordinate corresponding to the
+ * routing matrix origin ( board coordinate offset )
+ */
+ wxPoint GetBrdCoordOrigin()
+ {
+ return m_BrdBox.GetOrigin();
+ }
+
+ /**
+ * Function ComputeMatrixSize
+ * calculates the number of rows and columns of dimensions of \a aPcb for routing and
+ * automatic calculation of area.
+ * @param aPcb = the physical board
+ * @param aUseBoardEdgesOnly = true to use board edges only,
+ * = false to use the full board bounding box (default)
+ */
+ bool ComputeMatrixSize( const EDA_RECT& aBoundingBox );
+
+ /**
+ * Function InitBoard
+ * initializes the data structures.
+ *
+ * @return the amount of memory used or -1 if default.
+ */
+ int InitRoutingMatrix();
+
+ void UnInitRoutingMatrix();
+
+ // Initialize WriteCell to make the aLogicOp
+ void SetCellOperation( CELL_OP aLogicOp );
+
+ // functions to read/write one cell ( point on grid routing matrix:
+ MATRIX_CELL GetCell( int aRow, int aCol, int aSide);
+ void SetCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell);
+ void OrCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell);
+ void XorCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell);
+ void AndCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell);
+ void AddCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell);
+ DIST_CELL GetDist( int aRow, int aCol, int aSide );
+ void SetDist( int aRow, int aCol, int aSide, DIST_CELL );
+ int GetDir( int aRow, int aCol, int aSide );
+ void SetDir( int aRow, int aCol, int aSide, int aDir);
+
+ // calculate distance (with penalty) of a trace through a cell
+ int CalcDist(int x,int y,int z ,int side );
+
+ // calculate approximate distance (manhattan distance)
+ int GetApxDist( int r1, int c1, int r2, int c2 );
+
+
+ void TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, AR_MATRIX::CELL_OP op_logic );
+ void TraceSegmentPcb( TRACK* aTrack, int color, int marge, AR_MATRIX::CELL_OP op_logic );
+ void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1,
+ int marge, int aKeepOut, LSET aLayerMask );
+ void PlacePad( D_PAD* aPad, int color, int marge, AR_MATRIX::CELL_OP op_logic );
+ void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
+ double angle, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic );
+ void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
+ LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic );
+
+private:
+
+ void drawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
+ int color, CELL_OP op_logic );
+
+ void traceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
+ int color, AR_MATRIX::CELL_OP op_logic );
+ void traceFilledCircle( int cx, int cy, int radius,
+ LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic );
+ void traceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
+ LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic );
+
+
+ void tracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic );
+
+
+
+};
+
+#endif
diff --git a/pcbnew/autorouter/autoplacer_tool.cpp b/pcbnew/autorouter/autoplacer_tool.cpp
new file mode 100644
index 0000000..480d45b
--- /dev/null
+++ b/pcbnew/autorouter/autoplacer_tool.cpp
@@ -0,0 +1,126 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Kicad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 <gal/graphics_abstraction_layer.h>
+#include <class_draw_panel_gal.h>
+#include <view/view_controls.h>
+#include <view/view.h>
+#include <tool/tool_manager.h>
+#include <board_commit.h>
+#include <confirm.h>
+#include <preview_items/two_point_geom_manager.h>
+#include <preview_items/centreline_rect_item.h>
+
+// For frame ToolID values
+#include <pcbnew_id.h>
+
+// For action icons
+#include <bitmaps.h>
+
+#include <class_board_item.h>
+#include <class_module.h>
+#include <tools/pcb_actions.h>
+#include <tools/selection_tool.h>
+#include <tools/tool_event_utils.h>
+
+#include <widgets/progress_reporter.h>
+
+#include "autoplacer_tool.h"
+#include "ar_autoplacer.h"
+
+
+TOOL_ACTION PCB_ACTIONS::autoplaceSelectedComponents(
+ "pcbnew.Autoplacer.autoplaceSelected",
+ AS_GLOBAL, 0,
+ _( "Auto-place selected components" ), _( "Performs automatic placement of selected components" )
+ );
+
+TOOL_ACTION PCB_ACTIONS::autoplaceOffboardComponents(
+ "pcbnew.Autoplacer.autoplaceOffboard",
+ AS_GLOBAL, 0,
+ _( "Auto-place off-board components" ), _( "Performs automatic placement of components outside board area" )
+ );
+
+AUTOPLACE_TOOL::AUTOPLACE_TOOL() :
+ PCB_TOOL( "pcbnew.Autoplacer" )
+{
+}
+
+
+AUTOPLACE_TOOL::~AUTOPLACE_TOOL()
+{}
+
+int AUTOPLACE_TOOL::autoplace( std::vector<MODULE*>& aModules, bool aPlaceOffboard )
+{
+ auto overlay = view()->MakeOverlay();
+
+ Activate();
+
+ AR_AUTOPLACER autoplacer( board() );
+
+ BOARD_COMMIT commit( frame() );
+
+ autoplacer.SetOverlay( overlay );
+
+ std::unique_ptr<WX_PROGRESS_REPORTER> progressReporter(
+ new WX_PROGRESS_REPORTER( frame(), _( "Autoplace Components" ), 1 )
+ );
+
+ autoplacer.SetProgressReporter( progressReporter.get() );
+ auto result = autoplacer.AutoplaceModules( aModules, &commit, aPlaceOffboard );
+
+ if( result == AR_COMPLETED )
+ commit.Push( _("Autoplace components") );
+ else
+ commit.Revert();
+
+ return 0;
+}
+
+int AUTOPLACE_TOOL::autoplaceSelected( const TOOL_EVENT& aEvent )
+{
+ std::vector<MODULE*> mods;
+
+ for ( auto item : selection() )
+ {
+ if ( item->Type() == PCB_MODULE_T )
+ mods.push_back( static_cast<MODULE*>( item ) );
+ }
+
+ return autoplace( mods, false );
+}
+
+int AUTOPLACE_TOOL::autoplaceOffboard( const TOOL_EVENT& aEvent )
+{
+ std::vector<MODULE*> mods;
+
+ return autoplace( mods, true );
+}
+
+
+void AUTOPLACE_TOOL::setTransitions()
+{
+ Go( &AUTOPLACE_TOOL::autoplaceSelected, PCB_ACTIONS::autoplaceSelectedComponents.MakeEvent() );
+ Go( &AUTOPLACE_TOOL::autoplaceOffboard, PCB_ACTIONS::autoplaceOffboardComponents.MakeEvent() );
+}
diff --git a/pcbnew/autorouter/autoplacer_tool.h b/pcbnew/autorouter/autoplacer_tool.h
new file mode 100644
index 0000000..57eee27
--- /dev/null
+++ b/pcbnew/autorouter/autoplacer_tool.h
@@ -0,0 +1,52 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Kicad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 TOOLS_AUTOPLACE_TOOL_H
+#define TOOLS_AUTOPLACE_TOOL_H
+
+#include <tools/pcb_tool.h>
+
+#
+/**
+ * Class AUTOPLACE_TOOL
+ *
+ * Tool responsible for automagic placement of components.
+ */
+class AUTOPLACE_TOOL : public PCB_TOOL
+{
+public:
+ AUTOPLACE_TOOL();
+ ~AUTOPLACE_TOOL();
+
+ ///> Bind handlers to corresponding TOOL_ACTIONs
+ void setTransitions() override;
+
+private:
+ int autoplace( std::vector<MODULE*>& aModules, bool aPlaceOffboard );
+
+ int autoplaceSelected( const TOOL_EVENT& aEvent );
+ int autoplaceOffboard( const TOOL_EVENT& aEvent );
+};
+
+
+#endif // TOOLS_AUTOPLACE_TOOL_H
diff --git a/pcbnew/autorouter/graphpcb.cpp b/pcbnew/autorouter/graphpcb.cpp
index 119eed1..819f787 100644
--- a/pcbnew/autorouter/graphpcb.cpp
+++ b/pcbnew/autorouter/graphpcb.cpp
@@ -40,51 +40,32 @@
#include <class_drawsegment.h>
#include <pcbnew.h>
+#include <class_undoredo_container.h>
#include <autorout.h>
#include <cell.h>
-void TracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color );
-
-void TraceArc( int ux0, int uy0,
- int ux1, int uy1,
- double ArcAngle,
- int lg, LAYER_NUM layer, int color,
- int op_logic );
-
-
-static void DrawSegmentQcq( int ux0, int uy0,
- int ux1, int uy1,
- int lg, LAYER_NUM layer, int color,
- int op_logic );
-
-static void TraceFilledCircle( int cx, int cy, int radius,
- LSET aLayerMask,
- int color,
- int op_logic );
-
-static void TraceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
- int color, int op_logic );
+#include <class_undoredo_container.h>
// Macro call to update cell.
#define OP_CELL( layer, dy, dx ) \
{ \
if( layer == UNDEFINED_LAYER ) \
{ \
- RoutingMatrix.WriteCell( dy, dx, BOTTOM, color ); \
- if( RoutingMatrix.m_RoutingLayersCount > 1 ) \
- RoutingMatrix.WriteCell( dy, dx, TOP, color ); \
+ m_routingMatrix.WriteCell( dy, dx, BOTTOM, color ); \
+ if( m_routingMatrix.m_RoutingLayersCount > 1 ) \
+ m_routingMatrix.WriteCell( dy, dx, TOP, color ); \
} \
else \
{ \
if( layer == g_Route_Layer_BOTTOM ) \
- RoutingMatrix.WriteCell( dy, dx, BOTTOM, color ); \
- if( RoutingMatrix.m_RoutingLayersCount > 1 ) \
+ m_routingMatrix.WriteCell( dy, dx, BOTTOM, color ); \
+ if( m_routingMatrix.m_RoutingLayersCount > 1 ) \
if( layer == g_Route_Layer_TOP ) \
- RoutingMatrix.WriteCell( dy, dx, TOP, color ); \
+ m_routingMatrix.WriteCell( dy, dx, TOP, color ); \
} \
}
-void PlacePad( D_PAD* aPad, int color, int marge, int op_logic )
+void AUTOROUTER::PlacePad( D_PAD* aPad, int color, int marge, int op_logic )
{
int dx, dy;
wxPoint shape_pos = aPad->ShapePos();
@@ -131,138 +112,16 @@ void PlacePad( D_PAD* aPad, int color, int marge, int op_logic )
}
-/* Set to color the cells included in the circle
- * Parameters:
- * center: cx, cy.
- * radius: a value add to the radius or half the score pad
- * aLayerMask: layer occupied
- * color: mask write in cells
- * op_logic: type of writing in the cell (WRITE, OR)
- */
-void TraceFilledCircle( int cx, int cy, int radius,
- LSET aLayerMask, int color, int op_logic )
-{
- int row, col;
- int ux0, uy0, ux1, uy1;
- int row_max, col_max, row_min, col_min;
- int trace = 0;
- double fdistmin, fdistx, fdisty;
- int tstwrite = 0;
- int distmin;
-
- if( aLayerMask[g_Route_Layer_BOTTOM] )
- trace = 1; // Trace on BOTTOM
-
- if( aLayerMask[g_Route_Layer_TOP] )
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
- trace |= 2; // Trace on TOP
-
- if( trace == 0 )
- return;
-
- RoutingMatrix.SetCellOperation( op_logic );
-
- cx -= RoutingMatrix.GetBrdCoordOrigin().x;
- cy -= RoutingMatrix.GetBrdCoordOrigin().y;
-
- distmin = radius;
-
- // Calculate the bounding rectangle of the circle.
- ux0 = cx - radius;
- uy0 = cy - radius;
- ux1 = cx + radius;
- uy1 = cy + radius;
-
- // Calculate limit coordinates of cells belonging to the rectangle.
- row_max = uy1 / RoutingMatrix.m_GridRouting;
- col_max = ux1 / RoutingMatrix.m_GridRouting;
- row_min = uy0 / RoutingMatrix.m_GridRouting; // if (uy0 > row_min*Board.m_GridRouting) row_min++;
- col_min = ux0 / RoutingMatrix.m_GridRouting; // if (ux0 > col_min*Board.m_GridRouting) col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= (RoutingMatrix.m_Nrows - 1) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= (RoutingMatrix.m_Ncols - 1) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- // Calculate coordinate limits of cell belonging to the rectangle.
- if( row_min > row_max )
- row_max = row_min;
-
- if( col_min > col_max )
- col_max = col_min;
-
- fdistmin = (double) distmin * distmin;
-
- for( row = row_min; row <= row_max; row++ )
- {
- fdisty = (double) ( cy - ( row * RoutingMatrix.m_GridRouting ) );
- fdisty *= fdisty;
-
- for( col = col_min; col <= col_max; col++ )
- {
- fdistx = (double) ( cx - ( col * RoutingMatrix.m_GridRouting ) );
- fdistx *= fdistx;
-
- if( fdistmin <= ( fdistx + fdisty ) )
- continue;
-
- if( trace & 1 )
- RoutingMatrix.WriteCell( row, col, BOTTOM, color );
-
- if( trace & 2 )
- RoutingMatrix.WriteCell( row, col, TOP, color );
-
- tstwrite = 1;
- }
- }
-
- if( tstwrite )
- return;
-
- /* If no cell has been written, it affects the 4 neighboring diagonal
- * (Adverse event: pad off grid in the center of the 4 neighboring
- * diagonal) */
- distmin = RoutingMatrix.m_GridRouting / 2 + 1;
- fdistmin = ( (double) distmin * distmin ) * 2; // Distance to center point diagonally
-
- for( row = row_min; row <= row_max; row++ )
- {
- fdisty = (double) ( cy - ( row * RoutingMatrix.m_GridRouting ) );
- fdisty *= fdisty;
-
- for( col = col_min; col <= col_max; col++ )
- {
- fdistx = (double) ( cx - ( col * RoutingMatrix.m_GridRouting ) );
- fdistx *= fdistx;
-
- if( fdistmin <= ( fdistx + fdisty ) )
- continue;
-
- if( trace & 1 )
- RoutingMatrix.WriteCell( row, col, BOTTOM, color );
-
- if( trace & 2 )
- RoutingMatrix.WriteCell( row, col, TOP, color );
- }
- }
-}
-void TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, int op_logic )
+void AUTOROUTER::TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, int op_logic )
{
int half_width = ( pt_segm->GetWidth() / 2 ) + marge;
// Calculate the bounding rectangle of the segment (if H, V or Via)
- int ux0 = pt_segm->GetStart().x - RoutingMatrix.GetBrdCoordOrigin().x;
- int uy0 = pt_segm->GetStart().y - RoutingMatrix.GetBrdCoordOrigin().y;
- int ux1 = pt_segm->GetEnd().x - RoutingMatrix.GetBrdCoordOrigin().x;
- int uy1 = pt_segm->GetEnd().y - RoutingMatrix.GetBrdCoordOrigin().y;
+ int ux0 = pt_segm->GetStart().x - m_routingMatrix.GetBrdCoordOrigin().x;
+ int uy0 = pt_segm->GetStart().y - m_routingMatrix.GetBrdCoordOrigin().y;
+ int ux1 = pt_segm->GetEnd().x - m_routingMatrix.GetBrdCoordOrigin().x;
+ int uy1 = pt_segm->GetEnd().y - m_routingMatrix.GetBrdCoordOrigin().y;
LAYER_NUM layer = pt_segm->GetLayer();
@@ -287,7 +146,7 @@ void TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, int op_logic )
}
}
-void TraceSegmentPcb( TRACK* aTrack, int color, int marge, int op_logic )
+void AUTOROUTER::TraceSegmentPcb( TRACK* aTrack, int color, int marge, int op_logic )
{
int half_width = ( aTrack->GetWidth() / 2 ) + marge;
@@ -317,13 +176,13 @@ void TraceSegmentPcb( TRACK* aTrack, int color, int marge, int op_logic )
else
{
// Calculate the bounding rectangle of the segment
- int ux0 = aTrack->GetStart().x - RoutingMatrix.GetBrdCoordOrigin().x;
- int uy0 = aTrack->GetStart().y - RoutingMatrix.GetBrdCoordOrigin().y;
- int ux1 = aTrack->GetEnd().x - RoutingMatrix.GetBrdCoordOrigin().x;
- int uy1 = aTrack->GetEnd().y - RoutingMatrix.GetBrdCoordOrigin().y;
+ int ux0 = aTrack->GetStart().x - m_routingMatrix.GetBrdCoordOrigin().x;
+ int uy0 = aTrack->GetStart().y - m_routingMatrix.GetBrdCoordOrigin().y;
+ int ux1 = aTrack->GetEnd().x - m_routingMatrix.GetBrdCoordOrigin().x;
+ int uy1 = aTrack->GetEnd().y - m_routingMatrix.GetBrdCoordOrigin().y;
// Ordinary track
- PCB_LAYER_ID layer = aTrack->GetLayer();
+ LAYER_ID layer = aTrack->GetLayer();
if( color == VIA_IMPOSSIBLE )
layer = UNDEFINED_LAYER;
@@ -333,511 +192,3 @@ void TraceSegmentPcb( TRACK* aTrack, int color, int marge, int op_logic )
}
-/* Draws a line, if layer = -1 on all layers
- */
-void TracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color, int op_logic )
-{
- int dx, dy, lim;
- int cumul, inc, il, delta;
-
- RoutingMatrix.SetCellOperation( op_logic );
-
- if( x0 == x1 ) // Vertical.
- {
- if( y1 < y0 )
- std::swap( y0, y1 );
-
- dy = y0 / RoutingMatrix.m_GridRouting;
- lim = y1 / RoutingMatrix.m_GridRouting;
- dx = x0 / RoutingMatrix.m_GridRouting;
-
- // Clipping limits of board.
- if( ( dx < 0 ) || ( dx >= RoutingMatrix.m_Ncols ) )
- return;
-
- if( dy < 0 )
- dy = 0;
-
- if( lim >= RoutingMatrix.m_Nrows )
- lim = RoutingMatrix.m_Nrows - 1;
-
- for( ; dy <= lim; dy++ )
- {
- OP_CELL( layer, dy, dx );
- }
-
- return;
- }
-
- if( y0 == y1 ) // Horizontal
- {
- if( x1 < x0 )
- std::swap( x0, x1 );
-
- dx = x0 / RoutingMatrix.m_GridRouting;
- lim = x1 / RoutingMatrix.m_GridRouting;
- dy = y0 / RoutingMatrix.m_GridRouting;
-
- // Clipping limits of board.
- if( ( dy < 0 ) || ( dy >= RoutingMatrix.m_Nrows ) )
- return;
-
- if( dx < 0 )
- dx = 0;
-
- if( lim >= RoutingMatrix.m_Ncols )
- lim = RoutingMatrix.m_Ncols - 1;
-
- for( ; dx <= lim; dx++ )
- {
- OP_CELL( layer, dy, dx );
- }
-
- return;
- }
-
- // Here is some perspective: using the algorithm LUCAS.
- if( abs( x1 - x0 ) >= abs( y1 - y0 ) ) // segment slightly inclined/
- {
- if( x1 < x0 )
- {
- std::swap( x1, x0 );
- std::swap( y1, y0 );
- }
-
- dx = x0 / RoutingMatrix.m_GridRouting;
- lim = x1 / RoutingMatrix.m_GridRouting;
- dy = y0 / RoutingMatrix.m_GridRouting;
- inc = 1;
-
- if( y1 < y0 )
- inc = -1;
-
- il = lim - dx; cumul = il / 2;
- delta = abs( y1 - y0 ) / RoutingMatrix.m_GridRouting;
-
- for( ; dx <= lim; )
- {
- if( ( dx >= 0 ) && ( dy >= 0 ) &&
- ( dx < RoutingMatrix.m_Ncols ) &&
- ( dy < RoutingMatrix.m_Nrows ) )
- {
- OP_CELL( layer, dy, dx );
- }
-
- dx++;
- cumul += delta;
-
- if( cumul > il )
- {
- cumul -= il;
- dy += inc;
- }
- }
- }
- else
- {
- if( y1 < y0 )
- {
- std::swap( x1, x0 );
- std::swap( y1, y0 );
- }
-
- dy = y0 / RoutingMatrix.m_GridRouting;
- lim = y1 / RoutingMatrix.m_GridRouting;
- dx = x0 / RoutingMatrix.m_GridRouting;
- inc = 1;
-
- if( x1 < x0 )
- inc = -1;
-
- il = lim - dy;
- cumul = il / 2;
- delta = abs( x1 - x0 ) / RoutingMatrix.m_GridRouting;
-
- for( ; dy <= lim; )
- {
- if( ( dx >= 0 ) && ( dy >= 0 ) && ( dx < RoutingMatrix.m_Ncols ) && ( dy < RoutingMatrix.m_Nrows ) )
- {
- OP_CELL( layer, dy, dx );
- }
-
- dy++;
- cumul += delta;
-
- if( cumul > il )
- {
- cumul -= il;
- dx += inc;
- }
- }
- }
-}
-
-
-void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
- LSET aLayerMask, int color, int op_logic )
-{
- int row, col;
- int row_min, row_max, col_min, col_max;
- int trace = 0;
-
- if( aLayerMask[g_Route_Layer_BOTTOM] )
- trace = 1; // Trace on BOTTOM
-
- if( aLayerMask[g_Route_Layer_TOP] && RoutingMatrix.m_RoutingLayersCount > 1 )
- trace |= 2; // Trace on TOP
-
- if( trace == 0 )
- return;
-
- RoutingMatrix.SetCellOperation( op_logic );
-
- ux0 -= RoutingMatrix.GetBrdCoordOrigin().x;
- uy0 -= RoutingMatrix.GetBrdCoordOrigin().y;
- ux1 -= RoutingMatrix.GetBrdCoordOrigin().x;
- uy1 -= RoutingMatrix.GetBrdCoordOrigin().y;
-
- // Calculating limits coord cells belonging to the rectangle.
- row_max = uy1 / RoutingMatrix.m_GridRouting;
- col_max = ux1 / RoutingMatrix.m_GridRouting;
- row_min = uy0 / RoutingMatrix.m_GridRouting;
-
- if( uy0 > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- col_min = ux0 / RoutingMatrix.m_GridRouting;
-
- if( ux0 > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( row = row_min; row <= row_max; row++ )
- {
- for( col = col_min; col <= col_max; col++ )
- {
- if( trace & 1 )
- RoutingMatrix.WriteCell( row, col, BOTTOM, color );
-
- if( trace & 2 )
- RoutingMatrix.WriteCell( row, col, TOP, color );
- }
- }
-}
-
-
-void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
- double angle, LSET aLayerMask, int color, int op_logic )
-{
- int row, col;
- int cx, cy; // Center of rectangle
- int radius; // Radius of the circle
- int row_min, row_max, col_min, col_max;
- int rotrow, rotcol;
- int trace = 0;
-
- if( aLayerMask[g_Route_Layer_BOTTOM] )
- trace = 1; // Trace on BOTTOM
-
- if( aLayerMask[g_Route_Layer_TOP] )
- {
- if( RoutingMatrix.m_RoutingLayersCount > 1 )
- trace |= 2; // Trace on TOP
- }
-
- if( trace == 0 )
- return;
-
- RoutingMatrix.SetCellOperation( op_logic );
-
- ux0 -= RoutingMatrix.GetBrdCoordOrigin().x;
- uy0 -= RoutingMatrix.GetBrdCoordOrigin().y;
- ux1 -= RoutingMatrix.GetBrdCoordOrigin().x;
- uy1 -= RoutingMatrix.GetBrdCoordOrigin().y;
-
- cx = (ux0 + ux1) / 2;
- cy = (uy0 + uy1) / 2;
- radius = KiROUND( Distance( ux0, uy0, cx, cy ) );
-
- // Calculating coordinate limits belonging to the rectangle.
- row_max = ( cy + radius ) / RoutingMatrix.m_GridRouting;
- col_max = ( cx + radius ) / RoutingMatrix.m_GridRouting;
- row_min = ( cy - radius ) / RoutingMatrix.m_GridRouting;
-
- if( uy0 > row_min * RoutingMatrix.m_GridRouting )
- row_min++;
-
- col_min = ( cx - radius ) / RoutingMatrix.m_GridRouting;
-
- if( ux0 > col_min * RoutingMatrix.m_GridRouting )
- col_min++;
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- if( col_min < 0 )
- col_min = 0;
-
- if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- for( row = row_min; row <= row_max; row++ )
- {
- for( col = col_min; col <= col_max; col++ )
- {
- rotrow = row * RoutingMatrix.m_GridRouting;
- rotcol = col * RoutingMatrix.m_GridRouting;
- RotatePoint( &rotcol, &rotrow, cx, cy, -angle );
-
- if( rotrow <= uy0 )
- continue;
-
- if( rotrow >= uy1 )
- continue;
-
- if( rotcol <= ux0 )
- continue;
-
- if( rotcol >= ux1 )
- continue;
-
- if( trace & 1 )
- RoutingMatrix.WriteCell( row, col, BOTTOM, color );
-
- if( trace & 2 )
- RoutingMatrix.WriteCell( row, col, TOP, color );
- }
- }
-}
-
-
-/* Fills all cells inside a segment
- * half-width = lg, org = ux0,uy0 end = ux1,uy1
- * coordinates are in PCB units
- */
-void DrawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
- int color, int op_logic )
-{
- int row, col;
- int inc;
- int row_max, col_max, row_min, col_min;
- int demi_pas;
-
- int cx, cy, dx, dy;
-
- RoutingMatrix.SetCellOperation( op_logic );
-
- // Make coordinate ux1 tj > ux0 to simplify calculations
- if( ux1 < ux0 )
- {
- std::swap( ux1, ux0 );
- std::swap( uy1, uy0 );
- }
-
- // Calculating the incrementing the Y axis
- inc = 1;
-
- if( uy1 < uy0 )
- inc = -1;
-
- demi_pas = RoutingMatrix.m_GridRouting / 2;
-
- col_min = ( ux0 - lg ) / RoutingMatrix.m_GridRouting;
-
- if( col_min < 0 )
- col_min = 0;
-
- col_max = ( ux1 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
-
- if( col_max > ( RoutingMatrix.m_Ncols - 1 ) )
- col_max = RoutingMatrix.m_Ncols - 1;
-
- if( inc > 0 )
- {
- row_min = ( uy0 - lg ) / RoutingMatrix.m_GridRouting;
- row_max = ( uy1 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
- }
- else
- {
- row_min = ( uy1 - lg ) / RoutingMatrix.m_GridRouting;
- row_max = ( uy0 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
- }
-
- if( row_min < 0 )
- row_min = 0;
-
- if( row_min > ( RoutingMatrix.m_Nrows - 1 ) )
- row_min = RoutingMatrix.m_Nrows - 1;
-
- if( row_max < 0 )
- row_max = 0;
-
- if( row_max > ( RoutingMatrix.m_Nrows - 1 ) )
- row_max = RoutingMatrix.m_Nrows - 1;
-
- dx = ux1 - ux0;
- dy = uy1 - uy0;
-
- double angle;
- if( dx )
- {
- angle = ArcTangente( dy, dx );
- }
- else
- {
- angle = 900;
-
- if( dy < 0 )
- angle = -900;
- }
-
- RotatePoint( &dx, &dy, angle ); // dx = length, dy = 0
-
- for( col = col_min; col <= col_max; col++ )
- {
- int cxr;
- cxr = ( col * RoutingMatrix.m_GridRouting ) - ux0;
-
- for( row = row_min; row <= row_max; row++ )
- {
- cy = (row * RoutingMatrix.m_GridRouting) - uy0;
- cx = cxr;
- RotatePoint( &cx, &cy, angle );
-
- if( abs( cy ) > lg )
- continue; // The point is too far on the Y axis.
-
- /* This point a test is close to the segment: the position
- * along the X axis must be tested.
- */
- if( ( cx >= 0 ) && ( cx <= dx ) )
- {
- OP_CELL( layer, row, col );
- continue;
- }
-
- // Examination of extremities are rounded.
- if( ( cx < 0 ) && ( cx >= -lg ) )
- {
- if( ( ( cx * cx ) + ( cy * cy ) ) <= ( lg * lg ) )
- OP_CELL( layer, row, col );
-
- continue;
- }
-
- if( ( cx > dx ) && ( cx <= ( dx + lg ) ) )
- {
- if( ( ( ( cx - dx ) * ( cx - dx ) ) + ( cy * cy ) ) <= ( lg * lg ) )
- OP_CELL( layer, row, col );
-
- continue;
- }
- }
- }
-}
-
-
-/* Fills all cells of the routing matrix contained in the circle
- * half-width = lg, center = ux0, uy0, ux1,uy1 is a point on the circle.
- * coord are in PCB units.
- */
-void TraceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
- int color, int op_logic )
-{
- int radius, nb_segm;
- int x0, y0, // Starting point of the current segment trace.
- x1, y1; // End point.
- int ii;
- int angle;
-
- radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
-
- x0 = x1 = radius;
- y0 = y1 = 0;
-
- if( lg < 1 )
- lg = 1;
-
- nb_segm = ( 2 * radius ) / lg;
-
- if( nb_segm < 5 )
- nb_segm = 5;
-
- if( nb_segm > 100 )
- nb_segm = 100;
-
- for( ii = 1; ii < nb_segm; ii++ )
- {
- angle = (3600 * ii) / nb_segm;
- x1 = KiROUND( cosdecideg( radius, angle ) );
- y1 = KiROUND( sindecideg( radius, angle ) );
- DrawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
- x0 = x1;
- y0 = y1;
- }
-
- DrawSegmentQcq( x1 + ux0, y1 + uy0, ux0 + radius, uy0, lg, layer, color, op_logic );
-}
-
-
-/* Fills all routing matrix cells contained in the arc
- * angle = ArcAngle, half-width lg
- * center = ux0,uy0, starting at ux1, uy1. Coordinates are in
- * PCB units.
- */
-void TraceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
- LAYER_NUM layer, int color, int op_logic )
-{
- int radius, nb_segm;
- int x0, y0, // Starting point of the current segment trace
- x1, y1; // End point
- int ii;
- double angle, StAngle;
-
-
- radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
-
- x0 = ux1 - ux0;
- y0 = uy1 - uy0;
- StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );
-
- if( lg < 1 )
- lg = 1;
-
- nb_segm = ( 2 * radius ) / lg;
- nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;
-
- if( nb_segm < 5 )
- nb_segm = 5;
-
- if( nb_segm > 100 )
- nb_segm = 100;
-
- for( ii = 1; ii <= nb_segm; ii++ )
- {
- angle = ( ArcAngle * ii ) / nb_segm;
- angle += StAngle;
-
- NORMALIZE_ANGLE_POS( angle );
-
- x1 = KiROUND( cosdecideg( radius, angle ) );
- y1 = KiROUND( cosdecideg( radius, angle ) );
- DrawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
- x0 = x1;
- y0 = y1;
- }
-}
diff --git a/pcbnew/autorouter/move_and_route_event_functions.cpp b/pcbnew/autorouter/move_and_route_event_functions.cpp
index 6adf7cc..124b780 100644
--- a/pcbnew/autorouter/move_and_route_event_functions.cpp
+++ b/pcbnew/autorouter/move_and_route_event_functions.cpp
@@ -63,6 +63,7 @@ wxString ModulesMaskSelection = wxT( "*" );
*/
void PCB_EDIT_FRAME::OnPlaceOrRouteFootprints( wxCommandEvent& event )
{
+ #if 0
int id = event.GetId();
if( m_mainToolBar == NULL )
@@ -178,6 +179,7 @@ void PCB_EDIT_FRAME::OnPlaceOrRouteFootprints( wxCommandEvent& event )
GetBoard()->m_Status_Pcb &= ~DO_NOT_SHOW_GENERAL_RASTNEST;
Compile_Ratsnest( &dc, true );
+ #endif
}
diff --git a/pcbnew/autorouter/solve.cpp b/pcbnew/autorouter/solve.cpp
index 4c83d42..fc0e685 100644
--- a/pcbnew/autorouter/solve.cpp
+++ b/pcbnew/autorouter/solve.cpp
@@ -48,44 +48,6 @@
#include <autorout.h>
#include <cell.h>
-static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
- int two_sides,
- int row_source,
- int col_source,
- int row_target,
- int col_target,
- RATSNEST_ITEM* pt_rat );
-
-static int Retrace( AUTOROUTER_CONTEXT& ctx,
- int,
- int,
- int,
- int,
- int,
- int net_code );
-
-static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx,
- int col,
- int row,
- int side,
- int orient,
- int current_net_code );
-
-static void AddNewTrace( AUTOROUTER_CONTEXT& ctx );
-
-
-static int segm_oX, segm_oY;
-static int segm_fX, segm_fY; /* Origin and position of the current
- * trace segment. */
-static RATSNEST_ITEM* pt_cur_ch;
-static int s_Clearance; // Clearance value used in autorouter
-
-static PICKED_ITEMS_LIST s_ItemsListPicker;
-
-int OpenNodes; // total number of nodes opened
-int ClosNodes; // total number of nodes closed
-int MoveNodes; // total number of nodes moved
-int MaxNodes; // maximum number of nodes opened at one time
#define NOSUCCESS 0
#define STOP_FROM_ESC -1
@@ -263,7 +225,7 @@ static long newmask[8] =
* -1 if escape (stop being routed) request
* -2 if default memory allocation
*/
-int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
+int AUTOROUTER::solve( int aLayersCount )
{
int current_net_code;
int row_source, col_source, row_target, col_target;
@@ -274,9 +236,8 @@ int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
int routedCount = 0; // routed ratsnest count
bool two_sides = aLayersCount == 2;
- m_canvas->SetAbortRequest( false );
- s_Clearance = aCtx.board->GetDesignSettings().GetDefault()->GetClearance();
+ s_Clearance = m_board->GetDesignSettings().GetDefault()->GetClearance();
// Prepare the undo command info
s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but...
@@ -291,6 +252,7 @@ int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
&pt_cur_ch ) )
{
// Test to stop routing ( escape key pressed )
+ #ifdef AR_YIELD
wxYield();
if( m_canvas->GetAbortRequest() )
@@ -306,39 +268,42 @@ int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
m_canvas->SetAbortRequest( false );
}
}
+ #endif
- EraseMsgBox();
+ m_frame->EraseMsgBox();
routedCount++;
- net = aCtx.board->FindNet( current_net_code );
+ net = m_board->FindNet( current_net_code );
if( net )
{
msg.Printf( wxT( "[%8.8s]" ), GetChars( net->GetNetname() ) );
- AppendMsgPanel( wxT( "Net route" ), msg, BROWN );
- msg.Printf( wxT( "%d / %d" ), routedCount, RoutingMatrix.m_RouteCount );
- AppendMsgPanel( wxT( "Activity" ), msg, BROWN );
+ m_frame->AppendMsgPanel( wxT( "Net route" ), msg, BROWN );
+ msg.Printf( wxT( "%d / %d" ), routedCount, m_routingMatrix.m_RouteCount );
+ m_frame->AppendMsgPanel( wxT( "Activity" ), msg, BROWN );
}
- segm_oX = aCtx.bbox.GetX() + ( RoutingMatrix.m_GridRouting * col_source );
- segm_oY = aCtx.bbox.GetY() + ( RoutingMatrix.m_GridRouting * row_source );
- segm_fX = aCtx.bbox.GetX() + ( RoutingMatrix.m_GridRouting * col_target );
- segm_fY = aCtx.bbox.GetY() + ( RoutingMatrix.m_GridRouting * row_target );
+ segm_oX = m_bbox.GetX() + ( m_routingMatrix.m_GridRouting * col_source );
+ segm_oY = m_bbox.GetY() + ( m_routingMatrix.m_GridRouting * row_source );
+ segm_fX = m_bbox.GetX() + ( m_routingMatrix.m_GridRouting * col_target );
+ segm_fY = m_bbox.GetY() + ( m_routingMatrix.m_GridRouting * row_target );
// Draw segment.
+#ifdef AR_DRAW
GRLine( m_canvas->GetClipBox(), aCtx.dc,
segm_oX, segm_oY, segm_fX, segm_fY,
0, WHITE );
- pt_cur_ch->m_PadStart->Draw( m_canvas, aCtx.dc, GR_OR | GR_HIGHLIGHT );
- pt_cur_ch->m_PadEnd->Draw( m_canvas, aCtx.dc, GR_OR | GR_HIGHLIGHT );
+ pt_cur_ch->m_padStart->Draw( m_canvas, aCtx.dc, GR_OR | GR_HIGHLIGHT );
+ pt_cur_ch->m_padEnd->Draw( m_canvas, aCtx.dc, GR_OR | GR_HIGHLIGHT );
+#endif
- success = Autoroute_One_Track( aCtx, two_sides, row_source, col_source,
+ success = Autoroute_One_Track( two_sides, row_source, col_source,
row_target, col_target, pt_cur_ch );
switch( success )
{
case NOSUCCESS:
- pt_cur_ch->m_Status |= CH_UNROUTABLE;
+ pt_cur_ch->m_status |= CH_UNROUTABLE;
nbunsucces++;
break;
@@ -356,21 +321,23 @@ int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
}
msg.Printf( wxT( "%d" ), nbsucces );
- AppendMsgPanel( wxT( "OK" ), msg, GREEN );
+ m_frame->AppendMsgPanel( wxT( "OK" ), msg, GREEN );
msg.Printf( wxT( "%d" ), nbunsucces );
- AppendMsgPanel( wxT( "Fail" ), msg, RED );
- msg.Printf( wxT( " %d" ), aCtx.board->GetUnconnectedNetCount() );
- AppendMsgPanel( wxT( "Not Connected" ), msg, CYAN );
+ m_frame->AppendMsgPanel( wxT( "Fail" ), msg, RED );
+ msg.Printf( wxT( " %d" ), m_board->GetUnconnectedNetCount() );
+ m_frame->AppendMsgPanel( wxT( "Not Connected" ), msg, CYAN );
// Delete routing from display.
- pt_cur_ch->m_PadStart->Draw( m_canvas, aCtx.dc, GR_AND );
- pt_cur_ch->m_PadEnd->Draw( m_canvas, aCtx.dc, GR_AND );
+#ifdef AR_DRAW
+ pt_cur_ch->m_padStart->Draw( m_canvas, aCtx.dc, GR_AND );
+ pt_cur_ch->m_padEnd->Draw( m_canvas, aCtx.dc, GR_AND );
+#endif
if( stop )
break;
}
- SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
+ m_frame->SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
return SUCCESS;
@@ -392,13 +359,13 @@ int PCB_EDIT_FRAME::Solve( AUTOROUTER_CONTEXT& aCtx, int aLayersCount )
* Escape STOP_FROM_ESC if demand
* ERR_MEMORY if memory allocation failed.
*/
-static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
+int AUTOROUTER::Autoroute_One_Track(
int two_sides,
int row_source,
int col_source,
int row_target,
int col_target,
- RATSNEST_ITEM* pt_rat )
+ AR_CONNECTION* pt_rat )
{
int r, c, side, d, apx_dist, nr, nc;
int result, skip;
@@ -422,21 +389,21 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
wxString msg;
// @todo this could be a bottle neck
- LSET all_cu = LSET::AllCuMask( ctx.board->GetCopperLayerCount() );
+ LSET all_cu = LSET::AllCuMask( m_board->GetCopperLayerCount() );
wxBusyCursor dummy_cursor; // Set an hourglass cursor while routing a
// track
result = NOSUCCESS;
- marge = s_Clearance + ( ctx.pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 );
+ marge = s_Clearance + ( m_frame->GetDesignSettings().GetCurrentTrackWidth() / 2 );
// clear direction flags
- i = RoutingMatrix.m_Nrows * RoutingMatrix.m_Ncols * sizeof(DIR_CELL);
+ i = m_routingMatrix.m_Nrows * m_routingMatrix.m_Ncols * sizeof(DIR_CELL);
if( two_sides )
- memset( RoutingMatrix.m_DirSide[TOP], FROM_NOWHERE, i );
- memset( RoutingMatrix.m_DirSide[BOTTOM], FROM_NOWHERE, i );
+ memset( m_routingMatrix.m_DirSide[TOP], FROM_NOWHERE, i );
+ memset( m_routingMatrix.m_DirSide[BOTTOM], FROM_NOWHERE, i );
lastopen = lastclos = lastmove = 0;
@@ -451,9 +418,9 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
pt_cur_ch = pt_rat;
current_net_code = pt_rat->GetNet();
- padLayerMaskStart = pt_cur_ch->m_PadStart->GetLayerSet();
+ padLayerMaskStart = pt_cur_ch->m_padStart->GetLayerSet();
- padLayerMaskEnd = pt_cur_ch->m_PadEnd->GetLayerSet();
+ padLayerMaskEnd = pt_cur_ch->m_padEnd->GetLayerSet();
/* First Test if routing possible ie if the pads are accessible
@@ -469,27 +436,27 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
* On the routing grid (1 grid point must be in the pad)
*/
{
- int cX = ( RoutingMatrix.m_GridRouting * col_source ) + ctx.bbox.GetX();
- int cY = ( RoutingMatrix.m_GridRouting * row_source ) + ctx.bbox.GetY();
- int dx = pt_cur_ch->m_PadStart->GetSize().x / 2;
- int dy = pt_cur_ch->m_PadStart->GetSize().y / 2;
- int px = pt_cur_ch->m_PadStart->GetPosition().x;
- int py = pt_cur_ch->m_PadStart->GetPosition().y;
-
- if( ( ( int( pt_cur_ch->m_PadStart->GetOrientation() ) / 900 ) & 1 ) != 0 )
+ int cX = ( m_routingMatrix.m_GridRouting * col_source ) + m_bbox.GetX();
+ int cY = ( m_routingMatrix.m_GridRouting * row_source ) + m_bbox.GetY();
+ int dx = pt_cur_ch->m_padStart->GetSize().x / 2;
+ int dy = pt_cur_ch->m_padStart->GetSize().y / 2;
+ int px = pt_cur_ch->m_padStart->GetPosition().x;
+ int py = pt_cur_ch->m_padStart->GetPosition().y;
+
+ if( ( ( int( pt_cur_ch->m_padStart->GetOrientation() ) / 900 ) & 1 ) != 0 )
std::swap( dx, dy );
if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
goto end_of_route;
- cX = ( RoutingMatrix.m_GridRouting * col_target ) + ctx.bbox.GetX();
- cY = ( RoutingMatrix.m_GridRouting * row_target ) + ctx.bbox.GetY();
- dx = pt_cur_ch->m_PadEnd->GetSize().x / 2;
- dy = pt_cur_ch->m_PadEnd->GetSize().y / 2;
- px = pt_cur_ch->m_PadEnd->GetPosition().x;
- py = pt_cur_ch->m_PadEnd->GetPosition().y;
+ cX = ( m_routingMatrix.m_GridRouting * col_target ) + m_bbox.GetX();
+ cY = ( m_routingMatrix.m_GridRouting * row_target ) + m_bbox.GetY();
+ dx = pt_cur_ch->m_padEnd->GetSize().x / 2;
+ dy = pt_cur_ch->m_padEnd->GetSize().y / 2;
+ px = pt_cur_ch->m_padEnd->GetPosition().x;
+ py = pt_cur_ch->m_padEnd->GetPosition().y;
- if( ( ( int( pt_cur_ch->m_PadEnd->GetOrientation() ) / 900) & 1 ) != 0 )
+ if( ( ( int( pt_cur_ch->m_padEnd->GetOrientation() ) / 900) & 1 ) != 0 )
std::swap( dx, dy );
if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
@@ -505,27 +472,27 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
}
// Placing the bit to remove obstacles on 2 pads to a link.
- ctx.pcbframe->SetStatusText( wxT( "Gen Cells" ) );
+ m_frame->SetStatusText( wxT( "Gen Cells" ) );
- PlacePad( pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL );
- PlacePad( pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL );
+ PlacePad( pt_cur_ch->m_padStart, CURRENT_PAD, marge, WRITE_OR_CELL );
+ PlacePad( pt_cur_ch->m_padEnd, CURRENT_PAD, marge, WRITE_OR_CELL );
// Regenerates the remaining barriers (which may encroach on the
// placement bits precedent)
- i = ctx.board->GetPadCount();
+ i = m_board->GetPadCount();
- for( unsigned ii = 0; ii < ctx.board->GetPadCount(); ii++ )
+ for( unsigned ii = 0; ii < m_board->GetPadCount(); ii++ )
{
- D_PAD* ptr = ctx.board->GetPad( ii );
+ D_PAD* ptr = m_board->GetPad( ii );
- if( ( pt_cur_ch->m_PadStart != ptr ) && ( pt_cur_ch->m_PadEnd != ptr ) )
+ if( ( pt_cur_ch->m_padStart != ptr ) && ( pt_cur_ch->m_padEnd != ptr ) )
{
PlacePad( ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL );
}
}
InitQueue(); // initialize the search queue
- apx_dist = RoutingMatrix.GetApxDist( row_source, col_source, row_target, col_target );
+ apx_dist = m_routingMatrix.GetApxDist( row_source, col_source, row_target, col_target );
// Initialize first search.
if( two_sides ) // Preferred orientation.
@@ -594,7 +561,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) )
{
- curcell = RoutingMatrix.GetCell( r, c, side );
+ curcell = m_routingMatrix.GetCell( r, c, side );
if( curcell & CURRENT_PAD )
curcell &= ~HOLE;
@@ -603,16 +570,18 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
&& (tab_mask[side] & padLayerMaskEnd).any() )
{
// Remove link.
+#ifdef AR_DRAW
GRSetDrawMode( ctx.dc, GR_XOR );
- GRLine( ctx.pcbframe->GetCanvas()->GetClipBox(),
+ GRLine( m_frame->GetCanvas()->GetClipBox(),
ctx.dc,
segm_oX, segm_oY,
segm_fX, segm_fY,
0,
WHITE );
+#endif
// Generate trace.
- if( Retrace( ctx, row_source, col_source,
+ if( Retrace( row_source, col_source,
row_target, col_target, side, current_net_code ) )
{
result = SUCCESS; // Success : Route OK
@@ -621,7 +590,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
break; // Routing complete.
}
- if( ctx.pcbframe->GetCanvas()->GetAbortRequest() )
+ if( m_frame->GetCanvas()->GetAbortRequest() )
{
result = STOP_FROM_ESC;
break;
@@ -639,7 +608,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
lastmove = MoveNodes;
msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d" ),
OpenNodes, ClosNodes, MoveNodes );
- ctx.pcbframe->SetStatusText( msg );
+ m_frame->SetStatusText( msg );
}
_self = 0;
@@ -664,14 +633,14 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
nc = c + delta[i][1];
// off the edge?
- if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
- nc < 0 || nc >= RoutingMatrix.m_Ncols )
+ if( nr < 0 || nr >= m_routingMatrix.m_Nrows ||
+ nc < 0 || nc >= m_routingMatrix.m_Ncols )
continue; // off the edge
if( _self == 5 && selfok2[i].present )
continue;
- newcell = RoutingMatrix.GetCell( nr, nc, side );
+ newcell = m_routingMatrix.GetCell( nr, nc, side );
if( newcell & CURRENT_PAD )
newcell &= ~HOLE;
@@ -692,7 +661,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
if( delta[i][0] && delta[i][1] )
{
// check first buddy
- buddy = RoutingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side );
+ buddy = m_routingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side );
if( buddy & CURRENT_PAD )
buddy &= ~HOLE;
@@ -702,7 +671,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
// if (buddy & (blocking[i].b1)) continue;
// check second buddy
- buddy = RoutingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side );
+ buddy = m_routingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side );
if( buddy & CURRENT_PAD )
buddy &= ~HOLE;
@@ -713,31 +682,31 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
// if (buddy & (blocking[i].b2)) continue;
}
- olddir = RoutingMatrix.GetDir( r, c, side );
- newdist = d + RoutingMatrix.CalcDist( ndir[i], olddir,
+ olddir = m_routingMatrix.GetDir( r, c, side );
+ newdist = d + m_routingMatrix.CalcDist( ndir[i], olddir,
( olddir == FROM_OTHERSIDE ) ?
- RoutingMatrix.GetDir( r, c, 1 - side ) : 0, side );
+ m_routingMatrix.GetDir( r, c, 1 - side ) : 0, side );
// if (a) not visited yet, or (b) we have
// found a better path, add it to queue
- if( !RoutingMatrix.GetDir( nr, nc, side ) )
+ if( !m_routingMatrix.GetDir( nr, nc, side ) )
{
- RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
- RoutingMatrix.SetDist( nr, nc, side, newdist );
+ m_routingMatrix.SetDir( nr, nc, side, ndir[i] );
+ m_routingMatrix.SetDist( nr, nc, side, newdist );
if( SetQueue( nr, nc, side, newdist,
- RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
+ m_routingMatrix.GetApxDist( nr, nc, row_target, col_target ),
row_target, col_target ) == 0 )
{
return ERR_MEMORY;
}
}
- else if( newdist < RoutingMatrix.GetDist( nr, nc, side ) )
+ else if( newdist < m_routingMatrix.GetDist( nr, nc, side ) )
{
- RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
- RoutingMatrix.SetDist( nr, nc, side, newdist );
+ m_routingMatrix.SetDir( nr, nc, side, ndir[i] );
+ m_routingMatrix.SetDist( nr, nc, side, newdist );
ReSetQueue( nr, nc, side, newdist,
- RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
+ m_routingMatrix.GetApxDist( nr, nc, row_target, col_target ),
row_target, col_target );
}
}
@@ -745,7 +714,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
//* Test the other layer. *
if( two_sides )
{
- olddir = RoutingMatrix.GetDir( r, c, side );
+ olddir = m_routingMatrix.GetDir( r, c, side );
if( olddir == FROM_OTHERSIDE )
continue; // useless move, so don't bother
@@ -754,7 +723,7 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
continue;
// check for holes or traces on other side
- if( ( newcell = RoutingMatrix.GetCell( r, c, 1 - side ) ) != 0 )
+ if( ( newcell = m_routingMatrix.GetCell( r, c, 1 - side ) ) != 0 )
continue;
// check for nearby holes or traces on both sides
@@ -762,17 +731,17 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
{
nr = r + delta[i][0]; nc = c + delta[i][1];
- if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
- nc < 0 || nc >= RoutingMatrix.m_Ncols )
+ if( nr < 0 || nr >= m_routingMatrix.m_Nrows ||
+ nc < 0 || nc >= m_routingMatrix.m_Ncols )
continue; // off the edge !!
- if( RoutingMatrix.GetCell( nr, nc, side ) /* & blocking2[i] */ )
+ if( m_routingMatrix.GetCell( nr, nc, side ) /* & blocking2[i] */ )
{
skip = 1; // can't drill via here
break;
}
- if( RoutingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i] */ )
+ if( m_routingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i] */ )
{
skip = 1; // can't drill via here
break;
@@ -782,25 +751,25 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
if( skip ) // neighboring hole or trace?
continue; // yes, can't drill via here
- newdist = d + RoutingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side );
+ newdist = d + m_routingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side );
/* if (a) not visited yet,
* or (b) we have found a better path,
* add it to queue */
- if( !RoutingMatrix.GetDir( r, c, 1 - side ) )
+ if( !m_routingMatrix.GetDir( r, c, 1 - side ) )
{
- RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
- RoutingMatrix.SetDist( r, c, 1 - side, newdist );
+ m_routingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
+ m_routingMatrix.SetDist( r, c, 1 - side, newdist );
if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ) == 0 )
{
return ERR_MEMORY;
}
}
- else if( newdist < RoutingMatrix.GetDist( r, c, 1 - side ) )
+ else if( newdist < m_routingMatrix.GetDist( r, c, 1 - side ) )
{
- RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
- RoutingMatrix.SetDist( r, c, 1 - side, newdist );
+ m_routingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
+ m_routingMatrix.SetDist( r, c, 1 - side, newdist );
ReSetQueue( r, c,
1 - side,
newdist,
@@ -812,12 +781,12 @@ static int Autoroute_One_Track( AUTOROUTER_CONTEXT& ctx,
}
end_of_route:
- PlacePad( pt_cur_ch->m_PadStart, ~CURRENT_PAD, marge, WRITE_AND_CELL );
- PlacePad( pt_cur_ch->m_PadEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL );
+ PlacePad( pt_cur_ch->m_padStart, ~CURRENT_PAD, marge, WRITE_AND_CELL );
+ PlacePad( pt_cur_ch->m_padEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL );
msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d"),
OpenNodes, ClosNodes, MoveNodes );
- ctx.pcbframe->SetStatusText( msg );
+ m_frame->SetStatusText( msg );
return result;
}
@@ -940,7 +909,7 @@ static long bit[8][9] =
* 0 if error
* > 0 if Ok
*/
-static int Retrace( AUTOROUTER_CONTEXT& ctx,
+int AUTOROUTER::Retrace(
int row_source, int col_source,
int row_target, int col_target, int target_side,
int current_net_code )
@@ -962,7 +931,7 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
{
// find where we came from to get here
r2 = r1; c2 = c1; s2 = s1;
- x = RoutingMatrix.GetDir( r1, c1, s1 );
+ x = m_routingMatrix.GetDir( r1, c1, s1 );
switch( x )
{
@@ -1012,7 +981,7 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
}
if( r0 != ILLEGAL )
- y = RoutingMatrix.GetDir( r0, c0, s0 );
+ y = m_routingMatrix.GetDir( r0, c0, s0 );
// see if target or hole
if( ( ( r1 == row_target ) && ( c1 == col_target ) ) || ( s1 != s0 ) )
@@ -1055,11 +1024,11 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
case FROM_OTHERSIDE:
default:
- DisplayError( ctx.pcbframe, wxT( "Retrace: error 1" ) );
+ DisplayError( m_frame, wxT( "Retrace: error 1" ) );
return 0;
}
- OrCell_Trace( ctx, r1, c1, s1, p_dir, current_net_code );
+ OrCell_Trace( r1, c1, s1, p_dir, current_net_code );
}
else
{
@@ -1074,10 +1043,10 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
|| x == FROM_OTHERSIDE )
&& ( ( b = bit[y - 1][x - 1] ) != 0 ) )
{
- OrCell_Trace( ctx, r1, c1, s1, b, current_net_code );
+ OrCell_Trace( r1, c1, s1, b, current_net_code );
if( b & HOLE )
- OrCell_Trace( ctx, r2, c2, s2, HOLE, current_net_code );
+ OrCell_Trace( r2, c2, s2, HOLE, current_net_code );
}
else
{
@@ -1130,7 +1099,7 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
return 0;
}
- OrCell_Trace( ctx, r2, c2, s2, p_dir, current_net_code );
+ OrCell_Trace( r2, c2, s2, p_dir, current_net_code );
}
// move to next cell
@@ -1142,7 +1111,7 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
s1 = s2;
} while( !( ( r2 == row_source ) && ( c2 == col_source ) ) );
- AddNewTrace( ctx );
+ AddNewTrace( );
return 1;
}
@@ -1150,30 +1119,30 @@ static int Retrace( AUTOROUTER_CONTEXT& ctx,
/* This function is used by Retrace and read the autorouting matrix data cells to create
* the real track on the physical board
*/
-static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx, int col, int row,
+void AUTOROUTER::OrCell_Trace( int col, int row,
int side, int orient, int current_net_code )
{
if( orient == HOLE ) // placement of a via
{
- VIA* newVia = new VIA( ctx.board );
+ VIA* newVia = new VIA( m_board );
g_CurrentTrackList.PushBack( newVia );
g_CurrentTrackSegment->SetState( TRACK_AR, true );
g_CurrentTrackSegment->SetLayer( F_Cu );
- g_CurrentTrackSegment->SetStart( wxPoint( ctx.bbox.GetX() + RoutingMatrix.m_GridRouting * row,
- ctx.bbox.GetY() + RoutingMatrix.m_GridRouting * col ) );
+ g_CurrentTrackSegment->SetStart( wxPoint( m_bbox.GetX() + m_routingMatrix.m_GridRouting * row,
+ m_bbox.GetY() + m_routingMatrix.m_GridRouting * col ) );
g_CurrentTrackSegment->SetEnd( g_CurrentTrackSegment->GetStart() );
- g_CurrentTrackSegment->SetWidth( ctx.board->GetDesignSettings().GetCurrentViaSize() );
- newVia->SetViaType( ctx.board->GetDesignSettings().m_CurrentViaType );
+ g_CurrentTrackSegment->SetWidth( m_board->GetDesignSettings().GetCurrentViaSize() );
+ newVia->SetViaType( m_board->GetDesignSettings().m_CurrentViaType );
g_CurrentTrackSegment->SetNetCode( current_net_code );
}
else // placement of a standard segment
{
- TRACK* newTrack = new TRACK( ctx.board );
+ TRACK* newTrack = new TRACK( m_board );
int dx0, dy0, dx1, dy1;
g_CurrentTrackList.PushBack( newTrack );
@@ -1184,8 +1153,8 @@ static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx, int col, int row,
g_CurrentTrackSegment->SetLayer( g_Route_Layer_TOP );
g_CurrentTrackSegment->SetState( TRACK_AR, true );
- g_CurrentTrackSegment->SetEnd( wxPoint( ctx.bbox.GetX() + RoutingMatrix.m_GridRouting * row,
- ctx.bbox.GetY() + RoutingMatrix.m_GridRouting * col ) );
+ g_CurrentTrackSegment->SetEnd( wxPoint( m_bbox.GetX() + m_routingMatrix.m_GridRouting * row,
+ m_bbox.GetY() + m_routingMatrix.m_GridRouting * col ) );
g_CurrentTrackSegment->SetNetCode( current_net_code );
if( g_CurrentTrackSegment->Back() == NULL ) // Start trace.
@@ -1196,17 +1165,17 @@ static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx, int col, int row,
dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x;
dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y;
- dx0 = pt_cur_ch->m_PadEnd->GetPosition().x - g_CurrentTrackSegment->GetStart().x;
- dy0 = pt_cur_ch->m_PadEnd->GetPosition().y - g_CurrentTrackSegment->GetStart().y;
+ dx0 = pt_cur_ch->m_padEnd->GetPosition().x - g_CurrentTrackSegment->GetStart().x;
+ dy0 = pt_cur_ch->m_padEnd->GetPosition().y - g_CurrentTrackSegment->GetStart().y;
// If aligned, change the origin point.
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )
{
- g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() );
+ g_CurrentTrackSegment->SetStart( pt_cur_ch->m_padEnd->GetPosition() );
}
else // Creation of a supplemental segment
{
- g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() );
+ g_CurrentTrackSegment->SetStart( pt_cur_ch->m_padEnd->GetPosition() );
newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
newTrack->SetStart( g_CurrentTrackSegment->GetEnd());
@@ -1222,7 +1191,7 @@ static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx, int col, int row,
}
}
- g_CurrentTrackSegment->SetWidth( ctx.board->GetDesignSettings().GetCurrentTrackWidth() );
+ g_CurrentTrackSegment->SetWidth( m_board->GetDesignSettings().GetCurrentTrackWidth() );
if( g_CurrentTrackSegment->GetStart() != g_CurrentTrackSegment->GetEnd() )
{
@@ -1254,48 +1223,48 @@ static void OrCell_Trace( AUTOROUTER_CONTEXT& ctx, int col, int row,
* connected
* Center on pads even if they are off grid.
*/
-static void AddNewTrace( AUTOROUTER_CONTEXT& ctx )
+void AUTOROUTER::AddNewTrace( )
{
if( g_FirstTrackSegment == NULL )
return;
int dx0, dy0, dx1, dy1;
int marge, via_marge;
- EDA_DRAW_PANEL* panel = ctx.pcbframe->GetCanvas();
- PCB_SCREEN* screen = ctx.pcbframe->GetScreen();
+ EDA_DRAW_PANEL* panel = m_frame->GetCanvas();
+ PCB_SCREEN* screen = m_frame->GetScreen();
- marge = s_Clearance + ( ctx.pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 );
- via_marge = s_Clearance + ( ctx.pcbframe->GetDesignSettings().GetCurrentViaSize() / 2 );
+ marge = s_Clearance + ( m_frame->GetDesignSettings().GetCurrentTrackWidth() / 2 );
+ via_marge = s_Clearance + ( m_frame->GetDesignSettings().GetCurrentViaSize() / 2 );
dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x;
dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y;
// Place on center of pad if off grid.
- dx0 = pt_cur_ch->m_PadStart->GetPosition().x - g_CurrentTrackSegment->GetStart().x;
- dy0 = pt_cur_ch->m_PadStart->GetPosition().y - g_CurrentTrackSegment->GetStart().y;
+ dx0 = pt_cur_ch->m_padStart->GetPosition().x - g_CurrentTrackSegment->GetStart().x;
+ dy0 = pt_cur_ch->m_padStart->GetPosition().y - g_CurrentTrackSegment->GetStart().y;
// If aligned, change the origin point.
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )
{
- g_CurrentTrackSegment->SetEnd( pt_cur_ch->m_PadStart->GetPosition() );
+ g_CurrentTrackSegment->SetEnd( pt_cur_ch->m_padStart->GetPosition() );
}
else
{
TRACK* newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
- newTrack->SetEnd( pt_cur_ch->m_PadStart->GetPosition() );
+ newTrack->SetEnd( pt_cur_ch->m_padStart->GetPosition() );
newTrack->SetStart( g_CurrentTrackSegment->GetEnd() );
g_CurrentTrackList.PushBack( newTrack );
}
- g_FirstTrackSegment->start = ctx.board->GetPad( g_FirstTrackSegment,
+ g_FirstTrackSegment->start = m_board->GetPad( g_FirstTrackSegment,
ENDPOINT_START );
if( g_FirstTrackSegment->start )
g_FirstTrackSegment->SetState( BEGIN_ONPAD, true );
- g_CurrentTrackSegment->end = ctx.board->GetPad( g_CurrentTrackSegment,
+ g_CurrentTrackSegment->end = m_board->GetPad( g_CurrentTrackSegment,
ENDPOINT_END );
if( g_CurrentTrackSegment->end )
@@ -1315,18 +1284,20 @@ static void AddNewTrace( AUTOROUTER_CONTEXT& ctx )
// Put entire new current segment list in BOARD
TRACK* track;
- TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( ctx.board );
+ TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( m_board );
while( ( track = g_CurrentTrackList.PopFront() ) != NULL )
{
ITEM_PICKER picker( track, UR_NEW );
s_ItemsListPicker.PushItem( picker );
- ctx.board->m_Track.Insert( track, insertBeforeMe );
+ m_board->m_Track.Insert( track, insertBeforeMe );
}
+#ifdef AR_DRAW
DrawTraces( panel, ctx.dc, firstTrack, newCount, GR_OR );
- ctx.pcbframe->TestNetConnection( ctx.dc, netcode );
+ m_frame->TestNetConnection( ctx.dc, netcode );
+#endif
screen->SetModify();
}
diff --git a/pcbnew/autorouter/work.cpp b/pcbnew/autorouter/work.cpp
index 68aa48c..d579569 100644
--- a/pcbnew/autorouter/work.cpp
+++ b/pcbnew/autorouter/work.cpp
@@ -32,6 +32,17 @@
* @file work.cpp
* @brief Automatic routing routines
*/
+ #include <fctsys.h>
+ #include <common.h>
+ #include <macros.h>
+ #include <trigo.h>
+ #include <math_for_graphics.h>
+ #include <class_board.h>
+ #include <class_track.h>
+ #include <class_drawsegment.h>
+
+ #include <pcbnew.h>
+ #include <class_undoredo_container.h>
#include <fctsys.h>
#include <common.h>
@@ -41,31 +52,15 @@
#include <cell.h>
-struct CWORK // a unit of work is a source-target to connect
- // this is a ratsnest item in the routing matrix world
-{
- int m_FromRow; // source row
- int m_FromCol; // source column
- int m_ToRow; // target row
- int m_ToCol; // target column
- RATSNEST_ITEM* m_Ratsnest; // Corresponding ratsnest
- int m_NetCode; // m_NetCode
- int m_ApxDist; // approximate distance
- int m_Cost; // cost for sort by length
- int m_Priority; // route priority
- // the function that calculates the cost of this ratsnest:
- void CalculateCost();
-};
// the list of ratsnests
-static std::vector <CWORK> WorkList;
-static unsigned Current = 0;
+
// initialize the work list
-void InitWork()
+void AUTOROUTER::InitWork()
{
WorkList.clear();
Current = 0;
@@ -78,10 +73,10 @@ void InitWork()
* 0 if memory allocation failed
*/
-int SetWork( int r1, int c1,
+int AUTOROUTER::SetWork( int r1, int c1,
int n_c,
int r2, int c2,
- RATSNEST_ITEM* pt_ch, int pri )
+ AR_CONNECTION* pt_ch, int pri )
{
CWORK item;
item.m_FromRow = r1;
@@ -90,7 +85,7 @@ int SetWork( int r1, int c1,
item.m_ToRow = r2;
item.m_ToCol = c2;
item.m_Ratsnest = pt_ch;
- item.m_ApxDist = RoutingMatrix.GetApxDist( r1, c1, r2, c2 );
+ item.m_ApxDist = m_routingMatrix.GetApxDist( r1, c1, r2, c2 );
item.CalculateCost();
item.m_Priority = pri;
WorkList.push_back( item );
@@ -99,10 +94,10 @@ int SetWork( int r1, int c1,
/* fetch a unit of work from the work list */
-void GetWork( int* r1, int* c1,
+void AUTOROUTER::GetWork( int* r1, int* c1,
int* n_c,
int* r2, int* c2,
- RATSNEST_ITEM** pt_ch )
+ AR_CONNECTION** pt_ch )
{
if( Current < WorkList.size() )
{
@@ -132,7 +127,7 @@ bool sort_by_cost( const CWORK& ref, const CWORK& item )
return ref.m_Priority >= item.m_Priority;
}
-void SortWork()
+void AUTOROUTER::SortWork()
{
sort( WorkList.begin(), WorkList.end(), sort_by_cost );
}
diff --git a/pcbnew/connectivity_data.cpp b/pcbnew/connectivity_data.cpp
index 6498ae7..3a4199b 100644
--- a/pcbnew/connectivity_data.cpp
+++ b/pcbnew/connectivity_data.cpp
@@ -659,3 +659,42 @@ void CONNECTIVITY_DATA::SetProgressReporter( PROGRESS_REPORTER* aReporter )
m_progressReporter = aReporter;
m_connAlgo->SetProgressReporter( m_progressReporter );
}
+
+const std::vector<CN_EDGE> CONNECTIVITY_DATA::GetRatsnestForComponent( MODULE* aComponent, bool aSkipInternalConnections )
+{
+ std::set<int> nets;
+ std::set<D_PAD*> pads;
+ std::vector<CN_EDGE> edges;
+
+ for( auto pad : aComponent->Pads() )
+ {
+ nets.insert( pad->GetNetCode() );
+ pads.insert( pad );
+ }
+
+ for ( auto netcode : nets )
+ {
+ auto net = GetRatsnestForNet( netcode );
+
+ for ( auto edge : net->GetEdges() )
+ {
+ auto srcNode = edge.GetSourceNode();
+ auto dstNode = edge.GetTargetNode();
+
+ auto srcParent = static_cast<D_PAD*>( srcNode->Parent() );
+ auto dstParent = static_cast<D_PAD*>( dstNode->Parent() );
+
+ bool srcFound = ( pads.find(srcParent) != pads.end() );
+ bool dstFound = ( pads.find(dstParent) != pads.end() );
+
+ if ( srcFound && dstFound && !aSkipInternalConnections )
+ {
+ edges.push_back( edge );
+ } else if ( srcFound || dstFound )
+ {
+ edges.push_back( edge );
+ }
+ }
+ }
+ return edges;
+}
\ No newline at end of file
diff --git a/pcbnew/connectivity_data.h b/pcbnew/connectivity_data.h
index bf9c57e..7e7f6ce 100644
--- a/pcbnew/connectivity_data.h
+++ b/pcbnew/connectivity_data.h
@@ -48,6 +48,7 @@ class RN_DATA;
class RN_NET;
class TRACK;
class D_PAD;
+class MODULE;
class PROGRESS_REPORTER;
struct CN_DISJOINT_NET_ENTRY
@@ -235,6 +236,9 @@ public:
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
+ const std::vector<CN_EDGE> GetRatsnestForComponent( MODULE* aComponent, bool aSkipInternalConnections = false );
+
+
private:
int countRelevantItems( const std::vector<BOARD_ITEM*>& aItems );
diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp
index 0652c18..f51475e 100644
--- a/pcbnew/edit.cpp
+++ b/pcbnew/edit.cpp
@@ -156,10 +156,6 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
case ID_POPUP_PCB_MOVE_MODULE_REQUEST:
case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST:
case ID_POPUP_PCB_MOVE_PCB_TARGET_REQUEST:
- case ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES:
- case ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE:
- case ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES:
- case ID_POPUP_PCB_AUTOPLACE_FREE_MODULE:
break;
case ID_POPUP_CANCEL_CURRENT_COMMAND:
@@ -1257,44 +1253,7 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
m_canvas->Refresh();
break;
- case ID_POPUP_PCB_SPREAD_ALL_MODULES:
- if( !IsOK( this,
- _("Not locked footprints inside the board will be moved. OK?") ) )
- break;
- // Fall through
- case ID_POPUP_PCB_SPREAD_NEW_MODULES:
- if( GetBoard()->m_Modules == NULL )
- {
- DisplayError( this, _( "No footprint found!" ) );
- return;
- }
- else
- {
- MODULE* footprint = GetBoard()->m_Modules;
- std::vector<MODULE*> footprintList;
- for( ; footprint != NULL; footprint = footprint->Next() )
- footprintList.push_back( footprint );
-
- SpreadFootprints( &footprintList, id == ID_POPUP_PCB_SPREAD_NEW_MODULES,
- true, GetCrossHairPosition() );
- }
- break;
- case ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE:
- LockModule( (MODULE*) GetScreen()->GetCurItem(), true );
- break;
-
- case ID_POPUP_PCB_AUTOPLACE_FREE_MODULE:
- LockModule( (MODULE*) GetScreen()->GetCurItem(), false );
- break;
-
- case ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES:
- LockModule( NULL, false );
- break;
-
- case ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES:
- LockModule( NULL, true );
- break;
-
+
default:
wxString msg;
msg.Printf( wxT( "PCB_EDIT_FRAME::Process_Special_Functions() unknown event id %d" ), id );
diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp
index 91407e2..d458c51 100644
--- a/pcbnew/menubar_pcb_editor.cpp
+++ b/pcbnew/menubar_pcb_editor.cpp
@@ -337,6 +337,23 @@ void preparePlaceMenu( wxMenu* aParentMenu )
_( "&Grid Origin" ),
_( "Set grid origin point" ),
KiBitmap( grid_select_axis_xpm ) );
+
+ aParentMenu->AppendSeparator();
+
+ wxMenu* autoplaceSubmenu = new wxMenu;
+ AddMenuItem( autoplaceSubmenu, ID_POPUP_PCB_AUTOPLACE_OFF_BOARD_MODULES,
+ _( "&Autoplace off-board components" ), _( "" ), KiBitmap( grid_select_axis_xpm ) // fixme: icons
+ );
+
+ AddMenuItem( autoplaceSubmenu, ID_POPUP_PCB_AUTOPLACE_SELECTED_MODULES,
+ _( "&Autoplace selected components" ), _( "" ), KiBitmap( grid_select_axis_xpm ) // fixme: icons
+ );
+
+
+ AddMenuItem( aParentMenu, autoplaceSubmenu,
+ -1, _( "&Auto-place" ),
+ _( "Automatic component placement" ), KiBitmap( grid_select_axis_xpm ) // fixme: icons
+ );
}
diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp
index fa1b2ce..a01d926 100644
--- a/pcbnew/onrightclick.cpp
+++ b/pcbnew/onrightclick.cpp
@@ -394,17 +394,7 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
case ID_NO_TOOL_SELECTED:
{
wxMenu* commands = new wxMenu;
- AddMenuItem( aPopMenu, commands, ID_POPUP_PCB_AUTOPLACE_COMMANDS,
- _( "Global Spread and Place" ), KiBitmap( move_xpm ) );
- AddMenuItem( commands, ID_POPUP_PCB_SPREAD_ALL_MODULES,
- _( "Spread out All Footprints" ), KiBitmap( move_xpm ) );
- commands->Append( ID_POPUP_PCB_SPREAD_NEW_MODULES,
- _( "Spread out Footprints not Already on Board" ) );
- AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES,
- _( "Unlock All Footprints" ), KiBitmap( unlocked_xpm ) );
- AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES,
- _( "Lock All Footprints" ), KiBitmap( locked_xpm ) );
-
+
if( !trackFound )
{
msg = AddHotkeyName( _( "Begin Track" ), g_Board_Editor_Hotkeys_Descr, HK_ADD_NEW_TRACK );
@@ -808,17 +798,9 @@ void PCB_EDIT_FRAME::createPopUpMenuForFootprints( MODULE* aModule, wxMenu* menu
if( !aModule->IsLocked() )
{
- msg = AddHotkeyName( _("Lock Footprint" ), g_Board_Editor_Hotkeys_Descr,
- HK_LOCK_UNLOCK_FOOTPRINT );
- AddMenuItem( sub_menu_footprint, ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE, msg,
- KiBitmap( locked_xpm ) );
}
else
{
- msg = AddHotkeyName( _( "Unlock Footprint" ), g_Board_Editor_Hotkeys_Descr,
- HK_LOCK_UNLOCK_FOOTPRINT );
- AddMenuItem( sub_menu_footprint, ID_POPUP_PCB_AUTOPLACE_FREE_MODULE, msg,
- KiBitmap( unlocked_xpm ) );
}
}
diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp
index b45924a..bc41141 100644
--- a/pcbnew/pcb_edit_frame.cpp
+++ b/pcbnew/pcb_edit_frame.cpp
@@ -255,12 +255,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
EVT_MENU( ID_POPUP_PCB_DELETE_TRACKSEG, PCB_EDIT_FRAME::Process_Special_Functions )
EVT_MENU_RANGE( ID_POPUP_GENERAL_START_RANGE, ID_POPUP_GENERAL_END_RANGE,
PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_SPREAD_ALL_MODULES, PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_SPREAD_NEW_MODULES, PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE, PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES, PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES, PCB_EDIT_FRAME::Process_Special_Functions )
- EVT_MENU( ID_POPUP_PCB_AUTOPLACE_FREE_MODULE, PCB_EDIT_FRAME::Process_Special_Functions )
// User interface update event handlers.
EVT_UPDATE_UI( ID_SAVE_BOARD, PCB_EDIT_FRAME::OnUpdateSave )
diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h
index b076383..abd5008 100644
--- a/pcbnew/pcbnew_id.h
+++ b/pcbnew/pcbnew_id.h
@@ -250,28 +250,11 @@ enum pcbnew_ids
// reserve a block of MAX_ITEMS_IN_PICKER ids for the item selection popup
ID_POPUP_PCB_ITEM_SELECTION_START,
ID_POPUP_PCB_ITEM_SELECTION_END = MAX_ITEMS_IN_PICKER + ID_POPUP_PCB_ITEM_SELECTION_START,
- ID_POPUP_PCB_AUTOPLACE_START_RANGE,
- ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE,
- ID_POPUP_PCB_AUTOPLACE_FREE_MODULE,
- ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES,
- ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES,
- ID_POPUP_PCB_AUTOPLACE_CURRENT_MODULE,
- ID_POPUP_PCB_SPREAD_ALL_MODULES,
- ID_POPUP_PCB_SPREAD_NEW_MODULES,
- ID_POPUP_PCB_AUTOPLACE_COMMANDS,
- ID_POPUP_PCB_AUTOPLACE_ALL_MODULES,
- ID_POPUP_PCB_AUTOPLACE_NEW_MODULES,
- ID_POPUP_PCB_AUTOPLACE_NEXT_MODULE,
-
- ID_POPUP_PCB_AUTOROUTE_COMMANDS,
- ID_POPUP_PCB_AUTOROUTE_ALL_MODULES,
- ID_POPUP_PCB_AUTOROUTE_MODULE,
- ID_POPUP_PCB_AUTOROUTE_PAD,
- ID_POPUP_PCB_AUTOROUTE_NET,
-
- ID_POPUP_PCB_AUTOROUTE_RESET_UNROUTED,
- ID_POPUP_PCB_AUTOROUTE_SELECT_LAYERS,
- ID_POPUP_PCB_AUTOPLACE_END_RANGE,
+
+ ID_POPUP_PCB_SPREAD_SELECTED_MODULES,
+ ID_POPUP_PCB_SPREAD_OFF_BOARD_MODULES,
+ ID_POPUP_PCB_AUTOPLACE_SELECTED_MODULES,
+ ID_POPUP_PCB_AUTOPLACE_OFF_BOARD_MODULES,
ID_MENU_READ_BOARD_BACKUP_FILE,
ID_MENU_RECOVER_BOARD_AUTOSAVE,
diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp
index cded71f..22ee622 100644
--- a/pcbnew/tools/pcb_actions.cpp
+++ b/pcbnew/tools/pcb_actions.cpp
@@ -212,6 +212,13 @@ OPT<TOOL_EVENT> PCB_ACTIONS::TranslateLegacyId( int aId )
case ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES:
return PCB_ACTIONS::zoneUnfillAll.MakeEvent();
+
+ case ID_POPUP_PCB_AUTOPLACE_OFF_BOARD_MODULES:
+ return PCB_ACTIONS::autoplaceOffboardComponents.MakeEvent();
+
+ case ID_POPUP_PCB_AUTOPLACE_SELECTED_MODULES:
+ return PCB_ACTIONS::autoplaceSelectedComponents.MakeEvent();
+
}
return OPT<TOOL_EVENT>();
diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h
index b7ebf85..78d88fe 100644
--- a/pcbnew/tools/pcb_actions.h
+++ b/pcbnew/tools/pcb_actions.h
@@ -406,6 +406,8 @@ public:
static TOOL_ACTION copySettingsToPads;
static TOOL_ACTION globalEditPads;
+ static TOOL_ACTION autoplaceOffboardComponents;
+ static TOOL_ACTION autoplaceSelectedComponents;
///> @copydoc COMMON_ACTIONS::TranslateLegacyId()
virtual OPT<TOOL_EVENT> TranslateLegacyId( int aId ) override;
diff --git a/pcbnew/tools/tools_common.cpp b/pcbnew/tools/tools_common.cpp
index 76d2d57..4bc4cfa 100644
--- a/pcbnew/tools/tools_common.cpp
+++ b/pcbnew/tools/tools_common.cpp
@@ -45,6 +45,7 @@
#include <router/router_tool.h>
#include <router/length_tuner_tool.h>
+#include <autorouter/autoplacer_tool.h>
void PCB_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager )
{
@@ -64,4 +65,5 @@ void PCB_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager )
aToolManager->RegisterTool( new MICROWAVE_TOOL );
aToolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
aToolManager->RegisterTool( new ZONE_FILLER_TOOL );
+ aToolManager->RegisterTool( new AUTOPLACE_TOOL );
}
--
2.7.4
Follow ups