Exemple #1
0
bool LIB_ARC::Load( LINE_READER& aLineReader, wxString& aErrorMsg )
{
    int startx, starty, endx, endy, cnt;
    char tmp[256];
    char* line = (char*) aLineReader;

    cnt = sscanf( line + 2, "%d %d %d %d %d %d %d %d %s %d %d %d %d",
                  &m_Pos.x, &m_Pos.y, &m_Radius, &m_t1, &m_t2, &m_Unit,
                  &m_Convert, &m_Width, tmp, &startx, &starty, &endx, &endy );
    if( cnt < 8 )
    {
        aErrorMsg.Printf( _( "arc only had %d parameters of the required 8" ), cnt );
        return false;
    }

    if( tmp[0] == 'F' )
        m_Fill = FILLED_SHAPE;

    if( tmp[0] == 'f' )
        m_Fill = FILLED_WITH_BG_BODYCOLOR;

    NORMALIZE_ANGLE_POS( m_t1 );
    NORMALIZE_ANGLE_POS( m_t2 );

    // Actual Coordinates of arc ends are read from file
    if( cnt >= 13 )
    {
        m_ArcStart.x = startx;
        m_ArcStart.y = starty;
        m_ArcEnd.x   = endx;
        m_ArcEnd.y   = endy;
    }
    else
    {
        // Actual Coordinates of arc ends are not read from file
        // (old library), calculate them
        m_ArcStart.x = m_Radius;
        m_ArcStart.y = 0;
        m_ArcEnd.x   = m_Radius;
        m_ArcEnd.y   = 0;
        RotatePoint( &m_ArcStart.x, &m_ArcStart.y, -m_t1 );
        m_ArcStart.x += m_Pos.x;
        m_ArcStart.y += m_Pos.y;
        RotatePoint( &m_ArcEnd.x, &m_ArcEnd.y, -m_t2 );
        m_ArcEnd.x += m_Pos.x;
        m_ArcEnd.y += m_Pos.y;
    }

    return true;
}
void MODULE::SetOrientation( double newangle )
{
    double  angleChange = newangle - m_Orient;  // change in rotation

    NORMALIZE_ANGLE_POS( newangle );

    m_Orient = newangle;

    for( D_PAD* pad = m_Pads;  pad;  pad = pad->Next() )
    {
        pad->SetOrientation( pad->GetOrientation() + angleChange );
        pad->SetDrawCoord();
    }

    // Update of the reference and value.
    m_Reference->SetDrawCoord();
    m_Value->SetDrawCoord();

    // Displace contours and text of the footprint.
    for( BOARD_ITEM* item = m_Drawings;  item;  item = item->Next() )
    {
        if( item->Type() == PCB_MODULE_EDGE_T )
        {
            static_cast<EDGE_MODULE*>( item )->SetDrawCoord();
        }
        else if( item->Type() == PCB_MODULE_TEXT_T )
        {
            static_cast<TEXTE_MODULE*>( item )->SetDrawCoord();
        }
    }

    CalculateBoundingBox();
}
/* Creates the footprint shape list.
 * Since module shape is customizable after the placement we cannot share them;
 * instead we opt for the one-module-one-shape-one-component-one-device approach
 */
static void CreateShapesSection( FILE* aFile, BOARD* aPcb )
{
    MODULE*     module;
    D_PAD*      pad;
    const char* layer;
    wxString    pinname;
    const char* mirror = "0";

    fputs( "$SHAPES\n", aFile );

    const LSET all_cu = LSET::AllCuMask();

    for( module = aPcb->m_Modules; module; module = module->Next() )
    {
        FootprintWriteShape( aFile, module );

        for( pad = module->Pads(); pad; pad = pad->Next() )
        {
            /* Funny thing: GenCAD requires the pad side even if you use
             *  padstacks (which are theorically optional but gerbtools
             *requires* them). Now the trouble thing is that 'BOTTOM'
             *  is interpreted by someone as a padstack flip even
             *  if the spec explicitly says it's not... */
            layer = "ALL";

            if( ( pad->GetLayerSet() & all_cu ) == LSET( B_Cu ) )
            {
                layer = module->GetFlag() ? "TOP" : "BOTTOM";
            }
            else if( ( pad->GetLayerSet() & all_cu ) == LSET( F_Cu ) )
            {
                layer = module->GetFlag() ? "BOTTOM" : "TOP";
            }

            pad->StringPadName( pinname );

            if( pinname.IsEmpty() )
                pinname = wxT( "none" );

            double orient = pad->GetOrientation() - module->GetOrientation();
            NORMALIZE_ANGLE_POS( orient );

            // Bottom side modules use the flipped padstack
            fprintf( aFile, (module->GetFlag()) ?
                     "PIN %s PAD%dF %g %g %s %g %s\n" :
                     "PIN %s PAD%d %g %g %s %g %s\n",
                     TO_UTF8( pinname ), pad->GetSubRatsnest(),
                     pad->GetPos0().x / SCALE_FACTOR,
                     -pad->GetPos0().y / SCALE_FACTOR,
                     layer, orient / 10.0, mirror );
        }
    }

    fputs( "$ENDSHAPES\n\n", aFile );
}
const double DRAWSEGMENT::GetArcAngleStart() const
{
    // due to the Y axis orient atan2 needs - y value
    double angleStart = ArcTangente( GetArcStart().y - GetCenter().y,
                                     GetArcStart().x - GetCenter().x );

    // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg
    // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg.
    // and this is not easy to handle in calculations
    NORMALIZE_ANGLE_POS( angleStart );

    return angleStart;
}
/* Return text rotation for drawings and plotting
 */
