Lift some point-vs-shape APIs into SHAPE base class

Also provide a virtual method for conversion to polygon
This commit is contained in:
Jon Evans 2023-08-15 23:49:22 -04:00
parent d02e4f3254
commit bf0592ad53
17 changed files with 176 additions and 28 deletions

View File

@ -30,11 +30,13 @@
#include <vector>
#include <geometry/seg.h>
#include <geometry/eda_angle.h>
#include <geometry/geometry_utils.h>
#include <math/vector2d.h>
#include <math/box2.h>
#include <wx/string.h>
class SHAPE_LINE_CHAIN;
class SHAPE_POLY_SET;
/**
* Lists all supported shapes.
@ -232,6 +234,39 @@ public:
return BBox( 0 ).Centre(); // if nothing better is available....
}
/**
* Returns the minimum distance from a given point to this shape.
* Always returns zero if the point is inside a closed shape and aOutlineOnly is false.
*
* @param aP is the point to test
* @param aOutlineOnly can be set to true to measure the distance to the outline of the shape
* @return the distance from the shape to aP
*/
virtual int Distance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
/**
* @see SHAPE::Distance
*/
virtual SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
/**
* Check if point \a aP lies inside a closed shape. Always returns false if this shape is not closed.
*
* @param aPt point to check
* @param aUseBBoxCache gives better performance if the bounding box caches have been
* generated.
* @return true if the point is inside the shape (edge is not treated as being inside).
*/
virtual bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const;
/**
* Fills a SHAPE_POLY_SET with a polygon representation of this shape.
* @param aBuffer [out] will be filled with the polygonal representation of this shape.
* @param aError controls the maximum allowed deviation when converting rounded shapes to segments
* @param aErrorLoc controls where the error is placed when approximating rounded shapes
*/
virtual void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, ERROR_LOC aErrorLoc ) const = 0;
/**
* @param aCenter is the rotation center.
* @param aAngle rotation angle.
@ -288,18 +323,9 @@ public:
virtual bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
VECTOR2I* aLocation = nullptr ) const override;
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
SEG::ecoord SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly = false ) const override;
/**
* Check if point \a 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 performance 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;
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0, bool aUseBBoxCache = false ) const override;
/**
* Check if point \a aP lies on an edge or vertex of the line chain.
@ -324,6 +350,10 @@ public:
virtual bool IsClosed() const = 0;
virtual BOX2I* GetCachedBBox() const { return nullptr; }
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override
{}
};
#endif // __SHAPE_H

View File

@ -244,6 +244,9 @@ public:
&& ( aArc.m_width == m_width );
}
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ) const
{

View File

@ -137,6 +137,9 @@ public:
virtual const std::string Format( bool aCplusPlus = true ) const override;
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
CIRCLE m_circle;
};

View File

@ -154,7 +154,8 @@ public:
std::copy( m_shapes.begin(), m_shapes.end(), std::back_inserter( aSubshapes ) );
}
bool ConvertToSimplePolygon( SHAPE_SIMPLE* aOut ) const;
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
BOX2I m_cachedBBox;

View File

@ -456,14 +456,6 @@ public:
return &m_bbox;
}
/**
* Compute the minimum distance between the line chain and a point \a aP.
*
* @param aP the point.
* @return minimum distance.
*/
int Distance( const VECTOR2I& aP, bool aOutlineOnly = false ) const;
/**
* Reverse point order in the line chain.
*
@ -875,6 +867,9 @@ public:
virtual size_t GetPointCount() const override { return PointCount(); }
virtual size_t GetSegmentCount() const override { return SegmentCount(); }
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
protected:
friend class SHAPE_POLY_SET;

View File

@ -75,6 +75,9 @@ public:
{
return false;
}
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override {}
};
#endif

View File

@ -1203,6 +1203,9 @@ public:
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX* aClosestVertex = nullptr,
int aClearance = 0 ) const;
bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0,
bool aUseBBoxCache = false ) const override;
/**
* Construct BBoxCaches for Contains(), below.
*
@ -1403,6 +1406,12 @@ public:
*/
static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths, bool aReverseOrientation = false, bool aEvenOdd = false );
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override
{
aBuffer.Append( *this );
}
private:
enum DROP_TRIANGULATION_FLAG { SINGLETON };

View File

@ -190,6 +190,9 @@ public:
virtual const std::string Format( bool aCplusPlus = true ) const override;
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
VECTOR2I m_p0; ///< Top-left corner
int m_w; ///< Width

View File

@ -161,6 +161,9 @@ public:
virtual const std::string Format( bool aCplusPlus = true ) const override;
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
SEG m_seg;
int m_width;

View File

@ -180,6 +180,9 @@ public:
return true;
}
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const override;
private:
// vertices
SHAPE_LINE_CHAIN m_points;

View File

