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

#ifndef G2D_CLINE_H
#define G2D_CLINE_H
#include <opc89.h>
#include <gengeo2d/prim.h>
#include <gengeo2d/vect.h>
#include <gengeo2d/box.h>


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

/* Construct a cline from two endpoints */
G2D_INLINE g2d_cline_t g2d_cline(g2d_vect_t p1, g2d_vect_t p2);

/* Calculate the bounding box of a cline */
G2D_INLINE g2d_box_t g2d_cline_bbox(const g2d_cline_t *line);


/* Convert a point into an offset or an offset into a point */
G2D_INLINE g2d_offs_t g2d__offs_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt_in);
G2D_INLINE g2d_offs_t g2d_offs_cline_pt(const g2d_cline_t *line, g2d_vect_t pt_in);
G2D_INLINE g2d_cvect_t g2d__cline_offs(const g2d_cline_t *line, g2d_offs_t offs);
G2D_INLINE g2d_vect_t g2d_cline_offs(const g2d_cline_t *line, g2d_offs_t offs);

/* Intersection between a cline and a cline or box */
G2D_INLINE int g2d__iscp_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_cvect_t ip[2],  g2d_offs_t offs[2]);
G2D_INLINE int g2d_iscp_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_vect_t ip[2],  g2d_offs_t offs[2]);
G2D_INLINE int g2d_isc_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2);
G2D_INLINE int g2d__iscp_cline_box(const g2d_cline_t *line, const g2d_box_t *box,  g2d_cvect_t ip[2], g2d_offs_t offs[2]);
G2D_INLINE int g2d_iscp_cline_box(const g2d_cline_t *line, const g2d_box_t *box,  g2d_vect_t ip[2], g2d_offs_t offs[2]);
G2D_INLINE int g2d_isc_cline_box(const g2d_cline_t *line, const g2d_box_t *box);

/* If allways_offs is 1, offs is loaded with line1,line2 offsets even if
   the offsets are out of bound and there is no intersection */
G2D_INLINE int g2d__iscp_cline_cline_o(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_cvect_t ip[2],  g2d_offs_t offs[2], int always_offs);

/* Calculate a new cline based on the original, moved in-line and/or
   perpendicular to the original */
G2D_INLINE g2d_cline_t g2d_cline_shift(const g2d_cline_t *line, g2d_coord_t in_line, g2d_coord_t perp);
G2D_INLINE g2d__cline_t g2d__cline_shift(const g2d__cline_t *line, g2d_calc_t in_line, g2d_calc_t perp);

/* Calculate a new cline longer (positive values) or shorter (negative values)
   on each endpoint. Value 0 means do not touch the endpoint. */
G2D_INLINE g2d_cline_t g2d_cline_extend(const g2d_cline_t *line, g2d_coord_t end1, g2d_coord_t end2);
G2D_INLINE g2d__cline_t g2d__cline_extend(const g2d__cline_t *line, g2d_calc_t end1, g2d_calc_t end2);

/* Special case (optimized) intersections with axis aligned centerlines */
G2D_INLINE int g2d__iscp_cline_hcline(const g2d_cline_t *line, g2d_calc_t y, g2d_calc_t x1, g2d_calc_t x2, g2d_cvect_t *ip, g2d_offs_t *offs);
G2D_INLINE int g2d__iscp_cline_vcline(const g2d_cline_t *line, g2d_calc_t x, g2d_calc_t y1, g2d_calc_t y2, g2d_cvect_t *ip, g2d_offs_t *offs);

/* Return the coordinate where an infinite horizontal or vertical line would
   cross the infinitely extended cline (no boundary checks applied) */
G2D_INLINE g2d_calc_t g2d__cline_x_for_y(const g2d_cline_t *cline, g2d_calc_t y);
G2D_INLINE g2d_calc_t g2d__cline_y_for_x(const g2d_cline_t *cline, g2d_calc_t x);
G2D_INLINE g2d_coord_t g2d_cline_x_for_y(const g2d_cline_t *cline, g2d_coord_t y);
G2D_INLINE g2d_coord_t g2d_cline_y_for_x(const g2d_cline_t *cline, g2d_coord_t x);

/* Project pt onto the line (perpendicular projection) and return the
   offset of the projected point within the line */
