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

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


/* Convex hull, using the monotone chain algorithm */

/* temporary workaround for an opc89 bug */
G2D_INLINE g2d_vect_t *g2d_vect_t_convfrom_g2d_vect_t(g2d_vect_t *v) { return g2d_vect_t_convfrom_g2d_vect_t(v); }

/* Decude if 3 consecutive points are turning CCW (returns positive), CW
   (returns negative) or colinear (returns 0). */
G2D_INLINE g2d_calc_t g2d_chull_ccw(g2d_vect_t *p1, g2d_vect_t *p2, g2d_vect_t p3)
{
	return g2d_calc_t_sub_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(p2->x  ,p1->x)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(p3.y  ,p1->y))) ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(p2->y  ,p1->y)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(p3.x  ,p1->x)))));
}

static int g2d_chull_cmp(const void *P1, const void *P2)
{
	const g2d_vect_t *p1 = P1, *p2 = P2;
	if (g2d_coord_t_eq_g2d_coord_t(p1->x  ,p2->x))
		return (p1->y < p2->y) ? 1 : -1;
	return (p1->x < p2->x) ? 1 : -1;
}

static void opfunc g2d_chull_sort(g2d_vect_t *src, long int src_len)
{
	qsort(src, src_len, (long int)(sizeof(g2d_vect_t)), g2d_chull_cmp);
}

/* Fills in dst up to *dst_len items, load *dst_len with the actual number of
   items. Returns 0 on success; failure happens if input dst_len is too small.
   Safe value: src_len+3. Note: src is modified: it is sorted */
G2D_INLINE int g2d_chull(g2d_vect_t **dst, long int *dst_len, g2d_vect_t *src, long int src_len)
{
	long int i, t, k = 0, max = *dst_len;
	int res = 0;

	g2d_chull_sort(src, src_len);

	/* bottom side */
	for(i = 0; i < src_len; i++) {
		while((k >= 2) && g2d_calc_t_lte_g2d_calc_t(g2d_chull_ccw(dst[k - 2], dst[k - 1], src[i])  ,g2d_calc_t_convfrom_double(0.0)))
			k--;
		if (k >= max) {
			res = 1;
			break;
		}
		dst[k] = &src[i];
		k++;
	}

	/* top side */
	for(i = src_len - 2, t = k + 1; i >= 0; i--) {
		while((k >= t) && g2d_calc_t_lte_g2d_calc_t(g2d_chull_ccw(dst[k - 2], dst[k - 1], src[i])  ,g2d_calc_t_convfrom_double(0.0)))
			k--;
		if (k >= max) {
			res = 1;
			break;
		}
		dst[k] = &src[i];
		k++;
	}
	*dst_len = k-1; /* last point is the same as the first point, remove the redundancy */
	return res;
}
#endif /* G2D_chull_H */
