KiCad PCB EDA Suite
Loading...
Searching...
No Matches
edit_points.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-2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[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
27#include <gal/color4d.h>
28#include <gal/painter.h>
29#include <math/util.h> // for KiROUND
30#include <geometry/seg.h>
31#include <wx/string.h>
32#include <vector>
33#include <algorithm>
34#include "tool/edit_points.h"
35
36
37bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const
38{
39 // Corners of the EDIT_POINT square
40 VECTOR2I topLeft = GetPosition() - aSize;
41 VECTOR2I bottomRight = GetPosition() + aSize;
42
43 return ( aPoint.x > topLeft.x && aPoint.y > topLeft.y &&
44 aPoint.x < bottomRight.x && aPoint.y < bottomRight.y );
45}
46
47
50 m_parent( aParent ),
51 m_swapX( false ),
52 m_swapY( false ),
53 m_allowPoints( true )
54{
55}
56
57
58EDIT_POINT* EDIT_POINTS::FindPoint( const VECTOR2I& aLocation, KIGFX::VIEW *aView ) // fixme: ugly
59{
60 unsigned size = std::abs( KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) ) );
61
62 if( m_allowPoints )
63 {
64 for( EDIT_POINT& point : m_points )
65 {
66 if( point.WithinPoint( aLocation, size ) )
67 return &point;
68 }
69 }
70
71 for( EDIT_LINE& line : m_lines )
72 {
73 if( line.WithinPoint( aLocation, size ) )
74 return &line;
75 }
76
77 return nullptr;
78}
79
80
81int EDIT_POINTS::GetContourStartIdx( int aPointIdx ) const
82{
83 int lastIdx = 0;
84
85 for( int idx : m_contours )
86 {
87 if( idx >= aPointIdx )
88 return lastIdx;
89
90 lastIdx = idx + 1;
91 }
92
93 return lastIdx;
94}
95
96
97int EDIT_POINTS::GetContourEndIdx( int aPointIdx ) const
98{
99 for( int idx : m_contours )
100 {
101 if( idx >= aPointIdx )
102 return idx;
103 }
104
105 return m_points.size() - 1;
106}
107
108
109bool EDIT_POINTS::IsContourStart( int aPointIdx ) const
110{
111 for( int idx : m_contours )
112 {
113 if( idx + 1 == aPointIdx )
114 return true;
115
116 // the list is sorted, so we cannot expect it any further
117 if( idx > aPointIdx )
118 break;
119 }
120
121 return ( aPointIdx == 0 );
122}
123
124
125bool EDIT_POINTS::IsContourEnd( int aPointIdx ) const
126{
127 for( int idx : m_contours )
128 {
129 if( idx == aPointIdx )
130 return true;
131
132 // the list is sorted, so we cannot expect it any further
133 if( idx > aPointIdx )
134 break;
135 }
136
137 // the end of the list surely is the end of a contour
138 return ( aPointIdx == (int) m_points.size() - 1 );
139}
140
141
142EDIT_POINT* EDIT_POINTS::Previous( const EDIT_POINT& aPoint, bool aTraverseContours )
143{
144 for( unsigned int i = 0; i < m_points.size(); ++i )
145 {
146 if( m_points[i] == aPoint )
147 {
148 if( !aTraverseContours && IsContourStart( i ) )
149 return &m_points[GetContourEndIdx( i )];
150
151 if( i == 0 )
152 return &m_points[m_points.size() - 1];
153 else
154 return &m_points[i - 1];
155 }
156 }
157
158 return nullptr;
159}
160
161
163{
164 for( unsigned int i = 0; i < m_lines.size(); ++i )
165 {
166 if( m_lines[i] == aLine )
167 {
168 if( i == 0 )
169 return &m_lines[m_lines.size() - 1];
170 else
171 return &m_lines[i - 1];
172 }
173 }
174
175 return nullptr;
176}
177
178
179EDIT_POINT* EDIT_POINTS::Next( const EDIT_POINT& aPoint, bool aTraverseContours )
180{
181 for( unsigned int i = 0; i < m_points.size(); ++i )
182 {
183 if( m_points[i] == aPoint )
184 {
185 if( !aTraverseContours && IsContourEnd( i ) )
186 return &m_points[GetContourStartIdx( i )];
187
188 if( i == m_points.size() - 1 )
189 return &m_points[0];
190 else
191 return &m_points[i + 1];
192 }
193 }
194
195 return nullptr;
196}
197
198
200{
201 for( unsigned int i = 0; i < m_lines.size(); ++i )
202 {
203 if( m_lines[i] == aLine )
204 {
205 if( i == m_lines.size() - 1 )
206 return &m_lines[0];
207 else
208 return &m_lines[i + 1];
209 }
210 }
211
212 return nullptr;
213}
214
215
217{
218 BOX2I box;
219 bool empty = true;
220
221 for( const auto& point : m_points )
222 {
223 if( empty )
224 {
225 box.SetOrigin( point.GetPosition() );
226 empty = false;
227 }
228 else
229 {
230 box.Merge( point.GetPosition() );
231 }
232 }
233
234 for( const auto& line : m_lines )
235 {
236 if( empty )
237 {
238 box.SetOrigin( line.GetOrigin().GetPosition() );
239 box.SetEnd( line.GetEnd().GetPosition() );
240 empty = false;
241 }
242 else
243 {
244 box.Merge( line.GetOrigin().GetPosition() );
245 box.Merge( line.GetEnd().GetPosition() );
246 }
247 }
248
249 return box;
250}
251
252
253void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
254{
255 KIGFX::GAL* gal = aView->GetGAL();
256 KIGFX::RENDER_SETTINGS* settings = aView->GetPainter()->GetSettings();
257 KIGFX::COLOR4D drawColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
258
259 // Don't assume LAYER_AUX_ITEMS is always a good choice. Compare with background.
260 if( aView->GetGAL()->GetClearColor().Distance( drawColor ) < 0.5 )
261 drawColor.Invert();
262
263 // Linear darkening doesn't fit well with human color perception, and there's no guarantee
264 // that there's enough room for contrast either.
265 KIGFX::COLOR4D borderColor;
266 KIGFX::COLOR4D highlightColor;
267 double brightness = drawColor.GetBrightness();
268
269 if( brightness > 0.5 )
270 {
271 borderColor = drawColor.Darkened( 0.7 ).WithAlpha( 0.8 );
272 highlightColor = drawColor.Darkened( 0.5 ).WithAlpha( 0.8 );
273 }
274 else if( brightness > 0.2 )
275 {
276 borderColor = drawColor.Brightened( 0.4 ).WithAlpha( 0.8 );
277 highlightColor = drawColor.Brightened( 0.3 ).WithAlpha( 0.8 );
278 }
279 else
280 {
281 borderColor = drawColor.Brightened( 0.7 ).WithAlpha( 0.8 );
282 highlightColor = drawColor.Brightened( 0.5 ).WithAlpha( 0.8 );
283 }
284
286 gal->SetFillColor( drawColor );
287 gal->SetStrokeColor( borderColor );
288 gal->SetIsFill( true );
289 gal->SetIsStroke( true );
290 gal->SetLayerDepth( gal->GetMinDepth() );
291
292 double size = aView->ToWorld( EDIT_POINT::POINT_SIZE ) / 2.0;
293 double borderSize = aView->ToWorld( EDIT_POINT::BORDER_SIZE );
294 double hoverSize = aView->ToWorld( EDIT_POINT::HOVER_SIZE );
295
296 auto drawPoint =
297 [&]( const EDIT_POINT& aPoint, bool aDrawCircle = false )
298 {
299 if( aPoint.IsHover() || aPoint.IsActive() )
300 {
301 gal->SetStrokeColor( highlightColor );
302 gal->SetLineWidth( hoverSize );
303 }
304 else
305 {
306 gal->SetStrokeColor( borderColor );
307 gal->SetLineWidth( borderSize );
308 }
309
310 gal->SetFillColor( drawColor );
311
312 if( aDrawCircle )
313 gal->DrawCircle( aPoint.GetPosition(), size );
314 else
315 gal->DrawRectangle( aPoint.GetPosition() - size, aPoint.GetPosition() + size );
316 };
317
318 for( const EDIT_POINT& point : m_points )
319 drawPoint( point, point.DrawCircle() );
320
321 for( const EDIT_LINE& line : m_lines )
322 {
323 if( line.HasCenterPoint() )
324 {
325 drawPoint( line.GetPosition(), true );
326 }
327
328 if( line.DrawLine() )
329 {
330 gal->SetLineWidth( borderSize / 4 );
331 gal->SetStrokeColor( borderColor );
332 gal->DrawLine( line.GetOrigin().GetPosition(), line.GetEnd().GetPosition() );
333 }
334 }
335
336}
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
Represent a line connecting two EDIT_POINTs.
bool IsContourStart(int aPointIdx) const
Check if a point with given index is a contour origin.
bool m_allowPoints
If false, only allow editing of EDIT_LINES.
int GetContourEndIdx(int aPointIdx) const
Return index of the contour finish for a point with given index.
virtual const BOX2I ViewBBox() const override
EDIT_POINT * Previous(const EDIT_POINT &aPoint, bool aTraverseContours=true)
Return the point that is after the given point in the list.
EDIT_POINT * Next(const EDIT_POINT &aPoint, bool aTraverseContours=true)
Return the point that is before the given point in the list.
std::deque< EDIT_LINE > m_lines
EDIT_LINEs for modifying m_parent.
std::list< int > m_contours
Indices of end contour points.
EDIT_POINTS(EDA_ITEM *aParent)
bool m_swapY
Parent's Y coords are inverted.
bool IsContourEnd(int aPointIdx) const
Check is a point with given index is a contour finish.
EDA_ITEM * m_parent
Parent of the EDIT_POINTs.
std::deque< EDIT_POINT > m_points
EDIT_POINTs for modifying m_parent.
bool m_swapX
Parent's X coords are inverted.
EDIT_POINT * FindPoint(const VECTOR2I &aLocation, KIGFX::VIEW *aView)
Return a point that is at given coordinates or NULL if there is no such point.
int GetContourStartIdx(int aPointIdx) const
Return index of the contour origin for a point with given index.
virtual void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Represent a single point that can be used for modifying items.
Definition edit_points.h:48
static const int HOVER_SIZE
Border size when hovering.
bool IsActive() const
static const int POINT_SIZE
Single point size in pixels.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:72
bool WithinPoint(const VECTOR2I &aPoint, unsigned int aSize) const
Check if given point is within a square centered in the EDIT_POINT position.
bool IsHover() const
static const int BORDER_SIZE
Border size when not hovering.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:311
COLOR4D & Invert()
Makes the color inverted, alpha remains the same.
Definition color4d.h:242
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
Definition color4d.h:282
double GetBrightness() const
Returns the brightness value of the color ranged from 0.0 to 1.0.
Definition color4d.h:333
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:268
double Distance(const COLOR4D &other) const
Returns the distance (in RGB space) between two colors.
Definition color4d.cpp:532
Attribute save/restore for GAL attributes.
Abstract interface for drawing on a 2D-surface.
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
const COLOR4D & GetClearColor() const
double GetMinDepth() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition view.cpp:467
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:220
static bool empty(const wxTextEntryBase *aCtrl)
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc).
Definition layer_ids.h:282
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:79
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695