[dia] svg-import: some more transform support



commit 65e96f6958c765bbfbe612d1d777a4f4ad45aeaa
Author: Hans Breuer <hans breuer org>
Date:   Tue Jul 26 22:15:52 2011 +0200

    svg-import: some more transform support
    
     - move old matrix functions to it's only user (wanlink.c)
     - implement some of them taking a DiaMatrix*
     - svg-import.c : direct apply of (some) transformation to
       the corresponding object

 lib/geometry.c            |  126 ++++-----------------------------------
 lib/geometry.h            |   13 +----
 lib/libdia.def            |    3 +-
 objects/network/wanlink.c |   72 +++++++++++++++++++++-
 plug-ins/svg/svg-import.c |  147 ++++++++++++++++++++++++++++++++++++--------
 5 files changed, 202 insertions(+), 159 deletions(-)
---
diff --git a/lib/geometry.c b/lib/geometry.c
index 5e5660f..9fe1d52 100644
--- a/lib/geometry.c
+++ b/lib/geometry.c
@@ -412,132 +412,28 @@ distance_ellipse_point(const Point *centre, real width, real height,
     return dist - rad;
 }
 
-
 void
-transform_point (Matrix m, Point *src, Point *dest)
+transform_point (Point *pt, const DiaMatrix *m)
 {
-  real xx, yy, ww;
+  real x, y;
 
-  xx = m[0][0] * src->x + m[0][1] * src->y + m[0][2];
-  yy = m[1][0] * src->x + m[1][1] * src->y + m[1][2];
-  ww = m[2][0] * src->x + m[2][1] * src->y + m[2][2];
+  g_return_if_fail (pt != NULL && m != NULL);
 
-  if (!ww)
-    ww = 1.0;
+  x = pt->x;
+  y = pt->y;
 
-  dest->x = xx / ww;
-  dest->y = yy / ww;
+  pt->x = x * m->xx + y * m->xy + m->x0;
+  pt->y = x * m->yx + y * m->yy + m->y0;
 }
-
 void
-mult_matrix (Matrix m1, Matrix m2)
+transform_bezpoint (BezPoint *bpt, const DiaMatrix *m)
 {
-  Matrix result;
-  int i, j, k;
-
-  for (i = 0; i < 3; i++)
-    for (j = 0; j < 3; j++)
-      {
-	result [i][j] = 0.0;
-	for (k = 0; k < 3; k++)
-	  result [i][j] += m1 [i][k] * m2[k][j];
-      }
-
-  /*  copy the result into matrix 2  */
-  for (i = 0; i < 3; i++)
-    for (j = 0; j < 3; j++)
-      m2 [i][j] = result [i][j];
+  transform_point (&bpt->p1, m);
+  transform_point (&bpt->p2, m);
+  transform_point (&bpt->p3, m);
 }
 
 void