G2D_INLINE g2d_offs_t g2d__project_pt_cline(g2d_cvect_t pt, const g2d_cline_t *line);
G2D_INLINE g2d_offs_t g2d_project_pt_cline(g2d_vect_t pt, const g2d_cline_t *line);

/* Distance calculations */
G2D_INLINE g2d_calc_t g2d__dist2_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt);
G2D_INLINE g2d_calc_t g2d_dist2_cline_pt(const g2d_cline_t *line, g2d_vect_t pt);

/* Decide on which side of a line is a point; returns positive or negative for
   the sides, 0 if the point is on the (infinitely long) line */
G2D_INLINE g2d_calc_t g2d__side_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt);
G2D_INLINE g2d_calc_t g2d_side_cline_pt(const g2d_cline_t *line, g2d_vect_t pt);


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

G2D_INLINE g2d_cline_t g2d_cline(g2d_vect_t p1, g2d_vect_t p2)
{
	g2d_cline_t l;
	l.p1 = p1; l.p2 = p2;
	return l;
}

G2D_INLINE g2d_box_t g2d_cline_bbox(const g2d_cline_t *line)
{
	g2d_box_t b;
	b.p1 = b.p2 = line->p1;
	g2d_box_bump_pt(&b, line->p2);
	return b;
}

G2D_INLINE g2d_offs_t g2d__offs_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt_in)
{
	g2d_cvect_t lp2 = g2d_cvect_t_convfrom_g2d_vect_t(line->p2), lp1 = g2d_cvect_t_convfrom_g2d_vect_t(line->p1);
	g2d_cvect_t d = g2d_cvect_t_sub_g2d_cvect_t(lp2  ,lp1), pt = g2d_cvect_t_sub_g2d_cvect_t(pt_in  ,lp1);
	return g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t((g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(d.x  ,pt.x ) ,g2d_calc_t_mul_g2d_calc_t(d.y  ,pt.y)))  ,(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(d.x  ,d.x ) ,g2d_calc_t_mul_g2d_calc_t(d.y  ,d.y)))));
}

G2D_INLINE g2d_offs_t g2d_offs_cline_pt(const g2d_cline_t *line, g2d_vect_t pt_in)
{
	g2d_cvect_t lp2 = g2d_cvect_t_convfrom_g2d_vect_t(line->p2), lp1 = g2d_cvect_t_convfrom_g2d_vect_t(line->p1), ptin = g2d_cvect_t_convfrom_g2d_vect_t(pt_in);
	g2d_cvect_t d = g2d_cvect_t_sub_g2d_cvect_t(lp2  ,lp1), pt = g2d_cvect_t_sub_g2d_cvect_t(ptin  ,lp1);
	return g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t((g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(d.x  ,pt.x ) ,g2d_calc_t_mul_g2d_calc_t(d.y  ,pt.y)))  ,(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(d.x  ,d.x ) ,g2d_calc_t_mul_g2d_calc_t(d.y  ,d.y)))));
}

G2D_INLINE g2d_cvect_t g2d__cline_offs(const g2d_cline_t *line, g2d_offs_t offs)
{
	g2d_cvect_t r, d, lp1 = g2d_cvect_t_convfrom_g2d_vect_t(line->p1), lp2 = g2d_cvect_t_convfrom_g2d_vect_t(line->p2);
	d = g2d_cvect_t_sub_g2d_cvect_t(lp2  ,lp1);
	r = g2d_cvect_t_add_g2d_cvect_t(lp1  ,g2d_cvect_t_MUL_g2d_offs_t(offs  ,d));
	return r;
}

G2D_INLINE g2d_vect_t g2d_cline_offs(const g2d_cline_t *line, g2d_offs_t offs)
{
	return g2d_vect_t_convfrom_g2d_cvect_t(g2d__cline_offs(line, offs));
}

G2D_INLINE int g2d_cline_is_pt(const g2d_cline_t *line)
{
	return (g2d_coord_t_eq_g2d_coord_t(line->p1.x  ,line->p2.x)) && (g2d_coord_t_eq_g2d_coord_t(line->p1.y  ,line->p2.y));
}

