7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-19 17:51:41 +00:00

Make pad & via teardrops 1st-class citizens (props of the pad/via)

Change teardrop generation to rely more heavily on BOARD_CONNECTIVITY
for improved performance.

Add updating of teardrops on BOARD_COMMIT::Push().

Also converts m_CopperItemRTreeCache to std::shared_ptr.
We don't copy it around anyway, and having to create a new set
of std::unique_ptr's for each operation is likely to be more
expensive than std::shared_ptr's overhead.
This commit is contained in:
Jeff Young 2023-05-12 22:03:54 +01:00
parent 329025f8a7
commit 8b1fd62d35
83 changed files with 20386 additions and 10678 deletions
common
eeschema/dialogs
include
pcbnew
CMakeLists.txtboard.cppboard.hboard_commit.cppboard_commit.hboard_connected_item.cppboard_connected_item.hboard_design_settings.cpp
connectivity
dialogs
drc
menubar_pcb_editor.cpppad.cpppad.hpcb_edit_frame.cpppcbnew_id.h
plugins/kicad
router
teardrop
tools
zone.cpp

View File

@ -194,14 +194,31 @@ CHANGE_TYPE COMMIT::convert( UNDO_REDO aType ) const
return CHT_REMOVE;
default:
assert( false );
// Can't fall through if the assert fires, so quiet our warning
#ifdef NDEBUG
wxASSERT( false );
KI_FALLTHROUGH;
#endif
case UNDO_REDO::CHANGED:
return CHT_MODIFY;
}
}
UNDO_REDO COMMIT::convert( CHANGE_TYPE aType ) const
{
switch( aType )
{
case CHT_ADD:
return UNDO_REDO::NEWITEM;
case CHT_REMOVE:
return UNDO_REDO::DELETED;
default:
wxASSERT( false );
KI_FALLTHROUGH;
case CHT_MODIFY:
return UNDO_REDO::CHANGED;
}
}

View File

@ -2,7 +2,7 @@
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2012 CERN.
# Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
# Copyright (C) 2019-2023 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
@ -31,6 +31,7 @@ allowed
allow_missing_courtyard
allow_soldermask_bridges
allow_soldermask_bridges_in_footprints
allow_two_segments
anchor
angle
arc
@ -46,6 +47,8 @@ attr
autoplace_cost90
autoplace_cost180
aux_axis_origin
best_length_ratio
best_width_ratio
bevelled
blind
blind_buried_vias_allowed
@ -69,6 +72,7 @@ connect_pads
copperpour
copper_finish
crossbar
curve_points
custom
outline
convexhull
@ -96,6 +100,7 @@ edge_connector
edge_plating
edge_width
effects
enabled
end
epsilon_r
exclude_from_pos_files
@ -112,6 +117,7 @@ fill_segments
filled_polygon
filled_areas_thickness
fillet
filter_ratio
font
format
footprint
@ -171,12 +177,15 @@ layers
leader
leader_length
left
legacy_teardrops
linear
line_spacing
links
locked
loss_tangent
max_error
max_length
max_width
material
members
micro
@ -223,6 +232,7 @@ pad_prop_castellated
pad_prop_testpoint
pad_prop_heatsink
padvia
prefer_zone_connections
private_layers
property
page
@ -281,6 +291,7 @@ target
title
title_block
teardrop
teardrops
tedit
text_frame
text_position_mode

View File

