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  SetAxesEnabled( false );
59 
60  // Set grid defaults
61  SetGridVisibility( true );
62  SetCoarseGrid( 10 );
63  gridLineWidth = 0.5;
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 
182 
183  MATRIX3x3D translation;
184  translation.SetIdentity();
185  translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) );
186 
188  scale.SetIdentity();
189  scale.SetScale( VECTOR2D( worldScale, worldScale ) );
190 
191  MATRIX3x3D flip;
192 
193  flip.SetIdentity();
194  flip.SetScale( VECTOR2D( globalFlipX ? -1.0 : 1.0, globalFlipY ? -1.0 : 1.0 ) );
195 
196  MATRIX3x3D lookat;
197  lookat.SetIdentity();
198  lookat.SetTranslation( -lookAtPoint );
199 
200  worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
201  screenWorldMatrix = worldScreenMatrix.Inverse();
202 }
203 
204 
206 {
207  // just return the current value. This could be cleverer and take
208  // into account other settings in future
209  return gridMinSpacing;
210 }
211 
212 
214 {
216 
217  // Draw the grid
218  // For the drawing the start points, end points and increments have
219  // to be calculated in world coordinates
220  VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
221  VECTOR2D worldEndPoint = screenWorldMatrix * VECTOR2D( screenSize );
222 
223  const double gridThreshold = computeMinGridSpacing();
224 
225  int gridScreenSizeDense = KiROUND( gridSize.x * worldScale );
226  int gridScreenSizeCoarse = KiROUND( gridSize.x * static_cast<double>( gridTick ) * worldScale );
227 
228  // Compute the line marker or point radius of the grid
229  // Note: generic grids can't handle sub-pixel lines without
230  // either losing fine/course distinction or having some dots
231  // fail to render
232  double marker = std::max( 1.0, gridLineWidth ) / worldScale;
233  double doubleMarker = 2.0 * marker;
234 
235  // Draw axes if desired
236  if( axesEnabled )
237  {
238  SetIsFill( false );
239  SetIsStroke( true );
241  SetLineWidth( marker );
242 
243  drawGridLine( VECTOR2D( worldStartPoint.x, 0 ),
244  VECTOR2D( worldEndPoint.x, 0 ) );
245 
246  drawGridLine( VECTOR2D( 0, worldStartPoint.y ),
247  VECTOR2D( 0, worldEndPoint.y ) );
248  }
249 
250  if( !gridVisibility )
251  return;
252 
253  // Check if the grid would not be too dense
254  if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) <= gridThreshold )
255  return;
256 
257  // Compute grid staring and ending indexes to draw grid points on the
258  // visible screen area
259  // Note: later any point coordinate will be offsetted by gridOrigin
260  int gridStartX = KiROUND( ( worldStartPoint.x - gridOrigin.x ) / gridSize.x );
261  int gridEndX = KiROUND( ( worldEndPoint.x - gridOrigin.x ) / gridSize.x );
262  int gridStartY = KiROUND( ( worldStartPoint.y - gridOrigin.y ) / gridSize.y );
263  int gridEndY = KiROUND( ( worldEndPoint.y - gridOrigin.y ) / gridSize.y );
264 
265  // Ensure start coordinate > end coordinate
266  if( gridStartX > gridEndX )
267  std::swap( gridStartX, gridEndX );
268 
269  if( gridStartY > gridEndY )
270  std::swap( gridStartY, gridEndY );
271 
272  // Ensure the grid fills the screen
273  --gridStartX; ++gridEndX;
274  --gridStartY; ++gridEndY;
275 
276  // Draw the grid behind all other layers
277  SetLayerDepth( depthRange.y * 0.75 );
278 
280  {
281  SetIsFill( false );
282  SetIsStroke( true );
284 
285  // Now draw the grid, every coarse grid line gets the double width
286 
287  // Vertical lines
288  for( int j = gridStartY; j <= gridEndY; j++ )
289  {
290  const double y = j * gridSize.y + gridOrigin.y;
291 
292  if( axesEnabled && y == 0 )
293  continue;
294 
295  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
296  SetLineWidth( doubleMarker );
297  else
298  SetLineWidth( marker );
299 
300  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
301  || gridScreenSizeDense > gridThreshold )
302  {
303  drawGridLine( VECTOR2D( gridStartX * gridSize.x + gridOrigin.x, y ),
304  VECTOR2D( gridEndX * gridSize.x + gridOrigin.x, y ) );
305  }
306  }
307 
308  // Horizontal lines
309  for( int i = gridStartX; i <= gridEndX; i++ )
310  {
311  const double x = i * gridSize.x + gridOrigin.x;
312 
313  if( axesEnabled && x == 0 )
314  continue;
315 
316  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
317  SetLineWidth( doubleMarker );
318  else
319  SetLineWidth( marker );
320 
321  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
322  || gridScreenSizeDense > gridThreshold )
323  {
324  drawGridLine( VECTOR2D( x, gridStartY * gridSize.y + gridOrigin.y ),
325  VECTOR2D( x, gridEndY * gridSize.y + gridOrigin.y ) );
326  }
327  }
328  }
329  else if( gridStyle == GRID_STYLE::SMALL_CROSS )
330  {
331  SetIsFill( false );
332  SetIsStroke( true );
334 
335  SetLineWidth( marker );
336  double lineLen = GetLineWidth() * 2;
337 
338  // Vertical positions:
339  for( int j = gridStartY; j <= gridEndY; j++ )
340  {
341  if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
342  || gridScreenSizeDense > gridThreshold )
343  {
344  int posY = j * gridSize.y + gridOrigin.y;
345 
346  // Horizontal positions:
347  for( int i = gridStartX; i <= gridEndX; i++ )
348  {
349  if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold )
350  || gridScreenSizeDense > gridThreshold )
351  {
352  int posX = i * gridSize.x + gridOrigin.x;
353 
354  drawGridLine( VECTOR2D( posX - lineLen, posY ),
355  VECTOR2D( posX + lineLen, posY ) );
356 
357  drawGridLine( VECTOR2D( posX, posY - lineLen ),
358  VECTOR2D( posX, posY + lineLen ) );
359  }
360  }
361  }
362  }
363  }
364  else // Dotted grid
365  {
366  bool tickX, tickY;
367  SetIsFill( true );
368  SetIsStroke( false );
370 
371  for( int j = gridStartY; j <= gridEndY; j++ )
372  {
373  if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold )
374  tickY = true;
375  else
376  tickY = false;
377 
378  for( int i = gridStartX; i <= gridEndX; i++ )
379  {
380  if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold )
381  tickX = true;
382  else
383  tickX = false;
384 
385  if( tickX || tickY || gridScreenSizeDense > gridThreshold )
386  {
387  double radius = ( ( tickX && tickY ) ? doubleMarker : marker ) / 2.0;
388  DrawRectangle( VECTOR2D( i * gridSize.x - radius + gridOrigin.x,
389  j * gridSize.y - radius + gridOrigin.y ),
390  VECTOR2D( i * gridSize.x + radius + gridOrigin.x,
391  j * gridSize.y + radius + gridOrigin.y ) );
392  }
393  }
394  }
395  }
396 }
397 
398 
399 VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
400 {
401 #if 0
402  // This old code expects a non zero grid size, which can be wrong here.
403  return VECTOR2D( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
404  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
405 #else
406  // if grid size == 0.0 there is no grid, so use aPoint as grid reference position
407  double cx = gridSize.x > 0.0 ? KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x
408  : aPoint.x;
409  double cy = gridSize.y > 0.0 ? KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y
410  : aPoint.y;
411 
412  return VECTOR2D( cx, cy );
413 #endif
414 }
415 
416 const int GAL::MIN_DEPTH = -1024;
417 const int GAL::MAX_DEPTH = 1023;
418 const int GAL::GRID_DEPTH = MAX_DEPTH - 1;
419 
420 
422 {
423  auto color = cursorColor;
424 
425  // dim the cursor if it's only on because it was forced
426  // (this helps to provide a hint for active tools)
427  if( !isCursorEnabled )
428  {
429  color.a = color.a * 0.5;
430  }
431 
432  return color;
433 }
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)
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:168
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
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:188
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:171
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:112
static const int MIN_DEPTH
Possible depth range.
GAL(GAL_DISPLAY_OPTIONS &aOptions)
void SetFontBold(const bool aBold)
Set bold property of current font.
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.
void ResetTextAttributes()
Reset text attributes to default styling.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:588
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.
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:189
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:177
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.
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:213
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.