/*####################################
 #                                   #
 #    MATEMATICKE FUNKCE A TRIDY     #
 #####################################
 */


#pragma once
#ifndef MATH_FUNC_H
#define MATH_FUNC_H


#include "common.h"

// ################################

typedef long double distance_t;

#include <cmath>

// ################################

template<typename T>
class vector_2d {
public:
    T x, y;

    // --------------------------------

    vector_2d()
    {
        x = 0, y = 0;
    }

    // --------------------------------

    vector_2d(const T x_, const T y_)
    {
        x = x_;
        y = y_;
    }

    // --------------------------------

    vector_2d<T> operator+(const vector_2d& d) const
    {
        return vector_2d<T>(x+d.x, y+d.y);
    }

    // --------------------------------

    vector_2d<T> operator-(const vector_2d& d) const
    {
        return vector_2d<T>(x-d.x, y-d.y);
    }

    // --------------------------------

    const T operator*(const vector_2d& d) const
    {
        return x*d.x + y*d.y;
    }

    // --------------------------------

    vector_2d<T> operator*(const T coef_) const
    {
        return vector_2d<T>(x*coef_, y*coef_);
    }

    // --------------------------------

    vector_2d<T> operator/(const T coef_) const
    {
        return vector_2d<T>(x/coef_, y/coef_);
    }

    // --------------------------------

    bool operator == (const vector_2d<T>& d) const
    {
        return x == d.x && y == d.y;
    }

    // --------------------------------

    bool operator != (const vector_2d<T>& d) const
    {
        return !(*this == d);
    }

    // --------------------------------

    const T squaredNorm(void) const
    {
        return (x*x)+(y*y);
    }

    // --------------------------------

    const long double squaredNormDouble(void) const
    {
        return ((long double)x*(long double)x)+((long double)y*(long double)y);
    }

    // --------------------------------

    const T norm(void) const
    {
        return (T) sqrt((long double)squaredNormDouble());
    };

    // --------------------------------

    vector_2d<T> normedVector(void) const
    {
        return (*this) / norm();
    }

    // --------------------------------

    vector_2d<T> rotateLeft(void)
    {
        return vector_2d<T>(-y, x);
    }

};

// ################################

template<typename T, typename V>
const vector_2d<T> convert_vec(const vector_2d<V> vec)
{
    return vector_2d<T>((T)vec.x, (T)vec.y);
}

// ################################

template<typename T>
struct halfplane
{
    vector_2d<T> normalVector;
    T affinity;

    halfplane(const vector_2d<T>& nv, const T af)
    {
        normalVector = nv, affinity = af;
    }
};

// ################################

/* konstanty */

#define PI (3.1415926535897932384626433832795L)
#define PI2 (2.0L * PI)

// ################################

template<typename T>
T normalizeAngle(const T val)
{
    return fmod(val, (T)PI2);
}

template<typename D>
vector_2d<D> rotate_vec(D distance, D angle)
{
    angle = angle % 360;
    return vector_2d<D>((D)((double)distance * cos((double)angle / 180.0L * PI)), 
        (D)((double)distance * sin((double)angle / 180.0L * PI)));
}

double rand01(void);
unsigned long long random(void);

typedef double dist_t;
typedef double weight_t;
typedef vector_2d<dist_t> vector_dist_t;
typedef vector_2d<double> vector_dbl_t;


#endif