From b83dac68d02608f36b88cdd1ee041b7e2f0f67a8 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 10 May 2019 23:24:27 +0100 Subject: [PATCH] Fix drag-select hit-testing of LibEdit items. --- eeschema/lib_arc.cpp | 18 +++++++++++++----- eeschema/lib_bezier.cpp | 31 ++++++++++++++++++++++++++----- eeschema/lib_circle.cpp | 15 +++++++++++---- eeschema/lib_draw_item.cpp | 8 ++++---- eeschema/lib_polyline.cpp | 31 ++++++++++++++++++++++++++----- pcbnew/class_drawsegment.cpp | 1 - 6 files changed, 80 insertions(+), 24 deletions(-) diff --git a/eeschema/lib_arc.cpp b/eeschema/lib_arc.cpp index 8e11a72cd6..d54d4fd05a 100644 --- a/eeschema/lib_arc.cpp +++ b/eeschema/lib_arc.cpp @@ -109,16 +109,24 @@ bool LIB_ARC::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) c if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) return false; - EDA_RECT rect = DefaultTransform.TransformCoordinate( aRect ); + wxPoint center = DefaultTransform.TransformCoordinate( GetPosition() ); + int radius = GetRadius(); + int lineWidth = GetWidth(); + EDA_RECT sel = aRect ; if ( aAccuracy ) - rect.Inflate( aAccuracy ); + sel.Inflate( aAccuracy ); if( aContained ) - return rect.Contains( GetBoundingBox() ); + return sel.Contains( GetBoundingBox() ); - return rect.Intersects( GetBoundingBox() ); // JEY TODO somewhat coarse for filled arcs, - // egregiously coarse for unfilled... + EDA_RECT arcRect = GetBoundingBox().Common( sel ); + + /* All following tests must pass: + * 1. Rectangle must intersect arc BoundingBox + * 2. Rectangle must cross the outside of the arc + */ + return arcRect.Intersects( sel ) && arcRect.IntersectsCircleEdge( center, radius, lineWidth ); } diff --git a/eeschema/lib_bezier.cpp b/eeschema/lib_bezier.cpp index 85fe6592fc..61453b2a10 100644 --- a/eeschema/lib_bezier.cpp +++ b/eeschema/lib_bezier.cpp @@ -289,16 +289,37 @@ bool LIB_BEZIER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) return false; - EDA_RECT rect = DefaultTransform.TransformCoordinate( aRect ); + EDA_RECT sel = aRect; if ( aAccuracy ) - rect.Inflate( aAccuracy ); + sel.Inflate( aAccuracy ); if( aContained ) - return rect.Contains( GetBoundingBox() ); + return sel.Contains( GetBoundingBox() ); - return rect.Intersects( GetBoundingBox() ); // JEY TODO somewhat coarse for filled beziers, - // egregiously coarse for unfilled... + // Fast test: if aRect is outside the polygon bounding box, rectangles cannot intersect + if( !sel.Intersects( GetBoundingBox() ) ) + return false; + + // Account for the width of the line + sel.Inflate( GetWidth() / 2 ); + unsigned count = m_BezierPoints.size(); + + for( unsigned ii = 1; ii < count; ii++ ) + { + wxPoint vertex = DefaultTransform.TransformCoordinate( m_BezierPoints[ii-1] ); + wxPoint vertexNext = DefaultTransform.TransformCoordinate( m_BezierPoints[ii] ); + + // Test if the point is within aRect + if( sel.Contains( vertex ) ) + return true; + + // Test if this edge intersects aRect + if( sel.Intersects( vertex, vertexNext ) ) + return true; + } + + return false; } diff --git a/eeschema/lib_circle.cpp b/eeschema/lib_circle.cpp index 77cab3b651..53530534a5 100644 --- a/eeschema/lib_circle.cpp +++ b/eeschema/lib_circle.cpp @@ -68,15 +68,22 @@ bool LIB_CIRCLE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) return false; - EDA_RECT rect = DefaultTransform.TransformCoordinate( aRect ); + wxPoint center = DefaultTransform.TransformCoordinate( GetPosition() ); + int radius = GetRadius(); + int lineWidth = GetWidth(); + EDA_RECT sel = aRect ; if ( aAccuracy ) - rect.Inflate( aAccuracy ); + sel.Inflate( aAccuracy ); if( aContained ) - return rect.Contains( GetBoundingBox() ); + return sel.Contains( GetBoundingBox() ); - return rect.Intersects( GetBoundingBox() ); // JEY TODO somewhat coarse... + // If the rectangle does not intersect the bounding box, this is a much quicker test + if( !sel.Intersects( GetBoundingBox() ) ) + return false; + else + return sel.IntersectsCircleEdge( center, radius, lineWidth ); } diff --git a/eeschema/lib_draw_item.cpp b/eeschema/lib_draw_item.cpp index bfc7c58492..9cb2dfe68d 100644 --- a/eeschema/lib_draw_item.cpp +++ b/eeschema/lib_draw_item.cpp @@ -112,15 +112,15 @@ bool LIB_ITEM::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) return false; - EDA_RECT rect = DefaultTransform.TransformCoordinate( aRect ); + EDA_RECT sel = aRect; if ( aAccuracy ) - rect.Inflate( aAccuracy ); + sel.Inflate( aAccuracy ); if( aContained ) - return rect.Contains( GetBoundingBox() ); + return sel.Contains( GetBoundingBox() ); - return rect.Intersects( GetBoundingBox() ); + return sel.Intersects( GetBoundingBox() ); } diff --git a/eeschema/lib_polyline.cpp b/eeschema/lib_polyline.cpp index 01249f62d6..93371dfc02 100644 --- a/eeschema/lib_polyline.cpp +++ b/eeschema/lib_polyline.cpp @@ -263,16 +263,37 @@ bool LIB_POLYLINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccurac if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) ) return false; - EDA_RECT rect = aRect; + EDA_RECT sel = aRect; if ( aAccuracy ) - rect.Inflate( aAccuracy ); + sel.Inflate( aAccuracy ); if( aContained ) - return rect.Contains( GetBoundingBox() ); + return sel.Contains( GetBoundingBox() ); - return rect.Intersects( GetBoundingBox() ); // JEY TODO somewhat coarse for filled polylines, - // egregiously coarse for unfilled... + // Fast test: if rect is outside the polygon bounding box, then they cannot intersect + if( !sel.Intersects( GetBoundingBox() ) ) + return false; + + // Account for the width of the line + sel.Inflate( GetWidth() / 2 ); + int count = m_PolyPoints.size(); + + for( int ii = 0; ii < count; ii++ ) + { + wxPoint pt = DefaultTransform.TransformCoordinate( m_PolyPoints[ ii ] ); + wxPoint ptNext = DefaultTransform.TransformCoordinate( m_PolyPoints[ (ii+1) % count ] ); + + // Test if the point is within aRect + if( sel.Contains( pt ) ) + return true; + + // Test if this edge intersects aRect + if( sel.Intersects( pt, ptNext ) ) + return true; + } + + return false; } diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index 7b8e083886..5cce96c2a9 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -740,7 +740,6 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy { return arect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() ); } - } break;