/* Basic idea copied from pcb-rnd */
G2D_INLINE int g2d__iscp_cline_cline_o(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_cvect_t ip[2],  g2d_offs_t offs[2], int always_offs)
{
	g2d_offs_t o0, o1, o21;
	g2d_calc_t s, r;
	g2d_cvect_t l1d, l2d, pt;

	l1d = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line1->p2  ,line1->p1));
	l2d = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line2->p2  ,line2->p1));
	pt  = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line1->p1  ,line2->p1));

	s = g2d__crossp(l1d, pt);
	r = g2d__crossp(l1d, l2d);

	
	if (g2d_calc_t_eq_g2d_calc_t(r  ,g2d_calc_t_convfrom_double(0.0))) {
		/* parallel or overlapping lines */
		if (g2d_calc_t_eq_g2d_calc_t(s  ,g2d_calc_t_convfrom_double(0.0))) { /* overlap */
			int isp1 = g2d_cline_is_pt(line1), isp2 = g2d_cline_is_pt(line2);

			/* special case: both lines are point */
			if (isp1 && isp2) {
				if (g2d_vect_t_eq_g2d_vect_t(line1->p1  ,line2->p1)) {
					if (offs != NULL)
						offs[0] = g2d_offs_t_convfrom_double(0.0);
					if (ip != NULL)
						ip[0] = g2d_cvect_t_convfrom_g2d_vect_t(line1->p1);
					return 1;
				}
				return 0;
			}

			/* special case: one line is really a point: there will be only intersection */
			if (isp2) {
				g2d_offs_t of0 = g2d_offs_cline_pt(line1, line2->p1);
				if ((g2d_offs_t_lt_g2d_offs_t(of0  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(of0  ,g2d_offs_t_convfrom_double(1.0))))
					return 0; /* point is out of range for the line */
				if (offs != NULL)
					offs[0] = of0;
				if (ip != NULL)
					ip[0] = g2d_cvect_t_convfrom_g2d_vect_t(line2->p1);
				return 1;
			}
			if (isp1) {
				g2d_offs_t of0 = g2d_offs_cline_pt(line2, line1->p1);
				if ((g2d_offs_t_lt_g2d_offs_t(of0  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(of0  ,g2d_offs_t_convfrom_double(1.0))))
					return 0; /* point is out of range for the line */
				if (offs != NULL)
					offs[0] = g2d_offs_t_convfrom_double(0.0);
				if (ip != NULL)
					ip[0] = g2d_cvect_t_convfrom_g2d_vect_t(line1->p1);
				return 1;
			}

			/* o0 is line2's offset in line1 (overlap end 0 in line1) */
			o0 = g2d_offs_cline_pt(line1, line2->p1);
			if ((g2d_offs_t_lt_g2d_offs_t(o0  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(o0  ,g2d_offs_t_convfrom_double(1.0))))
				o0 = g2d_offs_cline_pt(line1, line2->p2);

			/* o21 is line1's offset in line2 (overlap end 1 in line2),
			   o1 is the same point's offset in line1 */
			o21 = g2d_offs_cline_pt(line2, line1->p1);
			if ((g2d_offs_t_lt_g2d_offs_t(o21  ,g2d_offs_t_convfrom_double(0.0))) || (g2d_offs_t_gt_g2d_offs_t(o21  ,g2d_offs_t_convfrom_double(1.0))))
				o1 = g2d_offs_t_convfrom_double(1.0); /* g2d_offs_cline_pt(line1, line1->p2); line->p1 was out of range, use p2 */
			else
				o1 = g2d_offs_t_convfrom_double(0.0); /* g2d_offs_cline_pt(line1, line1->p1); p1 is the one we need */

			if (ip != NULL) {
				ip[0].x = g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line1->p1.x ) ,g2d_calc_t_MUL_g2d_offs_t(o0  ,l1d.x));
				ip[0].y = g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line1->p1.y ) ,g2d_calc_t_MUL_g2d_offs_t(o0  ,l1d.y));
				if (g2d_offs_t_eq_g2d_offs_t(o1  ,g2d_offs_t_convfrom_double(1.0)))
					ip[1] = g2d_cvect_t_convfrom_g2d_vect_t(line1->p2);
				else
					ip[1] = g2d_cvect_t_convfrom_g2d_vect_t(line1->p1);
			}
			if (offs != NULL) {
				offs[0] = o0;
				offs[1] = o1;
			}
			if (g2d_offs_t_eq_g2d_offs_t(o0  ,o1))
				return 1;
			return 2;
		}
		return 0;
	}

	s /= r;
	r = g2d_calc_t_div_g2d_calc_t(g2d__crossp(l2d, pt)  ,r);

	if ((g2d_calc_t_gte_g2d_calc_t(r  ,g2d_calc_t_convfrom_double(0.0))) && (g2d_calc_t_lte_g2d_calc_t(r  ,g2d_calc_t_convfrom_double(1.0)))) {
		/* intersection is within the limits of line2 */
		if ((g2d_calc_t_gte_g2d_calc_t(s  ,g2d_calc_t_convfrom_double(0.0))) && (g2d_calc_t_lte_g2d_calc_t(s  ,g2d_calc_t_convfrom_double(1.0)))) {
			/* intersection is also within the limits of line1 */
			if (ip != NULL) {
				ip[0].x = g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line1->p1.x ) ,g2d_calc_t_mul_g2d_calc_t(r  ,l1d.x));
				ip[0].y = g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line1->p1.y ) ,g2d_calc_t_mul_g2d_calc_t(r  ,l1d.y));
			}
			if (offs != NULL)
				offs[0] = g2d_offs_t_convfrom_g2d_calc_t(r);
			return 1;
		}
	}

	/* intersection is not on the line segments */
	if (always_offs) {
		offs[0] = g2d_offs_t_convfrom_g2d_calc_t(r);
		offs[1] = g2d_offs_t_convfrom_g2d_calc_t(s);
	}
	return 0;
}

