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 
45  m_frame( aFrame )
46 {
48 }
49 
50 
52 {
53 }
54 
55 
56 void GRID_HELPER::SetGrid( int aSize )
57 {
58  assert( false );
59 }
60 
61 
62 void GRID_HELPER::SetOrigin( const VECTOR2I& aOrigin )
63 {
64  assert( false );
65 }
66 
67 
69 {
70  PCB_SCREEN* screen = m_frame->GetScreen();
71 
72  const wxRealPoint& size = screen->GetGridSize();
73 
74  return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
75 }
76 
77 
79 {
80  return VECTOR2I( m_frame->GetGridOrigin() );
81 }
82 
83 
84 void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin, bool aEnableDiagonal )
85 {
86  if( aEnable )
87  m_auxAxis = aOrigin;
88  else
90 
91  m_diagonalAuxAxesEnable = aEnable;
92 }
93 
94 
95 VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) const
96 {
97  const VECTOR2D gridOffset( GetOrigin() );
98  const VECTOR2D gridSize( GetGrid() );
99 
100  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
101  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
102 
103  if( !m_auxAxis )
104  return nearest;
105 
106  if( std::abs( m_auxAxis->x - aPoint.x ) < std::abs( nearest.x - aPoint.x ) )
107  nearest.x = m_auxAxis->x;
108 
109  if( std::abs( m_auxAxis->y - aPoint.y ) < std::abs( nearest.y - aPoint.y ) )
110  nearest.y = m_auxAxis->y;
111 
112  return nearest;
113 }
114 
115 
116 VECTOR2I GRID_HELPER::AlignToSegment ( const VECTOR2I& aPoint, const SEG& aSeg )
117 {
118  OPT_VECTOR2I pts[6];
119 
120  const VECTOR2D gridOffset( GetOrigin() );
121  const VECTOR2D gridSize( GetGrid() );
122 
123  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
124  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
125 
126  pts[0] = aSeg.A;
127  pts[1] = aSeg.B;
128  pts[2] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 1, 0 ) ) );
129  pts[3] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 0, 1 ) ) );
130 
131  int min_d = std::numeric_limits<int>::max();
132 
133  for( int i = 0; i < 4; i++ )
134  {
135  if( pts[i] && aSeg.Contains( *pts[i] ) )
136  {
137  int d = (*pts[i] - aPoint).EuclideanNorm();
138 
139  if( d < min_d )
140  {
141  min_d = d;
142  nearest = *pts[i];
143  }
144  }
145  }
146 
147  return nearest;
148 }
149 
151 {
152  clearAnchors();
153  computeAnchors( aItem, aMousePos );
154 
155  double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
156  double lineSnapMinCornerDistance = 50.0 / worldScale;
157 
158  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
159  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
160  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
161  ANCHOR* best = NULL;
162  double minDist = std::numeric_limits<double>::max();
163 
164  if( nearestOrigin )
165  {
166  minDist = nearestOrigin->Distance( aMousePos );
167  best = nearestOrigin;
168  }
169 
170  if( nearestCorner )
171  {
172  double dist = nearestCorner->Distance( aMousePos );
173 
174  if( dist < minDist )
175  {
176  minDist = dist;
177  best = nearestCorner;
178  }
179  }
180 
181  if( nearestOutline )
182  {
183  double dist = nearestOutline->Distance( aMousePos );
184 
185  if( minDist > lineSnapMinCornerDistance && dist < minDist )
186  best = nearestOutline;
187  }
188 
189  return best ? best->pos : aMousePos;
190 }
191 
192 
193 std::set<BOARD_ITEM*> GRID_HELPER::queryVisible( const BOX2I& aArea ) const
194 {
195  std::set<BOARD_ITEM*> items;
196 
197  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
198  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
199 
200  auto view = m_frame->GetGalCanvas()->GetView();
201  view->Query( aArea, selectedItems ); // Get the list of selected items
202 
203  for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
204  {
205  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
206 
207  if( view->IsVisible( item ) )
208  items.insert ( item );
209  }
210 
211  return items;
212 }
213 
214 
215 VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDraggedItem )
216 {
217  double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
218  int snapRange = (int) ( 100.0 / worldScale );
219 
220  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ), VECTOR2I( snapRange, snapRange ) );
221 
222  clearAnchors();
223 
224  for( BOARD_ITEM* item : queryVisible( bb ) )
225  {
226  computeAnchors( item, aOrigin );
227  }
228 
229  LSET layers( aDraggedItem->GetLayer() );
230  ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers );
231 
232  VECTOR2I nearestGrid = Align( aOrigin );
233  double gridDist = ( nearestGrid - aOrigin ).EuclideanNorm();
234  if( nearest )
235  {
236  double snapDist = nearest->Distance( aOrigin );
237 
238  if( nearest && snapDist < gridDist )
239  return nearest->pos;
240  }
241 
242  return nearestGrid;
243 }
244 
245 
246 void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos )
247 {
248  VECTOR2I origin;
249 
250  switch( aItem->Type() )
251  {
252  case PCB_MODULE_T:
253  {
254  MODULE* mod = static_cast<MODULE*>( aItem );
255  addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod );
256 
257  for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() )
258  addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
259 
260  break;
261  }
262 
263 
264  case PCB_PAD_T:
265  {
266  D_PAD* pad = static_cast<D_PAD*>( aItem );
267  addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
268 
269  break;
270  }
271 
272  case PCB_MODULE_EDGE_T:
273  case PCB_LINE_T:
274  {
275  DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem );
276  VECTOR2I start = dseg->GetStart();
277  VECTOR2I end = dseg->GetEnd();
278  //LAYER_ID layer = dseg->GetLayer();
279 
280  switch( dseg->GetShape() )
281  {
282  case S_CIRCLE:
283  {
284  int r = ( start - end ).EuclideanNorm();
285 
286  addAnchor( start, ORIGIN | SNAPPABLE, dseg );
287  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg );
288  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg );
289  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg );
290  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg );
291  break;
292  }
293 
294  case S_ARC:
295  {
296  origin = dseg->GetCenter();
297  addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg );
298  addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg );
299  addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
300  break;
301  }
302 
303  case S_SEGMENT:
304  {
305  origin.x = start.x + ( start.x - end.x ) / 2;
306  origin.y = start.y + ( start.y - end.y ) / 2;
307  addAnchor( start, CORNER | SNAPPABLE, dseg );
308  addAnchor( end, CORNER | SNAPPABLE, dseg );
309  addAnchor( origin, ORIGIN, dseg );
310  break;
311  }
312 
313  default:
314  {
315  origin = dseg->GetStart();
316  addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
317  break;
318  }
319  }
320  break;
321  }
322 
323  case PCB_TRACE_T:
324  {
325  TRACK* track = static_cast<TRACK*>( aItem );
326  VECTOR2I start = track->GetStart();
327  VECTOR2I end = track->GetEnd();
328  origin.x = start.x + ( start.x - end.x ) / 2;
329  origin.y = start.y + ( start.y - end.y ) / 2;
330  addAnchor( start, CORNER | SNAPPABLE, track );
331  addAnchor( end, CORNER | SNAPPABLE, track );
332  addAnchor( origin, ORIGIN, track);
333  break;
334  }
335 
336  case PCB_VIA_T:
337  addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem );
338  break;
339 
340  case PCB_ZONE_AREA_T:
341  {
342  const SHAPE_POLY_SET* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
343 
344  SHAPE_LINE_CHAIN lc;
345  lc.SetClosed( true );
346 
347  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
348  {
349  addAnchor( *iter, CORNER, aItem );
350  lc.Append( *iter );
351  }
352 
353  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
354 
355  break;
356  }
357 
358  case PCB_MODULE_TEXT_T:
359  case PCB_TEXT_T:
360  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
361  default:
362 
363  break;
364  }
365 }
366 
367 
368 GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int aFlags, LSET aMatchLayers )
369 {
370  double minDist = std::numeric_limits<double>::max();
371  ANCHOR* best = NULL;
372 
373  for( ANCHOR& a : m_anchors )
374  {
375  if( !aMatchLayers[a.item->GetLayer()] )
376  continue;
377 
378  if( ( aFlags & a.flags ) != aFlags )
379  continue;
380 
381  double dist = a.Distance( aPos );
382 
383  if( dist < minDist )
384  {
385  minDist = dist;
386  best = &a;
387  }
388  }
389 
390  return best;
391 }
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:198
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
VECTOR2I & B
Definition: seg.h:52
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:416
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:56
const wxPoint GetCenter() const override
Function GetCenter()
double GetWorldScale() const
Get the world scale.
VECTOR2I Align(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:95
VIEW_CONTROLS class definition.
GRID_HELPER(PCB_BASE_FRAME *aFrame)
Definition: grid_helper.cpp:44
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:143
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Function IntersectLines()
Definition: seg.h:212
CONST_ITERATOR CIterateWithHoles(int aOutline) const
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
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea) const
bool m_diagonalAuxAxesEnable
Definition: grid_helper.h:105
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:68
void SetOrigin(const VECTOR2I &aOrigin)
Definition: grid_helper.cpp:62
KIGFX::VIEW * GetView() const
Function GetView() Returns a pointer to the VIEW instance used in the panel.
LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
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:117
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:77
const wxPoint & GetArcStart() const
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.
VECTOR2I & A
Definition: seg.h:51
STROKE_T GetShape() const
Class LSET is a set of LAYER_IDs.
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Class SHAPE_POLY_SET.
const wxPoint & GetStart() const
Definition: class_track.h:120
const wxPoint & GetPosition() const override
Definition: class_pad.h:170
Arcs (with rounded ends)
boost::optional< VECTOR2I > m_auxAxis
Definition: grid_helper.h:104
D_PAD * Next() const
Definition: class_pad.h:106
VECTOR2I GetOrigin() const
Definition: grid_helper.cpp:78
static LSET AllLayersMask()
Definition: lset.cpp:675
void addAnchor(const VECTOR2I &aPos, int aFlags=CORNER|SNAPPABLE, BOARD_ITEM *aItem=NULL)
Definition: grid_helper.h:89
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:103
const wxPoint GetArcEnd() const
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0), bool aEnableDiagonal=false)
Definition: grid_helper.cpp:84
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)
EDA_DRAW_PANEL_GAL * GetGalCanvas() const
Function GetGalCanvas returns a pointer to GAL-based canvas of given EDA draw frame.
Definition: draw_frame.h:803
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
Module description (excepted pads)
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:85
#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:98