From ef326260c2034d576c112844b303b53f7fb8b498 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Thu, 5 Jul 2012 11:29:42 +0200 Subject: [PATCH] Pcbnew: fix incorrect detection of arcs having angles != 90 degrees --- pcbnew/class_board.cpp | 4 +- pcbnew/class_drawsegment.cpp | 88 ++++++++++++++++-------------------- pcbnew/class_drawsegment.h | 6 +++ 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 02a07d1ec7..a495faf219 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -376,8 +376,8 @@ wxString BOARD::GetLayerName( int aLayerIndex, bool aTranslate ) const // Default layer names are statically initialized, -// because we want the Enghish name and the translation -// The Enghish name is stored here, and to get the tranlation +// because we want the English name and the translation +// The English name is stored here, and to get the tranlation // wxGetTranslation must be called explicitely static const wxChar * layer_FRONT_name = _( "Front" ); static const wxChar * layer_INNER1_name = _( "Inner1" ); diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index 2984d7c6c1..157f52907e 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -112,7 +112,6 @@ void DRAWSEGMENT::Flip( const wxPoint& aCentre ) SetLayer( BOARD::ReturnFlippedLayerNumber( GetLayer() ) ); } - const wxPoint DRAWSEGMENT::GetArcEnd() const { wxPoint endPoint; // start of arc @@ -134,45 +133,23 @@ const wxPoint DRAWSEGMENT::GetArcEnd() const return endPoint; // after rotation, the end of the arc. } - -/* use GetArcStart() now -const wxPoint DRAWSEGMENT::GetStart() const +const double DRAWSEGMENT::GetArcAngleStart() const { - switch( m_Shape ) - { - case S_ARC: - return m_End; // the start of the arc is held in field m_End, center point is in m_Start. + // due to the Y axis orient atan2 needs - y value + double angleStart = atan2( (double)(GetArcStart().y - GetCenter().y), + (double)(GetArcStart().x - GetCenter().x) ); + // angleStart is in radians, convert it in 1/10 degrees + angleStart = angleStart / M_PI * 1800.0; - case S_SEGMENT: - default: - return m_Start; - } + // Normalize it to 0 ... 360 deg, to avoid discontinuity for angles near 180 deg + // because 180 deg and -180 are very near angles when ampping betewwen -180 ... 180 deg. + // and this is not easy to handle in calculations + if( angleStart < 0 ) + angleStart += 3600.0; + + return angleStart; } - -const wxPoint DRAWSEGMENT::GetEnd() const -{ - wxPoint endPoint; // start of arc - - switch( m_Shape ) - { - case S_ARC: - // rotate the starting point of the arc, given by m_End, through the - // angle m_Angle to get the ending point of the arc. - // m_Start is the arc centre - endPoint = m_End; // m_End = start point of arc - RotatePoint( &endPoint, m_Start, -m_Angle ); - return endPoint; // after rotation, the end of the arc. - break; - - case S_SEGMENT: - default: - return m_End; - } -} -*/ - - void DRAWSEGMENT::SetAngle( double aAngle ) { NORMALIZE_ANGLE_360( aAngle ); @@ -450,14 +427,12 @@ EDA_RECT DRAWSEGMENT::GetBoundingBox() const bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) { - /* Calculate coordinates to test relative to segment origin. */ - wxPoint relPos = aPosition - m_Start; - switch( m_Shape ) { case S_CIRCLE: case S_ARC: { + wxPoint relPos = aPosition - GetCenter(); int radius = GetRadius(); int dist = (int) hypot( (double) relPos.x, (double) relPos.y ); @@ -466,18 +441,35 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) if( m_Shape == S_CIRCLE ) return true; - wxPoint startVec = wxPoint( m_End.x - m_Start.x, m_End.y - m_Start.y ); - wxPoint endVec = m_End - m_Start; - RotatePoint( &endVec, -m_Angle ); + // For arcs, the test point angle must be >= arc angle start + // and <= arc angle end + // However angle values > 360 deg are not easy to handle + // so we calculate the relative angle between arc start point and teast point + // this relative arc should be < arc angle if arc angle > 0 (CW arc) + // and > arc angle if arc angle < 0 (CCW arc) + double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg - // Check dot products - if( (long long)relPos.x*startVec.x + (long long)relPos.y*startVec.y < 0 ) - return false; + double arc_hittest = atan2( (double) relPos.y, (double) relPos.x ); + arc_hittest = arc_hittest / M_PI * 1800; // angles are in 1/10 deg - if( (long long)relPos.x*endVec.x + (long long)relPos.y*endVec.y < 0 ) - return false; + // Calculate relative angle between the starting point of the arc, and the test point + arc_hittest -= arc_angle_start; - return true; + // Normalise arc_hittest between 0 ... 360 deg + NORMALIZE_ANGLE_POS( arc_hittest ); + + // Check angle: inside the arc angle when it is > 0 + // and outside the not drawn arc when it is < 0 + if( GetAngle() >= 0.0 ) + { + if( arc_hittest <= GetAngle() ) + return true; + } + else + { + if( arc_hittest >= (3600.0 + GetAngle()) ) + return true; + } } } break; diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 048d355251..dc2b745919 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -120,6 +120,12 @@ public: const wxPoint& GetArcStart() const { return m_End; } const wxPoint GetArcEnd() const; + /** + * function GetArcAngleStart() + * @return the angle of the stating point of this arc, between 0 and 3600 in 0.1 deg + */ + const double GetArcAngleStart() const; + /** * Function GetRadius * returns the radius of this item