Commit e5deafb4 authored by Tomasz Włostowski's avatar Tomasz Włostowski
Browse files

bulk improvements for selection and edit tools (GAL) disambiguatin heuristics...

bulk improvements for selection and edit tools (GAL) disambiguatin heuristics and smarter grid alignment
parent a46a92f9
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -58,8 +58,27 @@ TOOL_ACTION COMMON_ACTIONS::findDummy( "pcbnew.Find.Dummy", // only block the ho
TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove",
        AS_GLOBAL, 'T');


// Edit tool actions
TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor",
        AS_CONTEXT, MD_CTRL + 'E',
        "Open in Footprint Editor", 
        "Opens the selected footprint in the Footprint Editor" );

TOOL_ACTION COMMON_ACTIONS::copyPadToSettings ( "pcbnew.InteractiveEdit.copyPadToSettings",
        AS_CONTEXT, 0,
        "Copy pad settings to Current Settings", 
        "Copies the properties of selected pad to the current template pad settings." );

TOOL_ACTION COMMON_ACTIONS::copySettingsToPads ( "pcbnew.InteractiveEdit.copySettingsToPads",
        AS_CONTEXT, 0,
        "Copy Current Settings to pads", 
        "Copies the current template pad settings to the selected pad(s)." );

TOOL_ACTION COMMON_ACTIONS::globalEditPads ( "pcbnew.InteractiveEdit.globalPadEdit",
        AS_CONTEXT, 0,
        "Global Pad Edition", 
        "Changes pad properties globally." );

TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit",
        AS_GLOBAL, 'M',
        "Move", "Moves the selected item(s)", AF_ACTIVATE );
