pcbnew: via placement tool, initial version

This commit is contained in:
Tomasz Włostowski 2017-04-22 17:46:31 +02:00
parent bd960f0e5c
commit 3b7b0603b6
12 changed files with 272 additions and 129 deletions

View File

@ -256,7 +256,7 @@ public:
DLIST_ITERATOR_WRAPPER<TRACK> Tracks() { return DLIST_ITERATOR_WRAPPER<TRACK>(m_Track); }
DLIST_ITERATOR_WRAPPER<MODULE> Modules() { return DLIST_ITERATOR_WRAPPER<MODULE>(m_Modules); }
DLIST_ITERATOR_WRAPPER<BOARD_ITEM> Drawings() { return DLIST_ITERATOR_WRAPPER<BOARD_ITEM>(m_Drawings); }
ZONE_CONTAINERS& Zones() { return m_ZoneDescriptorList; }
// will be deprecated as soon as append board functionality is fixed

View File

@ -990,24 +990,25 @@ void VIA::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, const w
void VIA::ViewGetLayers( int aLayers[], int& aCount ) const
{
aLayers[0] = LAYER_VIAS_HOLES;
aCount = 2;
aLayers[1] = GetNetnameLayer( m_Layer );
aCount = 3;
// Just show it on common via & via holes layers
switch( GetViaType() )
{
case VIA_THROUGH:
aLayers[1] = LAYER_VIA_THROUGH;
aLayers[2] = LAYER_VIA_THROUGH;
break;
case VIA_BLIND_BURIED:
aLayers[1] = LAYER_VIA_BBLIND;
aLayers[2] = m_Layer;
aLayers[3] = m_BottomLayer;
aLayers[2] = LAYER_VIA_BBLIND;
aLayers[3] = m_Layer;
aLayers[4] = m_BottomLayer;
aCount += 2;
break;
case VIA_MICROVIA:
aLayers[1] = LAYER_VIA_MICROVIA;
aLayers[2] = LAYER_VIA_MICROVIA;
break;
default:

View File

@ -30,6 +30,7 @@ enum pcbnew_ids
ID_PCB_MODULE_BUTT,
ID_TRACK_BUTT,
ID_PCB_ZONES_BUTT,
ID_PCB_DRAW_VIA_BUTT,
ID_PCB_KEEPOUT_AREA_BUTT,
ID_PCB_ADD_LINE_BUTT,
ID_PCB_CIRCLE_BUTT,

View File

@ -440,7 +440,10 @@ void PCB_EDIT_FRAME::ReCreateVToolbar()
_( "Add footprints" ), wxITEM_CHECK );
m_drawToolBar->AddTool( ID_TRACK_BUTT, wxEmptyString, KiBitmap( add_tracks_xpm ),
_( "Add tracks and vias" ), wxITEM_CHECK );
_( "Route tracks" ), wxITEM_CHECK );
m_drawToolBar->AddTool( ID_PCB_DRAW_VIA_BUTT, wxEmptyString, KiBitmap( add_via_xpm ),
_( "Add vias" ), wxITEM_CHECK );
m_drawToolBar->AddTool( ID_PCB_ZONES_BUTT, wxEmptyString, KiBitmap( add_zone_xpm ),
_( "Add filled zones" ), wxITEM_CHECK );

View File