G2D_INLINE int g2d__iscp_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_cvect_t ip[2],  g2d_offs_t offs[2])
{
	return g2d__iscp_cline_cline_o(line1, line2,  ip,  offs, 0);
}


G2D_INLINE int g2d_iscp_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2,  g2d_vect_t ip[2],  g2d_offs_t offs[2])
{
	g2d_cvect_t cip[2];
	int pts = g2d__iscp_cline_cline(line1, line2, cip, offs);
	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_cline_cline(const g2d_cline_t *line1, const g2d_cline_t *line2)
{
	static g2d_cvect_t *ip; /* = NULL - TODO: this is an opc89 workaround */
	return !!g2d__iscp_cline_cline(line1, line2, ip, 0);
}


G2D_INLINE g2d_calc_t g2d__cline_x_for_y(const g2d_cline_t *line, g2d_calc_t y)
{
	g2d_calc_t dx = g2d_calc_t_div_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y))));
	return g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p1.x ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(y  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.y)))  ,dx));
}

G2D_INLINE g2d_coord_t g2d_cline_x_for_y(const g2d_cline_t *line, g2d_coord_t y)
{
	g2d_calc_t dx = g2d_calc_t_div_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y))));
	return g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p1.x ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(y  ,line->p1.y)))  ,dx)));
}

G2D_INLINE g2d_calc_t g2d__cline_y_for_x(const g2d_cline_t *line, g2d_calc_t x)
{
	g2d_calc_t dy = g2d_calc_t_div_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x))));
	return g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p1.y ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(x  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.x)))  ,dy));
}

G2D_INLINE g2d_coord_t g2d_cline_y_for_x(const g2d_cline_t *line, g2d_coord_t x)
{
	g2d_calc_t dy = g2d_calc_t_div_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x))));
	return g2d_coord_t_convfrom_g2d_calc_t(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p1.y ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(x  ,line->p1.x)))  ,dy)));
}

/* WARNING: assumes x1 <= x2 */
G2D_INLINE int g2d__iscp_cline_hcline(const g2d_cline_t *line, g2d_calc_t y, g2d_calc_t x1, g2d_calc_t x2, g2d_cvect_t *ip, g2d_offs_t *offs)
{
	g2d_calc_t x;

	/* quick checks: if there is no chance for an intersection */
	if ((g2d_coord_t_lt_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(y ) ,((  G2D_MIN ( line->p1.y , line->p2.y ) )) ))|| (g2d_coord_t_gt_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(y ) ,((  G2D_MAX ( line->p1.y , line->p2.y ) ))))
		)return 0;

	x = g2d__cline_x_for_y(line, y);
	if (!((  g2d_is_between ( x , x1 , x2 ) ))
		)return 0;

	if (ip != NULL) {
		ip->x = x;
		ip->y = y;
	}
	if (offs != NULL)
		*offs =  g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(y  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.y)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y)))));
	return 1;
}