@ -171,7 +171,7 @@ void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent )
&& m_units != EDA_UNITS::DEGREES
&& m_units != EDA_UNITS::PERCENT )
{
int temp = (int) GetValue();
int temp = GetIntValue();
SetUnits( provider->GetUserUnits() );
m_iuScale = &provider->GetIuScale();

View File

@ -137,7 +137,7 @@ DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS_BASE::DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS_
fgSizer2->Add( 0, 0, 1, wxEXPAND, 5 );
m_selectedFilterOpt = new wxCheckBox( sbFilters->GetStaticBox(), wxID_ANY, _("Only include selected items"), wxDefaultPosition, wxDefaultSize, 0 );
m_selectedFilterOpt = new wxCheckBox( sbFilters->GetStaticBox(), wxID_ANY, _("Selected items only"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer2->Add( m_selectedFilterOpt, 0, wxRIGHT|wxLEFT, 5 );

View File

@ -1712,7 +1712,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Only include selected items</property>
<property name="label">Selected items only</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>

View File

@ -187,7 +187,7 @@ bool DIALOG_WIRE_BUS_PROPERTIES::TransferDataFromWindow()
{
if( !m_wireWidth.IsIndeterminate() )
{
int width = std::max( (long long int) 0, m_wireWidth.GetValue() );
int width = std::max( 0, m_wireWidth.GetIntValue() );
if( item->Type() == SCH_LINE_T )
static_cast<SCH_LINE*>( item )->SetLineWidth( width );

View File

@ -107,8 +107,8 @@ bool PANEL_EESCHEMA_EDITING_OPTIONS::TransferDataFromWindow()
cfg->m_Drawing.default_sheet_border_color = m_borderColorSwatch->GetSwatchColor();
cfg->m_Drawing.default_sheet_background_color = m_backgroundColorSwatch->GetSwatchColor();
cfg->m_Drawing.default_repeat_offset_x = schIUScale.IUToMils( (int) m_hPitch.GetValue() );
cfg->m_Drawing.default_repeat_offset_y = schIUScale.IUToMils( (int) m_vPitch.GetValue() );
cfg->m_Drawing.default_repeat_offset_x = schIUScale.IUToMils( m_hPitch.GetIntValue() );
cfg->m_Drawing.default_repeat_offset_y = schIUScale.IUToMils( m_vPitch.GetIntValue() );
cfg->m_Drawing.repeat_label_increment = m_spinLabelRepeatStep->GetValue();
cfg->m_Drawing.line_mode = m_choiceLineMode->GetSelection();

View File

@ -182,8 +182,10 @@ protected:
virtual EDA_ITEM* makeImage( EDA_ITEM* aItem ) const = 0;
CHANGE_TYPE convert( UNDO_REDO aType ) const;
UNDO_REDO convert( CHANGE_TYPE aType ) const;
std::set<EDA_ITEM*> m_changedItems;
protected:
std::set<EDA_ITEM*> m_changedItems;
std::vector<COMMIT_LINE> m_changes;
};

View File

@ -124,6 +124,8 @@ public:
*/
virtual long long int GetValue();
int GetIntValue() { return (int) GetValue(); }
/**
* Return the current value in Internal Units.
*

View File

@ -30,8 +30,6 @@ include_directories(
)
set( PCBNEW_DIALOGS
teardrop/dialog_teardrop_base.cpp
teardrop/dialog_teardrop.cpp
dialogs/dialog_filter_selection.cpp
dialogs/dialog_filter_selection_base.cpp
dialogs/dialog_board_setup.cpp
@ -88,6 +86,8 @@ set( PCBNEW_DIALOGS
dialogs/dialog_global_deletion_base.cpp
dialogs/dialog_global_edit_tracks_and_vias.cpp
dialogs/dialog_global_edit_tracks_and_vias_base.cpp
dialogs/dialog_global_edit_teardrops.cpp
dialogs/dialog_global_edit_teardrops_base.cpp
dialogs/dialog_global_edit_text_and_graphics.cpp
dialogs/dialog_global_edit_text_and_graphics_base.cpp
dialogs/dialog_global_fp_lib_table_config.cpp
@ -171,6 +171,8 @@ set( PCBNEW_DIALOGS
dialogs/panel_setup_layers_base.cpp
dialogs/panel_setup_rules.cpp
dialogs/panel_setup_rules_base.cpp
dialogs/panel_setup_teardrops.cpp
dialogs/panel_setup_teardrops_base.cpp
dialogs/panel_setup_text_and_graphics.cpp
dialogs/panel_setup_text_and_graphics_base.cpp
dialogs/panel_setup_tracks_and_vias.cpp
@ -354,6 +356,7 @@ set( PCBNEW_CLASS_SRCS
tools/zone_create_helper.cpp
tools/zone_filler_tool.cpp
teardrop/teardrop.cpp
teardrop/teardrop_parameters.cpp
teardrop/teardrop_utils.cpp
footprint_preview_panel.cpp

View File

@ -244,7 +244,8 @@ void BOARD::IncrementTimeStamp()
|| !m_IntersectsFCourtyardCache.empty()
|| !m_IntersectsBCourtyardCache.empty()
|| !m_LayerExpressionCache.empty()
|| !m_ZoneBBoxCache.empty() )
|| !m_ZoneBBoxCache.empty()
|| m_CopperItemRTreeCache )
{
std::unique_lock<std::mutex> cacheLock( m_CachesMutex );
@ -257,6 +258,8 @@ void BOARD::IncrementTimeStamp()
m_ZoneBBoxCache.clear();
m_CopperItemRTreeCache = nullptr;
// These are always regenerated before use, but still probably safer to clear them
// while we're here.
m_DRCMaxClearance = 0;
@ -265,12 +268,6 @@ void BOARD::IncrementTimeStamp()
m_DRCCopperZones.clear();
m_ZoneIsolatedIslandsMap.clear();
m_CopperZoneRTreeCache.clear();
m_CopperItemRTreeCache = std::make_unique<DRC_RTREE>();
}
else if( !m_CopperItemRTreeCache )
{
std::unique_lock<std::mutex> cacheLock( m_CachesMutex );
m_CopperItemRTreeCache = std::make_unique<DRC_RTREE>();
}
}

View File

@ -1156,6 +1156,9 @@ public:
*/
GroupLegalOpsField GroupLegalOps( const PCB_SELECTION& selection ) const;
bool LegacyTeardrops() const { return m_legacyTeardrops; }
void SetLegacyTeardrops( bool aFlag ) { m_legacyTeardrops = aFlag; }
// --------- Item order comparators ---------
struct cmp_items
@ -1177,7 +1180,7 @@ public:
std::unordered_map<PTR_PTR_LAYER_CACHE_KEY, bool> m_EnclosedByAreaCache;
std::unordered_map< wxString, LSET > m_LayerExpressionCache;
std::unordered_map<ZONE*, std::unique_ptr<DRC_RTREE>> m_CopperZoneRTreeCache;
std::unique_ptr<DRC_RTREE> m_CopperItemRTreeCache;
std::shared_ptr<DRC_RTREE> m_CopperItemRTreeCache;
mutable std::unordered_map<const ZONE*, BOX2I> m_ZoneBBoxCache;
// ------------ DRC caches -------------
@ -1249,6 +1252,12 @@ private:
*/
std::unique_ptr<BOARD_DESIGN_SETTINGS> m_designSettings;
/**
* Teardrops in 7.0 were applied as a post-processing step (rather than from pad and via
* properties). If this flag is set, then auto-teardrop-generation will be disabled.
*/
bool m_legacyTeardrops = false;
NETINFO_LIST m_NetInfo; // net info list (name, design constraints...
std::vector<BOARD_LISTENER*> m_listeners;

View File

@ -27,6 +27,7 @@
#include <board.h>
#include <footprint.h>
#include <pcb_group.h>
#include <pcb_track.h>
#include <tool/tool_manager.h>
#include <tools/pcb_selection_tool.h>
#include <tools/zone_filler_tool.h>
@ -35,6 +36,7 @@
#include <tools/pcb_tool_base.h>
#include <tools/pcb_actions.h>
#include <connectivity/connectivity_data.h>
#include <teardrop/teardrop.h>
#include <functional>
using namespace std::placeholders;
@ -82,8 +84,9 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
aItem->ClearFlags( IS_MODIFIED_CHILD );
// If aItem belongs a footprint, the full footprint will be saved because undo/redo does
// not handle "sub items" modifications. This has implications for auto-zone-refill, so
// we need to store a bit more information.
// not handle "sub items" modifications. This has implications for some udpate mechanisms,
// such as auto-zone-refill and teardrop regeneration, so we need to store a bit more
// information.
if( aChangeType == CHT_MODIFY )
{
if( aItem->Type() == PCB_FOOTPRINT_T )
@ -93,9 +96,23 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
{
child->SetFlags( IS_MODIFIED_CHILD );
} );
return COMMIT::Stage( aItem, aChangeType );
}
else if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
{
FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
bool parentFootprintStaged = alg::contains( m_changedItems, parentFootprint );
if( !parentFootprintStaged )
{
parentFootprint->RunOnChildren(
[&]( BOARD_ITEM* child )
{
child->ClearFlags( IS_MODIFIED_CHILD );
} );
}
if( aItem->Type() == PCB_GROUP_T )
{
static_cast<PCB_GROUP*>( aItem )->RunOnChildren(
@ -109,7 +126,10 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
aItem->SetFlags( IS_MODIFIED_CHILD );
}
aItem = aItem->GetParent();
if( !parentFootprintStaged )
return COMMIT::Stage( parentFootprint, aChangeType );
return *this;
}
else if( aItem->Type() == PCB_GROUP_T )
{
@ -120,6 +140,8 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
{
COMMIT::Stage( child, aChangeType );
} );
return COMMIT::Stage( aItem, aChangeType );
}
}
@ -127,13 +149,15 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
}
COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen )
COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType,
BASE_SCREEN* aScreen )
{
return COMMIT::Stage( container, aChangeType, aScreen );
}
COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag, BASE_SCREEN* aScreen )
COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag,
BASE_SCREEN* aScreen )
{
return COMMIT::Stage( aItems, aModFlag, aScreen );
}
@ -201,18 +225,23 @@ void BOARD_COMMIT::dirtyIntersectingZones( BOARD_ITEM* item, int aChangeType )
void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
{
// Objects potentially interested in changes:
PICKED_ITEMS_LIST undoList;
KIGFX::VIEW* view = m_toolMgr->GetView();
BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
PCB_BASE_FRAME* frame = dynamic_cast<PCB_BASE_FRAME*>( m_toolMgr->GetToolHolder() );
std::set<EDA_ITEM*> savedModules;
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
// Notification info
PICKED_ITEMS_LIST undoList;
std::set<EDA_ITEM*> savedModules;
bool itemsDeselected = false;
bool solderMaskDirty = false;
bool autofillZones = false;
bool selectedModified = false;
// Dirty flags and lists
bool solderMaskDirty = false;
bool autofillZones = false;
std::vector<BOARD_ITEM*> staleTeardropPadsAndVias;
std::set<PCB_TRACK*> staleTeardropTracks;
if( Empty() )
return;
@ -279,10 +308,46 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
}
}
if( boardItem->Type() == PCB_VIA_T || boardItem->Type() == PCB_FOOTPRINT_T
|| boardItem->IsOnLayer( F_Mask ) || boardItem->IsOnLayer( B_Mask ) )
if( m_isBoardEditor )
{
solderMaskDirty = true;
if( boardItem->Type() == PCB_VIA_T || boardItem->Type() == PCB_FOOTPRINT_T
|| boardItem->IsOnLayer( F_Mask ) || boardItem->IsOnLayer( B_Mask ) )
{
solderMaskDirty = true;
}
if( !( aCommitFlags & SKIP_TEARDROPS ) )
{
if( boardItem->Type() == PCB_PAD_T || boardItem->Type() == PCB_VIA_T )
{
staleTeardropPadsAndVias.push_back( boardItem );
}
else if( boardItem->Type() == PCB_TRACE_T || boardItem->Type() == PCB_ARC_T )
{
PCB_TRACK* track = static_cast<PCB_TRACK*>( boardItem );
staleTeardropTracks.insert( track );
std::vector<PAD*> connectedPads;
std::vector<PCB_VIA*> connectedVias;
connectivity->GetConnectedPadsAndVias( track, &connectedPads, &connectedVias );
for( PAD* pad : connectedPads )
staleTeardropPadsAndVias.push_back( pad );
for( PCB_VIA* via : connectedVias )
staleTeardropPadsAndVias.push_back( via );
}
else if( boardItem->Type() == PCB_FOOTPRINT_T )
{
for( PAD* pad : static_cast<FOOTPRINT*>( boardItem )->Pads() )
{
if( pad->GetFlags() & IS_MODIFIED_CHILD )
staleTeardropPadsAndVias.push_back( pad );
}
}
}
}
if( boardItem->IsSelected() )
@ -362,6 +427,14 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( autofillZones )
dirtyIntersectingZones( boardItem, changeType );
boardItem->SetFlags( STRUCT_DELETED );
if( boardItem->Type() == PCB_FOOTPRINT_T )
{
for( PAD* pad : static_cast<FOOTPRINT*>( boardItem )->Pads() )
pad->SetFlags( STRUCT_DELETED );
}
switch( boardItem->Type() )
{
case PCB_TEXT_T:
@ -545,19 +618,21 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
frame->HideSolderMask();
}
// Log undo items for any connectivity changes
if( !staleTeardropPadsAndVias.empty() || !staleTeardropTracks.empty() )
{
TEARDROP_MANAGER teardropMgr( board, m_toolMgr );
teardropMgr.UpdateTeardrops( *this, &staleTeardropPadsAndVias, &staleTeardropTracks );
}
// Log undo items for any connectivity or teardrop changes
for( size_t i = num_changes; i < m_changes.size(); ++i )
{
COMMIT_LINE& ent = m_changes[i];
wxASSERT( ( ent.m_type & CHT_TYPE ) == CHT_MODIFY );
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
wxASSERT( ent.m_copy );
ITEM_PICKER itemWrapper( nullptr, boardItem, convert( ent.m_type & CHT_TYPE ) );
itemWrapper.SetLink( ent.m_copy );
undoList.PushItem( itemWrapper );
}
@ -567,7 +642,14 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
}
if( view )
view->Update( boardItem );
{
if( ( ent.m_type & CHT_TYPE ) == CHT_ADD )
view->Add( boardItem );
else if( ( ent.m_type & CHT_TYPE ) == CHT_REMOVE )
view->Remove( boardItem );
else
view->Update( boardItem );
}
}
}