@ -88,7 +88,11 @@ TOOL_ACTION PCB_ACTIONS::drawZone( "pcbnew.InteractiveDrawing.zone",
AS_GLOBAL, 0,
_( "Add Filled Zone" ), _( "Add a filled zone" ), NULL, AF_ACTIVATE );
TOOL_ACTION PCB_ACTIONS::drawZoneKeepout( "pcbnew.InteractiveDrawing.keepout",
TOOL_ACTION PCB_ACTIONS::drawVia( "pcbnew.InteractiveDrawing.via",
AS_GLOBAL, 0,
_( "Add Vias" ), _( "Add free-stanging vias" ), NULL, AF_ACTIVATE );
TOOL_ACTION PCB_ACTIONS::drawKeepout( "pcbnew.InteractiveDrawing.keepout",
AS_GLOBAL, 0,
_( "Add Keepout Area" ), _( "Add a keepout area" ), NULL, AF_ACTIVATE );
@ -1392,6 +1396,136 @@ void DRAWING_TOOL::make45DegLine( DRAWSEGMENT* aSegment, DRAWSEGMENT* aHelper )
}
}
int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
{
struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
{
int findStitchedZoneNet( VIA *aVia )
{
const auto pos = aVia->GetPosition();
const auto lset = aVia->GetLayerSet();
for ( auto tv : m_board->Tracks() ) // fixme: move to BOARD class?
if( tv->HitTest(pos) && (tv->GetLayerSet() &
lset ).any() )
return -1;
for ( auto mod : m_board->Modules() )
for ( auto pad : mod->PadsIter() )
if( pad->HitTest(pos) && (pad->GetLayerSet() &
lset ).any() )
return -1;
std::set<ZONE_CONTAINER* > foundZones;
for( auto zone : m_board->Zones() )
{
if ( zone->HitTestFilledArea ( pos ) )
{
foundZones.insert ( zone );
}
}
for( auto z : foundZones )
{
if ( m_frame->GetActiveLayer() == z->GetLayer() )
return z->GetNetCode();
}
return -1;
}
bool PlaceItem( BOARD_ITEM *aItem ) override
{
auto via = static_cast<VIA*>(aItem);
int newNet = findStitchedZoneNet(via);
if(newNet > 0 )
via->SetNetCode( newNet );
return false;
}
std::unique_ptr<BOARD_ITEM> CreateItem() override
{
auto& ds = m_board->GetDesignSettings();
VIA* via = new VIA ( m_board );
via->SetNetCode( 0 );
via->SetViaType( ds.m_CurrentViaType );
// for microvias, the size and hole will be changed later.
via->SetWidth( ds.GetCurrentViaSize());
via->SetDrill( ds.GetCurrentViaDrill() );
// Usual via is from copper to component.
// layer pair is B_Cu and F_Cu.
via->SetLayerPair( B_Cu, F_Cu );
LAYER_ID first_layer = m_frame->GetActiveLayer();
LAYER_ID last_layer;
// prepare switch to new active layer:
if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
else
last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
// Adjust the actual via layer pair
switch( via->GetViaType() )
{
case VIA_BLIND_BURIED:
via->SetLayerPair( first_layer, last_layer );
break;
case VIA_MICROVIA: // from external to the near neighbor inner layer
{
LAYER_ID last_inner_layer = ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
if( first_layer == B_Cu )
last_layer = last_inner_layer;
else if( first_layer == F_Cu )
last_layer = In1_Cu;
else if( first_layer == last_inner_layer )
last_layer = B_Cu;
else if( first_layer == In1_Cu )
last_layer = F_Cu;
// else error: will be removed later
via->SetLayerPair( first_layer, last_layer );
// Update diameter and hole size, which where set previously
// for normal vias
NETINFO_ITEM* net = via->GetNet();
if( net )
{
via->SetWidth( net->GetMicroViaSize() );
via->SetDrill( net->GetMicroViaDrillSize() );
}
}
break;
default:
break;
}
return std::unique_ptr<BOARD_ITEM>(via);
}
};
VIA_PLACER placer;
frame()->SetToolID( ID_PCB_DRAW_VIA_BUTT, wxCURSOR_PENCIL, _( "Add vias" ) );
doInteractiveItemPlacement( &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK | IPO_ROTATE | IPO_FLIP | IPO_PROPERTIES );
frame()->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
return 0;
}
void DRAWING_TOOL::SetTransitions()
{
@ -1403,6 +1537,7 @@ void DRAWING_TOOL::SetTransitions()
Go( &DRAWING_TOOL::DrawZoneKeepout, PCB_ACTIONS::drawZoneKeepout.MakeEvent() );
Go( &DRAWING_TOOL::DrawZoneCutout, PCB_ACTIONS::drawZoneCutout.MakeEvent() );
Go( &DRAWING_TOOL::DrawSimilarZone, PCB_ACTIONS::drawSimilarZone.MakeEvent() );
Go( &DRAWING_TOOL::DrawVia, PCB_ACTIONS::drawVia.MakeEvent() );
Go( &DRAWING_TOOL::PlaceText, PCB_ACTIONS::placeText.MakeEvent() );
Go( &DRAWING_TOOL::PlaceDXF, PCB_ACTIONS::placeDXF.MakeEvent() );
Go( &DRAWING_TOOL::SetAnchor, PCB_ACTIONS::setAnchor.MakeEvent() );

View File

@ -135,6 +135,8 @@ public:
*/
int DrawZone( const TOOL_EVENT& aEvent );
int DrawVia( const TOOL_EVENT& aEvent );
/**
* Function DrawZoneKeepout()
* Starts interactively drawing a keepout area. After invoking the function an area settings

View File

@ -201,22 +201,32 @@ int MICROWAVE_TOOL::addMicrowaveFootprint( const TOOL_EVENT& aEvent )
frame.SetToolID( info.toolId, wxCURSOR_PENCIL, info.name );
ITEM_CREATOR moduleCreator = [this, &info] ( const TOOL_EVENT& aAddingEvent )
struct MICROWAVE_PLACER : public INTERACTIVE_PLACER_BASE
{
auto module = info.creatorFunc();
MICROWAVE_TOOL_INFO& m_info;
// Module has been added in the legacy backend,
// so we have to remove it before committing the change
// @todo LEGACY
if( module )
MICROWAVE_PLACER( MICROWAVE_TOOL_INFO& aInfo ) :
m_info( aInfo ) {};
std::unique_ptr<BOARD_ITEM> CreateItem() override
{
board()->Remove( module.get() );
}
auto module = m_info.creatorFunc();
return module;
// Module has been added in the legacy backend,
// so we have to remove it before committing the change
// @todo LEGACY
if( module )
{
m_board->Remove( module.get() );
}
return std::unique_ptr<BOARD_ITEM>( module.release() );
}
};
doInteractiveItemPlacement( moduleCreator, _( "Place microwave feature" ) );
MICROWAVE_PLACER placer ( info );
doInteractiveItemPlacement( &placer, _( "Place microwave feature" ) );
frame.SetNoToolSelected();

View File

@ -95,85 +95,28 @@ void MODULE_EDITOR_TOOLS::Reset( RESET_REASON aReason )
}
int MODULE_EDITOR_TOOLS::PlacePad( const TOOL_EVENT& aEvent )
{
struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
{
std::unique_ptr<BOARD_ITEM> CreateItem() override
{
D_PAD* pad = new D_PAD ( m_board->m_Modules );
m_frame->Import_Pad_Settings( pad, false ); // use the global settings for pad
// pad->IncrementPadName( true, true );
return std::unique_ptr<BOARD_ITEM>( pad );
}
};
PAD_PLACER placer;
frame()->SetToolID( ID_MODEDIT_PAD_TOOL, wxCURSOR_PENCIL, _( "Add pads" ) );
assert( board()->m_Modules );
D_PAD* pad = new D_PAD( board()->m_Modules );
frame()->Import_Pad_Settings( pad, false ); // use the global settings for pad
doInteractiveItemPlacement( &placer, _( "Place pad" ), IPO_REPEAT | IPO_SINGLE_CLICK | IPO_ROTATE | IPO_FLIP | IPO_PROPERTIES );
VECTOR2I cursorPos = getViewControls()->GetCursorPosition();
pad->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( view() );
preview.Add( pad );
view()->Add( &preview );
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
getViewControls()->ShowCursor( true );
getViewControls()->SetSnapping( true );
Activate();
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
cursorPos = getViewControls()->GetCursorPosition();
if( evt->IsMotion() )
{
pad->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
view()->Update( &preview );
}
else if( evt->Category() == TC_COMMAND )
{
if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
{
const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
*frame(), *evt );
pad->Rotate( pad->GetPosition(), rotationAngle );
view()->Update( &preview );
}
else if( evt->IsAction( &PCB_ACTIONS::flip ) )
{
pad->Flip( pad->GetPosition() );
view()->Update( &preview );
}
else if( evt->IsCancel() || evt->IsActivate() )
{
preview.Clear();
delete pad;
break;
}
}
else if( evt->IsClick( BUT_LEFT ) )
{
BOARD_COMMIT commit( frame() );
commit.Add( pad );
board()->m_Status_Pcb = 0; // I have no clue why, but it is done in the legacy view
// Take the next available pad number
pad->IncrementPadName( true, true );
// Handle the view aspect
preview.Remove( pad );
commit.Push( _( "Add a pad" ) );
// Start placing next pad
pad = new D_PAD( board()->m_Modules );
frame()->Import_Pad_Settings( pad, false );
pad->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
preview.Add( pad );
}
}
view()->Remove( &preview );
frame()->SetNoToolSelected();
return 0;

View File

@ -58,6 +58,9 @@ boost::optional<TOOL_EVENT> PCB_ACTIONS::TranslateLegacyId( int aId )
case ID_PCB_ZONES_BUTT:
return PCB_ACTIONS::drawZone.MakeEvent();
case ID_PCB_DRAW_VIA_BUTT:
return PCB_ACTIONS::drawVia.MakeEvent();
case ID_PCB_KEEPOUT_AREA_BUTT:
return PCB_ACTIONS::drawZoneKeepout.MakeEvent();

View File

@ -139,6 +139,9 @@ public:
/// Activation of the drawing tool (drawing a ZONE)
static TOOL_ACTION drawZone;
/// Activation of the drawing tool (drawing a VIA)
static TOOL_ACTION drawVia;
/// Activation of the drawing tool (drawing a keepout area)
static TOOL_ACTION drawZoneKeepout;

View File

@ -35,36 +35,44 @@
#include "pcb_actions.h"
#include "tool_event_utils.h"
void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
const wxString& aCommitMessage )
void PCB_TOOL::doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE *aPlacer,
const wxString& aCommitMessage,
int aOptions )
{
using namespace std::placeholders;
KIGFX::VIEW& view = *getView();
KIGFX::VIEW_CONTROLS& controls = *getViewControls();
auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
std::unique_ptr<BOARD_ITEM> newItem;
Activate();
BOARD_COMMIT commit( &frame );
BOARD_COMMIT commit( frame() );
GetManager()->RunAction( PCB_ACTIONS::selectionClear, true );
// do not capture or auto-pan until we start placing an item
controls.ShowCursor( true );
controls.SetSnapping( true );
controls()->ShowCursor( true );
controls()->SetSnapping( true );
// Add a VIEW_GROUP that serves as a preview for the new item
SELECTION preview;
view.Add( &preview );
view()->Add( &preview );
aPlacer->m_board = board();
aPlacer->m_frame = frame();
if ( aOptions & IPO_SINGLE_CLICK )
{
VECTOR2I cursorPos = controls()->GetCursorPosition();
newItem = aPlacer->CreateItem();
newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
preview.Add( newItem.get() );
}
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
VECTOR2I cursorPos = controls.GetCursorPosition();
VECTOR2I cursorPos = controls()->GetCursorPosition();
if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) )
{
@ -75,9 +83,12 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
preview.Clear();
controls.SetAutoPan( false );
controls.CaptureCursor( false );
controls.ShowCursor( true );
if ( aOptions & IPO_SINGLE_CLICK )
break;
controls()->SetAutoPan( false );
controls()->CaptureCursor( false );
controls()->ShowCursor( true );
}
else
{
@ -93,14 +104,14 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
if( !newItem )
{
// create the item if possible
newItem = aItemCreator( *evt );
newItem = aPlacer->CreateItem();
// no item created, so wait for another click
if( !newItem )
continue;
controls.CaptureCursor( true );
controls.SetAutoPan( true );
controls()->CaptureCursor( true );
controls()->SetAutoPan( true );
newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
@ -119,6 +130,8 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
newItem->ClearFlags();
preview.Remove( newItem.get() );
aPlacer->PlaceItem( newItem.get() );
if( newItem->Type() == PCB_MODULE_T )
{
auto module = dyn_cast<MODULE*>( newItem.get() );
@ -128,9 +141,22 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
commit.Add( newItem.release() );
commit.Push( aCommitMessage );
controls.CaptureCursor( false );
controls.SetAutoPan( false );
controls.ShowCursor( true );
controls()->CaptureCursor( false );
controls()->SetAutoPan( false );
controls()->ShowCursor( true );
if (! ( aOptions & IPO_REPEAT ) )
break;
if ( aOptions & IPO_SINGLE_CLICK )
{
VECTOR2I cursorPos = controls()->GetCursorPosition();
newItem = aPlacer->CreateItem();
newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
preview.Add( newItem.get() );
}
}
}
@ -141,17 +167,17 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
* it around, eg rotate and flip
*/
if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
{
const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
frame, *evt );
*frame(), *evt );
newItem->Rotate( newItem->GetPosition(), rotationAngle );
view.Update( &preview );
view()->Update( &preview );
}
else if( evt->IsAction( &PCB_ACTIONS::flip ) )
else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
{
newItem->Flip( newItem->GetPosition() );
view.Update( &preview );
view()->Update( &preview );
}
}
@ -161,9 +187,9 @@ void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
// Show a preview of the item
view.Update( &preview );
view()->Update( &preview );
}
}
view.Remove( &preview );
view()->Remove( &preview );
}

