graphics_abstraction_layer.cpp 8.73 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * 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) 2012 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
 */

#include <wx/log.h>

#include <gal/graphics_abstraction_layer.h>
#include <gal/definitions.h>

32
using namespace KIGFX;
33

34 35 36 37

const double GAL::METRIC_UNIT_LENGTH = 1e9;


38
GAL::GAL() :
39
    strokeFont( this )
40 41 42 43 44 45
{
    // Set the default values for the internal variables
    SetIsFill( false );
    SetIsStroke( true );
    SetFillColor( COLOR4D( 0.0, 0.0, 0.0, 0.0 ) );
    SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
46
    SetLookAtPoint( VECTOR2D( 0, 0 ) );
47
    SetZoomFactor( 1.0 );
48 49
    SetWorldUnitLength( 1.0 / METRIC_UNIT_LENGTH * 2.54 );   // 1 inch in nanometers
    SetScreenDPI( 106 );                                     // Display resolution setting
50
    SetDepthRange( VECTOR2D( GAL::MIN_DEPTH, GAL::MAX_DEPTH ) );
51
    SetFlip( false, false );
52 53 54 55
    SetLineWidth( 1.0 );

    // Set grid defaults
    SetGridVisibility( true );
56
    SetGridStyle( GRID_STYLE_LINES );
57 58
    SetGridOriginMarkerSize( 15 );
    SetGridDrawThreshold( 10 );
59 60 61 62 63
    SetCoarseGrid( 10 );
    SetGridLineWidth( 0.5 );

    // Initialize the cursor shape
    SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
64 65
    SetCursorSize( 80 );
    SetCursorEnabled( false );
66 67

    strokeFont.LoadNewStrokeFont( newstroke_font, newstroke_font_bufsize );
68 69 70 71 72 73 74 75
}


GAL::~GAL()
{
}


76 77 78 79 80 81 82 83 84 85 86
void GAL::SetTextAttributes( const EDA_TEXT* aText )
{
    strokeFont.SetGlyphSize( VECTOR2D( aText->GetSize() ) );
    strokeFont.SetHorizontalJustify( aText->GetHorizJustify() );
    strokeFont.SetVerticalJustify( aText->GetVertJustify() );
    strokeFont.SetBold( aText->IsBold() );
    strokeFont.SetItalic( aText->IsItalic() );
    strokeFont.SetMirrored( aText->IsMirrored() );
}


Maciej Suminski's avatar
Maciej Suminski committed
87 88 89 90 91 92 93 94
void GAL::ComputeWorldScreenMatrix()
{
    ComputeWorldScale();

    worldScreenMatrix.SetIdentity();

    MATRIX3x3D translation;
    translation.SetIdentity();
95
    translation.SetTranslation( 0.5 * VECTOR2D( screenSize ) );
Maciej Suminski's avatar
Maciej Suminski committed
96 97 98 99 100 101 102

    MATRIX3x3D scale;
    scale.SetIdentity();
    scale.SetScale( VECTOR2D( worldScale, worldScale ) );

    MATRIX3x3D flip;
    flip.SetIdentity();
103
    flip.SetScale( VECTOR2D( flipX, flipY ) );
Maciej Suminski's avatar
Maciej Suminski committed
104 105 106 107 108 109

    MATRIX3x3D lookat;
    lookat.SetIdentity();
    lookat.SetTranslation( -lookAtPoint );

    worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
110
    screenWorldMatrix = worldScreenMatrix.Inverse();
Maciej Suminski's avatar
Maciej Suminski committed
111 112 113
}


