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 <connectivity.h>
45 
46 /* a list of DRAG_SEGM_PICKER items used to move or drag tracks */
47 std::vector<DRAG_SEGM_PICKER> g_DragSegmentList;
48 
49 /* helper class to handle a list of track segments to drag or move
50  */
52 {
53  m_Track = aTrack;
58  m_TempFlags = 0;
59  m_RotationOffset = 0.0;
60  m_Flipped = false;
61 }
62 
63 
65 {
66  MODULE* module = NULL;
67 
68  if( m_Pad_Start )
69  {
70  module = m_Pad_Start->GetParent();
72  }
73 
74  if( m_Pad_End )
75  {
76  if( module == NULL )
77  module = m_Pad_End->GetParent();
78 
80  }
81 
82  if( module )
83  {
84  m_Flipped = module->IsFlipped();
85  m_RotationOffset = module->GetOrientation();
86  }
87 }
88 
89 
91 {
92  // the track start position is the pad position + m_PadStartOffset
93  // however m_PadStartOffset is known for the initial rotation/flip
94  // this is also true for track end position and m_PadEndOffset
95  // Therefore, because rotation/flipping is allowed during a drag
96  // and move module, we should recalculate the pad offset,
97  // depending on the current orientation/flip state of the module
98  // relative to its initial orientation.
99  // (although most of time, offset is 0,0)
100 
101  double curr_rot_offset = m_RotationOffset;
102  MODULE* module = NULL;
103  bool flip = false;
104 
105  if( m_Pad_Start )
106  module = m_Pad_Start->GetParent();
107 
108  if( module == NULL && m_Pad_End )
109  module = m_Pad_End->GetParent();
110 
111  if( module )
112  {
113  flip = m_Flipped != module->IsFlipped();
114  curr_rot_offset = module->GetOrientation() - m_RotationOffset;
115 
116  if( flip ) // when flipping, module orientation is negated
117  curr_rot_offset = - module->GetOrientation() - m_RotationOffset;
118  }
119 
120  if( m_Pad_Start )
121  {
122  wxPoint padoffset = m_PadStartOffset;
123 
124  if( curr_rot_offset != 0.0 )
125  RotatePoint(&padoffset, curr_rot_offset);
126 
127  if( flip )
128  padoffset.y = -padoffset.y;
129 
130  m_Track->SetStart( m_Pad_Start->GetPosition() - aOffset + padoffset );
131  }
132 
133  if( m_Pad_End )
134  {
135  wxPoint padoffset = m_PadEndOffset;
136 
137  if( curr_rot_offset != 0.0 )
138  RotatePoint( &padoffset, curr_rot_offset );
139 
140  if( flip )
141  padoffset.y = -padoffset.y;
142 
143  m_Track->SetEnd( m_Pad_End->GetPosition() - aOffset + padoffset );
144  }
145 }
146 
147 
148 // A sort function needed to build ordered pads lists
149 extern bool sortPadsByXthenYCoord( D_PAD* const & ref, D_PAD* const & comp );
150 
151 
153 {
154  m_Pad = NULL;
155  m_Module = aModule;
156 
157  std::vector<D_PAD*> padList;
158 
159  for( auto pad : aModule->Pads() )
160  padList.push_back( pad );
161 
162  sort( padList.begin(), padList.end(), sortPadsByXthenYCoord );
163 
164  fillList( padList );
165 }
166 
167 
169 {
170  m_Pad = aPad;
171  m_Module = NULL;
172 
173  // Build connections info
174  std::vector<D_PAD*> padList;
175  padList.push_back( aPad );
176 
177  fillList( padList );
178 }
179 
180 
181 // A helper function to sort track list per tracks
182 bool sort_tracklist( const DRAG_SEGM_PICKER& ref, const DRAG_SEGM_PICKER& tst )
183 {
184  return ref.m_Track < tst.m_Track;
185 }
186 
187 void DRAG_LIST::fillList( std::vector<D_PAD*>& aList )
188 {
189  // clear flags and variables of selected tracks
190  for( auto pad : aList )
191  {
192  auto connectedTracks = m_Brd->GetConnectivity()->GetConnectedTracks( pad );
193 
194  // store track connected to the pad
195  for( auto track : connectedTracks )
196  {
197  track->start = NULL;
198  track->end = NULL;
199  track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false );
200  }
201  }
202 
203  // store tracks connected to pads
204  for( auto pad : aList )
205  {
206  auto connectedTracks = m_Brd->GetConnectivity()->GetConnectedTracks( pad );
207 
208  // store track connected to the pad
209  for( auto track : connectedTracks )
210  {
211  if( pad->HitTest( track->GetStart() ) )
212  {
213  track->start = pad;
214  track->SetState( START_ON_PAD, true );
215  }
216 
217  if( pad->HitTest( track->GetEnd() ) )
218  {
219  track->end = pad;
220  track->SetState( END_ON_PAD, true );
221  }
222 
223  DRAG_SEGM_PICKER wrapper( track );
224  m_DragList.push_back( wrapper );
225  }
226  }
227 
228  // remove duplicate in m_DragList:
229  // a track can be stored more than once if connected to 2 overlapping pads, or
230  // each track end connected to 2 moving pads
231  // to avoid artifact in draw function, items should be not duplicated
232  // However, there is not a lot of items to be removed, so there ir no optimization.
233 
234  // sort the drag list by track pointers
235  sort( m_DragList.begin(), m_DragList.end(), sort_tracklist );
236 
237  // Explore the list, merge duplicates
238  for( int ii = 0; ii < (int)m_DragList.size()-1; ii++ )
239  {
240  int jj = ii+1;
241 
242  if( m_DragList[ii].m_Track != m_DragList[jj].m_Track )
243  continue;
244 
245  // duplicate found: merge info and remove duplicate
246  if( m_DragList[ii].m_Pad_Start == NULL )
247  m_DragList[ii].m_Pad_Start = m_DragList[jj].m_Pad_Start;
248 
249  if( m_DragList[ii].m_Pad_End == NULL )
250  m_DragList[ii].m_Pad_End = m_DragList[jj].m_Pad_End;
251 
252  m_DragList.erase( m_DragList.begin() + jj );
253  ii--;
254  }
255 
256  // Initialize pad offsets and other params
257  for( unsigned ii = 0; ii < m_DragList.size(); ii++ )
258  m_DragList[ii].SetAuxParameters();
259 
260  // Copy the list in global list
262 }
263 
264 
266 {
267  for( unsigned ii = 0; ii < m_DragList.size(); ii++ )
268  m_DragList[ii].m_Track->ClearFlags();
269 
270  m_DragList.clear();
271 
272  m_Module = NULL;
273  m_Pad = NULL;
274 }
275 
276 
277 // Redraw the list of segments stored in g_DragSegmentList, while moving a footprint
279 {
280  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
281  {
282  TRACK* track = g_DragSegmentList[ii].m_Track;
283 
284 #ifndef USE_WX_OVERLAY
285  track->Draw( panel, DC, GR_XOR ); // erase from screen at old position
286 #endif
287  g_DragSegmentList[ii].SetTrackEndsCoordinates( g_Offset_Module );
288  track->Draw( panel, DC, GR_XOR );
289  }
290 }
291 
292 
294 {
295  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
296  g_DragSegmentList[ii].m_Track->ClearFlags();
297 
298  g_DragSegmentList.clear();
299 }
300 
301 
302 void AddSegmentToDragList( int flag, TRACK* aTrack )
303 {
304  DRAG_SEGM_PICKER wrapper( aTrack );
305 
306  if( flag & STARTPOINT )
307  {
308  wrapper.m_TempFlags |= STARTPOINT;
309  aTrack->SetFlags( STARTPOINT );
310  }
311 
312  if( flag & ENDPOINT )
313  {
314  wrapper.m_TempFlags |= ENDPOINT;
315  aTrack->SetFlags( ENDPOINT );
316  }
317 
318  g_DragSegmentList.push_back( wrapper );
319 }
320 
321 
322 void Collect_TrackSegmentsToDrag( BOARD* aPcb, const wxPoint& aRefPos, LSET aLayerMask,
323  int aNetCode, int aMaxDist )
324 {
325  TRACK* track = aPcb->m_Track->GetStartNetCode( aNetCode );
326 
327  for( ; track; track = track->Next() )
328  {
329  if( track->GetNetCode() != aNetCode ) // not the same netcode: all candidates tested
330  break;
331 
332  if( !( aLayerMask & track->GetLayerSet() ).any() )
333  continue; // Cannot be connected, not on the same layer
334 
335  if( track->IsDragging() )
336  continue; // already put in list
337 
338  STATUS_FLAGS flag = 0;
339  int maxdist = std::max( aMaxDist, track->GetWidth() / 2 );
340 
341  if( (track->GetFlags() & STARTPOINT) == 0 )
342  {
343  wxPoint delta = track->GetStart() - aRefPos;
344 
345  if( std::abs( delta.x ) <= maxdist && std::abs( delta.y ) <= maxdist )
346  {
347  int dist = KiROUND( EuclideanNorm( delta ) );
348 
349  if( dist <= maxdist )
350  {
351  flag |= STARTPOINT;
352 
353  if( track->Type() == PCB_VIA_T )
354  flag |= ENDPOINT;
355  }
356  }
357  }
358 
359  if( (track->GetFlags() & ENDPOINT) == 0 )
360  {
361  wxPoint delta = track->GetEnd() - aRefPos;
362 
363  if( std::abs( delta.x ) <= maxdist && std::abs( delta.y ) <= maxdist )
364  {
365  int dist = KiROUND( EuclideanNorm( delta ) );
366 
367  if( dist <= maxdist )
368  flag |= ENDPOINT;
369  }
370  }
371 
372  // Note: vias will be flagged with both STARTPOINT and ENDPOINT
373  // and must not be entered twice.
374  if( flag )
375  {
376  AddSegmentToDragList( flag, track );
377 
378  // If a connected via is found at location aRefPos,
379  // collect also tracks connected by this via.
380  if( track->Type() == PCB_VIA_T )
381  Collect_TrackSegmentsToDrag( aPcb, aRefPos, track->GetLayerSet(),
382  aNetCode, track->GetWidth() / 2 );
383  }
384  }
385 }
386 
387 
388 void UndrawAndMarkSegmentsToDrag( EDA_DRAW_PANEL* aCanvas, wxDC* aDC )
389 {
390  for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
391  {
392  TRACK* track = g_DragSegmentList[ii].m_Track;
393 
394  track->Draw( aCanvas, aDC, GR_XOR );
395  track->SetState( IN_EDIT, false );
396  track->SetFlags( IS_DRAGGED );
397 
398  if( g_DragSegmentList[ii].m_TempFlags & STARTPOINT )
399  track->SetFlags( STARTPOINT );
400 
401  if( g_DragSegmentList[ii].m_TempFlags & ENDPOINT )
402  track->SetFlags( ENDPOINT );
403 
404  track->Draw( aCanvas, aDC, GR_XOR );
405  }
406 }
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:73
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:322
#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 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.
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
DLIST_ITERATOR_WRAPPER< D_PAD > Pads()
Definition: class_module.h:140
BOARD * m_Brd
Definition: drag.h:115
void DrawSegmentWhileMovingFootprint(EDA_DRAW_PANEL *panel, wxDC *DC)
Definition: dragsegm.cpp:278
#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:90
#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:64
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:265
DRAG_SEGM_PICKER(TRACK *aTrack)
Definition: dragsegm.cpp:51
Class LSET is a set of PCB_LAYER_IDs.
Classes used in Pcbnew, CvPcb and GerbView.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:253
double GetOrientation() const
Definition: class_module.h:160
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:227
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
unsigned STATUS_FLAGS
Definition: base_struct.h:144
D_PAD * m_Pad
Definition: drag.h:117
void EraseDragList()
Function EraseDragList clear the .m_Flags of all track segments stored in g_DragSegmentList and clear...
Definition: dragsegm.cpp:293
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:169
int GetWidth() const
Definition: class_track.h:115
void AddSegmentToDragList(int flag, TRACK *aTrack)
Definition: dragsegm.cpp:302
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:152
The common library.
void fillList(std::vector< D_PAD * > &aList)
Fills m_DragList with of track segments connected to pads in aConnections For each selected track seg...
Definition: dragsegm.cpp:187
TRACK * m_Track
Definition: drag.h:61
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< TRACK > m_Track
Definition: class_board.h:246
Module description (excepted pads)
void UndrawAndMarkSegmentsToDrag(EDA_DRAW_PANEL *aCanvas, wxDC *aDC)
Definition: dragsegm.cpp:388
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:182
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:47
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:290
#define STARTPOINT
Definition: base_struct.h:118
bool IsDragging() const
Definition: base_struct.h:219