From 48161dcc4a1b1e53288355bbf741aa01bacef7d6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 18 Mar 2014 11:05:24 +0100 Subject: [PATCH] Yet another approach to EC_LINE and EC_CONVERGING edit constraints. --- pcbnew/tools/edit_points.cpp | 103 ++++++++++++----------------------- pcbnew/tools/edit_points.h | 68 ++++++++++++++++------- 2 files changed, 84 insertions(+), 87 deletions(-) diff --git a/pcbnew/tools/edit_points.cpp b/pcbnew/tools/edit_points.cpp index e98a8dee6b..23c8f1dbf4 100644 --- a/pcbnew/tools/edit_points.cpp +++ b/pcbnew/tools/edit_points.cpp @@ -147,54 +147,41 @@ void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const } -void EC_45DEGREE::Apply() +void EC_45DEGREE::Apply( EDIT_POINT& aHandle ) { // Current line vector - VECTOR2I lineVector( m_constrained.GetPosition() - m_constrainer.GetPosition() ); + VECTOR2I lineVector( aHandle.GetPosition() - m_constrainer.GetPosition() ); double angle = lineVector.Angle(); // Find the closest angle, which is a multiple of 45 degrees double newAngle = round( angle / ( M_PI / 4.0 ) ) * M_PI / 4.0; VECTOR2I newLineVector = lineVector.Rotate( newAngle - angle ); - m_constrained.SetPosition( m_constrainer.GetPosition() + newLineVector ); + aHandle.SetPosition( m_constrainer.GetPosition() + newLineVector ); } EC_LINE::EC_LINE( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ) : EDIT_CONSTRAINT( aConstrained ), m_constrainer( aConstrainer ) { - // Compute line coefficients - VECTOR2D delta = m_constrainer.GetPosition() - m_constrained.GetPosition(); - m_coefA = delta.y / delta.x; - m_coefB = m_constrainer.GetY() - m_coefA * m_constrainer.GetX(); + m_line = m_constrained.GetPosition() - m_constrainer.GetPosition(); } -void EC_LINE::Apply() +void EC_LINE::Apply( EDIT_POINT& aHandle ) { - VECTOR2I position = m_constrained.GetPosition(); + SEG main( m_constrainer.GetPosition(), m_constrainer.GetPosition() + m_line ); + SEG projection( aHandle.GetPosition(), aHandle.GetPosition() + m_line.Perpendicular() ); - if( std::isfinite( m_coefA ) ) - { - if( abs( m_coefA ) < 1 ) - position.y = m_coefA * position.x + m_coefB; - else - position.x = ( position.y - m_coefB ) / m_coefA; - } - else // vertical line - { - position.x = m_constrainer.GetX(); - } - - m_constrained.SetPosition( position ); + if( OPT_VECTOR2I intersect = projection.IntersectLines( main ) ) + aHandle.SetPosition( *intersect ); } -void EC_CIRCLE::Apply() +void EC_CIRCLE::Apply( EDIT_POINT& aHandle ) { VECTOR2I centerToEnd = m_end.GetPosition() - m_center.GetPosition(); - VECTOR2I centerToPoint = m_constrained.GetPosition() - m_center.GetPosition(); + VECTOR2I centerToPoint = aHandle.GetPosition() - m_center.GetPosition(); int radius = centerToEnd.EuclideanNorm(); double angle = centerToPoint.Angle(); @@ -202,20 +189,18 @@ void EC_CIRCLE::Apply() VECTOR2I newLine( radius, 0 ); newLine = newLine.Rotate( angle ); - m_constrained.SetPosition( m_center.GetPosition() + newLine ); + aHandle.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 ) + EDIT_CONSTRAINT( 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 + // Previous and next points, to make constraining lines (adjacent to the dragged line) EDIT_POINT& prevOrigin = *aPoints.Previous( origin ); EDIT_POINT& nextEnd = *aPoints.Next( end ); @@ -223,9 +208,8 @@ EC_CONVERGING::EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ) : 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; + // Store the current vector of the line + m_draggedVector = end.GetPosition() - origin.GetPosition() ; } @@ -236,8 +220,12 @@ EC_CONVERGING::~EC_CONVERGING() } -void EC_CONVERGING::Apply() +void EC_CONVERGING::Apply( EDIT_POINT& aHandle ) { + // The dragged segment + SEG dragged( m_line.GetPosition(), m_line.GetPosition() + m_draggedVector ); + + // The dragged segment endpoints EDIT_POINT& origin = m_line.GetOrigin(); EDIT_POINT& end = m_line.GetEnd(); @@ -245,42 +233,12 @@ void EC_CONVERGING::Apply() 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 + EDIT_POINT& prevOrigin = *m_editPoints.Previous( origin ); + EDIT_POINT& nextEnd = *m_editPoints.Next( 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 + SEG originSide = SEG( origin.GetPosition(), prevOrigin.GetPosition() ); + SEG endSide = SEG( end.GetPosition(), nextEnd.GetPosition() ); // First intersection point (dragged segment against origin side) if( OPT_VECTOR2I originIntersect = dragged.IntersectLines( originSide ) ) @@ -289,4 +247,15 @@ void EC_CONVERGING::Apply() // Second intersection point (dragged segment against end side) if( OPT_VECTOR2I endIntersect = dragged.IntersectLines( endSide ) ) end.SetPosition( *endIntersect ); + + // Check if adjacent segments intersect (did we dragged the line to the point that it may + // create a selfintersecting polygon?) + originSide = SEG( origin.GetPosition(), prevOrigin.GetPosition() ); + endSide = SEG( end.GetPosition(), nextEnd.GetPosition() ); + + if( OPT_VECTOR2I originEndIntersect = endSide.Intersect( originSide ) ) + { + origin.SetPosition( *originEndIntersect ); + end.SetPosition( *originEndIntersect ); + } } diff --git a/pcbnew/tools/edit_points.h b/pcbnew/tools/edit_points.h index 49aa2b9383..0c1dd343c2 100644 --- a/pcbnew/tools/edit_points.h +++ b/pcbnew/tools/edit_points.h @@ -58,9 +58,19 @@ public: /** * Function Apply() * - * Corrects coordinates of the constrained point. + * Corrects coordinates of the constrained edit handle. */ - virtual void Apply() = 0; + virtual void Apply( EDIT_TYPE& aHandle ) = 0; + + /** + * Function Apply() + * + * Corrects coordinates of the constrained edit handle. + */ + void Apply() + { + Apply( m_constrained ); + } protected: EDIT_TYPE& m_constrained; ///< Point that is constrained by rules implemented by Apply() @@ -234,7 +244,7 @@ public: ///> @copydoc EDIT_POINT::GetPosition() virtual VECTOR2I GetPosition() const { - return m_origin.GetPosition() + ( m_end.GetPosition() - m_origin.GetPosition() ) / 2; + return ( m_origin.GetPosition() + m_end.GetPosition() ) / 2; } ///> @copydoc EDIT_POINT::GetPosition() @@ -266,6 +276,11 @@ public: return m_origin; } + const EDIT_POINT& GetOrigin() const + { + return m_origin; + } + /** * Function GetEnd() * @@ -276,6 +291,11 @@ public: return m_end; } + const EDIT_POINT& GetEnd() const + { + return m_end; + } + bool operator==( const EDIT_POINT& aOther ) const { return GetPosition() == aOther.GetPosition(); @@ -458,11 +478,11 @@ public: {} ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply() + virtual void Apply( EDIT_POINT& aHandle ) { - VECTOR2I point = m_constrained.GetPosition(); + VECTOR2I point = aHandle.GetPosition(); point.x = m_constrainer.GetPosition().x; - m_constrained.SetPosition( point ); + aHandle.SetPosition( point ); } private: @@ -489,11 +509,11 @@ public: {} ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply() + virtual void Apply( EDIT_POINT& aHandle ) { - VECTOR2I point = m_constrained.GetPosition(); + VECTOR2I point = aHandle.GetPosition(); point.y = m_constrainer.GetPosition().y; - m_constrained.SetPosition( point ); + aHandle.SetPosition( point ); } private: @@ -521,7 +541,7 @@ public: {} ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply(); + virtual void Apply( EDIT_POINT& aHandle ); private: const EDIT_POINT& m_constrainer; ///< Point that imposes the constraint. @@ -540,12 +560,11 @@ public: EC_LINE( EDIT_POINT& aConstrained, const EDIT_POINT& aConstrainer ); ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply(); + virtual void Apply( EDIT_POINT& aHandle ); private: EDIT_POINT m_constrainer; ///< Point that imposes the constraint. - double m_coefA; ///< Line A coefficient (y = Ax + B) - double m_coefB; ///< Line B coefficient (y = Ax + B) + VECTOR2I m_line; ///< Vector representing the constraining line. }; @@ -569,7 +588,7 @@ public: {} ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply(); + virtual void Apply( EDIT_POINT& aHandle ); private: ///> Point that imposes the constraint (center of the circle). @@ -594,14 +613,23 @@ public: virtual ~EC_CONVERGING(); ///> @copydoc EDIT_CONSTRAINT::Apply() - virtual void Apply(); + virtual void Apply( EDIT_POINT& aHandle ); 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) + ///> Constraint for origin side segment. + EDIT_CONSTRAINT* m_originSideConstraint; + + ///> Constraint for end side segment. + EDIT_CONSTRAINT* m_endSideConstraint; + + ///> Dragged segment. + EDIT_LINE& m_line; + + ///> EDIT_POINTS instance that stores currently modified lines. + EDIT_POINTS& m_editPoints; + + ///> Vector that represents the initial direction of the dragged segment. + VECTOR2I m_draggedVector; }; #endif /* EDIT_POINTS_H_ */