Commit 94cfed4b authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Initial version of POINT_EDITOR.

parent 235da608
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -251,6 +251,8 @@ set( PCBNEW_CLASS_SRCS
    tools/selection_tool.cpp
    tools/selection_area.cpp
    tools/bright_box.cpp
    tools/edit_points.cpp
    tools/point_editor.cpp
    tools/drawing_tool.cpp
    tools/edit_tool.cpp
    tools/pcb_tools.cpp
+74 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KICAD, a free EDA CAD application.
 *
 * Copyright (C) 2014 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <boost/foreach.hpp>

#include "edit_points.h"
#include <gal/graphics_abstraction_layer.h>

#include <class_drawsegment.h>

EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent ) :
    EDA_ITEM( NOT_USED ), m_parent( aParent )
{
}


EDIT_POINTS::~EDIT_POINTS()
{
}


EDIT_POINT* EDIT_POINTS::FindPoint( const VECTOR2I& aLocation )
{
    float size = m_view->ToWorld( EDIT_POINT::POINT_SIZE );

    std::deque<EDIT_POINT>::iterator it, itEnd;
    for( it = m_points.begin(), itEnd = m_points.end(); it != itEnd; ++it )
    {
        EDIT_POINT& point = *it;

        if( point.WithinPoint( aLocation, size ) )
            return &point;
    }

    return NULL;
}


void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const
{
    aGal->SetFillColor( KIGFX::COLOR4D( 1.0, 1.0, 1.0, 1.0 ) ); // TODO dynamic color depending on parent's color
    aGal->SetIsFill( true );
    aGal->SetIsStroke( false );
    aGal->PushDepth();
    aGal->SetLayerDepth( -512.0 );      // TODO no hardcoded depths?

    float size = m_view->ToWorld( EDIT_POINT::POINT_SIZE );

    BOOST_FOREACH( const EDIT_POINT& point, m_points )
        aGal->DrawRectangle( point.GetPosition() - size / 2, point.GetPosition() + size / 2 );

    aGal->PopDepth();
}
+247 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KICAD, a free EDA CAD application.
 *
 * Copyright (C) 2014 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#ifndef EDIT_POINTS_H_
#define EDIT_POINTS_H_

#include <vector>
#include <list>
#include <math/box2.h>

#include <base_struct.h>
#include <layers_id_colors_and_visibility.h>

class EDIT_POINT;

class EDIT_POINT_CONSTRAINT
{
public:
    EDIT_POINT_CONSTRAINT( EDIT_POINT* aConstrained ) : m_constrained( aConstrained ) {};
    virtual ~EDIT_POINT_CONSTRAINT() {};

    virtual void Apply() = 0;

protected:
    EDIT_POINT* m_constrained;
};


// TODO docs
class EDIT_POINT
{
public:
    EDIT_POINT( const VECTOR2I& aPoint ) :
        m_point( aPoint ), m_constraint( NULL ) {};
    ~EDIT_POINT()
    {
        delete m_constraint;
    }

    const VECTOR2I& GetPosition() const
    {
        return m_point;
    }

    void SetPosition( const VECTOR2I& aPosition )
    {
        m_point = aPosition;
    }

    bool WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const
    {
        VECTOR2I topLeft = GetPosition() - aSize;
        VECTOR2I bottomRight = GetPosition() + aSize;

        return ( aPoint.x > topLeft.x && aPoint.y > topLeft.y &&
                 aPoint.x < bottomRight.x && aPoint.y < bottomRight.y );
    }

    void SetConstraint( EDIT_POINT_CONSTRAINT* aConstraint )
    {
        m_constraint = aConstraint;
    }

    void ClearConstraint( EDIT_POINT_CONSTRAINT* aConstraint )
    {
        delete m_constraint;
        m_constraint = NULL;
    }

    EDIT_POINT_CONSTRAINT* GetConstraint() const
    {
        return m_constraint;
    }

    void ApplyConstraint()
    {
        if( m_constraint )
            m_constraint->Apply();
    }

    ///> Single point size in pixels
    static const int POINT_SIZE = 10;

private:
    VECTOR2I m_point;
    EDIT_POINT_CONSTRAINT* m_constraint;
};


class EDIT_POINTS : public EDA_ITEM
{
public:
    EDIT_POINTS( EDA_ITEM* aParent );
    ~EDIT_POINTS();

    /**
     * Function FindPoint
     * Returns a point that is at given coordinates or NULL if there is no such point.
     * @param aLocation is the location for searched point.
     */
    EDIT_POINT* FindPoint( const VECTOR2I& aLocation );

    void Add( const EDIT_POINT& aPoint )
    {
        m_points.push_back( aPoint );
    }

    void Add( const VECTOR2I& aPoint )
    {
        m_points.push_back( EDIT_POINT( aPoint ) );
    }

    EDIT_POINT& operator[]( unsigned int aIndex )
    {
        return m_points[aIndex];
    }

    const EDIT_POINT& operator[]( unsigned int aIndex ) const
    {
        return m_points[aIndex];
    }

    unsigned int Size() const
    {
        return m_points.size();
    }

