KiCad PCB EDA Suite
ee_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  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <functional>
27 using namespace std::placeholders;
28 
30 #include <macros.h>
31 #include <math/util.h> // for KiROUND
32 #include <math/vector2d.h>
33 #include <sch_item.h>
34 #include <sch_painter.h>
35 #include <tool/tool_manager.h>
36 #include <view/view.h>
37 #include <view/view_controls.h>
38 
39 #include "ee_grid_helper.h"
40 
41 
43  m_toolMgr( aToolMgr )
44 {
45  m_enableSnap = true;
46  m_enableSnapLine = true;
47  m_snapItem = nullptr;
48  KIGFX::VIEW* view = m_toolMgr->GetView();
49 
50  m_viewAxis.SetSize( 20000 );
52  m_viewAxis.SetColor( COLOR4D( 0.0, 0.1, 0.4, 0.8 ) );
53  m_viewAxis.SetDrawAtZero( true );
54  view->Add( &m_viewAxis );
55  view->SetVisible( &m_viewAxis, false );
56 
58  m_viewSnapPoint.SetColor( COLOR4D( 0.0, 0.1, 0.4, 1.0 ) );
60  view->Add( &m_viewSnapPoint );
61  view->SetVisible( &m_viewSnapPoint, false );
62 
64  m_viewSnapLine.SetColor( COLOR4D( 0.33, 0.55, 0.95, 1.0 ) );
66  view->Add( &m_viewSnapLine );
67  view->SetVisible( &m_viewSnapLine, false );
68 }
69 
70 
72 {
73 }
74 
75 
77 {
79 
80  return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
81 }
82 
83 
85 {
86  VECTOR2D origin = m_toolMgr->GetView()->GetGAL()->GetGridOrigin();
87 
88  return VECTOR2I( origin );
89 }
90 
91 
92 void EE_GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin )
93 {
94  if( aEnable )
95  {
96  m_auxAxis = aOrigin;
97  m_viewAxis.SetPosition( wxPoint( aOrigin ) );
98  m_toolMgr->GetView()->SetVisible( &m_viewAxis, true );
99  }
100  else
101  {
103  m_toolMgr->GetView()->SetVisible( &m_viewAxis, false );
104  }
105 }
106 
107 
109 {
110  const VECTOR2D gridOffset( GetOrigin() );
111  const VECTOR2D grid( GetGrid() );
112 
113  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / grid.x ) * grid.x + gridOffset.x,
114  KiROUND( ( aPoint.y - gridOffset.y ) / grid.y ) * grid.y + gridOffset.y );
115 
116  return nearest;
117 }
118 
119 
121 {
122  if( !m_toolMgr->GetView()->GetGAL()->GetGridSnapping() )
123  return aPoint;
124 
125  VECTOR2I nearest = AlignGrid( aPoint );
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 EE_GRID_HELPER::AlignToWire( const VECTOR2I& aPoint, const SEG& aSeg )
141 {
142  OPT_VECTOR2I pts[6];
143 
144  if( !m_enableSnap )
145  return aPoint;
146 
147  const VECTOR2D gridOffset( GetOrigin() );
148  const VECTOR2D gridSize( GetGrid() );
149 
150  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
151  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
152 
153  pts[0] = aSeg.A;
154  pts[1] = aSeg.B;
155  pts[2] = aSeg.IntersectLines( SEG( nearest + VECTOR2I( -1, 0 ), nearest + VECTOR2I( 1, 0 ) ) );
156  pts[3] = aSeg.IntersectLines( SEG( nearest + VECTOR2I( 0, -1 ), nearest + VECTOR2I( 0, 1 ) ) );
157 
158  int min_d = std::numeric_limits<int>::max();
159 
160  for( int i = 0; i < 4; i++ )
161  {
162  if( pts[i] && aSeg.Contains( *pts[i] ) )
163  {
164  int d = (*pts[i] - aPoint).EuclideanNorm();
165 
166  if( d < min_d )
167  {
168  min_d = d;
169  nearest = *pts[i];
170  }
171  }
172  }
173 
174  return nearest;
175 }
176 
177 VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, std::vector<SCH_ITEM*>& aItems )
178 {
179  clearAnchors();
180 
181  for( SCH_ITEM* item : aItems )
182  computeAnchors( item, aMousePos, true );
183 
184  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
185  double lineSnapMinCornerDistance = 50.0 / worldScale;
186 
187  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
188  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
189  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
190  ANCHOR* best = NULL;
191  double minDist = std::numeric_limits<double>::max();
192 
193  if( nearestOrigin )
194  {
195  minDist = nearestOrigin->Distance( aMousePos );
196  best = nearestOrigin;
197  }
198 
199  if( nearestCorner )
200  {
201  double dist = nearestCorner->Distance( aMousePos );
202 
203  if( dist < minDist )
204  {
205  minDist = dist;
206  best = nearestCorner;
207  }
208  }
209 
210  if( nearestOutline )
211  {
212  double dist = nearestOutline->Distance( aMousePos );
213 
214  if( minDist > lineSnapMinCornerDistance && dist < minDist )
215  best = nearestOutline;
216  }
217 
218  return best ? best->pos : aMousePos;
219 }
220 
221 
222 std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
223  const std::vector<SCH_ITEM*>& aSkip ) const
224 {
225  std::set<SCH_ITEM*> items;
226  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
227 
228  KIGFX::VIEW* view = m_toolMgr->GetView();
229 
230  view->Query( aArea, selectedItems );
231 
232  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
233  {
234  SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
235 
236  // The item must be visible and on an active layer
237  if( view->IsVisible( item )
238  && item->ViewGetLOD( it.second, view ) < view->GetScale() )
239  {
240  items.insert ( item );
241  }
242  }
243 
244 
245  for( SCH_ITEM* skipItem : aSkip )
246  items.erase( skipItem );
247 
248  return items;
249 }
250 
251 
253 {
254  return BestSnapAnchor( aOrigin, LSET::AllLayersMask(), { aDraggedItem } );
255 }
256 
257 
258 VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
259  const std::vector<SCH_ITEM*>& aSkip )
260 {
261  int snapDist = GetGrid().x;
262  int snapRange = snapDist;
263 
264  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
265  VECTOR2I( snapRange, snapRange ) );
266 
267  clearAnchors();
268 
269  for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
270  computeAnchors( item, aOrigin );
271 
272  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
273  VECTOR2I nearestGrid = Align( aOrigin );
274 
275  if( nearest )
276  snapDist = nearest->Distance( aOrigin );
277 
279  {
280  bool snapLine = false;
281  int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
282  int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
283 
285  if( x_dist < snapRange && x_dist < snapDist )
286  {
287  nearestGrid.x = m_viewSnapLine.GetPosition().x;
288  snapLine = true;
289  }
290 
291  if( y_dist < snapRange && y_dist < snapDist )
292  {
293  nearestGrid.y = m_viewSnapLine.GetPosition().y;
294  snapLine = true;
295  }
296 
297  if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
298  {
299  m_viewSnapLine.SetEndPosition( nearestGrid );
300 
303  else
305 
306  return nearestGrid;
307  }
308  }
309 
310  if( nearest && m_enableSnap )
311  {
312 
313  if( snapDist <= snapRange )
314  {
315  m_viewSnapPoint.SetPosition( wxPoint( nearest->pos ) );
316  m_viewSnapLine.SetPosition( wxPoint( nearest->pos ) );
318 
321  else
323 
324  m_snapItem = nearest;
325  return nearest->pos;
326  }
327  }
328 
329  m_snapItem = nullptr;
332  return nearestGrid;
333 }
334 
335 
337 {
338  if( !m_snapItem )
339  return nullptr;
340 
341  return m_snapItem->item;
342 }
343 
344 
345 void EE_GRID_HELPER::computeAnchors( SCH_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom )
346 {
347  switch( aItem->Type() )
348  {
349  case SCH_COMPONENT_T:
350  case SCH_SHEET_T:
351  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
353  case SCH_JUNCTION_T:
354  case SCH_NO_CONNECT_T:
355  case SCH_LINE_T:
356  case SCH_GLOBAL_LABEL_T:
357  case SCH_HIER_LABEL_T:
358  case SCH_LABEL_T:
360  {
361  std::vector<wxPoint> pts = aItem->GetConnectionPoints();
362 
363  for( auto pt : pts )
364  addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
365 
366  break;
367  }
368 
369  default:
370  break;
371  }
372 }
373 
374 
376  LSET aMatchLayers )
377 {
378  double minDist = std::numeric_limits<double>::max();
379  ANCHOR* best = NULL;
380 
381  for( ANCHOR& a : m_anchors )
382  {
383  if( ( aFlags & a.flags ) != aFlags )
384  continue;
385 
386  double dist = a.Distance( aPos );
387 
388  if( dist < minDist )
389  {
390  minDist = dist;
391  best = &a;
392  }
393  }
394 
395  return best;
396 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
void SetPosition(const wxPoint &aPosition) override
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:290
double Distance(const VECTOR2I &aP) const
wxPoint GetPosition() const override
EE_GRID_HELPER(TOOL_MANAGER *aToolMgr)
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, std::vector< SCH_ITEM * > &aItem)
virtual std::vector< wxPoint > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:391
ANCHOR * m_snapItem
VECTOR2I m_skipPoint
VIEW_CONTROLS class definition.
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
SCH_ITEM * GetSnapped() const
Function GetSnapped If the EE_GRID_HELPER has highlighted a snap point (target shown),...
VECTOR2I Align(const VECTOR2I &aPoint) const
void computeAnchors(SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false)
computeAnchors inserts the local anchor points in to the grid helper for the specified schematic item...
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, SCH_ITEM *aDraggedItem)
GAL * GetGAL() const
Function GetGAL() Returns the GAL this view is using to draw graphical primitives.
Definition: view.h:182
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Function IntersectLines()
Definition: seg.h:191
void SetEndPosition(const VECTOR2D &aPosition)
virtual wxPoint GetPosition() const
Definition: eda_item.h:326
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
This file contains miscellaneous commonly used macros and functions.
TOOL_MANAGER.
Definition: tool_manager.h:51
OPT< VECTOR2I > m_auxAxis
bool GetGridSnapping() const
LSET is a set of PCB_LAYER_IDs.
#define NULL
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:37
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
bool IsVisible(const VIEW_ITEM *aItem) const
Returns information if the item is visible (or not).
Definition: view.cpp:1499
void SetSize(int aSize)
void SetDrawAtZero(bool aDrawFlag)
Function SetDrawAtZero() Set the draw at zero flag.
static LSET AllLayersMask()
Definition: lset.cpp:786
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: seg.h:39
const VECTOR2D & GetGridSize() const
Returns the grid size.
VECTOR2I GetGrid() const
std::vector< ANCHOR > m_anchors
VECTOR2I AlignToWire(const VECTOR2I &aPoint, const SEG &aSeg)
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:68
VECTOR2I A
Definition: seg.h:47
VECTOR2I AlignGrid(const VECTOR2I &aPoint) const
std::set< SCH_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< SCH_ITEM * > &aSkip) const
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
void SetColor(const KIGFX::COLOR4D &aColor)
boost::optional< T > OPT
Definition: optional.h:7
TOOL_MANAGER * m_toolMgr
const VECTOR2D & GetGridOrigin() const
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1459
void addAnchor(const VECTOR2I &aPos, int aFlags, SCH_ITEM *aItem)
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:327
virtual 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:433
VIEW.
Definition: view.h:63
void SetStyle(MARKER_STYLE aStyle)
double GetScale() const
Function GetScale()
Definition: view.h:259
double GetWorldScale() const
Get the world scale.
VECTOR2I GetOrigin() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Function ViewGetLOD() Returns the level of detail (LOD) of the item.
Definition: view_item.h:141
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1513
KICAD_T Type() const
Function Type()
Definition: eda_item.h:182
Color has changed.
Definition: view_item.h:59
bool Contains(const SEG &aSeg) const
Definition: seg.h:299
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100
VECTOR2I B
Definition: seg.h:48