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.
|
||||
*
|
||||
|
|
|
@ -393,27 +393,27 @@ void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer, const
|
|||
}
|
||||
|
||||
|
||||
static int convertArcToPolyline( SHAPE_LINE_CHAIN& aPolyline, VECTOR2I aCenter, int aRadius,
|
||||
double aStartAngle, double aArcAngle, double aAccuracy,
|
||||
int ConvertArcToPolyline( SHAPE_LINE_CHAIN& aPolyline, VECTOR2I aCenter, int aRadius,
|
||||
double aStartAngleDeg, double aArcAngleDeg, double aAccuracy,
|
||||
ERROR_LOC aErrorLoc )
|
||||
{
|
||||
double endAngle = aStartAngle + aArcAngle;
|
||||
double endAngle = aStartAngleDeg + aArcAngleDeg;
|
||||
int n = 2;
|
||||
|
||||
if( aRadius >= aAccuracy )
|
||||
n = GetArcToSegmentCount( aRadius, aAccuracy, aArcAngle )+1; // n >= 3
|
||||
n = GetArcToSegmentCount( aRadius, aAccuracy, aArcAngleDeg )+1; // n >= 3
|
||||
|
||||
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 );
|
||||
aRadius += actual_delta_radius;
|
||||
}
|
||||
|
||||
for( int i = 0; i <= n ; i++ )
|
||||
{
|
||||
double rot = aStartAngle;
|
||||
rot += ( aArcAngle * i ) / n;
|
||||
double rot = aStartAngleDeg;
|
||||
rot += ( aArcAngleDeg * i ) / n;
|
||||
|
||||
double x = aCenter.x + aRadius * cos( 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();
|
||||
|
||||
convertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
|
||||
ConvertArcToPolyline( polyshape.Outline(2), center, arc_outer_radius,
|
||||
arc_angle_start_deg, arc_angle, aError, errorLocOuter );
|
||||
|
||||
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 );
|
||||
else
|
||||
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.
|
||||
// for now, support by using line segments.
|
||||
|
||||
outline = new SHAPE( image, T_outline );
|
||||
|
||||
image->Append( outline );
|
||||
|
||||
path = new PATH( outline );
|
||||
|
||||
outline->SetShape( path );
|
||||
path->SetAperture( scale( graphic->GetWidth() ) );
|
||||
path->SetLayerId( "signal" );
|
||||
|
||||
// Do the math using KiCad units, that way we stay out of the
|
||||
// scientific notation range of floating point numbers in the
|
||||
// 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 = graphic->GetRadius();
|
||||
wxPoint circle_centre = graphic->m_Start0;
|
||||
|
||||
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
|
||||
int seg_per_circle = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
|
||||
|
||||
for( int ii = 0; ii < seg_per_circle; ++ii )
|
||||
for( int ii = 0; ii < polyline.PointCount(); ++ii )
|
||||
{
|
||||
double radians = 2*M_PI / seg_per_circle * ii;
|
||||
wxPoint point( KiROUND( radius * cos( radians ) ),
|
||||
KiROUND( radius * sin( radians ) ) );
|
||||
|
||||
point += graphic->m_Start0; // an offset
|
||||
|
||||
path->AppendPoint( mapPt( point ) );
|
||||
wxPoint corner( polyline.CPoint( ii ).x, polyline.CPoint( ii ).y );
|
||||
path->AppendPoint( mapPt( corner ) );
|
||||
}
|
||||
// The shape must be closed
|
||||
wxPoint point( radius , 0 );
|
||||
point += graphic->m_Start0;
|
||||
path->AppendPoint( mapPt( point ) );
|
||||
}
|
||||
break;
|
||||
|
||||
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:
|
||||
{
|
||||
// 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:
|
||||
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
|
||||
// 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 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue