kicad/pcbnew/autorouter/solve.cpp

1349 lines
42 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
*
* 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
*/
/* see "Autorouting With the A* Algorithm" (Dr.Dobbs journal)
*/
/**
* @file solve.cpp
*/
#include <fctsys.h>
#include <class_drawpanel.h>
#include <confirm.h>
#include <wxPcbStruct.h>
#include <gr_basic.h>
#include <macros.h>
#include <class_board.h>
#include <class_track.h>
#include <pcbnew.h>
#include <protos.h>
#include <autorout.h>
#include <cell.h>
static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe,
wxDC* DC,
int two_sides,
int row_source,
int col_source,
int row_target,
int col_target,
RATSNEST_ITEM* pt_rat );
static int Retrace( PCB_EDIT_FRAME* pcbframe,
wxDC* DC,
int,
int,
int,
int,
int,
int net_code );
static void OrCell_Trace( BOARD* pcb,
int col,
int row,
int side,
int orient,
int current_net_code );
static void AddNewTrace( PCB_EDIT_FRAME* pcbframe, wxDC* DC );
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
2007-08-23 04:28:46 +00:00
#define NOSUCCESS 0
#define STOP_FROM_ESC -1
#define ERR_MEMORY -2
#define SUCCESS 1
#define TRIVIAL_SUCCESS 2
/*
** visit neighboring cells like this (where [9] is on the other side):
**
** +---+---+---+
** | 1 | 2 | 3 |
** +---+---+---+
** | 4 |[9]| 5 |
** +---+---+---+
** | 6 | 7 | 8 |
** +---+---+---+
*/
/* for visiting neighbors on the same side: increments/decrements coord of
* [] [0] = row [] (1] = col was added to the coord of the midpoint for
* Get the coord of the 8 neighboring points.
*/
static const int delta[8][2] =
{
{ 1, -1 }, // northwest
{ 1, 0 }, // north
{ 1, 1 }, // northeast
{ 0, -1 }, // west
{ 0, 1 }, // east
{ -1, -1 }, // southwest
{ -1, 0 }, // south
{ -1, 1 } // southeast
2007-08-23 04:28:46 +00:00
};
static const int ndir[8] =
{
// for building paths back to source
2009-01-25 17:38:30 +00:00
FROM_SOUTHEAST, FROM_SOUTH, FROM_SOUTHWEST,
2007-08-23 04:28:46 +00:00
FROM_EAST, FROM_WEST,
2009-01-25 17:38:30 +00:00
FROM_NORTHEAST, FROM_NORTH, FROM_NORTHWEST
2007-08-23 04:28:46 +00:00
};
// blocking masks for neighboring cells
#define BLOCK_NORTHEAST ( DIAG_NEtoSW | BENT_StoNE | BENT_WtoNE \
| ANGLE_NEtoSE | ANGLE_NWtoNE \
| SHARP_NtoNE | SHARP_EtoNE | HOLE )
#define BLOCK_SOUTHEAST ( DIAG_SEtoNW | BENT_NtoSE | BENT_WtoSE \
| ANGLE_NEtoSE | ANGLE_SEtoSW \
| SHARP_EtoSE | SHARP_StoSE | HOLE )
#define BLOCK_SOUTHWEST ( DIAG_NEtoSW | BENT_NtoSW | BENT_EtoSW \
| ANGLE_SEtoSW | ANGLE_SWtoNW \
| SHARP_StoSW | SHARP_WtoSW | HOLE )
#define BLOCK_NORTHWEST ( DIAG_SEtoNW | BENT_EtoNW | BENT_StoNW \
| ANGLE_SWtoNW | ANGLE_NWtoNE \
| SHARP_WtoNW | SHARP_NtoNW | HOLE )
#define BLOCK_NORTH ( LINE_VERTICAL | BENT_NtoSE | BENT_NtoSW \
| BENT_EtoNW | BENT_WtoNE \
| BENT_StoNE | BENT_StoNW \
| CORNER_NORTHEAST | CORNER_NORTHWEST \
| ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_NWtoNE \
| DIAG_NEtoSW | DIAG_SEtoNW \
| SHARP_NtoNE | SHARP_NtoNW \
| SHARP_EtoNE | SHARP_WtoNW | HOLE )
#define BLOCK_EAST ( LINE_HORIZONTAL | BENT_EtoSW | BENT_EtoNW \
| BENT_NtoSE | BENT_StoNE \
| BENT_WtoNE | BENT_WtoSE \
| CORNER_NORTHEAST | CORNER_SOUTHEAST \
| ANGLE_NEtoSE | ANGLE_SEtoSW | ANGLE_NWtoNE \
| DIAG_NEtoSW | DIAG_SEtoNW \
| SHARP_EtoNE | SHARP_EtoSE \
| SHARP_NtoNE | SHARP_StoSE | HOLE )
#define BLOCK_SOUTH ( LINE_VERTICAL | BENT_StoNE | BENT_StoNW \
| BENT_EtoSW | BENT_WtoSE \
| BENT_NtoSE | BENT_NtoSW \
| CORNER_SOUTHEAST | CORNER_SOUTHWEST \
| ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_SEtoSW \
| DIAG_NEtoSW | DIAG_SEtoNW \
| SHARP_StoSE | SHARP_StoSW \
| SHARP_EtoSE | SHARP_WtoSW | HOLE )
#define BLOCK_WEST ( LINE_HORIZONTAL | BENT_WtoNE | BENT_WtoSE \
| BENT_NtoSW | BENT_StoNW \
| BENT_EtoSW | BENT_EtoNW \
| CORNER_SOUTHWEST | CORNER_NORTHWEST \
| ANGLE_SWtoNW | ANGLE_SEtoSW | ANGLE_NWtoNE \
| DIAG_NEtoSW | DIAG_SEtoNW \
| SHARP_WtoSW | SHARP_WtoNW \
| SHARP_NtoNW | SHARP_StoSW | HOLE )
2007-08-23 04:28:46 +00:00
struct block
{
int r1, c1;
long b1;
int r2, c2;
long b2;
};
// blocking masks for diagonal traces
static struct block blocking[8] =
{ {
0, -1,
BLOCK_NORTHEAST,
1, 0,
BLOCK_SOUTHWEST
},
{
0, 0, 0,
0, 0, 0
},
{
1, 0,
BLOCK_SOUTHEAST,
0, 1,
BLOCK_NORTHWEST
},
{
0, 0, 0,
0, 0, 0
},
{
0, 0, 0,
0, 0, 0
},
{
0, -1,
BLOCK_SOUTHEAST,
-1, 0,
BLOCK_NORTHWEST
},
{
0, 0, 0,
0, 0, 0
},
{
-1, 0,
BLOCK_NORTHEAST,
0, 1,
BLOCK_SOUTHWEST
} };
// mask for hole-related blocking effects
2007-08-23 04:28:46 +00:00
static struct
{
long trace;
int present;
} selfok2[8] =
{
{ HOLE_NORTHWEST, 0 },
{ HOLE_NORTH, 0 },
{ HOLE_NORTHEAST, 0 },
{ HOLE_WEST, 0 },
{ HOLE_EAST, 0 },
{ HOLE_SOUTHWEST, 0 },
{ HOLE_SOUTH, 0 },
{ HOLE_SOUTHEAST, 0 }
2007-08-23 04:28:46 +00:00
};
static long newmask[8] =
{
// patterns to mask out in neighbor cells
0,
CORNER_NORTHWEST | CORNER_NORTHEAST,
2009-01-25 17:38:30 +00:00
0,
CORNER_NORTHWEST | CORNER_SOUTHWEST,
CORNER_NORTHEAST | CORNER_SOUTHEAST,
0,
CORNER_SOUTHWEST | CORNER_SOUTHEAST,
2009-01-25 17:38:30 +00:00
0
2007-08-23 04:28:46 +00:00
};
/* Route all traces
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
* :
* 1 if OK
* -1 if escape (stop being routed) request
* -2 if default memory allocation
2007-08-23 04:28:46 +00:00
*/
int PCB_EDIT_FRAME::Solve( wxDC* DC, int aLayersCount )
{
int current_net_code;
int row_source, col_source, row_target, col_target;
int success, nbsucces = 0, nbunsucces = 0;
NETINFO_ITEM* net;
bool stop = false;
wxString msg;
int routedCount = 0; // routed ratsnest count
bool two_sides = aLayersCount == 2;
2007-08-23 04:28:46 +00:00
m_canvas->SetAbortRequest( false );
2007-08-23 04:28:46 +00:00
s_Clearance = GetBoard()->GetDesignSettings().GetDefault()->GetClearance();
// Prepare the undo command info
s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but...
// go until no more work to do
2007-08-23 04:28:46 +00:00
GetWork( &row_source, &col_source, &current_net_code,
&row_target, &col_target, &pt_cur_ch ); // First net to route.
2007-08-23 04:28:46 +00:00
for( ; row_source != ILLEGAL; GetWork( &row_source, &col_source,
&current_net_code, &row_target,
&col_target,
2009-01-25 17:38:30 +00:00
&pt_cur_ch ) )
2007-08-23 04:28:46 +00:00
{
// Test to stop routing ( escape key pressed )
2007-08-23 04:28:46 +00:00
wxYield();
if( m_canvas->GetAbortRequest() )
2007-08-23 04:28:46 +00:00
{
if( IsOK( this, _( "Abort routing?" ) ) )
{
success = STOP_FROM_ESC;
2011-03-09 14:30:39 +00:00
stop = true;
2007-08-23 04:28:46 +00:00
break;
}
else
{
m_canvas->SetAbortRequest( false );
}
2007-08-23 04:28:46 +00:00
}
EraseMsgBox();
routedCount++;
net = GetBoard()->FindNet( current_net_code );
if( net )
2007-08-23 04:28:46 +00:00
{
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 );
2007-08-23 04:28:46 +00:00
}
segm_oX = GetBoard()->GetBoundingBox().GetX() + (RoutingMatrix.m_GridRouting * col_source);
segm_oY = GetBoard()->GetBoundingBox().GetY() + (RoutingMatrix.m_GridRouting * row_source);
segm_fX = GetBoard()->GetBoundingBox().GetX() + (RoutingMatrix.m_GridRouting * col_target);
segm_fY = GetBoard()->GetBoundingBox().GetY() + (RoutingMatrix.m_GridRouting * row_target);
// Draw segment.
GRLine( m_canvas->GetClipBox(), DC,
segm_oX, segm_oY, segm_fX, segm_fY,
0, WHITE );
pt_cur_ch->m_PadStart->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
pt_cur_ch->m_PadEnd->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
2007-08-23 04:28:46 +00:00
success = Autoroute_One_Track( this, DC,
two_sides, row_source, col_source,
row_target, col_target, pt_cur_ch );
2007-08-23 04:28:46 +00:00
switch( success )
{
case NOSUCCESS:
pt_cur_ch->m_Status |= CH_UNROUTABLE;
2007-08-23 04:28:46 +00:00
nbunsucces++;
break;
case STOP_FROM_ESC:
2011-03-09 14:30:39 +00:00
stop = true;
2007-08-23 04:28:46 +00:00
break;
case ERR_MEMORY:
2011-03-09 14:30:39 +00:00
stop = true;
2007-08-23 04:28:46 +00:00
break;
default:
nbsucces++;
break;
}
msg.Printf( wxT( "%d" ), nbsucces );
AppendMsgPanel( wxT( "OK" ), msg, GREEN );
msg.Printf( wxT( "%d" ), nbunsucces );
AppendMsgPanel( wxT( "Fail" ), msg, RED );
msg.Printf( wxT( " %d" ), GetBoard()->GetUnconnectedNetCount() );
AppendMsgPanel( wxT( "Not Connected" ), msg, CYAN );
2007-08-23 04:28:46 +00:00
// Delete routing from display.
pt_cur_ch->m_PadStart->Draw( m_canvas, DC, GR_AND );
pt_cur_ch->m_PadEnd->Draw( m_canvas, DC, GR_AND );
2007-08-23 04:28:46 +00:00
if( stop )
break;
}
SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
2007-08-23 04:28:46 +00:00
return SUCCESS;
}
2007-08-23 04:28:46 +00:00
/* Route a trace on the BOARD.
* Parameters:
* 1 side / 2 sides (0 / 1)
* Coord source (row, col)
* Coord destination (row, col)
* Net_code
* Pointer to the ratsnest reference
2008-02-12 01:02:53 +00:00
*
* Returns:
* SUCCESS if routed
2011-03-09 14:30:39 +00:00
* TRIVIAL_SUCCESS if pads are connected by overlay (no track needed)
* If failure NOSUCCESS
* Escape STOP_FROM_ESC if demand
* ERR_MEMORY if memory allocation failed.
2007-08-23 04:28:46 +00:00
*/
static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe,
wxDC* DC,
int two_sides,
int row_source,
int col_source,
int row_target,
int col_target,
RATSNEST_ITEM* pt_rat )
{
int r, c, side, d, apx_dist, nr, nc;
int result, skip;
int i;
long curcell, newcell, buddy, lastopen, lastclos, lastmove;
int newdist, olddir, _self;
int current_net_code;
int marge;
LSET padLayerMaskStart; // Mask layers belonging to the starting pad.
LSET padLayerMaskEnd; // Mask layers belonging to the ending pad.
LSET topLayerMask( g_Route_Layer_TOP );
LSET bottomLayerMask( g_Route_Layer_BOTTOM );
LSET routeLayerMask; // Mask two layers for routing.
LSET tab_mask[2]; // Enables the calculation of the mask layer being
// tested. (side = TOP or BOTTOM)
int start_mask_layer = 0;
wxString msg;
// @todo this could be a bottle neck
LSET all_cu = LSET::AllCuMask( pcbframe->GetBoard()->GetCopperLayerCount() );
wxBusyCursor dummy_cursor; // Set an hourglass cursor while routing a
// track
2009-01-25 17:48:59 +00:00
2007-08-23 04:28:46 +00:00
result = NOSUCCESS;
marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 );
2007-08-23 04:28:46 +00:00
// clear direction flags
i = RoutingMatrix.m_Nrows * 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 );
2007-08-23 04:28:46 +00:00
lastopen = lastclos = lastmove = 0;
// Set tab_masque[side] for final test of routing.
if( two_sides )
tab_mask[TOP] = topLayerMask;
tab_mask[BOTTOM] = bottomLayerMask;
// Set active layers mask.
routeLayerMask = topLayerMask | bottomLayerMask;
2007-08-23 04:28:46 +00:00
pt_cur_ch = pt_rat;
2012-02-19 04:02:19 +00:00
current_net_code = pt_rat->GetNet();
padLayerMaskStart = pt_cur_ch->m_PadStart->GetLayerSet();
2012-02-19 04:02:19 +00:00
padLayerMaskEnd = pt_cur_ch->m_PadEnd->GetLayerSet();
2007-08-23 04:28:46 +00:00
/* First Test if routing possible ie if the pads are accessible
* on the routing layers.
*/
if( ( routeLayerMask & padLayerMaskStart ) == 0 )
2007-08-23 04:28:46 +00:00
goto end_of_route;
if( ( routeLayerMask & padLayerMaskEnd ) == 0 )
2007-08-23 04:28:46 +00:00
goto end_of_route;
/* Then test if routing possible ie if the pads are accessible
* On the routing grid (1 grid point must be in the pad)
*/
2007-08-23 04:28:46 +00:00
{
int cX = ( RoutingMatrix.m_GridRouting * col_source )
+ pcbframe->GetBoard()->GetBoundingBox().GetX();
int cY = ( RoutingMatrix.m_GridRouting * row_source )
+ pcbframe->GetBoard()->GetBoundingBox().GetY();
2012-02-19 04:02:19 +00:00
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;
2007-08-23 04:28:46 +00:00
2012-02-19 04:02:19 +00:00
if( ( ( int( pt_cur_ch->m_PadStart->GetOrientation() ) / 900 ) & 1 ) != 0 )
std::swap( dx, dy );
if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
2007-08-23 04:28:46 +00:00
goto end_of_route;
cX = ( RoutingMatrix.m_GridRouting * col_target )
+ pcbframe->GetBoard()->GetBoundingBox().GetX();
cY = ( RoutingMatrix.m_GridRouting * row_target )
+ pcbframe->GetBoard()->GetBoundingBox().GetY();
2012-02-19 04:02:19 +00:00
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;
2012-02-19 04:02:19 +00:00
if( ( ( int( pt_cur_ch->m_PadEnd->GetOrientation() ) / 900) & 1 ) != 0 )
std::swap( dx, dy );
2007-08-23 04:28:46 +00:00
if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
2007-08-23 04:28:46 +00:00
goto end_of_route;
}
// Test the trivial case: direct connection overlay pads.
if( row_source == row_target && col_source == col_target &&
( padLayerMaskEnd & padLayerMaskStart & all_cu ).any() )
2007-08-23 04:28:46 +00:00
{
result = TRIVIAL_SUCCESS;
goto end_of_route;
}
// Placing the bit to remove obstacles on 2 pads to a link.
pcbframe->SetStatusText( wxT( "Gen Cells" ) );
2007-08-23 04:28:46 +00:00
PlacePad( pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL );
PlacePad( pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL );
2007-08-23 04:28:46 +00:00
// Regenerates the remaining barriers (which may encroach on the
// placement bits precedent)
i = pcbframe->GetBoard()->GetPadCount();
for( unsigned ii = 0; ii < pcbframe->GetBoard()->GetPadCount(); ii++ )
2007-08-23 04:28:46 +00:00
{
D_PAD* ptr = pcbframe->GetBoard()->GetPad( ii );
if( ( pt_cur_ch->m_PadStart != ptr ) && ( pt_cur_ch->m_PadEnd != ptr ) )
2007-08-23 04:28:46 +00:00
{
PlacePad( ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL );
2007-08-23 04:28:46 +00:00
}
}
InitQueue(); // initialize the search queue
apx_dist = RoutingMatrix.GetApxDist( row_source, col_source, row_target, col_target );
2007-08-23 04:28:46 +00:00
// Initialize first search.
if( two_sides ) // Preferred orientation.
2007-08-23 04:28:46 +00:00
{
if( abs( row_target - row_source ) > abs( col_target - col_source ) )
{
if( ( padLayerMaskStart & topLayerMask ).any() )
2007-08-23 04:28:46 +00:00
{
start_mask_layer = 2;
2007-08-23 04:28:46 +00:00
if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
2009-01-25 17:38:30 +00:00
row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
if( ( padLayerMaskStart & bottomLayerMask ).any() )
2007-08-23 04:28:46 +00:00
{
start_mask_layer |= 1;
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
2009-01-25 17:38:30 +00:00
row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
}
else
{
if( ( padLayerMaskStart & bottomLayerMask ).any() )
2007-08-23 04:28:46 +00:00
{
start_mask_layer = 1;
2007-08-23 04:28:46 +00:00
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
2009-01-25 17:38:30 +00:00
row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
if( ( padLayerMaskStart & topLayerMask ).any() )
2007-08-23 04:28:46 +00:00
{
start_mask_layer |= 2;
if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
2009-01-25 17:38:30 +00:00
row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
}
}
else if( ( padLayerMaskStart & bottomLayerMask ).any() )
2007-08-23 04:28:46 +00:00
{
start_mask_layer = 1;
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
// search until success or we exhaust all possibilities
2007-08-23 04:28:46 +00:00
GetQueue( &r, &c, &side, &d, &apx_dist );
2007-08-23 04:28:46 +00:00
for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) )
{
curcell = RoutingMatrix.GetCell( r, c, side );
2007-08-23 04:28:46 +00:00
if( curcell & CURRENT_PAD )
curcell &= ~HOLE;
if( (r == row_target) && (c == col_target) // success if layer OK
&& (tab_mask[side] & padLayerMaskEnd).any() )
2007-08-23 04:28:46 +00:00
{
// Remove link.
2007-08-23 04:28:46 +00:00
GRSetDrawMode( DC, GR_XOR );
GRLine( pcbframe->GetCanvas()->GetClipBox(),
2009-01-25 17:38:30 +00:00
DC,
segm_oX,
segm_oY,
segm_fX,
segm_fY,
0,
WHITE );
2007-08-23 04:28:46 +00:00
// Generate trace.
2007-08-23 04:28:46 +00:00
if( Retrace( pcbframe, DC, row_source, col_source,
2009-01-25 17:38:30 +00:00
row_target, col_target, side, current_net_code ) )
2007-08-23 04:28:46 +00:00
{
result = SUCCESS; // Success : Route OK
2007-08-23 04:28:46 +00:00
}
break; // Routing complete.
2007-08-23 04:28:46 +00:00
}
if( pcbframe->GetCanvas()->GetAbortRequest() )
{
result = STOP_FROM_ESC;
break;
2007-08-23 04:28:46 +00:00
}
// report every COUNT new nodes or so
2009-01-28 17:08:35 +00:00
#define COUNT 20000
if( ( OpenNodes - lastopen > COUNT )
|| ( ClosNodes - lastclos > COUNT )
|| ( MoveNodes - lastmove > COUNT ) )
2009-09-10 15:22:26 +00:00
{
lastopen = OpenNodes;
2009-01-28 17:08:35 +00:00
lastclos = ClosNodes;
2009-09-10 15:22:26 +00:00
lastmove = MoveNodes;
msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d" ),
OpenNodes, ClosNodes, MoveNodes );
pcbframe->SetStatusText( msg );
2009-09-10 15:22:26 +00:00
}
2009-01-28 17:08:35 +00:00
2007-08-23 04:28:46 +00:00
_self = 0;
2007-08-23 04:28:46 +00:00
if( curcell & HOLE )
{
_self = 5;
// set 'present' bits
2007-08-23 04:28:46 +00:00
for( i = 0; i < 8; i++ )
{
selfok2[i].present = 0;
if( curcell & selfok2[i].trace )
2007-08-23 04:28:46 +00:00
selfok2[i].present = 1;
}
}
for( i = 0; i < 8; i++ ) // consider neighbors
2007-08-23 04:28:46 +00:00
{
nr = r + delta[i][0];
nc = c + delta[i][1];
2007-08-23 04:28:46 +00:00
// off the edge?
if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
nc < 0 || nc >= RoutingMatrix.m_Ncols )
continue; // off the edge
2007-08-23 04:28:46 +00:00
if( _self == 5 && selfok2[i].present )
continue;
newcell = RoutingMatrix.GetCell( nr, nc, side );
2007-08-23 04:28:46 +00:00
if( newcell & CURRENT_PAD )
newcell &= ~HOLE;
// check for non-target hole
2007-08-23 04:28:46 +00:00
if( newcell & HOLE )
{
if( nr != row_target || nc != col_target )
continue;
}
// check for traces
2007-08-23 04:28:46 +00:00
else if( newcell & HOLE & ~(newmask[i]) )
{
2007-08-23 04:28:46 +00:00
continue;
}
2007-08-23 04:28:46 +00:00
// check blocking on corner neighbors
2007-08-23 04:28:46 +00:00
if( delta[i][0] && delta[i][1] )
{
// check first buddy
buddy = RoutingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side );
2007-08-23 04:28:46 +00:00
if( buddy & CURRENT_PAD )
buddy &= ~HOLE;
2007-08-23 04:28:46 +00:00
if( buddy & HOLE )
continue;
// if (buddy & (blocking[i].b1)) continue;
// check second buddy
buddy = RoutingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side );
2007-08-23 04:28:46 +00:00
if( buddy & CURRENT_PAD )
buddy &= ~HOLE;
2007-08-23 04:28:46 +00:00
if( buddy & HOLE )
continue;
// if (buddy & (blocking[i].b2)) continue;
2007-08-23 04:28:46 +00:00
}
olddir = RoutingMatrix.GetDir( r, c, side );
newdist = d + RoutingMatrix.CalcDist( ndir[i], olddir,
( olddir == FROM_OTHERSIDE ) ?
RoutingMatrix.GetDir( r, c, 1 - side ) : 0, side );
2007-08-23 04:28:46 +00:00
// if (a) not visited yet, or (b) we have
// found a better path, add it to queue
if( !RoutingMatrix.GetDir( nr, nc, side ) )
2007-08-23 04:28:46 +00:00
{
RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
RoutingMatrix.SetDist( nr, nc, side, newdist );
2007-08-23 04:28:46 +00:00
if( SetQueue( nr, nc, side, newdist,
RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
2009-01-25 17:38:30 +00:00
row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
else if( newdist < RoutingMatrix.GetDist( nr, nc, side ) )
2007-08-23 04:28:46 +00:00
{
RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
RoutingMatrix.SetDist( nr, nc, side, newdist );
2007-08-23 04:28:46 +00:00
ReSetQueue( nr, nc, side, newdist,
RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
2009-01-25 17:38:30 +00:00
row_target, col_target );
2007-08-23 04:28:46 +00:00
}
}
//* Test the other layer. *
if( two_sides )
2007-08-23 04:28:46 +00:00
{
olddir = RoutingMatrix.GetDir( r, c, side );
2007-08-23 04:28:46 +00:00
if( olddir == FROM_OTHERSIDE )
continue; // useless move, so don't bother
if( curcell ) // can't drill via if anything here
2007-08-23 04:28:46 +00:00
continue;
// check for holes or traces on other side
if( ( newcell = RoutingMatrix.GetCell( r, c, 1 - side ) ) != 0 )
2007-08-23 04:28:46 +00:00
continue;
// check for nearby holes or traces on both sides
2007-08-23 04:28:46 +00:00
for( skip = 0, i = 0; i < 8; i++ )
{
nr = r + delta[i][0]; nc = c + delta[i][1];
if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
nc < 0 || nc >= RoutingMatrix.m_Ncols )
continue; // off the edge !!
2007-08-23 04:28:46 +00:00
if( RoutingMatrix.GetCell( nr, nc, side ) /* & blocking2[i] */ )
2007-08-23 04:28:46 +00:00
{
skip = 1; // can't drill via here
2007-08-23 04:28:46 +00:00
break;
}
if( RoutingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i] */ )
2007-08-23 04:28:46 +00:00
{
skip = 1; // can't drill via here
2007-08-23 04:28:46 +00:00
break;
}
}
if( skip ) // neighboring hole or trace?
continue; // yes, can't drill via here
2007-08-23 04:28:46 +00:00
newdist = d + RoutingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side );
2007-08-23 04:28:46 +00:00
/* if (a) not visited yet,
* or (b) we have found a better path,
* add it to queue */
if( !RoutingMatrix.GetDir( r, c, 1 - side ) )
2007-08-23 04:28:46 +00:00
{
RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
RoutingMatrix.SetDist( r, c, 1 - side, newdist );
if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ) == 0 )
2007-08-23 04:28:46 +00:00
{
return ERR_MEMORY;
}
}
else if( newdist < RoutingMatrix.GetDist( r, c, 1 - side ) )
2007-08-23 04:28:46 +00:00
{
RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
RoutingMatrix.SetDist( r, c, 1 - side, newdist );
ReSetQueue( r, c,
1 - side,
newdist,
apx_dist,
row_target,
col_target );
2007-08-23 04:28:46 +00:00
}
} // Finished attempt to route on other layer.
2007-08-23 04:28:46 +00:00
}
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 );
msg.Printf( wxT( "Activity: Open %d Closed %d Moved %d"),
OpenNodes, ClosNodes, MoveNodes );
pcbframe->SetStatusText( msg );
2009-01-28 17:08:35 +00:00
2007-08-23 04:28:46 +00:00
return result;
}
2007-08-23 04:28:46 +00:00
static long bit[8][9] =
{
// OT=Otherside
// N, NE, E, SE, S, SW, W, NW, OT
// N
{ LINE_VERTICAL,
BENT_StoNE,
CORNER_SOUTHEAST,
SHARP_StoSE,
0,
SHARP_StoSW,
CORNER_SOUTHWEST,
BENT_StoNW,
( HOLE | HOLE_SOUTH )
},
// NE
{
BENT_NtoSW,
DIAG_NEtoSW,
BENT_EtoSW,
ANGLE_SEtoSW,
SHARP_StoSW,
0,
SHARP_WtoSW,
ANGLE_SWtoNW,
( HOLE | HOLE_SOUTHWEST )
},
// E
{
CORNER_NORTHWEST,
BENT_WtoNE,
LINE_HORIZONTAL,
BENT_WtoSE,
CORNER_SOUTHWEST,
SHARP_WtoSW,
0,
SHARP_WtoNW,
( HOLE | HOLE_WEST )
},
// SE
{
SHARP_NtoNW,
ANGLE_NWtoNE,
BENT_EtoNW,
DIAG_SEtoNW,
BENT_StoNW,
ANGLE_SWtoNW,
SHARP_WtoNW,
0,
( HOLE | HOLE_NORTHWEST )
},
// S
{
0,
SHARP_NtoNE,
CORNER_NORTHEAST,
BENT_NtoSE,
LINE_VERTICAL,
BENT_NtoSW,
CORNER_NORTHWEST,
SHARP_NtoNW,
( HOLE | HOLE_NORTH )
},
// SW
{
SHARP_NtoNE,
0,
SHARP_EtoNE,
ANGLE_NEtoSE,
BENT_StoNE,
DIAG_NEtoSW,
BENT_WtoNE,
ANGLE_NWtoNE,
( HOLE | HOLE_NORTHEAST )
},
// W
{
CORNER_NORTHEAST,
SHARP_EtoNE,
0,
SHARP_EtoSE,
CORNER_SOUTHEAST,
BENT_EtoSW,
LINE_HORIZONTAL,
BENT_EtoNW,
( HOLE | HOLE_EAST )
},
// NW
{
BENT_NtoSE,
ANGLE_NEtoSE,
SHARP_EtoSE,
0,
SHARP_StoSE,
ANGLE_SEtoSW,
BENT_WtoSE,
DIAG_SEtoNW,
( HOLE | HOLE_SOUTHEAST )
}
2007-08-23 04:28:46 +00:00
};
2009-01-25 17:38:30 +00:00
/* work from target back to source, actually laying the traces
* Parameters:
* start on side target_side, of coordinates row_target, col_target.
* arrive on side masque_layer_start, coordinate row_source, col_source
* The search is done in reverse routing, the point of arrival (target) to
* the starting point (source)
* The router.
2008-02-12 01:02:53 +00:00
*
* Target_side = symbol (TOP / BOTTOM) of departure
* = Mask_layer_source mask layers Arrival
2008-02-12 01:02:53 +00:00
*
* Returns:
* 0 if error
* > 0 if Ok
2007-08-23 04:28:46 +00:00
*/
static int Retrace( PCB_EDIT_FRAME* pcbframe, wxDC* DC,
int row_source, int col_source,
int row_target, int col_target, int target_side,
int current_net_code )
{
2007-08-23 04:28:46 +00:00
int r0, c0, s0;
int r1, c1, s1; // row, col, starting side.
int r2, c2, s2; // row, col, ending side.
2007-08-23 04:28:46 +00:00
int x, y = -1;
long b;
r1 = row_target;
c1 = col_target; // start point is target ( end point is source )
2007-08-23 04:28:46 +00:00
s1 = target_side;
r0 = c0 = s0 = ILLEGAL;
wxASSERT( g_CurrentTrackList.GetCount() == 0 );
2007-08-23 04:28:46 +00:00
do
{
// find where we came from to get here
2007-08-23 04:28:46 +00:00
r2 = r1; c2 = c1; s2 = s1;
x = RoutingMatrix.GetDir( r1, c1, s1 );
2007-08-23 04:28:46 +00:00
switch( x )
{
case FROM_NORTH:
r2++;
break;
2007-08-23 04:28:46 +00:00
case FROM_EAST:
c2++;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTH:
r2--;
break;
2007-08-23 04:28:46 +00:00
case FROM_WEST:
c2--;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHEAST:
r2++;
c2++;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHEAST:
r2--;
c2++;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHWEST:
r2--;
c2--;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHWEST:
r2++;
c2--;
break;
2007-08-23 04:28:46 +00:00
case FROM_OTHERSIDE:
s2 = 1 - s2;
break;
2007-08-23 04:28:46 +00:00
default:
wxMessageBox( wxT( "Retrace: internal error: no way back" ) );
2007-08-23 04:28:46 +00:00
return 0;
}
if( r0 != ILLEGAL )
y = RoutingMatrix.GetDir( r0, c0, s0 );
2007-08-23 04:28:46 +00:00
// see if target or hole
if( ( ( r1 == row_target ) && ( c1 == col_target ) ) || ( s1 != s0 ) )
2007-08-23 04:28:46 +00:00
{
int p_dir;
switch( x )
{
case FROM_NORTH:
p_dir = HOLE_NORTH;
break;
2007-08-23 04:28:46 +00:00
case FROM_EAST:
p_dir = HOLE_EAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTH:
p_dir = HOLE_SOUTH;
break;
2007-08-23 04:28:46 +00:00
case FROM_WEST:
p_dir = HOLE_WEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHEAST:
p_dir = HOLE_NORTHEAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHEAST:
p_dir = HOLE_SOUTHEAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHWEST:
p_dir = HOLE_SOUTHWEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHWEST:
p_dir = HOLE_NORTHWEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_OTHERSIDE:
default:
DisplayError( pcbframe, wxT( "Retrace: error 1" ) );
return 0;
}
OrCell_Trace( pcbframe->GetBoard(), r1, c1, s1, p_dir, current_net_code );
2007-08-23 04:28:46 +00:00
}
else
{
if( ( y == FROM_NORTH || y == FROM_NORTHEAST
|| y == FROM_EAST || y == FROM_SOUTHEAST
|| y == FROM_SOUTH || y == FROM_SOUTHWEST
|| y == FROM_WEST || y == FROM_NORTHWEST )
&& ( x == FROM_NORTH || x == FROM_NORTHEAST
|| x == FROM_EAST || x == FROM_SOUTHEAST
|| x == FROM_SOUTH || x == FROM_SOUTHWEST
|| x == FROM_WEST || x == FROM_NORTHWEST
|| x == FROM_OTHERSIDE )
&& ( ( b = bit[y - 1][x - 1] ) != 0 ) )
2007-08-23 04:28:46 +00:00
{
OrCell_Trace( pcbframe->GetBoard(), r1, c1, s1, b, current_net_code );
2007-08-23 04:28:46 +00:00
if( b & HOLE )
OrCell_Trace( pcbframe->GetBoard(), r2, c2, s2, HOLE, current_net_code );
2007-08-23 04:28:46 +00:00
}
else
{
wxMessageBox( wxT( "Retrace: error 2" ) );
2007-08-23 04:28:46 +00:00
return 0;
}
}
if( ( r2 == row_source ) && ( c2 == col_source ) ) // see if source
{
2007-08-23 04:28:46 +00:00
int p_dir;
switch( x )
{
case FROM_NORTH:
p_dir = HOLE_SOUTH;
break;
2007-08-23 04:28:46 +00:00
case FROM_EAST:
p_dir = HOLE_WEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTH:
p_dir = HOLE_NORTH;
break;
2007-08-23 04:28:46 +00:00
case FROM_WEST:
p_dir = HOLE_EAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHEAST:
p_dir = HOLE_SOUTHWEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHEAST:
p_dir = HOLE_NORTHWEST;
break;
2007-08-23 04:28:46 +00:00
case FROM_SOUTHWEST:
p_dir = HOLE_NORTHEAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_NORTHWEST:
p_dir = HOLE_SOUTHEAST;
break;
2007-08-23 04:28:46 +00:00
case FROM_OTHERSIDE:
default:
wxMessageBox( wxT( "Retrace: error 3" ) );
2007-08-23 04:28:46 +00:00
return 0;
}
OrCell_Trace( pcbframe->GetBoard(), r2, c2, s2, p_dir, current_net_code );
2007-08-23 04:28:46 +00:00
}
// move to next cell
r0 = r1;
c0 = c1;
s0 = s1;
r1 = r2;
c1 = c2;
s1 = s2;
} while( !( ( r2 == row_source ) && ( c2 == col_source ) ) );
2007-08-23 04:28:46 +00:00
AddNewTrace( pcbframe, DC );
2007-08-23 04:28:46 +00:00
return 1;
}
/* This function is used by Retrace and read the autorouting matrix data cells to create
* the real track on the physical board
*/
2007-08-23 04:28:46 +00:00
static void OrCell_Trace( BOARD* pcb, int col, int row,
int side, int orient, int current_net_code )
{
if( orient == HOLE ) // placement of a via
2007-08-23 04:28:46 +00:00
{
VIA *newVia = new VIA( pcb );
2007-08-23 04:28:46 +00:00
g_CurrentTrackList.PushBack( newVia );
2007-08-23 04:28:46 +00:00
g_CurrentTrackSegment->SetState( TRACK_AR, true );
g_CurrentTrackSegment->SetLayer( F_Cu );
g_CurrentTrackSegment->SetStart(wxPoint( pcb->GetBoundingBox().GetX() +
( RoutingMatrix.m_GridRouting * row ),
pcb->GetBoundingBox().GetY() +
( RoutingMatrix.m_GridRouting * col )));
g_CurrentTrackSegment->SetEnd( g_CurrentTrackSegment->GetStart() );
g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentViaSize() );
newVia->SetViaType( pcb->GetDesignSettings().m_CurrentViaType );
g_CurrentTrackSegment->SetNetCode( current_net_code );
2007-08-23 04:28:46 +00:00
}
else // placement of a standard segment
2007-08-23 04:28:46 +00:00
{
TRACK *newTrack = new TRACK( pcb );
int dx0, dy0, dx1, dy1;
2007-08-23 04:28:46 +00:00
g_CurrentTrackList.PushBack( newTrack );
2007-08-23 04:28:46 +00:00
g_CurrentTrackSegment->SetLayer( g_Route_Layer_BOTTOM );
2007-08-23 04:28:46 +00:00
if( side == TOP )
g_CurrentTrackSegment->SetLayer( g_Route_Layer_TOP );
2007-08-23 04:28:46 +00:00
g_CurrentTrackSegment->SetState( TRACK_AR, true );
g_CurrentTrackSegment->SetEnd( wxPoint( pcb->GetBoundingBox().GetX() +
( RoutingMatrix.m_GridRouting * row ),
pcb->GetBoundingBox().GetY() +
( RoutingMatrix.m_GridRouting * col )));
g_CurrentTrackSegment->SetNetCode( current_net_code );
2007-08-23 04:28:46 +00:00
if( g_CurrentTrackSegment->Back() == NULL ) // Start trace.
2007-08-23 04:28:46 +00:00
{
g_CurrentTrackSegment->SetStart( wxPoint( segm_fX, segm_fY ) );
2007-08-23 04:28:46 +00:00
// Placement on the center of the pad if outside grid.
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;
2007-08-23 04:28:46 +00:00
// If aligned, change the origin point.
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )
2007-08-23 04:28:46 +00:00
{
g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() );
2007-08-23 04:28:46 +00:00
}
else // Creation of a supplemental segment
2007-08-23 04:28:46 +00:00
{
g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() );
2008-02-12 01:02:53 +00:00
newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
newTrack->SetStart( g_CurrentTrackSegment->GetEnd());
2007-08-23 04:28:46 +00:00
g_CurrentTrackList.PushBack( newTrack );
2007-08-23 04:28:46 +00:00
}
}
else
{
if( g_CurrentTrackSegment->Back() )
2007-08-23 04:28:46 +00:00
{
g_CurrentTrackSegment->SetStart( g_CurrentTrackSegment->Back()->GetEnd() );
2007-08-23 04:28:46 +00:00
}
}
g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentTrackWidth() );
2007-08-23 04:28:46 +00:00
if( g_CurrentTrackSegment->GetStart() != g_CurrentTrackSegment->GetEnd() )
2007-08-23 04:28:46 +00:00
{
// Reduce aligned segments by one.
TRACK* oldTrack = g_CurrentTrackSegment->Back();
if( oldTrack && oldTrack->Type() != PCB_VIA_T )
2007-08-23 04:28:46 +00:00
{
dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x;
dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y;
dx0 = oldTrack->GetEnd().x - oldTrack->GetStart().x;
dy0 = oldTrack->GetEnd().y - oldTrack->GetStart().y;
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )
2007-08-23 04:28:46 +00:00
{
oldTrack->SetEnd( g_CurrentTrackSegment->GetEnd() );
delete g_CurrentTrackList.PopBack();
2007-08-23 04:28:46 +00:00
}
}
}
}
}
2007-08-23 04:28:46 +00:00
/* Insert the new track created in the list of tracks.
* amend the points of beginning and end of the track so that they are
* connected
* Center on pads even if they are off grid.
2007-08-23 04:28:46 +00:00
*/
static void AddNewTrace( PCB_EDIT_FRAME* pcbframe, wxDC* DC )
{
2009-01-25 17:38:30 +00:00
if( g_FirstTrackSegment == NULL )
return;
int dx0, dy0, dx1, dy1;
int marge, via_marge;
EDA_DRAW_PANEL* panel = pcbframe->GetCanvas();
PCB_SCREEN* screen = pcbframe->GetScreen();
marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 );
via_marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentViaSize() / 2 );
dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x;
dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y;
// 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;
// If aligned, change the origin point.
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) )
2007-08-23 04:28:46 +00:00
{
g_CurrentTrackSegment->SetEnd( pt_cur_ch->m_PadStart->GetPosition() );
2007-08-23 04:28:46 +00:00
}
else
2007-08-23 04:28:46 +00:00
{
TRACK* newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
2008-02-12 01:02:53 +00:00
newTrack->SetEnd( pt_cur_ch->m_PadStart->GetPosition() );
newTrack->SetStart( g_CurrentTrackSegment->GetEnd() );
g_CurrentTrackList.PushBack( newTrack );
2007-08-23 04:28:46 +00:00
}
g_FirstTrackSegment->start = pcbframe->GetBoard()->GetPad( g_FirstTrackSegment,
ENDPOINT_START );
2007-08-23 04:28:46 +00:00
if( g_FirstTrackSegment->start )
g_FirstTrackSegment->SetState( BEGIN_ONPAD, true );
g_CurrentTrackSegment->end = pcbframe->GetBoard()->GetPad( g_CurrentTrackSegment,
ENDPOINT_END );
2007-08-23 04:28:46 +00:00
if( g_CurrentTrackSegment->end )
g_CurrentTrackSegment->SetState( END_ONPAD, true );
// Out the new track on the matrix board
for( TRACK* track = g_FirstTrackSegment; track; track = track->Next() )
2007-08-23 04:28:46 +00:00
{
TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
2007-08-23 04:28:46 +00:00
}
2009-01-25 17:38:30 +00:00
// Insert new segments in real board
int netcode = g_FirstTrackSegment->GetNetCode();
2009-01-25 17:38:30 +00:00
TRACK* firstTrack = g_FirstTrackSegment;
int newCount = g_CurrentTrackList.GetCount();
// Put entire new current segment list in BOARD
TRACK* track;
TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( pcbframe->GetBoard() );
2009-01-25 17:38:30 +00:00
while( ( track = g_CurrentTrackList.PopFront() ) != NULL )
{
ITEM_PICKER picker( track, UR_NEW );
s_ItemsListPicker.PushItem( picker );
2009-01-25 17:38:30 +00:00
pcbframe->GetBoard()->m_Track.Insert( track, insertBeforeMe );
}
DrawTraces( panel, DC, firstTrack, newCount, GR_OR );
2009-01-25 17:38:30 +00:00
pcbframe->TestNetConnection( DC, netcode );
2009-01-25 17:38:30 +00:00
screen->SetModify();
}