Return individual custom pad shapes instead of a SHAPE_POLY_SET.
Also implements an optional pointer to return the actual distance from all the SHAPE collision routines. Fixes https://gitlab.com/kicad/code/kicad/issues/4774
This commit is contained in:
parent
af8f05d570
commit
441dfa30f0
|
@ -193,7 +193,7 @@ public:
|
||||||
return Intersect( aSeg, false, true );
|
return Intersect( aSeg, false, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance ) const;
|
bool Collide( const SEG& aSeg, int aClearance, int* aActual = nullptr ) const;
|
||||||
|
|
||||||
ecoord SquaredDistance( const SEG& aSeg ) const;
|
ecoord SquaredDistance( const SEG& aSeg ) const;
|
||||||
|
|
||||||
|
@ -341,8 +341,6 @@ public:
|
||||||
|
|
||||||
bool Contains( const VECTOR2I& aP ) const;
|
bool Contains( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
|
|
||||||
|
|
||||||
void Reverse()
|
void Reverse()
|
||||||
{
|
{
|
||||||
std::swap( A, B );
|
std::swap( A, B );
|
||||||
|
|
|
@ -118,9 +118,11 @@ public:
|
||||||
*
|
*
|
||||||
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance,
|
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance,
|
||||||
* indicating a collision.
|
* indicating a collision.
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return true, if there is a collision.
|
* @return true, if there is a collision.
|
||||||
*/
|
*/
|
||||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
|
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const
|
||||||
{
|
{
|
||||||
return Collide( SEG( aP, aP ), aClearance );
|
return Collide( SEG( aP, aP ), aClearance );
|
||||||
}
|
}
|
||||||
|
@ -133,19 +135,23 @@ public:
|
||||||
* @param aShape shape to check collision against
|
* @param aShape shape to check collision against
|
||||||
* @param aClearance minimum clearance
|
* @param aClearance minimum clearance
|
||||||
* @param aMTV minimum translation vector
|
* @param aMTV minimum translation vector
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return true, if there is a collision.
|
* @return true, if there is a collision.
|
||||||
*/
|
*/
|
||||||
virtual bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I& aMTV ) const;
|
virtual bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const;
|
||||||
virtual bool Collide( const SHAPE* aShape, int aClearance = 0 ) const;
|
virtual bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Collide()
|
* Function Collide()
|
||||||
*
|
*
|
||||||
* Checks if the boundary of shape (this) lies closer to the segment aSeg than aClearance,
|
* Checks if the boundary of shape (this) lies closer to the segment aSeg than aClearance,
|
||||||
* indicating a collision.
|
* indicating a collision.
|
||||||
|
* @aActual an optional pointer to an int to be updated with the actual distance in the
|
||||||
|
* case of collision.
|
||||||
* @return true, if there is a collision.
|
* @return true, if there is a collision.
|
||||||
*/
|
*/
|
||||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0 ) const = 0;
|
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function BBox()
|
* Function BBox()
|
||||||
|
@ -169,7 +175,14 @@ public:
|
||||||
return BBox( 0 ).Centre(); // if nothing better is available....
|
return BBox( 0 ).Centre(); // if nothing better is available....
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Move ( const VECTOR2I& aVector ) = 0;
|
/**
|
||||||
|
* Function Rotate
|
||||||
|
* @param aCenter is the rotation center
|
||||||
|
* @param aAngle rotation angle in radians
|
||||||
|
*/
|
||||||
|
virtual void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) = 0;
|
||||||
|
|
||||||
|
virtual void Move( const VECTOR2I& aVector ) = 0;
|
||||||
|
|
||||||
virtual bool IsSolid() const = 0;
|
virtual bool IsSolid() const = 0;
|
||||||
|
|
||||||
|
@ -182,7 +195,7 @@ protected:
|
||||||
SHAPE_TYPE m_type;
|
SHAPE_TYPE m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance,
|
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV );
|
VECTOR2I* aMTV );
|
||||||
|
|
||||||
#endif // __SHAPE_H
|
#endif // __SHAPE_H
|
||||||
|
|
|
@ -76,8 +76,8 @@ public:
|
||||||
|
|
||||||
const BOX2I BBox( int aClearance = 0 ) const override;
|
const BOX2I BBox( int aClearance = 0 ) const override;
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const override;
|
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
void SetWidth( int aWidth )
|
void SetWidth( int aWidth )
|
||||||
{
|
{
|
||||||
|
@ -102,7 +102,7 @@ public:
|
||||||
* @param aCenter is the rotation center
|
* @param aCenter is the rotation center
|
||||||
* @param aAngle rotation angle in radians
|
* @param aAngle rotation angle in radians
|
||||||
*/
|
*/
|
||||||
void Rotate( double aAngle, const VECTOR2I& aCenter );
|
void Rotate( double aAngle, const VECTOR2I& aCenter ) override;
|
||||||
|
|
||||||
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } );
|
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } );
|
||||||
|
|
||||||
|
|
|
@ -63,11 +63,20 @@ public:
|
||||||
return BOX2I( m_center - rc, rc * 2 );
|
return BOX2I( m_center - rc, rc * 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
{
|
{
|
||||||
int rc = aClearance + m_radius;
|
int minDist = aClearance + m_radius;
|
||||||
|
ecoord dist_sq = aSeg.SquaredDistance( m_center );
|
||||||
|
|
||||||
return aSeg.Distance( m_center ) < rc;
|
if( dist_sq < (ecoord) minDist * minDist )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - m_radius );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRadius( int aRadius )
|
void SetRadius( int aRadius )
|
||||||
|
@ -95,6 +104,11 @@ public:
|
||||||
m_center += aVector;
|
m_center += aVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
|
||||||
|
{
|
||||||
|
// That was easy....
|
||||||
|
}
|
||||||
|
|
||||||
bool IsSolid() const override
|
bool IsSolid() const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -386,9 +386,11 @@ public:
|
||||||
* Checks if point aP lies closer to us than aClearance.
|
* Checks if point aP lies closer to us than aClearance.
|
||||||
* @param aP the point to check for collisions with
|
* @param aP the point to check for collisions with
|
||||||
* @param aClearance minimum distance that does not qualify as a collision.
|
* @param aClearance minimum distance that does not qualify as a collision.
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return true, when a collision has been found
|
* @return true, when a collision has been found
|
||||||
*/
|
*/
|
||||||
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const override;
|
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Collide()
|
* Function Collide()
|
||||||
|
@ -396,9 +398,11 @@ public:
|
||||||
* Checks if segment aSeg lies closer to us than aClearance.
|
* Checks if segment aSeg lies closer to us than aClearance.
|
||||||
* @param aSeg the segment to check for collisions with
|
* @param aSeg the segment to check for collisions with
|
||||||
* @param aClearance minimum distance that does not qualify as a collision.
|
* @param aClearance minimum distance that does not qualify as a collision.
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return true, when a collision has been found
|
* @return true, when a collision has been found
|
||||||
*/
|
*/
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Distance()
|
* Function Distance()
|
||||||
|
@ -408,6 +412,7 @@ public:
|
||||||
* @return minimum distance.
|
* @return minimum distance.
|
||||||
*/
|
*/
|
||||||
int Distance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
|
int Distance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
|
||||||
|
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Reverse()
|
* Function Reverse()
|
||||||
|
@ -747,7 +752,7 @@ public:
|
||||||
* @param aCenter is the rotation center
|
* @param aCenter is the rotation center
|
||||||
* @param aAngle rotation angle in radians
|
* @param aAngle rotation angle in radians
|
||||||
*/
|
*/
|
||||||
void Rotate( double aAngle, const VECTOR2I& aCenter = VECTOR2I( 0, 0 ) );
|
void Rotate( double aAngle, const VECTOR2I& aCenter = VECTOR2I( 0, 0 ) ) override;
|
||||||
|
|
||||||
bool IsSolid() const override
|
bool IsSolid() const override
|
||||||
{
|
{
|
||||||
|
|
|
@ -975,7 +975,7 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
* @param aCenter is the rotation center
|
* @param aCenter is the rotation center
|
||||||
* @param aAngle rotation angle in radians
|
* @param aAngle rotation angle in radians
|
||||||
*/
|
*/
|
||||||
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } );
|
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override;
|
||||||
|
|
||||||
/// @copydoc SHAPE::IsSolid()
|
/// @copydoc SHAPE::IsSolid()
|
||||||
bool IsSolid() const override
|
bool IsSolid() const override
|
||||||
|
@ -1003,9 +1003,11 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
* will be tested.
|
* will be tested.
|
||||||
* @param aClearance is the security distance; if the point lies closer to the polygon
|
* @param aClearance is the security distance; if the point lies closer to the polygon
|
||||||
* than aClearance distance, then there is a collision.
|
* than aClearance distance, then there is a collision.
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return bool - true if the point aP collides with the polygon; false in any other case.
|
* @return bool - true if the point aP collides with the polygon; false in any other case.
|
||||||
*/
|
*/
|
||||||
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const override;
|
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Collide
|
* Function Collide
|
||||||
|
@ -1016,10 +1018,12 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
* will be tested.
|
* will be tested.
|
||||||
* @param aClearance is the security distance; if the segment passes closer to the polygon
|
* @param aClearance is the security distance; if the segment passes closer to the polygon
|
||||||
* than aClearance distance, then there is a collision.
|
* than aClearance distance, then there is a collision.
|
||||||
|
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||||
|
* of a collision.
|
||||||
* @return bool - true if the segment aSeg collides with the polygon;
|
* @return bool - true if the segment aSeg collides with the polygon;
|
||||||
* false in any other case.
|
* false in any other case.
|
||||||
*/
|
*/
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function CollideVertex
|
* Function CollideVertex
|
||||||
|
|
|
@ -91,9 +91,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc SHAPE::Collide()
|
/// @copydoc SHAPE::Collide()
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||||
|
|
||||||
bool DoCollide( const SEG& aSeg, int aClearance, int* aActualDist ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetPosition()
|
* Function GetPosition()
|
||||||
|
@ -140,6 +138,16 @@ public:
|
||||||
m_p0 += aVector;
|
m_p0 += aVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
|
||||||
|
{
|
||||||
|
m_p0 -= aCenter;
|
||||||
|
m_p0 = m_p0.Rotate( aAngle );
|
||||||
|
m_p0 += aCenter;
|
||||||
|
|
||||||
|
if( abs( sin( aAngle ) ) == 1 )
|
||||||
|
std::swap( m_h, m_w );
|
||||||
|
}
|
||||||
|
|
||||||
bool IsSolid() const override
|
bool IsSolid() const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -54,14 +54,36 @@ public:
|
||||||
return BOX2I( m_seg.A, m_seg.B - m_seg.A ).Inflate( aClearance + ( m_width + 1 ) / 2 );
|
return BOX2I( m_seg.A, m_seg.B - m_seg.A ).Inflate( aClearance + ( m_width + 1 ) / 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
{
|
{
|
||||||
return m_seg.Distance( aSeg ) < ( m_width + 1 ) / 2 + aClearance;
|
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
||||||
|
ecoord dist_sq = m_seg.SquaredDistance( aSeg );
|
||||||
|
|
||||||
|
if( dist_sq < (ecoord) min_dist * min_dist )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - ( m_width + 1 ) / 2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const override
|
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
{
|
{
|
||||||
return m_seg.Distance( aP ) < ( m_width + 1 ) / 2 + aClearance;
|
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
||||||
|
ecoord dist_sq = m_seg.SquaredDistance( aP );
|
||||||
|
|
||||||
|
if( dist_sq < (ecoord) min_dist * min_dist )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - ( m_width + 1 ) / 2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSeg( const SEG& aSeg )
|
void SetSeg( const SEG& aSeg )
|
||||||
|
@ -89,6 +111,18 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
|
||||||
|
{
|
||||||
|
m_seg.A -= aCenter;
|
||||||
|
m_seg.B -= aCenter;
|
||||||
|
|
||||||
|
m_seg.A = m_seg.A.Rotate( aAngle );
|
||||||
|
m_seg.B = m_seg.B.Rotate( aAngle );
|
||||||
|
|
||||||
|
m_seg.A += aCenter;
|
||||||
|
m_seg.B += aCenter;
|
||||||
|
}
|
||||||
|
|
||||||
void Move( const VECTOR2I& aVector ) override
|
void Move( const VECTOR2I& aVector ) override
|
||||||
{
|
{
|
||||||
m_seg.A += aVector;
|
m_seg.A += aVector;
|
||||||
|
|
|
@ -159,9 +159,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc SHAPE::Collide()
|
/// @copydoc SHAPE::Collide()
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||||
{
|
{
|
||||||
return m_points.Collide( aSeg, aClearance );
|
return m_points.Collide( aSeg, aClearance, aActual );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
|
||||||
|
{
|
||||||
|
m_points.Rotate( aAngle, aCenter );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Move( const VECTOR2I& aVector ) override
|
void Move( const VECTOR2I& aVector ) override
|
||||||
|
|
|
@ -34,57 +34,6 @@ int sgn( T aVal )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SEG::PointCloserThan( const VECTOR2I& aP, int aDist ) const
|
|
||||||
{
|
|
||||||
// See http://geomalgorithms.com/a02-_lines.html for some explanations and ideas.
|
|
||||||
VECTOR2I d = B - A;
|
|
||||||
ecoord dist_sq = (ecoord) aDist * aDist;
|
|
||||||
|
|
||||||
SEG::ecoord l_squared = d.Dot( d );
|
|
||||||
SEG::ecoord t = d.Dot( aP - A );
|
|
||||||
|
|
||||||
if( t <= 0 || !l_squared )
|
|
||||||
return ( aP - A ).SquaredEuclideanNorm() < dist_sq;
|
|
||||||
else if( t >= l_squared )
|
|
||||||
return ( aP - B ).SquaredEuclideanNorm() < dist_sq;
|
|
||||||
|
|
||||||
// JPC: This code is not trivial and is not commented
|
|
||||||
// and does not work for d.x or d.y = -1...1
|
|
||||||
// I am guessing it is here for calculation time optimization.
|
|
||||||
// if someone can understand it, please fix it.
|
|
||||||
// It can be tested with a segment having d.x or d.y value
|
|
||||||
// is -1 or +1 ("this" is a quasi vertical or horizontal segment)
|
|
||||||
int dxdy = std::abs( d.x ) - std::abs( d.y );
|
|
||||||
|
|
||||||
if( ( dxdy >= -1 && dxdy <= 1 ) // quasi 45 deg segment
|
|
||||||
/*|| std::abs( d.x ) <= 1 // quasi horizontal segment
|
|
||||||
|| std::abs( d.y ) <= 1 // quasi vertical segment */ )
|
|
||||||
{
|
|
||||||
int ca = -sgn( d.y );
|
|
||||||
int cb = sgn( d.x );
|
|
||||||
int cc = -ca * A.x - cb * A.y;
|
|
||||||
|
|
||||||
ecoord num = (ecoord) ca * aP.x + (ecoord) cb * aP.y + cc;
|
|
||||||
num *= num;
|
|
||||||
|
|
||||||
if( ca && cb )
|
|
||||||
num >>= 1;
|
|
||||||
|
|
||||||
if( num > ( dist_sq + 100 ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
else if( num < ( dist_sq - 100 ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VECTOR2I nearest;
|
|
||||||
nearest.x = A.x + rescale( t, (ecoord) d.x, l_squared );
|
|
||||||
nearest.y = A.y + rescale( t, (ecoord) d.y, l_squared );
|
|
||||||
|
|
||||||
return ( nearest - aP ).SquaredEuclideanNorm() <= dist_sq;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
||||||
{
|
{
|
||||||
// fixme: rather inefficient....
|
// fixme: rather inefficient....
|
||||||
|
@ -176,22 +125,33 @@ bool SEG::ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SEG::Collide( const SEG& aSeg, int aClearance ) const
|
bool SEG::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
// check for intersection
|
// check for intersection
|
||||||
// fixme: move to a method
|
// fixme: move to a method
|
||||||
if( ccw( A, aSeg.A, aSeg.B ) != ccw( B, aSeg.A, aSeg.B ) &&
|
if( ccw( A, aSeg.A, aSeg.B ) != ccw( B, aSeg.A, aSeg.B ) &&
|
||||||
ccw( A, B, aSeg.A ) != ccw( A, B, aSeg.B ) )
|
ccw( A, B, aSeg.A ) != ccw( A, B, aSeg.B ) )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHK( _seg, _pt ) \
|
ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
if( (_seg).PointCloserThan( _pt, aClearance ) ) return true;
|
|
||||||
|
|
||||||
CHK( *this, aSeg.A );
|
dist_sq = std::min( dist_sq, SquaredDistance( aSeg.A ) );
|
||||||
CHK( *this, aSeg.B );
|
dist_sq = std::min( dist_sq, SquaredDistance( aSeg.B ) );
|
||||||
CHK( aSeg, A );
|
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( A ) );
|
||||||
CHK( aSeg, B );
|
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( B ) );
|
||||||
#undef CHK
|
|
||||||
|
if( dist_sq < (ecoord) aClearance * aClearance )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = sqrt( dist_sq );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -199,5 +159,5 @@ bool SEG::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
|
|
||||||
bool SEG::Contains( const VECTOR2I& aP ) const
|
bool SEG::Contains( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
return PointCloserThan( aP, 1 );
|
return SquaredDistance( aP ) < 1; // 1 * 1 to be pedantic
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,23 +72,17 @@ SHAPE_ARC::SHAPE_ARC( const SHAPE_ARC& aOther )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
int minDist = aClearance + m_width / 2;
|
int minDist = aClearance + m_width / 2;
|
||||||
auto center = GetCenter();
|
VECTOR2I center = GetCenter();
|
||||||
auto centerDist = aSeg.Distance( center );
|
ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
auto p1 = GetP1();
|
|
||||||
|
|
||||||
if( centerDist < minDist )
|
VECTOR2I ab = ( aSeg.B - aSeg.A );
|
||||||
return true;
|
VECTOR2I ac = ( center - aSeg.A );
|
||||||
|
|
||||||
auto ab = (aSeg.B - aSeg.A );
|
|
||||||
auto ac = ( center - aSeg.A );
|
|
||||||
|
|
||||||
auto lenAbSq = ab.SquaredEuclideanNorm();
|
|
||||||
|
|
||||||
auto lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
|
|
||||||
|
|
||||||
|
ecoord lenAbSq = ab.SquaredEuclideanNorm();
|
||||||
|
double lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
|
||||||
|
|
||||||
if( lambda >= 0.0 && lambda <= 1.0 )
|
if( lambda >= 0.0 && lambda <= 1.0 )
|
||||||
{
|
{
|
||||||
|
@ -97,29 +91,22 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
|
p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
|
||||||
p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
|
p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
|
||||||
|
|
||||||
auto p0pdist = ( m_start - p ).EuclideanNorm();
|
dist_sq = std::min( dist_sq, ( m_start - p ).SquaredEuclideanNorm() );
|
||||||
|
dist_sq = std::min( dist_sq, ( m_end - p ).SquaredEuclideanNorm() );
|
||||||
if( p0pdist < minDist )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
auto p1pdist = ( p1 - p ).EuclideanNorm();
|
|
||||||
|
|
||||||
if( p1pdist < minDist )
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p0dist = aSeg.Distance( m_start );
|
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_start ) );
|
||||||
|
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_end ) );
|
||||||
|
|
||||||
|
if( dist_sq < (ecoord) minDist * minDist )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - m_width / 2 );
|
||||||
|
|
||||||
if( p0dist > minDist )
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
auto p1dist = aSeg.Distance( p1 );
|
return false;
|
||||||
|
|
||||||
if( p1dist > minDist )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,7 +163,7 @@ const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
|
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
int minDist = aClearance + m_width / 2;
|
int minDist = aClearance + m_width / 2;
|
||||||
auto bbox = BBox( minDist );
|
auto bbox = BBox( minDist );
|
||||||
|
@ -184,9 +171,22 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
|
||||||
if( !bbox.Contains( aP ) )
|
if( !bbox.Contains( aP ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto dist = ( aP - GetCenter() ).EuclideanNorm();
|
ecoord min_dist_sq = (ecoord) minDist * minDist;
|
||||||
|
ecoord r = GetRadius();
|
||||||
|
ecoord r_sq = r * r;
|
||||||
|
|
||||||
return dist <= ( GetRadius() + minDist ) && dist >= ( GetRadius() - minDist );
|
ecoord dist_sq = ( aP - GetCenter() ).SquaredEuclideanNorm();
|
||||||
|
ecoord dist_to_edge_sq = abs( dist_sq - r_sq );
|
||||||
|
|
||||||
|
if( dist_to_edge_sq < min_dist_sq )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, (int) sqrt( dist_to_edge_sq ) - m_width / 2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <assert.h> // for assert
|
#include <assert.h> // for assert
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits.h> // for INT_MAX
|
#include <limits.h> // for INT_MAX
|
||||||
#include <stdlib.h> // for abs
|
|
||||||
|
|
||||||
#include <geometry/seg.h> // for SEG
|
#include <geometry/seg.h> // for SEG
|
||||||
#include <geometry/shape.h>
|
#include <geometry/shape.h>
|
||||||
|
@ -36,13 +35,12 @@
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_simple.h>
|
#include <geometry/shape_simple.h>
|
||||||
#include <math/box2.h> // for BOX2I
|
|
||||||
#include <math/vector2d.h>
|
#include <math/vector2d.h>
|
||||||
|
|
||||||
typedef VECTOR2I::extended_type ecoord;
|
typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
|
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
|
||||||
ecoord min_dist_sq = min_dist * min_dist;
|
ecoord min_dist_sq = min_dist * min_dist;
|
||||||
|
@ -54,21 +52,25 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int
|
||||||
if( dist_sq >= min_dist_sq )
|
if( dist_sq >= min_dist_sq )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( aNeedMTV )
|
if( aActual )
|
||||||
aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() - aB.GetRadius() );
|
||||||
|
|
||||||
|
if( aMTV )
|
||||||
|
*aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const VECTOR2I c = aB.GetCenter();
|
const VECTOR2I c = aB.GetCenter();
|
||||||
const VECTOR2I p0 = aA.GetPosition();
|
const VECTOR2I p0 = aA.GetPosition();
|
||||||
const VECTOR2I size = aA.GetSize();
|
const VECTOR2I size = aA.GetSize();
|
||||||
const int r = aB.GetRadius();
|
const int r = aB.GetRadius();
|
||||||
const int min_dist = aClearance + r;
|
const int min_dist = aClearance + r;
|
||||||
|
const ecoord min_dist_sq = (ecoord) min_dist * min_dist;
|
||||||
|
|
||||||
const VECTOR2I vts[] =
|
const VECTOR2I vts[] =
|
||||||
{
|
{
|
||||||
|
@ -79,47 +81,52 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aC
|
||||||
VECTOR2I( p0.x, p0.y )
|
VECTOR2I( p0.x, p0.y )
|
||||||
};
|
};
|
||||||
|
|
||||||
int nearest_seg_dist = INT_MAX;
|
ecoord nearest_side_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
VECTOR2I nearest;
|
VECTOR2I nearest;
|
||||||
|
|
||||||
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
|
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
|
||||||
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
|
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
|
||||||
|
|
||||||
|
if( inside && !aMTV )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = 0;
|
||||||
|
|
||||||
if( !aNeedMTV && inside )
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
for( int i = 0; i < 4; i++ )
|
for( int i = 0; i < 4; i++ )
|
||||||
{
|
{
|
||||||
const SEG seg( vts[i], vts[i + 1] );
|
const SEG side( vts[i], vts[ i + 1] );
|
||||||
|
|
||||||
VECTOR2I pn = seg.NearestPoint( c );
|
VECTOR2I pn = side.NearestPoint( c );
|
||||||
|
int side_dist_sq = ( pn - c ).SquaredEuclideanNorm();
|
||||||
|
|
||||||
int d = ( pn - c ).EuclideanNorm();
|
if(( side_dist_sq < min_dist_sq ) && !aMTV && !aActual )
|
||||||
|
|
||||||
if( ( d < min_dist ) && !aNeedMTV )
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( d < nearest_seg_dist )
|
if( side_dist_sq < nearest_side_dist_sq )
|
||||||
{
|
{
|
||||||
nearest = pn;
|
nearest = pn;
|
||||||
nearest_seg_dist = d;
|
nearest_side_dist_sq = side_dist_sq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nearest_seg_dist >= min_dist && !inside )
|
if( !inside && nearest_side_dist_sq >= min_dist_sq )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
VECTOR2I delta = c - nearest;
|
VECTOR2I delta = c - nearest;
|
||||||
|
|
||||||
if( !aNeedMTV )
|
if( aActual )
|
||||||
return true;
|
*aActual = std::max( 0, (int) sqrt( nearest_side_dist_sq ) - r );
|
||||||
|
|
||||||
|
if( aMTV )
|
||||||
if( inside )
|
{
|
||||||
aMTV = -delta.Resize( abs( min_dist + 1 + nearest_seg_dist ) + 1 );
|
if( inside )
|
||||||
else
|
*aMTV = -delta.Resize( abs( min_dist + 1 + sqrt( nearest_side_dist_sq ) ) + 1 );
|
||||||
aMTV = delta.Resize( abs( min_dist + 1 - nearest_seg_dist ) + 1 );
|
else
|
||||||
|
*aMTV = delta.Resize( abs( min_dist + 1 - sqrt( nearest_side_dist_sq ) ) + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -154,387 +161,438 @@ static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aCleara
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for( int s = 0; s < aB.SegmentCount(); s++ )
|
for( int s = 0; s < aB.SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
if( aA.Collide( aB.CSegment( s ), aClearance ) )
|
if( aA.Collide( aB.CSegment( s ), aClearance, aActual ) )
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !aNeedMTV || !found )
|
if( !found )
|
||||||
return found;
|
return false;
|
||||||
|
|
||||||
SHAPE_CIRCLE cmoved( aA );
|
if( aMTV )
|
||||||
VECTOR2I f_total( 0, 0 );
|
|
||||||
|
|
||||||
for( int s = 0; s < aB.SegmentCount(); s++ )
|
|
||||||
{
|
{
|
||||||
VECTOR2I f = pushoutForce( cmoved, aB.CSegment( s ), aClearance );
|
SHAPE_CIRCLE cmoved( aA );
|
||||||
cmoved.SetCenter( cmoved.GetCenter() + f );
|
VECTOR2I f_total( 0, 0 );
|
||||||
f_total += f;
|
|
||||||
|
for( int s = 0; s < aB.SegmentCount(); s++ )
|
||||||
|
{
|
||||||
|
VECTOR2I f = pushoutForce( cmoved, aB.CSegment( s ), aClearance );
|
||||||
|
cmoved.SetCenter( cmoved.GetCenter() + f );
|
||||||
|
f_total += f;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aMTV = f_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
aMTV = f_total;
|
return true;
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
bool found;
|
int min_dist = aClearance + aA.GetRadius();
|
||||||
const SHAPE_LINE_CHAIN& lc( aB.Vertices() );
|
ecoord dist_sq = aB.Vertices().SquaredDistance( aA.GetCenter() );
|
||||||
|
|
||||||
found = lc.Distance( aA.GetCenter() ) <= aClearance + aA.GetRadius();
|
if( dist_sq > (ecoord) min_dist * min_dist )
|
||||||
|
return false;
|
||||||
|
|
||||||
if( !aNeedMTV || !found )
|
if( aActual )
|
||||||
return found;
|
*aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() );
|
||||||
|
|
||||||
SHAPE_CIRCLE cmoved( aA );
|
if( aMTV )
|
||||||
VECTOR2I f_total( 0, 0 );
|
|
||||||
|
|
||||||
for( int s = 0; s < lc.SegmentCount(); s++ )
|
|
||||||
{
|
{
|
||||||
VECTOR2I f = pushoutForce( cmoved, lc.CSegment( s ), aClearance );
|
SHAPE_CIRCLE cmoved( aA );
|
||||||
cmoved.SetCenter( cmoved.GetCenter() + f );
|
VECTOR2I f_total( 0, 0 );
|
||||||
f_total += f;
|
|
||||||
}
|
|
||||||
|
|
||||||
aMTV = f_total;
|
for( int s = 0; s < aB.Vertices().SegmentCount(); s++ )
|
||||||
return found;
|
{
|
||||||
|
VECTOR2I f = pushoutForce( cmoved, aB.Vertices().CSegment( s ), aClearance );
|
||||||
|
cmoved.SetCenter( cmoved.GetCenter() + f );
|
||||||
|
f_total += f;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aMTV = f_total;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
bool col = aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2);
|
bool col = aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual );
|
||||||
|
|
||||||
|
if( col && aMTV )
|
||||||
|
*aMTV = -pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2);
|
||||||
|
|
||||||
if( col && aNeedMTV )
|
|
||||||
{
|
|
||||||
aMTV = -pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2);
|
|
||||||
}
|
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < aB.SegmentCount(); i++ )
|
for( int i = 0; i < aB.SegmentCount(); i++ )
|
||||||
if( aA.Collide( aB.CSegment( i ), aClearance ) )
|
{
|
||||||
|
if( aA.Collide( aB.CSegment( i ), aClearance, aActual ) )
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
|
return Collide( aA, aB.Vertices(), aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_SIMPLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_SIMPLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
return Collide( aA.Vertices(), aB.Vertices(), aClearance, aNeedMTV, aMTV );
|
return Collide( aA.Vertices(), aB.Vertices(), aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
|
int minActual = INT_MAX;
|
||||||
|
int actual;
|
||||||
|
|
||||||
for( int s = 0; s < aB.SegmentCount(); s++ )
|
for( int s = 0; s < aB.SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
if( aA.Collide( aB.CSegment( s ), aClearance ) )
|
if( aA.Collide( aB.CSegment( s ), aClearance, &actual ) )
|
||||||
return true;
|
{
|
||||||
|
minActual = std::min( minActual, actual );
|
||||||
|
|
||||||
|
if( !aActual )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, minActual );
|
||||||
|
|
||||||
|
return minActual < INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
||||||
|
int* aActual, VECTOR2I* aMTV )
|
||||||
|
{
|
||||||
|
return Collide( aA, aB.Vertices(), aClearance, aActual, aMTV );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||||
|
int* aActual, VECTOR2I* aMTV )
|
||||||
|
{
|
||||||
|
int actual;
|
||||||
|
|
||||||
|
if( aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, &actual ) )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, actual - aSeg.GetWidth() / 2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
|
||||||
{
|
|
||||||
return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
|
||||||
{
|
|
||||||
return aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
return aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2 );
|
int actual;
|
||||||
|
|
||||||
|
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, &actual ) )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, actual - aB.GetWidth() / 2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2 ) )
|
int actual;
|
||||||
|
|
||||||
|
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, &actual ) )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = std::max( 0, actual - aB.GetWidth() / 2 );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_SIMPLE& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_SIMPLE& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
return Collide( aA.Vertices(), aB, aClearance, aNeedMTV, aMTV );
|
return Collide( aA.Vertices(), aB, aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
return Collide( aA.Outline(), aB.Outline(), aClearance, aNeedMTV, aMTV );
|
return Collide( aA.Outline(), aB.Outline(), aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_RECT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_RECT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lc = aA.ConvertToPolyline();
|
const auto lc = aA.ConvertToPolyline();
|
||||||
return Collide( lc, aB.Outline(), aClearance, aNeedMTV, aMTV );
|
return Collide( lc, aB.Outline(), aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lc = aA.ConvertToPolyline();
|
const auto lc = aA.ConvertToPolyline();
|
||||||
bool rv = Collide( aB, lc, aClearance, aNeedMTV, aMTV );
|
bool rv = Collide( aB, lc, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
if( rv && aNeedMTV )
|
if( rv && aMTV )
|
||||||
aMTV = -aMTV;
|
*aMTV = - *aMTV ;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lc = aA.ConvertToPolyline();
|
const auto lc = aA.ConvertToPolyline();
|
||||||
return Collide( lc, aB, aClearance, aNeedMTV, aMTV );
|
return Collide( lc, aB, aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lc = aA.ConvertToPolyline();
|
const auto lc = aA.ConvertToPolyline();
|
||||||
return Collide( lc, aB, aClearance, aNeedMTV, aMTV );
|
return Collide( lc, aB, aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SIMPLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lc = aA.ConvertToPolyline();
|
const auto lc = aA.ConvertToPolyline();
|
||||||
return Collide( lc, aB.Vertices(), aClearance, aNeedMTV, aMTV );
|
|
||||||
|
return Collide( lc, aB.Vertices(), aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_ARC& aB, int aClearance,
|
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_ARC& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
const auto lcA = aA.ConvertToPolyline();
|
const auto lcA = aA.ConvertToPolyline();
|
||||||
const auto lcB = aB.ConvertToPolyline();
|
const auto lcB = aB.ConvertToPolyline();
|
||||||
return Collide( lcA, lcB, aClearance, aNeedMTV, aMTV );
|
return Collide( lcA, lcB, aClearance, aActual, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ShapeAType, class ShapeBType>
|
template<class T_a, class T_b>
|
||||||
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
|
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||||
|
VECTOR2I* aMTV )
|
||||||
|
|
||||||
{
|
{
|
||||||
return Collide (*static_cast<const ShapeAType*>( aA ),
|
return Collide( *static_cast<const T_a*>( aA ), *static_cast<const T_b*>( aB ),
|
||||||
*static_cast<const ShapeBType*>( aB ),
|
aClearance, aActual, aMTV);
|
||||||
aClearance, aNeedMTV, aMTV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ShapeAType, class ShapeBType>
|
template<class T_a, class T_b>
|
||||||
inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
|
inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||||
|
VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
bool rv = Collide (*static_cast<const ShapeBType*>( aB ),
|
bool rv = Collide( *static_cast<const T_b*>( aB ), *static_cast<const T_a*>( aA ),
|
||||||
*static_cast<const ShapeAType*>( aA ),
|
aClearance, aActual, aMTV);
|
||||||
aClearance, aNeedMTV, aMTV);
|
|
||||||
if(rv && aNeedMTV)
|
if( rv && aMTV)
|
||||||
aMTV = -aMTV;
|
*aMTV = - *aMTV;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
|
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, VECTOR2I* aMTV )
|
||||||
{
|
{
|
||||||
switch( aA->Type() )
|
switch( aA->Type() )
|
||||||
{
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
case SH_RECT:
|
case SH_RECT:
|
||||||
switch( aB->Type() )
|
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
case SH_CIRCLE:
|
||||||
switch( aB->Type() )
|
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
case SH_LINE_CHAIN:
|
||||||
switch( aB->Type() )
|
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
case SH_SEGMENT:
|
||||||
switch( aB->Type() )
|
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
case SH_SIMPLE:
|
||||||
switch( aB->Type() )
|
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aB, aA, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_SIMPLE, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCaseReversed<SHAPE_SIMPLE, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SH_ARC:
|
case SH_ARC:
|
||||||
switch( aB->Type() )
|
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
{
|
|
||||||
case SH_RECT:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_CIRCLE:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SEGMENT:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_SIMPLE:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
case SH_ARC:
|
|
||||||
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
return CollCase<SHAPE_SIMPLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
return CollCaseReversed<SHAPE_SIMPLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
switch( aB->Type() )
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SEGMENT:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_SIMPLE:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
case SH_ARC:
|
||||||
|
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unsupported_collision = true;
|
bool unsupported_collision = true;
|
||||||
|
@ -546,53 +604,46 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, VECTOR2I& aMTV ) const
|
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const
|
||||||
{
|
{
|
||||||
return CollideShapes( this, aShape, aClearance, true, aMTV );
|
return CollideShapes( this, aShape, aClearance, nullptr, aMTV );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE::Collide( const SHAPE* aShape, int aClearance ) const
|
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
VECTOR2I dummy;
|
return CollideShapes( this, aShape, aClearance, aActual, nullptr );
|
||||||
|
|
||||||
return CollideShapes( this, aShape, aClearance, false, dummy );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
return DoCollide( aSeg, aClearance, &dummy );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_RECT::DoCollide( const SEG& aSeg, int aClearance, int* aActualDist ) const
|
|
||||||
{
|
{
|
||||||
if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) )
|
if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) )
|
||||||
{
|
{
|
||||||
*aActualDist = 0;
|
*aActual = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
|
VECTOR2I corners[] = { VECTOR2I( m_p0.x, m_p0.y ),
|
||||||
VECTOR2I( m_p0.x, m_p0.y + m_h ),
|
VECTOR2I( m_p0.x, m_p0.y + m_h ),
|
||||||
VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ),
|
VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ),
|
||||||
VECTOR2I( m_p0.x + m_w, m_p0.y ),
|
VECTOR2I( m_p0.x + m_w, m_p0.y ),
|
||||||
VECTOR2I( m_p0.x, m_p0.y ) };
|
VECTOR2I( m_p0.x, m_p0.y ) };
|
||||||
|
|
||||||
SEG s( vts[0], vts[1] );
|
SEG s( corners[0], corners[1] );
|
||||||
SEG::ecoord dist_squared = s.SquaredDistance( aSeg );
|
SEG::ecoord dist_squared = s.SquaredDistance( aSeg );
|
||||||
|
|
||||||
for( int i = 1; i < 4; i++ )
|
for( int i = 1; i < 4; i++ )
|
||||||
{
|
{
|
||||||
s = SEG( vts[i], vts[i + 1] );
|
s = SEG( corners[i], corners[ i + 1] );
|
||||||
dist_squared = std::min( dist_squared, s.SquaredDistance( aSeg ) );
|
dist_squared = std::min( dist_squared, s.SquaredDistance( aSeg ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( dist_squared < SEG::ecoord( aClearance ) * SEG::ecoord( aClearance ) )
|
if( dist_squared < (ecoord) aClearance * aClearance )
|
||||||
{
|
{
|
||||||
*aActualDist = sqrt( dist_squared );
|
if( aActual )
|
||||||
|
*aActual = sqrt( dist_squared );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,11 +85,29 @@ void SHAPE_LINE_CHAIN::convertArc( ssize_t aArcIndex )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
|
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
// fixme: ugly!
|
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
SEG s( aP, aP );
|
SEG::ecoord clearance_sq = SEG::Square( aClearance );
|
||||||
return this->Collide( s, aClearance );
|
|
||||||
|
for( int i = 0; i < SegmentCount(); i++ )
|
||||||
|
{
|
||||||
|
const SEG& s = CSegment( i );
|
||||||
|
dist_sq = std::min( dist_sq, s.SquaredDistance( aP ) );
|
||||||
|
|
||||||
|
if( !aActual && dist_sq < clearance_sq )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dist_sq < clearance_sq )
|
||||||
|
{
|
||||||
|
if( aActual )
|
||||||
|
*aActual = sqrt( dist_sq );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,23 +125,26 @@ void SHAPE_LINE_CHAIN::Rotate( double aAngle, const VECTOR2I& aCenter )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
BOX2I box_a( aSeg.A, aSeg.B - aSeg.A );
|
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
|
SEG::ecoord clearance_sq = SEG::Square( aClearance );
|
||||||
|
|
||||||
for( int i = 0; i < SegmentCount(); i++ )
|
for( int i = 0; i < SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
const SEG& s = CSegment( i );
|
const SEG& s = CSegment( i );
|
||||||
BOX2I box_b( s.A, s.B - s.A );
|
dist_sq = std::min( dist_sq, s.SquaredDistance( aSeg ) );
|
||||||
|
|
||||||
BOX2I::ecoord_type d = box_a.SquaredDistance( box_b );
|
if( !aActual && dist_sq < clearance_sq )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if( d < dist_sq )
|
if( dist_sq < clearance_sq )
|
||||||
{
|
{
|
||||||
if( s.Collide( aSeg, aClearance ) )
|
if( aActual )
|
||||||
return true;
|
*aActual = sqrt( dist_sq );
|
||||||
}
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -267,13 +288,19 @@ void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
|
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
|
||||||
{
|
{
|
||||||
int d = INT_MAX;
|
return sqrt( SquaredDistance( aP, aOutlineOnly ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SEG::ecoord SHAPE_LINE_CHAIN::SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly ) const
|
||||||
|
{
|
||||||
|
ecoord d = VECTOR2I::ECOORD_MAX;
|
||||||
|
|
||||||
if( IsClosed() && PointInside( aP ) && !aOutlineOnly )
|
if( IsClosed() && PointInside( aP ) && !aOutlineOnly )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for( int s = 0; s < SegmentCount(); s++ )
|
for( int s = 0; s < SegmentCount(); s++ )
|
||||||
d = std::min( d, CSegment( s ).Distance( aP ) );
|
d = std::min( d, CSegment( s ).SquaredDistance( aP ) );
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1224,50 +1224,35 @@ bool SHAPE_POLY_SET::PointOnEdge( const VECTOR2I& aP ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
|
ecoord dist_sq = SquaredDistance( aSeg );
|
||||||
|
|
||||||
SHAPE_POLY_SET polySet = SHAPE_POLY_SET( *this );
|
if( dist_sq < (ecoord) aClearance * aClearance )
|
||||||
|
|
||||||
// Inflate the polygon if necessary.
|
|
||||||
if( aClearance > 0 )
|
|
||||||
{
|
{
|
||||||
// fixme: the number of arc segments should not be hardcoded
|
if( aActual )
|
||||||
polySet.Inflate( aClearance, 8 );
|
*aActual = sqrt( dist_sq );
|
||||||
}
|
|
||||||
|
|
||||||
// We are going to check to see if the segment crosses an external
|
|
||||||
// boundary. However, if the full segment is inside the polyset, this
|
|
||||||
// will not be true. So we first test to see if one of the points is
|
|
||||||
// inside. If true, then we collide
|
|
||||||
if( polySet.Contains( aSeg.A ) )
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for( CONST_SEGMENT_ITERATOR it = CIterateSegmentsWithHoles(); it; it++ )
|
|
||||||
{
|
|
||||||
const SEG polygonEdge = *it;
|
|
||||||
|
|
||||||
if( polygonEdge.Intersect( aSeg, true ) )
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::Collide( const VECTOR2I& aP, int aClearance ) const
|
bool SHAPE_POLY_SET::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET polySet = SHAPE_POLY_SET( *this );
|
ecoord dist_sq = SquaredDistance( aP );
|
||||||
|
|
||||||
// Inflate the polygon if necessary.
|
if( dist_sq < (ecoord) aClearance * aClearance )
|
||||||
if( aClearance > 0 )
|
|
||||||
{
|
{
|
||||||
// fixme: the number of arc segments should not be hardcoded
|
if( aActual )
|
||||||
polySet.Inflate( aClearance, 8 );
|
*aActual = sqrt( dist_sq );
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is a collision if and only if the point is inside of the polygon.
|
return false;
|
||||||
return polySet.Contains( aP );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int
|
||||||
return std::abs( delta.y ) <= aDist;
|
return std::abs( delta.y ) <= aDist;
|
||||||
|
|
||||||
SEG segment( aStart, aEnd );
|
SEG segment( aStart, aEnd );
|
||||||
return segment.PointCloserThan( aRefPoint, aDist + 1 );
|
return segment.SquaredDistance( aRefPoint ) < SEG::Square( aDist + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -370,7 +370,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
|
||||||
{
|
{
|
||||||
case S_CIRCLE:
|
case S_CIRCLE:
|
||||||
if( width == 0 )
|
if( width == 0 )
|
||||||
TransformCircleToPolygon( aCornerBuffer, GetCenter(), GetRadius() + width / 2, aError );
|
TransformCircleToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError );
|
||||||
else
|
else
|
||||||
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError, width );
|
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError, width );
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,6 +34,9 @@
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <class_drawsegment.h>
|
#include <class_drawsegment.h>
|
||||||
#include <base_units.h>
|
#include <base_units.h>
|
||||||
|
#include <geometry/shape_simple.h>
|
||||||
|
#include <geometry/shape_segment.h>
|
||||||
|
#include <geometry/shape_circle.h>
|
||||||
#include <settings/color_settings.h>
|
#include <settings/color_settings.h>
|
||||||
#include <settings/settings_manager.h>
|
#include <settings/settings_manager.h>
|
||||||
|
|
||||||
|
@ -590,16 +593,13 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
||||||
int radius = GetRadius();
|
int radius = GetRadius();
|
||||||
int dist = KiROUND( EuclideanNorm( aPosition - GetCenter() ) );
|
int dist = KiROUND( EuclideanNorm( aPosition - GetCenter() ) );
|
||||||
|
|
||||||
if( m_Width == 0 )
|
if( m_Width == 0 ) // Filled circle hit-test
|
||||||
{
|
{
|
||||||
// Filled circle hit-test
|
|
||||||
if( dist <= radius + maxdist )
|
if( dist <= radius + maxdist )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else // Ring hit-test
|
||||||
if( m_Width > 0 )
|
|
||||||
{
|
{
|
||||||
// Ring hit-test
|
|
||||||
if( abs( radius - dist ) <= maxdist )
|
if( abs( radius - dist ) <= maxdist )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,7 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
||||||
std::vector<wxPoint> pts;
|
std::vector<wxPoint> pts;
|
||||||
GetRectCorners( &pts );
|
GetRectCorners( &pts );
|
||||||
|
|
||||||
if( m_Width == 0 )
|
if( m_Width == 0 ) // Filled rect hit-test
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET poly;
|
SHAPE_POLY_SET poly;
|
||||||
poly.NewOutline();
|
poly.NewOutline();
|
||||||
|
@ -677,8 +677,7 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
||||||
if( poly.Collide( VECTOR2I( aPosition ), maxdist ) )
|
if( poly.Collide( VECTOR2I( aPosition ), maxdist ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else // Open rect hit-test
|
||||||
if( m_Width > 0 )
|
|
||||||
{
|
{
|
||||||
if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
|
if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
|
||||||
|| TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
|
|| TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
|
||||||
|
@ -828,7 +827,7 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_CURVE: // not yet handled
|
case S_CURVE:
|
||||||
if( aContained )
|
if( aContained )
|
||||||
{
|
{
|
||||||
return arect.Contains( bb );
|
return arect.Contains( bb );
|
||||||
|
@ -1015,6 +1014,112 @@ void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<SHAPE*> DRAWSEGMENT::MakeEffectiveShapes()
|
||||||
|
{
|
||||||
|
std::vector<SHAPE*> effectiveShapes;
|
||||||
|
|
||||||
|
switch( m_Shape )
|
||||||
|
{
|
||||||
|
case S_ARC:
|
||||||
|
{
|
||||||
|
SHAPE_ARC arc( GetCenter(), GetArcStart(), (double) GetAngle() / 10.0 );
|
||||||
|
SHAPE_LINE_CHAIN l = arc.ConvertToPolyline();
|
||||||
|
|
||||||
|
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A,
|
||||||
|
l.Segment( i ).B, m_Width ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case S_SEGMENT:
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( GetStart(), GetEnd(), m_Width ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_RECT:
|
||||||
|
{
|
||||||
|
std::vector<wxPoint> pts;
|
||||||
|
GetRectCorners( &pts );
|
||||||
|
|
||||||
|
if( m_Width == 0 )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], m_Width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], m_Width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], m_Width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], m_Width ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_CIRCLE:
|
||||||
|
{
|
||||||
|
if( m_Width == 0 )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_CIRCLE( GetCenter(), GetRadius() ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
|
||||||
|
SHAPE_ARC circle( GetCenter(), GetEnd(), 360.0 );
|
||||||
|
SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
|
||||||
|
|
||||||
|
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A,
|
||||||
|
l.Segment( i ).B, m_Width ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case S_CURVE:
|
||||||
|
{
|
||||||
|
RebuildBezierToSegmentsPointsList( GetWidth() );
|
||||||
|
wxPoint start_pt = GetBezierPoints()[0];
|
||||||
|
|
||||||
|
for( unsigned int jj = 1; jj < GetBezierPoints().size(); jj++ )
|
||||||
|
{
|
||||||
|
wxPoint end_pt = GetBezierPoints()[jj];
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( start_pt, end_pt, m_Width ) );
|
||||||
|
start_pt = end_pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case S_POLYGON:
|
||||||
|
{
|
||||||
|
SHAPE_LINE_CHAIN l = GetPolyShape().Outline( 0 );
|
||||||
|
|
||||||
|
if( IsPolygonFilled() )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxFAIL_MSG( "DRAWSEGMENT::MakeEffectiveShapes unsupported DRAWSEGMENT shape: "
|
||||||
|
+ STROKE_T_asString( m_Shape ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return effectiveShapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::vector<wxPoint> DRAWSEGMENT::BuildPolyPointsList() const
|
const std::vector<wxPoint> DRAWSEGMENT::BuildPolyPointsList() const
|
||||||
{
|
{
|
||||||
std::vector<wxPoint> rv;
|
std::vector<wxPoint> rv;
|
||||||
|
|
|
@ -36,9 +36,9 @@
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
#include <math_for_graphics.h>
|
#include <math_for_graphics.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
|
|
||||||
#include <geometry/shape_poly_set.h>
|
#include <geometry/shape_poly_set.h>
|
||||||
|
|
||||||
|
|
||||||
class LINE_READER;
|
class LINE_READER;
|
||||||
class EDA_DRAW_FRAME;
|
class EDA_DRAW_FRAME;
|
||||||
class MODULE;
|
class MODULE;
|
||||||
|
@ -237,6 +237,11 @@ public:
|
||||||
|
|
||||||
void SetPolyPoints( const std::vector<wxPoint>& aPoints );
|
void SetPolyPoints( const std::vector<wxPoint>& aPoints );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a set of SHAPE objects representing the DRAWSEGMENT. Caller owns the objects.
|
||||||
|
*/
|
||||||
|
std::vector<SHAPE*> MakeEffectiveShapes();
|
||||||
|
|
||||||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||||
|
|
||||||
const EDA_RECT GetBoundingBox() const override;
|
const EDA_RECT GetBoundingBox() const override;
|
||||||
|
|
|
@ -327,32 +327,28 @@ void D_PAD::BuildEffectiveShapes() const
|
||||||
|
|
||||||
if( GetShape() == PAD_SHAPE_CUSTOM )
|
if( GetShape() == PAD_SHAPE_CUSTOM )
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET* poly = new SHAPE_POLY_SET();
|
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
|
||||||
MergePrimitivesAsPolygon( poly );
|
{
|
||||||
poly->Rotate( -DECIDEG2RAD( m_Orient ) );
|
for( SHAPE* shape : primitive->MakeEffectiveShapes() )
|
||||||
poly->Move( shapePos );
|
{
|
||||||
add( poly );
|
shape->Rotate( -DECIDEG2RAD( m_Orient ) );
|
||||||
|
shape->Move( shapePos );
|
||||||
|
add( shape );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounding box and radius
|
// Bounding box and radius
|
||||||
//
|
//
|
||||||
m_effectiveBoundingRadius = calcBoundingRadius();
|
m_effectiveBoundingRadius = calcBoundingRadius();
|
||||||
|
|
||||||
bool first_shape = true;
|
m_effectiveBoundingBox = EDA_RECT(); // reset to prepare for merging
|
||||||
|
|
||||||
for( const std::shared_ptr<SHAPE>& shape : m_effectiveShapes )
|
for( const std::shared_ptr<SHAPE>& shape : m_effectiveShapes )
|
||||||
{
|
{
|
||||||
BOX2I r = shape->BBox();
|
BOX2I r = shape->BBox();
|
||||||
|
m_effectiveBoundingBox.Merge( EDA_RECT( (wxPoint) r.GetOrigin(),
|
||||||
if( first_shape )
|
wxSize( r.GetWidth(), r.GetHeight() ) ) );
|
||||||
{
|
|
||||||
m_effectiveBoundingBox.SetOrigin( (wxPoint) r.GetOrigin() );
|
|
||||||
m_effectiveBoundingBox.SetEnd( (wxPoint) r.GetEnd() );
|
|
||||||
first_shape = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_effectiveBoundingBox.Merge( EDA_RECT( (wxPoint) r.GetOrigin(),
|
|
||||||
wxSize( r.GetWidth(), r.GetHeight() ) ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole shape
|
// Hole shape
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||||
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -32,13 +32,10 @@
|
||||||
#include <fctsys.h>
|
#include <fctsys.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <confirm.h>
|
#include <confirm.h>
|
||||||
#include <pcbnew.h>
|
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <macros.h>
|
|
||||||
#include <pcb_base_frame.h>
|
#include <pcb_base_frame.h>
|
||||||
#include <base_units.h>
|
#include <base_units.h>
|
||||||
#include <widgets/wx_grid.h>
|
#include <widgets/wx_grid.h>
|
||||||
#include <class_board.h>
|
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
|
|
||||||
|
@ -224,8 +221,11 @@ DIALOG_PAD_PRIMITIVE_POLY_PROPS::DIALOG_PAD_PRIMITIVE_POLY_PROPS( wxWindow* aPar
|
||||||
m_shape( aShape ),
|
m_shape( aShape ),
|
||||||
m_thickness( aFrame, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true )
|
m_thickness( aFrame, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true )
|
||||||
{
|
{
|
||||||
for( const VECTOR2I& pt : m_shape->GetPolyShape().Outline( 0 ).CPoints() )
|
if( !m_shape->GetPolyShape().IsEmpty() )
|
||||||
m_currPoints.emplace_back( pt );
|
{
|
||||||
|
for( const VECTOR2I& pt : m_shape->GetPolyShape().Outline( 0 ).CPoints() )
|
||||||
|
m_currPoints.emplace_back( pt );
|
||||||
|
}
|
||||||
|
|
||||||
m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
|
m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
|
||||||
m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );
|
m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );
|
||||||
|
|
|
@ -626,7 +626,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActualDist )
|
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual )
|
||||||
{
|
{
|
||||||
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
|
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
|
||||||
|
|
||||||
|
@ -634,33 +634,24 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance
|
||||||
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// JEY TODO:
|
int actual = INT_MAX;
|
||||||
// TOM TODO: MTV only works as a proxy for actual-distance for convex shapes
|
|
||||||
|
|
||||||
VECTOR2I mtv; // minimum translation vector calculated by Collide()
|
|
||||||
VECTOR2I maxMtv( 0, 0 ); // is the move distance between 2 shapes calculated
|
|
||||||
// by Collide to do not have a collision
|
|
||||||
bool shapes_collide = false;
|
|
||||||
|
|
||||||
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
|
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
|
||||||
{
|
{
|
||||||
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
||||||
{
|
{
|
||||||
if( aShape->Collide( bShape.get(), aMinClearance, mtv ) )
|
int this_dist;
|
||||||
{
|
|
||||||
shapes_collide = true;
|
|
||||||
|
|
||||||
if( mtv.SquaredEuclideanNorm() > maxMtv.SquaredEuclideanNorm() )
|
if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
|
||||||
maxMtv = mtv;
|
actual = std::min( actual, this_dist );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( shapes_collide )
|
if( actual < INT_MAX )
|
||||||
{
|
{
|
||||||
// returns the actual clearance (clearance < aMinClearance) for diags:
|
// returns the actual clearance (clearance < aMinClearance) for diags:
|
||||||
if( aActualDist )
|
if( aActual )
|
||||||
*aActualDist = std::max( 0, aMinClearance - maxMtv.EuclideanNorm() );
|
*aActual = std::max( 0, actual );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -719,7 +710,7 @@ bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_P
|
||||||
SHAPE_RECT padShape( padBBox.GetPosition(), padBBox.GetWidth(), padBBox.GetHeight() );
|
SHAPE_RECT padShape( padBBox.GetPosition(), padBBox.GetWidth(), padBBox.GetHeight() );
|
||||||
int actual;
|
int actual;
|
||||||
|
|
||||||
if( padShape.DoCollide( refSeg, minClearance + widths, &actual ) )
|
if( padShape.Collide( refSeg, minClearance + widths, &actual ) )
|
||||||
{
|
{
|
||||||
*aActualDist = std::max( 0, actual - widths );
|
*aActualDist = std::max( 0, actual - widths );
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -29,18 +29,12 @@
|
||||||
|
|
||||||
#include <fctsys.h>
|
#include <fctsys.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
|
|
||||||
#include <pcbnew.h>
|
#include <pcbnew.h>
|
||||||
|
|
||||||
#include <bezier_curves.h>
|
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
#include <class_board_item.h>
|
#include <class_board_item.h>
|
||||||
#include <class_drawsegment.h>
|
#include <class_drawsegment.h>
|
||||||
#include <class_edge_mod.h>
|
|
||||||
#include <class_pad.h>
|
#include <class_pad.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
#include <geometry/convex_hull.h>
|
|
||||||
#include <geometry/geometry_utils.h>
|
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -184,107 +178,7 @@ void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aErro
|
||||||
SHAPE_POLY_SET polyset;
|
SHAPE_POLY_SET polyset;
|
||||||
|
|
||||||
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
|
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
|
||||||
{
|
primitive->TransformShapeWithClearanceToPolygon( polyset, 0, aError );
|
||||||
int lineWidth = primitive->GetWidth();
|
|
||||||
|
|
||||||
switch( primitive->GetShape() )
|
|
||||||
{
|
|
||||||
case S_CURVE:
|
|
||||||
{
|
|
||||||
std::vector<wxPoint> ctrlPoints = { primitive->GetStart(), primitive->GetBezControl1(),
|
|
||||||
primitive->GetBezControl2(), primitive->GetEnd() };
|
|
||||||
BEZIER_POLY converter( ctrlPoints );
|
|
||||||
std::vector< wxPoint> poly;
|
|
||||||
converter.GetPoly( poly, lineWidth );
|
|
||||||
|
|
||||||
for( unsigned ii = 1; ii < poly.size(); ii++ )
|
|
||||||
TransformSegmentToPolygon( polyset, poly[ ii - 1 ], poly[ ii ], aError, lineWidth );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_SEGMENT: // usual segment : line with rounded ends
|
|
||||||
{
|
|
||||||
TransformSegmentToPolygon( polyset, primitive->GetStart(), primitive->GetEnd(),
|
|
||||||
aError, lineWidth );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_ARC: // Arc with rounded ends
|
|
||||||
{
|
|
||||||
TransformArcToPolygon( polyset, primitive->GetStart(), primitive->GetEnd(),
|
|
||||||
primitive->GetAngle(), aError, lineWidth );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_CIRCLE:
|
|
||||||
{
|
|
||||||
if( lineWidth ) // Ring
|
|
||||||
{
|
|
||||||
TransformRingToPolygon( polyset, primitive->GetStart(), primitive->GetRadius(),
|
|
||||||
aError, lineWidth );
|
|
||||||
}
|
|
||||||
else // Filled circle
|
|
||||||
{
|
|
||||||
TransformCircleToPolygon( polyset, primitive->GetStart(), primitive->GetRadius(),
|
|
||||||
aError );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_RECT:
|
|
||||||
{
|
|
||||||
wxPoint corners[4];
|
|
||||||
|
|
||||||
corners[0] = primitive->GetStart();
|
|
||||||
corners[1] = wxPoint( primitive->GetEnd().x, primitive->GetStart().y );
|
|
||||||
corners[2] = primitive->GetEnd();
|
|
||||||
corners[3] = wxPoint( primitive->GetStart().x, primitive->GetEnd().y );
|
|
||||||
|
|
||||||
if( lineWidth ) // Rect boundary
|
|
||||||
{
|
|
||||||
TransformSegmentToPolygon( polyset, corners[0], corners[1], aError, lineWidth );
|
|
||||||
TransformSegmentToPolygon( polyset, corners[1], corners[2], aError, lineWidth );
|
|
||||||
TransformSegmentToPolygon( polyset, corners[2], corners[3], aError, lineWidth );
|
|
||||||
TransformSegmentToPolygon( polyset, corners[3], corners[0], aError, lineWidth );
|
|
||||||
}
|
|
||||||
else // Filled rect
|
|
||||||
{
|
|
||||||
// Insert the polygon:
|
|
||||||
polyset.NewOutline();
|
|
||||||
|
|
||||||
for( const wxPoint& corner : corners )
|
|
||||||
polyset.Append( corner );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_POLYGON:
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET poly;
|
|
||||||
poly.NewOutline();
|
|
||||||
|
|
||||||
for( const VECTOR2I& pt : primitive->GetPolyShape().Outline( 0 ).CPoints() )
|
|
||||||
poly.Append( pt );
|
|
||||||
|
|
||||||
if( primitive->GetWidth() > 0 )
|
|
||||||
{
|
|
||||||
int numSegs = std::max( GetArcToSegmentCount( lineWidth / 2, aError, 360.0 ), 6 );
|
|
||||||
poly.Inflate( lineWidth / 2, numSegs );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the polygon:
|
|
||||||
polyset.NewOutline();
|
|
||||||
polyset.Append( poly );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// un-handled primitive
|
|
||||||
wxASSERT_MSG( false, "D_PAD::addPadPrimitivesToPolygon not implemented for "
|
|
||||||
+ BOARD_ITEM::ShowShape( primitive->GetShape() ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
|
polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VEC
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( aNeedMTV )
|
if( aNeedMTV )
|
||||||
return Shape()->Collide( aOther->Shape(), aClearance, *aMTV );
|
return Shape()->Collide( aOther->Shape(), aClearance, aMTV );
|
||||||
else
|
else
|
||||||
return Shape()->Collide( aOther->Shape(), aClearance );
|
return Shape()->Collide( aOther->Shape(), aClearance );
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,90 +826,14 @@ bool PNS_KICAD_IFACE_BASE::syncTextItem( PNS::NODE* aWorld, EDA_TEXT* aText, PCB
|
||||||
|
|
||||||
bool PNS_KICAD_IFACE_BASE::syncGraphicalItem( PNS::NODE* aWorld, DRAWSEGMENT* aItem )
|
bool PNS_KICAD_IFACE_BASE::syncGraphicalItem( PNS::NODE* aWorld, DRAWSEGMENT* aItem )
|
||||||
{
|
{
|
||||||
std::vector<SHAPE_SEGMENT*> segs;
|
|
||||||
|
|
||||||
if( aItem->GetLayer() != Edge_Cuts && !IsCopperLayer( aItem->GetLayer() ) )
|
if( aItem->GetLayer() != Edge_Cuts && !IsCopperLayer( aItem->GetLayer() ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch( aItem->GetShape() )
|
// TODO: where do we handle filled polygons on copper layers?
|
||||||
{
|
if( aItem->GetShape() == S_POLYGON && aItem->IsPolygonFilled() )
|
||||||
case S_ARC:
|
return false;
|
||||||
{
|
|
||||||
SHAPE_ARC arc( aItem->GetCenter(), aItem->GetArcStart(), aItem->GetAngle() / 10.0 );
|
|
||||||
auto l = arc.ConvertToPolyline();
|
|
||||||
|
|
||||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
for( SHAPE* shape : aItem->MakeEffectiveShapes() )
|
||||||
{
|
|
||||||
SHAPE_SEGMENT* seg = new SHAPE_SEGMENT( l.CSegment( i ), aItem->GetWidth() );
|
|
||||||
segs.push_back( seg );
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_SEGMENT:
|
|
||||||
segs.push_back(
|
|
||||||
new SHAPE_SEGMENT( aItem->GetStart(), aItem->GetEnd(), aItem->GetWidth() ) );
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_RECT:
|
|
||||||
{
|
|
||||||
std::vector<wxPoint> pts;
|
|
||||||
aItem->GetRectCorners( &pts );
|
|
||||||
|
|
||||||
segs.push_back( new SHAPE_SEGMENT( pts[0], pts[1], aItem->GetWidth() ) );
|
|
||||||
segs.push_back( new SHAPE_SEGMENT( pts[1], pts[2], aItem->GetWidth() ) );
|
|
||||||
segs.push_back( new SHAPE_SEGMENT( pts[2], pts[3], aItem->GetWidth() ) );
|
|
||||||
segs.push_back( new SHAPE_SEGMENT( pts[3], pts[0], aItem->GetWidth() ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case S_CIRCLE:
|
|
||||||
{
|
|
||||||
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
|
|
||||||
SHAPE_ARC circle( aItem->GetCenter(), aItem->GetEnd(), 360.0 );
|
|
||||||
auto l = circle.ConvertToPolyline();
|
|
||||||
|
|
||||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
|
||||||
segs.push_back( new SHAPE_SEGMENT( l.CSegment( i ), aItem->GetWidth() ) );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_CURVE:
|
|
||||||
{
|
|
||||||
aItem->RebuildBezierToSegmentsPointsList( aItem->GetWidth() );
|
|
||||||
auto pts = aItem->GetBezierPoints();
|
|
||||||
|
|
||||||
for( size_t ii = 1; ii < pts.size(); ii++ )
|
|
||||||
{
|
|
||||||
segs.push_back( new SHAPE_SEGMENT(
|
|
||||||
VECTOR2I( pts[ii - 1] ), VECTOR2I( pts[ii] ), aItem->GetWidth() ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case S_POLYGON:
|
|
||||||
if( !aItem->IsPolygonFilled() )
|
|
||||||
{
|
|
||||||
auto poly = aItem->BuildPolyPointsList();
|
|
||||||
for( size_t ii = 1; ii < poly.size(); ii++ )
|
|
||||||
{
|
|
||||||
segs.push_back( new SHAPE_SEGMENT(
|
|
||||||
VECTOR2I( poly[ii - 1] ), VECTOR2I( poly[ii] ), aItem->GetWidth() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
segs.push_back( new SHAPE_SEGMENT(
|
|
||||||
VECTOR2I( poly.back() ), VECTOR2I( poly.front() ), aItem->GetWidth() ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( auto seg : segs )
|
|
||||||
{
|
{
|
||||||
std::unique_ptr< PNS::SOLID > solid( new PNS::SOLID );
|
std::unique_ptr< PNS::SOLID > solid( new PNS::SOLID );
|
||||||
|
|
||||||
|
@ -920,7 +844,7 @@ bool PNS_KICAD_IFACE_BASE::syncGraphicalItem( PNS::NODE* aWorld, DRAWSEGMENT* aI
|
||||||
|
|
||||||
solid->SetNet( -1 );
|
solid->SetNet( -1 );
|
||||||
solid->SetParent( nullptr );
|
solid->SetParent( nullptr );
|
||||||
solid->SetShape( seg );
|
solid->SetShape( shape );
|
||||||
solid->SetRoutable( false );
|
solid->SetRoutable( false );
|
||||||
|
|
||||||
aWorld->Add( std::move( solid ) );
|
aWorld->Add( std::move( solid ) );
|
||||||
|
|
|
@ -814,7 +814,7 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
|
||||||
*/
|
*/
|
||||||
SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
{
|
{
|
||||||
int clearance = getClearance( aCurrent, aObstacleVia ) ;
|
int clearance = getClearance( aCurrent, aObstacleVia ) + PNS_HULL_MARGIN;
|
||||||
LINE_PAIR_VEC draggedLines;
|
LINE_PAIR_VEC draggedLines;
|
||||||
bool lineCollision = false;
|
bool lineCollision = false;
|
||||||
bool viaCollision = false;
|
bool viaCollision = false;
|
||||||
|
@ -835,9 +835,9 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
currentLine = (LINE*) aCurrent;
|
currentLine = (LINE*) aCurrent;
|
||||||
lineCollision = CollideShapes( aObstacleVia->Shape(), currentLine->Shape(),
|
lineCollision = aObstacleVia->Shape()->Collide( currentLine->Shape(),
|
||||||
clearance + currentLine->Width() / 2 + PNS_HULL_MARGIN,
|
clearance + currentLine->Width() / 2,
|
||||||
true, mtvLine );
|
&mtvLine );
|
||||||
|
|
||||||
if( currentLine->EndsWithVia() )
|
if( currentLine->EndsWithVia() )
|
||||||
{
|
{
|
||||||
|
@ -846,8 +846,8 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
|
|
||||||
if( currentNet != obstacleNet && currentNet >= 0 && obstacleNet >= 0 )
|
if( currentNet != obstacleNet && currentNet >= 0 && obstacleNet >= 0 )
|
||||||
{
|
{
|
||||||
viaCollision = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(),
|
viaCollision = currentLine->Via().Shape()->Collide( aObstacleVia->Shape(),
|
||||||
clearance + PNS_HULL_MARGIN, true, mtvVia );
|
clearance, &mtvVia );
|
||||||
}
|
}
|
||||||
|
|
||||||
// hole-to-hole is a mechanical constraint (broken drill bits), not an electrical
|
// hole-to-hole is a mechanical constraint (broken drill bits), not an electrical
|
||||||
|
@ -875,8 +875,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
}
|
}
|
||||||
else if( aCurrent->OfKind( ITEM::SOLID_T ) )
|
else if( aCurrent->OfKind( ITEM::SOLID_T ) )
|
||||||
{
|
{
|
||||||
CollideShapes( aObstacleVia->Shape(), aCurrent->Shape(),
|
aObstacleVia->Shape()->Collide( aCurrent->Shape(), clearance, &mtvSolid );
|
||||||
clearance + PNS_HULL_MARGIN, true, mtvSolid );
|
|
||||||
mtv = -mtvSolid;
|
mtv = -mtvSolid;
|
||||||
rank = aCurrent->Rank() + 10000;
|
rank = aCurrent->Rank() + 10000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,12 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
|
||||||
{
|
{
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
VIA mv( *this );
|
VIA mv( *this );
|
||||||
VECTOR2I force, totalForce, force2;
|
VECTOR2I force, totalForce;
|
||||||
|
|
||||||
while( iter < aMaxIterations )
|
while( iter < aMaxIterations )
|
||||||
{
|
{
|
||||||
NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv,
|
NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv, aSolidsOnly ? ITEM::SOLID_T
|
||||||
aSolidsOnly ? ITEM::SOLID_T : ITEM::ANY_T );
|
: ITEM::ANY_T );
|
||||||
|
|
||||||
if( !obs )
|
if( !obs )
|
||||||
break;
|
break;
|
||||||
|
@ -53,11 +53,10 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
|
||||||
mv.SetPos( mv.Pos() + l );
|
mv.SetPos( mv.Pos() + l );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool col = CollideShapes( obs->m_item->Shape(), mv.Shape(), clearance, true, force2 );
|
if( obs->m_item->Shape()->Collide( mv.Shape(), clearance, &force ) )
|
||||||
|
{
|
||||||
if( col ) {
|
totalForce += force;
|
||||||
totalForce += force2;
|
mv.SetPos( mv.Pos() + force );
|
||||||
mv.SetPos( mv.Pos() + force2 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iter++;
|
iter++;
|
||||||
|
|
Loading…
Reference in New Issue