pcbnew: Add arc approximation setting to board

This places the arc approximation setting in the kicad_pcb file and uses
it for all parts of the board rendering where arcs are converted to
segments.  This allows the user to customize their speed vs. accuracy
tradeoff.  The default setting of maximum error of 0.005mm is acceptable
for small boards on moderate systems.
This commit is contained in:
Seth Hillbrand 2019-05-22 07:47:38 -07:00
parent 0a668ee550
commit 6bcf1839b7
23 changed files with 460 additions and 753 deletions

View File

@ -111,6 +111,7 @@ layers
left left
links links
locked locked
max_error
micro micro
min_thickness min_thickness
mirror mirror

View File

@ -745,7 +745,6 @@ void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize
EDA_DRAW_MODE_T aTraceMode, void* aData ) EDA_DRAW_MODE_T aTraceMode, void* aData )
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64;
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient, TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
aCornerRadius, 0.0, 0, GetPlotterArcHighDef() ); aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );

View File

@ -70,6 +70,9 @@
#define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based #define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based
// on edge cut line thicknesses) should be used. // on edge cut line thicknesses) should be used.
#define MINIMUM_ERROR_SIZE_MM 0.001
#define MAXIMUM_ERROR_SIZE_MM 0.1
/** /**
* Struct VIA_DIMENSION * Struct VIA_DIMENSION
* is a small helper container to handle a stock of specific vias each with * is a small helper container to handle a stock of specific vias each with
@ -195,6 +198,9 @@ public:
int m_MicroViasMinDrill; ///< micro vias (not vias) min drill diameter int m_MicroViasMinDrill; ///< micro vias (not vias) min drill diameter
int m_CopperEdgeClearance; int m_CopperEdgeClearance;
// Maximum error allowed when approximating circles and arcs to segments
int m_MaxError;
// Global mask margins: // Global mask margins:
int m_SolderMaskMargin; ///< Solder mask margin int m_SolderMaskMargin; ///< Solder mask margin
int m_SolderMaskMinWidth; ///< Solder mask min width int m_SolderMaskMinWidth; ///< Solder mask min width

View File

@ -496,6 +496,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
m_MicroViasMinDrill = Millimeter2iu( DEFAULT_MICROVIASMINDRILL ); m_MicroViasMinDrill = Millimeter2iu( DEFAULT_MICROVIASMINDRILL );
m_CopperEdgeClearance = Millimeter2iu( DEFAULT_COPPEREDGECLEARANCE ); m_CopperEdgeClearance = Millimeter2iu( DEFAULT_COPPEREDGECLEARANCE );
m_MaxError = ARC_HIGH_DEF;
// Global mask margins: // Global mask margins:
m_SolderMaskMargin = Millimeter2iu( DEFAULT_SOLDERMASK_CLEARANCE ); m_SolderMaskMargin = Millimeter2iu( DEFAULT_SOLDERMASK_CLEARANCE );
m_SolderMaskMinWidth = Millimeter2iu( DEFAULT_SOLDERMASK_MIN_WIDTH ); m_SolderMaskMinWidth = Millimeter2iu( DEFAULT_SOLDERMASK_MIN_WIDTH );

View File

@ -327,6 +327,11 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
// add filled areas polygons // add filled areas polygons
aCornerBuffer.Append( m_FilledPolysList ); aCornerBuffer.Append( m_FilledPolysList );
auto board = GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
// add filled areas outlines, which are drawn with thick lines // add filled areas outlines, which are drawn with thick lines
for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ ) for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
@ -339,7 +344,7 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
const VECTOR2I& b = path.CPoint( j + 1 ); const VECTOR2I& b = path.CPoint( j + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ), ARC_HIGH_DEF, GetMinThickness() ); wxPoint( b.x, b.y ), maxError, GetMinThickness() );
} }
} }
} }

View File

@ -2472,8 +2472,9 @@ extern bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines,
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, wxString* aErrorText, wxPoint* aErrorLocation ) bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines, wxString* aErrorText, wxPoint* aErrorLocation )
{ {
bool success = BuildBoardPolygonOutlines( this, aOutlines, aErrorText, bool success = BuildBoardPolygonOutlines( this, aOutlines, aErrorText,
ARC_HIGH_DEF, aErrorLocation ); GetDesignSettings().m_MaxError, aErrorLocation );
// Make polygon strictly simple to avoid issues (especially in 3D viewer) // Make polygon strictly simple to avoid issues (especially in 3D viewer)
aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

View File

@ -938,12 +938,17 @@ bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const
// Check for hit in polygon // Check for hit in polygon
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT; bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
auto board = GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
TransformRoundChamferedRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient, TransformRoundChamferedRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,
GetRoundRectCornerRadius(), GetRoundRectCornerRadius(),
doChamfer ? GetChamferRectRatio() : 0.0, doChamfer ? GetChamferRectRatio() : 0.0,
doChamfer ? GetChamferPositions() : 0, doChamfer ? GetChamferPositions() : 0,
ARC_HIGH_DEF ); maxError );
const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 ); const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 );
return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta ); return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta );

View File

@ -1317,9 +1317,16 @@ bool ZONE_CONTAINER::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly ) const
break; break;
case ZONE_SETTINGS::SMOOTHING_FILLET: case ZONE_SETTINGS::SMOOTHING_FILLET:
aSmoothedPoly = m_Poly->Fillet( m_cornerRadius, ARC_HIGH_DEF ); {
break; auto board = GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
aSmoothedPoly = m_Poly->Fillet( m_cornerRadius, maxError );
break;
}
default: default:
// Acute angles between adjacent edges can create issues in calculations, // Acute angles between adjacent edges can create issues in calculations,
// in inflate/deflate outlines transforms, especially when the angle is very small. // in inflate/deflate outlines transforms, especially when the angle is very small.
@ -1362,7 +1369,13 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
// holes are linked to the main outline, so only one polygon is created. // holes are linked to the main outline, so only one polygon is created.
if( clearance ) if( clearance )
{ {
int segCount = std::max( GetArcToSegmentCount( clearance, ARC_HIGH_DEF, 360.0 ), 3 ); auto board = GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
int segCount = std::max( GetArcToSegmentCount( clearance, maxError, 360.0 ), 3 );
polybuffer.Inflate( clearance, segCount ); polybuffer.Inflate( clearance, segCount );
} }
polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST ); polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );

View File

@ -38,7 +38,8 @@ PANEL_SETUP_FEATURE_CONSTRAINTS::PANEL_SETUP_FEATURE_CONSTRAINTS( PAGED_DIALOG*
m_uviaMinSize( aFrame, m_uviaMinSizeLabel, m_uviaMinSizeCtrl, m_uviaMinSizeUnits, true ), m_uviaMinSize( aFrame, m_uviaMinSizeLabel, m_uviaMinSizeCtrl, m_uviaMinSizeUnits, true ),
m_uviaMinDrill( aFrame, m_uviaMinDrillLabel, m_uviaMinDrillCtrl, m_uviaMinDrillUnits, true ), m_uviaMinDrill( aFrame, m_uviaMinDrillLabel, m_uviaMinDrillCtrl, m_uviaMinDrillUnits, true ),
m_holeToHoleMin( aFrame, m_HoleToHoleTitle, m_SetHoleToHoleCtrl, m_HoleToHoleUnits, true ), m_holeToHoleMin( aFrame, m_HoleToHoleTitle, m_SetHoleToHoleCtrl, m_HoleToHoleUnits, true ),
m_edgeClearance( aFrame, m_EdgeClearanceLabel, m_EdgeClearanceCtrl, m_EdgeClearanceUnits, true ) m_edgeClearance( aFrame, m_EdgeClearanceLabel, m_EdgeClearanceCtrl, m_EdgeClearanceUnits, true ),
m_maxError( aFrame, m_maxErrorTitle, m_maxErrorCtrl, m_maxErrorUnits, true )
{ {
m_Frame = aFrame; m_Frame = aFrame;
m_BrdSettings = &m_Frame->GetBoard()->GetDesignSettings(); m_BrdSettings = &m_Frame->GetBoard()->GetDesignSettings();
@ -64,6 +65,8 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataToWindow()
m_OptRequireCourtyards->SetValue( m_BrdSettings->m_RequireCourtyards ); m_OptRequireCourtyards->SetValue( m_BrdSettings->m_RequireCourtyards );
m_OptOverlappingCourtyards->SetValue( m_BrdSettings->m_ProhibitOverlappingCourtyards ); m_OptOverlappingCourtyards->SetValue( m_BrdSettings->m_ProhibitOverlappingCourtyards );
m_maxError.SetValue( m_BrdSettings->m_MaxError );
return true; return true;
} }
@ -91,6 +94,9 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataFromWindow()
m_BrdSettings->SetRequireCourtyardDefinitions( m_OptRequireCourtyards->GetValue() ); m_BrdSettings->SetRequireCourtyardDefinitions( m_OptRequireCourtyards->GetValue() );
m_BrdSettings->SetProhibitOverlappingCourtyards( m_OptOverlappingCourtyards->GetValue() ); m_BrdSettings->SetProhibitOverlappingCourtyards( m_OptOverlappingCourtyards->GetValue() );
m_BrdSettings->m_MaxError = Clamp<int>( IU_PER_MM * MINIMUM_ERROR_SIZE_MM,
m_maxError.GetValue(), IU_PER_MM * MAXIMUM_ERROR_SIZE_MM );
return true; return true;
} }

View File

@ -48,6 +48,7 @@ public:
UNIT_BINDER m_uviaMinDrill; UNIT_BINDER m_uviaMinDrill;
UNIT_BINDER m_holeToHoleMin; UNIT_BINDER m_holeToHoleMin;
UNIT_BINDER m_edgeClearance; UNIT_BINDER m_edgeClearance;
UNIT_BINDER m_maxError;
public: public:
PANEL_SETUP_FEATURE_CONSTRAINTS( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFrame ); PANEL_SETUP_FEATURE_CONSTRAINTS( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFrame );

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017) // C++ code generated with wxFormBuilder (version Apr 23 2019)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -9,7 +9,7 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name )
{ {
wxBoxSizer* bMainSizer; wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxHORIZONTAL ); bMainSizer = new wxBoxSizer( wxHORIZONTAL );
@ -33,6 +33,29 @@ PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWi
sbFeatureRules->Add( m_OptOverlappingCourtyards, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); sbFeatureRules->Add( m_OptOverlappingCourtyards, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
sbFeatureRules->Add( 0, 0, 0, wxBOTTOM|wxEXPAND|wxTOP, 5 );
wxFlexGridSizer* fgSizer2;
fgSizer2 = new wxFlexGridSizer( 0, 3, 3, 0 );
fgSizer2->AddGrowableCol( 1 );
fgSizer2->SetFlexibleDirection( wxBOTH );
fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_maxErrorTitle = new wxStaticText( this, wxID_ANY, _("Maximum Error Dist:"), wxDefaultPosition, wxDefaultSize, 0 );
m_maxErrorTitle->Wrap( -1 );
fgSizer2->Add( m_maxErrorTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM, 5 );
m_maxErrorCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer2->Add( m_maxErrorCtrl, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND|wxLEFT|wxRIGHT, 5 );
m_maxErrorUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_maxErrorUnits->Wrap( -1 );
fgSizer2->Add( m_maxErrorUnits, 0, wxALL, 5 );
sbFeatureRules->Add( fgSizer2, 1, wxEXPAND, 5 );
bMainSizer->Add( sbFeatureRules, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); bMainSizer->Add( sbFeatureRules, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,11 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017) // C++ code generated with wxFormBuilder (version Apr 23 2019)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#ifndef __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__ #pragma once
#define __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__
#include <wx/artprov.h> #include <wx/artprov.h>
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
@ -17,10 +16,10 @@
#include <wx/font.h> #include <wx/font.h>
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/valtext.h> #include <wx/valtext.h>
#include <wx/sizer.h>
#include <wx/panel.h> #include <wx/panel.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -37,6 +36,9 @@ class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel
wxCheckBox* m_OptAllowMicroVias; wxCheckBox* m_OptAllowMicroVias;
wxCheckBox* m_OptRequireCourtyards; wxCheckBox* m_OptRequireCourtyards;
wxCheckBox* m_OptOverlappingCourtyards; wxCheckBox* m_OptOverlappingCourtyards;
wxStaticText* m_maxErrorTitle;
wxTextCtrl* m_maxErrorCtrl;
wxStaticText* m_maxErrorUnits;
wxStaticText* m_TrackMinWidthTitle; wxStaticText* m_TrackMinWidthTitle;
wxTextCtrl* m_TrackMinWidthCtrl; wxTextCtrl* m_TrackMinWidthCtrl;
wxStaticText* m_TrackMinWidthUnits; wxStaticText* m_TrackMinWidthUnits;
@ -61,9 +63,8 @@ class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel
public: public:
PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); PANEL_SETUP_FEATURE_CONSTRAINTS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
~PANEL_SETUP_FEATURE_CONSTRAINTS_BASE(); ~PANEL_SETUP_FEATURE_CONSTRAINTS_BASE();
}; };
#endif //__PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__

View File

@ -982,6 +982,12 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
} }
else if( aRefPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT ) else if( aRefPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{ {
auto board = aRefPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
// The reference pad can be rotated. calculate the rotated // The reference pad can be rotated. calculate the rotated
// coordinates ( note, the ref pad position is the origin of // coordinates ( note, the ref pad position is the origin of
// coordinates for this drc test) // coordinates for this drc test)
@ -989,7 +995,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
TransformRoundChamferedRectToPolygon( polysetref, wxPoint( 0, 0 ), aRefPad->GetSize(), TransformRoundChamferedRectToPolygon( polysetref, wxPoint( 0, 0 ), aRefPad->GetSize(),
aRefPad->GetOrientation(), aRefPad->GetOrientation(),
padRadius, aRefPad->GetChamferRectRatio(), padRadius, aRefPad->GetChamferRectRatio(),
aRefPad->GetChamferPositions(), ARC_HIGH_DEF ); aRefPad->GetChamferPositions(), maxError );
} }
else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM ) else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM )
{ {
@ -1024,6 +1030,12 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
} }
else if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT ) else if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{ {
auto board = aRefPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
// The reference pad can be rotated. calculate the rotated // The reference pad can be rotated. calculate the rotated
// coordinates ( note, the ref pad position is the origin of // coordinates ( note, the ref pad position is the origin of
// coordinates for this drc test) // coordinates for this drc test)
@ -1031,7 +1043,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
TransformRoundChamferedRectToPolygon( polysetcompare, relativePadPos, aPad->GetSize(), TransformRoundChamferedRectToPolygon( polysetcompare, relativePadPos, aPad->GetSize(),
aPad->GetOrientation(), aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(), padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF ); aPad->GetChamferPositions(), maxError );
} }
else if( aPad->GetShape() == PAD_SHAPE_CUSTOM ) else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
{ {
@ -1413,6 +1425,12 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
case PAD_SHAPE_CHAMFERED_RECT: case PAD_SHAPE_CHAMFERED_RECT:
{ {
auto board = aPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET polyset; SHAPE_POLY_SET polyset;
// The pad can be rotated. calculate the coordinates // The pad can be rotated. calculate the coordinates
// relatives to the segment being tested // relatives to the segment being tested
@ -1422,7 +1440,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
TransformRoundChamferedRectToPolygon( polyset, m_padToTestPos, aPad->GetSize(), TransformRoundChamferedRectToPolygon( polyset, m_padToTestPos, aPad->GetSize(),
aPad->GetOrientation(), aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(), padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF ); aPad->GetChamferPositions(), maxError );
// Rotate also coordinates by m_segmAngle, because the segment orient // Rotate also coordinates by m_segmAngle, because the segment orient
// is m_segmAngle. // is m_segmAngle.
// we are using a horizontal segment for test, because we know here // we are using a horizontal segment for test, because we know here

View File

@ -1206,9 +1206,6 @@ ZONE_CONTAINER* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
if( p.spacing ) if( p.spacing )
zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, zone->GetDefaultHatchPitch(), true ); zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, zone->GetDefaultHatchPitch(), true );
// clearances, etc.
zone->SetArcSegmentCount( ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
// We divide the thickness by half because we are tracing _inside_ the zone outline // We divide the thickness by half because we are tracing _inside_ the zone outline
// This means the radius of curvature will be twice the size for an equivalent EAGLE zone // This means the radius of curvature will be twice the size for an equivalent EAGLE zone
zone->SetMinThickness( zone->SetMinThickness(

View File

@ -526,6 +526,9 @@ void PCB_IO::formatSetup( BOARD* aBoard, int aNestLevel ) const
m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n", m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n",
FormatInternalUnits( dsnSettings.m_MicroViasMinDrill ).c_str() ); FormatInternalUnits( dsnSettings.m_MicroViasMinDrill ).c_str() );
m_out->Print( aNestLevel+1, "(max_error %s)\n",
FormatInternalUnits( dsnSettings.m_MaxError ).c_str() );
// 6.0 TODO: are we going to update the tokens we save these under? // 6.0 TODO: are we going to update the tokens we save these under?
// 6.0 TODO: need to save the LAYER_CLASS_OTHERS stuff // 6.0 TODO: need to save the LAYER_CLASS_OTHERS stuff
// 6.0 TODO: need to save the TextItalic and TextUpright settings // 6.0 TODO: need to save the TextItalic and TextUpright settings

View File

@ -32,14 +32,15 @@
#include <pcbnew.h> #include <pcbnew.h>
#include <class_pad.h> #include <bezier_curves.h>
#include <class_board.h>
#include <class_drawsegment.h> #include <class_drawsegment.h>
#include <class_edge_mod.h> #include <class_edge_mod.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h> #include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_rect.h>
#include <geometry/convex_hull.h> #include <geometry/convex_hull.h>
#include <geometry/geometry_utils.h> #include <geometry/geometry_utils.h>
#include <bezier_curves.h> #include <geometry/shape_rect.h>
void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget ) void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget )
@ -305,6 +306,12 @@ bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError )
*/ */
bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
{ {
auto board = GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
// if aMergedPolygon == NULL, use m_customShapeAsPolygon as target // if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
if( !aMergedPolygon ) if( !aMergedPolygon )
@ -318,7 +325,7 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
{ {
default: default:
case PAD_SHAPE_CIRCLE: case PAD_SHAPE_CIRCLE:
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0, 0 ), GetSize().x / 2, ARC_HIGH_DEF ); TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0, 0 ), GetSize().x / 2, maxError );
break; break;
case PAD_SHAPE_RECT: case PAD_SHAPE_RECT:
@ -330,7 +337,7 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
} }
} }
if( !buildCustomPadPolygon( aMergedPolygon, ARC_HIGH_DEF ) ) if( !buildCustomPadPolygon( aMergedPolygon, maxError ) )
return false; return false;
m_boundingRadius = -1; // The current bouding radius is no more valid. m_boundingRadius = -1; // The current bouding radius is no more valid.