View File

@ -42,6 +42,19 @@
* A tool operating on a BOARD object
**/
class PCB_TOOL;
class PCB_EDIT_FRAME;
struct INTERACTIVE_PLACER_BASE
{
virtual std::unique_ptr<BOARD_ITEM> CreateItem() = 0;
virtual bool PlaceItem( BOARD_ITEM *aItem ) { return false; }
PCB_EDIT_FRAME *m_frame;
BOARD *m_board;
};
class PCB_TOOL : public TOOL_INTERACTIVE
{
public:
@ -82,13 +95,14 @@ public:
protected:
/**
* Callable that returns a new board item.
*
* The event that triggered it is provided, so you can check modifier
* keys, position, etc, if required
*/
using ITEM_CREATOR = std::function< std::unique_ptr< BOARD_ITEM >( const TOOL_EVENT& aEvt ) >;
enum INTERACTIVE_PLACEMENT_OPTIONS {
IPO_ROTATE = 1,
IPO_FLIP = 2,
IPO_PROPERTIES = 4,
IPO_SINGLE_CLICK = 8,
IPO_REPEAT = 16
};
/**
* Helper function for performing a common interactive idiom:
@ -102,10 +116,12 @@ protected:
* @param aItemCreator the callable that will attempt to create the item
* @param aCommitMessage the message used on a successful commit
*/
void doInteractiveItemPlacement( ITEM_CREATOR aItemCreator,
const wxString& aCommitMessage );
void doInteractiveItemPlacement( INTERACTIVE_PLACER_BASE *aPlacer,
const wxString& aCommitMessage,
int aOptions = IPO_ROTATE | IPO_FLIP | IPO_REPEAT );
KIGFX::VIEW* view() const { return getView(); }
KIGFX::VIEW_CONTROLS* controls() const { return getViewControls(); }
PCB_EDIT_FRAME* frame() const { return getEditFrame<PCB_EDIT_FRAME>(); }
BOARD* board() const { return getModel<BOARD>(); }