diff --git a/common/pcb.keywords b/common/pcb.keywords index 4b49169ab6..da25076bb7 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -126,6 +126,9 @@ hatch_smoothing_level hatch_smoothing_value hide hole_to_hole_min +island +island_removal_mode +island_area_min italic justify keepout diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index fdb8dee9e2..f58dbb34c9 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -64,7 +64,7 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent, bool aInModule ) SetLocalFlags( 0 ); // flags tempoarry used in zone calculations m_Poly = new SHAPE_POLY_SET(); // Outlines m_FilledPolysUseThickness = true; // set the "old" way to build filled polygon areas (before 6.0.x) - m_removeIslands = true; + m_islandRemovalMode = ISLAND_REMOVAL_MODE::ALWAYS; aParent->GetZoneSettings().ExportSetting( *this ); m_needRefill = false; // True only after some edition. @@ -103,6 +103,7 @@ ZONE_CONTAINER& ZONE_CONTAINER::operator=( const ZONE_CONTAINER& aOther ) m_RawPolysList = aOther.m_RawPolysList; m_filledPolysHash = aOther.m_filledPolysHash; m_FillSegmList = aOther.m_FillSegmList; // vector <> copy + m_insulatedIslands = aOther.m_insulatedIslands; m_HatchFillTypeThickness = aOther.m_HatchFillTypeThickness; m_HatchFillTypeGap = aOther.m_HatchFillTypeGap; @@ -154,6 +155,7 @@ void ZONE_CONTAINER::initDataFromSrcInCopyCtor( const ZONE_CONTAINER& aZone ) m_RawPolysList = aZone.m_RawPolysList; m_filledPolysHash = aZone.m_filledPolysHash; m_FillSegmList = aZone.m_FillSegmList; // vector <> copy + m_insulatedIslands = aZone.m_insulatedIslands; m_doNotAllowCopperPour = aZone.m_doNotAllowCopperPour; m_doNotAllowVias = aZone.m_doNotAllowVias; @@ -267,10 +269,11 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet ) for( PCB_LAYER_ID layer : aLayerSet.Seq() ) { - m_FillSegmList[layer] = {}; - m_FilledPolysList[layer] = {}; - m_RawPolysList[layer] = {}; - m_filledPolysHash[layer] = {}; + m_FillSegmList[layer] = {}; + m_FilledPolysList[layer] = {}; + m_RawPolysList[layer] = {}; + m_filledPolysHash[layer] = {}; + m_insulatedIslands[layer] = {}; } } @@ -1143,6 +1146,18 @@ void ZONE_CONTAINER::CacheTriangulation() } +bool ZONE_CONTAINER::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) +{ + if( GetNetCode() < 1 ) + return true; + + if( !m_insulatedIslands.count( aLayer ) ) + return false; + + return m_insulatedIslands.at( aLayer ).count( aPolyIdx ); +} + + /* * Some intersecting zones, despite being on the same layer with the same net, cannot be * merged due to other parameters such as fillet radius. The copper pour will end up diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 25fe1d1a83..699c9ebae2 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -582,7 +582,10 @@ public: void ClearFilledPolysList() { for( std::pair& pair : m_FilledPolysList ) + { + m_insulatedIslands[pair.first].clear(); pair.second.RemoveAllContours(); + } } /** @@ -619,6 +622,18 @@ public: m_RawPolysList[aLayer] = aPolysList; } + /** + * Checks if a given filled polygon is an insulated island + * @param aLayer is the layer to test + * @param aPolyIdx is an inndex into m_FilledPolysList[aLayer] + * @return true if the given polygon is insulated (i.e. has no net connection) + */ + bool IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ); + + void SetIsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) + { + m_insulatedIslands[aLayer].insert( aPolyIdx ); + } /** * Function GetSmoothedPoly @@ -701,8 +716,12 @@ public: void SetDoNotAllowPads( bool aEnable ) { m_doNotAllowPads = aEnable; } void SetDoNotAllowFootprints( bool aEnable ) { m_doNotAllowFootprints = aEnable; } - bool GetRemoveIslands() const { return m_removeIslands; } - void SetRemoveIslands( bool aRemove ) { m_removeIslands = aRemove; } + const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const { return m_islandRemovalMode; } + void SetIslandRemovalMode( ISLAND_REMOVAL_MODE aRemove ) { + m_islandRemovalMode = aRemove; } + + long long int GetMinIslandArea() const { return m_minIslandArea; } + void SetMinIslandArea( long long int aArea ) { m_minIslandArea = aArea; } /** * Hatch related methods @@ -828,8 +847,13 @@ protected: int m_ZoneMinThickness; ///< Minimum thickness value in filled areas. bool m_FilledPolysUseThickness; ///< outline of filled polygons have thickness. - /// True if isolated copper (islands) should be removed after fill (default) - bool m_removeIslands; + ISLAND_REMOVAL_MODE m_islandRemovalMode; + + /** + * When island removal mode is set to AREA, islands below this area will be removed. + * If this value is negative, all islands will be removed. + */ + long long int m_minIslandArea; /** True when a zone was filled, false after deleting the filled areas. */ bool m_IsFilled; @@ -898,7 +922,9 @@ protected: ZONE_HATCH_STYLE m_hatchStyle; // hatch style, see enum above int m_hatchPitch; // for DIAGONAL_EDGE, distance between 2 hatch lines std::vector m_HatchLines; // hatch lines - std::vector m_insulatedIslands; + + /// For each layer, a set of insulated islands that were not removed + std::map> m_insulatedIslands; bool m_hv45; // constrain edges to horizontal, vertical or 45ยบ diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index 101234cf4b..3846f5131f 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -180,6 +180,13 @@ void CONNECTIVITY_DATA::RecalculateRatsnest( BOARD_COMMIT* aCommit ) { int net = c->OriginNet(); + // Don't add intentionally-kept zone islands to the ratsnest + if( c->IsOrphaned() && c->Size() == 1 ) + { + if( dynamic_cast( *c->begin() ) ) + continue; + } + if( m_connAlgo->IsNetDirty( net ) ) { addRatsnestCluster( c ); diff --git a/pcbnew/dialogs/dialog_copper_zones.cpp b/pcbnew/dialogs/dialog_copper_zones.cpp index 716d50305f..3df9b61c6f 100644 --- a/pcbnew/dialogs/dialog_copper_zones.cpp +++ b/pcbnew/dialogs/dialog_copper_zones.cpp @@ -65,6 +65,7 @@ private: UNIT_BINDER m_gridStyleRotation; UNIT_BINDER m_gridStyleThickness; UNIT_BINDER m_gridStyleGap; + UNIT_BINDER m_islandThreshold; bool TransferDataToWindow() override; bool TransferDataFromWindow() override; @@ -110,11 +111,13 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* m_minWidth( aParent, m_minWidthLabel, m_minWidthCtrl, m_minWidthUnits, true ), m_antipadClearance( aParent, m_antipadLabel, m_antipadCtrl, m_antipadUnits, true ), m_spokeWidth( aParent, m_spokeWidthLabel, m_spokeWidthCtrl, m_spokeWidthUnits, true ), - m_gridStyleRotation( aParent, m_staticTextGrindOrient, m_tcGridStyleOrientation, m_staticTextRotUnits, - false ), + m_gridStyleRotation( aParent, m_staticTextGrindOrient, m_tcGridStyleOrientation, + m_staticTextRotUnits, false ), m_gridStyleThickness( aParent, m_staticTextStyleThickness, m_tcGridStyleThickness, m_GridStyleThicknessUnits, false ), - m_gridStyleGap( aParent, m_staticTextGridGap, m_tcGridStyleGap, m_GridStyleGapUnits, false ) + m_gridStyleGap( aParent, m_staticTextGridGap, m_tcGridStyleGap, m_GridStyleGapUnits, false ), + m_islandThreshold( aParent, m_islandThresholdLabel, + m_tcIslandThreshold, m_islandThresholdUnits, false ) { m_Parent = aParent; m_bitmapNoNetWarning->SetBitmap( KiBitmap( dialog_warning_xpm ) ); @@ -130,6 +133,17 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* m_sdbSizerOK->SetDefault(); + m_cbRemoveIslands->Bind( wxEVT_CHOICE, + [&]( wxCommandEvent& ) + { + // Area mode is index 2 + bool val = m_cbRemoveIslands->GetSelection() == 2; + + m_tcIslandThreshold->Enable( val ); + m_islandThresholdLabel->Enable( val ); + m_islandThresholdUnits->Enable( val ); + } ); + FinishDialogSettings(); } @@ -179,6 +193,17 @@ bool DIALOG_COPPER_ZONE::TransferDataToWindow() m_antipadClearance.SetValue( m_settings.m_ThermalReliefGap ); m_spokeWidth.SetValue( m_settings.m_ThermalReliefCopperBridge ); + m_islandThreshold.SetDataType( EDA_DATA_TYPE::AREA ); + m_islandThreshold.SetDoubleValue( static_cast( m_settings.GetMinIslandArea() ) ); + + m_cbRemoveIslands->SetSelection( static_cast( m_settings.GetIslandRemovalMode() ) ); + + bool val = m_settings.GetIslandRemovalMode() == ISLAND_REMOVAL_MODE::AREA; + + m_tcIslandThreshold->Enable( val ); + m_islandThresholdLabel->Enable( val ); + m_islandThresholdUnits->Enable( val ); + wxString netNameDoNotShowFilter = wxT( "Net-*" ); m_NetFiltering = false; m_NetSortingByPadCount = true; @@ -235,10 +260,14 @@ bool DIALOG_COPPER_ZONE::TransferDataToWindow() m_spinCtrlSmoothLevel->SetValue( m_settings.m_HatchFillTypeSmoothingLevel ); m_spinCtrlSmoothValue->SetValue( m_settings.m_HatchFillTypeSmoothingValue ); + m_tcZoneName->SetValue( m_settings.m_Name ); + // Enable/Disable some widgets wxCommandEvent event; OnStyleSelection( event ); + Fit(); + return true; } @@ -248,7 +277,16 @@ void DIALOG_COPPER_ZONE::OnUpdateUI( wxUpdateUIEvent& ) if( m_ListNetNameSelection->GetSelection() < 0 ) m_ListNetNameSelection->SetSelection( 0 ); - m_bNoNetWarning->Show( m_ListNetNameSelection->GetSelection() == 0 ); + bool noNetSelected = m_ListNetNameSelection->GetSelection() == 0; + bool enableSize = !noNetSelected && ( m_cbRemoveIslands->GetSelection() == 2 ); + + m_bNoNetWarning->Show( noNetSelected ); + + // Zones with no net never have islands removed + m_cbRemoveIslands->Enable( !noNetSelected ); + m_islandThresholdLabel->Enable( enableSize ); + m_islandThresholdUnits->Enable( enableSize ); + m_tcIslandThreshold->Enable( enableSize ); if( m_cornerSmoothingType != m_cornerSmoothingChoice->GetSelection() ) { @@ -390,6 +428,10 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly ) cfg->m_Zones.thermal_relief_gap = Iu2Mils( m_settings.m_ThermalReliefGap ); cfg->m_Zones.thermal_relief_copper_width = Iu2Mils( m_settings.m_ThermalReliefCopperBridge ); + m_settings.SetIslandRemovalMode( + static_cast( m_cbRemoveIslands->GetSelection() ) ); + m_settings.SetMinIslandArea( m_islandThreshold.GetValue() ); + // If we use only exportable to others zones parameters, exit here: if( aUseExportableSetupOnly ) return true; @@ -422,6 +464,8 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly ) m_settings.m_NetcodeSelection = net ? net->GetNet() : 0; + m_settings.m_Name = m_tcZoneName->GetValue(); + return true; } diff --git a/pcbnew/dialogs/dialog_copper_zones_base.cpp b/pcbnew/dialogs/dialog_copper_zones_base.cpp index 5cbad54971..fffdaf7733 100644 --- a/pcbnew/dialogs/dialog_copper_zones_base.cpp +++ b/pcbnew/dialogs/dialog_copper_zones_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version v3.8.0) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -228,6 +228,15 @@ DIALOG_COPPER_ZONE_BASE::DIALOG_COPPER_ZONE_BASE( wxWindow* parent, wxWindowID i m_spokeWidthUnits->Wrap( -1 ); gbSizerSettings->Add( m_spokeWidthUnits, wxGBPosition( 4, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + m_staticText39 = new wxStaticText( sbSizer5->GetStaticBox(), wxID_ANY, _("Zone name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText39->Wrap( -1 ); + m_staticText39->SetToolTip( _("A unique name for this zone to identify it for DRC") ); + + gbSizerSettings->Add( m_staticText39, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_tcZoneName = new wxTextCtrl( sbSizer5->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + gbSizerSettings->Add( m_tcZoneName, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); + gbSizerSettings->AddGrowableCol( 1 ); @@ -239,85 +248,107 @@ DIALOG_COPPER_ZONE_BASE::DIALOG_COPPER_ZONE_BASE( wxWindow* parent, wxWindowID i wxStaticBoxSizer* sbSizerZoneStyle; sbSizerZoneStyle = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Fill") ), wxVERTICAL ); - wxFlexGridSizer* fgSizerZoneStyle; - fgSizerZoneStyle = new wxFlexGridSizer( 0, 3, 0, 0 ); - fgSizerZoneStyle->AddGrowableCol( 1 ); - fgSizerZoneStyle->SetFlexibleDirection( wxBOTH ); - fgSizerZoneStyle->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + wxGridBagSizer* gbSizer3; + gbSizer3 = new wxGridBagSizer( 0, 0 ); + gbSizer3->SetFlexibleDirection( wxBOTH ); + gbSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_staticTextGridFillType = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Fill type:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextGridFillType->Wrap( -1 ); - fgSizerZoneStyle->Add( m_staticTextGridFillType, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextGridFillType, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); wxString m_GridStyleCtrlChoices[] = { _("Solid shape"), _("Hatch pattern") }; int m_GridStyleCtrlNChoices = sizeof( m_GridStyleCtrlChoices ) / sizeof( wxString ); m_GridStyleCtrl = new wxChoice( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_GridStyleCtrlNChoices, m_GridStyleCtrlChoices, 0 ); m_GridStyleCtrl->SetSelection( 0 ); - fgSizerZoneStyle->Add( m_GridStyleCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); - - - fgSizerZoneStyle->Add( 0, 0, 1, wxEXPAND, 5 ); + gbSizer3->Add( m_GridStyleCtrl, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 ); m_staticTextGrindOrient = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Orientation:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextGrindOrient->Wrap( -1 ); - fgSizerZoneStyle->Add( m_staticTextGrindOrient, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextGrindOrient, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_tcGridStyleOrientation = new wxTextCtrl( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizerZoneStyle->Add( m_tcGridStyleOrientation, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + gbSizer3->Add( m_tcGridStyleOrientation, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); m_staticTextRotUnits = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("deg"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextRotUnits->Wrap( -1 ); - fgSizerZoneStyle->Add( m_staticTextRotUnits, 0, wxBOTTOM|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextRotUnits, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_staticTextStyleThickness = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Hatch width:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextStyleThickness->Wrap( -1 ); - fgSizerZoneStyle->Add( m_staticTextStyleThickness, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextStyleThickness, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_tcGridStyleThickness = new wxTextCtrl( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizerZoneStyle->Add( m_tcGridStyleThickness, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + gbSizer3->Add( m_tcGridStyleThickness, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); m_GridStyleThicknessUnits = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); m_GridStyleThicknessUnits->Wrap( -1 ); - fgSizerZoneStyle->Add( m_GridStyleThicknessUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); + gbSizer3->Add( m_GridStyleThicknessUnits, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_staticTextGridGap = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Hatch gap:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextGridGap->Wrap( -1 ); - fgSizerZoneStyle->Add( m_staticTextGridGap, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextGridGap, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_tcGridStyleGap = new wxTextCtrl( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizerZoneStyle->Add( m_tcGridStyleGap, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + gbSizer3->Add( m_tcGridStyleGap, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); m_GridStyleGapUnits = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); m_GridStyleGapUnits->Wrap( -1 ); - fgSizerZoneStyle->Add( m_GridStyleGapUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); + gbSizer3->Add( m_GridStyleGapUnits, wxGBPosition( 3, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_staticTextGridSmoothingLevel = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Smoothing effort:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextGridSmoothingLevel->Wrap( -1 ); m_staticTextGridSmoothingLevel->SetToolTip( _("Value of smoothing effort\n0 = no smoothing\n1 = chamfer\n2 = round corners\n3 = round corners (finer shape)") ); - fgSizerZoneStyle->Add( m_staticTextGridSmoothingLevel, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextGridSmoothingLevel, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_spinCtrlSmoothLevel = new wxSpinCtrl( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 3, 0 ); - fgSizerZoneStyle->Add( m_spinCtrlSmoothLevel, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); - - - fgSizerZoneStyle->Add( 0, 0, 1, wxEXPAND, 5 ); + gbSizer3->Add( m_spinCtrlSmoothLevel, wxGBPosition( 4, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 ); m_staticTextGridSmootingVal = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Smooth value (0..1):"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextGridSmootingVal->Wrap( -1 ); m_staticTextGridSmootingVal->SetToolTip( _("Ratio between smoothed corners size and the gap between lines\n0 = no smoothing\n1.0 = max radius/chamfer size (half gap value)") ); - fgSizerZoneStyle->Add( m_staticTextGridSmootingVal, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer3->Add( m_staticTextGridSmootingVal, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_spinCtrlSmoothValue = new wxSpinCtrlDouble( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 1, 0.100000, 0.1 ); m_spinCtrlSmoothValue->SetDigits( 0 ); - fgSizerZoneStyle->Add( m_spinCtrlSmoothValue, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + gbSizer3->Add( m_spinCtrlSmoothValue, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 ); + + m_staticText40 = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Remove islands:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText40->Wrap( -1 ); + m_staticText40->SetToolTip( _("Choose what to do with unconnected copper islands") ); + + gbSizer3->Add( m_staticText40, wxGBPosition( 6, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxString m_cbRemoveIslandsChoices[] = { _("Always"), _("Never"), _("Below area limit") }; + int m_cbRemoveIslandsNChoices = sizeof( m_cbRemoveIslandsChoices ) / sizeof( wxString ); + m_cbRemoveIslands = new wxChoice( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cbRemoveIslandsNChoices, m_cbRemoveIslandsChoices, 0 ); + m_cbRemoveIslands->SetSelection( 0 ); + gbSizer3->Add( m_cbRemoveIslands, wxGBPosition( 6, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 ); + + m_islandThresholdLabel = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("Minimum island size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_islandThresholdLabel->Wrap( -1 ); + m_islandThresholdLabel->Enable( false ); + m_islandThresholdLabel->SetToolTip( _("Isolated islands smaller than this will be removed") ); + + gbSizer3->Add( m_islandThresholdLabel, wxGBPosition( 7, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_tcIslandThreshold = new wxTextCtrl( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_tcIslandThreshold->Enable( false ); + + gbSizer3->Add( m_tcIslandThreshold, wxGBPosition( 7, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); + + m_islandThresholdUnits = new wxStaticText( sbSizerZoneStyle->GetStaticBox(), wxID_ANY, _("units"), wxDefaultPosition, wxDefaultSize, 0 ); + m_islandThresholdUnits->Wrap( -1 ); + m_islandThresholdUnits->Enable( false ); + + gbSizer3->Add( m_islandThresholdUnits, wxGBPosition( 7, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - fgSizerZoneStyle->Add( 0, 0, 1, wxEXPAND, 5 ); + gbSizer3->AddGrowableCol( 1 ); - - sbSizerZoneStyle->Add( fgSizerZoneStyle, 1, wxEXPAND, 5 ); + sbSizerZoneStyle->Add( gbSizer3, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); bSizerMiddle->Add( sbSizerZoneStyle, 1, wxEXPAND|wxTOP|wxRIGHT, 10 ); diff --git a/pcbnew/dialogs/dialog_copper_zones_base.fbp b/pcbnew/dialogs/dialog_copper_zones_base.fbp index 2c7c72b295..b4cb55ab7e 100644 --- a/pcbnew/dialogs/dialog_copper_zones_base.fbp +++ b/pcbnew/dialogs/dialog_copper_zones_base.fbp @@ -2498,6 +2498,137 @@ -1 + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Zone name: + 0 + + 0 + + + 0 + + 1 + m_staticText39 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + A unique name for this zone to identify it for DRC + + + + -1 + + + + 5 + 1 + 1 + wxALL|wxEXPAND + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_tcZoneName + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + @@ -2516,24 +2647,26 @@ none 5 - wxEXPAND + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT 1 - - 3 + + wxBOTH 1 0 - fgSizerZoneStyle + gbSizer3 wxFLEX_GROWMODE_SPECIFIED none - 0 0 - + 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + 1 1 1 @@ -2591,10 +2724,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL + 0 + 1 1 1 @@ -2656,20 +2792,13 @@ OnStyleSelection - + 5 - wxEXPAND - 1 - - 0 - protected - 0 - - - - 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + 1 1 1 @@ -2727,10 +2856,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL|wxEXPAND + 1 + 1 1 1 @@ -2791,10 +2923,13 @@ - + 5 - wxBOTTOM|wxRIGHT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + 1 1 1 @@ -2852,10 +2987,13 @@ -1 - + 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 2 + 1 1 1 @@ -2913,10 +3051,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL|wxEXPAND + 2 + 1 1 1 @@ -2977,10 +3118,13 @@ - + 5 - wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT - 0 + 1 + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 2 + 1 1 1 @@ -3038,10 +3182,13 @@ -1 - + 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 3 + 1 1 1 @@ -3099,10 +3246,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL|wxEXPAND + 3 + 1 1 1 @@ -3163,10 +3313,13 @@ - + 5 - wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT - 0 + 1 + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 3 + 1 1 1 @@ -3224,10 +3377,13 @@ -1 - + 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 4 + 1 1 1 @@ -3285,10 +3441,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL + 4 + 1 1 1 @@ -3347,20 +3506,13 @@ - + 5 - wxEXPAND - 1 - - 0 - protected - 0 - - - - 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 5 + 1 1 1 @@ -3418,10 +3570,13 @@ -1 - + 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND - 0 + 1 + 1 + wxALL + 5 + 1 1 1 @@ -3482,14 +3637,330 @@ - + 5 - wxEXPAND - 1 - - 0 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Remove islands: + 0 + + 0 + + + 0 + + 1 + m_staticText40 + 1 + + protected - 0 + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + Choose what to do with unconnected copper islands + + + + -1 + + + + 5 + 1 + 1 + wxALL + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Always" "Never" "Below area limit" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_cbRemoveIslands + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxALL + 7 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + Minimum island size: + 0 + + 0 + + + 0 + + 1 + m_islandThresholdLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + Isolated islands smaller than this will be removed + + + + -1 + + + + 5 + 1 + 1 + wxALL|wxEXPAND + 7 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_tcIslandThreshold + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + 1 + 2 + wxALIGN_CENTER_VERTICAL|wxALL + 7 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + units + 0 + + 0 + + + 0 + + 1 + m_islandThresholdUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 diff --git a/pcbnew/dialogs/dialog_copper_zones_base.h b/pcbnew/dialogs/dialog_copper_zones_base.h index 7d4366b4d8..65630dce43 100644 --- a/pcbnew/dialogs/dialog_copper_zones_base.h +++ b/pcbnew/dialogs/dialog_copper_zones_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version v3.8.0) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -98,6 +98,8 @@ class DIALOG_COPPER_ZONE_BASE : public DIALOG_SHIM wxStaticText* m_spokeWidthLabel; wxTextCtrl* m_spokeWidthCtrl; wxStaticText* m_spokeWidthUnits; + wxStaticText* m_staticText39; + wxTextCtrl* m_tcZoneName; wxStaticText* m_staticTextGridFillType; wxChoice* m_GridStyleCtrl; wxStaticText* m_staticTextGrindOrient; @@ -113,6 +115,11 @@ class DIALOG_COPPER_ZONE_BASE : public DIALOG_SHIM wxSpinCtrl* m_spinCtrlSmoothLevel; wxStaticText* m_staticTextGridSmootingVal; wxSpinCtrlDouble* m_spinCtrlSmoothValue; + wxStaticText* m_staticText40; + wxChoice* m_cbRemoveIslands; + wxStaticText* m_islandThresholdLabel; + wxTextCtrl* m_tcIslandThreshold; + wxStaticText* m_islandThresholdUnits; wxButton* m_ExportSetupButton; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; diff --git a/pcbnew/dialogs/dialog_keepout_area_properties.cpp b/pcbnew/dialogs/dialog_keepout_area_properties.cpp index af428fff47..1b2bb58284 100644 --- a/pcbnew/dialogs/dialog_keepout_area_properties.cpp +++ b/pcbnew/dialogs/dialog_keepout_area_properties.cpp @@ -97,6 +97,8 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::TransferDataToWindow() m_cbConstrainCtrl->SetValue( m_zonesettings.m_Zone_45_Only ); + m_tcName->SetValue( m_zonesettings.m_Name ); + switch( m_zonesettings.m_Zone_HatchingStyle ) { case ZONE_HATCH_STYLE::NO_HATCH: @@ -187,6 +189,8 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::TransferDataFromWindow() m_zonesettings.m_Zone_45_Only = m_cbConstrainCtrl->GetValue(); m_zonesettings.m_ZonePriority = 0; // for a keepout, this param is not used. + m_zonesettings.m_Name = m_tcName->GetValue(); + *m_ptr = m_zonesettings; return true; } diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp index d0ab8dbfbb..c600dba4ac 100644 --- a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp +++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp @@ -78,6 +78,21 @@ DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWind bSizerRight->Add( bSizerLowerRight, 0, wxEXPAND, 5 ); + wxBoxSizer* bSizer6; + bSizer6 = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText3 = new wxStaticText( this, wxID_ANY, _("Keepout name:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + m_staticText3->SetToolTip( _("A unique name for this zone to identify it for DRC") ); + + bSizer6->Add( m_staticText3, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_tcName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer6->Add( m_tcName, 1, wxALL, 5 ); + + + bSizerRight->Add( bSizer6, 1, wxEXPAND, 5 ); + bUpperSizer->Add( bSizerRight, 0, wxALL|wxEXPAND, 10 ); diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp index b93fb20778..a8ccfdab8e 100644 --- a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp +++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp @@ -728,6 +728,142 @@ + + 5 + wxEXPAND + 1 + + + bSizer6 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Keepout name: + 0 + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + A unique name for this zone to identify it for DRC + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_tcName + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.h b/pcbnew/dialogs/dialog_keepout_area_properties_base.h index bb001927e4..5d78da4cc2 100644 --- a/pcbnew/dialogs/dialog_keepout_area_properties_base.h +++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ class DIALOG_KEEPOUT_AREA_PROPERTIES_BASE : public DIALOG_SHIM wxCheckBox* m_cbConstrainCtrl; wxStaticText* m_staticTextStyle; wxChoice* m_OutlineAppearanceCtrl; + wxStaticText* m_staticText3; + wxTextCtrl* m_tcName; wxStaticLine* m_staticline1; wxStdDialogButtonSizer* m_sdbSizerButtons; wxButton* m_sdbSizerButtonsOK; diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index a98a064d31..913022fbdf 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -1793,7 +1793,7 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const m_out->Print( 0, " (tstamp %s)", TO_UTF8( aZone->m_Uuid.AsString() ) ); if( !aZone->GetZoneName().empty() ) - m_out->Print( 0, " (name %s)", TO_UTF8( aZone->GetZoneName() ) ); + m_out->Print( 0, " (name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() ); // Save the outline aux info std::string hatch; @@ -1901,6 +1901,13 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const FormatInternalUnits( aZone->GetCornerRadius() ).c_str() ); } + if( aZone->GetIslandRemovalMode() != ISLAND_REMOVAL_MODE::ALWAYS ) + { + m_out->Print( 0, " (island_removal_mode %d) (island_area_min %s)", + static_cast( aZone->GetIslandRemovalMode() ), + FormatInternalUnits( aZone->GetMinIslandArea() ).c_str() ); + } + if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN ) { m_out->Print( 0, "\n" ); @@ -1988,6 +1995,7 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const if( !fv.IsEmpty() ) { + int poly_index = 0; bool new_polygon = true; bool is_closed = false; @@ -1999,9 +2007,14 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const m_out->Print( aNestLevel + 1, "(filled_polygon\n" ); m_out->Print( aNestLevel + 2, "(layer %s)\n", TO_UTF8( BOARD::GetStandardLayerName( layer ) ) ); + + if( aZone->IsIsland( layer, poly_index ) ) + m_out->Print( aNestLevel + 2, "(island)\n" ); + m_out->Print( aNestLevel + 2, "(pts\n" ); new_polygon = false; is_closed = false; + poly_index++; } if( newLine == 0 ) diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h index 7582bf6ce8..f780449ccb 100644 --- a/pcbnew/kicad_plugin.h +++ b/pcbnew/kicad_plugin.h @@ -70,7 +70,7 @@ class TEXTE_PCB; //#define SEXPR_BOARD_FILE_VERSION 20200512 // page -> paper //#define SEXPR_BOARD_FILE_VERSION 20200518 // save hole_to_hole_min //#define SEXPR_BOARD_FILE_VERSION 20200614 // Add support for fp_rects and gr_rects -#define SEXPR_BOARD_FILE_VERSION 20200623 // Multilayer zones and zone name property +#define SEXPR_BOARD_FILE_VERSION 20200625 // Multilayer zones, zone names, island controls #define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names #define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library) diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index b694cff591..88e80fa4bd 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -3970,10 +3970,26 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent ) NeedRIGHT(); break; + + case T_island_removal_mode: + tmp = parseInt( "island_removal_mode" ); + + if( tmp >= 0 && tmp <= 2 ) + zone->SetIslandRemovalMode( static_cast( tmp ) ); + + NeedRIGHT(); + break; + + case T_island_area_min: + zone->SetMinIslandArea( parseBoardUnits( T_island_area_min ) ); + NeedRIGHT(); + break; + default: Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, " "hatch_thickness, hatch_gap, hatch_orientation, " - "hatch_smoothing_level, hatch_smoothing_value, smoothing, or radius" ); + "hatch_smoothing_level, hatch_smoothing_value, smoothing, radius" + "island_removal_mode, or island_area_min" ); } } break; @@ -4086,6 +4102,16 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent ) filledLayer = zone->GetLayer(); } + bool island = false; + + if( token == T_island ) + { + island = true; + NeedRIGHT(); + NeedLEFT(); + token = NextTok(); + } + if( token != T_pts ) Expecting( T_pts ); @@ -4094,7 +4120,10 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent ) SHAPE_POLY_SET& poly = pts.at( filledLayer ); - poly.NewOutline(); + int idx = poly.NewOutline(); + + if( island ) + zone->SetIsIsland( filledLayer, idx ); for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { @@ -4156,7 +4185,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent ) default: Expecting( "net, layer/layers, tstamp, hatch, priority, connect_pads, min_thickness, " - "fill, polygon, filled_polygon, fill_segments or name" ); + "fill, polygon, filled_polygon, fill_segments, or name" ); } } diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 3742b4368f..c00f0289ab 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -481,6 +481,8 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, // zones touch each other. std::set> plotted; + NETINFO_ITEM nonet( aBoard ); + for( ZONE_CONTAINER* zone : aBoard->Zones() ) { for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) @@ -493,10 +495,20 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, plotted.insert( pair ); SHAPE_POLY_SET aggregateArea = zone->GetFilledPolysList( layer ); + SHAPE_POLY_SET islands; bool needFracture = false; // If 2 or more filled areas are combined, resulting // aggregateArea will be simplified and fractured // (Long calculation time) + for( int i = 0; i < aggregateArea.OutlineCount(); i++ ) + { + if( zone->IsIsland( layer, i ) ) + { + islands.AddOutline( aggregateArea.CPolygon( i )[0] ); + aggregateArea.DeletePolygon( i ); + } + } + for( ZONE_CONTAINER* candidate : aBoard->Zones() ) { if( !candidate->IsOnLayer( layer ) ) @@ -524,7 +536,19 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, continue; plotted.insert( candidate_pair ); - aggregateArea.Append( candidate->GetFilledPolysList( layer ) ); + + SHAPE_POLY_SET candidateArea = candidate->GetFilledPolysList( layer ); + + for( int i = 0; i < candidateArea.OutlineCount(); i++ ) + { + if( candidate->IsIsland( layer, i ) ) + { + islands.AddOutline( candidateArea.CPolygon( i )[0] ); + candidateArea.DeletePolygon( i ); + } + } + + aggregateArea.Append( candidateArea ); needFracture = true; } @@ -535,6 +559,13 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, } itemplotter.PlotFilledAreas( zone, aggregateArea ); + + if( !islands.IsEmpty() ) + { + ZONE_CONTAINER dummy( *zone ); + dummy.SetNet( &nonet ); + itemplotter.PlotFilledAreas( &dummy, islands ); + } } } aPlotter->EndBlock( NULL ); diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 9def8f2600..9eed130f56 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -215,14 +215,26 @@ bool ZONE_FILLER::Fill( const std::vector& aZones, bool aCheck std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater() ); SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList( zone.m_layer ); + long long int minArea = zone.m_zone->GetMinIslandArea(); + ISLAND_REMOVAL_MODE mode = zone.m_zone->GetIslandRemovalMode(); + // Remove solid areas outside the board cutouts and the insulated islands // only zones with net code > 0 can have insulated islands by definition - if( zone.m_zone->GetNetCode() > 0 && zone.m_zone->GetRemoveIslands() ) + if( zone.m_zone->GetNetCode() > 0 && mode != ISLAND_REMOVAL_MODE::NEVER ) { - // solid areas outside the board cutouts are also removed, because they are usually insulated islands + // Area threshold is stored 1-D in internal units + if( mode == ISLAND_REMOVAL_MODE::AREA ) + minArea *= minArea; + + // solid areas outside the board cutouts are also removed, because they are usually + // insulated islands for( auto idx : zone.m_islands ) { - poly.DeletePolygon( idx ); + if( mode == ISLAND_REMOVAL_MODE::ALWAYS || poly.Outline( idx ).Area() < minArea + || !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) ) + poly.DeletePolygon( idx ); + else + zone.m_zone->SetIsIsland( zone.m_layer, idx ); } } // Zones with no net can have areas outside the board cutouts. diff --git a/pcbnew/zone_settings.cpp b/pcbnew/zone_settings.cpp index a37867e468..cd8465c9a5 100644 --- a/pcbnew/zone_settings.cpp +++ b/pcbnew/zone_settings.cpp @@ -62,6 +62,7 @@ ZONE_SETTINGS::ZONE_SETTINGS() //short hatches or full hatches m_Layers.reset().set( F_Cu ); + m_Name = wxEmptyString; // thickness of the gap in thermal reliefs: m_ThermalReliefGap = Mils2iu( ZONE_THERMAL_RELIEF_GAP_MIL ); @@ -75,7 +76,8 @@ ZONE_SETTINGS::ZONE_SETTINGS() m_cornerSmoothingType = SMOOTHING_NONE; m_cornerRadius = 0; - m_removeIslands = true; + m_removeIslands = ISLAND_REMOVAL_MODE::ALWAYS; + m_minIslandArea = 0; SetIsKeepout( false ); SetDoNotAllowCopperPour( false ); @@ -88,30 +90,32 @@ ZONE_SETTINGS::ZONE_SETTINGS() ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource ) { - m_ZonePriority = aSource.GetPriority(); - m_FillMode = aSource.GetFillMode(); - m_ZoneClearance = aSource.GetZoneClearance(); - m_ZoneMinThickness = aSource.GetMinThickness(); - m_HatchFillTypeThickness = aSource.GetHatchFillTypeThickness(); - m_HatchFillTypeGap = aSource.GetHatchFillTypeGap(); - m_HatchFillTypeOrientation = aSource.GetHatchFillTypeOrientation(); + m_ZonePriority = aSource.GetPriority(); + m_FillMode = aSource.GetFillMode(); + m_ZoneClearance = aSource.GetZoneClearance(); + m_ZoneMinThickness = aSource.GetMinThickness(); + m_HatchFillTypeThickness = aSource.GetHatchFillTypeThickness(); + m_HatchFillTypeGap = aSource.GetHatchFillTypeGap(); + m_HatchFillTypeOrientation = aSource.GetHatchFillTypeOrientation(); m_HatchFillTypeSmoothingLevel = aSource.GetHatchFillTypeSmoothingLevel(); m_HatchFillTypeSmoothingValue = aSource.GetHatchFillTypeSmoothingValue(); - m_NetcodeSelection = aSource.GetNetCode(); - m_Zone_HatchingStyle = aSource.GetHatchStyle(); - m_ThermalReliefGap = aSource.GetThermalReliefGap(); - m_ThermalReliefCopperBridge = aSource.GetThermalReliefCopperBridge(); - m_PadConnection = aSource.GetPadConnection(); - m_cornerSmoothingType = aSource.GetCornerSmoothingType(); - m_cornerRadius = aSource.GetCornerRadius(); - m_isKeepout = aSource.GetIsKeepout(); + m_NetcodeSelection = aSource.GetNetCode(); + m_Name = aSource.GetZoneName(); + m_Zone_HatchingStyle = aSource.GetHatchStyle(); + m_ThermalReliefGap = aSource.GetThermalReliefGap(); + m_ThermalReliefCopperBridge = aSource.GetThermalReliefCopperBridge(); + m_PadConnection = aSource.GetPadConnection(); + m_cornerSmoothingType = aSource.GetCornerSmoothingType(); + m_cornerRadius = aSource.GetCornerRadius(); + m_isKeepout = aSource.GetIsKeepout(); m_keepoutDoNotAllowCopperPour = aSource.GetDoNotAllowCopperPour(); - m_keepoutDoNotAllowVias = aSource.GetDoNotAllowVias(); - m_keepoutDoNotAllowTracks = aSource.GetDoNotAllowTracks(); - m_keepoutDoNotAllowPads = aSource.GetDoNotAllowPads(); + m_keepoutDoNotAllowVias = aSource.GetDoNotAllowVias(); + m_keepoutDoNotAllowTracks = aSource.GetDoNotAllowTracks(); + m_keepoutDoNotAllowPads = aSource.GetDoNotAllowPads(); m_keepoutDoNotAllowFootprints = aSource.GetDoNotAllowFootprints(); - m_Zone_45_Only = aSource.GetHV45(); - m_removeIslands = aSource.GetRemoveIslands(); + m_Zone_45_Only = aSource.GetHV45(); + m_removeIslands = aSource.GetIslandRemovalMode(); + m_minIslandArea = aSource.GetMinIslandArea(); m_Layers = aSource.GetLayerSet(); @@ -141,12 +145,14 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c aTarget.SetDoNotAllowPads( GetDoNotAllowPads() ); aTarget.SetDoNotAllowFootprints( GetDoNotAllowFootprints() ); aTarget.SetHV45( m_Zone_45_Only ); - aTarget.SetRemoveIslands( GetRemoveIslands() ); + aTarget.SetIslandRemovalMode( GetIslandRemovalMode() ); + aTarget.SetMinIslandArea( GetMinIslandArea() ); if( aFullExport ) { aTarget.SetPriority( m_ZonePriority ); aTarget.SetLayerSet( m_Layers ); + aTarget.SetZoneName( m_Name ); if( !m_isKeepout ) aTarget.SetNetCode( m_NetcodeSelection ); diff --git a/pcbnew/zone_settings.h b/pcbnew/zone_settings.h index 2509ad137b..ba492884b4 100644 --- a/pcbnew/zone_settings.h +++ b/pcbnew/zone_settings.h @@ -49,6 +49,14 @@ enum class ZONE_HATCH_STYLE DIAGONAL_EDGE }; +/// Whether or not to remove isolated islands from a zone +enum class ISLAND_REMOVAL_MODE +{ + ALWAYS, + NEVER, + AREA +}; + /** * ZONE_SETTINGS * handles zones parameters. @@ -83,6 +91,8 @@ public: int m_NetcodeSelection; ///< Net code selection for the current zone + wxString m_Name; ///< Unique name for the current zone (can be blank) + LSET m_Layers; ///< Layers that this zone exists on /// Option to show the zone area (outlines only, short hatches or full hatches @@ -112,7 +122,8 @@ private: bool m_keepoutDoNotAllowPads; bool m_keepoutDoNotAllowFootprints; - bool m_removeIslands; + ISLAND_REMOVAL_MODE m_removeIslands; + long long int m_minIslandArea; public: ZONE_SETTINGS(); @@ -181,8 +192,11 @@ public: void SetDoNotAllowPads( bool aEnable ) { m_keepoutDoNotAllowPads = aEnable; } void SetDoNotAllowFootprints( bool aEnable ) { m_keepoutDoNotAllowFootprints = aEnable; } - const bool GetRemoveIslands() const { return m_removeIslands; } - void SetRemoveIslands( bool aRemove ) { m_removeIslands = aRemove; } + const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const { return m_removeIslands; } + void SetIslandRemovalMode( ISLAND_REMOVAL_MODE aRemove ) { m_removeIslands = aRemove; } + + long long int GetMinIslandArea() const { return m_minIslandArea; } + void SetMinIslandArea( long long int aArea ) { m_minIslandArea = aArea; } };