int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent )
{
    boost::optional<VECTOR2D> startingPoint;

    if( m_editModules )
    {
        m_frame->SetToolID( ID_MODEDIT_LINE_TOOL, wxCURSOR_PENCIL, _( "Add graphic line" ) );

        EDGE_MODULE* line = new EDGE_MODULE( m_board->m_Modules );

        while( drawSegment( S_SEGMENT, reinterpret_cast<DRAWSEGMENT*&>( line ), startingPoint  ) )
        {
            if( line )
            {
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                line->SetParent( m_board->m_Modules );
                line->SetLocalCoord();
                m_board->m_Modules->GraphicalItems().PushFront( line );
                startingPoint = line->GetEnd();
            }
            else
            {
                startingPoint = boost::none;
            }

            line = new EDGE_MODULE( m_board->m_Modules );
        }
    }
    else // !m_editModules case
    {
        m_frame->SetToolID( ID_PCB_ADD_LINE_BUTT, wxCURSOR_PENCIL, _( "Add graphic line" ) );

        DRAWSEGMENT* line = new DRAWSEGMENT;

        while( drawSegment( S_SEGMENT, line, startingPoint ) )
        {
            if( line )
            {
                m_board->Add( line );
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( line, UR_NEW );
                startingPoint = line->GetEnd();
            }
            else
            {
                startingPoint = boost::none;
            }

            line = new DRAWSEGMENT;
        }
    }

    m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );

    return 0;
}
int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent )
{
    if( m_editModules )
    {
        m_frame->SetToolID( ID_MODEDIT_ARC_TOOL, wxCURSOR_PENCIL, _( "Add graphic arc" ) );

        EDGE_MODULE* arc = new EDGE_MODULE( m_board->m_Modules );

        while( drawArc( reinterpret_cast<DRAWSEGMENT*&>( arc ) ) )
        {
            if( arc )
            {
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                arc->SetParent( m_board->m_Modules );
                arc->SetLocalCoord();
                m_board->m_Modules->GraphicalItems().PushFront( arc );
            }

            arc = new EDGE_MODULE( m_board->m_Modules );
        }
    }
    else // !m_editModules case
    {
        m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) );

        DRAWSEGMENT* arc = new DRAWSEGMENT;

        while( drawArc( arc ) )
        {
            if( arc )
            {
                m_board->Add( arc );
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( arc, UR_NEW );
            }

            arc = new DRAWSEGMENT;
        }
    }

    m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );

    return 0;
}
int DRAWING_TOOL::DrawCircle( const TOOL_EVENT& aEvent )
{
    if( m_editModules )
    {
        m_frame->SetToolID( ID_MODEDIT_CIRCLE_TOOL, wxCURSOR_PENCIL, _( "Add graphic circle" ) );

        EDGE_MODULE* circle = new EDGE_MODULE( m_board->m_Modules );

        while( drawSegment( S_CIRCLE, reinterpret_cast<DRAWSEGMENT*&>( circle ) ) )
        {
            if( circle )
            {
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                circle->SetParent( m_board->m_Modules );
                circle->SetLocalCoord();
                m_board->m_Modules->GraphicalItems().PushFront( circle );
            }

            circle = new EDGE_MODULE( m_board->m_Modules );
        }
    }
    else // !m_editModules case
    {
        m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) );

        DRAWSEGMENT* circle = new DRAWSEGMENT;

        while( drawSegment( S_CIRCLE, circle ) )
        {
            if( circle )
            {
                m_board->Add( circle );
                m_frame->OnModify();
                m_frame->SaveCopyInUndoList( circle, UR_NEW );
            }

            circle = new DRAWSEGMENT;
        }
    }

    m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );

    return 0;
}
Esempio n. 4
0
void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint )
{
    EDA_ITEM* item = m_editPoints->GetParent();
    const SELECTION& selection = m_selectionTool->GetSelection();

    if( item->Type() == PCB_ZONE_AREA_T )
    {
        getEditFrame<PCB_BASE_FRAME>()->OnModify();
        getEditFrame<PCB_BASE_FRAME>()->SaveCopyInUndoList( selection.items, UR_CHANGED );

        ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
        CPolyLine* outline = zone->Outline();

        // Handle the last segment, so other segments can be easily handled in a loop
        unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0;
        SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ),
                  VECTOR2I( outline->GetPos( nextNearestIdx ) ) );
        unsigned int nearestDist = side.Distance( aBreakPoint );

        for( int i = 0; i < outline->GetCornersCount() - 1; ++i )
        {
            side = SEG( VECTOR2I( outline->GetPos( i ) ), VECTOR2I( outline->GetPos( i + 1 ) ) );

            unsigned int distance = side.Distance( aBreakPoint );
            if( distance < nearestDist )
            {
                nearestDist = distance;
                nearestIdx = i;
                nextNearestIdx = i + 1;
            }
        }

        // Find the point on the closest segment
        VECTOR2I sideOrigin( outline->GetPos( nearestIdx ) );
        VECTOR2I sideEnd( outline->GetPos( nextNearestIdx ) );
        SEG nearestSide( sideOrigin, sideEnd );
        VECTOR2I nearestPoint = nearestSide.NearestPoint( aBreakPoint );

        // Do not add points that have the same coordinates as ones that already belong to polygon
        // instead, add a point in the middle of the side
        if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
            nearestPoint = ( sideOrigin + sideEnd ) / 2;

        outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y );
    }

    else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T )
    {
        bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T;
        PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();

        frame->OnModify();

        if( moduleEdge )
            frame->SaveCopyInUndoList( getModel<BOARD>()->m_Modules, UR_MODEDIT );
        else
            frame->SaveCopyInUndoList( selection.items, UR_CHANGED );

        DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );

        if( segment->GetShape() == S_SEGMENT )
        {
            SEG seg( segment->GetStart(), segment->GetEnd() );
            VECTOR2I nearestPoint = seg.NearestPoint( aBreakPoint );

            // Move the end of the line to the break point..
            segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) );

            // and add another one starting from the break point
            DRAWSEGMENT* newSegment;

            if( moduleEdge )
            {
                EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment );
                assert( segment->GetParent()->Type() == PCB_MODULE_T );
                newSegment = new EDGE_MODULE( *edge );
                edge->SetLocalCoord();
            }
            else
            {
                newSegment = new DRAWSEGMENT( *segment );
            }

            newSegment->ClearSelected();
            newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) );
            newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) );

            if( moduleEdge )
            {
                static_cast<EDGE_MODULE*>( newSegment )->SetLocalCoord();
                getModel<BOARD>()->m_Modules->Add( newSegment );
            }
            else
            {
                getModel<BOARD>()->Add( newSegment );
            }

            getView()->Add( newSegment );
        }
    }
}
bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT*& aGraphic,
                                boost::optional<VECTOR2D> aStartingPoint )
{
    // Only two shapes are currently supported
    assert( aShape == S_SEGMENT || aShape == S_CIRCLE );

    DRAWSEGMENT line45;

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();

    bool direction45 = false;       // 45 degrees only mode
    bool started = false;
    VECTOR2I cursorPos = m_controls->GetCursorPosition();

    if( aStartingPoint )
    {
        LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

        // Init the new item attributes
        aGraphic->SetShape( (STROKE_T) aShape );
        aGraphic->SetWidth( m_lineWidth );
        aGraphic->SetStart( wxPoint( aStartingPoint->x, aStartingPoint->y ) );
        aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
        aGraphic->SetLayer( layer );

        if( aShape == S_SEGMENT )
            line45 = *aGraphic; // used only for direction 45 mode with lines

        preview.Add( aGraphic );
        m_controls->SetAutoPan( true );
        m_controls->CaptureCursor( true );

        started = true;
    }

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        bool updatePreview = false;            // should preview be updated
        cursorPos = m_controls->GetCursorPosition();

        // Enable 45 degrees lines only mode by holding control
        if( direction45 != evt->Modifier( MD_CTRL ) && started && aShape == S_SEGMENT )
        {
            direction45 = evt->Modifier( MD_CTRL );

            if( direction45 )
            {
                preview.Add( &line45 );
                make45DegLine( aGraphic, &line45 );
            }
            else
            {
                preview.Remove( &line45 );
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
            }

            updatePreview = true;
        }

        if( evt->IsCancel() || evt->IsActivate() || evt->IsAction( &COMMON_ACTIONS::layerChanged ) )
        {
            preview.Clear();
            updatePreview = true;
            delete aGraphic;
            aGraphic = NULL;
            break;
        }

        else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
        {
            if( !started )
            {
                LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

                if( IsCopperLayer( layer ) )
                {
                    DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
                }
                else
                {
                    // Init the new item attributes
                    aGraphic->SetShape( (STROKE_T) aShape );
                    m_lineWidth = getSegmentWidth( layer );
                    aGraphic->SetWidth( m_lineWidth );
                    aGraphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetLayer( layer );

                    if( aShape == S_SEGMENT )
                        line45 = *aGraphic; // used only for direction 45 mode with lines

                    preview.Add( aGraphic );
                    m_controls->SetAutoPan( true );
                    m_controls->CaptureCursor( true );

                    started = true;
                }
            }
            else
            {
                if( aGraphic->GetEnd() == aGraphic->GetStart() ||
                        ( evt->IsDblClick( BUT_LEFT ) && aShape == S_SEGMENT ) )
                                                // User has clicked twice in the same spot
                {                               // a clear sign that the current drawing is finished
                    if( direction45 )
                    {
                        // Now we have to add the helper line as well
                        if( m_editModules )
                        {
                            EDGE_MODULE* l = new EDGE_MODULE( m_board->m_Modules );

                            // Copy coordinates, layer, etc.
                            *static_cast<DRAWSEGMENT*>( l ) = line45;
                            l->SetEnd( aGraphic->GetStart() );
                            l->SetLocalCoord();

                            m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                            m_board->m_Modules->SetLastEditTime();
                            m_board->m_Modules->GraphicalItems().PushFront( l );

                            m_view->Add( l );
                            l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                        }
                        else
                        {
                            DRAWSEGMENT* l = static_cast<DRAWSEGMENT*>( line45.Clone() );
                            l->SetEnd( aGraphic->GetStart() );

                            m_frame->SaveCopyInUndoList( l, UR_NEW );
                            m_board->Add( l );

                            m_view->Add( l );
                            l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                        }

                        m_frame->OnModify();
                    }

                    delete aGraphic;
                    aGraphic = NULL;
                }
                else
                {
                    assert( aGraphic->GetLength() > 0 );
                    assert( aGraphic->GetWidth() > 0 );

                    m_view->Add( aGraphic );
                    aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                }

                preview.Clear();
                break;
            }
        }

        else if( evt->IsMotion() )
        {
            // 45 degree lines
            if( direction45 && aShape == S_SEGMENT )
                make45DegLine( aGraphic, &line45 );
            else
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );

            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) )
        {
            m_lineWidth += WIDTH_STEP;
            aGraphic->SetWidth( m_lineWidth );
            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) )
        {
            if( m_lineWidth > (unsigned) WIDTH_STEP )
            {
                m_lineWidth -= WIDTH_STEP;
                aGraphic->SetWidth( m_lineWidth );
                updatePreview = true;
            }
        }

        if( updatePreview )
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    return started;
}