From 5f8e0ef1e07616c37a6ffb913cac0a3ebeb3f7c5 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 30 Oct 2021 15:08:44 +0100 Subject: [PATCH] Patch up arc hit-testing and printing for 6.0 This could use another look when we're not so near release. We really shouldn't need to special case eeWinding vs. not eeWinding. Fixes https://gitlab.com/kicad/code/kicad/issues/9491 --- common/eda_shape.cpp | 81 +++++++++++++++++++++++------------------- eeschema/lib_shape.cpp | 9 +++-- include/eda_shape.h | 3 +- pcbnew/pcb_shape.cpp | 4 +-- 4 files changed, 55 insertions(+), 42 deletions(-) diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index b2e41e2458..2b5015a1da 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -37,12 +37,13 @@ #include -EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ) : +EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill, bool eeWinding ) : m_endsSwapped( false ), m_shape( aType ), m_width( aLineWidth ), m_fill( aFill ), - m_editState( 0 ) + m_editState( 0 ), + m_eeWinding( eeWinding ) { } @@ -691,16 +692,19 @@ bool EDA_SHAPE::hitTest( const wxPoint& aPosition, int aAccuracy ) const double endAngle; CalcArcAngles( startAngle, endAngle ); + if( m_eeWinding && NormalizeAngleDegrees( startAngle - endAngle, -180.0, 180.0 ) > 0 ) + std::swap( startAngle, endAngle ); + double relPosAngle = 180.0 / M_PI * atan2( relPos.y, relPos.x ); - if( relPosAngle >= startAngle && relPosAngle <= endAngle ) - return true; - + startAngle = NormalizeAngleDegrees( startAngle, 0.0, 360.0 ); + endAngle = NormalizeAngleDegrees( endAngle, 0.0, 360.0 ); relPosAngle = NormalizeAngleDegrees( relPosAngle, 0.0, 360.0 ); - if( relPosAngle >= startAngle && relPosAngle <= endAngle ) - return true; - + if( endAngle > startAngle ) + return relPosAngle >= startAngle && relPosAngle <= endAngle; + else + return relPosAngle >= startAngle || relPosAngle <= endAngle; } return false; @@ -974,36 +978,52 @@ std::vector EDA_SHAPE::GetRectCorners() const void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const { - // Do not include the center, which is not necessarily - // inside the BB of a arc with a small angle - aBBox.SetOrigin( m_start ); - aBBox.Merge( m_end ); + wxPoint start = m_start; + wxPoint end = m_end; + double t1, t2; + + CalcArcAngles( t1, t2 ); + + if( m_eeWinding && NormalizeAngleDegrees( t1 - t2, -180.0, 180.0 ) > 0 ) + std::swap( start, end ); + + // Do not include the center, which is not necessarily inside the BB of an arc with a small + // included angle + aBBox.SetOrigin( start ); + aBBox.Merge( end ); // Determine the starting quarter // 0 right-bottom // 1 left-bottom // 2 left-top // 3 right-top - unsigned int quarter = 0; // assume right-bottom + unsigned int quarter; - if( m_start.x < m_arcCenter.x ) + if( start.x < m_arcCenter.x ) { - if( m_start.y <= m_arcCenter.y ) + if( start.y <= m_arcCenter.y ) quarter = 2; - else // ( m_start.y > m_arcCenter.y ) + else quarter = 1; } - else if( m_start.x >= m_arcCenter.x ) + else if( start.x == m_arcCenter.x ) { - if( m_start.y < m_arcCenter.y ) + if( start.y < m_arcCenter.y ) quarter = 3; - else if( m_start.x == m_arcCenter.x ) + else quarter = 1; } + else + { + if( start.y < m_arcCenter.y ) + quarter = 3; + else + quarter = 0; + } int radius = GetRadius(); - VECTOR2I startRadial = GetStart() - getCenter(); - VECTOR2I endRadial = GetEnd() - getCenter(); + VECTOR2I startRadial = start - m_arcCenter; + VECTOR2I endRadial = end - m_arcCenter; double angleStart = ArcTangente( startRadial.y, startRadial.x ); double arcAngle = RAD2DECIDEG( endRadial.Angle() - startRadial.Angle() ); int angle = (int) NormalizeAnglePos( angleStart ) % 900 + NormalizeAnglePos( arcAngle ); @@ -1012,21 +1032,10 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const { switch( quarter ) { - case 0: - aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y + radius ) ); - break; // down - - case 1: - aBBox.Merge( wxPoint( m_arcCenter.x - radius, m_arcCenter.y ) ); - break; // left - - case 2: - aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y - radius ) ); - break; // up - - case 3: - aBBox.Merge( wxPoint( m_arcCenter.x + radius, m_arcCenter.y ) ); - break; // right + case 0: aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y + radius ) ); break; // down + case 1: aBBox.Merge( wxPoint( m_arcCenter.x - radius, m_arcCenter.y ) ); break; // left + case 2: aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y - radius ) ); break; // up + case 3: aBBox.Merge( wxPoint( m_arcCenter.x + radius, m_arcCenter.y ) ); break; // right } ++quarter %= 4; diff --git a/eeschema/lib_shape.cpp b/eeschema/lib_shape.cpp index 5ba87f991d..1b2f4fd2bf 100644 --- a/eeschema/lib_shape.cpp +++ b/eeschema/lib_shape.cpp @@ -36,7 +36,7 @@ LIB_SHAPE::LIB_SHAPE( LIB_SYMBOL* aParent, SHAPE_T aShape, int aDefaultLineWidth, FILL_T aFillType ) : LIB_ITEM( LIB_SHAPE_T, aParent ), - EDA_SHAPE( aShape, aDefaultLineWidth, aFillType ) + EDA_SHAPE( aShape, aDefaultLineWidth, aFillType, true ) { m_editState = 0; } @@ -255,8 +255,11 @@ void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, CalcArcAngles( t1, t2 ); - if( t1 > t2 ) - aTransform.MapAngles( &t1, &t2 ); + if( NormalizeAngle180( t1 - t2 ) > 0 ) + { + std::swap( pt1, pt2 ); + std::swap( t1, t2 ); + } } if( forceNoFill || GetFillType() == FILL_T::NO_FILL ) diff --git a/include/eda_shape.h b/include/eda_shape.h index d5305504ec..d0ba4ef75b 100644 --- a/include/eda_shape.h +++ b/include/eda_shape.h @@ -62,7 +62,7 @@ enum class FILL_T : int class EDA_SHAPE { public: - EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ); + EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill, bool eeWinding ); // Do not create a copy constructor & operator=. // The ones generated by the compiler are adequate. @@ -308,6 +308,7 @@ protected: SHAPE_POLY_SET m_poly; // Stores the S_POLYGON shape int m_editState; + bool m_eeWinding; // Awful hack }; #endif // EDA_SHAPE_H diff --git a/pcbnew/pcb_shape.cpp b/pcbnew/pcb_shape.cpp index eac4f78c25..d97ea2685d 100644 --- a/pcbnew/pcb_shape.cpp +++ b/pcbnew/pcb_shape.cpp @@ -35,14 +35,14 @@ PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T idtype, SHAPE_T shapetype ) : BOARD_ITEM( aParent, idtype ), - EDA_SHAPE( shapetype, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL ) + EDA_SHAPE( shapetype, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL, false ) { } PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, SHAPE_T shapetype ) : BOARD_ITEM( aParent, PCB_SHAPE_T ), - EDA_SHAPE( shapetype, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL ) + EDA_SHAPE( shapetype, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL, false ) { }