/*
  *** DO NOT EDIT ***
  This file has been generated by opc89, and will be overwritten.
  Please edit the source of this file instead.
*/

#ifndef G2D_VECT_H
#define G2D_VECT_H
#include <opc89.h>
#include <gengeo2d/prim.h>
#include <gengeo2d/common.h>


/****** API ******/

/* Construct a vector from two coordinates */
G2D_INLINE g2d_vect_t g2d_vect(g2d_coord_t x, g2d_coord_t y);
G2D_INLINE g2d_cvect_t g2d_cvect(g2d_calc_t x, g2d_calc_t y);

/* Noramalize the vector: keep direction but make it unit length */
G2D_INLINE g2d_cvect_t g2d__vect_normalize(g2d_cvect_t a);

/* Return the normal vector of v (with normalized the length) */
G2D_INLINE g2d_cvect_t g2d__vect_normal(g2d_cvect_t v);

/* Return a perpendicular vector to v (with the same length as v) */
G2D_INLINE g2d_cvect_t g2d__vect_perp(g2d_cvect_t v);

/* cross product */
G2D_INLINE g2d_calc_t g2d__crossp(g2d_cvect_t p1, g2d_cvect_t p2);

/* If src coord values are lower (down) or higher (up) than dst's,
   modify dst to match src */
G2D_INLINE void g2d_vect_bump_down(g2d_vect_t *dst, g2d_vect_t src);
G2D_INLINE void g2d_vect_bump_up(g2d_vect_t *dst, g2d_vect_t src);
G2D_INLINE void g2d__vect_bump_down(g2d_cvect_t *dst, g2d_cvect_t src);
G2D_INLINE void g2d__vect_bump_up(g2d_cvect_t *dst, g2d_cvect_t src);

/* Return the angle modulo 360, so it is -360..+360 */
G2D_INLINE g2d_angle_t g2d_normalize_angle(g2d_angle_t a);

/* Return the distance^2 or the distance between two points */
G2D_INLINE g2d_calc_t g2d__distance2(g2d_cvect_t p1, g2d_cvect_t p2);
G2D_INLINE g2d_calc_t g2d__distance(g2d_cvect_t p1, g2d_cvect_t p2);

/****** IMPLEMENTATION ******/

/*** operator functions ***/
G2D_INLINE opfunc int g2d_vect_t_eq_g2d_vect_t(g2d_vect_t a, g2d_vect_t b)
{
	return (a.x == b.x) && (a.y == b.y);
}

G2D_INLINE opfunc int g2d_cvect_t_eq_g2d_cvect_t(g2d_cvect_t a, g2d_cvect_t b)
{
	return (a.x == b.x) && (a.y == b.y);
}