double TEXTE_MODULE::GetDrawRotation() const
{
    MODULE* module = (MODULE*) m_Parent;
    double  rotation = m_Orient;

    if( module )
        rotation += module->GetOrientation();

    NORMALIZE_ANGLE_POS( rotation );

    // For angle = 0 .. 180 deg
    while( rotation > 900 )
        rotation -= 1800;

    return rotation;
}
void MODULE::Flip( const wxPoint& aCentre )
{
    // Move module to its final position:
    wxPoint finalPos = m_Pos;

    finalPos.y  = aCentre.y - ( finalPos.y - aCentre.y );     /// Mirror the Y position

    SetPosition( finalPos );

    // Flip layer
    SetLayer( FlipLayer( GetLayer() ) );

    // Reverse mirror orientation.
    NEGATE( m_Orient );
    NORMALIZE_ANGLE_POS( m_Orient );

    // Mirror pads to other side of board about the x axis, i.e. vertically.
    for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
        pad->Flip( m_Pos );

    // Mirror reference.
    m_Reference->FlipWithModule( m_Pos.y );

    // Mirror value.
    m_Value->FlipWithModule( m_Pos.y );

    // Reverse mirror module graphics and texts.
    for( EDA_ITEM* item = m_Drawings; item; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
            ( (EDGE_MODULE*) item )->Flip( m_Pos );
            break;

        case PCB_MODULE_TEXT_T:
            static_cast<TEXTE_MODULE*>( item )->FlipWithModule( m_Pos.y );
            break;

        default:
            wxMessageBox( wxT( "MODULE::Flip() error: Unknown Draw Type" ) );
            break;
        }
    }

    CalculateBoundingBox();
}
/* Fills all routing matrix cells contained in the arc
 * angle = ArcAngle, half-width lg
 * center = ux0,uy0, starting at ux1, uy1.  Coordinates are in
 * PCB units.
 */
void TraceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg,
               LAYER_NUM layer, int color, int op_logic )
{
    int radius, nb_segm;
    int x0, y0,             // Starting point of the current segment trace
        x1, y1;             // End point
    int ii;
    double angle, StAngle;


    radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) );

    x0 = ux1 - ux0;
    y0 = uy1 - uy0;
    StAngle = ArcTangente( uy1 - uy0, ux1 - ux0 );

    if( lg < 1 )
        lg = 1;

    nb_segm = ( 2 * radius ) / lg;
    nb_segm = ( nb_segm * std::abs( ArcAngle ) ) / 3600;

    if( nb_segm < 5 )
        nb_segm = 5;

    if( nb_segm > 100 )
        nb_segm = 100;

    for( ii = 1; ii <= nb_segm; ii++ )
    {
        angle  = ( ArcAngle * ii ) / nb_segm;
        angle += StAngle;

        NORMALIZE_ANGLE_POS( angle );

        x1 = KiROUND( cosdecideg( radius, angle ) );
        y1 = KiROUND( cosdecideg( radius, angle ) );
        DrawSegmentQcq( x0 + ux0, y0 + uy0, x1 + ux0, y1 + uy0, lg, layer, color, op_logic );
        x0 = x1;
        y0 = y1;
    }
}
void MODULE::SetOrientation( double newangle )
{
    double  angleChange = newangle - m_Orient;  // change in rotation
    wxPoint pt;

    NORMALIZE_ANGLE_POS( newangle );

    m_Orient = newangle;

    for( D_PAD* pad = m_Pads;  pad;  pad = pad->Next() )
    {
        pt = pad->GetPos0();

        pad->SetOrientation( pad->GetOrientation() + angleChange );

        RotatePoint( &pt, m_Orient );

        pad->SetPosition( GetPosition() + pt );
    }

    // Update of the reference and value.
    m_Reference->SetDrawCoord();
    m_Value->SetDrawCoord();

    // Displace contours and text of the footprint.
    for( BOARD_ITEM* item = m_Drawings;  item;  item = item->Next() )
    {
        if( item->Type() == PCB_MODULE_EDGE_T )
        {
            EDGE_MODULE* edge = (EDGE_MODULE*) item;
            edge->SetDrawCoord();
        }

        else if( item->Type() == PCB_MODULE_TEXT_T )
        {
            TEXTE_MODULE* text = (TEXTE_MODULE*) item;
            text->SetDrawCoord();
        }
    }

    CalculateBoundingBox();
}
void RotatePoint( double* pX, double* pY, double angle )
{
    double tmp;

    NORMALIZE_ANGLE_POS( angle );

    // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
    if( angle == 0 )
        return;

    if( angle == 900 )          /* sin = 1, cos = 0 */
    {
        tmp = *pX;
        *pX = *pY;
        *pY = -tmp;
    }
    else if( angle == 1800 )    /* sin = 0, cos = -1 */
    {
        *pX = -*pX;
        *pY = -*pY;
    }
    else if( angle == 2700 )    /* sin = -1, cos = 0 */
    {
        tmp = *pX;
        *pX = -*pY;
        *pY = tmp;
    }
    else
    {
        double fangle = DECIDEG2RAD( angle );
        double sinus = sin( fangle );
        double cosinus = cos( fangle );

        double fpx = (*pY * sinus ) + (*pX * cosinus );
        double fpy = (*pY * cosinus ) - (*pX * sinus );
        *pX = fpx;
        *pY = fpy;
    }
}
double TEXTE_MODULE::GetDrawRotation() const
{
    MODULE* module = (MODULE*) m_Parent;
    double  rotation = GetTextAngle();

    if( module )
        rotation += module->GetOrientation();

    if( m_unlocked )
    {
        NORMALIZE_ANGLE_POS( rotation );
    }
    else
    {
        // Keep angle between -90 .. 90 deg. Otherwise the text is not easy to read
        while( rotation > 900 )
            rotation -= 1800;

        while( rotation < -900 )
            rotation += 1800;
    }

    return rotation;
}
/* test DRC between 2 pads.
 * this function can be also used to test DRC between a pad and a hole,
 * because a hole is like a round or oval pad.
 */
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
    int     dist;
    double pad_angle;

    // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad
    int     dist_min = aRefPad->GetClearance( aPad );

    // relativePadPos is the aPad shape position relative to the aRefPad shape position
    wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();

    dist = KiROUND( EuclideanNorm( relativePadPos ) );

    // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
    if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min )
        return true;

    /* Here, pads are near and DRC depend on the pad shapes
     * We must compare distance using a fine shape analysis
     * Because a circle or oval shape is the easier shape to test, try to have
     * aRefPad shape type = PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
     * if aRefPad = TRAP. and aPad = RECT, also swap pads
     * Swap aRefPad and aPad if needed
     */
    bool swap_pads;
    swap_pads = false;

    // swap pads to make comparisons easier
    // Note also a ROUNDRECT pad with a corner radius = r can be considered as
    // a smaller RECT (size - 2*r) with a clearance increased by r
    // priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
    if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE )
    {
        // pad ref shape is here oval, rect, roundrect, trapezoid or custom
        switch( aPad->GetShape() )
        {
            case PAD_SHAPE_CIRCLE:
                swap_pads = true;
                break;

            case PAD_SHAPE_OVAL:
                swap_pads = true;
                break;

            case PAD_SHAPE_RECT:
            case PAD_SHAPE_ROUNDRECT:
                if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
                    swap_pads = true;
                break;

            default:
                break;
        }
    }

    if( swap_pads )
    {
        std::swap( aRefPad, aPad );
        relativePadPos = -relativePadPos;
    }

    // corners of aRefPad (used only for rect/roundrect/trap pad)
    wxPoint polyref[4];
    // corners of aRefPad (used only for custom pad)
    SHAPE_POLY_SET polysetref;

    // corners of aPad (used only for rect/roundrect/trap pad)
    wxPoint polycompare[4];
    // corners of aPad (used only custom pad)
    SHAPE_POLY_SET polysetcompare;

    /* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL,
     * if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
     * Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID,
     * aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID
     */
    bool diag = true;

    switch( aRefPad->GetShape() )
    {
    case PAD_SHAPE_CIRCLE:

        /* One can use checkClearanceSegmToPad to test clearance
         * aRefPad is like a track segment with a null length and a witdth = GetSize().x
         */
        m_segmLength = 0;
        m_segmAngle  = 0;

        m_segmEnd.x = m_segmEnd.y = 0;

        m_padToTestPos = relativePadPos;
        diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
        break;

    case PAD_SHAPE_TRAPEZOID:
    case PAD_SHAPE_ROUNDRECT:
    case PAD_SHAPE_RECT:
        // pad_angle = pad orient relative to the aRefPad orient
        pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
        NORMALIZE_ANGLE_POS( pad_angle );

        if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
        {
            int padRadius = aRefPad->GetRoundRectCornerRadius();
            dist_min += padRadius;
            GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
                                aRefPad->GetSize(), aRefPad->GetOrientation() );
        }
        else
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );

        switch( aPad->GetShape() )
        {
        case PAD_SHAPE_ROUNDRECT:
        case PAD_SHAPE_RECT:
        case PAD_SHAPE_TRAPEZOID:
            if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
            {
                int padRadius = aPad->GetRoundRectCornerRadius();
                dist_min += padRadius;
                GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
                                    aPad->GetSize(), aPad->GetOrientation() );
            }
            else
            {
                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

                // Move aPad shape to relativePadPos
                for( int ii = 0; ii < 4; ii++ )
                    polycompare[ii] += relativePadPos;
            }

            // And now test polygons:
            if( polysetref.OutlineCount() )
            {
                const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
                // And now test polygons:
                if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
                            polycompare, 4, dist_min ) )
                    diag = false;
            }
            else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) )
                diag = false;
            break;

        default:
            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
            break;
        }
        break;

    case PAD_SHAPE_OVAL:     /* an oval pad is like a track segment */
    {
        /* Create a track segment with same dimensions as the oval aRefPad
         * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
         */
        int segm_width;
        m_segmAngle = aRefPad->GetOrientation();                // Segment orient.

        if( aRefPad->GetSize().y < aRefPad->GetSize().x )     // Build an horizontal equiv segment
        {
            segm_width   = aRefPad->GetSize().y;
            m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y;
        }
        else        // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
        {
            segm_width   = aRefPad->GetSize().x;
            m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x;
            m_segmAngle += 900;
        }

        /* the start point must be 0,0 and currently relativePadPos
         * is relative the center of pad coordinate */
        wxPoint segstart;
        segstart.x = -m_segmLength / 2;                 // Start point coordinate of the horizontal equivalent segment

        RotatePoint( &segstart, m_segmAngle );          // actual start point coordinate of the equivalent segment
        // Calculate segment end position relative to the segment origin
        m_segmEnd.x = -2 * segstart.x;
        m_segmEnd.y = -2 * segstart.y;

        // Recalculate the equivalent segment angle in 0,1 degrees
        // to prepare a call to checkClearanceSegmToPad()
        m_segmAngle = ArcTangente( m_segmEnd.y, m_segmEnd.x );

        // move pad position relative to the segment origin
        m_padToTestPos = relativePadPos - segstart;

        // Use segment to pad check to test the second pad:
        diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
        break;
    }

    default:
        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
        break;
    }

    return diag;
}
bool DRAWSEGMENT::HitTest( const wxPoint& aPosition )
{
    switch( m_Shape )
    {
    case S_CIRCLE:
    case S_ARC:
        {
            wxPoint relPos = aPosition - GetCenter();
            int radius = GetRadius();
            int dist   = KiROUND( EuclideanNorm( relPos ) );

            if( abs( radius - dist ) <= ( m_Width / 2 ) )
            {
                if( m_Shape == S_CIRCLE )
                    return true;

                // For arcs, the test point angle must be >= arc angle start
                // and <= arc angle end
                // However angle values > 360 deg are not easy to handle
                // so we calculate the relative angle between arc start point and teast point
                // this relative arc should be < arc angle if arc angle > 0 (CW arc)
                // and > arc angle if arc angle < 0 (CCW arc)
                double arc_angle_start = GetArcAngleStart();    // Always 0.0 ... 360 deg, in 0.1 deg

                double arc_hittest = ArcTangente( relPos.y, relPos.x );

                // Calculate relative angle between the starting point of the arc, and the test point
                arc_hittest -= arc_angle_start;

                // Normalise arc_hittest between 0 ... 360 deg
                NORMALIZE_ANGLE_POS( arc_hittest );

                // Check angle: inside the arc angle when it is > 0
                // and outside the not drawn arc when it is < 0
                if( GetAngle() >= 0.0 )
                {
                    if( arc_hittest <= GetAngle() )
                        return true;
                }
                else
                {
                    if( arc_hittest >= (3600.0 + GetAngle()) )
                        return true;
                }
            }
        }
        break;

    case S_CURVE:
        for( unsigned int i= 1; i < m_BezierPoints.size(); i++)
        {
            if( TestSegmentHit( aPosition, m_BezierPoints[i-1], m_BezierPoints[i-1], m_Width / 2 ) )
                return true;
        }
        break;

    case S_SEGMENT:
        if( TestSegmentHit( aPosition, m_Start, m_End, m_Width / 2 ) )
            return true;
        break;

    default:
        wxASSERT( 0 );
        break;
    }
    return false;
}
/* test DRC between 2 pads.
 * this function can be also used to test DRC between a pas and a hole,
 * because a hole is like a round pad.
 */
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
    int     dist;

    double  pad_angle;

    // Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
    int     dist_min = aRefPad->GetClearance( aPad );

    // relativePadPos is the aPad shape position relative to the aRefPad shape position
    wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();

    dist = KiROUND( EuclideanNorm( relativePadPos ) );

    // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
    if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min )
        return true;

    /* Here, pads are near and DRC depend on the pad shapes
     * We must compare distance using a fine shape analysis
     * Because a circle or oval shape is the easier shape to test, try to have
     * aRefPad shape type = PAD_CIRCLE or PAD_OVAL.
     * if aRefPad = TRAP. and aPad = RECT, also swap pads
     * Swap aRefPad and aPad if needed
     */
    bool swap_pads;
    swap_pads = false;

    // swap pads to make comparisons easier
    // priority is aRefPad = ROUND then OVAL then RECT then other
    if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
    {
        // pad ref shape is here oval, rect or trapezoid
        switch( aPad->GetShape() )
        {
            case PAD_CIRCLE:
                swap_pads = true;
                break;

            case PAD_OVAL:
                swap_pads = true;
                break;

            case PAD_RECT:
                if( aRefPad->GetShape() != PAD_OVAL )
                    swap_pads = true;
                break;

            default:
                break;
        }
    }

    if( swap_pads )
    {
        EXCHG( aRefPad, aPad );
        relativePadPos = -relativePadPos;
    }

    /* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
     * if one of the 2 pads was a PAD_CIRCLE or PAD_OVAL.
     * Therefore, if aRefPad is a PAD_RECT or a PAD_TRAPEZOID,
     * aPad is also a PAD_RECT or a PAD_TRAPEZOID
     */
    bool diag = true;

    switch( aRefPad->GetShape() )
    {
    case PAD_CIRCLE:

        /* One can use checkClearanceSegmToPad to test clearance
         * aRefPad is like a track segment with a null length and a witdth = GetSize().x
         */
        m_segmLength = 0;
        m_segmAngle  = 0;

        m_segmEnd.x = m_segmEnd.y = 0;

        m_padToTestPos = relativePadPos;
        diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
        break;

    case PAD_RECT:
        // pad_angle = pad orient relative to the aRefPad orient
        pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
        NORMALIZE_ANGLE_POS( pad_angle );

        if( aPad->GetShape() == PAD_RECT )
        {
            wxSize size = aPad->GetSize();

            // The trivial case is if both rects are rotated by multiple of 90 deg
            // Most of time this is the case, and the test is fast
            if( ( (aRefPad->GetOrientation() == 0) || (aRefPad->GetOrientation() == 900)
                 || (aRefPad->GetOrientation() == 1800) || (aRefPad->GetOrientation() == 2700) )
               && ( (aPad->GetOrientation() == 0) || (aPad->GetOrientation() == 900) || (aPad->GetOrientation() == 1800)
                   || (aPad->GetOrientation() == 2700) ) )
            {
                if( (pad_angle == 900) || (pad_angle == 2700) )
                {
                    EXCHG( size.x, size.y );
                }

                // Test DRC:
                diag = false;
                RotatePoint( &relativePadPos, aRefPad->GetOrientation() );
                relativePadPos.x = std::abs( relativePadPos.x );
                relativePadPos.y = std::abs( relativePadPos.y );

                if( ( relativePadPos.x - ( (size.x + aRefPad->GetSize().x) / 2 ) ) >= dist_min )
                    diag = true;

                if( ( relativePadPos.y - ( (size.y + aRefPad->GetSize().y) / 2 ) ) >= dist_min )
                    diag = true;
            }
            else    // at least one pad has any other orient. Test is more tricky
            {   // Use the trapezoid2trapezoidDRC which also compare 2 rectangles with any orientation
                wxPoint polyref[4];         // Shape of aRefPad
                wxPoint polycompare[4];     // Shape of aPad
                aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
                aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

                // Move aPad shape to relativePadPos
                for( int ii = 0; ii < 4; ii++ )
                    polycompare[ii] += relativePadPos;

                // And now test polygons:
                if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                    diag = false;
            }
        }
        else if( aPad->GetShape() == PAD_TRAPEZOID )
        {
            wxPoint polyref[4];         // Shape of aRefPad
            wxPoint polycompare[4];     // Shape of aPad
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
            aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

            // Move aPad shape to relativePadPos
            for( int ii = 0; ii < 4; ii++ )
                polycompare[ii] += relativePadPos;

            // And now test polygons:
            if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                diag = false;
        }
        else
        {
            // Should not occur, because aPad and aRefPad are swapped
            // to have only aPad shape RECT or TRAP and aRefPad shape TRAP or RECT.
            wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad ref RECT @ %d, %d to pad shape %d @ %d, %d"),
                aRefPad->GetPosition().x, aRefPad->GetPosition().y,
                aPad->GetShape(), aPad->GetPosition().x, aPad->GetPosition().y );
        }
        break;

    case PAD_OVAL:     /* an oval pad is like a track segment */
    {
        /* Create a track segment with same dimensions as the oval aRefPad
         * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
         */
        int segm_width;
        m_segmAngle = aRefPad->GetOrientation();                // Segment orient.

        if( aRefPad->GetSize().y < aRefPad->GetSize().x )     // Build an horizontal equiv segment
        {
            segm_width   = aRefPad->GetSize().y;
            m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y;
        }
        else        // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
        {
            segm_width   = aRefPad->GetSize().x;
            m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x;
            m_segmAngle += 900;
        }

        /* the start point must be 0,0 and currently relativePadPos
         * is relative the center of pad coordinate */
        wxPoint segstart;
        segstart.x = -m_segmLength / 2;                 // Start point coordinate of the horizontal equivalent segment

        RotatePoint( &segstart, m_segmAngle );          // actual start point coordinate of the equivalent segment
        // Calculate segment end position relative to the segment origin
        m_segmEnd.x = -2 * segstart.x;
        m_segmEnd.y = -2 * segstart.y;

        // Recalculate the equivalent segment angle in 0,1 degrees
        // to prepare a call to checkClearanceSegmToPad()
        m_segmAngle = ArcTangente( m_segmEnd.y, m_segmEnd.x );

        // move pad position relative to the segment origin
        m_padToTestPos = relativePadPos - segstart;

        // Use segment to pad check to test the second pad:
        diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
        break;
    }

    case PAD_TRAPEZOID:

        // at this point, aPad is also a trapezoid, because all other shapes
        // have priority, and are already tested
        wxASSERT( aPad->GetShape() == PAD_TRAPEZOID );
        {
            wxPoint polyref[4];         // Shape of aRefPad
            wxPoint polycompare[4];     // Shape of aPad
            aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
            aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );

            // Move aPad shape to relativePadPos
            for( int ii = 0; ii < 4; ii++ )
                polycompare[ii] += relativePadPos;

            // And now test polygons:
            if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
                diag = false;
        }
        break;

    default:
        wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
        break;
    }

    return diag;
}
void MODULE::Flip( const wxPoint& aCentre )
{
    TEXTE_MODULE* text;

    // Move module to its final position:
    wxPoint finalPos = m_Pos;

    finalPos.y  = aCentre.y - ( finalPos.y - aCentre.y );     /// Mirror the Y position

    SetPosition( finalPos );

    // Flip layer
    SetLayer( FlipLayer( GetLayer() ) );

    // Reverse mirror orientation.
    NEGATE( m_Orient );
    NORMALIZE_ANGLE_POS( m_Orient );

    // Mirror pads to other side of board about the x axis, i.e. vertically.
    for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
        pad->Flip( m_Pos );

    // Mirror reference.
    text = m_Reference;
    text->m_Pos.y -= m_Pos.y;
    NEGATE( text->m_Pos.y );
    text->m_Pos.y += m_Pos.y;
    NEGATE(text->m_Pos0.y);
    NEGATE_AND_NORMALIZE_ANGLE_POS( text->m_Orient );
    text->SetLayer( FlipLayer( text->GetLayer() ) );
    text->m_Mirror = IsBackLayer( GetLayer() );

    // Mirror value.
    text = m_Value;
    text->m_Pos.y -= m_Pos.y;
    NEGATE( text->m_Pos.y );
    text->m_Pos.y += m_Pos.y;
    NEGATE( text->m_Pos0.y );
    NEGATE_AND_NORMALIZE_ANGLE_POS( text->m_Orient );
    text->SetLayer( FlipLayer( text->GetLayer() ) );
    text->m_Mirror = IsBackLayer( GetLayer() );

    // Reverse mirror module graphics and texts.
    for( EDA_ITEM* item = m_Drawings; item; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
            {
                EDGE_MODULE* em = (EDGE_MODULE*) item;

                wxPoint s = em->GetStart();
                s.y -= m_Pos.y;
                s.y  = -s.y;
                s.y += m_Pos.y;
                em->SetStart( s );

                wxPoint e = em->GetEnd();
                e.y -= m_Pos.y;
                e.y  = -e.y;
                e.y += m_Pos.y;
                em->SetEnd( e );

                NEGATE( em->m_Start0.y );
                NEGATE( em->m_End0.y );

                if( em->GetShape() == S_ARC )
                {
                    em->SetAngle( -em->GetAngle() );
                }

                em->SetLayer( FlipLayer( em->GetLayer() ) );
            }
            break;

        case PCB_MODULE_TEXT_T:
            text = (TEXTE_MODULE*) item;
            text->m_Pos.y -= m_Pos.y;
            NEGATE( text->m_Pos.y );
            text->m_Pos.y += m_Pos.y;
            NEGATE( text->m_Pos0.y );
            NEGATE_AND_NORMALIZE_ANGLE_POS( text->m_Orient );
            text->SetLayer( FlipLayer( text->GetLayer() ) );
            text->m_Mirror = IsBackLayer( GetLayer() );
            break;

        default:
            wxMessageBox( wxT( "MODULE::Flip() error: Unknown Draw Type" ) );
            break;
        }
    }

    CalculateBoundingBox();
}
void DIMENSION::AdjustDimensionDetails( bool aDoNotChangeText )
{
    const int   arrowz = Mils2iu( 50 );             // size of arrows
    int         ii;
    int         measure, deltax, deltay;            // value of the measure on X and Y axes
    int         arrow_up_X  = 0, arrow_up_Y = 0;    // coordinates of arrow line /
    int         arrow_dw_X  = 0, arrow_dw_Y = 0;    // coordinates of arrow line '\'
    int         hx, hy;                             // dimension line interval
    double      angle, angle_f;
    wxString    msg;

    // Init layer :
    m_Text.SetLayer( GetLayer() );

    // calculate the size of the dimension (text + line above the text)
    ii = m_Text.GetSize().y + m_Text.GetThickness() + (m_Width * 3);

    deltax  = m_featureLineDO.x - m_featureLineGO.x;
    deltay  = m_featureLineDO.y - m_featureLineGO.y;

    // Calculate dimension value
    measure = KiROUND( hypot( deltax, deltay ) );

    angle = atan2( (double)deltay, (double)deltax );

    // Calculation of parameters X and Y dimensions of the arrows and lines.
    hx = hy = ii;

    // Taking into account the slope of the side lines.
    if( measure )
    {
        hx  = abs( KiROUND( ( (double) deltay * hx ) / measure ) );
        hy  = abs( KiROUND( ( (double) deltax * hy ) / measure ) );

        if( m_featureLineGO.x > m_crossBarO.x )
            hx = -hx;

        if( m_featureLineGO.x == m_crossBarO.x )
            hx = 0;

        if( m_featureLineGO.y > m_crossBarO.y )
            hy = -hy;

        if( m_featureLineGO.y == m_crossBarO.y )
            hy = 0;

        angle_f     = angle + DEG2RAD( 27.5 );
        arrow_up_X  = wxRound( arrowz * cos( angle_f ) );
        arrow_up_Y  = wxRound( arrowz * sin( angle_f ) );
        angle_f     = angle - DEG2RAD( 27.5 );
        arrow_dw_X  = wxRound( arrowz * cos( angle_f ) );
        arrow_dw_Y  = wxRound( arrowz * sin( angle_f ) );
    }

    int dx = KiROUND( m_Height * cos( angle + M_PI / 2 ) );
    int dy = KiROUND( m_Height * sin( angle + M_PI / 2 ) );
    m_crossBarO.x   = m_featureLineGO.x + dx;
    m_crossBarO.y   = m_featureLineGO.y + dy;
    m_crossBarF.x   = m_featureLineDO.x + dx;
    m_crossBarF.y   = m_featureLineDO.y + dy;

    m_arrowG1F.x    = m_crossBarO.x + arrow_up_X;
    m_arrowG1F.y    = m_crossBarO.y + arrow_up_Y;

    m_arrowG2F.x    = m_crossBarO.x + arrow_dw_X;
    m_arrowG2F.y    = m_crossBarO.y + arrow_dw_Y;

    /* The right arrow is symmetrical to the left.
     *  / = -\  and  \ = -/
     */
    m_arrowD1F.x    = m_crossBarF.x - arrow_dw_X;
    m_arrowD1F.y    = m_crossBarF.y - arrow_dw_Y;

    m_arrowD2F.x    = m_crossBarF.x - arrow_up_X;
    m_arrowD2F.y    = m_crossBarF.y - arrow_up_Y;

    m_featureLineGF.x   = m_crossBarO.x + hx;
    m_featureLineGF.y   = m_crossBarO.y + hy;

    m_featureLineDF.x   = m_crossBarF.x + hx;
    m_featureLineDF.y   = m_crossBarF.y + hy;

    // Calculate the better text position and orientation:
    wxPoint textPos;
    textPos.x  = (m_crossBarF.x + m_featureLineGF.x) / 2;
    textPos.y  = (m_crossBarF.y + m_featureLineGF.y) / 2;
    m_Text.SetTextPosition( textPos );

    double newAngle = -RAD2DECIDEG( angle );

    NORMALIZE_ANGLE_POS( newAngle );

    if( newAngle > 900  &&  newAngle < 2700 )
        newAngle -= 1800;

    m_Text.SetOrientation( newAngle );

    if( !aDoNotChangeText )
    {
        m_Value = measure;
        msg     = ::CoordinateToString( m_Value );
        SetText( msg );
    }
}
void D_PAD::SetOrientation( double aAngle )
{
    NORMALIZE_ANGLE_POS( aAngle );
    m_Orient = aAngle;
}
void WinEDA_BasePcbFrame::Change_Side_Module(MODULE * Module, wxDC * DC)
/**********************************************************************/