    virtual const BOX2I ViewBBox() const
    {
        return m_parent->ViewBBox();
    }

    virtual void ViewDraw( int aLayer, KIGFX::GAL* aGal ) const;

    virtual void ViewGetLayers( int aLayers[], int& aCount ) const
    {
        aCount = 1;
        aLayers[0] = ITEM_GAL_LAYER( GP_OVERLAY );
    }

    void Show( int x, std::ostream& st ) const
    {
    }

private:
    EDA_ITEM* m_parent;
    std::deque<EDIT_POINT> m_points;
};


class EPC_VERTICAL : public EDIT_POINT_CONSTRAINT
{
public:
    EPC_VERTICAL( EDIT_POINT* aConstrained, EDIT_POINT& aConstrainer ) :
        EDIT_POINT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer )
    {}

    virtual ~EPC_VERTICAL() {};

    virtual void Apply()
    {
        VECTOR2I point = m_constrained->GetPosition();
        point.x = m_constrainer.GetPosition().x;
        m_constrained->SetPosition( point );
    }

    virtual std::list<EDIT_POINT*> GetConstrainers() const
    {
        return std::list<EDIT_POINT*>( 1, &m_constrainer );
    }

private:
    EDIT_POINT& m_constrainer;
};


class EPC_HORIZONTAL : public EDIT_POINT_CONSTRAINT
{
public:
    EPC_HORIZONTAL( EDIT_POINT* aConstrained, EDIT_POINT& aConstrainer ) :
        EDIT_POINT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer )
    {}

    virtual ~EPC_HORIZONTAL() {};

    virtual void Apply()
    {
        VECTOR2I point = m_constrained->GetPosition();
        point.y = m_constrainer.GetPosition().y;
        m_constrained->SetPosition( point );
    }

private:
    EDIT_POINT& m_constrainer;
};


class EPC_CIRCLE : public EDIT_POINT_CONSTRAINT
{
public:
    EPC_CIRCLE( EDIT_POINT* aConstrained, EDIT_POINT& aCenter, EDIT_POINT& aEnd ) :
        EDIT_POINT_CONSTRAINT( aConstrained ), m_center( aCenter ), m_end( aEnd )
    {}

    virtual ~EPC_CIRCLE() {};

    virtual void Apply()
    {
        VECTOR2I centerToEnd = m_end.GetPosition() - m_center.GetPosition();
        VECTOR2I centerToPoint = m_constrained->GetPosition() - m_center.GetPosition();

        int radius = centerToEnd.EuclideanNorm();
        double angle = centerToPoint.Angle();

        VECTOR2I newLine( radius, 0 );
        newLine = newLine.Rotate( angle );

        m_constrained->SetPosition( m_center.GetPosition() + newLine );
    }

private:
    EDIT_POINT& m_center;
    EDIT_POINT& m_end;
};

#endif /* EDIT_POINTS_H_ */
+3 −1
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "selection_tool.h"
#include "edit_tool.h"
#include "drawing_tool.h"
#include "point_editor.h"
#include "common_actions.h"
#include <router/router_tool.h>

@@ -71,6 +72,7 @@ void PCB_EDIT_FRAME::setupTools()
    m_toolManager->RegisterTool( new ROUTER_TOOL );
    m_toolManager->RegisterTool( new EDIT_TOOL );
    m_toolManager->RegisterTool( new DRAWING_TOOL );
    m_toolManager->RegisterTool( new POINT_EDITOR );

    m_toolManager->SetEnvironment( NULL, GetGalCanvas()->GetView(),
                                   GetGalCanvas()->GetViewControls(), this );
+304 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2013 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <tool/tool_manager.h>
#include <view/view_controls.h>
#include <confirm.h>

#include "common_actions.h"
#include "selection_tool.h"
#include "point_editor.h"

#include <class_drawsegment.h>

/**
 * Class POINT_EDITOR
 *
 * Tool that displays edit points allowing to modify items by dragging the points.
 */

class EDIT_POINTS_FACTORY
{
public:
    static EDIT_POINTS Make( EDA_ITEM* aItem )
    {
        // TODO generate list of points basing on the type
        EDIT_POINTS points( aItem );

        switch( aItem->Type() )
        {
            case PCB_LINE_T:
            {
                DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( aItem );

                switch( segment->GetShape() )
                {
                case S_SEGMENT:
                    points.Add( segment->GetStart() );
                    points.Add( segment->GetEnd() );

                    break;

                case S_ARC:
                    points.Add( segment->GetCenter() );         // points[0]
                    points.Add( segment->GetArcStart() );       // points[1]
                    points.Add( segment->GetArcEnd() );         // points[2]

                    // Set constraints
                    // Arc end has to stay at the same radius as the start
                    points[2].SetConstraint( new EPC_CIRCLE( &points[2], points[0], points[1] ) );
                    break;

                default:        // suppress warnings
                    break;
                }
            }
            break;

            default:
                break;
        }

        return points;
    }

private:
    EDIT_POINTS_FACTORY() {};
};


POINT_EDITOR::POINT_EDITOR() :
    TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL )
{
}


