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:
Jeff Young 2020-07-02 17:06:09 +01:00
parent af8f05d570
commit 441dfa30f0
26 changed files with 728 additions and 711 deletions

View File

@ -193,7 +193,7 @@ public:
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;
@ -341,8 +341,6 @@ public:
bool Contains( const VECTOR2I& aP ) const;
bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
void Reverse()
{
std::swap( A, B );

View File

@ -118,9 +118,11 @@ 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.
* @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 );
}
@ -133,19 +135,23 @@ 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.
* @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 ) const;
virtual bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const;
virtual bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = 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.
* @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()
@ -169,7 +175,14 @@ public:
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;
@ -182,7 +195,7 @@ protected:
SHAPE_TYPE m_type;
};
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 );
#endif // __SHAPE_H

View File

@ -76,8 +76,8 @@ public:
const BOX2I BBox( int aClearance = 0 ) const override;
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
bool Collide( const VECTOR2I& aP, 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;
void SetWidth( int aWidth )
{
@ -102,7 +102,7 @@ public:
* @param aCenter is the rotation center
* @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 } );

View File

@ -63,11 +63,20 @@ public:
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 )
@ -95,6 +104,11 @@ public:
m_center += aVector;
}
void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override
{
// That was easy....
}
bool IsSolid() const override
{
return true;

View File

@ -386,9 +386,11 @@ public:
* Checks if point aP lies closer to us than aClearance.
* @param aP the point to check for collisions with
* @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
*/
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()
@ -396,9 +398,11 @@ public:
* Checks if segment aSeg lies closer to us than aClearance.
* @param aSeg the segment to check for collisions with
* @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
*/
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()
@ -408,6 +412,7 @@ public:
* @return minimum distance.
*/
int Distance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
/**
* Function Reverse()
@ -747,7 +752,7 @@ public:
* @param aCenter is the rotation center
* @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
{

View File

@ -975,7 +975,7 @@ class SHAPE_POLY_SET : public SHAPE
* @param aCenter is the rotation center
* @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()
bool IsSolid() const override
@ -1003,9 +1003,11 @@ class SHAPE_POLY_SET : public SHAPE
* will be tested.
* @param aClearance is the security distance; if the point lies closer to the polygon
* 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.
*/
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
@ -1016,10 +1018,12 @@ class SHAPE_POLY_SET : public SHAPE
* will be tested.
* @param aClearance is the security distance; if the segment passes closer to the polygon
* 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;
* 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

View File

@ -91,9 +91,7 @@ public:
}
/// @copydoc SHAPE::Collide()
bool Collide( const SEG& aSeg, int aClearance = 0 ) const override;
bool DoCollide( const SEG& aSeg, int aClearance, int* aActualDist ) const;
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
/**
* Function GetPosition()
@ -140,6 +138,16 @@ public:
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
{
return true;

View File

@ -54,14 +54,36 @@ public:
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;
}
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const override
return false;
}
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 )
@ -89,6 +111,18 @@ public:
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
{
m_seg.A += aVector;

View File

@ -159,9 +159,14 @@ public:
}
/// @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

View File

@ -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
{
// 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
// fixme: move to a method
if( ccw( A, aSeg.A, aSeg.B ) != ccw( B, aSeg.A, aSeg.B ) &&
ccw( A, B, aSeg.A ) != ccw( A, B, aSeg.B ) )
{
if( aActual )
*aActual = 0;
return true;
}
#define CHK( _seg, _pt ) \
if( (_seg).PointCloserThan( _pt, aClearance ) ) return true;
ecoord dist_sq = VECTOR2I::ECOORD_MAX;
CHK( *this, aSeg.A );
CHK( *this, aSeg.B );
CHK( aSeg, A );
CHK( aSeg, B );
#undef CHK
dist_sq = std::min( dist_sq, SquaredDistance( aSeg.A ) );
dist_sq = std::min( dist_sq, SquaredDistance( aSeg.B ) );
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( A ) );
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( B ) );
if( dist_sq < (ecoord) aClearance * aClearance )
{
if( aActual )
*aActual = sqrt( dist_sq );
return true;
}
return false;
}
@ -199,5 +159,5 @@ bool SEG::Collide( const SEG& aSeg, int aClearance ) const
bool SEG::Contains( const VECTOR2I& aP ) const
{
return PointCloserThan( aP, 1 );
return SquaredDistance( aP ) < 1; // 1 * 1 to be pedantic
}

View File

@ -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;
auto center = GetCenter();
auto centerDist = aSeg.Distance( center );
auto p1 = GetP1();
VECTOR2I center = GetCenter();
ecoord dist_sq = VECTOR2I::ECOORD_MAX;
if( centerDist < minDist )
return true;
auto ab = (aSeg.B - aSeg.A );
auto ac = ( center - aSeg.A );
auto lenAbSq = ab.SquaredEuclideanNorm();
auto lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
VECTOR2I ab = ( aSeg.B - aSeg.A );
VECTOR2I ac = ( center - aSeg.A );
ecoord lenAbSq = ab.SquaredEuclideanNorm();
double lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
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.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;
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_start ) );
dist_sq = std::min( dist_sq, aSeg.SquaredDistance( m_end ) );
auto p1pdist = ( p1 - p ).EuclideanNorm();
if( dist_sq < (ecoord) minDist * minDist )
{
if( aActual )
*aActual = std::max( 0, (int) sqrt( dist_sq ) - m_width / 2 );
if( p1pdist < minDist )
return true;
}
auto p0dist = aSeg.Distance( m_start );
if( p0dist > minDist )
return true;
auto p1dist = aSeg.Distance( p1 );
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;
auto bbox = BBox( minDist );
@ -184,9 +171,22 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
if( !bbox.Contains( aP ) )
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;
}

View File

@ -26,7 +26,6 @@
#include <assert.h> // for assert
#include <cmath>
#include <limits.h> // for INT_MAX
#include <stdlib.h> // for abs
#include <geometry/seg.h> // for SEG
#include <geometry/shape.h>
@ -36,13 +35,12 @@
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_simple.h>
#include <math/box2.h> // for BOX2I
#include <math/vector2d.h>
typedef VECTOR2I::extended_type ecoord;
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_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 )
return false;
if( aNeedMTV )
aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
if( aActual )
*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;
}
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 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 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 )
};
int nearest_seg_dist = INT_MAX;
ecoord nearest_side_dist_sq = VECTOR2I::ECOORD_MAX;
VECTOR2I nearest;
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
if( inside && !aMTV )
{
if( aActual )
*aActual = 0;
if( !aNeedMTV && inside )
return true;
}
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( ( d < min_dist ) && !aNeedMTV )
if(( side_dist_sq < min_dist_sq ) && !aMTV && !aActual )
return true;
if( d < nearest_seg_dist )
if( side_dist_sq < nearest_side_dist_sq )
{
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;
VECTOR2I delta = c - nearest;
if( !aNeedMTV )
return true;
if( aActual )
*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 );
*aMTV = -delta.Resize( abs( min_dist + 1 + sqrt( nearest_side_dist_sq ) ) + 1 );
else
aMTV = delta.Resize( abs( min_dist + 1 - nearest_seg_dist ) + 1 );
*aMTV = delta.Resize( abs( min_dist + 1 - sqrt( nearest_side_dist_sq ) ) + 1 );
}
return true;
@ -154,22 +161,24 @@ 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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
bool found = false;
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;
break;
}
}
if( !aNeedMTV || !found )
return found;
if( !found )
return false;
if( aMTV )
{
SHAPE_CIRCLE cmoved( aA );
VECTOR2I f_total( 0, 0 );
@ -180,81 +189,123 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB,
f_total += f;
}
aMTV = f_total;
return found;
*aMTV = f_total;
}
return true;
}
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
bool found;
const SHAPE_LINE_CHAIN& lc( aB.Vertices() );
int min_dist = aClearance + aA.GetRadius();
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 )
return found;
if( aActual )
*aActual = std::max( 0, (int) sqrt( dist_sq ) - aA.GetRadius() );
if( aMTV )
{
SHAPE_CIRCLE cmoved( aA );
VECTOR2I f_total( 0, 0 );
for( int s = 0; s < lc.SegmentCount(); s++ )
for( int s = 0; s < aB.Vertices().SegmentCount(); s++ )
{
VECTOR2I f = pushoutForce( cmoved, lc.CSegment( s ), aClearance );
VECTOR2I f = pushoutForce( cmoved, aB.Vertices().CSegment( s ), aClearance );
cmoved.SetCenter( cmoved.GetCenter() + f );
f_total += f;
}
aMTV = f_total;
return found;
*aMTV = f_total;
}
return true;
}
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;
}
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++ )
if( aA.Collide( aB.CSegment( i ), aClearance ) )
{
if( aA.Collide( aB.CSegment( i ), aClearance, aActual ) )
return true;
}
return false;
}
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,
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
int minActual = INT_MAX;
int actual;
for( int s = 0; s < aB.SegmentCount(); s++ )
{
if( aA.Collide( aB.CSegment( s ), aClearance ) )
if( aA.Collide( aB.CSegment( s ), aClearance, &actual ) )
{
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;
}
@ -262,118 +313,125 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, in
}
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,
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,
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 false;
}
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,
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
const auto lc = aA.ConvertToPolyline();
bool rv = Collide( aB, lc, aClearance, aNeedMTV, aMTV );
bool rv = Collide( aB, lc, aClearance, aActual, aMTV );
if( rv && aNeedMTV )
aMTV = -aMTV;
if( rv && aMTV )
*aMTV = - *aMTV ;
return rv;
}
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();
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
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,
bool aNeedMTV, VECTOR2I& aMTV )
int* aActual, VECTOR2I* aMTV )
{
const auto lcA = aA.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>
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
template<class T_a, class T_b>
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
VECTOR2I* aMTV )
{
return Collide (*static_cast<const ShapeAType*>( aA ),
*static_cast<const ShapeBType*>( aB ),
aClearance, aNeedMTV, aMTV);
return Collide( *static_cast<const T_a*>( aA ), *static_cast<const T_b*>( aB ),
aClearance, aActual, aMTV);
}
template<class ShapeAType, class ShapeBType>
inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
template<class T_a, class T_b>
inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
VECTOR2I* aMTV )
{
bool rv = Collide (*static_cast<const ShapeBType*>( aB ),
*static_cast<const ShapeAType*>( aA ),
aClearance, aNeedMTV, aMTV);
if(rv && aNeedMTV)
aMTV = -aMTV;
bool rv = Collide( *static_cast<const T_b*>( aB ), *static_cast<const T_a*>( aA ),
aClearance, aActual, aMTV);
if( rv && aMTV)
*aMTV = - *aMTV;
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() )
{
@ -381,22 +439,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_CIRCLE>( aA, aB, aClearance, aActual, aMTV );
case SH_LINE_CHAIN:
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -407,22 +465,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_CIRCLE, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -433,22 +491,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN>( aB, aA, aClearance, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -459,22 +517,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -485,22 +543,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aB, aA, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aB, aA, aClearance, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_SIMPLE, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_SIMPLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_SIMPLE, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCaseReversed<SHAPE_SIMPLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -511,22 +569,22 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_ARC, SHAPE_RECT>( aA, aB, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_ARC, SHAPE_CIRCLE>( aA, aB, aClearance, aNeedMTV, aMTV );
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, aNeedMTV, aMTV );
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN>( aA, aB, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_ARC, SHAPE_SIMPLE>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_ARC, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aNeedMTV, aMTV );
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
default:
break;
@ -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, false, dummy );
return CollideShapes( this, aShape, aClearance, aActual, nullptr );
}
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance ) const
{
int dummy;
return DoCollide( aSeg, aClearance, &dummy );
}
bool SHAPE_RECT::DoCollide( const SEG& aSeg, int aClearance, int* aActualDist ) const
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
{
if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) )
{
*aActualDist = 0;
*aActual = 0;
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_w, m_p0.y + m_h ),
VECTOR2I( m_p0.x + m_w, 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 );
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 ) );
}
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;
}

View File

@ -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 s( aP, aP );
return this->Collide( s, aClearance );
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
SEG::ecoord clearance_sq = SEG::Square( 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 );
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
SEG::ecoord clearance_sq = SEG::Square( aClearance );
for( int i = 0; i < SegmentCount(); 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( d < dist_sq )
{
if( s.Collide( aSeg, aClearance ) )
if( !aActual && dist_sq < clearance_sq )
return true;
}
if( dist_sq < clearance_sq )
{
if( aActual )
*aActual = sqrt( dist_sq );
return true;
}
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 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 )
return 0;
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;
}

View File

@ -1224,30 +1224,15 @@ 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 );
// Inflate the polygon if necessary.
if( aClearance > 0 )
if( dist_sq < (ecoord) aClearance * aClearance )
{
// fixme: the number of arc segments should not be hardcoded
polySet.Inflate( aClearance, 8 );
}
if( aActual )
*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;
for( CONST_SEGMENT_ITERATOR it = CIterateSegmentsWithHoles(); it; it++ )
{
const SEG polygonEdge = *it;
if( polygonEdge.Intersect( aSeg, true ) )
return true;
}
@ -1255,19 +1240,19 @@ bool SHAPE_POLY_SET::Collide( const SEG& aSeg, int aClearance ) const
}
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( aClearance > 0 )
if( dist_sq < (ecoord) aClearance * aClearance )
{
// fixme: the number of arc segments should not be hardcoded
polySet.Inflate( aClearance, 8 );
if( aActual )
*aActual = sqrt( dist_sq );
return true;
}
// There is a collision if and only if the point is inside of the polygon.
return polySet.Contains( aP );
return false;
}

View File

@ -155,7 +155,7 @@ bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int
return std::abs( delta.y ) <= aDist;
SEG segment( aStart, aEnd );
return segment.PointCloserThan( aRefPoint, aDist + 1 );
return segment.SquaredDistance( aRefPoint ) < SEG::Square( aDist + 1 );
}

View File

@ -370,7 +370,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
{
case S_CIRCLE:
if( width == 0 )
TransformCircleToPolygon( aCornerBuffer, GetCenter(), GetRadius() + width / 2, aError );
TransformCircleToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError );
else
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError, width );
break;

View File

@ -34,6 +34,9 @@
#include <class_module.h>
#include <class_drawsegment.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/settings_manager.h>
@ -590,16 +593,13 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
int radius = GetRadius();
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 )
return true;
}
if( m_Width > 0 )
else // Ring hit-test
{
// Ring hit-test
if( abs( radius - dist ) <= maxdist )
return true;
}
@ -666,7 +666,7 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
std::vector<wxPoint> pts;
GetRectCorners( &pts );
if( m_Width == 0 )
if( m_Width == 0 ) // Filled rect hit-test
{
SHAPE_POLY_SET poly;
poly.NewOutline();
@ -677,8 +677,7 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
if( poly.Collide( VECTOR2I( aPosition ), maxdist ) )
return true;
}
if( m_Width > 0 )
else // Open rect hit-test
{
if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
|| TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
@ -828,7 +827,7 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
}
break;
case S_CURVE: // not yet handled
case S_CURVE:
if( aContained )
{
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
{
std::vector<wxPoint> rv;

View File

@ -36,9 +36,9 @@
#include <math/util.h> // for KiROUND
#include <math_for_graphics.h>
#include <trigo.h>
#include <geometry/shape_poly_set.h>
class LINE_READER;
class EDA_DRAW_FRAME;
class MODULE;
@ -237,6 +237,11 @@ public:
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;
const EDA_RECT GetBoundingBox() const override;

View File

@ -327,30 +327,26 @@ void D_PAD::BuildEffectiveShapes() const
if( GetShape() == PAD_SHAPE_CUSTOM )
{
SHAPE_POLY_SET* poly = new SHAPE_POLY_SET();
MergePrimitivesAsPolygon( poly );
poly->Rotate( -DECIDEG2RAD( m_Orient ) );
poly->Move( shapePos );
add( poly );
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
{
for( SHAPE* shape : primitive->MakeEffectiveShapes() )
{
shape->Rotate( -DECIDEG2RAD( m_Orient ) );
shape->Move( shapePos );
add( shape );
}
}
}
// Bounding box and radius
//
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 )
{
BOX2I r = shape->BBox();
if( first_shape )
{
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() ) ) );
}

View File

@ -7,7 +7,7 @@
* 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) 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
* modify it under the terms of the GNU General Public License
@ -32,13 +32,10 @@
#include <fctsys.h>
#include <common.h>
#include <confirm.h>
#include <pcbnew.h>
#include <trigo.h>
#include <macros.h>
#include <pcb_base_frame.h>
#include <base_units.h>
#include <widgets/wx_grid.h>
#include <class_board.h>
#include <class_module.h>
#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_thickness( aFrame, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true )
{
if( !m_shape->GetPolyShape().IsEmpty() )
{
for( const VECTOR2I& pt : m_shape->GetPolyShape().Outline( 0 ).CPoints() )
m_currPoints.emplace_back( pt );
}
m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );

View File

@ -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() ) );
@ -634,33 +634,24 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
return true;
// JEY TODO:
// 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;
int actual = INT_MAX;
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
{
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
{
if( aShape->Collide( bShape.get(), aMinClearance, mtv ) )
{
shapes_collide = true;
int this_dist;
if( mtv.SquaredEuclideanNorm() > maxMtv.SquaredEuclideanNorm() )
maxMtv = mtv;
}
if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
actual = std::min( actual, this_dist );
}
}
if( shapes_collide )
if( actual < INT_MAX )
{
// returns the actual clearance (clearance < aMinClearance) for diags:
if( aActualDist )
*aActualDist = std::max( 0, aMinClearance - maxMtv.EuclideanNorm() );
if( aActual )
*aActual = std::max( 0, actual );
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() );
int actual;
if( padShape.DoCollide( refSeg, minClearance + widths, &actual ) )
if( padShape.Collide( refSeg, minClearance + widths, &actual ) )
{
*aActualDist = std::max( 0, actual - widths );
return false;

View File

@ -29,18 +29,12 @@
#include <fctsys.h>
#include <trigo.h>
#include <pcbnew.h>
#include <bezier_curves.h>
#include <class_board.h>
#include <class_board_item.h>
#include <class_drawsegment.h>
#include <class_edge_mod.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/convex_hull.h>
#include <geometry/geometry_utils.h>
#include <geometry/shape_rect.h>
@ -184,107 +178,7 @@ void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aErro
SHAPE_POLY_SET polyset;
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
{
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;
}
}
primitive->TransformShapeWithClearanceToPolygon( polyset, 0, aError );
polyset.Simplify( SHAPE_POLY_SET::PM_FAST );

View File

@ -39,7 +39,7 @@ bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VEC
return false;
if( aNeedMTV )
return Shape()->Collide( aOther->Shape(), aClearance, *aMTV );
return Shape()->Collide( aOther->Shape(), aClearance, aMTV );
else
return Shape()->Collide( aOther->Shape(), aClearance );
}

View File

@ -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 )
{
std::vector<SHAPE_SEGMENT*> segs;
if( aItem->GetLayer() != Edge_Cuts && !IsCopperLayer( aItem->GetLayer() ) )
return false;
switch( aItem->GetShape() )
{
case S_ARC:
{
SHAPE_ARC arc( aItem->GetCenter(), aItem->GetArcStart(), aItem->GetAngle() / 10.0 );
auto l = arc.ConvertToPolyline();
// TODO: where do we handle filled polygons on copper layers?
if( aItem->GetShape() == S_POLYGON && aItem->IsPolygonFilled() )
return false;
for( int i = 0; i < l.SegmentCount(); i++ )
{
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 )
for( SHAPE* shape : aItem->MakeEffectiveShapes() )
{
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->SetParent( nullptr );
solid->SetShape( seg );
solid->SetShape( shape );
solid->SetRoutable( false );
aWorld->Add( std::move( solid ) );

View File

@ -814,7 +814,7 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
*/
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;
bool lineCollision = false;
bool viaCollision = false;
@ -835,9 +835,9 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
#endif
currentLine = (LINE*) aCurrent;
lineCollision = CollideShapes( aObstacleVia->Shape(), currentLine->Shape(),
clearance + currentLine->Width() / 2 + PNS_HULL_MARGIN,
true, mtvLine );
lineCollision = aObstacleVia->Shape()->Collide( currentLine->Shape(),
clearance + currentLine->Width() / 2,
&mtvLine );
if( currentLine->EndsWithVia() )
{
@ -846,8 +846,8 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
if( currentNet != obstacleNet && currentNet >= 0 && obstacleNet >= 0 )
{
viaCollision = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(),
clearance + PNS_HULL_MARGIN, true, mtvVia );
viaCollision = currentLine->Via().Shape()->Collide( aObstacleVia->Shape(),
clearance, &mtvVia );
}
// 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 ) )
{
CollideShapes( aObstacleVia->Shape(), aCurrent->Shape(),
clearance + PNS_HULL_MARGIN, true, mtvSolid );
aObstacleVia->Shape()->Collide( aCurrent->Shape(), clearance, &mtvSolid );
mtv = -mtvSolid;
rank = aCurrent->Rank() + 10000;
}

View File

@ -34,12 +34,12 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
{
int iter = 0;
VIA mv( *this );
VECTOR2I force, totalForce, force2;
VECTOR2I force, totalForce;
while( iter < aMaxIterations )
{
NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv,
aSolidsOnly ? ITEM::SOLID_T : ITEM::ANY_T );
NODE::OPT_OBSTACLE obs = aNode->CheckColliding( &mv, aSolidsOnly ? ITEM::SOLID_T
: ITEM::ANY_T );
if( !obs )
break;
@ -53,11 +53,10 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
mv.SetPos( mv.Pos() + l );
}
bool col = CollideShapes( obs->m_item->Shape(), mv.Shape(), clearance, true, force2 );
if( col ) {
totalForce += force2;
mv.SetPos( mv.Pos() + force2 );
if( obs->m_item->Shape()->Collide( mv.Shape(), clearance, &force ) )
{
totalForce += force;
mv.SetPos( mv.Pos() + force );
}
iter++;