added new function gimp_bezier_stroke_new_ellipse() that provides a simple

2004-08-21  Sven Neumann  <sven@gimp.org>

	* app/vectors/gimpbezierstroke.[ch]: added new function
	gimp_bezier_stroke_new_ellipse() that provides a simple API to
	create a bezier stroke that represents an ellipse.

	* app/vectors/gimpvectors-import.c: added support for the basic
	SVG shapes "circle" and "ellipse".
This commit is contained in:
Sven Neumann 2004-08-21 13:50:19 +00:00 committed by Sven Neumann
parent 5dd10c748d
commit 6f3c1ae503
4 changed files with 171 additions and 61 deletions

View File

@ -1,3 +1,12 @@
2004-08-21 Sven Neumann <sven@gimp.org>
* app/vectors/gimpbezierstroke.[ch]: added new function
gimp_bezier_stroke_new_ellipse() that provides a simple API to
create a bezier stroke that represents an ellipse.
* app/vectors/gimpvectors-import.c: added support for the basic
SVG shapes "circle" and "ellipse".
2004-08-21 Simon Budig <simon@gimp.org>
* plug-ins/common/gih.c: Fix some GUI issues. Make the relation

View File

@ -1583,20 +1583,20 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
gboolean sweep,
const GimpCoords *end)
{
GimpCoords start;
GimpCoords middle; /* between start and end */
GimpCoords trans_delta;
GimpCoords trans_center;
GimpCoords tmp_center;
GimpCoords center;
GimpCoords ellips[4]; /* control points of untransformed ellipse segment */
GimpCoords ctrl[4]; /* control points of next bezier segment */
GimpCoords start;
GimpCoords middle; /* between start and end */
GimpCoords trans_delta;
GimpCoords trans_center;
GimpCoords tmp_center;
GimpCoords center;
GimpCoords ellips[4]; /* control points of untransformed ellipse segment */
GimpCoords ctrl[4]; /* control points of next bezier segment */
GimpMatrix3 anglerot;
gdouble lambda;
gdouble phi0, phi1, phi2;
gdouble tmpx, tmpy;
gdouble lambda;
gdouble phi1, phi2;
gdouble tmpx, tmpy;
g_return_if_fail (GIMP_IS_BEZIER_STROKE (bez_stroke));
g_return_if_fail (bez_stroke->closed == FALSE);
@ -1615,13 +1615,14 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
gimp_matrix3_rotate (&anglerot, -angle_rad);
gimp_coords_mix (0.5, &start, -0.5, end, &trans_delta);
gimp_matrix3_transform_point (&anglerot, trans_delta.x, trans_delta.y,
gimp_matrix3_transform_point (&anglerot,
trans_delta.x, trans_delta.y,
&tmpx, &tmpy);
trans_delta.x = tmpx;
trans_delta.y = tmpy;
lambda = (trans_delta.x*trans_delta.x / radius_x / radius_x +
trans_delta.y*trans_delta.y / radius_y / radius_y);
lambda = (SQR (trans_delta.x) / SQR (radius_x) +
SQR (trans_delta.y) / SQR (radius_y));
if (lambda < 0.00001)
{
@ -1634,7 +1635,7 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
if (lambda > 1.0)
{
/* The radii are too small for a matching ellipse. We expand them
* so that they fit exacty (center of the ellipse between the
* so that they fit exactly (center of the ellipse between the
* start- and endpoint
*/
radius_x *= sqrt (lambda);
@ -1645,6 +1646,7 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
else
{
gdouble factor = sqrt ((1.0 - lambda) / lambda);
trans_center.x = trans_delta.y * radius_x / radius_y * factor;
trans_center.y = - trans_delta.x * radius_y / radius_x * factor;
}
@ -1659,7 +1661,8 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
gimp_matrix3_rotate (&anglerot, angle_rad);
tmp_center = trans_center;
gimp_matrix3_transform_point (&anglerot, tmp_center.x, tmp_center.y,
gimp_matrix3_transform_point (&anglerot,
tmp_center.x, tmp_center.y,
&tmpx, &tmpy);
tmp_center.x = tmpx;
tmp_center.y = tmpy;
@ -1673,14 +1676,17 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
phi2 = atan2 ((- trans_delta.y - trans_center.y) / radius_y,
(- trans_delta.x - trans_center.x) / radius_x);
if (phi1 < 0) phi1 += 2 * G_PI;
if (phi2 < 0) phi2 += 2 * G_PI;
if (phi1 < 0)
phi1 += 2 * G_PI;
if (phi2 < 0)
phi2 += 2 * G_PI;
while (phi1 < phi2)
phi1 += 2 * G_PI;
if (sweep)
{
while (phi2 < phi1) phi2 += 2 * G_PI;
phi0 = floor (phi1 / G_PI_2) * G_PI_2;
gdouble phi0 = floor (phi1 / G_PI_2) * G_PI_2;
while (phi0 < phi2)
{
@ -1712,9 +1718,7 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
}
else
{
while (phi1 < phi2) phi1 += 2 * G_PI;
phi0 = ceil (phi1 / G_PI_2) * G_PI_2;
gdouble phi0 = ceil (phi1 / G_PI_2) * G_PI_2;
while (phi0 > phi2)
{
@ -1746,6 +1750,34 @@ gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
}
}
GimpStroke *
gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
gdouble radius_x,
gdouble radius_y)
{
GimpStroke *stroke;
GimpCoords a = *center;
GimpCoords b = *center;
if (radius_x > radius_y)
{
a.x -= radius_x;
b.x += radius_x;
}
else
{
a.y -= radius_y;
b.y += radius_y;
}
stroke = gimp_bezier_stroke_new_moveto (&a);
gimp_bezier_stroke_arcto (stroke, radius_x, radius_y, 0, TRUE, FALSE, &b);
gimp_bezier_stroke_arcto (stroke, radius_x, radius_y, 0, TRUE, FALSE, &a);
return stroke;
}
/* helper function to get the associated anchor of a listitem */
@ -1765,6 +1797,7 @@ gimp_bezier_stroke_get_anchor_listitem (GList *list)
return list->next;
g_return_val_if_fail (/* bezier stroke inconsistent! */ FALSE, NULL);
return NULL;
}

View File

@ -66,12 +66,16 @@ void gimp_bezier_stroke_cubicto (GimpStroke *bez_stroke,
const GimpCoords *control2,
const GimpCoords *end);
void gimp_bezier_stroke_arcto (GimpStroke *bez_stroke,
const gdouble radius_x,
const gdouble radius_y,
const gdouble angle_rad,
const gboolean large_arc,
const gboolean sweep,
gdouble radius_x,
gdouble radius_y,
gdouble angle_rad,
gboolean large_arc,
gboolean sweep,
const GimpCoords *end);
GimpStroke * gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
gdouble radius_x,
gdouble radius_y);
GimpAnchor * gimp_bezier_stroke_extend (GimpStroke *stroke,
const GimpCoords *coords,

View File

@ -117,37 +117,43 @@ static const GMarkupParser markup_parser =
};
static void svg_handler_svg_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_svg_end (SvgHandler *handler,
SvgParser *parser);
static void svg_handler_group_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_path_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_line_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_poly_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_svg_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_svg_end (SvgHandler *handler,
SvgParser *parser);
static void svg_handler_group_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_path_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_ellipse_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_line_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static void svg_handler_poly_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser);
static const SvgHandler svg_handlers[] =
{
{ "svg", svg_handler_svg_start, svg_handler_svg_end },
{ "g", svg_handler_group_start, NULL },
{ "path", svg_handler_path_start, NULL },
{ "line", svg_handler_line_start, NULL },
{ "polyline", svg_handler_poly_start, NULL },
{ "polygon", svg_handler_poly_start, NULL }
{ "svg", svg_handler_svg_start, svg_handler_svg_end },
{ "g", svg_handler_group_start, NULL },
{ "path", svg_handler_path_start, NULL },
{ "circle", svg_handler_ellipse_start, NULL },
{ "ellipse", svg_handler_ellipse_start, NULL },
{ "line", svg_handler_line_start, NULL },
{ "polyline", svg_handler_poly_start, NULL },
{ "polygon", svg_handler_poly_start, NULL }
};
@ -586,6 +592,63 @@ svg_handler_path_start (SvgHandler *handler,
handler->paths = g_list_prepend (handler->paths, path);
}
static void
svg_handler_ellipse_start (SvgHandler *handler,
const gchar **names,
const gchar **values,
SvgParser *parser)
{
SvgPath *path = g_new0 (SvgPath, 1);
GimpCoords center = { 0.0, 0.0, 1.0, 0.5, 0.5, 0.5 };
gdouble rx = 0.0;
gdouble ry = 0.0;
while (*names)
{
if (strcmp (*names, "id") == 0 && !path->id)
{
path->id = g_strdup (*values);
}
else if (strcmp (*names, "cx") == 0)
{
center.x = g_ascii_strtod (*values, NULL);
}
else if (strcmp (*names, "cy") == 0)
{
center.y = g_ascii_strtod (*values, NULL);
}
else if (strcmp (*names, "r") == 0)
{
rx = ry = g_ascii_strtod (*values, NULL);
}
else if (strcmp (*names, "rx") == 0)
{
rx = g_ascii_strtod (*values, NULL);
}
else if (strcmp (*names, "ry") == 0)
{
ry = g_ascii_strtod (*values, NULL);
}
else if (strcmp (*names, "transform") == 0 && !handler->transform)
{
GimpMatrix3 matrix;
if (parse_svg_transform (*values, &matrix))
handler->transform = g_memdup (&matrix, sizeof (GimpMatrix3));
}
names++;
values++;
}
if (rx >= 0.0 && ry >= 0.0)
path->strokes = g_list_prepend (path->strokes,
gimp_bezier_stroke_new_ellipse (&center,
rx, ry));
handler->paths = g_list_prepend (handler->paths, path);
}
static void
svg_handler_line_start (SvgHandler *handler,
const gchar **names,
@ -684,7 +747,7 @@ svg_handler_poly_start (SvgHandler *handler,
if ((n > 3) && (n % 2 == 0))
{
points = g_string_sized_new (p - *values + 6);
points = g_string_sized_new (p - *values + 8);
g_string_append_len (points, "M ", 2);
g_string_append_len (points, m, l - m);
@ -868,7 +931,7 @@ parse_svg_viewbox (const gchar *value,
return success;
}
gboolean
static gboolean
parse_svg_transform (const gchar *value,
GimpMatrix3 *matrix)
{
@ -880,7 +943,7 @@ parse_svg_transform (const gchar *value,
gimp_matrix3_identity (matrix);
for (i= 0; value[i]; i++)
for (i = 0; value[i]; i++)
{
/* skip initial whitespace */
while (g_ascii_isspace (value[i]))
@ -918,10 +981,11 @@ parse_svg_transform (const gchar *value,
/* skip whitespace */
while (g_ascii_isspace (value[i]))
i++;
c = value[i];
if (g_ascii_isdigit (c) || c == '+' || c == '-' || c == '.')
{
if (n_args == G_N_ELEMENTS(args))
if (n_args == G_N_ELEMENTS (args))
return FALSE; /* too many args */
args[n_args] = g_ascii_strtod (value + i, &end_ptr);