+7 −0
Original line number Diff line number Diff line
@@ -236,6 +236,13 @@ public:

    /// Blocks CTRL+F, it is handled by wxWidgets
    static TOOL_ACTION findDummy;

    static TOOL_ACTION editFootprintInFpEditor;
    static TOOL_ACTION copyPadToSettings;
    static TOOL_ACTION copySettingsToPads;
    static TOOL_ACTION globalEditPads;


    /**
     * Function TranslateLegacyId()
     * Translates legacy tool ids to the corresponding TOOL_ACTION name.
+166 −57
Original line number Diff line number Diff line
@@ -22,11 +22,15 @@
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <limits>

#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <class_zone.h>
#include <wxPcbStruct.h>
#include <kiway.h>
#include <module_editor_frame.h>

#include <tool/tool_manager.h>
#include <view/view_controls.h>
@@ -41,6 +45,7 @@
#include "common_actions.h"
#include "selection_tool.h"
#include "edit_tool.h"
#include "grid_helper.h"

EDIT_TOOL::EDIT_TOOL() :
    TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ),
@@ -74,6 +79,11 @@ bool EDIT_TOOL::Init()
    m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty );
    m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty );

    // Footprint actions
    m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, 
                                SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && 
                                SELECTION_CONDITIONS::Count ( 1 ) );

    m_offset.x = 0;
    m_offset.y = 0;

@@ -82,6 +92,20 @@ bool EDIT_TOOL::Init()
    return true;
}

bool EDIT_TOOL::invokeInlineRouter()
{
    TRACK *track = uniqueSelected<TRACK> ();
    VIA *via = uniqueSelected<VIA> ();

    if( track || via )
    {
        printf("Calling interactive drag\n");
        m_toolMgr->RunAction( COMMON_ACTIONS::routerInlineDrag, true );
        return true;
    }

    return false;
}

int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{
@@ -90,11 +114,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    // Be sure that there is at least one item that we can modify
    if( !makeSelection( selection ) )
    // Be sure that there is at least one item that we can modify. If nothing was selected before,
	// try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
    if( !hoverSelection( selection ) )
    {
        setTransitions();

        return 0;
    }

@@ -102,6 +126,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )

    m_dragging = false;         // Are selected items being dragged?
    bool restore = false;       // Should items' state be restored when finishing the tool?
    bool lockOverride = false;
    bool isDragAndDrop = false;

    // By default, modified items need to update their geometry
    m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY;
@@ -109,9 +135,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
    KIGFX::VIEW_CONTROLS* controls = getViewControls();
    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
    controls->ShowCursor( true );
    controls->SetSnapping( true );
    //controls->SetSnapping( true );
    controls->ForceCursorPosition( false );

    GRID_HELPER grid ( editFrame );

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
@@ -151,10 +179,22 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )

        else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
        {
            m_cursor = controls->GetCursorPosition();
            //if ( invokeInlineRouter ( ) )
             //   break;

            VECTOR2I mousePos = evt->Position();

            m_cursor = grid.Align ( evt->Position() );
            isDragAndDrop = evt->IsDrag( BUT_LEFT );
            
            
            if( m_dragging )
            {
            

                m_cursor = grid.BestSnapAnchor ( evt->Position(), selection.Item<BOARD_ITEM>( 0 ) );
                getViewControls()->ForceCursorPosition ( true, m_cursor );

                wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) -
                                   selection.Item<BOARD_ITEM>( 0 )->GetPosition();

@@ -166,33 +206,52 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
            }
            else    // Prepare to start dragging
            {
                if( m_selectionTool->CheckLock() || selection.Empty() )
                m_selectionTool->SanitizeSelection( );
                
                if ( selection.Empty() )
                    break;

				// deal with locked items (override lock or abort the operation)
                SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock();
                
                if ( lockFlags == SELECTION_LOCKED )
                    break;
                else if ( lockFlags == SELECTION_LOCK_OVERRIDE )
                    lockOverride = true;
            
                // Save items, so changes can be undone
                editFrame->OnModify();
                editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );

                VECTOR2I origin;

                
                if( evt->IsDrag( BUT_LEFT ) )
                    mousePos = evt->DragOrigin();

                //    origin = grid.Align ( evt->DragOrigin() );
                //else
                origin = grid.Align ( mousePos );

                if( selection.Size() == 1 )
                {
                    // Set the current cursor position to the first dragged item origin, so the
                    // movement vector could be computed later
                    m_cursor = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() );
                    m_offset.x = 0;
                    m_offset.y = 0;
                    m_cursor = grid.BestDragOrigin ( mousePos, selection.Item<BOARD_ITEM>( 0 ) );
                    getViewControls()->ForceCursorPosition ( true, m_cursor );
                    grid.SetAuxAxes ( true, m_cursor );

                    VECTOR2I o = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() );
                    m_offset.x = o.x - m_cursor.x;
                    m_offset.y = o.y - m_cursor.y;
                }
                else
                {
                    VECTOR2D origin;

                    if( evt->IsDrag( BUT_LEFT ) )
                        origin = getView()->GetGAL()->GetGridPoint( evt->DragOrigin() );
                    else
                        origin = getViewControls()->GetCursorPosition();

                    // Update dragging offset (distance between cursor and the first dragged item)
                    m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() -
                                                         wxPoint( origin.x, origin.y );
              
                    getViewControls()->ForceCursorPosition ( true, origin );

                }

                controls->SetAutoPan( true );
@@ -204,7 +263,12 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
        }

        else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
		{
            if (!isDragAndDrop || !lockOverride )
                break; // Finish

            lockOverride = false;
        }
    }

    m_dragging = false;
@@ -231,7 +295,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
    ratsnest->Recalculate();

    controls->ShowCursor( false );
    controls->SetSnapping( false );
    //controls->SetSnapping( false );
    controls->SetAutoPan( false );

    setTransitions();
@@ -245,7 +309,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
    const SELECTION& selection = m_selectionTool->GetSelection();
    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();

    if( !makeSelection( selection ) )
    if( !hoverSelection( selection, false ) )
    {
        setTransitions();

@@ -258,22 +322,6 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
        // Display properties dialog
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 );

        // Check if user wants to edit pad or module properties
        if( item->Type() == PCB_MODULE_T )
        {
            VECTOR2D cursor = getViewControls()->GetCursorPosition();

            for( D_PAD* pad = static_cast<MODULE*>( item )->Pads(); pad; pad = pad->Next() )
            {
                if( pad->ViewBBox().Contains( cursor ) )
                {
                    // Turns out that user wants to edit a pad properties
                    item = pad;
                    break;
                }
            }
        }

        std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList;

        // Some of properties dialogs alter pointers, so we should deselect them
@@ -317,7 +365,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !makeSelection( selection ) || m_selectionTool->CheckLock() )
    if( !hoverSelection( selection ) )
    {
        setTransitions();

@@ -371,7 +419,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !makeSelection( selection ) || m_selectionTool->CheckLock() )
    if( !hoverSelection( selection ) )
    {
        setTransitions();

@@ -421,7 +469,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    if( !makeSelection( selection ) || m_selectionTool->CheckLock() )
    if( !hoverSelection( selection ) )
    {
        setTransitions();

@@ -476,41 +524,59 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )

    // Default removal procedure
    case PCB_MODULE_TEXT_T:
    {
        if( m_editModules )
    {
        TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( aItem );

        switch( text->GetType() )
        {
            case TEXTE_MODULE::TEXT_is_REFERENCE:
                DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete REFERENCE!" ) );
                DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component reference." ) );
                return;

            case TEXTE_MODULE::TEXT_is_VALUE:
                DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete VALUE!" ) );
                DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component value." ) );
                return;

            case TEXTE_MODULE::TEXT_is_DIVERS:    // suppress warnings
                break;
        }

        if( m_editModules )
        {

            MODULE* module = static_cast<MODULE*>( aItem->GetParent() );
            module->SetLastEditTime();
            board->m_Status_Pcb = 0; // it is done in the legacy view
            aItem->DeleteStructure();
        }

        return;
    }
    /* no break */

    case PCB_PAD_T:
    case PCB_MODULE_EDGE_T:
        if( m_editModules )
    {
        MODULE* module = static_cast<MODULE*>( aItem->GetParent() );
        module->SetLastEditTime();

        board->m_Status_Pcb = 0; // it is done in the legacy view
            aItem->DeleteStructure();


        if(!m_editModules)
        {
            if(aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1)
            {
                DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete the only remaining pad of the module (modules on PCB must have at least one pad)." ) );
                return;
            }
            getView()->Remove( aItem );
            board->Remove( aItem );
        }
        
        aItem->DeleteStructure();
        
        return;
        break;
    }

    case PCB_LINE_T:                // a segment not on copper layers
    case PCB_TEXT_T:                // a text on a layer
