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

#ifndef G2D_INTERSECT_H
#define G2D_INTERSECT_H
#include <opc89.h>
#include <gengeo2d/common.h>
#include <gengeo2d/prim.h>
#include <gengeo2d/vect.h>
#include <gengeo2d/box.h>
#include <gengeo2d/cline.h>
#include <gengeo2d/carc.h>
#include <gengeo2d/sline.h>
#include <gengeo2d/sarc.h>



G2D_INLINE int g2d__iscp_cline_carc(const g2d_cline_t *line, const g2d_carc_t *arc,  g2d_cvect_t ip[2],  g2d_offs_t offs[2], int offs_on_arc)
{
	g2d_calc_t b, dist2, r2 = g2d_calc_t_mul_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(arc->r ) ,g2d_calc_t_convfrom_g2d_coord_t(arc->r));
	g2d_offs_t iao, ilo, ppao, ppo;
	g2d_cvect_t i, ld, pp;
	g2d_angle_t start, end;
	int pts = 0;

	/* project the center of the arc onto the line and figure if the line is close enough */
	ppo = g2d__project_pt_cline(g2d_cvect_t_convfrom_g2d_vect_t(arc->c), line);
	pp = g2d__cline_offs(line, ppo);
	dist2 = g2d__distance2(g2d_cvect_t_convfrom_g2d_vect_t(arc->c), pp);
	if (g2d_calc_t_gt_g2d_calc_t(dist2  ,r2))
		return 0;

	/* if the line is just touching the circle (1 potential intersection) */
	if (g2d_calc_t_eq_g2d_calc_t(dist2  ,r2)) {
		if ((g2d_offs_t_lt_g2d_offs_t(ppo  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(ppo  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the line */
			return 0;

		ppao = g2d_offs_carc_pt(arc, g2d_vect_t_convfrom_g2d_cvect_t(pp));
		if ((g2d_offs_t_lt_g2d_offs_t(ppao  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(ppao  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the arc */
			return 0;

		if (ip != NULL) ip[0] = pp;
		if (offs != NULL) offs[0] = offs_on_arc ? ppao : ppo;
		return 1;
	}

	ld = g2d__vect_normalize(g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line->p2  ,line->p1)));
	g2d_carc_start_end_norm(arc, &start, &end);
	b = g2d_sqrt(g2d_calc_t_sub_g2d_calc_t(r2  ,dist2));

	/* intersection point */
	i = g2d_cvect_t_add_g2d_cvect_t(pp  ,g2d_calc_t_mul_g2d_cvect_t(b  ,ld));

	ilo = g2d__offs_cline_pt(line, i);
	if ((g2d_offs_t_lt_g2d_offs_t(ilo  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(ilo  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the line */
		goto skip1;
	iao = g2d__offs_carc_pt(arc, i);
	if ((g2d_offs_t_lt_g2d_offs_t(iao  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(iao  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the arc */
		goto skip1;

	if (ip != NULL) ip[0] = i;
	if (offs != NULL) offs[0] = offs_on_arc ? iao : ilo;
	pts++;

	skip1:;

	i = g2d_cvect_t_sub_g2d_cvect_t(pp  ,g2d_calc_t_mul_g2d_cvect_t(b  ,ld));

	ilo = g2d__offs_cline_pt(line, i);
	if ((g2d_offs_t_lt_g2d_offs_t(ilo  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(ilo  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the line */
		goto skip2;
	iao = g2d__offs_carc_pt(arc, i);
	if ((g2d_offs_t_lt_g2d_offs_t(iao  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(iao  ,g2d_offs_t_convfrom_double(1.0)))) /* not within the bounds of the arc */
		goto skip2;

	if (ip != NULL) ip[pts] = i;
	if (offs != NULL) offs[pts] = offs_on_arc ? iao : ilo;
	pts++;

	skip2:;
	return pts;
}

G2D_INLINE int g2d_iscp_cline_carc(const g2d_cline_t *line, const g2d_carc_t *arc,  g2d_vect_t ip[2],  g2d_offs_t offs[2], int offs_on_arc)
{
	g2d_cvect_t cip[2];
	int pts = g2d__iscp_cline_carc(line, arc, cip, offs, offs_on_arc);
	if (ip != NULL) {
		if (pts > 0) ip[0] = g2d_vect_t_convfrom_g2d_cvect_t(cip[0]);
		if (pts > 1) ip[1] = g2d_vect_t_convfrom_g2d_cvect_t(cip[1]);
	}
	return pts;
}


G2D_INLINE int g2d_isc_sline_sarc(const g2d_sline_t *line, const g2d_sarc_t *arc)
{
	g2d_cline_t cl1, cl2;
	g2d_carc_t ca1, ca2;
	g2d_vect_t pt;
	g2d_calc_t r;

	/* cheap test: sarc endpoint intersects sline */
	switch(arc->s.cap) {
		case G2D_CAP_ROUND:
			r = g2d_calc_t_div_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(arc->s.width ) ,g2d_calc_t_convfrom_double(2.0));
			pt = g2d_carc_offs(&arc->c, g2d_offs_t_convfrom_double(0.0));
			if (g2d_isc_sline_circle(line, pt, r)) return 1;
			pt = g2d_carc_offs(&arc->c, g2d_offs_t_convfrom_double(1.0));
			if (g2d_isc_sline_circle(line, pt, r)) return 1;
			break;
		/* TODO: need to handle square cap */
	}


	/* cheap test: sline endpoint intersects sarc */
	switch(line->s.cap) {
		case G2D_CAP_ROUND:
			r = g2d_calc_t_div_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->s.width ) ,g2d_calc_t_convfrom_double(2.0));
			g2d_sarc_sides(arc, &ca1, &ca2);
			pt = g2d_cline_offs(&line->c, g2d_offs_t_convfrom_double(0.0));
			if (g2d_iscp_carc_circle(&ca1, pt, r, 0, 0)) return 1;
			if (g2d_iscp_carc_circle(&ca2, pt, r, 0, 0)) return 1;
			pt = g2d_cline_offs(&line->c, g2d_offs_t_convfrom_double(1.0));
			if (g2d_iscp_carc_circle(&ca1, pt, r, 0, 0)) return 1;
			if (g2d_iscp_carc_circle(&ca2, pt, r, 0, 0)) return 1;
		/* TODO: need to handle square cap */
	}

	/* expensive tests: sarc edges vs sline edges */
	g2d_sline_sides(line, &cl1, &cl2);
	if (g2d__iscp_cline_carc(&cl1, &ca1, 0, 0, 0) > 0) return 1;
	if (g2d__iscp_cline_carc(&cl1, &ca2, 0, 0, 0) > 0) return 1;
	if (g2d__iscp_cline_carc(&cl2, &ca1, 0, 0, 0) > 0) return 1;
	if (g2d__iscp_cline_carc(&cl2, &ca2, 0, 0, 0) > 0) return 1;

	return 0;
}
#endif /* G2D_INTERSECT_H */
