geometry: derive SHAPE_LINE_CHAIN, SHAPE_SIMPLE and SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI from a common base class allowing to simplify collision detection

This commit is contained in:
Tomasz Wlostowski 2020-09-05 01:08:18 +02:00
parent eb6e1c4f90
commit 74623b8c98
6 changed files with 279 additions and 178 deletions

View File

@ -30,6 +30,7 @@
#include <math/vector2d.h>
#include <math/box2.h>
class SHAPE_LINE_CHAIN;
/**
* Enum SHAPE_TYPE
@ -38,15 +39,16 @@
enum SHAPE_TYPE
{
SH_RECT = 0, ///> axis-aligned rectangle
SH_SEGMENT, ///> line segment
SH_LINE_CHAIN, ///> line chain (polyline)
SH_CIRCLE, ///> circle
SH_RECT = 0, ///> axis-aligned rectangle
SH_SEGMENT, ///> line segment
SH_LINE_CHAIN, ///> line chain (polyline)
SH_CIRCLE, ///> circle
SH_SIMPLE, ///> simple polygon
SH_POLY_SET, ///> set of polygons (with holes, etc.)
SH_COMPOUND, ///> compound shape, consisting of multiple simple shapes
SH_ARC, ///> circular arc
SH_NULL ///> empty shape (no shape...)
SH_POLY_SET, ///> set of polygons (with holes, etc.)
SH_COMPOUND, ///> compound shape, consisting of multiple simple shapes
SH_ARC, ///> circular arc
SH_NULL, ///> empty shape (no shape...),
SH_POLY_SET_TRIANGLE ///> a single triangle belonging to a POLY_SET triangulation
};
static inline wxString SHAPE_TYPE_asString( SHAPE_TYPE a )
@ -62,22 +64,15 @@ static inline wxString SHAPE_TYPE_asString( SHAPE_TYPE a )
case SH_COMPOUND: return "SH_COMPOUND";
case SH_ARC: return "SH_ARC";
case SH_NULL: return "SH_NULL";
case SH_POLY_SET_TRIANGLE: return "SH_POLY_SET_TRIANGLE";
}
return wxEmptyString; // Just to quiet GCC.
}
/**
* SHAPE
*
* Represents an abstract shape on 2D plane.
*/
class SHAPE
class SHAPE_BASE
{
protected:
typedef VECTOR2I::extended_type ecoord;
public:
/**
* Constructor
@ -85,11 +80,11 @@ public:
* Creates an empty shape of type aType
*/
SHAPE( SHAPE_TYPE aType ) : m_type( aType )
SHAPE_BASE( SHAPE_TYPE aType ) : m_type( aType )
{}
// Destructor
virtual ~SHAPE()
virtual ~SHAPE_BASE()
{}
/**
@ -103,6 +98,45 @@ public:
return m_type;
}
virtual bool HasIndexableSubshapes() const
{
return false;
}
virtual size_t GetIndexableSubshapeCount() { return 0; }
virtual void GetIndexableSubshape( SHAPE_BASE& aSubshape ) const {};
protected:
///> type of our shape
SHAPE_TYPE m_type;
};
/**
* SHAPE
*
* Represents an abstract shape on 2D plane.
*/
class SHAPE : public SHAPE_BASE
{
protected:
typedef VECTOR2I::extended_type ecoord;
public:
/**
* Constructor
*
* Creates an empty shape of type aType
*/
SHAPE( SHAPE_TYPE aType ) : SHAPE_BASE( aType )
{}
// Destructor
virtual ~SHAPE()
{}
/**
* Function Clone()
*
@ -202,11 +236,82 @@ public:
virtual bool Parse( std::stringstream& aStream );
virtual const std::string Format( ) const;
protected:
///> type of our shape
SHAPE_TYPE m_type;
};
class SHAPE_LINE_CHAIN_BASE : public SHAPE
{
public:
SHAPE_LINE_CHAIN_BASE( SHAPE_TYPE aType ) : SHAPE( aType )
{
}
// Destructor
virtual ~SHAPE_LINE_CHAIN_BASE()
{
}
/**
* Function Collide()
*
* 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
*/
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr ) const override;
/**
* Function Collide()
*
* 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
*/
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr ) const override;
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
/**
* Function PointInside()
*
* Checks if point aP lies inside a polygon (any type) defined by the line chain.
* For closed shapes only.
* @param aPt point to check
* @param aUseBBoxCache gives better peformance if the bounding box caches have been
* generated.
* @return true if the point is inside the shape (edge is not treated as being inside).
*/
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const;
/**
* Function PointOnEdge()
*
* Checks if point aP lies on an edge or vertex of the line chain.
* @param aP point to check
* @return true if the point lies on the edge.
*/
bool PointOnEdge( const VECTOR2I& aP, int aAccuracy = 0 ) const;
/**
* Function EdgeContainingPoint()
*
* Checks if point aP lies on an edge or vertex of the line chain.
* @param aP point to check
* @return index of the first edge containing the point, otherwise negative
*/
int EdgeContainingPoint( const VECTOR2I& aP, int aAccuracy = 0 ) const;
virtual const VECTOR2I GetPoint( int aIndex ) const = 0;
virtual const SEG GetSegment( int aIndex ) const = 0;
virtual size_t GetPointCount() const = 0;
virtual size_t GetSegmentCount() const = 0;
virtual bool IsClosed() const = 0;
};
#endif // __SHAPE_H

