/**
 * Draw labelled ticks on a line. Ticks are spaced according to a
 * maximum density. Miror ticks are not labelled.
 *
 * @param aGal the GAL to draw on
 * @param aOrigin start of line to draw ticks on
 * @param aLine line vector
 * @param aMinorTickLen length of minor ticks in IU
 */
void drawTicksAlongLine( KIGFX::GAL& aGal, const VECTOR2D& aOrigin,
        const VECTOR2D& aLine, double aMinorTickLen )
{
    VECTOR2D tickLine = aLine.Rotate( -M_PI_2 );

    double tickSpace;
    TICK_FORMAT tickF = getTickFormatForScale( aGal.GetWorldScale(), tickSpace );

    // number of ticks in whole ruler
    int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace );

    // work out which way up the tick labels go
    double labelAngle = -tickLine.Angle();

    if( aLine.Angle() > 0 )
    {
        aGal.SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
    }
    else
    {
        aGal.SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
        labelAngle += M_PI;
    }

    // text and ticks are dimmed
    aGal.SetStrokeColor( PreviewOverlayDefaultColor().WithAlpha( PreviewOverlayDeemphAlpha( true ) ) );

    const auto labelOffset = tickLine.Resize( aMinorTickLen * ( majorTickLengthFactor + 1 ) );

    for( int i = 0; i < numTicks; ++i )
    {
        const auto tickPos = aOrigin + aLine.Resize( tickSpace * i );

        double length = aMinorTickLen;
        bool drawLabel = false;

        if( i % tickF.majorStep == 0)
        {
            drawLabel = true;
            length *= majorTickLengthFactor;
        }
        else if( tickF.midStep && i % tickF.midStep == 0 )
        {
            drawLabel = true;
            length *= midTickLengthFactor;
        }

        aGal.DrawLine( tickPos, tickPos + tickLine.Resize( length ) );

        if( drawLabel )
        {
            wxString label = DimensionLabel( "", tickSpace * i, g_UserUnit );

            // FIXME: spaces choke OpenGL lp:1668455
            label.erase( std::remove( label.begin(), label.end(), ' ' ), label.end() );

            aGal.BitmapText( label, tickPos + labelOffset, labelAngle );
        }
    }
}
Ejemplo n.º 2
0
SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide )
{
    SHAPE_LINE_CHAIN lc;

    if( aDir.EuclideanNorm( ) == 0.0f )
    {
        lc.Append( aP );
        return lc;
    }

    VECTOR2D dir_u( aDir );
    VECTOR2D dir_v( aDir.Perpendicular( ) );

    const int ArcSegments = Settings().m_cornerArcSegments;

    for( int i = ArcSegments - 1; i >= 0; i-- )
    {
        VECTOR2D p;
        double alpha = (double) i / (double) ( ArcSegments - 1 ) * M_PI / 2.0;
        p = aP + dir_u * cos( alpha ) + dir_v * ( aSide ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) );
        lc.Append( ( int ) p.x, ( int ) p.y );
    }

    return lc;
}
Ejemplo n.º 3
0
SHAPE_LINE_CHAIN PNS_MEANDER_SHAPE::circleQuad( VECTOR2D aP, VECTOR2D aDir, bool aSide )
{
    SHAPE_LINE_CHAIN lc;

    if( aDir.EuclideanNorm( ) == 0.0f )
    {
        lc.Append( aP );
        return lc;
    }

    VECTOR2D dir_u( aDir );
    VECTOR2D dir_v( aDir.Perpendicular( ) );

    const int ArcSegments = Settings().m_cornerArcSegments;

    double radius = (double) aDir.EuclideanNorm();
    double angleStep = M_PI / 2.0 / (double) ArcSegments;

    double correction = 12.0 * radius * ( 1.0 - cos( angleStep / 2.0 ) );

    if( !m_dual )
        correction = 0.0;
    else if( radius < m_meanCornerRadius )
        correction = 0.0;

    VECTOR2D p = aP;
    lc.Append( ( int ) p.x, ( int ) p.y );

    VECTOR2D dir_uu = dir_u.Resize( radius - correction );
    VECTOR2D dir_vv = dir_v.Resize( radius - correction );

    VECTOR2D shift = dir_u.Resize( correction );

    for( int i = ArcSegments - 1; i >= 0; i-- )
    {
        double alpha = (double) i / (double) ( ArcSegments - 1 ) * M_PI / 2.0;
        p = aP + shift + dir_uu * cos( alpha ) + dir_vv * ( aSide ? -1.0 : 1.0 ) * ( 1.0 - sin( alpha ) );
        lc.Append( ( int ) p.x, ( int ) p.y );
    }

    p = aP + dir_u + dir_v * ( aSide ? -1.0 : 1.0 );
    lc.Append( ( int ) p.x, ( int ) p.y );

    return lc;
}
/**
 * Draw simple ticks on the back of a line such that the line is
 * divided into n parts.
 *
 * @param aGal the GAL to draw on
 * @param aOrigin start of line to draw ticks on
 * @param aLine line vector
 * @param aTickLen length of ticks in IU
 * @param aNumDivisions number of parts to divide the line into
 */
