KiCad PCB EDA Suite
edit_tool.cpp File Reference
#include <limits>
#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <class_zone.h>
#include <collectors.h>
#include <pcb_edit_frame.h>
#include <kiway.h>
#include <class_draw_panel_gal.h>
#include <footprint_edit_frame.h>
#include <array_creator.h>
#include <pcbnew_id.h>
#include <tool/tool_manager.h>
#include <view/view_controls.h>
#include <view/view.h>
#include <gal/graphics_abstraction_layer.h>
#include <connectivity_data.h>
#include <confirm.h>
#include <bitmaps.h>
#include <hotkeys.h>
#include <cassert>
#include <functional>
#include "pcb_actions.h"
#include "selection_tool.h"
#include "edit_tool.h"
#include "picker_tool.h"
#include "grid_helper.h"
#include "kicad_clipboard.h"
#include "pcbnew_control.h"
#include <router/router_tool.h>
#include <dialogs/dialog_move_exact.h>
#include <dialogs/dialog_track_via_properties.h>
#include <dialogs/dialog_exchange_footprints.h>
#include <tools/tool_event_utils.h>
#include <preview_items/ruler_item.h>
#include <board_commit.h>

Go to the source code of this file.

Classes

class  GAL_ARRAY_CREATOR
 

Functions

bool Magnetize (PCB_BASE_EDIT_FRAME *frame, int aCurrentTool, wxSize aGridSize, wxPoint on_grid, wxPoint *curpos)
 Function Magnetize tests to see if there are any magnetic items within near reach of the given "curpos". More...
 
static wxPoint getAnchorPoint (const SELECTION &selection, const MOVE_PARAMETERS &params)
 
static wxPoint mirrorPointX (const wxPoint &aPoint, const wxPoint &aMirrorPoint)
 
static void mirrorPadX (D_PAD &aPad, const wxPoint &aMirrorPoint)
 Mirror a pad in the vertical axis passing through a point. More...
 

Function Documentation

static wxPoint getAnchorPoint ( const SELECTION selection,
const MOVE_PARAMETERS params 
)
static

Definition at line 188 of file edit_tool.cpp.

References MOVE_PARAMETERS::anchor, ANCHOR_CENTER_FOOTPRINT, ANCHOR_FROM_LIBRARY, ANCHOR_TOP_LEFT_PAD, EDA_ITEM::GetBoundingBox(), EDA_RECT::GetCenter(), SELECTION::GetCenter(), MODULE::GetFootprintRect(), BOARD_ITEM::GetPosition(), EDA_RECT::GetPosition(), MODULE::GetPosition(), SELECTION::GetSize(), SELECTION::GetTopLeftItem(), SELECTION::GetTopLeftModule(), MODULE::GetTopLeftPad(), mod, MOVE_PARAMETERS::origin, PAD_ATTRIB_SMD, PCB_MODULE_T, PCB_PAD_T, RELATIVE_TO_CURRENT_POSITION, EDA_ITEM::Type(), VECTOR2< T >::x, and VECTOR2< T >::y.

Referenced by EDIT_TOOL::MoveExact().