-identity_matrix (Matrix m)
-{
-  int i, j;
-
-  for (i = 0; i < 3; i++)
-    for (j = 0; j < 3; j++)
-      m[i][j] = (i == j) ? 1 : 0;
-
-}
-
-void
-translate_matrix (Matrix m, real x, real y)
-{
-  Matrix trans;
-
-  identity_matrix (trans);
-  trans[0][2] = x;
-  trans[1][2] = y;
-  mult_matrix (trans, m);
-}
-
-void
-scale_matrix (Matrix m, real x, real y)
-{
-  Matrix scale;
-
-  identity_matrix (scale);
-  scale[0][0] = x;
-  scale[1][1] = y;
-  mult_matrix (scale, m);
-}
-
-void
-rotate_matrix (Matrix m, real theta)
-{
-  Matrix rotate;
-  real cos_theta, sin_theta;
-
-  cos_theta = cos (theta);
-  sin_theta = sin (theta);
-
-  identity_matrix (rotate);
-  rotate[0][0] = cos_theta;
-  rotate[0][1] = -sin_theta;
-  rotate[1][0] = sin_theta;
-  rotate[1][1] = cos_theta;
-  mult_matrix (rotate, m);
-}
-
-void
-xshear_matrix (Matrix m, real shear)
-{
-  Matrix shear_m;
-
-  identity_matrix (shear_m);
-  shear_m[0][1] = shear;
-  mult_matrix (shear_m, m);
-}
-
-void
-yshear_matrix (Matrix m, real shear)
-{
-  Matrix shear_m;
-
-  identity_matrix (shear_m);
-  shear_m[1][0] = shear;
-  mult_matrix (shear_m, m);
-}
-
-/*  find the determinate for a 3x3 matrix  */
-G_GNUC_UNUSED static real
-determinate (Matrix m)
-{
-  int i;
-  double det = 0;
-
-  for (i = 0; i < 3; i ++)
-    {
-      det += m[0][i] * m[1][(i+1)%3] * m[2][(i+2)%3];
-      det -= m[2][i] * m[1][(i+1)%3] * m[0][(i+2)%3];
-    }
-
-  return det;
-}
-
-
-
-void
 point_convex(Point *dst, const Point *src1, const Point *src2, real alpha)
 {
   /* Make convex combination of src1 and src2:
diff --git a/lib/geometry.h b/lib/geometry.h
index 19905b0..889e1af 100644
--- a/lib/geometry.h
+++ b/lib/geometry.h
@@ -363,17 +363,8 @@ real distance_bez_shape_point(const BezPoint *b, guint npoints,
 real distance_ellipse_point(const Point *centre, real width, real height,
 			    real line_width, const Point *point);
 
-typedef real  Vector[3];
-typedef Vector  Matrix[3];
-
-void          transform_point             (Matrix, Point *, Point *);
-void          mult_matrix                 (Matrix, Matrix);
-void          identity_matrix             (Matrix);
-void          translate_matrix            (Matrix, real, real);
-void          scale_matrix                (Matrix, real, real);
-void          rotate_matrix               (Matrix, real);
-void          xshear_matrix               (Matrix, real);
-void          yshear_matrix               (Matrix, real);
+void transform_point (Point *pt, const DiaMatrix *m);
+void transform_bezpoint (BezPoint *bpt, const DiaMatrix *m);
 
 real dot2(Point *p1, Point *p2);
 void line_coef(real *a, real *b, real *c, Point *p1, Point *p2);
diff --git a/lib/libdia.def b/lib/libdia.def
index 7b5c200..fa55e43 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -457,7 +457,6 @@ EXPORTS
  give_focus
 ; give_focus_to_object
  
- identity_matrix
  int_rectangle_union
 
  intl_score_locale
@@ -616,6 +615,7 @@ EXPORTS
  point_scale
  point_sub
  transform_point
+ transform_bezpoint
 
  point_get_perp
  three_point_circle
@@ -691,7 +691,6 @@ EXPORTS
 
  reset_foci_on_diagram
 
- rotate_matrix
  nearest_pow
 
  new_text
diff --git a/objects/network/wanlink.c b/objects/network/wanlink.c
index 3b4acf9..e968b3b 100644
--- a/objects/network/wanlink.c
+++ b/objects/network/wanlink.c
@@ -362,6 +362,70 @@ wanlink_load(ObjectNode obj_node, int version, const char *filename)
     return obj;
 }
 
+typedef real  Vector[3];
+typedef Vector  Matrix[3];
+
+static void
+_transform_point (Matrix m, Point *src, Point *dest)
+{
+  real xx, yy, ww;
+
+  xx = m[0][0] * src->x + m[0][1] * src->y + m[0][2];
+  yy = m[1][0] * src->x + m[1][1] * src->y + m[1][2];
+  ww = m[2][0] * src->x + m[2][1] * src->y + m[2][2];
+
+  if (!ww)
+    ww = 1.0;
+
+  dest->x = xx / ww;
+  dest->y = yy / ww;
+}
+static void
+_identity_matrix (Matrix m)
+{
+  int i, j;
+
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      m[i][j] = (i == j) ? 1 : 0;
+
+}
+static void
+_mult_matrix (Matrix m1, Matrix m2)
+{
+  Matrix result;
+  int i, j, k;
+
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      {
+	result [i][j] = 0.0;
+	for (k = 0; k < 3; k++)
+	  result [i][j] += m1 [i][k] * m2[k][j];
+      }
+
+  /*  copy the result into matrix 2  */
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      m2 [i][j] = result [i][j];
+}
+static void
+_rotate_matrix (Matrix m, real theta)
+{
+  Matrix rotate;
+  real cos_theta, sin_theta;
+
+  cos_theta = cos (theta);
+  sin_theta = sin (theta);
+
+  _identity_matrix (rotate);
+  rotate[0][0] = cos_theta;
+  rotate[0][1] = -sin_theta;
+  rotate[1][0] = sin_theta;
+  rotate[1][1] = cos_theta;
+  _mult_matrix (rotate, m);
+}
+
 static void
 wanlink_update_data(WanLink *wanlink)
 {
@@ -417,8 +481,8 @@ wanlink_update_data(WanLink *wanlink)
   wanlink->poly[5].y = (len * 0.55);
   
   /* rotate */
-  identity_matrix (m);
-  rotate_matrix (m, angle);
+  _identity_matrix (m);
+  _rotate_matrix (m, angle);
 
   obj->bounding_box.top = origin.y;
   obj->bounding_box.left = origin.x;
@@ -428,8 +492,8 @@ wanlink_update_data(WanLink *wanlink)
   {
       Point new_pt;
       
-      transform_point (m, &wanlink->poly[i], 
-		       &new_pt);
+      _transform_point (m, &wanlink->poly[i], 
+		        &new_pt);
       point_add (&new_pt, &origin);
       wanlink->poly[i] = new_pt;
       if (wanlink->poly [i].y < obj->bounding_box.top)
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index a95caf0..90a58f5 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -289,6 +289,9 @@ apply_style(DiaObject *obj, xmlNodePtr node, DiaSvgStyle *parent_style)
       g_free(gs);
 }
 
+/* all the basic SVG elements allow their own transformation which
+ * is not directly supported by Dia and also not especially useful 
+ */
 /* read a path */
 static GList *
 read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list) 
@@ -301,7 +304,14 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
     GArray *bezpoints = NULL;
     gboolean closed = FALSE;
     gint i;
-    
+    DiaMatrix *matrix = NULL;
+
+    str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+    if (str) {
+      matrix = dia_svg_parse_transform (str, user_scale);
+      xmlFree (str);
+    }
+
     pathdata = str = (char *) xmlGetProp(node, (const xmlChar *)"d");
     do {
       bezpoints = dia_svg_parse_path (pathdata, &unparsed, &closed);
@@ -331,6 +341,8 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
 	  bcd->points[i].p2.y /= user_scale;
 	  bcd->points[i].p3.x /= user_scale;
 	  bcd->points[i].p3.y /= user_scale;
+	  if (matrix)
+	    transform_bezpoint (&bcd->points[i], matrix);
 	}
 	new_obj = otype->ops->create(NULL, bcd, &h1, &h2);
 	if (!closed)
@@ -347,6 +359,8 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
 
     if (bezpoints)
       g_array_free (bezpoints, TRUE);
+    if (matrix)
+      g_free (matrix);
 
     xmlFree (str);
 
@@ -367,6 +381,13 @@ read_text_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
     gchar *multiline = NULL;
     DiaSvgStyle *gs;
     gboolean any_tspan = FALSE;
