kicad/pcbnew/autorouter/graphpcb.cpp

844 lines
24 KiB
C++
Raw Normal View History

/**
* @file graphpcb.cpp
* @brief PCB editor autorouting and "graphics" routines.
*/
/*
* 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) 2011 Wayne Stambaugh <stambaughw@verizon.net>
*
* 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 <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 <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 );
// 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 ); \
} \
else \
{ \
if( layer == g_Route_Layer_BOTTOM ) \
RoutingMatrix.WriteCell( dy, dx, BOTTOM, color ); \
if( RoutingMatrix.m_RoutingLayersCount > 1 ) \
if( layer == g_Route_Layer_TOP ) \
RoutingMatrix.WriteCell( dy, dx, TOP, color ); \
} \
}
void PlacePad( D_PAD* aPad, int color, int marge, int op_logic )
{
2007-08-23 04:28:46 +00:00
int dx, dy;
* 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
wxPoint shape_pos = aPad->ShapePos();
2007-08-23 04:28:46 +00:00
2012-02-19 04:02:19 +00:00
dx = aPad->GetSize().x / 2;
dx += marge;
2007-08-23 04:28:46 +00:00
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
2007-08-23 04:28:46 +00:00
{
TraceFilledCircle( shape_pos.x, shape_pos.y, dx,
aPad->GetLayerSet(), color, op_logic );
2007-08-23 04:28:46 +00:00
return;
}
2012-02-19 04:02:19 +00:00
dy = aPad->GetSize().y / 2;
dy += marge;
2007-08-23 04:28:46 +00:00
if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID )
2007-08-23 04:28:46 +00:00
{
2012-02-19 04:02:19 +00:00
dx += abs( aPad->GetDelta().y ) / 2;
dy += abs( aPad->GetDelta().x ) / 2;
2007-08-23 04:28:46 +00:00
}
// The pad is a rectangle ( horizontal or vertical )
2012-02-19 04:02:19 +00:00
if( int( aPad->GetOrientation() ) % 900 == 0 )
{
// Orientation turned 90 deg.
2012-02-19 04:02:19 +00:00
if( aPad->GetOrientation() == 900 || aPad->GetOrientation() == 2700 )
{
std::swap( dx, dy );
2007-08-23 04:28:46 +00:00
}
TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy,
2007-08-23 04:28:46 +00:00
shape_pos.x + dx, shape_pos.y + dy,
aPad->GetLayerSet(), color, op_logic );
2007-08-23 04:28:46 +00:00
}
else
{
TraceFilledRectangle( shape_pos.x - dx, shape_pos.y - dy,
2007-08-23 04:28:46 +00:00
shape_pos.x + dx, shape_pos.y + dy,
aPad->GetOrientation(),
aPad->GetLayerSet(), color, op_logic );
2007-08-23 04:28:46 +00:00
}
}
/* 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)
2007-08-23 04:28:46 +00:00
*/
void TraceFilledCircle( int cx, int cy, int radius,
LSET aLayerMask, int color, int op_logic )
{
2007-08-23 04:28:46 +00:00
int row, col;
int ux0, uy0, ux1, uy1;
int row_max, col_max, row_min, col_min;
int trace = 0;
double fdistmin, fdistx, fdisty;
2007-08-23 04:28:46 +00:00
int tstwrite = 0;
int distmin;
if( aLayerMask[g_Route_Layer_BOTTOM] )
trace = 1; // Trace on BOTTOM
2007-08-23 04:28:46 +00:00
if( aLayerMask[g_Route_Layer_TOP] )
if( RoutingMatrix.m_RoutingLayersCount > 1 )
trace |= 2; // Trace on TOP
2007-08-23 04:28:46 +00:00
if( trace == 0 )
return;
RoutingMatrix.SetCellOperation( op_logic );
2007-08-23 04:28:46 +00:00
cx -= RoutingMatrix.GetBrdCoordOrigin().x;
cy -= RoutingMatrix.GetBrdCoordOrigin().y;
2007-08-23 04:28:46 +00:00
2011-03-09 14:30:39 +00:00
distmin = radius;
2007-08-23 04:28:46 +00:00
// Calculate the bounding rectangle of the circle.
2011-03-09 14:30:39 +00:00
ux0 = cx - radius;
uy0 = cy - radius;
ux1 = cx + radius;
uy1 = cy + radius;
2007-08-23 04:28:46 +00:00
// 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++;
2007-08-23 04:28:46 +00:00
if( row_min < 0 )
row_min = 0;
if( row_max >= (RoutingMatrix.m_Nrows - 1) )
row_max = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
if( col_min < 0 )
col_min = 0;
if( col_max >= (RoutingMatrix.m_Ncols - 1) )
col_max = RoutingMatrix.m_Ncols - 1;
2007-08-23 04:28:46 +00:00
// Calculate coordinate limits of cell belonging to the rectangle.
2007-08-23 04:28:46 +00:00
if( row_min > row_max )
row_max = row_min;
2007-08-23 04:28:46 +00:00
if( col_min > col_max )
col_max = col_min;
fdistmin = (double) distmin * distmin;
2007-08-23 04:28:46 +00:00
for( row = row_min; row <= row_max; row++ )
{
fdisty = (double) ( cy - ( row * RoutingMatrix.m_GridRouting ) );
2007-08-23 04:28:46 +00:00
fdisty *= fdisty;
2007-08-23 04:28:46 +00:00
for( col = col_min; col <= col_max; col++ )
{
fdistx = (double) ( cx - ( col * RoutingMatrix.m_GridRouting ) );
2007-08-23 04:28:46 +00:00
fdistx *= fdistx;
if( fdistmin <= ( fdistx + fdisty ) )
2007-08-23 04:28:46 +00:00
continue;
if( trace & 1 )
RoutingMatrix.WriteCell( row, col, BOTTOM, color );
2007-08-23 04:28:46 +00:00
if( trace & 2 )
RoutingMatrix.WriteCell( row, col, TOP, color );
2007-08-23 04:28:46 +00:00
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
2007-08-23 04:28:46 +00:00
for( row = row_min; row <= row_max; row++ )
{
fdisty = (double) ( cy - ( row * RoutingMatrix.m_GridRouting ) );
2007-08-23 04:28:46 +00:00
fdisty *= fdisty;
2007-08-23 04:28:46 +00:00
for( col = col_min; col <= col_max; col++ )
{
fdistx = (double) ( cx - ( col * RoutingMatrix.m_GridRouting ) );
2007-08-23 04:28:46 +00:00
fdistx *= fdistx;
if( fdistmin <= ( fdistx + fdisty ) )
2007-08-23 04:28:46 +00:00
continue;
if( trace & 1 )
RoutingMatrix.WriteCell( row, col, BOTTOM, color );
2007-08-23 04:28:46 +00:00
if( trace & 2 )
RoutingMatrix.WriteCell( row, col, TOP, color );
2007-08-23 04:28:46 +00:00
}
}
}
void 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;
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 S_ARC:
TraceArc( ux0, uy0, ux1, uy1, pt_segm->GetAngle(), half_width, layer, color, op_logic );
break;
// The segment is here a line segment.
default:
DrawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
}
}
2007-08-23 04:28:46 +00:00
void TraceSegmentPcb( TRACK* aTrack, int color, int marge, int op_logic )
{
int half_width = ( aTrack->GetWidth() / 2 ) + marge;
// Test if VIA (filled circle need to be drawn)
if( aTrack->Type() == PCB_VIA_T )
2007-08-23 04:28:46 +00:00
{
LSET layer_mask;
if( aTrack->IsOnLayer( g_Route_Layer_BOTTOM ) )
layer_mask.set( g_Route_Layer_BOTTOM );
if( aTrack->IsOnLayer( g_Route_Layer_TOP ) )
{
if( !layer_mask.any() )
layer_mask = LSET( g_Route_Layer_TOP );
else
layer_mask.set();
}
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 );
2007-08-23 04:28:46 +00:00
}
else
2007-08-23 04:28:46 +00:00
{
// 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;
2007-08-23 04:28:46 +00:00
// Ordinary track
LAYER_ID layer = aTrack->GetLayer();
if( color == VIA_IMPOSSIBLE )
layer = UNDEFINED_LAYER;
2007-08-23 04:28:46 +00:00
DrawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
2007-08-23 04:28:46 +00:00
}
}
/* Draws a line, if layer = -1 on all layers
2007-08-23 04:28:46 +00:00
*/
void TracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color, int op_logic )
{
2007-08-23 04:28:46 +00:00
int dx, dy, lim;
int cumul, inc, il, delta;
RoutingMatrix.SetCellOperation( op_logic );
2007-08-23 04:28:46 +00:00
if( x0 == x1 ) // Vertical.
2007-08-23 04:28:46 +00:00
{
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 ) )
2007-08-23 04:28:46 +00:00
return;
2007-08-23 04:28:46 +00:00
if( dy < 0 )
dy = 0;
if( lim >= RoutingMatrix.m_Nrows )
lim = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
for( ; dy <= lim; dy++ )
{
OP_CELL( layer, dy, dx );
}
return;
}
if( y0 == y1 ) // Horizontal
2007-08-23 04:28:46 +00:00
{
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 ) )
2007-08-23 04:28:46 +00:00
return;
2007-08-23 04:28:46 +00:00
if( dx < 0 )
dx = 0;
if( lim >= RoutingMatrix.m_Ncols )
lim = RoutingMatrix.m_Ncols - 1;
2007-08-23 04:28:46 +00:00
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/
2007-08-23 04:28:46 +00:00
{
if( x1 < x0 )
{
std::swap( x1, x0 );
std::swap( y1, y0 );
2007-08-23 04:28:46 +00:00
}
dx = x0 / RoutingMatrix.m_GridRouting;
lim = x1 / RoutingMatrix.m_GridRouting;
dy = y0 / RoutingMatrix.m_GridRouting;
inc = 1;
if( y1 < y0 )
2007-08-23 04:28:46 +00:00
inc = -1;
il = lim - dx; cumul = il / 2;
delta = abs( y1 - y0 ) / RoutingMatrix.m_GridRouting;
2007-08-23 04:28:46 +00:00
for( ; dx <= lim; )
{
if( ( dx >= 0 ) && ( dy >= 0 ) &&
( dx < RoutingMatrix.m_Ncols ) &&
( dy < RoutingMatrix.m_Nrows ) )
2007-08-23 04:28:46 +00:00
{
OP_CELL( layer, dy, dx );
}
dx++;
cumul += delta;
2007-08-23 04:28:46 +00:00
if( cumul > il )
{
cumul -= il;
dy += inc;
2007-08-23 04:28:46 +00:00
}
}
}
else
{
if( y1 < y0 )
{
std::swap( x1, x0 );
std::swap( y1, y0 );
2007-08-23 04:28:46 +00:00
}
dy = y0 / RoutingMatrix.m_GridRouting;
lim = y1 / RoutingMatrix.m_GridRouting;
dx = x0 / RoutingMatrix.m_GridRouting;
inc = 1;
if( x1 < x0 )
2007-08-23 04:28:46 +00:00
inc = -1;
il = lim - dy;
cumul = il / 2;
delta = abs( x1 - x0 ) / RoutingMatrix.m_GridRouting;
2007-08-23 04:28:46 +00:00
for( ; dy <= lim; )
{
if( ( dx >= 0 ) && ( dy >= 0 ) && ( dx < RoutingMatrix.m_Ncols ) && ( dy < RoutingMatrix.m_Nrows ) )
2007-08-23 04:28:46 +00:00
{
OP_CELL( layer, dy, dx );
}
dy++;
cumul += delta;
2007-08-23 04:28:46 +00:00
if( cumul > il )
{
cumul -= il;
dx += inc;
2007-08-23 04:28:46 +00:00
}
}
}
}
2007-08-23 04:28:46 +00:00
void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
LSET aLayerMask, int color, int op_logic )
{
2007-08-23 04:28:46 +00:00
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
2007-08-23 04:28:46 +00:00
if( aLayerMask[g_Route_Layer_TOP] && RoutingMatrix.m_RoutingLayersCount > 1 )
trace |= 2; // Trace on TOP
2007-08-23 04:28:46 +00:00
if( trace == 0 )
return;
RoutingMatrix.SetCellOperation( op_logic );
2007-08-23 04:28:46 +00:00
ux0 -= RoutingMatrix.GetBrdCoordOrigin().x;
uy0 -= RoutingMatrix.GetBrdCoordOrigin().y;
ux1 -= RoutingMatrix.GetBrdCoordOrigin().x;
uy1 -= RoutingMatrix.GetBrdCoordOrigin().y;
2007-08-23 04:28:46 +00:00
// 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 )
2007-08-23 04:28:46 +00:00
row_min++;
col_min = ux0 / RoutingMatrix.m_GridRouting;
if( ux0 > col_min * RoutingMatrix.m_GridRouting )
2007-08-23 04:28:46 +00:00
col_min++;
if( row_min < 0 )
row_min = 0;
if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
row_max = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
if( col_min < 0 )
col_min = 0;
if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
col_max = RoutingMatrix.m_Ncols - 1;
2007-08-23 04:28:46 +00:00
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 );
2007-08-23 04:28:46 +00:00
if( trace & 2 )
RoutingMatrix.WriteCell( row, col, TOP, color );
2007-08-23 04:28:46 +00:00
}
}
}
void TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1,
double angle, LSET aLayerMask, int color, int op_logic )
{
2007-08-23 04:28:46 +00:00
int row, col;
int cx, cy; // Center of rectangle
int radius; // Radius of the circle
2007-08-23 04:28:46 +00:00
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
2007-08-23 04:28:46 +00:00
if( aLayerMask[g_Route_Layer_TOP] )
{
if( RoutingMatrix.m_RoutingLayersCount > 1 )
trace |= 2; // Trace on TOP
}
2007-08-23 04:28:46 +00:00
if( trace == 0 )
return;
RoutingMatrix.SetCellOperation( op_logic );
2007-08-23 04:28:46 +00:00
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 )
2007-08-23 04:28:46 +00:00
row_min++;
col_min = ( cx - radius ) / RoutingMatrix.m_GridRouting;
if( ux0 > col_min * RoutingMatrix.m_GridRouting )
2007-08-23 04:28:46 +00:00
col_min++;
if( row_min < 0 )
row_min = 0;
if( row_max >= ( RoutingMatrix.m_Nrows - 1 ) )
row_max = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
if( col_min < 0 )
col_min = 0;
if( col_max >= ( RoutingMatrix.m_Ncols - 1 ) )
col_max = RoutingMatrix.m_Ncols - 1;
2007-08-23 04:28:46 +00:00
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;
2007-08-23 04:28:46 +00:00
RotatePoint( &rotcol, &rotrow, cx, cy, -angle );
2007-08-23 04:28:46 +00:00
if( rotrow <= uy0 )
continue;
2007-08-23 04:28:46 +00:00
if( rotrow >= uy1 )
continue;
2007-08-23 04:28:46 +00:00
if( rotcol <= ux0 )
continue;
2007-08-23 04:28:46 +00:00
if( rotcol >= ux1 )
continue;
2007-08-23 04:28:46 +00:00
if( trace & 1 )
RoutingMatrix.WriteCell( row, col, BOTTOM, color );
2007-08-23 04:28:46 +00:00
if( trace & 2 )
RoutingMatrix.WriteCell( row, col, TOP, color );
2007-08-23 04:28:46 +00:00
}
}
}
/* 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 )
{
2007-08-23 04:28:46 +00:00
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 );
2007-08-23 04:28:46 +00:00
// Make coordinate ux1 tj > ux0 to simplify calculations
2007-08-23 04:28:46 +00:00
if( ux1 < ux0 )
{
std::swap( ux1, ux0 );
std::swap( uy1, uy0 );
2007-08-23 04:28:46 +00:00
}
// Calculating the incrementing the Y axis
inc = 1;
if( uy1 < uy0 )
2007-08-23 04:28:46 +00:00
inc = -1;
demi_pas = RoutingMatrix.m_GridRouting / 2;
2007-08-23 04:28:46 +00:00
col_min = ( ux0 - lg ) / RoutingMatrix.m_GridRouting;
2007-08-23 04:28:46 +00:00
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;
2007-08-23 04:28:46 +00:00
if( inc > 0 )
{
row_min = ( uy0 - lg ) / RoutingMatrix.m_GridRouting;
row_max = ( uy1 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
2007-08-23 04:28:46 +00:00
}
else
{
row_min = ( uy1 - lg ) / RoutingMatrix.m_GridRouting;
row_max = ( uy0 + lg + demi_pas ) / RoutingMatrix.m_GridRouting;
2007-08-23 04:28:46 +00:00
}
if( row_min < 0 )
row_min = 0;
if( row_min > ( RoutingMatrix.m_Nrows - 1 ) )
row_min = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
if( row_max < 0 )
row_max = 0;
if( row_max > ( RoutingMatrix.m_Nrows - 1 ) )
row_max = RoutingMatrix.m_Nrows - 1;
2007-08-23 04:28:46 +00:00
dx = ux1 - ux0;
dy = uy1 - uy0;
2007-08-23 04:28:46 +00:00
double angle;
2007-08-23 04:28:46 +00:00
if( dx )
{
angle = ArcTangente( dy, dx );
}
2007-08-23 04:28:46 +00:00
else
{
angle = 900;
if( dy < 0 )
2007-08-23 04:28:46 +00:00
angle = -900;
}
RotatePoint( &dx, &dy, angle ); // dx = length, dy = 0
2007-08-23 04:28:46 +00:00
for( col = col_min; col <= col_max; col++ )
{
int cxr;
cxr = ( col * RoutingMatrix.m_GridRouting ) - ux0;
for( row = row_min; row <= row_max; row++ )
2007-08-23 04:28:46 +00:00
{
cy = (row * RoutingMatrix.m_GridRouting) - uy0;
2007-08-23 04:28:46 +00:00
cx = cxr;
RotatePoint( &cx, &cy, angle );
2007-08-23 04:28:46 +00:00
if( abs( cy ) > lg )
continue; // The point is too far on the Y axis.
2007-08-23 04:28:46 +00:00
/* This point a test is close to the segment: the position
* along the X axis must be tested.
*/
if( ( cx >= 0 ) && ( cx <= dx ) )
2007-08-23 04:28:46 +00:00
{
OP_CELL( layer, row, col );
continue;
}
// Examination of extremities are rounded.
if( ( cx < 0 ) && ( cx >= -lg ) )
2007-08-23 04:28:46 +00:00
{
if( ( ( cx * cx ) + ( cy * cy ) ) <= ( lg * lg ) )
2007-08-23 04:28:46 +00:00
OP_CELL( layer, row, col );
2007-08-23 04:28:46 +00:00
continue;
}
if( ( cx > dx ) && ( cx <= ( dx + lg ) ) )
2007-08-23 04:28:46 +00:00
{
if( ( ( ( cx - dx ) * ( cx - dx ) ) + ( cy * cy ) ) <= ( lg * lg ) )
2007-08-23 04:28:46 +00:00
OP_CELL( layer, row, col );
2007-08-23 04:28:46 +00:00
continue;
}
}
}
}
2007-08-23 04:28:46 +00:00
/* 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.
2007-08-23 04:28:46 +00:00
*/
void TraceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer,
int color, int op_logic )
{
2011-03-09 14:30:39 +00:00
int radius, nb_segm;
int x0, y0, // Starting point of the current segment trace.
x1, y1; // End point.
2007-08-23 04:28:46 +00:00
int ii;
int angle;
* 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
radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
2007-08-23 04:28:46 +00:00
2011-03-09 14:30:39 +00:00
x0 = x1 = radius;
y0 = y1 = 0;
2007-08-23 04:28:46 +00:00
if( lg < 1 )
lg = 1;
2011-03-09 14:30:39 +00:00
nb_segm = ( 2 * radius ) / lg;
2007-08-23 04:28:46 +00:00
if( nb_segm < 5 )
nb_segm = 5;
2007-08-23 04:28:46 +00:00
if( nb_segm > 100 )
nb_segm = 100;
2007-08-23 04:28:46 +00:00
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;
2007-08-23 04:28:46 +00:00
}
DrawSegmentQcq( x1 + ux0, y1 + uy0, ux0 + radius, uy0, lg, layer, color, op_logic );
}
2007-08-23 04:28:46 +00:00
/* 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.
2007-08-23 04:28:46 +00:00
*/
void TraceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
LAYER_NUM layer, int color, int op_logic )
{
2011-03-09 14:30:39 +00:00
int radius, nb_segm;
int x0, y0, // Starting point of the current segment trace
x1, y1; // End point
2007-08-23 04:28:46 +00:00
int ii;
double angle, StAngle;
2007-08-23 04:28:46 +00:00
radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );
2007-08-23 04:28:46 +00:00
x0 = ux1 - ux0;
y0 = uy1 - uy0;
2007-08-23 04:28:46 +00:00
StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );
2007-08-23 04:28:46 +00:00
if( lg < 1 )
lg = 1;
2011-03-09 14:30:39 +00:00
nb_segm = ( 2 * radius ) / lg;
nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;
2007-08-23 04:28:46 +00:00
if( nb_segm < 5 )
nb_segm = 5;
2007-08-23 04:28:46 +00:00
if( nb_segm > 100 )
nb_segm = 100;
for( ii = 1; ii <= nb_segm; ii++ )
{
angle = ( ArcAngle * ii ) / nb_segm;
2007-08-23 04:28:46 +00:00
angle += StAngle;
NORMALIZE_ANGLE_POS( angle );
2007-08-23 04:28:46 +00:00
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;
2007-08-23 04:28:46 +00:00
}
}