rework on zones (continued):try to fix a filling problem with kbool: cleanup code
This commit is contained in:
parent
537d4861ba
commit
f2f4cd535a
|
@ -21,16 +21,151 @@
|
||||||
* @param aCornerBuffer = a buffer to store the polygon
|
* @param aCornerBuffer = a buffer to store the polygon
|
||||||
* @param aStart = the segment start point coordinate
|
* @param aStart = the segment start point coordinate
|
||||||
* @param aEnd = the segment end 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 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,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
int aWidth );
|
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
|
* Convert the track shape to a closed polygon
|
||||||
* Used in filling zones calculations
|
* Used in filling zones calculations
|
||||||
* Circles (vias) and arcs (ends of tracks) are approximated by segments
|
* 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
|
* clearance when the circle is approxiamted by segment bigger or equal
|
||||||
* to the real clearance value (usually near from 1.0)
|
* to the real clearance value (usually near from 1.0)
|
||||||
*/
|
*/
|
||||||
void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
void TRACK:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
|
||||||
int aClearanceValue,
|
int aClearanceValue,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
double aCorrectionFactor )
|
double aCorrectionFactor )
|
||||||
{
|
{
|
||||||
wxPoint corner_position;
|
wxPoint corner_position;
|
||||||
int ii, angle;
|
int ii, angle;
|
||||||
int dx = (m_Width / 2) + aClearanceValue;
|
int dx = (m_Width / 2) + aClearanceValue;
|
||||||
|
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
||||||
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
|
||||||
|
|
||||||
switch( Type() )
|
switch( Type() )
|
||||||
{
|
{
|
||||||
|
@ -59,19 +193,25 @@ void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCorner
|
||||||
for( ii = 0; ii < aCircleToSegmentsCount; ii++ )
|
for( ii = 0; ii < aCircleToSegmentsCount; ii++ )
|
||||||
{
|
{
|
||||||
corner_position = wxPoint( dx, 0 );
|
corner_position = wxPoint( dx, 0 );
|
||||||
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
|
RotatePoint( &corner_position.x, &corner_position.y,
|
||||||
|
(1800 / aCircleToSegmentsCount) );
|
||||||
angle = ii * delta;
|
angle = ii * delta;
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position.x, &corner_position.y, angle );
|
||||||
corner_position += m_Start;
|
corner_position.x += m_Start.x;
|
||||||
aCornerBuffer.push_back( corner_position );
|
corner_position.y += m_Start.y;
|
||||||
|
CPolyPt polypoint( corner_position.x, corner_position.y );
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aCornerBuffer.back().end_contour = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
|
TransformRoundedEndsSegmentToPolygon(
|
||||||
m_Start, m_End, aCircleToSegmentsCount,
|
aCornerBuffer,
|
||||||
m_Width + (2 * aClearanceValue) );
|
m_Start, m_End,
|
||||||
|
aCircleToSegmentsCount,
|
||||||
|
m_Width + ( 2 * aClearanceValue) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +219,7 @@ void TRACK::TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCorner
|
||||||
|
|
||||||
/* Function TransformRoundedEndsSegmentToPolygon
|
/* Function TransformRoundedEndsSegmentToPolygon
|
||||||
*/
|
*/
|
||||||
void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
void TransformRoundedEndsSegmentToPolygon( std::vector <CPolyPt>& aCornerBuffer,
|
||||||
wxPoint aStart, wxPoint aEnd,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
int aWidth )
|
int aWidth )
|
||||||
|
@ -89,6 +229,7 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
||||||
wxPoint startp = aStart;
|
wxPoint startp = aStart;
|
||||||
wxPoint corner;
|
wxPoint corner;
|
||||||
int seg_len;
|
int seg_len;
|
||||||
|
CPolyPt polypoint;
|
||||||
|
|
||||||
// normalize the position in order to have endp.x >= 0;
|
// normalize the position in order to have endp.x >= 0;
|
||||||
if( endp.x < 0 )
|
if( endp.x < 0 )
|
||||||
|
@ -105,12 +246,16 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
||||||
corner = wxPoint( 0, rayon );
|
corner = wxPoint( 0, rayon );
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
corner += startp;
|
||||||
aCornerBuffer.push_back( corner );
|
polypoint.x = corner.x;
|
||||||
|
polypoint.y = corner.y;
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
|
|
||||||
corner = wxPoint( seg_len, rayon );
|
corner = wxPoint( seg_len, rayon );
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
corner += startp;
|
||||||
aCornerBuffer.push_back( corner );
|
polypoint.x = corner.x;
|
||||||
|
polypoint.y = corner.y;
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
|
|
||||||
// add right rounded end:
|
// add right rounded end:
|
||||||
for( int ii = delta; ii < 1800; ii += delta )
|
for( int ii = delta; ii < 1800; ii += delta )
|
||||||
|
@ -120,18 +265,24 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
||||||
corner.x += seg_len;
|
corner.x += seg_len;
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
corner += startp;
|
||||||
aCornerBuffer.push_back( corner );
|
polypoint.x = corner.x;
|
||||||
|
polypoint.y = corner.y;
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
}
|
}
|
||||||
|
|
||||||
corner = wxPoint( seg_len, -rayon );
|
corner = wxPoint( seg_len, -rayon );
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
corner += startp;
|
||||||
aCornerBuffer.push_back( corner );
|
polypoint.x = corner.x;
|
||||||
|
polypoint.y = corner.y;
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
|
|
||||||
corner = wxPoint( 0, -rayon );
|
corner = wxPoint( 0, -rayon );
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
corner += startp;
|
||||||
aCornerBuffer.push_back( corner );
|
polypoint.x = corner.x;
|
||||||
|
polypoint.y = corner.y;
|
||||||
|
aCornerBuffer.push_back( polypoint );
|
||||||
|
|
||||||
// add left rounded end:
|
// add left rounded end:
|
||||||
for( int ii = delta; ii < 1800; ii += delta )
|
for( int ii = delta; ii < 1800; ii += delta )
|
||||||
|
@ -140,12 +291,16 @@ void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
||||||
RotatePoint( &corner, ii );
|
RotatePoint( &corner, ii );
|
||||||
RotatePoint( &corner, -delta_angle );
|
RotatePoint( &corner, -delta_angle );
|
||||||
corner += startp;
|
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
|
* Convert the pad shape to a closed polygon
|
||||||
* Used in filling zones calculations
|
* Used in filling zones calculations
|
||||||
* Circles and arcs are approximated by segments
|
* 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
|
* clearance when the circle is approxiamted by segment bigger or equal
|
||||||
* to the real clearance value (usually near from 1.0)
|
* to the real clearance value (usually near from 1.0)
|
||||||
*/
|
*/
|
||||||
void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
void D_PAD:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
|
||||||
int aClearanceValue,
|
int aClearanceValue,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
double aCorrectionFactor )
|
double aCorrectionFactor )
|
||||||
{
|
{
|
||||||
wxPoint corner_position;
|
wxPoint corner_position;
|
||||||
int ii, angle;
|
int ii, angle;
|
||||||
int dx = (m_Size.x / 2) + aClearanceValue;
|
int dx = (m_Size.x / 2) + aClearanceValue;
|
||||||
int dy = (m_Size.y / 2) + aClearanceValue;
|
int dy = (m_Size.y / 2) + aClearanceValue;
|
||||||
|
|
||||||
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
|
||||||
wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset,
|
wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset,
|
||||||
* the pad position is NOT the shape position */
|
* the pad position is NOT the shape position */
|
||||||
wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads
|
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
|
* trapezoidal pads are considered as rect pad shape having they boudary box size
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch( m_PadShape )
|
switch( m_PadShape )
|
||||||
{
|
{
|
||||||
|
@ -180,52 +335,63 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
for( ii = 0; ii < aCircleToSegmentsCount; ii++ )
|
for( ii = 0; ii < aCircleToSegmentsCount; ii++ )
|
||||||
{
|
{
|
||||||
corner_position = wxPoint( dx, 0 );
|
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;
|
angle = ii * delta;
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += PadShapePos;
|
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;
|
break;
|
||||||
|
|
||||||
case PAD_OVAL:
|
case PAD_OVAL:
|
||||||
angle = m_Orient;
|
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 );
|
dy = (int) ( dy * aCorrectionFactor );
|
||||||
int angle_pg; // Polygon angle
|
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
|
RotatePoint( &shape_offset, angle ); // Rotating shape offset vector with component
|
||||||
|
|
||||||
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ ) // Half circle end cap...
|
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, (1800 / aCircleToSegmentsCount) );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
angle_pg = ii * delta;
|
angle_pg = ii * delta;
|
||||||
RotatePoint( &corner_position, angle_pg );
|
RotatePoint( &corner_position, angle_pg );
|
||||||
corner_position += PadShapePos - shape_offset;
|
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, (1800 / aCircleToSegmentsCount) );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
angle_pg = ii * delta;
|
angle_pg = ii * delta;
|
||||||
RotatePoint( &corner_position, angle_pg );
|
RotatePoint( &corner_position, angle_pg );
|
||||||
corner_position += PadShapePos + shape_offset;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
else //if( dy <= dx )
|
else //if( dy <= dx )
|
||||||
{
|
{
|
||||||
dx = (int) ( dx * aCorrectionFactor );
|
dx = (int) ( dx * aCorrectionFactor );
|
||||||
int angle_pg; // Polygon angle
|
int angle_pg; // Polygon angle
|
||||||
wxPoint shape_offset = wxPoint( (dy - dx), 0 );
|
wxPoint shape_offset = wxPoint( (dy - dx), 0 );
|
||||||
RotatePoint( &shape_offset, angle );
|
RotatePoint( &shape_offset, angle );
|
||||||
|
|
||||||
|
@ -237,7 +403,8 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
angle_pg = ii * delta;
|
angle_pg = ii * delta;
|
||||||
RotatePoint( &corner_position, angle_pg );
|
RotatePoint( &corner_position, angle_pg );
|
||||||
corner_position += PadShapePos - shape_offset;
|
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++ )
|
for( ii = 0; ii < aCircleToSegmentsCount / 2 + 1; ii++ )
|
||||||
|
@ -248,9 +415,11 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
angle_pg = ii * delta;
|
angle_pg = ii * delta;
|
||||||
RotatePoint( &corner_position, angle_pg );
|
RotatePoint( &corner_position, angle_pg );
|
||||||
corner_position += PadShapePos + shape_offset;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,21 +429,28 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
psize.y += ABS( m_DeltaSize.x );
|
psize.y += ABS( m_DeltaSize.x );
|
||||||
|
|
||||||
// fall through
|
// 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;
|
angle = m_Orient;
|
||||||
int rounding_radius = (int) ( aClearanceValue * aCorrectionFactor ); // Corner rounding radius
|
int rounding_radius = (int) ( aClearanceValue * aCorrectionFactor ); // Corner rounding radius
|
||||||
int angle_pg; // Polygon increment angle
|
int angle_pg; // Polygon increment angle
|
||||||
|
|
||||||
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
|
for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
|
||||||
{
|
{
|
||||||
corner_position = wxPoint( 0, -rounding_radius );
|
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;
|
angle_pg = i * delta;
|
||||||
RotatePoint( &corner_position, angle_pg ); // Rounding vector rotation
|
RotatePoint( &corner_position, angle_pg );
|
||||||
corner_position -= psize / 2; // Rounding vector + Pad corner offset
|
|
||||||
RotatePoint( &corner_position, angle ); // Rotate according to module orientation
|
// Rounding vector rotation
|
||||||
corner_position += PadShapePos; // Shift origin to position
|
corner_position -= psize / 2; // Rounding vector + Pad corner offset
|
||||||
aCornerBuffer.push_back( corner_position );
|
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++ )
|
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 );
|
corner_position -= wxPoint( psize.x / 2, -psize.y / 2 );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += PadShapePos;
|
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 );
|
corner_position = wxPoint( 0, rounding_radius );
|
||||||
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
|
RotatePoint( &corner_position, (1800 / aCircleToSegmentsCount) );
|
||||||
|
@ -298,7 +477,8 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
corner_position += psize / 2;
|
corner_position += psize / 2;
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += PadShapePos;
|
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++ )
|
||||||
|
@ -310,9 +490,398 @@ void D_PAD::TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBu
|
||||||
corner_position -= wxPoint( -psize.x / 2, psize.y / 2 );
|
corner_position -= wxPoint( -psize.x / 2, psize.y / 2 );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += PadShapePos;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#ifndef CLASS_DRAWSEGMENT_H
|
#ifndef CLASS_DRAWSEGMENT_H
|
||||||
#define CLASS_DRAWSEGMENT_H
|
#define CLASS_DRAWSEGMENT_H
|
||||||
|
#include "polyline.h"
|
||||||
|
|
||||||
class DRAWSEGMENT : public BOARD_ITEM
|
class DRAWSEGMENT : public BOARD_ITEM
|
||||||
{
|
{
|
||||||
|
@ -15,8 +16,8 @@ public:
|
||||||
int m_Shape; // Shape: line, Circle, Arc
|
int m_Shape; // Shape: line, Circle, Arc
|
||||||
int m_Type; // Used in complex associations ( Dimensions.. )
|
int m_Type; // Used in complex associations ( Dimensions.. )
|
||||||
int m_Angle; // Used only for Arcs: Arc angle in 1/10 deg
|
int m_Angle; // Used only for Arcs: Arc angle in 1/10 deg
|
||||||
wxPoint m_BezierC1; // Bezier Control Point 1
|
wxPoint m_BezierC1; // Bezier Control Point 1
|
||||||
wxPoint m_BezierC2; // Bezier Control Point 1
|
wxPoint m_BezierC2; // Bezier Control Point 1
|
||||||
|
|
||||||
std::vector<wxPoint> m_BezierPoints;
|
std::vector<wxPoint> m_BezierPoints;
|
||||||
public:
|
public:
|
||||||
|
@ -42,13 +43,13 @@ public:
|
||||||
* Function GetStart
|
* Function GetStart
|
||||||
* returns the starting point of the graphic
|
* returns the starting point of the graphic
|
||||||
*/
|
*/
|
||||||
wxPoint GetStart() const;
|
wxPoint GetStart() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetEnd
|
* Function GetEnd
|
||||||
* returns the ending point of the graphic
|
* returns the ending point of the graphic
|
||||||
*/
|
*/
|
||||||
wxPoint GetEnd() const;
|
wxPoint GetEnd() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Save
|
* Function Save
|
||||||
|
@ -56,15 +57,15 @@ public:
|
||||||
* @param aFile The FILE to write to.
|
* @param aFile The FILE to write to.
|
||||||
* @return bool - true if success writing else false.
|
* @return bool - true if success writing else false.
|
||||||
*/
|
*/
|
||||||
bool Save( FILE* aFile ) const;
|
bool Save( FILE* aFile ) const;
|
||||||
|
|
||||||
bool ReadDrawSegmentDescr( FILE* File, int* LineNum );
|
bool ReadDrawSegmentDescr( FILE* File, int* LineNum );
|
||||||
|
|
||||||
void Copy( DRAWSEGMENT* source );
|
void Copy( DRAWSEGMENT* source );
|
||||||
|
|
||||||
|
|
||||||
void Draw( WinEDA_DrawPanel* panel, wxDC* DC,
|
void Draw( WinEDA_DrawPanel* panel, wxDC* DC,
|
||||||
int aDrawMode, const wxPoint& offset = ZeroOffset );
|
int aDrawMode, const wxPoint& offset = ZeroOffset );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function DisplayInfo
|
* Function DisplayInfo
|
||||||
|
@ -73,7 +74,7 @@ public:
|
||||||
* Is virtual from EDA_BaseStruct.
|
* Is virtual from EDA_BaseStruct.
|
||||||
* @param frame A WinEDA_BasePcbFrame in which to print status information.
|
* @param frame A WinEDA_BasePcbFrame in which to print status information.
|
||||||
*/
|
*/
|
||||||
virtual void DisplayInfo( WinEDA_DrawFrame* frame );
|
virtual void DisplayInfo( WinEDA_DrawFrame* frame );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,7 +83,7 @@ public:
|
||||||
* @param ref_pos A wxPoint to test
|
* @param ref_pos A wxPoint to test
|
||||||
* @return bool - true if a hit, else false
|
* @return bool - true if a hit, else false
|
||||||
*/
|
*/
|
||||||
bool HitTest( const wxPoint& ref_pos );
|
bool HitTest( const wxPoint& ref_pos );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function HitTest (overlayed)
|
* Function HitTest (overlayed)
|
||||||
|
@ -91,7 +92,7 @@ public:
|
||||||
* @param refPos the given EDA_Rect to test
|
* @param refPos the given EDA_Rect to test
|
||||||
* @return bool - true if a hit, else false
|
* @return bool - true if a hit, else false
|
||||||
*/
|
*/
|
||||||
bool HitTest( EDA_Rect& refArea );
|
bool HitTest( EDA_Rect& refArea );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetClass
|
* Function GetClass
|
||||||
|
@ -116,36 +117,56 @@ public:
|
||||||
return hypot( delta.x, delta.y );
|
return hypot( delta.x, delta.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Move
|
* Function Move
|
||||||
* move this object.
|
* move this object.
|
||||||
* @param const wxPoint& aMoveVector - the move vector for this object.
|
* @param const wxPoint& aMoveVector - the move vector for this object.
|
||||||
*/
|
*/
|
||||||
virtual void Move(const wxPoint& aMoveVector)
|
virtual void Move( const wxPoint& aMoveVector )
|
||||||
{
|
{
|
||||||
m_Start += aMoveVector;
|
m_Start += aMoveVector;
|
||||||
m_End += aMoveVector;
|
m_End += aMoveVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Rotate
|
* Function Rotate
|
||||||
* Rotate this object.
|
* Rotate this object.
|
||||||
* @param const wxPoint& aRotCentre - the rotation point.
|
* @param const wxPoint& aRotCentre - the rotation point.
|
||||||
* @param aAngle - the rotation angle in 0.1 degree.
|
* @param aAngle - the rotation angle in 0.1 degree.
|
||||||
*/
|
*/
|
||||||
virtual void Rotate(const wxPoint& aRotCentre, int aAngle);
|
virtual void Rotate( const wxPoint& aRotCentre, int aAngle );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Flip
|
* Function Flip
|
||||||
* Flip this object, i.e. change the board side for this object
|
* Flip this object, i.e. change the board side for this object
|
||||||
* @param const wxPoint& aCentre - the rotation point.
|
* @param const wxPoint& aCentre - the rotation point.
|
||||||
*/
|
*/
|
||||||
virtual void Flip(const wxPoint& aCentre );
|
virtual void Flip( const wxPoint& aCentre );
|
||||||
|
|
||||||
|
/** 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 TransformShapeWithClearanceToPolygon(
|
||||||
|
std::vector <CPolyPt>& aCornerBuffer,
|
||||||
|
int aClearanceValue,
|
||||||
|
int
|
||||||
|
aCircleToSegmentsCount,
|
||||||
|
double aCorrectionFactor );
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
void Show( int nestLevel, std::ostream& os );
|
void Show( int nestLevel, std::ostream& os );
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
class Pcb3D_GLCanvas;
|
class Pcb3D_GLCanvas;
|
||||||
|
|
||||||
#include "pad_shapes.h"
|
#include "pad_shapes.h"
|
||||||
|
#include "polyline.h"
|
||||||
|
|
||||||
/* Default layers used for pads, according to the pad type.
|
/* Default layers used for pads, according to the pad type.
|
||||||
* this is default values only, they can be changed for a given pad
|
* this is default values only, they can be changed for a given pad
|
||||||
|
@ -141,7 +142,7 @@ public:
|
||||||
m_Pos = aPos;
|
m_Pos = aPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** function TransformPadWithClearanceToPolygon
|
/** function TransformShapeWithClearanceToPolygon
|
||||||
* Convert the pad shape to a closed polygon
|
* Convert the pad shape to a closed polygon
|
||||||
* Used in filling zones calculations
|
* Used in filling zones calculations
|
||||||
* Circles and arcs are approximated by segments
|
* Circles and arcs are approximated by segments
|
||||||
|
@ -152,7 +153,7 @@ public:
|
||||||
* clearance when the circle is approxiamted by segment bigger or equal
|
* clearance when the circle is approxiamted by segment bigger or equal
|
||||||
* to the real clearance value (usually near from 1.0)
|
* to the real clearance value (usually near from 1.0)
|
||||||
*/
|
*/
|
||||||
void TransformPadWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
|
||||||
int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor );
|
int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#define CLASS_PCB_TEXT_H
|
#define CLASS_PCB_TEXT_H
|
||||||
|
|
||||||
#include "base_struct.h"
|
#include "base_struct.h"
|
||||||
|
#include "polyline.h"
|
||||||
|
|
||||||
class TEXTE_PCB : public BOARD_ITEM, public EDA_TextStruct
|
class TEXTE_PCB : public BOARD_ITEM, public EDA_TextStruct
|
||||||
{
|
{
|
||||||
|
@ -110,6 +111,23 @@ public:
|
||||||
return wxT("PTEXT");
|
return wxT("PTEXT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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 TransformShapeWithClearanceToPolygon(
|
||||||
|
std::vector <CPolyPt>& aCornerBuffer,
|
||||||
|
int aClearanceValue,
|
||||||
|
int aCircleToSegmentsCount,
|
||||||
|
double aCorrectionFactor );
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
/**
|
/**
|
||||||
* Function Show
|
* Function Show
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define CLASS_TRACK_H
|
#define CLASS_TRACK_H
|
||||||
|
|
||||||
#include "base_struct.h"
|
#include "base_struct.h"
|
||||||
|
#include "polyline.h"
|
||||||
|
|
||||||
|
|
||||||
// Via attributes (m_Shape parmeter)
|
// Via attributes (m_Shape parmeter)
|
||||||
|
@ -148,7 +149,7 @@ public:
|
||||||
/* divers */
|
/* divers */
|
||||||
int Shape() const { return m_Shape & 0xFF; }
|
int Shape() const { return m_Shape & 0xFF; }
|
||||||
|
|
||||||
/** Function TransformTrackWithClearanceToPolygon
|
/** Function TransformShapeWithClearanceToPolygon
|
||||||
* Convert the track shape to a closed polygon
|
* Convert the track shape to a closed polygon
|
||||||
* Used in filling zones calculations
|
* Used in filling zones calculations
|
||||||
* Circles (vias) and arcs (ends of tracks) are approximated by segments
|
* Circles (vias) and arcs (ends of tracks) are approximated by segments
|
||||||
|
@ -159,7 +160,7 @@ public:
|
||||||
* clearance when the circle is approxiamted by segment bigger or equal
|
* clearance when the circle is approxiamted by segment bigger or equal
|
||||||
* to the real clearance value (usually near from 1.0)
|
* to the real clearance value (usually near from 1.0)
|
||||||
*/
|
*/
|
||||||
void TransformTrackWithClearanceToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
|
||||||
int aClearanceValue,
|
int aClearanceValue,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
double aCorrectionFactor );
|
double aCorrectionFactor );
|
||||||
|
|
|
@ -14,9 +14,15 @@
|
||||||
|
|
||||||
#if defined (CREATE_KBOOL_KEY_FILES) || (CREATE_KBOOL_KEY_FILES_FIRST_PASS)
|
#if defined (CREATE_KBOOL_KEY_FILES) || (CREATE_KBOOL_KEY_FILES_FIRST_PASS)
|
||||||
|
|
||||||
|
// Helper class to handle a coordinate
|
||||||
|
struct kfcoord
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
static FILE* kdebugFile;
|
static FILE* kdebugFile;
|
||||||
static char sDate_Time[256];
|
static char sDate_Time[256];
|
||||||
|
static vector <kfcoord> s_EntityCoordinates;
|
||||||
|
|
||||||
void CreateKeyFile()
|
void CreateKeyFile()
|
||||||
{
|
{
|
||||||
|
@ -48,6 +54,8 @@ void CreateKeyFile()
|
||||||
{
|
{
|
||||||
wxMessageBox( wxT( "CreateKeyFile() cannot create output file" ) );
|
wxMessageBox( wxT( "CreateKeyFile() cannot create output file" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_EntityCoordinates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,11 +66,11 @@ void CloseKeyFile()
|
||||||
fprintf( kdebugFile, "\nENDLIB;\n" );
|
fprintf( kdebugFile, "\nENDLIB;\n" );
|
||||||
fclose( kdebugFile );
|
fclose( kdebugFile );
|
||||||
}
|
}
|
||||||
|
s_EntityCoordinates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* sCurrEntityName = NULL;
|
const char* sCurrEntityName = NULL;
|
||||||
static int s_count;
|
|
||||||
|
|
||||||
void OpenKeyFileEntity( const char* aName )
|
void OpenKeyFileEntity( const char* aName )
|
||||||
{
|
{
|
||||||
|
@ -74,7 +82,7 @@ void OpenKeyFileEntity( const char* aName )
|
||||||
fprintf( kdebugFile, "STRNAME %s;\n", aName );
|
fprintf( kdebugFile, "STRNAME %s;\n", aName );
|
||||||
}
|
}
|
||||||
sCurrEntityName = aName;
|
sCurrEntityName = aName;
|
||||||
s_count = 0;
|
s_EntityCoordinates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,20 +92,45 @@ void CloseKeyFileEntity()
|
||||||
fprintf( kdebugFile, "\nENDSTR %s;\n", sCurrEntityName );
|
fprintf( kdebugFile, "\nENDSTR %s;\n", sCurrEntityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* start a polygon entity in key file
|
||||||
void StartKeyFilePolygon(int aCornersCount, int aLayer)
|
*/
|
||||||
|
void StartKeyFilePolygon( int aLayer)
|
||||||
{
|
{
|
||||||
|
s_EntityCoordinates.clear();
|
||||||
fprintf( kdebugFile, "\nBOUNDARY; LAYER %d; DATATYPE 0;\n", aLayer );
|
fprintf( kdebugFile, "\nBOUNDARY; LAYER %d; DATATYPE 0;\n", aLayer );
|
||||||
fprintf( kdebugFile, " XY %d;\n", aCornersCount );
|
|
||||||
s_count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EndKeyFileElement()
|
/* add a polygon corner to the current polygon entity in key file
|
||||||
|
*/
|
||||||
|
void AddKeyFilePointXY( int aXcoord, int aYcoord)
|
||||||
{
|
{
|
||||||
if ( s_count == 1 )
|
kfcoord coord;
|
||||||
fprintf( kdebugFile, "\n");
|
coord.x = aXcoord;
|
||||||
fprintf( kdebugFile, "\nENDEL;\n" );
|
coord.y = aYcoord;
|
||||||
s_count = 0;
|
s_EntityCoordinates.push_back( coord );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Close a polygon entity in key file
|
||||||
|
* write the entire polygon data to the file
|
||||||
|
*/
|
||||||
|
void EndKeyFilePolygon()
|
||||||
|
{
|
||||||
|
// Polygon must be closed: test for that and close it if needed
|
||||||
|
if( s_EntityCoordinates.size() )
|
||||||
|
{
|
||||||
|
if( s_EntityCoordinates.back().x != s_EntityCoordinates[0].x
|
||||||
|
|| s_EntityCoordinates.back().y != s_EntityCoordinates[0].y )
|
||||||
|
s_EntityCoordinates.push_back( s_EntityCoordinates[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( kdebugFile, " XY %d;\n", s_EntityCoordinates.size() );
|
||||||
|
|
||||||
|
for( unsigned ii = 0; ii < s_EntityCoordinates.size(); ii ++ )
|
||||||
|
fprintf( kdebugFile, " X %d; Y %d;\n",
|
||||||
|
s_EntityCoordinates[ii].x, s_EntityCoordinates[ii].y );
|
||||||
|
fprintf( kdebugFile, "ENDEL;\n" );
|
||||||
|
s_EntityCoordinates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer )
|
void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer )
|
||||||
|
@ -106,30 +139,15 @@ void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned corners_count = aZone->m_FilledPolysList.size();
|
unsigned corners_count = aZone->m_FilledPolysList.size();
|
||||||
int count = 0;
|
|
||||||
unsigned ic = 0;
|
unsigned ic = 0;
|
||||||
CPolyPt* corner;
|
|
||||||
|
|
||||||
while( ic < corners_count )
|
while( ic < corners_count )
|
||||||
{
|
{
|
||||||
// Count corners:
|
|
||||||
count = 0;
|
|
||||||
for( unsigned ii = ic; ii < corners_count; ii++ )
|
|
||||||
{
|
|
||||||
corner = &aZone->m_FilledPolysList[ii];
|
|
||||||
count++;
|
|
||||||
if( corner->end_contour )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write corners:
|
// write polygon:
|
||||||
StartKeyFilePolygon( count+1, aLayer );
|
StartKeyFilePolygon( aLayer );
|
||||||
corner = &aZone->m_FilledPolysList[ic];
|
|
||||||
int startpointX = corner->x;
|
|
||||||
int startpointY = corner->y;
|
|
||||||
for( ; ic < corners_count; ic++ )
|
for( ; ic < corners_count; ic++ )
|
||||||
{
|
{
|
||||||
corner = &aZone->m_FilledPolysList[ic];
|
CPolyPt* corner = &aZone->m_FilledPolysList[ic];
|
||||||
AddKeyFilePointXY( corner->x, corner->y );
|
AddKeyFilePointXY( corner->x, corner->y );
|
||||||
if( corner->end_contour )
|
if( corner->end_contour )
|
||||||
{
|
{
|
||||||
|
@ -137,21 +155,8 @@ void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Close polygon:
|
EndKeyFilePolygon();
|
||||||
AddKeyFilePointXY( startpointX, startpointY );
|
|
||||||
EndKeyFileElement();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddKeyFilePointXY( int aXcoord, int aYcoord)
|
|
||||||
{
|
|
||||||
if ( s_count >= 2 )
|
|
||||||
{
|
|
||||||
s_count = 0;
|
|
||||||
fprintf( kdebugFile, "\n");
|
|
||||||
}
|
|
||||||
fprintf( kdebugFile, " X %d; Y %d;", aXcoord, aYcoord );
|
|
||||||
s_count ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,9 +38,9 @@ void CloseKeyFileEntity();
|
||||||
/* polygon creations:
|
/* polygon creations:
|
||||||
*/
|
*/
|
||||||
void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer);
|
void CopyPolygonsFromFilledPolysListToKeyFile( ZONE_CONTAINER* aZone, int aLayer);
|
||||||
void StartKeyFilePolygon(int aCornersCount, int aLayer);
|
void StartKeyFilePolygon( int aLayer);
|
||||||
void AddKeyFilePointXY( int aXcoord, int aYcoord);
|
void AddKeyFilePointXY( int aXcoord, int aYcoord);
|
||||||
void EndKeyFileElement();
|
void EndKeyFilePolygon();
|
||||||
|
|
||||||
#endif // CREATE_KBOOL_KEY_FILES
|
#endif // CREATE_KBOOL_KEY_FILES
|
||||||
|
|
||||||
|
|
|
@ -51,43 +51,40 @@
|
||||||
|
|
||||||
extern void Test_For_Copper_Island_And_Remove( BOARD* aPcb,
|
extern void Test_For_Copper_Island_And_Remove( BOARD* aPcb,
|
||||||
ZONE_CONTAINER* aZone_container );
|
ZONE_CONTAINER* aZone_container );
|
||||||
extern void TransformRoundedEndsSegmentToPolygon( std::vector <wxPoint>& aCornerBuffer,
|
extern void TransformRoundedEndsSegmentToPolygon( std::vector <CPolyPt>& aCornerBuffer,
|
||||||
wxPoint aStart, wxPoint aEnd,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
int aWidth );
|
int aWidth );
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
void CreateThermalReliefPadPolygon( std::vector<CPolyPt>& aCornerBuffer,
|
||||||
bool s_GenDataForKbool = false;
|
D_PAD& aPad,
|
||||||
#endif
|
int aThermalGap,
|
||||||
|
int aCopperThickness,
|
||||||
|
int aMinThicknessValue,
|
||||||
|
int aCircleToSegmentsCount,
|
||||||
|
double aCorrectionFactor,
|
||||||
|
int aThermalRot );
|
||||||
|
|
||||||
|
|
||||||
// Local Functions:
|
// Local Functions:
|
||||||
#ifdef USE_STUBS_FOR_THERMAL
|
#ifdef USE_STUBS_FOR_THERMAL
|
||||||
#warning \
|
#warning \
|
||||||
USE_STUBS_FOR_THERMAL is defined: for test version only do not use for working pcbnew version
|
USE_STUBS_FOR_THERMAL is defined: for test version only do not use for working pcbnew version
|
||||||
void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_container,
|
void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_container,
|
||||||
int aThermalGap,
|
int aThermalGap,
|
||||||
int aCopperThickness, int aMinThicknessValue );
|
int aCopperThickness, int aMinThicknessValue );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
TRACK& aTrack, int aClearanceValue );
|
TRACK& aTrack, int aClearanceValue );
|
||||||
void AddPadWithClearancePolygon( Bool_Engine* aBooleng, D_PAD& aPad, int aClearanceValue );
|
void AddPadWithClearancePolygon( Bool_Engine* aBooleng, D_PAD& aPad, int aClearanceValue );
|
||||||
void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
int AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
||||||
D_PAD& aPad,
|
D_PAD& aPad,
|
||||||
int aThermalGap,
|
int aThermalGap,
|
||||||
int aCopperThickness, int aMinThicknessValue );
|
int aCopperThickness, int aMinThicknessValue );
|
||||||
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
||||||
wxPoint aStart, wxPoint aEnd,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aWidth );
|
int aWidth );
|
||||||
|
|
||||||
void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng,
|
|
||||||
TEXTE_PCB* aText, int aClearanceValue );
|
|
||||||
|
|
||||||
static void AddRingPolygon( Bool_Engine* aBooleng,
|
|
||||||
wxPoint aCentre,
|
|
||||||
wxPoint aStart,
|
|
||||||
int aArcAngle,
|
|
||||||
int aWidth );
|
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
/* how many segments are used to create a polygon from a circle: */
|
/* how many segments are used to create a polygon from a circle: */
|
||||||
|
@ -300,47 +297,67 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
if( item->GetLayer() != GetLayer() && item->GetLayer() != EDGE_N )
|
if( item->GetLayer() != GetLayer() && item->GetLayer() != EDGE_N )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
static std::vector <CPolyPt> cornerBuffer;
|
||||||
|
cornerBuffer.clear();
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
{
|
{
|
||||||
case TYPE_DRAWSEGMENT:
|
case TYPE_DRAWSEGMENT:
|
||||||
|
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||||
switch( ( (DRAWSEGMENT*) item )->m_Shape )
|
cornerBuffer,
|
||||||
{
|
m_ZoneClearance,
|
||||||
case S_CIRCLE:
|
s_CircleToSegmentsCount,
|
||||||
AddRingPolygon( booleng, ( (DRAWSEGMENT*) item )->m_Start, // Circle centre
|
s_Correction );
|
||||||
( (DRAWSEGMENT*) item )->m_End, 3600,
|
|
||||||
( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) );
|
|
||||||
have_poly_to_substract = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_ARC:
|
|
||||||
AddRingPolygon( booleng, ( (DRAWSEGMENT*) item )->m_Start, // Arc centre
|
|
||||||
( (DRAWSEGMENT*) item )->m_End,
|
|
||||||
( (DRAWSEGMENT*) item )->m_Angle,
|
|
||||||
( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) );
|
|
||||||
have_poly_to_substract = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
AddRoundedEndsSegmentPolygon( booleng,
|
|
||||||
( (DRAWSEGMENT*) item )->m_Start,
|
|
||||||
( (DRAWSEGMENT*) item )->m_End,
|
|
||||||
( (DRAWSEGMENT*) item )->m_Width +
|
|
||||||
(2 * m_ZoneClearance) );
|
|
||||||
have_poly_to_substract = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case TYPE_TEXTE:
|
case TYPE_TEXTE:
|
||||||
AddTextBoxWithClearancePolygon( booleng, (TEXTE_PCB*) item, m_ZoneClearance );
|
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygon(
|
||||||
have_poly_to_substract = true;
|
cornerBuffer,
|
||||||
|
m_ZoneClearance,
|
||||||
|
s_CircleToSegmentsCount,
|
||||||
|
s_Correction );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( cornerBuffer.size() == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// cornerBuffer can contain more than one polygon,
|
||||||
|
// so read cornerBuffer and verify if there is a end of polygon corner:
|
||||||
|
for( unsigned icnt = 0; icnt < cornerBuffer.size(); )
|
||||||
|
{
|
||||||
|
booleng->StartPolygonAdd( GROUP_B );
|
||||||
|
{
|
||||||
|
have_poly_to_substract = true;
|
||||||
|
unsigned ii;
|
||||||
|
for( ii = icnt; ii < cornerBuffer.size(); ii++ )
|
||||||
|
{
|
||||||
|
booleng->AddPoint( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
if( cornerBuffer[ii].end_contour )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
booleng->EndPolygonAdd();
|
||||||
|
|
||||||
|
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
||||||
|
StartKeyFilePolygon( 1 );
|
||||||
|
for( ii = icnt; ii < cornerBuffer.size(); ii++ )
|
||||||
|
{
|
||||||
|
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
if( cornerBuffer[ii].end_contour )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndKeyFilePolygon();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
icnt = ii + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
||||||
|
@ -417,11 +434,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
item_boundingbox.Inflate( m_ThermalReliefGapValue, m_ThermalReliefGapValue );
|
item_boundingbox.Inflate( m_ThermalReliefGapValue, m_ThermalReliefGapValue );
|
||||||
if( item_boundingbox.Intersects( zone_boundingbox ) )
|
if( item_boundingbox.Intersects( zone_boundingbox ) )
|
||||||
{
|
{
|
||||||
have_poly_to_substract = true;
|
if( AddThermalReliefPadPolygon( booleng, *pad,
|
||||||
AddThermalReliefPadPolygon( booleng, *pad,
|
|
||||||
m_ThermalReliefGapValue,
|
m_ThermalReliefGapValue,
|
||||||
m_ThermalReliefCopperBridgeValue,
|
m_ThermalReliefCopperBridgeValue,
|
||||||
m_ZoneMinThickness );
|
m_ZoneMinThickness ) )
|
||||||
|
have_poly_to_substract = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,14 +630,14 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
D_PAD& aPad, int aClearanceValue )
|
D_PAD& aPad, int aClearanceValue )
|
||||||
{
|
{
|
||||||
static std::vector <wxPoint> cornerBuffer;
|
static std::vector <CPolyPt> cornerBuffer;
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) == 0 )
|
if( aBooleng->StartPolygonAdd( GROUP_B ) == 0 )
|
||||||
return;
|
return;
|
||||||
cornerBuffer.clear();
|
cornerBuffer.clear();
|
||||||
aPad.TransformPadWithClearanceToPolygon( cornerBuffer,
|
aPad.TransformShapeWithClearanceToPolygon( cornerBuffer,
|
||||||
aClearanceValue,
|
aClearanceValue,
|
||||||
s_CircleToSegmentsCount,
|
s_CircleToSegmentsCount,
|
||||||
s_Correction );
|
s_Correction );
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
||||||
aBooleng->AddPoint( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
aBooleng->AddPoint( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
@ -628,13 +645,11 @@ void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
aBooleng->EndPolygonAdd();
|
aBooleng->EndPolygonAdd();
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
||||||
StartKeyFilePolygon( cornerBuffer.size() + 1, 1 );
|
StartKeyFilePolygon( 1 );
|
||||||
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
||||||
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
|
||||||
// Close polygon
|
EndKeyFilePolygon();
|
||||||
AddKeyFilePointXY( cornerBuffer[0].x, cornerBuffer[0].y );
|
|
||||||
EndKeyFileElement();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,6 +657,7 @@ void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
/** function CreateStubsForThermalShapes()
|
/** function CreateStubsForThermalShapes()
|
||||||
* Only for testing the thermal shapes by stubs purposes
|
* Only for testing the thermal shapes by stubs purposes
|
||||||
* Do not use for working pcbnew versions
|
* Do not use for working pcbnew versions
|
||||||
|
* This is just for kbool test only
|
||||||
*/
|
*/
|
||||||
void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_container,
|
void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_container,
|
||||||
int aThermalGap,
|
int aThermalGap,
|
||||||
|
@ -658,9 +674,6 @@ void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_cont
|
||||||
if( aCopperThickness <= aMinThicknessValue )
|
if( aCopperThickness <= aMinThicknessValue )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
|
||||||
s_GenDataForKbool = true;
|
|
||||||
#endif
|
|
||||||
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
|
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
|
||||||
{
|
{
|
||||||
for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() )
|
for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() )
|
||||||
|
@ -737,9 +750,6 @@ void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_cont
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
|
||||||
s_GenDataForKbool = false;
|
|
||||||
#endif
|
|
||||||
if( have_poly_to_add )
|
if( have_poly_to_add )
|
||||||
{
|
{
|
||||||
/* Add the main corrected polygon (i.e. the filled area using only one outline)
|
/* Add the main corrected polygon (i.e. the filled area using only one outline)
|
||||||
|
@ -774,404 +784,60 @@ void CreateStubsForThermalShapes( BOARD* aPcb, ZONE_CONTAINER* aZone_cont
|
||||||
* When Kbool calculates the filled areas :
|
* When Kbool calculates the filled areas :
|
||||||
* i.e when substracting holes (thermal shapes) to the full zone area
|
* i.e when substracting holes (thermal shapes) to the full zone area
|
||||||
* under certains circumstances kboll drop some holes.
|
* under certains circumstances kboll drop some holes.
|
||||||
* These circumstances are:
|
* see CreateThermalReliefPadPolygon().
|
||||||
* 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 AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
int AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
||||||
D_PAD& aPad,
|
D_PAD& aPad,
|
||||||
int aThermalGap,
|
int aThermalGap,
|
||||||
int aCopperThickness, int aMinThicknessValue )
|
int aCopperThickness, int aMinThicknessValue )
|
||||||
{
|
{
|
||||||
wxPoint corner, corner_end;
|
static std::vector <CPolyPt> cornerBuffer;
|
||||||
wxPoint PadShapePos = aPad.ReturnShapePos(); /* Note: for pad having a shape offset,
|
cornerBuffer.clear();
|
||||||
* the pad position is NOT the shape position */
|
|
||||||
int angle = 0;
|
|
||||||
wxSize copper_thickness;
|
|
||||||
int dx = aPad.m_Size.x / 2;
|
|
||||||
int dy = aPad.m_Size.y / 2;
|
|
||||||
|
|
||||||
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
|
int polycount = 0;
|
||||||
|
int thermalRot = 450;
|
||||||
/* 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 ) );
|
|
||||||
#ifndef CREATE_KBOOL_KEY_FILES_WITH_0_DEG
|
|
||||||
corners_buffer.push_back( corner );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
// angle = 450 (45.0 degrees orientation) seems work fine.
|
|
||||||
// angle = 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
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES_WITH_0_DEG
|
#ifdef CREATE_KBOOL_KEY_FILES_WITH_0_DEG
|
||||||
angle = 0;
|
thermalRot = 0;
|
||||||
#else
|
|
||||||
angle = 450;
|
|
||||||
#endif
|
|
||||||
int angle_pad = aPad.m_Orient; // Pad orientation
|
|
||||||
for( unsigned ihole = 0; ihole < 4; ihole++ )
|
|
||||||
{
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
|
||||||
StartKeyFilePolygon( corners_buffer.size() + 1, 1 );
|
|
||||||
#endif
|
|
||||||
for( unsigned ii = 0; ii < corners_buffer.size(); ii++ )
|
|
||||||
{
|
|
||||||
corner = corners_buffer[ii];
|
|
||||||
RotatePoint( &corner, angle + angle_pad ); // Rotate by segment angle and pad orientation
|
|
||||||
corner += PadShapePos;
|
|
||||||
aBooleng->AddPoint( corner.x, corner.y );
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
|
||||||
AddKeyFilePointXY( corner.x, corner.y );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
|
||||||
|
|
||||||
// Close polygon
|
|
||||||
corner = corners_buffer[0];
|
|
||||||
RotatePoint( &corner, angle + angle_pad ); // Rotate by segment angle and pad orientation
|
|
||||||
corner += PadShapePos;
|
|
||||||
AddKeyFilePointXY( corner.x, corner.y );
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
CreateThermalReliefPadPolygon( cornerBuffer,
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
aPad, aThermalGap, aCopperThickness,
|
||||||
EndKeyFileElement();
|
aMinThicknessValue,
|
||||||
#endif
|
s_CircleToSegmentsCount,
|
||||||
angle += 900; // Note: angle in in 0.1 deg.
|
s_Correction, thermalRot );
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAD_OVAL:
|
// cornerBuffer can contain more than one polygon,
|
||||||
|
// so read cornerBuffer and verify if there is a end of polygon corner:
|
||||||
|
for( unsigned icnt = 0; icnt < cornerBuffer.size(); )
|
||||||
{
|
{
|
||||||
// Oval pad support along the lines of round and rectangular pads
|
aBooleng->StartPolygonAdd( GROUP_B );
|
||||||
std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
|
polycount++;
|
||||||
|
unsigned ii;
|
||||||
int dx = (aPad.m_Size.x / 2) + aThermalGap; // Cutout radius x
|
for( ii = icnt; ii < cornerBuffer.size(); ii++ )
|
||||||
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 );
|
aBooleng->AddPoint( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
supp_angle = 900;
|
if( cornerBuffer[ii].end_contour )
|
||||||
EXCHG( copper_thickness.x, copper_thickness.y );
|
break;
|
||||||
}
|
|
||||||
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
|
aBooleng->EndPolygonAdd();
|
||||||
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
|
#ifdef CREATE_KBOOL_KEY_FILES
|
||||||
corner_end.y = copper_thickness.y / 2;
|
StartKeyFilePolygon( 1 );
|
||||||
corner_end.x =
|
for( ii = icnt; ii < cornerBuffer.size(); ii++ )
|
||||||
(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 );
|
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
RotatePoint( &corner, delta );
|
if( cornerBuffer[ii].end_contour )
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//corners_buffer.push_back(corner + shape_offset); // TODO: about one mil geometry error forms somewhere.
|
EndKeyFilePolygon();
|
||||||
corners_buffer.push_back( corner_end + shape_offset );
|
#endif
|
||||||
corners_buffer.push_back( last_corner + shape_offset ); // Enabling the line above shows intersection point.
|
|
||||||
|
|
||||||
/* Create 2 holes, rotated by pad rotation.
|
icnt = ii + 1;
|
||||||
*/
|
|
||||||
angle = aPad.m_Orient + supp_angle;
|
|
||||||
for( int irect = 0; irect < 2; irect++ )
|
|
||||||
{
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
|
|
||||||
{
|
|
||||||
wxPoint cpos = corners_buffer[ic];
|
|
||||||
RotatePoint( &cpos, angle );
|
|
||||||
cpos += PadShapePos;
|
|
||||||
aBooleng->AddPoint( cpos.x, cpos.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
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++ )
|
|
||||||
{
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
|
|
||||||
{
|
|
||||||
wxPoint cpos = corners_buffer[ic];
|
|
||||||
RotatePoint( &cpos, angle );
|
|
||||||
cpos += PadShapePos;
|
|
||||||
aBooleng->AddPoint( cpos.x, cpos.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
angle += 1800;
|
|
||||||
if( angle >= 3600 )
|
|
||||||
angle -= 3600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case PAD_RECT: // draw 4 Holes
|
return polycount;
|
||||||
{
|
|
||||||
/* 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 ) );
|
|
||||||
|
|
||||||
angle = aPad.m_Orient;
|
|
||||||
int rounding_radius = (int) ( aThermalGap * s_Correction ); // Corner rounding radius
|
|
||||||
int angle_pg; // Polygon increment angle
|
|
||||||
|
|
||||||
for( int i = 0; i < s_CircleToSegmentsCount / 4 + 1; i++ )
|
|
||||||
{
|
|
||||||
wxPoint corner_position = wxPoint( 0, -rounding_radius );
|
|
||||||
RotatePoint( &corner_position, (1800 / s_CircleToSegmentsCount) ); // 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++ )
|
|
||||||
{
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
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
|
|
||||||
aBooleng->AddPoint( cpos.x, cpos.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
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++ )
|
|
||||||
{
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
|
|
||||||
{
|
|
||||||
wxPoint cpos = corners_buffer[ic];
|
|
||||||
RotatePoint( &cpos, angle );
|
|
||||||
cpos += PadShapePos;
|
|
||||||
aBooleng->AddPoint( cpos.x, cpos.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
angle += 1800;
|
|
||||||
if( angle >= 3600 )
|
|
||||||
angle -= 3600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1182,9 +848,9 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
||||||
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
TRACK& aTrack, int aClearanceValue )
|
TRACK& aTrack, int aClearanceValue )
|
||||||
{
|
{
|
||||||
static std::vector <wxPoint> cornerBuffer;
|
static std::vector <CPolyPt> cornerBuffer;
|
||||||
cornerBuffer.clear();
|
cornerBuffer.clear();
|
||||||
aTrack.TransformTrackWithClearanceToPolygon( cornerBuffer,
|
aTrack.TransformShapeWithClearanceToPolygon( cornerBuffer,
|
||||||
aClearanceValue,
|
aClearanceValue,
|
||||||
s_CircleToSegmentsCount,
|
s_CircleToSegmentsCount,
|
||||||
s_Correction );
|
s_Correction );
|
||||||
|
@ -1198,13 +864,11 @@ void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
aBooleng->EndPolygonAdd();
|
aBooleng->EndPolygonAdd();
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
#ifdef CREATE_KBOOL_KEY_FILES_FIRST_PASS
|
||||||
StartKeyFilePolygon( cornerBuffer.size() + 1, 1 );
|
StartKeyFilePolygon( 1 );
|
||||||
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
||||||
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
|
||||||
// Close polygon
|
EndKeyFilePolygon();
|
||||||
AddKeyFilePointXY( cornerBuffer[0].x, cornerBuffer[0].y );
|
|
||||||
EndKeyFileElement();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,12 +881,12 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
||||||
wxPoint aStart, wxPoint aEnd,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aWidth )
|
int aWidth )
|
||||||
{
|
{
|
||||||
static std::vector <wxPoint> cornerBuffer;
|
static std::vector <CPolyPt> cornerBuffer;
|
||||||
cornerBuffer.clear();
|
cornerBuffer.clear();
|
||||||
TransformRoundedEndsSegmentToPolygon( cornerBuffer,
|
TransformRoundedEndsSegmentToPolygon( cornerBuffer,
|
||||||
aStart, aEnd,
|
aStart, aEnd,
|
||||||
s_CircleToSegmentsCount,
|
s_CircleToSegmentsCount,
|
||||||
aWidth );
|
aWidth );
|
||||||
|
|
||||||
if( !aBooleng->StartPolygonAdd( GROUP_B ) )
|
if( !aBooleng->StartPolygonAdd( GROUP_B ) )
|
||||||
return;
|
return;
|
||||||
|
@ -1233,100 +897,15 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
||||||
aBooleng->EndPolygonAdd();
|
aBooleng->EndPolygonAdd();
|
||||||
|
|
||||||
#ifdef CREATE_KBOOL_KEY_FILES
|
#ifdef CREATE_KBOOL_KEY_FILES
|
||||||
StartKeyFilePolygon( cornerBuffer.size() + 1, 1 );
|
StartKeyFilePolygon( 1 );
|
||||||
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
for( unsigned ii = 0; ii < cornerBuffer.size(); ii++ )
|
||||||
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
AddKeyFilePointXY( cornerBuffer[ii].x, cornerBuffer[ii].y );
|
||||||
|
|
||||||
// Close polygon
|
EndKeyFilePolygon();
|
||||||
AddKeyFilePointXY( cornerBuffer[0].x, cornerBuffer[0].y );
|
|
||||||
EndKeyFileElement();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Function AddRingPolygon
|
|
||||||
* Add a polygon cutout for an Arc in a zone area
|
|
||||||
* Convert arcs to multiple straight segments
|
|
||||||
* @param aBooleng = the bool engine to use
|
|
||||||
* @param aCentre = centre of the arc or circle
|
|
||||||
* @param aStart = start point of the arc, or apoint of the circle
|
|
||||||
* @param aArcAngle = arc angle in 0.1 degrees. For a circle, aArcAngle = 3600
|
|
||||||
* @param aWidth = width of the line
|
|
||||||
*/
|
|
||||||
void AddRingPolygon( Bool_Engine* aBooleng, wxPoint aCentre,
|
|
||||||
wxPoint aStart, int aArcAngle,
|
|
||||||
int aWidth )
|
|
||||||
{
|
|
||||||
wxPoint arc_start, arc_end;
|
|
||||||
int delta = 3600 / s_CircleToSegmentsCount; // 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, curr_start = arc_start;
|
|
||||||
for( int ii = delta; ii < aArcAngle; ii += delta )
|
|
||||||
{
|
|
||||||
curr_end = arc_start;
|
|
||||||
RotatePoint( &curr_end, aCentre, -ii );
|
|
||||||
AddRoundedEndsSegmentPolygon( aBooleng, curr_start, curr_end, aWidth );
|
|
||||||
curr_start = curr_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( curr_end != arc_end )
|
|
||||||
AddRoundedEndsSegmentPolygon( aBooleng, curr_end, arc_end, aWidth );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** function AddTextBoxWithClearancePolygon
|
|
||||||
* creates a polygon containing the text and add it to bool engine
|
|
||||||
*/
|
|
||||||
void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng,
|
|
||||||
TEXTE_PCB* aText, int aClearanceValue )
|
|
||||||
{
|
|
||||||
if( aText->GetLength() == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
wxPoint corners[4]; // Buffer of polygon corners
|
|
||||||
|
|
||||||
EDA_Rect rect = aText->GetTextBox( -1 );
|
|
||||||
rect.Inflate( aClearanceValue, aClearanceValue );
|
|
||||||
corners[0] = rect.GetOrigin();
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
for( int ii = 0; ii < 4; ii++ )
|
|
||||||
{
|
|
||||||
// Rotate polygon
|
|
||||||
RotatePoint( &corners[ii].x,
|
|
||||||
&corners[ii].y,
|
|
||||||
aText->m_Pos.x,
|
|
||||||
aText->m_Pos.y,
|
|
||||||
aText->m_Orient );
|
|
||||||
aBooleng->AddPoint( corners[ii].x, corners[ii].y );
|
|
||||||
}
|
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************************************/
|
/***********************************************************************************************************/
|
||||||
int ZONE_CONTAINER::CopyPolygonsFromFilledPolysListToBoolengine( Bool_Engine* aBoolengine,
|
int ZONE_CONTAINER::CopyPolygonsFromFilledPolysListToBoolengine( Bool_Engine* aBoolengine,
|
||||||
GroupType aGroup )
|
GroupType aGroup )
|
||||||
|
|
Loading…
Reference in New Issue