KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The KiCad Developers, see AUTHORS.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, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <wx/log.h>
24#include <advanced_config.h>
26#include <gal/definitions.h>
27#include <font/font.h>
28
31
32#include <math/util.h> // for KiROUND
33
34#include <algorithm>
35#include <cmath>
36#include <limits>
37
38using namespace KIGFX;
39
40
41GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
42 m_options( aDisplayOptions ),
43
44 // m_currentNativeCursor is initialized with KICURSOR::DEFAULT value to avoid
45 // if comparison with uninitialized value on SetNativeCursorStyle method.
46 // Some classes inheriting from GAL has different SetNativeCursorStyle method
47 // implementation and therefore it's called also on constructor
48 // to change the value from DEFAULT to KICURSOR::ARROW
50{
51 // Set the default values for the internal variables
52 SetIsFill( false );
53 SetIsStroke( true );
54 SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
55 SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
56 SetLookAtPoint( VECTOR2D( 0, 0 ) );
57 SetZoomFactor( 1.0 );
58 SetRotation( 0.0 );
59
60 // this value for SetWorldUnitLength is only suitable for Pcbnew.
61 // Other editors/viewer must call SetWorldUnitLength with their internal units
62 SetWorldUnitLength( 1e-9 /* 1 nm */ / 0.0254 /* 1 inch in meters */ );
63
64 // wxDC::GetPPI() reports 96 DPI, but somehow this value
65 // is the closest match to the legacy renderer
66 SetScreenDPI( ADVANCED_CFG::GetCfg().m_ScreenDPI );
68 SetLayerDepth( 0.0 );
69 SetFlip( false, false );
70 SetLineWidth( 1.0f );
71 SetMinLineWidth( 1.0f );
73 SetAxesEnabled( false );
74
75 // Set grid defaults
76 SetGridVisibility( true );
77 SetCoarseGrid( 10 );
78 m_gridLineWidth = 0.5f;
81
82 // Initialize the cursor shape
83 SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
86 SetCursorEnabled( false );
87
88 // Initialize the native widget to an arrow cursor
90
91 // Initialize text properties
93
94 // subscribe for settings updates
95 m_observerLink = m_options.Subscribe( this );
96}
97
98
100{
101}
102
103
105{
106 // defer to the child class first
107 updatedGalDisplayOptions( aOptions );
108
109 // there is no refresh to do at this level
110}
111
112
113void GAL::DrawEllipse( const VECTOR2D& aCenterPoint, double aMajorRadius, double aMinorRadius,
114 const EDA_ANGLE& aRotation )
115{
116 const VECTOR2I intCenter( KiROUND( aCenterPoint.x ), KiROUND( aCenterPoint.y ) );
117
118 SHAPE_ELLIPSE e( intCenter, KiROUND( aMajorRadius ), KiROUND( aMinorRadius ), aRotation );
119
120 SHAPE_LINE_CHAIN chain = e.ConvertToPolyline( std::max( 1, KiROUND( aMajorRadius / 500.0 ) ) );
122}
123
124
125void GAL::DrawEllipseArc( const VECTOR2D& aCenterPoint, double aMajorRadius, double aMinorRadius,
126 const EDA_ANGLE& aRotation, const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aEndAngle )
127{
128 const VECTOR2I intCenter( KiROUND( aCenterPoint.x ), KiROUND( aCenterPoint.y ) );
129
130 SHAPE_ELLIPSE e( intCenter, KiROUND( aMajorRadius ), KiROUND( aMinorRadius ), aRotation, aStartAngle, aEndAngle );
131
132 SHAPE_LINE_CHAIN chain = e.ConvertToPolyline( std::max( 1, KiROUND( aMajorRadius / 500.0 ) ) );
134}
135
136
138{
139 bool refresh = false;
140
141 if( m_options.m_gridStyle != m_gridStyle )
142 {
143 m_gridStyle = m_options.m_gridStyle;
144 refresh = true;
145 }
146
147 if( m_options.m_gridLineWidth != m_gridLineWidth )
148 {
149 m_gridLineWidth = m_options.m_scaleFactor * m_options.m_gridLineWidth + 0.25;
150 refresh = true;
151 }
152
153 if( m_options.m_gridMinSpacing != m_gridMinSpacing )
154 {
155 m_gridMinSpacing = m_options.m_gridMinSpacing;
156 refresh = true;
157 }
158
159 if( m_options.m_axesEnabled != m_axesEnabled )
160 {
161 m_axesEnabled = m_options.m_axesEnabled;
162 refresh = true;
163 }
164
165 if( m_options.m_forceDisplayCursor != m_forceDisplayCursor )
166 {
167 m_forceDisplayCursor = m_options.m_forceDisplayCursor;
168 refresh = true;
169 }
170
171 if( m_options.GetCursorMode() != m_crossHairMode )
172 {
173 m_crossHairMode = m_options.GetCursorMode();
174 refresh = true;
175 }
176
177 // tell the derived class if the base class needs an update or not
178 return refresh;
179}
180
181
183{
184 // Tiny but non-zero - this will always need setting
185 // there is no built-in default
186 SetGlyphSize( { 1, 1 } );
187
190
191 SetFontBold( false );
192 SetFontItalic( false );
193 SetFontUnderlined( false );
194 SetTextMirrored( false );
195}
196
197
199{
201
202 MATRIX3x3D translation;
203 translation.SetIdentity();
204 // We're deliberately dividing integers to avoid fractional pixel offsets.
205 translation.SetTranslation( VECTOR2D( m_screenSize.x/2, m_screenSize.y/2 ) );
206
207 MATRIX3x3D rotate;
208 rotate.SetIdentity();
209 rotate.SetRotation( m_rotation );
210
212 scale.SetIdentity();
213 scale.SetScale( VECTOR2D( m_worldScale, m_worldScale ) );
214
215 MATRIX3x3D flip;
216 flip.SetIdentity();
217 flip.SetScale( VECTOR2D( m_globalFlipX ? -1.0 : 1.0, m_globalFlipY ? -1.0 : 1.0 ) );
218
219 MATRIX3x3D lookat;
220 lookat.SetIdentity();
221 lookat.SetTranslation( -m_lookAtPoint );
222
223 m_worldScreenMatrix = translation * rotate * flip * scale * lookat;
225}
226
227
229{
230 const MATRIX3x3D& matrix = GetScreenWorldMatrix();
231
232 VECTOR2D halfSize = VECTOR2D( matrix.GetScale().x * m_screenSize.x * 0.5,
233 matrix.GetScale().y * m_screenSize.y * 0.5 );
234
235 BOX2D extents;
236 extents.SetOrigin( GetLookAtPoint() - halfSize );
237 extents.SetSize( halfSize * 2 );
238
239 return extents;
240}
241
242
244{
245 // just return the current value. This could be cleverer and take
246 // into account other settings in future
247 return m_gridMinSpacing;
248}
249
250
251void GAL::SetGridSources( std::vector<GRID_SOURCE> aSources )
252{
253 std::stable_sort( aSources.begin(), aSources.end(),
254 []( const GRID_SOURCE& a, const GRID_SOURCE& b )
255 {
256 return a.TakesPrecedenceOver( b );
257 } );
258
259 m_gridSources = std::move( aSources );
260}
261
262
264{
265 const VECTOR2D corners[4] = { m_screenWorldMatrix * VECTOR2D( 0, 0 ),
269
270 const double co = std::cos( aSrc.orientation );
271 const double so = std::sin( aSrc.orientation );
272
273 BOX2D bbox;
274
275 for( const VECTOR2D& w : corners )
276 {
277 const VECTOR2D off = w - aSrc.origin;
278 bbox.Merge( VECTOR2D( co * off.x - so * off.y, so * off.x + co * off.y ) );
279 }
280
281 return bbox;
282}
283
284
285VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
286{
287 // m_gridSources is precedence-ordered by SetGridSources, so the first cursor-snap
288 // source covering aPoint is the one that owns it.
289 for( const GRID_SOURCE& src : m_gridSources )
290 {
291 if( src.snapCursor && src.Contains( aPoint ) )
292 return src.Snap( aPoint );
293 }
294
295 // Display-grid fallback. Grid size 0 = no grid, return aPoint unchanged.
296 double cx = m_gridSize.x > 0.0 ? KiROUND( ( aPoint.x - m_gridOffset.x ) / m_gridSize.x ) *
298 : aPoint.x;
299 double cy = m_gridSize.y > 0.0 ? KiROUND( ( aPoint.y - m_gridOffset.y ) / m_gridSize.y ) *
301 : aPoint.y;
302
303 return VECTOR2D( cx, cy );
304}
305
306
307// MIN_DEPTH must be set to be - (VIEW::VIEW_MAX_LAYERS + abs(VIEW::TOP_LAYER_MODIFIER))
308// MAX_DEPTH must be set to be VIEW::VIEW_MAX_LAYERS + abs(VIEW::TOP_LAYER_MODIFIER) -1
309// VIEW_MAX_LAYERS and TOP_LAYER_MODIFIER are defined in view.h.
310// TOP_LAYER_MODIFIER is set as -VIEW_MAX_LAYERS
311// Currently KIGFX::VIEW::VIEW_MAX_LAYERS = MAX_LAYERS_FOR_VIEW
313const int GAL::MAX_DEPTH = 2*MAX_LAYERS_FOR_VIEW - 1;
314const int GAL::GRID_DEPTH = MAX_DEPTH - 1;
315
316
318{
319 COLOR4D color = m_cursorColor;
320
321 // dim the cursor if it's only on because it was forced
322 // (this helps to provide a hint for active tools)
323 if( !m_isCursorEnabled )
324 color.a = color.a * 0.5;
325
326 return color;
327}
328
329
330void GAL::BitmapText( const wxString& aText, const VECTOR2I& aPosition, const EDA_ANGLE& aAngle )
331{
333
334 if( aText.IsEmpty() )
335 return;
336
338 attrs.m_Angle = aAngle;
339 attrs.m_Mirrored = m_globalFlipX; // Prevent text flipping when view is flipped
340
341 // Bitmap font has different metrics than the stroke font so we compensate a bit before
342 // stroking
343 attrs.m_Size = VECTOR2I( m_attributes.m_Size.x, m_attributes.m_Size.y * 0.95 );
344 attrs.m_StrokeWidth = GetLineWidth() * 0.74;
345
346 font->Draw( this, aText, aPosition, attrs, KIFONT::METRICS::Default() );
347}
348
349
350bool GAL::SetNativeCursorStyle( KICURSOR aCursor, bool aHiDPI )
351{
352 if( m_currentNativeCursor == aCursor )
353 return false;
354
355 m_currentNativeCursor = aCursor;
356
357 return true;
358}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
constexpr void SetSize(const SizeVec &size)
Definition box2.h:245
GAL(GAL_DISPLAY_OPTIONS &aOptions)
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:143
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
Definition font.cpp:240
static const METRICS & Default()
Definition font.cpp:48
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double a
Alpha component.
Definition color4d.h:393
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawEllipseArc(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle)
Draw an elliptical arc in world coordinates.
bool m_isCursorEnabled
Is the cursor enabled?
BOX2D GetVisibleWorldExtents() const
MATRIX3x3D m_worldScreenMatrix
World transformation.
void SetVerticalJustify(const GR_TEXT_V_ALIGN_T aVerticalJustify)
void SetFontBold(const bool aBold)
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
void SetFontUnderlined(bool aUnderlined)
void SetHorizontalJustify(const GR_TEXT_H_ALIGN_T aHorizontalJustify)
bool m_axesEnabled
Should the axes be drawn.
void SetRotation(double aRotation)
Get/set the rotation angle (in radians).
float m_gridLineWidth
Line width of the grid.
void SetFlip(bool xAxis, bool yAxis)
Sets flipping of the screen.
VECTOR2I m_screenSize
Screen size in screen (wx logical) coordinates.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
void OnGalDisplayOptionsChanged(const GAL_DISPLAY_OPTIONS &aOptions) override
Handler for observer settings changes.
void SetCursorEnabled(bool aCursorEnabled)
Enable/disable cursor.
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
virtual bool SetNativeCursorStyle(KICURSOR aCursor, bool aHiDPI)
Set the cursor in the native panel.
GRID_STYLE m_gridStyle
Grid display style.
void SetCursorColor(const COLOR4D &aCursorColor)
Set the cursor color.
COLOR4D m_cursorColor
Cursor color.
int m_gridMinSpacing
Minimum screen size of the grid (pixels) below which the grid is not drawn.
const VECTOR2D & GetLookAtPoint() const
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
void SetZoomFactor(double aZoomFactor)
void computeWorldScale()
Compute the scaling factor for the world->screen matrix.
TEXT_ATTRIBUTES m_attributes
void ResetTextAttributes()
Reset text attributes to default styling.
static const int MIN_DEPTH
Possible depth range.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
double m_rotation
Rotation transformation (radians)
VECTOR2D m_gridSize
The grid size.
COLOR4D getCursorColor() const
Get the actual cursor color to draw.
void SetTextMirrored(const bool aMirrored)
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList)
Draw a polyline.
void SetCoarseGrid(int aInterval)
Draw every tick line wider.
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Handle updating display options.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
BOX2D gridScreenBBox(const GRID_SOURCE &aSrc) const
VECTOR2D m_gridOffset
The grid offset to compensate cursor position.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
double m_worldScale
The scale factor world->screen.
void SetGridSources(std::vector< GRID_SOURCE > aSources)
Set the grid-source list rendered alongside the display grid.
void SetLookAtPoint(const VECTOR2D &aPoint)
Get/set the Point in world space to look at.
VECTOR2D GetGridPoint(const VECTOR2D &aPoint) const
For a given point it returns the nearest point belonging to the grid in world coordinates.
void SetWorldUnitLength(double aWorldUnitLength)
Set the unit length.
virtual void SetMinLineWidth(float aLineWidth)
Set the minimum line width in pixels.
KICURSOR m_currentNativeCursor
Current cursor.
bool m_globalFlipY
Flag for Y axis flipping.
static const int GRID_DEPTH
Depth level on which the grid is drawn.
void SetGlyphSize(const VECTOR2I aSize)
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
double computeMinGridSpacing() const
Compute minimum grid spacing from the grid settings.
void SetFontItalic(bool aItalic)
std::vector< GRID_SOURCE > m_gridSources
Sources overlayed on the display grid.
virtual void DrawEllipse(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation)
Draw a closed ellipse.
GAL_DISPLAY_OPTIONS & m_options
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
void SetGridVisibility(bool aVisibility)
Set the visibility setting of the grid.
float GetLineWidth() const
Get the line width.
bool m_globalFlipX
Flag for X axis flipping.
KIGFX::CROSS_HAIR_MODE m_crossHairMode
Crosshair drawing mode.
void SetDepthRange(const VECTOR2D &aDepthRange)
Set the range of the layer depth.
VECTOR2D m_lookAtPoint
Point to be looked at in world space.
void SetScreenDPI(double aScreenDPI)
Set the dots per inch of the screen.
bool m_forceDisplayCursor
Always show cursor.
static const int MAX_DEPTH
void SetIdentity()
Set the matrix to the identity matrix.
Definition matrix3x3.h:236
void SetRotation(T aAngle)
Set the rotation components of the matrix.
Definition matrix3x3.h:271
void SetScale(VECTOR2< T > aScale)
Set the scale components of the matrix.
Definition matrix3x3.h:283
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition matrix3x3.h:291
void SetTranslation(VECTOR2< T > aTranslation)
Set the translation components of the matrix.
Definition matrix3x3.h:252
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
KICURSOR
Definition cursors.h:40
@ ARROW
Definition cursors.h:42
#define MAX_LAYERS_FOR_VIEW
Definition definitions.h:41
MATRIX3x3< double > MATRIX3x3D
Definition matrix3x3.h:469
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:30
@ LINES
Use lines for the grid.
const int scale
double orientation
Rotation about origin, radians CCW.
VECTOR2D origin
Render-time projection of a grid: GRID_GEOMETRY (kind/origin/pitch/orientation/extent) plus rendering...
const SHAPE_LINE_CHAIN chain
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_CENTER
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682