PNS: Detect collisions including newline width

The new line collision search uses BBox() to check for colliding
objects.  BBox in the SHAPE_LINE_CHAIN did not include width as the
chains were assumed to be zero-width.  This is not the case for
PNS::LINE elements.

We mostly don't notice this because DRC checks for SEGMENT collisions
but it becomes obvious/annoying when we cannot place a track for unknown
reasons and the snap-back doesn't take line width into account.

Fixes #3776 | https://gitlab.com/kicad/code/kicad/issues/3776

(cherry picked from commit fe15511d38)
This commit is contained in:
Seth Hillbrand 2020-01-17 06:19:27 -08:00
parent 923dad6ca8
commit 9e6b56d783
2 changed files with 41 additions and 13 deletions

View File

@ -74,15 +74,17 @@ public:
* Constructor * Constructor
* Initializes an empty line chain. * Initializes an empty line chain.
*/ */
SHAPE_LINE_CHAIN() : SHAPE_LINE_CHAIN() : SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
SHAPE( SH_LINE_CHAIN ), m_closed( false )
{} {}
/** /**
* Copy Constructor * Copy Constructor
*/ */
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) : SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape )
SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) : SHAPE( SH_LINE_CHAIN ),
m_points( aShape.m_points ),
m_closed( aShape.m_closed ),
m_width( aShape.m_width )
{} {}
/** /**
@ -90,7 +92,7 @@ public:
* Initializes a 2-point line chain (a single segment) * Initializes a 2-point line chain (a single segment)
*/ */
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) : SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) :
SHAPE( SH_LINE_CHAIN ), m_closed( false ) SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
{ {
m_points.resize( 2 ); m_points.resize( 2 );
m_points[0] = aA; m_points[0] = aA;
@ -98,7 +100,7 @@ public:
} }
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) : SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) :
SHAPE( SH_LINE_CHAIN ), m_closed( false ) SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
{ {
m_points.resize( 3 ); m_points.resize( 3 );
m_points[0] = aA; m_points[0] = aA;
@ -107,7 +109,7 @@ public:
} }
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC, const VECTOR2I& aD ) : SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC, const VECTOR2I& aD ) :
SHAPE( SH_LINE_CHAIN ), m_closed( false ) SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
{ {
m_points.resize( 4 ); m_points.resize( 4 );
m_points[0] = aA; m_points[0] = aA;
@ -119,7 +121,8 @@ public:
SHAPE_LINE_CHAIN( const VECTOR2I* aV, int aCount ) : SHAPE_LINE_CHAIN( const VECTOR2I* aV, int aCount ) :
SHAPE( SH_LINE_CHAIN ), SHAPE( SH_LINE_CHAIN ),
m_closed( false ) m_closed( false ),
m_width( 0 )
{ {
m_points.resize( aCount ); m_points.resize( aCount );
@ -127,9 +130,8 @@ public:
m_points[i] = *aV++; m_points[i] = *aV++;
} }
SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath ) : SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath )
SHAPE( SH_LINE_CHAIN ), : SHAPE( SH_LINE_CHAIN ), m_closed( true ), m_width( 0 )
m_closed( true )
{ {
m_points.reserve( aPath.size() ); m_points.reserve( aPath.size() );
@ -174,6 +176,24 @@ public:
return m_closed; return m_closed;
} }
/**
* Sets the width of all segments in the chain
* @param aWidth width in internal units
*/
void SetWidth( int aWidth )
{
m_width = aWidth;
}
/**
* Gets the current width of the segments in the chain
* @return width in internal units
*/
int Width() const
{
return m_width;
}
/** /**
* Function SegmentCount() * Function SegmentCount()
* *
@ -299,8 +319,8 @@ public:
BOX2I bbox; BOX2I bbox;
bbox.Compute( m_points ); bbox.Compute( m_points );
if( aClearance != 0 ) if( aClearance != 0 || m_width != 0 )
bbox.Inflate( aClearance ); bbox.Inflate( aClearance + m_width );
return bbox; return bbox;
} }
@ -684,6 +704,12 @@ private:
/// is the line chain closed? /// is the line chain closed?
bool m_closed; bool m_closed;
/// Width of the segments (for BBox calculations in RTree)
/// TODO Adjust usage of SHAPE_LINE_CHAIN to account for where we need a width and where not
/// Alternatively, we could split the class into a LINE_CHAIN (no width) and SHAPE_LINE_CHAIN that derives from
/// SHAPE as well that does have a width. Not sure yet on the correct path.
int m_width;
/// cached bounding box /// cached bounding box
BOX2I m_bbox; BOX2I m_bbox;
}; };

View File

@ -105,6 +105,7 @@ public:
void SetShape( const SHAPE_LINE_CHAIN& aLine ) void SetShape( const SHAPE_LINE_CHAIN& aLine )
{ {
m_line = aLine; m_line = aLine;
m_line.SetWidth( m_width );
} }
///> Returns the shape of the line ///> Returns the shape of the line
@ -153,6 +154,7 @@ public:
void SetWidth( int aWidth ) void SetWidth( int aWidth )
{ {
m_width = aWidth; m_width = aWidth;
m_line.SetWidth( aWidth );
} }
///> Returns line width ///> Returns line width