@@ -526,7 +592,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
    default:                        // other types do not need to (or should not) be handled
        assert( false );
        return;
        break;
    }

    getView()->Remove( aItem );
@@ -541,6 +606,8 @@ void EDIT_TOOL::setTransitions()
    Go( &EDIT_TOOL::Flip,       COMMON_ACTIONS::flip.MakeEvent() );
    Go( &EDIT_TOOL::Remove,     COMMON_ACTIONS::remove.MakeEvent() );
    Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() );

    Go( &EDIT_TOOL::editFootprintInFpEditor, COMMON_ACTIONS::editFootprintInFpEditor.MakeEvent() );
}


@@ -550,6 +617,7 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw )
    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();

    ratsnest->ClearSimple();

    for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
    {
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
@@ -579,15 +647,27 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection )
    }
}


bool EDIT_TOOL::makeSelection( const SELECTION& aSelection )
bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize )
{
    if( aSelection.Empty() )                        // Try to find an item that could be modified
    {
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true );

    return !aSelection.Empty();
        if ( m_selectionTool->CheckLock() == SELECTION_LOCKED )
        {
            m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );        
            return false;
        }
    }

    if ( aSanitize )
        m_selectionTool->SanitizeSelection();

    if ( aSelection.Empty() )
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    
    return !aSelection.Empty();
}

void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList )
{
@@ -626,3 +706,32 @@ void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList )
        }
    }
}

int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
{
    MODULE *mod = uniqueSelected <MODULE> ();
    
    if( !mod )
        return 0;

    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
    
    editFrame-> SetCurItem( mod );

    if( editFrame->GetCurItem()->GetTimeStamp() == 0 )    // Module Editor needs a non null timestamp
    {
        editFrame->GetCurItem()->SetTimeStamp( GetNewTimeStamp() );
        editFrame->OnModify();
    }

    FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) editFrame->Kiway().Player( FRAME_PCB_MODULE_EDITOR, true );

    editor->Load_Module_From_BOARD( (MODULE*)editFrame->GetCurItem() );
    editFrame->SetCurItem( NULL );     // the current module could be deleted by

    editor->Show( true );
    editor->Raise();        // Iconize( false );

    setTransitions();
    return 0;
}
+16 −1
Original line number Diff line number Diff line
@@ -147,10 +147,25 @@ private:

    ///> If there are no items currently selected, it tries to choose the item that is under
    ///> the cursor or displays a disambiguation menu if there are multpile items.
    bool makeSelection( const SELECTION& aSelection );
    bool hoverSelection( const SELECTION& aSelection, bool aSanitize = true );

    ///> Updates view with the changes in the list.
    void processChanges( const PICKED_ITEMS_LIST* aList );

    int editFootprintInFpEditor( const TOOL_EVENT& aEvent );

    bool invokeInlineRouter();

    template <class T> T* uniqueSelected()
    {
        const SELECTION& selection = m_selectionTool->GetSelection();

        if(selection.items.GetCount() > 1)
            return NULL;

        BOARD_ITEM *item = selection.Item<BOARD_ITEM>( 0 );
        return dyn_cast<T*> (item);
    }
};

