diff options
Diffstat (limited to 'pcbnew/autorouter/graphpcb.cpp')
-rw-r--r-- | pcbnew/autorouter/graphpcb.cpp | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/pcbnew/autorouter/graphpcb.cpp b/pcbnew/autorouter/graphpcb.cpp new file mode 100644 index 0000000..840bfcb --- /dev/null +++ b/pcbnew/autorouter/graphpcb.cpp @@ -0,0 +1,843 @@ +/** + * @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 ) +{ + int dx, dy; + wxPoint shape_pos = aPad->ShapePos(); + + 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 ); + } +} + + +/* 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 ) +{ + 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; + } +} + +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 ) + { + 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 ); + } + 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; + + // Ordinary track + LAYER_ID layer = aTrack->GetLayer(); + + if( color == VIA_IMPOSSIBLE ) + layer = UNDEFINED_LAYER; + + DrawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, 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; + } +} |