View File

@ -825,10 +825,15 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
wxSize prsize( size.x * 2, size.y * 2 ); // size is the half pad area size) wxSize prsize( size.x * 2, size.y * 2 ); // size is the half pad area size)
const int corner_radius = aPad->GetRoundRectCornerRadius( prsize ); const int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
bool doChamfer = shape == PAD_SHAPE_CHAMFERED_RECT; bool doChamfer = shape == PAD_SHAPE_CHAMFERED_RECT;
auto board = aPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), prsize, TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), prsize,
0.0, corner_radius, aPad->GetChamferRectRatio(), 0.0, corner_radius, aPad->GetChamferRectRatio(),
doChamfer ? aPad->GetChamferPositions() : 0, ARC_HIGH_DEF ); doChamfer ? aPad->GetChamferPositions() : 0, maxError );
m_gal->DrawPolygon( polySet ); m_gal->DrawPolygon( polySet );
break; break;
} }
@ -843,12 +848,18 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
// for solder paste). // for solder paste).
if( custom_margin ) if( custom_margin )
{ {
auto board = aPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
outline.Append( aPad->GetCustomShapeAsPolygon() ); outline.Append( aPad->GetCustomShapeAsPolygon() );
// outline polygon can have holes linked to the main outline. // outline polygon can have holes linked to the main outline.
// So use InflateWithLinkedHoles(), not Inflate() that can create // So use InflateWithLinkedHoles(), not Inflate() that can create
// bad shapes if custom_margin is < 0 // bad shapes if custom_margin is < 0
int numSegs = std::max( GetArcToSegmentCount( custom_margin, ARC_HIGH_DEF, 360.0 ), 6 ); int numSegs = std::max( GetArcToSegmentCount( custom_margin, maxError, 360.0 ), 6 );
outline.InflateWithLinkedHoles( custom_margin, numSegs, SHAPE_POLY_SET::PM_FAST ); outline.InflateWithLinkedHoles( custom_margin, numSegs, SHAPE_POLY_SET::PM_FAST );
m_gal->DrawPolygon( outline ); m_gal->DrawPolygon( outline );
} }

