Hook up EE_GRID_HELPER to some more tools.

Also implements EE_GRID_HELPER layers so that connectable things
snap to connectable things and graphics snap to graphics.

Fixes https://gitlab.com/kicad/code/kicad/issues/5641
This commit is contained in:
Jeff Young 2020-12-03 15:10:23 +00:00
parent e79df4a3ed
commit a19028a396
7 changed files with 105 additions and 38 deletions

View File

@ -75,4 +75,7 @@
///< The intersheets references suffix string
#define DEFAULT_IREF_SUFFIX "]"
///< Radius of snap "gravity well"
#define SNAP_RANGE 55
#endif

View File

@ -23,6 +23,15 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* EE_GRID_HELPER
*
* A helper class for doing grid and object snapping.
*
* It shares its roots with PCBNew's GRID_HELPER, but uses the layers architecture to split
* connectable items from graphic items.
*/
#include <functional>
using namespace std::placeholders;
@ -174,7 +183,8 @@ VECTOR2I EE_GRID_HELPER::AlignToWire( const VECTOR2I& aPoint, const SEG& aSeg )
return nearest;
}
VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, const EE_SELECTION& aItems )
VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, int aLayer,
const EE_SELECTION& aItems )
{
clearAnchors();
@ -184,9 +194,9 @@ VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, const EE_SEL
double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
double lineSnapMinCornerDistance = 50.0 / worldScale;
ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aLayer );
ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aLayer );
ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aLayer );
ANCHOR* best = NULL;
double minDist = std::numeric_limits<double>::max();
@ -245,20 +255,20 @@ std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
}
VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, SCH_ITEM* aDraggedItem )
VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aSkip )
{
EE_SELECTION draggedItems;
draggedItems.Add( aDraggedItem );
EE_SELECTION skipItems;
skipItems.Add( aSkip );
return BestSnapAnchor( aOrigin, LSET::AllLayersMask(), draggedItems );
return BestSnapAnchor( aOrigin, aLayer, skipItems );
}
VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer,
const EE_SELECTION& aSkip )
{
int snapDist = GetGrid().x;
int snapRange = snapDist;
int snapRange = SNAP_RANGE * IU_PER_MILS;
BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
VECTOR2I( snapRange, snapRange ) );
@ -268,7 +278,7 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aL
for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
computeAnchors( item, aOrigin );
ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayer );
VECTOR2I nearestGrid = m_enableGrid ? Align( aOrigin ) : aOrigin;
if( nearest )
@ -358,7 +368,7 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM* aItem, const VECTOR2I& aRefPos, b
{
std::vector<wxPoint> pts = aItem->GetConnectionPoints();
for( auto pt : pts )
for( const wxPoint& pt : pts )
addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
break;
@ -371,7 +381,7 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM* aItem, const VECTOR2I& aRefPos, b
EE_GRID_HELPER::ANCHOR* EE_GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int aFlags,
LSET aMatchLayers )
int aMatchLayer )
{
double minDist = std::numeric_limits<double>::max();
ANCHOR* best = NULL;
@ -381,6 +391,11 @@ EE_GRID_HELPER::ANCHOR* EE_GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int
if( ( aFlags & a.flags ) != aFlags )
continue;
if( aMatchLayer == LAYER_CONNECTABLE && !a.item->IsConnectable() )
continue;
else if( aMatchLayer == LAYER_GRAPHICS && a.item->IsConnectable() )
continue;
double dist = a.Distance( aPos );
if( dist < minDist )

View File

@ -23,6 +23,15 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* EE_GRID_HELPER
*
* A helper class for doing grid and object snapping.
*
* It shares its roots with PCBNew's GRID_HELPER, but uses the layers architecture to split
* connectable items from graphic items.
*/
#ifndef __GRID_HELPER_H
#define __GRID_HELPER_H
@ -35,7 +44,17 @@ class LSET;
class SCH_ITEM;
class SEG;
class EE_GRID_HELPER {
enum EE_GRID_HELPER_LAYERS : int
{
LAYER_ANY = SCH_LAYER_ID_END + 1,
LAYER_CONNECTABLE,
LAYER_GRAPHICS
};
class EE_GRID_HELPER
{
public:
EE_GRID_HELPER( TOOL_MANAGER* aToolMgr );
@ -61,11 +80,10 @@ public:
VECTOR2I AlignToWire( const VECTOR2I& aPoint, const SEG& aSeg );
VECTOR2I BestDragOrigin( const VECTOR2I& aMousePos, const EE_SELECTION& aItems );
VECTOR2I BestDragOrigin( const VECTOR2I& aMousePos, int aLayer, const EE_SELECTION& aItems );
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, SCH_ITEM* aDraggedItem );
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
const EE_SELECTION& aSkip = {} );
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aDraggedItem );
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, const EE_SELECTION& aSkip = {} );
void SetSkipPoint( const VECTOR2I& aPoint )
{
@ -119,7 +137,7 @@ private:
m_anchors.emplace_back( ANCHOR( aPos, aFlags, aItem ) );
}
ANCHOR* nearestAnchor( const VECTOR2I& aPos, int aFlags, LSET aMatchLayers );
ANCHOR* nearestAnchor( const VECTOR2I& aPos, int aFlags, int aMatchLayer );
/**
* computeAnchors inserts the local anchor points in to the grid helper for the specified

View File

@ -342,7 +342,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled )
{
// Check if we want to auto start wires
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(), nullptr );
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(),
LAYER_CONNECTABLE, nullptr );
if( m_frame->eeconfig()->m_Drawing.auto_start_wires
&& collector[0]->IsPointClickableAnchor( (wxPoint) snappedCursorPos ) )
@ -507,7 +508,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( collector.GetCount() == 1 && !modifier_enabled )
{
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(), nullptr );
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(),
LAYER_CONNECTABLE, nullptr );
if( m_frame->eeconfig()->m_Drawing.auto_start_wires
&& collector[0]->IsPointClickableAnchor( (wxPoint) snappedCursorPos ) )
@ -864,9 +866,11 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
// pin should select the symbol with this setting
// To avoid conflict with the auto-start wires option
EE_GRID_HELPER grid( m_toolMgr );
wxPoint cursorPos = wxPoint( grid.BestSnapAnchor( aPos, nullptr ) );
wxPoint cursorPos = wxPoint( grid.BestSnapAnchor( aPos, LAYER_CONNECTABLE,
nullptr ) );
if( !m_isSymbolEditor && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol
if( !m_isSymbolEditor
&& m_frame->eeconfig()->m_Selection.select_pin_selects_symbol
&& !other->IsPointClickableAnchor( cursorPos ) )
{
collector.Transfer( other );

View File

@ -24,6 +24,7 @@
#include "sch_drawing_tools.h"
#include "ee_selection_tool.h"
#include "ee_grid_helper.h"
#include <ee_actions.h>
#include <sch_edit_frame.h>
#include <project.h>
@ -807,15 +808,19 @@ SCH_SHEET_PIN* SCH_DRAWING_TOOLS::createSheetPin( SCH_SHEET* aSheet, SCH_HIERLAB
int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
{
SCH_ITEM* item = nullptr;
KIGFX::VIEW_CONTROLS* controls = getViewControls();
EE_GRID_HELPER grid( m_toolMgr );
bool isImportMode = aEvent.IsAction( &EE_ACTIONS::importSheetPin );
bool isText = aEvent.IsAction( &EE_ACTIONS::placeSchematicText );
bool isGlobalLabel = aEvent.IsAction( &EE_ACTIONS::placeGlobalLabel );
bool isHierLabel = aEvent.IsAction( &EE_ACTIONS::placeHierLabel );
bool isNetLabel = aEvent.IsAction( &EE_ACTIONS::placeLabel );
KICAD_T type = aEvent.Parameter<KICAD_T>();
int snapLayer = isText ? LAYER_GRAPHICS : LAYER_CONNECTABLE;
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
getViewControls()->ShowCursor( true );
controls->ShowCursor( true );
std::string tool = aEvent.GetCommandStr().get();
m_frame->PushTool( tool );
@ -849,8 +854,11 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
while( TOOL_EVENT* evt = Wait() )
{
setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
VECTOR2I cursorPos = grid.BestSnapAnchor( controls->GetCursorPosition( false ), snapLayer,
item );
auto cleanup =
[&] ()
@ -956,7 +964,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
}
// Restore cursor after dialog
getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
controls->WarpCursor( controls->GetCursorPosition(), true );
if( item )
{
@ -969,7 +977,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
setCursor();
}
getViewControls()->SetCursorPosition( cursorPos, false );
controls->SetCursorPosition( cursorPos, false );
}
// ... and second click places:
@ -1020,8 +1028,8 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
}
// Enable autopanning and cursor capture only when there is a footprint to be placed
getViewControls()->SetAutoPan( item != nullptr );
getViewControls()->CaptureCursor( item != nullptr );
controls->SetAutoPan( item != nullptr );
controls->CaptureCursor( item != nullptr );
}
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );

View File

@ -503,10 +503,13 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType,
while( TOOL_EVENT* evt = Wait() )
{
setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
wxPoint cursorPos = wxPoint( grid.BestSnapAnchor(
evt->IsPrime() ? evt->Position() : controls->GetMousePosition(), nullptr ) );
grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
wxPoint cursorPos = evt->IsPrime() ? (wxPoint) evt->Position()
: (wxPoint) controls->GetMousePosition();
cursorPos = (wxPoint) grid.BestSnapAnchor( cursorPos, LAYER_CONNECTABLE, nullptr );
controls->ForceCursorPosition( true, cursorPos );
bool forceHV = m_frame->eeconfig()->m_Drawing.hv_lines_only;
@ -516,7 +519,7 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType,
{
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
for( auto wire : m_wires )
for( SCH_LINE* wire : m_wires )
delete wire;
m_wires.clear();

View File

@ -172,6 +172,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
bool chain_commands = false;
TOOL_EVENT* evt = const_cast<TOOL_EVENT*>( &aEvent );
VECTOR2I prevPos;
int snapLayer = UNDEFINED_LAYER;
m_cursor = controls->GetCursorPosition();
@ -247,6 +248,21 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
//
for( EDA_ITEM* item : selection )
{
if( static_cast<SCH_ITEM*>( item )->IsConnectable() )
{
if( snapLayer == LAYER_GRAPHICS )
snapLayer = LAYER_ANY;
else
snapLayer = LAYER_CONNECTABLE;
}
else
{
if( snapLayer == LAYER_CONNECTABLE )
snapLayer = LAYER_ANY;
else
snapLayer = LAYER_GRAPHICS;
}
if( item->IsNew() )
{
if( item->HasFlag( TEMP_SELECTED ) && m_isDragOperation )
@ -317,7 +333,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
if( m_frame->GetMoveWarpsCursor() )
{
// User wants to warp the mouse
m_cursor = grid.BestDragOrigin( m_cursor, selection );
m_cursor = grid.BestDragOrigin( m_cursor, snapLayer, selection );
}
else
{
@ -338,7 +354,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
// Follow the mouse
//
m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ),
LSET::AllLayersMask(), selection );
snapLayer, selection );
VECTOR2I delta( m_cursor - prevPos );
m_anchorPos = m_cursor;