View File

@ -41,6 +41,7 @@ class TOOL_BASE;
#define SKIP_SET_DIRTY 0x0004
#define SKIP_CONNECTIVITY 0x0008
#define ZONE_FILL_OP 0x0010
#define SKIP_TEARDROPS 0x0020
class BOARD_COMMIT : public COMMIT
{

View File

@ -203,5 +203,89 @@ static struct BOARD_CONNECTED_ITEM_DESC
&BOARD_CONNECTED_ITEM::GetNetname ) )
.SetIsHiddenFromPropertiesManager()
.SetIsHiddenFromLibraryEditors();
auto supportsTeardrops =
[]( INSPECTABLE* aItem ) -> bool
{
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem ) )
{
if( bci->GetBoard()->LegacyTeardrops() )
return false;
return bci->Type() == PCB_PAD_T || bci->Type() == PCB_VIA_T;
}
return false;
};
auto supportsTeardropPreferZoneSetting =
[]( INSPECTABLE* aItem ) -> bool
{
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem ) )
{
if( bci->GetBoard()->LegacyTeardrops() )
return false;
return bci->Type() == PCB_PAD_T;
}
return false;
};
const wxString groupTeardrops = _HKI( "Teardrops" );
auto enableTeardrops = new PROPERTY<BOARD_CONNECTED_ITEM, bool>( _HKI( "Enable Teardrops" ),
&BOARD_CONNECTED_ITEM::SetTeardropsEnabled,
&BOARD_CONNECTED_ITEM::GetTeardropsEnabled );
enableTeardrops->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( enableTeardrops, groupTeardrops );
auto bestLength = new PROPERTY<BOARD_CONNECTED_ITEM, double>( _HKI( "Best Length Ratio" ),
&BOARD_CONNECTED_ITEM::SetTeardropBestLengthRatio,
&BOARD_CONNECTED_ITEM::GetTeardropBestLengthRatio );
bestLength->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( bestLength, groupTeardrops );
auto maxLength = new PROPERTY<BOARD_CONNECTED_ITEM, int>( _HKI( "Max Length" ),
&BOARD_CONNECTED_ITEM::SetTeardropMaxLength,
&BOARD_CONNECTED_ITEM::GetTeardropMaxLength, PROPERTY_DISPLAY::PT_SIZE );
maxLength->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( maxLength, groupTeardrops );
auto bestWidth = new PROPERTY<BOARD_CONNECTED_ITEM, double>( _HKI( "Best Width Ratio" ),
&BOARD_CONNECTED_ITEM::SetTeardropBestWidthRatio,
&BOARD_CONNECTED_ITEM::GetTeardropBestWidthRatio );
bestWidth->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( bestWidth, groupTeardrops );
auto maxWidth = new PROPERTY<BOARD_CONNECTED_ITEM, int>( _HKI( "Max Width" ),
&BOARD_CONNECTED_ITEM::SetTeardropMaxWidth,
&BOARD_CONNECTED_ITEM::GetTeardropMaxWidth, PROPERTY_DISPLAY::PT_SIZE );
maxWidth->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( maxWidth, groupTeardrops );
auto curvePts = new PROPERTY<BOARD_CONNECTED_ITEM, int>( _HKI( "Curve Points" ),
&BOARD_CONNECTED_ITEM::SetTeardropCurvePts,
&BOARD_CONNECTED_ITEM::GetTeardropCurvePts );
curvePts->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( curvePts, groupTeardrops );
auto preferZones = new PROPERTY<BOARD_CONNECTED_ITEM, bool>( _HKI( "Prefer zone connections" ),
&BOARD_CONNECTED_ITEM::SetTeardropPreferZoneConnections,
&BOARD_CONNECTED_ITEM::GetTeardropPreferZoneConnections );
preferZones->SetAvailableFunc( supportsTeardropPreferZoneSetting );
propMgr.AddProperty( preferZones, groupTeardrops );
auto twoTracks = new PROPERTY<BOARD_CONNECTED_ITEM, bool>( _HKI( "Allow teardrops to span two tracks" ),
&BOARD_CONNECTED_ITEM::SetTeardropAllowSpanTwoTracks,
&BOARD_CONNECTED_ITEM::GetTeardropAllowSpanTwoTracks );
twoTracks->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( twoTracks, groupTeardrops );
auto maxTrackWidth = new PROPERTY<BOARD_CONNECTED_ITEM, double>( _HKI( "Max Width Ratio" ),
&BOARD_CONNECTED_ITEM::SetTeardropMaxTrackWidth,
&BOARD_CONNECTED_ITEM::GetTeardropMaxTrackWidth );
maxTrackWidth->SetAvailableFunc( supportsTeardrops );
propMgr.AddProperty( maxTrackWidth, groupTeardrops );
}
} _BOARD_CONNECTED_ITEM_DESC;

