KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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>
29#include <sch_item.h>
30#include <sch_line.h>
31#include <sch_painter.h>
32#include <tool/tool_manager.h>
34#include <trigo.h>
35#include <view/view.h>
36#include "ee_grid_helper.h"
37
38
40 GRID_HELPER( aToolMgr )
41{
42 KIGFX::VIEW* view = m_toolMgr->GetView();
43
44 m_viewAxis.SetSize( 20000 );
46 m_viewAxis.SetColor( COLOR4D( 0.0, 0.1, 0.4, 0.8 ) );
48 view->Add( &m_viewAxis );
49 view->SetVisible( &m_viewAxis, false );
50
52 m_viewSnapPoint.SetColor( COLOR4D( 0.0, 0.1, 0.4, 1.0 ) );
54 view->Add( &m_viewSnapPoint );
55 view->SetVisible( &m_viewSnapPoint, false );
56
58 m_viewSnapLine.SetColor( COLOR4D( 0.33, 0.55, 0.95, 1.0 ) );
60 view->Add( &m_viewSnapLine );
61 view->SetVisible( &m_viewSnapLine, false );
62}
63
64
66{
67 KIGFX::VIEW* view = m_toolMgr->GetView();
68
69 view->Remove( &m_viewAxis );
70 view->Remove( &m_viewSnapPoint );
71 view->Remove( &m_viewSnapLine );
72}
73
74
76 const EE_SELECTION& aItems )
77{
79
80 // If we're working with any connectable objects, skip non-connectable objects
81 // since they are often off-grid, e.g. text anchors
82 bool hasConnectables = false;
83
84 for( EDA_ITEM* item : aItems )
85 {
86 GRID_HELPER_GRIDS grid = GetItemGrid( static_cast<SCH_ITEM*>( item ) );
88 {
89 hasConnectables = true;
90 break;
91 }
92 }
93
94 for( EDA_ITEM* item : aItems )
95 computeAnchors( static_cast<SCH_ITEM*>( item ), aMousePos, true, !hasConnectables );
96
97 double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
98 double lineSnapMinCornerDistance = 50.0 / worldScale;
99
100 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aGrid );
101 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aGrid );
102 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aGrid );
103 ANCHOR* best = nullptr;
104 double minDist = std::numeric_limits<double>::max();
105
106 if( nearestOrigin )
107 {
108 minDist = nearestOrigin->Distance( aMousePos );
109 best = nearestOrigin;
110 }
111
112 if( nearestCorner )
113 {
114 double dist = nearestCorner->Distance( aMousePos );
115
116 if( dist < minDist )
117 {
118 minDist = dist;
119 best = nearestCorner;
120 }
121 }
122
123 if( nearestOutline )
124 {
125 double dist = nearestOutline->Distance( aMousePos );
126
127 if( minDist > lineSnapMinCornerDistance && dist < minDist )
128 best = nearestOutline;
129 }
130
131 return best ? best->pos : aMousePos;
132}
133
134
136 SCH_ITEM* aSkip )
137{
138 EE_SELECTION skipItems;
139 skipItems.Add( aSkip );
140
141 return BestSnapAnchor( aOrigin, aGrid, skipItems );
142}
143
144
146 const EE_SELECTION& aSkip )
147{
148 constexpr int snapRange = SNAP_RANGE * schIUScale.IU_PER_MILS;
149
150 VECTOR2I pt = aOrigin;
151 VECTOR2I snapDist( snapRange, snapRange );
152 bool snapLineX = false;
153 bool snapLineY = false;
154 bool snapPoint = false;
155 bool gridChecked = false;
156
157 BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
158 VECTOR2I( snapRange, snapRange ) );
159
160 clearAnchors();
161
162 for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
163 computeAnchors( item, aOrigin );
164
165 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aGrid );
166 VECTOR2I nearestGrid = Align( aOrigin, aGrid );
167
169 {
170 if( std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x ) < snapDist.x )
171 {
173 snapDist.x = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
174 snapLineX = true;
175 }
176
177 if( std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y ) < snapDist.y )
178 {
180 snapDist.y = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
181 snapLineY = true;
182 }
183
184 if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
185 {
186 pt.x = nearestGrid.x;
187 snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
188 snapLineX = false;
189 }
190
191 if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
192 {
193 pt.y = nearestGrid.y;
194 snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
195 snapLineY = false;
196 }
197
198 gridChecked = true;
199 }
200
201 if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
202 {
203
204 if( canUseGrid() && ( nearestGrid - aOrigin ).EuclideanNorm() < snapDist.EuclideanNorm() )
205 {
206 pt = nearestGrid;
207 snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
208 snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
209 snapPoint = false;
210 }
211 else
212 {
213 pt = nearest->pos;
214 snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
215 snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
216 snapPoint = true;
217 }
218
219 snapLineX = snapLineY = false;
220 gridChecked = true;
221 }
222
223 if( canUseGrid() && !gridChecked )
224 pt = nearestGrid;
225
226 if( snapLineX || snapLineY )
227 {
229
232 else
234 }
235 else if( snapPoint )
236 {
237 m_snapItem = nearest;
240
242
245 else
247 }
248 else
249 {
252 }
253
254 return pt;
255}
256
257
259{
261 int idx = -1;
262
264
265 if( !grid.overrides_enabled )
266 return g;
267
268 switch( aGrid )
269 {
270 case GRID_CONNECTABLE:
271 if( grid.override_connected )
272 idx = grid.override_connected_idx;
273
274 break;
275
276 case GRID_WIRES:
277 if( grid.override_wires )
278 idx = grid.override_wires_idx;
279
280 break;
281
282 case GRID_TEXT:
283 if( grid.override_text )
284 idx = grid.override_text_idx;
285
286 break;
287
288 case GRID_GRAPHICS:
289 if( grid.override_graphics )
290 idx = grid.override_graphics_idx;
291
292 break;
293
294 default:
295 break;
296 }
297
298 if( idx >= 0 && idx < (int) grid.grids.size() )
299 g = grid.grids[idx].ToDouble( schIUScale );
300
301 return g;
302}
303
304
306{
307 if( !m_snapItem )
308 return nullptr;
309
310 return static_cast<SCH_ITEM*>( m_snapItem->item );
311}
312
313
314std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
315 const EE_SELECTION& aSkipList ) const
316{
317 std::set<SCH_ITEM*> items;
318 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
319
320 KIGFX::VIEW* view = m_toolMgr->GetView();
321
322 view->Query( aArea, selectedItems );
323
324 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
325 {
326 SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
327
328 // The item must be visible and on an active layer
329 if( view->IsVisible( item ) && item->ViewGetLOD( it.second, view ) < view->GetScale() )
330 items.insert ( item );
331 }
332
333 for( EDA_ITEM* skipItem : aSkipList )
334 items.erase( static_cast<SCH_ITEM*>( skipItem ) );
335
336 return items;
337}
338
339
341{
342 GRID_HELPER_GRIDS grid = GetItemGrid( aSelection.Front() );
343
344 // Find the largest grid of all the items and use that
345 for( EDA_ITEM* item : aSelection )
346 {
347 GRID_HELPER_GRIDS itemGrid = GetItemGrid( item );
348
349 if( GetGridSize( itemGrid ) > GetGridSize( grid ) )
350 grid = itemGrid;
351 }
352
353 return grid;
354}
355
356
358{
359 if( !aItem )
360 return GRID_CURRENT;
361
362 switch( aItem->Type() )
363 {
364 case LIB_SYMBOL_T:
365 case LIB_PIN_T:
366 case SCH_SYMBOL_T:
367 case SCH_PIN_T:
368 case SCH_SHEET_PIN_T:
369 case SCH_SHEET_T:
370 case SCH_NO_CONNECT_T:
372 case SCH_HIER_LABEL_T:
373 case SCH_LABEL_T:
375 return GRID_CONNECTABLE;
376
377 case LIB_FIELD_T:
378 case SCH_FIELD_T:
379 case LIB_TEXT_T:
380 case SCH_TEXT_T:
381 return GRID_TEXT;
382
383 case LIB_SHAPE_T:
384 case SCH_SHAPE_T:
385 // The text box's border lines are what need to be on the graphic grid
386 case LIB_TEXTBOX_T:
387 case SCH_TEXTBOX_T:
388 case SCH_BITMAP_T:
389 return GRID_GRAPHICS;
390
391 case SCH_JUNCTION_T:
392 return GRID_WIRES;
393
394 case SCH_LINE_T:
395 if( static_cast<const SCH_LINE*>( aItem )->IsConnectable() )
396 return GRID_WIRES;
397 else
398 return GRID_GRAPHICS;
399
402 return GRID_WIRES;
403
404 default:
405 return GRID_CURRENT;
406 }
407}
408
409
410void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom,
411 bool aIncludeText )
412{
413 bool isGraphicLine =
414 aItem->Type() == SCH_LINE_T && static_cast<SCH_LINE*>( aItem )->IsGraphicLine();
415
416 switch( aItem->Type() )
417 {
418 case SCH_TEXT_T:
419 case SCH_TEXTBOX_T:
420 case SCH_FIELD_T:
421 {
422 if( aIncludeText )
423 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
424
425 break;
426 }
427
428 case SCH_SYMBOL_T:
429 case SCH_SHEET_T:
430 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
432
433 case SCH_JUNCTION_T:
434 case SCH_NO_CONNECT_T:
435 case SCH_LINE_T:
436 // Don't add anchors for graphic lines unless we're including text,
437 // they may be on a non-connectable grid
438 if( isGraphicLine && !aIncludeText )
439 break;
440
443 case SCH_HIER_LABEL_T:
444 case SCH_LABEL_T:
447 case SCH_SHEET_PIN_T:
448 {
449 std::vector<VECTOR2I> pts = aItem->GetConnectionPoints();
450
451 for( const VECTOR2I& pt : pts )
452 addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
453
454 break;
455 }
456
457 default:
458 break;
459 }
460
461 // Don't add anchors for graphic lines unless we're including text,
462 // they may be on a non-connectable grid
463 if( aItem->Type() == SCH_LINE_T && ( aIncludeText || !isGraphicLine ) )
464 {
465 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
466 VECTOR2I pt = Align( aRefPos );
467
468 if( line->GetStartPoint().x == line->GetEndPoint().x )
469 {
470 VECTOR2I possible( line->GetStartPoint().x, pt.y );
471
472 if( TestSegmentHit( possible, line->GetStartPoint(), line->GetEndPoint(), 0 ) )
473 addAnchor( possible, SNAPPABLE | VERTICAL, aItem );
474 }
475 else if( line->GetStartPoint().y == line->GetEndPoint().y )
476 {
477 VECTOR2I possible( pt.x, line->GetStartPoint().y );
478
479 if( TestSegmentHit( possible, line->GetStartPoint(), line->GetEndPoint(), 0 ) )
480 addAnchor( possible, SNAPPABLE | HORIZONTAL, aItem );
481 }
482 }
483}
484
485
487 GRID_HELPER_GRIDS aGrid )
488{
489 double minDist = std::numeric_limits<double>::max();
490 ANCHOR* best = nullptr;
491
492 for( ANCHOR& a : m_anchors )
493 {
494 SCH_ITEM* item = static_cast<SCH_ITEM*>( a.item );
495
496 if( ( aFlags & a.flags ) != aFlags )
497 continue;
498
499 if( aGrid == GRID_CONNECTABLE && !item->IsConnectable() )
500 continue;
501 else if( aGrid == GRID_GRAPHICS && item->IsConnectable() )
502 continue;
503
504 double dist = a.Distance( aPos );
505
506 if( dist < minDist )
507 {
508 minDist = dist;
509 best = &a;
510 }
511 }
512
513 return best;
514}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
WINDOW_SETTINGS m_Window
Definition: app_settings.h:170
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:239
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
GRID_HELPER_GRIDS GetSelectionGrid(const SELECTION &aItem) const override
Gets the coarsest grid that applies to a selecion of items.
~EE_GRID_HELPER() override
GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const override
Gets the coarsest grid that applies to an item.
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, GRID_HELPER_GRIDS aGrid, const EE_SELECTION &aItems)
std::set< SCH_ITEM * > queryVisible(const BOX2I &aArea, const EE_SELECTION &aSkipList) const
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, GRID_HELPER_GRIDS aGrid, SCH_ITEM *aSkip)
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, GRID_HELPER_GRIDS aGrid)
VECTOR2D GetGridSize(GRID_HELPER_GRIDS aGrid) const override
Return the size of the specified grid.
SCH_ITEM * GetSnapped() const
Function GetSnapped If the EE_GRID_HELPER has highlighted a snap point (target shown),...
EE_GRID_HELPER(TOOL_MANAGER *aToolMgr)
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,...
VECTOR2I m_skipPoint
Definition: grid_helper.h:182
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:172
ANCHOR * m_snapItem
Definition: grid_helper.h:180
bool m_enableSnapLine
Definition: grid_helper.h:179
bool m_enableSnap
Definition: grid_helper.h:177
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:148
bool canUseGrid() const
Check whether it is possible to use the grid – this depends both on local grid helper settings and gl...
void clearAnchors()
Definition: grid_helper.h:154
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:184
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:185
virtual VECTOR2I Align(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
Definition: grid_helper.h:60
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:186
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:170
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
const VECTOR2D & GetGridSize() const
Return the grid size.
double GetWorldScale() const
Get the world scale.
void SetPosition(const VECTOR2I &aPosition) override
void SetColor(const KIGFX::COLOR4D &aColor)
VECTOR2I GetPosition() const override
void SetStyle(MARKER_STYLE aStyle)
void SetSize(int aSize)
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
void SetEndPosition(const VECTOR2D &aPosition)
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:141
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:271
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:313
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:350
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:421
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:1619
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1589
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1546
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:151
virtual bool IsConnectable() const
Definition: sch_item.h:372
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:387
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
VECTOR2I GetEndPoint() const
Definition: sch_line.h:145
VECTOR2I GetStartPoint() const
Definition: sch_line.h:140
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
EDA_ITEM * Front() const
Definition: selection.h:208
Master controller class:
Definition: tool_manager.h:57
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:387
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:378
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
#define SNAP_RANGE
GRID_HELPER_GRIDS
Definition: grid_helper.h:37
@ GRID_TEXT
Definition: grid_helper.h:44
@ GRID_CURRENT
Definition: grid_helper.h:39
@ GRID_GRAPHICS
Definition: grid_helper.h:45
@ GRID_CONNECTABLE
Definition: grid_helper.h:41
@ GRID_WIRES
Definition: grid_helper.h:42
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:54
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
const double IU_PER_MILS
Definition: base_units.h:78
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:142
GRID_SETTINGS grid
Definition: app_settings.h:81
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:174
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128
@ SCH_LINE_T
Definition: typeinfo.h:146
@ LIB_SYMBOL_T
Definition: typeinfo.h:198
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:143
@ LIB_TEXT_T
Definition: typeinfo.h:200
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ LIB_TEXTBOX_T
Definition: typeinfo.h:201
@ SCH_FIELD_T
Definition: typeinfo.h:155
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:154
@ SCH_LABEL_T
Definition: typeinfo.h:151
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ LIB_SHAPE_T
Definition: typeinfo.h:199
@ SCH_SHAPE_T
Definition: typeinfo.h:147
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:153
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:145
@ LIB_PIN_T
Definition: typeinfo.h:202
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:157
@ SCH_TEXT_T
Definition: typeinfo.h:150
@ LIB_FIELD_T
Definition: typeinfo.h:208
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:144
@ SCH_BITMAP_T
Definition: typeinfo.h:148
@ SCH_TEXTBOX_T
Definition: typeinfo.h:149
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:152
@ SCH_JUNCTION_T
Definition: typeinfo.h:142
@ SCH_PIN_T
Definition: typeinfo.h:159
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588