You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							389 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							389 lines
						
					
					
						
							18 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KiCad, a free EDA CAD application. | |
|  * | |
|  * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr | |
|  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> | |
|  * Copyright The KiCad Developers, see AUTHORS.txt for contributors. | |
|  * | |
|  * This program is free software; you can redistribute it and/or | |
|  * modify it under the terms of the GNU General Public License | |
|  * as published by the Free Software Foundation; either version 2 | |
|  * of the License, or (at your option) any later version. | |
|  * | |
|  * This program is distributed in the hope that it will be useful, | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|  * GNU General Public License for more details. | |
|  * | |
|  * You should have received a copy of the GNU General Public License | |
|  * along with this program; if not, you may find one here: | |
|  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
|  * or you may search the http://www.gnu.org website for the version 2 license, | |
|  * or you may write to the Free Software Foundation, Inc., | |
|  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | |
|  */ | |
| 
 | |
| #include <zone_settings.h> | |
|  | |
| #include <pcb_base_frame.h> | |
| #include <board.h> | |
| #include <lset.h> | |
| #include <settings/color_settings.h> | |
| #include <zones.h> | |
|  | |
| #include <zone.h> | |
| #include <wx/dataview.h> | |
| #include <widgets/color_swatch.h> | |
|  | |
| bool ZONE_LAYER_PROPERTIES::operator==( const ZONE_LAYER_PROPERTIES& aOther ) const | |
| { | |
|     return hatching_offset == aOther.hatching_offset; | |
| } | |
| 
 | |
| ZONE_SETTINGS::ZONE_SETTINGS() | |
| { | |
|     m_ZonePriority = 0; | |
|     m_FillMode = ZONE_FILL_MODE::POLYGONS; // Mode for filling zone | |
|     // Zone clearance value | |
|     m_ZoneClearance = pcbIUScale.mmToIU( ZONE_CLEARANCE_MM ); | |
|     // Min thickness value in filled areas (this is the minimum width of copper to fill solid areas) : | |
|     m_ZoneMinThickness = pcbIUScale.mmToIU( ZONE_THICKNESS_MM ); | |
|     // Arbitrary defaults for the hatch settings | |
|     m_HatchThickness = std::max( m_ZoneMinThickness * 4, pcbIUScale.mmToIU( 1.0 ) ); | |
|     m_HatchGap       = std::max( m_ZoneMinThickness * 6, pcbIUScale.mmToIU( 1.5 ) ); | |
|     m_HatchOrientation = ANGLE_0;   // Grid style: orientation of grid lines | |
|     m_HatchSmoothingLevel = 0;      // Grid pattern smoothing type. 0 = no smoothing | |
|     m_HatchSmoothingValue = 0.1;    // Grid pattern chamfer value relative to the gap value | |
|     m_HatchHoleMinArea = 0.15;      // Min size before holes are dropped (ratio of hole size) | |
|     m_HatchBorderAlgorithm = 1;     // 0 = use zone min thickness; 1 = use hatch width | |
|     m_NetcodeSelection = 0;         // Net code selection for the current zone | |
|     m_ZoneBorderDisplayStyle = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; // Option to show the zone | |
|                                                                          // outlines only, short | |
|                                                                          // hatches or full hatches | |
|     m_BorderHatchPitch = pcbIUScale.mmToIU( ZONE_BORDER_HATCH_DIST_MM ); | |
| 
 | |
|     m_Layers.reset().set( F_Cu ); | |
|     m_Name = wxEmptyString; | |
| 
 | |
|     // thickness of the gap in thermal reliefs: | |
|     m_ThermalReliefGap = pcbIUScale.mmToIU( ZONE_THERMAL_RELIEF_GAP_MM ); | |
|     // thickness of the copper bridge in thermal reliefs: | |
|     m_ThermalReliefSpokeWidth = pcbIUScale.mmToIU( ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM ); | |
| 
 | |
|     m_padConnection = ZONE_CONNECTION::THERMAL; // How pads are covered by copper in zone | |
|  | |
|     m_Locked = false; | |
| 
 | |
|     m_cornerSmoothingType = SMOOTHING_NONE; | |
|     m_cornerRadius = 0; | |
| 
 | |
|     m_removeIslands = ISLAND_REMOVAL_MODE::ALWAYS; | |
|     m_minIslandArea = 10 * pcbIUScale.IU_PER_MM * pcbIUScale.IU_PER_MM; | |
| 
 | |
|     SetIsRuleArea( false ); | |
|     SetRuleAreaPlacementSourceType( RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME ); | |
|     SetDoNotAllowZoneFills( false ); | |
|     SetDoNotAllowVias( true ); | |
|     SetDoNotAllowTracks( true ); | |
|     SetDoNotAllowPads( true ); | |
|     SetDoNotAllowFootprints( false ); | |
| 
 | |
|     m_TeardropType = TEARDROP_TYPE::TD_NONE; | |
|     m_ruleAreaPlacementEnabled = false; | |
| } | |
| 
 | |
