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-2021 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 #include <macros.h>
28 #include <sch_item.h>
29 #include <sch_line.h>
30 #include <sch_painter.h>
31 #include <tool/tool_manager.h>
32 #include <trigo.h>
33 #include <view/view.h>
34 #include "ee_grid_helper.h"
35 
36 
38  GRID_HELPER( aToolMgr )
39 {
40  KIGFX::VIEW* view = m_toolMgr->GetView();
41 
42  m_viewAxis.SetSize( 20000 );
44  m_viewAxis.SetColor( COLOR4D( 0.0, 0.1, 0.4, 0.8 ) );
45  m_viewAxis.SetDrawAtZero( true );
46  view->Add( &m_viewAxis );
47  view->SetVisible( &m_viewAxis, false );
48 
50  m_viewSnapPoint.SetColor( COLOR4D( 0.0, 0.1, 0.4, 1.0 ) );
52  view->Add( &m_viewSnapPoint );
53  view->SetVisible( &m_viewSnapPoint, false );
54 
56  m_viewSnapLine.SetColor( COLOR4D( 0.33, 0.55, 0.95, 1.0 ) );
58  view->Add( &m_viewSnapLine );
59  view->SetVisible( &m_viewSnapLine, false );
60 }
61 
62 
63 VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, int aLayer,
64  const EE_SELECTION& aItems )
65 {
66  clearAnchors();
67 
68  for( EDA_ITEM* item : aItems )
69  computeAnchors( static_cast<SCH_ITEM*>( item ), aMousePos, true );
70 
71  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
72  double lineSnapMinCornerDistance = 50.0 / worldScale;
73 
74  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aLayer );
75  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aLayer );
76  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aLayer );
77  ANCHOR* best = nullptr;
78  double minDist = std::numeric_limits<double>::max();
79 
80  if( nearestOrigin )
81  {
82  minDist = nearestOrigin->Distance( aMousePos );
83  best = nearestOrigin;
84  }
85 
86  if( nearestCorner )
87  {
88  double dist = nearestCorner->Distance( aMousePos );
89 
90  if( dist < minDist )
91  {
92  minDist = dist;
93  best = nearestCorner;
94  }
95  }
96 
97  if( nearestOutline )
98  {
99  double dist = nearestOutline->Distance( aMousePos );
100 
101  if( minDist > lineSnapMinCornerDistance && dist < minDist )
102  best = nearestOutline;
103  }
104 
105  return best ? best->pos : aMousePos;
106 }
107 
108 
109 VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aSkip )
110 {
111  EE_SELECTION skipItems;
112  skipItems.Add( aSkip );
113 
114  return BestSnapAnchor( aOrigin, aLayer, skipItems );
115 }
116 
117 
119  const EE_SELECTION& aSkip )
120 {
121  constexpr int snapRange = SNAP_RANGE * IU_PER_MILS;
122 
123  VECTOR2I pt = aOrigin;
124  VECTOR2I snapDist( snapRange, snapRange );
125  bool snapLineX = false;
126  bool snapLineY = false;
127  bool snapPoint = false;
128  bool gridChecked = false;
129 
130  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
131  VECTOR2I( snapRange, snapRange ) );
132 
133  clearAnchors();
134 
135  for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
136  computeAnchors( item, aOrigin );
137 
138  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayer );
139  VECTOR2I nearestGrid = Align( aOrigin );
140 
142  {
143  if( std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x ) < snapDist.x )
144  {
145  pt.x = m_viewSnapLine.GetPosition().x;
146  snapDist.x = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
147  snapLineX = true;
148  }
149 
150  if( std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y ) < snapDist.y )
151  {
152  pt.y = m_viewSnapLine.GetPosition().y;
153  snapDist.y = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
154  snapLineY = true;
155  }
156 
157  if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
158  {
159  pt.x = nearestGrid.x;
160  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
161  snapLineX = false;
162  }
163 
164  if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
165  {
166  pt.y = nearestGrid.y;
167  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
168  snapLineY = false;
169  }
170 
171  gridChecked = true;
172  }
173 
174  if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
175  {
176 
177  if( canUseGrid() && ( nearestGrid - aOrigin ).EuclideanNorm() < snapDist.EuclideanNorm() )
178  {
179  pt = nearestGrid;
180  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
181  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
182  snapPoint = false;
183  }
184  else
185  {
186  pt = nearest->pos;
187  snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
188  snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
189  snapPoint = true;
190  }
191 
192  snapLineX = snapLineY = false;
193  gridChecked = true;
194  }
195 
196  if( canUseGrid() && !gridChecked )
197  pt = nearestGrid;
198 
199  if( snapLineX || snapLineY )
200  {
202 
205  else
207  }
208  else if( snapPoint )
209  {
210  m_snapItem = nearest;
211  m_viewSnapPoint.SetPosition( (wxPoint) pt );
212  m_viewSnapLine.SetPosition( (wxPoint) pt );
213 
215 
218  else
220  }
221  else
222  {
225  }
226 
227  return pt;
228 }
229 
231 {
232  if( !m_snapItem )
233  return nullptr;
234 
235  return static_cast<SCH_ITEM*>( m_snapItem->item );
236 }
237 
238 
239 std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
240  const EE_SELECTION& aSkipList ) const
241 {
242  std::set<SCH_ITEM*> items;
243  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
244 
245  KIGFX::VIEW* view = m_toolMgr->GetView();
246 
247  view->Query( aArea, selectedItems );
248 
249  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
250  {
251  SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
252 
253  // The item must be visible and on an active layer
254  if( view->IsVisible( item ) && item->ViewGetLOD( it.second, view ) < view->GetScale() )
255  items.insert ( item );
256  }
257 
258  for( EDA_ITEM* skipItem : aSkipList )
259  items.erase( static_cast<SCH_ITEM*>( skipItem ) );
260 
261  return items;
262 }
263 
264 
265 void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom )
266 {
267  switch ( aItem->Type() )
268  {
269  case SCH_SYMBOL_T:
270  case SCH_SHEET_T:
271  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
273  case SCH_JUNCTION_T:
274  case SCH_NO_CONNECT_T:
275  case SCH_LINE_T:
276  case SCH_GLOBAL_LABEL_T:
277  case SCH_HIER_LABEL_T:
278  case SCH_LABEL_T:
280  {
281  std::vector<wxPoint> pts = aItem->GetConnectionPoints();
282 
283  for( const wxPoint &pt : pts )
284  addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
285 
286  break;
287  }
288 
289  default:
290  break;
291  }
292 
293  if( SCH_LINE* line = dyn_cast<SCH_LINE*>( aItem ) )
294  {
295  VECTOR2I pt = Align( aRefPos );
296 
297  if( line->GetStartPoint().x == line->GetEndPoint().x )
298  {
299  VECTOR2I possible( line->GetStartPoint().x, pt.y );
300 
301  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(),
302  0 ) )
303  addAnchor( possible, SNAPPABLE | VERTICAL, aItem );
304  }
305  else if( line->GetStartPoint().y == line->GetEndPoint().y )
306  {
307  VECTOR2I possible( pt.x, line->GetStartPoint().y );
308 
309  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(),
310  0 ) )
311  addAnchor( possible, SNAPPABLE | HORIZONTAL, aItem );
312  }
313 
314  }
315 }
316 
317 
319  int aMatchLayer )
320 {
321  double minDist = std::numeric_limits<double>::max();
322  ANCHOR* best = nullptr;
323 
324  for( ANCHOR& a : m_anchors )
325  {
326  SCH_ITEM* item = static_cast<SCH_ITEM*>( a.item );
327 
328  if( ( aFlags & a.flags ) != aFlags )
329  continue;
330 
331  if( aMatchLayer == LAYER_CONNECTABLE && !item->IsConnectable() )
332  continue;
333  else if( aMatchLayer == LAYER_GRAPHICS && item->IsConnectable() )
334  continue;
335 
336  double dist = a.Distance( aPos );
337 
338  if( dist < minDist )
339  {
340  minDist = dist;
341  best = &a;
342  }
343  }
344 
345  return best;
346 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
void SetPosition(const wxPoint &aPosition) override
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:283
virtual bool IsConnectable() const
Definition: sch_item.h:347
wxPoint GetPosition() const override
ANCHOR * m_snapItem
Definition: grid_helper.h:137
EE_GRID_HELPER(TOOL_MANAGER *aToolMgr)
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:106
virtual std::vector< wxPoint > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:362
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:32
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:129
SCH_ITEM * GetSnapped() const
Function GetSnapped If the EE_GRID_HELPER has highlighted a snap point (target shown),...
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:143
void computeAnchors(SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false)
Insert the local anchor points in to the grid helper for the specified schematic item,...
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, int aLayer, SCH_ITEM *aDraggedItem)
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
std::set< SCH_ITEM * > queryVisible(const BOX2I &aArea, const EE_SELECTION &aSkipList) const
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, int aMatchLayer)
void SetEndPosition(const VECTOR2D &aPosition)
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
This file contains miscellaneous commonly used macros and functions.
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, int aLayer, const EE_SELECTION &aItems)
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:141
Master controller class:
Definition: tool_manager.h:54
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:100
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1498
void SetSize(int aSize)
bool TestSegmentHit(const wxPoint &aRefPoint, const wxPoint &aStart, const wxPoint &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
#define SNAP_RANGE
bool canUseGrid() const
Check whether it is possible to use the grid – this depends both on local grid helper settings and gl...
Definition: grid_helper.h:121
bool m_enableSnap
Definition: grid_helper.h:134
bool m_enableSnapLine
Definition: grid_helper.h:136
virtual VECTOR2I Align(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:95
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
VECTOR2I m_skipPoint
Definition: grid_helper.h:139
#define IU_PER_MILS
Definition: plotter.cpp:136
void SetColor(const KIGFX::COLOR4D &aColor)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1458
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:318
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:424
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:142
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
void SetStyle(MARKER_STYLE aStyle)
double GetScale() const
Definition: view.h:264
double GetWorldScale() const
Get the world scale.
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:127
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
void clearAnchors()
Definition: grid_helper.h:112
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:132
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1512
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
Position or shape has changed.
Definition: view_item.h:49
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103