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_table.h>
32#include <sch_tablecell.h>
33#include <sch_painter.h>
34#include <tool/tool_manager.h>
36#include <trigo.h>
37#include <view/view.h>
38#include "ee_grid_helper.h"
39
40
42 GRID_HELPER( aToolMgr )
43{
44 KIGFX::VIEW* view = m_toolMgr->GetView();
45
46 m_viewAxis.SetSize( 20000 );
48 m_viewAxis.SetColor( COLOR4D( 0.0, 0.1, 0.4, 0.8 ) );
50 view->Add( &m_viewAxis );
51 view->SetVisible( &m_viewAxis, false );
52
54 m_viewSnapPoint.SetColor( COLOR4D( 0.0, 0.1, 0.4, 1.0 ) );
56 view->Add( &m_viewSnapPoint );
57 view->SetVisible( &m_viewSnapPoint, false );
58
60 m_viewSnapLine.SetColor( COLOR4D( 0.33, 0.55, 0.95, 1.0 ) );
62 view->Add( &m_viewSnapLine );
63 view->SetVisible( &m_viewSnapLine, false );
64}
65
66
68{
69 KIGFX::VIEW* view = m_toolMgr->GetView();
70
71 view->Remove( &m_viewAxis );
72 view->Remove( &m_viewSnapPoint );
73 view->Remove( &m_viewSnapLine );
74}
75
76
78 const EE_SELECTION& aItems )
79{
81
82 // If we're working with any connectable objects, skip non-connectable objects
83 // since they are often off-grid, e.g. text anchors
84 bool hasConnectables = false;
85
86 for( EDA_ITEM* item : aItems )
87 {
88 GRID_HELPER_GRIDS grid = GetItemGrid( static_cast<SCH_ITEM*>( item ) );
90 {
91 hasConnectables = true;
92 break;
93 }
94 }
95
96 for( EDA_ITEM* item : aItems )
97 computeAnchors( static_cast<SCH_ITEM*>( item ), aMousePos, true, !hasConnectables );
98
99 double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
100 double lineSnapMinCornerDistance = 50.0 / worldScale;
101
102 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aGrid );
103 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aGrid );
104 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aGrid );
105 ANCHOR* best = nullptr;
106 double minDist = std::numeric_limits<double>::max();
107
108 if( nearestOrigin )
109 {
110 minDist = nearestOrigin->Distance( aMousePos );
111 best = nearestOrigin;
112 }
113
114 if( nearestCorner )
115 {
116 double dist = nearestCorner->Distance( aMousePos );
117
118 if( dist < minDist )
119 {
120 minDist = dist;
121 best = nearestCorner;
122 }
123 }
124
125 if( nearestOutline )
126 {
127 double dist = nearestOutline->Distance( aMousePos );
128
129 if( minDist > lineSnapMinCornerDistance && dist < minDist )
130 best = nearestOutline;
131 }
132
133 return best ? best->pos : aMousePos;
134}
135
136
138 SCH_ITEM* aSkip )
139{
140 EE_SELECTION skipItems;
141 skipItems.Add( aSkip );
142
143 return BestSnapAnchor( aOrigin, aGrid, skipItems );
144}
145
146
148 const EE_SELECTION& aSkip )
149{
150 constexpr int snapRange = SNAP_RANGE * schIUScale.IU_PER_MILS;
151
152 VECTOR2I pt = aOrigin;
153 VECTOR2I snapDist( snapRange, snapRange );
154 bool snapLineX = false;
155 bool snapLineY = false;
156 bool snapPoint = false;
157 bool gridChecked = false;
158
159 BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
160 VECTOR2I( snapRange, snapRange ) );
161
162 clearAnchors();
163
164 for( SCH_ITEM* item : queryVisible( bb, aSkip ) )
165 computeAnchors( item, aOrigin );
166
167 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aGrid );
168 VECTOR2I nearestGrid = Align( aOrigin, aGrid );
169
171 {
172 if( std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x ) < snapDist.x )
173 {
175 snapDist.x = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
176 snapLineX = true;
177 }
178
179 if( std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y ) < snapDist.y )
180 {
182 snapDist.y = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
183 snapLineY = true;
184 }
185
186 if( canUseGrid() && std::abs( nearestGrid.x - aOrigin.x ) < snapDist.x )
187 {
188 pt.x = nearestGrid.x;
189 snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
190 snapLineX = false;
191 }
192
193 if( canUseGrid() && std::abs( nearestGrid.y - aOrigin.y ) < snapDist.y )
194 {
195 pt.y = nearestGrid.y;
196 snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
197 snapLineY = false;
198 }
199
200 gridChecked = true;
201 }
202
203 if( m_enableSnap && nearest && nearest->Distance( aOrigin ) < snapDist.EuclideanNorm() )
204 {
205
206 if( canUseGrid() && ( nearestGrid - aOrigin ).EuclideanNorm() < snapDist.EuclideanNorm() )
207 {
208 pt = nearestGrid;
209 snapDist.x = std::abs( nearestGrid.x - aOrigin.x );
210 snapDist.y = std::abs( nearestGrid.y - aOrigin.y );
211 snapPoint = false;
212 }
213 else
214 {
215 pt = nearest->pos;
216 snapDist.x = std::abs( nearest->pos.x - aOrigin.x );
217 snapDist.y = std::abs( nearest->pos.y - aOrigin.y );
218 snapPoint = true;
219 }
220
221 snapLineX = snapLineY = false;
222 gridChecked = true;
223 }
224
225 if( canUseGrid() && !gridChecked )
226 pt = nearestGrid;
227
228 if( snapLineX || snapLineY )
229 {
231
234 else
236 }
237 else if( snapPoint )
238 {
239 m_snapItem = nearest;
242
244
247 else
249 }
250 else
251 {
254 }
255
256 return pt;
257}
258
259
261{
263 int idx = -1;
264
266
267 if( !grid.overrides_enabled )
268 return g;
269
270 switch( aGrid )
271 {
272 case GRID_CONNECTABLE:
273 if( grid.override_connected )
274 idx = grid.override_connected_idx;
275
276 break;
277
278 case GRID_WIRES:
279 if( grid.override_wires )
280 idx = grid.override_wires_idx;
281
282 break;
283
284 case GRID_TEXT:
285 if( grid.override_text )
286 idx = grid.override_text_idx;
287
288 break;
289
290 case GRID_GRAPHICS:
291 if( grid.override_graphics )
292 idx = grid.override_graphics_idx;
293
294 break;
295
296 default:
297 break;
298 }
299
300 if( idx >= 0 && idx < (int) grid.grids.size() )
301 g = grid.grids[idx].ToDouble( schIUScale );
302
303 return g;
304}
305
306
308{
309 if( !m_snapItem )
310 return nullptr;
311
312 return static_cast<SCH_ITEM*>( m_snapItem->item );
313}
314
315
316std::set<SCH_ITEM*> EE_GRID_HELPER::queryVisible( const BOX2I& aArea,
317 const EE_SELECTION& aSkipList ) const
318{
319 std::set<SCH_ITEM*> items;
320 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
321
322 KIGFX::VIEW* view = m_toolMgr->GetView();
323
324 view->Query( aArea, selectedItems );
325
326 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
327 {
328 SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
329
330 // The item must be visible and on an active layer
331 if( view->IsVisible( item ) && item->ViewGetLOD( it.second, view ) < view->GetScale() )
332 items.insert ( item );
333 }
334
335 for( EDA_ITEM* skipItem : aSkipList )
336 items.erase( static_cast<SCH_ITEM*>( skipItem ) );
337
338 return items;
339}
340
341
343{
344 GRID_HELPER_GRIDS grid = GetItemGrid( aSelection.Front() );
345
346 // Find the largest grid of all the items and use that
347 for( EDA_ITEM* item : aSelection )
348 {
349 GRID_HELPER_GRIDS itemGrid = GetItemGrid( item );
350
351 if( GetGridSize( itemGrid ) > GetGridSize( grid ) )
352 grid = itemGrid;
353 }
354
355 return grid;
356}
357
358
360{
361 if( !aItem )
362 return GRID_CURRENT;
363
364 switch( aItem->Type() )
365 {
366 case LIB_SYMBOL_T:
367 case SCH_SYMBOL_T:
368 case SCH_PIN_T:
369 case SCH_SHEET_PIN_T:
370 case SCH_SHEET_T:
371 case SCH_NO_CONNECT_T:
373 case SCH_HIER_LABEL_T:
374 case SCH_LABEL_T:
376 case SCH_RULE_AREA_T:
377 return GRID_CONNECTABLE;
378
379 case SCH_FIELD_T:
380 case SCH_TEXT_T:
381 return GRID_TEXT;
382
383 case SCH_SHAPE_T:
384 // The text box's border lines are what need to be on the graphic grid
385 case SCH_TEXTBOX_T:
386 case SCH_BITMAP_T:
387 return GRID_GRAPHICS;
388
389 case SCH_JUNCTION_T:
390 return GRID_WIRES;
391
392 case SCH_LINE_T:
393 if( static_cast<const SCH_LINE*>( aItem )->IsConnectable() )
394 return GRID_WIRES;
395 else
396 return GRID_GRAPHICS;
397
400 return GRID_WIRES;
401
402 default:
403 return GRID_CURRENT;
404 }
405}
406
407
408void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom,
409 bool aIncludeText )
410{
411 bool isGraphicLine =
412 aItem->Type() == SCH_LINE_T && static_cast<SCH_LINE*>( aItem )->IsGraphicLine();
413
414 switch( aItem->Type() )
415 {
416 case SCH_TEXT_T:
417 case SCH_FIELD_T:
418 {
419 if( aIncludeText )
420 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
421
422 break;
423 }
424
425 case SCH_TABLE_T:
426 {
427 if( aIncludeText )
428 {
429 addAnchor( aItem->GetPosition(), SNAPPABLE | CORNER, aItem );
430 addAnchor( static_cast<SCH_TABLE*>( aItem )->GetEnd(), SNAPPABLE | CORNER, aItem );
431 }
432
433 break;
434 }
435
436 case SCH_TEXTBOX_T:
437 case SCH_TABLECELL_T:
438 {
439 if( aIncludeText )
440 {
441 addAnchor( aItem->GetPosition(), SNAPPABLE | CORNER, aItem );
442 addAnchor( dynamic_cast<SCH_SHAPE*>( aItem )->GetEnd(), SNAPPABLE | CORNER, aItem );
443 }
444
445 break;
446 }
447
448 case SCH_SYMBOL_T:
449 case SCH_SHEET_T:
450 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
452
453 case SCH_JUNCTION_T:
454 case SCH_NO_CONNECT_T:
455 case SCH_LINE_T:
456 // Don't add anchors for graphic lines unless we're including text,
457 // they may be on a non-connectable grid
458 if( isGraphicLine && !aIncludeText )
459 break;
460
463 case SCH_HIER_LABEL_T:
464 case SCH_LABEL_T:
467 case SCH_SHEET_PIN_T:
468 {
469 std::vector<VECTOR2I> pts = aItem->GetConnectionPoints();
470
471 for( const VECTOR2I& pt : pts )
472 addAnchor( VECTOR2I( pt ), SNAPPABLE | CORNER, aItem );
473
474 break;
475 }
476
477 default:
478 break;
479 }
480
481 // Don't add anchors for graphic lines unless we're including text,
482 // they may be on a non-connectable grid
483 if( aItem->Type() == SCH_LINE_T && ( aIncludeText || !isGraphicLine ) )
484 {
485 SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
486 VECTOR2I pt = Align( aRefPos );
487
488 if( line->GetStartPoint().x == line->GetEndPoint().x )
489 {
490 VECTOR2I possible( line->GetStartPoint().x, pt.y );
491
492 if( TestSegmentHit( possible, line->GetStartPoint(), line->GetEndPoint(), 0 ) )
493 addAnchor( possible, SNAPPABLE | VERTICAL, aItem );
494 }
495 else if( line->GetStartPoint().y == line->GetEndPoint().y )
496 {
497 VECTOR2I possible( pt.x, line->GetStartPoint().y );
498
499 if( TestSegmentHit( possible, line->GetStartPoint(), line->GetEndPoint(), 0 ) )
500 addAnchor( possible, SNAPPABLE | HORIZONTAL, aItem );
501 }
502 }
503}
504
505
507 GRID_HELPER_GRIDS aGrid )
508{
509 double minDist = std::numeric_limits<double>::max();
510 ANCHOR* best = nullptr;
511
512 for( ANCHOR& a : m_anchors )
513 {
514 SCH_ITEM* item = static_cast<SCH_ITEM*>( a.item );
515
516 if( ( aFlags & a.flags ) != aFlags )
517 continue;
518
519 if( aGrid == GRID_CONNECTABLE && !item->IsConnectable() )
520 continue;
521 else if( aGrid == GRID_GRAPHICS && item->IsConnectable() )
522 continue;
523
524 double dist = a.Distance( aPos );
525
526 if( dist < minDist )
527 {
528 minDist = dist;
529 best = &a;
530 }
531 }
532
533 return best;
534}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
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:88
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:242
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
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:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
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
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:1631
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:1601
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1558
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:174
virtual bool IsConnectable() const
Definition: sch_item.h:457
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:472
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:140
VECTOR2I GetStartPoint() const
Definition: sch_line.h:135
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
EDA_ITEM * Front() const
Definition: selection.h:172
Master controller class:
Definition: tool_manager.h:62
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:400
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
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:77
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_TABLE_T
Definition: typeinfo.h:165
@ SCH_LINE_T
Definition: typeinfo.h:163
@ LIB_SYMBOL_T
Definition: typeinfo.h:148
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:160
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_TABLECELL_T
Definition: typeinfo.h:166
@ SCH_FIELD_T
Definition: typeinfo.h:150
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:171
@ SCH_LABEL_T
Definition: typeinfo.h:167
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_SHAPE_T
Definition: typeinfo.h:149
@ SCH_RULE_AREA_T
Definition: typeinfo.h:170
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:169
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:162
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:173
@ SCH_TEXT_T
Definition: typeinfo.h:151
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:161
@ SCH_BITMAP_T
Definition: typeinfo.h:164
@ SCH_TEXTBOX_T
Definition: typeinfo.h:152
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:168
@ SCH_JUNCTION_T
Definition: typeinfo.h:159
@ SCH_PIN_T
Definition: typeinfo.h:153
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588