|
|
|
@ -21,16 +21,151 @@ |
|
|
|
* @param aCornerBuffer = a buffer to store the polygon |
|
|
|
* @param aStart = the segment start point coordinate |
|
|
|
* @param aEnd = the segment end point coordinate |
|
|
|
* @param aWidth = the segment width |
|
|
|
* @param aCircleToSegmentsCount = the number of segments to approximate a circle |
|
|
|
* @param aWidth = the segment width |
|
|
|
*/ |
|
|
|
void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
void TransformRoundedEndsSegmentToPolygon( std::vector <CPolyPt>& aCornerBuffer, |
|
|
|
wxPoint aStart, wxPoint aEnd, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
int aWidth ); |
|
|
|
|
|
|
|
|
|
|
|
/** Function TransformTrackWithClearanceToPolygon
|
|
|
|
/** Function TransformArcToPolygon
|
|
|
|
* Creates a polygon from an Arc |
|
|
|
* Convert arcs to multiple straight segments |
|
|
|
* @param aCornerBuffer = a buffer to store the polygon |
|
|
|
* @param aCentre = centre of the arc or circle |
|
|
|
* @param aStart = start point of the arc, or a point on the circle |
|
|
|
* @param aArcAngle = arc angle in 0.1 degrees. For a circle, aArcAngle = 3600 |
|
|
|
* @param aCircleToSegmentsCount = the number of segments to approximate a circle |
|
|
|
* @param aWidth = width (thickness) of the line |
|
|
|
*/ |
|
|
|
void TransformArcToPolygon( std::vector <CPolyPt>& aCornerBuffer, |
|
|
|
wxPoint aCentre, wxPoint aStart, int aArcAngle, |
|
|
|
int aCircleToSegmentsCount, int aWidth ) |
|
|
|
{ |
|
|
|
wxPoint arc_start, arc_end; |
|
|
|
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
|
|
|
|
|
|
|
arc_end = arc_start = aStart; |
|
|
|
if( aArcAngle != 3600 ) |
|
|
|
{ |
|
|
|
RotatePoint( &arc_end, aCentre, -aArcAngle ); |
|
|
|
} |
|
|
|
|
|
|
|
if( aArcAngle < 0 ) |
|
|
|
{ |
|
|
|
EXCHG( arc_start, arc_end ); |
|
|
|
NEGATE( aArcAngle ); |
|
|
|
} |
|
|
|
|
|
|
|
// Compute the ends of segments and creates poly
|
|
|
|
wxPoint curr_end = arc_start; |
|
|
|
wxPoint curr_start = arc_start; |
|
|
|
for( int ii = delta; ii < aArcAngle; ii += delta ) |
|
|
|
{ |
|
|
|
curr_end = arc_start; |
|
|
|
RotatePoint( &curr_end, aCentre, -ii ); |
|
|
|
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, |
|
|
|
curr_start, curr_end, aCircleToSegmentsCount, aWidth ); |
|
|
|
curr_start = curr_end; |
|
|
|
} |
|
|
|
|
|
|
|
if( curr_end != arc_end ) |
|
|
|
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, |
|
|
|
curr_end, arc_end, aCircleToSegmentsCount, aWidth ); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Function TEXTE_PCB::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( GetLength() == 0 ) |
|
|
|
return; |
|
|
|
|
|
|
|
CPolyPt corners[4]; // Buffer of polygon corners
|
|
|
|
|
|
|
|
EDA_Rect rect = GetTextBox( -1 ); |
|
|
|
rect.Inflate( aClearanceValue, 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 DRAWSEGMENT::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 TRACK::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 |
|
|
|
@ -41,16 +176,15 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
* clearance when the circle is approxiamted by segment bigger or equal |
|
|
|
* to the real clearance value (usually near from 1.0) |
|
|
|
*/ |
|
|
|
void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
int aClearanceValue, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
double aCorrectionFactor ) |
|
|
|
void TRACK:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer, |
|
|
|
int aClearanceValue, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
double aCorrectionFactor ) |
|
|
|
{ |
|
|
|
wxPoint corner_position; |
|
|
|
int ii, angle; |
|
|
|
int dx = (m_Width / 2) + aClearanceValue; |
|
|
|
|
|
|
|
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
|
|
|
int dx = (m_Width / 2) + aClearanceValue; |
|
|
|
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
|
|
|
|
|
|
|
switch( Type() ) |
|
|
|
{ |
|
|
|
@ -59,19 +193,25 @@ void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCorner |
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount; ii++ ) |
|
|
|
{ |
|
|
|
corner_position = wxPoint( dx, 0 ); |
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); |
|
|
|
RotatePoint( &corner_position.x, &corner_position.y, |
|
|
|
(1800 / aCircleToSegmentsCount) ); |
|
|
|
angle = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
corner_position += m_Start; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
RotatePoint( &corner_position.x, &corner_position.y, angle ); |
|
|
|
corner_position.x += m_Start.x; |
|
|
|
corner_position.y += m_Start.y; |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
aCornerBuffer.back().end_contour = true; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, |
|
|
|
m_Start, m_End, aCircleToSegmentsCount, |
|
|
|
m_Width + (2 * aClearanceValue) ); |
|
|
|
TransformRoundedEndsSegmentToPolygon( |
|
|
|
aCornerBuffer, |
|
|
|
m_Start, m_End, |
|
|
|
aCircleToSegmentsCount, |
|
|
|
m_Width + ( 2 * aClearanceValue) ); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -79,7 +219,7 @@ void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCorner |
|
|
|
|
|
|
|
/* Function TransformRoundedEndsSegmentToPolygon
|
|
|
|
*/ |
|
|
|
void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
void TransformRoundedEndsSegmentToPolygon( std::vector <CPolyPt>& aCornerBuffer, |
|
|
|
wxPoint aStart, wxPoint aEnd, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
int aWidth ) |
|
|
|
@ -89,6 +229,7 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
wxPoint startp = aStart; |
|
|
|
wxPoint corner; |
|
|
|
int seg_len; |
|
|
|
CPolyPt polypoint; |
|
|
|
|
|
|
|
// normalize the position in order to have endp.x >= 0;
|
|
|
|
if( endp.x < 0 ) |
|
|
|
@ -105,12 +246,16 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
corner = wxPoint( 0, rayon ); |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
|
|
|
|
corner = wxPoint( seg_len, rayon ); |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
|
|
|
|
// add right rounded end:
|
|
|
|
for( int ii = delta; ii < 1800; ii += delta ) |
|
|
|
@ -120,18 +265,24 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
corner.x += seg_len; |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
corner = wxPoint( seg_len, -rayon ); |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
|
|
|
|
corner = wxPoint( 0, -rayon ); |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
|
|
|
|
// add left rounded end:
|
|
|
|
for( int ii = delta; ii < 1800; ii += delta ) |
|
|
|
@ -140,12 +291,16 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
RotatePoint( &corner, ii ); |
|
|
|
RotatePoint( &corner, -delta_angle ); |
|
|
|
corner += startp; |
|
|
|
aCornerBuffer.push_back( corner ); |
|
|
|
polypoint.x = corner.x; |
|
|
|
polypoint.y = corner.y; |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
aCornerBuffer.back().end_contour = true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** function TransformPadWithClearanceToPolygon
|
|
|
|
/** function D_PAD::TransformShapeWithClearanceToPolygon
|
|
|
|
* Convert the pad shape to a closed polygon |
|
|
|
* Used in filling zones calculations |
|
|
|
* Circles and arcs are approximated by segments |
|
|
|
@ -156,22 +311,22 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
* clearance when the circle is approxiamted by segment bigger or equal |
|
|
|
* to the real clearance value (usually near from 1.0) |
|
|
|
*/ |
|
|
|
void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer, |
|
|
|
int aClearanceValue, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
double aCorrectionFactor ) |
|
|
|
void D_PAD:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer, |
|
|
|
int aClearanceValue, |
|
|
|
int aCircleToSegmentsCount, |
|
|
|
double aCorrectionFactor ) |
|
|
|
{ |
|
|
|
wxPoint corner_position; |
|
|
|
int ii, 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 |
|
|
|
*/ |
|
|
|
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 ) |
|
|
|
{ |
|
|
|
@ -180,52 +335,63 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount; ii++ ) |
|
|
|
{ |
|
|
|
corner_position = wxPoint( dx, 0 ); |
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); // Half increment offset to get more space between
|
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); |
|
|
|
|
|
|
|
// Half increment offset to get more space between
|
|
|
|
angle = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
corner_position += PadShapePos; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
aCornerBuffer.back().end_contour = true; |
|
|
|
break; |
|
|
|
|
|
|
|
case PAD_OVAL: |
|
|
|
angle = m_Orient; |
|
|
|
if( dy > dx ) // Oval pad X/Y ratio for choosing translation axles
|
|
|
|
if( dy > dx ) // Oval pad X/Y ratio for choosing translation axles
|
|
|
|
{ |
|
|
|
dy = (int) ( dy * aCorrectionFactor ); |
|
|
|
int angle_pg; // Polygon angle
|
|
|
|
wxPoint shape_offset = wxPoint( 0, (dy - dx) ); |
|
|
|
wxPoint shape_offset = wxPoint( 0, dy - dx ); |
|
|
|
RotatePoint( &shape_offset, angle ); // Rotating shape offset vector with component
|
|
|
|
|
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ ) // Half circle end cap...
|
|
|
|
{ |
|
|
|
corner_position = wxPoint( dx, 0 ); // Coordinate translation +dx
|
|
|
|
corner_position = wxPoint( dx, 0 ); |
|
|
|
|
|
|
|
// Coordinate translation +dx
|
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
angle_pg = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle_pg ); |
|
|
|
corner_position += PadShapePos - shape_offset; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ ) // Second half circle end cap...
|
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ ) // Second half circle end cap...
|
|
|
|
{ |
|
|
|
corner_position = wxPoint( -dx, 0 ); // Coordinate translation -dx
|
|
|
|
corner_position = wxPoint( -dx, 0 ); |
|
|
|
|
|
|
|
// Coordinate translation -dx
|
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
angle_pg = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle_pg ); |
|
|
|
corner_position += PadShapePos + shape_offset; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
aCornerBuffer.back().end_contour = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
else //if( dy <= dx )
|
|
|
|
{ |
|
|
|
dx = (int) ( dx * aCorrectionFactor ); |
|
|
|
int angle_pg; // Polygon angle
|
|
|
|
int angle_pg; // Polygon angle
|
|
|
|
wxPoint shape_offset = wxPoint( (dy - dx), 0 ); |
|
|
|
RotatePoint( &shape_offset, angle ); |
|
|
|
|
|
|
|
@ -237,7 +403,8 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
angle_pg = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle_pg ); |
|
|
|
corner_position += PadShapePos - shape_offset; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ ) |
|
|
|
@ -248,9 +415,11 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
angle_pg = ii * delta; |
|
|
|
RotatePoint( &corner_position, angle_pg ); |
|
|
|
corner_position += PadShapePos + shape_offset; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
aCornerBuffer.back().end_contour = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
@ -260,21 +429,28 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
psize.y += ABS( m_DeltaSize.x ); |
|
|
|
|
|
|
|
// fall through
|
|
|
|
case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners // Easy implementation for rectangular cutouts with rounded corners
|
|
|
|
case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners // Easy implementation for rectangular cutouts with rounded corners
|
|
|
|
angle = m_Orient; |
|
|
|
int rounding_radius = (int) ( aClearanceValue * aCorrectionFactor ); // Corner rounding radius
|
|
|
|
int angle_pg; // Polygon increment angle
|
|
|
|
int rounding_radius = (int) ( aClearanceValue * aCorrectionFactor ); // Corner rounding radius
|
|
|
|
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
|
|
|
|
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
|
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
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++ ) |
|
|
|
@ -286,10 +462,13 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
corner_position -= wxPoint( psize.x / 2, -psize.y / 2 ); |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
corner_position += PadShapePos; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) |
|
|
|
for( int i = 0; |
|
|
|
i < aCircleToSegmentsCount / 4 + 1; |
|
|
|
i++ ) |
|
|
|
{ |
|
|
|
corner_position = wxPoint( 0, rounding_radius ); |
|
|
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) ); |
|
|
|
@ -298,7 +477,8 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
corner_position += psize / 2; |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
corner_position += PadShapePos; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
CPolyPt polypoint( corner_position.x, corner_position.y ); |
|
|
|
aCornerBuffer.push_back( polypoint ); |
|
|
|
} |
|
|
|
|
|
|
|
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ ) |
|
|
|
@ -310,9 +490,398 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu |
|
|
|
corner_position -= wxPoint( -psize.x / 2, psize.y / 2 ); |
|
|
|
RotatePoint( &corner_position, angle ); |
|
|
|
corner_position += PadShapePos; |
|
|
|
aCornerBuffer.push_back( corner_position ); |
|
|
|
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 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 |
|
|
|
*/ |
|
|
|
|
|
|
|
/* WARNING:
|
|
|
|
* When Kbool calculates the filled areas : |
|
|
|
* i.e when substracting holes (thermal shapes) to the full zone area |
|
|
|
* under certains circumstances kboll drop some holes. |
|
|
|
* These circumstances are: |
|
|
|
* some identical holes (same thermal shape and size) are *exactly* on the same vertical line |
|
|
|
* And |
|
|
|
* nothing else between holes |
|
|
|
* And |
|
|
|
* angles less than 90 deg between 2 consecutive lines in hole outline (sometime occurs without this condition) |
|
|
|
* And |
|
|
|
* a hole above the identical holes |
|
|
|
* |
|
|
|
* In fact, it is easy to find these conditions in pad arrays. |
|
|
|
* So to avoid this, the workaround is do not use holes outlines that include |
|
|
|
* angles less than 90 deg between 2 consecutive lines |
|
|
|
* this is made in round and oblong thermal reliefs |
|
|
|
* |
|
|
|
* Note 1: polygons are drawm using outlines witk a thickness = aMinThicknessValue |
|
|
|
* so shapes must keep 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.m_Size.x / 2; |
|
|
|
int dy = aPad.m_Size.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 = min( dx, aCopperThickness ); |
|
|
|
copper_thickness.y = min( dy, aCopperThickness ); |
|
|
|
|
|
|
|
switch( aPad.m_PadShape ) |
|
|
|
{ |
|
|
|
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:
|
|
|
|
int outer_radius = dx + aThermalGap; // The radius of the outer arc is pad radius + aThermalGap
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// WARNING: problems with kbool if angle = 0 (in fact when angle < 200):
|
|
|
|
// bad filled polygon on some cases, when pads are on a same vertical line
|
|
|
|
// this seems a bug in kbool polygon (exists in 2.0 kbool version)
|
|
|
|
// aThermalRot = 450 (45.0 degrees orientation) seems work fine.
|
|
|
|
// aThermalRot = 0 with thermal shapes without angle < 90 deg has problems in rare circumstances
|
|
|
|
// Note: with the 2 step build ( thermal shapes added after areas are built), 0 seems work
|
|
|
|
int angle_pad = aPad.m_Orient; // 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.m_Size.x / 2) + aThermalGap; // Cutout radius x
|
|
|
|
int dy = (aPad.m_Size.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
|
|
|
|
corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) ); |
|
|
|
|
|
|
|
// Arc start point calculation, the intersecting point of cutout arc and thermal spoke edge
|
|
|
|
if( copper_thickness.x > deltasize ) // If copper thickness is more than shape offset, we need to calculate arc intercept point.
|
|
|
|
{ |
|
|
|
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 ); |
|
|
|
corner.x = ( deltasize - copper_thickness.x ) / 2; |
|
|
|
} |
|
|
|
|
|
|
|
// 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.m_Orient + 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.m_Orient + 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.m_Size.x / 2) + aThermalGap; // Cutout radius x
|
|
|
|
int dy = (aPad.m_Size.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.m_Orient; |
|
|
|
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 ); |
|
|
|
RotatePoint( &corner_position, 1800 / aCircleToSegmentsCount ); // Start at half increment offset
|
|
|
|
angle_pg = i * delta; |
|
|
|
RotatePoint( &corner_position, angle_pg ); // Rounding vector rotation
|
|
|
|
corner_position -= aPad.m_Size / 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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |