kicad/include/gal/graphics_abstraction_layer.h

936 lines
26 KiB
C++

/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2016 Kicad Developers, see change_log.txt for contributors.
*
* Graphics Abstraction Layer (GAL) - base class
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GRAPHICSABSTRACTIONLAYER_H_
#define GRAPHICSABSTRACTIONLAYER_H_
#include <deque>
#include <stack>
#include <limits>
#include <math/matrix3x3.h>
#include <gal/color4d.h>
#include <gal/definitions.h>
#include <gal/stroke_font.h>
#include <newstroke_font.h>
namespace KIGFX
{
/**
* GridStyle: Type definition of the grid style
*/
enum GRID_STYLE
{
GRID_STYLE_LINES, ///< Use lines for the grid
GRID_STYLE_DOTS ///< Use dots for the grid
};
/**
* @brief Class GAL is the abstract interface for drawing on a 2D-surface.
*
* The functions are optimized for drawing shapes of an EDA-program such as KiCad. Most methods
* are abstract and need to be implemented by a lower layer, for example by a cairo or OpenGL implementation.
* <br>
* Almost all methods use world coordinates as arguments. The board design is defined in world space units;
* for drawing purposes these are transformed to screen units with this layer. So zooming is handled here as well.
*
*/
class GAL
{
public:
// Constructor / Destructor
GAL();
virtual ~GAL();
/// @brief Returns the initalization status for the canvas.
virtual bool IsInitialized() const { return true; }
// ---------------
// Drawing methods
// ---------------
/// @brief Begin the drawing, needs to be called for every new frame.
virtual void BeginDrawing() {};
/// @brief End the drawing, needs to be called for every new frame.
virtual void EndDrawing() {};
/**
* @brief Draw a line.
*
* Start and end points are defined as 2D-Vectors.
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
virtual void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) {};
/**
* @brief Draw a rounded segment.
*
* Start and end points are defined as 2D-Vectors.
*
* @param aStartPoint is the start point of the segment.
* @param aEndPoint is the end point of the segment.
* @param aWidth is a width of the segment
*/
virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) {};
/**
* @brief Draw a polyline
*
* @param aPointList is a list of 2D-Vectors containing the polyline points.
*/
virtual void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) {};
virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) {};
/**
* @brief Draw a circle using world coordinates.
*
* @param aCenterPoint is the center point of the circle.
* @param aRadius is the radius of the circle.
*/
virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) {};
/**
* @brief Draw an arc.
*
* @param aCenterPoint is the center point of the arc.
* @param aRadius is the arc radius.
* @param aStartAngle is the start angle of the arc.
* @param aEndAngle is the end angle of the arc.
*/
virtual void
DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle ) {};
/**
* @brief Draw a rectangle.
*
* @param aStartPoint is the start point of the rectangle.
* @param aEndPoint is the end point of the rectangle.
*/
virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) {};
/**
* @brief Draw a polygon.
*
* @param aPointList is the list of the polygon points.
*/
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) {};
virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) {};
/**
* @brief Draw a cubic bezier spline.
*
* @param startPoint is the start point of the spline.
* @param controlPointA is the first control point.
* @param controlPointB is the second control point.
* @param endPoint is the end point of the spline.
*/
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
const VECTOR2D& controlPointB, const VECTOR2D& endPoint ) {};
// --------------
// Screen methods
// --------------
/// @brief Resizes the canvas.
virtual void ResizeScreen( int aWidth, int aHeight ) {};
/// @brief Shows/hides the GAL canvas
virtual bool Show( bool aShow ) { return true; };
/// @brief Returns GAL canvas size in pixels
const VECTOR2I& GetScreenPixelSize() const
{
return screenSize;
}
/// @brief Force all remaining objects to be drawn.
virtual void Flush() {};
/**
* @brief Clear the screen.
* @param aColor is the color used for clearing.
*/
virtual void ClearScreen( const COLOR4D& aColor ) {};
// -----------------
// Attribute setting
// -----------------
/**
* @brief Enable/disable fill.
*
* @param aIsFillEnabled is true, when the graphics objects should be filled, else false.
*/
inline virtual void SetIsFill( bool aIsFillEnabled )
{
isFillEnabled = aIsFillEnabled;
}
/**
* @brief Enable/disable stroked outlines.
*
* @param aIsStrokeEnabled is true, if the outline of an object should be stroked.
*/
inline virtual void SetIsStroke( bool aIsStrokeEnabled )
{
isStrokeEnabled = aIsStrokeEnabled;
}
/**
* @brief Set the fill color.
*
* @param aColor is the color for filling.
*/
inline virtual void SetFillColor( const COLOR4D& aColor )
{
fillColor = aColor;
}
/**
* @brief Set the stroke color.
*
* @param aColor is the color for stroking the outline.
*/
inline virtual void SetStrokeColor( const COLOR4D& aColor )
{
strokeColor = aColor;
}
/**
* @brief Get the stroke color.
*
* @return the color for stroking the outline.
*/
inline const COLOR4D& GetStrokeColor() const
{
return strokeColor;
}
/**
* @brief Set the line width.
*
* @param aLineWidth is the line width.
*/
inline virtual void SetLineWidth( double aLineWidth )
{
lineWidth = aLineWidth;
}
/**
* @brief Get the line width.
*
* @return the actual line width.
*/
inline double GetLineWidth() const
{
return lineWidth;
}
/**
* @brief Set the depth of the layer (position on the z-axis)
*
* @param aLayerDepth the layer depth for the objects.
*/
inline virtual void SetLayerDepth( double aLayerDepth )
{
assert( aLayerDepth <= depthRange.y );
assert( aLayerDepth >= depthRange.x );
layerDepth = aLayerDepth;
}
// ----
// Text
// ----
const STROKE_FONT& GetStrokeFont() const
{
return strokeFont;
}
/**
* @brief Draws a vector type text using preloaded Newstroke font.
*
* @param aText is the text to be drawn.
* @param aPosition is the text position in world coordinates.
* @param aRotationAngle is the text rotation angle.
*/
inline virtual void StrokeText( const wxString& aText, const VECTOR2D& aPosition,
double aRotationAngle )
{
strokeFont.Draw( aText, aPosition, aRotationAngle );
}
/**
* @brief Compute the X and Y size of a given text. The text is expected to be
* a only one line text.
*
* @param aText is the text string (one line).
* @return is the text size.
*/
VECTOR2D GetTextLineSize( const UTF8& aText ) const;
/**
* Compute the vertical position of an overbar, sometimes used in texts.
* This is the distance between the text base line and the overbar.
* @return the relative position of the overbar axis.
*/
double GetOverbarVerticalPosition() const
{
return strokeFont.computeOverbarVerticalPosition();
}
/**
* @brief Loads attributes of the given text (bold/italic/underline/mirrored and so on).
*
* @param aText is the text item.
*/
virtual void SetTextAttributes( const EDA_TEXT* aText );
/// @copydoc STROKE_FONT::SetGlyphSize()
inline void SetGlyphSize( const VECTOR2D aGlyphSize )
{
strokeFont.SetGlyphSize( aGlyphSize );
}
/// @copydoc STROKE_FONT::SetBold()
inline void SetBold( const bool aBold )
{
strokeFont.SetBold( aBold );
}
/// @copydoc STROKE_FONT::SetItalic()
inline void SetItalic( const bool aItalic )
{
strokeFont.SetItalic( aItalic );
}
/// @copydoc STROKE_FONT::SetMirrored()
inline void SetMirrored( const bool aMirrored )
{
strokeFont.SetMirrored( aMirrored );
}
/// @copydoc STROKE_FONT::SetHorizontalJustify()
inline void SetHorizontalJustify( const EDA_TEXT_HJUSTIFY_T aHorizontalJustify )
{
strokeFont.SetHorizontalJustify( aHorizontalJustify );
}
/// @copydoc STROKE_FONT::SetVerticalJustify()
inline void SetVerticalJustify( const EDA_TEXT_VJUSTIFY_T aVerticalJustify )
{
strokeFont.SetVerticalJustify( aVerticalJustify );
}
// --------------
// Transformation
// --------------
/**
* @brief Transform the context.
*
* @param aTransformation is the ransformation matrix.
*/
virtual void Transform( const MATRIX3x3D& aTransformation ) {};
/**
* @brief Rotate the context.
*
* @param aAngle is the rotation angle in radians.
*/
virtual void Rotate( double aAngle ) {};
/**
* @brief Translate the context.
*
* @param aTranslation is the translation vector.
*/
virtual void Translate( const VECTOR2D& aTranslation ) {};
/**
* @brief Scale the context.
*
* @param aScale is the scale factor for the x- and y-axis.
*/
virtual void Scale( const VECTOR2D& aScale ) {};
/// @brief Save the context.
virtual void Save() {};
/// @brief Restore the context.
virtual void Restore() {};
// --------------------------------------------
// Group methods
// ---------------------------------------------
/**
* @brief Begin a group.
*
* A group is a collection of graphic items.
* Hierarchical groups are possible, attributes and transformations can be used.
*
* @return the number of the group.
*/
virtual int BeginGroup() { return 0; };
/// @brief End the group.
virtual void EndGroup() {};
/**
* @brief Draw the stored group.
*
* @param aGroupNumber is the group number.
*/
virtual void DrawGroup( int aGroupNumber ) {};
/**
* @brief Changes the color used to draw the group.
*
* @param aGroupNumber is the group number.
* @param aNewColor is the new color.
*/
virtual void ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) {};
/**
* @brief Changes the depth (Z-axis position) of the group.
*
* @param aGroupNumber is the group number.
* @param aDepth is the new depth.
*/
virtual void ChangeGroupDepth( int aGroupNumber, int aDepth ) {};
/**
* @brief Delete the group from the memory.
*
* @param aGroupNumber is the group number.
*/
virtual void DeleteGroup( int aGroupNumber ) {};
/**
* @brief Delete all data created during caching of graphic items.
*/
virtual void ClearCache() {};
// --------------------------------------------------------
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @brief Compute the world <-> screen transformation matrix
virtual void ComputeWorldScreenMatrix();
/**
* @brief Get the world <-> screen transformation matrix.
*
* @return the transformation matrix.
*/
const MATRIX3x3D& GetWorldScreenMatrix() const
{
return worldScreenMatrix;
}
/**
* @brief Get the screen <-> world transformation matrix.
*
* @return the transformation matrix.
*/
const MATRIX3x3D& GetScreenWorldMatrix() const
{
return screenWorldMatrix;
}
/**
* @brief Set the world <-> screen transformation matrix.
*
* @param aMatrix is the 3x3 world <-> screen transformation matrix.
*/
inline void SetWorldScreenMatrix( const MATRIX3x3D& aMatrix )
{
worldScreenMatrix = aMatrix;
}
/**
* @brief Set the unit length.
*
* This defines the length [inch] per one integer. For instance a value 0.001 means
* that the coordinate [1000, 1000] corresponds with a point at (1 inch, 1 inch) or
* 1 mil resolution per integer.
*
* @param aWorldUnitLength is the world Unit length.
*/
inline void SetWorldUnitLength( double aWorldUnitLength )
{
worldUnitLength = aWorldUnitLength;
}
/**
* @brief Set the dots per inch of the screen.
*
* This value depends on the user screen, it should be configurable by the application.
* For instance a typical notebook with HD+ resolution (1600x900) has 106 DPI.
*
* @param aScreenDPI are the screen DPI.
*/
inline void SetScreenDPI( double aScreenDPI )
{
screenDPI = aScreenDPI;
}
/**
* @brief Set the Point in world space to look at.
*
* This point corresponds with the center of the actual drawing area.
*
* @param aPoint is the look at point (center of the actual drawing area).
*/
inline void SetLookAtPoint( const VECTOR2D& aPoint )
{
lookAtPoint = aPoint;
}
/**
* @brief Get the look at point.
*
* @return the look at point.
*/
inline const VECTOR2D& GetLookAtPoint() const
{
return lookAtPoint;
}
/**
* @brief Set the zoom factor of the scene.
*
* @param aZoomFactor is the zoom factor.
*/
inline void SetZoomFactor( double aZoomFactor )
{
zoomFactor = aZoomFactor;
}
/**
* @brief Get the zoom factor
*
* @return the zoom factor.
*/
inline double GetZoomFactor() const
{
return zoomFactor;
}
/**
* @brief Set the range of the layer depth.
*
* Usually required for the OpenGL implementation, any object outside this range is not drawn.
*
* @param aDepthRange is the depth range where component x is the near clipping plane and y
* is the far clipping plane.
*/
inline void SetDepthRange( const VECTOR2D& aDepthRange )
{
depthRange = aDepthRange;
}
/**
* @brief Returns the minimum depth in the currently used range (the top).
*/
inline double GetMinDepth() const
{
return depthRange.x;
}
/**
* @brief Returns the maximum depth in the currently used range (the bottom).
*/
inline double GetMaxDepth() const
{
return depthRange.y;
}
/**
* @brief Get the world scale.
*
* @return the actual world scale factor.
*/
inline double GetWorldScale() const
{
return worldScale;
}
/**
* @brief Sets flipping of the screen.
*
* @param xAxis is the flip flag for the X axis.
* @param yAxis is the flip flag for the Y axis.
*/
inline void SetFlip( bool xAxis, bool yAxis )
{
if( xAxis )
flipX = -1.0; // flipped
else
flipX = 1.0; // regular
if( yAxis )
flipY = -1.0; // flipped
else
flipY = 1.0; // regular
}
// ---------------------------
// Buffer manipulation methods
// ---------------------------
/**
* @brief Save the screen contents.
*/
virtual void SaveScreen() {};
/**
* @brief Restore the screen contents.
*/
virtual void RestoreScreen() {};
/**
* @brief Sets the target for rendering.
*
* @param aTarget is the new target for rendering.
*/
virtual void SetTarget( RENDER_TARGET aTarget ) {};
/**
* @brief Gets the currently used target for rendering.
*
* @return The current rendering target.
*/
virtual RENDER_TARGET GetTarget() const { return TARGET_CACHED; };
/**
* @brief Clears the target for rendering.
*
* @param aTarget is the target to be cleared.
*/
virtual void ClearTarget( RENDER_TARGET aTarget ) {};
// -------------
// Grid methods
// -------------
/**
* @brief Sets the visibility setting of the grid.
*
* @param aVisibility is the new visibility setting of the grid.
*/
inline void SetGridVisibility( bool aVisibility )
{
gridVisibility = aVisibility;
}
/**
* @brief Set the origin point for the grid.
*
* @param aGridOrigin is a vector containing the grid origin point, in world coordinates.
*/
inline void SetGridOrigin( const VECTOR2D& aGridOrigin )
{
gridOrigin = aGridOrigin;
if( gridSize.x == 0.0 || gridSize.y == 0.0 )
gridOffset = VECTOR2D(0.0, 0.0);
else
gridOffset = VECTOR2D( (long) gridOrigin.x % (long) gridSize.x,
(long) gridOrigin.y % (long) gridSize.y );
}
/**
* @brief Set the threshold for grid drawing.
*
* @param aThreshold is the minimum grid cell size (in pixels) for which the grid is drawn.
*/
inline void SetGridDrawThreshold( int aThreshold )
{
gridDrawThreshold = aThreshold;
}
/**
* @brief Set the grid size.
*
* @param aGridSize is a vector containing the grid size in x and y direction.
*/
inline void SetGridSize( const VECTOR2D& aGridSize )
{
gridSize = aGridSize;
gridOffset = VECTOR2D( (long) gridOrigin.x % (long) gridSize.x,
(long) gridOrigin.y % (long) gridSize.y );
}
/**
* @brief Returns the grid size.
*
* @return A vector containing the grid size in x and y direction.
*/
inline const VECTOR2D& GetGridSize() const
{
return gridSize;
}
/**
* @brief Set the grid color.
*
* @param aGridColor is the grid color, it should have a low alpha value for the best effect.
*/
inline void SetGridColor( const COLOR4D& aGridColor )
{
gridColor = aGridColor;
}
/**
* @brief Draw every tick line wider.
*
* @param aInterval increase the width of every aInterval line, if 0 do not use this feature.
*/
inline void SetCoarseGrid( int aInterval )
{
gridTick = aInterval;
}
/**
* @brief Get the grid line width.
*
* @return the grid line width
*/
inline double GetGridLineWidth() const
{
return gridLineWidth;
}
/**
* @brief Set the grid line width.
*
* @param aGridLineWidth is the rid line width.
*/
inline void SetGridLineWidth( double aGridLineWidth )
{
gridLineWidth = aGridLineWidth;
}
///> @brief Draw the grid
void DrawGrid();
/**
* Function GetGridPoint()
* For a given point it returns the nearest point belonging to the grid in world coordinates.
*
* @param aPoint is the point for which the grid point is searched.
* @return The nearest grid point in world coordinates.
*/
VECTOR2D GetGridPoint( const VECTOR2D& aPoint ) const;
/**
* @brief Change the grid display style.
*
* @param aGridStyle is the new style for grid.
*/
inline virtual void SetGridStyle( GRID_STYLE aGridStyle )
{
gridStyle = aGridStyle;
}
/**
* @brief Compute the point position in world coordinates from given screen coordinates.
*
* @param aPoint the pointposition in screen coordinates.
* @return the point position in world coordinates.
*/
inline VECTOR2D ToWorld( const VECTOR2D& aPoint ) const
{
return VECTOR2D( screenWorldMatrix * aPoint );
}
/**
* @brief Compute the point position in screen coordinates from given world coordinates.
*
* @param aPoint the pointposition in world coordinates.
* @return the point position in screen coordinates.
*/
inline VECTOR2D ToScreen( const VECTOR2D& aPoint ) const
{
return VECTOR2D( worldScreenMatrix * aPoint );
}
/**
* @brief Enable/disable cursor.
*
* @param aCursorEnabled is true if the cursor should be drawn, else false.
*/
inline void SetCursorEnabled( bool aCursorEnabled )
{
isCursorEnabled = aCursorEnabled;
}
/**
* @brief Set the cursor color.
*
* @param aCursorColor is the color of the cursor.
*/
inline void SetCursorColor( const COLOR4D& aCursorColor )
{
cursorColor = aCursorColor;
}
/**
* @brief Returns the cursor size.
*
* @return The current cursor size (in pixels).
*/
inline unsigned int GetCursorSize() const
{
return cursorSize;
}
/**
* @brief Set the cursor size.
*
* @param aCursorSize is the size of the cursor expressed in pixels.
*/
virtual inline void SetCursorSize( unsigned int aCursorSize )
{
cursorSize = aCursorSize;
}
/**
* @brief Draw the cursor.
*
* @param aCursorPosition is the cursor position in screen coordinates.
*/
virtual void DrawCursor( const VECTOR2D& aCursorPosition ) {};
/**
* @brief Changes the current depth to deeper, so it is possible to draw objects right beneath
* other.
*/
inline void AdvanceDepth()
{
layerDepth -= 0.001;
}
/**
* @brief Stores current drawing depth on the depth stack.
*/
inline void PushDepth()
{
depthStack.push( layerDepth );
}
/**
* @brief Restores previously stored drawing depth for the depth stack.
*/
inline void PopDepth()
{
layerDepth = depthStack.top();
depthStack.pop();
}
static const double METRIC_UNIT_LENGTH;
protected:
std::stack<double> depthStack; ///< Stored depth values
VECTOR2I screenSize; ///< Screen size in screen coordinates
double worldUnitLength; ///< The unit length of the world coordinates [inch]
double screenDPI; ///< The dots per inch of the screen
VECTOR2D lookAtPoint; ///< Point to be looked at in world space
double zoomFactor; ///< The zoom factor
MATRIX3x3D worldScreenMatrix; ///< World transformation
MATRIX3x3D screenWorldMatrix; ///< Screen transformation
double worldScale; ///< The scale factor world->screen
double flipX; ///< Flag for X axis flipping
double flipY; ///< Flag for Y axis flipping
double lineWidth; ///< The line width
bool isFillEnabled; ///< Is filling of graphic objects enabled ?
bool isStrokeEnabled; ///< Are the outlines stroked ?
COLOR4D fillColor; ///< The fill color
COLOR4D strokeColor; ///< The color of the outlines
double layerDepth; ///< The actual layer depth
VECTOR2D depthRange; ///< Range of the depth
// Grid settings
bool gridVisibility; ///< Should the grid be shown
GRID_STYLE gridStyle; ///< Grid display style
VECTOR2D gridSize; ///< The grid size
VECTOR2D gridOrigin; ///< The grid origin
VECTOR2D gridOffset; ///< The grid offset to compensate cursor position
COLOR4D gridColor; ///< Color of the grid
int gridTick; ///< Every tick line gets the double width
double gridLineWidth; ///< Line width of the grid
int gridDrawThreshold; ///< Minimum screen size of the grid (pixels)
///< below which the grid is not drawn
// Cursor settings
bool isCursorEnabled; ///< Is the cursor enabled?
COLOR4D cursorColor; ///< Cursor color
unsigned int cursorSize; ///< Size of the cursor in pixels
VECTOR2D cursorPosition; ///< Current cursor position (world coordinates)
/// Instance of object that stores information about how to draw texts
STROKE_FONT strokeFont;
/// Compute the scaling factor for the world->screen matrix
inline void ComputeWorldScale()
{
worldScale = screenDPI * worldUnitLength * zoomFactor;
}
/**
* @brief Draw a grid line (usually a simplified line function).
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) {};
/// Possible depth range
static const int MIN_DEPTH;
static const int MAX_DEPTH;
/// Depth level on which the grid is drawn
static const int GRID_DEPTH;
};
} // namespace KIGFX
#endif /* GRAPHICSABSTRACTIONLAYER_H_ */