| 
 | |
| bool ZONE_SETTINGS::operator==( const ZONE_SETTINGS& aOther ) const | |
| { | |
|     if( m_ZonePriority                != aOther.m_ZonePriority ) return false; | |
|     if( m_FillMode                    != aOther.m_FillMode ) return false; | |
|     if( m_ZoneClearance               != aOther.m_ZoneClearance ) return false; | |
|     if( m_ZoneMinThickness            != aOther.m_ZoneMinThickness ) return false; | |
|     if( m_HatchThickness              != aOther.m_HatchThickness ) return false; | |
|     if( m_HatchGap                    != aOther.m_HatchGap ) return false; | |
|     if( m_HatchOrientation            != aOther.m_HatchOrientation ) return false; | |
|     if( m_HatchSmoothingLevel         != aOther.m_HatchSmoothingLevel ) return false; | |
|     if( m_HatchSmoothingValue         != aOther.m_HatchSmoothingValue ) return false; | |
|     if( m_HatchBorderAlgorithm        != aOther.m_HatchBorderAlgorithm ) return false; | |
|     if( m_HatchHoleMinArea            != aOther.m_HatchHoleMinArea ) return false; | |
|     if( m_NetcodeSelection            != aOther.m_NetcodeSelection ) return false; | |
|     if( m_Name                        != aOther.m_Name ) return false; | |
|     if( m_ZoneBorderDisplayStyle      != aOther.m_ZoneBorderDisplayStyle ) return false; | |
|     if( m_BorderHatchPitch            != aOther.m_BorderHatchPitch ) return false; | |
|     if( m_ThermalReliefGap            != aOther.m_ThermalReliefGap ) return false; | |
|     if( m_ThermalReliefSpokeWidth     != aOther.m_ThermalReliefSpokeWidth ) return false; | |
|     if( m_padConnection               != aOther.m_padConnection ) return false; | |
|     if( m_cornerSmoothingType         != aOther.m_cornerSmoothingType ) return false; | |
|     if( m_cornerRadius                != aOther.m_cornerRadius ) return false; | |
|     if( m_isRuleArea                  != aOther.m_isRuleArea ) return false; | |
|     if( m_ruleAreaPlacementEnabled    != aOther.m_ruleAreaPlacementEnabled ) return false; | |
|     if( m_ruleAreaPlacementSourceType != aOther.m_ruleAreaPlacementSourceType ) return false; | |
|     if( m_ruleAreaPlacementSource     != aOther.m_ruleAreaPlacementSource ) return false; | |
|     if( m_keepoutDoNotAllowZoneFills  != aOther.m_keepoutDoNotAllowZoneFills ) return false; | |
|     if( m_keepoutDoNotAllowVias       != aOther.m_keepoutDoNotAllowVias ) return false; | |
|     if( m_keepoutDoNotAllowTracks     != aOther.m_keepoutDoNotAllowTracks ) return false; | |
|     if( m_keepoutDoNotAllowPads       != aOther.m_keepoutDoNotAllowPads ) return false; | |
|     if( m_keepoutDoNotAllowFootprints != aOther.m_keepoutDoNotAllowFootprints ) return false; | |
|     if( m_Locked                      != aOther.m_Locked ) return false; | |
|     if( m_removeIslands               != aOther.m_removeIslands ) return false; | |
|     if( m_minIslandArea               != aOther.m_minIslandArea ) return false; | |
| 
 | |
|     if( !std::equal( std::begin( m_layerProperties ), std::end( m_layerProperties ), | |
|                      std::begin( aOther.m_layerProperties ) ) ) | |
|         return false; | |
| 
 | |
|     // Currently, the teardrop area type is not really a ZONE_SETTINGS parameter, | |
|     // but a ZONE parameter only. | |
|     // However it can be used in dialogs | |
|     if( m_TeardropType != aOther.m_TeardropType ) return false; | |
| 
 | |
|     if( m_Layers != aOther.m_Layers ) return false; | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE& aSource ) | |
| { | |
|     m_ZonePriority                = aSource.GetAssignedPriority(); | |
|     m_FillMode                    = aSource.GetFillMode(); | |
|     m_ZoneClearance               = aSource.GetLocalClearance().value(); | |
|     m_ZoneMinThickness            = aSource.GetMinThickness(); | |
|     m_HatchThickness              = aSource.GetHatchThickness(); | |
|     m_HatchGap                    = aSource.GetHatchGap(); | |
|     m_HatchOrientation            = aSource.GetHatchOrientation(); | |
|     m_HatchSmoothingLevel         = aSource.GetHatchSmoothingLevel(); | |
|     m_HatchSmoothingValue         = aSource.GetHatchSmoothingValue(); | |
|     m_HatchBorderAlgorithm        = aSource.GetHatchBorderAlgorithm(); | |
|     m_HatchHoleMinArea            = aSource.GetHatchHoleMinArea(); | |
|     m_NetcodeSelection            = aSource.GetNetCode(); | |
|     m_Name                        = aSource.GetZoneName(); | |
|     m_ZoneBorderDisplayStyle      = aSource.GetHatchStyle(); | |
|     m_BorderHatchPitch            = aSource.GetBorderHatchPitch(); | |
|     m_ThermalReliefGap            = aSource.GetThermalReliefGap(); | |
|     m_ThermalReliefSpokeWidth     = aSource.GetThermalReliefSpokeWidth(); | |
|     m_padConnection               = aSource.GetPadConnection(); | |
|     m_cornerSmoothingType         = aSource.GetCornerSmoothingType(); | |
|     m_cornerRadius                = aSource.GetCornerRadius(); | |
|     m_isRuleArea                  = aSource.GetIsRuleArea(); | |
|     m_ruleAreaPlacementEnabled    = aSource.GetRuleAreaPlacementEnabled(); | |
|     m_ruleAreaPlacementSourceType = aSource.GetRuleAreaPlacementSourceType(); | |
|     m_ruleAreaPlacementSource     = aSource.GetRuleAreaPlacementSource(); | |
|     m_keepoutDoNotAllowZoneFills  = aSource.GetDoNotAllowZoneFills(); | |
|     m_keepoutDoNotAllowVias       = aSource.GetDoNotAllowVias(); | |
|     m_keepoutDoNotAllowTracks     = aSource.GetDoNotAllowTracks(); | |
|     m_keepoutDoNotAllowPads       = aSource.GetDoNotAllowPads(); | |
|     m_keepoutDoNotAllowFootprints = aSource.GetDoNotAllowFootprints(); | |
|     m_Locked                      = aSource.IsLocked(); | |
|     m_removeIslands               = aSource.GetIslandRemovalMode(); | |
|     m_minIslandArea               = aSource.GetMinIslandArea(); | |
| 
 | |
|     m_layerProperties.clear(); | |
| 
 | |
|     std::ranges::copy( aSource.LayerProperties(), | |
|                        std::inserter( m_layerProperties, std::end( m_layerProperties ) ) ); | |
| 
 | |
|     // Currently, the teardrop area type is not really a ZONE_SETTINGS parameter, | |
|     // but a ZONE parameter only. | |
|     // However it can be used in dialogs | |
|     m_TeardropType                = aSource.GetTeardropAreaType(); | |
| 
 | |
|     m_Layers = aSource.GetLayerSet(); | |
| 
 | |
|     return *this; | |
| } | |
| 
 | |
