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 GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
38  options( aDisplayOptions ),
39  strokeFont( this )
40 {
41  // Set the default values for the internal variables
42  SetIsFill( false );
43  SetIsStroke( true );
44  SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
45  SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
46  SetLookAtPoint( VECTOR2D( 0, 0 ) );
47  SetZoomFactor( 1.0 );
48  SetRotation( 0.0 );
49  // this value for SetWorldUnitLength is only suitable for Pcbnew.
50  // Other editors/viewer must call SetWorldUnitLength with their internal units
51  SetWorldUnitLength( 1e-9 /* 1 nm */ / 0.0254 /* 1 inch in meters */ );
52  // wxDC::GetPPI() reports 96 DPI, but somehow this value
53  // is the closest match to the legacy renderer
54  SetScreenDPI( 91 );
56  SetLayerDepth( 0.0 );
57  SetFlip( false, false );
58  SetLineWidth( 1.0f );
60  SetAxesEnabled( false );
61 
62  // Set grid defaults
63  SetGridVisibility( true );
64  SetCoarseGrid( 10 );
65  gridLineWidth = 0.5f;
67  gridMinSpacing = 10;
68 
69  // Initialize the cursor shape
70  SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
71  fullscreenCursor = false;
72  forceDisplayCursor = false;
73  SetCursorEnabled( false );
74 
75  // Initialize text properties
77 
79 
80  // subscribe for settings updates
81  observerLink = options.Subscribe( this );
82 }
83 
84 
86 {
87 }
88 
89 
91 {
92  // defer to the child class first
93  updatedGalDisplayOptions( aOptions );
94 
95  // there is no refresh to do at this level
96 }
97 
98 
100 {
101  bool refresh = false;
102 
103  if( options.m_gridStyle != gridStyle )
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 
134  {
136  refresh = true;
137  }
138 
139  // tell the derived class if the base class needs an update or not
140  return refresh;
141 }
142 
143 
144 void GAL::SetTextAttributes( const EDA_TEXT* aText )
145 {
146  SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
149  SetFontBold( aText->IsBold() );
150  SetFontItalic( aText->IsItalic() );
151  SetTextMirrored( aText->IsMirrored() );
152 }
153 
154 
156 {
157  // Tiny but non-zero - this will always need setting
158  // there is no built-in default
159  SetGlyphSize( { 1.0, 1.0 } );
160 
163 
164  SetFontBold( false );
165  SetFontItalic( false );
166  SetTextMirrored( false );
167 }
168 
169 
170 VECTOR2D GAL::GetTextLineSize( const UTF8& aText ) const
171 {
172  // Compute the X and Y size of a given text.
173  // Because computeTextLineSize expects a one line text,
174  // aText is expected to be only one line text.
175  return strokeFont.computeTextLineSize( aText );
176 }
177 
178 
180 {
182 
183  MATRIX3x3D translation;
184  translation.SetIdentity();
185  translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) );
186 
187  MATRIX3x3D rotate;
188  rotate.SetIdentity();
189  rotate.SetRotation( rotation );
190 
192  scale.SetIdentity();
193  scale.SetScale( VECTOR2D( worldScale, worldScale ) );
194 
195  MATRIX3x3D flip;
196  flip.SetIdentity();
197  flip.SetScale( VECTOR2D( globalFlipX ? -1.0 : 1.0, globalFlipY ? -1.0 : 1.0 ) );
198 
199  MATRIX3x3D lookat;
200  lookat.SetIdentity();
201  lookat.SetTranslation( -lookAtPoint );
202 
203  worldScreenMatrix = translation * rotate * flip * scale * lookat;
205 }
206 
207 
209 {
210  // just return the current value. This could be cleverer and take
211  // into account other settings in future
212  return gridMinSpacing;
213 }
214 
215 
217 {
219 
220  // Draw the grid
221  // For the drawing the start points, end points and increments have
222  // to be calculated in world coordinates
223  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
224  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
225 
226  const double gridThreshold = computeMinGridSpacing();
227 
228  int gridScreenSizeDense = KiROUND( gridSize.x * worldScale );
229  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) * worldScale );
230 
231  // Compute the line marker or point radius of the grid
232  // Note: generic grids can't handle sub-pixel lines without
233  // either losing fine/course distinction or having some dots
234  // fail to render
235  float marker = std::fmax( 1.0f, gridLineWidth ) / worldScale;
236  float doubleMarker = 2.0f * marker;
237 
238  // Draw axes if desired
239  if( axesEnabled )
240  {
241  SetIsFill( false );
242  SetIsStroke( true );
244  SetLineWidth( marker );
245 
246  drawGridLine( VECTOR2D( worldStartPoint.x, 0 ),
247  VECTOR2D( worldEndPoint.x, 0 ) );
248 
249  drawGridLine( VECTOR2D( 0, worldStartPoint.y ),
250  VECTOR2D( 0, worldEndPoint.y ) );
251  }
252 
253  if( !gridVisibility )
254  return;
255 
256  // Check if the grid would not be too dense
257  if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) <= gridThreshold )
258  return;
259 
260  // Compute grid staring and ending indexes to draw grid points on the
261  // visible screen area
262  // Note: later any point coordinate will be offsetted by gridOrigin
263  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridSize.x );
264  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridSize.x );
265  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridSize.y );
266  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridSize.y );
267 
268  // Ensure start coordinate > end coordinate
269  if( gridStartX > gridEndX )
270  std::swap( gridStartX, gridEndX );
271 
272  if( gridStartY > gridEndY )
273  std::swap( gridStartY, gridEndY );
274 
275  // Ensure the grid fills the screen
276  --gridStartX; ++gridEndX;
277  --gridStartY; ++gridEndY;
278 
279  // Draw the grid behind all other layers
280  SetLayerDepth( depthRange.y * 0.75 );
281 
283  {
284  SetIsFill( false );
285  SetIsStroke( true );
287 
288  // Now draw the grid, every coarse grid line gets the double width
289 
290  // Vertical lines
291  for( int j = gridStartY; j <= gridEndY; j++ )
292  {
293  const double y = j * gridSize.y + gridOrigin.y;
294 
295  if( axesEnabled && y == 0 )
296  continue;
297 
298  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
299  SetLineWidth( doubleMarker );
300  else
301  SetLineWidth( marker );
302 
303  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
304  || gridScreenSizeDense > gridThreshold )
305  {
306  drawGridLine( VECTOR2D( gridStartX * gridSize.x + gridOrigin.x, y ),
307  VECTOR2D( gridEndX * gridSize.x + gridOrigin.x, y ) );
308  }
309  }
310 
311  // Horizontal lines
312  for( int i = gridStartX; i <= gridEndX; i++ )
313  {
314  const double x = i * gridSize.x + gridOrigin.x;
315 
316  if( axesEnabled && x == 0 )
317  continue;
318 
319  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
320  SetLineWidth( doubleMarker );
321  else
322  SetLineWidth( marker );
323 
324  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
325  || gridScreenSizeDense > gridThreshold )
326  {
327  drawGridLine( VECTOR2D( x, gridStartY * gridSize.y + gridOrigin.y ),
328  VECTOR2D( x, gridEndY * gridSize.y + gridOrigin.y ) );
329  }
330  }
331  }
332  else if( gridStyle == GRID_STYLE::SMALL_CROSS )
333  {
334  SetIsFill( false );
335  SetIsStroke( true );
337 
338  SetLineWidth( marker );
339  double lineLen = GetLineWidth() * 2;
340 
341  // Vertical positions:
342  for( int j = gridStartY; j <= gridEndY; j++ )
343  {
344  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
345  || gridScreenSizeDense > gridThreshold )
346  {
347  int posY = j * gridSize.y + gridOrigin.y;
348 
349  // Horizontal positions:
350  for( int i = gridStartX; i <= gridEndX; i++ )
351  {
352  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
353  || gridScreenSizeDense > gridThreshold )
354  {
355  int posX = i * gridSize.x + gridOrigin.x;
356 
357  drawGridLine( VECTOR2D( posX - lineLen, posY ),
358  VECTOR2D( posX + lineLen, posY ) );
359 
360  drawGridLine( VECTOR2D( posX, posY - lineLen ),
361  VECTOR2D( posX, posY + lineLen ) );
362  }
363  }
364  }
365  }
366  }
367  else // Dotted grid
368  {
369  bool tickX, tickY;
370  SetIsFill( true );
371  SetIsStroke( false );
373 
374  for( int j = gridStartY; j <= gridEndY; j++ )
375  {
376  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
377  tickY = true;
378  else
379  tickY = false;
380 
381  for( int i = gridStartX; i <= gridEndX; i++ )
382  {
383  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
384  tickX = true;
385  else
386  tickX = false;
387 
388  if( tickX || tickY || gridScreenSizeDense > gridThreshold )
389  {
390  double radius = ( ( tickX && tickY ) ? doubleMarker : marker ) / 2.0;
391  DrawRectangle( VECTOR2D( i * gridSize.x - radius + gridOrigin.x,
392  j * gridSize.y - radius + gridOrigin.y ),
393  VECTOR2D( i * gridSize.x + radius + gridOrigin.x,
394  j * gridSize.y + radius + gridOrigin.y ) );
395  }
396  }
397  }
398  }
399 }
400 
401 
402 VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
403 {
404 #if 0
405  // This old code expects a non zero grid size, which can be wrong here.
406  return VECTOR2D( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
407  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
408 #else
409  // if grid size == 0.0 there is no grid, so use aPoint as grid reference position
410  double cx = gridSize.x > 0.0 ? KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x
411  : aPoint.x;
412  double cy = gridSize.y > 0.0 ? KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y
413  : aPoint.y;
414 
415  return VECTOR2D( cx, cy );
416 #endif
417 }
418 
419 const int GAL::MIN_DEPTH = -1024;
420 const int GAL::MAX_DEPTH = 1023;
421 const int GAL::GRID_DEPTH = MAX_DEPTH - 1;
422 
423 
425 {
426  auto color = cursorColor;
427 
428  // dim the cursor if it's only on because it was forced
429  // (this helps to provide a hint for active tools)
430  if( !isCursorEnabled )
431  {
432  color.a = color.a * 0.5;
433  }
434 
435  return color;
436 }
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 string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
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:57
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:121
bool IsItalic() const
Definition: eda_text.h:183
void SetRotation(T aAngle)
Set the rotation components of the matrix.
Definition: matrix3x3.h:249
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:161
GAL_DISPLAY_OPTIONS & options
double rotation
Rotation transformation (radians)
int color
Definition: DXF_plotter.cpp:62
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:49
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.
void SetScreenDPI(double aScreenDPI)
Set the dots per inch of the screen.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:203
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:186
virtual void SetLineWidth(float aLineWidth)
Set the line width.
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:127
static const int MIN_DEPTH
Possible depth range.
GAL(GAL_DISPLAY_OPTIONS &aOptions)
void SetFontBold(const bool aBold)
Set bold property of current font.
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.
void ResetTextAttributes()
Reset text attributes to default styling.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
COLOR4D axesColor
Color of the axes.
float gridLineWidth
Line width of the grid.
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.
void SetAxesEnabled(bool aAxesEnabled)
Enables drawing the axes.
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:204
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
void SetRotation(double aRotation)
Set the rotation angle.
bool globalFlipY
Flag for Y axis flipping.
bool IsMirrored() const
Definition: eda_text.h:192
double worldScale
The scale factor world->screen.
VECTOR2D gridSize
The grid size.
size_t i
Definition: json11.cpp:597
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.
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:228
void SetHorizontalJustify(const EDA_TEXT_HJUSTIFY_T aHorizontalJustify)
Set the horizontal justify for text drawing.
float GetLineWidth() const
Get the line width.
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