Commit fffd3be6 authored by jean-pierre charras's avatar jean-pierre charras
Browse files

Fixed some issues with arcs (Arcs are a nightmare in graphic applications).

parent c5668298
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@
GERBER::GERBER( WinEDA_GerberFrame* aParent, int aLayer )
{
    m_Parent = aParent;
    m_Layer  = aLayer;           // Layer Number
    m_GraphicLayer  = aLayer;           // Graphic layer Number

    m_Selected_Tool = FIRST_DCODE;

@@ -157,6 +157,7 @@ void GERBER::ResetDefaultValues()
    m_FilesPtr        = 0;
    m_PolygonFillMode = false;
    m_PolygonFillModeState = 0;
    m_Selected_Tool = FIRST_DCODE;
}


+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ public:
    wxString           m_FileName;                                      // Full File Name for this layer
    wxString           m_ImageName;                                     // Image name, from IN <name>* command
    wxString           m_LayerName;                                     // Layer name, from LN <name>* command
    int                m_Layer;                                         // Layer Number
    int                m_GraphicLayer;                                  // Graphic layer Number
    bool               m_LayerNegative;                                 // true = Negative Layer
    bool               m_GerbMetric;                                    // false = Inches, true = metric
    bool               m_Relative;                                      // false = absolute Coord, true = relative Coord
+6 −0
Original line number Diff line number Diff line
@@ -352,6 +352,12 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode,
        break;

    case GBR_ARC:
#if 0     // for arc debug only
        GRLine( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
                    GetABPosition( m_ArcCentre ), 0, color );
        GRLine( &aPanel->m_ClipBox, aDC, GetABPosition( m_End ),
                    GetABPosition( m_ArcCentre ), 0, color );