#endif
+334 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2014 CERN
 * @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 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 <boost/foreach.hpp>
#include <boost/bind.hpp>

#include <wxPcbStruct.h>

#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <class_zone.h>
#include <class_draw_panel_gal.h>

#include <view/view_controls.h>
#include <gal/graphics_abstraction_layer.h>

#include <geometry/shape_line_chain.h>

#include "grid_helper.h"

GRID_HELPER::GRID_HELPER ( PCB_BASE_FRAME *aFrame ) : 
	m_frame ( aFrame )
{

}
	
GRID_HELPER::~GRID_HELPER ()
{

}

void GRID_HELPER::SetGrid ( int aSize )
{
	assert ( false );
}

void GRID_HELPER::SetOrigin ( const VECTOR2I& aOrigin )
{
}

VECTOR2I GRID_HELPER::GetGrid ()
{
	PCB_SCREEN *screen = m_frame->GetScreen();

	const wxRealPoint& size = screen->GetGridSize();

	return VECTOR2I ( KiROUND ( size.x ), KiROUND ( size.y ) );
}

VECTOR2I GRID_HELPER::GetOrigin ()
{
	return VECTOR2I ( 0, 0 );
}

void GRID_HELPER::SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal)
{
	if( aEnable )
		m_auxAxis = aOrigin;
	else
		m_auxAxis = boost::optional <VECTOR2I> ();

	m_diagonalAuxAxesEnable = aEnable;	
}

VECTOR2I GRID_HELPER::Align ( const VECTOR2I& aPoint )
{
	const VECTOR2D gridOffset ( GetOrigin () );
	const VECTOR2D gridSize ( GetGrid() );

	VECTOR2I nearest ( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
                       round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );

	if ( !m_auxAxis )
		return nearest;

	if ( std::abs ( m_auxAxis->x - aPoint.x) < std::abs ( nearest.x - aPoint.x ) )
		nearest.x = m_auxAxis->x;

	if ( std::abs ( m_auxAxis->y - aPoint.y) < std::abs ( nearest.y - aPoint.y ) )
		nearest.y = m_auxAxis->y;

	return nearest;
}

VECTOR2I GRID_HELPER::BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem )
{
    clearAnchors();
   	computeAnchors( aItem, aMousePos );
    
    double worldScale = m_frame->GetGalCanvas()->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* best = NULL;
	double minDist = std::numeric_limits<double>::max(); 	

	if (nearestOrigin)
	{
		minDist = nearestOrigin->Distance(aMousePos);
		best = nearestOrigin;
	}

	if (nearestCorner)
	{
		double dist = nearestCorner->Distance(aMousePos);
		if (dist < minDist)
		{
			minDist = dist;
			best = nearestCorner;
		}
	}

	if (nearestOutline)
    {
    	double dist = nearestOutline->Distance(aMousePos);
    	if (minDist > lineSnapMinCornerDistance && dist < minDist)
    		best = nearestOutline;
    }

    return best ? best->pos : aMousePos;
}

std::set<BOARD_ITEM *> GRID_HELPER::queryVisible ( const BOX2I& aArea )
{
	std::set <BOARD_ITEM *> items;

    std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
	std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;

	m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems );         // Get the list of selected items

  	for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
    {
    	BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
    	if( item->ViewIsVisible() )
    		items.insert ( item );
    }

    return items;
}

VECTOR2I GRID_HELPER::BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem )
{
	double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
    int snapRange = (int) (100.0 / worldScale);

    BOX2I bb ( VECTOR2I ( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2) , VECTOR2I  (snapRange, snapRange) );

    clearAnchors();

    BOOST_FOREACH ( BOARD_ITEM *item, queryVisible ( bb ) )
    {
        computeAnchors(item, aOrigin);
    }

	LSET layers ( aDraggedItem->GetLayer() );
    ANCHOR *nearest = nearestAnchor ( aOrigin, CORNER | SNAPPABLE, layers );

    VECTOR2I nearestGrid = Align ( aOrigin );
    double gridDist = (nearestGrid - aOrigin).EuclideanNorm();
    if (nearest)
    {
     	double snapDist = nearest->Distance ( aOrigin );

	    if(nearest && snapDist < gridDist)
    	 	return nearest->pos;
   	}

   	return nearestGrid;
}

