/*
 *                            COPYRIGHT
 *
 *  libpolybool, 2D polygon bool operations
 *  Copyright (C) 2023, 2024 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrust in 2023,2024)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA
 *
 *  Contact:
 *    Project page: http://www.repo.hu/projects/librnd
 *    lead developer: http://www.repo.hu/projects/librnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 *
 */

/* poly bool internals */

#ifndef POLYBOOL_PA_H
#define POLYBOOL_PA_H

#include "pa_config.h"

typedef double pa_angle_t;
#define pa_angle_equ(a, b)   ((a) == (b))
#define pa_angle_lt(a, b)    ((a) < (b))
#define pa_angle_gt(a, b)    ((a) > (b))
#define pa_angle_gte(a, b)   ((a) >= (b))
#define pa_angle_lte(a, b)   ((a) <= (b))
#define pa_angle_valid(a)    (((a) >= 0.0) && ((a) <= 4.0))

#define pa_vnode_equ(vna, vnb) Vequ2((vna)->point, (vnb)->point)

typedef enum pa_pline_label_e {
	PA_PLL_UNKNWN  = 0
} pa_pline_label_t;

typedef enum pa_plinept_label_e {
	PA_PTL_UNKNWN  = 0
} pa_plinept_label_t;

#define PA_ISC_TOUCHES 99


enum {
	pa_err_ok = 0
};

/* A segment is an object of the pline between ->v and ->v->next, upgraded
   with a bounding box so that it can be added to an rtree. Also remembers
   its parent pline, plus random temporary fields used in the calculations */
typedef struct pa_seg_s {
	rnd_box_t box;
	rnd_vnode_t *v;
	rnd_pline_t *p;
} pa_seg_t;

void rnd_poly_copy_edge_tree(rnd_pline_t *dst, const rnd_pline_t *src);

#include "pb2_geo_raw.h"

/* Returns whether pl intersects with the line segment specified in lx;ly; if
   it does, and cx and cy are not NULL, fill in cx;cy with the first
   intersection point */
rnd_bool rnd_pline_isect_line(rnd_pline_t *pl, rnd_coord_t lx1, rnd_coord_t ly1, rnd_coord_t lx2, rnd_coord_t ly2, rnd_coord_t *cx, rnd_coord_t *cy);

/* Update the bbox of pl using pt's coords */
RND_INLINE void pa_pline_box_bump_pt(rnd_pline_t *pl, const rnd_vector_t pt)
{
	if (pt[0]     < pl->xmin) pl->xmin = pt[0];
	if ((pt[0]+1) > pl->xmax) pl->xmax = pt[0]+1;
	if (pt[1]     < pl->ymin) pl->ymin = pt[1];
	if ((pt[1]+1) > pl->ymax) pl->ymax = pt[1]+1;
}

RND_INLINE void pa_pline_box_bump_curve(rnd_pline_t *pl, rnd_vnode_t *v)
{
	rnd_rtree_box_t bb;

	switch(v->flg.curve_type) {
		case RND_VNODE_LINE: pa_pline_box_bump_pt(pl, v->point); break;
		case RND_VNODE_ARC:
			pb2_raw_arc_bbox(&bb, v->point, v->next->point, v->curve.arc.center, v->curve.arc.adir);
			if (bb.x1 < pl->xmin) pl->xmin = bb.x1;
			if (bb.y1 < pl->ymin) pl->ymin = bb.y1;
			if (bb.x2 > pl->xmax) pl->xmax = bb.x2;
			if (bb.y2 > pl->ymax) pl->ymax = bb.y2;
			break;
	}
}


int rnd_polyarea_boolean_free_nochk(rnd_polyarea_t *a_, rnd_polyarea_t *b_, rnd_polyarea_t **res, int op);

int pa_pline_is_point_on_curve(pa_seg_t *s, rnd_vector_t pt);

void pa_calc_angle_nn(pa_angle_t *dst, rnd_vector_t PT, rnd_vector_t OTHER);

void pa_calc_angle_n0_dbl(pa_angle_t *dst, double VECT[]);

#define pa_swap(type,a,b) \
do { \
	type __tmp__ = a; \
	a = b; \
	b = __tmp__; \
} while(0)


/* Returns the number of intersection points of curves starting from a1 and a2:
   0 if there's no intersection, 1 if there's a single intersection or 2 on
   overlap or 2 intersections (if either curve is an arc) */
int rnd_pa_curves_isc(rnd_vnode_t *a1, rnd_vnode_t *a2, rnd_vector_t i1, rnd_vector_t i2);

/* Wrapper around gengeo2d's iscp_cline_cline_o() */
int pb2_iscp_cline_cline_o(rnd_vector_t l1a, rnd_vector_t l1b, rnd_vector_t l2a, rnd_vector_t l2b, rnd_vector_t ipo[2], double offs[2], int always_offs);


#endif