+    DiaMatrix *matrix = NULL;
+
+    str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+    if (str) {
+      matrix = dia_svg_parse_transform (str, user_scale);
+      xmlFree (str);
+    }
 
     gs = g_new(DiaSvgStyle, 1);
     dia_svg_style_init (gs, parent_style);
@@ -419,6 +440,11 @@ read_text_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
       str = xmlNodeGetContent(node);
     }
     if(str || multiline) {
+      if (matrix) {
+        /* TODO: transform the text, too - when it is supported */
+	transform_point (&point, matrix);
+	g_free (matrix);
+      }
       new_obj = otype->ops->create(&point, otype->default_user_data,
 				 &h1, &h2);
       list = g_list_append (list, new_obj);
@@ -481,6 +507,13 @@ read_poly_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, char *obj
     xmlChar *str;
     char *tmp;
     int i;
+    DiaMatrix *matrix = NULL;
+
+    str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+    if (str) {
+      matrix = dia_svg_parse_transform (str, user_scale);
+      xmlFree (str);
+    }
     
     str = xmlGetProp(node, (const xmlChar *)"points");
     tmp = (char *) str;
@@ -504,8 +537,12 @@ read_poly_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, char *obj
     for (i = 0; i < pcd->num_points; i++) {
       points[i].x = rarr[2*i];
       points[i].y = rarr[2*i+1];
+      if (matrix)
+        transform_point (&points[i], matrix);
     }
     g_array_free(arr, TRUE);
+    if (matrix)
+      g_free (matrix);
   
     pcd->points = points;
     new_obj = otype->ops->create(NULL, pcd,
@@ -530,19 +567,24 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
   Handle *h1, *h2;
   GPtrArray *props;
   Point start = {0, 0};
+  DiaMatrix *matrix = NULL;
+
+  str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = dia_svg_parse_transform (str, user_scale);
+    xmlFree (str);
+  }
   
   str = xmlGetProp(node, (const xmlChar *)"cx");
   if (str) {
     start.x = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
   }
-  else return list;
   str = xmlGetProp(node, (const xmlChar *)"cy");
   if (str) {
     start.y = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
   }
-  else return list;
   str = xmlGetProp(node, (const xmlChar *)"rx");
   if (str) {
     width = get_value_as_cm((char *) str, NULL)*2;
@@ -553,20 +595,24 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
     height = get_value_as_cm((char *) str, NULL)*2;
     xmlFree(str);
   }
-  str = xmlGetProp(node, (const xmlChar *)"ry");
-  if (str) {
-    height = get_value_as_cm((char *) str, NULL)*2;
-    xmlFree(str);
-  }
+  /* not part of ellipse attributes, just here for circle */
   str = xmlGetProp(node, (const xmlChar *)"r");
   if (str) {
     width = height = get_value_as_cm((char *) str, NULL)*2;
     xmlFree(str);
   }
-  if (width <= 0.0 || height <= 0.0) {
-    g_debug ("Ellipse too small %gx%g", width, height);
-    return list;
+  if (matrix) {
+    /* TODO: transform angle - when it is supported */
+    Point wh = {width, height};
+    transform_point (&wh, matrix);
+    width = wh.x;
+    height = wh.y;
+    transform_point (&start, matrix);
+    g_free (matrix);
   }
+  /* A negative value is an error [...]. A value of zero disables rendering of the element. */
+  if (width <= 0.0 || height <= 0.0)
+    return list;
   new_obj = otype->ops->create(&start, otype->default_user_data,
 				 &h1, &h2);
   apply_style(new_obj, node, parent_style);			
@@ -589,31 +635,44 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
   PointProperty *ptprop;
   GPtrArray *props;
   Point start, end;
+  DiaMatrix *matrix = NULL;
+
+  str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = dia_svg_parse_transform (str, user_scale);
+    xmlFree (str);
+  }
 
   str = xmlGetProp(node, (const xmlChar *)"x1");
   if (str) {
     start.x = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
-  }
-  else return list;
+  } else
+    start.x = 0.0;
   str = xmlGetProp(node, (const xmlChar *)"y1");
   if (str) {
     start.y = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
-  }
-  else return list;
+  } else
+    start.y;
   str = xmlGetProp(node, (const xmlChar *)"x2");
   if (str) {
     end.x = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
-  }
-  else return list;
+  } else
+    end.x = start.x;
   str = xmlGetProp(node, (const xmlChar *)"y2");
   if (str) {
     end.y = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
+  } else
+    end.y = start.y;
+
+  if (matrix) {
+    transform_point (&start, matrix);
+    transform_point (&end, matrix);
+    g_free (matrix);
   }
