KiCad PCB EDA Suite
graphics_abstraction_layer.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) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2012-2017 Kicad Developers, see change_log.txt for contributors.
6  *
7  * Graphics Abstraction Layer (GAL) - base class
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <wx/log.h>
28 
30 #include <gal/definitions.h>
31 
32 #include <cmath>
33 
34 using namespace KIGFX;
35 
36 
37 const double GAL::METRIC_UNIT_LENGTH = 1e9;
38 
39 
40 GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
41  options( aDisplayOptions ),
42  strokeFont( this )
43 {
44  // Set the default values for the internal variables
45  SetIsFill( false );
46  SetIsStroke( true );
47  SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
48  SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
49  SetLookAtPoint( VECTOR2D( 0, 0 ) );
50  SetZoomFactor( 1.0 );
51  SetWorldUnitLength( 1.0 / METRIC_UNIT_LENGTH * 2.54 ); // 1 inch in nanometers
52  SetScreenDPI( 106 ); // Display resolution setting
54  SetLayerDepth( 0.0 );
55  SetFlip( false, false );
56  SetLineWidth( 1.0 );
58 
59  // Set grid defaults
60  SetGridVisibility( true );
61  SetCoarseGrid( 10 );
62  gridLineWidth = 0.5;
64  gridMinSpacing = 10;
65 
66  // Initialize the cursor shape
67  SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
68  fullscreenCursor = false;
69  forceDisplayCursor = false;
70  SetCursorEnabled( false );
71 
73 
74  // subscribe for settings updates
75  observerLink = options.Subscribe( this );
76 }
77 
78 
80 {
81 }
82 
83 
85 {
86  // defer to the child class first
87  updatedGalDisplayOptions( aOptions );
88 
89  // there is no refresh to do at this level
90 }
91 
92 
94 {
95  bool refresh = false;
96 
98  {
100  refresh = true;
101  }
102 
104  {
106  refresh = true;
107  }
108 
110  {
112  refresh = true;
113  }
114 
116  {
118  refresh = true;
119  }
120 
122  {
124  refresh = true;
125  }
126 
128  {
130  refresh = true;
131  }
132 
133  // tell the derived class if the base class needs an update or not
134  return refresh;
135 }
136 
137 
138 void GAL::SetTextAttributes( const EDA_TEXT* aText )
139 {
140  SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
143  SetFontBold( aText->IsBold() );
144  SetFontItalic( aText->IsItalic() );
145  SetTextMirrored( aText->IsMirrored() );
146 }
147 
148 
149 VECTOR2D GAL::GetTextLineSize( const UTF8& aText ) const
150 {
151  // Compute the X and Y size of a given text.
152  // Because computeTextLineSize expects a one line text,
153  // aText is expected to be only one line text.
154  return strokeFont.computeTextLineSize( aText );
155 }
156 
157 
159 {
161 
163 
164  MATRIX3x3D translation;
165  translation.SetIdentity();
166  translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) );
167 
169  scale.SetIdentity();
170  scale.SetScale( VECTOR2D( worldScale, worldScale ) );
171 
172  MATRIX3x3D flip;
173 
174  flip.SetIdentity();
175  flip.SetScale( VECTOR2D( globalFlipX ? -1.0 : 1.0, globalFlipY ? -1.0 : 1.0 ) );
176 
177  MATRIX3x3D lookat;
178  lookat.SetIdentity();
179  lookat.SetTranslation( -lookAtPoint );
180 
181  worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
182  screenWorldMatrix = worldScreenMatrix.Inverse();
183 }
184 
185 
187 {
188  // just return the current value. This could be cleverer and take
189  // into account other settings in future
190  return gridMinSpacing;
191 }
192 
193 
195 {
197 
198  // Draw the grid
199  // For the drawing the start points, end points and increments have
200  // to be calculated in world coordinates
201  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
202  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
203 
204  const double gridThreshold = computeMinGridSpacing();
205 
206  int gridScreenSizeDense = KiROUND( gridSize.x * worldScale );
207  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) * worldScale );
208 
209  // Compute the line marker or point radius of the grid
210  // Note: generic grids can't handle sub-pixel lines without
211  // either losing fine/course distinction or having some dots
212  // fail to render
213  double marker = std::max( 1.0, gridLineWidth ) / worldScale;
214  double doubleMarker = 2.0 * marker;
215 
216  // Draw axes if desired
217  if( axesEnabled )
218  {
219  SetIsFill( false );
220  SetIsStroke( true );
222  SetLineWidth( marker );
223 
224  drawGridLine( VECTOR2D( worldStartPoint.x, 0 ),
225  VECTOR2D( worldEndPoint.x, 0 ) );
226 
227  drawGridLine( VECTOR2D( 0, worldStartPoint.y ),
228  VECTOR2D( 0, worldEndPoint.y ) );
229  }
230 
231  if( !gridVisibility )
232  return;
233 
234  // Check if the grid would not be too dense
235  if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) <= gridThreshold )
236  return;
237 
238  // Compute grid variables
239  int gridStartX = KiROUND( worldStartPoint.x / gridSize.x );
240  int gridEndX = KiROUND( worldEndPoint.x / gridSize.x );
241  int gridStartY = KiROUND( worldStartPoint.y / gridSize.y );
242  int gridEndY = KiROUND( worldEndPoint.y / gridSize.y );
243 
244  // Correct the index, else some lines are not correctly painted
245  gridStartY -= std::abs( gridOrigin.y / gridSize.y ) + 1;
246  gridEndY -= std::abs( gridOrigin.y / gridSize.y ) - 1;
247 
248  gridStartX -= std::abs( gridOrigin.x / gridSize.x ) + 1;
249  gridEndX -= std::abs( gridOrigin.x / gridSize.x ) - 1;
250 
251  int dirX = gridEndX >= gridStartX ? 1 : -1;
252  int dirY = gridEndY >= gridStartY ? 1 : -1;
253 
254  // Draw the grid behind all other layers
255  SetLayerDepth( depthRange.y * 0.75 );
256 
258  {
259  SetIsFill( false );
260  SetIsStroke( true );
262 
263  // Now draw the grid, every coarse grid line gets the double width
264 
265  // Vertical lines
266  for( int j = gridStartY; j != gridEndY; j += dirY )
267  {
268  const double y = j * gridSize.y + gridOrigin.y;
269 
270  if( axesEnabled && y == 0 )
271  continue;
272 
273  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
274  SetLineWidth( doubleMarker );
275  else
276  SetLineWidth( marker );
277 
278  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
279  || gridScreenSizeDense > gridThreshold )
280  {
281  drawGridLine( VECTOR2D( gridStartX * gridSize.x + gridOrigin.x, y ),
282  VECTOR2D( gridEndX * gridSize.x + gridOrigin.x, y ) );
283  }
284  }
285 
286  // Horizontal lines
287  for( int i = gridStartX; i != gridEndX; i += dirX )
288  {
289  const double x = i * gridSize.x + gridOrigin.x;
290 
291  if( axesEnabled && x == 0 )
292  continue;
293 
294  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
295  SetLineWidth( doubleMarker );
296  else
297  SetLineWidth( marker );
298 
299  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
300  || gridScreenSizeDense > gridThreshold )
301  {
302  drawGridLine( VECTOR2D( x, gridStartY * gridSize.y + gridOrigin.y ),
303  VECTOR2D( x, gridEndY * gridSize.y + gridOrigin.y ) );
304  }
305  }
306  }
307  else if( gridStyle == GRID_STYLE::SMALL_CROSS )
308  {
309  SetIsFill( false );
310  SetIsStroke( true );
312 
313  SetLineWidth( marker );
314  double lineLen = GetLineWidth() * 2;
315 
316  // Vertical positions:
317  for( int j = gridStartY; j != gridEndY; j += dirY )
318  {
319  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
320  || gridScreenSizeDense > gridThreshold )
321  {
322  int posY = j * gridSize.y + gridOrigin.y;
323 
324  // Horizontal positions:
325  for( int i = gridStartX; i != gridEndX; i += dirX )
326  {
327  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
328  || gridScreenSizeDense > gridThreshold )
329  {
330  int posX = i * gridSize.x + gridOrigin.x;
331 
332  drawGridLine( VECTOR2D( posX - lineLen, posY ),
333  VECTOR2D( posX + lineLen, posY ) );
334 
335  drawGridLine( VECTOR2D( posX, posY - lineLen ),
336  VECTOR2D( posX, posY + lineLen ) );
337  }
338  }
339  }
340  }
341  }
342  else // Dotted grid
343  {
344  bool tickX, tickY;
345  SetIsFill( true );
346  SetIsStroke( false );
348 
349  for( int j = gridStartY; j != gridEndY; j += dirY )
350  {
351  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
352  tickY = true;
353  else
354  tickY = false;
355 
356  for( int i = gridStartX; i != gridEndX; i += dirX )
357  {
358  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
359  tickX = true;
360  else
361  tickX = false;
362 
363  if( tickX || tickY || gridScreenSizeDense > gridThreshold )
364  {
365  double radius = ( ( tickX && tickY ) ? doubleMarker : marker ) / 2.0;
366  DrawRectangle( VECTOR2D( i * gridSize.x - radius + gridOrigin.x,
367  j * gridSize.y - radius + gridOrigin.y ),
368  VECTOR2D( i * gridSize.x + radius + gridOrigin.x,
369  j * gridSize.y + radius + gridOrigin.y ) );
370  }
371  }
372  }
373  }
374 }
375 
376 
377 VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
378 {
379  return VECTOR2D( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
380  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
381 }
382 
383 const int GAL::MIN_DEPTH = -1024;
384 const int GAL::MAX_DEPTH = 1023;
385 const int GAL::GRID_DEPTH = MAX_DEPTH - 1;
386 
387 
389 {
390  auto color = cursorColor;
391 
392  // dim the cursor if it's only on because it was forced
393  // (this helps to provide a hint for active tools)
394  if( !isCursorEnabled )
395  {
396  color.a = color.a * 0.5;
397  }
398 
399  return color;
400 }
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
static const int GRID_DEPTH
Depth level on which the grid is drawn.
int gridTick
Every tick line gets the double width.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
void SetFontItalic(const bool aItalic)
Set italic property of current font.
MATRIX3x3 Inverse() const
Determine the inverse of the matrix.
Definition: matrix3x3.h:343
STROKE_FONT strokeFont
Instance of object that stores information about how to draw texts.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
Use lines for the grid.
bool axesEnabled
Should the axes be drawn.
VECTOR2D gridOffset
The grid offset to compensate cursor position.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:56
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
bool IsItalic() const
Definition: eda_text.h:170
KIGFX::GRID_STYLE m_gridStyle
The grid style to draw the grid in
bool isCursorEnabled
Is the cursor enabled?
void SetCursorEnabled(bool aCursorEnabled)
Enable/disable cursor.
virtual void SetTextAttributes(const EDA_TEXT *aText)
Loads attributes of the given text (bold/italic/underline/mirrored and so on).
int gridMinSpacing
Minimum screen size of the grid (pixels) below which the grid is not drawn.
GRID_STYLE gridStyle
Grid display style.
LINK Subscribe(ObserverInterface *aObserver)
Function Subscribe adds a subscription returning an RAII link.
Definition: observable.h:162
GAL_DISPLAY_OPTIONS & options
const int newstroke_font_bufsize
void SetFlip(bool xAxis, bool yAxis)
Sets flipping of the screen.
bool LoadNewStrokeFont(const char *const aNewStrokeFont[], int aNewStrokeFontSize)
Load the new stroke font.
Definition: stroke_font.cpp:47
VECTOR2D depthRange
Range of the depth.
MATRIX3x3D screenWorldMatrix
Screen transformation.
bool m_forceDisplayCursor
Force cursor display
bool globalFlipX
Flag for X axis flipping.
double m_gridMinSpacing
Minimum pixel distance between displayed grid lines
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
#define abs(a)
Definition: auxiliary.h:84
void SetScreenDPI(double aScreenDPI)
Set the dots per inch of the screen.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:190
void SetIdentity()
Set the matrix to the identity matrix.
Definition: matrix3x3.h:214
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
virtual void drawGridLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a grid line (usually a simplified line function).
VECTOR2D lookAtPoint
Point to be looked at in world space.
bool IsBold() const
Definition: eda_text.h:173
Auxiliary rendering target (noncached)
Definition: definitions.h:42
bool m_axesEnabled
Whether or not to draw the coordinate system axes
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:114
static const int MIN_DEPTH
Possible depth range.
GAL(GAL_DISPLAY_OPTIONS &aOptions)
void SetFontBold(const bool aBold)
Set bold property of current font.
double a
Alpha component.
Definition: color4d.h:284
virtual void SetLineWidth(double aLineWidth)
Set the line width.
COLOR4D cursorColor
Cursor color.
bool fullscreenCursor
Shape of the cursor (fullscreen or small cross)
void OnGalDisplayOptionsChanged(const GAL_DISPLAY_OPTIONS &aOptions) override
Handler for observer settings changes.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:589
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
static const double METRIC_UNIT_LENGTH
COLOR4D axesColor
Color of the axes.
VECTOR2D computeTextLineSize(const UTF8 &aText) const
Compute the X and Y size of a given text.
VECTOR2D gridOrigin
The grid origin.
void SetTextMirrored(const bool aMirrored)
Set a mirrored property of text.
void SetCursorColor(const COLOR4D &aCursorColor)
Set the cursor color.
void SetVerticalJustify(const EDA_TEXT_VJUSTIFY_T aVerticalJustify)
Set the vertical justify for text drawing.
MATRIX3x3D worldScreenMatrix
World transformation.
const char *const newstroke_font[]
Array containing strokes for unicode glyphs.
void SetWorldUnitLength(double aWorldUnitLength)
Set the unit length.
Use small cross instead of dots for the grid.
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Function updatedGalDisplayOptions.
virtual void DrawGrid()
>
void computeWorldScale()
Compute the scaling factor for the world->screen matrix.
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:191
VECTOR2D GetGridPoint(const VECTOR2D &aPoint) const
Function GetGridPoint() For a given point it returns the nearest point belonging to the grid in world...
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
void SetCoarseGrid(int aInterval)
Draw every tick line wider.
COLOR4D gridColor
Color of the grid.
const int scale
bool gridVisibility
Should the grid be shown.
void SetScale(VECTOR2< T > aScale)
Set the scale components of the matrix.
Definition: matrix3x3.h:261
#define max(a, b)
Definition: auxiliary.h:86
bool globalFlipY
Flag for Y axis flipping.
bool IsMirrored() const
Definition: eda_text.h:179
double worldScale
The scale factor world->screen.
VECTOR2D gridSize
The grid size.
double m_gridLineWidth
Thickness to render grid lines/dots
VECTOR2I screenSize
Screen size in screen coordinates.
void SetZoomFactor(double aZoomFactor)
Set the zoom factor of the scene.
double GetLineWidth() const
Get the line width.
void SetGridVisibility(bool aVisibility)
Sets the visibility setting of the grid.
void SetTranslation(VECTOR2< T > aTranslation)
Set the translation components of the matrix.
Definition: matrix3x3.h:230
void SetGlyphSize(const VECTOR2D aGlyphSize)
Set the font glyph size.
void SetLookAtPoint(const VECTOR2D &aPoint)
Set the Point in world space to look at.
const wxSize & GetTextSize() const
Definition: eda_text.h:215
void SetHorizontalJustify(const EDA_TEXT_HJUSTIFY_T aHorizontalJustify)
Set the horizontal justify for text drawing.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
VECTOR2D GetTextLineSize(const UTF8 &aText) const
Compute the X and Y size of a given text.
void SetDepthRange(const VECTOR2D &aDepthRange)
Set the range of the layer depth.
bool m_fullscreenCursor
Fullscreen crosshair or small cross
bool forceDisplayCursor
Always show cursor.
virtual void SetTarget(RENDER_TARGET aTarget)
Sets the target for rendering.
static const int MAX_DEPTH
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
double gridLineWidth
Line width of the grid.