View File

@ -43,7 +43,7 @@
*
* SHAPE_LINE_CHAIN class shall not be used for polygons!
*/
class SHAPE_LINE_CHAIN : public SHAPE
class SHAPE_LINE_CHAIN : public SHAPE_LINE_CHAIN_BASE
{
private:
typedef std::vector<VECTOR2I>::iterator point_iter;
@ -99,7 +99,7 @@ public:
* Constructor
* Initializes an empty line chain.
*/
SHAPE_LINE_CHAIN() : SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
SHAPE_LINE_CHAIN() : SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
{}
/**
@ -107,7 +107,7 @@ public:
*/
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape )
: SHAPE( SH_LINE_CHAIN ),
: SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ),
m_points( aShape.m_points ),
m_shapes( aShape.m_shapes ),
m_arcs( aShape.m_arcs ),
@ -119,7 +119,7 @@ public:
SHAPE_LINE_CHAIN( const std::vector<int>& aV);
SHAPE_LINE_CHAIN( const std::vector<wxPoint>& aV, bool aClosed = false )
: SHAPE( SH_LINE_CHAIN ), m_closed( aClosed ), m_width( 0 )
: SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ), m_closed( aClosed ), m_width( 0 )
{
m_points.reserve( aV.size() );
@ -130,14 +130,14 @@ public:
}
SHAPE_LINE_CHAIN( const std::vector<VECTOR2I>& aV, bool aClosed = false )
: SHAPE( SH_LINE_CHAIN ), m_closed( aClosed ), m_width( 0 )
: SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ), m_closed( aClosed ), m_width( 0 )
{
m_points = aV;
m_shapes = std::vector<ssize_t>( aV.size(), ssize_t( SHAPE_IS_PT ) );
}
SHAPE_LINE_CHAIN( const SHAPE_ARC& aArc, bool aClosed = false )
: SHAPE( SH_LINE_CHAIN ),
: SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ),
m_closed( aClosed ),
m_width( 0 )
{
@ -147,7 +147,7 @@ public:
}
SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath ) :
SHAPE( SH_LINE_CHAIN ),
SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ),
m_closed( true ),
m_width( 0 )
{
@ -194,7 +194,7 @@ public:
*
* @return aClosed: true, when our line is closed.
*/
bool IsClosed() const
bool IsClosed() const override
{
return m_closed;
}
@ -372,30 +372,6 @@ public:
return m_bbox;
}
/**
* Function Collide()
*
* 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, int* aActual = nullptr ) const override;
/**
* Function Collide()
*
* 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, int* aActual = nullptr ) const override;
/**
* Function Distance()
*
@ -404,7 +380,6 @@ 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()
@ -600,37 +575,6 @@ public:
*/
int PathLength( const VECTOR2I& aP ) const;
/**
* Function PointInside()
*
* Checks if point aP lies inside a polygon (any type) defined by the line chain.
* For closed shapes only.
* @param aPt point to check
* @param aUseBBoxCache gives better peformance if the bounding box caches have been
* generated.
* @return true if the point is inside the shape (edge is not treated as being inside).
*/
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const;
/**
* Function PointOnEdge()
*
* Checks if point aP lies on an edge or vertex of the line chain.
* @param aP point to check
* @return true if the point lies on the edge.
*/
bool PointOnEdge( const VECTOR2I& aP, int aAccuracy = 0 ) const;
/**
* Function EdgeContainingPoint()
*
* Checks if point aP lies on an edge or vertex of the line chain.
* @param aP point to check
* @return index of the first edge containing the point, otherwise negative
*/
int EdgeContainingPoint( const VECTOR2I& aP, int aAccuracy = 0 ) const;
/**
* Function CheckClearance()
*
@ -775,6 +719,11 @@ public:
return aSegment < m_shapes.size() && m_shapes[aSegment] != SHAPE_IS_PT;
}
virtual const VECTOR2I GetPoint( int aIndex ) const override { return CPoint(aIndex); }
virtual const SEG GetSegment( int aIndex ) const override { return CSegment(aIndex); }
virtual size_t GetPointCount() const override { return PointCount(); }
virtual size_t GetSegmentCount() const override { return SegmentCount(); }
private:
constexpr static ssize_t SHAPE_IS_PT = -1;

View File

@ -71,13 +71,64 @@ class SHAPE_POLY_SET : public SHAPE
class TRIANGULATED_POLYGON
{
public:
struct TRI
struct TRI : public SHAPE_LINE_CHAIN_BASE
{
TRI( int _a = 0, int _b = 0, int _c = 0 ) : a( _a ), b( _b ), c( _c )
TRI( int _a = 0, int _b = 0, int _c = 0, TRIANGULATED_POLYGON* aParent = nullptr ) :
SHAPE_LINE_CHAIN_BASE( SH_POLY_SET_TRIANGLE ),
a( _a ), b( _b ), c( _c ), parent( aParent )
{
}
virtual void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override {};
virtual void Move( const VECTOR2I& aVector ) override {};
virtual bool IsSolid() const override { return true; }
virtual bool IsClosed() const override { return true; }
virtual const BOX2I BBox( int aClearance = 0 ) const override
{
BOX2I bbox( parent->m_vertices[a] );
bbox.Merge( parent->m_vertices[b] );
bbox.Merge( parent->m_vertices[c] );
if( aClearance != 0 )
bbox.Inflate( aClearance );
return bbox;
}
virtual const VECTOR2I GetPoint( int aIndex ) const override
{
switch(aIndex)
{
case 0: return parent->m_vertices[a];
case 1: return parent->m_vertices[b];
case 2: return parent->m_vertices[c];
default: assert(false);
}
return VECTOR2I(0, 0);
}
virtual const SEG GetSegment( int aIndex ) const override
{
switch(aIndex)
{
case 0: return SEG( parent->m_vertices[a], parent->m_vertices[b] );
case 1: return SEG( parent->m_vertices[b], parent->m_vertices[c] );
case 2: return SEG( parent->m_vertices[c], parent->m_vertices[a] );
default: assert(false);
}
return SEG();
}
virtual size_t GetPointCount() const override { return 3; }
virtual size_t GetSegmentCount() const override { return 3; }
int a, b, c;
TRIANGULATED_POLYGON* parent;
};
void Clear()
@ -101,7 +152,7 @@ class SHAPE_POLY_SET : public SHAPE
void AddTriangle( int a, int b, int c )
{
m_triangles.emplace_back( a, b, c );
m_triangles.emplace_back( a, b, c, this );
}
void AddVertex( const VECTOR2I& aP )
@ -114,7 +165,7 @@ class SHAPE_POLY_SET : public SHAPE
return m_triangles.size();
}
size_t GetVertexCount() const
size_t GetVertexCount() const
{
return m_vertices.size();
}

View File

@ -39,7 +39,8 @@
* Internally the vertices are held in a SHAPE_LINE_CHAIN, please note that
* there is a "virtual" line segment between the last and first vertex.
*/
class SHAPE_SIMPLE : public SHAPE
class SHAPE_SIMPLE : public SHAPE_LINE_CHAIN_BASE
{
public:
/**
@ -47,20 +48,20 @@ public:
* Creates an empty polygon
*/
SHAPE_SIMPLE() :
SHAPE( SH_SIMPLE )
SHAPE_LINE_CHAIN_BASE( SH_SIMPLE )
{
m_points.SetClosed( true );
}
SHAPE_SIMPLE( const SHAPE_LINE_CHAIN& aPoly ) :
SHAPE( SH_SIMPLE ),
SHAPE_LINE_CHAIN_BASE( SH_SIMPLE ),
m_points( aPoly )
{
m_points.SetClosed( true );
}
SHAPE_SIMPLE( const SHAPE_SIMPLE& aOther ) :
SHAPE( SH_SIMPLE ), m_points( aOther.m_points )
SHAPE_LINE_CHAIN_BASE( SH_SIMPLE ), m_points( aOther.m_points )
{}
SHAPE* Clone() const override
@ -179,6 +180,16 @@ public:
return true;
}
virtual const VECTOR2I GetPoint( int aIndex ) const override { return m_points.CPoint(aIndex); }
virtual const SEG GetSegment( int aIndex ) const override { return m_points.CSegment(aIndex); }
virtual size_t GetPointCount() const override { return m_points.PointCount(); }
virtual size_t GetSegmentCount() const override { return m_points.SegmentCount(); }
bool IsClosed() const override
{
return true;
}
private:
// vertices
SHAPE_LINE_CHAIN m_points;