114 115
void GAL::DrawGrid()
{
116 117 118
    if( !gridVisibility )
        return;

119 120
    SetTarget( TARGET_NONCACHED );

121
    // Draw the origin marker
122
    double originSize = gridOriginMarkerSize / worldScale;
123
    SetLayerDepth( GAL::GRID_DEPTH );
124 125 126 127
    SetIsFill( false );
    SetIsStroke( true );
    SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
    SetLineWidth( gridLineWidth / worldScale );
128 129 130 131 132
    DrawLine( gridOrigin + VECTOR2D( -originSize, -originSize ),
              gridOrigin + VECTOR2D( originSize, originSize ) );
    DrawLine( gridOrigin + VECTOR2D( -originSize, originSize ),
              gridOrigin + VECTOR2D( originSize, -originSize ) );
    DrawCircle( gridOrigin, originSize * 0.7 );
133 134

    // Draw the grid
135 136
    // For the drawing the start points, end points and increments have
    // to be calculated in world coordinates
137 138
    VECTOR2D worldStartPoint = screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
    VECTOR2D worldEndPoint   = screenWorldMatrix * VECTOR2D( screenSize );
139 140

    int gridScreenSizeDense  = round( gridSize.x * worldScale );
141
    int gridScreenSizeCoarse = round( gridSize.x * static_cast<double>( gridTick ) * worldScale );
142

143 144 145
    // Compute the line marker or point radius of the grid
    double marker = 2.0 * gridLineWidth / worldScale;
    double doubleMarker = 2.0 * marker;
146

147 148
    // Check if the grid would not be too dense
    if( std::max( gridScreenSizeDense, gridScreenSizeCoarse ) > gridDrawThreshold )
149
    {
150
        // Compute grid variables
151 152 153 154
        int gridStartX  = round( worldStartPoint.x / gridSize.x );
        int gridEndX    = round( worldEndPoint.x / gridSize.x );
        int gridStartY  = round( worldStartPoint.y / gridSize.y );
        int gridEndY    = round( worldEndPoint.y / gridSize.y );
155

156 157
        assert( gridEndX >= gridStartX );
        assert( gridEndY >= gridStartY );
158 159

        // Correct the index, else some lines are not correctly painted
160 161 162 163
        gridStartX -= abs( gridOrigin.x / gridSize.x ) + 1;
        gridStartY -= abs( gridOrigin.y / gridSize.y ) + 1;
        gridEndX += abs( gridOrigin.x / gridSize.x ) + 1;
        gridEndY += abs( gridOrigin.y / gridSize.y ) + 1;
164

165
        // Draw the grid behind all other layers
166 167
        SetLayerDepth( depthRange.y * 0.75 );

168
        if( gridStyle == GRID_STYLE_LINES )
169
        {
170 171 172 173 174
            SetIsFill( false );
            SetIsStroke( true );
            SetStrokeColor( gridColor );

            // Now draw the grid, every coarse grid line gets the double width
175 176

            // Vertical lines
177
            for( int j = gridStartY; j < gridEndY; j += 1 )
178
            {
179 180 181 182 183 184 185 186
                if( j % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
                    SetLineWidth( doubleMarker );
                else
                    SetLineWidth( marker );

                if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
                    || gridScreenSizeDense > gridDrawThreshold )
                {
187 188
                    drawGridLine( VECTOR2D( gridStartX * gridSize.x, j * gridSize.y + gridOrigin.y ),
                                  VECTOR2D( gridEndX * gridSize.x,   j * gridSize.y + gridOrigin.y ) );
189
                }
190 191
            }

192
            // Horizontal lines
193
            for( int i = gridStartX; i < gridEndX; i += 1 )
194
            {
195 196 197 198 199 200 201 202
                if( i % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
                    SetLineWidth( doubleMarker );
                else
                    SetLineWidth( marker );

                if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
                    || gridScreenSizeDense > gridDrawThreshold )
                {
203 204
                    drawGridLine( VECTOR2D( i * gridSize.x + gridOrigin.x, gridStartY * gridSize.y ),
                                  VECTOR2D( i * gridSize.x + gridOrigin.x, gridEndY * gridSize.y ) );
205
                }
206
            }
207
        }
208
        else    // Dotted grid
209
        {
210 211 212 213
            bool tickX, tickY;
            SetIsFill( true );
            SetIsStroke( false );
            SetFillColor( gridColor );
214

215
            for( int j = gridStartY; j < gridEndY; j += 1 )
216
            {
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
                if( j % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
                    tickY = true;
                else
                    tickY = false;

                for( int i = gridStartX; i < gridEndX; i += 1 )
                {
                    if( i % gridTick == 0 && gridScreenSizeDense > gridDrawThreshold )
                        tickX = true;
                    else
                        tickX = false;

                    if( tickX || tickY || gridScreenSizeDense > gridDrawThreshold )
                    {
                        double radius = ( tickX && tickY ) ? doubleMarker : marker;
232 233 234 235
                        DrawRectangle( VECTOR2D( i * gridSize.x - radius + gridOrigin.x,
                                                 j * gridSize.y - radius + gridOrigin.y ),
                                       VECTOR2D( i * gridSize.x + radius + gridOrigin.x,
                                                 j * gridSize.y + radius + gridOrigin.y ) );
236 237
                    }
                }
238
            }
239 240 241
        }
    }
}
Maciej Suminski's avatar
Maciej Suminski committed
242 243


244
VECTOR2D GAL::GetGridPoint( const VECTOR2D& aPoint ) const
Maciej Suminski's avatar
Maciej Suminski committed
245
{
246 247
    return VECTOR2D( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
                     round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
Maciej Suminski's avatar
Maciej Suminski committed
248
}