| 
 | |
| void ZONE_SETTINGS::ExportSetting( ZONE& aTarget, bool aFullExport ) const | |
| { | |
|     aTarget.SetFillMode( m_FillMode ); | |
|     aTarget.SetLocalClearance( m_ZoneClearance ); | |
|     aTarget.SetMinThickness( m_ZoneMinThickness ); | |
|     aTarget.SetHatchThickness( m_HatchThickness ); | |
|     aTarget.SetHatchGap( m_HatchGap ); | |
|     aTarget.SetHatchOrientation( m_HatchOrientation ); | |
|     aTarget.SetHatchSmoothingLevel( m_HatchSmoothingLevel ); | |
|     aTarget.SetHatchSmoothingValue( m_HatchSmoothingValue ); | |
|     aTarget.SetHatchBorderAlgorithm( m_HatchBorderAlgorithm ); | |
|     aTarget.SetHatchHoleMinArea( m_HatchHoleMinArea ); | |
|     aTarget.SetThermalReliefGap( m_ThermalReliefGap ); | |
|     aTarget.SetThermalReliefSpokeWidth( m_ThermalReliefSpokeWidth ); | |
|     aTarget.SetPadConnection( m_padConnection ); | |
|     aTarget.SetCornerSmoothingType( m_cornerSmoothingType ); | |
|     aTarget.SetCornerRadius( m_cornerRadius ); | |
|     aTarget.SetIsRuleArea( GetIsRuleArea() ); | |
|     aTarget.SetRuleAreaPlacementEnabled( GetRuleAreaPlacementEnabled() ); | |
|     aTarget.SetRuleAreaPlacementSourceType( GetRuleAreaPlacementSourceType() ); | |
|     aTarget.SetRuleAreaPlacementSource( GetRuleAreaPlacementSource() ); | |
|     aTarget.SetDoNotAllowZoneFills( GetDoNotAllowZoneFills() ); | |
|     aTarget.SetDoNotAllowVias( GetDoNotAllowVias() ); | |
|     aTarget.SetDoNotAllowTracks( GetDoNotAllowTracks() ); | |
|     aTarget.SetDoNotAllowPads( GetDoNotAllowPads() ); | |
|     aTarget.SetDoNotAllowFootprints( GetDoNotAllowFootprints() ); | |
|     aTarget.SetLocked( m_Locked ); | |
|     aTarget.SetIslandRemovalMode( GetIslandRemovalMode() ); | |
|     aTarget.SetMinIslandArea( GetMinIslandArea() ); | |
|     // Currently, the teardrop area type is not imported from a ZONE_SETTINGS, because | |
|     // it is not really a ZONE_SETTINGS parameter, but a ZONE parameter only | |
| #if 0 | |
|     aTarget.SetTeardropAreaType( m_TeardropType ); | |
| #endif | |
|  | |
| 
 | |
|     if( aFullExport ) | |
|     { | |
|         aTarget.SetAssignedPriority( m_ZonePriority ); | |
| 
 | |
|         aTarget.SetLayerProperties( m_layerProperties ); | |
|         aTarget.SetLayerSet( m_Layers ); | |
| 
 | |
|         aTarget.SetZoneName( m_Name ); | |
| 
 | |
|         if( !m_isRuleArea ) | |
|             aTarget.SetNetCode( m_NetcodeSelection ); | |
|     } | |
| 
 | |
|     // call SetBorderDisplayStyle last, because hatch lines will be rebuilt, | |
|     // using new parameters values | |
|     aTarget.SetBorderDisplayStyle( m_ZoneBorderDisplayStyle, | |
|                                    m_BorderHatchPitch, true ); | |
| } | |
| 
 | |