189 {
190  wxPoint anchorPoint;
191 
192  if( params.origin == RELATIVE_TO_CURRENT_POSITION )
193  {
194  return wxPoint( 0, 0 );
195  }
196 
197  // set default anchor
198  VECTOR2I rp = selection.GetCenter();
199  anchorPoint = wxPoint( rp.x, rp.y );
200 
201  // If the anchor is not ANCHOR_FROM_LIBRARY then the user applied an override.
202  // Also run through this block if only one item is slected because it may be a module,
203  // in which case we want something different than the center of the selection
204  if( ( params.anchor != ANCHOR_FROM_LIBRARY ) || ( selection.GetSize() == 1 ) )
205  {
206  BOARD_ITEM* topLeftItem = static_cast<BOARD_ITEM*>( selection.GetTopLeftModule() );
207 
208  // no module found if the GetTopLeftModule() returns null
209  if( topLeftItem != nullptr )
210  {
211  if( topLeftItem->Type() == PCB_MODULE_T )
212  {
213  // Cast to module to allow access to the pads
214  MODULE* mod = static_cast<MODULE*>( topLeftItem );
215 
216  switch( params.anchor )
217  {
218  case ANCHOR_FROM_LIBRARY:
219  anchorPoint = mod->GetPosition();
220  break;
221 
222  case ANCHOR_TOP_LEFT_PAD:
223  topLeftItem = mod->GetTopLeftPad();
224  break;
225 
227  anchorPoint = mod->GetFootprintRect().GetCenter();
228  break;
229  }
230  }
231 
232  if( topLeftItem->Type() == PCB_PAD_T )
233  {
234  if( static_cast<D_PAD*>( topLeftItem )->GetAttribute() == PAD_ATTRIB_SMD )
235  {
236  // Use the top left corner of SMD pads as an anchor instead of the center
237  anchorPoint = topLeftItem->GetBoundingBox().GetPosition();
238  }
239  else
240  {
241  anchorPoint = topLeftItem->GetPosition();
242  }
243  }
244  }
245  else // no module found in the selection
246  {
247  // in a selection of non-modules
248  if( params.anchor == ANCHOR_TOP_LEFT_PAD )
249  {
250  // approach the top left pad override for non-modules by using the position of
251  // the topleft item as an anchor
252  topLeftItem = static_cast<BOARD_ITEM*>( selection.GetTopLeftItem() );
253  anchorPoint = topLeftItem->GetPosition();
254  }
255  }
256  }
257 
258  return anchorPoint;
259 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:209
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:61
MOVE_EXACT_ORIGIN origin
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
class MODULE, a footprint
Definition: typeinfo.h:89
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Returns the area of the module footprint excluding any text...
EDA_ITEM * GetTopLeftItem(bool onlyModules=false) const
Definition: selection.cpp:90
const wxPoint GetPosition() const
Definition: eda_rect.h:113
D_PAD * GetTopLeftPad()
virtual const wxPoint GetPosition() const =0
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:89
VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition: selection.cpp:67
EDA_ITEM * GetTopLeftModule() const
Definition: selection.cpp:126
const wxPoint GetPosition() const override
Definition: class_module.h:182
MOVE_EXACT_ANCHOR anchor
#define mod(a, n)
Definition: greymap.cpp:24
const wxPoint GetCenter() const
Definition: eda_rect.h:115
bool Magnetize ( PCB_BASE_EDIT_FRAME frame,
int  aCurrentTool,
wxSize  aGridSize,
wxPoint  on_grid,
wxPoint curpos 
)

Function Magnetize tests to see if there are any magnetic items within near reach of the given "curpos".

If yes, then curpos is adjusted appropriately according to that near magnetic item and true is returned.

Parameters
frame= the current frame
aCurrentTool= the current tool id (from vertical right toolbar)
aGridSize= the current grid size
on_grid= the on grid position near initial position ( often on_grid = curpos)
curposThe initial position, and what to adjust if a change is needed.
Returns
bool - true if the position was adjusted magnetically, else false.

Definition at line 129 of file magnetic_tracks_functions.cpp.

References TRACK::Back(), CAPTURE_ALWAYS, CAPTURE_CURSOR_IN_TRACK_TOOL, FindBestGridPointOnTrack(), g_CurrentTrackSegment, PCB_BASE_FRAME::GetBoard(), PCB_BASE_FRAME::GetCurItem(), TRACK::GetEnd(), EDA_ITEM::GetFlags(), GetLineLength(), BOARD_CONNECTED_ITEM::GetNetCode(), BOARD::GetPad(), D_PAD::GetPosition(), PCB_BASE_FRAME::GetScreen(), TRACK::GetStart(), BOARD::GetVisibleTrack(), TRACK::GetWidth(), ID_TRACK_BUTT, BOARD::IsLayerVisible(), Join(), PCB_SCREEN::m_Active_Layer, PCB_GENERAL_SETTINGS::m_legacyDrcOn, PCB_GENERAL_SETTINGS::m_legacyUseTwoSegmentTracks, PCB_GENERAL_SETTINGS::m_magneticPads, PCB_GENERAL_SETTINGS::m_magneticTracks, BOARD::m_Track, TRACK::Next(), PCB_TRACE_T, PCB_VIA_T, EDA_DRAW_FRAME::RefPos(), PCB_BASE_FRAME::Settings(), EDA_ITEM::Type(), wxPoint::x, and wxPoint::y.

Referenced by EDIT_TOOL::MeasureTool().

131 {
132  // Note: only used for routing in the Legacy Toolset and for the measurement tool in the
133  // Modern Toolset. Can be greatly simplified when the Legacy Toolset is retired.
134 
135  bool doCheckNet = frame->Settings().m_magneticPads != CAPTURE_ALWAYS && frame->Settings().m_legacyDrcOn;
136  bool doCheckLayer = aCurrentTool == ID_TRACK_BUTT;
137  bool doTrack = false;
138  bool doPad = false;
139  bool amMovingVia = false;
140 
141  BOARD* m_Pcb = frame->GetBoard();
142  TRACK* currTrack = g_CurrentTrackSegment;
143  BOARD_ITEM* currItem = frame->GetCurItem();
144  PCB_SCREEN* screen = frame->GetScreen();
145  wxPoint pos = frame->RefPos( true );
146 
147  // D( printf( "currTrack=%p currItem=%p currTrack->Type()=%d currItem->Type()=%d\n", currTrack, currItem, currTrack ? currTrack->Type() : 0, currItem ? currItem->Type() : 0 ); )
148 
149  if( !currTrack && currItem && currItem->Type()==PCB_VIA_T && currItem->GetFlags() )
150  {
151  // moving a VIA
152  currTrack = (TRACK*) currItem;
153  amMovingVia = true;
154 
155  return false; // comment this return out and play with it.
156  }
157  else if( currItem != currTrack )
158  {
159  currTrack = NULL;
160  }
161 
162  if( frame->Settings().m_magneticPads == CAPTURE_ALWAYS )
163  doPad = true;
164 
165  if( frame->Settings().m_magneticTracks == CAPTURE_ALWAYS )
166  doTrack = true;
167 
168  if( aCurrentTool == ID_TRACK_BUTT || amMovingVia )
169  {
171 
172  if( frame->Settings().m_magneticPads == q )
173  doPad = true;
174 
175  if( frame->Settings().m_magneticTracks == q )
176  doTrack = true;
177  }
178 
179  // The search precedence order is pads, then tracks/vias
180  if( doPad )
181  {
182  D_PAD* pad;
183  if( doCheckLayer )
184  pad = m_Pcb->GetPad( pos, LSET( screen->m_Active_Layer ) );
185  else
186  pad = m_Pcb->GetPad( pos );
187 
188  if( pad )
189  {
190  if( doCheckNet && currTrack && currTrack->GetNetCode() != pad->GetNetCode() )
191  return false;
192 
193  *curpos = pad->GetPosition();
194  return true;
195  }
196  }
197 
198  // after pads, only track & via tests remain, skip them if not desired
199  if( doTrack )
200  {
201  PCB_LAYER_ID layer = screen->m_Active_Layer;
202 
203  for( TRACK* via = m_Pcb->m_Track;
204  via && (via = via->GetVia( *curpos, layer )) != NULL;
205  via = via->Next() )
206  {
207  if( via != currTrack ) // a via cannot influence itself
208  {
209  if( !doCheckNet || !currTrack || currTrack->GetNetCode() == via->GetNetCode() )
210  {
211  *curpos = via->GetStart();
212  // D(printf("via hit\n");)
213  return true;
214  }
215  }
216  }
217 
218  if( !currTrack )
219  {
220  LSET layers( layer );
221 
222  TRACK* track = m_Pcb->GetVisibleTrack( m_Pcb->m_Track, pos, layers );
223 
224  if( !track || track->Type() != PCB_TRACE_T )
225  {
226  return false;
227  }
228 
229  return FindBestGridPointOnTrack( curpos, on_grid, track );
230  }
231 
232  /*
233  * In two segment mode, ignore the final segment if it's inside a grid square.
234  */
235  if( !amMovingVia && currTrack && frame->Settings().m_legacyUseTwoSegmentTracks && currTrack->Back()
236  && currTrack->GetStart().x - aGridSize.x < currTrack->GetEnd().x
237  && currTrack->GetStart().x + aGridSize.x > currTrack->GetEnd().x
238  && currTrack->GetStart().y - aGridSize.y < currTrack->GetEnd().y
239  && currTrack->GetStart().y + aGridSize.y > currTrack->GetEnd().y )
240  {
241  currTrack = currTrack->Back();
242  }
243 
244 
245  for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
246  {
247  if( track->Type() != PCB_TRACE_T )
248  continue;
249 
250  if( doCheckNet && currTrack && currTrack->GetNetCode() != track->GetNetCode() )
251  continue;
252 
253  if( m_Pcb->IsLayerVisible( track->GetLayer() ) == false )
254  continue;
255 
256  // omit the layer check if moving a via
257  if( !amMovingVia && !track->IsOnLayer( layer ) )
258  continue;
259 
260  if( !track->HitTest( *curpos ) )
261  continue;
262 
263  if( Join( curpos, track->GetStart(), track->GetEnd(), currTrack->GetStart(), currTrack->GetEnd() ) )
264  {
265  return true;
266  }
267 
268  if( aCurrentTool == ID_TRACK_BUTT || amMovingVia )
269  {
270  // At this point we have a drawing mouse on a track, we are drawing
271  // a new track and that new track is parallel to the track the
272  // mouse is on. Find the nearest end point of the track under mouse
273  // to the mouse and return that.
274  double distStart = GetLineLength( *curpos, track->GetStart() );
275  double distEnd = GetLineLength( *curpos, track->GetEnd() );
276 
277  // if track not via, or if its a via dragging but not with its adjacent track
278  if( currTrack->Type() != PCB_VIA_T ||
279  ( currTrack->GetStart() != track->GetStart() && currTrack->GetStart() != track->GetEnd() ))
280  {
281  double max_dist = currTrack->GetWidth() / 2.0f;
282 
283  if( distStart <= max_dist )
284  {
285  // D(printf("nearest end is start\n");)
286  *curpos = track->GetStart();
287  return true;
288  }
289 
290  if( distEnd <= max_dist )
291  {
292  // D(printf("nearest end is end\n");)
293  *curpos = track->GetEnd();
294  return true;
295  }
296 
297  // @todo otherwise confine curpos such that it stays centered within "track"
298  }
299  }
300  }
301  }
302 
303  return false;
304 }
#define g_CurrentTrackSegment
most recently created segment
Definition: pcbnew.h:99
KICAD_T Type() const
Function Type()
Definition: base_struct.h:209
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:266
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Function GetLineLength returns the length of a line segment defined by aPointA and aPointB...
Definition: trigo.h:191
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Function IsOnLayer tests to see if this object is on the given layer.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
MAGNETIC_PAD_OPTION_VALUES m_magneticPads
BOARD * GetBoard() const
D_PAD * GetPad(unsigned aIndex) const
Function GetPad.
PCB_LAYER_ID m_Active_Layer
Definition: pcb_screen.h:44
TRACK * Back() const
Definition: class_track.h:100
const wxPoint & GetEnd() const
Definition: class_track.h:119
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
MAGNETIC_PAD_OPTION_VALUES m_magneticTracks
PCB_LAYER_ID
A quick note on layer IDs:
virtual bool HitTest(const wxPoint &aPosition) const override
Function HitTest tests if aPosition is contained within or on the bounding area of an item...
Class LSET is a set of PCB_LAYER_IDs.
PCB_GENERAL_SETTINGS & Settings()
const wxPoint & GetStart() const
Definition: class_track.h:122
TRACK * GetVisibleTrack(TRACK *aStartingTrace, const wxPoint &aPosition, LSET aLayerSet) const
Function GetVisibleTrack finds the neighboring visible segment of aTrace at aPosition that is on a la...
static bool Join(wxPoint *aIntersectPoint, wxPoint a0, wxPoint a1, wxPoint b0, wxPoint b1)
Function Join finds the point where line segment (b1,b0) intersects with segment (a1,a0).
bool FindBestGridPointOnTrack(wxPoint *aNearPos, wxPoint on_grid, const TRACK *track)
Finds the projection of a grid point on a track.
int GetNetCode() const
Function GetNetCode.
wxPoint RefPos(bool useMouse) const
Function RefPos Return the reference position, coming from either the mouse position or the cursor po...
TRACK * Next() const
Definition: class_track.h:99
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
int GetWidth() const
Definition: class_track.h:116
PCB_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DLIST< TRACK > m_Track
Definition: class_board.h:248
const wxPoint GetPosition() const override
Definition: class_pad.h:220
BOARD_ITEM * GetCurItem()
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:454
static void mirrorPadX ( D_PAD aPad,
const wxPoint aMirrorPoint 
)
static

Mirror a pad in the vertical axis passing through a point.

Definition at line 746 of file edit_tool.cpp.

References D_PAD::GetDelta(), D_PAD::GetOffset(), D_PAD::GetOrientation(), D_PAD::GetPosition(), mirrorPointX(), D_PAD::SetDelta(), D_PAD::SetOffset(), D_PAD::SetOrientation(), D_PAD::SetPosition(), D_PAD::SetX0(), and wxPoint::x.

Referenced by EDIT_TOOL::Mirror().

747 {
748  wxPoint tmpPt = mirrorPointX( aPad.GetPosition(), aMirrorPoint );
749 
750  aPad.SetPosition( tmpPt );
751 
752  aPad.SetX0( aPad.GetPosition().x );
753 
754  tmpPt = aPad.GetOffset();
755  tmpPt.x = -tmpPt.x;
756  aPad.SetOffset( tmpPt );
757 
758  auto tmpz = aPad.GetDelta();
759  tmpz.x = -tmpz.x;
760  aPad.SetDelta( tmpz );
761 
762  aPad.SetOrientation( -aPad.GetOrientation() );
763 }
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:219
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:382
const wxSize & GetDelta() const
Definition: class_pad.h:272
static wxPoint mirrorPointX(const wxPoint &aPoint, const wxPoint &aMirrorPoint)
Definition: edit_tool.cpp:731
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:401
void SetX0(int x)
Definition: class_pad.h:266
const wxPoint GetPosition() const override
Definition: class_pad.h:220
void SetOffset(const wxPoint &aOffset)
Definition: class_pad.h:277
const wxPoint & GetOffset() const
Definition: class_pad.h:278
void SetDelta(const wxSize &aSize)
Definition: class_pad.h:271
static wxPoint mirrorPointX ( const wxPoint aPoint,
const wxPoint aMirrorPoint 
)
static

Mirror a point about the vertical axis passing through another point

Definition at line 731 of file edit_tool.cpp.

References wxPoint::x.

Referenced by mirrorPadX().

732 {
733  wxPoint mirrored = aPoint;
734 
735  mirrored.x -= aMirrorPoint.x;
736  mirrored.x = -mirrored.x;
737  mirrored.x += aMirrorPoint.x;
738 
739  return mirrored;
740 }