#endif
        if( !isFilled )
        {
            GRArc1( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
+18 −0
Original line number Diff line number Diff line
G04 Draw a rectangle with a rounded right side
G04 Hand coded by Julian Lamb *
%MOIN*%
%FSLAX23Y23*%
%ADD10C,0.050*%

G04 Draw a rectangle with a rounded right side*
G36*
G01X0Y0D02*
X00200Y0D01*
G75*
G03X00200Y00200I0J00100D01*
G01X0Y00200D01*
G04 Do not close with a final line, so let gerbv automatically close*
G37*


M02*
+123 −107
Original line number Diff line number Diff line
@@ -3,12 +3,15 @@
/********************/

#include "fctsys.h"

//#include "polygons_defs.h"
#include "common.h"

//#include "confirm.h"
//#include "macros.h"
#include "gerbview.h"
#include "trigo.h"
#include "macros.h"
#include "class_gerber_draw_item.h"
#include "class_GERBER.h"

@@ -20,8 +23,8 @@
/* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes):
 * Gn =
 * G01 linear interpolation (right trace)
 * G02, G20, G21 Circular interpolation, meaning trig <0
 * G03, G30, G31 Circular interpolation, meaning trigo> 0
 * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
 * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
 * G04 = comment
 * G06 parabolic interpolation
 * G07 Cubic Interpolation
@@ -224,8 +227,8 @@ static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
 */
static void fillArcGBRITEM(  GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer,
                             const wxPoint& aStart, const wxPoint& aEnd,
                             const wxPoint& rel_center, int aWidth,
                             bool clockwise, bool multiquadrant,
                             const wxPoint& aRelCenter, int aWidth,
                             bool aClockwise, bool aMultiquadrant,
                             bool aLayerNegative,
                             bool aImageNegative  )
{
@@ -236,52 +239,75 @@ static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aL
    aGbrItem->m_Size.x  = aGbrItem->m_Size.y = aWidth;
    aGbrItem->m_Flashed = false;

    if( multiquadrant )
    {
        center.x = aStart.x + rel_center.x;
        center.y = aStart.y + rel_center.y;

        if( clockwise )
        {
            aGbrItem->m_Start = aStart;
            aGbrItem->m_End   = aEnd;
        }
    if( aMultiquadrant )
        center = aStart + aRelCenter;
    else
    {
            aGbrItem->m_Start = aEnd;
            aGbrItem->m_End   = aStart;
        }
    }
    else
    {
        center = rel_center;
        // in single quadrant mode the relative coordinate aRelCenter is always >= 0
        // So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
        center = aRelCenter;

        // calculate arc end coordinate relative to the staring point,
        // because center is relative to the center point
        delta  = aEnd - aStart;

        // now calculate the relative to aStart center position, for a draw function
        // that use trigonometric arc angle (or counter-clockwise)
        /* Quadrants:
         *    Y
         *  2 | 1
         * -------X
         *  3 | 4
         * C = actual relative arc center, S = arc start (axis origin) E = relative arc end
         */
        if( (delta.x >= 0) && (delta.y >= 0) )
        {
            // Quadrant 2
        /* Quadrant 1 (trigo or cclockwise):
         *  C | E
         * ---S---
         *  3 | 4
         */
            NEGATE( center.x);
        }
        else if( (delta.x >= 0) && (delta.y < 0) )
        {
            // Quadrant 1
            center.y = -center.y;
        /* Quadrant 4 (trigo or cclockwise):
         *  2 | C
         * ---S---
         *  3 | E
         */
        // Nothing to do
        }
        else if( (delta.x < 0) && (delta.y >= 0) )
        {
            // Quadrant 4
            center.x = -center.x;
        /* Quadrant 2 (trigo or cclockwise):
         *  E | 1
         * ---S---
         *  C | 4
         */
            NEGATE( center.x);
            NEGATE( center.y);
        }
        else
        {
            // Quadrant 3
            center.x = -center.x;
            center.y = -center.y;
        /* Quadrant 3 (trigo or cclockwise):
         *  2 | 1
         * ---S---
         *  E | C
         */
            NEGATE( center.y);
        }

        center.x += aStart.x;
        center.y += aStart.y;
        // Due to your draw arc function, we need this:
        if( !aClockwise )
            center = - center;

        if( clockwise )
        // Calculate actual arc center coordinate:
        center += aStart;
    }

    if( aClockwise )
    {
        aGbrItem->m_Start = aStart;
        aGbrItem->m_End   = aEnd;
@@ -291,11 +317,10 @@ static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aL
        aGbrItem->m_Start = aEnd;
        aGbrItem->m_End   = aStart;
    }
    }

    aGbrItem->m_DCode     = Dcode_index;
    aGbrItem->m_ArcCentre = center;

    aGbrItem->m_DCode     = Dcode_index;
    aGbrItem->m_LayerNegative = aLayerNegative;
    aGbrItem->m_ImageNegative = aImageNegative;

@@ -370,68 +395,51 @@ static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGbrItem,
                     aStart, aEnd, rel_center, 0,
                     clockwise, multiquadrant, aLayerNegative, aImageNegative );

    // dummyTrack has right geometric parameters, and has its Y coordinates negated (to match the pcbnew Y axis).
    // Approximate arc by 36 segments per 360 degree
    const int increment_angle = 360 / 36;

    wxPoint   center;
    center = dummyGbrItem.m_ArcCentre;

    // Calculate relative coordinates;
    // Calculate coordinates relative to arc center;
    wxPoint start = dummyGbrItem.m_Start - center;
    wxPoint end   = dummyGbrItem.m_End - center;

    /* Calculate angle arc
     * angle is here clockwise because Y axis is reversed
     * angles are in 0.1 deg
     * angle is trigonometrical (counter-clockwise),
     * and axis is the X,Y gerber coordinates
     */
    double start_angle = atan2( (double) start.y, (double) start.x );
    start_angle = 180 * start_angle / M_PI;
    double end_angle = atan2( (double) end.y, (double) end.x );
    end_angle = 180 * end_angle / M_PI;
    double angle = start_angle - end_angle;

//    D( printf( " >>>> st %d,%d angle %f, end %d,%d angle %f delta %f\n",
//        start.x, start.y, start_angle, end.x, end.y, end_angle, angle ) );
    if( !clockwise )
    {
        EXCHG( start, end );
        D( printf( " >>>> reverse arc\n" ) );
    }

    // Normalize angle
    while( angle > 360.0 )
        angle -= 360.0;

    while( angle < 0.0 )
        angle += 360.0;

    int count = (int) ( angle / increment_angle );
    if( count <= 0 )
        count = 1;

//    D( printf( " >>>> angle %f, cnt %d sens %d\n", angle, count, clockwise ) );
    int start_angle = wxRound(atan2( (double) start.y, (double) start.x ) * 1800 / M_PI);
    int end_angle = wxRound(atan2( (double) end.y, (double) end.x ) * 1800 / M_PI);

    // dummyTrack has right geometric parameters, but
    // fillArcGBRITEM calculate arc parameters for a draw function that expects
    // start_angle < end_angle. So ensure this is the case here:
    // Due to the fact atan2 returns angles between -180 to + 180 degrees,
    // this not always the case ( a modulo 360.0 degrees can be lost )
    if( start_angle > end_angle )
        end_angle += 3600;

    int arc_angle = start_angle - end_angle;
    // Approximate arc by 36 segments per 360 degree
    int increment_angle = 3600 / 36;
    int count = ABS( arc_angle / increment_angle );

    // calculate segments
    // calculate polygon corners
    // when not clockwise, dummyGbrItem arc goes from end to start
    wxPoint start_arc = start;
    for( int ii = 1; ii <= count; ii++ )
    for( int ii = 0; ii <= count; ii++ )
    {
        int rot;
        wxPoint end_arc = start;
        int     rot     = 10 * ii * increment_angle; // rot is in 0.1 deg
        if( ii < count )
        {
        if( clockwise )
                RotatePoint( &end_arc, rot );
            else
                RotatePoint( &end_arc, -rot );
        }
            rot = ii * increment_angle; // rot is in 0.1 deg
        else
            end_arc = end;
            rot = (count - ii) * increment_angle; // rot is in 0.1 deg

//        D( printf( " >> Add arc %d rot %d, edge poly item %d,%d to %d,%d\n",
//                ii, rot, start_arc.x, start_arc.y,end_arc.x, end_arc.y ); )
        if( ii < count )
                RotatePoint( &end_arc, -rot );
        else    // last point
            end_arc = clockwise ? end : start;

        if( aGbrItem->m_PolyCorners.size() == 0 )
            aGbrItem->m_PolyCorners.push_back( start_arc + center );
        aGbrItem->m_PolyCorners.push_back( end_arc + center );

        start_arc = end_arc;
@@ -472,6 +480,7 @@ wxPoint GERBER::ReadXYCoord( char*& Text )
            {
                if( *Text == '.' )
                    is_float = true;

                // count digits only (sign and decimal point are not counted)
                if( (*Text >= '0') && (*Text <='9') )
                    nbdigits++;
@@ -568,6 +577,7 @@ wxPoint GERBER::ReadIJCoord( char*& Text )
            {
                if( *Text == '.' )
                    is_float = true;

                // count digits only (sign and decimal point are not counted)
                if( (*Text >= '0') && (*Text <='9') )
                    nbdigits++;
@@ -737,7 +747,7 @@ bool GERBER::Execute_G_Command( char*& text, int G_commande )

    case GC_TURN_OFF_360_INTERPOL:      // disable Multi cadran arc and Arc interpol
        m_360Arc_enbl  = false;
        m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
        m_Iterpolation = GERB_INTERPOL_LINEAR_1X;   // not sure it should be done
        break;

    case GC_TURN_ON_360_INTERPOL:
@@ -865,6 +875,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
            case GERB_INTERPOL_ARC_NEG:
            case GERB_INTERPOL_ARC_POS:
                gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );

                //               D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
                //                          m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
                //                          m_CurrentPos.y, m_PolygonFillModeState,
@@ -877,6 +888,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int

            default:
                gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );

//                D( printf( "Add poly edge %d,%d to %d,%d fill %d\n",
//                           m_PreviousPos.x, m_PreviousPos.y,
//                           m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); )
@@ -931,6 +943,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
            case GERB_INTERPOL_LINEAR_1X:
                gbritem = new GERBER_DRAW_ITEM( pcb, this );
                pcb->m_Drawings.Append( gbritem );

//                D( printf( "Add line %d,%d to %d,%d\n",
//                           m_PreviousPos.x, m_PreviousPos.y,
//                            m_CurrentPos.x, m_CurrentPos.y ); )
@@ -948,6 +961,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
            case GERB_INTERPOL_ARC_POS:
                gbritem = new GERBER_DRAW_ITEM( pcb, this );
                pcb->m_Drawings.Append( gbritem );

//                D( printf( "Add arc %d,%d to %d,%d center %d, %d interpol %d 360_enb %d\n",
//                           m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
//                           m_CurrentPos.y, m_IJPos.x,
@@ -971,6 +985,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int

        case 2:     // code D2: exposure OFF (i.e. "move to")
            m_Exposure = false;

//            D( printf( "Move to %d,%d to %d,%d\n",
//                       m_PreviousPos.x, m_PreviousPos.y,
//                        m_CurrentPos.x, m_CurrentPos.y ); )
@@ -988,6 +1003,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int

            gbritem = new GERBER_DRAW_ITEM( pcb, this );
            pcb->m_Drawings.Append( gbritem );

//          D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer,
//                                m_CurrentPos.x, m_CurrentPos.y ); )
            fillFlashedGBRITEM( gbritem, aperture,
Loading