Take fill into account when hit-testing arcs.
Fixes https://gitlab.com/kicad/code/kicad/issues/11305
This commit is contained in:
parent
a12f77b8f6
commit
9402b2aeda
|
@ -725,28 +725,37 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
|
||||||
int radius = GetRadius();
|
int radius = GetRadius();
|
||||||
int dist = KiROUND( EuclideanNorm( relPos ) );
|
int dist = KiROUND( EuclideanNorm( relPos ) );
|
||||||
|
|
||||||
if( abs( radius - dist ) <= maxdist )
|
if( IsFilled() )
|
||||||
{
|
{
|
||||||
EDA_ANGLE startAngle;
|
// Check distance from arc center
|
||||||
EDA_ANGLE endAngle;
|
if( dist > radius + maxdist )
|
||||||
CalcArcAngles( startAngle, endAngle );
|
return false;
|
||||||
|
}
|
||||||
if( m_upsideDownCoords && ( startAngle - endAngle ).Normalize180() > ANGLE_0 )
|
else
|
||||||
std::swap( startAngle, endAngle );
|
{
|
||||||
|
// Check distance from arc circumference
|
||||||
EDA_ANGLE relPosAngle( relPos );
|
if( abs( radius - dist ) > maxdist )
|
||||||
|
return false;
|
||||||
startAngle.Normalize();
|
|
||||||
endAngle.Normalize();
|
|
||||||
relPosAngle.Normalize();
|
|
||||||
|
|
||||||
if( endAngle > startAngle )
|
|
||||||
return relPosAngle >= startAngle && relPosAngle <= endAngle;
|
|
||||||
else
|
|
||||||
return relPosAngle >= startAngle || relPosAngle <= endAngle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// Finally, check to see if it's within arc's swept angle.
|
||||||
|
EDA_ANGLE startAngle;
|
||||||
|
EDA_ANGLE endAngle;
|
||||||
|
CalcArcAngles( startAngle, endAngle );
|
||||||
|
|
||||||
|
if( m_upsideDownCoords && ( startAngle - endAngle ).Normalize180() > ANGLE_0 )
|
||||||
|
std::swap( startAngle, endAngle );
|
||||||
|
|
||||||
|
EDA_ANGLE relPosAngle( relPos );
|
||||||
|
|
||||||
|
startAngle.Normalize();
|
||||||
|
endAngle.Normalize();
|
||||||
|
relPosAngle.Normalize();
|
||||||
|
|
||||||
|
if( endAngle > startAngle )
|
||||||
|
return relPosAngle >= startAngle && relPosAngle <= endAngle;
|
||||||
|
else
|
||||||
|
return relPosAngle >= startAngle || relPosAngle <= endAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SHAPE_T::BEZIER:
|
case SHAPE_T::BEZIER:
|
||||||
|
@ -808,7 +817,6 @@ bool EDA_SHAPE::hitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy )
|
||||||
arect.Normalize();
|
arect.Normalize();
|
||||||
arect.Inflate( aAccuracy );
|
arect.Inflate( aAccuracy );
|
||||||
|
|
||||||
EDA_RECT arcRect;
|
|
||||||
EDA_RECT bb = getBoundingBox();
|
EDA_RECT bb = getBoundingBox();
|
||||||
|
|
||||||
switch( m_shape )
|
switch( m_shape )
|
||||||
|
@ -822,14 +830,10 @@ bool EDA_SHAPE::hitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the rectangle does not intersect the bounding box, this is a much quicker test
|
// If the rectangle does not intersect the bounding box, this is a much quicker test
|
||||||
if( !aRect.Intersects( bb ) )
|
if( !arect.Intersects( bb ) )
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return arect.IntersectsCircleEdge( getCenter(), GetRadius(), GetWidth() );
|
return arect.IntersectsCircleEdge( getCenter(), GetRadius(), GetWidth() );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SHAPE_T::ARC:
|
case SHAPE_T::ARC:
|
||||||
|
@ -841,14 +845,19 @@ bool EDA_SHAPE::hitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy )
|
||||||
// Test if the rect crosses the arc
|
// Test if the rect crosses the arc
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arcRect = bb.Common( arect );
|
if( !arect.Intersects( bb ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
/* All following tests must pass:
|
if( IsFilled() )
|
||||||
* 1. Rectangle must intersect arc BoundingBox
|
{
|
||||||
* 2. Rectangle must cross the outside of the arc
|
return ( arect.Intersects( getCenter(), GetStart() )
|
||||||
*/
|
|| arect.Intersects( getCenter(), GetEnd() )
|
||||||
return arcRect.Intersects( arect ) &&
|
|| arect.IntersectsCircleEdge( getCenter(), GetRadius(), GetWidth() ) );
|
||||||
arcRect.IntersectsCircleEdge( getCenter(), GetRadius(), GetWidth() );
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return arect.IntersectsCircleEdge( getCenter(), GetRadius(), GetWidth() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case SHAPE_T::RECT:
|
case SHAPE_T::RECT:
|
||||||
|
@ -1013,6 +1022,15 @@ std::vector<VECTOR2I> EDA_SHAPE::GetRectCorners() const
|
||||||
|
|
||||||
void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
|
void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
|
||||||
{
|
{
|
||||||
|
// Start, end, and each inflection point the arc crosses will enclose the entire arc.
|
||||||
|
// Only include the center when filled; it's not necessarily inside the BB of an unfilled
|
||||||
|
// arc with a small included angle.
|
||||||
|
aBBox.SetOrigin( m_start );
|
||||||
|
aBBox.Merge( m_end );
|
||||||
|
|
||||||
|
if( IsFilled() )
|
||||||
|
aBBox.Merge( m_arcCenter );
|
||||||
|
|
||||||
int radius = GetRadius();
|
int radius = GetRadius();
|
||||||
EDA_ANGLE t1, t2;
|
EDA_ANGLE t1, t2;
|
||||||
|
|
||||||
|
@ -1024,12 +1042,6 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
|
||||||
t1.Normalize();
|
t1.Normalize();
|
||||||
t2.Normalize();
|
t2.Normalize();
|
||||||
|
|
||||||
// Start, end, and each inflection point the arc crosses will enclose the entire arc
|
|
||||||
// Do not include the center, which is not necessarily inside the BB of an arc with a
|
|
||||||
// small included angle
|
|
||||||
aBBox.SetOrigin( m_start );
|
|
||||||
aBBox.Merge( m_end );
|
|
||||||
|
|
||||||
if( t2 > t1 )
|
if( t2 > t1 )
|
||||||
{
|
{
|
||||||
if( t1 < ANGLE_0 && t2 > ANGLE_0 )
|
if( t1 < ANGLE_0 && t2 > ANGLE_0 )
|
||||||
|
|
Loading…
Reference in New Issue