G2D_INLINE int g2d__iscp_cline_vcline(const g2d_cline_t *line, g2d_calc_t x, g2d_calc_t y1, g2d_calc_t y2, g2d_cvect_t *ip, g2d_offs_t *offs)
{
	g2d_calc_t y;

	/* quick checks: if there is no chance for an intersection */
	if ((g2d_coord_t_lt_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(x ) ,((  G2D_MIN ( line->p1.x , line->p2.x ) )) ))|| (g2d_coord_t_gt_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(x ) ,((  G2D_MAX ( line->p1.x , line->p2.x ) ))))
		)return 0;

	y = g2d__cline_y_for_x(line, x);
	if (!((  g2d_is_between ( y , y1 , y2 ) ))
		)return 0;

	if (ip != NULL) {
		ip->x = x;
		ip->y = y;
	}
	if (offs != NULL)
		*offs =  g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(x  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.x)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x)))));
	return 1;
}

G2D_INLINE int g2d__iscp_cline_box(const g2d_cline_t *line, const g2d_box_t *box,  g2d_cvect_t ip[2], g2d_offs_t offs[2])
{
	int idx = 0;
	if (g2d__iscp_cline_hcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), &ip[idx], &offs[idx])) { if ((g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p1.x)) || (g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p2.x))) return 1; idx++; if (idx == 2) return 2; }
	if (g2d__iscp_cline_hcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), &ip[idx], &offs[idx])) { if ((g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p1.x)) || (g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p2.x))) return 1; idx++; if (idx == 2) return 2; }
	if (g2d__iscp_cline_vcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), &ip[idx], &offs[idx])) { if ((g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].y ) ,box->p1.y)) || (g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p2.y))) return 1; idx++; if (idx == 2) return 2; }
	if (g2d__iscp_cline_vcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), &ip[idx], &offs[idx])) { if ((g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].y ) ,box->p1.y)) || (g2d_coord_t_eq_g2d_coord_t(g2d_coord_t_convfrom_g2d_calc_t(ip[idx].x ) ,box->p2.y))) return 1; idx++; if (idx == 2) return 2; }
	return idx;
}

G2D_INLINE int g2d_iscp_cline_box(const g2d_cline_t *line, const g2d_box_t *box,  g2d_vect_t ip[2], g2d_offs_t offs[2])
{
	g2d_cvect_t cip[2];
	int pts = g2d__iscp_cline_box(line, box, cip, offs);
	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_cline_box(const g2d_cline_t *line, const g2d_box_t *box)
{
	if (g2d__iscp_cline_hcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), 0, 0)) return 1;
	if (g2d__iscp_cline_hcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), 0, 0)) return 1;
	if (g2d__iscp_cline_vcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p1.x), g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), 0, 0)) return 1;
	if (g2d__iscp_cline_vcline(line, g2d_calc_t_convfrom_g2d_coord_t(box->p2.x), g2d_calc_t_convfrom_g2d_coord_t(box->p1.y), g2d_calc_t_convfrom_g2d_coord_t(box->p2.y), 0, 0)) return 1;
	return 0;
}

G2D_INLINE g2d_cline_t g2d_cline_shift(const g2d_cline_t *line, g2d_coord_t in_line, g2d_coord_t perp)
{
	g2d_cline_t r;
	g2d_cvect_t dv, nv;

	r = *line;

	dv = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line->p2  ,line->p1));
	if ((g2d_coord_t_neq_g2d_coord_t(in_line  ,g2d_coord_t_convfrom_int(0))) || (g2d_coord_t_neq_g2d_coord_t(perp  ,g2d_coord_t_convfrom_int(0))))
		dv = g2d__vect_normalize(dv);

	if (g2d_coord_t_neq_g2d_coord_t(in_line  ,g2d_coord_t_convfrom_int(0))) {
		dv = g2d_calc_t_MUL_g2d_cvect_t(dv  ,g2d_calc_t_convfrom_g2d_coord_t(in_line));
		r.p1 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t_ADD_g2d_vect_t(r.p1  ,dv));
		r.p2 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t_ADD_g2d_vect_t(r.p2  ,dv));
	}

	if (g2d_coord_t_neq_g2d_coord_t(perp  ,g2d_coord_t_convfrom_int(0))) {
		nv = g2d_calc_t_MUL_g2d_cvect_t(g2d__vect_perp(dv)  ,g2d_calc_t_convfrom_g2d_coord_t(perp));
		r.p1 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t_ADD_g2d_vect_t(r.p1  ,nv));
		r.p2 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t_ADD_g2d_vect_t(r.p2  ,nv));
	}
	return r;
}

