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  SetWorldUnitLength( 1e-9 /* 1 nm */ / 0.0254 /* 1 inch in meters */ );
50  // wxDC::GetPPI() reports 96 DPI, but somehow this value
51  // is the closest match to the legacy renderer
52  SetScreenDPI( 91 );
54  SetLayerDepth( 0.0 );
55  SetFlip( false, false );
56  SetLineWidth( 1.0f );
58  SetAxesEnabled( false );
59 
60  // Set grid defaults
61  SetGridVisibility( true );
62  SetCoarseGrid( 10 );
63  gridLineWidth = 0.5f;
65  gridMinSpacing = 10;
66 
67  // Initialize the cursor shape
68  SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
69  fullscreenCursor = false;
70  forceDisplayCursor = false;
71  SetCursorEnabled( false );
72 
73  // Initialize text properties
75 
77 
78  // subscribe for settings updates
79  observerLink = options.Subscribe( this );
80 }
81 
82 
84 {
85 }
86 
87 
89 {
90  // defer to the child class first
91  updatedGalDisplayOptions( aOptions );
92 
93  // there is no refresh to do at this level
94 }
95 
96 
98 {
99  bool refresh = false;
100 
101  if( options.m_gridStyle != gridStyle )
102  {
104  refresh = true;
105  }
106 
108  {
110  refresh = true;
111  }
112 
114  {
116  refresh = true;
117  }
118 
120  {
122  refresh = true;
123  }
124 
126  {
128  refresh = true;
129  }
130 
132  {
134  refresh = true;
135  }
136 
137  // tell the derived class if the base class needs an update or not
138  return refresh;
139 }
140 
141 
142 void GAL::SetTextAttributes( const EDA_TEXT* aText )
143 {
144  SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
147  SetFontBold( aText->IsBold() );
148  SetFontItalic( aText->IsItalic() );
149  SetTextMirrored( aText->IsMirrored() );
150 }
151 
152 
154 {
155  // Tiny but non-zero - this will always need setting
156  // there is no built-in default
157  SetGlyphSize( { 1.0, 1.0 } );
158 
161 
162  SetFontBold( false );
163  SetFontItalic( false );
164  SetTextMirrored( false );
165 }
166 
167 
168 VECTOR2D GAL::GetTextLineSize( const UTF8& aText ) const
169 {
170  // Compute the X and Y size of a given text.
171  // Because computeTextLineSize expects a one line text,
172  // aText is expected to be only one line text.
173  return strokeFont.computeTextLineSize( aText );
174 }
175 
176 
178 {
180 
181  MATRIX3x3D translation;
182  translation.SetIdentity();
183  translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) );
184 
185  MATRIX3x3D rotate;
186  rotate.SetIdentity();
187  rotate.SetRotation( rotation );
188 
190  scale.SetIdentity();
191  scale.SetScale( VECTOR2D( worldScale, worldScale ) );
192 
193  MATRIX3x3D flip;
194  flip.SetIdentity();
195  flip.SetScale( VECTOR2D( globalFlipX ? -1.0 : 1.0, globalFlipY ? -1.0 : 1.0 ) );
196 
197  MATRIX3x3D lookat;
198  lookat.SetIdentity();
199  lookat.SetTranslation( -lookAtPoint );
200 
201  worldScreenMatrix = translation * rotate * flip * scale * lookat;
203 }
204 
205 
207 {
208  // just return the current value. This could be cleverer and take
209  // into account other settings in future
210  return gridMinSpacing;
211 }
212 
213 
215 {
217 
218  // Draw the grid
219  // For the drawing the start points, end points and increments have
220  // to be calculated in world coordinates
221  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
222  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
223 
224  const double gridThreshold = computeMinGridSpacing();
225 
226  int gridScreenSizeDense = KiROUND( gridSize.x * worldScale );
227  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) * worldScale );
228 
229  // Compute the line marker or point radius of the grid
230  // Note: generic grids can't handle sub-pixel lines without
231  // either losing fine/course distinction or having some dots
232  // fail to render
233  float marker = std::fmax( 1.0f, gridLineWidth ) / worldScale;
234  float doubleMarker = 2.0f * marker;
235 
236  // Draw axes if desired
237  if( axesEnabled )
238  {
239  SetIsFill( false );
240  SetIsStroke( true );
242  SetLineWidth( marker );
243 
244  drawGridLine( VECTOR2D( worldStartPoint.x, 0 ),
245  VECTOR2D( worldEndPoint.x, 0 ) );
246 
247  drawGridLine( VECTOR2D( 0, worldStartPoint.y ),
248  VECTOR2D( 0, worldEndPoint.y ) );
249  }
250 
251  if( !gridVisibility )
252  return;
253 
254  // Check if the grid would not be too dense
255  if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) <= gridThreshold )
256  return;
257 
258  // Compute grid staring and ending indexes to draw grid points on the
259  // visible screen area
260  // Note: later any point coordinate will be offsetted by gridOrigin
261  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridSize.x );
262  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridSize.x );
263  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridSize.y );
264  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridSize.y );
265 
266  // Ensure start coordinate > end coordinate
267  if( gridStartX > gridEndX )
268  std::swap( gridStartX, gridEndX );
269 
270  if( gridStartY > gridEndY )
271  std::swap( gridStartY, gridEndY );
272 
273  // Ensure the grid fills the screen
274  --gridStartX; ++gridEndX;
275  --gridStartY; ++gridEndY;
276 
277  // Draw the grid behind all other layers
278  SetLayerDepth( depthRange.y * 0.75 );
279 
281  {
282  SetIsFill( false );
283  SetIsStroke( true );
285 
286  // Now draw the grid, every coarse grid line gets the double width
287 
288  // Vertical lines
289  for( int j = gridStartY; j <= gridEndY; j++ )
290  {
291  const double y = j * gridSize.y + gridOrigin.y;
292 
293  if( axesEnabled && y == 0 )
294  continue;
295 
296  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
297  SetLineWidth( doubleMarker );
298  else
299  SetLineWidth( marker );
300 
301  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
302  || gridScreenSizeDense > gridThreshold )
303  {
304  drawGridLine( VECTOR2D( gridStartX * gridSize.x + gridOrigin.x, y ),
305  VECTOR2D( gridEndX * gridSize.x + gridOrigin.x, y ) );
306  }
307  }
308 
309  // Horizontal lines
310  for( int i = gridStartX; i <= gridEndX; i++ )
311  {
312  const double x = i * gridSize.x + gridOrigin.x;
313 
314  if( axesEnabled && x == 0 )
315  continue;
316 
317  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
318  SetLineWidth( doubleMarker );
319  else
320  SetLineWidth( marker );
321 
322  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
323  || gridScreenSizeDense > gridThreshold )
324  {
325  drawGridLine( VECTOR2D( x, gridStartY * gridSize.y + gridOrigin.y ),
326  VECTOR2D( x, gridEndY * gridSize.y + gridOrigin.y ) );
327  }
328  }
329  }
330  else if( gridStyle == GRID_STYLE::SMALL_CROSS )
331  {
332  SetIsFill( false );
333  SetIsStroke( true );
335 
336  SetLineWidth( marker );
337  double lineLen = GetLineWidth() * 2;
338 
339  // Vertical positions:
340  for( int j = gridStartY; j <= gridEndY; j++ )
341  {
342  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
343  || gridScreenSizeDense > gridThreshold )
344  {
345  int posY = j * gridSize.y + gridOrigin.y;
346 
347  // Horizontal positions:
348  for( int i = gridStartX; i <= gridEndX; i++ )
349  {
350  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
351  || gridScreenSizeDense > gridThreshold )
352  {
353  int posX = i * gridSize.x + gridOrigin.x;
354 
355  drawGridLine( VECTOR2D( posX - lineLen, posY ),
356  VECTOR2D( posX + lineLen, posY ) );
357 
358  drawGridLine( VECTOR2D( posX, posY - lineLen ),
359  VECTOR2D( posX, posY + lineLen ) );
360  }
361  }
362  }
363  }
364  }
365  else // Dotted grid
366  {
367  bool tickX, tickY;
368  SetIsFill( true );
369  SetIsStroke( false );
371 
372  for( int j = gridStartY; j <= gridEndY; j++ )
373  {
374  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
375  tickY = true;
376  else
377  tickY = false;
378 
379  for( int i = gridStartX; i <= gridEndX; i++ )
380  {
381  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
382  tickX = true;
383  else
384  tickX = false;
385 
386  if( tickX || tickY || gridScreenSizeDense > gridThreshold )
387  {
388  double radius = ( ( tickX && tickY ) ? doubleMarker : marker ) / 2.0;
389  DrawRectangle( VECTOR2D( i * gridSize.x - radius + gridOrigin.x,
390  j * gridSize.y - radius + gridOrigin.y ),
391  VECTOR2D( i * gridSize.x + radius + gridOrigin.x,
392  j * gridSize.y + radius + gridOrigin.y ) );
393  }
394  }
395  }
396  }
397 }
398 
399 
400 VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
401 {
402 #if 0
403  // This old code expects a non zero grid size, which can be wrong here.
404  return VECTOR2D( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
405  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
406 #else
407  // if grid size == 0.0 there is no grid, so use aPoint as grid reference position
408  double cx = gridSize.x > 0.0 ? KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x
409  : aPoint.x;
410  double cy = gridSize.y > 0.0 ? KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y
411  : aPoint.y;
412 
413  return VECTOR2D( cx, cy );
414 #endif
415 }
416 
417 const int GAL::MIN_DEPTH = -1024;
418 const int GAL::MAX_DEPTH = 1023;
419 const int GAL::GRID_DEPTH = MAX_DEPTH - 1;
420 
421 
423 {
424  auto color = cursorColor;
425 
426  // dim the cursor if it's only on because it was forced
427  // (this helps to provide a hint for active tools)
428  if( !isCursorEnabled )
429  {
430  color.a = color.a * 0.5;
431  }
432 
433  return color;
434 }
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:58
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
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