void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::OnOkClick( wxCommandEvent& event )
/*******************************************************************/
/* Copy values in text control to the item parameters
*/
{
    LAYER_NUM layer = m_LayerSelectionCtrl->GetLayerSelection();

    if( IsCopperLayer( layer ) )
    {
        /* an edge is put on a copper layer: this it is very dangerous. a
         * confirmation is requested */
        if( !IsOK( NULL,
                   _( "The graphic item will be on a copper layer. This is very dangerous. Are you sure?" ) ) )
            return;
    }

    m_parent->SaveCopyInUndoList( m_module, UR_MODEDIT );
    m_module->SetLastEditTime();

    wxString msg;

    wxPoint coord;

    msg = m_Center_StartXCtrl->GetValue();
    coord.x = ValueFromString( g_UserUnit, msg );
    msg = m_Center_StartYCtrl->GetValue();
    coord.y = ValueFromString( g_UserUnit, msg );
    m_item->SetStart( coord );
    m_item->SetStart0( coord );

    msg = m_EndX_Radius_Ctrl->GetValue();
    coord.x = ValueFromString( g_UserUnit, msg );
    msg = m_EndY_Ctrl->GetValue();
    coord.y = ValueFromString( g_UserUnit, msg );
    m_item->SetEnd( coord );
    m_item->SetEnd0( coord );

    msg = m_ThicknessCtrl->GetValue();
    m_item->SetWidth( ValueFromString( g_UserUnit, msg ) );

    msg = m_DefaultThicknessCtrl->GetValue();
    int thickness = ValueFromString( g_UserUnit, msg );
    m_brdSettings.m_ModuleSegmentWidth = thickness;
    m_parent->SetDesignSettings( m_brdSettings );

    m_item->SetLayer( layer );

    if( m_item->GetShape() == S_ARC )
    {
        double angle;
        m_Angle_Ctrl->GetValue().ToDouble( &angle );
        NORMALIZE_ANGLE_360(angle);
        m_item->SetAngle( angle );
    }

    m_parent->OnModify();
    m_parent->SetMsgPanel( m_item );

    Close( true );
}
bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::TransferDataFromWindow()
{
    if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() )
        return false;

    LAYER_NUM layer = m_LayerSelectionCtrl->GetLayerSelection();

    if( IsCopperLayer( layer ) )
    {
        /* an edge is put on a copper layer: this it is very dangerous. a
         * confirmation is requested */
        if( !IsOK( NULL,
                   _( "The graphic item will be on a copper layer. This is very dangerous. Are you sure?" ) ) )
            return false;;
    }

    m_parent->SaveCopyInUndoList( m_module, UR_MODEDIT );
    m_module->SetLastEditTime();

    wxString msg;

    wxPoint coord;

    msg = m_Center_StartXCtrl->GetValue();
    coord.x = ValueFromString( g_UserUnit, msg );
    msg = m_Center_StartYCtrl->GetValue();
    coord.y = ValueFromString( g_UserUnit, msg );
    m_item->SetStart( coord );
    m_item->SetStart0( coord );

    msg = m_EndX_Radius_Ctrl->GetValue();
    coord.x = ValueFromString( g_UserUnit, msg );
    msg = m_EndY_Ctrl->GetValue();
    coord.y = ValueFromString( g_UserUnit, msg );
    m_item->SetEnd( coord );
    m_item->SetEnd0( coord );

    msg = m_ThicknessCtrl->GetValue();
    m_item->SetWidth( ValueFromString( g_UserUnit, msg ) );

    msg = m_DefaultThicknessCtrl->GetValue();
    int thickness = ValueFromString( g_UserUnit, msg );
    m_brdSettings.m_ModuleSegmentWidth = thickness;
    m_parent->SetDesignSettings( m_brdSettings );

    m_item->SetLayer( ToLAYER_ID( layer ) );

    if( m_item->GetShape() == S_ARC )
    {
        m_item->SetAngle( m_AngleValue * 10.0 );
    }

    m_parent->OnModify();
    m_parent->SetMsgPanel( m_item );

    return true;
}
Example #3
0
/**
 * Function PlaceCells
 * Initialize the matrix routing by setting obstacles for each occupied cell
 * a cell set to HOLE is an obstacle for tracks and vias
 * a cell set to VIA_IMPOSSIBLE is an obstacle for vias only.
 * a cell set to CELL_is_EDGE is a frontier.
 * Tracks and vias having the same net code as net_code are skipped
 * (htey do not are obstacles)
 *
 * For single-sided Routing 1:
 * BOTTOM side is used, and Route_Layer_BOTTOM = Route_Layer_TOP
 *
 * If flag == FORCE_PADS: all pads will be put in matrix as obstacles.
 */