G2D_INLINE g2d__cline_t g2d__cline_shift(const g2d__cline_t *line, g2d_calc_t in_line, g2d_calc_t perp)
{
	g2d__cline_t r;
	g2d_cvect_t dv, nv;

	r = *line;

	dv = g2d_cvect_t_sub_g2d_cvect_t(line->p2  ,line->p1);
	if ((g2d_calc_t_neq_g2d_calc_t(in_line  ,g2d_calc_t_convfrom_double(0.0))) || (g2d_calc_t_neq_g2d_calc_t(perp  ,g2d_calc_t_convfrom_double(0.0))))
		dv = g2d__vect_normalize(dv);

	if (g2d_calc_t_neq_g2d_calc_t(in_line  ,g2d_calc_t_convfrom_double(0.0))) {
		dv = g2d_calc_t_MUL_g2d_cvect_t(dv  ,in_line);
		r.p1 = g2d_cvect_t_add_g2d_cvect_t(r.p1  ,dv);
		r.p2 = g2d_cvect_t_add_g2d_cvect_t(r.p2  ,dv);
	}

	if (g2d_calc_t_neq_g2d_calc_t(perp  ,g2d_calc_t_convfrom_double(0.0))) {
		nv = g2d_calc_t_MUL_g2d_cvect_t(g2d__vect_perp(dv)  ,perp);
		r.p1 = g2d_cvect_t_add_g2d_cvect_t(r.p1  ,nv);
		r.p2 = g2d_cvect_t_add_g2d_cvect_t(r.p2  ,nv);
	}
	return r;
}

G2D_INLINE g2d_cline_t g2d_cline_extend(const g2d_cline_t *line, g2d_coord_t end1, g2d_coord_t end2)
{
	g2d_cvect_t dv;
	g2d_cline_t r;

	if ((g2d_coord_t_eq_g2d_coord_t(end1  ,g2d_coord_t_convfrom_int(0))) && (g2d_coord_t_eq_g2d_coord_t(end2  ,g2d_coord_t_convfrom_int(0))))
		return *line;

	dv = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line->p2  ,line->p1));
	dv = g2d__vect_normalize(dv);
	r = *line;

	if (g2d_coord_t_neq_g2d_coord_t(end1  ,g2d_coord_t_convfrom_int(0)))
		r.p1 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_vect_t_sub_g2d_cvect_t(r.p1  ,g2d_calc_t_MUL_g2d_cvect_t(dv  ,g2d_calc_t_convfrom_g2d_coord_t(end1))));
	if (g2d_coord_t_neq_g2d_coord_t(end2  ,g2d_coord_t_convfrom_int(0)))
		r.p2 = g2d_vect_t_convfrom_g2d_cvect_t(g2d_cvect_t_ADD_g2d_vect_t(r.p2  ,g2d_calc_t_MUL_g2d_cvect_t(dv  ,g2d_calc_t_convfrom_g2d_coord_t(end2))));
	return r;
}

G2D_INLINE g2d__cline_t g2d__cline_extend(const g2d__cline_t *line, g2d_calc_t end1, g2d_calc_t end2)
{
	g2d_cvect_t dv;
	g2d__cline_t r;

	if ((g2d_calc_t_eq_g2d_calc_t(end1  ,g2d_calc_t_convfrom_double(0.0))) && (g2d_calc_t_eq_g2d_calc_t(end2  ,g2d_calc_t_convfrom_double(0.0))))
		return *line;

	dv = g2d_cvect_t_sub_g2d_cvect_t(line->p2  ,line->p1);
	dv = g2d__vect_normalize(dv);
	r = *line;

	if (g2d_calc_t_neq_g2d_calc_t(end1  ,g2d_calc_t_convfrom_double(0.0)))
		r.p1 = g2d_cvect_t_sub_g2d_cvect_t(r.p1  ,g2d_calc_t_MUL_g2d_cvect_t(dv  ,end1));
	if (g2d_calc_t_neq_g2d_calc_t(end2  ,g2d_calc_t_convfrom_double(0.0)))
		r.p2 = g2d_cvect_t_add_g2d_cvect_t(r.p2  ,g2d_calc_t_MUL_g2d_cvect_t(dv  ,end2));
	return r;
}

