Support optional location reporting in SHAPE collisions.
Also fixes a few bugs in the collision routines.
This commit is contained in:
parent
39d2a46b30
commit
bf67648562
|
@ -167,13 +167,16 @@ public:
|
|||
*
|
||||
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance,
|
||||
* indicating a collision.
|
||||
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||
* of a collision.
|
||||
* @param aActual [out] an optional pointer to an int to store the actual distance in the
|
||||
* event of a collision.
|
||||
* @param aLocation [out] an option pointer to a point to store a nearby location in the
|
||||
* event of a collision.
|
||||
* @return true, if there is a collision.
|
||||
*/
|
||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const
|
||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0,
|
||||
int* aActual = nullptr, VECTOR2I* aLocation = nullptr ) const
|
||||
{
|
||||
return Collide( SEG( aP, aP ), aClearance, aActual );
|
||||
return Collide( SEG( aP, aP ), aClearance, aActual, aLocation );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,23 +187,30 @@ public:
|
|||
* @param aShape shape to check collision against
|
||||
* @param aClearance minimum clearance
|
||||
* @param aMTV minimum translation vector
|
||||
* @param aActual an optional pointer to an int to store the actual distance in the event
|
||||
* of a collision.
|
||||
* @param aActual [out] an optional pointer to an int to store the actual distance in the
|
||||
* event of a collision.
|
||||
* @param aLocation [out] an option pointer to a point to store a nearby location in the
|
||||
* event of 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 = 0, int* aActual = nullptr ) const;
|
||||
|
||||
virtual bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Function Collide()
|
||||
*
|
||||
* Checks if the boundary of shape (this) lies closer to the segment aSeg than aClearance,
|
||||
* indicating a collision.
|
||||
* @aActual an optional pointer to an int to be updated with the actual distance in the
|
||||
* case of collision.
|
||||
* @param aActual [out] an optional pointer to an int to be updated with the actual distance
|
||||
* int the event of a collision.
|
||||
* @param aLocation [out] an option pointer to a point to store a nearby location in the
|
||||
* event of a collision.
|
||||
* @return true, if there is a collision.
|
||||
*/
|
||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const = 0;
|
||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const = 0;
|
||||
|
||||
/**
|
||||
* Function BBox()
|
||||
|
@ -263,7 +273,8 @@ public:
|
|||
* of a collision.
|
||||
* @return true, when a collision has been found
|
||||
*/
|
||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0,
|
||||
int* aActual = nullptr, VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
/**
|
||||
* Function Collide()
|
||||
|
@ -276,7 +287,9 @@ public:
|
|||
* @return true, when a collision has been found
|
||||
*/
|
||||
|
||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0,
|
||||
int* aActual = nullptr, VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,8 +73,10 @@ public:
|
|||
|
||||
const BOX2I BBox( 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, int* aActual = nullptr ) const override;
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
void SetWidth( int aWidth )
|
||||
{
|
||||
|
|
|
@ -65,13 +65,18 @@ public:
|
|||
return BOX2I( m_center - rc, rc * 2 );
|
||||
}
|
||||
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
int minDist = aClearance + m_radius;
|
||||
ecoord dist_sq = aSeg.SquaredDistance( m_center );
|
||||
VECTOR2I pn = aSeg.NearestPoint( m_center );
|
||||
ecoord dist_sq = ( pn - m_center ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) minDist * minDist )
|
||||
if( dist_sq == 0 || dist_sq < SEG::Square( minDist ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = pn;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - m_radius );
|
||||
|
||||
|
|
|
@ -47,19 +47,20 @@ class SHAPE_COMPOUND : public SHAPE
|
|||
SHAPE_COMPOUND* Clone() const override;
|
||||
const std::string Format() const override;
|
||||
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const override
|
||||
{
|
||||
return SHAPE::Collide( aShape, aClearance, aMTV );
|
||||
}
|
||||
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
return SHAPE::Collide( aShape, aClearance, aActual );
|
||||
return SHAPE::Collide( aShape, aClearance, aActual, aLocation );
|
||||
}
|
||||
|
||||
|
||||
const std::vector<SHAPE*>& Shapes() const
|
||||
{
|
||||
return m_shapes;
|
||||
|
|
|
@ -57,7 +57,8 @@ public:
|
|||
return BOX2I();
|
||||
}
|
||||
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1070,7 +1070,8 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* of a collision.
|
||||
* @return bool - true if the point aP collides with the polygon; false in any other case.
|
||||
*/
|
||||
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
/**
|
||||
* Function Collide
|
||||
|
@ -1092,7 +1093,8 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* @return bool - true if the segment aSeg collides with the polygon;
|
||||
* false in any other case.
|
||||
*/
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
/**
|
||||
* Function CollideVertex
|
||||
|
@ -1244,10 +1246,13 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* computes the minimum distance between the aIndex-th polygon and aPoint.
|
||||
* @param aPoint is the point whose distance to the aIndex-th polygon has to be measured.
|
||||
* @param aIndex is the index of the polygon whose distace to aPoint has to be measured.
|
||||
* @param aNearest [out] an optional pointer to be filled in with the point on the
|
||||
* polyset which is closest to aPoint.
|
||||
* @return int - The minimum distance between aPoint and all the segments of the aIndex-th
|
||||
* polygon. If the point is contained in the polygon, the distance is zero.
|
||||
*/
|
||||
SEG::ecoord SquaredDistanceToPolygon( VECTOR2I aPoint, int aIndex ) const;
|
||||
SEG::ecoord SquaredDistanceToPolygon( VECTOR2I aPoint, int aIndex,
|
||||
VECTOR2I* aNearest ) const;
|
||||
|
||||
/**
|
||||
* Function DistanceToPolygon
|
||||
|
@ -1256,22 +1261,26 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* @param aSegment is the segment whose distance to the aIndex-th polygon has to be
|
||||
* measured.
|
||||
* @param aIndex is the index of the polygon whose distace to aPoint has to be measured.
|
||||
* @param aSegmentWidth is the width of the segment; defaults to zero.
|
||||
* @param aNearest [out] an optional pointer to be filled in with the point on the
|
||||
* polyset which is closest to aSegment.
|
||||
* @return int - The minimum distance between aSegment and all the segments of the
|
||||
* aIndex-th polygon. If the point is contained in the polygon, the
|
||||
* distance is zero.
|
||||
*/
|
||||
SEG::ecoord SquaredDistanceToPolygon( const SEG& aSegment, int aIndex ) const;
|
||||
SEG::ecoord SquaredDistanceToPolygon( const SEG& aSegment, int aIndex,
|
||||
VECTOR2I* aNearest) const;
|
||||
|
||||
/**
|
||||
* Function SquaredDistance
|
||||
* computes the minimum distance squared between aPoint and all the polygons in the set.
|
||||
* Squared distances are used because they avoid the cost of doing square-roots.
|
||||
* @param aPoint is the point whose distance to the set has to be measured.
|
||||
* @param aNearest [out] an optional pointer to be filled in with the point on the
|
||||
* polyset which is closest to aPoint.
|
||||
* @return The minimum distance squared between aPoint and all the polygons in the set.
|
||||
* If the point is contained in any of the polygons, the distance is zero.
|
||||
*/
|
||||
SEG::ecoord SquaredDistance( VECTOR2I aPoint ) const;
|
||||
SEG::ecoord SquaredDistance( VECTOR2I aPoint, VECTOR2I* aNearest = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Function SquaredDistance
|
||||
|
@ -1279,10 +1288,12 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* Squared distances are used because they avoid the cost of doing square-roots.
|
||||
* @param aSegment is the segment whose distance to the polygon set has to be measured.
|
||||
* @param aSegmentWidth is the width of the segment; defaults to zero.
|
||||
* @param aNearest [out] an optional pointer to be filled in with the point on the
|
||||
* polyset which is closest to aSegment.
|
||||
* @return The minimum distance squared between aSegment and all the polygons in the set.
|
||||
* If the point is contained in the polygon, the distance is zero.
|
||||
*/
|
||||
SEG::ecoord SquaredDistance( const SEG& aSegment ) const;
|
||||
SEG::ecoord SquaredDistance( const SEG& aSegment, VECTOR2I* aNearest = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Function IsVertexInHole.
|
||||
|
|
|
@ -95,13 +95,15 @@ public:
|
|||
return SHAPE::Collide( aShape, aClearance, aMTV );
|
||||
}
|
||||
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
return SHAPE::Collide( aShape, aClearance, aActual );
|
||||
return SHAPE::Collide( aShape, aClearance, aActual, aLocation );
|
||||
}
|
||||
|
||||
/// @copydoc SHAPE::Collide()
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override;
|
||||
|
||||
/**
|
||||
* Function GetPosition()
|
||||
|
|
|
@ -61,18 +61,23 @@ public:
|
|||
return SHAPE::Collide( aShape, aClearance, aMTV );
|
||||
}
|
||||
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
return SHAPE::Collide( aShape, aClearance, aActual );
|
||||
return SHAPE::Collide( aShape, aClearance, aActual, aLocation );
|
||||
}
|
||||
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
||||
ecoord dist_sq = m_seg.SquaredDistance( aSeg );
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) min_dist * min_dist )
|
||||
if( dist_sq == 0 || dist_sq < SEG::Square( min_dist ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = m_seg.NearestPoint( aSeg );
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - ( m_width + 1 ) / 2 );
|
||||
|
||||
|
@ -82,13 +87,17 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
int min_dist = ( m_width + 1 ) / 2 + aClearance;
|
||||
ecoord dist_sq = m_seg.SquaredDistance( aP );
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) min_dist * min_dist )
|
||||
if( dist_sq == 0 || dist_sq < SEG::Square( min_dist ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = m_seg.NearestPoint( aP );
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - ( m_width + 1 ) / 2 );
|
||||
|
||||
|
|
|
@ -160,9 +160,10 @@ public:
|
|||
}
|
||||
|
||||
/// @copydoc SHAPE::Collide()
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override
|
||||
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
||||
VECTOR2I* aLocation = nullptr ) const override
|
||||
{
|
||||
return m_points.Collide( aSeg, aClearance, aActual );
|
||||
return m_points.Collide( aSeg, aClearance, aActual, aLocation );
|
||||
}
|
||||
|
||||
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
|
||||
|
|
|
@ -36,57 +36,27 @@ int sgn( T aVal )
|
|||
|
||||
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
||||
{
|
||||
// fixme: rather inefficient....
|
||||
if( Intersect( aSeg ) )
|
||||
return 0;
|
||||
VECTOR2I closestOnRef = NearestPoint( aSeg );
|
||||
VECTOR2I closestOnASeg = aSeg.NearestPoint( *this );
|
||||
|
||||
const VECTOR2I pts[4] =
|
||||
{
|
||||
aSeg.NearestPoint( A ) - A,
|
||||
aSeg.NearestPoint( B ) - B,
|
||||
NearestPoint( aSeg.A ) - aSeg.A,
|
||||
NearestPoint( aSeg.B ) - aSeg.B
|
||||
};
|
||||
|
||||
ecoord m = VECTOR2I::ECOORD_MAX;
|
||||
|
||||
for( int i = 0; i < 4; i++ )
|
||||
m = std::min( m, pts[i].SquaredEuclideanNorm() );
|
||||
|
||||
return m;
|
||||
return ( closestOnRef - closestOnASeg ).SquaredEuclideanNorm();
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I SEG::NearestPoint( const SEG& aSeg ) const
|
||||
{
|
||||
if( auto p = Intersect( aSeg ) )
|
||||
if( OPT_VECTOR2I p = Intersect( aSeg ) )
|
||||
return *p;
|
||||
|
||||
const VECTOR2I pts_origin[4] =
|
||||
{
|
||||
aSeg.NearestPoint( A ),
|
||||
aSeg.NearestPoint( B ),
|
||||
NearestPoint( aSeg.A ),
|
||||
NearestPoint( aSeg.B )
|
||||
};
|
||||
VECTOR2I nearestA = NearestPoint( aSeg.A );
|
||||
VECTOR2I deltaA = nearestA - aSeg.A;
|
||||
VECTOR2I nearestB = NearestPoint( aSeg.B );
|
||||
VECTOR2I deltaB = nearestB - aSeg.B;
|
||||
|
||||
const ecoord pts_dist[4] =
|
||||
{
|
||||
( pts_origin[0] - A ).SquaredEuclideanNorm(),
|
||||
( pts_origin[1] - B ).SquaredEuclideanNorm(),
|
||||
( pts_origin[2] - aSeg.A ).SquaredEuclideanNorm(),
|
||||
( pts_origin[3] - aSeg.B ).SquaredEuclideanNorm()
|
||||
};
|
||||
|
||||
int min_i = 0;
|
||||
|
||||
for( int i = 0; i < 4; i++ )
|
||||
{
|
||||
if( pts_dist[i] < pts_dist[min_i] )
|
||||
min_i = i;
|
||||
}
|
||||
|
||||
return pts_origin[min_i];
|
||||
if( deltaA.SquaredEuclideanNorm() < deltaB.SquaredEuclideanNorm() )
|
||||
return nearestA;
|
||||
else
|
||||
return nearestB;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -65,11 +65,13 @@ SHAPE_ARC::SHAPE_ARC( const SHAPE_ARC& aOther )
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
|
||||
{
|
||||
int minDist = aClearance + m_width / 2;
|
||||
VECTOR2I center = GetCenter();
|
||||
ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
ecoord dist_sq;
|
||||
ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
VECTOR2I ab = ( aSeg.B - aSeg.A );
|
||||
VECTOR2I ac = ( center - aSeg.A );
|
||||
|
@ -84,17 +86,46 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
|||
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);
|
||||
|
||||
dist_sq = std::min( dist_sq, ( m_start - p ).SquaredEuclideanNorm() );
|
||||
dist_sq = std::min( dist_sq, ( m_end - p ).SquaredEuclideanNorm() );
|
||||
dist_sq = ( m_start - p ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
closest_dist_sq = dist_sq;
|
||||
nearest = p;
|
||||
}
|
||||
|
||||
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_start ) );
|
||||
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_end ) );
|
||||
dist_sq = ( m_end - p ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) minDist * minDist )
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
closest_dist_sq = dist_sq;
|
||||
nearest = p;
|
||||
}
|
||||
}
|
||||
|
||||
dist_sq = aSeg.SquaredDistance( m_start );
|
||||
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
closest_dist_sq = dist_sq;
|
||||
nearest = m_start;
|
||||
}
|
||||
|
||||
dist_sq = aSeg.SquaredDistance( m_end );
|
||||
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
closest_dist_sq = dist_sq;
|
||||
nearest = m_end;
|
||||
}
|
||||
|
||||
if( closest_dist_sq == 0 || closest_dist_sq < SEG::Square( minDist ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - m_width / 2 );
|
||||
*aActual = std::max( 0, (int) sqrt( closest_dist_sq ) - m_width / 2 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -156,7 +187,8 @@ const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
int minDist = aClearance + m_width / 2;
|
||||
auto bbox = BBox( minDist );
|
||||
|
@ -164,15 +196,17 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) cons
|
|||
if( !bbox.Contains( aP ) )
|
||||
return false;
|
||||
|
||||
ecoord min_dist_sq = (ecoord) minDist * minDist;
|
||||
ecoord r = GetRadius();
|
||||
ecoord r_sq = r * r;
|
||||
ecoord min_dist_sq = SEG::Square( minDist );
|
||||
ecoord r_sq = SEG::Square( GetRadius() );
|
||||
|
||||
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( aLocation )
|
||||
*aLocation = ( aP + GetCenter() ) / 2;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_to_edge_sq ) - m_width / 2 );
|
||||
|
||||
|
|
|
@ -41,37 +41,41 @@
|
|||
typedef VECTOR2I::extended_type ecoord;
|
||||
|
||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
|
||||
ecoord min_dist_sq = min_dist * min_dist;
|
||||
|
||||
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
|
||||
|
||||
ecoord dist_sq = delta.SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq >= min_dist_sq )
|
||||
return false;
|
||||
|
||||
if( dist_sq < min_dist_sq )
|
||||
{
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() - aB.GetRadius() );
|
||||
|
||||
if( aLocation )
|
||||
*aLocation = ( aA.GetCenter() + aB.GetCenter() ) / 2;
|
||||
|
||||
if( aMTV )
|
||||
*aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const VECTOR2I c = aB.GetCenter();
|
||||
const VECTOR2I p0 = aA.GetPosition();
|
||||
const VECTOR2I size = aA.GetSize();
|
||||
const int r = aB.GetRadius();
|
||||
const int min_dist = aClearance + r;
|
||||
const ecoord min_dist_sq = (ecoord) min_dist * min_dist;
|
||||
const ecoord min_dist_sq = SEG::Square( min_dist );
|
||||
|
||||
const VECTOR2I vts[] =
|
||||
{
|
||||
|
@ -88,14 +92,9 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aC
|
|||
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
|
||||
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
|
||||
|
||||
// If we're not looking for MTV, short-circuit once we find a hard collision
|
||||
if( !aMTV && inside )
|
||||
{
|
||||
if( aActual )
|
||||
*aActual = 0;
|
||||
|
||||
// If we're not looking for MTV or actual, short-circuit once we find a hard collision
|
||||
if( inside && !aActual && !aLocation && !aMTV )
|
||||
return true;
|
||||
}
|
||||
|
||||
for( int i = 0; i < 4; i++ )
|
||||
{
|
||||
|
@ -104,37 +103,41 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aC
|
|||
VECTOR2I pn = side.NearestPoint( c );
|
||||
ecoord side_dist_sq = ( pn - c ).SquaredEuclideanNorm();
|
||||
|
||||
// If we're not looking for MTV or actual, short-circuit once we find any collision
|
||||
if( !aMTV && !aActual && ( side_dist_sq == 0 || side_dist_sq < min_dist_sq ) )
|
||||
return true;
|
||||
|
||||
if( side_dist_sq < nearest_side_dist_sq )
|
||||
{
|
||||
nearest = pn;
|
||||
nearest_side_dist_sq = side_dist_sq;
|
||||
|
||||
// If we're not looking for actual or MTV, short-circuit once we find any collision
|
||||
if( ( nearest_side_dist_sq == 0 || !aActual ) && !aMTV )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !inside && nearest_side_dist_sq >= min_dist_sq )
|
||||
return false;
|
||||
|
||||
VECTOR2I delta = c - nearest;
|
||||
if( inside || nearest_side_dist_sq < min_dist_sq )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( nearest_side_dist_sq ) - r );
|
||||
|
||||
if( aMTV )
|
||||
{
|
||||
VECTOR2I delta = c - nearest;
|
||||
|
||||
if( inside )
|
||||
*aMTV = -delta.Resize( abs( min_dist + 1 + sqrt( nearest_side_dist_sq ) ) + 1 );
|
||||
else
|
||||
*aMTV = delta.Resize( abs( min_dist + 1 - sqrt( nearest_side_dist_sq ) ) + 1 );
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aClearance )
|
||||
{
|
||||
|
@ -162,54 +165,40 @@ static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aCleara
|
|||
return f;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
|
||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB,
|
||||
int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
bool collided = false;
|
||||
int closest_dist = INT_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( int s = 0; s < aB.GetSegmentCount(); s++ )
|
||||
{
|
||||
if( aA.Collide( aB.GetSegment( s ), aClearance, aActual ) )
|
||||
int collision_dist = 0;
|
||||
VECTOR2I pn;
|
||||
|
||||
if( aA.Collide( aB.GetSegment( s ), aClearance,
|
||||
aActual || aLocation ? &collision_dist : nullptr,
|
||||
aLocation ? &pn : nullptr ) )
|
||||
{
|
||||
collided = true;
|
||||
if( collision_dist < closest_dist )
|
||||
{
|
||||
nearest = pn;
|
||||
closest_dist = collision_dist;
|
||||
|
||||
if( closest_dist == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !collided )
|
||||
return false;
|
||||
|
||||
if( aMTV )
|
||||
{
|
||||
SHAPE_CIRCLE cmoved( aA );
|
||||
VECTOR2I f_total( 0, 0 );
|
||||
|
||||
for( int s = 0; s < aB.GetSegmentCount(); s++ )
|
||||
{
|
||||
VECTOR2I f = pushoutForce( cmoved, aB.GetSegment( s ), aClearance );
|
||||
cmoved.SetCenter( cmoved.GetCenter() + f );
|
||||
f_total += f;
|
||||
}
|
||||
|
||||
*aMTV = f_total;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
if( closest_dist < aClearance )
|
||||
{
|
||||
int min_dist = aClearance + aA.GetRadius();
|
||||
ecoord dist_sq = aB.SquaredDistance( aA.GetCenter() );
|
||||
|
||||
if( dist_sq > (ecoord) min_dist * min_dist )
|
||||
return false;
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() );
|
||||
*aActual = closest_dist;
|
||||
|
||||
if( aMTV )
|
||||
{
|
||||
|
@ -225,32 +214,66 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE&
|
|||
|
||||
*aMTV = f_total;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
if( aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual, aLocation ) )
|
||||
{
|
||||
if( !aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual ) )
|
||||
return false;
|
||||
|
||||
if( aMTV )
|
||||
*aMTV = -pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
|
||||
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CHAIN_BASE& aB,
|
||||
int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
// TODO: why doesn't this handle MTV?
|
||||
// TODO: worse, why this doesn't handle closed shapes?
|
||||
|
||||
int closest_dist = INT_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( int i = 0; i < aB.GetSegmentCount(); i++ )
|
||||
{
|
||||
if( aA.Collide( aB.GetSegment( i ), aClearance, aActual ) )
|
||||
int collision_dist = 0;
|
||||
VECTOR2I pn;
|
||||
|
||||
if( aA.Collide( aB.GetSegment( i ), aClearance,
|
||||
aActual || aLocation ? &collision_dist : nullptr,
|
||||
aLocation ? &pn : nullptr ) )
|
||||
{
|
||||
if( collision_dist < closest_dist )
|
||||
{
|
||||
nearest = pn;
|
||||
closest_dist = collision_dist;
|
||||
|
||||
if( closest_dist == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( closest_dist < aClearance )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = closest_dist;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -259,41 +282,66 @@ static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CH
|
|||
|
||||
|
||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
int minActual = INT_MAX;
|
||||
int actual;
|
||||
// TODO: why doesn't this handle MTV?
|
||||
|
||||
if( aB.IsClosed() && aB.PointInside( aA.Centre() ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = aA.Centre();
|
||||
|
||||
if( aActual )
|
||||
*aActual = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int closest_dist = INT_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( int s = 0; s < aB.GetSegmentCount(); s++ )
|
||||
{
|
||||
if( aA.Collide( aB.GetSegment( s ), aClearance, &actual ) )
|
||||
{
|
||||
minActual = std::min( minActual, actual );
|
||||
int collision_dist = 0;
|
||||
VECTOR2I pn;
|
||||
|
||||
// If we're not looking for MTV or Actual, short-circuit after any collision
|
||||
if( !aActual && !aMTV )
|
||||
return true;
|
||||
if( aA.Collide( aB.GetSegment( s ), aClearance,
|
||||
aActual || aLocation ? &collision_dist : nullptr,
|
||||
aLocation ? &pn : nullptr ) )
|
||||
{
|
||||
if( collision_dist < closest_dist )
|
||||
{
|
||||
nearest = pn;
|
||||
closest_dist = collision_dist;
|
||||
|
||||
if( closest_dist == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( closest_dist < aClearance )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, minActual );
|
||||
*aActual = closest_dist;
|
||||
|
||||
// TODO: why doesn't this handle MTV?
|
||||
return true;
|
||||
}
|
||||
|
||||
return minActual < INT_MAX;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
int actual;
|
||||
|
||||
if( aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, &actual ) )
|
||||
if( aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual, aLocation ) )
|
||||
{
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, actual - aSeg.GetWidth() / 2 );
|
||||
*aActual = std::max( 0, *aActual - aSeg.GetWidth() / 2 );
|
||||
|
||||
// TODO: why doesn't this handle MTV?
|
||||
|
||||
|
@ -305,14 +353,12 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int
|
|||
|
||||
|
||||
static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
int actual;
|
||||
|
||||
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, &actual ) )
|
||||
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation ) )
|
||||
{
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, actual - aB.GetWidth() / 2 );
|
||||
*aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
|
||||
|
||||
// TODO: why doesn't this handle MTV?
|
||||
|
||||
|
@ -323,15 +369,13 @@ static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, in
|
|||
}
|
||||
|
||||
|
||||
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_SEGMENT& aB,
|
||||
int aClearance, int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
int actual;
|
||||
|
||||
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, &actual ) )
|
||||
if( aA.Collide( aB.GetSeg(), aClearance + aB.GetWidth() / 2, aActual, aLocation ) )
|
||||
{
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, actual - aB.GetWidth() / 2 );
|
||||
*aActual = std::max( 0, *aActual - aB.GetWidth() / 2 );
|
||||
|
||||
// TODO: why doesn't this handle MTV?
|
||||
|
||||
|
@ -343,23 +387,23 @@ static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_SEGMENT
|
|||
|
||||
|
||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
return Collide( aA.Outline(), aB.Outline(), aClearance, aActual, aMTV );
|
||||
return Collide( aA.Outline(), aB.Outline(), aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_RECT& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lc = aA.ConvertToPolyline();
|
||||
return Collide( lc, aB.Outline(), aClearance, aActual, aMTV );
|
||||
return Collide( lc, aB.Outline(), aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lc = aA.ConvertToPolyline();
|
||||
bool rv = Collide( aB, lc, aClearance, aActual, aMTV );
|
||||
bool rv = Collide( aB, lc, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
if( rv && aMTV )
|
||||
*aMTV = - *aMTV ;
|
||||
|
@ -368,50 +412,50 @@ static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_CIRCLE& aB, int aCl
|
|||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lc = aA.ConvertToPolyline();
|
||||
return Collide( lc, aB, aClearance, aActual, aMTV );
|
||||
return Collide( lc, aB, aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SEGMENT& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lc = aA.ConvertToPolyline();
|
||||
return Collide( lc, aB, aClearance, aActual, aMTV );
|
||||
return Collide( lc, aB, aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lc = aA.ConvertToPolyline();
|
||||
|
||||
return Collide( lc, aB, aClearance, aActual, aMTV );
|
||||
return Collide( lc, aB, aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_ARC& aB, int aClearance,
|
||||
int* aActual, VECTOR2I* aMTV )
|
||||
int* aActual, VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
const auto lcA = aA.ConvertToPolyline();
|
||||
const auto lcB = aB.ConvertToPolyline();
|
||||
return Collide( lcA, lcB, aClearance, aActual, aMTV );
|
||||
return Collide( lcA, lcB, aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
template<class T_a, class T_b>
|
||||
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||
VECTOR2I* aMTV )
|
||||
VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
|
||||
{
|
||||
return Collide( *static_cast<const T_a*>( aA ), *static_cast<const T_b*>( aB ),
|
||||
aClearance, aActual, aMTV);
|
||||
aClearance, aActual, aLocation, aMTV);
|
||||
}
|
||||
|
||||
template<class T_a, class T_b>
|
||||
inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||
VECTOR2I* aMTV )
|
||||
VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
bool rv = Collide( *static_cast<const T_b*>( aB ), *static_cast<const T_a*>( aA ),
|
||||
aClearance, aActual, aMTV);
|
||||
aClearance, aActual, aLocation, aMTV);
|
||||
|
||||
if( rv && aMTV)
|
||||
*aMTV = - *aMTV;
|
||||
|
@ -420,10 +464,9 @@ inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance,
|
|||
}
|
||||
|
||||
|
||||
static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, VECTOR2I* aMTV )
|
||||
static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
|
||||
|
||||
switch( aA->Type() )
|
||||
{
|
||||
case SH_NULL:
|
||||
|
@ -433,23 +476,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -463,23 +506,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -493,23 +536,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -523,23 +566,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -554,23 +597,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCaseReversed<SHAPE_LINE_CHAIN_BASE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCaseReversed<SHAPE_LINE_CHAIN_BASE, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -584,23 +627,23 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
switch( aB->Type() )
|
||||
{
|
||||
case SH_RECT:
|
||||
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_CIRCLE:
|
||||
return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_LINE_CHAIN:
|
||||
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SEGMENT:
|
||||
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_SIMPLE:
|
||||
case SH_POLY_SET_TRIANGLE:
|
||||
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_ARC:
|
||||
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
|
||||
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
|
||||
case SH_NULL:
|
||||
return false;
|
||||
|
@ -622,93 +665,123 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, VECTOR2I* aMTV )
|
||||
static bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation, VECTOR2I* aMTV )
|
||||
{
|
||||
int currentActual = std::numeric_limits<int>::max();
|
||||
VECTOR2I currentLocation;
|
||||
VECTOR2I currentMTV(0, 0);
|
||||
bool colliding = false;
|
||||
|
||||
bool exitOnFirstCollision = aActual == nullptr && aMTV == nullptr;
|
||||
|
||||
auto collideCompoundSubshapes = [&] ( const SHAPE* elemA, const SHAPE* elemB, int clearance ) -> bool
|
||||
auto canExit =
|
||||
[&]()
|
||||
{
|
||||
int actual;
|
||||
if( !colliding )
|
||||
return false;
|
||||
|
||||
if( aActual && currentActual > 0 )
|
||||
return false;
|
||||
|
||||
if( aMTV )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto collideCompoundSubshapes =
|
||||
[&]( const SHAPE* elemA, const SHAPE* elemB, int clearance ) -> bool
|
||||
{
|
||||
int actual = 0;
|
||||
VECTOR2I location;
|
||||
VECTOR2I mtv;
|
||||
|
||||
bool c = collideSingleShapes( elemA, elemB, clearance,
|
||||
aActual ? &actual : nullptr,
|
||||
aMTV ? &mtv : nullptr );
|
||||
if(c)
|
||||
if( collideSingleShapes( elemA, elemB, clearance,
|
||||
aActual || aLocation ? &actual : nullptr,
|
||||
aLocation ? &location : nullptr,
|
||||
aMTV ? &mtv : nullptr ) )
|
||||
{
|
||||
if (aActual)
|
||||
if( actual < currentActual )
|
||||
{
|
||||
currentActual = std::min( actual, currentActual );
|
||||
}
|
||||
if( aMTV )
|
||||
{
|
||||
if( mtv.SquaredEuclideanNorm() > currentMTV.SquaredEuclideanNorm() )
|
||||
currentMTV = mtv;
|
||||
}
|
||||
currentActual = actual;
|
||||
currentLocation = location;
|
||||
}
|
||||
|
||||
return c;
|
||||
if( aMTV && mtv.SquaredEuclideanNorm() > currentMTV.SquaredEuclideanNorm() )
|
||||
{
|
||||
currentMTV = mtv;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if( aA->Type() == SH_COMPOUND && aB->Type() == SH_COMPOUND )
|
||||
{
|
||||
auto cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
|
||||
auto cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
|
||||
const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
|
||||
const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
|
||||
|
||||
for( auto elemA : cmpA->Shapes() )
|
||||
for( const SHAPE* elemA : cmpA->Shapes() )
|
||||
{
|
||||
for( auto elemB : cmpB->Shapes() )
|
||||
for( const SHAPE* elemB : cmpB->Shapes() )
|
||||
{
|
||||
if( collideCompoundSubshapes( elemA, elemB, aClearance ) )
|
||||
{
|
||||
colliding = true;
|
||||
if ( exitOnFirstCollision )
|
||||
|
||||
if( canExit() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( colliding && exitOnFirstCollision )
|
||||
|
||||
if( canExit() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( aA->Type() == SH_COMPOUND )
|
||||
{
|
||||
auto cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
|
||||
for( auto elemA : cmpA->Shapes() )
|
||||
const SHAPE_COMPOUND* cmpA = static_cast<const SHAPE_COMPOUND*>( aA );
|
||||
|
||||
for( const SHAPE* elemA : cmpA->Shapes() )
|
||||
{
|
||||
if( collideCompoundSubshapes( elemA, aB, aClearance ) )
|
||||
{
|
||||
colliding = true;
|
||||
if ( exitOnFirstCollision )
|
||||
|
||||
if( canExit() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( aB->Type() == SH_COMPOUND )
|
||||
{
|
||||
auto cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
|
||||
for( auto elemB : cmpB->Shapes() )
|
||||
const SHAPE_COMPOUND* cmpB = static_cast<const SHAPE_COMPOUND*>( aB );
|
||||
|
||||
for( const SHAPE* elemB : cmpB->Shapes() )
|
||||
{
|
||||
if( collideCompoundSubshapes( aA, elemB, aClearance ) )
|
||||
{
|
||||
colliding = true;
|
||||
if ( exitOnFirstCollision )
|
||||
|
||||
if( canExit() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return collideSingleShapes( aA, aB, aClearance, aActual, aMTV );
|
||||
return collideSingleShapes( aA, aB, aClearance, aActual, aLocation, aMTV );
|
||||
}
|
||||
|
||||
if( colliding )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = currentLocation;
|
||||
|
||||
if( aActual )
|
||||
*aActual = currentActual;
|
||||
|
||||
if( aMTV )
|
||||
*aMTV = currentMTV;
|
||||
}
|
||||
|
@ -718,13 +791,13 @@ static bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int
|
|||
|
||||
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const
|
||||
{
|
||||
return collideShapes( this, aShape, aClearance, nullptr, aMTV );
|
||||
return collideShapes( this, aShape, aClearance, nullptr, nullptr, aMTV );
|
||||
}
|
||||
|
||||
|
||||
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, int* aActual ) const
|
||||
bool SHAPE::Collide( const SHAPE* aShape, int aClearance, int* aActual, VECTOR2I* aLocation ) const
|
||||
{
|
||||
return collideShapes( this, aShape, aClearance, aActual, nullptr );
|
||||
return collideShapes( this, aShape, aClearance, aActual, aLocation, nullptr );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -113,23 +113,42 @@ bool SHAPE_COMPOUND::IsSolid() const
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_COMPOUND::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||
bool SHAPE_COMPOUND::Collide( const SEG& aSeg, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
int dist = std::numeric_limits<int>::max();
|
||||
int closest_dist = std::numeric_limits<int>::max();
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( auto& item : m_shapes )
|
||||
for( SHAPE* item : m_shapes )
|
||||
{
|
||||
if( item->Collide( aSeg, aClearance, aActual ) )
|
||||
{
|
||||
if( !aActual || *aActual == 0 )
|
||||
return true;
|
||||
int actual = 0;
|
||||
VECTOR2I pn;
|
||||
|
||||
dist = std::min( dist, *aActual );
|
||||
if( item->Collide( aSeg, aClearance,
|
||||
aActual || aLocation ? &actual : nullptr,
|
||||
aLocation ? &pn : nullptr ) )
|
||||
{
|
||||
if( actual < closest_dist )
|
||||
{
|
||||
nearest = pn;
|
||||
closest_dist = actual;
|
||||
|
||||
if( closest_dist == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( closest_dist < aClearance )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = dist;
|
||||
*aActual = closest_dist;
|
||||
|
||||
return dist != std::numeric_limits<int>::max();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -85,26 +85,38 @@ void SHAPE_LINE_CHAIN::convertArc( ssize_t aArcIndex )
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_LINE_CHAIN_BASE::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||
bool SHAPE_LINE_CHAIN_BASE::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
SEG::ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
SEG::ecoord clearance_sq = SEG::Square( aClearance );
|
||||
VECTOR2I nearest;
|
||||
|
||||
// fixme: why this only checks open curves?
|
||||
|
||||
for( int i = 0; i < GetSegmentCount(); i++ )
|
||||
{
|
||||
const SEG& s = GetSegment( i );
|
||||
dist_sq = std::min( dist_sq, s.SquaredDistance( aP ) );
|
||||
VECTOR2I pn = s.NearestPoint( aP );
|
||||
SEG::ecoord dist_sq = ( pn - aP ).SquaredEuclideanNorm();
|
||||
|
||||
if( ( dist_sq == 0 || dist_sq < clearance_sq ) && !aActual )
|
||||
return true;
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
nearest = pn;
|
||||
closest_dist_sq = dist_sq;
|
||||
|
||||
if( closest_dist_sq == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( dist_sq == 0 || dist_sq < clearance_sq )
|
||||
if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = sqrt( dist_sq );
|
||||
*aActual = sqrt( closest_dist_sq );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -127,24 +139,37 @@ void SHAPE_LINE_CHAIN::Rotate( double aAngle, const VECTOR2I& aCenter )
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_LINE_CHAIN_BASE::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||
bool SHAPE_LINE_CHAIN_BASE::Collide( const SEG& aSeg, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
SEG::ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
SEG::ecoord clearance_sq = SEG::Square( aClearance );
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( int i = 0; i < GetSegmentCount(); i++ )
|
||||
{
|
||||
const SEG& s = GetSegment( i );
|
||||
dist_sq = std::min( dist_sq, s.SquaredDistance( aSeg ) );
|
||||
SEG::ecoord dist_sq =s.SquaredDistance( aSeg );
|
||||
|
||||
if( ( dist_sq == 0 || dist_sq < clearance_sq ) && !aActual )
|
||||
return true;
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
if( aLocation )
|
||||
nearest = s.NearestPoint( aSeg );
|
||||
|
||||
closest_dist_sq = dist_sq;
|
||||
|
||||
if( closest_dist_sq == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( dist_sq == 0 || dist_sq < clearance_sq )
|
||||
if( closest_dist_sq == 0 || closest_dist_sq < clearance_sq )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = sqrt( dist_sq );
|
||||
*aActual = sqrt( closest_dist_sq );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1224,12 +1224,17 @@ bool SHAPE_POLY_SET::PointOnEdge( const VECTOR2I& aP ) const
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||
bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
ecoord dist_sq = SquaredDistance( aSeg );
|
||||
VECTOR2I nearest;
|
||||
ecoord dist_sq = SquaredDistance( aSeg, aLocation ? &nearest : nullptr );
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) aClearance * aClearance )
|
||||
if( dist_sq == 0 || dist_sq < SEG::Square( aClearance ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = sqrt( dist_sq );
|
||||
|
||||
|
@ -1240,12 +1245,17 @@ bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance, int* aActual ) co
|
|||
}
|
||||
|
||||
|
||||
bool SHAPE_POLY_SET::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
|
||||
bool SHAPE_POLY_SET::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
ecoord dist_sq = SquaredDistance( aP );
|
||||
VECTOR2I nearest;
|
||||
ecoord dist_sq = SquaredDistance( aP, aLocation ? &nearest : nullptr );
|
||||
|
||||
if( dist_sq == 0 || dist_sq < (ecoord) aClearance * aClearance )
|
||||
if( dist_sq == 0 || dist_sq < SEG::Square( aClearance ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = sqrt( dist_sq );
|
||||
|
||||
|
@ -1571,14 +1581,20 @@ SHAPE_POLY_SET::POLYGON SHAPE_POLY_SET::FilletPolygon( unsigned int aRadius, int
|
|||
}
|
||||
|
||||
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex ) const
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( VECTOR2I aPoint, int aPolygonIndex,
|
||||
VECTOR2I* aNearest ) const
|
||||
{
|
||||
// We calculate the min dist between the segment and each outline segment. However, if the
|
||||
// segment to test is inside the outline, and does not cross any edge, it can be seen outside
|
||||
// the polygon. Therefore test if a segment end is inside (testing only one end is enough).
|
||||
// Use an accuracy of "1" to say that we don't care if it's exactly on the edge or not.
|
||||
if( containsSingle( aPoint, aPolygonIndex, 1 ) )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = aPoint;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CONST_SEGMENT_ITERATOR iterator = CIterateSegmentsWithHoles( aPolygonIndex );
|
||||
|
||||
|
@ -1589,21 +1605,32 @@ SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( VECTOR2I aPoint, int aPoly
|
|||
SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
|
||||
|
||||
if( currentDistance < minDistance )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = (*iterator).NearestPoint( aPoint );
|
||||
|
||||
minDistance = currentDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( const SEG& aSegment, int aPolygonIndex ) const
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( const SEG& aSegment, int aPolygonIndex,
|
||||
VECTOR2I* aNearest ) const
|
||||
{
|
||||
// We calculate the min dist between the segment and each outline segment. However, if the
|
||||
// segment to test is inside the outline, and does not cross any edge, it can be seen outside
|
||||
// the polygon. Therefore test if a segment end is inside (testing only one end is enough).
|
||||
// Use an accuracy of "1" to say that we don't care if it's exactly on the edge or not.
|
||||
if( containsSingle( aSegment.A, aPolygonIndex, 1 ) )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = ( aSegment.A + aSegment.B ) / 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CONST_SEGMENT_ITERATOR iterator = CIterateSegmentsWithHoles( aPolygonIndex );
|
||||
SEG::ecoord minDistance = (*iterator).SquaredDistance( aSegment );
|
||||
|
@ -1613,47 +1640,66 @@ SEG::ecoord SHAPE_POLY_SET::SquaredDistanceToPolygon( const SEG& aSegment, int a
|
|||
SEG::ecoord currentDistance = (*iterator).SquaredDistance( aSegment );
|
||||
|
||||
if( currentDistance < minDistance )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = (*iterator).NearestPoint( aSegment );
|
||||
|
||||
minDistance = currentDistance;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the maximum of minDistance and zero
|
||||
return minDistance < 0 ? 0 : minDistance;
|
||||
}
|
||||
|
||||
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistance( VECTOR2I aPoint ) const
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistance( VECTOR2I aPoint, VECTOR2I* aNearest ) const
|
||||
{
|
||||
SEG::ecoord currentDistance;
|
||||
SEG::ecoord minDistance = SquaredDistanceToPolygon( aPoint, 0 );
|
||||
SEG::ecoord currentDistance_sq;
|
||||
SEG::ecoord minDistance_sq = VECTOR2I::ECOORD_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
// Iterate through all the polygons and get the minimum distance.
|
||||
for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ )
|
||||
for( unsigned int polygonIdx = 0; polygonIdx < m_polys.size(); polygonIdx++ )
|
||||
{
|
||||
currentDistance = SquaredDistanceToPolygon( aPoint, polygonIdx );
|
||||
currentDistance_sq = SquaredDistanceToPolygon( aPoint, polygonIdx,
|
||||
aNearest ? &nearest : nullptr );
|
||||
|
||||
if( currentDistance < minDistance )
|
||||
minDistance = currentDistance;
|
||||
if( currentDistance_sq < minDistance_sq )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = nearest;
|
||||
|
||||
minDistance_sq = currentDistance_sq;
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
return minDistance_sq;
|
||||
}
|
||||
|
||||
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistance( const SEG& aSegment ) const
|
||||
SEG::ecoord SHAPE_POLY_SET::SquaredDistance( const SEG& aSegment, VECTOR2I* aNearest ) const
|
||||
{
|
||||
SEG::ecoord currentDistance;
|
||||
SEG::ecoord minDistance = SquaredDistanceToPolygon( aSegment, 0 );
|
||||
SEG::ecoord currentDistance_sq;
|
||||
SEG::ecoord minDistance_sq = VECTOR2I::ECOORD_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
// Iterate through all the polygons and get the minimum distance.
|
||||
for( unsigned int polygonIdx = 1; polygonIdx < m_polys.size(); polygonIdx++ )
|
||||
for( unsigned int polygonIdx = 0; polygonIdx < m_polys.size(); polygonIdx++ )
|
||||
{
|
||||
currentDistance = SquaredDistanceToPolygon( aSegment, polygonIdx );
|
||||
currentDistance_sq = SquaredDistanceToPolygon( aSegment, polygonIdx,
|
||||
aNearest ? &nearest : nullptr );
|
||||
|
||||
if( currentDistance < minDistance )
|
||||
minDistance = currentDistance;
|
||||
if( currentDistance_sq < minDistance_sq )
|
||||
{
|
||||
if( aNearest )
|
||||
*aNearest = nearest;
|
||||
|
||||
minDistance_sq = currentDistance_sq;
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
return minDistance_sq;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,10 +26,25 @@
|
|||
#include <geometry/shape_rect.h>
|
||||
|
||||
|
||||
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
||||
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual,
|
||||
VECTOR2I* aLocation ) const
|
||||
{
|
||||
if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) )
|
||||
if( BBox( 0 ).Contains( aSeg.A ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = aSeg.A;
|
||||
|
||||
if( aActual )
|
||||
*aActual = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( BBox( 0 ).Contains( aSeg.B ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = aSeg.B;
|
||||
|
||||
if( aActual )
|
||||
*aActual = 0;
|
||||
|
||||
|
@ -42,19 +57,33 @@ bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
|
|||
VECTOR2I( m_p0.x + m_w, m_p0.y ),
|
||||
VECTOR2I( m_p0.x, m_p0.y ) };
|
||||
|
||||
SEG s( corners[0], corners[1] );
|
||||
SEG::ecoord dist_squared = s.SquaredDistance( aSeg );
|
||||
SEG::ecoord closest_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||
VECTOR2I nearest;
|
||||
|
||||
for( int i = 1; i < 4; i++ )
|
||||
for( int i = 0; i < 4; i++ )
|
||||
{
|
||||
s = SEG( corners[i], corners[ i + 1] );
|
||||
dist_squared = std::min( dist_squared, s.SquaredDistance( aSeg ) );
|
||||
SEG side = SEG( corners[i], corners[ i + 1] );
|
||||
VECTOR2I pnA = side.NearestPoint( aSeg );
|
||||
VECTOR2I pnB = aSeg.NearestPoint( side );
|
||||
SEG::ecoord dist_sq = ( pnA - pnB ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
nearest = pnA;
|
||||
closest_dist_sq = dist_sq;
|
||||
|
||||
if( closest_dist_sq == 0 || !aActual )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( dist_squared < (ecoord) aClearance * aClearance )
|
||||
if( closest_dist_sq < SEG::Square( aClearance ) )
|
||||
{
|
||||
if( aLocation )
|
||||
*aLocation = nearest;
|
||||
|
||||
if( aActual )
|
||||
*aActual = sqrt( dist_squared );
|
||||
*aActual = sqrt( closest_dist_sq );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -237,7 +237,6 @@ set( PCBNEW_MICROWAVE_SRCS
|
|||
set( PCBNEW_DRC_SRCS
|
||||
drc/drc_test_provider.cpp
|
||||
drc/drc_test_provider_annulus.cpp
|
||||
drc/drc_test_provider_clearance_base.cpp
|
||||
drc/drc_test_provider_disallow.cpp
|
||||
drc/drc_test_provider_connectivity.cpp
|
||||
drc/drc_test_provider_copper_clearance.cpp
|
||||
|
|
|
@ -956,25 +956,6 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
|
|||
}
|
||||
|
||||
|
||||
bool D_PAD::Collide( const D_PAD* aPad, int aMinClearance, int* aActual )
|
||||
{
|
||||
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - ShapePos() ) );
|
||||
|
||||
// Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
|
||||
if( center2center - GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
||||
return false;
|
||||
|
||||
|
||||
return GetEffectiveShape()->Collide( aPad->GetEffectiveShape().get(), aMinClearance, aActual );
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::Collide( const SHAPE_SEGMENT* aSeg, int aMinClearance, int* aActual )
|
||||
{
|
||||
return aSeg->Collide( GetEffectiveShape().get(), aMinClearance, aActual );
|
||||
}
|
||||
|
||||
|
||||
int D_PAD::Compare( const D_PAD* padref, const D_PAD* padcmp )
|
||||
{
|
||||
int diff;
|
||||
|
|
|
@ -536,9 +536,6 @@ public:
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
|
||||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
|
||||
|
||||
bool Collide( const SHAPE_SEGMENT* aSeg, int aMinClearance, int* aActual = nullptr );
|
||||
bool Collide( const D_PAD* aPad, int aMinClearance, int* aActual = nullptr );
|
||||
|
||||
wxString GetClass() const override
|
||||
{
|
||||
return wxT( "PAD" );
|
||||
|
|
|
@ -167,7 +167,7 @@ DRC_ITEM DRC_ITEM::unresolvedVariable( DRCE_UNRESOLVED_VARIABLE,
|
|||
wxT( "unresolved_variable" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::silkOverPad( DRCE_SILK_OVER_PAD,
|
||||
_( "Silkscreen overlapping component pad(s)" ),
|
||||
_( "Silkscreen overlapping pad" ),
|
||||
wxT( "silk_over_pad" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::silkClearance( DRCE_SILK_CLEARANCE,
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <drc/drc_test_provider_clearance_base.h>
|
||||
|
||||
const int UI_EPSILON = Mils2iu( 5 );
|
||||
|
||||
|
||||
wxPoint DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( PCB_LAYER_ID aLayer, TRACK* aTrack,
|
||||
ZONE_CONTAINER* aZone )
|
||||
{
|
||||
SHAPE_POLY_SET* zonePoly = nullptr;
|
||||
|
||||
if( aZone->IsFilled() && aZone->HasFilledPolysForLayer( aLayer ) )
|
||||
zonePoly = const_cast<SHAPE_POLY_SET*>( &aZone->GetFilledPolysList( aLayer ) );
|
||||
|
||||
if( !zonePoly || zonePoly->IsEmpty() )
|
||||
zonePoly = aZone->Outline();
|
||||
|
||||
SEG trackSeg( aTrack->GetStart(), aTrack->GetEnd() );
|
||||
SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
|
||||
SEG closestSeg;
|
||||
|
||||
for( auto it = zonePoly->CIterateSegments( 0, -1, true ); it; it++ )
|
||||
{
|
||||
SEG::ecoord dist_sq = trackSeg.SquaredDistance( *it );
|
||||
|
||||
if( dist_sq < closestDist_sq )
|
||||
{
|
||||
closestDist_sq = dist_sq;
|
||||
closestSeg = *it;
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2I pt1 = closestSeg.A;
|
||||
VECTOR2I pt2 = closestSeg.B;
|
||||
|
||||
// Do a binary search for a "good enough" marker location
|
||||
while( GetLineLength( (wxPoint) pt1, (wxPoint) pt2 ) > UI_EPSILON )
|
||||
{
|
||||
if( trackSeg.SquaredDistance( pt1 ) < trackSeg.SquaredDistance( pt2 ) )
|
||||
pt2 = ( pt1 + pt2 ) / 2;
|
||||
else
|
||||
pt1 = ( pt1 + pt2 ) / 2;
|
||||
}
|
||||
|
||||
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
|
||||
return (wxPoint) pt1;
|
||||
}
|
||||
|
||||
wxPoint DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, const SEG& aConflictSeg )
|
||||
{
|
||||
wxPoint pt1 = aTrack->GetPosition();
|
||||
wxPoint pt2 = aTrack->GetEnd();
|
||||
|
||||
// Do a binary search along the track for a "good enough" marker location
|
||||
while( GetLineLength( pt1, pt2 ) > UI_EPSILON )
|
||||
{
|
||||
if( aConflictSeg.SquaredDistance( pt1 ) < aConflictSeg.SquaredDistance( pt2 ) )
|
||||
pt2 = ( pt1 + pt2 ) / 2;
|
||||
else
|
||||
pt1 = ( pt1 + pt2 ) / 2;
|
||||
}
|
||||
|
||||
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
|
||||
return pt1;
|
||||
}
|
|
@ -47,10 +47,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
wxPoint getLocation( TRACK* aTrack, const SEG& aConflictSeg );
|
||||
wxPoint getLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone );
|
||||
|
||||
protected:
|
||||
BOARD* m_board;
|
||||
int m_largestClearance;
|
||||
|
|
|
@ -216,7 +216,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
aItem, track, layer );
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual = INT_MAX;
|
||||
wxPoint pos;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
|
@ -226,11 +226,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
if( !bboxShape.Collide( &trackSeg, 0 ) )
|
||||
continue;
|
||||
|
||||
if( !itemShape->Collide( &trackSeg, minClearance, &actual ) )
|
||||
if( !itemShape->Collide( &trackSeg, minClearance, &actual, &pos ) )
|
||||
continue;
|
||||
|
||||
pos = (wxPoint) itemShape->Centre();
|
||||
|
||||
if( actual < INT_MAX )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
@ -244,7 +242,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
drcItem->SetItems( track, aItem );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, pos );
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,10 +260,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
aItem, pad, layer );
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
|
||||
// Fast test to detect a pad candidate inside the text bounding box
|
||||
// Finer test (time consuming) is made only for pads near the text.
|
||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||
|
@ -273,7 +271,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
||||
continue;
|
||||
|
||||
if( !pad->GetEffectiveShape()->Collide( itemShape.get(), minClearance, &actual ) )
|
||||
if( !itemShape->Collide( pad->GetEffectiveShape().get(), minClearance, &actual, &pos ) )
|
||||
continue;
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
@ -287,7 +285,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
|||
drcItem->SetItems( pad, aItem );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, pad->GetPosition());
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,6 +313,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer,
|
||||
TRACKS::iterator aStartIt,
|
||||
TRACKS::iterator aEndIt )
|
||||
|
@ -362,12 +361,13 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
aRefSeg, pad, aLayer );
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
const std::shared_ptr<SHAPE>& padShape = pad->GetEffectiveShape();
|
||||
|
||||
if( padShape->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
||||
if( padShape->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
||||
|
@ -380,7 +380,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
drcItem->SetItems( aRefSeg, pad );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, pad->GetPosition());
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,6 +421,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
|
@ -442,9 +443,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
|
||||
reportViolation( drcItem, (wxPoint) intersection.get() );
|
||||
}
|
||||
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
||||
else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual, &pos ) )
|
||||
{
|
||||
wxPoint pos = getLocation( aRefSeg, trackSeg.GetSeg() );
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
||||
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
@ -456,7 +456,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
drcItem->SetItems( aRefSeg, track );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, pos );
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
|
||||
if( !m_drcEngine->GetReportAllTrackErrors() )
|
||||
break;
|
||||
|
@ -494,11 +494,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
int minClearance = constraint.GetValue().Min();
|
||||
int halfWidth = refSegWidth / 2;
|
||||
int allowedDist = minClearance + halfWidth - bds.GetDRCEpsilon();
|
||||
|
||||
const SHAPE_POLY_SET& zonePoly = zone->GetFilledPolysList( aLayer );
|
||||
int actual;
|
||||
VECTOR2I location;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
|
||||
if( zonePoly.Collide( testSeg, allowedDist, &actual, &location ) )
|
||||
{
|
||||
actual = std::max( 0, actual - halfWidth );
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
@ -512,7 +515,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_I
|
|||
drcItem->SetItems( aRefSeg, zone );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, getLocation( aLayer, aRefSeg, zone ));
|
||||
reportViolation( drcItem, (wxPoint) location );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -639,12 +642,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( int aRefPadIdx,
|
|||
int minClearance = constraint.GetValue().Min();
|
||||
int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
std::shared_ptr<SHAPE> refPadShape = refPad->GetEffectiveShape();
|
||||
std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape();
|
||||
|
||||
if( refPadShape->Collide( pad->GetEffectiveShape().get(), clearanceAllowed, &actual ) )
|
||||
if( refPadShape->Collide( padShape.get(), clearanceAllowed, &actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||
|
||||
|
@ -657,7 +662,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( int aRefPadIdx,
|
|||
drcItem->SetItems( refPad, pad );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, refPad->GetPosition());
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,12 +140,14 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
|||
|
||||
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
|
||||
outlineItem, boardItem );
|
||||
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
if( refShape->Collide( shape.get(), minClearance, &actual ) )
|
||||
if( refShape->Collide( shape.get(), minClearance, &actual, &pos ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
|
||||
|
||||
|
@ -158,7 +160,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
|
|||
drcItem->SetItems( outlineItem, boardItem );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, (wxPoint) refShape->Centre());
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,44 +119,40 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
|
|||
return true;
|
||||
};
|
||||
|
||||
auto checkClearance = [&]( const DRC_RTREE::LAYER_PAIR& aLayers,
|
||||
auto checkClearance =
|
||||
[&]( const DRC_RTREE::LAYER_PAIR& aLayers,
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aRefItem,
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool {
|
||||
auto constraint = m_drcEngine->EvalRulesForItems(
|
||||
DRC_CONSTRAINT_TYPE_SILK_TO_PAD, aRefItem->parent, aTestItem->parent );
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool
|
||||
{
|
||||
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_PAD,
|
||||
aRefItem->parent,
|
||||
aTestItem->parent );
|
||||
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
int actual;
|
||||
|
||||
if( ! aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual ) )
|
||||
if( !aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual, &pos ) )
|
||||
return true;
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SILK_OVER_PAD );
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
constraint.GetParentRule()->m_Name,
|
||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( aRefItem->parent, aTestItem->parent );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, aRefItem->parent->GetPosition() );
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
|
||||
|
||||
return !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_OVER_PAD );
|
||||
};
|
||||
|
||||
int numPads = forEachGeometryItem(
|
||||
{ PCB_PAD_T }, LSET::AllTechMask() | LSET::AllCuMask(), addPadToTree );
|
||||
int numPads = forEachGeometryItem( { PCB_PAD_T }, LSET::AllTechMask() | LSET::AllCuMask(),
|
||||
addPadToTree );
|
||||
|
||||
int numSilk =
|
||||
forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T },
|
||||
int numSilk = forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T },
|
||||
LSET( 2, F_SilkS, B_SilkS ), addSilkToTree );
|
||||
|
||||
reportAux( _("Testing %d pads against %d silkscreen features."), numPads, numSilk );
|
||||
|
|
|
@ -24,12 +24,9 @@
|
|||
#include <common.h>
|
||||
#include <class_board.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <class_pad.h>
|
||||
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/polygon_test_point_inside.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
|
||||
|
@ -47,9 +44,7 @@
|
|||
|
||||
*/
|
||||
|
||||
namespace test {
|
||||
|
||||
class DRC_TEST_PROVIDER_SILK_TO_SILK : public ::DRC_TEST_PROVIDER
|
||||
class DRC_TEST_PROVIDER_SILK_TO_SILK : public DRC_TEST_PROVIDER
|
||||
{
|
||||
public:
|
||||
DRC_TEST_PROVIDER_SILK_TO_SILK ()
|
||||
|
@ -85,10 +80,8 @@ private:
|
|||
int m_largestClearance;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
||||
bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
||||
{
|
||||
m_board = m_drcEngine->GetBoard();
|
||||
|
||||
|
@ -113,20 +106,22 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
|||
return true;
|
||||
};
|
||||
|
||||
auto checkClearance = [&]( const DRC_RTREE::LAYER_PAIR& aLayers,
|
||||
auto checkClearance =
|
||||
[&]( const DRC_RTREE::LAYER_PAIR& aLayers,
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aRefItem,
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool {
|
||||
auto constraint = m_drcEngine->EvalRulesForItems(
|
||||
DRC_CONSTRAINT_TYPE_SILK_TO_SILK, aRefItem->parent, aTestItem->parent );
|
||||
|
||||
DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool
|
||||
{
|
||||
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_SILK,
|
||||
aRefItem->parent,
|
||||
aTestItem->parent );
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
|
||||
accountCheck( constraint );
|
||||
|
||||
int actual;
|
||||
|
||||
// only check for silkscreen collisions belonging to different modules or overlapping texts
|
||||
|
||||
// only check for silkscreen collisions belonging to different modules or
|
||||
// overlapping texts
|
||||
|
||||
KICAD_T typeRef = aRefItem->parent->Type();
|
||||
KICAD_T typeTest = aTestItem->parent->Type();
|
||||
|
@ -144,7 +139,6 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
|||
parentModTest = static_cast<MODULE*> ( aTestItem->parent->GetParent() );
|
||||
}
|
||||
|
||||
|
||||
// silkscreen drawings within the same module (or globally on the board)
|
||||
// don't report clearance errors. Everything else does.
|
||||
|
||||
|
@ -160,7 +154,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
|||
return true;
|
||||
}
|
||||
|
||||
if( ! aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual ) )
|
||||
if( ! aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual, &pos ) )
|
||||
return true;
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
|
||||
|
@ -175,14 +169,12 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
|||
drcItem->SetItems( aRefItem->parent, aTestItem->parent );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, aRefItem->parent->GetPosition() );
|
||||
|
||||
reportViolation( drcItem, (wxPoint) pos );
|
||||
|
||||
return !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_CLEARANCE );
|
||||
};
|
||||
|
||||
int numSilk =
|
||||
forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T },
|
||||
int numSilk = forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T },
|
||||
LSET( 2, F_SilkS, B_SilkS ), addToTree );
|
||||
|
||||
reportAux( _("Testing %d silkscreen features."), numSilk );
|
||||
|
@ -201,7 +193,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run()
|
|||
}
|
||||
|
||||
|
||||
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_SILK_TO_SILK::GetConstraintTypes() const
|
||||
std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_SILK_TO_SILK::GetConstraintTypes() const
|
||||
{
|
||||
return { DRC_CONSTRAINT_TYPE_SILK_TO_SILK };
|
||||
}
|
||||
|
@ -209,5 +201,5 @@ std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_SILK_TO_SILK::GetConstra
|
|||
|
||||
namespace detail
|
||||
{
|
||||
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_SILK_TO_SILK> dummy;
|
||||
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_SILK_TO_SILK> dummy;
|
||||
}
|
|
@ -39,7 +39,6 @@ add_executable( drc_proto
|
|||
../../pcbnew/drc/drc_rule_condition.cpp
|
||||
../../pcbnew/drc/drc_rule_parser.cpp
|
||||
../../pcbnew/drc/drc_test_provider.cpp
|
||||
../../pcbnew/drc/drc_test_provider_clearance_base.cpp
|
||||
../../pcbnew/drc/drc_test_provider_copper_clearance.cpp
|
||||
../../pcbnew/drc/drc_test_provider_hole_clearance.cpp
|
||||
../../pcbnew/drc/drc_test_provider_edge_clearance.cpp
|
||||
|
|
Loading…
Reference in New Issue