From 125ef0a679af83da97717d85d8edfc1e43845525 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 27 Feb 2014 17:29:08 +0100 Subject: [PATCH] Initial version of POINT_EDITOR. --- pcbnew/CMakeLists.txt | 4 +- pcbnew/tools/edit_points.cpp | 74 +++++++++ pcbnew/tools/edit_points.h | 247 +++++++++++++++++++++++++++ pcbnew/tools/pcb_tools.cpp | 4 +- pcbnew/tools/point_editor.cpp | 304 ++++++++++++++++++++++++++++++++++ pcbnew/tools/point_editor.h | 74 +++++++++ 6 files changed, 705 insertions(+), 2 deletions(-) create mode 100644 pcbnew/tools/edit_points.cpp create mode 100644 pcbnew/tools/edit_points.h create mode 100644 pcbnew/tools/point_editor.cpp create mode 100644 pcbnew/tools/point_editor.h diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index e697375ec2..43ce8ba3f3 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -251,7 +251,9 @@ set( PCBNEW_CLASS_SRCS tools/selection_tool.cpp tools/selection_area.cpp tools/bright_box.cpp - tools/drawing_tool.cpp + tools/edit_points.cpp + tools/point_editor.cpp + tools/drawing_tool.cpp tools/edit_tool.cpp tools/pcb_tools.cpp tools/common_actions.cpp diff --git a/pcbnew/tools/edit_points.cpp b/pcbnew/tools/edit_points.cpp new file mode 100644 index 0000000000..5efe90bae0 --- /dev/null +++ b/pcbnew/tools/edit_points.cpp @@ -0,0 +1,74 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 + +#include "edit_points.h" +#include + +#include + +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::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(); +} diff --git a/pcbnew/tools/edit_points.h b/pcbnew/tools/edit_points.h new file mode 100644 index 0000000000..7ddfa2fcf9 --- /dev/null +++ b/pcbnew/tools/edit_points.h @@ -0,0 +1,247 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2014 CERN + * @author Maciej Suminski + * + * 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 +#include +#include + +#include +#include + +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 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 GetConstrainers() const + { + return std::list( 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_ */ diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index 9ddfccc34d..53683e1a55 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -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 @@ -70,7 +71,8 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new SELECTION_TOOL ); m_toolManager->RegisterTool( new ROUTER_TOOL ); m_toolManager->RegisterTool( new EDIT_TOOL ); - m_toolManager->RegisterTool( new DRAWING_TOOL ); + m_toolManager->RegisterTool( new DRAWING_TOOL ); + m_toolManager->RegisterTool( new POINT_EDITOR ); m_toolManager->SetEnvironment( NULL, GetGalCanvas()->GetView(), GetGalCanvas()->GetViewControls(), this ); diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp new file mode 100644 index 0000000000..efd1c35094 --- /dev/null +++ b/pcbnew/tools/point_editor.cpp @@ -0,0 +1,304 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * 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 +#include +#include + +#include "common_actions.h" +#include "selection_tool.h" +#include "point_editor.h" + +#include + +/** + * 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( 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( 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( 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( 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; + } +} diff --git a/pcbnew/tools/point_editor.h b/pcbnew/tools/point_editor.h new file mode 100644 index 0000000000..a44ac07a00 --- /dev/null +++ b/pcbnew/tools/point_editor.h @@ -0,0 +1,74 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * 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 __POINT_EDITOR_H +#define __POINT_EDITOR_H + +#include +#include "edit_points.h" + +class SELECTION_TOOL; + +/** + * Class POINT_EDITOR + * + * Tool that displays edit points allowing to modify items by dragging the points. + */ + +class POINT_EDITOR : public TOOL_INTERACTIVE +{ +public: + POINT_EDITOR(); + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ) {}; + + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + + /** + * Function OnSelected() + * + * Change selection event handler. + */ + int OnSelected( TOOL_EVENT& aEvent ); + +private: + ///> Selection tool used for obtaining selected items + SELECTION_TOOL* m_selectionTool; + + ///> Currently edited point, NULL if there is none. + EDIT_POINT* m_dragPoint; + + ///> Updates item's points with edit points. + void updateItem( EDA_ITEM* aItem, EDIT_POINTS& aPoints ) const; + + ///> Updates edit points with item's points. + void updatePoints( const EDA_ITEM* aItem, EDIT_POINTS& aPoints ) const; + + ///> Sets up handlers for various events. + void setTransitions(); +}; + +#endif