G2D_INLINE opfunc g2d_cvect_t g2d_vect_t_add_g2d_vect_t(g2d_vect_t a, g2d_vect_t b)
{
#ifndef g2d_vect_t_ADD_g2d_vect_t
#define g2d_vect_t_ADD_g2d_vect_t(a,b) g2d_vect_t_add_g2d_vect_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = a.x + b.x;
	r.y = a.y + b.y;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_add_g2d_vect_t(g2d_cvect_t a, g2d_vect_t b)
{
#ifndef g2d_cvect_t_ADD_g2d_vect_t
#define g2d_cvect_t_ADD_g2d_vect_t(a,b) g2d_cvect_t_add_g2d_vect_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = a.x + b.x;
	r.y = a.y + b.y;
	return r;
}

G2D_INLINE opfunc g2d_vect_t g2d_vect_t_sub_g2d_vect_t(g2d_vect_t a, g2d_vect_t b)
{
	g2d_vect_t r;
	r.x = a.x - b.x;
	r.y = a.y - b.y;
	return r;
}


G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_add_g2d_cvect_t(g2d_cvect_t a, g2d_cvect_t b)
{
#ifndef g2d_cvect_t_ADD_g2d_cvect_t
#define g2d_cvect_t_ADD_g2d_cvect_t(a,b) g2d_cvect_t_add_g2d_cvect_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = a.x + b.x;
	r.y = a.y + b.y;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_sub_g2d_cvect_t(g2d_cvect_t a, g2d_cvect_t b)
{
	g2d_cvect_t r;
	r.x = a.x - b.x;
	r.y = a.y - b.y;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_mul_int(g2d_cvect_t v, int i)
{
#ifndef g2d_cvect_t_MUL_int
#define g2d_cvect_t_MUL_int(a,b) g2d_cvect_t_mul_int(b,a)
#endif


	g2d_cvect_t r;
	r.x = v.x * i;
	r.y = v.y * i;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_calc_t_mul_g2d_cvect_t(g2d_calc_t i, g2d_cvect_t v)
{
#ifndef g2d_calc_t_MUL_g2d_cvect_t
#define g2d_calc_t_MUL_g2d_cvect_t(a,b) g2d_calc_t_mul_g2d_cvect_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = v.x * i;
	r.y = v.y * i;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_mul_g2d_calc_t(g2d_cvect_t v, g2d_calc_t c)
{
#ifndef g2d_cvect_t_MUL_g2d_calc_t
#define g2d_cvect_t_MUL_g2d_calc_t(a,b) g2d_cvect_t_mul_g2d_calc_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = v.x * c;
	r.y = v.y * c;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_mul_g2d_coord_t(g2d_cvect_t v, g2d_coord_t c)
{
#ifndef g2d_cvect_t_MUL_g2d_coord_t
#define g2d_cvect_t_MUL_g2d_coord_t(a,b) g2d_cvect_t_mul_g2d_coord_t(b,a)
#endif


	g2d_cvect_t r;
	r.x = v.x * c;
	r.y = v.y * c;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t a)
{
	g2d_cvect_t cv;
	cv.x = a.x; cv.y = a.y;
	return cv;
}

G2D_INLINE opfunc g2d_vect_t g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t a)
{
	g2d_vect_t v;
	v.x = g2d_coord_t_convfrom_g2d_calc_t(a.x);
	v.y = g2d_coord_t_convfrom_g2d_calc_t(a.y);
	return v;
}

G2D_INLINE opfunc g2d_calc_t g2d_calc_t_convfrom_g2d_cvect_t(g2d_cvect_t a)
{
	return g2d_sqrt(a.x * a.x + a.y * a.y);
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_mul_g2d_offs_t(g2d_cvect_t v, g2d_offs_t o)
{
#ifndef g2d_cvect_t_MUL_g2d_offs_t
#define g2d_cvect_t_MUL_g2d_offs_t(a,b) g2d_cvect_t_mul_g2d_offs_t(b,a)
#endif


	return g2d_cvect(v.x*o, v.y*o);
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_neg(g2d_cvect_t v)
{
	v.x = -v.x;
	v.y = -v.y;
	return v;
}

G2D_INLINE opfunc g2d_cvect_t g2d_vect_t_sub_g2d_cvect_t(g2d_vect_t a, g2d_cvect_t b)
{
	g2d_cvect_t r = g2d_cvect(a.x, a.y);
	r.x = r.x - b.x;
	r.y = r.y - b.y;
	return r;
}

G2D_INLINE opfunc g2d_cvect_t g2d_cvect_t_sub_g2d_vect_t(g2d_cvect_t a, g2d_vect_t b)
{
	g2d_cvect_t r;
	r.x = a.x - b.x;
	r.y = a.y - b.y;
	return r;
}

/*** plain C89 funtions ***/
G2D_INLINE g2d_cvect_t g2d__vect_normalize(g2d_cvect_t a)
{
	g2d_cvect_t r;
	g2d_calc_t len = g2d_calc_t_convfrom_g2d_cvect_t(a); /* opc89 call: double_convfrom_g2d_cvect_t() */
	r.x = g2d_calc_t_div_g2d_calc_t(a.x  ,len);
	r.y = g2d_calc_t_div_g2d_calc_t(a.y  ,len);
	return r;
}

G2D_INLINE g2d_cvect_t g2d__vect_normal(g2d_cvect_t a)
{
	g2d_cvect_t r;
	g2d_calc_t len = g2d_calc_t_convfrom_g2d_cvect_t(a);
	r.x = g2d_calc_t_div_g2d_calc_t(a.y  ,len);
	r.y = g2d_calc_t_div_g2d_calc_t(g2d_calc_t_neg(a.x ) ,len);
	return r;
}

G2D_INLINE g2d_cvect_t g2d__vect_perp(g2d_cvect_t a)
{
	g2d_cvect_t r;
	r.x = a.y;
	r.y = g2d_calc_t_neg(a.x);
	return r;
}

G2D_INLINE void g2d__vect_bump_down(g2d_cvect_t *dst, g2d_cvect_t src)
{
	if (g2d_calc_t_lt_g2d_calc_t(src.x  ,dst->x))
		dst->x = src.x;
	if (g2d_calc_t_lt_g2d_calc_t(src.y  ,dst->y))
		dst->y = src.y;
}

G2D_INLINE void g2d__vect_bump_up(g2d_cvect_t *dst, g2d_cvect_t src)
{
	if (g2d_calc_t_gt_g2d_calc_t(src.x  ,dst->x))
		dst->x = src.x;
	if (g2d_calc_t_gt_g2d_calc_t(src.y  ,dst->y))
		dst->y = src.y;
}

G2D_INLINE void g2d_vect_bump_down(g2d_vect_t *dst, g2d_vect_t src)
{
	if (g2d_coord_t_lt_g2d_coord_t(src.x  ,dst->x))
		dst->x = src.x;
	if (g2d_coord_t_lt_g2d_coord_t(src.y  ,dst->y))
		dst->y = src.y;
}

G2D_INLINE void g2d_vect_bump_up(g2d_vect_t *dst, g2d_vect_t src)
{
	if (g2d_coord_t_gt_g2d_coord_t(src.x  ,dst->x))
		dst->x = src.x;
	if (g2d_coord_t_gt_g2d_coord_t(src.y  ,dst->y))
		dst->y = src.y;
}

G2D_INLINE g2d_vect_t g2d_vect(g2d_coord_t x, g2d_coord_t y)
{
	g2d_vect_t v;
	v.x = x; v.y = y;
	return v;
}

G2D_INLINE g2d_cvect_t g2d_cvect(g2d_calc_t x, g2d_calc_t y)
{
	g2d_cvect_t v;
	v.x = x; v.y = y;
	return v;
}

G2D_INLINE g2d_calc_t g2d__crossp(g2d_cvect_t p1, g2d_cvect_t p2)
{
	return (g2d_calc_t_sub_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(p1.x  ,p2.y ) ,g2d_calc_t_mul_g2d_calc_t(p1.y  ,p2.x)));
}

G2D_INLINE g2d_angle_t g2d_normalize_angle(g2d_angle_t a)
{

	const g2d_angle_t zero = g2d_angle_t_convfrom_double(0.0), pi2 = (g2d_angle_t_convfrom_double((G2D_PI)*2.0));

	while(g2d_angle_t_lt_g2d_angle_t(a  ,zero))
		a += (G2D_PI)*2.0;
	while(g2d_angle_t_gte_g2d_angle_t(a  ,pi2))
		a -= ((G2D_PI)*2.0);
	return a;
}

G2D_INLINE g2d_calc_t g2d__distance2(g2d_cvect_t p1, g2d_cvect_t p2)
{
	p1 = g2d_cvect_t_sub_g2d_cvect_t(p1  ,p2);
	return g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(p1.x  ,p1.x ) ,g2d_calc_t_mul_g2d_calc_t(p1.y  ,p1.y));
}

G2D_INLINE g2d_calc_t g2d__distance(g2d_cvect_t p1, g2d_cvect_t p2)
{
	p1 = g2d_cvect_t_sub_g2d_cvect_t(p1  ,p2);
	return g2d_sqrt(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(p1.x  ,p1.x ) ,g2d_calc_t_mul_g2d_calc_t(p1.y  ,p1.y)));
}
#endif /* G2D_VECT_H */
