From e9713bb291cdf718ead186275a045101f04ef5b9 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 21 Sep 2013 20:09:41 +0200 Subject: [PATCH] Pcbnew: Block selection enhancement, from Bug #593997 (whishlist) 1. block created from-left-to-right selects only 100%inside selection objects (as it now does) 2.block created from-right-to-left selects all overlapping objects inside selection From the patch sent by mathieulj (mathieulj), and some fixes and code cleaning. --- common/base_struct.cpp | 30 +++++++++++ common/trigo.cpp | 69 ++++++++++++++++++++++++- include/base_struct.h | 26 +++++----- include/class_board_item.h | 20 +++++++ include/trigo.h | 13 +++++ pcbnew/block.cpp | 21 ++++---- pcbnew/class_dimension.cpp | 15 ++++-- pcbnew/class_dimension.h | 5 +- pcbnew/class_drawsegment.cpp | 50 ++++++++++++------ pcbnew/class_drawsegment.h | 5 +- pcbnew/class_mire.cpp | 11 ++-- pcbnew/class_mire.h | 5 +- pcbnew/class_module.cpp | 20 +++---- pcbnew/class_module.h | 5 +- pcbnew/class_pcb_text.h | 7 ++- pcbnew/class_track.cpp | 29 ++++++++--- pcbnew/class_track.h | 5 +- pcbnew/class_zone.cpp | 60 ++++++++++++++++----- pcbnew/class_zone.h | 25 ++++++++- pcbnew/zones_test_and_combine_areas.cpp | 8 +-- polygon/PolyLine.cpp | 13 ++--- polygon/PolyLine.h | 5 +- 22 files changed, 343 insertions(+), 104 deletions(-) diff --git a/common/base_struct.cpp b/common/base_struct.cpp index 37969c81fe..4af6994e9b 100644 --- a/common/base_struct.cpp +++ b/common/base_struct.cpp @@ -320,6 +320,36 @@ bool EDA_RECT::Contains( const EDA_RECT& aRect ) const } +/* Intersects + * test for a common area between segment and rect. + * return true if at least a common point is found + */ +bool EDA_RECT::Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2 ) const +{ + wxPoint point2, point4; + + if( Contains( aPoint1 ) || Contains( aPoint2 ) ) + return true; + + point2.x = GetEnd().x; + point2.y = GetOrigin().y; + point4.x = GetOrigin().x; + point4.y = GetEnd().y; + + //Only need to test 3 sides since a straight line cant enter and exit on same side + if( SegmentIntersectsSegment( aPoint1, aPoint2, GetOrigin() , point2 ) ) + return true; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, point2 , GetEnd() ) ) + return true; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, GetEnd() , point4 ) ) + return true; + + return false; +} + + /* Intersects * test for a common area between 2 rect. * return true if at least a common point is found diff --git a/common/trigo.cpp b/common/trigo.cpp index 160458eeb7..d41ae2b15f 100644 --- a/common/trigo.cpp +++ b/common/trigo.cpp @@ -9,6 +9,71 @@ #include #include + +bool SegmentIntersectsSegment( const wxPoint &a_p1_l1, const wxPoint &a_p2_l1, + const wxPoint &a_p1_l2, const wxPoint &a_p2_l2 ) +{ + + //We are forced to use 64bit ints because the internal units can oveflow 32bit ints when + // multiplied with each other, the alternative would be to scale the units down (i.e. divide + // by a fixed number). + long long dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab; + long long num_a, num_b, den; + + //Test for intersection within the bounds of both line segments using line equations of the + // form: + // x_k(u_k) = u_k * dX_k + x_k(0) + // y_k(u_k) = u_k * dY_k + y_k(0) + // with 0 <= u_k <= 1 and k = [ a, b ] + + dX_a = a_p2_l1.x - a_p1_l1.x; + dY_a = a_p2_l1.y - a_p1_l1.y; + dX_b = a_p2_l2.x - a_p1_l2.x; + dY_b = a_p2_l2.y - a_p1_l2.y; + dX_ab = a_p1_l2.x - a_p1_l1.x; + dY_ab = a_p1_l2.y - a_p1_l1.y; + + den = dY_a * dX_b - dY_b * dX_a ; + + //Check if lines are parallel + if( den == 0 ) + return false; + + num_a = dY_ab * dX_b - dY_b * dX_ab; + num_b = dY_ab * dX_a - dY_a * dX_ab; + + //We wont calculate directly the u_k of the intersection point to avoid floating point + // division but they could be calculated with: + // u_a = (float) num_a / (float) den; + // u_b = (float) num_b / (float) den; + + if( den < 0 ) + { + den = -den; + num_a = -num_a; + num_b = -num_b; + } + + //Test sign( u_a ) and return false if negative + if( num_a < 0 ) + return false; + + //Test sign( u_b ) and return false if negative + if( num_b < 0 ) + return false; + + //Test to ensure (u_a <= 1) + if( num_a > den ) + return false; + + //Test to ensure (u_b <= 1) + if( num_b > den ) + return false; + + return true; +} + + /* Function TestSegmentHit * test for hit on line segment * i.e. a reference point is within a given distance from segment @@ -29,7 +94,7 @@ static inline double square( int x ) // helper function to calculate x*x { return (double) x * x; } -bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, +bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist ) { // test for vertical or horizontal segment @@ -163,7 +228,7 @@ double ArcTangente( int dy, int dx ) /* gcc is surprisingly smart in optimizing these conditions in a tree! */ - + if( dx == 0 && dy == 0 ) return 0; diff --git a/include/base_struct.h b/include/base_struct.h index 0b3e15a899..2fce8196a3 100644 --- a/include/base_struct.h +++ b/include/base_struct.h @@ -300,11 +300,25 @@ public: /** * Function Intersects + * tests for a common area between rectangles. + * + * @param aRect A rectangle to test intersection with. * @return bool - true if the argument rectangle intersects this rectangle. * (i.e. if the 2 rectangles have at least a common point) */ bool Intersects( const EDA_RECT& aRect ) const; + /** + * Function Intersects + * tests for a common area between a segment and this rectangle. + * + * @param aPoint1 First point of the segment to test intersection with. + * @param aPoint2 Second point of the segment to test intersection with. + * @return bool - true if the argument segment intersects this rectangle. + * (i.e. if the segment and rectangle have at least a common point) + */ + bool Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2 ) const; + /** * Function operator(wxRect) * overloads the cast operator to return a wxRect @@ -530,18 +544,6 @@ public: return false; // derived classes should override this function } - /** - * Function HitTest - * tests if the \a aRect intersects this object. - * For now, an ending point must be inside \a aRect. - * - * @param aRect A reference to an EDA_RECT object containg the area to test. - * @return True if \a aRect intersects the object, otherwise false. - */ - virtual bool HitTest( const EDA_RECT& aRect ) const - { - return false; // derived classes should override this function - } /** * Function GetBoundingBox diff --git a/include/class_board_item.h b/include/class_board_item.h index 586490e5f6..2ac2862b41 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -223,6 +223,26 @@ public: */ wxString GetLayerName() const; + virtual bool HitTest( const wxPoint& aPosition ) + { + return EDA_ITEM::HitTest( aPosition ); + } + + /** + * Function HitTest + * tests if the \a aRect intersects or contains this object (depending on \a aContained). + * + * @param aRect A reference to an EDA_RECT object containg the area to test. + * @param aContained Test if \a aRect contains this object completly. + * @param aAccuracy Increase the item bounding box by this amount. + * @return bool - True if \a aRect contains this object completly or if \a aRect intersects + * the object and \a aContained is False, otherwise false. + */ + virtual bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0) const + { + return false; // derived classes should override this function + } + /** * Function FormatInternalUnits diff --git a/include/trigo.h b/include/trigo.h index ad6c345258..f7ced0916e 100644 --- a/include/trigo.h +++ b/include/trigo.h @@ -31,6 +31,19 @@ #include #include // For wxPoint +/** + * Function SegmentIntersectsSegment + * + * @param a_p1_l1 The first point of the first line. + * @param a_p2_l1 The second point of the first line. + * @param a_p1_l2 The first point of the second line. + * @param a_p2_l2 The second point of the second line. + * @return bool - true if the two segments defined by four points intersect. + * (i.e. if the 2 segments have at least a common point) + */ +bool SegmentIntersectsSegment( const wxPoint &a_p1_l1, const wxPoint &a_p2_l1, + const wxPoint &a_p1_l2, const wxPoint &a_p2_l2 ); + /* * Calculate the new point of coord coord pX, pY, * for a rotation center 0, 0, and angle in (1 / 10 degree) diff --git a/pcbnew/block.cpp b/pcbnew/block.cpp index 06d63ca524..bb86e61cfa 100644 --- a/pcbnew/block.cpp +++ b/pcbnew/block.cpp @@ -382,6 +382,7 @@ bool PCB_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) void PCB_EDIT_FRAME::Block_SelectItems() { LAYER_MSK layerMask; + bool selectOnlyComplete = GetScreen()->m_BlockLocate.GetWidth() > 0 ; GetScreen()->m_BlockLocate.Normalize(); @@ -395,7 +396,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() { LAYER_NUM layer = module->GetLayer(); - if( module->HitTest( GetScreen()->m_BlockLocate ) + if( module->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) && ( !module->IsLocked() || blockIncludeLockedModules ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) ) @@ -410,14 +411,14 @@ void PCB_EDIT_FRAME::Block_SelectItems() // Add tracks and vias if( blockIncludeTracks ) { - for( TRACK* pt_segm = m_Pcb->m_Track; pt_segm != NULL; pt_segm = pt_segm->Next() ) + for( TRACK* track = m_Pcb->m_Track; track != NULL; track = track->Next() ) { - if( pt_segm->HitTest( GetScreen()->m_BlockLocate ) ) + if( track->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) { if( blockIncludeItemsOnInvisibleLayers - || m_Pcb->IsLayerVisible( pt_segm->GetLayer() ) ) + || m_Pcb->IsLayerVisible( track->GetLayer() ) ) { - picker.SetItem ( pt_segm ); + picker.SetItem ( track ); itemsList->PushItem( picker ); } } @@ -446,7 +447,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() if( (GetLayerMask( PtStruct->GetLayer() ) & layerMask) == 0 ) break; - if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) + if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it @@ -456,7 +457,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() if( !blockIncludePcbTexts ) break; - if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) + if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it @@ -466,7 +467,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) break; - if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) + if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it @@ -476,7 +477,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) break; - if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) + if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) break; select_me = true; // This item is in bloc: select it @@ -500,7 +501,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() { ZONE_CONTAINER* area = m_Pcb->GetArea( ii ); - if( area->HitTest( GetScreen()->m_BlockLocate ) ) + if( area->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) ) { if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsLayerVisible( area->GetLayer() ) ) diff --git a/pcbnew/class_dimension.cpp b/pcbnew/class_dimension.cpp index 6a2cfb407b..b124bb9712 100644 --- a/pcbnew/class_dimension.cpp +++ b/pcbnew/class_dimension.cpp @@ -430,12 +430,19 @@ bool DIMENSION::HitTest( const wxPoint& aPosition ) } -bool DIMENSION::HitTest( const EDA_RECT& aRect ) const +bool DIMENSION::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { - if( aRect.Contains( GetPosition() ) ) - return true; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); - return false; + EDA_RECT rect = GetBoundingBox(); + if( aAccuracy ) + rect.Inflate( aAccuracy ); + + if( aContained ) + return arect.Contains( rect ); + + return arect.Intersects( rect ); } diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index a04920cce4..fd9414f9b8 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -129,7 +129,10 @@ public: bool HitTest( const wxPoint& aPosition ); - bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; wxString GetClass() const { diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index 2a6fb5ef39..62126b2fca 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -494,30 +494,48 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) } -bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect ) const +bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { + wxPoint p1, p2; + int radius; + float theta; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); + switch( m_Shape ) { case S_CIRCLE: - { - int radius = GetRadius(); - - // Text if area intersects the circle: - EDA_RECT area = aRect; - area.Inflate( radius ); - - if( area.Contains( m_Start ) ) - return true; - } + // Test if area intersects or contains the circle: + if( aContained ) + return arect.Contains( GetBoundingBox() ); + else + return arect.Intersects( GetBoundingBox() ); break; case S_ARC: - case S_SEGMENT: - if( aRect.Contains( GetStart() ) ) - return true; + radius = hypot( (double)( GetEnd().x - GetStart().x ), + (double)( GetEnd().y - GetStart().y ) ); + theta = std::atan2( GetEnd().y - GetStart().y , GetEnd().x - GetStart().x ); + + //Approximate the arc with two lines. This should be accurate enough for selection. + p1.x = radius * std::cos( theta + M_PI/4 ) + GetStart().x; + p1.y = radius * std::sin( theta + M_PI/4 ) + GetStart().y; + p2.x = radius * std::cos( theta + M_PI/2 ) + GetStart().x; + p2.y = radius * std::sin( theta + M_PI/2 ) + GetStart().y; + + if( aContained ) + return arect.Contains( GetEnd() ) && aRect.Contains( p1 ) && aRect.Contains( p2 ); + else + return arect.Intersects( GetEnd(), p1 ) || aRect.Intersects( p1, p2 ); + + break; + + case S_SEGMENT: + if( aContained ) + return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() ); + else + return arect.Intersects( GetStart(), GetEnd() ); - if( aRect.Contains( GetEnd() ) ) - return true; break; default: diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 757e973eb0..f0c895ef35 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -172,7 +172,10 @@ public: virtual bool HitTest( const wxPoint& aPosition ); - virtual bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; wxString GetClass() const { diff --git a/pcbnew/class_mire.cpp b/pcbnew/class_mire.cpp index e6acf880eb..f03413cd4b 100644 --- a/pcbnew/class_mire.cpp +++ b/pcbnew/class_mire.cpp @@ -178,10 +178,15 @@ bool PCB_TARGET::HitTest( const wxPoint& aPosition ) } -bool PCB_TARGET::HitTest( const EDA_RECT& aRect ) const +bool PCB_TARGET::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { - if( aRect.Contains( m_Pos ) ) - return true; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); + + if( aContained ) + return arect.Contains( GetBoundingBox() ); + else + return GetBoundingBox().Intersects( arect ); return false; } diff --git a/pcbnew/class_mire.h b/pcbnew/class_mire.h index 32f02dd103..8d6f240db5 100644 --- a/pcbnew/class_mire.h +++ b/pcbnew/class_mire.h @@ -93,7 +93,10 @@ public: bool HitTest( const wxPoint& aPosition ); - bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; EDA_RECT GetBoundingBox() const; diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index aef466c887..96a6ee1949 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -555,21 +555,15 @@ bool MODULE::HitTest( const wxPoint& aPosition ) } -bool MODULE::HitTest( const EDA_RECT& aRect ) const +bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { - if( m_BoundaryBox.GetX() < aRect.GetX() ) - return false; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); - if( m_BoundaryBox.GetY() < aRect.GetY() ) - return false; - - if( m_BoundaryBox.GetRight() > aRect.GetRight() ) - return false; - - if( m_BoundaryBox.GetBottom() > aRect.GetBottom() ) - return false; - - return true; + if( aContained ) + return arect.Contains( m_BoundaryBox ); + else + return m_BoundaryBox.Intersects( arect ); } diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index ad83e94f8c..e7fd39ec23 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -318,7 +318,10 @@ public: bool HitTest( const wxPoint& aPosition ); - bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; /** * Function GetReference diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index 6bae690be1..8bdf10163d 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -71,9 +71,12 @@ public: return TextHitTest( aPosition ); } - bool HitTest( const EDA_RECT& aRect ) const + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const { - return TextHitTest( aRect ); + return TextHitTest( aRect, aContained, aAccuracy ); } wxString GetClass() const diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index a7b64bc949..13dfc6a853 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -1186,15 +1186,32 @@ bool TRACK::HitTest( const wxPoint& aPosition ) } -bool TRACK::HitTest( const EDA_RECT& aRect ) const +bool TRACK::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { - if( aRect.Contains( m_Start ) ) - return true; + EDA_RECT box; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); - if( aRect.Contains( m_End ) ) - return true; + if( Type() == PCB_VIA_T ) + { + box.SetOrigin( GetStart() ); + box.Inflate( GetWidth() >> 1 ); - return false; + if(aContained) + return arect.Contains( box ); + else + return arect.Intersects( box ); + } + else + { + if( aContained ) + // Tracks are a specila case: + // they are considered inside the rect if one end + // is inside the rect + return arect.Contains( GetStart() ) || arect.Contains( GetEnd() ); + else + return arect.Intersects( GetStart(), GetEnd() ); + } } diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index d4a79a1545..a9775234cc 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -257,7 +257,10 @@ public: virtual bool HitTest( const wxPoint& aPosition ); - virtual bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; /** * Function GetVia diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 085d7e9b61..94f19b8484 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -557,25 +557,61 @@ bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) } -bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect ) const +bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const { - bool is_out_of_box = false; + EDA_RECT arect = aRect; + arect.Inflate( aAccuracy ); + CRect rect = m_Poly->GetBoundingBox(); + EDA_RECT bbox; - CRect rect = m_Poly->GetCornerBounds(); + bbox.SetOrigin( rect.left, rect.bottom ); + bbox.SetEnd( rect.right, rect.top ); - if( rect.left < aRect.GetX() ) - is_out_of_box = true; + if( aContained ) + return arect.Contains( bbox ); + else // Test for intersection between aRect and the polygon + // For a polygon, using its bounding box has no sense here + { + // Fast test: if aRect is outside the polygon bounding box, + // rectangles cannot intersect + if( ! bbox.Intersects( arect ) ) + return false; - if( rect.top < aRect.GetY() ) - is_out_of_box = true; + // aRect is inside the polygon bounding box, + // and can intersect the polygon: use a fine test. + // aRect intersects the polygon if at least one aRect corner + // is inside the polygon + wxPoint corner = arect.GetOrigin(); - if( rect.right > aRect.GetRight() ) - is_out_of_box = true; + if( HitTestInsideZone( corner ) ) + return true; - if( rect.bottom > aRect.GetBottom() ) - is_out_of_box = true; + corner.x = arect.GetEnd().x; - return is_out_of_box ? false : true; + if( HitTestInsideZone( corner ) ) + return true; + + corner = arect.GetEnd(); + + if( HitTestInsideZone( corner ) ) + return true; + + corner.x = arect.GetOrigin().x; + + if( HitTestInsideZone( corner ) ) + return true; + + // No corner inside arect, but outlines can intersect arect + // if one of outline corners is inside arect + int count = m_Poly->GetCornersCount(); + for( int ii =0; ii < count; ii++ ) + { + if( arect.Contains( m_Poly->GetPos( ii ) ) ) + return true; + } + + return false; + } } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 45fcafbfea..27816806b6 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -151,7 +151,7 @@ public: void DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode = GR_OR ); - /* Function GetBoundingBox + /** Function GetBoundingBox * @return an EDA_RECT that is the bounding box of the zone outline */ EDA_RECT GetBoundingBox() const; @@ -253,8 +253,26 @@ public: void SetOutline( CPolyLine* aOutline ) { m_Poly = aOutline; } + /** + * Function HitTest + * tests if a point is near an outline edge or a corner of this zone. + * @param aRefPos A wxPoint to test + * @return bool - true if a hit, else false + */ virtual bool HitTest( const wxPoint& aPosition ); + /** + * Function HitTest + * tests if a point is inside the zone area, i.e. inside the main outline + * and outside holes. + * @param aRefPos A wxPoint to test + * @return bool - true if a hit, else false + */ + bool HitTestInsideZone( const wxPoint& aPosition ) const + { + return m_Poly->TestPointInside( aPosition.x, aPosition.y ); + } + /** * Function HitTestFilledArea * tests if the given wxPoint is within the bounds of a filled area of this zone. @@ -360,7 +378,10 @@ public: */ bool HitTestForEdge( const wxPoint& refPos ); - virtual bool HitTest( const EDA_RECT& aRect ) const; + /** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, + * bool aContained = true, int aAccuracy ) const + */ + bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const; /** * Function Fill_Zone diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index b967f5cead..362d469daa 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -102,7 +102,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, continue; // legal polygon - CRect b1 = curr_area->Outline()->GetCornerBounds(); + CRect b1 = curr_area->Outline()->GetBoundingBox(); bool mod_ia1 = false; for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- ) @@ -121,7 +121,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, if( curr_area->GetLayer() != area2->GetLayer() ) continue; - CRect b2 = area2->Outline()->GetCornerBounds(); + CRect b2 = area2->Outline()->GetBoundingBox(); if( !( b1.left > b2.right || b1.right < b2.left || b1.bottom > b2.top || b1.top < b2.bottom ) ) @@ -194,8 +194,8 @@ bool BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area CPolyLine* poly2 = area_to_test->Outline(); // test bounding rects - CRect b1 = poly1->GetCornerBounds(); - CRect b2 = poly2->GetCornerBounds(); + CRect b1 = poly1->GetBoundingBox(); + CRect b2 = poly2->GetBoundingBox(); if( b1.bottom > b2.top || b1.top < b2.bottom || b1.left > b2.right || b1.right < b2.left ) diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index d134aafdac..6947b79eaa 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -582,14 +582,7 @@ int CPolyLine::GetEndContour( int ic ) } -CRect CPolyLine::GetBounds() -{ - CRect r = GetCornerBounds(); - return r; -} - - -CRect CPolyLine::GetCornerBounds() +CRect CPolyLine::GetBoundingBox() { CRect r; @@ -608,7 +601,7 @@ CRect CPolyLine::GetCornerBounds() } -CRect CPolyLine::GetCornerBounds( int icont ) +CRect CPolyLine::GetBoundingBox( int icont ) { CRect r; @@ -1381,7 +1374,7 @@ bool CPolyLine::IsPolygonSelfIntersecting() cr.reserve( n_cont ); for( int icont = 0; icont