From 19a87ac7804e14a8b1a69f46deb5b9e5e0495b9f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 14 Mar 2014 15:37:55 +0100 Subject: [PATCH] Added EC_CONVERGING for zone areas modification. --- pcbnew/tools/edit_points.cpp | 89 ++++++++++++++++++++++++++++++++++- pcbnew/tools/edit_points.h | 25 ++++++++++ pcbnew/tools/point_editor.cpp | 53 +++++++++++++-------- pcbnew/tools/point_editor.h | 9 ++++ 4 files changed, 155 insertions(+), 21 deletions(-) diff --git a/pcbnew/tools/edit_points.cpp b/pcbnew/tools/edit_points.cpp index 00fdb101ae..e98a8dee6b 100644 --- a/pcbnew/tools/edit_points.cpp +++ b/pcbnew/tools/edit_points.cpp @@ -26,8 +26,7 @@ #include "edit_points.h" #include - -#include +#include bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const { @@ -205,3 +204,89 @@ void EC_CIRCLE::Apply() m_constrained.SetPosition( m_center.GetPosition() + newLine ); } + + +EC_CONVERGING::EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ) : + EDIT_CONSTRAINT( aLine.GetEnd() ), + /*m_end( aLine.GetEnd() ), m_origin( aLine.GetOrigin() ),*/ m_line( aLine ), + m_editPoints( aPoints ) +{ + // Dragged segment endings + EDIT_POINT& origin = aLine.GetOrigin(); + EDIT_POINT& end = aLine.GetEnd(); + + // Add constraint to the line origin, so it moves only along it current line + EDIT_POINT& prevOrigin = *aPoints.Previous( origin ); + EDIT_POINT& nextEnd = *aPoints.Next( end ); + + // Constraints for segments adjacent to the dragged one + m_originSideConstraint = new EC_LINE( origin, prevOrigin ); + m_endSideConstraint = new EC_LINE( end, nextEnd ); + + // Compute dragged segment slope + VECTOR2D delta = m_line.GetPosition() - end.GetPosition(); + m_coefA = delta.y / delta.x; +} + + +EC_CONVERGING::~EC_CONVERGING() +{ + delete m_originSideConstraint; + delete m_endSideConstraint; +} + + +void EC_CONVERGING::Apply() +{ + EDIT_POINT& origin = m_line.GetOrigin(); + EDIT_POINT& end = m_line.GetEnd(); + + // Do not allow points on the adjacent segments move freely + m_originSideConstraint->Apply(); + m_endSideConstraint->Apply(); + + // Find points that make adjacent segments + EDIT_POINT& prevOrigin = *m_editPoints.Previous( origin ); // point previous to origin + EDIT_POINT& nextEnd = *m_editPoints.Next( end ); // point next to end + + // Two segments adjacent to the dragged segment + SEG originSide( origin.GetPosition(), prevOrigin.GetPosition() ); + SEG endSide( end.GetPosition(), nextEnd.GetPosition() ); + + VECTOR2I draggedCenter; // center point of the dragged segment + + // Check if adjacent segments intersect (did we dragged the line to the point that it may + // create a selfintersecting polygon?) + if( OPT_VECTOR2I originEndIntersect = endSide.Intersect( originSide ) ) + draggedCenter = *originEndIntersect; + else + draggedCenter = m_line.GetPosition(); + + // Line B coefficient (y=Ax+B) for the dragged segment (A coefficient is computed up on the + // the construction of EC_CONVERGING + double coefB = draggedCenter.y - m_coefA * draggedCenter.x; + VECTOR2D draggedEnd = draggedCenter + 10000; + + if( std::isfinite( m_coefA ) ) + { + if( std::abs( m_coefA ) < 1 ) + draggedEnd.y = m_coefA * draggedEnd.x + coefB; + else + draggedEnd.x = ( draggedEnd.y - coefB ) / m_coefA; + } + else // vertical line + { + draggedEnd.x = draggedCenter.x; + draggedEnd.y = draggedEnd.x + coefB; + } + + SEG dragged( draggedCenter, draggedEnd ); // the dragged segment + + // First intersection point (dragged segment against origin side) + if( OPT_VECTOR2I originIntersect = dragged.IntersectLines( originSide ) ) + origin.SetPosition( *originIntersect ); + + // Second intersection point (dragged segment against end side) + if( OPT_VECTOR2I endIntersect = dragged.IntersectLines( endSide ) ) + end.SetPosition( *endIntersect ); +} diff --git a/pcbnew/tools/edit_points.h b/pcbnew/tools/edit_points.h index 1d10e21a45..49aa2b9383 100644 --- a/pcbnew/tools/edit_points.h +++ b/pcbnew/tools/edit_points.h @@ -579,4 +579,29 @@ private: const EDIT_POINT& m_end; }; + +/** + * Class EC_CONVERGING + * + * EDIT_CONSTRAINT for 3 segment: dragged and two adjacent ones, enforcing to keep their slopes + * and allows only to change ending points. Applied to zones. + */ +class EC_CONVERGING : public EDIT_CONSTRAINT +{ +public: + EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ); + + virtual ~EC_CONVERGING(); + + ///> @copydoc EDIT_CONSTRAINT::Apply() + virtual void Apply(); + +private: + EC_LINE* m_originSideConstraint; ///< Constraint for origin side segment + EC_LINE* m_endSideConstraint; ///< Constraint for end side segment + EDIT_LINE& m_line; ///< Dragged segment + EDIT_POINTS& m_editPoints; ///< EDIT_POINT instance storing modified lines + double m_coefA; ///< Original dragged segment A coefficient (y = Ax + B) +}; + #endif /* EDIT_POINTS_H_ */ diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index 3caec5eb5e..f48f0583dc 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -135,7 +135,7 @@ private: POINT_EDITOR::POINT_EDITOR() : TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL ), m_dragPoint( NULL ), - m_original( VECTOR2I( 0, 0 ) ) + m_original( VECTOR2I( 0, 0 ) ), m_altConstrainer( VECTOR2I( 0, 0 ) ) { } @@ -143,6 +143,7 @@ POINT_EDITOR::POINT_EDITOR() : void POINT_EDITOR::Reset( RESET_REASON aReason ) { m_editPoints.reset(); + m_altConstraint.reset(); } @@ -175,8 +176,6 @@ int POINT_EDITOR::OnSelectionChange( TOOL_EVENT& aEvent ) KIGFX::VIEW* view = getView(); PCB_EDIT_FRAME* editFrame = getEditFrame(); EDA_ITEM* item = selection.items.GetPickedItem( 0 ); - EDIT_POINT constrainer( VECTOR2I( 0, 0 ) ); - boost::shared_ptr > degree45Constraint; m_editPoints = EDIT_POINTS_FACTORY::Make( item ); if( !m_editPoints ) @@ -237,24 +236,14 @@ int POINT_EDITOR::OnSelectionChange( TOOL_EVENT& aEvent ) modified = true; } - if( !!evt->Modifier( MD_CTRL ) != (bool) degree45Constraint ) // 45 degrees mode - { - if( !degree45Constraint ) - { - // Find a proper constraining point for 45 degrees mode - constrainer = get45DegConstrainer(); - degree45Constraint.reset( new EC_45DEGREE( *m_dragPoint, constrainer ) ); - } - else - { - degree45Constraint.reset(); - } - } + bool enableAltConstraint = !!evt->Modifier( MD_CTRL ); + if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint + setAltConstraint( enableAltConstraint ); m_dragPoint->SetPosition( controls->GetCursorPosition() ); - if( degree45Constraint ) - degree45Constraint->Apply(); + if( m_altConstraint ) + m_altConstraint->Apply(); else m_dragPoint->ApplyConstraint(); @@ -271,7 +260,7 @@ int POINT_EDITOR::OnSelectionChange( TOOL_EVENT& aEvent ) else if( evt->IsMouseUp( BUT_LEFT ) ) { - degree45Constraint.reset(); + setAltConstraint( false ); modified = false; } @@ -540,6 +529,32 @@ void POINT_EDITOR::updatePoints() const } +void POINT_EDITOR::setAltConstraint( bool aEnabled ) +{ + if( aEnabled ) + { + EDIT_LINE* line = dynamic_cast( m_dragPoint ); + if( line ) + { + if( m_editPoints->GetParent()->Type() == PCB_ZONE_AREA_T ) + { + m_altConstraint.reset( new EC_CONVERGING( *line, *m_editPoints ) ); + } + } + else + { + // Find a proper constraining point for 45 degrees mode + m_altConstrainer = get45DegConstrainer(); + m_altConstraint.reset( new EC_45DEGREE( *m_dragPoint, m_altConstrainer ) ); + } + } + else + { + m_altConstraint.reset(); + } +} + + EDIT_POINT POINT_EDITOR::get45DegConstrainer() const { EDA_ITEM* item = m_editPoints->GetParent(); diff --git a/pcbnew/tools/point_editor.h b/pcbnew/tools/point_editor.h index 8e37a142cd..fe77760c3d 100644 --- a/pcbnew/tools/point_editor.h +++ b/pcbnew/tools/point_editor.h @@ -68,6 +68,12 @@ private: ///> Currently available edit points. boost::shared_ptr m_editPoints; + // Alternative constraint, enabled while a modifier key is held + boost::shared_ptr > m_altConstraint; + + // EDIT_POINT for alternative constraint mode + EDIT_POINT m_altConstrainer; + ///> Updates item's points with edit points. void updateItem() const; @@ -83,6 +89,9 @@ private: return m_dragPoint == &aPoint; } + ///> Sets up an alternative constraint (typically enabled upon a modifier key being pressed). + void setAltConstraint( bool aEnabled ); + ///> Returns a point that should be used as a constrainer for 45 degrees mode. EDIT_POINT get45DegConstrainer() const;