KiCad PCB EDA Suite
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 (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@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 
27 #include <gal/color4d.h>
28 #include <painter.h>
29 #include <math/util.h> // for KiROUND
30 #include "tool/edit_points.h"
31 
32 
33 bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const
34 {
35  // Corners of the EDIT_POINT square
36  VECTOR2I topLeft = GetPosition() - aSize;
37  VECTOR2I bottomRight = GetPosition() + aSize;
38 
39  return ( aPoint.x > topLeft.x && aPoint.y > topLeft.y &&
40  aPoint.x < bottomRight.x && aPoint.y < bottomRight.y );
41 }
42 
43 
45  : EDA_ITEM( NOT_USED ), m_parent( aParent ), m_allowPoints( true )
46 {
47 }
48 
49 
50 EDIT_POINT* EDIT_POINTS::FindPoint( const VECTOR2I& aLocation, KIGFX::VIEW *aView ) // fixme: ugly
51 {
52  unsigned size = std::abs( KiROUND( aView->ToWorld( EDIT_POINT::POINT_SIZE ) ) );
53 
54  if( m_allowPoints )
55  {
56  for( auto& point : m_points )
57  {
58  if( point.WithinPoint( aLocation, size ) )
59  return &point;
60  }
61  }
62 
63  for( auto& line : m_lines )
64  {
65  if( line.WithinPoint( aLocation, size ) )
66  return &line;
67  }
68 
69  return nullptr;
70 }
71 
72 
73 int EDIT_POINTS::GetContourStartIdx( int aPointIdx ) const
74 {
75  int lastIdx = 0;
76 
77  for( int idx : m_contours )
78  {
79  if( idx >= aPointIdx )
80  return lastIdx;
81 
82  lastIdx = idx + 1;
83  }
84 
85  return lastIdx;
86 }
87 
88 
89 int EDIT_POINTS::GetContourEndIdx( int aPointIdx ) const
90 {
91  for( int idx : m_contours )
92  {
93  if( idx >= aPointIdx )
94  return idx;
95  }
96 
97  return m_points.size() - 1;
98 }
99 
100 
101 bool EDIT_POINTS::IsContourStart( int aPointIdx ) const
102 {
103  for( int idx : m_contours )
104  {
105  if( idx + 1 == aPointIdx )
106  return true;
107 
108  // the list is sorted, so we cannot expect it any further
109  if( idx > aPointIdx )
110  break;
111  }
112 
113  return ( aPointIdx == 0 );
114 }
115 
116 
117 bool EDIT_POINTS::IsContourEnd( int aPointIdx ) const
118 {
119  for( int idx : m_contours )
120  {
121  if( idx == aPointIdx )
122  return true;
123 
124  // the list is sorted, so we cannot expect it any further
125  if( idx > aPointIdx )
126  break;
127  }
128 
129  // the end of the list surely is the end of a contour
130  return ( aPointIdx == (int) m_points.size() - 1 );
131 }
132 
133 
134 EDIT_POINT* EDIT_POINTS::Previous( const EDIT_POINT& aPoint, bool aTraverseContours )
135 {
136  for( unsigned int i = 0; i < m_points.size(); ++i )
137  {
138  if( m_points[i] == aPoint )
139  {
140  if( !aTraverseContours && IsContourStart( i ) )
141  return &m_points[GetContourEndIdx( i )];
142 
143  if( i == 0 )
144  return &m_points[m_points.size() - 1];
145  else
146  return &m_points[i - 1];
147  }
148  }
149 
150  return nullptr;
151 }
152 
153 
155 {
156  for( unsigned int i = 0; i < m_lines.size(); ++i )
157  {
158  if( m_lines[i] == aLine )
159  {
160  if( i == 0 )
161  return &m_lines[m_lines.size() - 1];
162  else
163  return &m_lines[i - 1];
164  }
165  }
166 
167  return nullptr;
168 }
169 
170 
171 EDIT_POINT* EDIT_POINTS::Next( const EDIT_POINT& aPoint, bool aTraverseContours )
172 {
173  for( unsigned int i = 0; i < m_points.size(); ++i )
174  {
175  if( m_points[i] == aPoint )
176  {
177  if( !aTraverseContours && IsContourEnd( i ) )
178  return &m_points[GetContourStartIdx( i )];
179 
180  if( i == m_points.size() - 1 )
181  return &m_points[0];
182  else
183  return &m_points[i + 1];
184  }
185  }
186 
187  return nullptr;
188 }
189 
190 
192 {
193  for( unsigned int i = 0; i < m_lines.size(); ++i )
194  {
195  if( m_lines[i] == aLine )
196  {
197  if( i == m_lines.size() - 1 )
198  return &m_lines[0];
199  else
200  return &m_lines[i + 1];
201  }
202  }
203 
204  return nullptr;
205 }
206 
207 
209 {
210  BOX2I box;
211  bool empty = true;
212 
213  for( const auto& point : m_points )
214  {
215  if( empty )
216  {
217  box.SetOrigin( point.GetPosition() );
218  empty = false;
219  }
220  else
221  {
222  box.Merge( point.GetPosition() );
223  }
224  }
225 
226  for( const auto& line : m_lines )
227  {
228  if( empty )
229  {
230  box.SetOrigin( line.GetOrigin().GetPosition() );
231  box.SetEnd( line.GetEnd().GetPosition() );
232  empty = false;
233  }
234  else
235  {
236  box.Merge( line.GetOrigin().GetPosition() );
237  box.Merge( line.GetEnd().GetPosition() );
238  }
239  }
240 
241  return box;
242 }
243 
244 
245 void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
246 {
247  auto gal = aView->GetGAL();
248 
249  KIGFX::RENDER_SETTINGS* settings = aView->GetPainter()->GetSettings();
250  KIGFX::COLOR4D drawColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
251 
252  // Don't assume LAYER_AUX_ITEMS is always a good choice. Compare with background.
253  if( aView->GetGAL()->GetClearColor().Distance( drawColor ) < 0.5 )
254  drawColor.Invert();
255 
256  // Linear darkening doesn't fit well with human color perception, and there's no guarantee
257  // that there's enough room for contrast either.
258  KIGFX::COLOR4D bgColor;
259  double brightness = drawColor.GetBrightness();
260 
261  if( brightness > 0.5 )
262  bgColor = drawColor.Darkened( 0.3 ).WithAlpha( 0.8 );
263  else if( brightness > 0.2 )
264  bgColor = drawColor.Darkened( 0.6 ).WithAlpha( 0.8 );
265  else
266  bgColor = drawColor.Brightened( 0.3 ).WithAlpha( 0.8 );
267 
268  KIGFX::COLOR4D highlightColor = settings->GetLayerColor( LAYER_SELECT_OVERLAY );
269 
270  gal->SetFillColor( drawColor );
271  gal->SetStrokeColor( bgColor );
272  gal->SetIsFill( true );
273  gal->SetIsStroke( true );
274  gal->PushDepth();
275  gal->SetLayerDepth( gal->GetMinDepth() );
276 
277  double size = aView->ToWorld( EDIT_POINT::POINT_SIZE ) / 2.0;
278  double borderSize = aView->ToWorld( EDIT_POINT::BORDER_SIZE );
279  double hoverSize = aView->ToWorld( EDIT_POINT::HOVER_SIZE );
280 
281  auto drawPoint =
282  [&]( const EDIT_POINT& aPoint, bool aDrawCircle = false )
283  {
284  if( aPoint.IsHover() || aPoint.IsActive() )
285  {
286  gal->SetStrokeColor( highlightColor );
287  gal->SetLineWidth( hoverSize );
288  }
289  else
290  {
291  gal->SetStrokeColor( bgColor );
292  gal->SetLineWidth( borderSize );
293  }
294 
295  gal->SetFillColor( aPoint.IsActive() ? highlightColor : drawColor );
296 
297  if( aDrawCircle )
298  gal->DrawCircle( aPoint.GetPosition(), size );
299  else
300  gal->DrawRectangle( aPoint.GetPosition() - size, aPoint.GetPosition() + size );
301  };
302 
303  for( const EDIT_POINT& point : m_points )
304  drawPoint( point );
305 
306  for( const EDIT_LINE& line : m_lines )
307  drawPoint( line, true );
308 
309  gal->PopDepth();
310 }
currently selected items overlay
Definition: layer_ids.h:214
COLOR4D & Invert()
Makes the color inverted, alpha remains the same.
Definition: color4d.h:245
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:217
double GetBrightness() const
Returns the brightness value of the color ranged from 0.0 to 1.0.
Definition: color4d.h:330
int GetContourEndIdx(int aPointIdx) const
Return index of the contour finish for a point with given index.
Definition: edit_points.cpp:89
std::list< int > m_contours
Indices of end contour points.
Definition: edit_points.h:524
std::deque< EDIT_POINT > m_points
EDIT_POINTs for modifying m_parent.
Definition: edit_points.h:522
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
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:452
std::deque< EDIT_LINE > m_lines
EDIT_LINEs for modifying m_parent.
Definition: edit_points.h:523
the 3d code uses this value
Definition: typeinfo.h:79
Represent a line connecting two EDIT_POINTs.
Definition: edit_points.h:215
EDIT_POINT * Next(const EDIT_POINT &aPoint, bool aTraverseContours=true)
Return the point that is before the given point in the list.
virtual const BOX2I ViewBBox() const override
static const int BORDER_SIZE
Border size when hovering.
Definition: edit_points.h:189
bool m_allowPoints
If false, only allow editing of EDIT_LINES.
Definition: edit_points.h:525
bool IsContourStart(int aPointIdx) const
Check if a point with given index is a contour origin.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:308
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
bool IsContourEnd(int aPointIdx) const
Check is a point with given index is a contour finish.
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
Definition: color4d.h:279
virtual void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:208
bool IsActive() const
Definition: edit_points.h:171
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition: color4d.h:265
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.
Definition: edit_points.cpp:50
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:70
int GetContourStartIdx(int aPointIdx) const
Return index of the contour origin for a point with given index.
Definition: edit_points.cpp:73
int Distance(const COLOR4D &other) const
Returns the distance (in RGB space) between two colors.
Definition: color4d.cpp:506
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:363
const COLOR4D & GetClearColor() const
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:207
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
void SetOrigin(const Vec &pos)
Definition: box2.h:193
static bool empty(const wxTextEntryBase *aCtrl)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
EDIT_POINTS(EDA_ITEM *aParent)
Definition: edit_points.cpp:44
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
static const int POINT_SIZE
Border size when not hovering.
Definition: edit_points.h:186
EDIT_POINT * Previous(const EDIT_POINT &aPoint, bool aTraverseContours=true)
Return the point that is after the given point in the list.
Represent a single point that can be used for modifying items.
Definition: edit_points.h:47
bool IsHover() const
Definition: edit_points.h:174
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
static const int HOVER_SIZE
Definition: edit_points.h:192
bool WithinPoint(const VECTOR2I &aPoint, unsigned int aSize) const
Check if given point is within a square centered in the EDIT_POINT position.
Definition: edit_points.cpp:33
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103