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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
EDA_RECT me(*this);
|
||||
|
|
|
@ -157,6 +157,15 @@ public:
|
|||
*/
|
||||
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
|
||||
* 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
|
||||
{
|
||||
arcRect = arcRect.Common( arect );
|
||||
//arcRect.Inflate( GetWidth() );
|
||||
|
||||
/* All following tests must pass:
|
||||
* 1. Rectangle must intersect arc BoundingBox
|
||||
|
@ -568,9 +567,15 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
|
|||
break;
|
||||
case S_SEGMENT:
|
||||
if( aContained )
|
||||
{
|
||||
return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Account for the width of the line
|
||||
arect.Inflate( GetWidth() / 2 );
|
||||
return arect.Intersects( GetStart(), GetEnd() );
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
EDA_RECT area;
|
||||
|
@ -192,7 +195,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
|||
break;
|
||||
|
||||
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.y = 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 ) );
|
||||
|
||||
// Set the bbox
|
||||
area.SetOrigin( m_Pos );
|
||||
area.SetOrigin( ShapePos() );
|
||||
area.Inflate( dx, dy );
|
||||
break;
|
||||
|
||||
|
@ -226,7 +229,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
|||
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
|
||||
|
||||
// Set the bbox
|
||||
area.SetOrigin( m_Pos );
|
||||
area.SetOrigin( ShapePos() );
|
||||
area.Inflate( dx, dy );
|
||||
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) ) );
|
||||
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) ) );
|
||||
|
||||
area.SetOrigin( m_Pos.x+x, m_Pos.y+y );
|
||||
area.SetSize( dx-x, dy-y );
|
||||
break;
|
||||
|
@ -782,18 +786,28 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
|
|||
arect.Normalize();
|
||||
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;
|
||||
|
||||
if( aContained )
|
||||
return arect.Contains( GetBoundingBox() );
|
||||
int dist;
|
||||
|
||||
// This covers total containment for all test cases
|
||||
if( arect.Contains( bb ) )
|
||||
return true;
|
||||
|
||||
switch( GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
|
||||
case PAD_SHAPE_RECT:
|
||||
break;
|
||||
return arect.Intersects( shapeRect, m_Orient );
|
||||
case PAD_SHAPE_OVAL:
|
||||
break;
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
|
|
Loading…
Reference in New Issue