kicad/pcbnew/board_items_to_polygon_shap...

763 lines
31 KiB
C++

/***
* @file board_items_to_polygon_shape_transform.cpp
* @brief function to convert shapes of items ( pads, tracks... ) to polygons
*/
/* Function to convert pads and tranck shapes to polygons
* Used to fill zones areas
*/
#include <vector>
#include <fctsys.h>
#include <polygons_defs.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
#include <trigo.h>
#include <class_pad.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_zone.h>
#include <convert_basic_shapes_to_polygon.h>
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TEXTE_PCB::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
if( GetText().Length() == 0 )
return;
CPolyPt corners[4]; // Buffer of polygon corners
EDA_RECT rect = GetTextBox( -1 );
rect.Inflate( aClearanceValue );
corners[0].x = rect.GetOrigin().x;
corners[0].y = rect.GetOrigin().y;
corners[1].y = corners[0].y;
corners[1].x = rect.GetRight();
corners[2].x = corners[1].x;
corners[2].y = rect.GetBottom();
corners[3].y = corners[2].y;
corners[3].x = corners[0].x;
for( int ii = 0; ii < 4; ii++ )
{
// Rotate polygon
RotatePoint( &corners[ii].x, &corners[ii].y, m_Pos.x, m_Pos.y, m_Orient );
aCornerBuffer.push_back( corners[ii] );
}
aCornerBuffer.back().end_contour = true;
}
/* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* param aCornerBuffer = a buffer to store the polygon
* param aClearanceValue = the clearance around the pad
* param aCircleToSegmentsCount = the number of segments to approximate a circle
* param aCorrectionFactor = the correction to apply to circles radius to keep
* param aAddClearance = true to add a clearance area to the polygon
* false to create the outline polygon.
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool aAddClearance )
{
/* Creates the main polygon (i.e. the filled area using only one outline)
* and reserve a clearance margin around the outlines and holes
*/
std::vector <CPolyPt> zoneOutines;
BuildFilledPolysListData( NULL, &zoneOutines );
int clearance = 0;
if( aAddClearance )
{
GetClearance();
if( aClearanceValue > clearance )
clearance = aClearanceValue;
}
// Calculate the polygon with clearance and holes
// holes are linked to the main outline, so only one polygon should be created.
KI_POLYGON_SET polyset_zone_solid_areas;
std::vector<KI_POLY_POINT> cornerslist;
unsigned ic = 0;
unsigned corners_count = zoneOutines.size();
while( ic < corners_count )
{
cornerslist.clear();
KI_POLYGON poly;
{
for( ; ic < corners_count; ic++ )
{
CPolyPt* corner = &zoneOutines[ic];
cornerslist.push_back( KI_POLY_POINT( corner->x, corner->y ) );
if( corner->end_contour )
{
ic++;
break;
}
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
polyset_zone_solid_areas.push_back( poly );
}
}
polyset_zone_solid_areas += clearance;
// Put the resultng polygon in buffer
for( unsigned ii = 0; ii < polyset_zone_solid_areas.size(); ii++ )
{
KI_POLYGON& poly = polyset_zone_solid_areas[ii];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly.size(); jj++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aCornerBuffer.push_back( corner );
}
corner.end_contour = true;
aCornerBuffer.pop_back();
aCornerBuffer.push_back( corner );
}
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
switch( m_Shape )
{
case S_CIRCLE:
TransformArcToPolygon( aCornerBuffer, m_Start, // Circle centre
m_End, 3600,
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) );
break;
case S_ARC:
TransformArcToPolygon( aCornerBuffer, m_Start,
m_End, m_Angle,
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) );
break;
default:
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, m_Start, m_End,
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) );
break;
}
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TRACK:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
switch( Type() )
{
case PCB_VIA_T:
{
int radius = (m_Width / 2) + aClearanceValue;
radius = KiROUND( radius * aCorrectionFactor );
TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aCircleToSegmentsCount );
}
break;
default:
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
m_Start, m_End,
aCircleToSegmentsCount,
m_Width + ( 2 * aClearanceValue) );
break;
}
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the pad shape to a closed polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void D_PAD:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
wxPoint corner_position;
int angle;
int dx = (m_Size.x / 2) + aClearanceValue;
int dy = (m_Size.y / 2) + aClearanceValue;
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads
* trapezoidal pads are considered as rect
* pad shape having they boudary box size */
switch( m_PadShape )
{
case PAD_CIRCLE:
dx = (int) ( dx * aCorrectionFactor );
TransformCircleToPolygon( aCornerBuffer, PadShapePos, dx,
aCircleToSegmentsCount );
break;
case PAD_OVAL:
// An oval pad has the same shape as a segment with rounded ends
angle = m_Orient;
{
int width;
wxPoint shape_offset;
if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis
{
dy = (int) ( dy * aCorrectionFactor );
shape_offset.y = dy - dx;
width = dx * 2;
}
else //if( dy <= dx )
{
dx = (int) ( dx * aCorrectionFactor );
shape_offset.x = dy - dx;
width = dy * 2;
}
RotatePoint( &shape_offset, angle );
wxPoint start = PadShapePos - shape_offset;
wxPoint end = PadShapePos + shape_offset;
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, start, end,
aCircleToSegmentsCount, width );
}
break;
default:
case PAD_TRAPEZOID:
psize.x += std::abs( m_DeltaSize.y );
psize.y += std::abs( m_DeltaSize.x );
// fall through
case PAD_RECT:
// Easy implementation for rectangular cutouts with rounded corners
angle = m_Orient;
// Corner rounding radius
int rounding_radius = (int) ( aClearanceValue * aCorrectionFactor );
int angle_pg; // Polygon increment angle
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
corner_position = wxPoint( 0, -rounding_radius );
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
// Start at half increment offset
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
// Rounding vector rotation
corner_position -= psize / 2; // Rounding vector + Pad corner offset
RotatePoint( &corner_position, angle );
// Rotate according to module orientation
corner_position += PadShapePos; // Shift origin to position
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.push_back( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
corner_position = wxPoint( -rounding_radius, 0 );
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position -= wxPoint( psize.x / 2, -psize.y / 2 );
RotatePoint( &corner_position, angle );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.push_back( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
corner_position = wxPoint( 0, rounding_radius );
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position += psize / 2;
RotatePoint( &corner_position, angle );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.push_back( polypoint );
}
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
corner_position = wxPoint( rounding_radius, 0 );
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg );
corner_position -= wxPoint( -psize.x / 2, psize.y / 2 );
RotatePoint( &corner_position, angle );
corner_position += PadShapePos;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.push_back( polypoint );
}
aCornerBuffer.back().end_contour = true;
break;
}
}
/**
* Function CreateThermalReliefPadPolygon
* Add holes around a pad to create a thermal relief
* copper thickness is min (dx/2, aCopperWitdh) or min (dy/2, aCopperWitdh)
* @param aCornerBuffer = a buffer to store the polygon
* @param aPad = the current pad used to create the thermal shape
* @param aThermalGap = gap in thermal shape
* @param aCopperThickness = stubs thickness in thermal shape
* @param aMinThicknessValue = min copper thickness allowed
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* @param aThermalRot = for rond pads the rotation of thermal stubs (450 usually for 45 deg.)
*/
/* thermal reliefs are created as 4 polygons.
* each corner of a polygon if calculated for a pad at position 0, 0, orient 0,
* and then moved and rotated acroding to the pad position and orientation
*/
/*
* Note 1: polygons are drawm using outlines witk a thickness = aMinThicknessValue
* so shapes must take in account this outline thickness
*
* Note 2:
* Trapezoidal pads are not considered here because they are very special case
* and are used in microwave applications and they *DO NOT* have a thermal relief that
* change the shape by creating stubs and destroy their properties.
*/
void CreateThermalReliefPadPolygon( std::vector<CPolyPt>& aCornerBuffer,
D_PAD& aPad,
int aThermalGap,
int aCopperThickness,
int aMinThicknessValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
int aThermalRot )
{
wxPoint corner, corner_end;
wxPoint PadShapePos = aPad.ReturnShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
wxSize copper_thickness;
int dx = aPad.GetSize().x / 2;
int dy = aPad.GetSize().y / 2;
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
/* Keep in account the polygon outline thickness
* aThermalGap must be increased by aMinThicknessValue/2 because drawing external outline
* with a thickness of aMinThicknessValue will reduce gap by aMinThicknessValue/2
*/
aThermalGap += aMinThicknessValue / 2;
/* Keep in account the polygon outline thickness
* copper_thickness must be decreased by aMinThicknessValue because drawing outlines
* with a thickness of aMinThicknessValue will increase real thickness by aMinThicknessValue
*/
aCopperThickness -= aMinThicknessValue;
if( aCopperThickness < 0 )
aCopperThickness = 0;
copper_thickness.x = std::min( dx, aCopperThickness );
copper_thickness.y = std::min( dy, aCopperThickness );
switch( aPad.GetShape() )
{
case PAD_CIRCLE: // Add 4 similar holes
{
/* we create 4 copper holes and put them in position 1, 2, 3 and 4
* here is the area of the rectangular pad + its thermal gap
* the 4 copper holes remove the copper in order to create the thermal gap
* 4 ------ 1
* | |
* | |
* | |
* | |
* 3 ------ 2
* holes 2, 3, 4 are the same as hole 1, rotated 90, 180, 270 deg
*/
// Build the hole pattern, for the hole in the X >0, Y > 0 plane:
// The pattern roughtly is a 90 deg arc pie
std::vector <wxPoint> corners_buffer;
// Radius of outer arcs of the shape corrected for arc approximation by lines
int outer_radius = (int) ( (dx + aThermalGap) * aCorrectionFactor );
// Crosspoint of thermal spoke sides, the first point of polygon buffer
corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) );
// Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
// and first seg of arc approx
corner.x = copper_thickness.x / 2;
int y = outer_radius - (aThermalGap / 4);
corner.y = (int) sqrt( ( ( (double) y * y ) - (double) corner.x * corner.x ) );
if( aThermalRot != 0 )
corners_buffer.push_back( corner );
// calculate the starting point of the outter arc
corner.x = copper_thickness.x / 2;
double dtmp = sqrt( ( (double) outer_radius * outer_radius ) -
( (double) corner.x * corner.x ) );
corner.y = (int) dtmp;
RotatePoint( &corner, 90 );
// calculate the ending point of the outter arc
corner_end.x = corner.y;
corner_end.y = corner.x;
// calculate intermediate points (y coordinate from corner.y to corner_end.y
while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
{
corners_buffer.push_back( corner );
RotatePoint( &corner, delta );
}
corners_buffer.push_back( corner_end );
/* add an intermediate point, to avoid angles < 90 deg between last arc approx line
* and radius line
*/
corner.x = corners_buffer[1].y;
corner.y = corners_buffer[1].x;
corners_buffer.push_back( corner );
// Now, add the 4 holes ( each is the pattern, rotated by 0, 90, 180 and 270 deg
// aThermalRot = 450 (45.0 degrees orientation) work fine.
int angle_pad = aPad.GetOrientation(); // Pad orientation
int th_angle = aThermalRot;
for( unsigned ihole = 0; ihole < 4; ihole++ )
{
for( unsigned ii = 0; ii < corners_buffer.size(); ii++ )
{
corner = corners_buffer[ii];
RotatePoint( &corner, th_angle + angle_pad ); // Rotate by segment angle and pad orientation
corner += PadShapePos;
aCornerBuffer.push_back( CPolyPt( corner.x, corner.y ) );
}
aCornerBuffer.back().end_contour = true;
th_angle += 900; // Note: th_angle in in 0.1 deg.
}
}
break;
case PAD_OVAL:
{
// Oval pad support along the lines of round and rectangular pads
std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
int dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
int dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
wxPoint shape_offset;
// We want to calculate an oval shape with dx > dy.
// if this is not the case, exchange dx and dy, and rotate the shape 90 deg.
int supp_angle = 0;
if( dx < dy )
{
EXCHG( dx, dy );
supp_angle = 900;
EXCHG( copper_thickness.x, copper_thickness.y );
}
int deltasize = dx - dy; // = distance between shape position and the 2 demi-circle ends centre
// here we have dx > dy
// Radius of outer arcs of the shape:
int outer_radius = dy; // The radius of the outer arc is radius end + aThermalGap
// Some coordinate fiddling, depending on the shape offset direction
shape_offset = wxPoint( deltasize, 0 );
// Crosspoint of thermal spoke sides, the first point of polygon buffer
corner.x = copper_thickness.x / 2;
corner.y = copper_thickness.y / 2;
corners_buffer.push_back( corner );
// Arc start point calculation, the intersecting point of cutout arc and thermal spoke edge
// If copper thickness is more than shape offset, we need to calculate arc intercept point.
if( copper_thickness.x > deltasize )
{
corner.x = copper_thickness.x / 2;
corner.y = (int) sqrt( ( (double) outer_radius * outer_radius ) -
( (double) ( corner.x - delta ) * ( corner.x - deltasize ) ) );
corner.x -= deltasize;
/* creates an intermediate point, to have a > 90 deg angle
* between the side and the first segment of arc approximation
*/
wxPoint intpoint = corner;
intpoint.y -= aThermalGap / 4;
corners_buffer.push_back( intpoint + shape_offset );
RotatePoint( &corner, 90 );
}
else
{
corner.x = copper_thickness.x / 2;
corner.y = outer_radius;
corners_buffer.push_back( corner );
}
// Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
// and first seg of arc approx
wxPoint last_corner;
last_corner.y = copper_thickness.y / 2;
int px = outer_radius - (aThermalGap / 4);
last_corner.x =
(int) sqrt( ( ( (double) px * px ) - (double) last_corner.y * last_corner.y ) );
// Arc stop point calculation, the intersecting point of cutout arc and thermal spoke edge
corner_end.y = copper_thickness.y / 2;
corner_end.x =
(int) sqrt( ( (double) outer_radius *
outer_radius ) - ( (double) corner_end.y * corner_end.y ) );
RotatePoint( &corner_end, -90 );
// calculate intermediate arc points till limit is reached
while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
{
corners_buffer.push_back( corner + shape_offset );
RotatePoint( &corner, delta );
}
//corners_buffer.push_back(corner + shape_offset); // TODO: about one mil geometry error forms somewhere.
corners_buffer.push_back( corner_end + shape_offset );
corners_buffer.push_back( last_corner + shape_offset ); // Enabling the line above shows intersection point.
/* Create 2 holes, rotated by pad rotation.
*/
int angle = aPad.GetOrientation() + supp_angle;
for( int irect = 0; irect < 2; irect++ )
{
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.push_back( CPolyPt( cpos.x, cpos.y ) );
}
aCornerBuffer.back().end_contour = true;
angle += 1800; // this is calculate hole 3
if( angle >= 3600 )
angle -= 3600;
}
// Create holes, that are the mirrored from the previous holes
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint swap = corners_buffer[ic];
swap.x = -swap.x;
corners_buffer[ic] = swap;
}
// Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
angle = aPad.GetOrientation() + supp_angle;
for( int irect = 0; irect < 2; irect++ )
{
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.push_back( CPolyPt( cpos.x, cpos.y ) );
}
aCornerBuffer.back().end_contour = true;
angle += 1800;
if( angle >= 3600 )
angle -= 3600;
}
}
break;
case PAD_RECT: // draw 4 Holes
{
/* we create 4 copper holes and put them in position 1, 2, 3 and 4
* here is the area of the rectangular pad + its thermal gap
* the 4 copper holes remove the copper in order to create the thermal gap
* 4 ------ 1
* | |
* | |
* | |
* | |
* 3 ------ 2
* hole 3 is the same as hole 1, rotated 180 deg
* hole 4 is the same as hole 2, rotated 180 deg and is the same as hole 1, mirrored
*/
// First, create a rectangular hole for position 1 :
// 2 ------- 3
// | |
// | |
// | |
// 1 -------4
// Modified rectangles with one corner rounded. TODO: merging with oval thermals
// and possibly round too.
std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
int dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
int dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
// The first point of polygon buffer is left lower corner, second the crosspoint of
// thermal spoke sides, the third is upper right corner and the rest are rounding
// vertices going anticlockwise. Note the inveted Y-axis in CG.
corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 + copper_thickness.y / 2) ) ); // Adds small miters to zone
corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4), -copper_thickness.y / 2 ) ); // fill and spoke corner
corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -copper_thickness.y / 2 ) );
corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -(dy - aThermalGap / 4) ) );
corners_buffer.push_back( wxPoint( -(aThermalGap / 4 + copper_thickness.x / 2), -dy ) );
int angle = aPad.GetOrientation();
int rounding_radius = (int) ( aThermalGap * aCorrectionFactor ); // Corner rounding radius
int angle_pg; // Polygon increment angle
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
{
wxPoint corner_position = wxPoint( 0, -rounding_radius );
// Start at half increment offset
RotatePoint( &corner_position, 1800 / aCircleToSegmentsCount );
angle_pg = i * delta;
RotatePoint( &corner_position, angle_pg ); // Rounding vector rotation
corner_position -= aPad.GetSize() / 2; // Rounding vector + Pad corner offset
corners_buffer.push_back( wxPoint( corner_position.x, corner_position.y ) );
}
for( int irect = 0; irect < 2; irect++ )
{
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle ); // Rotate according to module orientation
cpos += PadShapePos; // Shift origin to position
aCornerBuffer.push_back( CPolyPt( cpos.x, cpos.y ) );
}
aCornerBuffer.back().end_contour = true;
angle += 1800; // this is calculate hole 3
if( angle >= 3600 )
angle -= 3600;
}
// Create holes, that are the mirrored from the previous holes
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint swap = corners_buffer[ic];
swap.x = -swap.x;
corners_buffer[ic] = swap;
}
// Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
for( int irect = 0; irect < 2; irect++ )
{
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.push_back( CPolyPt( cpos.x, cpos.y ) );
}
aCornerBuffer.back().end_contour = true;
angle += 1800;
if( angle >= 3600 )
angle -= 3600;
}
}
break;
default:
;
}
}