/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2020 Tibor 'Igor2' Palinkas
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/camv-rnd
 *    lead developer: http://repo.hu/projects/camv-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#ifndef CAMV_GEO_H
#define CAMV_GEO_H


#define G2D_INLINE RND_INLINE

#include <math.h>
#include <opc89.h>
#include <librnd/core/global_typedefs.h>
#include <gengeo2d/common.h>

typedef funcops rnd_coord_t g2d_coord_t;
typedef funcops double g2d_calc_t;
typedef funcops double g2d_offs_t;
typedef funcops double g2d_angle_t;

#define G2D_COORD_MAX ((long)((1UL<<31)-1))
#define G2D_COORD_TOL2 (0.01)

G2D_INLINE g2d_coord_t g2d_round_coord(g2d_calc_t x_)
{
	double t, x = x_;

	if (x >= 0.0) {
		t = ceil(x);
		if (t - x > 0.5)
			t -= 1.0;
		return t;
	}

	t = ceil(-x);
	if ((t + x) > 0.5)
		t -= 1.0;
	return -t;
}

G2D_INLINE g2d_coord_t g2d_round_coord_down(g2d_calc_t x) { return floor(x); }
G2D_INLINE g2d_coord_t g2d_round_coord_up(g2d_calc_t x) { return ceil(x); }


G2D_INLINE opfunc g2d_calc_t g2d_calc_t_div_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a/b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_mul_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a*b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_sub_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a-b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_add_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a+b; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_neg(g2d_calc_t a) { return -a; }
G2D_INLINE opfunc int g2d_calc_t_eq_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a==b; }
G2D_INLINE opfunc int g2d_calc_t_neq_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a!=b; }
G2D_INLINE opfunc int g2d_calc_t_lt_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a<b; }
G2D_INLINE opfunc int g2d_calc_t_lte_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_calc_t_gt_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a>b; }
G2D_INLINE opfunc int g2d_calc_t_gte_g2d_calc_t(g2d_calc_t a, g2d_calc_t b) { return a>=b; }
G2D_INLINE opfunc double double_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_calc_t g2d_calc_t_mul_g2d_offs_t(g2d_calc_t a, g2d_offs_t b) { return a*b; }

G2D_INLINE opfunc g2d_coord_t g2d_coord_t_add_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a+b; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_sub_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a-b; }
G2D_INLINE opfunc int g2d_coord_t_eq_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a==b; }
G2D_INLINE opfunc int g2d_coord_t_neq_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a!=b; }
G2D_INLINE opfunc int g2d_coord_t_lt_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a<b; }
G2D_INLINE opfunc int g2d_coord_t_lte_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_coord_t_gt_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a>b; }
G2D_INLINE opfunc int g2d_coord_t_gte_g2d_coord_t(g2d_coord_t a, g2d_coord_t b) { return a>=b; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_neg(g2d_coord_t a) { return -a; }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t a) { return g2d_round_coord(a); }
G2D_INLINE opfunc g2d_coord_t g2d_coord_t_convfrom_int(int a) { return a; }

G2D_INLINE opfunc g2d_angle_t g2d_angle_t_add_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a+b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_sub_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a-b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_div_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a/b; }
G2D_INLINE opfunc int g2d_angle_t_eq_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a==b; }
G2D_INLINE opfunc int g2d_angle_t_lt_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a<b; }
G2D_INLINE opfunc int g2d_angle_t_lte_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a<=b; }
G2D_INLINE opfunc int g2d_angle_t_gt_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a>b; }
G2D_INLINE opfunc int g2d_angle_t_gte_g2d_angle_t(g2d_angle_t a, g2d_angle_t b) { return a>=b; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }
G2D_INLINE opfunc double double_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_neg(g2d_angle_t a) { return -a; }
G2D_INLINE opfunc g2d_angle_t g2d_angle_t_mul_g2d_offs_t(g2d_angle_t a, g2d_offs_t b) { return a*b; }

G2D_INLINE opfunc int g2d_offs_t_eq_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a == b; }
G2D_INLINE opfunc int g2d_offs_t_lt_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a < b; }
G2D_INLINE opfunc int g2d_offs_t_lte_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a <= b; }
G2D_INLINE opfunc int g2d_offs_t_gt_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a > b; }
G2D_INLINE opfunc int g2d_offs_t_gte_g2d_offs_t(g2d_offs_t a, g2d_offs_t b) { return a >= b; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_g2d_angle_t(g2d_angle_t a) { return a; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_double(double a) { return a; }
G2D_INLINE opfunc g2d_offs_t g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t a) { return a; }

G2D_INLINE g2d_calc_t g2d_sqrt(g2d_calc_t a) { return g2d_calc_t_convfrom_double(sqrt(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_calc_t g2d_cos(g2d_angle_t a) { return g2d_calc_t_convfrom_double(cos(double_convfrom_g2d_angle_t(a))); }
G2D_INLINE g2d_calc_t g2d_sin(g2d_angle_t a) { return g2d_calc_t_convfrom_double(sin(double_convfrom_g2d_angle_t(a))); }
G2D_INLINE g2d_angle_t g2d_acos(g2d_calc_t a) { return g2d_angle_t_convfrom_double(acos(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_angle_t g2d_asin(g2d_calc_t a) { return g2d_angle_t_convfrom_double(asin(double_convfrom_g2d_calc_t(a))); }
G2D_INLINE g2d_angle_t g2d_atan2(g2d_calc_t a, g2d_calc_t b) { return g2d_angle_t_convfrom_double(atan2(double_convfrom_g2d_calc_t(a), double_convfrom_g2d_calc_t(b))); }

#endif
