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 #include <sch_item.h>
28 #include <sch_line.h>
29 #include <sch_painter.h>
30 #include <tool/tool_manager.h>
31 #include <trigo.h>
32 #include <view/view.h>
33 #include "ee_grid_helper.h"
34 
35 
37  GRID_HELPER( aToolMgr )
38 {
39  KIGFX::VIEW* view = m_toolMgr->GetView();
40 
41  m_viewAxis.SetSize( 20000 );
43  m_viewAxis.SetColor( COLOR4D( 0.0, 0.1, 0.4, 0.8 ) );
44  m_viewAxis.SetDrawAtZero( true );
45  view->Add( &m_viewAxis );
46  view->SetVisible( &m_viewAxis, false );
47 
49  m_viewSnapPoint.SetColor( COLOR4D( 0.0, 0.1, 0.4, 1.0 ) );
51  view->Add( &m_viewSnapPoint );
52  view->SetVisible( &m_viewSnapPoint, false );
53 
55  m_viewSnapLine.SetColor( COLOR4D( 0.33, 0.55, 0.95, 1.0 ) );
57  view->Add( &m_viewSnapLine );
58  view->SetVisible( &m_viewSnapLine, false );
59 }
60 
61 
62 VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, int aLayer,
63  const EE_SELECTION& aItems )
64 {
65  clearAnchors();
66 
67  for( EDA_ITEM* item : aItems )
68  computeAnchors( static_cast<SCH_ITEM*>( item ), aMousePos, true );
69 
70  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
71  double lineSnapMinCornerDistance = 50.0 / worldScale;
72 
73  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aLayer );
74  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aLayer );
75  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aLayer );
76  ANCHOR* best = NULL;
77  double minDist = std::numeric_limits<double>::max();
78 
79  if( nearestOrigin )
80  {
81  minDist = nearestOrigin->Distance( aMousePos );
82  best = nearestOrigin;
83  }
84 
85  if( nearestCorner )
86  {
87  double dist = nearestCorner->Distance( aMousePos );
88 
89  if( dist < minDist )
90  {
91  minDist = dist;
92  best = nearestCorner;
93  }
94  }
95 
96  if( nearestOutline )
97  {
98  double dist = nearestOutline->Distance( aMousePos );
99 
100  if( minDist > lineSnapMinCornerDistance && dist < minDist )
101  best = nearestOutline;
102  }
103 
104  return best ? best->pos : aMousePos;
105 }
106 
107 
108 VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aSkip )
109 {
110  EE_SELECTION skipItems;
111  skipItems.Add( aSkip );
112 
113  return BestSnapAnchor( aOrigin, aLayer, skipItems );
114 }
115 
116 
118  const EE_SELECTION& aSkip )
119 {
120  constexpr int snapRange = SNAP_RANGE * IU_PER_MILS;
121 
122  VECTOR2I pt = aOrigin;
123  VECTOR2I snapDist( snapRange, snapRange );
124  bool snapLineX = false;
125  bool snapLineY = false;
126  bool snapPoint = false;
127  bool gridChecked = false;
128 
129  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
130  VECTOR2I( snapRange, snapRange ) );
131 
132  clearAnchors();
133 
134  for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
135  computeAnchors( item, aOrigin );
136 
137  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayer );
138  VECTOR2I nearestGrid = Align( aOrigin );
139 
141  {
142  if( std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x ) < snapDist.x )
143  {
144  pt.x = m_viewSnapLine.GetPosition().x;
145  snapDist.x = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
146  snapLineX = true;
147  }
148 
149  if( std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y ) < snapDist.y )
150  {
151  pt.y = m_viewSnapLine.GetPosition().y;
152  snapDist.y = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
153  snapLineY = true;
154  }
155 
156  if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
157  {
158  pt.x = nearestGrid.x;
159  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
160  snapLineX = false;
161  }
162 
163  if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
164  {
165  pt.y = nearestGrid.y;
166  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
167  snapLineY = false;
168  }
169 
170  gridChecked = true;
171  }
172 
173  if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
174  {
175 
176  if( canUseGrid() && ( nearestGrid - aOrigin ).EuclideanNorm() < snapDist.EuclideanNorm() )
177  {
178  pt = nearestGrid;
179  snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
180  snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
181  snapPoint = false;
182  }
183  else
184  {
185  pt = nearest->pos;
186  snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
187  snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
188  snapPoint = true;
189  }
190 
191  snapLineX = snapLineY = false;
192  gridChecked = true;
193  }
194 
195  if( canUseGrid() && !gridChecked )
196  pt = nearestGrid;
197 
198  if( snapLineX || snapLineY )
199  {
201 
204  else
206  }
207  else if( snapPoint )
208  {
209  m_snapItem = nearest;
210  m_viewSnapPoint.SetPosition( (wxPoint) pt );
211  m_viewSnapLine.SetPosition( (wxPoint) pt );
212 
214 
217  else
219  }
220  else
221  {
224  }
225 
226  return pt;
227 }
228 
230 {
231  if( !m_snapItem )
232  return nullptr;
233 
234  return static_cast<SCH_ITEM*>( m_snapItem->item );
235 }
236 
237 
238 std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
239  const EE_SELECTION& aSkipList ) const
240 {
241  std::set<SCH_ITEM*> items;
242  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
243 
244  KIGFX::VIEW* view = m_toolMgr->GetView();
245 
246  view->Query( aArea, selectedItems );
247 
248  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
249  {
250  SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
251 
252  // The item must be visible and on an active layer
253  if( view->IsVisible( item ) && item->ViewGetLOD( it.second, view ) < view->GetScale() )
254  items.insert ( item );
255  }
256 
257  for( EDA_ITEM* skipItem : aSkipList )
258  items.erase( static_cast<SCH_ITEM*>( skipItem ) );
259 
260  return items;
261 }
262 
263 
264 void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom )
265 {
266  switch ( aItem->Type() )
267  {
268  case SCH_COMPONENT_T:
269  case SCH_SHEET_T:
270  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
272  case SCH_JUNCTION_T:
273  case SCH_NO_CONNECT_T:
274  case SCH_LINE_T:
275  case SCH_GLOBAL_LABEL_T:
276  case SCH_HIER_LABEL_T:
277  case SCH_LABEL_T:
279  {
280  std::vector<wxPoint> pts = aItem->GetConnectionPoints();
281 
282  for( const wxPoint &pt : pts )
283  addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
284 
285  break;
286  }
287 
288  default:
289  break;
290  }
291 
292  if( SCH_LINE* line = dyn_cast<SCH_LINE*>( aItem ) )
293  {
294  VECTOR2I pt = Align( aRefPos );
295 
296  if( line->GetStartPoint().x == line->GetEndPoint().x )
297  {
298  VECTOR2I possible( line->GetStartPoint().x, pt.y );
299 
300  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(), 0 ) )
301  addAnchor( possible, SNAPPABLE | VERTICAL, aItem );
302  }
303  else if( line->GetStartPoint().y == line->GetEndPoint().y )
304  {
305  VECTOR2I possible( pt.x, line->GetStartPoint().y );
306 
307  if( TestSegmentHit( wxPoint( possible ), line->GetStartPoint(), line->GetEndPoint(), 0 ) )
308  addAnchor( possible, SNAPPABLE | HORIZONTAL, aItem );
309  }
310 
311  }
312 }
313 
314 
316  int aMatchLayer )
317 {
318  double minDist = std::numeric_limits<double>::max();
319  ANCHOR* best = NULL;
320 
321  for( ANCHOR& a : m_anchors )
322  {
323  SCH_ITEM* item = static_cast<SCH_ITEM*>( a.item );
324 
325  if( ( aFlags & a.flags ) != aFlags )
326  continue;
327 
328  if( aMatchLayer == LAYER_CONNECTABLE && !item->IsConnectable() )
329  continue;
330  else if( aMatchLayer == LAYER_GRAPHICS && item->IsConnectable() )
331  continue;
332 
333  double dist = a.Distance( aPos );
334 
335  if( dist < minDist )
336  {
337  minDist = dist;
338  best = &a;
339  }
340  }
341 
342  return best;
343 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:148
void SetPosition(const wxPoint &aPosition) override
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:289
virtual bool IsConnectable() const
Definition: sch_item.h:376
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:390
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)
computeAnchors inserts 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:189
#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:301
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:77
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, int aLayer, const EE_SELECTION &aItems)
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:141
Master controller class:
Definition: tool_manager.h:52
#define NULL
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:1494
void SetSize(int aSize)
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:72
VECTOR2I m_skipPoint
Definition: grid_helper.h:139
#define IU_PER_MILS
Definition: plotter.cpp:137
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:149
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1454
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:321
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:427
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:67
void SetStyle(MARKER_STYLE aStyle)
double GetScale() const
Definition: view.h:263
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:196
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:137
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:1508
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
Position or shape has changed.
Definition: view_item.h:54
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:98