void PlaceCells( BOARD* aPcb, int net_code, int flag )
{
    int       ux0 = 0, uy0 = 0, ux1, uy1, dx, dy;
    int       marge, via_marge;
    LAYER_MSK layerMask;

    // use the default NETCLASS?
    NETCLASS* nc = aPcb->m_NetClasses.GetDefault();

    int       trackWidth = nc->GetTrackWidth();
    int       clearance  = nc->GetClearance();
    int       viaSize    = nc->GetViaDiameter();

    marge     = clearance + (trackWidth / 2);
    via_marge = clearance + (viaSize / 2);

    // Place PADS on matrix routing:
    for( unsigned i = 0; i < aPcb->GetPadCount(); ++i )
    {
        D_PAD* pad = aPcb->GetPad( i );

        if( net_code != pad->GetNet() || (flag & FORCE_PADS) )
        {
            ::PlacePad( pad, HOLE, marge, WRITE_CELL );
        }

        ::PlacePad( pad, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
    }

    // Place outlines of modules on matrix routing, if they are on a copper layer
    // or on the edge layer
    TRACK tmpSegm( NULL );  // A dummy track used to create segments.

    for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
    {
        for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() )
        {
            switch( item->Type() )
            {
            case PCB_MODULE_EDGE_T:
            {
                EDGE_MODULE* edge = (EDGE_MODULE*) item;

                tmpSegm.SetLayer( edge->GetLayer() );

                if( tmpSegm.GetLayer() == EDGE_N )
                    tmpSegm.SetLayer( UNDEFINED_LAYER );

                tmpSegm.SetStart( edge->GetStart() );
                tmpSegm.SetEnd(   edge->GetEnd() );
                tmpSegm.SetShape( edge->GetShape() );
                tmpSegm.SetWidth( edge->GetWidth() );
                tmpSegm.m_Param = edge->GetAngle();
                tmpSegm.SetNet( -1 );

                TraceSegmentPcb( &tmpSegm, HOLE, marge, WRITE_CELL );
                TraceSegmentPcb( &tmpSegm, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
            }
            break;

            default:
                break;
            }
        }
    }

    // Place board outlines and texts on copper layers:
    for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_LINE_T:
        {
            DRAWSEGMENT* DrawSegm;

            int          type_cell = HOLE;
            DrawSegm = (DRAWSEGMENT*) item;
            tmpSegm.SetLayer( DrawSegm->GetLayer() );

            if( DrawSegm->GetLayer() == EDGE_N )
            {
                tmpSegm.SetLayer( UNDEFINED_LAYER );
                type_cell |= CELL_is_EDGE;
            }

            tmpSegm.SetStart( DrawSegm->GetStart() );
            tmpSegm.SetEnd(   DrawSegm->GetEnd() );
            tmpSegm.SetShape( DrawSegm->GetShape() );
            tmpSegm.SetWidth( DrawSegm->GetWidth() );
            tmpSegm.m_Param = DrawSegm->GetAngle();
            tmpSegm.SetNet( -1 );

            TraceSegmentPcb( &tmpSegm, type_cell, marge, WRITE_CELL );
        }
        break;

        case PCB_TEXT_T:
        {
            TEXTE_PCB* PtText;
            PtText = (TEXTE_PCB*) item;

            if( PtText->GetText().Length() == 0 )
                break;

            EDA_RECT textbox = PtText->GetTextBox( -1 );
            ux0 = textbox.GetX();
            uy0 = textbox.GetY();
            dx  = textbox.GetWidth();
            dy  = textbox.GetHeight();

            /* Put bounding box (rectangle) on matrix */
            dx /= 2;
            dy /= 2;

            ux1 = ux0 + dx;
            uy1 = uy0 + dy;

            ux0 -= dx;
            uy0 -= dy;

            layerMask = GetLayerMask( PtText->GetLayer() );

            TraceFilledRectangle( ux0 - marge, uy0 - marge, ux1 + marge,
                                  uy1 + marge, PtText->GetOrientation(),
                                  layerMask, HOLE, WRITE_CELL );

            TraceFilledRectangle( ux0 - via_marge, uy0 - via_marge,
                                  ux1 + via_marge, uy1 + via_marge,
                                  PtText->GetOrientation(),
                                  layerMask, VIA_IMPOSSIBLE, WRITE_OR_CELL );
        }
        break;

        default:
            break;
        }
    }

    /* Put tracks and vias on matrix */
    for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
    {
        if( net_code == track->GetNet() )
            continue;

        TraceSegmentPcb( track, HOLE, marge, WRITE_CELL );
        TraceSegmentPcb( track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
    }
}
bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::Validate()
{
    wxArrayString error_msgs;

    if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::Validate() )
        return false;

    // Load the start and end points -- all types use these in the checks.
    int startx = ValueFromString( g_UserUnit, m_Center_StartXCtrl->GetValue() );
    int starty = ValueFromString( g_UserUnit, m_Center_StartYCtrl->GetValue() );
    int endx   = ValueFromString( g_UserUnit, m_EndX_Radius_Ctrl->GetValue() );
    int endy   = ValueFromString( g_UserUnit, m_EndY_Ctrl->GetValue() );

    // Type specific checks.
    switch( m_item->GetShape() )
    {
    case S_ARC:
        // Check angle of arc.
        double angle;
        m_AngleCtrl->GetValue().ToDouble( &angle );
        NORMALIZE_ANGLE_360( angle );

        if( angle == 0 )
        {
            error_msgs.Add( _( "The arc angle must be greater than zero." ) );
        }

        // Fall through.
    case S_CIRCLE:

        // Check radius.
        if( (startx == endx) && (starty == endy) )
            error_msgs.Add( _( "The radius must be greater than zero." ) );

        break;

    default:

        // Check start and end are not the same.
        if( (startx == endx) && (starty == endy) )
            error_msgs.Add( _( "The start and end points cannot be the same." ) );

        break;
    }

    // Check the item thickness.
    int thickness = ValueFromString( g_UserUnit, m_ThicknessCtrl->GetValue() );

    if( thickness <= 0 )
        error_msgs.Add( _( "The item thickness must be greater than zero." ) );

    // And the default thickness.
    thickness = ValueFromString( g_UserUnit, m_DefaultThicknessCtrl->GetValue() );

    if( thickness <= 0 )
        error_msgs.Add( _( "The default thickness must be greater than zero." ) );

    if( error_msgs.GetCount() )
    {
        HTML_MESSAGE_BOX dlg( this, _( "Error list" ) );
        dlg.ListSet( error_msgs );
        dlg.ShowModal();
    }

    return error_msgs.GetCount() == 0;
}
bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::TransferDataToWindow()
{
    // Set unit symbol
    wxStaticText* texts_unit[] =
    {
        m_StartPointXUnit,
        m_StartPointYUnit,
        m_EndPointXUnit,
        m_EndPointYUnit,
        m_ThicknessTextUnit,
        m_DefaulThicknessTextUnit,
    };

    for( size_t ii = 0; ii < DIM( texts_unit ); ii++ )
    {
        texts_unit[ii]->SetLabel( GetAbbreviatedUnitsLabel() );
    }

    wxString msg;

    // Change texts according to the segment shape:
    switch( m_item->GetShape() )
    {
    case S_CIRCLE:
        SetTitle( _( "Circle Properties" ) );
        m_StartPointXLabel->SetLabel( _( "Center X" ) );
        m_StartPointYLabel->SetLabel( _( "Center Y" ) );
        m_EndPointXLabel->SetLabel( _( "Point X" ) );
        m_EndPointYLabel->SetLabel( _( "Point Y" ) );
        m_AngleText->Show( false );
        m_AngleCtrl->Show( false );
        m_AngleUnit->Show( false );
        break;

    case S_ARC:
        SetTitle( _( "Arc Properties" ) );
        m_StartPointXLabel->SetLabel( _( "Center X" ) );
        m_StartPointYLabel->SetLabel( _( "Center Y" ) );
        m_EndPointXLabel->SetLabel( _( "Start Point X" ) );
        m_EndPointYLabel->SetLabel( _( "Start Point Y" ) );

        m_AngleValue = m_item->GetAngle() / 10.0;
        break;

    case S_SEGMENT:
        SetTitle( _( "Line Segment Properties" ) );

        // Fall through.
    default:
        m_AngleText->Show( false );
        m_AngleCtrl->Show( false );
        m_AngleUnit->Show( false );
        break;
    }

    PutValueInLocalUnits( *m_Center_StartXCtrl, m_item->GetStart().x );

    PutValueInLocalUnits( *m_Center_StartYCtrl, m_item->GetStart().y );

    PutValueInLocalUnits( *m_EndX_Radius_Ctrl, m_item->GetEnd().x );

    PutValueInLocalUnits( *m_EndY_Ctrl, m_item->GetEnd().y );

    PutValueInLocalUnits( *m_ThicknessCtrl, m_item->GetWidth() );

    PutValueInLocalUnits( *m_DefaultThicknessCtrl, m_brdSettings.m_ModuleSegmentWidth );

    // Configure the layers list selector
    m_LayerSelectionCtrl->SetLayersHotkeys( false );
    m_LayerSelectionCtrl->SetLayerSet( LSET::InternalCuMask().set( Edge_Cuts ) );
    m_LayerSelectionCtrl->SetBoardFrame( m_parent );
    m_LayerSelectionCtrl->Resync();

    if( m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ) < 0 )
    {
        wxMessageBox( _( "This item was on an unknown layer.\n"
                         "It has been moved to the front silk screen layer. Please fix it." ) );
        m_LayerSelectionCtrl->SetLayerSelection( F_SilkS );
    }

    return DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataToWindow();
}
void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::initDlg()
/* Initialize messages and values in text control,
 * according to the item parameters values
*/
{
    SetFocus();
    m_StandardButtonsSizerOK->SetDefault();

    // Set unit symbol
    wxStaticText * texts_unit[] =
    {
        m_StartPointXUnit,
        m_StartPointYUnit,
        m_EndPointXUnit,
        m_EndPointYUnit,
        m_ThicknessTextUnit,
        m_DefaulThicknessTextUnit,
        NULL
    };

    for( int ii = 0; ; ii++ )
    {
        if( texts_unit[ii] == NULL )
            break;
        texts_unit[ii]->SetLabel( GetAbbreviatedUnitsLabel() );
    }

    wxString msg;

    // Change texts according to the segment shape:
    switch ( m_item->GetShape() )
    {
    case S_CIRCLE:
        m_StartPointXLabel->SetLabel(_("Center X"));
        m_StartPointYLabel->SetLabel(_("Center Y"));
        m_EndPointXLabel->SetLabel(_("Point X"));
        m_EndPointYLabel->SetLabel(_("Point Y"));
        m_Angle_Text->Show(false);
        m_Angle_Ctrl->Show(false);
        m_AngleUnit->Show(false);
        break;

    case S_ARC:
        m_StartPointXLabel->SetLabel(_("Center X"));
        m_StartPointYLabel->SetLabel(_("Center Y"));
        m_EndPointXLabel->SetLabel(_("Start Point X"));
        m_EndPointYLabel->SetLabel(_("Start Point Y"));

        // Here the angle is a double, but the UI is still working
        // with integers
        msg << int( m_item->GetAngle() );
        m_Angle_Ctrl->SetValue(msg);
        break;

    default:
        m_Angle_Text->Show(false);
        m_Angle_Ctrl->Show(false);
        m_AngleUnit->Show(false);
        break;
    }

    PutValueInLocalUnits( *m_Center_StartXCtrl, m_item->GetStart().x );

    PutValueInLocalUnits( *m_Center_StartYCtrl, m_item->GetStart().y );

    PutValueInLocalUnits( *m_EndX_Radius_Ctrl, m_item->GetEnd().x );

    PutValueInLocalUnits( *m_EndY_Ctrl, m_item->GetEnd().y );

    PutValueInLocalUnits( *m_ThicknessCtrl, m_item->GetWidth() );

    PutValueInLocalUnits( *m_DefaultThicknessCtrl, m_brdSettings.m_ModuleSegmentWidth );

    // Configure the layers list selector
    m_LayerSelectionCtrl->SetLayersHotkeys( false );
    m_LayerSelectionCtrl->SetLayerMask( INTERNAL_CU_LAYERS|EDGE_LAYER );
    m_LayerSelectionCtrl->SetBoardFrame( m_parent );
    m_LayerSelectionCtrl->Resync();
    if( m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ) < 0 )
    {
        wxMessageBox( _("This item has an illegal layer id.\n"
                        "Now, forced on the front silk screen layer. Please, fix it") );
        m_LayerSelectionCtrl->SetLayerSelection( SILKSCREEN_N_FRONT );
    }
}
/* generate shapes of graphic items (outlines) on layer aLayer as polygons,
 * and adds these polygons to aCornerBuffer
 * aCornerBuffer = the buffer to store polygons
 * aInflateValue = a value to inflate shapes
 * aCircleToSegmentsCount = number of segments to approximate a circle
 * aCorrectionFactor = the correction to apply to the circle radius
 *  to generate the polygon.
 *  if aCorrectionFactor = 1.0, the polygon is inside the circle
 *  the radius of circle approximated by segments is
 *  initial radius * aCorrectionFactor
 */
