KiCad PCB EDA Suite
grid_helper.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <functional>
26 using namespace std::placeholders;
27 
28 #include <wxPcbStruct.h>
29 
30 #include <class_board.h>
31 #include <class_module.h>
32 #include <class_edge_mod.h>
33 #include <class_zone.h>
34 #include <class_draw_panel_gal.h>
35 
36 #include <view/view.h>
37 #include <view/view_controls.h>
39 
41 
42 #include "grid_helper.h"
43 
44 
46  m_frame( aFrame )
47 {
50 
51  m_viewAxis.SetSize( 20000 );
53  m_viewAxis.SetColor( COLOR4D( 1.0, 1.0, 1.0, 0.4 ) );
54  m_viewAxis.SetDrawAtZero( true );
55  view->Add( &m_viewAxis );
56  view->SetVisible( &m_viewAxis, false );
57 
59  m_viewSnapPoint.SetColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
61  view->Add( &m_viewSnapPoint );
62  view->SetVisible( &m_viewSnapPoint, false );
63 }
64 
65 
67 {
68 }
69 
70 
71 void GRID_HELPER::SetGrid( int aSize )
72 {
73  assert( false );
74 }
75 
76 
77 void GRID_HELPER::SetOrigin( const VECTOR2I& aOrigin )
78 {
79  assert( false );
80 }
81 
82 
84 {
85  PCB_SCREEN* screen = m_frame->GetScreen();
86 
87  const wxRealPoint& size = screen->GetGridSize();
88 
89  return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
90 }
91 
92 
94 {
95  return VECTOR2I( m_frame->GetGridOrigin() );
96 }
97 
98 
99 void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin, bool aEnableDiagonal )
100 {
101  KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView();
102 
103  if( aEnable )
104  {
105  m_auxAxis = aOrigin;
106  m_viewAxis.SetPosition( aOrigin );
107  view->SetVisible( &m_viewAxis, true );
108  }
109  else
110  {
112  view->SetVisible( &m_viewAxis, false );
113  }
114 
115  m_diagonalAuxAxesEnable = aEnable;
116 }
117 
118 
119 VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) const
120 {
121  const VECTOR2D gridOffset( GetOrigin() );
122  const VECTOR2D gridSize( GetGrid() );
123 
124  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
125  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
126 
127  if( !m_auxAxis )
128  return nearest;
129 
130  if( std::abs( m_auxAxis->x - aPoint.x ) < std::abs( nearest.x - aPoint.x ) )
131  nearest.x = m_auxAxis->x;
132 
133  if( std::abs( m_auxAxis->y - aPoint.y ) < std::abs( nearest.y - aPoint.y ) )
134  nearest.y = m_auxAxis->y;
135 
136  return nearest;
137 }
138 
139 
140 VECTOR2I GRID_HELPER::AlignToSegment( const VECTOR2I& aPoint, const SEG& aSeg )
141 {
142  OPT_VECTOR2I pts[6];
143 
144  const VECTOR2D gridOffset( GetOrigin() );
145  const VECTOR2D gridSize( GetGrid() );
146 
147  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
148  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
149 
150  pts[0] = aSeg.A;
151  pts[1] = aSeg.B;
152  pts[2] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 1, 0 ) ) );
153  pts[3] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 0, 1 ) ) );
154 
155  int min_d = std::numeric_limits<int>::max();
156 
157  for( int i = 0; i < 4; i++ )
158  {
159  if( pts[i] && aSeg.Contains( *pts[i] ) )
160  {
161  int d = (*pts[i] - aPoint).EuclideanNorm();
162 
163  if( d < min_d )
164  {
165  min_d = d;
166  nearest = *pts[i];
167  }
168  }
169  }
170 
171  return nearest;
172 }
173 
174 
176 {
177  clearAnchors();
178  computeAnchors( aItem, aMousePos );
179 
180  double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
181  double lineSnapMinCornerDistance = 50.0 / worldScale;
182 
183  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
184  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
185  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
186  ANCHOR* best = NULL;
187  double minDist = std::numeric_limits<double>::max();
188 
189  if( nearestOrigin )
190  {
191  minDist = nearestOrigin->Distance( aMousePos );
192  best = nearestOrigin;
193  }
194 
195  if( nearestCorner )
196  {
197  double dist = nearestCorner->Distance( aMousePos );
198 
199  if( dist < minDist )
200  {
201  minDist = dist;
202  best = nearestCorner;
203  }
204  }
205 
206  if( nearestOutline )
207  {
208  double dist = nearestOutline->Distance( aMousePos );
209 
210  if( minDist > lineSnapMinCornerDistance && dist < minDist )
211  best = nearestOutline;
212  }
213 
214  return best ? best->pos : aMousePos;
215 }
216 
217 
218 std::set<BOARD_ITEM*> GRID_HELPER::queryVisible( const BOX2I& aArea ) const
219 {
220  std::set<BOARD_ITEM*> items;
221 
222  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
223  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
224 
225  auto view = m_frame->GetGalCanvas()->GetView();
226  view->Query( aArea, selectedItems ); // Get the list of selected items
227 
228  for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
229  {
230  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
231 
232  if( view->IsVisible( item ) )
233  items.insert ( item );
234  }
235 
236  return items;
237 }
238 
239 
240 VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDraggedItem )
241 {
242  double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
243  int snapRange = (int) ( 100.0 / worldScale );
244 
245  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ), VECTOR2I( snapRange, snapRange ) );
246 
247  clearAnchors();
248 
249  for( BOARD_ITEM* item : queryVisible( bb ) )
250  {
251  computeAnchors( item, aOrigin );
252  }
253 
254  LSET layers;
255 
256  if( aDraggedItem )
257  layers = aDraggedItem->GetLayer();
258  else
259  layers = LSET::AllLayersMask();
260 
261  ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers );
262 
263  VECTOR2I nearestGrid = Align( aOrigin );
264  double gridDist = ( nearestGrid - aOrigin ).EuclideanNorm();
265 
266  if( nearest )
267  {
268  double snapDist = nearest->Distance( aOrigin );
269 
270  if( nearest && snapDist < gridDist )
271  {
272  m_viewSnapPoint.SetPosition( nearest->pos );
274  return nearest->pos;
275  }
276  }
277 
279  return nearestGrid;
280 }
281 
282 
283 void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos )
284 {
285  VECTOR2I origin;
286 
287  switch( aItem->Type() )
288  {
289  case PCB_MODULE_T:
290  {
291  MODULE* mod = static_cast<MODULE*>( aItem );
292 
293  for( auto pad : mod->Pads() )
294  {
295  if( pad->GetBoundingBox().Contains( wxPoint( aRefPos.x, aRefPos.y ) ) )
296  {
297  addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
298  break;
299  }
300  }
301 
302  // if the cursor is not over a pad, then drag the module by its origin
303  addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod );
304  break;
305  }
306 
307  case PCB_PAD_T:
308  {
309  D_PAD* pad = static_cast<D_PAD*>( aItem );
310  addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
311 
312  break;
313  }
314 
315  case PCB_MODULE_EDGE_T:
316  case PCB_LINE_T:
317  {
318  DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem );
319  VECTOR2I start = dseg->GetStart();
320  VECTOR2I end = dseg->GetEnd();
321  //PCB_LAYER_ID layer = dseg->GetLayer();
322 
323  switch( dseg->GetShape() )
324  {
325  case S_CIRCLE:
326  {
327  int r = ( start - end ).EuclideanNorm();
328 
329  addAnchor( start, ORIGIN | SNAPPABLE, dseg );
330  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg );
331  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg );
332  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg );
333  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg );
334  break;
335  }
336 
337  case S_ARC:
338  {
339  origin = dseg->GetCenter();
340  addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg );
341  addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg );
342  addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
343  break;
344  }
345 
346  case S_SEGMENT:
347  {
348  origin.x = start.x + ( start.x - end.x ) / 2;
349  origin.y = start.y + ( start.y - end.y ) / 2;
350  addAnchor( start, CORNER | SNAPPABLE, dseg );
351  addAnchor( end, CORNER | SNAPPABLE, dseg );
352  addAnchor( origin, ORIGIN, dseg );
353  break;
354  }
355 
356  default:
357  {
358  origin = dseg->GetStart();
359  addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
360  break;
361  }
362  }
363  break;
364  }
365 
366  case PCB_TRACE_T:
367  {
368  TRACK* track = static_cast<TRACK*>( aItem );
369  VECTOR2I start = track->GetStart();
370  VECTOR2I end = track->GetEnd();
371  origin.x = start.x + ( start.x - end.x ) / 2;
372  origin.y = start.y + ( start.y - end.y ) / 2;
373  addAnchor( start, CORNER | SNAPPABLE, track );
374  addAnchor( end, CORNER | SNAPPABLE, track );
375  addAnchor( origin, ORIGIN, track);
376  break;
377  }
378 
379  case PCB_VIA_T:
380  addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem );
381  break;
382 
383  case PCB_ZONE_AREA_T:
384  {
385  const SHAPE_POLY_SET* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
386 
387  SHAPE_LINE_CHAIN lc;
388  lc.SetClosed( true );
389 
390  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
391  {
392  addAnchor( *iter, CORNER, aItem );
393  lc.Append( *iter );
394  }
395 
396  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
397 
398  break;
399  }
400 
401  case PCB_MODULE_TEXT_T:
402  case PCB_TEXT_T:
403  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
404  default:
405 
406  break;
407  }
408 }
409 
410 
411 GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int aFlags, LSET aMatchLayers )
412 {
413  double minDist = std::numeric_limits<double>::max();
414  ANCHOR* best = NULL;
415 
416  for( ANCHOR& a : m_anchors )
417  {
418  if( !aMatchLayers[a.item->GetLayer()] )
419  continue;
420 
421  if( ( aFlags & a.flags ) != aFlags )
422  continue;
423 
424  double dist = a.Distance( aPos );
425 
426  if( dist < minDist )
427  {
428  minDist = dist;
429  best = &a;
430  }
431  }
432 
433  return best;
434 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:104
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, BOARD_ITEM *aItem)
KICAD_T Type() const
Function Type()
Definition: base_struct.h:212
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
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
int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Function Query() Finds all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:418
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
void SetGrid(int aSize)
Definition: grid_helper.cpp:71
const wxPoint GetCenter() const override
Function GetCenter()
double GetWorldScale() const
Get the world scale.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
VECTOR2I Align(const VECTOR2I &aPoint) const
VIEW_CONTROLS class definition.
GRID_HELPER(PCB_BASE_FRAME *aFrame)
Definition: grid_helper.cpp:45
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:155
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Function IntersectLines()
Definition: seg.h:170
CONST_ITERATOR CIterateWithHoles(int aOutline) const
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:107
const wxPoint & GetGridOrigin() const override
Function GetGridOrigin returns the absolute coordinates of the origin of the snap grid...
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:114
static const int dist[10][10]
Definition: dist.cpp:57
DLIST_ITERATOR_WRAPPER< D_PAD > Pads()
Definition: class_module.h:140
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea) const
bool m_diagonalAuxAxesEnable
Definition: grid_helper.h:106
virtual const wxPoint & GetPosition() const =0
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:104
Classes to handle copper zones.
usual segment : line with rounded ends
class D_PAD, a pad in a footprint
Definition: typeinfo.h:102
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem)
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:83
void SetOrigin(const VECTOR2I &aOrigin)
Definition: grid_helper.cpp:77
KIGFX::VIEW * GetView() const
Function GetView() Returns a pointer to the VIEW instance used in the panel.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590
#define abs(a)
Definition: auxiliary.h:84
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
const wxPoint & GetEnd() const
Definition: class_track.h:118
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:78
const wxPoint & GetArcStart() const
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:107
class MODULE, a footprint
Definition: typeinfo.h:101
void SetClosed(bool aClosed)
Function SetClosed()
KIGFX::GAL * GetGAL() const
Function GetGAL() Returns a pointer to the GAL instance used in the panel.
STROKE_T GetShape() const
Class LSET is a set of PCB_LAYER_IDs.
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
void SetPosition(const VECTOR2D &aPosition)
Class SHAPE_POLY_SET.
const wxPoint & GetStart() const
Definition: class_track.h:121
const wxPoint & GetPosition() const override
Definition: class_pad.h:206
void SetSize(int aSize)
Arcs (with rounded ends)
void SetDrawAtZero(bool aDrawFlag)
Function SetDrawAtZero() Set the draw at zero flag.
boost::optional< VECTOR2I > m_auxAxis
Definition: grid_helper.h:105
VECTOR2I GetOrigin() const
Definition: grid_helper.cpp:93
static LSET AllLayersMask()
Definition: lset.cpp:683
void addAnchor(const VECTOR2I &aPos, int aFlags=CORNER|SNAPPABLE, BOARD_ITEM *aItem=NULL)
Definition: grid_helper.h:90
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:105
Definition: seg.h:37
#define max(a, b)
Definition: auxiliary.h:86
Class SHAPE_LINE_CHAIN.
PCB_BASE_FRAME * m_frame
Definition: grid_helper.h:104
const wxPoint GetArcEnd() const
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
VECTOR2I A
Definition: seg.h:47
void SetColor(const KIGFX::COLOR4D &aColor)
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0), bool aEnableDiagonal=false)
Definition: grid_helper.cpp:99
PCB_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
void computeAnchors(BOARD_ITEM *aItem, const VECTOR2I &aRefPos)
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1331
EDA_DRAW_PANEL_GAL * GetGalCanvas() const
Function GetGalCanvas returns a pointer to GAL-based canvas of given EDA draw frame.
Definition: draw_frame.h:870
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:312
Module description (excepted pads)
Class VIEW.
Definition: view.h:58
void SetStyle(MARKER_STYLE aStyle)
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
bool Contains(const VECTOR2I &aP) const
Definition: seg.cpp:155
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:86
#define mod(a, n)
Definition: greymap.cpp:24
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
void clearAnchors()
Definition: grid_helper.h:99
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
VECTOR2I B
Definition: seg.h:48