bool POINT_EDITOR::Init()
{
    // Find the selection tool, so they can cooperate
    m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) );

    if( !m_selectionTool )
    {
        DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
        return false;
    }

    setTransitions();

    return true;
}


int POINT_EDITOR::OnSelected( TOOL_EVENT& aEvent )
{
    std::cout << "point editor activated" << std::endl;
    std::cout << aEvent.Format() << std::endl;

    const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection();
    KIGFX::VIEW_CONTROLS* controls = getViewControls();
    m_dragPoint = NULL;

    if( selection.Size() == 1 )
    {
        Activate();

        EDA_ITEM* item = selection.items.GetPickedItem( 0 );
        EDIT_POINTS editPoints = EDIT_POINTS_FACTORY::Make( item );
        m_toolMgr->GetView()->Add( &editPoints );

        // Main loop: keep receiving events
        while( OPT_TOOL_EVENT evt = Wait() )
        {
            if( evt->IsCancel() ||
                evt->Matches( m_selectionTool->ClearedEvent ) ||
                evt->Matches( m_selectionTool->DeselectedEvent ) ||
                evt->Matches( m_selectionTool->SelectedEvent ) )
            {
                m_toolMgr->PassEvent();
                break;
            }

            else if( evt->IsMotion() )
            {
                EDIT_POINT* point = editPoints.FindPoint( evt->Position() );

                if( m_dragPoint != point )
                {
                    if( point )
                    {
                        controls->ShowCursor( true );
                        controls->SetAutoPan( true );
                        controls->SetSnapping( true );
                    }
                    else
                    {
                        controls->ShowCursor( false );
                        controls->SetAutoPan( false );
                        controls->SetSnapping( false );
                    }
                }

                m_dragPoint = point;
            }

            else if( evt->IsDrag( BUT_LEFT ) )
            {
                if( m_dragPoint )
                {
                    m_dragPoint->SetPosition( controls->GetCursorPosition() );
                    m_dragPoint->ApplyConstraint();
                    updateItem( item, editPoints );
                    updatePoints( item, editPoints );

                    editPoints.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                }
                else
                {
                    m_toolMgr->PassEvent();
                }
            }

            else if( evt->IsClick( BUT_LEFT ) )
            {
                m_toolMgr->PassEvent();
            }
        }

        m_toolMgr->GetView()->Remove( &editPoints );
        item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    controls->ShowCursor( false );
    controls->SetAutoPan( false );
    controls->SetSnapping( false );

    setTransitions();

    return 0;
}


void POINT_EDITOR::setTransitions()
{
    Go( &POINT_EDITOR::OnSelected, m_selectionTool->SelectedEvent );
}


void POINT_EDITOR::updateItem( EDA_ITEM* aItem, EDIT_POINTS& aPoints ) const
{
    switch( aItem->Type() )
    {
    case PCB_LINE_T:
    {
        DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( aItem );
        switch( segment->GetShape() )
        {
        case S_SEGMENT:
            if( &aPoints[0] == m_dragPoint )
                segment->SetStart( wxPoint( aPoints[0].GetPosition().x, aPoints[0].GetPosition().y ) );
            else if( &aPoints[1] == m_dragPoint )
                segment->SetEnd( wxPoint( aPoints[1].GetPosition().x, aPoints[1].GetPosition().y ) );

            break;

        case S_ARC:
        {
            const VECTOR2I& center = aPoints[0].GetPosition();
            const VECTOR2I& start = aPoints[1].GetPosition();
            const VECTOR2I& end = aPoints[2].GetPosition();

            if( center != segment->GetCenter() )
            {
                wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
                segment->Move( moveVector );

                aPoints[1].SetPosition( segment->GetArcStart() );
                aPoints[2].SetPosition( segment->GetArcEnd() );
            }

            else
            {
                segment->SetArcStart( wxPoint( start.x, start.y ) );

                VECTOR2D startLine = start - center;
                VECTOR2I endLine = end - center;
                double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );

                // Adjust the new angle to (counter)clockwise setting
                bool clockwise = ( segment->GetAngle() > 0 );
                if( clockwise && newAngle < 0.0 )
                    newAngle += 3600.0;
                else if( !clockwise && newAngle > 0.0 )
                    newAngle -= 3600.0;

                segment->SetAngle( newAngle );
            }
        }
        break;

        default:        // suppress warnings
            break;
        }
        break;
    }

    default:
        break;
    }
}


void POINT_EDITOR::updatePoints( const EDA_ITEM* aItem, EDIT_POINTS& aPoints ) const
{
    switch( aItem->Type() )
    {
    case PCB_LINE_T:
    {
        const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( aItem );
        {
            switch( segment->GetShape() )
            {
            case S_SEGMENT:
                aPoints[0].SetPosition( segment->GetStart() );
                aPoints[1].SetPosition( segment->GetEnd() );
                break;

            case S_ARC:
                aPoints[0].SetPosition( segment->GetCenter() );
                aPoints[1].SetPosition( segment->GetArcStart() );
                aPoints[2].SetPosition( segment->GetArcEnd() );
                break;

            default:        // suppress warnings
                break;
            }
        }
        break;
    }

    default:
        break;
    }
}
Loading