| void ZONE_SETTINGS::CopyFrom( const ZONE_SETTINGS& aOther, bool aCopyFull ) | |
| { | |
|     // clang-format off | |
|     m_ZonePriority                = aOther.m_ZonePriority; | |
|     m_FillMode                    = aOther.m_FillMode; | |
|     m_ZoneClearance               = aOther.m_ZoneClearance; | |
|     m_ZoneMinThickness            = aOther.m_ZoneMinThickness; | |
|     m_HatchThickness              = aOther.m_HatchThickness; | |
|     m_HatchGap                    = aOther.m_HatchGap; | |
|     m_HatchOrientation            = aOther.m_HatchOrientation; | |
|     m_HatchSmoothingLevel         = aOther.m_HatchSmoothingLevel; | |
|     m_HatchSmoothingValue         = aOther.m_HatchSmoothingValue; | |
|     m_HatchBorderAlgorithm        = aOther.m_HatchBorderAlgorithm; | |
|     m_HatchHoleMinArea            = aOther.m_HatchHoleMinArea; | |
|     m_NetcodeSelection            = aOther.m_NetcodeSelection; | |
|     m_Name                        = aOther.m_Name; | |
|     m_ZoneBorderDisplayStyle      = aOther.m_ZoneBorderDisplayStyle; | |
|     m_BorderHatchPitch            = aOther.m_BorderHatchPitch; | |
|     m_ThermalReliefGap            = aOther.m_ThermalReliefGap; | |
|     m_ThermalReliefSpokeWidth     = aOther.m_ThermalReliefSpokeWidth; | |
|     m_padConnection               = aOther.m_padConnection; | |
|     m_cornerSmoothingType         = aOther.m_cornerSmoothingType; | |
|     m_cornerRadius                = aOther.m_cornerRadius; | |
|     m_isRuleArea                  = aOther.m_isRuleArea; | |
|     m_ruleAreaPlacementEnabled    = aOther.m_ruleAreaPlacementEnabled; | |
|     m_ruleAreaPlacementSourceType = aOther.m_ruleAreaPlacementSourceType; | |
|     m_ruleAreaPlacementSource     = aOther.m_ruleAreaPlacementSource; | |
|     m_keepoutDoNotAllowZoneFills  = aOther.m_keepoutDoNotAllowZoneFills; | |
|     m_keepoutDoNotAllowVias       = aOther.m_keepoutDoNotAllowVias; | |
|     m_keepoutDoNotAllowTracks     = aOther.m_keepoutDoNotAllowTracks; | |
|     m_keepoutDoNotAllowPads       = aOther.m_keepoutDoNotAllowPads; | |
|     m_keepoutDoNotAllowFootprints = aOther.m_keepoutDoNotAllowFootprints; | |
|     m_Locked                      = aOther.m_Locked; | |
|     m_removeIslands               = aOther.m_removeIslands; | |
|     m_minIslandArea               = aOther.m_minIslandArea; | |
|     // clang-format on | |
|  | |
|     if( aCopyFull ) | |
|     { | |
|         m_layerProperties.clear(); | |
| 
 | |
|         std::ranges::copy( aOther.m_layerProperties, | |
|                            std::inserter( m_layerProperties, std::end( m_layerProperties ) ) ); | |
| 
 | |
|         m_TeardropType = aOther.m_TeardropType; | |
| 
 | |
|         m_Layers = aOther.m_Layers; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void ZONE_SETTINGS::SetCornerRadius( int aRadius ) | |
| { | |
|     if( aRadius < 0 ) | |
|         m_cornerRadius = 0; | |
|     else | |
|         m_cornerRadius = aRadius; | |
| } | |
| 
 | |
| 
 | |
| #ifdef __WXOSX_MAC__ | |
| const static wxSize LAYER_BITMAP_SIZE( 28, 28 );  // wxCocoa impl unhappy if this isn't square... | |
| #else | |
| const static wxSize LAYER_BITMAP_SIZE( 24, 16 ); | |
| #endif | |
|  | |
| const static wxSize CHECKERBOARD_SIZE( 8, 8 ); | |
| 
 | |
| 
 | |
| const ZONE_SETTINGS& ZONE_SETTINGS::GetDefaultSettings() | |
| { | |
|     static ZONE_SETTINGS defaultSettings; | |
| 
 | |
|     return defaultSettings; | |
| } | |
| 
 | |
| 
 | |
| // A helper for setting up a dialog list for specifying zone layers.  Used by all three | |
| // zone settings dialogs. | |
| void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME* aFrame, | |
|                                      LSET aLayers, bool aFpEditorMode ) | |
| { | |
|     BOARD* board = aFrame->GetBoard(); | |
|     COLOR4D backgroundColor = aFrame->GetColorSettings()->GetColor( LAYER_PCB_BACKGROUND ); | |
| 
 | |
|     // In the Footprint Editor In1_Cu is used as a proxy for "all inner layers" | |
|     if( aFpEditorMode ) | |
|         aLayers.set( In1_Cu ); | |
| 
 | |
|     wxDataViewColumn* checkColumn = aList->AppendToggleColumn( | |
|             wxEmptyString, wxDATAVIEW_CELL_ACTIVATABLE, wxCOL_WIDTH_DEFAULT, wxALIGN_CENTER ); | |
| 
 | |
|     wxDataViewColumn* layerColumn = aList->AppendIconTextColumn( wxEmptyString ); | |
|     wxDataViewColumn* layerIDColumn = aList->AppendTextColumn( wxEmptyString ); | |
|     layerIDColumn->SetHidden( true ); | |
| 
 | |
|     int textWidth = 0; | |
| 
 | |
|     for( PCB_LAYER_ID layerID : aLayers.UIOrder() ) | |
|     { | |
|         wxString layerName = board->GetLayerName( layerID ); | |
| 
 | |
|         if( aFpEditorMode && layerID == In1_Cu ) | |
|             layerName = _( "Inner layers" ); | |
| 
 | |
|         // wxCOL_WIDTH_AUTOSIZE doesn't work on all platforms, so we calculate width here | |
|         textWidth = std::max( textWidth, KIUI::GetTextSize( layerName, aList ).x ); | |
| 
 | |
|         COLOR4D layerColor = aFrame->GetColorSettings()->GetColor( layerID ); | |
|         auto bitmap = COLOR_SWATCH::MakeBitmap( layerColor, backgroundColor, LAYER_BITMAP_SIZE, | |
|                                                 CHECKERBOARD_SIZE, aList->GetBackgroundColour() ); | |
|         wxIcon icon; | |
|         icon.CopyFromBitmap( bitmap ); | |
| 
 | |
|         wxVector<wxVariant> row; | |
|         row.push_back( wxVariant( m_Layers.test( layerID ) ) ); | |
|         row.push_back( wxVariant( wxDataViewIconText( layerName, icon ) ) ); | |
|         row.push_back( wxVariant( wxString::Format( wxT( "%i" ), layerID ) ) ); | |
|         aList->AppendItem( row ); | |
| 
 | |
|         if( m_Layers.test( layerID ) ) | |
|             aList->SetToggleValue( true, (unsigned) aList->GetItemCount() - 1, 0 ); | |
|     } | |
| 
 | |
|     int checkColSize = aList->FromDIP( 22 ); | |
|     int layerColSize = textWidth + LAYER_BITMAP_SIZE.x + aList->FromDIP( 15 ); | |
| 
 | |
|     // You'd think the fact that m_layers is a list would encourage wxWidgets not to save room | |
|     // for the tree expanders... but you'd be wrong.  Force indent to 0. | |
|     aList->SetIndent( 0 ); | |
|     aList->SetMinClientSize( wxSize( checkColSize + layerColSize, | |
|                                      aList->GetMinClientSize().y ) ); | |
| 
 | |
|     checkColumn->SetWidth( checkColSize ); | |
|     layerColumn->SetWidth( layerColSize ); | |
| } | |
| 
 | |
| 
 |