KiCad PCB EDA Suite
dragsegm.cpp
Go to the documentation of this file.
1 
7 /*
8  * This program source code file is part of KiCad, a free EDA CAD application.
9  *
10  * Copyright (C) 2004-2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
11  * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, you may find one here:
25  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
26  * or you may search the http://www.gnu.org website for the version 2 license,
27  * or you may write to the Free Software Foundation, Inc.,
28  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29  */
30 
31 #include <fctsys.h>
32 #include <common.h>
33 #include <trigo.h>
34 #include <gr_basic.h>
35 #include <class_drawpanel.h>
36 #include <wxBasePcbFrame.h>
37 #include <macros.h>
38 
39 #include <drag.h>
40 #include <pcbnew.h>
41 
42 #include <class_module.h>
43 #include <class_board.h>
44 #include <connect.h>
45 
46 
47 /* a list of DRAG_SEGM_PICKER items used to move or drag tracks */
48 std::vector<DRAG_SEGM_PICKER> g_DragSegmentList;
49 
50 /* helper class to handle a list of track segments to drag or move
51  */
53 {
54  m_Track = aTrack;
59  m_TempFlags = 0;
60  m_RotationOffset = 0.0;
61  m_Flipped = false;
62 }
63 
64 
66 {
67  MODULE* module = NULL;
68 
69  if( m_Pad_Start )
70  {
71  module = m_Pad_Start->GetParent();
73  }
74 
75  if( m_Pad_End )
76  {
77  if( module == NULL )
78  module = m_Pad_End->GetParent();
79 
81  }
82 
83  if( module )
84  {
85  m_Flipped = module->IsFlipped();
86  m_RotationOffset = module->GetOrientation();
87  }
88 }
89 
90 
92 {
93  // the track start position is the pad position + m_PadStartOffset
94  // however m_PadStartOffset is known for the initial rotation/flip
95  // this is also true for track end position and m_PadEndOffset
96  // Therefore, because rotation/flipping is allowed during a drag
97  // and move module, we should recalculate the pad offset,
98  // depending on the current orientation/flip state of the module
99  // relative to its initial orientation.
100  // (although most of time, offset is 0,0)
101 
102  double curr_rot_offset = m_RotationOffset;
103  MODULE* module = NULL;
104  bool flip = false;
105 
106  if( m_Pad_Start )
107  module = m_Pad_Start->GetParent();
108 
109  if( module == NULL && m_Pad_End )
110  module = m_Pad_End->GetParent();
111 
112  if( module )
113  {
114  flip = m_Flipped != module->IsFlipped();
115  curr_rot_offset = module->GetOrientation() - m_RotationOffset;
116 
117  if( flip ) // when flipping, module orientation is negated
118  curr_rot_offset = - module->GetOrientation() - m_RotationOffset;
119  }
120 
121  if( m_Pad_Start )
122  {
123  wxPoint padoffset = m_PadStartOffset;
124 
125  if( curr_rot_offset != 0.0 )
126  RotatePoint(&padoffset, curr_rot_offset);
127 
128  if( flip )
129  padoffset.y = -padoffset.y;
130 
131  m_Track->SetStart( m_Pad_Start->GetPosition() - aOffset + padoffset );
132  }
133 
134  if( m_Pad_End )
135  {
136  wxPoint padoffset = m_PadEndOffset;
137 
138  if( curr_rot_offset != 0.0 )
139  RotatePoint( &padoffset, curr_rot_offset );
140 
141  if( flip )
142  padoffset.y = -padoffset.y;
143 
144  m_Track->SetEnd( m_Pad_End->GetPosition() - aOffset + padoffset );
145  }
146 }
147 
148 
149 // A sort function needed to build ordered pads lists
150 extern bool sortPadsByXthenYCoord( D_PAD* const & ref, D_PAD* const & comp );
151 
152 
154 {
155  m_Pad = NULL;
156  m_Module = aModule;
157 
158  // Build connections info
159  CONNECTIONS connections( m_Brd );
160  std::vector<D_PAD*>&padList = connections.GetPadsList();
161 
162  for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
163  padList.push_back( pad );
164 
165  sort( padList.begin(), padList.end(), sortPadsByXthenYCoord );
166 
167  fillList( connections );
168 }
169 
170 
172 {
173  m_Pad = aPad;
174  m_Module = NULL;
175 
176  // Build connections info
177  CONNECTIONS connections( m_Brd );
178  std::vector<D_PAD*>&padList = connections.GetPadsList();
179  padList.push_back( aPad );
180 
181  fillList( connections );
182 }
183 
184 
185 // A helper function to sort track list per tracks
186 bool sort_tracklist( const DRAG_SEGM_PICKER& ref, const DRAG_SEGM_PICKER& tst )
187 {
188  return ref.m_Track < tst.m_Track;
189 }
190 
191 
192 void DRAG_LIST::fillList( CONNECTIONS& aConnections )
193 {
194  aConnections.BuildTracksCandidatesList( m_Brd->m_Track, NULL);
195 
196  // Build connections info tracks to pads
197  // Rebuild pads to track info only)
198  aConnections.SearchTracksConnectedToPads( false, true );
199 
200  std::vector<D_PAD*>padList = aConnections.GetPadsList();
201 
202  // clear flags and variables of selected tracks
203  for( unsigned ii = 0; ii < padList.size(); ii++ )
204  {
205  D_PAD * pad = padList[ii];
206 
207  // store track connected to the pad
208  for( unsigned jj = 0; jj < pad->m_TracksConnected.size(); jj++ )
209  {
210  TRACK * track = pad->m_TracksConnected[jj];
211  track->start = NULL;
212  track->end = NULL;
213  track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false );
214  }
215  }
216 
217  // store tracks connected to pads
218  for( unsigned ii = 0; ii < padList.size(); ii++ )
219  {
220  D_PAD * pad = padList[ii];
221 
222  // store track connected to the pad
223  for( unsigned jj = 0; jj < pad->m_TracksConnected.size(); jj++ )
224  {
225  TRACK * track = pad->m_TracksConnected[jj];
226 
227  if( pad->HitTest( track->GetStart() ) )
228  {
229  track->start = pad;
230  track->SetState( START_ON_PAD, true );
231  }
232 
233  if( pad->HitTest( track->GetEnd() ) )
234  {
235  track->end = pad;
236  track->SetState( END_ON_PAD, true );
237  }
238 
239  DRAG_SEGM_PICKER wrapper( track );
240  m_DragList.push_back( wrapper );
241  }
242  }
243 
244  // remove duplicate in m_DragList:
245  // a track can be stored more than once if connected to 2 overlapping pads, or
246  // each track end connected to 2 moving pads
247  // to avoid artifact in draw function, items should be not duplicated
248  // However, there is not a lot of items to be removed, so there ir no optimization.
249 
250  // sort the drag list by track pointers
251  sort( m_DragList.begin(), m_DragList.end(), sort_tracklist );
252 
253  // Explore the list, merge duplicates
254  for( int ii = 0; ii < (int)m_DragList.size()-1; ii++ )
255  {
256  int jj = ii+1;
257 
258  if( m_DragList[ii].m_Track != m_DragList[jj].m_Track )
259  continue;
260 
261  // duplicate found: merge info and remove duplicate
262  if( m_DragList[ii].m_Pad_Start == NULL )
263  m_DragList[ii].m_Pad_Start = m_DragList[jj].m_Pad_Start;
264 
265  if( m_DragList[ii].m_Pad_End == NULL )
266  m_DragList[ii].m_Pad_End = m_DragList[jj].m_Pad_End;
267 
268  m_DragList.erase( m_DragList.begin() + jj );
269  ii--;
270  }
271 
272  // Initialize pad offsets and other params
273  for( unsigned ii = 0; ii < m_DragList.size(); ii++ )
274  m_DragList[ii].SetAuxParameters();
275 
276  // Copy the list in global list
278 }
279 
280 
282 {
283  for( unsigned ii = 0; ii < m_DragList.size(); ii++ )
284  m_DragList[ii].m_Track->ClearFlags();
285 
286  m_DragList.clear();
287 
288  m_Module = NULL;
289  m_Pad = NULL;
290 }
291 
292 
293 // Redraw the list of segments stored in g_DragSegmentList, while moving a footprint
295 {
296  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
297  {
298  TRACK* track = g_DragSegmentList[ii].m_Track;
299 
300 #ifndef USE_WX_OVERLAY
301  track->Draw( panel, DC, GR_XOR ); // erase from screen at old position
302 #endif
303  g_DragSegmentList[ii].SetTrackEndsCoordinates( g_Offset_Module );
304  track->Draw( panel, DC, GR_XOR );
305  }
306 }
307 
308 
310 {
311  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
312  g_DragSegmentList[ii].m_Track->ClearFlags();
313 
314  g_DragSegmentList.clear();
315 }
316 
317 
318 void AddSegmentToDragList( int flag, TRACK* aTrack )
319 {
320  DRAG_SEGM_PICKER wrapper( aTrack );
321 
322  if( flag & STARTPOINT )
323  {
324  wrapper.m_TempFlags |= STARTPOINT;
325  aTrack->SetFlags( STARTPOINT );
326  }
327 
328  if( flag & ENDPOINT )
329  {
330  wrapper.m_TempFlags |= ENDPOINT;
331  aTrack->SetFlags( ENDPOINT );
332  }
333 
334  g_DragSegmentList.push_back( wrapper );
335 }
336 
337 
338 void Collect_TrackSegmentsToDrag( BOARD* aPcb, const wxPoint& aRefPos, LSET aLayerMask,
339  int aNetCode, int aMaxDist )
340 {
341  TRACK* track = aPcb->m_Track->GetStartNetCode( aNetCode );
342 
343  for( ; track; track = track->Next() )
344  {
345  if( track->GetNetCode() != aNetCode ) // not the same netcode: all candidates tested
346  break;
347 
348  if( !( aLayerMask & track->GetLayerSet() ).any() )
349  continue; // Cannot be connected, not on the same layer
350 
351  if( track->IsDragging() )
352  continue; // already put in list
353 
354  STATUS_FLAGS flag = 0;
355  int maxdist = std::max( aMaxDist, track->GetWidth() / 2 );
356 
357  if( (track->GetFlags() & STARTPOINT) == 0 )
358  {
359  wxPoint delta = track->GetStart() - aRefPos;
360 
361  if( std::abs( delta.x ) <= maxdist && std::abs( delta.y ) <= maxdist )
362  {
363  int dist = KiROUND( EuclideanNorm( delta ) );
364 
365  if( dist <= maxdist )
366  {
367  flag |= STARTPOINT;
368 
369  if( track->Type() == PCB_VIA_T )
370  flag |= ENDPOINT;
371  }
372  }
373  }
374 
375  if( (track->GetFlags() & ENDPOINT) == 0 )
376  {
377  wxPoint delta = track->GetEnd() - aRefPos;
378 
379  if( std::abs( delta.x ) <= maxdist && std::abs( delta.y ) <= maxdist )
380  {
381  int dist = KiROUND( EuclideanNorm( delta ) );
382 
383  if( dist <= maxdist )
384  flag |= ENDPOINT;
385  }
386  }
387 
388  // Note: vias will be flagged with both STARTPOINT and ENDPOINT
389  // and must not be entered twice.
390  if( flag )
391  {
392  AddSegmentToDragList( flag, track );
393 
394  // If a connected via is found at location aRefPos,
395  // collect also tracks connected by this via.
396  if( track->Type() == PCB_VIA_T )
397  Collect_TrackSegmentsToDrag( aPcb, aRefPos, track->GetLayerSet(),
398  aNetCode, track->GetWidth() / 2 );
399  }
400  }
401 }
402 
403 
404 void UndrawAndMarkSegmentsToDrag( EDA_DRAW_PANEL* aCanvas, wxDC* aDC )
405 {
406  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
407  {
408  TRACK* track = g_DragSegmentList[ii].m_Track;
409 
410  track->Draw( aCanvas, aDC, GR_XOR );
411  track->SetState( IN_EDIT, false );
412  track->SetFlags( IS_DRAGGED );
413 
414  if( g_DragSegmentList[ii].m_TempFlags & STARTPOINT )
415  track->SetFlags( STARTPOINT );
416 
417  if( g_DragSegmentList[ii].m_TempFlags & ENDPOINT )
418  track->SetFlags( ENDPOINT );
419 
420  track->Draw( aCanvas, aDC, GR_XOR );
421  }
422 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:104
MODULE * m_Module
Definition: drag.h:116
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:255
wxPoint g_Offset_Module
Definition: pcbnew.cpp:83
wxPoint m_PadEndOffset
Definition: drag.h:79
int m_TempFlags
Definition: drag.h:68
#define IN_EDIT
Item currently edited.
Definition: base_struct.h:111
void Collect_TrackSegmentsToDrag(BOARD *aPcb, const wxPoint &aRefPos, LSET aLayerMask, int aNetCode, int aMaxDist)
Function Collect_TrackSegmentsToDrag.
Definition: dragsegm.cpp:338
bool HitTest(const wxPoint &aPosition) const override
Function HitTest tests if aPosition is contained within or on the bounding area of an item...
Definition: class_pad.cpp:700
#define END_ON_PAD
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
void fillList(CONNECTIONS &aConnections)
Fills m_DragList with of track segments connected to pads in aConnections For each selected track seg...
Definition: dragsegm.cpp:192
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:117
wxPoint m_startInitialValue
Definition: drag.h:81
bool sortPadsByXthenYCoord(D_PAD *const &ref, D_PAD *const &comp)
Function SortPadsByXCoord is used by GetSortedPadListByXCoord to Sort a pad list by x coordinate valu...
Class BOARD to handle a board.
helper classes to find track to track and track to pad connections.
MODULE * GetParent() const
Definition: class_pad.h:108
bool m_Flipped
Definition: drag.h:74
static const int dist[10][10]
Definition: dist.cpp:57
BOARD * m_Brd
Definition: drag.h:115
void DrawSegmentWhileMovingFootprint(EDA_DRAW_PANEL *panel, wxDC *DC)
Definition: dragsegm.cpp:294
#define BUSY
Pcbnew: flag indicating that the structure has.
Definition: base_struct.h:134
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
wxPoint m_PadStartOffset
Definition: drag.h:77
int GetState(int type) const
Definition: base_struct.h:237
void SetTrackEndsCoordinates(wxPoint aOffset)
Calculate track ends position while dragging pads and when modules are rotated, flipped.
Definition: dragsegm.cpp:91
#define START_ON_PAD
#define abs(a)
Definition: auxiliary.h:84
void SetAuxParameters()
Set auxiliary parameters relative to calculations needed to find track ends positions while dragging ...
Definition: dragsegm.cpp:65
static const int delta[8][2]
Definition: solve.cpp:112
const wxPoint & GetEnd() const
Definition: class_track.h:118
This file contains miscellaneous commonly used macros and functions.
std::vector< DRAG_SEGM_PICKER > m_DragList
Definition: drag.h:119
wxPoint m_endInitialValue
Definition: drag.h:82
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:115
void ClearList()
Function ClearList clear the .m_Flags of all track segments in m_DragList and clear the list...
Definition: dragsegm.cpp:281
DRAG_SEGM_PICKER(TRACK *aTrack)
Definition: dragsegm.cpp:52
Class LSET is a set of PCB_LAYER_IDs.
void BuildTracksCandidatesList(TRACK *aBegin, TRACK *aEnd=NULL)
Function BuildTracksCandidatesList Fills m_Candidates with all connecting points (track ends or via l...
Definition: connect.cpp:252
Classes used in Pcbnew, CvPcb and GerbView.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:253
std::vector< D_PAD * > & GetPadsList()
Function GetPadsList.
Definition: connect.h:120
double GetOrientation() const
Definition: class_module.h:147
D_PAD * m_Pad_Start
Definition: drag.h:62
const wxPoint & GetStart() const
Definition: class_track.h:121
Useful classes and functions used to collect tracks to drag.
const wxPoint & GetPosition() const override
Definition: class_pad.h:170
bool IsFlipped() const
function IsFlipped
Definition: class_module.h:214
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
D_PAD * Next() const
Definition: class_pad.h:106
unsigned STATUS_FLAGS
Definition: base_struct.h:144
D_PAD * m_Pad
Definition: drag.h:117
void SearchTracksConnectedToPads(bool add_to_padlist=true, bool add_to_tracklist=true)
function SearchTracksConnectedToPads Explores the list of pads.
Definition: connect.cpp:114
void EraseDragList()
Function EraseDragList clear the .m_Flags of all track segments stored in g_DragSegmentList and clear...
Definition: dragsegm.cpp:309
int GetNetCode() const
Function GetNetCode.
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
TRACK * Next() const
Definition: class_track.h:98
void SetState(int type, int state)
Definition: base_struct.h:242
D_PAD * m_Pad_End
Definition: drag.h:65
TRACK * GetStartNetCode(int NetCode)
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
int GetWidth() const
Definition: class_track.h:115
void AddSegmentToDragList(int flag, TRACK *aTrack)
Definition: dragsegm.cpp:318
double m_RotationOffset
Definition: drag.h:71
#define ENDPOINT
Definition: base_struct.h:119
void BuildDragListe(MODULE *aModule)
Build the list of track segments connected to pads of aModule in m_DragList For each selected track s...
Definition: dragsegm.cpp:153
The common library.
TRACK * m_Track
Definition: drag.h:61
std::vector< TRACK * > m_TracksConnected
void SetStart(const wxPoint &aStart)
Definition: class_track.h:120
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
DLIST< D_PAD > & Pads()
Definition: class_module.h:133
DLIST< TRACK > m_Track
Definition: class_board.h:244
Module description (excepted pads)
void UndrawAndMarkSegmentsToDrag(EDA_DRAW_PANEL *aCanvas, wxDC *aDC)
Definition: dragsegm.cpp:404
Helper classes to handle a list of track segments to drag and has info to undo/abort the move command...
Definition: drag.h:58
bool sort_tracklist(const DRAG_SEGM_PICKER &ref, const DRAG_SEGM_PICKER &tst)
Definition: dragsegm.cpp:186
BOARD_CONNECTED_ITEM * end
Definition: class_track.h:90
BOARD_CONNECTED_ITEM * start
Definition: class_track.h:89
std::vector< DRAG_SEGM_PICKER > g_DragSegmentList
Definition: dragsegm.cpp:48
#define STARTPOINT
Definition: base_struct.h:118
bool IsDragging() const
Definition: base_struct.h:219