summaryrefslogblamecommitdiffstats
path: root/friendfinder/render/line.c
blob: 4a2e0a8045c427089eed4542b5addf3d1208f0cd (plain) (tree)
1
2
3
4
5
6




                  
                 



































































































































































































































































































































































































                                                                                                             
#include <stdio.h>

#include <Evas.h>

#include <math.h>
#include "line.h"

static Evas_Smart *get_smart();

static void _line_object_add(Evas_Object *o);
static void _line_object_del(Evas_Object *o);
static void _line_object_move(Evas_Object *o, Evas_Coord x, Evas_Coord y);
static void _line_object_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h);
static void _line_object_show(Evas_Object *o);
static void _line_object_hide(Evas_Object *o);
static void _line_object_color_set(Evas_Object *o, int r, int g, int b, int a);
static void _line_object_clip_set(Evas_Object *o, Evas_Object *clip);
static void _line_object_clip_unset(Evas_Object *o);

#define SMART_LINE_NAME "e_smart_line"

struct polyline *polyline_empty()
{
	struct polyline *pl;

	pl = (struct polyline *)malloc(sizeof(struct polyline));
	if (pl == NULL)
		return NULL;

	pl->w = 0;
	pl->a = 255;
	pl->r = 0;
	pl->g = 0;
	pl->b = 0;

	pl->points = NULL;
	pl->count = 0;
	pl->mode = 0;

	return pl;
}

void polyline_delete(struct polyline *pl)
{
	free(pl->points);
	free(pl);
}

void polyline_set_color(struct polyline *pl, int r, int g, int b, int a)
{
	pl->a = a;
	pl->r = r;
	pl->g = g;
	pl->b = b;
}

void polyline_set_width(struct polyline *pl, int w)
{
	pl->w = w;
}

void polyline_add_point(struct polyline *pl, struct point p)
{
	pl->points = realloc(pl->points, (pl->count + 1) * sizeof(struct point));
	pl->points[pl->count] = p;
	pl->count++;
}

struct smart_line
{
	Evas_Object *obj;
	Evas_Coord x, y, w, h;

	Evas_Object *clip;
	Evas_Object *poly;
	struct point *points;
	struct polyline *pl;
	int pcount;
};

Evas_Object *e_smart_line_add(Evas *e)
{
	Evas_Object *o;
	struct smart_line *smart;
	
	o = evas_object_smart_add(e, get_smart());
	smart = evas_object_smart_data_get(o);
	if(smart == NULL)
	{
		evas_object_del(o);
		return NULL;
	}
	smart->points = NULL;
	smart->pcount = 0;
	smart->pl = NULL;
	return o;
}

static inline int  
line_cut(struct line l0, struct line l1, struct point *p)
{
	Evas_Coord c1, c2, det, a1, a2, b1, b2;

	b1 = l0.p0.x - l0.p1.x; // b1 = x1 - x2
	a1 = l0.p1.y - l0.p0.y; // a1 = y2 - y1
	c1 = l0.p1.x * l0.p0.y - l0.p0.x * l0.p1.y; // c = x2*y1 - x1*y2;

	b2 = l1.p0.x - l1.p1.x; // b2 = x3 - x4
	a2 = l1.p1.y - l1.p0.y; // a2 = y4 - y3
	c2 = l1.p1.x * l1.p0.y - l1.p0.x * l1.p1.y;

	det = a1 * b2 - a2 * b1;
	if(det == 0) 
		return -1;

	p->x = (b1*c2 - b2*c1)/det;
	p->y = (a2*c1 - a1*c2)/det;
	
	return 0;	
}

static inline struct line
new_line(struct point p0, struct point p1)
{
	struct line l;
	l.p0 = p0;
	l.p1 = p1;
	return l;
}

static inline void 
wide_line(Evas_Coord w, struct line l, struct line *l0, struct line *l1)
{
	Evas_Coord dX, dY, dx, dy;
	double scale, len, ddx, ddy;
		
	dX = l.p1.x - l.p0.x;
	dY = l.p1.y - l.p0.y;
	len = sqrt(dX * dX + dY * dY);
	scale = (double)(w) / (2 * len);
	
	ddx = -scale * (double)dY;
	ddy = scale * (double)dX;
	ddx += (ddx > 0) ? 0.5 : -0.5;
	ddy += (ddy > 0) ? 0.5 : -0.5;
	
	dx = (Evas_Coord)ddx;
	dy = (Evas_Coord)ddy;
		
	l0->p0.x = l.p0.x + dx;
	l0->p0.y = l.p0.y + dy;

	l1->p0.x = l.p0.x - dx;
	l1->p0.y = l.p0.y - dy;

	l0->p1.x = l.p1.x + dx;
	l0->p1.y = l.p1.y + dy;

	l1->p1.x = l.p1.x - dx;
	l1->p1.y = l.p1.y - dy;
}

static int _is_line_valid(struct line *l, int w)
{
	int dx = abs(l->p1.x - l->p0.x);
	int dy = abs(l->p1.y - l->p0.y);
	if(dx < w && dy < w)
		return 0;
	return 1;
}