View File

@ -1380,6 +1380,11 @@ void PCB_PARSER::parseSetup()
NeedRIGHT(); NeedRIGHT();
break; break;
case T_max_error:
designSettings.m_MaxError = parseBoardUnits( T_max_error );
NeedRIGHT();
break;
case T_pcbplotparams: case T_pcbplotparams:
{ {
PCB_PLOT_PARAMS plotParams; PCB_PLOT_PARAMS plotParams;

View File

@ -454,7 +454,9 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
// shape polygon can have holes linked to the main outline. // shape polygon can have holes linked to the main outline.
// So use InflateWithLinkedHoles(), not Inflate() that can create // So use InflateWithLinkedHoles(), not Inflate() that can create
// bad shapes if margin.x is < 0 // bad shapes if margin.x is < 0
int numSegs = std::max( GetArcToSegmentCount( margin.x, ARC_HIGH_DEF, 360.0 ), 6 ); int numSegs = std::max(
GetArcToSegmentCount( margin.x, aBoard->GetDesignSettings().m_MaxError,
360.0 ), 6 );
shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST ); shape.InflateWithLinkedHoles( margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
dummy.DeletePrimitivesList(); dummy.DeletePrimitivesList();
dummy.AddPrimitive( shape, 0 ); dummy.AddPrimitive( shape, 0 );
@ -870,7 +872,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
ZONE_CONTAINER zone( aBoard ); ZONE_CONTAINER zone( aBoard );
zone.SetMinThickness( 0 ); // trace polygons only zone.SetMinThickness( 0 ); // trace polygons only
zone.SetLayer( layer ); zone.SetLayer( layer );
int numSegs = std::max( GetArcToSegmentCount( inflate, ARC_HIGH_DEF, 360.0 ), 6 ); int numSegs = std::max(
GetArcToSegmentCount( inflate, aBoard->GetDesignSettings().m_MaxError, 360.0 ), 6 );
areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST ); areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
areas.Inflate( -inflate, numSegs ); areas.Inflate( -inflate, numSegs );

View File

@ -187,7 +187,7 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() ); const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() );
TransformRoundChamferedRectToPolygon( polygons, shape_pos, aPad->GetSize(), TransformRoundChamferedRectToPolygon( polygons, shape_pos, aPad->GetSize(),
aPad->GetOrientation(), corner_radius, aPad->GetChamferRectRatio(), aPad->GetOrientation(), corner_radius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF ); aPad->GetChamferPositions(), m_board->GetDesignSettings().m_MaxError );
if( polygons.OutlineCount() == 0 ) if( polygons.OutlineCount() == 0 )
break; break;

View File

@ -517,7 +517,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
0, rradius, 0, rradius,
aPad->GetChamferRectRatio(), aPad->GetChamferRectRatio(),
doChamfer ? aPad->GetChamferPositions() : 0, doChamfer ? aPad->GetChamferPositions() : 0,
ARC_HIGH_DEF ); aBoard->GetDesignSettings().m_MaxError );
SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 ); SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 );
for( int ndx=0; ndx < reportedLayers; ++ndx ) for( int ndx=0; ndx < reportedLayers; ++ndx )

View File

@ -426,7 +426,8 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
// the shape itself // the shape itself
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() ); SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
int numSegs = std::max( int numSegs = std::max(
GetArcToSegmentCount( clearance, ARC_HIGH_DEF, 360.0 ), 6 ); GetArcToSegmentCount( clearance,
m_board->GetDesignSettings().m_MaxError, 360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
outline.Inflate( KiROUND( clearance * correction ), numSegs ); outline.Inflate( KiROUND( clearance * correction ), numSegs );
pad->CustomShapeAsPolygonToBoardPosition( pad->CustomShapeAsPolygonToBoardPosition(
@ -474,8 +475,9 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
{ {
// the pad shape in zone can be its convex hull or // the pad shape in zone can be its convex hull or
// the shape itself // the shape itself
int numSegs = int numSegs = std::max(
std::max( GetArcToSegmentCount( gap, ARC_HIGH_DEF, 360.0 ), 6 ); GetArcToSegmentCount( gap, m_board->GetDesignSettings().m_MaxError,
360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() ); SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
outline.Inflate( KiROUND( gap * correction ), numSegs ); outline.Inflate( KiROUND( gap * correction ), numSegs );
@ -547,7 +549,8 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
{ {
case PCB_LINE_T: case PCB_LINE_T:
static_cast<DRAWSEGMENT*>( aItem )->TransformShapeWithClearanceToPolygon( static_cast<DRAWSEGMENT*>( aItem )->TransformShapeWithClearanceToPolygon(
aFeatures, zclearance, ARC_HIGH_DEF, ignoreLineWidth ); aFeatures, zclearance, m_board->GetDesignSettings().m_MaxError,
ignoreLineWidth );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
@ -557,7 +560,8 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
case PCB_MODULE_EDGE_T: case PCB_MODULE_EDGE_T:
static_cast<EDGE_MODULE*>( aItem )->TransformShapeWithClearanceToPolygon( static_cast<EDGE_MODULE*>( aItem )->TransformShapeWithClearanceToPolygon(
aFeatures, zclearance, ARC_HIGH_DEF, ignoreLineWidth ); aFeatures, zclearance, m_board->GetDesignSettings().m_MaxError,
ignoreLineWidth );
break; break;
case PCB_MODULE_TEXT_T: case PCB_MODULE_TEXT_T:
@ -667,7 +671,7 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
{ {
CreateThermalReliefPadPolygon( aFeatures, *pad, thermalGap, CreateThermalReliefPadPolygon( aFeatures, *pad, thermalGap,
aZone->GetThermalReliefCopperBridge( pad ), aZone->GetMinThickness(), aZone->GetThermalReliefCopperBridge( pad ), aZone->GetMinThickness(),
ARC_HIGH_DEF, s_thermalRot ); m_board->GetDesignSettings().m_MaxError, s_thermalRot );
} }
} }
} }
@ -717,8 +721,9 @@ void ZONE_FILLER::computeRawFilledAreas( const ZONE_CONTAINER* aZone,
SHAPE_POLY_SET solidAreas = aSmoothedOutline; SHAPE_POLY_SET solidAreas = aSmoothedOutline;
int numSegs = int numSegs = std::max(
std::max( GetArcToSegmentCount( outline_half_thickness, ARC_HIGH_DEF, 360.0 ), 6 ); GetArcToSegmentCount( outline_half_thickness, m_board->GetDesignSettings().m_MaxError,
360.0 ), 6 );
double correction = GetCircletoPolyCorrectionFactor( numSegs ); double correction = GetCircletoPolyCorrectionFactor( numSegs );
solidAreas.Inflate( -outline_half_thickness, numSegs ); solidAreas.Inflate( -outline_half_thickness, numSegs );
@ -845,7 +850,8 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol
else else
{ {
int numSegs = std::max( int numSegs = std::max(
GetArcToSegmentCount( aZone->GetMinThickness() / 2, ARC_HIGH_DEF, 360.0 ), 6 ); GetArcToSegmentCount( aZone->GetMinThickness() / 2,
m_board->GetDesignSettings().m_MaxError, 360.0 ), 6 );
aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, numSegs ); aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, numSegs );
// Remove the non filled areas due to the hatch pattern // Remove the non filled areas due to the hatch pattern