/*****
 NAME
 	dvector.h - macro definition for vector operations
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 REFERENCE
 	physics for game developers by David M. Bourg (O'REILLY)
 NOTE
 	All macros in this file are tested in "fvector-test.c"
	in the "test" directory.
 */

#if !defined(DVECTOR_H_INCLUDED)
#define DVECTOR_H_INCLUDED

#include <coconut/tmath.h>
#include <math.h>

#define	v2d_tolerance		0.000001
#define	v3d_tolerance		0.000001
#define	v2d_round_limit		1000.0
#define	v3d_round_limit		1000.0

/* v2d_set */
#define	v2d_set(VEC, X, Y) \
	do { \
		(VEC).x = (X) ; (VEC).y = (Y) ; \
	} while(0)

/* v2d_set */
#define	v3d_set(VEC, X, Y, Z) \
	do { \
		(VEC).x = (X) ; (VEC).y = (Y) ; (VEC).z = (Z) ; \
	} while(0)

/* v2d_reverse */
#define	v2d_reverse(VEC) \
	do { \
		(VEC).x = -(VEC).x ; (VEC).y = -(VEC).y ; \
	} while(0)

/* v3d_reverse */
#define	v3d_reverse(VEC) \
	do { \
		(VEC).x = -(VEC).x ; (VEC).y = -(VEC).y ; (VEC).z = -(VEC).z ; \
	} while(0)

/* v2d_pos_tolerance */
#define	v2d_scalar_pos_tolerance(X) \
  ((X) > v2d_tolerance ? (X) : v2d_tolerance)
#define	v3d_scalar_pos_tolerance(X) \
  ((X) > v3d_tolerance ? (X) : v3d_tolerance)

/* v2d_round */
#define	v2d_scalar_round(X) \
  (rint((X) * v2d_round_limit) / v2d_round_limit)
#define	v3d_scalar_round(X) \
  (rint((X) * v3d_round_limit) / v3d_round_limit)

/* v2d_non_neg_zero */
#define	v2d_scalar_no_neg_zero(X)	((X) == -0.0 ? 0.0 : (X))
#define	v3d_scalar_no_neg_zero(X)	((X) == -0.0 ? 0.0 : (X))

/* v2d_magnitude(vec) = root(vec.x^2 + vec.y^2) */
#define	v2d_magnitude(VEC) \
  (sqrt((VEC).x * (VEC).x + (VEC).y * (VEC).y))

/* v3d_magnitude(vec) = root(vec.x^2 + vec.y^2 + vec.z^2) */
#define	v3d_magnitude(VEC) \
  (sqrt((VEC).x * (VEC).x + (VEC).y * (VEC).y + (VEC).z * (VEC).z))

/* v2d_normalize(vec)
   WARNING: if the magnitude of the vector "VEC" is 0, it causes 0 divide err */
#define	v2d_normalize(VEC) \
  do { \
  	double v2d_tmp = v2d_magnitude(VEC) ; \
	(VEC).x /= v2d_tmp ; \
	(VEC).y /= v2d_tmp ; \
  } while(0)
#define	v2d_normalize_z(VEC) \
  do { \
  	double v2d_tmp = v2d_magnitude(VEC) ; \
	v2d_tmp = v2d_scalar_pos_tolerance(v2d_tmp) ; \
	(VEC).x /= v2d_tmp ; \
	(VEC).y /= v2d_tmp ; \
  } while(0)

/* v3d_normalize(vec)
   WARNING: if the magnitude of the vector "VEC" is 0, it causes 0 divide err */
#define	v3d_normalize(VEC) \
  do { \
  	double v3d_tmp = v3d_magnitude(VEC) ; \
	(VEC).x /= v3d_tmp ; \
	(VEC).y /= v3d_tmp ; \
	(VEC).z /= v3d_tmp ; \
  } while(0)
#define	v3d_normalize_z(VEC) \
  do { \
  	double v3d_tmp = v3d_magnitude(VEC) ; \
	v3d_tmp = v3d_scalar_pos_tolerance(v3d_tmp) ; \
	(VEC).x /= v3d_tmp ; \
	(VEC).y /= v3d_tmp ; \
	(VEC).z /= v3d_tmp ; \
  } while(0)

/* v2d_uni_add */
#define	v2d_uni_add(DST, SRC) \
	do { \
		(DST).x+=(SRC).x ; (DST).y+=(SRC).y ; \
	} while(0)

/* v3d_uni_add */
#define	v3d_uni_add(DST, SRC) \
	do { \
		(DST).x+=(SRC).x ; (DST).y+=(SRC).y ; (DST).z+=(SRC).z ; \
	} while(0)

/* v2d_uni_sub */
#define	v2d_uni_sub(DST, SRC) \
	do { \
		(DST).x-=(SRC).x ; (DST).y-=(SRC).y ; \
	} while(0)

/* v3d_uni_sub */
#define	v3d_uni_sub(DST, SRC) \
	do { \
		(DST).x-=(SRC).x ; (DST).y-=(SRC).y ; (DST).z-=(SRC).z ; \
	} while(0)

/* v2d_scalar_mult */
#define	v2d_scalar_mult(DST, D) \
	do { \
		(DST).x*=(D) ; (DST).y*=(D) ; \
	} while(0) 

/* v3d_scalar_mult */
#define	v3d_scalar_mult(DST, D) \
	do { \
		(DST).x*=(D) ; (DST).y*=(D) ; (DST).z*=(D) ; \
	} while(0) 

/* v2d_scalar_div */
#define	v2d_scalar_div(DST, D) \
	do { \
		(DST).x/=(D) ; (DST).y/=(D) ; \
	} while(0) 

/* v3d_scalar_div */
#define	v3d_scalar_div(DST, D) \
	do { \
		(DST).x/=(D) ; (DST).y/=(D) ; (DST).z/=(D) ; \
	} while(0) 

/* v2d_bin_add */
#define	v2d_bin_add(DST, SRC1, SRC2) \
	do { \
		(DST).x = (SRC1).x + (SRC2).x ; \
		(DST).y = (SRC1).y + (SRC2).y ; \
	} while(0)

/* v3d_bin_add */
#define	v3d_bin_add(DST, SRC1, SRC2) \
	do { \
		(DST).x = (SRC1).x + (SRC2).x ; \
		(DST).y = (SRC1).y + (SRC2).y ; \
		(DST).z = (SRC1).z + (SRC2).z ; \
	} while(0)

/* v2d_bin_sub */
#define	v2d_bin_sub(DST, SRC1, SRC2) \
	do { \
		(DST).x = (SRC1).x - (SRC2).x ; \
		(DST).y = (SRC1).y - (SRC2).y ; \
	} while(0)

/* v3d_bin_sub */
#define	v3d_bin_sub(DST, SRC1, SRC2) \
	do { \
		(DST).x = (SRC1).x - (SRC2).x ; \
		(DST).y = (SRC1).y - (SRC2).y ; \
		(DST).z = (SRC1).z - (SRC2).z ; \
	} while(0)

#endif /* !defined(DVECTOR_H_INCLUDED) */