View File

@ -27,6 +27,7 @@
#define BOARD_CONNECTED_ITEM_H
#include <board_item.h>
#include <teardrop/teardrop_parameters.h>
class NETCLASS;
class NETINFO_ITEM;
@ -168,22 +169,50 @@ public:
*/
wxString GetNetClassName() const;
void SetLocalRatsnestVisible( bool aVisible )
{
m_localRatsnestVisible = aVisible;
}
void SetLocalRatsnestVisible( bool aVisible ) { m_localRatsnestVisible = aVisible; }
bool GetLocalRatsnestVisible() const { return m_localRatsnestVisible; }
bool GetLocalRatsnestVisible() const
{
return m_localRatsnestVisible;
}
TEARDROP_PARAMETERS& GetTeardropParams() { return m_teardropParams; }
const TEARDROP_PARAMETERS& GetTeardropParams() const { return m_teardropParams; }
void SetTeardropsEnabled( bool aEnable ) { m_teardropParams.m_Enabled = aEnable; }
bool GetTeardropsEnabled() const { return m_teardropParams.m_Enabled; }
void SetTeardropBestLengthRatio( double aRatio ) { m_teardropParams.m_BestLengthRatio = aRatio; }
double GetTeardropBestLengthRatio() const { return m_teardropParams.m_BestLengthRatio; }
void SetTeardropMaxLength( int aMaxLength ) { m_teardropParams.m_TdMaxLen = aMaxLength; }
int GetTeardropMaxLength() const { return m_teardropParams.m_TdMaxLen; }
void SetTeardropBestWidthRatio( double aRatio ) { m_teardropParams.m_BestWidthRatio = aRatio; }
double GetTeardropBestWidthRatio() const { return m_teardropParams.m_BestWidthRatio; }
void SetTeardropMaxWidth( int aMaxWidth ) { m_teardropParams.m_TdMaxWidth = aMaxWidth; }
int GetTeardropMaxWidth() const { return m_teardropParams.m_TdMaxWidth; }
void SetTeardropCurvePts( int aPointCount ) { m_teardropParams.m_CurveSegCount = aPointCount; }
int GetTeardropCurvePts() const { return m_teardropParams.m_CurveSegCount; }
void SetTeardropPreferZoneConnections( bool aPrefer ) { m_teardropParams.m_TdOnPadsInZones = !aPrefer; }
bool GetTeardropPreferZoneConnections() const { return !m_teardropParams.m_TdOnPadsInZones; }
void SetTeardropAllowSpanTwoTracks( bool aAllow ) { m_teardropParams.m_AllowUseTwoTracks = aAllow; }
bool GetTeardropAllowSpanTwoTracks() const { return m_teardropParams.m_AllowUseTwoTracks; }
void SetTeardropMaxTrackWidth( double aRatio ) { m_teardropParams.m_WidthtoSizeFilterRatio = aRatio; }
double GetTeardropMaxTrackWidth() const { return m_teardropParams.m_WidthtoSizeFilterRatio; }
protected:
/// Store all information about the net that item belongs to.
NETINFO_ITEM* m_netinfo;
/// Not all BOARD_CONNECTED_ITEMs support teardrops, but we want those that do to share a
/// single section in the property inspector.
TEARDROP_PARAMETERS m_teardropParams;
private:
bool m_localRatsnestVisible;
};
#endif // BOARD_CONNECTED_ITEM_H

View File

@ -471,9 +471,6 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
entry["td_onpadsmd"] = m_TeardropParamsList.m_TargetPadsWithNoHole;
entry["td_ontrackend"] = m_TeardropParamsList.m_TargetTrack2Track;
entry["td_onroundshapesonly"] = m_TeardropParamsList.m_UseRoundShapesOnly;
entry["td_allow_use_two_tracks"] = m_TeardropParamsList.m_AllowUseTwoTracks;
entry["td_curve_segcount"] = m_TeardropParamsList.m_CurveSegCount;
entry["td_on_pad_in_zone"] = m_TeardropParamsList.m_TdOnPadsInZones;
js.push_back( entry );
@ -501,14 +498,20 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
if( entry.contains( "td_onroundshapesonly" ) )
m_TeardropParamsList.m_UseRoundShapesOnly = entry["td_onroundshapesonly"].get<bool>();
if( entry.contains( "td_allow_use_two_tracks" ) )
m_TeardropParamsList.m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
// Legacy settings
for( int ii = 0; ii < 3; ++ii )
{
TEARDROP_PARAMETERS* td_prm = m_TeardropParamsList.GetParameters( (TARGET_TD)ii );
if( entry.contains( "td_curve_segcount" ) )
m_TeardropParamsList.m_CurveSegCount = entry["td_curve_segcount"].get<int>();
if( entry.contains( "td_allow_use_two_tracks" ) )
td_prm->m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
if( entry.contains( "td_on_pad_in_zone" ) )
m_TeardropParamsList.m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
if( entry.contains( "td_curve_segcount" ) )
td_prm->m_CurveSegCount = entry["td_curve_segcount"].get<int>();
if( entry.contains( "td_on_pad_in_zone" ) )
td_prm->m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
}
}
},
{} ) );
@ -526,11 +529,14 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
entry["td_target_name"] = GetTeardropTargetCanonicalName( (TARGET_TD)ii );
entry["td_maxlen"] = pcbIUScale.IUTomm( td_prm->m_TdMaxLen );
entry["td_maxheight"] = pcbIUScale.IUTomm( td_prm->m_TdMaxHeight );
entry["td_length_ratio"] = td_prm->m_LengthRatio;
entry["td_height_ratio"] = td_prm->m_HeightRatio;
entry["td_maxheight"] = pcbIUScale.IUTomm( td_prm->m_TdMaxWidth );
entry["td_length_ratio"] = td_prm->m_BestLengthRatio;
entry["td_height_ratio"] = td_prm->m_BestWidthRatio;
entry["td_curve_segcount"] = td_prm->m_CurveSegCount;
entry["td_width_to_size_filter_ratio"] = td_prm->m_WidthtoSizeFilterRatio;
entry["td_allow_use_two_tracks"] = td_prm->m_AllowUseTwoTracks;
entry["td_curve_segcount"] = td_prm->m_CurveSegCount;
entry["td_on_pad_in_zone"] = td_prm->m_TdOnPadsInZones;
js.push_back( entry );
}
@ -560,19 +566,28 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
td_prm->m_TdMaxLen = pcbIUScale.mmToIU( entry["td_maxlen"].get<double>() );
if( entry.contains( "td_maxheight" ) )
td_prm->m_TdMaxHeight = pcbIUScale.mmToIU( entry["td_maxheight"].get<double>() );
td_prm->m_TdMaxWidth = pcbIUScale.mmToIU( entry["td_maxheight"].get<double>() );
if( entry.contains( "td_length_ratio" ) )
td_prm->m_LengthRatio = entry["td_length_ratio"].get<double>();
td_prm->m_BestLengthRatio = entry["td_length_ratio"].get<double>();
if( entry.contains( "td_height_ratio" ) )
td_prm->m_HeightRatio = entry["td_height_ratio"].get<double>();
td_prm->m_BestWidthRatio = entry["td_height_ratio"].get<double>();
if( entry.contains( "td_curve_segcount" ) )
td_prm->m_CurveSegCount = entry["td_curve_segcount"].get<int>();
if( entry.contains( "td_width_to_size_filter_ratio" ) )
td_prm->m_WidthtoSizeFilterRatio = entry["td_width_to_size_filter_ratio"].get<double>();
if( entry.contains( "td_allow_use_two_tracks" ) )
td_prm->m_AllowUseTwoTracks = entry["td_allow_use_two_tracks"].get<bool>();
if( entry.contains( "td_curve_segcount" ) )
td_prm->m_CurveSegCount = entry["td_curve_segcount"].get<int>();
if( entry.contains( "td_on_pad_in_zone" ) )
td_prm->m_TdOnPadsInZones = entry["td_on_pad_in_zone"].get<bool>();
}
}
},

