From a3855cb4f29e87c1832368c1b6db0377651f14c3 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 12 Jul 2019 13:56:02 +0100 Subject: [PATCH] Allow thermal spokes to be same width as minimum width. Also some changes for readability and clarity, both in the code and in the Feature Constraints panel. Fixes: lp:1835674 * https://bugs.launchpad.net/kicad/+bug/1835674 --- common/geometry/shape_poly_set.cpp | 4 +- include/geometry/shape_poly_set.h | 13 +- pcbnew/dialogs/dialog_copper_zones.cpp | 5 +- .../panel_setup_feature_constraints_base.cpp | 234 ++--- .../panel_setup_feature_constraints_base.fbp | 909 +++++++++++++++++- .../panel_setup_feature_constraints_base.h | 22 +- pcbnew/zone_filler.cpp | 93 +- 7 files changed, 1061 insertions(+), 219 deletions(-) diff --git a/common/geometry/shape_poly_set.cpp b/common/geometry/shape_poly_set.cpp index 4ed76bf0f2..2af996c1b1 100644 --- a/common/geometry/shape_poly_set.cpp +++ b/common/geometry/shape_poly_set.cpp @@ -552,7 +552,7 @@ void SHAPE_POLY_SET::InflateWithLinkedHoles( int aFactor, int aCircleSegmentsCou } -void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount, bool aPreseveCorners ) +void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount, bool aPreserveCorners ) { // A static table to avoid repetitive calculations of the coefficient // 1.0 - cos( M_PI/aCircleSegmentsCount) @@ -564,7 +564,7 @@ void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount, bool aPrese // N.B. using jtSquare here does not create square corners. They end up mitered by // aFactor. Setting jtMiter and forcing the limit to be aFactor creates sharp corners. - JoinType type = aPreseveCorners ? jtMiter : jtRound; + JoinType type = aPreserveCorners ? jtMiter : jtRound; for( const POLYGON& poly : m_polys ) { diff --git a/include/geometry/shape_poly_set.h b/include/geometry/shape_poly_set.h index 21fe7db04f..dba5c8df4f 100644 --- a/include/geometry/shape_poly_set.h +++ b/include/geometry/shape_poly_set.h @@ -840,13 +840,18 @@ class SHAPE_POLY_SET : public SHAPE * * @param aFactor - number of units to offset edges * @param aCircleSegmentsCount - number of segments per 360° to use in curve approx - * @param aPreseveCorners - If true, use square joints to keep angles preserved + * @param aPreserveCorners - If true, use square joints to keep angles preserved */ - void Inflate( int aFactor, int aCircleSegmentsCount, bool aPreseveCorners = false ); + void Inflate( int aFactor, int aCircleSegmentsCount, bool aPreserveCorners = false ); - void Inflate( int aFactor, bool aPreseveCorners ) + void Inflate( int aFactor, bool aPreserveCorners ) { - Inflate( aFactor, 32, aPreseveCorners ); + Inflate( aFactor, 32, aPreserveCorners ); + } + + void Deflate( int aFactor, int aCircleSegmentsCount, bool aPreserveCorners = false ) + { + Inflate( -aFactor, aPreserveCorners, aPreserveCorners ); } ///> Performs outline inflation/deflation, using round corners. diff --git a/pcbnew/dialogs/dialog_copper_zones.cpp b/pcbnew/dialogs/dialog_copper_zones.cpp index deb057f56f..f5e80f4db2 100644 --- a/pcbnew/dialogs/dialog_copper_zones.cpp +++ b/pcbnew/dialogs/dialog_copper_zones.cpp @@ -355,10 +355,9 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly ) m_settings.m_ThermalReliefGap = m_antipadClearance.GetValue(); m_settings.m_ThermalReliefCopperBridge = m_spokeWidth.GetValue(); - if( m_settings.m_ThermalReliefCopperBridge <= m_settings.m_ZoneMinThickness ) + if( m_settings.m_ThermalReliefCopperBridge < m_settings.m_ZoneMinThickness ) { - DisplayError( this, - _( "Thermal relief spoke must be greater than the minimum width." ) ); + DisplayError( this, _( "Thermal spoke width cannot be smaller than the minimum width." ) ); return false; } diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp b/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp index 44312adb00..f0e7c1fd9e 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Dec 1 2018) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -9,240 +9,240 @@ /////////////////////////////////////////////////////////////////////////// -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 ) +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 ) { 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, wxTOP|wxRIGHT|wxLEFT, 5 ); - + m_OptAllowMicroVias = new wxCheckBox( this, wxID_ANY, _("Allow micro vias (uVias)"), wxDefaultPosition, wxDefaultSize, 0 ); sbFeatureRules->Add( m_OptAllowMicroVias, 0, wxTOP|wxRIGHT|wxLEFT, 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|wxLEFT, 5 ); - + m_OptOverlappingCourtyards = new wxCheckBox( this, wxID_ANY, _("Prohibit overlapping courtyards"), wxDefaultPosition, wxDefaultSize, 0 ); sbFeatureRules->Add( m_OptOverlappingCourtyards, 0, wxALL, 5 ); - - - sbFeatureRules->Add( 0, 0, 0, wxBOTTOM|wxEXPAND|wxTOP, 5 ); - + + + sbFeatureRules->Add( 0, 0, 0, wxEXPAND|wxBOTTOM, 5 ); + wxBoxSizer* bSizerArcToPoly; bSizerArcToPoly = new wxBoxSizer( wxVERTICAL ); - + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizerArcToPoly->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 ); - - m_stCircleToPolyOpt = new wxStaticText( this, wxID_ANY, _("Arc to polygon approximation:"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizerArcToPoly->Add( m_staticline2, 0, wxEXPAND | wxALL, 2 ); + + m_stCircleToPolyOpt = new wxStaticText( this, wxID_ANY, _("Arc/circle drawing"), wxDefaultPosition, wxDefaultSize, 0 ); m_stCircleToPolyOpt->Wrap( -1 ); - m_stCircleToPolyOpt->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - - bSizerArcToPoly->Add( m_stCircleToPolyOpt, 0, wxALL, 5 ); - + m_stCircleToPolyOpt->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + + bSizerArcToPoly->Add( m_stCircleToPolyOpt, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + wxFlexGridSizer* fgSizer2; fgSizer2 = new wxFlexGridSizer( 0, 4, 3, 0 ); fgSizer2->AddGrowableCol( 2 ); fgSizer2->SetFlexibleDirection( wxBOTH ); fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - - + + fgSizer2->Add( 15, 0, 1, wxEXPAND, 5 ); - - m_maxErrorTitle = new wxStaticText( this, wxID_ANY, _("Maximum error:"), wxDefaultPosition, wxDefaultSize, 0 ); + + m_maxErrorTitle = new wxStaticText( this, wxID_ANY, _("Maximum deviation:"), wxDefaultPosition, wxDefaultSize, 0 ); m_maxErrorTitle->Wrap( -1 ); m_maxErrorTitle->SetToolTip( _("This is the maximum distance between a circle and the polygonal shape that approximate it.\nThe error max defines the number of segments of this polygon.") ); - + fgSizer2->Add( m_maxErrorTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxLEFT, 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, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - - - bSizerArcToPoly->Add( fgSizer2, 0, wxEXPAND, 5 ); - - - sbFeatureRules->Add( bSizerArcToPoly, 0, wxEXPAND, 5 ); - + + + bSizerArcToPoly->Add( fgSizer2, 0, wxEXPAND|wxBOTTOM, 5 ); + + + sbFeatureRules->Add( bSizerArcToPoly, 0, wxEXPAND|wxTOP, 5 ); + m_bSizerPolygonFillOption = new wxBoxSizer( wxVERTICAL ); - + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - m_bSizerPolygonFillOption->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); - - m_stZoneFilledPolysOpt = new wxStaticText( this, wxID_ANY, _("Option to fill polygons in zones:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_bSizerPolygonFillOption->Add( m_staticline1, 0, wxEXPAND | wxALL, 2 ); + + m_stZoneFilledPolysOpt = new wxStaticText( this, wxID_ANY, _("Zone fill strategy"), wxDefaultPosition, wxDefaultSize, 0 ); m_stZoneFilledPolysOpt->Wrap( -1 ); - m_stZoneFilledPolysOpt->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - - m_bSizerPolygonFillOption->Add( m_stZoneFilledPolysOpt, 0, wxALL, 5 ); - + m_stZoneFilledPolysOpt->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + + m_bSizerPolygonFillOption->Add( m_stZoneFilledPolysOpt, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + wxBoxSizer* bSizer5; bSizer5 = new wxBoxSizer( wxVERTICAL ); - - m_cbOutlinePolygonBestQ = new wxCheckBox( this, wxID_ANY, _("Thick outlines (old algorithm)"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer5->Add( m_cbOutlinePolygonBestQ, 0, wxALL, 5 ); - - m_cbOutlinePolygonFastest = new wxCheckBox( this, wxID_ANY, _("No outline (fastest draw mode)"), wxDefaultPosition, wxDefaultSize, 0 ); - m_cbOutlinePolygonFastest->SetValue(true); - bSizer5->Add( m_cbOutlinePolygonFastest, 0, wxALL, 5 ); - - + + m_cbOutlinePolygonBestQ = new wxCheckBox( this, wxID_ANY, _("Stroked outlines (legacy)"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer5->Add( m_cbOutlinePolygonBestQ, 0, wxALL, 4 ); + + m_cbOutlinePolygonFastest = new wxCheckBox( this, wxID_ANY, _("Smoothed polygons (best performance)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_cbOutlinePolygonFastest->SetValue(true); + bSizer5->Add( m_cbOutlinePolygonFastest, 0, wxBOTTOM|wxRIGHT|wxLEFT, 4 ); + + m_bSizerPolygonFillOption->Add( bSizer5, 1, wxEXPAND|wxLEFT, 15 ); - - - sbFeatureRules->Add( m_bSizerPolygonFillOption, 0, wxEXPAND, 5 ); - - + + + sbFeatureRules->Add( m_bSizerPolygonFillOption, 0, wxEXPAND|wxTOP, 5 ); + + bMainSizer->Add( sbFeatureRules, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - - + + bMainSizer->Add( 0, 0, 0, wxEXPAND|wxRIGHT|wxLEFT, 15 ); - + wxBoxSizer* sbFeatureConstraints; sbFeatureConstraints = new wxBoxSizer( wxVERTICAL ); - + wxFlexGridSizer* fgFeatureConstraints; - fgFeatureConstraints = new wxFlexGridSizer( 0, 3, 3, 0 ); + fgFeatureConstraints = new wxFlexGridSizer( 0, 3, 2, 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|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 ); - + // Connect Events m_cbOutlinePolygonBestQ->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::onChangeOutlineOpt ), NULL, this ); m_cbOutlinePolygonFastest->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::onChangeOutlineOpt ), NULL, this ); @@ -253,5 +253,5 @@ PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::~PANEL_SETUP_FEATURE_CONSTRAINTS_BASE() // Disconnect Events m_cbOutlinePolygonBestQ->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::onChangeOutlineOpt ), NULL, this ); m_cbOutlinePolygonFastest->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_SETUP_FEATURE_CONSTRAINTS_BASE::onChangeOutlineOpt ), NULL, this ); - + } diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp b/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp index aebd5eb34e..b90409a09f 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.fbp @@ -1,6 +1,6 @@ - + C++ @@ -14,7 +14,6 @@ panel_setup_feature_constraints_base 1000 none - 1 panel_setup_feature_constraints_base @@ -49,6 +48,36 @@ wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer @@ -125,6 +154,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -189,6 +242,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -263,6 +340,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -327,11 +428,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + 5 - wxBOTTOM|wxEXPAND|wxTOP + wxEXPAND|wxBOTTOM 0 0 @@ -341,7 +466,7 @@ 5 - wxEXPAND + wxEXPAND|wxTOP 0 @@ -349,7 +474,7 @@ wxVERTICAL none - 5 + 2 wxEXPAND | wxALL 0 @@ -404,11 +529,34 @@ + + + + + + + + + + + + + + + + + + + + + + + 5 - wxALL + wxTOP|wxRIGHT|wxLEFT 0 1 @@ -434,12 +582,11 @@ 1 1 - ,90,92,-1,70,0 + ,90,90,-1,70,0 0 0 wxID_ANY - Arc to polygon approximation: - 0 + Arc/circle drawing 0 @@ -465,11 +612,34 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + 5 - wxEXPAND + wxEXPAND|wxBOTTOM 0 4 @@ -525,8 +695,7 @@ 0 0 wxID_ANY - Maximum error: - 0 + Maximum deviation: 0 @@ -552,6 +721,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -616,6 +808,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -651,7 +870,6 @@ 0 wxID_ANY mm - 0 0 @@ -677,6 +895,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -685,7 +926,7 @@ 5 - wxEXPAND + wxEXPAND|wxTOP 0 @@ -693,7 +934,7 @@ wxVERTICAL protected - 5 + 2 wxEXPAND | wxALL 0 @@ -748,11 +989,34 @@ + + + + + + + + + + + + + + + + + + + + + + + 5 - wxALL + wxTOP|wxRIGHT|wxLEFT 0 1 @@ -778,12 +1042,11 @@ 1 1 - ,90,92,-1,70,0 + ,90,90,-1,70,0 0 0 wxID_ANY - Option to fill polygons in zones: - 0 + Zone fill strategy 0 @@ -809,6 +1072,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -821,7 +1107,7 @@ wxVERTICAL none - 5 + 4 wxALL 0 @@ -853,7 +1139,7 @@ 0 0 wxID_ANY - Thick outlines (old algorithm) + Stroked outlines (legacy) 0 @@ -882,12 +1168,35 @@ + onChangeOutlineOpt + + + + + + + + + + + + + + + + + + + + + + - 5 - wxALL + 4 + wxBOTTOM|wxRIGHT|wxLEFT 0 1 @@ -918,7 +1227,7 @@ 0 0 wxID_ANY - No outline (fastest draw mode) + Smoothed polygons (best performance) 0 @@ -947,7 +1256,30 @@ + onChangeOutlineOpt + + + + + + + + + + + + + + + + + + + + + + @@ -990,7 +1322,7 @@ wxFLEX_GROWMODE_SPECIFIED none 0 - 3 + 2 5 wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM @@ -1024,7 +1356,6 @@ 0 wxID_ANY Minimum track width: - 0 0 @@ -1050,6 +1381,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1114,6 +1468,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1149,7 +1530,6 @@ 0 wxID_ANY mm - 0 0 @@ -1175,6 +1555,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1240,7 +1643,6 @@ 0 wxID_ANY Minimum via diameter: - 0 0 @@ -1266,6 +1668,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1330,6 +1755,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1365,7 +1817,6 @@ 0 wxID_ANY mm - 0 0 @@ -1391,6 +1842,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1426,7 +1900,6 @@ 0 wxID_ANY Minimum via drill: - 0 0 @@ -1452,6 +1925,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1516,6 +2012,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1551,7 +2074,6 @@ 0 wxID_ANY mm - 0 0 @@ -1577,6 +2099,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1642,7 +2187,6 @@ 0 wxID_ANY Minimum uVia diameter: - 0 0 @@ -1668,6 +2212,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1732,6 +2299,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1767,7 +2361,6 @@ 0 wxID_ANY mm - 0 0 @@ -1793,6 +2386,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1828,7 +2444,6 @@ 0 wxID_ANY Minimum uVia drill: - 0 0 @@ -1854,6 +2469,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -1918,6 +2556,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1953,7 +2618,6 @@ 0 wxID_ANY mm - 0 0 @@ -1979,6 +2643,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -2044,7 +2731,6 @@ 0 wxID_ANY Minimum hole to hole: - 0 0 @@ -2070,6 +2756,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -2134,6 +2843,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2169,7 +2905,6 @@ 0 wxID_ANY mm - 0 0 @@ -2195,11 +2930,34 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + 5 - wxEXPAND + wxEXPAND|wxTOP 1 0 @@ -2260,7 +3018,6 @@ 0 wxID_ANY Copper edge clearance: - 0 0 @@ -2286,6 +3043,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + @@ -2350,6 +3130,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2385,7 +3192,6 @@ 0 wxID_ANY mm - 0 0 @@ -2411,6 +3217,29 @@ -1 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/panel_setup_feature_constraints_base.h b/pcbnew/dialogs/panel_setup_feature_constraints_base.h index 008c496482..bc25a7ab8a 100644 --- a/pcbnew/dialogs/panel_setup_feature_constraints_base.h +++ b/pcbnew/dialogs/panel_setup_feature_constraints_base.h @@ -1,11 +1,12 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Dec 1 2018) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// -#pragma once +#ifndef __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__ +#define __PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__ #include #include @@ -28,10 +29,10 @@ /////////////////////////////////////////////////////////////////////////////// /// 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; @@ -68,15 +69,16 @@ class PANEL_SETUP_FEATURE_CONSTRAINTS_BASE : public wxPanel wxStaticText* m_EdgeClearanceLabel; wxTextCtrl* m_EdgeClearanceCtrl; wxStaticText* m_EdgeClearanceUnits; - + // Virtual event handlers, overide them in your derived class virtual void onChangeOutlineOpt( wxCommandEvent& event ) { event.Skip(); } - - + + 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, const wxString& name = wxEmptyString ); + + 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(); - + }; +#endif //__PANEL_SETUP_FEATURE_CONSTRAINTS_BASE_H__ diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index e419a03bf3..fbe0c81415 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -672,40 +672,46 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, { m_high_def = m_board->GetDesignSettings().m_MaxError; m_low_def = std::min( ARC_LOW_DEF, int( m_high_def*1.5 ) ); // Reasonable value - int outline_half_thickness = aZone->GetMinThickness() / 2; - int numSegs = std::max( GetArcToSegmentCount( outline_half_thickness, m_high_def, 360.0 ), 6 ); + + // Features which are min_width should survive pruning; features that are *less* than + // min_width should not. Therefore we subtract epsilon from the min_width when + // deflating/inflating. + int half_min_width = aZone->GetMinThickness() / 2; + int epsilon = Millimeter2iu( 0.001 ); + int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 ); + + std::deque thermalSpokes; + SHAPE_POLY_SET clearanceHoles; std::unique_ptr dumper( new SHAPE_FILE_IO( s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) ); + aRawPolys = aSmoothedOutline; + if( s_DumpZonesWhenFilling ) dumper->BeginGroup( "clipper-zone" ); - SHAPE_POLY_SET solidAreas = aSmoothedOutline; - std::deque thermalSpokes; - SHAPE_POLY_SET clearanceHoles; - - knockoutThermalReliefs( aZone, solidAreas ); + knockoutThermalReliefs( aZone, aRawPolys ); if( s_DumpZonesWhenFilling ) - dumper->Write( &solidAreas, "solid-areas-minus-thermal-reliefs" ); + dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" ); buildCopperItemClearances( aZone, clearanceHoles ); if( s_DumpZonesWhenFilling ) - dumper->Write( &solidAreas, "clearance holes" ); + dumper->Write( &aRawPolys, "clearance holes" ); buildThermalSpokes( aZone, thermalSpokes ); // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary // because the "real" subtract-clearance-holes has to be done after the spokes are added. static const bool USE_BBOX_CACHES = true; - SHAPE_POLY_SET testAreas = solidAreas; + SHAPE_POLY_SET testAreas = aRawPolys; testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST ); - // Remove areas that don't meet minimum-width criteria - testAreas.Inflate( -outline_half_thickness, numSegs, true ); - testAreas.Inflate( outline_half_thickness, numSegs, true ); + // Prune features that don't meet minimum-width criteria + testAreas.Deflate( half_min_width - epsilon, numSegs, true ); + testAreas.Inflate( half_min_width - epsilon, numSegs, true ); // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed // things up a bit. @@ -718,7 +724,7 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, // Hit-test against zone body if( testAreas.Contains( testPt, -1, false, true, USE_BBOX_CACHES ) ) { - solidAreas.AddOutline( spoke ); + aRawPolys.AddOutline( spoke ); continue; } @@ -727,53 +733,49 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, { if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) ) { - solidAreas.AddOutline( spoke ); + aRawPolys.AddOutline( spoke ); break; } } } - solidAreas.Simplify( SHAPE_POLY_SET::PM_FAST ); + aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST ); if( s_DumpZonesWhenFilling ) - dumper->Write( &solidAreas, "solid-areas-with-thermal-spokes" ); + dumper->Write( &aRawPolys, "solid-areas-with-thermal-spokes" ); - solidAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST ); - solidAreas.Inflate( -outline_half_thickness, numSegs ); + aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST ); + // Prune features that don't meet minimum-width criteria + aRawPolys.Deflate( half_min_width - epsilon, numSegs ); if( s_DumpZonesWhenFilling ) - dumper->Write( &solidAreas, "solid-areas-before-hatching" ); + dumper->Write( &aRawPolys, "solid-areas-before-hatching" ); // Now remove the non filled areas due to the hatch pattern if( aZone->GetFillMode() == ZFM_HATCH_PATTERN ) - addHatchFillTypeOnZone( aZone, solidAreas ); + addHatchFillTypeOnZone( aZone, aRawPolys ); if( s_DumpZonesWhenFilling ) - dumper->Write( &solidAreas, "solid-areas-after-hatching" ); + dumper->Write( &aRawPolys, "solid-areas-after-hatching" ); - SHAPE_POLY_SET areas_fractured = solidAreas; - - // Inflate polygon to recreate the polygon (without the too narrow areas) - // if the filled polygons have a outline thickness = 0 - int inflate_value = aZone->GetFilledPolysUseThickness() ? 0 : outline_half_thickness; - - if( inflate_value <= Millimeter2iu( 0.001 ) ) // avoid very small outline thickness - inflate_value = 0; - - if( inflate_value ) + // Re-inflate after pruning of areas that don't meet minimum-width criteria + if( aZone->GetFilledPolysUseThickness() ) { - areas_fractured.Simplify( SHAPE_POLY_SET::PM_FAST ); - areas_fractured.Inflate( outline_half_thickness, 16 ); + // if we're stroking the zone with a min-width stroke then this will naturally + // inflate the zone + } + else if( half_min_width - epsilon > epsilon ) // avoid very small outline thickness + { + aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST ); + aRawPolys.Inflate( half_min_width - epsilon, 16 ); } - areas_fractured.Fracture( SHAPE_POLY_SET::PM_FAST ); + aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST ); if( s_DumpZonesWhenFilling ) - dumper->Write( &areas_fractured, "areas_fractured" ); + dumper->Write( &aRawPolys, "areas_fractured" ); - aFinalPolys = areas_fractured; - - aRawPolys = aFinalPolys; + aFinalPolys = aRawPolys; if( s_DumpZonesWhenFilling ) dumper->EndGroup(); @@ -802,12 +804,17 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, SHAPE_POLY_SET& aRawPol } else { + // Features which are min_width should survive pruning; features that are *less* than + // min_width should not. Therefore we subtract epsilon from the min_width when + // deflating/inflating. + int half_min_width = aZone->GetMinThickness() / 2; + int epsilon = Millimeter2iu( 0.001 ); + int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 ); + if( m_brdOutlinesValid ) smoothedPoly.BooleanIntersection( m_boardOutline, SHAPE_POLY_SET::PM_FAST ); - int numSegs = std::max( GetArcToSegmentCount( aZone->GetMinThickness() / 2, - m_board->GetDesignSettings().m_MaxError, 360.0 ), 6 ); - smoothedPoly.Inflate( -aZone->GetMinThickness() / 2, numSegs ); + smoothedPoly.Deflate( half_min_width - epsilon, numSegs ); // Remove the non filled areas due to the hatch pattern if( aZone->GetFillMode() == ZFM_HATCH_PATTERN ) @@ -1055,7 +1062,7 @@ void ZONE_FILLER::addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, SHAPE_POL // Clamp holes to the area of filled zones with a outline thickness // > aZone->GetMinThickness() to be sure the thermal pads can be built int outline_margin = std::max( (aZone->GetMinThickness()*10)/9, linethickness/2 ); - filledPolys.Inflate( -outline_margin, 16 ); + filledPolys.Deflate( outline_margin, 16 ); holes.BooleanIntersection( filledPolys, SHAPE_POLY_SET::PM_FAST ); if( orientation != 0.0 )