KiCad PCB EDA Suite
magnetic_tracks_functions.cpp File Reference
#include <fctsys.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
#include <macros.h>
#include <class_board.h>
#include <class_track.h>
#include <pcbnew_id.h>

Go to the source code of this file.

Functions

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). More...
 
bool Project (wxPoint *aNearPos, wxPoint on_grid, const TRACK *track)
 Finds the projection of a grid point on a track. More...
 
bool Magnetize (PCB_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...
 

Function Documentation

static bool Join ( wxPoint aIntersectPoint,
wxPoint  a0,
wxPoint  a1,
wxPoint  b0,
wxPoint  b1 
)
static

Function Join finds the point where line segment (b1,b0) intersects with segment (a1,a0).

If that point would be outside of (a0,a1), the respective endpoint is used. Join returns the point in "res" and "true" if a suitable point was found, "false" if both lines are parallel or if the length of either segment is zero.

Definition at line 53 of file magnetic_tracks_functions.cpp.

References KiROUND(), max, min, wxPoint::x, and wxPoint::y.

Referenced by Magnetize().

54 {
55  /* References:
56  http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
57  http://www.gekkou.co.uk/blogs/monologues/2007/12/13/1197586800000.html
58  */
59 
60  double denom;
61  double t;
62 
63  // if either segment is zero length
64  if( a1.x==a0.x && a1.y==a0.y )
65  return false;
66 
67  if( b1.x==b0.x && b1.y==b0.y )
68  return false;
69 
70  a1 -= a0;
71  b1 -= b0;
72 
73  b0 -= a0;
74 
75  denom = (double) b1.y * a1.x - (double) b1.x * a1.y;
76 
77  if( !denom )
78  {
79  return false; // parallel
80  }
81 
82  t = ((double) b1.y * b0.x - (double) b1.x * b0.y ) / denom;
83 
84  t = std::min( std::max( t, 0.0 ), 1.0 );
85 
86  aIntersectPoint->x = KiROUND( a0.x + t * a1.x );
87  aIntersectPoint->y = KiROUND( a0.y + t * a1.y );
88 
89  return true;
90 }
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
#define max(a, b)
Definition: auxiliary.h:86
#define min(a, b)
Definition: auxiliary.h:85
bool Magnetize ( PCB_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, g_CurrentTrackSegment, g_Drc_On, g_MagneticPadOption, g_MagneticTrackOption, g_TwoSegmentTrackBuild, 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, BOARD::m_Track, TRACK::Next(), PCB_TRACE_T, PCB_VIA_T, Project(), EDA_DRAW_FRAME::RefPos(), EDA_ITEM::Type(), wxPoint::x, and wxPoint::y.

Referenced by PCB_EDIT_FRAME::GeneralControl().

131 {
132  bool doCheckNet = g_MagneticPadOption != CAPTURE_ALWAYS && g_Drc_On;
133  bool doTrack = false;
134  bool doPad = false;
135  bool amMovingVia = false;
136 
137  BOARD* m_Pcb = frame->GetBoard();
138  TRACK* currTrack = g_CurrentTrackSegment;
139  BOARD_ITEM* currItem = frame->GetCurItem();
140  PCB_SCREEN* screen = frame->GetScreen();
141  wxPoint pos = frame->RefPos( true );
142 
143  // D( printf( "currTrack=%p currItem=%p currTrack->Type()=%d currItem->Type()=%d\n", currTrack, currItem, currTrack ? currTrack->Type() : 0, currItem ? currItem->Type() : 0 ); )
144 
145  if( !currTrack && currItem && currItem->Type()==PCB_VIA_T && currItem->GetFlags() )
146  {
147  // moving a VIA
148  currTrack = (TRACK*) currItem;
149  amMovingVia = true;
150 
151  return false; // comment this return out and play with it.
152  }
153  else if( currItem != currTrack )
154  {
155  currTrack = NULL;
156  }
157 
159  doPad = true;
160 
162  doTrack = true;
163 
164  if( aCurrentTool == ID_TRACK_BUTT || amMovingVia )
165  {
167 
168  if( g_MagneticPadOption == q )
169  doPad = true;
170 
171  if( g_MagneticTrackOption == q )
172  doTrack = true;
173  }
174 
175  // The search precedence order is pads, then tracks/vias
176  if( doPad )
177  {
178  LSET layer_mask( screen->m_Active_Layer );
179  D_PAD* pad = m_Pcb->GetPad( pos, layer_mask );
180 
181  if( pad )
182  {
183  if( doCheckNet && currTrack && currTrack->GetNetCode() != pad->GetNetCode() )
184  return false;
185 
186  *curpos = pad->GetPosition();
187  return true;
188  }
189  }
190 
191  // after pads, only track & via tests remain, skip them if not desired
192  if( doTrack )
193  {
194  PCB_LAYER_ID layer = screen->m_Active_Layer;
195 
196  for( TRACK* via = m_Pcb->m_Track;
197  via && (via = via->GetVia( *curpos, layer )) != NULL;
198  via = via->Next() )
199  {
200  if( via != currTrack ) // a via cannot influence itself
201  {
202  if( !doCheckNet || !currTrack || currTrack->GetNetCode() == via->GetNetCode() )
203  {
204  *curpos = via->GetStart();
205  // D(printf("via hit\n");)
206  return true;
207  }
208  }
209  }
210 
211  if( !currTrack )
212  {
213  LSET layers( layer );
214 
215  TRACK* track = m_Pcb->GetVisibleTrack( m_Pcb->m_Track, pos, layers );
216 
217  if( !track || track->Type() != PCB_TRACE_T )
218  {
219  return false;
220  }
221 
222  return Project( curpos, on_grid, track );
223  }
224 
225  /*
226  * In two segment mode, ignore the final segment if it's inside a grid square.
227  */
228  if( !amMovingVia && currTrack && g_TwoSegmentTrackBuild && currTrack->Back()
229  && currTrack->GetStart().x - aGridSize.x < currTrack->GetEnd().x
230  && currTrack->GetStart().x + aGridSize.x > currTrack->GetEnd().x
231  && currTrack->GetStart().y - aGridSize.y < currTrack->GetEnd().y
232  && currTrack->GetStart().y + aGridSize.y > currTrack->GetEnd().y )
233  {
234  currTrack = currTrack->Back();
235  }
236 
237 
238  for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
239  {
240  if( track->Type() != PCB_TRACE_T )
241  continue;
242 
243  if( doCheckNet && currTrack && currTrack->GetNetCode() != track->GetNetCode() )
244  continue;
245 
246  if( m_Pcb->IsLayerVisible( track->GetLayer() ) == false )
247  continue;
248 
249  // omit the layer check if moving a via
250  if( !amMovingVia && !track->IsOnLayer( layer ) )
251  continue;
252 
253  if( !track->HitTest( *curpos ) )
254  continue;
255 
256  if( Join( curpos, track->GetStart(), track->GetEnd(), currTrack->GetStart(), currTrack->GetEnd() ) )
257  {
258  return true;
259  }
260 
261  if( aCurrentTool == ID_TRACK_BUTT || amMovingVia )
262  {
263  // At this point we have a drawing mouse on a track, we are drawing
264  // a new track and that new track is parallel to the track the
265  // mouse is on. Find the nearest end point of the track under mouse
266  // to the mouse and return that.
267  double distStart = GetLineLength( *curpos, track->GetStart() );
268  double distEnd = GetLineLength( *curpos, track->GetEnd() );
269 
270  // if track not via, or if its a via dragging but not with its adjacent track
271  if( currTrack->Type() != PCB_VIA_T ||
272  ( currTrack->GetStart() != track->GetStart() && currTrack->GetStart() != track->GetEnd() ))
273  {
274  double max_dist = currTrack->GetWidth() / 2.0f;
275 
276  if( distStart <= max_dist )
277  {
278  // D(printf("nearest end is start\n");)
279  *curpos = track->GetStart();
280  return true;
281  }
282 
283  if( distEnd <= max_dist )
284  {
285  // D(printf("nearest end is end\n");)
286  *curpos = track->GetEnd();
287  return true;
288  }
289 
290  // @todo otherwise confine curpos such that it stays centered within "track"
291  }
292  }
293  }
294  }
295 
296  return false;
297 }
#define g_CurrentTrackSegment
most recently created segment
Definition: pcbnew.h:101
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
bool g_Drc_On
Definition: pcbnew.cpp:70
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:255
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:183
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...
BOARD * GetBoard() const
PCB_LAYER_ID m_Active_Layer
TRACK * Back() const
Definition: class_track.h:99
const wxPoint & GetEnd() const
Definition: class_track.h:118
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
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.
const wxPoint & GetStart() const
Definition: class_track.h:121
const wxPoint & GetPosition() const override
Definition: class_pad.h:170
bool Project(wxPoint *aNearPos, wxPoint on_grid, const TRACK *track)
Finds the projection of a grid point on a track.
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...
D_PAD * GetPad(unsigned aIndex) const
Function GetPad.
Definition: class_board.h:750
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).
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...
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
TRACK * Next() const
Definition: class_track.h:98
int g_MagneticTrackOption
Definition: pcbnew.cpp:81
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
int GetWidth() const
Definition: class_track.h:115
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:108
DLIST< TRACK > m_Track
Definition: class_board.h:244
int g_MagneticPadOption
Definition: pcbnew.cpp:80
BOARD_ITEM * GetCurItem()
bool g_TwoSegmentTrackBuild
Definition: pcbnew.cpp:76
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:440
bool Project ( wxPoint res,
wxPoint  on_grid,
const TRACK track 
)

Finds the projection of a grid point on a track.

This is the point from where we want to draw new orthogonal tracks when starting on a track.

Definition at line 97 of file magnetic_tracks_functions.cpp.

References TRACK::GetEnd(), TRACK::GetStart(), KiROUND(), max, min, wxPoint::x, and wxPoint::y.

Referenced by Magnetize(), and PushTrack().

98 {
99  if( track->GetStart ()== track->GetEnd() )
100  return false;
101 
102  wxPoint vec = track->GetEnd() - track->GetStart();
103 
104  double t = double( on_grid.x - track->GetStart().x ) * vec.x +
105  double( on_grid.y - track->GetStart().y ) * vec.y;
106 
107  t /= (double) vec.x * vec.x + (double) vec.y * vec.y;
108  t = std::min( std::max( t, 0.0 ), 1.0 );
109 
110  aNearPos->x = KiROUND( track->GetStart().x + t * vec.x );
111  aNearPos->y = KiROUND( track->GetStart().y + t * vec.y );
112 
113  return true;
114 }
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
const wxPoint & GetEnd() const
Definition: class_track.h:118
const wxPoint & GetStart() const
Definition: class_track.h:121
#define max(a, b)
Definition: auxiliary.h:86
#define min(a, b)
Definition: auxiliary.h:85