View File

@ -637,6 +637,28 @@ const
}
void CONNECTIVITY_DATA::GetConnectedPadsAndVias( const BOARD_CONNECTED_ITEM* aItem,
std::vector<PAD*>* pads,
std::vector<PCB_VIA*>* vias )
{
for( CN_ITEM* citem : m_connAlgo->ItemEntry( aItem ).GetItems() )
{
for( CN_ITEM* connected : citem->ConnectedItems() )
{
if( connected->Valid() )
{
BOARD_CONNECTED_ITEM* parent = connected->Parent();
if( parent->Type() == PCB_PAD_T )
pads->push_back( static_cast<PAD*>( parent ) );
else if( parent->Type() == PCB_VIA_T )
vias->push_back( static_cast<PCB_VIA*>( parent ) );
}
}
}
}
unsigned int CONNECTIVITY_DATA::GetNodeCount( int aNet ) const
{
int sum = 0;

View File

@ -51,6 +51,7 @@ class ZONE;
class RN_DATA;
class RN_NET;
class PCB_TRACK;
class PCB_VIA;
class PAD;
class FOOTPRINT;
class PROGRESS_REPORTER;
@ -193,6 +194,9 @@ public:
void GetConnectedPads( const BOARD_CONNECTED_ITEM* aItem, std::set<PAD*>* pads ) const;
void GetConnectedPadsAndVias( const BOARD_CONNECTED_ITEM* aItem, std::vector<PAD*>* pads,
std::vector<PCB_VIA*>* vias );
/**
* Function GetConnectedItemsAtAnchor()
* Returns a list of items connected to a source item aItem at position aAnchor

View File

@ -228,7 +228,7 @@ const std::vector<CN_ITEM*> CN_LIST::Add( ZONE* zone, PCB_LAYER_ID aLayer )
zitem->BuildRTree();
for( VECTOR2I pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() )
for( const VECTOR2I& pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() )
zitem->AddAnchor( pt );
rv.push_back( Add( zitem ) );

View File

@ -258,18 +258,22 @@ class CN_ZONE_LAYER : public CN_ITEM
public:
CN_ZONE_LAYER( ZONE* aParent, PCB_LAYER_ID aLayer, int aSubpolyIndex ) :
CN_ITEM( aParent, false ),
m_zone( aParent ),
m_subpolyIndex( aSubpolyIndex ),
m_layer( aLayer )
{
m_triangulatedPoly = aParent->GetFilledPolysList( aLayer );
m_fillPoly = aParent->GetFilledPolysList( aLayer );
SetLayers( aLayer );
}
void BuildRTree()
{
for( unsigned int ii = 0; ii < m_triangulatedPoly->TriangulatedPolyCount(); ++ii )
if( m_zone->IsTeardropArea() )
return;
for( unsigned int ii = 0; ii < m_fillPoly->TriangulatedPolyCount(); ++ii )
{
const auto* triangleSet = m_triangulatedPoly->TriangulatedPolygon( ii );
const auto* triangleSet = m_fillPoly->TriangulatedPolygon( ii );
if( triangleSet->GetSourceOutlineIndex() != m_subpolyIndex )
continue;
@ -291,6 +295,9 @@ public:
bool ContainsPoint( const VECTOR2I& p ) const
{
if( m_zone->IsTeardropArea() )
return m_fillPoly->Outline( m_subpolyIndex ).Collide( p ) ;
int min[2] = { p.x, p.y };
int max[2] = { p.x, p.y };
bool collision = false;
@ -319,11 +326,14 @@ public:
const SHAPE_LINE_CHAIN& GetOutline() const
{
return m_triangulatedPoly->Outline( m_subpolyIndex );
return m_fillPoly->Outline( m_subpolyIndex );
}
bool Collide( SHAPE* aRefShape ) const
{
if( m_zone->IsTeardropArea() )
return m_fillPoly->Collide( aRefShape );
BOX2I bbox = aRefShape->BBox();
int min[2] = { bbox.GetX(), bbox.GetY() };
int max[2] = { bbox.GetRight(), bbox.GetBottom() };
@ -349,9 +359,10 @@ public:
bool HasSingleConnection();
private:
ZONE* m_zone;
int m_subpolyIndex;
PCB_LAYER_ID m_layer;
std::shared_ptr<SHAPE_POLY_SET> m_triangulatedPoly;
std::shared_ptr<SHAPE_POLY_SET> m_fillPoly;
RTree<const SHAPE*, int, 2, double> m_rTree;
};

View File

@ -42,6 +42,7 @@
#include "dialog_board_setup.h"
#include "panel_setup_rules.h"
#include "panel_setup_teardrops.h"
std::mutex DIALOG_BOARD_SETUP::g_Mutex;
@ -64,6 +65,7 @@ DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) :
m_maskAndPagePage( 0 ),
m_constraintsPage( 0 ),
m_tracksAndViasPage( 0 ),
m_teardropsPage( 0 ),
m_netclassesPage( 0 ),
m_severitiesPage( 0 )
@ -149,6 +151,13 @@ DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) :
return new PANEL_SETUP_TRACKS_AND_VIAS( aParent, m_frame );
}, _( "Pre-defined Sizes" ) );
m_teardropsPage = m_treebook->GetPageCount();
m_treebook->AddLazySubPage(
[this]( wxWindow* aParent ) -> wxWindow*
{
return new PANEL_SETUP_TEARDROPS( aParent, m_frame );
}, _( "Teardrops" ) );
m_netclassesPage = m_treebook->GetPageCount();
m_treebook->AddLazySubPage(
[this]( wxWindow* aParent ) -> wxWindow*
@ -353,6 +362,12 @@ void DIALOG_BOARD_SETUP::onAuxiliaryAction( wxCommandEvent& aEvent )
m_tracksAndViasPage )->ImportSettingsFrom( otherBoard );
}
if( importDlg.m_TeardropsOpt->GetValue() )
{
RESOLVE_PAGE( PANEL_SETUP_TEARDROPS,
m_teardropsPage )->ImportSettingsFrom( otherBoard );
}
if( importDlg.m_MaskAndPasteOpt->GetValue() )
{
RESOLVE_PAGE( PANEL_SETUP_MASK_AND_PASTE,

View File

@ -67,6 +67,7 @@ private:
size_t m_maskAndPagePage;
size_t m_constraintsPage;
size_t m_tracksAndViasPage;
size_t m_teardropsPage;
size_t m_netclassesPage;
size_t m_severitiesPage;
};

View File

@ -479,8 +479,8 @@ bool DIALOG_COPPER_ZONE::TransferDataFromWindow()
}
m_settings.m_HatchOrientation = m_gridStyleRotation.GetAngleValue();
m_settings.m_HatchThickness = m_gridStyleThickness.GetValue();
m_settings.m_HatchGap = m_gridStyleGap.GetValue();
m_settings.m_HatchThickness = m_gridStyleThickness.GetIntValue();
m_settings.m_HatchGap = m_gridStyleGap.GetIntValue();
m_settings.m_HatchSmoothingLevel = m_spinCtrlSmoothLevel->GetValue();
m_settings.m_HatchSmoothingValue = m_spinCtrlSmoothValue->GetValue();
@ -514,7 +514,7 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly )
if( m_settings.m_FillMode == ZONE_FILL_MODE::HATCH_PATTERN )
{
int minThickness = m_minWidth.GetValue();
int minThickness = m_minWidth.GetIntValue();
if( !m_gridStyleThickness.Validate( minThickness, INT_MAX ) )
return false;
@ -542,15 +542,17 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aUseExportableSetupOnly )
pcbIUScale.mmToIU( ZONE_BORDER_HATCH_MAXDIST_MM ) ) )
return false;
m_settings.m_BorderHatchPitch = m_outlineHatchPitch.GetValue();
m_settings.m_BorderHatchPitch = m_outlineHatchPitch.GetIntValue();
m_settings.m_ZoneClearance = m_clearance.GetValue();
m_settings.m_ZoneMinThickness = m_minWidth.GetValue();
m_settings.m_ZoneClearance = m_clearance.GetIntValue();
m_settings.m_ZoneMinThickness = m_minWidth.GetIntValue();
m_settings.SetCornerSmoothingType( m_cornerSmoothingChoice->GetSelection() );
m_settings.SetCornerRadius( m_settings.GetCornerSmoothingType() == ZONE_SETTINGS::SMOOTHING_NONE
? 0 : m_cornerRadius.GetValue() );
if( m_settings.GetCornerSmoothingType() == ZONE_SETTINGS::SMOOTHING_NONE )
m_settings.SetCornerRadius( 0 );
else
m_settings.SetCornerRadius( m_cornerRadius.GetIntValue() );
m_settings.m_ZonePriority = m_PriorityLevelCtrl->GetValue();

View File

@ -0,0 +1,569 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 <widgets/unit_binder.h>
#include <pcb_edit_frame.h>
#include <board.h>
#include <board_design_settings.h>
#include <pcb_track.h>
#include <pcb_group.h>
#include <footprint.h>
#include <teardrop/teardrop.h>
#include <zone_filler.h>
#include <connectivity/connectivity_data.h>
#include <pcb_layer_box_selector.h>
#include <tool/tool_manager.h>
#include <tools/global_edit_tool.h>
#include "dialog_global_edit_teardrops_base.h"
// Globals to remember control settings during a session
static bool g_vias = true;
static bool g_pthPads = true;
static bool g_smdPads = true;
static bool g_trackToTrack = false;
static bool g_filterByNetclass;
static wxString g_netclassFilter;
static bool g_filterByNet;
static wxString g_netFilter;
static bool g_filterByLayer;
static int g_layerFilter;
static bool g_filterRoundPads = false;
static bool g_filterSelected = false;
static int g_action = 1;
class DIALOG_GLOBAL_EDIT_TEARDROPS : public DIALOG_GLOBAL_EDIT_TEARDROPS_BASE
{
public:
DIALOG_GLOBAL_EDIT_TEARDROPS( PCB_EDIT_FRAME* aParent );
~DIALOG_GLOBAL_EDIT_TEARDROPS() override;
protected:
void onSpecifiedValuesUpdateUi( wxUpdateUIEvent& event ) override
{
event.Enable( m_specifiedValues->GetValue() );
}
void onCurvedEdgesUpdateUi( wxUpdateUIEvent& event ) override
{
event.Enable( m_specifiedValues->GetValue() && m_rbCurved->GetValue() );
}
void onFilterUpdateUi( wxUpdateUIEvent& event ) override
{
event.Enable( !m_trackToTrack->GetValue() );
}
// We can't use standard wxWidgets radio button processing for these because you must
// be able to turn them both off to set a "don't modify" state
void onStraightLines( wxMouseEvent& event ) override
{
if( !m_rbStraightLines->GetValue() )
{
m_rbStraightLines->SetValue( true );
m_rbCurved->SetValue( false );
}
else
{
m_rbStraightLines->SetValue( false );
}
}
void onCurvedLines( wxMouseEvent& event ) override
{
if( !m_rbCurved->GetValue() )
{
m_rbCurved->SetValue( true );
m_rbStraightLines->SetValue( false );
}
else
{
m_rbCurved->SetValue( false );
}
}
void onTrackToTrack( wxCommandEvent& event ) override
{
if( event.IsChecked() && m_specifiedValues->GetValue() )
{
m_specifiedValues->SetValue( false );
m_addTeardrops->SetValue( true );
}
}
void OnNetclassFilterSelect( wxCommandEvent& event ) override
{
m_netclassFilterOpt->SetValue( true );
}
void OnLayerFilterSelect( wxCommandEvent& event ) override
{
m_layerFilterOpt->SetValue( true );
}
void OnNetFilterSelect( wxCommandEvent& event )
{
m_netFilterOpt->SetValue( true );
}
void OnExistingFilterSelect( wxCommandEvent& event ) override
{
if( event.IsChecked() )
m_specifiedValues->SetLabel( _( "Update teardrops to specified values:" ) );
else
m_specifiedValues->SetLabel( _( "Add teardrops with specified values:" ) );
}
void setSpecifiedParams( TEARDROP_PARAMETERS* targetParams );
void visitItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem );
void processItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem );
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
void onShowBoardSetup( wxHyperlinkEvent& event ) override
{
m_parent->ShowBoardSetupDialog( _( "Teardrops" ) );
}
void buildFilterLists();
private:
PCB_EDIT_FRAME* m_parent;
BOARD* m_brd;
PCB_SELECTION m_selection;
UNIT_BINDER m_teardropHDPercent;
UNIT_BINDER m_teardropLenPercent;
UNIT_BINDER m_teardropMaxLen;
UNIT_BINDER m_teardropHeightPercent;
UNIT_BINDER m_teardropMaxHeight;
UNIT_BINDER m_curvePoints;
};
DIALOG_GLOBAL_EDIT_TEARDROPS::DIALOG_GLOBAL_EDIT_TEARDROPS( PCB_EDIT_FRAME* aParent ) :
DIALOG_GLOBAL_EDIT_TEARDROPS_BASE( aParent ),
m_teardropHDPercent( aParent, m_stHDRatio, m_tcHDRatio, m_stHDRatioUnits ),
m_teardropLenPercent( aParent, m_stLenPercentLabel, m_tcLenPercent, m_stLenPercentUnits ),
m_teardropMaxLen( aParent, m_stMaxLen, m_tcTdMaxLen, m_stMaxLenUnits ),
m_teardropHeightPercent( aParent, m_stHeightPercentLabel, m_tcHeightPercent, m_stHeightPercentUnits ),
m_teardropMaxHeight( aParent, m_stMaxHeight, m_tcMaxHeight, m_stMaxHeightUnits ),
m_curvePoints( aParent, m_curvePointsLabel, m_curvePointsCtrl, nullptr )
{
m_parent = aParent;
m_brd = m_parent->GetBoard();
m_bitmapTeardrop->SetBitmap( KiBitmap( BITMAPS::teardrop_sizes ) );
m_teardropHDPercent.SetUnits( EDA_UNITS::PERCENT );
m_teardropLenPercent.SetUnits( EDA_UNITS::PERCENT );
m_teardropHeightPercent.SetUnits( EDA_UNITS::PERCENT );
m_curvePoints.SetUnits( EDA_UNITS::UNSCALED );
m_minTrackWidthHint->SetFont( KIUI::GetInfoFont( this ).Italic() );
buildFilterLists();
SetupStandardButtons();
m_netFilter->Connect( NET_SELECTED,
wxCommandEventHandler( DIALOG_GLOBAL_EDIT_TEARDROPS::OnNetFilterSelect ),
nullptr, this );
finishDialogSettings();
}
DIALOG_GLOBAL_EDIT_TEARDROPS::~DIALOG_GLOBAL_EDIT_TEARDROPS()
{
g_vias = m_vias->GetValue();
g_pthPads = m_pthPads->GetValue();
g_smdPads = m_smdPads->GetValue();
g_trackToTrack = m_trackToTrack->GetValue();
g_filterByNetclass = m_netclassFilterOpt->GetValue();
g_netclassFilter = m_netclassFilter->GetStringSelection();
g_filterByNet = m_netFilterOpt->GetValue();
g_netFilter = m_netFilter->GetSelectedNetname();
g_filterByLayer = m_layerFilterOpt->GetValue();
g_layerFilter = m_layerFilter->GetLayerSelection();
g_filterRoundPads = m_roundPadsFilter->GetValue();
g_filterSelected = m_selectedItemsFilter->GetValue();
if( m_removeTeardrops->GetValue() )
g_action = 0;
else if( m_specifiedValues->GetValue() )
g_action = 2;
else
g_action = 1;
m_netFilter->Disconnect( NET_SELECTED,
wxCommandEventHandler( DIALOG_GLOBAL_EDIT_TEARDROPS::OnNetFilterSelect ),
nullptr, this );
}
void DIALOG_GLOBAL_EDIT_TEARDROPS::buildFilterLists()
{
// Populate the net filter list with net names
m_netFilter->SetBoard( m_brd );
m_netFilter->SetNetInfo( &m_brd->GetNetInfo() );
if( !m_brd->GetHighLightNetCodes().empty() )
m_netFilter->SetSelectedNetcode( *m_brd->GetHighLightNetCodes().begin() );
// Populate the netclass filter list with netclass names
wxArrayString netclassNames;
std::shared_ptr<NET_SETTINGS>& settings = m_brd->GetDesignSettings().m_NetSettings;
netclassNames.push_back( settings->m_DefaultNetClass->GetName() );
for( const auto& [ name, netclass ] : settings->m_NetClasses )
netclassNames.push_back( name );
m_netclassFilter->Set( netclassNames );
m_netclassFilter->SetStringSelection( m_brd->GetDesignSettings().GetCurrentNetClassName() );
// Populate the layer filter list
m_layerFilter->SetBoardFrame( m_parent );
m_layerFilter->SetLayersHotkeys( false );
m_layerFilter->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
m_layerFilter->Resync();
m_layerFilter->SetLayerSelection( m_parent->GetActiveLayer() );
}
bool DIALOG_GLOBAL_EDIT_TEARDROPS::TransferDataToWindow()
{
PCB_SELECTION_TOOL* selTool = m_parent->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
m_selection = selTool->GetSelection();
BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( m_selection.Front() );
m_vias->SetValue( g_vias );
m_pthPads->SetValue( g_pthPads );
m_smdPads->SetValue( g_smdPads );
m_trackToTrack->SetValue( g_trackToTrack );
if( g_filterByNetclass && m_netclassFilter->SetStringSelection( g_netclassFilter ) )
m_netclassFilterOpt->SetValue( true );
else if( item )
m_netclassFilter->SetStringSelection( item->GetNet()->GetNetClass()->GetName() );
if( g_filterByNet && m_brd->FindNet( g_netFilter ) != nullptr )
{
m_netFilter->SetSelectedNet( g_netFilter );
m_netFilterOpt->SetValue( true );
}
else if( item )
{
m_netFilter->SetSelectedNetcode( item->GetNetCode() );
}
if( g_filterByLayer && m_layerFilter->SetLayerSelection( g_layerFilter ) != wxNOT_FOUND )
{
m_layerFilterOpt->SetValue( true );
}
else if( item )
{
if( item->Type() == PCB_ZONE_T ) // a zone can be on more than one layer
m_layerFilter->SetLayerSelection( static_cast<ZONE*>(item)->GetFirstLayer() );
else
m_layerFilter->SetLayerSelection( item->GetLayer() );
}
m_roundPadsFilter->SetValue( g_filterRoundPads );
m_selectedItemsFilter->SetValue( g_filterSelected );
if( g_action == 0 )
m_removeTeardrops->SetValue( true );
else if( g_action == 1 )
m_addTeardrops->SetValue( true );
else
m_specifiedValues->SetValue( true );
m_cbPreferZoneConnection->Set3StateValue( wxCHK_UNDETERMINED );
m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
m_teardropHDPercent.SetValue( INDETERMINATE_ACTION );
m_teardropLenPercent.SetValue( INDETERMINATE_ACTION );
m_teardropMaxLen.SetValue( INDETERMINATE_ACTION );
m_teardropHeightPercent.SetValue( INDETERMINATE_ACTION );
m_teardropMaxHeight.SetValue( INDETERMINATE_ACTION );
m_curvePoints.SetValue( INDETERMINATE_ACTION );
return true;
}
void DIALOG_GLOBAL_EDIT_TEARDROPS::setSpecifiedParams( TEARDROP_PARAMETERS* targetParams )
{
if( m_cbPreferZoneConnection->Get3StateValue() != wxCHK_UNDETERMINED )
targetParams->m_TdOnPadsInZones = !m_cbPreferZoneConnection->GetValue();
if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
if( !m_teardropHDPercent.IsIndeterminate() )
targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
if( !m_teardropLenPercent.IsIndeterminate() )
targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
if( !m_teardropMaxLen.IsIndeterminate() )
targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
if( !m_teardropHeightPercent.IsIndeterminate() )
targetParams->m_BestWidthRatio = m_teardropHeightPercent.GetDoubleValue() / 100.0;
if( !m_teardropMaxHeight.IsIndeterminate() )
targetParams->m_TdMaxWidth = m_teardropMaxHeight.GetIntValue();
if( m_rbStraightLines->GetValue() )
{
targetParams->m_CurveSegCount = 0;
}
else if( m_rbCurved->GetValue() )
{
if( !m_curvePoints.IsIndeterminate() )
targetParams->m_CurveSegCount = m_curvePoints.GetIntValue();
else if( targetParams->m_CurveSegCount == 0 )
targetParams->m_CurveSegCount = 5;
}
}
void DIALOG_GLOBAL_EDIT_TEARDROPS::processItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem )
{
BOARD_DESIGN_SETTINGS& brdSettings = m_brd->GetDesignSettings();
TEARDROP_PARAMETERS* targetParams = nullptr;
if( aItem->Type() == PCB_PAD_T )
targetParams = &static_cast<PAD*>( aItem )->GetTeardropParams();
else if( aItem->Type() == PCB_VIA_T )
targetParams = &static_cast<PCB_VIA*>( aItem )->GetTeardropParams();
else
return;
aCommit->Stage( aItem, CHT_MODIFY );
if( m_removeTeardrops->GetValue() )
{
targetParams->m_Enabled = false;
}
else if( m_addTeardrops->GetValue() )
{
if( TEARDROP_MANAGER::IsRound( aItem ) )
*targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_ROUND );
else
*targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_RECT );
targetParams->m_Enabled = true;
}
else if( m_specifiedValues->GetValue() )
{
setSpecifiedParams( targetParams );
if( !m_existingFilter->GetValue() )
targetParams->m_Enabled = true;
}
}
void DIALOG_GLOBAL_EDIT_TEARDROPS::visitItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem )
{
if( m_selectedItemsFilter->GetValue() )
{
if( !aItem->IsSelected() )
{
PCB_GROUP* group = aItem->GetParentGroup();
while( group && !group->IsSelected() )
group = group->GetParentGroup();
if( !group )
return;
}
}
if( m_netFilterOpt->GetValue() && m_netFilter->GetSelectedNetcode() >= 0 )
{
if( aItem->GetNetCode() != m_netFilter->GetSelectedNetcode() )
return;
}
if( m_netclassFilterOpt->GetValue() && !m_netclassFilter->GetStringSelection().IsEmpty() )
{
if( aItem->GetEffectiveNetClass()->GetName() != m_netclassFilter->GetStringSelection() )
return;
}
if( m_layerFilterOpt->GetValue() && m_layerFilter->GetLayerSelection() != UNDEFINED_LAYER )
{
if( aItem->GetLayer() != m_layerFilter->GetLayerSelection() )
return;
}
if( m_roundPadsFilter->GetValue() )
{
if( !TEARDROP_MANAGER::IsRound( aItem ) )
return;
}
if( m_existingFilter->GetValue() )
{
if( aItem->Type() == PCB_PAD_T )
{
if( !static_cast<PAD*>( aItem )->GetTeardropParams().m_Enabled )
return;
}
else if( aItem->Type() == PCB_VIA_T )
{
if( !static_cast<PCB_VIA*>( aItem )->GetTeardropParams().m_Enabled )
return;
}
}
processItem( aCommit, aItem );
}
bool DIALOG_GLOBAL_EDIT_TEARDROPS::TransferDataFromWindow()
{
m_brd->SetLegacyTeardrops( false );
BOARD_COMMIT commit( m_parent );
wxBusyCursor dummy;
if( m_vias->GetValue() )
{
for( PCB_TRACK* track : m_brd->Tracks() )
{
if ( track->Type() == PCB_VIA_T )
visitItem( &commit, track );
}
}
for( FOOTPRINT* footprint : m_brd->Footprints() )
{
for( PAD* pad : footprint->Pads() )
{
if( m_pthPads->GetValue() && pad->GetAttribute() == PAD_ATTRIB::PTH )
{
visitItem( &commit, pad );
}
else if( m_smdPads->GetValue() && ( pad->GetAttribute() == PAD_ATTRIB::SMD
|| pad->GetAttribute() == PAD_ATTRIB::CONN ) )
{
visitItem( &commit, pad );
}
}
}
if( m_trackToTrack->GetValue() )
{
TEARDROP_PARAMETERS_LIST* paramsList = m_brd->GetDesignSettings().GetTeadropParamsList();
TEARDROP_PARAMETERS* targetParams = paramsList->GetParameters( TARGET_TRACK );
TEARDROP_MANAGER teardropManager( m_brd, m_parent->GetToolManager() );
teardropManager.DeleteTrackToTrackTeardrops( commit );
if( m_removeTeardrops->GetValue() )
{
targetParams->m_Enabled = false; // JEY TODO: how does this get undone/redone?
}
else if( m_addTeardrops->GetValue() )
{
targetParams->m_Enabled = true; // JEY TODO: how does this get undone/redone?
teardropManager.AddTeardropsOnTracks( commit, nullptr, true );
}
}
// If there are no filters then a force-full-update is equivalent, and will be faster.
if( !m_netFilterOpt->GetValue()
&& !m_netclassFilterOpt->GetValue()
&& !m_layerFilterOpt->GetValue()
&& !m_roundPadsFilter->GetValue()
&& !m_existingFilter->GetValue()
&& !m_selectedItemsFilter->GetValue() )
{
commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS );
TEARDROP_MANAGER teardropMgr( m_brd, m_parent->GetToolManager() );
teardropMgr.UpdateTeardrops( commit, nullptr, nullptr, true /* forceFullUpdate */ );
commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS | APPEND_UNDO );
}
else
{
commit.Push( _( "Edit Teardrops" ) );
}
// Showing the unfilled, fully cross-hatched teardrops seems to be working fairly well, and
// accurate fills can then be manually generated by doing a zone fill.
//
// But here's the old code which allowed for either "draft" fills or an automatic full zone
// fill in case we decide the current situation isn't good enough:
#if 0
if( aFillAfter )
{
ZONE_FILLER filler( m_board, aCommit );
if( m_reporter )
filler.SetProgressReporter( m_reporter );
filler.Fill( m_board->Zones() );
if( aCommit )
aCommit->Push( _( "Edit Teardrops" ), APPEND_UNDO );
}
else
{
// Fill raw teardrop shapes. This is a rough calculation, just to show a filled
// shape on screen without the (potentially large) performance hit of a zone refill
int epsilon = pcbIUScale.mmToIU( 0.001 );
int allowed_error = pcbIUScale.mmToIU( 0.005 );
for( ZONE* zone: m_createdTdList )
{
int half_min_width = zone->GetMinThickness() / 2;
int numSegs = GetArcToSegmentCount( half_min_width, allowed_error, FULL_CIRCLE );
SHAPE_POLY_SET filledPolys = *zone->Outline();
filledPolys.Deflate( half_min_width - epsilon, numSegs );
// Re-inflate after pruning of areas that don't meet minimum-width criteria
if( half_min_width - epsilon > epsilon )
filledPolys.Inflate( half_min_width - epsilon, numSegs );
zone->SetFilledPolysList( zone->GetFirstLayer(), filledPolys );
}
}
#endif
return true;
}
int GLOBAL_EDIT_TOOL::EditTeardrops( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
DIALOG_GLOBAL_EDIT_TEARDROPS dlg( editFrame );
dlg.ShowQuasiModal(); // QuasiModal required for NET_SELECTOR
return 0;
}

Some files were not shown because too many files have changed in this diff Show More