KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "tool/grid_helper.h"
25
26#include <functional>
27#include <cmath>
28#include <limits>
29
30#include <advanced_config.h>
32#include <math/util.h> // for KiROUND
33#include <math/vector2d.h>
34#include <tool/tool_manager.h>
35#include <tool/tools_holder.h>
36#include <view/view.h>
38
39
42{
44 m_enableSnap = true;
45 m_enableSnapLine = true;
46 m_enableGrid = true;
47 m_snapItem = std::nullopt;
48
49 m_manualGrid = VECTOR2D( 1, 1 );
51 m_manualOrigin = VECTOR2I( 0, 0 );
53}
54
55
56GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
58{
59 m_toolMgr = aToolMgr;
60
61 if( !m_toolMgr )
62 return;
64 KIGFX::VIEW* view = m_toolMgr->GetView();
65 wxUnusedVar( aConstructionLayer );
66
69
70 m_snapManager.SetUpdateCallback(
71 [view, this]( bool aAnythingShown )
72 {
73 const bool currentlyVisible = view->IsVisible( &m_constructionGeomPreview );
74
75 if( currentlyVisible && aAnythingShown )
76 {
78 }
79 else
80 {
81 view->SetVisible( &m_constructionGeomPreview, aAnythingShown );
82 }
83
84 m_toolMgr->GetToolHolder()->RefreshCanvas();
85 } );
87 // Initialise manual values from view for compatibility
88 m_manualGrid = view->GetGAL()->GetGridSize();
92}
93
94
96{
97 if( !m_toolMgr )
98 return;
99
100 KIGFX::VIEW& view = *m_toolMgr->GetView();
102
103 if( m_anchorDebug )
104 view.Remove( m_anchorDebug.get() );
105}
106
107
109{
110 static bool permitted = ADVANCED_CFG::GetCfg().m_EnableSnapAnchorsDebug;
111
112 if( !m_toolMgr )
113 return nullptr;
114
115 if( permitted && !m_anchorDebug )
116 {
117 KIGFX::VIEW& view = *m_toolMgr->GetView();
118 m_anchorDebug = std::make_unique<KIGFX::ANCHOR_DEBUG>();
119 view.Add( m_anchorDebug.get() );
120 view.SetVisible( m_anchorDebug.get(), true );
121 }
122
123 return m_anchorDebug.get();
124}
125
126
128{
129 if( m_toolMgr )
130 m_toolMgr->GetView()->SetVisible( &m_constructionGeomPreview, aShow );
131}
132
133
134void GRID_HELPER::SetSnapLineDirections( const std::vector<VECTOR2I>& aDirections )
135{
136 m_snapManager.GetSnapLineManager().SetDirections( aDirections );
137}
138
139
141{
142 m_snapManager.GetSnapLineManager().SetSnapLineOrigin( aOrigin );
143}
144
145void GRID_HELPER::SetSnapLineEnd( const std::optional<VECTOR2I>& aEnd )
146{
147 m_snapManager.GetSnapLineManager().SetSnapLineEnd( aEnd );
148}
149
151{
152 m_snapManager.GetSnapLineManager().ClearSnapLine();
153}
154
155
156std::optional<VECTOR2I> GRID_HELPER::SnapToConstructionLines( const VECTOR2I& aPoint,
157 const VECTOR2I& aNearestGrid,
158 const VECTOR2D& aGrid,
159 double aSnapRange ) const
160{
161 const SNAP_LINE_MANAGER& snapLineManager = m_snapManager.GetSnapLineManager();
162 const OPT_VECTOR2I& snapOrigin = snapLineManager.GetSnapLineOrigin();
163
164 if( !snapOrigin || snapLineManager.GetDirections().empty() )
165 return std::nullopt;
166
167 const VECTOR2I& origin = *snapOrigin;
168
169 const std::vector<VECTOR2I>& directions = snapLineManager.GetDirections();
170 const std::optional<int> activeDirection = snapLineManager.GetActiveDirection();
171
172 const VECTOR2D originVec( origin );
173 const VECTOR2D cursorVec( aPoint );
174 const VECTOR2D delta = cursorVec - originVec;
175
176 std::optional<VECTOR2I> bestPoint;
177 double bestPerp = std::numeric_limits<double>::max();
178 double bestDistance = std::numeric_limits<double>::max();
179
180 for( size_t ii = 0; ii < directions.size(); ++ii )
181 {
182 const VECTOR2I& dir = directions[ii];
183 VECTOR2D dirVector( dir );
184 double dirLength = dirVector.EuclideanNorm();
185
186 if( dirLength == 0.0 )
187 continue;
188
189 VECTOR2D dirUnit = dirVector / dirLength;
190
191 double distanceAlong = delta.Dot( dirUnit );
192 VECTOR2D projection = originVec + dirUnit * distanceAlong;
193 VECTOR2D offset = delta - dirUnit * distanceAlong;
194 double perpDistance = offset.EuclideanNorm();
195
196 double snapThreshold = aSnapRange;
197
198 if( activeDirection && *activeDirection == static_cast<int>( ii ) )
199 snapThreshold *= 1.5;
200
201 if( perpDistance > snapThreshold )
202 continue;
203
204 VECTOR2D candidate = projection;
205
206 if( canUseGrid() )
207 {
208 if( dir.x == 0 && dir.y != 0 )
209 {
210 candidate.x = origin.x;
211 candidate.y = aNearestGrid.y;
212 }
213 else if( dir.y == 0 && dir.x != 0 )
214 {
215 candidate.x = aNearestGrid.x;
216 candidate.y = origin.y;
217 }
218 else
219 {
220 double stepDistance = std::sqrt( aGrid.x * aGrid.x + aGrid.y * aGrid.y );
221
222 if( stepDistance == 0.0 )
223 continue;
224
225 double steps = std::round( distanceAlong / stepDistance );
226 candidate = originVec + dirUnit * ( steps * stepDistance );
227 }
228 }
229
230 VECTOR2I candidateInt( KiROUND( candidate.x ), KiROUND( candidate.y ) );
231
232 if( candidateInt == m_skipPoint )
233 continue;
234
235 VECTOR2D candidateDelta( candidateInt.x - aPoint.x, candidateInt.y - aPoint.y );
236 double candidateDistance = candidateDelta.EuclideanNorm();
237
238 if( perpDistance < bestPerp
239 || ( std::abs( perpDistance - bestPerp ) < 1e-9 && candidateDistance < bestDistance ) )
240 {
241 bestPerp = perpDistance;
242 bestDistance = candidateDistance;
243 bestPoint = candidateInt;
244 }
245 }
246
247 return bestPoint;
248}
249
250
252{
253 if( !m_toolMgr )
254 return;
255
256 m_viewSnapPoint.SetPosition( aPoint.m_point );
257 m_viewSnapPoint.SetSnapTypes( aPoint.m_types );
258
259 if( m_toolMgr->GetView()->IsVisible( &m_viewSnapPoint ) )
260 m_toolMgr->GetView()->Update( &m_viewSnapPoint, KIGFX::GEOMETRY );
261 else
262 m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, true );
263}
264
265
267{
268 VECTOR2D size = m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
269 return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
270}
271
272
274{
275 return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetVisibleGridSize() : m_manualVisibleGrid;
276}
277
278
280{
281 if( m_toolMgr )
282 {
283 VECTOR2D origin = m_toolMgr->GetView()->GetGAL()->GetGridOrigin();
284 return VECTOR2I( origin );
285 }
286
287 return m_manualOrigin;
288}
289
290
292{
293 GRID_HELPER_GRIDS grid = GetItemGrid( aSelection.Front() );
294
295 // Find the largest grid of all the items and use that
296 for( EDA_ITEM* item : aSelection )
297 {
298 GRID_HELPER_GRIDS itemGrid = GetItemGrid( item );
299
300 if( GetGridSize( itemGrid ) > GetGridSize( grid ) )
301 grid = itemGrid;
302 }
303
304 return grid;
305}
306
307
309{
310 return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
311}
312
313
314void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin )
315{
316 if( aEnable )
317 {
318 m_auxAxis = aOrigin;
319 m_viewAxis.SetPosition( aOrigin );
320 if( m_toolMgr )
321 m_toolMgr->GetView()->SetVisible( &m_viewAxis, true );
322 }
323 else
324 {
325 m_auxAxis = std::optional<VECTOR2I>();
326 if( m_toolMgr )
327 m_toolMgr->GetView()->SetVisible( &m_viewAxis, false );
328 }
329}
330
331
333{
334 return computeNearest( aPoint, GetGrid(), GetOrigin() );
335}
336
337
339 const VECTOR2D& aOffset ) const
340{
341 return computeNearest( aPoint, aGrid, aOffset );
342}
343
344
346 const VECTOR2I& aOffset ) const
347{
348 return VECTOR2I( KiROUND( (double) ( aPoint.x - aOffset.x ) / aGrid.x ) * aGrid.x + aOffset.x,
349 KiROUND( (double) ( aPoint.y - aOffset.y ) / aGrid.y ) * aGrid.y + aOffset.y );
350}
351
352
354{
355 return Align( aPoint, GetGrid(), GetOrigin() );
356}
357
358
359VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid,
360 const VECTOR2D& aOffset ) const
361{
362 if( !canUseGrid() )
363 return aPoint;
364
365 VECTOR2I nearest = AlignGrid( aPoint, aGrid, aOffset );
366
367 if( !m_auxAxis )
368 return nearest;
369
370 if( std::abs( m_auxAxis->x - aPoint.x ) < std::abs( nearest.x - aPoint.x ) )
371 nearest.x = m_auxAxis->x;
372
373 if( std::abs( m_auxAxis->y - aPoint.y ) < std::abs( nearest.y - aPoint.y ) )
374 nearest.y = m_auxAxis->y;
375
376 return nearest;
377}
378
379
381{
382 return m_enableGrid && ( m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSnapping()
384}
385
386
387std::optional<VECTOR2I> GRID_HELPER::GetSnappedPoint() const
388{
389 if( m_snapItem )
390 return m_snapItem->pos;
391
392 return std::nullopt;
393}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
KIGFX::CONSTRUCTION_GEOM m_constructionGeomPreview
Show construction geometry (if any) on the canvas.
std::optional< VECTOR2I > m_auxAxis
VECTOR2I computeNearest(const VECTOR2I &aPoint, const VECTOR2I &aGrid, const VECTOR2I &aOffset) const
std::optional< VECTOR2I > SnapToConstructionLines(const VECTOR2I &aPoint, const VECTOR2I &aNearestGrid, const VECTOR2D &aGrid, double aSnapRange) const
void SetSnapLineDirections(const std::vector< VECTOR2I > &aDirections)
VECTOR2I m_skipPoint
bool m_enableGrid
virtual GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const
Get the coarsest grid that applies to an item.
void showConstructionGeometry(bool aShow)
SNAP_MANAGER m_snapManager
Manage the construction geometry, snap lines, reference points, etc.
virtual ~GRID_HELPER()
VECTOR2D m_manualVisibleGrid
void SetSnapLineOrigin(const VECTOR2I &aOrigin)
bool m_manualGridSnapping
VECTOR2I m_manualOrigin
virtual GRID_HELPER_GRIDS GetSelectionGrid(const SELECTION &aSelection) const
Gets the coarsest grid that applies to a selecion of items.
TOOL_MANAGER * m_toolMgr
std::optional< VECTOR2I > GetSnappedPoint() const
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
VECTOR2D GetVisibleGrid() const
std::unique_ptr< KIGFX::ANCHOR_DEBUG > m_anchorDebug
#VIEW_ITEM for visualising anchor points, if enabled.
virtual VECTOR2D GetGridSize(GRID_HELPER_GRIDS aGrid) const
Return the size of the specified grid.
VECTOR2I GetGrid() const
bool m_enableSnapLine
bool m_enableSnap
VECTOR2I GetOrigin() const
bool canUseGrid() const
Check whether it is possible to use the grid – this depends both on local grid helper settings and gl...
void ClearSnapLine()
std::optional< ANCHOR > m_snapItem
KIGFX::ANCHOR_DEBUG * enableAndGetAnchorDebug()
Enable the anchor debug if permitted and return it.
void SetSnapLineEnd(const std::optional< VECTOR2I > &aEnd)
KIGFX::SNAP_INDICATOR m_viewSnapPoint
virtual VECTOR2I Align(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
Definition grid_helper.h:75
void updateSnapPoint(const TYPED_POINT2I &aPoint)
KIGFX::ORIGIN_VIEWITEM m_viewAxis
VECTOR2D m_manualGrid
virtual VECTOR2I AlignGrid(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
Definition grid_helper.h:80
View item to draw debug items for anchors.
const VECTOR2D & GetGridOrigin() const
VECTOR2D GetVisibleGridSize() const
Return the visible grid size in x and y directions.
const VECTOR2D & GetGridSize() const
Return the grid size.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:341
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:1685
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition view.cpp:1655
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1612
EDA_ITEM * Front() const
Definition selection.h:177
const std::vector< VECTOR2I > & GetDirections() const
std::optional< int > GetActiveDirection() const
const OPT_VECTOR2I & GetSnapLineOrigin() const
Master controller class:
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:283
GRID_HELPER_GRIDS
Definition grid_helper.h:44
bool m_EnableSnapAnchorsDebug
Enable snap anchors debug visualization.
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:55
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:39
VECTOR2I m_point
Definition point_types.h:77
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694