Преобразования на плоскости

Класс Spin2d предназначен для задания вращений. В первом конструкторе указывается угол вращения и логическая переменная degree, которая показывает в каких единицах задан угол: в радианах (false) или градусах (true). Во втором конструкторе указываются два направления: из которого ( a ) в который ( b ) делается поворот. Вектора могут иметь произвольную длину. В случае, когда хотя бы один из них нулевой, поворот будет неподвижный. Функция-член getAngle возвращает угол в радианах данного преобразования. Функция-член getReper показывает два вектора в которые перейдут вектора (1,0) и (0,1) после вращения. Оператор () делает преобразование для данного вектора. Оператор ~ возвращает преобразование обратное текущему. Оператор * осуществляет композицию двух преобразований ( вначале применяется правое, а потом - левое ). Имеется набор поворотов на фиксированные углы: Spin2d::d030 и т.д.

class Spin2d
{
    double x, y;

    Spin2d ( double a, double b ) : x(a), y(b) {}
public:
    Spin2d () : x(1.), y(0.) {}

    explicit Spin2d ( double a, bool degree = false );

    Spin2d ( const Vector2d & a, const Vector2d & b );

    double getAngle () const;

    void getReper ( Vector2d & ax, Vector2d & ay ) const
    {
        ax.x =  x; ax.y = y;
        ay.x = -y; ay.y = x;
    }

    Vector2d operator () ( const Vector2d & v ) const
    {
        return Vector2d ( v.x * x + v.y * y, v.y * x - v.x * y );
    }

    Spin2d operator ~ () const
    {
        return Spin2d ( x, -y );
    }

    friend Spin2d operator * ( const Spin2d & l, const Spin2d & r );

    static const Spin2d d030;
    static const Spin2d d045;
    static const Spin2d d060;
    static const Spin2d d090;
    static const Spin2d d120;
    static const Spin2d d135;
    static const Spin2d d150;
    static const Spin2d d180;
    static const Spin2d d210;
    static const Spin2d d225;
    static const Spin2d d240;
    static const Spin2d d270;
    static const Spin2d d300;
    static const Spin2d d315;
    static const Spin2d d330;
};

Класс Conform2d предназначен для осуществления преобразований подобия ( перенос, вращение, увеличение-уменьшение ). Он содержит три члена: коэффициент увеличения magn, объект spin для вращений и вектор trans для переноса. Операторы () делают преобразование для вектора, отрезка и прямой - вначале применяется вращение, потом увеличение, а затем добавляется вектор переноса. Оператор ~ возвращает преобразование обратное текущему. Оператор * осуществляет композицию двух преобразований ( вначале применяется правое, а потом - левое ).

class Conform2d
{
public:
    double   magn;
    Spin2d   spin;
    Vector2d trans;

    Conform2d () : trans (0.,0.), magn (1.) {}

    explicit Conform2d ( const Spin2d & s ) : spin ( s ), trans (0.,0.), magn (1.) {}

    Conform2d ( const Spin2d & s, const Vector2d & t, double m = 1. ) : spin(s), trans(t), magn(m) {}

    Def<Conform2d> operator~ () const
    {
        Def<Conform2d> res;
        if ( magn != 0 )
        {
            res.spin = ~spin;
            res.magn = 1. / magn;
            res.trans = (-res.magn) * res.spin ( trans );
            res.isDef = true;
        }
        return res;
    }

    Vector2d operator() ( const Vector2d & v ) const
    {
        return spin ( v ) * magn + trans;
    }

    Segment2d operator () ( const Segment2d & p ) const
    {
        return Segment2d ( (*this) ( p.a ), (*this) ( p.b ) );
    }

    Line2d operator() ( const Line2d & p ) const
    {
        const Vector2d v = spin ( p.norm );
        return Line2d ( v, magn * p.dist - v * trans );
    }
};

inline Conform2d operator * ( const Conform2d & l, const Conform2d & r )
{
    return Conform2d ( l.spin * r.spin, l ( r.trans ), l.magn * r.magn );
}