View File

@ -162,15 +162,15 @@ static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aCleara
return f;
}
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
#if 0
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
bool collided = false;
for( int s = 0; s < aB.SegmentCount(); s++ )
for( int s = 0; s < aB.GetSegmentCount(); s++ )
{
if( aA.Collide( aB.CSegment( s ), aClearance, aActual ) )
if( aA.Collide( aB.GetSegment( s ), aClearance, aActual ) )
{
collided = true;
break;
@ -185,9 +185,9 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB,
SHAPE_CIRCLE cmoved( aA );
VECTOR2I f_total( 0, 0 );
for( int s = 0; s < aB.SegmentCount(); s++ )
for( int s = 0; s < aB.GetSegmentCount(); s++ )
{
VECTOR2I f = pushoutForce( cmoved, aB.CSegment( s ), aClearance );
VECTOR2I f = pushoutForce( cmoved, aB.GetSegment( s ), aClearance );
cmoved.SetCenter( cmoved.GetCenter() + f );
f_total += f;
}
@ -197,13 +197,13 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB,
return true;
}
#endif
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
int min_dist = aClearance + aA.GetRadius();
ecoord dist_sq = aB.Vertices().SquaredDistance( aA.GetCenter() );
ecoord dist_sq = aB.SquaredDistance( aA.GetCenter() );
if( dist_sq > (ecoord) min_dist * min_dist )
return false;
@ -216,9 +216,9 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int
SHAPE_CIRCLE cmoved( aA );
VECTOR2I f_total( 0, 0 );
for( int s = 0; s < aB.Vertices().SegmentCount(); s++ )
for( int s = 0; s < aB.GetSegmentCount(); s++ )
{
VECTOR2I f = pushoutForce( cmoved, aB.Vertices().CSegment( s ), aClearance );
VECTOR2I f = pushoutForce( cmoved, aB.GetSegment( s ), aClearance );
cmoved.SetCenter( cmoved.GetCenter() + f );
f_total += f;
}
@ -242,14 +242,15 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, i
}
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
// TODO: why doesn't this handle MTV?
// TODO: worse, why this doesn't handle closed shapes?
for( int i = 0; i < aB.SegmentCount(); i++ )
for( int i = 0; i < aB.GetSegmentCount(); i++ )
{
if( aA.Collide( aB.CSegment( i ), aClearance, aActual ) )
if( aA.Collide( aB.GetSegment( i ), aClearance, aActual ) )
return true;
}
@ -257,29 +258,15 @@ static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN&
}
static inline bool Collide( const SHAPE_LINE_CHAIN& 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_SIMPLE& aA, const SHAPE_SIMPLE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
return Collide( aA.Vertices(), aB.Vertices(), aClearance, aActual, aMTV );
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
int minActual = INT_MAX;
int actual;
for( int s = 0; s < aB.SegmentCount(); s++ )
for( int s = 0; s < aB.GetSegmentCount(); s++ )
{
if( aA.Collide( aB.CSegment( s ), aClearance, &actual ) )
if( aA.Collide( aB.GetSegment( s ), aClearance, &actual ) )
{
minActual = std::min( minActual, actual );
@ -298,13 +285,6 @@ 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,
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 )
{
@ -343,7 +323,7 @@ static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, in
}
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, int aClearance,
static inline bool Collide( const SHAPE_LINE_CHAIN_BASE& aA, const SHAPE_SEGMENT& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
int actual;
@ -362,12 +342,6 @@ static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB,
}
static inline bool Collide( const SHAPE_SIMPLE& aA, const SHAPE_SEGMENT& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
return Collide( aA.Vertices(), aB, aClearance, aActual, aMTV );
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_RECT& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
@ -407,12 +381,12 @@ static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SEGMENT& aB, int aC
return Collide( lc, aB, aClearance, aActual, aMTV );
}
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_SIMPLE& aB, int aClearance,
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_LINE_CHAIN_BASE& aB, int aClearance,
int* aActual, VECTOR2I* aMTV )
{
const auto lc = aA.ConvertToPolyline();
return Collide( lc, aB.Vertices(), aClearance, aActual, aMTV );
return Collide( lc, aB, aClearance, aActual, aMTV );
}
static inline bool Collide( const SHAPE_ARC& aA, const SHAPE_ARC& aB, int aClearance,
@ -454,6 +428,7 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
{
case SH_NULL:
return false;
case SH_RECT:
switch( aB->Type() )
{
@ -470,7 +445,8 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_RECT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
@ -499,7 +475,8 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_CIRCLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
@ -528,7 +505,8 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_LINE_CHAIN, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
@ -557,7 +535,8 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aB, aA, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_SEGMENT, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
@ -571,25 +550,27 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
break;
case SH_SIMPLE:
case SH_POLY_SET_TRIANGLE:
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
return CollCase<SHAPE_RECT, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_CIRCLE, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
return CollCase<SHAPE_CIRCLE, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
case SH_LINE_CHAIN:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SIMPLE>( aB, aA, aClearance, aActual, aMTV );
return CollCase<SHAPE_LINE_CHAIN, SHAPE_LINE_CHAIN_BASE>( aB, aA, aClearance, aActual, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_SIMPLE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_SIMPLE, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_LINE_CHAIN_BASE, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCaseReversed<SHAPE_SIMPLE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
return CollCaseReversed<SHAPE_LINE_CHAIN_BASE, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );
case SH_NULL:
return false;
@ -615,7 +596,8 @@ static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearanc
return CollCase<SHAPE_ARC, SHAPE_SEGMENT>( aA, aB, aClearance, aActual, aMTV );
case SH_SIMPLE:
return CollCase<SHAPE_ARC, SHAPE_SIMPLE>( aA, aB, aClearance, aActual, aMTV );
case SH_POLY_SET_TRIANGLE:
return CollCase<SHAPE_ARC, SHAPE_LINE_CHAIN_BASE>( aA, aB, aClearance, aActual, aMTV );
case SH_ARC:
return CollCase<SHAPE_ARC, SHAPE_ARC>( aA, aB, aClearance, aActual, aMTV );

View File

@ -37,7 +37,7 @@
class SHAPE;
SHAPE_LINE_CHAIN::SHAPE_LINE_CHAIN( const std::vector<int>& aV)
: SHAPE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
: SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ), m_closed( false ), m_width( 0 )
{
for(size_t i = 0; i < aV.size(); i+= 2 )
{
@ -85,14 +85,16 @@ void SHAPE_LINE_CHAIN::convertArc( ssize_t aArcIndex )
}
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
bool SHAPE_LINE_CHAIN_BASE::Collide( const VECTOR2I& aP, int aClearance, int* aActual ) const
{
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
SEG::ecoord clearance_sq = SEG::Square( aClearance );
for( int i = 0; i < SegmentCount(); i++ )
// fixme: why this only checks open curves?
for( int i = 0; i < GetSegmentCount(); i++ )
{
const SEG& s = CSegment( i );
const SEG& s = GetSegment( i );
dist_sq = std::min( dist_sq, s.SquaredDistance( aP ) );
if( ( dist_sq == 0 || dist_sq < clearance_sq ) && !aActual )
@ -125,14 +127,14 @@ void SHAPE_LINE_CHAIN::Rotate( double aAngle, const VECTOR2I& aCenter )
}
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
bool SHAPE_LINE_CHAIN_BASE::Collide( const SEG& aSeg, int aClearance, int* aActual ) const
{
SEG::ecoord dist_sq = VECTOR2I::ECOORD_MAX;
SEG::ecoord clearance_sq = SEG::Square( aClearance );
for( int i = 0; i < SegmentCount(); i++ )
for( int i = 0; i < GetSegmentCount(); i++ )
{
const SEG& s = CSegment( i );
const SEG& s = GetSegment( i );
dist_sq = std::min( dist_sq, s.SquaredDistance( aSeg ) );
if( ( dist_sq == 0 || dist_sq < clearance_sq ) && !aActual )
@ -292,15 +294,15 @@ int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
}
SEG::ecoord SHAPE_LINE_CHAIN::SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly ) const
SEG::ecoord SHAPE_LINE_CHAIN_BASE::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 ).SquaredDistance( aP ) );
for( int s = 0; s < GetSegmentCount(); s++ )
d = std::min( d, GetSegment( s ).SquaredDistance( aP ) );
return d;
}
@ -601,16 +603,18 @@ int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const
}
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
bool SHAPE_LINE_CHAIN_BASE::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
{
/*
* Don't check the bounding box unless it's cached. Building it is about the same speed as
* the rigorous test below and so just slows things down by doing potentially two tests.
*/
if( aUseBBoxCache && !m_bbox.Contains( aPt ) )
return false;
//if( aUseBBoxCache && !m_bbox.Contains( aPt ) )
//return false;
if( !m_closed || PointCount() < 3 )
// fixme: bbox cache...
if( !IsClosed() || GetPointCount() < 3 )
return false;
bool inside = false;
@ -626,13 +630,12 @@ bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUs
* Note: we open-code CPoint() here so that we don't end up calculating the size of the
* vector number-of-points times. This has a non-trivial impact on zone fill times.
*/
const std::vector<VECTOR2I>& points = CPoints();
int pointCount = points.size();
int pointCount = GetPointCount();
for( int i = 0; i < pointCount; )
{
const auto p1 = points[ i++ ];
const auto p2 = points[ i == pointCount ? 0 : i ];
const auto p1 = GetPoint( i++ );
const auto p2 = GetPoint( i == pointCount ? 0 : i );
const auto diff = p2 - p1;
if( diff.y != 0 )
@ -653,25 +656,25 @@ bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUs
}
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aPt, int aAccuracy ) const
bool SHAPE_LINE_CHAIN_BASE::PointOnEdge( const VECTOR2I& aPt, int aAccuracy ) const
{
return EdgeContainingPoint( aPt, aAccuracy ) >= 0;
}
int SHAPE_LINE_CHAIN::EdgeContainingPoint( const VECTOR2I& aPt, int aAccuracy ) const
int SHAPE_LINE_CHAIN_BASE::EdgeContainingPoint( const VECTOR2I& aPt, int aAccuracy ) const
{
if( !PointCount() )
if( !GetPointCount() )
return -1;
else if( PointCount() == 1 )
else if( GetPointCount() == 1 )
{
VECTOR2I dist = m_points[0] - aPt;
VECTOR2I dist = GetPoint(0) - aPt;
return ( hypot( dist.x, dist.y ) <= aAccuracy + 1 ) ? 0 : -1;
}
for( int i = 0; i < SegmentCount(); i++ )
for( int i = 0; i < GetSegmentCount(); i++ )
{
const SEG s = CSegment( i );
const SEG s = GetSegment( i );
if( s.A == aPt || s.B == aPt )
return i;