2015-02-18 00:29:54 +00:00
/*
* KiRouter - a push - and - ( sometimes - ) shove PCB router
*
* Copyright ( C ) 2013 CERN
2021-07-19 23:56:05 +00:00
* Copyright ( C ) 2016 - 2021 KiCad Developers , see AUTHORS . txt for contributors .
2015-02-18 00:29:54 +00:00
* Author : Tomasz Wlostowski < tomasz . wlostowski @ cern . ch >
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
2016-06-29 10:23:11 +00:00
# include <functional>
using namespace std : : placeholders ;
2015-02-18 00:29:54 +00:00
# include <pcb_painter.h>
2020-01-13 01:44:19 +00:00
# include <pcbnew_settings.h>
2015-02-18 00:29:54 +00:00
2021-01-16 23:17:32 +00:00
# include <tools/pcb_grid_helper.h>
2021-06-03 12:11:15 +00:00
# include <wx/log.h>
2015-02-18 00:29:54 +00:00
2016-08-15 15:16:47 +00:00
# include "pns_kicad_iface.h"
2015-02-18 00:29:54 +00:00
# include "pns_tool_base.h"
2021-03-21 11:24:55 +00:00
# include "pns_arc.h"
2016-08-15 15:16:51 +00:00
# include "pns_solid.h"
2016-08-15 15:16:47 +00:00
2016-12-02 17:58:12 +00:00
2015-02-18 00:29:54 +00:00
using namespace KIGFX ;
2016-08-29 14:38:11 +00:00
namespace PNS {
2015-02-18 00:29:54 +00:00
2016-08-29 17:31:13 +00:00
TOOL_BASE : : TOOL_BASE ( const std : : string & aToolName ) :
2019-05-12 11:49:58 +00:00
PCB_TOOL_BASE ( aToolName )
2015-02-18 00:29:54 +00:00
{
2016-09-29 16:59:11 +00:00
m_gridHelper = nullptr ;
m_iface = nullptr ;
m_router = nullptr ;
2019-05-17 00:13:21 +00:00
m_cancelled = false ;
2016-08-17 13:09:48 +00:00
2016-09-29 16:59:11 +00:00
m_startItem = nullptr ;
2015-03-10 14:38:27 +00:00
2016-09-29 16:59:11 +00:00
m_endItem = nullptr ;
m_gridHelper = nullptr ;
2020-01-11 00:11:31 +00:00
m_cancelled = false ;
2015-02-18 00:29:54 +00:00
}
2016-08-29 17:31:13 +00:00
TOOL_BASE : : ~ TOOL_BASE ( )
2015-02-18 00:29:54 +00:00
{
2015-11-03 16:19:42 +00:00
delete m_gridHelper ;
2016-08-17 13:09:48 +00:00
delete m_iface ;
delete m_router ;
2015-02-18 00:29:54 +00:00
}
2016-08-29 17:31:13 +00:00
void TOOL_BASE : : Reset ( RESET_REASON aReason )
2015-02-18 00:29:54 +00:00
{
2016-08-17 13:09:48 +00:00
delete m_gridHelper ;
delete m_iface ;
delete m_router ;
2016-08-15 15:16:47 +00:00
m_iface = new PNS_KICAD_IFACE ;
2017-08-03 15:53:07 +00:00
m_iface - > SetBoard ( board ( ) ) ;
2016-08-15 15:16:47 +00:00
m_iface - > SetView ( getView ( ) ) ;
2017-10-31 11:03:58 +00:00
m_iface - > SetHostTool ( this ) ;
2016-08-15 15:16:47 +00:00
2016-08-29 17:31:13 +00:00
m_router = new ROUTER ;
2017-08-03 15:53:07 +00:00
m_router - > SetInterface ( m_iface ) ;
2015-02-18 00:29:54 +00:00
m_router - > ClearWorld ( ) ;
m_router - > SyncWorld ( ) ;
2020-01-13 01:44:19 +00:00
2015-02-18 00:29:54 +00:00
m_router - > UpdateSizes ( m_savedSizes ) ;
2015-11-03 16:19:42 +00:00
2020-05-06 01:43:37 +00:00
PCBNEW_SETTINGS * settings = frame ( ) - > GetPcbNewSettings ( ) ;
2020-02-28 03:53:00 +00:00
if ( ! settings - > m_PnsSettings )
settings - > m_PnsSettings = std : : make_unique < ROUTING_SETTINGS > ( settings , " tools.pns " ) ;
m_router - > LoadSettings ( settings - > m_PnsSettings . get ( ) ) ;
2020-01-13 01:44:19 +00:00
2021-01-16 23:17:32 +00:00
m_gridHelper = new PCB_GRID_HELPER ( m_toolMgr , frame ( ) - > GetMagneticItemsSettings ( ) ) ;
2015-02-18 00:29:54 +00:00
}
2015-02-18 16:53:46 +00:00
2019-03-17 03:34:08 +00:00
ITEM * TOOL_BASE : : pickSingleItem ( const VECTOR2I & aWhere , int aNet , int aLayer , bool aIgnorePads ,
2020-07-02 21:52:37 +00:00
const std : : vector < ITEM * > aAvoidItems )
2015-02-18 00:29:54 +00:00
{
2020-11-10 23:12:28 +00:00
int tl = aLayer > 0 ? aLayer : getView ( ) - > GetTopLayer ( ) ;
2015-02-18 00:29:54 +00:00
2018-04-08 20:20:51 +00:00
static const int candidateCount = 5 ;
ITEM * prioritized [ candidateCount ] ;
2020-07-02 21:52:37 +00:00
SEG : : ecoord dist [ candidateCount ] ;
2015-02-18 00:29:54 +00:00
2018-04-08 20:20:51 +00:00
for ( int i = 0 ; i < candidateCount ; i + + )
2018-05-03 16:31:00 +00:00
{
2020-07-02 21:52:37 +00:00
prioritized [ i ] = nullptr ;
dist [ i ] = VECTOR2I : : ECOORD_MAX ;
2018-05-03 16:31:00 +00:00
}
2015-02-18 00:29:54 +00:00
2016-08-29 17:31:13 +00:00
ITEM_SET candidates = m_router - > QueryHoverItems ( aWhere ) ;
2015-02-18 00:29:54 +00:00
2021-06-06 18:16:31 +00:00
if ( candidates . Empty ( ) )
candidates = m_router - > QueryHoverItems ( aWhere , true ) ;
2016-08-29 17:31:13 +00:00
for ( ITEM * item : candidates . Items ( ) )
2015-02-18 00:29:54 +00:00
{
2018-02-03 09:39:46 +00:00
if ( ! item - > IsRoutable ( ) )
continue ;
2015-02-18 00:29:54 +00:00
if ( ! IsCopperLayer ( item - > Layers ( ) . Start ( ) ) )
continue ;
2019-08-15 07:21:48 +00:00
if ( ! m_iface - > IsAnyLayerVisible ( item - > Layers ( ) ) )
continue ;
2020-09-26 13:42:40 +00:00
if ( alg : : contains ( aAvoidItems , item ) )
2019-03-17 03:34:08 +00:00
continue ;
2015-02-18 00:29:54 +00:00
// fixme: this causes flicker with live loop removal...
//if( item->Parent() && !item->Parent()->ViewIsVisible() )
// continue;
2022-09-05 18:44:41 +00:00
if ( item - > OfKind ( ITEM : : SOLID_T ) & & aIgnorePads )
{
continue ;
}
else if ( aNet < = 0 | | item - > Net ( ) = = aNet )
2015-02-18 00:29:54 +00:00
{
2016-08-29 17:31:13 +00:00
if ( item - > OfKind ( ITEM : : VIA_T | ITEM : : SOLID_T ) )
2015-02-18 00:29:54 +00:00
{
2020-11-10 23:12:28 +00:00
SEG : : ecoord d = ( item - > Shape ( ) - > Centre ( ) - aWhere ) . SquaredEuclideanNorm ( ) ;
2018-05-03 16:31:00 +00:00
2020-11-10 23:12:28 +00:00
if ( d < dist [ 2 ] )
2018-05-03 16:31:00 +00:00
{
2015-02-18 00:29:54 +00:00
prioritized [ 2 ] = item ;
2020-11-10 23:12:28 +00:00
dist [ 2 ] = d ;
2018-05-03 16:31:00 +00:00
}
2020-11-10 23:12:28 +00:00
if ( item - > Layers ( ) . Overlaps ( tl ) & & d < dist [ 0 ] )
2018-05-03 16:31:00 +00:00
{
2015-02-18 00:29:54 +00:00
prioritized [ 0 ] = item ;
2020-11-10 23:12:28 +00:00
dist [ 0 ] = d ;
2018-05-03 16:31:00 +00:00
}
2015-02-18 00:29:54 +00:00
}
2020-11-10 23:12:28 +00:00
else // ITEM::SEGMENT_T | ITEM::ARC_T
2015-02-18 00:29:54 +00:00
{
2020-11-10 23:12:28 +00:00
LINKED_ITEM * li = static_cast < LINKED_ITEM * > ( item ) ;
SEG : : ecoord d = std : : min ( ( li - > Anchor ( 0 ) - aWhere ) . SquaredEuclideanNorm ( ) ,
( li - > Anchor ( 1 ) - aWhere ) . SquaredEuclideanNorm ( ) ) ;
if ( d < dist [ 3 ] )
{
2015-02-18 00:29:54 +00:00
prioritized [ 3 ] = item ;
2020-11-10 23:12:28 +00:00
dist [ 3 ] = d ;
}
if ( item - > Layers ( ) . Overlaps ( tl ) & & d < dist [ 1 ] )
{
2015-02-18 00:29:54 +00:00
prioritized [ 1 ] = item ;
2020-11-10 23:12:28 +00:00
dist [ 1 ] = d ;
}
2015-02-18 00:29:54 +00:00
}
}
2022-09-05 18:44:41 +00:00
else if ( item - > OfKind ( ITEM : : SOLID_T ) & & item - > IsFreePad ( ) )
{
// Allow free pads only when already inside pad
if ( item - > Shape ( ) - > Collide ( aWhere ) )
{
prioritized [ 0 ] = item ;
dist [ 0 ] = 0 ;
}
}
2018-04-08 20:20:51 +00:00
else if ( item - > Net ( ) = = 0 & & m_router - > Settings ( ) . Mode ( ) = = RM_MarkObstacles )
{
2021-07-19 23:56:05 +00:00
// Allow unconnected items as last resort in RM_MarkObstacles mode
2018-04-08 20:20:51 +00:00
if ( item - > Layers ( ) . Overlaps ( tl ) )
prioritized [ 4 ] = item ;
}
2015-02-18 00:29:54 +00:00
}
2021-07-19 23:56:05 +00:00
ITEM * rv = nullptr ;
2015-02-18 00:29:54 +00:00
2021-12-26 00:36:12 +00:00
bool highContrast = ( frame ( ) - > GetDisplayOptions ( ) . m_ContrastModeDisplay ! = HIGH_CONTRAST_MODE : : NORMAL ) ;
2020-07-11 17:40:23 +00:00
2018-04-08 20:20:51 +00:00
for ( int i = 0 ; i < candidateCount ; i + + )
2015-02-18 00:29:54 +00:00
{
2016-08-29 17:31:13 +00:00
ITEM * item = prioritized [ i ] ;
2015-02-18 00:29:54 +00:00
2020-07-11 17:40:23 +00:00
if ( highContrast & & item & & ! item - > Layers ( ) . Overlaps ( tl ) )
item = nullptr ;
2015-02-18 00:29:54 +00:00
2018-10-20 14:57:54 +00:00
if ( item & & ( aLayer < 0 | | item - > Layers ( ) . Overlaps ( aLayer ) ) )
2015-02-18 00:29:54 +00:00
{
rv = item ;
break ;
}
}
if ( rv )
2016-08-17 14:00:21 +00:00
{
2022-02-05 02:06:25 +00:00
wxLogTrace ( wxT ( " PNS " ) , wxT ( " %s, layer : %d, tl: %d " ) ,
rv - > KindStr ( ) . c_str ( ) ,
rv - > Layers ( ) . Start ( ) ,
2021-07-19 23:56:05 +00:00
tl ) ;
2016-08-17 14:00:21 +00:00
}
2015-02-18 00:29:54 +00:00
return rv ;
}
2022-12-06 02:24:09 +00:00
void TOOL_BASE : : highlightNets ( bool aEnabled , std : : set < int > aNetcodes )
2015-02-18 00:29:54 +00:00
{
RENDER_SETTINGS * rs = getView ( ) - > GetPainter ( ) - > GetSettings ( ) ;
2022-12-06 02:24:09 +00:00
if ( aNetcodes . size ( ) > 0 & & aEnabled )
2018-12-02 19:21:43 +00:00
{
2022-12-06 02:24:09 +00:00
// If the user has previously set some of the routed nets to be highlighted,
// we assume they want to keep them highlighted after routing
2018-12-02 19:21:43 +00:00
2022-12-06 02:24:09 +00:00
const std : : set < int > & currentNetCodes = rs - > GetHighlightNetCodes ( ) ;
bool keep = false ;
for ( const int & netcode : aNetcodes )
{
if ( currentNetCodes . find ( netcode ) ! = currentNetCodes . end ( ) )
{
keep = true ;
break ;
}
}
if ( rs - > IsHighlightEnabled ( ) & & keep )
m_startHighlightNetcodes = currentNetCodes ;
else
m_startHighlightNetcodes . clear ( ) ;
rs - > SetHighlight ( aNetcodes , true ) ;
2018-12-02 19:21:43 +00:00
}
2015-02-18 00:29:54 +00:00
else
2018-12-02 19:21:43 +00:00
{
2022-12-06 02:24:09 +00:00
rs - > SetHighlight ( m_startHighlightNetcodes , m_startHighlightNetcodes . size ( ) > 0 ) ;
2018-12-02 19:21:43 +00:00
}
2015-02-18 00:29:54 +00:00
2022-07-09 03:06:10 +00:00
// Do not remove this call. This is required to update the layers when we highlight a net.
// In this case, highlighting a net dims all other elements, so the colors need to update
getView ( ) - > UpdateAllLayersColor ( ) ;
2015-02-18 00:29:54 +00:00
}
2021-07-19 23:56:05 +00:00
2017-08-03 15:53:07 +00:00
bool TOOL_BASE : : checkSnap ( ITEM * aItem )
{
2019-06-01 10:39:39 +00:00
// Sync PNS engine settings with the general PCB editor options.
2017-08-03 15:53:07 +00:00
auto & pnss = m_router - > Settings ( ) ;
2022-12-29 11:16:25 +00:00
// If we're dragging a track segment, don't try to snap to items on the same copper layer with same nets. This is not a perfect heuristic, but seems to work reasonably well :-)
2021-12-15 00:46:03 +00:00
// This way we avoid 'flickery' behaviour for short segments when the snap algo is trying to
// snap to the corners of the segments next to the one being dragged.
if ( m_startItem & & aItem & & m_router - > GetState ( ) = = ROUTER : : DRAG_SEGMENT
& & aItem - > Layer ( ) = = m_startItem - > Layer ( ) & & aItem - > OfKind ( ITEM : : SEGMENT_T )
2022-12-29 11:16:25 +00:00
& & m_startItem - > OfKind ( ITEM : : SEGMENT_T )
& & aItem - > Net ( ) = = m_startItem - > Net ( ) )
2021-12-15 00:46:03 +00:00
return false ;
2020-01-13 01:44:19 +00:00
pnss . SetSnapToPads (
2020-05-22 18:27:05 +00:00
frame ( ) - > GetMagneticItemsSettings ( ) - > pads = = MAGNETIC_OPTIONS : : CAPTURE_CURSOR_IN_TRACK_TOOL | |
frame ( ) - > GetMagneticItemsSettings ( ) - > pads = = MAGNETIC_OPTIONS : : CAPTURE_ALWAYS ) ;
2017-08-03 15:53:07 +00:00
2020-01-13 01:44:19 +00:00
pnss . SetSnapToTracks (
2020-05-22 18:27:05 +00:00
frame ( ) - > GetMagneticItemsSettings ( ) - > tracks = = MAGNETIC_OPTIONS : : CAPTURE_CURSOR_IN_TRACK_TOOL
| | frame ( ) - > GetMagneticItemsSettings ( ) - > tracks = = MAGNETIC_OPTIONS : : CAPTURE_ALWAYS ) ;
2017-08-03 15:53:07 +00:00
if ( aItem )
{
2019-05-17 00:13:21 +00:00
if ( aItem - > OfKind ( ITEM : : VIA_T | ITEM : : SEGMENT_T | ITEM : : ARC_T ) )
2019-06-01 10:39:39 +00:00
return pnss . GetSnapToTracks ( ) ;
else if ( aItem - > OfKind ( ITEM : : SOLID_T ) )
return pnss . GetSnapToPads ( ) ;
2017-08-03 15:53:07 +00:00
}
2019-06-01 10:39:39 +00:00
return false ;
2017-08-03 15:53:07 +00:00
}
2015-02-18 16:53:46 +00:00
2021-07-19 23:56:05 +00:00
2018-07-26 22:35:11 +00:00
void TOOL_BASE : : updateStartItem ( const TOOL_EVENT & aEvent , bool aIgnorePads )
2015-02-18 00:29:54 +00:00
{
2020-12-11 13:11:20 +00:00
int tl = getView ( ) - > GetTopLayer ( ) ;
2022-03-29 12:43:00 +00:00
VECTOR2I cp = aEvent . IsPrime ( ) ? aEvent . Position ( )
: controls ( ) - > GetCursorPosition ( ! aEvent . Modifier ( MD_SHIFT ) ) ;
2015-08-04 09:37:16 +00:00
VECTOR2I p ;
2020-12-11 13:11:20 +00:00
GAL * gal = m_toolMgr - > GetView ( ) - > GetGAL ( ) ;
2015-08-04 09:37:16 +00:00
2017-08-16 12:11:07 +00:00
controls ( ) - > ForceCursorPosition ( false ) ;
2021-05-09 19:17:01 +00:00
m_gridHelper - > SetUseGrid ( gal - > GetGridSnapping ( ) & & ! aEvent . DisableGridSnapping ( ) ) ;
2019-01-29 15:16:11 +00:00
m_gridHelper - > SetSnap ( ! aEvent . Modifier ( MD_SHIFT ) ) ;
2017-08-16 12:11:07 +00:00
2015-02-18 00:29:54 +00:00
if ( aEvent . IsMotion ( ) | | aEvent . IsClick ( ) )
2015-08-04 09:37:16 +00:00
p = aEvent . Position ( ) ;
2016-08-15 15:16:53 +00:00
else
2015-08-04 09:37:16 +00:00
p = cp ;
2015-02-18 00:29:54 +00:00
2021-11-21 14:31:05 +00:00
m_startItem = pickSingleItem ( aEvent . IsClick ( ) ? cp : p , - 1 , - 1 , aIgnorePads ) ;
2015-02-18 00:29:54 +00:00
2021-01-26 02:19:26 +00:00
if ( ! m_gridHelper - > GetUseGrid ( ) & & m_startItem & & ! m_startItem - > Layers ( ) . Overlaps ( tl ) )
2016-09-29 16:59:11 +00:00
m_startItem = nullptr ;
2015-02-18 00:29:54 +00:00
2020-12-11 13:11:20 +00:00
m_startSnapPoint = snapToItem ( m_startItem , p ) ;
2021-05-25 20:55:57 +00:00
controls ( ) - > ForceCursorPosition ( true , m_startSnapPoint ) ;
2015-02-18 00:29:54 +00:00
}
2015-02-18 16:53:46 +00:00
2017-01-18 08:04:11 +00:00
void TOOL_BASE : : updateEndItem ( const TOOL_EVENT & aEvent )
2015-02-18 00:29:54 +00:00
{
2020-12-11 13:11:20 +00:00
int layer ;
GAL * gal = m_toolMgr - > GetView ( ) - > GetGAL ( ) ;
2021-05-09 19:17:01 +00:00
m_gridHelper - > SetUseGrid ( gal - > GetGridSnapping ( ) & & ! aEvent . DisableGridSnapping ( ) ) ;
2020-12-11 13:11:20 +00:00
m_gridHelper - > SetSnap ( ! aEvent . Modifier ( MD_SHIFT ) ) ;
2019-01-29 15:16:11 +00:00
controls ( ) - > ForceCursorPosition ( false ) ;
2022-12-06 02:24:09 +00:00
2022-11-09 13:09:08 +00:00
VECTOR2I mousePos = controls ( ) - > GetMousePosition ( ) ;
2022-12-06 02:24:09 +00:00
2022-11-09 13:09:08 +00:00
if ( m_router - > GetState ( ) = = ROUTER : : ROUTE_TRACK & & aEvent . IsDrag ( ) )
{
// If the user is moving the mouse quickly while routing then clicks will come in as
// short drags. In this case we want to use the drag origin rather than the current
// mouse position.
2022-06-03 21:11:34 +00:00
mousePos = aEvent . DragOrigin ( ) ;
2022-11-09 13:09:08 +00:00
}
2015-02-18 00:29:54 +00:00
2018-04-08 20:20:51 +00:00
if ( m_router - > Settings ( ) . Mode ( ) ! = RM_MarkObstacles & &
2020-12-04 16:57:19 +00:00
( m_router - > GetCurrentNets ( ) . empty ( ) | | m_router - > GetCurrentNets ( ) . front ( ) < 0 ) )
2015-02-18 00:29:54 +00:00
{
2020-12-11 13:11:20 +00:00
m_endSnapPoint = snapToItem ( nullptr , mousePos ) ;
2017-08-03 15:53:07 +00:00
controls ( ) - > ForceCursorPosition ( true , m_endSnapPoint ) ;
2016-09-29 16:59:11 +00:00
m_endItem = nullptr ;
2015-02-18 00:29:54 +00:00
return ;
}
if ( m_router - > IsPlacingVia ( ) )
layer = - 1 ;
else
layer = m_router - > GetCurrentLayer ( ) ;
2016-09-29 16:59:11 +00:00
ITEM * endItem = nullptr ;
2015-08-21 14:35:34 +00:00
std : : vector < int > nets = m_router - > GetCurrentNets ( ) ;
2016-06-29 20:07:55 +00:00
for ( int net : nets )
2015-08-21 14:35:34 +00:00
{
2019-03-17 03:34:08 +00:00
endItem = pickSingleItem ( mousePos , net , layer , false , { m_startItem } ) ;
2015-08-21 14:35:34 +00:00
if ( endItem )
break ;
}
2015-02-18 00:29:54 +00:00
2021-04-04 14:22:23 +00:00
if ( m_gridHelper - > GetSnap ( ) & & checkSnap ( endItem ) )
2017-08-03 15:53:07 +00:00
{
m_endItem = endItem ;
2020-12-11 13:11:20 +00:00
m_endSnapPoint = snapToItem ( endItem , mousePos ) ;
2020-10-31 15:41:50 +00:00
}
else
{
2017-08-03 15:53:07 +00:00
m_endItem = nullptr ;
2019-01-29 15:16:11 +00:00
m_endSnapPoint = m_gridHelper - > Align ( mousePos ) ;
2017-08-03 15:53:07 +00:00
}
2015-02-18 00:29:54 +00:00
2019-01-29 15:16:11 +00:00
controls ( ) - > ForceCursorPosition ( true , m_endSnapPoint ) ;
2015-02-18 00:29:54 +00:00
if ( m_endItem )
2016-08-17 14:00:21 +00:00
{
2022-02-05 02:06:25 +00:00
wxLogTrace ( wxT ( " PNS " ) , wxT ( " %s, layer : %d " ) ,
2020-10-31 15:41:50 +00:00
m_endItem - > KindStr ( ) . c_str ( ) ,
m_endItem - > Layers ( ) . Start ( ) ) ;
2016-08-17 14:00:21 +00:00
}
2015-02-18 00:29:54 +00:00
}
2016-08-15 15:16:53 +00:00
2016-08-29 17:31:13 +00:00
ROUTER * TOOL_BASE : : Router ( ) const
2016-08-15 15:16:47 +00:00
{
return m_router ;
}
2016-08-15 15:16:51 +00:00
2016-08-15 15:16:53 +00:00
2021-07-26 23:47:26 +00:00
const VECTOR2I TOOL_BASE : : snapToItem ( ITEM * aItem , const VECTOR2I & aP )
2016-08-15 15:16:51 +00:00
{
2020-12-11 13:11:20 +00:00
if ( ! aItem | | ! m_iface - > IsItemVisible ( aItem ) )
2016-08-15 15:16:51 +00:00
{
2016-09-29 16:59:11 +00:00
return m_gridHelper - > Align ( aP ) ;
2016-08-15 15:16:51 +00:00
}
switch ( aItem - > Kind ( ) )
{
2016-08-29 17:31:13 +00:00
case ITEM : : SOLID_T :
2020-12-11 13:11:20 +00:00
return static_cast < SOLID * > ( aItem ) - > Pos ( ) ;
2016-08-15 15:16:51 +00:00
2016-08-29 17:31:13 +00:00
case ITEM : : VIA_T :
2020-12-11 13:11:20 +00:00
return static_cast < VIA * > ( aItem ) - > Pos ( ) ;
2016-08-15 15:16:51 +00:00
2016-08-29 17:31:13 +00:00
case ITEM : : SEGMENT_T :
2019-05-17 00:13:21 +00:00
case ITEM : : ARC_T :
2016-08-15 15:16:51 +00:00
{
2019-05-17 00:13:21 +00:00
LINKED_ITEM * li = static_cast < LINKED_ITEM * > ( aItem ) ;
2020-11-10 23:12:28 +00:00
VECTOR2I A = li - > Anchor ( 0 ) ;
VECTOR2I B = li - > Anchor ( 1 ) ;
SEG : : ecoord w_sq = SEG : : Square ( li - > Width ( ) / 2 ) ;
SEG : : ecoord distA_sq = ( aP - A ) . SquaredEuclideanNorm ( ) ;
SEG : : ecoord distB_sq = ( aP - B ) . SquaredEuclideanNorm ( ) ;
2019-05-17 00:13:21 +00:00
2020-11-10 23:12:28 +00:00
if ( distA_sq < w_sq | | distB_sq < w_sq )
2020-10-31 15:41:50 +00:00
{
2020-12-11 13:11:20 +00:00
return ( distA_sq < distB_sq ) ? A : B ;
2020-10-31 15:41:50 +00:00
}
2020-12-11 13:11:20 +00:00
else if ( aItem - > Kind ( ) = = ITEM : : SEGMENT_T )
2020-10-31 15:41:50 +00:00
{
2021-07-19 23:56:05 +00:00
// TODO(snh): Clean this up
2020-12-11 13:11:20 +00:00
SEGMENT * seg = static_cast < SEGMENT * > ( li ) ;
return m_gridHelper - > AlignToSegment ( aP , seg - > Seg ( ) ) ;
}
else if ( aItem - > Kind ( ) = = ITEM : : ARC_T )
{
ARC * arc = static_cast < ARC * > ( li ) ;
return m_gridHelper - > AlignToArc ( aP , * static_cast < const SHAPE_ARC * > ( arc - > Shape ( ) ) ) ;
2020-10-31 15:41:50 +00:00
}
2021-07-19 23:56:05 +00:00
2020-12-11 13:11:20 +00:00
break ;
2021-07-19 23:56:05 +00:00
}
2016-08-15 15:16:51 +00:00
default :
break ;
}
2020-12-11 13:11:20 +00:00
return m_gridHelper - > Align ( aP ) ;
2016-08-15 15:16:51 +00:00
}
2016-08-29 14:38:11 +00:00
}