void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
                        LAYER_NUM aLayer,
                        CPOLYGONS_LIST& aCornerBuffer,
                        int                    aInflateValue,
                        int                    aCircleToSegmentsCount,
                        double                 aCorrectionFactor )
{
    std::vector<TEXTE_MODULE *> texts;  // List of TEXTE_MODULE to convert
    EDGE_MODULE* outline;

    for( EDA_ITEM* item = GraphicalItems(); item != NULL; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
            if( ((TEXTE_MODULE*)item)->GetLayer() == aLayer )
                texts.push_back( (TEXTE_MODULE *) item );
            break;

        case PCB_MODULE_EDGE_T:
            outline = (EDGE_MODULE*) item;
            if( outline->GetLayer() != aLayer )
                break;

            switch( outline->GetShape() )
            {
            case S_SEGMENT:
                TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
                                           outline->GetStart(),
                                           outline->GetEnd(),
                                           aCircleToSegmentsCount,
                                           outline->GetWidth() );
                break;

            case S_CIRCLE:
                TransformRingToPolygon( aCornerBuffer, outline->GetCenter(),
                                outline->GetRadius(), aCircleToSegmentsCount,
                                outline->GetWidth() );
                break;

            case S_ARC:
                TransformArcToPolygon( aCornerBuffer,
                            outline->GetCenter(), outline->GetArcStart(),
                            outline->GetAngle(),
                            aCircleToSegmentsCount, outline->GetWidth() );
                break;

            case S_POLYGON:
                // for outline shape = S_POLYGON:
                // We must compute true coordinates from m_PolyPoints
                // which are relative to module position and module orientation = 0
                for( unsigned ii = 0; ii < outline->GetPolyPoints().size(); ii++ )
                {
                    CPolyPt corner( outline->GetPolyPoints()[ii] );
                    RotatePoint( &corner.x, &corner.y, GetOrientation() );
                    corner.x += GetPosition().x;
                    corner.y += GetPosition().y;
                    aCornerBuffer.Append( corner );
                }
                aCornerBuffer.CloseLastContour();
                break;

            default:
                DBG( printf( "Error: Shape %d not implemented!\n",
                        outline->GetShape() ); )
                break;
            }
                break;

            default:
                break;
        }
    }
