Commit e9713bb2 authored by jean-pierre charras's avatar jean-pierre charras

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.
parent d5ecafd5
...@@ -320,6 +320,36 @@ bool EDA_RECT::Contains( const EDA_RECT& aRect ) const ...@@ -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 /* Intersects
* test for a common area between 2 rect. * test for a common area between 2 rect.
* return true if at least a common point is found * return true if at least a common point is found
......
...@@ -9,6 +9,71 @@ ...@@ -9,6 +9,71 @@
#include <common.h> #include <common.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
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 /* Function TestSegmentHit
* test for hit on line segment * test for hit on line segment
* i.e. a reference point is within a given distance from 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 ...@@ -29,7 +94,7 @@ static inline double square( int x ) // helper function to calculate x*x
{ {
return (double) x * x; return (double) x * x;
} }
bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart,
wxPoint aEnd, int aDist ) wxPoint aEnd, int aDist )
{ {
// test for vertical or horizontal segment // test for vertical or horizontal segment
...@@ -163,7 +228,7 @@ double ArcTangente( int dy, int dx ) ...@@ -163,7 +228,7 @@ double ArcTangente( int dy, int dx )
/* gcc is surprisingly smart in optimizing these conditions in /* gcc is surprisingly smart in optimizing these conditions in
a tree! */ a tree! */
if( dx == 0 && dy == 0 ) if( dx == 0 && dy == 0 )
return 0; return 0;
......
...@@ -300,11 +300,25 @@ public: ...@@ -300,11 +300,25 @@ public:
/** /**
* Function Intersects * 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. * @return bool - true if the argument rectangle intersects this rectangle.
* (i.e. if the 2 rectangles have at least a common point) * (i.e. if the 2 rectangles have at least a common point)
*/ */
bool Intersects( const EDA_RECT& aRect ) const; 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) * Function operator(wxRect)
* overloads the cast operator to return a wxRect * overloads the cast operator to return a wxRect
...@@ -530,18 +544,6 @@ public: ...@@ -530,18 +544,6 @@ public:
return false; // derived classes should override this function 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 * Function GetBoundingBox
......
...@@ -223,6 +223,26 @@ public: ...@@ -223,6 +223,26 @@ public:
*/ */
wxString GetLayerName() const; 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 * Function FormatInternalUnits
......
...@@ -31,6 +31,19 @@ ...@@ -31,6 +31,19 @@
#include <math.h> #include <math.h>
#include <wx/gdicmn.h> // For wxPoint #include <wx/gdicmn.h> // 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, * Calculate the new point of coord coord pX, pY,
* for a rotation center 0, 0, and angle in (1 / 10 degree) * for a rotation center 0, 0, and angle in (1 / 10 degree)
......
...@@ -382,6 +382,7 @@ bool PCB_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) ...@@ -382,6 +382,7 @@ bool PCB_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
void PCB_EDIT_FRAME::Block_SelectItems() void PCB_EDIT_FRAME::Block_SelectItems()
{ {
LAYER_MSK layerMask; LAYER_MSK layerMask;
bool selectOnlyComplete = GetScreen()->m_BlockLocate.GetWidth() > 0 ;
GetScreen()->m_BlockLocate.Normalize(); GetScreen()->m_BlockLocate.Normalize();
...@@ -395,7 +396,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -395,7 +396,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
{ {
LAYER_NUM layer = module->GetLayer(); LAYER_NUM layer = module->GetLayer();
if( module->HitTest( GetScreen()->m_BlockLocate ) if( module->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete )
&& ( !module->IsLocked() || blockIncludeLockedModules ) ) && ( !module->IsLocked() || blockIncludeLockedModules ) )
{ {
if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) ) if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) )
...@@ -410,14 +411,14 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -410,14 +411,14 @@ void PCB_EDIT_FRAME::Block_SelectItems()
// Add tracks and vias // Add tracks and vias
if( blockIncludeTracks ) 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 if( blockIncludeItemsOnInvisibleLayers
|| m_Pcb->IsLayerVisible( pt_segm->GetLayer() ) ) || m_Pcb->IsLayerVisible( track->GetLayer() ) )
{ {
picker.SetItem ( pt_segm ); picker.SetItem ( track );
itemsList->PushItem( picker ); itemsList->PushItem( picker );
} }
} }
...@@ -446,7 +447,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -446,7 +447,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
if( (GetLayerMask( PtStruct->GetLayer() ) & layerMask) == 0 ) if( (GetLayerMask( PtStruct->GetLayer() ) & layerMask) == 0 )
break; break;
if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
break; break;
select_me = true; // This item is in bloc: select it select_me = true; // This item is in bloc: select it
...@@ -456,7 +457,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -456,7 +457,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
if( !blockIncludePcbTexts ) if( !blockIncludePcbTexts )
break; break;
if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
break; break;
select_me = true; // This item is in bloc: select it select_me = true; // This item is in bloc: select it
...@@ -466,7 +467,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -466,7 +467,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 )
break; break;
if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
break; break;
select_me = true; // This item is in bloc: select it select_me = true; // This item is in bloc: select it
...@@ -476,7 +477,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -476,7 +477,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 ) if( ( GetLayerMask( PtStruct->GetLayer() ) & layerMask ) == 0 )
break; break;
if( !PtStruct->HitTest( GetScreen()->m_BlockLocate ) ) if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
break; break;
select_me = true; // This item is in bloc: select it select_me = true; // This item is in bloc: select it
...@@ -500,7 +501,7 @@ void PCB_EDIT_FRAME::Block_SelectItems() ...@@ -500,7 +501,7 @@ void PCB_EDIT_FRAME::Block_SelectItems()
{ {
ZONE_CONTAINER* area = m_Pcb->GetArea( ii ); ZONE_CONTAINER* area = m_Pcb->GetArea( ii );
if( area->HitTest( GetScreen()->m_BlockLocate ) ) if( area->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
{ {
if( blockIncludeItemsOnInvisibleLayers if( blockIncludeItemsOnInvisibleLayers
|| m_Pcb->IsLayerVisible( area->GetLayer() ) ) || m_Pcb->IsLayerVisible( area->GetLayer() ) )
......
...@@ -430,12 +430,19 @@ bool DIMENSION::HitTest( const wxPoint& aPosition ) ...@@ -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() ) ) EDA_RECT arect = aRect;
return true; arect.Inflate( aAccuracy );
return false; EDA_RECT rect = GetBoundingBox();
if( aAccuracy )
rect.Inflate( aAccuracy );
if( aContained )
return arect.Contains( rect );
return arect.Intersects( rect );
} }
......
...@@ -129,7 +129,10 @@ public: ...@@ -129,7 +129,10 @@ public:
bool HitTest( const wxPoint& aPosition ); 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 wxString GetClass() const
{ {
......
...@@ -494,30 +494,48 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) ...@@ -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 ) switch( m_Shape )
{ {
case S_CIRCLE: case S_CIRCLE:
{ // Test if area intersects or contains the circle:
int radius = GetRadius(); if( aContained )
return arect.Contains( GetBoundingBox() );
else
return arect.Intersects( GetBoundingBox() );
break;
// Text if area intersects the circle: case S_ARC:
EDA_RECT area = aRect; radius = hypot( (double)( GetEnd().x - GetStart().x ),
area.Inflate( radius ); (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 );
if( area.Contains( m_Start ) )
return true;
}
break; break;
case S_ARC:
case S_SEGMENT: case S_SEGMENT:
if( aRect.Contains( GetStart() ) ) if( aContained )
return true; return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
else
return arect.Intersects( GetStart(), GetEnd() );
if( aRect.Contains( GetEnd() ) )
return true;
break; break;
default: default:
......
...@@ -172,7 +172,10 @@ public: ...@@ -172,7 +172,10 @@ public:
virtual bool HitTest( const wxPoint& aPosition ); 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 wxString GetClass() const
{ {
......
...@@ -178,10 +178,15 @@ bool PCB_TARGET::HitTest( const wxPoint& aPosition ) ...@@ -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 ) ) EDA_RECT arect = aRect;
return true; arect.Inflate( aAccuracy );
if( aContained )
return arect.Contains( GetBoundingBox() );
else
return GetBoundingBox().Intersects( arect );
return false; return false;
} }
......
...@@ -93,7 +93,10 @@ public: ...@@ -93,7 +93,10 @@ public:
bool HitTest( const wxPoint& aPosition ); 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; EDA_RECT GetBoundingBox() const;
......
...@@ -555,21 +555,15 @@ bool MODULE::HitTest( const wxPoint& aPosition ) ...@@ -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() ) EDA_RECT arect = aRect;
return false; 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() ) if( aContained )
return false; return arect.Contains( m_BoundaryBox );
else
return true; return m_BoundaryBox.Intersects( arect );
} }
......
...@@ -318,7 +318,10 @@ public: ...@@ -318,7 +318,10 @@ public:
bool HitTest( const wxPoint& aPosition ); 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 * Function GetReference
......
...@@ -71,9 +71,12 @@ public: ...@@ -71,9 +71,12 @@ public:
return TextHitTest( aPosition ); 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 wxString GetClass() const
......
...@@ -1186,15 +1186,32 @@ bool TRACK::HitTest( const wxPoint& aPosition ) ...@@ -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 ) ) EDA_RECT box;
return true; EDA_RECT arect = aRect;
arect.Inflate( aAccuracy );
if( aRect.Contains( m_End ) ) if( Type() == PCB_VIA_T )
return true; {
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() );
}
} }
......
...@@ -257,7 +257,10 @@ public: ...@@ -257,7 +257,10 @@ public:
virtual bool HitTest( const wxPoint& aPosition ); 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 * Function GetVia
......
...@@ -557,25 +557,61 @@ bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) ...@@ -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() ) if( aContained )
is_out_of_box = true; 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;
// 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( HitTestInsideZone( corner ) )
return true;
corner.x = arect.GetEnd().x;
if( HitTestInsideZone( corner ) )
return true;
if( rect.top < aRect.GetY() ) corner = arect.GetEnd();
is_out_of_box = true;
if( rect.right > aRect.GetRight() ) if( HitTestInsideZone( corner ) )
is_out_of_box = true; return true;
if( rect.bottom > aRect.GetBottom() ) corner.x = arect.GetOrigin().x;
is_out_of_box = true;
return is_out_of_box ? false : true; 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;
}
} }
......
...@@ -151,7 +151,7 @@ public: ...@@ -151,7 +151,7 @@ public:
void DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC, void DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC,
GR_DRAWMODE draw_mode = GR_OR ); GR_DRAWMODE draw_mode = GR_OR );
/* Function GetBoundingBox /** Function GetBoundingBox
* @return an EDA_RECT that is the bounding box of the zone outline * @return an EDA_RECT that is the bounding box of the zone outline
*/ */
EDA_RECT GetBoundingBox() const; EDA_RECT GetBoundingBox() const;
...@@ -253,8 +253,26 @@ public: ...@@ -253,8 +253,26 @@ public:
void SetOutline( CPolyLine* aOutline ) { m_Poly = aOutline; } 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 ); 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 * Function HitTestFilledArea
* tests if the given wxPoint is within the bounds of a filled area of this zone. * tests if the given wxPoint is within the bounds of a filled area of this zone.
...@@ -360,7 +378,10 @@ public: ...@@ -360,7 +378,10 @@ public:
*/ */
bool HitTestForEdge( const wxPoint& refPos ); 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 * Function Fill_Zone
......
...@@ -102,7 +102,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, ...@@ -102,7 +102,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
continue; continue;
// legal polygon // legal polygon
CRect b1 = curr_area->Outline()->GetCornerBounds(); CRect b1 = curr_area->Outline()->GetBoundingBox();
bool mod_ia1 = false; bool mod_ia1 = false;
for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- ) for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- )
...@@ -121,7 +121,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, ...@@ -121,7 +121,7 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
if( curr_area->GetLayer() != area2->GetLayer() ) if( curr_area->GetLayer() != area2->GetLayer() )
continue; continue;
CRect b2 = area2->Outline()->GetCornerBounds(); CRect b2 = area2->Outline()->GetBoundingBox();
if( !( b1.left > b2.right || b1.right < b2.left if( !( b1.left > b2.right || b1.right < b2.left
|| b1.bottom > b2.top || b1.top < b2.bottom ) ) || b1.bottom > b2.top || b1.top < b2.bottom ) )
...@@ -194,8 +194,8 @@ bool BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area ...@@ -194,8 +194,8 @@ bool BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area
CPolyLine* poly2 = area_to_test->Outline(); CPolyLine* poly2 = area_to_test->Outline();
// test bounding rects // test bounding rects
CRect b1 = poly1->GetCornerBounds(); CRect b1 = poly1->GetBoundingBox();
CRect b2 = poly2->GetCornerBounds(); CRect b2 = poly2->GetBoundingBox();
if( b1.bottom > b2.top || b1.top < b2.bottom || if( b1.bottom > b2.top || b1.top < b2.bottom ||
b1.left > b2.right || b1.right < b2.left ) b1.left > b2.right || b1.right < b2.left )
......
...@@ -582,14 +582,7 @@ int CPolyLine::GetEndContour( int ic ) ...@@ -582,14 +582,7 @@ int CPolyLine::GetEndContour( int ic )
} }
CRect CPolyLine::GetBounds() CRect CPolyLine::GetBoundingBox()
{
CRect r = GetCornerBounds();
return r;
}
CRect CPolyLine::GetCornerBounds()
{ {
CRect r; CRect r;
...@@ -608,7 +601,7 @@ CRect CPolyLine::GetCornerBounds() ...@@ -608,7 +601,7 @@ CRect CPolyLine::GetCornerBounds()
} }
CRect CPolyLine::GetCornerBounds( int icont ) CRect CPolyLine::GetBoundingBox( int icont )
{ {
CRect r; CRect r;
...@@ -1381,7 +1374,7 @@ bool CPolyLine::IsPolygonSelfIntersecting() ...@@ -1381,7 +1374,7 @@ bool CPolyLine::IsPolygonSelfIntersecting()
cr.reserve( n_cont ); cr.reserve( n_cont );
for( int icont = 0; icont<n_cont; icont++ ) for( int icont = 0; icont<n_cont; icont++ )
cr.push_back( GetCornerBounds( icont ) ); cr.push_back( GetBoundingBox( icont ) );
for( int icont = 0; icont<n_cont; icont++ ) for( int icont = 0; icont<n_cont; icont++ )
{ {
......
...@@ -296,9 +296,8 @@ public: ...@@ -296,9 +296,8 @@ public:
void MoveOrigin( int x_off, int y_off ); void MoveOrigin( int x_off, int y_off );
// misc. functions // misc. functions
CRect GetBounds(); CRect GetBoundingBox();
CRect GetCornerBounds(); CRect GetBoundingBox( int icont );
CRect GetCornerBounds( int icont );
void Copy( const CPolyLine* src ); void Copy( const CPolyLine* src );
bool TestPointInside( int x, int y ); bool TestPointInside( int x, int y );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment