From 7dd98d215c2d7205c4b46eec9615130320c7be20 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Fri, 12 Sep 2003 13:23:01 +0000 Subject: [PATCH] added gimp_matrix3_affine(). 2003-09-12 Sven Neumann * libgimpmath/gimpmatrix.[ch]: added gimp_matrix3_affine(). * app/vectors/gimpvectors-import.c: added (yet unused) funtion to parse SVG transform attributes. * app/vectors/gimpvectors-export.c: fixed a stupid bug. --- ChangeLog | 9 + app/vectors/gimpvectors-export.c | 9 +- app/vectors/gimpvectors-import.c | 233 ++++++++++++++---- devel-docs/ChangeLog | 5 + .../libgimpmath/libgimpmath-sections.txt | 3 +- devel-docs/libgimpmath/tmpl/gimpmatrix.sgml | 38 ++- libgimpmath/gimpmatrix.c | 132 ++++++---- libgimpmath/gimpmatrix.h | 36 +-- 8 files changed, 336 insertions(+), 129 deletions(-) diff --git a/ChangeLog b/ChangeLog index f3c1c6d371..63a488318e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2003-09-12 Sven Neumann + + * libgimpmath/gimpmatrix.[ch]: added gimp_matrix3_affine(). + + * app/vectors/gimpvectors-import.c: added (yet unused) funtion to + parse SVG transform attributes. + + * app/vectors/gimpvectors-export.c: fixed a stupid bug. + 2003-09-12 Michael Natterer * app/core/gimpimage-mask-select.c (gimp_image_mask_select_vectors) diff --git a/app/vectors/gimpvectors-export.c b/app/vectors/gimpvectors-export.c index 4e1e1c4e4e..379b4cdfe8 100644 --- a/app/vectors/gimpvectors-export.c +++ b/app/vectors/gimpvectors-export.c @@ -61,7 +61,6 @@ gimp_vectors_export (const GimpImage *image, GError **error) { FILE *file; - gchar *data; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (vectors == NULL || GIMP_IS_VECTORS (vectors), FALSE); @@ -109,8 +108,6 @@ gimp_vectors_export (const GimpImage *image, return FALSE; } - g_free (data); - return TRUE; } @@ -149,10 +146,8 @@ gimp_vectors_path_data (const GimpVectors *vectors) control_points = gimp_stroke_control_points_get (stroke, &closed); if (! first_stroke) - { - g_string_append_printf (str, "\n "); - } - + g_string_append_printf (str, "\n "); + first_stroke = FALSE; if (GIMP_IS_BEZIER_STROKE (stroke)) diff --git a/app/vectors/gimpvectors-import.c b/app/vectors/gimpvectors-import.c index b219945399..2cb5ee3172 100644 --- a/app/vectors/gimpvectors-import.c +++ b/app/vectors/gimpvectors-import.c @@ -84,12 +84,14 @@ static void parser_end_element (GMarkupParseContext *context, static void parser_start_unknown (VectorsParser *parser); static void parser_end_unknown (VectorsParser *parser); -static void parse_svg_viewbox (VectorsParser *parser, - const gchar *value); -static void parse_path_data (GimpVectors *vectors, - const gchar *data); -static void parser_add_vectors (VectorsParser *parser, - GimpVectors *vectors); +static gboolean parse_svg_viewbox (const gchar *value, + Rectangle *rect); +static gboolean parse_svg_transform (const gchar *value, + GimpMatrix3 *matrix); +static void parse_path_data (GimpVectors *vectors, + const gchar *data); +static void parser_add_vectors (VectorsParser *parser, + GimpVectors *vectors); static const GMarkupParser markup_parser = @@ -202,7 +204,12 @@ parser_start_element (GMarkupParseContext *context, while (*attribute_names) { if (strcmp (*attribute_names, "viewBox") == 0) - parse_svg_viewbox (parser, *attribute_values); + { + Rectangle rect; + + if (parse_svg_viewbox (*attribute_values, &rect)) + parser->viewbox = rect; + } attribute_names++; attribute_values++; @@ -318,6 +325,173 @@ parser_add_vectors (VectorsParser *parser, } +static gboolean +parse_svg_viewbox (const gchar *value, + Rectangle *rect) +{ + gchar *tok; + gchar *str = g_strdup (value); + gboolean success = FALSE; + + tok = strtok (str, ", \t"); + if (tok) + { + rect->x = g_ascii_strtod (tok, NULL); + tok = strtok (NULL, ", \t"); + if (tok) + { + rect->y = g_ascii_strtod (tok, NULL); + tok = strtok (NULL, ", \t"); + if (tok != NULL) + { + rect->w = g_ascii_strtod (tok, NULL); + tok = strtok (NULL, ", \t"); + if (tok) + { + rect->h = g_ascii_strtod (tok, NULL); + success = TRUE; + } + } + } + } + + g_free (str); + + return success; +} + +gboolean +parse_svg_transform (const gchar *value, + GimpMatrix3 *matrix) +{ + gint i; + gchar keyword[32]; + gdouble args[6]; + gint n_args; + gint key_len; + + gimp_matrix3_identity (matrix); + + for (i= 0; value[i]; i++) + { + /* skip initial whitespace */ + while (g_ascii_isspace (value[i])) + i++; + + /* parse keyword */ + for (key_len = 0; key_len < sizeof (keyword); key_len++) + { + gchar c = value[i]; + + if (g_ascii_isalpha (c) || c == '-') + keyword[key_len] = value[i++]; + else + break; + } + + if (key_len >= sizeof (keyword)) + return FALSE; + + keyword[key_len] = '\0'; + + /* skip whitespace */ + while (g_ascii_isspace (value[i])) + i++; + + if (value[i] != '(') + return FALSE; + i++; + + for (n_args = 0; ; n_args++) + { + gchar c; + gchar *end_ptr; + + /* 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)) + return FALSE; /* too many args */ + + args[n_args] = g_ascii_strtod (value + i, &end_ptr); + i = end_ptr - value; + + while (g_ascii_isspace (value[i])) + i++; + + /* skip optional comma */ + if (value[i] == ',') + i++; + } + else if (c == ')') + break; + else + return FALSE; + } + + /* ok, have parsed keyword and args, now modify the transform */ + if (!strcmp (keyword, "matrix")) + { + if (n_args != 6) + return FALSE; + + gimp_matrix3_affine (matrix, + args[0], args[1], + args[2], args[3], + args[4], args[5]); + } + else if (!strcmp (keyword, "translate")) + { + if (n_args == 1) + args[1] = 0.0; + else if (n_args != 2) + return FALSE; + + gimp_matrix3_translate (matrix, args[0], args[1]); + } + else if (!strcmp (keyword, "scale")) + { + if (n_args == 1) + args[1] = args[0]; + else if (n_args != 2) + return FALSE; + + gimp_matrix3_scale (matrix, args[0], args[1]); + } + else if (!strcmp (keyword, "rotate")) + { + if (n_args != 1) + return FALSE; + + gimp_matrix3_rotate (matrix, gimp_deg_to_rad (args[0])); + } + else if (!strcmp (keyword, "skewX")) + { + if (n_args != 1) + return FALSE; + + gimp_matrix3_xshear (matrix, tan (gimp_deg_to_rad (args[0]))); + } + else if (!strcmp (keyword, "skewY")) + { + if (n_args != 1) + return FALSE; + + gimp_matrix3_yshear (matrix, tan (gimp_deg_to_rad (args[0]))); + } + else + { + return FALSE; /* unknown keyword */ + } + } + + return TRUE; +} + + /**********************************************************/ /* Below is the code that parses the actual path data. */ /* */ @@ -344,50 +518,6 @@ static void parse_path_do_cmd (ParsePathContext *ctx, gboolean final); -static void -parse_svg_viewbox (VectorsParser *parser, - const gchar *value) -{ - gint x, y, w, h; - gchar *tok; - gchar *str = g_strdup (value); - gboolean success = FALSE; - - x = y = w = h = 0; - - tok = strtok (str, ", \t"); - if (tok) - { - x = g_ascii_strtod (tok, NULL); - tok = strtok (NULL, ", \t"); - if (tok) - { - y = g_ascii_strtod (tok, NULL); - tok = strtok (NULL, ", \t"); - if (tok != NULL) - { - w = g_ascii_strtod (tok, NULL); - tok = strtok (NULL, ", \t"); - if (tok) - { - h = g_ascii_strtod (tok, NULL); - success = TRUE; - } - } - } - } - - g_free (str); - - if (success) - { - parser->viewbox.x = x; - parser->viewbox.y = y; - parser->viewbox.w = w; - parser->viewbox.h = h; - } -} - static void parse_path_data (GimpVectors *vectors, const gchar *data) @@ -553,7 +683,6 @@ parse_path_data (GimpVectors *vectors, } } - /* supply defaults for missing parameters, assuming relative coordinates are to be interpreted as x,y */ static void diff --git a/devel-docs/ChangeLog b/devel-docs/ChangeLog index 8c0cfb2d1f..f6565f60e2 100644 --- a/devel-docs/ChangeLog +++ b/devel-docs/ChangeLog @@ -1,3 +1,8 @@ +2003-09-12 Sven Neumann + + * libgimpmath/libgimpmath-sections.txt + * libgimpmath/tmpl/gimpmatrix.sgml: updated for new function. + 2003-09-11 Sven Neumann * libgimpwidgets/libgimpwidgets-sections.txt diff --git a/devel-docs/libgimpmath/libgimpmath-sections.txt b/devel-docs/libgimpmath/libgimpmath-sections.txt index 622025bc3c..c030a0ae1f 100644 --- a/devel-docs/libgimpmath/libgimpmath-sections.txt +++ b/devel-docs/libgimpmath/libgimpmath-sections.txt @@ -25,13 +25,14 @@ GimpMatrix4 gimp_matrix2_identity gimp_matrix2_mult gimp_matrix3_identity -gimp_matrix3_transform_point gimp_matrix3_mult gimp_matrix3_translate gimp_matrix3_scale gimp_matrix3_rotate gimp_matrix3_xshear gimp_matrix3_yshear +gimp_matrix3_affine +gimp_matrix3_transform_point gimp_matrix3_determinant gimp_matrix3_invert gimp_matrix3_is_diagonal diff --git a/devel-docs/libgimpmath/tmpl/gimpmatrix.sgml b/devel-docs/libgimpmath/tmpl/gimpmatrix.sgml index ca7785f43b..e0e21a9037 100644 --- a/devel-docs/libgimpmath/tmpl/gimpmatrix.sgml +++ b/devel-docs/libgimpmath/tmpl/gimpmatrix.sgml @@ -70,18 +70,6 @@ basic matrix manipulations and tests. @matrix: - - - - - -@matrix: -@x: -@y: -@newx: -@newy: - - @@ -138,6 +126,32 @@ basic matrix manipulations and tests. @amount: + + + + + +@matrix: +@a: +@b: +@c: +@d: +@e: +@f: + + + + + + + +@matrix: +@x: +@y: +@newx: +@newy: + + diff --git a/libgimpmath/gimpmatrix.c b/libgimpmath/gimpmatrix.c index 61d2c22f4d..6d4eb23996 100644 --- a/libgimpmath/gimpmatrix.c +++ b/libgimpmath/gimpmatrix.c @@ -1,4 +1,4 @@ -/* LIBGIMP - The GIMP Library +/* LIBGIMP - The GIMP Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * gimpmatrix.c @@ -33,7 +33,7 @@ /** * gimp_matrix2_identity: * @matrix: A matrix. - * + * * Sets the matrix to the identity matrix. */ void @@ -49,11 +49,11 @@ gimp_matrix2_identity (GimpMatrix2 *matrix) * gimp_matrix2_mult: * @matrix1: The first input matrix. * @matrix2: The second input matrix which will be overwritten by the result. - * + * * Multiplies two matrices and puts the result into the second one. */ void -gimp_matrix2_mult (const GimpMatrix2 *matrix1, +gimp_matrix2_mult (const GimpMatrix2 *matrix1, GimpMatrix2 *matrix2) { GimpMatrix2 tmp; @@ -73,7 +73,7 @@ gimp_matrix2_mult (const GimpMatrix2 *matrix1, /** * gimp_matrix3_identity: * @matrix: A matrix. - * + * * Sets the matrix to the identity matrix. */ void @@ -93,14 +93,14 @@ gimp_matrix3_identity (GimpMatrix3 *matrix) * @y: The source Y coordinate. * @newx: The transformed X coordinate. * @newy: The transformed Y coordinate. - * + * * Transforms a point in 2D as specified by the transformation matrix. */ void -gimp_matrix3_transform_point (const GimpMatrix3 *matrix, - gdouble x, +gimp_matrix3_transform_point (const GimpMatrix3 *matrix, + gdouble x, gdouble y, - gdouble *newx, + gdouble *newx, gdouble *newy) { gdouble w; @@ -124,11 +124,11 @@ gimp_matrix3_transform_point (const GimpMatrix3 *matrix, * gimp_matrix3_mult: * @matrix1: The first input matrix. * @matrix2: The second input matrix which will be overwritten by the result. - * + * * Multiplies two matrices and puts the result into the second one. */ void -gimp_matrix3_mult (const GimpMatrix3 *matrix1, +gimp_matrix3_mult (const GimpMatrix3 *matrix1, GimpMatrix3 *matrix2) { gint i, j; @@ -157,12 +157,12 @@ gimp_matrix3_mult (const GimpMatrix3 *matrix1, * @matrix: The matrix that is to be translated. * @x: Translation in X direction. * @y: Translation in Y direction. - * + * * Translates the matrix by x and y. */ void -gimp_matrix3_translate (GimpMatrix3 *matrix, - gdouble x, +gimp_matrix3_translate (GimpMatrix3 *matrix, + gdouble x, gdouble y) { gdouble g, h, i; @@ -184,12 +184,12 @@ gimp_matrix3_translate (GimpMatrix3 *matrix, * @matrix: The matrix that is to be scaled. * @x: X scale factor. * @y: Y scale factor. - * - * Scales the matrix by x and y + * + * Scales the matrix by x and y */ void -gimp_matrix3_scale (GimpMatrix3 *matrix, - gdouble x, +gimp_matrix3_scale (GimpMatrix3 *matrix, + gdouble x, gdouble y) { matrix->coeff[0][0] *= x; @@ -205,11 +205,11 @@ gimp_matrix3_scale (GimpMatrix3 *matrix, * gimp_matrix3_rotate: * @matrix: The matrix that is to be rotated. * @theta: The angle of rotation (in radians). - * + * * Rotates the matrix by theta degrees. */ void -gimp_matrix3_rotate (GimpMatrix3 *matrix, +gimp_matrix3_rotate (GimpMatrix3 *matrix, gdouble theta) { gdouble t1, t2; @@ -217,7 +217,7 @@ gimp_matrix3_rotate (GimpMatrix3 *matrix, cost = cos (theta); sint = sin (theta); - + t1 = matrix->coeff[0][0]; t2 = matrix->coeff[1][0]; matrix->coeff[0][0] = cost * t1 - sint * t2; @@ -238,11 +238,11 @@ gimp_matrix3_rotate (GimpMatrix3 *matrix, * gimp_matrix3_xshear: * @matrix: The matrix that is to be sheared. * @amount: X shear amount. - * + * * Shears the matrix in the X direction. */ void -gimp_matrix3_xshear (GimpMatrix3 *matrix, +gimp_matrix3_xshear (GimpMatrix3 *matrix, gdouble amount) { matrix->coeff[0][0] += amount * matrix->coeff[1][0]; @@ -254,11 +254,11 @@ gimp_matrix3_xshear (GimpMatrix3 *matrix, * gimp_matrix3_yshear: * @matrix: The matrix that is to be sheared. * @amount: Y shear amount. - * + * * Shears the matrix in the Y direction. */ void -gimp_matrix3_yshear (GimpMatrix3 *matrix, +gimp_matrix3_yshear (GimpMatrix3 *matrix, gdouble amount) { matrix->coeff[1][0] += amount * matrix->coeff[0][0]; @@ -266,12 +266,58 @@ gimp_matrix3_yshear (GimpMatrix3 *matrix, matrix->coeff[1][2] += amount * matrix->coeff[0][2]; } + +/** + * gimp_matrix3_affine: + * @matrix: The input matrix. + * @a: + * @b: + * @c: + * @d: + * @e: + * @f: + * + * Applies the affine transformation given by six values to @matrix. + * The six values form define an affine transformation matrix as + * illustrated below: + * + * ( a c e ) + * ( b d f ) + * ( 0 0 1 ) + **/ +void +gimp_matrix3_affine (GimpMatrix3 *matrix, + gdouble a, + gdouble b, + gdouble c, + gdouble d, + gdouble e, + gdouble f) +{ + GimpMatrix3 affine; + + affine.coeff[0][0] = a; + affine.coeff[1][0] = b; + affine.coeff[2][0] = 0.0; + + affine.coeff[0][1] = c; + affine.coeff[1][1] = d; + affine.coeff[2][1] = 0.0; + + affine.coeff[0][2] = e; + affine.coeff[1][2] = f; + affine.coeff[2][2] = 1.0; + + gimp_matrix3_mult (&affine, matrix); +} + + /** * gimp_matrix3_determinant: - * @matrix: The input matrix. - * + * @matrix: The input matrix. + * * Calculates the determinant of the given matrix. - * + * * Returns: The determinant. */ gdouble @@ -295,7 +341,7 @@ gimp_matrix3_determinant (const GimpMatrix3 *matrix) /** * gimp_matrix3_invert: * @matrix: The matrix that is to be inverted. - * + * * Inverts the given matrix. */ void @@ -313,7 +359,7 @@ gimp_matrix3_invert (GimpMatrix3 *matrix) inv.coeff[0][0] = (matrix->coeff[1][1] * matrix->coeff[2][2] - matrix->coeff[1][2] * matrix->coeff[2][1]) * det; - + inv.coeff[1][0] = - (matrix->coeff[1][0] * matrix->coeff[2][2] - matrix->coeff[1][2] * matrix->coeff[2][0]) * det; @@ -328,13 +374,13 @@ gimp_matrix3_invert (GimpMatrix3 *matrix) inv.coeff[2][1] = - (matrix->coeff[0][0] * matrix->coeff[2][1] - matrix->coeff[0][1] * matrix->coeff[2][0]) * det; - + inv.coeff[0][2] = (matrix->coeff[0][1] * matrix->coeff[1][2] - matrix->coeff[0][2] * matrix->coeff[1][1]) * det; - + inv.coeff[1][2] = - (matrix->coeff[0][0] * matrix->coeff[1][2] - matrix->coeff[0][2] * matrix->coeff[1][0]) * det; - + inv.coeff[2][2] = (matrix->coeff[0][0] * matrix->coeff[1][1] - matrix->coeff[0][1] * matrix->coeff[1][0]) * det; @@ -348,9 +394,9 @@ gimp_matrix3_invert (GimpMatrix3 *matrix) /** * gimp_matrix3_is_diagonal: * @matrix: The matrix that is to be tested. - * + * * Checks if the given matrix is diagonal. - * + * * Returns: TRUE if the matrix is diagonal. */ gboolean @@ -373,9 +419,9 @@ gimp_matrix3_is_diagonal (const GimpMatrix3 *matrix) /** * gimp_matrix3_is_identity: * @matrix: The matrix that is to be tested. - * + * * Checks if the given matrix is the identity matrix. - * + * * Returns: TRUE if the matrix is the identity matrix. */ gboolean @@ -403,20 +449,20 @@ gimp_matrix3_is_identity (const GimpMatrix3 *matrix) return TRUE; } -/* Check if we'll need to interpolate when applying this matrix. - This function returns TRUE if all entries of the upper left - 2x2 matrix are either 0 or 1 +/* Check if we'll need to interpolate when applying this matrix. + This function returns TRUE if all entries of the upper left + 2x2 matrix are either 0 or 1 */ /** * gimp_matrix3_is_simple: * @matrix: The matrix that is to be tested. - * + * * Checks if we'll need to interpolate when applying this matrix as * a transformation. - * - * Returns: TRUE if all entries of the upper left 2x2 matrix are either + * + * Returns: TRUE if all entries of the upper left 2x2 matrix are either * 0 or 1 */ gboolean diff --git a/libgimpmath/gimpmatrix.h b/libgimpmath/gimpmatrix.h index 6c14a97b9f..0b9960a1b6 100644 --- a/libgimpmath/gimpmatrix.h +++ b/libgimpmath/gimpmatrix.h @@ -44,29 +44,32 @@ struct _GimpMatrix4 void gimp_matrix2_identity (GimpMatrix2 *matrix); -void gimp_matrix2_mult (const GimpMatrix2 *matrix1, +void gimp_matrix2_mult (const GimpMatrix2 *matrix1, GimpMatrix2 *matrix2); void gimp_matrix3_identity (GimpMatrix3 *matrix); -void gimp_matrix3_transform_point (const GimpMatrix3 *matrix, - gdouble x, - gdouble y, - gdouble *newx, - gdouble *newy); -void gimp_matrix3_mult (const GimpMatrix3 *matrix1, +void gimp_matrix3_mult (const GimpMatrix3 *matrix1, GimpMatrix3 *matrix2); -void gimp_matrix3_translate (GimpMatrix3 *matrix, - gdouble x, +void gimp_matrix3_translate (GimpMatrix3 *matrix, + gdouble x, gdouble y); -void gimp_matrix3_scale (GimpMatrix3 *matrix, - gdouble x, +void gimp_matrix3_scale (GimpMatrix3 *matrix, + gdouble x, gdouble y); -void gimp_matrix3_rotate (GimpMatrix3 *matrix, +void gimp_matrix3_rotate (GimpMatrix3 *matrix, gdouble theta); -void gimp_matrix3_xshear (GimpMatrix3 *matrix, +void gimp_matrix3_xshear (GimpMatrix3 *matrix, gdouble amount); -void gimp_matrix3_yshear (GimpMatrix3 *matrix, +void gimp_matrix3_yshear (GimpMatrix3 *matrix, gdouble amount); +void gimp_matrix3_affine (GimpMatrix3 *matrix, + gdouble a, + gdouble b, + gdouble c, + gdouble d, + gdouble e, + gdouble f); + gdouble gimp_matrix3_determinant (const GimpMatrix3 *matrix); void gimp_matrix3_invert (GimpMatrix3 *matrix); @@ -74,6 +77,11 @@ gboolean gimp_matrix3_is_diagonal (const GimpMatrix3 *matrix); gboolean gimp_matrix3_is_identity (const GimpMatrix3 *matrix); gboolean gimp_matrix3_is_simple (const GimpMatrix3 *matrix); +void gimp_matrix3_transform_point (const GimpMatrix3 *matrix, + gdouble x, + gdouble y, + gdouble *newx, + gdouble *newy); void gimp_matrix4_to_deg (const GimpMatrix4 *matrix, gdouble *a,