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

#ifndef G2D_BOX_H
#define G2D_BOX_H
#include <assert.h>
#include <opc89.h>
#include <gengeo2d/prim.h>
#include <gengeo2d/vect.h>


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

/* Construct a box from two corners */
G2D_INLINE g2d_box_t g2d_box(g2d_vect_t p1, g2d_vect_t p2);

/* Returns 1 if the box is valid (non-negative-sized), 0 otherwise */
G2D_INLINE int g2d_box_is_valid(const g2d_box_t *box);

/* Construct an invalid box (that can be bumped into valid) */
G2D_INLINE g2d_box_t g2d_box_invalid(void);

/* Enlarge box so that it includes pt */
G2D_INLINE void g2d_box_bump_pt(g2d_box_t *box, g2d_vect_t pt);

/* Return 1 if point/box is (fully) within the box; being on the edge is
   considered within. */
G2D_INLINE int g2d_point_in_box(const g2d_box_t *box, g2d_vect_t pt);
G2D_INLINE int g2d_box_in_box(const g2d_box_t *outer, const g2d_box_t *inner);

/* Return 1 if two boxes have any common point (edges included) */
G2D_INLINE int g2d_isc_box_box(const g2d_box_t *a, const g2d_box_t *b);

/* Calculate the section of box that is within clipbox */
G2D_INLINE g2d_box_t g2d_box_clip(const g2d_box_t *box, const g2d_box_t *clipbox);

/* Return the centerpoint of the box */
G2D_INLINE g2d_vect_t g2d_box_center(const g2d_box_t *box);

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

G2D_INLINE g2d_box_t g2d_box(g2d_vect_t p1, g2d_vect_t p2)
{
	g2d_box_t box;
	box.p1 = p1; box.p2 = p2;
	return box;
}

G2D_INLINE int g2d_box_is_valid(const g2d_box_t *box)
{
	return (g2d_coord_t_lte_g2d_coord_t(box->p1.x  ,box->p2.x)) && (g2d_coord_t_lte_g2d_coord_t(box->p1.y  ,box->p2.y));
}

G2D_INLINE g2d_box_t g2d_box_invalid(void)
{
	g2d_box_t box;
	box.p1.x = G2D_COORD_MAX; box.p1.y = G2D_COORD_MAX;
	box.p2.x = g2d_coord_t_neg(G2D_COORD_MAX); box.p2.y = g2d_coord_t_neg(G2D_COORD_MAX);
	return box;
}

G2D_INLINE void g2d_box_bump_pt(g2d_box_t *box, g2d_vect_t pt)
{
	g2d_vect_bump_down(&box->p1, pt);
	g2d_vect_bump_up(&box->p2, pt);
}

G2D_INLINE void g2d__box_bump_pt(g2d_box_t *box, g2d_cvect_t pt)
{
	g2d_vect_bump_down(&box->p1, g2d_vect(g2d_round_coord_down(pt.x), g2d_round_coord_down(pt.y)));
	g2d_vect_bump_up(&box->p2,   g2d_vect(g2d_round_coord_up(pt.x), g2d_round_coord_up(pt.y)));
}


G2D_INLINE int g2d_point_in_box(const g2d_box_t *box, g2d_vect_t pt)
{
	return (g2d_coord_t_gte_g2d_coord_t(pt.x  ,box->p1.x)) && (g2d_coord_t_gte_g2d_coord_t(pt.y  ,box->p1.y)) && (g2d_coord_t_lt_g2d_coord_t(pt.x  ,box->p2.x)) && (g2d_coord_t_lt_g2d_coord_t(pt.y  ,box->p2.y));
}

G2D_INLINE int g2d_box_in_box(const g2d_box_t *outer, const g2d_box_t *inner)
{
	return (g2d_coord_t_lte_g2d_coord_t(outer->p1.x  ,inner->p1.x)) && (g2d_coord_t_lte_g2d_coord_t(inner->p2.x  ,outer->p2.x)) && (g2d_coord_t_lte_g2d_coord_t(outer->p1.y  ,inner->p1.y)) && (g2d_coord_t_lte_g2d_coord_t(inner->p2.y  ,outer->p2.y));
}

G2D_INLINE int g2d_isc_box_box(const g2d_box_t *a, const g2d_box_t *b)
{
	return (g2d_coord_t_lte_g2d_coord_t(a->p1.x  ,b->p2.x)) && (g2d_coord_t_lte_g2d_coord_t(b->p1.x  ,a->p2.x)) && (g2d_coord_t_lte_g2d_coord_t(a->p1.y  ,b->p2.y)) && (g2d_coord_t_lte_g2d_coord_t(b->p1.y  ,a->p2.y));
}

G2D_INLINE g2d_box_t g2d_box_clip(const g2d_box_t *box, const g2d_box_t *clipbox)
{
	g2d_box_t r;
	 assert ( g2d_isc_box_box(box, clipbox) ) ;
	r.p1.x =(  G2D_MAX ( box->p1.x , clipbox->p1.x ) );
	r.p2.x =(  G2D_MIN ( box->p2.x , clipbox->p2.x ) );
	r.p1.y =(  G2D_MAX ( box->p1.y , clipbox->p1.y ) );
	r.p2.y =(  G2D_MIN ( box->p2.y , clipbox->p2.y ) );
	 assert ( g2d_box_in_box(clipbox, &r) ) ;
	return r;
}

G2D_INLINE g2d_vect_t g2d_box_center(const g2d_box_t *box)
{
	g2d_calc_t two = g2d_calc_t_convfrom_double(2.0), x = (g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_add_g2d_coord_t(box->p1.x,box->p2.x))), y = (g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_add_g2d_coord_t(box->p1.y,box->p2.y)));
	return g2d_vect(g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t(x,two)), g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t(y,two)));
}

#endif /* G2D_BOX_H */
