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 <[email protected]>
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  // Text anchors are often off the connectivity grid. For now, this means
69  // we can only consider anchors from text objects if they are the only thing
70  // selected.
71  bool includeText = ( aItems.Size() == 1
72  || aItems.OnlyContains( { SCH_TEXT_T, SCH_FIELD_T } ) );
73 
74  for( EDA_ITEM* item : aItems )
75  computeAnchors( static_cast<SCH_ITEM*>( item ), aMousePos, true, includeText );
76 
77  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
78  double lineSnapMinCornerDistance = 50.0 / worldScale;
79 
80  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aLayer );
81  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aLayer );
82  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aLayer );
83  ANCHOR* best = nullptr;
84  double minDist = std::numeric_limits<double>::max();
85 
86  if( nearestOrigin )
87  {
88  minDist = nearestOrigin->Distance( aMousePos );
89  best = nearestOrigin;
90  }
91 
92  if( nearestCorner )
93  {
94  double dist = nearestCorner->Distance( aMousePos );
95 
96  if( dist < minDist )
97  {
98  minDist = dist;
99  best = nearestCorner;
100  }
101  }
102 
103  if( nearestOutline )
104  {
105  double dist = nearestOutline->Distance( aMousePos );
106 
107  if( minDist > lineSnapMinCornerDistance && dist < minDist )
108  best = nearestOutline;
109  }
110 
111  return best ? best->pos : aMousePos;
112 }
113 
114 
115 VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aSkip )
116 {
117  EE_SELECTION skipItems;
118  skipItems.Add( aSkip );
119 
120  return BestSnapAnchor( aOrigin, aLayer, skipItems );
121 }
122 
123 
125  const EE_SELECTION& aSkip )
126 {
127  constexpr int snapRange = SNAP_RANGE * IU_PER_MILS;
128 
129  VECTOR2I pt = aOrigin;
130  VECTOR2I snapDist( snapRange, snapRange );
131  bool snapLineX = false;
132  bool snapLineY = false;
133  bool snapPoint = false;
134  bool gridChecked = false;
135 
136  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
137  VECTOR2I( snapRange, snapRange ) );
138 
139  clearAnchors();
140 
141  for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
142  computeAnchors( item, aOrigin );
143 
144  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayer );
145  VECTOR2I nearestGrid = Align( aOrigin );
146 
148  {
149  if( std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x ) < snapDist.x )
150  {
151  pt.x = m_viewSnapLine.GetPosition().x;
152  snapDist.x = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
153  snapLineX = true;
154  }
155 
156  if( std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y ) < snapDist.y )
157  {
158  pt.y = m_viewSnapLine.GetPosition().y;
159  snapDist.y = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
160  snapLineY = true;
161  }
162 
163  if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
164  {
165  pt.x = nearestGrid.x;
166  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
167  snapLineX = false;
168  }
169 
170  if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
171  {
172  pt.y = nearestGrid.y;
173  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
174  snapLineY = false;
175  }
176 
177  gridChecked = true;
178  }
179 
180  if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
181  {
182 
183  if( canUseGrid() && ( nearestGrid - aOrigin ).EuclideanNorm() < snapDist.EuclideanNorm() )
184  {
185  pt = nearestGrid;
186  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
187  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
188  snapPoint = false;
189  }
190  else
191  {
192  pt = nearest->pos;
193  snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
194  snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
195  snapPoint = true;
196  }
197 
198  snapLineX = snapLineY = false;
199  gridChecked = true;
200  }
201 
202  if( canUseGrid() && !gridChecked )
203  pt = nearestGrid;
204 
205  if( snapLineX || snapLineY )
206  {
208 
211  else
213  }
214  else if( snapPoint )
215  {
216  m_snapItem = nearest;
217  m_viewSnapPoint.SetPosition( (wxPoint) pt );
218  m_viewSnapLine.SetPosition( (wxPoint) pt );
219 
221 
224  else
226  }
227  else
228  {
231  }
232 
233  return pt;
234 }
235 
237 {
238  if( !m_snapItem )
239  return nullptr;
240 
241  return static_cast<SCH_ITEM*>( m_snapItem->item );
242 }
243 
244 
245 std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
246  const EE_SELECTION& aSkipList ) const
247 {
248  std::set<SCH_ITEM*> items;
249  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
250 
251  KIGFX::VIEW* view = m_toolMgr->GetView();
252 
253  view->Query( aArea, selectedItems );
254 
255  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
256  {
257  SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
258 
259  // The item must be visible and on an active layer
260  if( view->IsVisible( item ) && item->ViewGetLOD( it.second, view ) < view->GetScale() )
261  items.insert ( item );
262  }
263 
264  for( EDA_ITEM* skipItem : aSkipList )
265  items.erase( static_cast<SCH_ITEM*>( skipItem ) );
266 
267  return items;
268 }
269 
270 
271 void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom,
272  bool aIncludeText )
273 {
274  switch( aItem->Type() )
275  {
276  case SCH_TEXT_T:
277  case SCH_FIELD_T:
278  {
279  if( aIncludeText )
280  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
281 
282  break;
283  }
284 
285  case SCH_SYMBOL_T:
286  case SCH_SHEET_T:
287  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
289 
290  case SCH_JUNCTION_T:
291  case SCH_NO_CONNECT_T:
292  case SCH_LINE_T:
293  case SCH_GLOBAL_LABEL_T:
294  case SCH_HIER_LABEL_T:
295  case SCH_LABEL_T:
297  {
298  std::vector<wxPoint> pts = aItem->GetConnectionPoints();
299 
300  for( const wxPoint& pt : pts )
301  addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
302 
303  break;
304  }
305 
306  default:
307  break;
308  }
309 
310  if( SCH_LINE* line = dyn_cast<SCH_LINE*>( aItem ) )
311  {
312  VECTOR2I pt = Align( aRefPos );
313 
314  if( line->GetStartPoint().x == line->GetEndPoint().x )
315  {
316  VECTOR2I possible( line->GetStartPoint().x, pt.y );
317 
318  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(),
319  0 ) )
320  addAnchor( possible, SNAPPABLE | VERTICAL, aItem );
321  }
322  else if( line->GetStartPoint().y == line->GetEndPoint().y )
323  {
324  VECTOR2I possible( pt.x, line->GetStartPoint().y );
325 
326  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(),
327  0 ) )
328  addAnchor( possible, SNAPPABLE | HORIZONTAL, aItem );
329  }
330 
331  }
332 }
333 
334 
336  int aMatchLayer )
337 {
338  double minDist = std::numeric_limits<double>::max();
339  ANCHOR* best = nullptr;
340 
341  for( ANCHOR& a : m_anchors )
342  {
343  SCH_ITEM* item = static_cast<SCH_ITEM*>( a.item );
344 
345  if( ( aFlags & a.flags ) != aFlags )
346  continue;
347 
348  if( aMatchLayer == LAYER_CONNECTABLE && !item->IsConnectable() )
349  continue;
350  else if( aMatchLayer == LAYER_GRAPHICS && item->IsConnectable() )
351  continue;
352 
353  double dist = a.Distance( aPos );
354 
355  if( dist < minDist )
356  {
357  minDist = dist;
358  best = &a;
359  }
360  }
361 
362  return best;
363 }
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:349
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:364
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
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:251
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
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:1556
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
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
Definition: selection.cpp:170
VECTOR2I m_skipPoint
Definition: grid_helper.h:139
int Size() const
Returns the number of selected parts.
Definition: selection.h:104
#define IU_PER_MILS
Definition: plotter.cpp:130
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:99
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1516
void computeAnchors(SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false, bool aIncludeText=false)
Insert the local anchor points in to the grid helper for the specified schematic item,...
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:320
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:426
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:1570
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
Position or shape has changed.
Definition: view_item.h:49
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103