/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2019 Tibor 'Igor2' Palinkas
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/camv-rnd
 *    lead developer: http://repo.hu/projects/camv-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#include <librnd/config.h>

#include "obj_arc.h"
#include "obj_any.h"

#include <librnd/hid/hid_inlines.h>
#include "geo.h"
#include <gengeo2d/carc.h>
#include <gengeo2d/sarc.h>

static void camv_arc_free_fields(camv_any_obj_t *obj)
{
	/* no dynamic allocation */
}

static void camv_arc_draw(camv_any_obj_t *obj, rnd_hid_gc_t gc, rnd_xform_mx_t *mx)
{
	rnd_hid_set_line_cap(gc, rnd_cap_round);
	rnd_hid_set_line_width(gc, obj->arc.thick);
	if (mx != NULL) {
		camv_layer_t *ly = obj->arc.parent_layer;
		rnd_coord_t cx = rnd_xform_x((*mx), obj->arc.cx, obj->arc.cy);
		rnd_coord_t cy = rnd_xform_y((*mx), obj->arc.cx, obj->arc.cy);
		double rx = obj->arc.r * ly->mx_sx, ry = obj->arc.r * ly->mx_sy;
		double start= obj->arc.start - ly->mx_rotdeg, delta = obj->arc.delta;

		rnd_render->draw_arc(gc, cx, cy, rx, ry, start, delta);
	}
	else
		rnd_render->draw_arc(gc, obj->arc.cx, obj->arc.cy, obj->arc.r, obj->arc.r, obj->arc.start, obj->arc.delta);
}

static void camv_arc_bbox(camv_any_obj_t *obj)
{
	g2d_sarc_t a;
	g2d_box_t box;

	a.c.c.x = obj->arc.cx;
	a.c.c.y = obj->arc.cy;
	a.c.r = obj->arc.r;
	a.c.start = (180-obj->arc.start) / RND_RAD_TO_DEG;
	a.c.delta = -obj->arc.delta / RND_RAD_TO_DEG;
	a.s.width = obj->arc.thick;
	a.s.cap = G2D_CAP_ROUND;
	box = g2d_sarc_bbox(&a);

	obj->arc.bbox.x1 = box.p1.x; obj->arc.bbox.y1 = box.p1.y;
	obj->arc.bbox.x2 = box.p2.x; obj->arc.bbox.y2 = box.p2.y;
	obj->arc.bbox_valid = 1;
}


static void camv_arc_copy(camv_any_obj_t *dst, const camv_any_obj_t *src)
{
	memcpy(&dst->arc, &src->arc, sizeof(camv_arc_t));
}

static void camv_arc_move(camv_any_obj_t *o, rnd_coord_t dx, rnd_coord_t dy)
{
	o->arc.cx += dx;
	o->arc.cy += dy;
	if (o->arc.bbox_valid) {
		o->arc.bbox.x1 += dx; o->arc.bbox.y1 += dy;
		o->arc.bbox.x2 += dx; o->arc.bbox.y2 += dy;
	}
}

static camv_any_obj_t *camv_arc_alloc(void) { return (camv_any_obj_t *)camv_arc_new(); }

static int camv_arc_isc_box(const camv_any_obj_t *o, const camv_rtree_box_t *box)
{
	g2d_carc_t sa;
	g2d_box_t bx;
	g2d_vect_t ip[8];
	g2d_offs_t offs[8];

	bx.p1.x = box->x1; bx.p1.y = box->y1;
	bx.p2.x = box->x2; bx.p2.y = box->y2;

	sa.c.x = o->arc.cx; sa.c.y = o->arc.cy;
	sa.r = o->arc.r;
	sa.start = o->arc.start; sa.delta = o->arc.delta;
/*	sa.thickness = o->arc.thick */
TODO("geo: use sarc instead of carc");
	return g2d_iscp_carc_box(&sa, &bx, ip, offs);
}



static const camv_objcalls_t camv_arc_calls = {
	camv_arc_alloc,
	camv_arc_free_fields,
	camv_arc_draw,
	camv_arc_bbox,
	camv_arc_copy,
	camv_arc_move,
	camv_arc_isc_box
};

void camv_arc_init(camv_arc_t *arc)
{
	memset(arc, 0, sizeof(camv_arc_t));
	arc->type = CAMV_OBJ_ARC;
	arc->calls = &camv_arc_calls;
}

camv_arc_t *camv_arc_new(void)
{
	camv_arc_t *res = malloc(sizeof(camv_arc_t));
	camv_arc_init(res);
	return res;
}

