DSN export: export RECT and ARC shapes (on silkscreen layer) from footprints
Also export arc track segments as lines. (Freerouter does not support QARCs) Fixes #8769 https://gitlab.com/kicad/code/kicad/issues/8769
This commit is contained in:
parent
fb246403d2
commit
54b6f51633
|
@ -48,6 +48,22 @@ enum RECT_CHAMFER_POSITIONS : int
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a polyline to approximate a arc
|
||||||
|
*
|
||||||
|
* @param aPolyline is a buffer to store the polyline.
|
||||||
|
* @param aCenter is the center of the arc.
|
||||||
|
* @param aRadius is the radius of the arc.
|
||||||
|
* @param aStartAngleDeg is the starting point (in degrees) of the arc.
|
||||||
|
* @param aArcAngleDeg is the angle (in degrees) of the arc.
|
||||||
|
* @param aError is the internal units allowed for error approximation.
|
||||||
|
* @param aErrorLoc determines if the approximation error be placed outside or inside the polygon.
|
||||||
|
*/
|
||||||
|
int ConvertArcToPolyline( SHAPE_LINE_CHAIN& aPolyline, VECTOR2I aCenter, int aRadius,
|
||||||
|
double aStartAngleDeg, double aArcAngleDeg, double aAccuracy,
|
||||||
|
ERROR_LOC aErrorLoc );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a circle to a polygon, using multiple straight lines.
|
* Convert a circle to a polygon, using multiple straight lines.
|
||||||
*
|
*
|
||||||
|
|
|
@ -393,27 +393,27 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int convertArcToPolyline( SHAPE_LINE_CHAIN& aPolyline, VECTOR2I aCenter, int aRadius,
|
int ConvertArcToPolyline( SHAPE_LINE_CHAIN& aPolyline, VECTOR2I aCenter, int aRadius,
|
||||||
double aStartAngle, double aArcAngle, double aAccuracy,
|
double aStartAngleDeg, double aArcAngleDeg, double aAccuracy,
|
||||||
ERROR_LOC aErrorLoc )
|
ERROR_LOC aErrorLoc )
|
||||||
{
|
{
|
||||||
double endAngle = aStartAngle + aArcAngle;
|
double endAngle = aStartAngleDeg + aArcAngleDeg;
|
||||||
int n = 2;
|
int n = 2;
|
||||||
|
|
||||||
if( aRadius >= aAccuracy )
|
if( aRadius >= aAccuracy )
|
||||||
n = GetArcToSegmentCount( aRadius, aAccuracy, aArcAngle )+1; // n >= 3
|
n = GetArcToSegmentCount( aRadius, aAccuracy, aArcAngleDeg )+1; // n >= 3
|
||||||
|
|
||||||
if( aErrorLoc == ERROR_OUTSIDE )
|
if( aErrorLoc == ERROR_OUTSIDE )
|
||||||
{
|
{
|
||||||
int seg360 = std::abs( KiROUND( n * 360.0 / aArcAngle ) );
|
int seg360 = std::abs( KiROUND( n * 360.0 / aArcAngleDeg ) );
|
||||||
int actual_delta_radius = CircleToEndSegmentDeltaRadius( aRadius, seg360 );
|
int actual_delta_radius = CircleToEndSegmentDeltaRadius( aRadius, seg360 );
|
||||||
aRadius += actual_delta_radius;
|
aRadius += actual_delta_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i = 0; i <= n ; i++ )
|
for( int i = 0; i <= n ; i++ )
|
||||||
{
|
{
|
||||||
double rot = aStartAngle;
|
double rot = aStartAngleDeg;
|
||||||
rot += ( aArcAngle * i ) / n;
|
rot += ( aArcAngleDeg * i ) / n;
|
||||||
|
|
||||||
double x = aCenter.x + aRadius * cos( rot * M_PI / 180.0 );
|
double x = aCenter.x + aRadius * cos( rot * M_PI / 180.0 );
|
||||||
double y = aCenter.y + aRadius * sin( rot * M_PI / 180.0 );
|
double y = aCenter.y + aRadius * sin( rot * M_PI / 180.0 );
|
||||||
|
@ -480,11 +480,11 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, wxPoi
|
||||||
|
|
||||||
polyshape.NewOutline();
|
polyshape.NewOutline();
|
||||||
|
|
||||||
convertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
|
ConvertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
|
||||||
arc_angle_start_deg, arc_angle, aError, errorLocOuter );
|
arc_angle_start_deg, arc_angle, aError, errorLocOuter );
|
||||||
|
|
||||||
if( arc_inner_radius > 0 )
|
if( arc_inner_radius > 0 )
|
||||||
convertArcToPolyline( polyshape.Outline(2), center, arc_inner_radius,
|
ConvertArcToPolyline( polyshape.Outline(2), center, arc_inner_radius,
|
||||||
arc_angle_end_deg, -arc_angle, aError, errorLocInner );
|
arc_angle_end_deg, -arc_angle, aError, errorLocInner );
|
||||||
else
|
else
|
||||||
polyshape.Append( center );
|
polyshape.Append( center );
|
||||||
|
|
|
@ -742,46 +742,126 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
||||||
{
|
{
|
||||||
// this is best done by 4 QARC's but freerouter does not yet support QARCs.
|
// this is best done by 4 QARC's but freerouter does not yet support QARCs.
|
||||||
// for now, support by using line segments.
|
// for now, support by using line segments.
|
||||||
|
|
||||||
outline = new SHAPE( image, T_outline );
|
outline = new SHAPE( image, T_outline );
|
||||||
|
|
||||||
image->Append( outline );
|
image->Append( outline );
|
||||||
|
|
||||||
path = new PATH( outline );
|
path = new PATH( outline );
|
||||||
|
|
||||||
outline->SetShape( path );
|
outline->SetShape( path );
|
||||||
path->SetAperture( scale( graphic->GetWidth() ) );
|
path->SetAperture( scale( graphic->GetWidth() ) );
|
||||||
path->SetLayerId( "signal" );
|
path->SetLayerId( "signal" );
|
||||||
|
|
||||||
// Do the math using KiCad units, that way we stay out of the
|
double radius = graphic->GetRadius();
|
||||||
// scientific notation range of floating point numbers in the
|
wxPoint circle_centre = graphic->m_Start0;
|
||||||
// DSN file. We do not parse scientific notation in our own
|
|
||||||
// lexer/beautifier, and the spec is not clear that this is
|
|
||||||
// required. Fixed point floats are all that should be needed.
|
|
||||||
|
|
||||||
double radius = GetLineLength( graphic->GetStart(), graphic->GetEnd() );
|
SHAPE_LINE_CHAIN polyline;
|
||||||
|
ConvertArcToPolyline( polyline, VECTOR2I( circle_centre ), radius,
|
||||||
|
0.0, 360.0, ARC_HIGH_DEF, ERROR_INSIDE );
|
||||||
|
|
||||||
// seg count to approximate circle by line segments
|
for( int ii = 0; ii < polyline.PointCount(); ++ii )
|
||||||
int seg_per_circle = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
|
|
||||||
|
|
||||||
for( int ii = 0; ii < seg_per_circle; ++ii )
|
|
||||||
{
|
{
|
||||||
double radians = 2*M_PI / seg_per_circle * ii;
|
wxPoint corner( polyline.CPoint( ii ).x, polyline.CPoint( ii ).y );
|
||||||
wxPoint point( KiROUND( radius * cos( radians ) ),
|
path->AppendPoint( mapPt( corner ) );
|
||||||
KiROUND( radius * sin( radians ) ) );
|
|
||||||
|
|
||||||
point += graphic->m_Start0; // an offset
|
|
||||||
|
|
||||||
path->AppendPoint( mapPt( point ) );
|
|
||||||
}
|
}
|
||||||
// The shape must be closed
|
|
||||||
wxPoint point( radius , 0 );
|
|
||||||
point += graphic->m_Start0;
|
|
||||||
path->AppendPoint( mapPt( point ) );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCB_SHAPE_TYPE::RECT:
|
case PCB_SHAPE_TYPE::RECT:
|
||||||
|
{
|
||||||
|
outline = new SHAPE( image, T_outline );
|
||||||
|
|
||||||
|
image->Append( outline );
|
||||||
|
path = new PATH( outline );
|
||||||
|
|
||||||
|
outline->SetShape( path );
|
||||||
|
path->SetAperture( scale( graphic->GetWidth() ) );
|
||||||
|
path->SetLayerId( "signal" );
|
||||||
|
wxPoint corner = graphic->GetStart0();
|
||||||
|
path->AppendPoint( mapPt( corner ) );
|
||||||
|
|
||||||
|
corner.x = graphic->GetEnd0().x;
|
||||||
|
path->AppendPoint( mapPt( corner ) );
|
||||||
|
|
||||||
|
corner.y = graphic->GetEnd0().y;
|
||||||
|
path->AppendPoint( mapPt( corner ) );
|
||||||
|
|
||||||
|
corner.x = graphic->GetStart0().x;
|
||||||
|
path->AppendPoint( mapPt( corner ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PCB_SHAPE_TYPE::ARC:
|
case PCB_SHAPE_TYPE::ARC:
|
||||||
|
{
|
||||||
|
// this is best done by QARC's but freerouter does not yet support QARCs.
|
||||||
|
// for now, support by using line segments.
|
||||||
|
// So we use a polygon (PATH) to create a approximative arc shape
|
||||||
|
outline = new SHAPE( image, T_outline );
|
||||||
|
|
||||||
|
image->Append( outline );
|
||||||
|
path = new PATH( outline );
|
||||||
|
|
||||||
|
outline->SetShape( path );
|
||||||
|
path->SetAperture( 0 );//scale( graphic->GetWidth() ) );
|
||||||
|
path->SetLayerId( "signal" );
|
||||||
|
|
||||||
|
wxPoint arc_centre = graphic->m_Start0;
|
||||||
|
double radius = graphic->GetRadius()+ graphic->GetWidth()/2;
|
||||||
|
double arcStartDeg = graphic->GetArcAngleStart() / 10.0;
|
||||||
|
double arcAngleDeg = graphic->GetAngle() / 10.0;
|
||||||
|
|
||||||
|
// For some obscure reason, FreeRouter does not show the same polygonal
|
||||||
|
// shape for polygons CW and CCW. So used only the order of corners
|
||||||
|
// giving the best look.
|
||||||
|
if( arcAngleDeg < 0 )
|
||||||
|
{
|
||||||
|
arcStartDeg = graphic->GetArcAngleEnd() / 10.0;
|
||||||
|
arcAngleDeg = - arcAngleDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAPE_LINE_CHAIN polyline;
|
||||||
|
ConvertArcToPolyline( polyline, VECTOR2I( arc_centre ), radius,
|
||||||
|
arcStartDeg, arcAngleDeg, ARC_HIGH_DEF, ERROR_INSIDE );
|
||||||
|
|
||||||
|
SHAPE_POLY_SET polyBuffer;
|
||||||
|
polyBuffer.AddOutline( polyline );
|
||||||
|
|
||||||
|
radius -= graphic->GetWidth();
|
||||||
|
|
||||||
|
if( radius > 0 )
|
||||||
|
{
|
||||||
|
polyline.Clear();
|
||||||
|
ConvertArcToPolyline( polyline, VECTOR2I( arc_centre ), radius,
|
||||||
|
arcStartDeg, arcAngleDeg, ARC_HIGH_DEF, ERROR_INSIDE );
|
||||||
|
|
||||||
|
// Add points in reverse order, to create a closed polygon
|
||||||
|
for( int ii = polyline.PointCount()-1; ii >= 0; --ii )
|
||||||
|
polyBuffer.Append( polyline.CPoint( ii ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the polygon is closed
|
||||||
|
polyBuffer.Append( polyBuffer.Outline(0).CPoint( 0 ) );
|
||||||
|
|
||||||
|
wxPoint move = graphic->GetCenter() - arc_centre;
|
||||||
|
|
||||||
|
TransformCircleToPolygon( polyBuffer, graphic->GetArcStart() - move,
|
||||||
|
graphic->GetWidth()/2,
|
||||||
|
ARC_HIGH_DEF, ERROR_INSIDE );
|
||||||
|
|
||||||
|
TransformCircleToPolygon( polyBuffer, graphic->GetArcEnd() - move,
|
||||||
|
graphic->GetWidth()/2,
|
||||||
|
ARC_HIGH_DEF, ERROR_INSIDE );
|
||||||
|
|
||||||
|
polyBuffer.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
|
SHAPE_LINE_CHAIN& poly = polyBuffer.Outline( 0 );
|
||||||
|
|
||||||
|
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||||
|
{
|
||||||
|
wxPoint corner( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
|
||||||
|
path->AppendPoint( mapPt( corner ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1571,7 +1651,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
||||||
{
|
{
|
||||||
// export all of them for now, later we'll decide what controls we need
|
// export all of them for now, later we'll decide what controls we need
|
||||||
// on this.
|
// on this.
|
||||||
static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, EOT };
|
static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, PCB_ARC_T, EOT };
|
||||||
|
|
||||||
items.Collect( aBoard, scanTRACKs );
|
items.Collect( aBoard, scanTRACKs );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue