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
links
locked
max_error
micro
min_thickness
mirror

View File

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

View File

@ -70,6 +70,9 @@
#define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based
// 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
* 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_CopperEdgeClearance;
// Maximum error allowed when approximating circles and arcs to segments
int m_MaxError;
// Global mask margins:
int m_SolderMaskMargin; ///< Solder mask margin
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_CopperEdgeClearance = Millimeter2iu( DEFAULT_COPPEREDGECLEARANCE );
m_MaxError = ARC_HIGH_DEF;
// Global mask margins:
m_SolderMaskMargin = Millimeter2iu( DEFAULT_SOLDERMASK_CLEARANCE );
m_SolderMaskMinWidth = Millimeter2iu( DEFAULT_SOLDERMASK_MIN_WIDTH );

View File

@ -327,6 +327,11 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
// add filled areas polygons
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
for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
@ -339,7 +344,7 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
const VECTOR2I& b = path.CPoint( j + 1 );
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 success = BuildBoardPolygonOutlines( this, aOutlines, aErrorText,
ARC_HIGH_DEF, aErrorLocation );
GetDesignSettings().m_MaxError, aErrorLocation );
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
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
SHAPE_POLY_SET outline;
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,
GetRoundRectCornerRadius(),
doChamfer ? GetChamferRectRatio() : 0.0,
doChamfer ? GetChamferPositions() : 0,
ARC_HIGH_DEF );
maxError );
const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 );
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;
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:
// Acute angles between adjacent edges can create issues in calculations,
// 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.
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.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_uviaMinDrill( aFrame, m_uviaMinDrillLabel, m_uviaMinDrillCtrl, m_uviaMinDrillUnits, 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_BrdSettings = &m_Frame->GetBoard()->GetDesignSettings();
@ -64,6 +65,8 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataToWindow()
m_OptRequireCourtyards->SetValue( m_BrdSettings->m_RequireCourtyards );
m_OptOverlappingCourtyards->SetValue( m_BrdSettings->m_ProhibitOverlappingCourtyards );
m_maxError.SetValue( m_BrdSettings->m_MaxError );
return true;
}
@ -91,6 +94,9 @@ bool PANEL_SETUP_FEATURE_CONSTRAINTS::TransferDataFromWindow()
m_BrdSettings->SetRequireCourtyardDefinitions( m_OptRequireCourtyards->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;
}
@ -103,4 +109,4 @@ void PANEL_SETUP_FEATURE_CONSTRAINTS::ImportSettingsFrom( BOARD* aBoard )
TransferDataToWindow();
m_BrdSettings = savedSettings;
}
}

View File

@ -48,6 +48,7 @@ public:
UNIT_BINDER m_uviaMinDrill;
UNIT_BINDER m_holeToHoleMin;
UNIT_BINDER m_edgeClearance;
UNIT_BINDER m_maxError;
public:
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/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -9,166 +9,189 @@
///////////////////////////////////////////////////////////////////////////
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;
bMainSizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* sbFeatureRules;
sbFeatureRules = new wxBoxSizer( wxVERTICAL );
m_OptAllowBlindBuriedVias = new wxCheckBox( this, wxID_ANY, _("Allow blind/buried vias"), wxDefaultPosition, wxDefaultSize, 0 );
sbFeatureRules->Add( m_OptAllowBlindBuriedVias, 0, wxRIGHT|wxTOP, 5 );
m_OptAllowMicroVias = new wxCheckBox( this, wxID_ANY, _("Allow micro vias (uVias)"), wxDefaultPosition, wxDefaultSize, 0 );
sbFeatureRules->Add( m_OptAllowMicroVias, 0, wxRIGHT|wxTOP, 5 );
sbFeatureRules->Add( 0, 0, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
m_OptRequireCourtyards = new wxCheckBox( this, wxID_ANY, _("Require courtyard definitions in footprints"), wxDefaultPosition, wxDefaultSize, 0 );
sbFeatureRules->Add( m_OptRequireCourtyards, 0, wxTOP|wxRIGHT, 5 );
m_OptOverlappingCourtyards = new wxCheckBox( this, wxID_ANY, _("Prohibit overlapping courtyards"), wxDefaultPosition, wxDefaultSize, 0 );
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( 0, 0, 0, wxEXPAND|wxRIGHT|wxLEFT, 25 );
wxBoxSizer* sbFeatureConstraints;
sbFeatureConstraints = new wxBoxSizer( wxVERTICAL );
wxFlexGridSizer* fgFeatureConstraints;
fgFeatureConstraints = new wxFlexGridSizer( 0, 3, 3, 0 );
fgFeatureConstraints->AddGrowableCol( 1 );
fgFeatureConstraints->SetFlexibleDirection( wxBOTH );
fgFeatureConstraints->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_TrackMinWidthTitle = new wxStaticText( this, wxID_ANY, _("Minimum track width:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_TrackMinWidthTitle->Wrap( -1 );
fgFeatureConstraints->Add( m_TrackMinWidthTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM, 5 );
m_TrackMinWidthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_TrackMinWidthCtrl->SetMinSize( wxSize( 120,-1 ) );
fgFeatureConstraints->Add( m_TrackMinWidthCtrl, 0, wxALIGN_LEFT|wxALIGN_TOP|wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_TrackMinWidthUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_TrackMinWidthUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_TrackMinWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxALL|wxEXPAND, 5 );
m_ViaMinTitle = new wxStaticText( this, wxID_ANY, _("Minimum via diameter:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_ViaMinTitle->Wrap( -1 );
fgFeatureConstraints->Add( m_ViaMinTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_SetViasMinSizeCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_SetViasMinSizeCtrl, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_ViaMinUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_ViaMinUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_ViaMinUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_ViaMinDrillTitle = new wxStaticText( this, wxID_ANY, _("Minimum via drill:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_ViaMinDrillTitle->Wrap( -1 );
fgFeatureConstraints->Add( m_ViaMinDrillTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_SetViasMinDrillCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_SetViasMinDrillCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_ViaMinDrillUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_ViaMinDrillUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_ViaMinDrillUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND|wxTOP, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND|wxTOP, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND|wxTOP, 5 );
m_uviaMinSizeLabel = new wxStaticText( this, wxID_ANY, _("Minimum uVia diameter:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_uviaMinSizeLabel->Wrap( -1 );
fgFeatureConstraints->Add( m_uviaMinSizeLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_uviaMinSizeCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_uviaMinSizeCtrl, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_uviaMinSizeUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_uviaMinSizeUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_uviaMinSizeUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_uviaMinDrillLabel = new wxStaticText( this, wxID_ANY, _("Minimum uVia drill:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_uviaMinDrillLabel->Wrap( -1 );
fgFeatureConstraints->Add( m_uviaMinDrillLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_uviaMinDrillCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_uviaMinDrillCtrl, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_uviaMinDrillUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
m_uviaMinDrillUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_uviaMinDrillUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
m_HoleToHoleTitle = new wxStaticText( this, wxID_ANY, _("Minimum hole to hole:"), wxDefaultPosition, wxDefaultSize, 0 );
m_HoleToHoleTitle->Wrap( -1 );
fgFeatureConstraints->Add( m_HoleToHoleTitle, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP, 5 );
m_SetHoleToHoleCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_SetHoleToHoleCtrl, 0, wxEXPAND|wxALL, 5 );
m_HoleToHoleUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_HoleToHoleUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_HoleToHoleUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
fgFeatureConstraints->Add( 0, 0, 1, wxEXPAND, 5 );
m_EdgeClearanceLabel = new wxStaticText( this, wxID_ANY, _("Copper edge clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_EdgeClearanceLabel->Wrap( -1 );
fgFeatureConstraints->Add( m_EdgeClearanceLabel, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
m_EdgeClearanceCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_EdgeClearanceCtrl, 0, wxALL|wxEXPAND, 5 );
m_EdgeClearanceUnits = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_EdgeClearanceUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_EdgeClearanceUnits, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
sbFeatureConstraints->Add( fgFeatureConstraints, 1, wxEXPAND|wxTOP|wxLEFT, 5 );
bMainSizer->Add( sbFeatureConstraints, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
this->SetSizer( bMainSizer );
this->Layout();
bMainSizer->Fit( this );

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/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__
#define __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
@ -17,10 +16,10 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include <wx/sizer.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
@ -28,15 +27,18 @@
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel
class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel
{
private:
protected:
wxCheckBox* m_OptAllowBlindBuriedVias;
wxCheckBox* m_OptAllowMicroVias;
wxCheckBox* m_OptRequireCourtyards;
wxCheckBox* m_OptOverlappingCourtyards;
wxStaticText* m_maxErrorTitle;
wxTextCtrl* m_maxErrorCtrl;
wxStaticText* m_maxErrorUnits;
wxStaticText* m_TrackMinWidthTitle;
wxTextCtrl* m_TrackMinWidthCtrl;
wxStaticText* m_TrackMinWidthUnits;
@ -58,12 +60,11 @@ class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel
wxStaticText* m_EdgeClearanceLabel;
wxTextCtrl* m_EdgeClearanceCtrl;
wxStaticText* m_EdgeClearanceUnits;
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();
};
#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 )
{
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
// coordinates ( note, the ref pad position is the origin of
// 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(),
aRefPad->GetOrientation(),
padRadius, aRefPad->GetChamferRectRatio(),
aRefPad->GetChamferPositions(), ARC_HIGH_DEF );
aRefPad->GetChamferPositions(), maxError );
}
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 )
{
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
// coordinates ( note, the ref pad position is the origin of
// coordinates for this drc test)
@ -1031,7 +1043,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
TransformRoundChamferedRectToPolygon( polysetcompare, relativePadPos, aPad->GetSize(),
aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF );
aPad->GetChamferPositions(), maxError );
}
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:
{
auto board = aPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET polyset;
// The pad can be rotated. calculate the coordinates
// 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(),
aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF );
aPad->GetChamferPositions(), maxError );
// Rotate also coordinates by m_segmAngle, because the segment orient
// is m_segmAngle.
// 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 )
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
// This means the radius of curvature will be twice the size for an equivalent EAGLE zone
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",
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: need to save the LAYER_CLASS_OTHERS stuff
// 6.0 TODO: need to save the TextItalic and TextUpright settings

View File

@ -32,14 +32,15 @@
#include <pcbnew.h>
#include <class_pad.h>
#include <bezier_curves.h>
#include <class_board.h>
#include <class_drawsegment.h>
#include <class_edge_mod.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_rect.h>
#include <geometry/convex_hull.h>
#include <geometry/geometry_utils.h>
#include <bezier_curves.h>
#include <geometry/shape_rect.h>
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 )
{
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 )
@ -318,7 +325,7 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon )
{
default:
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;
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;
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)
const int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
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,
0.0, corner_radius, aPad->GetChamferRectRatio(),
doChamfer ? aPad->GetChamferPositions() : 0, ARC_HIGH_DEF );
doChamfer ? aPad->GetChamferPositions() : 0, maxError );
m_gal->DrawPolygon( polySet );
break;
}
@ -843,12 +848,18 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
// for solder paste).
if( custom_margin )
{
auto board = aPad->GetBoard();
int maxError = ARC_HIGH_DEF;
if( board )
maxError = board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET outline;
outline.Append( aPad->GetCustomShapeAsPolygon() );
// outline polygon can have holes linked to the main outline.
// So use InflateWithLinkedHoles(), not Inflate() that can create
// 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 );
m_gal->DrawPolygon( outline );
}

View File

@ -1380,6 +1380,11 @@ void PCB_PARSER::parseSetup()
NeedRIGHT();
break;
case T_max_error:
designSettings.m_MaxError = parseBoardUnits( T_max_error );
NeedRIGHT();
break;
case T_pcbplotparams:
{
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.
// So use InflateWithLinkedHoles(), not Inflate() that can create
// 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 );
dummy.DeletePrimitivesList();
dummy.AddPrimitive( shape, 0 );
@ -869,8 +871,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
// is only a very small calculation time for these calculations)
ZONE_CONTAINER zone( aBoard );
zone.SetMinThickness( 0 ); // trace polygons only
zone.SetLayer ( layer );
int numSegs = std::max( GetArcToSegmentCount( inflate, ARC_HIGH_DEF, 360.0 ), 6 );
zone.SetLayer( layer );
int numSegs = std::max(
GetArcToSegmentCount( inflate, aBoard->GetDesignSettings().m_MaxError, 360.0 ), 6 );
areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
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() );
TransformRoundChamferedRectToPolygon( polygons, shape_pos, aPad->GetSize(),
aPad->GetOrientation(), corner_radius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), ARC_HIGH_DEF );
aPad->GetChamferPositions(), m_board->GetDesignSettings().m_MaxError );
if( polygons.OutlineCount() == 0 )
break;

View File

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

View File

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