Commit c5973eb8 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Add documentation to .h files and update code formatting

parent c25acdbb
Loading
Loading
Loading
Loading
+223 −135
Original line number Diff line number Diff line
@@ -11,54 +11,69 @@ TEARDROP::TEARDROP()
    m_type = TEARDROP_NONE;
}

bool TEARDROP::Create(TRACK &aTrack, ENDPOINT_T endPoint, TEARDROP_TYPE type = TEARDROP_STRAIGHT)

bool TEARDROP::Create(TRACK& aTrack, ENDPOINT_T aEndPoint, TEARDROP_TYPE aType = TEARDROP_STRAIGHT )
{
    bool result = false;

    BOARD_CONNECTED_ITEM *anObject = GetObjectOnEnd(aTrack, endPoint);
    BOARD_CONNECTED_ITEM* object = getObjectOnEnd( aTrack, aEndPoint );
    VIA* aVia = NULL;
    if (anObject == NULL) {

    if( object == NULL )
    {
        return false;
    }
    else {
        switch (anObject->Type()) {
    else
    {
        switch( object->Type() )
        {
        case PCB_VIA_T:
            aVia = dynamic_cast<VIA *>(anObject);
            aVia = dynamic_cast<VIA*>( object );
            break;

        case PCB_PAD_T:
            aVia = new VIA( NULL );
            aVia->SetLayer(anObject->GetLayer());
            aVia->SetPosition(anObject->GetPosition());
            aVia->SetWidth(2 * dynamic_cast<D_PAD *>(anObject)->GetBoundingRadius());

            aVia->SetLayer( object->GetLayer() );
            aVia->SetPosition( object->GetPosition() );
            aVia->SetWidth( 2 * dynamic_cast<D_PAD*>( object )->GetBoundingRadius() );
            break;

        default:
            break;
        }
    }

    if (type == TEARDROP_STRAIGHT) {
        result = StraightSegments(aTrack, *aVia, 100);
    if( aType == TEARDROP_STRAIGHT )
    {
        result = straightSegments( aTrack, *aVia, 100 );
    }
    else if (type == TEARDROP_CURVED) {
        result = CurvedSegments(aTrack, *aVia);
    else if( aType == TEARDROP_CURVED )
    {
        result = curvedSegments( aTrack, *aVia );
    }

    return result;
}

bool TEARDROP::SetVector(TRACK &aTrack, const VIA & aVia, VECTOR2I &startPoint, VECTOR2I &endPoint)

bool TEARDROP::setVector(TRACK& aTrack, const VIA& aVia, VECTOR2I& aStartPoint, VECTOR2I& aEndPoint )
{
    // Decide which end of the track is inside via and set this point as end of vector
    STATUS_FLAGS status = aTrack.IsPointOnEnds( aVia.GetPosition(), aVia.GetWidth() / 2 );
    if (status == STARTPOINT) {
        startPoint = aTrack.GetEnd();
        endPoint = aTrack.GetStart();

    if( status == STARTPOINT )
    {
        aStartPoint = aTrack.GetEnd();
        aEndPoint = aTrack.GetStart();
    }
    else if (status == ENDPOINT) {
        startPoint = aTrack.GetStart();
        endPoint = aTrack.GetEnd();
    else if( status == ENDPOINT )
    {
        aStartPoint = aTrack.GetStart();
        aEndPoint = aTrack.GetEnd();
    }
    else {
    else
    {
        // The via is too far from any end or the track is too short
        return false;
    }
@@ -66,21 +81,24 @@ bool TEARDROP::SetVector(TRACK &aTrack, const VIA & aVia, VECTOR2I &startPoint,
    return true;
}

bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia)

bool TEARDROP::curvedSegments( TRACK& aTrack, const VIA& aVia )
{
    VECTOR2I    startPoint( 0, 0 );
    VECTOR2I    endPoint( 0, 0 );
    std::vector<VECTOR2I> upperSegment;
    std::vector<VECTOR2I>   lowerSegment;

    if ( !SetVector(aTrack, aVia, startPoint, endPoint) ) {
    if( !setVector( aTrack, aVia, startPoint, endPoint ) )
    {
        return false;
    }

    // Check that the track is not too short
    double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2);
    double minLength = (150 * aVia.GetWidth() / 2) / 100;
    if (segOutsideVia < minLength) {

    if( segOutsideVia < minLength )
    {
        return false;
    }

@@ -88,65 +106,94 @@ bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia)
    VECTOR2I    viaCenter( aVia.GetPosition().x, aVia.GetPosition().y );
    VECTOR2I    apertureUpper( 0, 0 );
    VECTOR2I    apertureLower( 0, 0 );

    double radius = (aVia.GetWidth() / 2) - (aTrack.GetWidth() / 2);
    double rotationAngle = VECTOR2I( startPoint - endPoint ).Angle();

    // Calculate the segments of deltoid composing the outline of a teardrop
    for ( int i = 10; i <= 60; i = i + 10 ) {
        PointOnCurve(i, radius, point);
    for( int i = 0; i <= 60; i = i + 10 )
    {
        pointOnCurve( i, radius, point );
        point = point.Rotate( rotationAngle );
        point += viaCenter;
        m_coordinates.push_back( point );
        if (i == 50) {

        if( i == 50 )
        {
            apertureUpper = point;
        }
    }
    for ( int i = 300; i <= 350; i = i + 10 ) {
        PointOnCurve(i, radius, point);

    for( int i = 300; i <= 360; i = i + 10 )
    {
        pointOnCurve( i, radius, point );
        point = point.Rotate( rotationAngle );
        point += viaCenter;
        m_coordinates.push_back( point );
        if (i == 340) {

        if( i == 340 )
        {
            apertureLower = point;
        }
    }

    // Calculate the number of segments needed to fill the area inside the teardrop
    if (aVia.GetWidth() / 2 > 2 * aTrack.GetWidth()) {
    if( aVia.GetWidth() / 2 > 2 * aTrack.GetWidth() )
    {
        // First, calculate the distance between two points on both sides of the track and
        // number of iterations required to fill the zone
        SEG aperture( apertureUpper, apertureLower );
        int numSegments = aperture.Length() / aTrack.GetWidth();

        int delta = radius / numSegments;
        for (int iteration = 0; iteration < numSegments; iteration++) {

        // Second, fill the inward teardrop area
        for( int iteration = 0; iteration < numSegments; iteration++ )
        {
            radius = radius - delta;
            for ( int i = 10; i <= 60; i = i + 10 ) {
                PointOnCurve(i, radius, point);
            for( int i = 10; i <= 60; i = i + 10 )
            {
                pointOnCurve( i, radius, point );
                point = point.Rotate( rotationAngle );
                point += viaCenter;
                if (i == 10) {

                // Stop calculations in case the coordinates are inside the via
                if( i == 10 )
                {
                    int distance = SEG( viaCenter, point ).Length();
                    if (distance < aVia.GetWidth() / 2) {

                    if( distance < aVia.GetWidth() / 2 )
                    {
                        break;
                    }
                }
                m_coordinates.push_back( point );
            }

            lowerSegment.clear();
            for ( int i = 350; i >= 300; i = i - 10 ) {
                PointOnCurve(i, radius, point);
            for( int i = 350; i >= 300; i = i - 10 )
            {
                pointOnCurve( i, radius, point );
                point = point.Rotate( rotationAngle );
                point += viaCenter;
                if (i == 350) {

                // Stop calculations in case the coordinates are inside the via
                if( i == 350 )
                {
                    int distance = SEG( viaCenter, point ).Length();
                    if (distance < aVia.GetWidth() / 2) {

                    if( distance < aVia.GetWidth() / 2 )
                    {
                        break;
                    }
                }
                lowerSegment.push_back( point );
            }
            // Revert coordinates order
            for (std::vector<VECTOR2I>::reverse_iterator iter = lowerSegment.rbegin(); iter != lowerSegment.rend(); ++iter) {

            // Revert coordinates order. This is necessary to create tracks in correct order later on
            for( std::vector<VECTOR2I>::reverse_iterator iter = lowerSegment.rbegin();
                 iter != lowerSegment.rend();
                 ++iter )
            {
                m_coordinates.push_back( *iter );
            }
        }
@@ -155,27 +202,32 @@ bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia)
    return true;
}

bool TEARDROP::StraightSegments(TRACK &aTrack, const VIA &aVia, int distance = 100)

bool TEARDROP::straightSegments(TRACK& aTrack, const VIA& aVia, int aDistance = 100 )
{
    VECTOR2I    startPoint( 0, 0 );
    VECTOR2I    endPoint( 0, 0 );
    VECTOR2I    viaCenter( aVia.GetPosition().x, aVia.GetPosition().y );

    if ( !SetVector(aTrack, aVia, startPoint, endPoint) ) {
    if( !setVector( aTrack, aVia, startPoint, endPoint ) )
    {
        return false;
    }

    // Check that the track is not too short
    double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2);
    double minLength = (distance * aVia.GetWidth() / 2) / 100;
    if (segOutsideVia < minLength) {
    double minLength = (aDistance * aVia.GetWidth() / 2) / 100;

    if( segOutsideVia < minLength )
    {
        return false;
    }

    // Equation coefficients
    double r = (aVia.GetWidth() / 2) + ((distance * aVia.GetWidth()) / (2 *100));
    double r = (aVia.GetWidth() / 2) + ( (aDistance * aVia.GetWidth()) / (2 * 100) );
    double a = pow( (endPoint.x - startPoint.x), 2 ) + pow( (endPoint.y - startPoint.y), 2 );
    double b = 2 * (double)(endPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) + 2 * (double)(endPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y);
    double b = 2 * (double)(endPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) +
            2 * (double)(endPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y);
    double c = pow( (startPoint.x - viaCenter.x), 2 ) + pow( (startPoint.y - viaCenter.y), 2 ) - pow( r, 2 );
    double t = 2 * c / (-b + sqrt( b * b - 4 * a * c));

@@ -199,30 +251,36 @@ bool TEARDROP::StraightSegments(TRACK &aTrack, const VIA &aVia, int distance = 1

    // Calculate the number of segments needed to fill the area inside the teardrop
    std::vector<VECTOR2I> splitPoints;
    if (aVia.GetWidth() / 2 > 2 * aTrack.GetWidth()) {

    if( aVia.GetWidth() / 2 > 2 * aTrack.GetWidth() )
    {
        // First, calculate the intersection point of the circle and one hand of the teardrop
        r = aVia.GetWidth() / 2;
        a = pow( (upperPoint.x - startPoint.x), 2 ) + pow( (upperPoint.y - startPoint.y), 2 );
        b = 2 * (double)(upperPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) + 2 * (double)(upperPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y);
        b = 2 * (double)(upperPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) +
                2 * (double)(upperPoint.y - startPoint.y) * (double) (startPoint.y - viaCenter.y);
        c = pow( (startPoint.x - viaCenter.x), 2 ) + pow( (startPoint.y - viaCenter.y), 2 ) - pow( r, 2 );
        t = 2 * c / ( -b + sqrt( b * b - 4 * a * c ) );

        x = (upperPoint.x - startPoint.x) * t + startPoint.x;
        y = (upperPoint.y - startPoint.y) * t + startPoint.y;
        VECTOR2I intersectionPoint( (int) x, (int) y );

        // Second, calculate the distance between the given track and the intersection point
        SEG trackSegment(aTrack.GetStart().x, aTrack.GetStart().y, aTrack.GetEnd().x, aTrack.GetEnd().y);
        SEG trackSegment( aTrack.GetStart().x, aTrack.GetStart().y,
                aTrack.GetEnd().x, aTrack.GetEnd().y );
        int dist = trackSegment.LineDistance( intersectionPoint );
        int numSegments = 2 * dist / aTrack.GetWidth();

        // Third, subdivide the diameter of the via and build additional segments
        SEG segDiameter = SEG( upperPoint, lowerPoint );
        SplitSegment(segDiameter, numSegments, splitPoints);
        splitSegment( segDiameter, numSegments, splitPoints );
    }

    std::list<VECTOR2I> outlinePoints;
    outlinePoints.push_back( upperPoint );
    for (size_t i = 0; i < splitPoints.size(); i++) {
    for( size_t i = 0; i < splitPoints.size(); i++ )
    {
        outlinePoints.push_back( splitPoints[i] );
    }
    outlinePoints.push_back( lowerPoint );
@@ -230,30 +288,39 @@ bool TEARDROP::StraightSegments(TRACK &aTrack, const VIA &aVia, int distance = 1
    // Biuld triangles filling the teardrop
    int vertexNum = 0;
    std::list<VECTOR2I>::iterator iter = outlinePoints.begin();
    while ( iter != outlinePoints.end() ) {
        switch (vertexNum) {
    while( iter != outlinePoints.end() )
    {
        switch( vertexNum )
        {
        case 0:
            m_coordinates.push_back( linePoint );
            vertexNum++;
            break;

        case 1:
            m_coordinates.push_back( *iter );
            vertexNum++;
            iter++;
            break;

        case 2:
            m_coordinates.push_back( *iter );
            vertexNum = 0;
            iter++;
            break;
        default:break;

        default:
            break;
        }
    }

    // Append additional vertexies in order to finish last triangle
    if (vertexNum == 0) {
    if( vertexNum == 0 )
    {
        m_coordinates.push_back( linePoint );
    }
    else if (vertexNum == 2) {
    else if( vertexNum == 2 )
    {
        m_coordinates.push_back( m_coordinates[m_coordinates.size() - 3] );
        m_coordinates.push_back( linePoint );
    }
@@ -261,34 +328,47 @@ bool TEARDROP::StraightSegments(TRACK &aTrack, const VIA &aVia, int distance = 1
    return true;
}


// TODO: m_TracksConnected member is considered a temporary storage. Find another way to get an object
BOARD_CONNECTED_ITEM* TEARDROP::GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoint)
BOARD_CONNECTED_ITEM* TEARDROP::getObjectOnEnd(TRACK& aTrack, ENDPOINT_T aEndPoint )
{
    wxPoint trackPoint;
    BOARD_CONNECTED_ITEM* item = NULL;
    std::vector<TRACK*>::const_iterator iter;

    if (endPoint == ENDPOINT_START) {
    if( aEndPoint == ENDPOINT_START )
    {
        trackPoint = aTrack.GetStart();
    }
    else {
    else
    {
        trackPoint = aTrack.GetEnd();
    }

    // Check for vias first
    for (iter = aTrack.m_TracksConnected.begin(); iter != aTrack.m_TracksConnected.end(); ++iter) {
    for( iter = aTrack.m_TracksConnected.begin(); iter != aTrack.m_TracksConnected.end(); ++iter )
    {
        KICAD_T type = (*iter)->Type();
        bool hitTest = (*iter)->HitTest( trackPoint );
        if (type == PCB_VIA_T && hitTest == true) {

        if( (type == PCB_VIA_T) && (hitTest == true) )
        {
            item = *iter;
        }
    }

    // Check for pads if via was not found on this end of the track
    if (item == NULL) {
        for (std::vector<D_PAD *>::iterator iter = aTrack.m_PadsConnected.begin(); iter != aTrack.m_PadsConnected.end(); ++iter) {
    if( item == NULL )
    {
        for( std::vector<D_PAD*>::iterator iter = aTrack.m_PadsConnected.begin();
             iter != aTrack.m_PadsConnected.end();
             ++iter )
        {
            PAD_SHAPE_T shape = (*iter)->GetShape();
            bool hitTest = (*iter)->HitTest( trackPoint );
            if (shape == PAD_CIRCLE && hitTest == true) {

            if( shape == PAD_CIRCLE && hitTest == true )
            {
                item = *iter;
            }
        }
@@ -297,20 +377,28 @@ BOARD_CONNECTED_ITEM* TEARDROP::GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoin
    return item;
}

void TEARDROP::SplitSegment(const SEG &segment, int splits, std::vector<VECTOR2I> &points)

void TEARDROP::splitSegment( const SEG& aSegment, int aSplits, std::vector<VECTOR2I>& aPoints )
{
    int dX  = abs( (aSegment.A.x - aSegment.B.x) / aSplits );
    int dY  = abs( (aSegment.A.y - aSegment.B.y) / aSplits );

    if( aSegment.A.x > aSegment.B.x )
    {
    int dX = abs((segment.A.x - segment.B.x) / splits);
    int dY = abs((segment.A.y - segment.B.y) / splits);
    if (segment.A.x > segment.B.x) {
        dX = -dX;
    }
    if (segment.A.y > segment.B.y) {

    if( aSegment.A.y > aSegment.B.y )
    {
        dY = -dY;
    }

    VECTOR2I delta( dX, dY );
    points.push_back(segment.A + delta);
    aPoints.push_back( aSegment.A + delta );

    // The last point is excluded as it will coinside with already built tracks
    for (int i = 1; i < splits - 1; i++) {
        points.push_back(points.back() + delta);
    for( int i = 1; i < aSplits - 1; i++ )
    {
        aPoints.push_back( aPoints.back() + delta );
    }
}
+79 −42
Original line number Diff line number Diff line
@@ -17,92 +17,129 @@
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file class_teardrop.h
 * @brief Definitions for teardrops.
 */

#ifndef CLASS_TEARDROP_H
#define CLASS_TEARDROP_H

#include "class_track.h"
#include "geometry/seg.h"

/**
 * @brief The TEARDROP class
 * is base definition of a teardrop. It is intended for calculation and holding of points which
 * compose a teardrop. This class does not contain any methods which create actual tracks.
 */
class TEARDROP
{
public:
    TEARDROP();

    /**
     * @brief Defines the type of a teardrop.
     * @brief The TEARDROP_TYPE defines the type of a teardrop.
     */
    typedef enum {
    typedef enum
    {
        TEARDROP_NONE,      ///< The type is undefined
        TEARDROP_STRAIGHT,  ///< The teardrop is created by two straight segments
        TEARDROP_CURVED     ///< The teardrop is created by several segments approximating a curve
    } TEARDROP_TYPE;

    /**
     * @brief GetType returns the type of the teardrop.
     * @return TEARDROP_TYPE
     * @brief Function \a GetType
     * returns the type of the teardrop.
     * @return TEARDROP_TYPE - the type of the teardrop
     */
    TEARDROP_TYPE GetType() const { return m_type; }

    /**
     * @brief Function Create creates a teardrop(s) for a given track
     * @param aTrack
     * @return \a true in case the teardrops were successfully built and \a false otherwise
     * @brief Function \a Create
     * creates a teardrop(s) for a given track.
     * @param [in] aTrack is a track at which teardrop(s) should be created
     * @param [in] aEndPoint is an end point at which a teardrop should be created
     * @param [in] aType defines the type of a teardrop
     * @return bool - \a true in case the teardrops were successfully built and \a false otherwise
     */
    bool Create(TRACK &aTrack, ENDPOINT_T endPoint, TEARDROP_TYPE type);
    bool Create( TRACK& aTrack, ENDPOINT_T aEndPoint, TEARDROP_TYPE aType );

    void GetCoordinates(std::vector<VECTOR2I> &points) const {points = m_coordinates;}
    /**
     * @brief Function \a GetCoordinates
     * returns the coordinates of created teardrop.
     * @param [out] aPoints is a container for coordinates
     */
    void GetCoordinates( std::vector<VECTOR2I>& aPoints ) const { aPoints = m_coordinates; }

private:
    ///> Contains the type of teardrop
    /// Contains the type of teardrop
    TEARDROP_TYPE m_type;
    ///> \a m_upperSegment and \a m_lowerSegment contain coordinates of segments composing a teardrop
    std::vector<VECTOR2I> m_upperSegment;
    std::vector<VECTOR2I> m_lowerSegment;
    /// Contains the actual coordinates of teardrop
    std::vector<VECTOR2I> m_coordinates;

    /**
     * @brief Function \a CurvedSegments computes several points on deltoid curve and moves
     * these points along the vector defined by \a aTrack.
     * @brief Function \a curvedSegments
     * computes several points on deltoid curve and moves these points along the vector
     * defined by \a aTrack.
     *
     * This function computes the coordinates of points only and does not build actual track segments.
     * See deltiod description and its parametric equations on [wiki page](http://en.wikipedia.org/wiki/Deltoid_curve).
     * @param [in] aTrack defines a vector along which the curved segments should be built
     * @param [in] aVia used as the center of coordinates
     * @return \a true in case the segments were successfully built and \a false otherwise
     * @return bool - \a true in case the segments were successfully built and \a false otherwise
     */
    bool CurvedSegments(TRACK &aTrack, const VIA &aVia);
    bool curvedSegments( TRACK& aTrack, const VIA& aVia );

    /**
     * @brief Function \a StraightSegments builds two tangent lines for a circle from a givent point.
     * @brief Function \a straightSegments
     * builds two tangent lines to a circle from a givent point.
     *
     * This function computes the coordinates of points only and does not build actual track segments.
     * @param [in] aTrack defines a vector along which the segments should be built
     * @param [in] aVia represents a circle to which the segments should be built
     * @param [in] distance is distance ratio (in percent) from circle center in respect to its diameter
     * @return \a true in case the segments were successfully built and \a false otherwise
     * @param [in] aDistance is distance ratio (in percent) from circle center in respect to its diameter
     * @return bool - \a true in case the segments were successfully built and \a false otherwise
     */
    bool straightSegments( TRACK& aTrack, const VIA& aVia, int aDistance );

    /**
     * @brief Function \a setVector
     * creates a vector from \a aTrack directed into \a aVia.
     * @param [in] aTrack is used to create a vector
     * @param [in] aVia is an object to which the vector should be pointed to
     * @param [out] aStartPoint is start point of resulting vector
     * @param [out] aEndPoint is end point of resulting vector
     * @return bool - \a true in case the vector is created successfully and \a false otherwise
     */
    bool setVector( TRACK& aTrack, const VIA& aVia, VECTOR2I& aStartPoint, VECTOR2I& aEndPoint );

    /**
     * @brief Function \a getObjectOnEnd
     * returns an object (via or pad) at the given end of a track.
     * @param [in] aTrack is a reference track
     * @param [in] aEndPoint defines the end in question
     * @return BOARD_CONNECTED_ITEM - the object found or NULL otherwise
     */
    bool StraightSegments(TRACK &aTrack, const VIA &aVia, int distance);
    BOARD_CONNECTED_ITEM* getObjectOnEnd( TRACK& aTrack, ENDPOINT_T aEndPoint );

    /**
     * @brief Function SetVector creates a vector from \a aTrack directed into \a aVia
     * @param aTrack is used to create a vector
     * @param startPoint is start point of resulting vector
     * @param endPoint is end point of resulting vector
     * @return \a true in case the vector is created successfully and \a false otherwise
     * @brief Function \a splitSegment
     * splits a segment into given number of subsegments.
     * @param [in] aSegment is a segment to be split
     * @param [i] aSplits is a number of splits
     * @param [out] aPoints is a container for split points
     */
    bool SetVector(TRACK &aTrack, const VIA &aVia, VECTOR2I &startPoint, VECTOR2I &endPoint);
    void splitSegment( const SEG& aSegment, int aSplits, std::vector<VECTOR2I>& aPoints );

    BOARD_CONNECTED_ITEM* GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoint);
    void SplitSegment(const SEG &segment, int splits, std::vector<VECTOR2I> &points);
    inline void PointOnCurve(int angle, double radius, VECTOR2I &point) {
    /**
     * @brief Function \a pointOnCurve
     * calculates a single point on a deltoid curve.
     * @param [in] aAngle is an angle at which the point should be calculated
     * @param [in] aRadius is the radius of a rolling circle
     * @param [out] aPoint is a container for calculated point
     */
    inline void pointOnCurve( int aAngle, double aRadius, VECTOR2I& aPoint )
    {
        double coeff = M_PI / 180.0;
        point.x = 2 * radius * cos(coeff * angle) + radius * cos(2 * coeff * angle);
        point.y = 2 * radius * sin(coeff * angle) - radius * sin(2 * coeff * angle);

        aPoint.x = 2 * aRadius * cos( coeff * aAngle ) + aRadius * cos( 2 * coeff * aAngle );
        aPoint.y = 2 * aRadius * sin( coeff * aAngle ) - aRadius * sin( 2 * coeff * aAngle );
    }
};

+138 −89

File changed.

Preview size limit exceeded, changes collapsed.

+91 −20

File changed.

Preview size limit exceeded, changes collapsed.

+212 −114

File changed.

Preview size limit exceeded, changes collapsed.

Loading