efl/src/static_libs/triangulator/triangulator_simple.c

160 lines
4.4 KiB
C

#include "triangulator_simple.h"
Triangulator_Simple *
triangulator_simple_new(void)
{
Triangulator_Simple *st = calloc(1, sizeof(Triangulator_Simple));
st->vertices = eina_inarray_new(sizeof(float), 0);
st->stops = eina_inarray_new(sizeof(int), 0);
return st;
}
void
triangulator_simple_free(Triangulator_Simple *st)
{
eina_inarray_free(st->vertices);
eina_inarray_free(st->stops);
}
static void
_add_line(Triangulator_Simple *st, const float x, const float y)
{
float *ptr;
ptr = eina_inarray_grow(st->vertices, 2);
ptr[0] = x;
ptr[1] = y;
if (x > st->maxx)
st->maxx = x;
else if (x < st->minx)
st->minx = x;
if (y > st->maxy)
st->maxy = y;
else if (y < st->miny)
st->miny = y;
}
static void
_calculate_centroid(const Efl_Gfx_Path_Command *cmds, const double *pts, double *cx, double *cy)
{
double sumx = 0, sumy = 0;
int count = 0;
sumx += pts[0];
sumy += pts[1];
for (cmds++, count++, pts+=2; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
{
switch (*cmds)
{
case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
sumx += pts[0];
sumy += pts[1];
pts +=2;
count++;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
sumx += pts[0];
sumy += pts[1];
sumx += pts[2];
sumy += pts[3];
sumx += pts[4];
sumy += pts[5];
pts +=6;
count +=3;
break;
case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
*cx = sumx/count;
*cy = sumy/count;
return;
default:
break;
}
}
//
*cx = sumx/count;
*cy = sumy/count;
}
void
triangulator_simple_process(Triangulator_Simple *st, const Efl_Gfx_Path_Command *cmds, const double *pts, Eina_Bool convex)
{
double bw, bh, cx, cy, x, y, t, one_over_threshold_minus_1;
float *ptr;
int *stop_ptr, threshold, i;
Eina_Bezier b;
eina_inarray_resize(st->vertices, 0);
eina_inarray_resize(st->stops, 0);
if (!convex)
{
_calculate_centroid(cmds, pts, &cx, &cy);
_add_line(st, cx, cy);
}
cx = pts[0];
cy = pts[1];
// The first element is always a moveTo
_add_line(st, cx, cy);
pts += 2;
cmds++;
for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
{
switch (*cmds)
{
case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
// add closing line for the previous contour
_add_line(st, cx, cy);
// update stop array
stop_ptr = eina_inarray_grow(st->stops, 1);
stop_ptr[0] = eina_inarray_count(st->vertices);
// add centroid if not convex
if (!convex)
{
_calculate_centroid(cmds, pts, &cx, &cy);
_add_line(st, cx, cy);
}
cx = pts[0];
cy = pts[1];
_add_line(st, cx, cy);
pts += 2;
break;
case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
_add_line(st, pts[0], pts[1]);
pts += 2;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
ptr = eina_inarray_nth(st->vertices, eina_inarray_count(st->vertices) - 2);
eina_bezier_values_set(&b, ptr[0], ptr[1], pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
eina_bezier_bounds_get(&b, NULL, NULL , &bw, &bh);
threshold = fminf(64, fmaxf(bw, bh) * 3.14f / 6);
if (threshold < 3) threshold = 3;
one_over_threshold_minus_1 = 1.0 / (threshold - 1);
for (i=1; i<threshold; ++i)
{
t = i * one_over_threshold_minus_1;
eina_bezier_point_at(&b, t, &x, &y);
_add_line(st, x, y);
}
pts += 6;
break;
case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
case EFL_GFX_PATH_COMMAND_TYPE_LAST:
case EFL_GFX_PATH_COMMAND_TYPE_END:
break;
}
}
// add closing line for the previous contour
_add_line(st, cx, cy);
// update stop array
stop_ptr = eina_inarray_grow(st->stops, 1);
stop_ptr[0] = eina_inarray_count(st->vertices);
}