Класс LinTran2d осуществляет линейные преобразования, т.е. такие для которых выполняется формула
p ( x + y ) = p ( x ) + p ( y ). Операторы () делают преобразование вектора, отрезка и прямой. Оператор *= предназначен для умножения преобразования на число. Оператор ~ возвращает преобразование обратное данному. Оператор * преднаначен для композиции преобразований.

class LinTran2d
{
public:
    Vector2d x, y;

    LinTran2d () : x(1,0), y(0,1) {}

    LinTran2d ( const Vector2d & a, const Vector2d & b ) : x ( a ), y ( b ) {}
    
    explicit LinTran2d ( const Spin2d & spin )
    {
        spin.getReper ( x, y );
    }

    Vector2d operator () ( const Vector2d & p ) const
    {
        return Vector2d ( x * p, y * p );
    }

    Segment2d operator () ( const Segment2d & p ) const
    {
        return Segment2d ( (*this) ( p.a ), (*this) ( p.b ) );
    }

    Line2d operator() ( const Line2d & p ) const;

    LinTran2d & operator *= ( double d )
    {
        x *= d; y *= d; return *this;
    }

    Def<LinTran2d> operator ~ () const
    {
        Def<LinTran2d> res;
        double d = x % y;
        if ( d != 0 )
        {
            d = 1 / d;
            res.x.x =   y.y * d;
            res.x.y = - x.y * d;
            res.y.x = - y.x * d;
            res.y.y =   x.x * d;
            res.isDef = true;
        }
        return res;
    }

    friend inline LinTran2d operator * ( const LinTran2d & l, const LinTran2d & r )
    {
        return LinTran2d ( l.x.x * r.x + l.x.y * r.y, l.y.x * r.x + l.y.y * r.y );
    }
};

Класс Affin2d предназначет для реализации афинных преобразований и состоит из линейного преобразования ( t ) и сдвига ( s ). Операторы () делают преобразование вектора, отрезка и прямой. Оператор ~ возвращает преобразование обратное данному. Оператор * является умножением в смысле теории групп и не является коммутативным.

class Affin2d
{
public:
    LinTran2d t;
    Vector2d s;

    Affin2d () : s ( 0., 0. ) {}

    Affin2d ( const Vector2d & a, const Vector2d & b, const Vector2d & c ) : t ( a, b ), s ( c ) {}

    Affin2d ( const LinTran2d & a, const Vector2d & b ) : t ( a ), s ( b ) {}

    explicit Affin2d ( const Vector2d & v ) : s ( v ) {}

    explicit Affin2d ( const Spin2d & spin ) : t ( spin ), s ( 0., 0. ) {}

    explicit Affin2d ( const LinTran2d & tran ) : t ( tran ), s ( 0., 0. ) {}

    explicit Affin2d ( const Conform2d & conf ) : t ( conf.spin ), s ( conf.trans )
    {
        t *= conf.magn;
    }

    Vector2d operator () ( const Vector2d & p ) const
    {
        return t ( p ) + s;
    }

    Segment2d operator () ( const Segment2d & p ) const
    {
        return Segment2d ( (*this) ( p.a ), (*this) ( p.b ) );
    }

    Line2d operator() ( const Line2d & p ) const;

    Def<Affin2d> operator ~ () const
    {
        const Def<LinTran2d> lin ( ~t );
        return lin.isDef ? Affin2d ( lin, lin ( -s ) ) : Def<Affin2d>();
    }

    friend inline Affin2d operator * ( const Affin2d & l, const Affin2d & r )
    {
        return Affin2d ( l.t * r.t, l ( r.s ) );
    }

    friend inline Affin2d operator * ( const Affin2d & l, const LinTran2d & r )
    {
        return Affin2d ( l.t * r, l.s );
    }

    friend inline Affin2d operator * ( const LinTran2d & l, const Affin2d & r )
    {
        return Affin2d ( l * r.t, l ( r.s ) );
    }
};
Описание шаблона классов Def находится здесь.
Описание класса Vector2d находится здесь.
Описание классов Segment2d и Line2d находится здесь.

Примеры использования всех этих классов можно посмотреть в приложении DEMO.

Исходники находятся в файлах vector2d.h, vector2d.cpp.

Наверх