|
Packit |
bc1512 |
/* This file is part of GEGL editor -- a gtk frontend for GEGL
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
bc1512 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
bc1512 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
bc1512 |
* (at your option) any later version.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
bc1512 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bc1512 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
bc1512 |
* GNU General Public License for more details.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
bc1512 |
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Copyright (C) 2005, 2008 Øyvind Kolås
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "config.h"
|
|
Packit |
bc1512 |
#include "gegl-path-smooth.h"
|
|
Packit |
bc1512 |
#include <gegl.h>
|
|
Packit |
bc1512 |
#include "gegl-path.h"
|
|
Packit |
bc1512 |
#include <math.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static GeglPathList *
|
|
Packit |
bc1512 |
points_to_bezier_path (gdouble coord_x[],
|
|
Packit |
bc1512 |
gdouble coord_y[],
|
|
Packit |
bc1512 |
gint n_coords)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglPathList *ret = NULL;
|
|
Packit |
bc1512 |
gint i;
|
|
Packit |
bc1512 |
gdouble smooth_value;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
smooth_value = 0.8;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!n_coords)
|
|
Packit |
bc1512 |
return NULL;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
ret = gegl_path_list_append (ret, 'M', coord_x[0], coord_y[0]);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (i=1;i
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gdouble x2 = coord_x[i];
|
|
Packit |
bc1512 |
gdouble y2 = coord_y[i];
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gdouble x0,y0,x1,y1,x3,y3;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (i==1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x0=coord_x[i-1];
|
|
Packit |
bc1512 |
y0=coord_y[i-1];
|
|
Packit |
bc1512 |
x1 = coord_x[i-1];
|
|
Packit |
bc1512 |
y1 = coord_y[i-1];
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x0=coord_x[i-2];
|
|
Packit |
bc1512 |
y0=coord_y[i-2];
|
|
Packit |
bc1512 |
x1 = coord_x[i-1];
|
|
Packit |
bc1512 |
y1 = coord_y[i-1];
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (i+1 < n_coords)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x3 = coord_x[i+1];
|
|
Packit |
bc1512 |
y3 = coord_y[i+1];
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x3 = coord_x[i];
|
|
Packit |
bc1512 |
y3 = coord_y[i];
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gdouble xc1 = (x0 + x1) / 2.0;
|
|
Packit |
bc1512 |
gdouble yc1 = (y0 + y1) / 2.0;
|
|
Packit |
bc1512 |
gdouble xc2 = (x1 + x2) / 2.0;
|
|
Packit |
bc1512 |
gdouble yc2 = (y1 + y2) / 2.0;
|
|
Packit |
bc1512 |
gdouble xc3 = (x2 + x3) / 2.0;
|
|
Packit |
bc1512 |
gdouble yc3 = (y2 + y3) / 2.0;
|
|
Packit |
bc1512 |
gdouble len1 = sqrt( (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0) );
|
|
Packit |
bc1512 |
gdouble len2 = sqrt( (x2-x1) * (x2-x1) + (y2-y1) * (y2-y1) );
|
|
Packit |
bc1512 |
gdouble len3 = sqrt( (x3-x2) * (x3-x2) + (y3-y2) * (y3-y2) );
|
|
Packit |
bc1512 |
gdouble k1 = len1 / (len1 + len2);
|
|
Packit |
bc1512 |
gdouble k2 = len2 / (len2 + len3);
|
|
Packit |
bc1512 |
gdouble xm1 = xc1 + (xc2 - xc1) * k1;
|
|
Packit |
bc1512 |
gdouble ym1 = yc1 + (yc2 - yc1) * k1;
|
|
Packit |
bc1512 |
gdouble xm2 = xc2 + (xc3 - xc2) * k2;
|
|
Packit |
bc1512 |
gdouble ym2 = yc2 + (yc3 - yc2) * k2;
|
|
Packit |
bc1512 |
gdouble ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
|
|
Packit |
bc1512 |
gdouble ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
|
|
Packit |
bc1512 |
gdouble ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
|
|
Packit |
bc1512 |
gdouble ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (i==n_coords-1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
ctrl2_x = x2;
|
|
Packit |
bc1512 |
ctrl2_y = y2;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
ret = gegl_path_list_append (ret, 'C', ctrl1_x, ctrl1_y,
|
|
Packit |
bc1512 |
ctrl2_x, ctrl2_y,
|
|
Packit |
bc1512 |
x2, y2);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
return ret;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static GeglPathList *gegl_path_smooth_flatten (GeglPathList *original)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglPathList *ret;
|
|
Packit |
bc1512 |
GeglPathList *iter;
|
|
Packit |
bc1512 |
gdouble *coordsx;
|
|
Packit |
bc1512 |
gdouble *coordsy;
|
|
Packit |
bc1512 |
gboolean is_smooth_path = TRUE;
|
|
Packit |
bc1512 |
gint count;
|
|
Packit |
bc1512 |
gint i;
|
|
Packit |
bc1512 |
/* first we do a run through the path checking it's length
|
|
Packit |
bc1512 |
* and determining whether we can flatten the incoming path
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
for (count=0,iter = original; iter; iter=iter->next)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
switch (iter->d.type)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
case '*':
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
default:
|
|
Packit |
bc1512 |
is_smooth_path=FALSE;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
count ++;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!is_smooth_path)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
return original;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
coordsx = g_new0 (gdouble, count);
|
|
Packit |
bc1512 |
coordsy = g_new0 (gdouble, count);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (i=0, iter = original; iter; iter=iter->next, i++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
coordsx[i] = iter->d.point[0].x;
|
|
Packit |
bc1512 |
coordsy[i] = iter->d.point[0].y;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
ret = points_to_bezier_path (coordsx, coordsy, count);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
g_free (coordsx);
|
|
Packit |
bc1512 |
g_free (coordsy);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return ret;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
void gegl_path_smooth_init (void)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
static gboolean done = FALSE;
|
|
Packit |
bc1512 |
if (done)
|
|
Packit |
bc1512 |
return;
|
|
Packit |
bc1512 |
done = TRUE;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_path_add_type ('*', 2, "path");
|
|
Packit |
bc1512 |
gegl_path_add_flattener (gegl_path_smooth_flatten);
|
|
Packit |
bc1512 |
}
|