G2D_INLINE g2d_offs_t g2d__project_pt_cline(g2d_cvect_t pt, const g2d_cline_t *line)
{
	g2d_cvect_t a = g2d_cvect_t_sub_g2d_vect_t(pt  ,line->p1);
	g2d_cvect_t d = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line->p2  ,line->p1));
	g2d_calc_t len = g2d_calc_t_convfrom_g2d_cvect_t(d);

	d.x = g2d_calc_t_div_g2d_calc_t(d.x  ,len);
	d.y = g2d_calc_t_div_g2d_calc_t(d.y  ,len);

	return g2d_offs_t_convfrom_g2d_calc_t(g2d_calc_t_div_g2d_calc_t((g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(a.x  ,d.x ) ,g2d_calc_t_mul_g2d_calc_t(a.y  ,d.y)))  ,len));
}

G2D_INLINE g2d_offs_t g2d_project_pt_cline(g2d_vect_t pt, const g2d_cline_t *line)
{
	return g2d__project_pt_cline(g2d_cvect_t_convfrom_g2d_vect_t(pt), line);
}


G2D_INLINE g2d_calc_t g2d__dist2_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt)
{
	g2d_cvect_t d;
	g2d_calc_t tmp;
	g2d_offs_t o;

	o = g2d__project_pt_cline(pt, line);

	if (g2d_offs_t_lte_g2d_offs_t(o  ,g2d_offs_t_convfrom_double(0.0))) return g2d__distance2(g2d_cvect_t_convfrom_g2d_vect_t(line->p1), pt);
	if (g2d_offs_t_gte_g2d_offs_t(o  ,g2d_offs_t_convfrom_double(1.0))) return g2d__distance2(g2d_cvect_t_convfrom_g2d_vect_t(line->p2), pt);

	d = g2d_cvect_t_convfrom_g2d_vect_t(g2d_vect_t_sub_g2d_vect_t(line->p2  ,line->p1));
	tmp = g2d_calc_t_sub_g2d_calc_t(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_sub_g2d_calc_t((g2d_calc_t_mul_g2d_calc_t(d.y  ,pt.x))  ,(g2d_calc_t_mul_g2d_calc_t(d.x  ,pt.y)) ) ,(g2d_calc_t_mul_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p2.x ) ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.y))) ) ,(g2d_calc_t_mul_g2d_calc_t(g2d_calc_t_convfrom_g2d_coord_t(line->p2.y ) ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.x))));

	return g2d_calc_t_div_g2d_calc_t((g2d_calc_t_mul_g2d_calc_t(tmp  ,tmp))  ,(g2d_calc_t_add_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t(d.x,d.x ) ,g2d_calc_t_mul_g2d_calc_t(d.y,d.y))));
}

G2D_INLINE g2d_calc_t g2d_dist2_cline_pt(const g2d_cline_t *line, g2d_vect_t pt)
{
	return g2d__dist2_cline_pt(line, g2d_cvect_t_convfrom_g2d_vect_t(pt));
}

G2D_INLINE g2d_calc_t g2d__side_cline_pt(const g2d_cline_t *line, g2d_cvect_t pt)
{
	return g2d_calc_t_sub_g2d_calc_t(g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(pt.x  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.x)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.y  ,line->p1.y))) ) ,g2d_calc_t_mul_g2d_calc_t((g2d_calc_t_sub_g2d_calc_t(pt.y  ,g2d_calc_t_convfrom_g2d_coord_t(line->p1.y)))  ,(g2d_calc_t_convfrom_g2d_coord_t(g2d_coord_t_sub_g2d_coord_t(line->p2.x  ,line->p1.x)))));
}

G2D_INLINE g2d_calc_t g2d_side_cline_pt(const g2d_cline_t *line, g2d_vect_t pt)
{
	return g2d__side_cline_pt(line, g2d_cvect_t_convfrom_g2d_vect_t(pt));
}
#endif /* G2D_CLINE_H */