/* Change de cote un composant : il y a inversion MIROIR autour de l'axe X
	Le changement n'est fait que si la couche est
		- CUIVRE ou CMP
		Si DC == NULL, il n'y a pas de redessin du composant et du chevelu
*/
{
D_PAD* pt_pad ;
TEXTE_MODULE* pt_texte;
EDGE_MODULE * pt_edgmod ;
EDA_BaseStruct * PtStruct;

	if ( Module == NULL ) return;
	if( (Module->m_Layer != CMP_N) && (Module->m_Layer != CUIVRE_N) ) return;

	m_CurrentScreen->SetModify();

	if ( ! (Module->m_Flags & IS_MOVED) )
		{
		m_Pcb->m_Status_Pcb &= ~( LISTE_CHEVELU_OK | CONNEXION_OK);
		if ( DC ) Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_XOR);

		/* Effacement chevelu general si necessaire */
		if ( DC && g_Show_Ratsnest) DrawGeneralRatsnest(DC);
		/* Init des variables utilisees dans la routine Dessine_Drag_segment() */
		g_Offset_Module.x = 0;
		g_Offset_Module.y = 0;
		}

	else	// Module en deplacement
		{
		/* efface empreinte ( vue en contours) si elle a ete deja dessinee */
		if ( DC )
			{
			DrawModuleOutlines(DrawPanel, DC, Module);
			Dessine_Segments_Dragges(DrawPanel, DC);
			}
		}

	/* mise a jour du Flag de l'empreinte et des couches des contours et textes */
	Module->m_Layer = ChangeSideNumLayer(Module->m_Layer);

	/* Inversion miroir de l'orientation */
	Module->m_Orient = - Module->m_Orient;
	NORMALIZE_ANGLE_POS(Module->m_Orient);

	/* Inversion miroir + layers des pastilles */
	pt_pad = Module->m_Pads;
	for ( ; pt_pad != NULL; pt_pad = (D_PAD*) pt_pad->Pnext )
		{
		pt_pad->m_Pos.y -= Module->m_Pos.y ;
		pt_pad->m_Pos.y = -pt_pad->m_Pos.y;
		pt_pad->m_Pos.y += Module->m_Pos.y;
		pt_pad->m_Pos0.y = - pt_pad->m_Pos0.y;
		pt_pad->m_Offset.y = -pt_pad->m_Offset.y;
		pt_pad->m_DeltaSize.y = -pt_pad->m_DeltaSize.y;
		NEGATE_AND_NORMALIZE_ANGLE_POS(pt_pad->m_Orient);
		/* change cote pour pastilles surfaciques */
		pt_pad->m_Masque_Layer = ChangeSideMaskLayer(pt_pad->m_Masque_Layer);
		}

	/* Inversion miroir de la Reference et mise en miroir : */
	pt_texte = Module->m_Reference;
	pt_texte->m_Pos.y -= Module->m_Pos.y;
	pt_texte->m_Pos.y = -pt_texte->m_Pos.y;
	pt_texte->m_Pos.y += Module->m_Pos.y;
	pt_texte->m_Pos0.y = pt_texte->m_Pos0.y;
	pt_texte->m_Miroir = 1 ;
	NEGATE_AND_NORMALIZE_ANGLE_POS(pt_texte->m_Orient);
	pt_texte->m_Layer = Module->m_Layer;
	pt_texte->m_Layer = ChangeSideNumLayer(pt_texte->m_Layer);
	if( Module->m_Layer == CUIVRE_N) pt_texte->m_Layer = SILKSCREEN_N_CU;
	if( Module->m_Layer == CMP_N) pt_texte->m_Layer = SILKSCREEN_N_CMP;
	if( (Module->m_Layer == SILKSCREEN_N_CU) ||
			(Module->m_Layer == ADHESIVE_N_CU) || (Module->m_Layer == CUIVRE_N) )
			 pt_texte->m_Miroir = 0 ;

	/* Inversion miroir de la Valeur et mise en miroir : */
	pt_texte = Module->m_Value;
	pt_texte->m_Pos.y -= Module->m_Pos.y;
	pt_texte->m_Pos.y = -pt_texte->m_Pos.y;
	pt_texte->m_Pos.y += Module->m_Pos.y;
	pt_texte->m_Pos0.y = pt_texte->m_Pos0.y;
	pt_texte->m_Miroir = 1 ;
	NEGATE_AND_NORMALIZE_ANGLE_POS(pt_texte->m_Orient);
	pt_texte->m_Layer = Module->m_Layer;
	pt_texte->m_Layer = ChangeSideNumLayer(pt_texte->m_Layer);
	if( Module->m_Layer == CUIVRE_N) pt_texte->m_Layer = SILKSCREEN_N_CU;
	if( Module->m_Layer == CMP_N) pt_texte->m_Layer = SILKSCREEN_N_CMP;
	if( (Module->m_Layer == SILKSCREEN_N_CU) ||
		(Module->m_Layer == ADHESIVE_N_CU) || (Module->m_Layer == CUIVRE_N) )
		 pt_texte->m_Miroir = 0 ;

	/* Inversion miroir des dessins de l'empreinte : */
	PtStruct = Module->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext)
		{
		switch( PtStruct->m_StructType)
			{
			case TYPEEDGEMODULE:
				pt_edgmod = (EDGE_MODULE *) PtStruct;
				pt_edgmod->m_Start.y -= Module->m_Pos.y;
				pt_edgmod->m_Start.y = -pt_edgmod->m_Start.y ;
				pt_edgmod->m_Start.y += Module->m_Pos.y;
				pt_edgmod->m_End.y -= Module->m_Pos.y;
				pt_edgmod->m_End.y = -pt_edgmod->m_End.y ;
				pt_edgmod->m_End.y += Module->m_Pos.y;
				/* inversion des coords locales */
				pt_edgmod->m_Start0.y = -pt_edgmod->m_Start0.y;
				pt_edgmod->m_End0.y = -pt_edgmod->m_End0.y;
				if ( pt_edgmod->m_Shape == S_ARC )
				{
					pt_edgmod->m_Angle = - pt_edgmod->m_Angle;
				}

				pt_edgmod->m_Layer = ChangeSideNumLayer(pt_edgmod->m_Layer);
				break;

			case TYPETEXTEMODULE:
				/* Inversion miroir de la position et mise en miroir : */
				pt_texte = (TEXTE_MODULE*)PtStruct;
				pt_texte->m_Pos.y -= Module->m_Pos.y;
				pt_texte->m_Pos.y = -pt_texte->m_Pos.y;
				pt_texte->m_Pos.y += Module->m_Pos.y;
				pt_texte->m_Pos0.y = pt_texte->m_Pos0.y;
				pt_texte->m_Miroir = 1 ;
				NEGATE_AND_NORMALIZE_ANGLE_POS(pt_texte->m_Orient);

				pt_texte->m_Layer = Module->m_Layer;
				pt_texte->m_Layer = ChangeSideNumLayer(pt_texte->m_Layer);
				if( Module->m_Layer == CUIVRE_N) pt_texte->m_Layer = SILKSCREEN_N_CU;
				if(Module->m_Layer == CMP_N) pt_texte->m_Layer = SILKSCREEN_N_CMP;
				if((Module->m_Layer == SILKSCREEN_N_CU) ||
				   (Module->m_Layer == ADHESIVE_N_CU) || (Module->m_Layer == CUIVRE_N))
					 pt_texte->m_Miroir = 0 ;

				break;

			default: DisplayError(this, wxT("Unknown Draw Type")); break;

			}
		}

	/* calcul du rectangle d'encadrement */
	Module->Set_Rectangle_Encadrement();

	Module->Display_Infos(this);

	if( !(Module->m_Flags & IS_MOVED) ) /* Inversion simple */
	{
		if ( DC )
		{
			Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR);
			/* affichage chevelu general si necessaire */
			ReCompile_Ratsnest_After_Changes( DC );
		}
	}

	else
	{
		if ( DC )
		{
			DrawModuleOutlines(DrawPanel, DC, Module);
			Dessine_Segments_Dragges(DrawPanel, DC);
		}
		m_Pcb->m_Status_Pcb &= ~CHEVELU_LOCAL_OK;
	}
}