@ -30,6 +30,11 @@
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_compound.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_simple.h>
#include <convert_basic_shapes_to_polygon.h>
bool SHAPE::Parse( std::stringstream& aStream )
{
@ -75,3 +80,40 @@ int SHAPE::GetClearance( const SHAPE* aOther ) const
return actual_clearance;
}
int SHAPE::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
{
return sqrt( SquaredDistance( aP, aOutlineOnly ) );
}
SEG::ecoord SHAPE::SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly ) const
{
SHAPE_POLY_SET buffer;
TransformToPolygon( buffer, 0, ERROR_INSIDE );
if( buffer.OutlineCount() < 1 )
return VECTOR2I::ECOORD_MAX;
return buffer.COutline( 0 ).SquaredDistance( aP, aOutlineOnly );
}
bool SHAPE::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
{
SHAPE_POLY_SET buffer;
TransformToPolygon( buffer, aAccuracy, ERROR_INSIDE );
if( buffer.OutlineCount() < 1 )
return false;
return buffer.COutline( 0 ).PointInside( aPt, aAccuracy, aUseBBoxCache );
}
void SHAPE_SIMPLE::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
aBuffer.AddOutline( m_points );
}

View File

@ -29,6 +29,7 @@
#include <geometry/seg.h> // for SEG
#include <geometry/shape_arc.h>
#include <geometry/shape_line_chain.h>
#include <convert_basic_shapes_to_polygon.h>
#include <trigo.h>
@ -610,3 +611,9 @@ bool SHAPE_ARC::sliceContainsPoint( const VECTOR2I& p ) const
return alg::within_wrapped_range( phi.AsDegrees(), sa.AsDegrees(), ea.AsDegrees(), 360.0 );
}
void SHAPE_ARC::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, ERROR_LOC aErrorLoc ) const
{
TransformArcToPolygon( aBuffer, m_start, m_mid, m_end, m_width, aError, aErrorLoc );
}

View File

@ -155,7 +155,9 @@ bool SHAPE_COMPOUND::Collide( const SEG& aSeg, int aClearance, int* aActual,
}
bool SHAPE_COMPOUND::ConvertToSimplePolygon( SHAPE_SIMPLE* aOut ) const
void SHAPE_COMPOUND::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
return false;
for( SHAPE* item : m_shapes )
item->TransformToPolygon( aBuffer, aError, aErrorLoc );
}

View File

@ -34,6 +34,7 @@
#include <core/kicad_algo.h> // for alg::run_on_pair
#include <geometry/seg.h> // for SEG, OPT_VECTOR2I
#include <geometry/shape_line_chain.h>
#include <geometry/shape_poly_set.h>
#include <math/box2.h> // for BOX2I
#include <math/util.h> // for rescale
#include <math/vector2d.h> // for VECTOR2, VECTOR2I
@ -875,12 +876,6 @@ void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
}
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const
{
return sqrt( SquaredDistance( aP, aOutlineOnly ) );
}
SEG::ecoord SHAPE_LINE_CHAIN_BASE::SquaredDistance( const VECTOR2I& aP, bool aOutlineOnly ) const
{
ecoord d = VECTOR2I::ECOORD_MAX;
@ -2133,6 +2128,13 @@ double SHAPE_LINE_CHAIN::Area( bool aAbsolute ) const
}
void SHAPE_LINE_CHAIN::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
aBuffer.AddOutline( *this );
}
SHAPE_LINE_CHAIN::POINT_INSIDE_TRACKER::POINT_INSIDE_TRACKER( const VECTOR2I& aPoint ) :
m_point( aPoint ),
m_finished( false ),

View File

@ -3065,3 +3065,15 @@ SHAPE_POLY_SET::BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAI
return result;
}
bool SHAPE_POLY_SET::PointInside( const VECTOR2I& aPt, int aAccuracy, bool aUseBBoxCache ) const
{
for( int idx = 0; idx < OutlineCount(); idx++ )
{
if( COutline( idx ).PointInside( aPt, aAccuracy, aUseBBoxCache ) )
return true;
}
return false;
}

View File

@ -25,6 +25,7 @@
#include <geometry/shape_rect.h>
#include <convert_basic_shapes_to_polygon.h>
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
{
@ -107,3 +108,17 @@ const std::string SHAPE_RECT::Format( bool aCplusPlus ) const
return ss.str();
}
void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
int idx = aBuffer.NewOutline();
SHAPE_LINE_CHAIN& outline = aBuffer.Outline( idx );
outline.Append( m_p0 );
outline.Append( { m_p0.x + m_w, m_p0.y } );
outline.Append( { m_p0.x + m_w, m_p0.y + m_h } );
outline.Append( { m_p0.x, m_p0.y + m_h } );
outline.SetClosed( true );
}

View File

@ -26,6 +26,7 @@
#include <geometry/shape_segment.h>
#include <geometry/shape_circle.h>
#include <convert_basic_shapes_to_polygon.h>
const std::string SHAPE_SEGMENT::Format( bool aCplusPlus ) const
{
@ -87,6 +88,14 @@ const std::string SHAPE_CIRCLE::Format( bool aCplusPlus ) const
return ss.str();
}
void SHAPE_CIRCLE::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
TransformCircleToPolygon( aBuffer, m_circle.Center, m_circle.Radius, aError, aErrorLoc );
}
bool SHAPE_SEGMENT::Is45Degree( EDA_ANGLE aTollerance ) const
{
EDA_ANGLE mag = EDA_ANGLE( m_seg.A - m_seg.B ).Normalize180();
@ -102,3 +111,9 @@ bool SHAPE_SEGMENT::Is45Degree( EDA_ANGLE aTollerance ) const
return false;
}
void SHAPE_SEGMENT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
ERROR_LOC aErrorLoc ) const
{
TransformOvalToPolygon( aBuffer, m_seg.A, m_seg.B, m_width, aError, aErrorLoc );
}