284 lines
9.0 KiB
C++
284 lines
9.0 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2018 CERN
|
|
* Copyright (C) 2019-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#ifndef __SHAPE_ARC_H
|
|
#define __SHAPE_ARC_H
|
|
|
|
#include <geometry/shape.h>
|
|
#include <base_units.h>
|
|
#include <math/vector2d.h> // for VECTOR2I
|
|
#include <geometry/eda_angle.h>
|
|
|
|
class SHAPE_LINE_CHAIN;
|
|
|
|
class SHAPE_ARC : public SHAPE
|
|
{
|
|
public:
|
|
|
|
SHAPE_ARC() :
|
|
SHAPE( SH_ARC ),
|
|
m_width( 0 ),
|
|
m_radius( 0 )
|
|
{};
|
|
|
|
/**
|
|
* Construct and arc using center, start, angle.
|
|
*
|
|
* Center and angle are used to calculate the mid and end points of the arc, and are not
|
|
* stored.
|
|
*
|
|
* @param aArcCenter is the arc center.
|
|
* @param aArcStartPoint is the arc start point.
|
|
* @param aCenterAngle is the arc angle.
|
|
* @param aWidth is the arc line thickness.
|
|
*/
|
|
SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint,
|
|
const EDA_ANGLE& aCenterAngle, int aWidth = 0 );
|
|
|
|
/**
|
|
* @param aArcStart is the arc start point.
|
|
* @param aArcEnd is the arc end point.
|
|
* @param aArcMid is the arc mid point.
|
|
* @param aWidth is the arc line thickness.
|
|
*/
|
|
SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid, const VECTOR2I& aArcEnd,
|
|
int aWidth );
|
|
|
|
/**
|
|
* Build a SHAPE_ARC which is tangent to two segments and a given radius.
|
|
*
|
|
* @param aSegmentA is the first segment
|
|
* @param aSegmentB is the second segment
|
|
* @param aRadius is the arc radius
|
|
* @param aWidth is the arc line thickness
|
|
*/
|
|
SHAPE_ARC( const SEG& aSegmentA, const SEG& aSegmentB, int aRadius, int aWidth = 0 );
|
|
|
|
SHAPE_ARC( const SHAPE_ARC& aOther );
|
|
|
|
virtual ~SHAPE_ARC() {}
|
|
|
|
SHAPE* Clone() const override
|
|
{
|
|
return new SHAPE_ARC( *this );
|
|
}
|
|
|
|
/**
|
|
* Construct this arc from the given start, end and angle.
|
|
*
|
|
* @param aStart is the arc starting point
|
|
* @param aEnd is the arc endpoint
|
|
* @param aAngle is the arc included angle
|
|
* @param aWidth is the arc line thickness
|
|
* @return this arc.
|
|
*/
|
|
SHAPE_ARC& ConstructFromStartEndAngle( const VECTOR2I& aStart, const VECTOR2I& aEnd,
|
|
const EDA_ANGLE& aAngle, double aWidth = 0 );
|
|
|
|
/**
|
|
* Constructs this arc from the given start, end and center.
|
|
* @param aStart is the arc starting point
|
|
* @param aEnd is the arc endpoint
|
|
* @param aCenter is the arc center
|
|
* @param aClockwise determines which of the two solutions to construct
|
|
* @param aWidth is the arc line thickness
|
|
* @return *this
|
|
*/
|
|
SHAPE_ARC& ConstructFromStartEndCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd,
|
|
const VECTOR2I& aCenter, bool aClockwise = false,
|
|
double aWidth = 0 );
|
|
|
|
const VECTOR2I& GetP0() const { return m_start; }
|
|
const VECTOR2I& GetP1() const { return m_end; }
|
|
const VECTOR2I& GetArcMid() const { return m_mid; }
|
|
const VECTOR2I& GetCenter() const;
|
|
|
|
const BOX2I BBox( int aClearance = 0 ) const override;
|
|
|
|
VECTOR2I NearestPoint( const VECTOR2I& aP ) const;
|
|
|
|
bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
|
|
VECTOR2I* aLocation = nullptr ) const override;
|
|
bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr,
|
|
VECTOR2I* aLocation = nullptr ) const override;
|
|
|
|
|
|
bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
|
|
VECTOR2I* aLocation = nullptr ) const override
|
|
{
|
|
return SHAPE::Collide( aShape, aClearance, aActual, aLocation );
|
|
}
|
|
|
|
/**
|
|
* Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
|
|
* Ignores arc width.
|
|
*
|
|
* @param aSeg Line to intersect against (treated as an infinite line)
|
|
* @param aIpsBuffer Buffer to store the resulting intersection points (if any)
|
|
* @return Number of intersection points found
|
|
*/
|
|
int IntersectLine( const SEG& aSeg, std::vector<VECTOR2I>* aIpsBuffer ) const;
|
|
|
|
/**
|
|
* Find intersection points between this arc and aArc. Ignores arc width.
|
|
*
|
|
* @param aSeg
|
|
* @param aIpsBuffer Buffer to store the resulting intersection points (if any)
|
|
* @return Number of intersection points found
|
|
*/
|
|
int Intersect( const SHAPE_ARC& aArc, std::vector<VECTOR2I>* aIpsBuffer ) const;
|
|
|
|
void SetWidth( int aWidth )
|
|
{
|
|
m_width = aWidth;
|
|
}
|
|
|
|
int GetWidth() const
|
|
{
|
|
return m_width;
|
|
}
|
|
|
|
bool IsSolid() const override
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void Move( const VECTOR2I& aVector ) override;
|
|
|
|
/**
|
|
* Rotate the arc by a given angle about a point.
|
|
*
|
|
* @param aCenter is the rotation center.
|
|
* @param aAngle rotation angle.
|
|
*/
|
|
void Rotate( const EDA_ANGLE& aAngle, const VECTOR2I& aCenter ) override;
|
|
|
|
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } );
|
|
|
|
void Mirror( const SEG& axis );
|
|
|
|
void Reverse();
|
|
|
|
SHAPE_ARC Reversed() const;
|
|
|
|
double GetRadius() const;
|
|
|
|
SEG GetChord() const
|
|
{
|
|
return SEG( m_start, m_end );
|
|
}
|
|
|
|
/**
|
|
* @return the central angle of the arc shape, normalized between 0..360 deg.
|
|
*/
|
|
EDA_ANGLE GetCentralAngle() const;
|
|
|
|
/**
|
|
* @return the start angle of the arc shape, normalized between 0..360 deg.
|
|
*/
|
|
EDA_ANGLE GetStartAngle() const;
|
|
|
|
/**
|
|
* @return the end angle of the arc shape, normalized between 0..360 deg.
|
|
*/
|
|
EDA_ANGLE GetEndAngle() const;
|
|
|
|
/**
|
|
* @return the length of the arc shape.
|
|
*/
|
|
double GetLength() const;
|
|
|
|
/**
|
|
* @note The default is #ARC_HIGH_DEF in Pcbnew units. This is to allow common geometry
|
|
* collision functions. Other programs should call this using explicit accuracy
|
|
* values.
|
|
*
|
|
* @todo Unify KiCad internal units.
|
|
*
|
|
* @return a default accuracy value for ConvertToPolyline() to build the polyline.
|
|
*/
|
|
static double DefaultAccuracyForPCB(){ return 0.005 * PCB_IU_PER_MM; }
|
|
|
|
/**
|
|
* Construct a SHAPE_LINE_CHAIN of segments from a given arc.
|
|
*
|
|
* @note The default is #ARC_HIGH_DEF in Pcbnew units. This is to allow common geometry
|
|
* collision functions. Other programs should call this using explicit accuracy
|
|
* values.
|
|
*
|
|
* @todo Unify KiCad internal units.
|
|
*
|
|
* @param aAccuracy maximum divergence from true arc given in internal units.
|
|
* @param aEffectiveAccuracy is the actual divergence from true arc given.
|
|
* the approximation error is between -aEffectiveAccuracy/2 and +aEffectiveAccuracy/2
|
|
* in internal units
|
|
* @return a #SHAPE_LINE_CHAIN.
|
|
*/
|
|
const SHAPE_LINE_CHAIN ConvertToPolyline( double aAccuracy = DefaultAccuracyForPCB(),
|
|
double* aEffectiveAccuracy = nullptr ) const;
|
|
|
|
bool operator==( SHAPE_ARC const& aArc ) const
|
|
{
|
|
return ( aArc.m_start == m_start ) && ( aArc.m_end == m_end ) && ( aArc.m_mid == m_mid )
|
|
&& ( aArc.m_width == m_width );
|
|
}
|
|
|
|
void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
|
|
ERROR_LOC aErrorLoc ) const override;
|
|
|
|
/**
|
|
* @return true if the arc is counter-clockwise.
|
|
*/
|
|
bool IsCCW() const
|
|
{
|
|
VECTOR2I v1 = m_end - m_mid;
|
|
VECTOR2I v2 = m_start - m_mid;
|
|
|
|
return v1.Cross( v2 ) > 0;
|
|
}
|
|
|
|
bool IsClockwise() const { return !IsCCW(); }
|
|
|
|
private:
|
|
void update_values();
|
|
|
|
bool sliceContainsPoint( const VECTOR2I& p ) const;
|
|
|
|
private:
|
|
VECTOR2I m_start;
|
|
VECTOR2I m_mid;
|
|
VECTOR2I m_end;
|
|
int m_width;
|
|
|
|
BOX2I m_bbox; // Calculated value
|
|
VECTOR2I m_center; // Calculated value
|
|
double m_radius; // Calculated value
|
|
};
|
|
|
|
// Required for Boost Test BOOST_CHECK_EQUAL:
|
|
std::ostream& operator<<( std::ostream& aStream, const SHAPE_ARC& aArc );
|
|
|
|
#endif
|