-  else return list;
 
   new_obj = otype->ops->create(&start, otype->default_user_data,
 				 &h1, &h2);
@@ -642,7 +701,7 @@ static GList *
 read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list) 
 {
   xmlChar *str;
-  real width, height;
+  real width = 0.0, height = 0.0;
   DiaObjectType *otype = object_get_type("Standard - Box");
   DiaObject *new_obj;
   Handle *h1, *h2;
@@ -651,33 +710,36 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
   GPtrArray *props;
   Point start,end;
   real corner_radius = 0.0;
+  DiaMatrix *matrix = NULL;
+
+  str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = dia_svg_parse_transform (str, user_scale);
+    xmlFree (str);
+  }
 
   str = xmlGetProp(node, (const xmlChar *)"x");
   if (str) {
     start.x = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
-  }
-  else 
+  } else 
     start.x = 0.0;
   str = xmlGetProp(node, (const xmlChar *)"y");
   if (str) {
     start.y = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
-  }
-  else 
+  } else 
     start.y = 0.0;
   str = xmlGetProp(node, (const xmlChar *)"width");
   if (str) {
     width = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
   }
-  else return list;
   str = xmlGetProp(node, (const xmlChar *)"height");
   if (str) {
     height = get_value_as_cm((char *) str, NULL);
     xmlFree(str);
   }
-  else return list;
   str = xmlGetProp(node, (const xmlChar *)"rx");
   if (str) {
     corner_radius = get_value_as_cm((char *) str, NULL);
@@ -693,7 +755,16 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
     }
     xmlFree(str);
   }
-  
+
+  if (matrix) {
+    /* TODO: for rotated rects we would need to create a polygon */
+    transform_point (&start, matrix);
+    transform_point (&end, matrix);
+    g_free (matrix);
+  }
+  /* A negative value is an error [...]. A value of zero disables rendering of the element. */
+  if (width <= 0.0 || height <= 0.0)
+    return list; /* just ignore it w/o much complaints */
   new_obj = otype->ops->create(&start, otype->default_user_data,
 				 &h1, &h2);
   list = g_list_append (list, new_obj);
@@ -728,6 +799,13 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, const gc
   xmlChar *str;
   real x = 0, y = 0, width = 0, height = 0;
   DiaObject *new_obj;
+  DiaMatrix *matrix = NULL;
+
+  str = (char *) xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = dia_svg_parse_transform (str, user_scale);
+    xmlFree (str);
+  }
 
   str = xmlGetProp(node, (const xmlChar *)"x");
   if (str) {
@@ -750,7 +828,22 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, const gc
     xmlFree(str);
   }
   /* TODO: aspect ratio? */
- 
+
+  if (matrix) {
+    /* TODO: transform angle - when it is supported */
+    Point xy = {x, y};
+    Point wh = {width, height};
+
+    transform_point (&xy, matrix);
+    transform_point (&wh, matrix);
+    width = wh.x;
+    height = wh.y;
+    x = xy.x;
+    y = xy.y;
+
+    g_free (matrix);
+  }
+
   str = xmlGetProp(node, (const xmlChar *)"xlink:href");
   if (!str) /* this doesn't look right but it appears to work w/o namespace --hb */
     str = xmlGetProp(node, (const xmlChar *)"href");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]