void drawBacksideTicks( KIGFX::GAL& aGal, const VECTOR2D& aOrigin,
        const VECTOR2D& aLine, double aTickLen, int aNumDivisions )
{
    const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions;
    const auto backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen );

    for( int i = 0; i < aNumDivisions + 1; ++i )
    {
        const auto backTickPos = aOrigin + aLine.Resize( backTickSpace * i );
        aGal.DrawLine( backTickPos, backTickPos + backTickVec );
    }
}
Ejemplo n.º 5
0
void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
    /* Helper drawing:                   ____--- v3       ^
     *                           ____---- ...   \          \
     *                   ____----      ...       \   end    \
     *     v1    ____----           ...    ____----          \ width
     *       ----                ...___----        \          \
     *       \             ___...--                 \          v
     *        \    ____----...                ____---- v2
     *         ----     ...           ____----
     *  start   \    ...      ____----
     *           \... ____----
     *            ----
     *            v0
     * dots mark triangles' hypotenuses
     */

    VECTOR2D startEndVector = aEndPoint - aStartPoint;
    double   lineLength     = startEndVector.EuclideanNorm();

    if( lineLength <= 0.0 )
        return;

    double   scale          = 0.5 * lineWidth / lineLength;

    // The perpendicular vector also needs transformations
    glm::vec4 vector = currentManager->GetTransformation() *
                       glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 );

    // Line width is maintained by the vertex shader
    currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
    currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );    // v0

    currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
    currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );    // v1

    currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
    currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );        // v3

    currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
    currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );    // v0

    currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
    currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );        // v3

    currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
    currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );        // v2
}
Ejemplo n.º 6
0
void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
                              double aWidth )
{
    VECTOR2D startEndVector = aEndPoint - aStartPoint;
    double   lineAngle      = startEndVector.Angle();

    if( isFillEnabled )
    {
        // Filled tracks
        currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );

        SetLineWidth( aWidth );
        drawLineQuad( aStartPoint, aEndPoint );

        // Draw line caps
        drawFilledSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2 );
        drawFilledSemiCircle( aEndPoint,   aWidth / 2, lineAngle - M_PI / 2 );
    }
    else
    {
        // Outlined tracks
        double lineLength = startEndVector.EuclideanNorm();

        currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );

        Save();

        currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
        currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );

        drawLineQuad( VECTOR2D( 0.0,         aWidth / 2.0 ),
                      VECTOR2D( lineLength,  aWidth / 2.0 ) );

        drawLineQuad( VECTOR2D( 0.0,        -aWidth / 2.0 ),
                      VECTOR2D( lineLength, -aWidth / 2.0 ) );

        // Draw line caps
        drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 );
        drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 );

        Restore();
    }
}
static void drawCursorStrings( KIGFX::GAL& aGal, const VECTOR2D& aCursor,
    const VECTOR2D& aRulerVec )
{
    // draw the cursor labels
    std::vector<wxString> cursorStrings;

    cursorStrings.push_back( DimensionLabel( "r", aRulerVec.EuclideanNorm(), g_UserUnit ) );

    double degs = RAD2DECIDEG( -aRulerVec.Angle() );
    cursorStrings.push_back( DimensionLabel( "θ", degs, DEGREES ) );

    for( auto& str: cursorStrings )
    {
        // FIXME: remove spaces that choke OpenGL lp:1668455
        str.erase( std::remove( str.begin(), str.end(), ' ' ), str.end() );
    }

    auto temp = aRulerVec;
    DrawTextNextToCursor( aGal, aCursor, -temp, cursorStrings );
}
Ejemplo n.º 8
0
void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
                             double aWidth )
{
    if( isFillEnabled )
    {
        // Filled tracks mode
        SetLineWidth( aWidth );

        cairo_move_to( currentContext, (double) aStartPoint.x, (double) aStartPoint.y );
        cairo_line_to( currentContext, (double) aEndPoint.x, (double) aEndPoint.y );
    }
    else
    {
        // Outline mode for tracks
        VECTOR2D startEndVector = aEndPoint - aStartPoint;
        double   lineAngle      = atan2( startEndVector.y, startEndVector.x );
        double   lineLength     = startEndVector.EuclideanNorm();

        cairo_save( currentContext );

        cairo_translate( currentContext, aStartPoint.x, aStartPoint.y );
        cairo_rotate( currentContext, lineAngle );

        cairo_arc( currentContext, 0.0,        0.0, aWidth / 2.0,  M_PI / 2.0, 3.0 * M_PI / 2.0 );
        cairo_arc( currentContext, lineLength, 0.0, aWidth / 2.0, -M_PI / 2.0, M_PI / 2.0 );

        cairo_move_to( currentContext, 0.0,        aWidth / 2.0 );
        cairo_line_to( currentContext, lineLength, aWidth / 2.0 );

        cairo_move_to( currentContext, 0.0,        -aWidth / 2.0 );
        cairo_line_to( currentContext, lineLength, -aWidth / 2.0 );

        cairo_restore( currentContext );
    }

    isElementAdded = true;
}
Ejemplo n.º 9
0
void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
{
    VECTOR2D start( aTrack->GetStart() );
    VECTOR2D end( aTrack->GetEnd() );
    int      width = aTrack->GetWidth();

    if( m_pcbSettings.m_netNamesOnTracks && IsNetnameLayer( aLayer ) )
    {
        // If there is a net name - display it on the track
        if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED )
        {
            VECTOR2D line = ( end - start );
            double length = line.EuclideanNorm();

            // Check if the track is long enough to have a netname displayed
            if( length < 10 * width )
                return;

            const wxString& netName = aTrack->GetShortNetname();
            VECTOR2D textPosition = start + line / 2.0;     // center of the track
            double textOrientation = -atan( line.y / line.x );
            double textSize = std::min( static_cast<double>( width ), length / netName.length() );

            // Set a proper color for the label
            const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aTrack->GetLayer() );
            COLOR4D labelColor = m_pcbSettings.GetColor( NULL, aLayer );

            if( color.GetBrightness() > 0.5 )
                m_gal->SetStrokeColor( labelColor.Inverted() );
            else
                m_gal->SetStrokeColor( labelColor );

            m_gal->SetLineWidth( width / 10.0 );
            m_gal->SetBold( false );
            m_gal->SetItalic( false );
            m_gal->SetMirrored( false );
            m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) );
            m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
            m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
            m_gal->StrokeText( netName, textPosition, textOrientation );
        }
    }
    else if( IsCopperLayer( aLayer ) )
    {
        // Draw a regular track
        const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aLayer );
        m_gal->SetStrokeColor( color );
        m_gal->SetIsStroke( true );

        if( m_pcbSettings.m_sketchMode[TRACKS_VISIBLE] )
        {
            // Outline mode
            m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
            m_gal->SetIsFill( false );
        }
        else
        {
            // Filled mode
            m_gal->SetFillColor( color );
            m_gal->SetIsFill( true );
        }
        m_gal->DrawSegment( start, end, width );
    }
}
Ejemplo n.º 10
0
void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
{
    VECTOR2D start( aTrack->GetStart() );
    VECTOR2D end( aTrack->GetEnd() );
    int      width = aTrack->GetWidth();

    if( m_pcbSettings.m_netNamesOnTracks && IsNetnameLayer( aLayer ) )
    {
        // If there is a net name - display it on the track
        if( aTrack->GetNetCode() > NETINFO_LIST::UNCONNECTED )
        {
            VECTOR2D line = ( end - start );
            double length = line.EuclideanNorm();

            // Check if the track is long enough to have a netname displayed
            if( length < 10 * width )
                return;

            const wxString& netName = aTrack->GetShortNetname();
            VECTOR2D textPosition = start + line / 2.0;     // center of the track

            double textOrientation;

            if( end.y == start.y ) // horizontal
                textOrientation = 0;
            else if( end.x == start.x ) // vertical
                textOrientation = M_PI / 2;
            else
                textOrientation = -atan( line.y / line.x );

            double textSize = width;

            m_gal->SetIsStroke( true );
            m_gal->SetIsFill( false );
            m_gal->SetStrokeColor( m_pcbSettings.GetColor( NULL, aLayer ) );
            m_gal->SetLineWidth( width / 10.0 );
            m_gal->SetFontBold( false );
            m_gal->SetFontItalic( false );
            m_gal->SetTextMirrored( false );
            m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) );
            m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
            m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
            m_gal->BitmapText( netName, textPosition, textOrientation );
        }
    }
    else if( IsCopperLayer( aLayer ) )
    {
        // Draw a regular track
        const COLOR4D& color = m_pcbSettings.GetColor( aTrack, aLayer );
        bool outline_mode = m_pcbSettings.m_sketchMode[LAYER_TRACKS];
        m_gal->SetStrokeColor( color );
        m_gal->SetFillColor( color );
        m_gal->SetIsStroke( outline_mode );
        m_gal->SetIsFill( not outline_mode );
        m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );

        m_gal->DrawSegment( start, end, width );

        // Clearance lines
        constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING | PCB_RENDER_SETTINGS::CL_TRACKS;

        if( ( m_pcbSettings.m_clearance & clearanceFlags ) == clearanceFlags )
        {
            m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
            m_gal->SetIsFill( false );
            m_gal->SetIsStroke( true );
            m_gal->SetStrokeColor( color );
            m_gal->DrawSegment( start, end, width + aTrack->GetClearance() * 2 );
        }
    }
}