void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos )
{
	VECTOR2I origin;

    
    switch ( aItem->Type() )
    {
        case PCB_MODULE_T:
        {
             MODULE *mod = static_cast <MODULE *> (aItem);
			addAnchor ( mod->GetPosition(), ORIGIN | SNAPPABLE, mod );

            for (D_PAD *pad = mod->Pads(); pad; pad = pad->Next() )
            	addAnchor ( pad->GetPosition(), CORNER | SNAPPABLE, pad );
           
            break;
        }

        case PCB_MODULE_EDGE_T:
        case PCB_LINE_T:
        {
            DRAWSEGMENT *dseg = static_cast <DRAWSEGMENT*> (aItem);
            VECTOR2I start = dseg->GetStart();
            VECTOR2I end = dseg->GetEnd();
 			//LAYER_ID layer = dseg->GetLayer();


            switch( dseg->GetShape() )
            {
                case S_CIRCLE:
                {
                    int r = (start - end).EuclideanNorm();
                    
                    addAnchor ( start, ORIGIN | SNAPPABLE, dseg );
                    addAnchor ( start + VECTOR2I ( -r, 0 ) , OUTLINE | SNAPPABLE, dseg );
                    addAnchor ( start + VECTOR2I ( r, 0 ) , OUTLINE | SNAPPABLE, dseg );
					addAnchor ( start + VECTOR2I ( 0, -r ) , OUTLINE | SNAPPABLE, dseg);
                    addAnchor ( start + VECTOR2I ( 0, r ) , OUTLINE | SNAPPABLE, dseg );
                    break;
                }

                case S_ARC:
                {
                    origin = dseg->GetCenter();
                  	addAnchor ( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg );
                    addAnchor ( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg );
					addAnchor ( origin, ORIGIN | SNAPPABLE, dseg );
					break;    
                }

                case S_SEGMENT:
                {
                    origin.x = start.x + ( start.x - end.x ) / 2;
                    origin.y = start.y + ( start.y - end.y ) / 2;
                 	addAnchor ( start, CORNER | SNAPPABLE, dseg );
                    addAnchor ( end, CORNER | SNAPPABLE, dseg );
					addAnchor ( origin, ORIGIN, dseg );
                    break;
                }  

                default:
                {
                    origin = dseg->GetStart();
					addAnchor ( origin, ORIGIN | SNAPPABLE, dseg );
                    break;
                }
            }
            break;
        }

        case PCB_TRACE_T:
        {
            TRACK *track = static_cast <TRACK*> (aItem);
            VECTOR2I start = track->GetStart();
            VECTOR2I end = track->GetEnd();
            origin.x = start.x + ( start.x - end.x ) / 2;
            origin.y = start.y + ( start.y - end.y ) / 2;
           	addAnchor ( start, CORNER | SNAPPABLE, track );
            addAnchor ( end, CORNER | SNAPPABLE, track );
			addAnchor ( origin, ORIGIN, track);
            break;
        }  

        case PCB_ZONE_AREA_T:
        {
            const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
            int cornersCount = outline->GetCornersCount();
            
            SHAPE_LINE_CHAIN lc;
            lc.SetClosed ( true );
            
            for( int i = 0; i < cornersCount; ++i )
            {
            	const VECTOR2I p ( outline->GetPos( i ) );
	           	addAnchor ( p, CORNER, aItem );
				lc.Append ( p );
			}

			addAnchor( lc.NearestPoint ( aRefPos ), OUTLINE, aItem );

            break;
        }

        case PCB_MODULE_TEXT_T:
        case PCB_TEXT_T:
			addAnchor ( aItem->GetPosition(), ORIGIN, aItem );
        default:
            

        break;
   }

}

GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers )
{
	double minDist = std::numeric_limits<double>::max();
 	ANCHOR *best = NULL;

 	BOOST_FOREACH( ANCHOR& a, m_anchors )
 	{
 		if ( !aMatchLayers [ a.item->GetLayer() ]	)
 			continue;

 		if ( ( aFlags & a.flags ) != aFlags )
 			continue;

 		double dist = a.Distance(aPos);

 		if(dist < minDist)
 			{
 				minDist = dist;
 				best = &a;
 			}
 	}

 	return best;

}
 No newline at end of file
Loading