HitTest for Rectangular pads
HitTest for Rectangular pads - Works at any rotation, even with Shape Offset - Fixed bugs in D_PAD BoundingBox calculation
This commit is contained in:
parent
a0afcd5a62
commit
f338d46476
|
@ -443,6 +443,110 @@ bool EDA_RECT::Intersects( const EDA_RECT& aRect ) const
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EDA_RECT::Intersects( const EDA_RECT& aRect, double aRot ) const
|
||||||
|
{
|
||||||
|
/* Most rectangles will be axis aligned.
|
||||||
|
* It is quicker to check for this case and pass the rect
|
||||||
|
* to the simpler intersection test
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Prevent floating point comparison errors
|
||||||
|
static const double ROT_EPS = 0.000000001;
|
||||||
|
|
||||||
|
static const double ROT_PARALLEL[] = { -3600, -1800, 0, 1800, 3600 };
|
||||||
|
static const double ROT_PERPENDICULAR[] = { -2700, -900, 0, 900, 2700 };
|
||||||
|
|
||||||
|
NORMALIZE_ANGLE_POS<double>( aRot );
|
||||||
|
|
||||||
|
// Test for non-rotated rectangle
|
||||||
|
for( int ii=0; ii<5; ii++ )
|
||||||
|
{
|
||||||
|
if( std::fabs( aRot - ROT_PARALLEL[ii] ) < ROT_EPS )
|
||||||
|
{
|
||||||
|
return Intersects( aRect );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for rectangle rotated by multiple of 90 degrees
|
||||||
|
for( int jj=0; jj<4; jj++ )
|
||||||
|
{
|
||||||
|
if( std::fabs( aRot - ROT_PERPENDICULAR[jj] ) < ROT_EPS )
|
||||||
|
{
|
||||||
|
EDA_RECT rotRect;
|
||||||
|
|
||||||
|
// Rotate the supplied rect by 90 degrees
|
||||||
|
rotRect.SetOrigin( aRect.Centre() );
|
||||||
|
rotRect.Inflate( aRect.GetHeight(), aRect.GetWidth() );
|
||||||
|
return Intersects( rotRect );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is some non-orthogonal rotation.
|
||||||
|
* There are three cases to test:
|
||||||
|
* A) One point of this rect is inside the rotated rect
|
||||||
|
* B) One point of the rotated rect is inside this rect
|
||||||
|
* C) One of the sides of the rotated rect intersect this
|
||||||
|
*/
|
||||||
|
|
||||||
|
wxPoint corners[4];
|
||||||
|
|
||||||
|
/* Test A : Any corners exist in rotated rect? */
|
||||||
|
|
||||||
|
corners[0] = m_Pos;
|
||||||
|
corners[1] = m_Pos + wxPoint( m_Size.x, 0 );
|
||||||
|
corners[2] = m_Pos + wxPoint( m_Size.x, m_Size.y );
|
||||||
|
corners[3] = m_Pos + wxPoint( 0, m_Size.y );
|
||||||
|
|
||||||
|
wxPoint rCentre = aRect.Centre();
|
||||||
|
|
||||||
|
for( int i=0; i<4; i++ )
|
||||||
|
{
|
||||||
|
wxPoint delta = corners[i] - rCentre;
|
||||||
|
RotatePoint( &delta, -aRot );
|
||||||
|
delta += rCentre;
|
||||||
|
|
||||||
|
if( aRect.Contains( delta ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test B : Any corners of rotated rect exist in this one? */
|
||||||
|
int w = aRect.GetWidth() / 2;
|
||||||
|
int h = aRect.GetHeight() / 2;
|
||||||
|
|
||||||
|
// Construct corners around center of shape
|
||||||
|
corners[0] = wxPoint( -w, -h );
|
||||||
|
corners[1] = wxPoint( w, -h );
|
||||||
|
corners[2] = wxPoint( w, h );
|
||||||
|
corners[3] = wxPoint( -w, h );
|
||||||
|
|
||||||
|
// Rotate and test each corner
|
||||||
|
for( int j=0; j<4; j++ )
|
||||||
|
{
|
||||||
|
RotatePoint( &corners[j], aRot );
|
||||||
|
corners[j] += rCentre;
|
||||||
|
|
||||||
|
if( Contains( corners[j] ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test C : Any sides of rotated rect intersect this */
|
||||||
|
|
||||||
|
if( Intersects( corners[0], corners[1] ) ||
|
||||||
|
Intersects( corners[1], corners[2] ) ||
|
||||||
|
Intersects( corners[2], corners[3] ) ||
|
||||||
|
Intersects( corners[3], corners[0] ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const wxPoint EDA_RECT::ClosestPointTo( const wxPoint& aPoint ) const
|
const wxPoint EDA_RECT::ClosestPointTo( const wxPoint& aPoint ) const
|
||||||
{
|
{
|
||||||
EDA_RECT me(*this);
|
EDA_RECT me(*this);
|
||||||
|
|
|
@ -157,6 +157,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool Intersects( const EDA_RECT& aRect ) const;
|
bool Intersects( const EDA_RECT& aRect ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for a common area between this rectangle,
|
||||||
|
* and a rectangle with arbitrary rotation
|
||||||
|
*
|
||||||
|
* @param aRect a rectangle to test intersection with
|
||||||
|
* @param aRot rectangle rotation (in 1/10 degrees)
|
||||||
|
*/
|
||||||
|
bool Intersects( const EDA_RECT& aRect, double aRot ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Intersects
|
* Function Intersects
|
||||||
* tests for a common area between a segment and this rectangle.
|
* tests for a common area between a segment and this rectangle.
|
||||||
|
|
|
@ -556,7 +556,6 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arcRect = arcRect.Common( arect );
|
arcRect = arcRect.Common( arect );
|
||||||
//arcRect.Inflate( GetWidth() );
|
|
||||||
|
|
||||||
/* All following tests must pass:
|
/* All following tests must pass:
|
||||||
* 1. Rectangle must intersect arc BoundingBox
|
* 1. Rectangle must intersect arc BoundingBox
|
||||||
|
@ -568,9 +567,15 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
|
||||||
break;
|
break;
|
||||||
case S_SEGMENT:
|
case S_SEGMENT:
|
||||||
if( aContained )
|
if( aContained )
|
||||||
|
{
|
||||||
return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
|
return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// Account for the width of the line
|
||||||
|
arect.Inflate( GetWidth() / 2 );
|
||||||
return arect.Intersects( GetStart(), GetEnd() );
|
return arect.Intersects( GetStart(), GetEnd() );
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,9 @@ int D_PAD::GetRoundRectCornerRadius( const wxSize& aSize ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the BoundingBox for a D_PAD
|
||||||
|
*/
|
||||||
const EDA_RECT D_PAD::GetBoundingBox() const
|
const EDA_RECT D_PAD::GetBoundingBox() const
|
||||||
{
|
{
|
||||||
EDA_RECT area;
|
EDA_RECT area;
|
||||||
|
@ -192,7 +195,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAD_SHAPE_OVAL:
|
case PAD_SHAPE_OVAL:
|
||||||
// Calculate the position of each rounded ent
|
// Calculate the position of each rounded end
|
||||||
quadrant1.x = m_Size.x/2;
|
quadrant1.x = m_Size.x/2;
|
||||||
quadrant1.y = 0;
|
quadrant1.y = 0;
|
||||||
quadrant2.x = 0;
|
quadrant2.x = 0;
|
||||||
|
@ -207,7 +210,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
||||||
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
|
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
|
||||||
|
|
||||||
// Set the bbox
|
// Set the bbox
|
||||||
area.SetOrigin( m_Pos );
|
area.SetOrigin( ShapePos() );
|
||||||
area.Inflate( dx, dy );
|
area.Inflate( dx, dy );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -226,7 +229,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
||||||
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
|
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
|
||||||
|
|
||||||
// Set the bbox
|
// Set the bbox
|
||||||
area.SetOrigin( m_Pos );
|
area.SetOrigin( ShapePos() );
|
||||||
area.Inflate( dx, dy );
|
area.Inflate( dx, dy );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -251,6 +254,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
||||||
y = std::min( quadrant1.y, std::min( quadrant2.y, std::min( quadrant3.y, quadrant4.y) ) );
|
y = std::min( quadrant1.y, std::min( quadrant2.y, std::min( quadrant3.y, quadrant4.y) ) );
|
||||||
dx = std::max( quadrant1.x, std::max( quadrant2.x, std::max( quadrant3.x, quadrant4.x) ) );
|
dx = std::max( quadrant1.x, std::max( quadrant2.x, std::max( quadrant3.x, quadrant4.x) ) );
|
||||||
dy = std::max( quadrant1.y, std::max( quadrant2.y, std::max( quadrant3.y, quadrant4.y) ) );
|
dy = std::max( quadrant1.y, std::max( quadrant2.y, std::max( quadrant3.y, quadrant4.y) ) );
|
||||||
|
|
||||||
area.SetOrigin( m_Pos.x+x, m_Pos.y+y );
|
area.SetOrigin( m_Pos.x+x, m_Pos.y+y );
|
||||||
area.SetSize( dx-x, dy-y );
|
area.SetSize( dx-x, dy-y );
|
||||||
break;
|
break;
|
||||||
|
@ -782,18 +786,28 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
|
||||||
arect.Normalize();
|
arect.Normalize();
|
||||||
arect.Inflate( aAccuracy );
|
arect.Inflate( aAccuracy );
|
||||||
|
|
||||||
if( !arect.Intersects( GetBoundingBox() ) )
|
EDA_RECT shapeRect;
|
||||||
|
|
||||||
|
shapeRect.SetOrigin( ShapePos() );
|
||||||
|
shapeRect.Inflate( GetSize().x / 2, GetSize().y / 2 );
|
||||||
|
|
||||||
|
EDA_RECT bb = GetBoundingBox();
|
||||||
|
|
||||||
|
if( !arect.Intersects( bb ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( aContained )
|
int dist;
|
||||||
return arect.Contains( GetBoundingBox() );
|
|
||||||
|
// This covers total containment for all test cases
|
||||||
|
if( arect.Contains( bb ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
switch( GetShape() )
|
switch( GetShape() )
|
||||||
{
|
{
|
||||||
case PAD_SHAPE_CIRCLE:
|
case PAD_SHAPE_CIRCLE:
|
||||||
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
|
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
|
||||||
case PAD_SHAPE_RECT:
|
case PAD_SHAPE_RECT:
|
||||||
break;
|
return arect.Intersects( shapeRect, m_Orient );
|
||||||
case PAD_SHAPE_OVAL:
|
case PAD_SHAPE_OVAL:
|
||||||
break;
|
break;
|
||||||
case PAD_SHAPE_TRAPEZOID:
|
case PAD_SHAPE_TRAPEZOID:
|
||||||
|
|
Loading…
Reference in New Issue