static void _line_update(struct smart_line *smart, int dx, int dy)
{
	int i;

	evas_object_polygon_points_clear(smart->poly);
	for(i = 0; i < smart->pcount; i++)
	{
//		printf("p[%i]: %i,%i\n", i, poly[i].x, poly[i].y);
		evas_object_polygon_point_add(smart->poly, smart->points[i].x - dx, smart->points[i].y - dy);
	}
	evas_object_show(smart->poly);
}

struct polyline *e_smart_line_get(Evas_Object *o)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);
	return smart->pl;
}

void e_smart_line_set(Evas_Object *o, struct polyline *pl)
{
	int i;
	struct smart_line *smart;
	struct line l0_0 = {{0}};
	struct line l0_1 = {{0}};

	struct point fwd[pl->count];
	struct point bwd[pl->count];
	
	int pcount = 0;
	struct point last;	

	if(pl->count < 1)
		return;
	smart = evas_object_smart_data_get(o);
	last = pl->points[0];
	
	for(i = 1; i < pl->count; i++)
	{
		struct point tmp;
		struct line l = new_line(last, pl->points[i]);
		if(!_is_line_valid(&l, pl->w))
				continue;
		
		if(pcount == 0)
		{	
			wide_line(pl->w, l, &l0_0, &l0_1);
			fwd[pcount] = l0_0.p0;
			bwd[pcount] = l0_1.p0;
			last = pl->points[i];
			pcount++;
			continue;
		}
		if(i >= pl->count - 1)
		{
			fwd[pcount] = l0_0.p1;
			bwd[pcount] = l0_1.p1;
			pcount++;
			break;
		}
	
		struct line l1_0, l1_1;

		wide_line(pl->w, l, &l1_0, &l1_1);
	
		if(line_cut(l0_0, l1_0, &tmp) < 0)
			continue;
		fwd[pcount] = tmp;

		if(line_cut(l0_1, l1_1, &tmp) < 0)
			continue;
		
		bwd[pcount] = tmp;
		last = pl->points[i];
		l0_0 = l1_0;
		l0_1 = l1_1;
		pcount++;
	}
	
	if(smart->points != NULL)
		free(smart->points);
	smart->points = (struct point *)malloc(sizeof(struct point) * pcount * 2);
	smart->pcount = pcount * 2;

	for(i = 0; i < pcount; i++)
	{
		smart->points[i] = fwd[i];
		smart->points[2 * pcount - i - 1] = bwd[i];	
	}
	evas_object_color_set(smart->poly, pl->r, pl->g, pl->b, pl->a);
	_line_update(smart, smart->x, smart->y);
	smart->pl = pl;
}

static void _line_object_add(Evas_Object *o)
{
	struct smart_line *smart;

	smart = calloc(1, sizeof(struct smart_line));
	if (smart == NULL)
		return;

	smart->obj = o;
	smart->x = 0;
	smart->y = 0;
	smart->w = 0;
	smart->h = 0;

	smart->clip = evas_object_rectangle_add(evas_object_evas_get(o));
	evas_object_smart_member_add(smart->clip, o);
	evas_object_color_set(smart->clip, 255, 255, 255, 255);
	evas_object_move(smart->clip, smart->x, smart->y);
	evas_object_resize(smart->clip, smart->w, smart->h);

	smart->poly = evas_object_polygon_add(evas_object_evas_get(o));
	evas_object_smart_member_add(smart->poly, o);
	evas_object_color_set(smart->poly, 255, 255, 255, 255);
	evas_object_move(smart->poly, smart->x, smart->y);
	evas_object_resize(smart->poly, smart->w, smart->h);
	evas_object_show(smart->poly);
	
	evas_object_smart_data_set(o, smart);
}

static void _line_object_del(Evas_Object *o)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	evas_object_del(smart->clip);
	evas_object_del(smart->poly);

	free(smart);
}

static void _line_object_move(Evas_Object *o, Evas_Coord x, Evas_Coord y)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o); 

	smart->x = x;
	smart->y = y;

	_line_update(smart, smart->x, smart->y);
}

static void _line_object_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	smart->w = w;
	smart->h = h;
	evas_object_resize(smart->clip, smart->w, smart->h);
	evas_object_resize(smart->poly, smart->w, smart->h);
}

static void _line_object_show(Evas_Object *o)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	evas_object_show(smart->clip);
}

static void _line_object_hide(Evas_Object *o)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	evas_object_hide(smart->clip);
}

static void _line_object_color_set(Evas_Object *o, int r, int g, int b, int a)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	evas_object_color_set(smart->poly, r, g, b, a);
}

static void _line_object_clip_set(Evas_Object *o, Evas_Object *clip)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);
	
	evas_object_clip_set(smart->clip, clip);
}

static void _line_object_clip_unset(Evas_Object *o)
{
	struct smart_line *smart;
	smart = evas_object_smart_data_get(o);

	evas_object_clip_unset(smart->clip);
}

static Evas_Smart *get_smart()
{
	static Evas_Smart *e_smart_line = NULL;
	
	if(e_smart_line != NULL)
		return e_smart_line;

	e_smart_line = evas_smart_new(SMART_LINE_NAME,
		_line_object_add,
		_line_object_del,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		_line_object_move,
		_line_object_resize,
		_line_object_show,
		_line_object_hide,
		_line_object_color_set,
		_line_object_clip_set,
		_line_object_clip_unset,
		NULL);
	return e_smart_line;
}