/* Creates the shape of a footprint (section SHAPE)
 *  The shape is always given "normal" (Orient 0, not mirrored)
 * It's almost guaranteed that the silk layer will be imported wrong but
 * the shape also contains the pads!
 */
static void FootprintWriteShape( FILE* aFile, MODULE* module )
{
    EDGE_MODULE* PtEdge;
    EDA_ITEM*    PtStruct;

    // Control Y axis change sign for flipped modules
    int          Yaxis_sign = -1;

    // Flip for bottom side components
    if( module->GetFlag() )
        Yaxis_sign = 1;

    /* creates header: */
    fprintf( aFile, "\nSHAPE %s\n", TO_UTF8( module->GetReference() ) );

    if( module->GetAttributes() & MOD_VIRTUAL )
    {
        fprintf( aFile, "INSERT SMD\n" );
    }
    else
    {
        if( module->GetAttributes() & MOD_CMS )
        {
            fprintf( aFile, "INSERT SMD\n" );
        }
        else
        {
            fprintf( aFile, "INSERT TH\n" );
        }
    }

#if 0 /* ATTRIBUTE name and value is unspecified and the original exporter
       * got the syntax wrong, so CAM350 rejected the whole shape! */

    if( module->m_Attributs != MOD_DEFAULT )
    {
        fprintf( aFile, "ATTRIBUTE" );

        if( module->m_Attributs & MOD_CMS )
            fprintf( aFile, " PAD_SMD" );

        if( module->m_Attributs & MOD_VIRTUAL )
            fprintf( aFile, " VIRTUAL" );

        fprintf( aFile, "\n" );
    }
#endif

    // Silk outline; wildly interpreted by various importers:
    // CAM350 read it right but only closed shapes
    // ProntoPlace double-flip it (at least the pads are correct)
    // GerberTool usually get it right...
    for( PtStruct = module->GraphicalItems(); PtStruct; PtStruct = PtStruct->Next() )
    {
        switch( PtStruct->Type() )
        {
        case PCB_MODULE_TEXT_T:

            // If we wanted to export text, this is not the correct section
            break;

        case PCB_MODULE_EDGE_T:
            PtEdge = (EDGE_MODULE*) PtStruct;
            if( PtEdge->GetLayer() == F_SilkS
                || PtEdge->GetLayer() == B_SilkS )
            {
                switch( PtEdge->GetShape() )
                {
                case S_SEGMENT:
                    fprintf( aFile, "LINE %g %g %g %g\n",
                             (PtEdge->m_Start0.x) / SCALE_FACTOR,
                             (Yaxis_sign * PtEdge->m_Start0.y) / SCALE_FACTOR,
                             (PtEdge->m_End0.x) / SCALE_FACTOR,
                             (Yaxis_sign * PtEdge->m_End0.y ) / SCALE_FACTOR );
                    break;

                case S_CIRCLE:
                {
                    int radius = KiROUND( GetLineLength( PtEdge->m_End0,
                                                         PtEdge->m_Start0 ) );
                    fprintf( aFile, "CIRCLE %g %g %g\n",
                             PtEdge->m_Start0.x / SCALE_FACTOR,
                             Yaxis_sign * PtEdge->m_Start0.y / SCALE_FACTOR,
                             radius / SCALE_FACTOR );
                    break;
                }

                case S_ARC:
                {
                    int arcendx, arcendy;
                    arcendx = PtEdge->m_End0.x - PtEdge->m_Start0.x;
                    arcendy = PtEdge->m_End0.y - PtEdge->m_Start0.y;
                    RotatePoint( &arcendx, &arcendy, -PtEdge->GetAngle() );
                    arcendx += PtEdge->GetStart0().x;
                    arcendy += PtEdge->GetStart0().y;
                    if( Yaxis_sign == -1 )
                    {
                        // Flipping Y flips the arc direction too
                        fprintf( aFile, "ARC %g %g %g %g %g %g\n",
                                 (arcendx) / SCALE_FACTOR,
                                 (Yaxis_sign * arcendy) / SCALE_FACTOR,
                                 (PtEdge->m_End0.x) / SCALE_FACTOR,
                                 (Yaxis_sign * PtEdge->GetEnd0().y) / SCALE_FACTOR,
                                 (PtEdge->GetStart0().x) / SCALE_FACTOR,
                                 (Yaxis_sign * PtEdge->GetStart0().y) / SCALE_FACTOR );
                    }
                    else
                    {
                        fprintf( aFile, "ARC %g %g %g %g %g %g\n",
                                 (PtEdge->GetEnd0().x) / SCALE_FACTOR,
                                 (Yaxis_sign * PtEdge->GetEnd0().y) / SCALE_FACTOR,
                                 (arcendx) / SCALE_FACTOR,
                                 (Yaxis_sign * arcendy) / SCALE_FACTOR,
                                 (PtEdge->GetStart0().x) / SCALE_FACTOR,
                                 (Yaxis_sign * PtEdge->GetStart0().y) / SCALE_FACTOR );
                    }
                    break;
                }

                default:
                    DisplayError( NULL, wxT( "Type Edge Module invalid." ) );
                    break;
                }
            }
            break;

        default:
            break;
        }
    }
}
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();
}