[dia] [transform] svg: more transformation support for Standard objects
- From: Hans Breuer <hans src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] [transform] svg: more transformation support for Standard objects
- Date: Wed, 1 Oct 2014 19:59:30 +0000 (UTC)
commit d5d5b662517bbf7c67cc8832b545ba8d47b80833
Author: Hans Breuer <hans breuer org>
Date: Wed Oct 1 20:20:31 2014 +0200
[transform] svg: more transformation support for Standard objects
New optional method DiaObject::transform() to apply an affine transformation
to the object. Immediately visible effect - without SVG - is rotation support
for 'Standard - Box' and 'Standard - Ellipse'.
'Standard - Text' and 'Standard - Image' are not fully supported yet, because
they require significant work on the renderer level.
Standard - Arc, Outline and ZigZagLine are not included because they wont be
used from SVG and the direct support is considered pointless.
Currently the intended main use-case is improved transformation from SVG
especially on the level of single elements. The included test file
transform-variations.svg shows the issues solved and open.
lib/group.c | 4 +-
lib/group.h | 1 -
lib/libdia.def | 2 +-
lib/object.h | 25 ++++++--
lib/standard-path.c | 19 ++++++
objects/standard/bezier.c | 16 +++++
objects/standard/beziergon.c | 16 +++++
objects/standard/box.c | 126 +++++++++++++++++++++++++++++++-----
objects/standard/ellipse.c | 120 ++++++++++++++++++++++++++++++++---
objects/standard/image.c | 30 +++++++++
objects/standard/line.c | 14 ++++
objects/standard/polygon.c | 17 +++++
objects/standard/polyline.c | 17 +++++
plug-ins/svg/svg-import.c | 130 ++++++++++++++------------------------
samples/transform-variations.svg | 98 ++++++++++++++++++++++++++++
15 files changed, 518 insertions(+), 117 deletions(-)
---
diff --git a/lib/group.c b/lib/group.c
index 86d8e49..879ce64 100644
--- a/lib/group.c
+++ b/lib/group.c
@@ -68,6 +68,7 @@ static DiaObject *group_copy(Group *group);
static const PropDescription *group_describe_props(Group *group);
static void group_get_props(Group *group, GPtrArray *props);
static void group_set_props(Group *group, GPtrArray *props);
+static void group_transform (Group *group, const DiaMatrix *m);
static ObjectOps group_ops = {
(DestroyFunc) group_destroy,
@@ -85,6 +86,7 @@ static ObjectOps group_ops = {
(SetPropsFunc) group_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) group_apply_properties_list,
+ (TransformFunc) group_transform
};
DiaObjectType group_type = {
@@ -888,7 +890,7 @@ group_prop_change_free(GroupPropChange *change)
g_list_free(change->changes_per_object);
}
-void
+static void
group_transform (Group *group, const DiaMatrix *m)
{
g_return_if_fail (m != NULL);
diff --git a/lib/group.h b/lib/group.h
index ce3705e..9059008 100644
--- a/lib/group.h
+++ b/lib/group.h
@@ -33,7 +33,6 @@ DiaObject *group_create_with_matrix(GList *objects, DiaMatrix *matrix);
GList *group_objects(DiaObject *group);
void group_destroy_shallow(DiaObject *group);
-void group_transform (Group *group, const DiaMatrix *mat);
const DiaMatrix *group_get_transform (Group *group);
#define IS_GROUP(obj) ((obj)->type == &group_type)
diff --git a/lib/libdia.def b/lib/libdia.def
index e56ed53..26026dc 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -300,6 +300,7 @@ EXPORTS
pixbuf_decode_base64
dia_path_renderer_get_type
+ path_build_ellipse
dia_pattern_new
dia_pattern_add_color
@@ -491,7 +492,6 @@ EXPORTS
group_destroy_shallow
group_objects
group_type
- group_transform
get_active_focus
give_focus
diff --git a/lib/object.h b/lib/object.h
index 84bad53..637459f 100644
--- a/lib/object.h
+++ b/lib/object.h
@@ -403,6 +403,20 @@ typedef DiaMenu *(*ObjectMenuFunc) (DiaObject* obj, Point *position);
*/
typedef gboolean (*TextEditFunc) (DiaObject *obj, Text *text, TextEditState state, gchar *textchange);
+/*!
+ * \brief Transform the object with the given matrix
+ *
+ * This function - if not null - will apply the transformation matrix to the
+ * object. It should be implemented for every standard object, because it's
+ * main use-case is the support of transformations from SVG.
+ *
+ * @param obj Explicit this pointer
+ * @param m The transformation matrix
+ * @returns TRUE if the matrix can be applied to the object, FALSE otherwise.
+ * \public \memberof _DiaObject
+ */
+typedef gboolean (*TransformFunc) (DiaObject *obj, const DiaMatrix *m);
+
/*************************************
** The functions provided in object.c
*************************************/
@@ -479,14 +493,15 @@ struct _ObjectOps {
TextEditFunc edit_text;
ApplyPropertiesListFunc apply_properties_list;
-
+ /*! check for NULL before calling */
+ TransformFunc transform;
/*!
Unused places (for extension).
These should be NULL for now. In the future they might be used.
Then an older object will be binary compatible, because all new code
checks if new ops are supported (!= NULL)
*/
- void (*(unused[4]))(DiaObject *obj,...);
+ void (*(unused[3]))(DiaObject *obj,...);
};
/*!
@@ -498,7 +513,7 @@ struct _ObjectOps {
when connection objects. (Then handles and
connections are changed).
- position is not necessarly the corner of the object, but rather
+ position is not necessarily the corner of the object, but rather
some 'good' spot on it which will be natural to snap to.
*/
struct _DiaObject {
@@ -540,13 +555,13 @@ struct _DiaObject {
* should not be accessed directly, but through dia_object_get_bounding_box().
* Note that handles and connection points are not included by this, but
* added by that which needs it.
- * Internal: If this is set to a 0x0 box, returns bounding_box. That is for
+ * Internal: If this is set to a NULL, returns bounding_box. That is for
* those objects that don't actually calculate it, but can just use the BB.
* Since handles and CPs are not in the BB, that will be the case for most
* objects.
*/
Rectangle *enclosing_box;
- /*! Metainfo of the object, should not be manipulated directy. Use dia_object_set_meta() */
+ /*! Metainfo of the object, should not be manipulated directly. Use dia_object_set_meta() */
GHashTable *meta;
};
diff --git a/lib/standard-path.c b/lib/standard-path.c
index 82036d2..0da1645 100644
--- a/lib/standard-path.c
+++ b/lib/standard-path.c
@@ -186,6 +186,7 @@ static DiaMenu *stdpath_get_object_menu(StdPath *stdpath,
Point *clickedpoint);
static void stdpath_get_props(StdPath *stdpath, GPtrArray *props);
static void stdpath_set_props(StdPath *stdpath, GPtrArray *props);
+static gboolean stdpath_transform(StdPath *stdpath, const DiaMatrix *m);
static ObjectOps stdpath_ops = {
(DestroyFunc) stdpath_destroy,
@@ -203,6 +204,7 @@ static ObjectOps stdpath_ops = {
(SetPropsFunc) stdpath_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) stdpath_transform,
};
/*!
@@ -1030,6 +1032,23 @@ stdpath_select (StdPath *stdpath, Point *clicked_point,
{
stdpath_update_handles (stdpath);
}
+/*!
+ * \brief Change the object state regarding selection
+ * \memberof _StdPath
+ */
+static gboolean
+stdpath_transform(StdPath *stdpath, const DiaMatrix *m)
+{
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < stdpath->num_points; i++)
+ transform_bezpoint (&stdpath->points[i], m);
+
+ stdpath_update_data(stdpath);
+ return TRUE;
+}
gboolean
text_to_path (const Text *text, GArray *points)
diff --git a/objects/standard/bezier.c b/objects/standard/bezier.c
index caa64a1..005d503 100644
--- a/objects/standard/bezier.c
+++ b/objects/standard/bezier.c
@@ -85,6 +85,7 @@ static void bezierline_save(Bezierline *bezierline, ObjectNode obj_node,
DiaContext *ctx);
static DiaObject *bezierline_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *bezierline_get_object_menu(Bezierline *bezierline, Point *clickedpoint);
+static gboolean bezierline_transform(Bezierline *bezierline, const DiaMatrix *m);
static void compute_gap_points(Bezierline *bezierline, Point *gap_points);
static real approx_bez_length(BezierConn *bez);
@@ -129,6 +130,7 @@ static ObjectOps bezierline_ops = {
(SetPropsFunc) bezierline_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) bezierline_transform,
};
static PropNumData gap_range = { -G_MAXFLOAT, G_MAXFLOAT, 0.1};
@@ -812,3 +814,17 @@ bezierline_get_object_menu(Bezierline *bezierline, Point *clickedpoint)
(ctype != BEZ_CORNER_CUSP);
return &bezierline_menu;
}
+
+static gboolean
+bezierline_transform(Bezierline *bezierline, const DiaMatrix *m)
+{
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < bezierline->bez.bezier.num_points; i++)
+ transform_bezpoint (&bezierline->bez.bezier.points[i], m);
+
+ bezierline_update_data(bezierline);
+ return TRUE;
+}
diff --git a/objects/standard/beziergon.c b/objects/standard/beziergon.c
index 0ae7456..52d1b1a 100644
--- a/objects/standard/beziergon.c
+++ b/objects/standard/beziergon.c
@@ -88,6 +88,7 @@ static void beziergon_save(Beziergon *beziergon, ObjectNode obj_node,
static DiaObject *beziergon_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *beziergon_get_object_menu(Beziergon *beziergon,
Point *clickedpoint);
+static gboolean beziergon_transform(Beziergon *beziergon, const DiaMatrix *m);
static ObjectTypeOps beziergon_type_ops =
{
@@ -155,6 +156,7 @@ static ObjectOps beziergon_ops = {
(SetPropsFunc) beziergon_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) beziergon_transform,
};
static void
@@ -545,3 +547,17 @@ beziergon_get_object_menu(Beziergon *beziergon, Point *clickedpoint)
beziergon_menu_items[1].active = beziergon->bezier.bezier.num_points > 3;
return &beziergon_menu;
}
+
+static gboolean
+beziergon_transform(Beziergon *beziergon, const DiaMatrix *m)
+{
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < beziergon->bezier.bezier.num_points; i++)
+ transform_bezpoint (&beziergon->bezier.bezier.points[i], m);
+
+ beziergon_update_data(beziergon);
+ return TRUE;
+}
diff --git a/objects/standard/box.c b/objects/standard/box.c
index 64dac85..e855d02 100644
--- a/objects/standard/box.c
+++ b/objects/standard/box.c
@@ -31,6 +31,7 @@
#include "attributes.h"
#include "properties.h"
#include "create.h"
+#include "message.h"
#include "pattern.h"
#include "tool-icons.h"
@@ -69,6 +70,7 @@ struct _Box {
real corner_radius;
AspectType aspect;
DiaPattern *pattern;
+ real angle; /*!< between [-45°-45°] to simplify connection point handling */
};
static struct _BoxProperties {
@@ -99,6 +101,7 @@ static void box_set_props(Box *box, GPtrArray *props);
static void box_save(Box *box, ObjectNode obj_node, DiaContext *ctx);
static DiaObject *box_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *box_get_object_menu(Box *box, Point *clickedpoint);
+static gboolean box_transform(Box *box, const DiaMatrix *m);
static ObjectTypeOps box_type_ops =
{
@@ -121,10 +124,12 @@ static PropOffset box_offsets[] = {
{ "line_join", PROP_TYPE_ENUM, offsetof(Box, line_join) },
{ "corner_radius", PROP_TYPE_REAL, offsetof(Box, corner_radius) },
{ "pattern", PROP_TYPE_PATTERN, offsetof(Box, pattern) },
+ { "angle", PROP_TYPE_REAL, offsetof(Box, angle) },
{ NULL, 0, 0 }
};
static PropNumData corner_radius_data = { 0.0, 10.0, 0.1 };
+static PropNumData angle_data = { -45, 45, 1 };
static PropEnumData prop_aspect_data[] = {
{ N_("Free"), FREE_ASPECT },
@@ -145,6 +150,8 @@ static PropDescription box_props[] = {
{ "aspect", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE,
N_("Aspect ratio"), NULL, prop_aspect_data },
PROP_STD_PATTERN,
+ { "angle", PROP_TYPE_REAL, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
+ N_("Rotation"), N_("Rotation angle"), &angle_data },
PROP_DESC_END
};
@@ -179,6 +186,7 @@ static ObjectOps box_ops = {
(SetPropsFunc) box_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) box_transform,
};
static void
@@ -189,17 +197,50 @@ box_set_props(Box *box, GPtrArray *props)
box_update_data(box);
}
+static void
+_box_get_poly (const Box *box, Point corners[4])
+{
+ const Element *elem = &box->element;
+
+ corners[0] = elem->corner;
+ corners[1] = corners[0];
+ corners[1].x += elem->width;
+ corners[2] = corners[1];
+ corners[2].y += elem->height;
+ corners[3] = corners[2];
+ corners[3].x -= elem->width;
+
+ if (box->angle != 0) {
+ real cx = elem->corner.x + elem->width / 2.0;
+ real cy = elem->corner.y + elem->height / 2.0;
+ DiaMatrix m = { 1.0, 0.0, 0.0, 1.0, cx, cy };
+ DiaMatrix t = { 1.0, 0.0, 0.0, 1.0, -cx, -cy };
+ int i;
+
+ dia_matrix_set_angle_and_scales (&m, G_PI*box->angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ for (i = 0; i < 4; ++i)
+ transform_point (&corners[i], &m);
+ }
+}
+
static real
box_distance_from(Box *box, Point *point)
{
Element *elem = &box->element;
- Rectangle rect;
- rect.left = elem->corner.x - box->border_width/2;
- rect.right = elem->corner.x + elem->width + box->border_width/2;
- rect.top = elem->corner.y - box->border_width/2;
- rect.bottom = elem->corner.y + elem->height + box->border_width/2;
- return distance_rectangle_point(&rect, point);
+ if (box->angle == 0) {
+ Rectangle rect;
+ rect.left = elem->corner.x - box->border_width/2;
+ rect.right = elem->corner.x + elem->width + box->border_width/2;
+ rect.top = elem->corner.y - box->border_width/2;
+ rect.bottom = elem->corner.y + elem->height + box->border_width/2;
+ return distance_rectangle_point(&rect, point);
+ } else {
+ Point corners[4];
+ _box_get_poly (box, corners);
+ return distance_polygon_point (corners, 4, box->border_width, point);
+ }
}
static void
@@ -326,31 +367,28 @@ box_draw(Box *box, DiaRenderer *renderer)
if (renderer_ops->is_capable_to(renderer, RENDER_PATTERN))
renderer_ops->set_pattern (renderer, box->pattern);
}
- /* we only want separate calls for potential pattern fill */
- if (box->corner_radius > 0) {
+ if (box->angle == 0) {
renderer_ops->draw_rounded_rect (renderer,
&elem->corner, &lr_corner,
&fill, &box->border_color,
box->corner_radius);
} else {
- renderer_ops->draw_rect(renderer,
- &elem->corner,
- &lr_corner,
- &fill, &box->border_color);
+ Point poly[4];
+ _box_get_poly (box, poly);
+ renderer_ops->draw_polygon (renderer, poly, 4, &fill, &box->border_color);
}
if (renderer_ops->is_capable_to(renderer, RENDER_PATTERN))
renderer_ops->set_pattern (renderer, NULL);
} else {
- if (box->corner_radius > 0) {
+ if (box->angle == 0) {
renderer_ops->draw_rounded_rect (renderer,
&elem->corner, &lr_corner,
NULL, &box->border_color,
box->corner_radius);
} else {
- renderer_ops->draw_rect (renderer,
- &elem->corner,
- &lr_corner,
- NULL, &box->border_color);
+ Point poly[4];
+ _box_get_poly (box, poly);
+ renderer_ops->draw_polygon (renderer, poly, 4, &box->inner_color, &box->border_color);
}
}
}
@@ -393,6 +431,18 @@ box_update_data(Box *box)
box->connections[8].pos.x = elem->corner.x + elem->width / 2.0;
box->connections[8].pos.y = elem->corner.y + elem->height / 2.0;
+ if (box->angle != 0) {
+ real cx = elem->corner.x + elem->width / 2.0;
+ real cy = elem->corner.y + elem->height / 2.0;
+ DiaMatrix m = { 1.0, 0.0, 0.0, 1.0, cx, cy };
+ DiaMatrix t = { 1.0, 0.0, 0.0, 1.0, -cx, -cy };
+ int i;
+
+ dia_matrix_set_angle_and_scales (&m, G_PI*box->angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ for (i = 0; i < 8; ++i)
+ transform_point (&box->connections[i].pos, &m);
+ }
box->connections[0].directions = DIR_NORTH|DIR_WEST;
box->connections[1].directions = DIR_NORTH;
box->connections[2].directions = DIR_NORTH|DIR_EAST;
@@ -455,6 +505,7 @@ box_create(Point *startpoint,
box->show_background = default_properties.show_background;
box->corner_radius = default_properties.corner_radius;
box->aspect = default_properties.aspect;
+ box->angle = 0.0;
element_init(elem, 8, NUM_CONNECTIONS);
@@ -505,6 +556,7 @@ box_copy(Box *box)
newbox->dashlength = box->dashlength;
newbox->corner_radius = box->corner_radius;
newbox->aspect = box->aspect;
+ newbox->angle = box->angle;
if (box->pattern)
newbox->pattern = g_object_ref (box->pattern);
@@ -563,6 +615,11 @@ box_save(Box *box, ObjectNode obj_node, DiaContext *ctx)
if (box->pattern)
data_add_pattern(new_attribute(obj_node, "pattern"),
box->pattern, ctx);
+
+ if (box->angle != 0.0)
+ data_add_real(new_attribute(obj_node, "angle"),
+ box->angle, ctx);
+
}
static DiaObject *
@@ -632,6 +689,11 @@ box_load(ObjectNode obj_node, int version, DiaContext *ctx)
if (attr != NULL)
box->pattern = data_pattern(attribute_first_data(attr), ctx);
+ box->angle = 0.0;
+ attr = object_find_attribute(obj_node, "angle");
+ if (attr != NULL)
+ box->angle = data_real(attribute_first_data(attr), ctx);
+
element_init(elem, 8, NUM_CONNECTIONS);
for (i=0;i<NUM_CONNECTIONS;i++) {
@@ -744,3 +806,33 @@ box_get_object_menu(Box *box, Point *clickedpoint)
return &box_menu;
}
+
+static gboolean
+box_transform(Box *box, const DiaMatrix *m)
+{
+ real a, sx, sy;
+
+ g_return_val_if_fail(m != NULL, FALSE);
+
+ if (!dia_matrix_get_angle_and_scales (m, &a, &sx, &sy)) {
+ dia_log_message ("box_transform() can't convert given matrix");
+ return FALSE;
+ } else {
+ real width = box->element.width * sx;
+ real height = box->element.height * sy;
+ real angle = a*180/G_PI;
+ Point c = { box->element.corner.x + width/2.0, box->element.corner.y + height/2.0 };
+
+ /* rotation is invariant to the center */
+ transform_point (&c, m);
+ /* XXX: we have to bring angle in range [-45..45] which may swap width and height */
+ box->angle = angle;
+ box->element.width = width;
+ box->element.height = height;
+ box->element.corner.x = c.x - width / 2.0;
+ box->element.corner.y = c.y - height / 2.0;
+ }
+
+ box_update_data(box);
+ return TRUE;
+}
diff --git a/objects/standard/ellipse.c b/objects/standard/ellipse.c
index 1b4a409..7496463 100644
--- a/objects/standard/ellipse.c
+++ b/objects/standard/ellipse.c
@@ -31,6 +31,8 @@
#include "attributes.h"
#include "properties.h"
#include "pattern.h"
+#include "diapathrenderer.h"
+#include "message.h"
#include "tool-icons.h"
@@ -65,6 +67,7 @@ struct _Ellipse {
LineStyle line_style;
real dashlength;
DiaPattern *pattern;
+ real angle; /*!< between [-45�-45�] to simplify connection point handling */
};
static struct _EllipseProperties {
@@ -93,6 +96,7 @@ static void ellipse_set_props(Ellipse *ellipse, GPtrArray *props);
static void ellipse_save(Ellipse *ellipse, ObjectNode obj_node, DiaContext *ctx);
static DiaObject *ellipse_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *ellipse_get_object_menu(Ellipse *ellipse, Point *clickedpoint);
+static gboolean ellipse_transform(Ellipse *ellipse, const DiaMatrix *m);
static ObjectTypeOps ellipse_type_ops =
{
@@ -113,9 +117,12 @@ static PropOffset ellipse_offsets[] = {
{ "line_style", PROP_TYPE_LINESTYLE,
offsetof(Ellipse, line_style), offsetof(Ellipse, dashlength) },
{ "pattern", PROP_TYPE_PATTERN, offsetof(Ellipse, pattern) },
+ { "angle", PROP_TYPE_REAL, offsetof(Ellipse, angle) },
{ NULL, 0, 0 }
};
+static PropNumData angle_data = { -45, 45, 1 };
+
static PropEnumData prop_aspect_data[] = {
{ N_("Free"), FREE_ASPECT },
{ N_("Fixed"), FIXED_ASPECT },
@@ -132,6 +139,8 @@ static PropDescription ellipse_props[] = {
{ "aspect", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE,
N_("Aspect ratio"), NULL, prop_aspect_data },
PROP_STD_PATTERN,
+ { "angle", PROP_TYPE_REAL, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
+ N_("Rotation"), N_("Rotation angle"), &angle_data },
PROP_DESC_END
};
@@ -166,6 +175,7 @@ static ObjectOps ellipse_ops = {
(SetPropsFunc) ellipse_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) ellipse_transform,
};
static void
@@ -178,6 +188,24 @@ ellipse_set_props(Ellipse *ellipse, GPtrArray *props)
ellipse_update_data(ellipse);
}
+static GArray *
+_ellipse_to_path (Ellipse *ellipse, Point *center)
+{
+ Element *elem = &ellipse->element;
+ DiaMatrix m = { 1.0, 0.0, 0.0, 1.0, center->x, center->y };
+ DiaMatrix t = { 1.0, 0.0, 0.0, 1.0, -center->x, -center->y };
+ GArray *path;
+ int i;
+
+ dia_matrix_set_angle_and_scales (&m, G_PI*ellipse->angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ path = g_array_new (FALSE, FALSE, sizeof(BezPoint));
+ path_build_ellipse (path, center, elem->width, elem->height);
+ for (i = 0; i < path->len; ++i)
+ transform_bezpoint (&g_array_index (path, BezPoint, i), &m);
+ return path;
+}
+
static real
ellipse_distance_from(Ellipse *ellipse, Point *point)
{
@@ -187,6 +215,15 @@ ellipse_distance_from(Ellipse *ellipse, Point *point)
center.x = elem->corner.x+elem->width/2;
center.y = elem->corner.y+elem->height/2;
+ if (ellipse->angle != 0) {
+ real dist;
+ GArray *path = _ellipse_to_path (ellipse, ¢er);
+
+ dist = distance_bez_shape_point (&g_array_index (path, BezPoint, 0), path->len,
+ ellipse->border_width, point);
+ g_array_free (path, TRUE);
+ return dist;
+ }
return distance_ellipse_point(¢er, elem->width, elem->height,
ellipse->border_width, point);
}
@@ -298,7 +335,8 @@ ellipse_draw(Ellipse *ellipse, DiaRenderer *renderer)
DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
Point center;
Element *elem;
-
+ GArray *path = NULL;
+
assert(ellipse != NULL);
assert(renderer != NULL);
@@ -307,6 +345,9 @@ ellipse_draw(Ellipse *ellipse, DiaRenderer *renderer)
center.x = elem->corner.x + elem->width/2;
center.y = elem->corner.y + elem->height/2;
+ if (ellipse->angle != 0)
+ path = _ellipse_to_path (ellipse, ¢er);
+
renderer_ops->set_linewidth(renderer, ellipse->border_width);
renderer_ops->set_linestyle(renderer, ellipse->line_style, ellipse->dashlength);
if (ellipse->show_background) {
@@ -317,18 +358,30 @@ ellipse_draw(Ellipse *ellipse, DiaRenderer *renderer)
if (renderer_ops->is_capable_to(renderer, RENDER_PATTERN))
renderer_ops->set_pattern (renderer, ellipse->pattern);
}
- renderer_ops->draw_ellipse (renderer,
- ¢er,
- elem->width, elem->height,
- &fill, &ellipse->border_color);
+ if (!path)
+ renderer_ops->draw_ellipse (renderer,
+ ¢er,
+ elem->width, elem->height,
+ &fill, &ellipse->border_color);
+ else
+ renderer_ops->draw_beziergon (renderer,
+ &g_array_index (path, BezPoint, 0), path->len,
+ &fill, &ellipse->border_color);
if (renderer_ops->is_capable_to(renderer, RENDER_PATTERN))
renderer_ops->set_pattern (renderer, NULL);
} else {
- renderer_ops->draw_ellipse (renderer,
- ¢er,
- elem->width, elem->height,
- NULL, &ellipse->border_color);
+ if (!path)
+ renderer_ops->draw_ellipse (renderer,
+ ¢er,
+ elem->width, elem->height,
+ NULL, &ellipse->border_color);
+ else
+ renderer_ops->draw_beziergon (renderer,
+ &g_array_index (path, BezPoint, 0), path->len,
+ NULL, &ellipse->border_color);
}
+ if (path)
+ g_array_free (path, TRUE);
}
static void
@@ -372,6 +425,16 @@ ellipse_update_data(Ellipse *ellipse)
ellipse->connections[8].pos.x = center.x;
ellipse->connections[8].pos.y = center.y;
+ if (ellipse->angle != 0) {
+ DiaMatrix m = { 1.0, 0.0, 0.0, 1.0, center.x, center.y };
+ DiaMatrix t = { 1.0, 0.0, 0.0, 1.0, -center.x, -center.y };
+ int i;
+
+ dia_matrix_set_angle_and_scales (&m, G_PI*ellipse->angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ for (i = 0; i < 8; ++i)
+ transform_point (&ellipse->connections[i].pos, &m);
+ }
/* Update directions -- if the ellipse is very thin, these may not be good */
ellipse->connections[0].directions = DIR_NORTH|DIR_WEST;
ellipse->connections[1].directions = DIR_NORTH;
@@ -476,6 +539,7 @@ ellipse_copy(Ellipse *ellipse)
newellipse->dashlength = ellipse->dashlength;
newellipse->show_background = ellipse->show_background;
newellipse->aspect = ellipse->aspect;
+ newellipse->angle = ellipse->angle;
newellipse->line_style = ellipse->line_style;
if (ellipse->pattern)
newellipse->pattern = g_object_ref (ellipse->pattern);
@@ -520,6 +584,9 @@ ellipse_save(Ellipse *ellipse, ObjectNode obj_node, DiaContext *ctx)
if (ellipse->aspect != FREE_ASPECT)
data_add_enum(new_attribute(obj_node, "aspect"),
ellipse->aspect, ctx);
+ if (ellipse->angle != 0.0)
+ data_add_real(new_attribute(obj_node, "angle"),
+ ellipse->angle, ctx);
if (ellipse->line_style != LINESTYLE_SOLID) {
data_add_enum(new_attribute(obj_node, "line_style"),
@@ -577,6 +644,11 @@ static DiaObject *ellipse_load(ObjectNode obj_node, int version, DiaContext *ctx
if (attr != NULL)
ellipse->aspect = data_enum(attribute_first_data(attr), ctx);
+ ellipse->angle = 0.0;
+ attr = object_find_attribute(obj_node, "angle");
+ if (attr != NULL)
+ ellipse->angle = data_real(attribute_first_data(attr), ctx);
+
ellipse->line_style = LINESTYLE_SOLID;
attr = object_find_attribute(obj_node, "line_style");
if (attr != NULL)
@@ -708,3 +780,33 @@ ellipse_get_object_menu(Ellipse *ellipse, Point *clickedpoint)
return &ellipse_menu;
}
+
+static gboolean
+ellipse_transform(Ellipse *ellipse, const DiaMatrix *m)
+{
+ real a, sx, sy;
+
+ g_return_val_if_fail(m != NULL, FALSE);
+
+ if (!dia_matrix_get_angle_and_scales (m, &a, &sx, &sy)) {
+ dia_log_message ("ellipse_transform() can't convert given matrix");
+ return FALSE;
+ } else {
+ real width = ellipse->element.width * sx;
+ real height = ellipse->element.height * sy;
+ real angle = a*180/G_PI;
+ Point c = { ellipse->element.corner.x + width/2.0, ellipse->element.corner.y + height/2.0 };
+
+ /* rotation is invariant to the center */
+ transform_point (&c, m);
+ /* XXX: we have to bring angle in range [-45..45] which may swap width and height */
+ ellipse->angle = angle;
+ ellipse->element.width = width;
+ ellipse->element.height = height;
+ ellipse->element.corner.x = c.x - width / 2.0;
+ ellipse->element.corner.y = c.y - height / 2.0;
+ }
+
+ ellipse_update_data(ellipse);
+ return TRUE;
+}
diff --git a/objects/standard/image.c b/objects/standard/image.c
index 4d42026..712190c 100644
--- a/objects/standard/image.c
+++ b/objects/standard/image.c
@@ -89,6 +89,7 @@ static ObjectChange* image_move_handle(Image *image, Handle *handle,
HandleMoveReason reason, ModifierKeys modifiers);
static ObjectChange* image_move(Image *image, Point *to);
static void image_draw(Image *image, DiaRenderer *renderer);
+static gboolean image_transform(Image *image, const DiaMatrix *m);
static void image_update_data(Image *image);
static DiaObject *image_create(Point *startpoint,
void *user_data,
@@ -160,6 +161,7 @@ static ObjectOps image_ops = {
(SetPropsFunc) image_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) image_transform,
};
static PropOffset image_offsets[] = {
@@ -463,6 +465,34 @@ image_draw(Image *image, DiaRenderer *renderer)
}
}
+static gboolean
+image_transform(Image *image, const DiaMatrix *m)
+{
+ Element *elem = &image->element;
+ real a, sx, sy;
+
+ g_return_val_if_fail(m != NULL, FALSE);
+
+ if (!dia_matrix_get_angle_and_scales (m, &a, &sx, &sy)) {
+ dia_log_message ("image_transform() can't convert given matrix");
+ return FALSE;
+ } else {
+ real width = elem->width * sx;
+ real height = elem->height * sy;
+ real angle = a*180/G_PI;
+ Point c = { elem->corner.x + width/2.0, elem->corner.y + height/2.0 };
+
+ /* rotation is invariant to the center */
+ transform_point (&c, m);
+ /* XXX: implement image rotate! */
+ elem->width = width;
+ elem->height = height;
+ elem->corner.x = c.x - width / 2.0;
+ elem->corner.y = c.y - height / 2.0;
+ }
+ return TRUE;
+}
+
static void
image_update_data(Image *image)
{
diff --git a/objects/standard/line.c b/objects/standard/line.c
index 3627a38..53c5762 100644
--- a/objects/standard/line.c
+++ b/objects/standard/line.c
@@ -94,6 +94,7 @@ static void line_set_props(Line *line, GPtrArray *props);
static void line_save(Line *line, ObjectNode obj_node, DiaContext *ctx);
static DiaObject *line_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *line_get_object_menu(Line *line, Point *clickedpoint);
+static gboolean line_transform(Line *line, const DiaMatrix *m);
void Line_adjust_for_absolute_gap(Line *line, Point *gap_endpoints);
@@ -181,6 +182,7 @@ static ObjectOps line_ops = {
(SetPropsFunc) line_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) line_transform,
};
static void
@@ -342,7 +344,19 @@ line_get_object_menu(Line *line, Point *clickedpoint)
return &object_menu;
}
+static gboolean
+line_transform(Line *line, const DiaMatrix *m)
+{
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < 2; i++)
+ transform_point (&line->connection.endpoints[i], m);
+ line_update_data(line);
+ return TRUE;
+}
/*!
* \brief Gap calculation for _Line
diff --git a/objects/standard/polygon.c b/objects/standard/polygon.c
index e4313dd..103ce79 100644
--- a/objects/standard/polygon.c
+++ b/objects/standard/polygon.c
@@ -90,6 +90,7 @@ static void polygon_save(Polygon *polygon, ObjectNode obj_node,
DiaContext *ctx);
static DiaObject *polygon_load(ObjectNode obj_node, int version, DiaContext *ctx);
static DiaMenu *polygon_get_object_menu(Polygon *polygon, Point *clickedpoint);
+static gboolean polygon_transform(Polygon *polygon, const DiaMatrix *m);
static ObjectTypeOps polygon_type_ops =
{
@@ -157,6 +158,7 @@ static ObjectOps polygon_ops = {
(SetPropsFunc) polygon_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) polygon_transform,
};
static void
@@ -500,3 +502,18 @@ polygon_get_object_menu(Polygon *polygon, Point *clickedpoint)
polygon_menu_items[1].active = polygon->poly.numpoints > 3;
return &polygon_menu;
}
+
+static gboolean
+polygon_transform(Polygon *polygon, const DiaMatrix *m)
+{
+ PolyShape *poly = &polygon->poly;
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < poly->numpoints; i++)
+ transform_point (&poly->points[i], m);
+
+ polygon_update_data(polygon);
+ return TRUE;
+}
diff --git a/objects/standard/polyline.c b/objects/standard/polyline.c
index ce27995..80468ca 100644
--- a/objects/standard/polyline.c
+++ b/objects/standard/polyline.c
@@ -81,6 +81,7 @@ static DiaObject *polyline_load(ObjectNode obj_node, int version, DiaContext *ct
static DiaMenu *polyline_get_object_menu(Polyline *polyline, Point *clickedpoint);
void polyline_calculate_gap_endpoints(Polyline *polyline, Point *gap_endpoints);
static void polyline_exchange_gap_points(Polyline *polyline, Point *gap_points);
+static gboolean polyline_transform(Polyline *polyline, const DiaMatrix *m);
static ObjectTypeOps polyline_type_ops =
{
@@ -164,6 +165,7 @@ static ObjectOps polyline_ops = {
(SetPropsFunc) polyline_set_props,
(TextEditFunc) 0,
(ApplyPropertiesListFunc) object_apply_props,
+ (TransformFunc) polyline_transform,
};
static void
@@ -638,3 +640,18 @@ polyline_get_object_menu(Polyline *polyline, Point *clickedpoint)
polyline_menu_items[1].active = polyline->poly.numpoints > 2;
return &polyline_menu;
}
+
+static gboolean
+polyline_transform(Polyline *polyline, const DiaMatrix *m)
+{
+ PolyConn *poly = &polyline->poly;
+ int i;
+
+ g_return_val_if_fail (m != NULL, FALSE);
+
+ for (i = 0; i < poly->numpoints; i++)
+ transform_point (&poly->points[i], m);
+
+ polyline_update_data(polyline);
+ return TRUE;
+}
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index ff2edad..9c8783e 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -4,7 +4,7 @@
*
* svg-import.c: SVG import filter for dia
* Copyright (C) 2002 Steffen Macke
- * Copyright (C) 2005 Hans Breuer
+ * Copyright (C) 2005-2014 Hans Breuer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -216,7 +216,7 @@ _node_get_real (xmlNodePtr node, const char *name, real defval)
* \ingroup SvgImport
*/
static void
-use_position (DiaObject *obj, xmlNodePtr node)
+use_position (DiaObject *obj, xmlNodePtr node, DiaContext *ctx)
{
Point pos = {0, 0};
xmlChar *str;
@@ -234,41 +234,29 @@ use_position (DiaObject *obj, xmlNodePtr node)
DiaMatrix *m = dia_svg_parse_transform ((char *)str, user_scale);
if (m) {
- if (IS_GROUP (obj)) {
+ if (obj->ops->transform) {
/* it is the only one transformation aware yet */
- Group *grp = (Group *)obj;
-
- group_transform (grp, m);
+ if (!obj->ops->transform (obj, m))
+ dia_context_add_message (ctx, _("Failed to apply transformation for '%s'"),
+ obj->type->name);
} else {
GPtrArray *props = g_ptr_array_new ();
PointProperty *pp;
RealProperty *pr;
- PointarrayProperty *pap = NULL;
- BezPointarrayProperty *bpap = NULL;
- Property *prop = NULL;
/* setting obj_pos is pointless, it is read-only in all objects */
prop_list_add_point (props, "obj_pos", &pos);
prop_list_add_point (props, "elem_corner", &pos);
prop_list_add_real (props, "elem_width", 1.0);
prop_list_add_real (props, "elem_height", 1.0);
- prop_list_add_real (props, PROP_STDNAME_LINE_WIDTH, 0.1);
-
- if ((prop = object_prop_by_name_type (obj, "bez_points", PROP_TYPE_BEZPOINTARRAY)) != NULL) {
- prop_list_add_list (props, prop_list_from_single (prop));
- bpap = g_ptr_array_index (props, 5);
- } else if ((prop = object_prop_by_name_type (obj, "poly_points", PROP_TYPE_POINTARRAY)) !=
NULL) {
- prop_list_add_list (props, prop_list_from_single (prop));
- pap = g_ptr_array_index (props, 5);
- }
obj->ops->get_props (obj, props);
- /* try to transform the object without the full matrix */
+ /* XXX: try to transform the object without the full matrix */
pp = g_ptr_array_index (props, 0);
pp->point_data.x += m->x0;
pp->point_data.y += m->y0;
- /* set position a second time, now for non-elements */
+ /* XXX: set position a second time, now for non-elements */
pp = g_ptr_array_index (props, 1);
pp->point_data.x += m->x0;
pp->point_data.y += m->y0;
@@ -277,24 +265,8 @@ use_position (DiaObject *obj, xmlNodePtr node)
pr->real_data *= m->xx;
pr = g_ptr_array_index (props, 3);
pr->real_data *= m->yy;
- pr = g_ptr_array_index (props, 4);
- pr->real_data *= m->yy;
-
- if (bpap) {
- GArray *data = bpap->bezpointarray_data;
- int i;
- for (i = 0; i < data->len; ++i)
- transform_bezpoint (&g_array_index(data, BezPoint, i), m);
- } else if (pap) {
- GArray *data = pap->pointarray_data;
- int i;
- for (i = 0; i < data->len; ++i)
- transform_point (&g_array_index(data, Point, i), m);
- }
obj->ops->set_props (obj, props);
- if (prop)
- prop->ops->free (prop);
prop_list_free (props);
}
g_free (m);
@@ -967,7 +939,7 @@ read_poly_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
static GList *
read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
GHashTable *style_ht, GHashTable *pattern_ht,
- GList *list)
+ GList *list, DiaContext *ctx)
{
xmlChar *str;
real width, height;
@@ -995,15 +967,6 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
width = height = get_value_as_cm((char *) str, NULL)*2;
xmlFree(str);
}
- 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;
@@ -1014,6 +977,13 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
props = make_element_props(start.x-(width/2), start.y-(height/2),
width, height);
new_obj->ops->set_props(new_obj, props);
+ if (matrix) {
+ g_return_val_if_fail (new_obj->ops->transform, list);
+ if (!new_obj->ops->transform (new_obj, matrix))
+ dia_context_add_message (ctx, _("Failed to apply transformation for '%s'"),
+ new_obj->type->name);
+ g_free (matrix);
+ }
prop_list_free(props);
return g_list_append (list, new_obj);
}
@@ -1025,7 +995,7 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
static GList *
read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
GHashTable *style_ht, GHashTable *pattern_ht,
- GList *list)
+ GList *list, DiaContext *ctx)
{
xmlChar *str;
DiaObjectType *otype = object_get_type("Standard - Line");
@@ -1047,12 +1017,6 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
end.x = _node_get_real (node, "x2", start.x);
end.y = _node_get_real (node, "y2", start.y);
- if (matrix) {
- transform_point (&start, matrix);
- transform_point (&end, matrix);
- g_free (matrix);
- }
-
new_obj = otype->ops->create(&start, otype->default_user_data,
&h1, &h2);
@@ -1072,6 +1036,14 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
+ if (matrix) {
+ g_return_val_if_fail (new_obj->ops->transform, list);
+ if (!new_obj->ops->transform (new_obj, matrix))
+ dia_context_add_message (ctx, _("Failed to apply transformation for '%s'"),
+ new_obj->type->name);
+ g_free (matrix);
+ }
+
return g_list_append (list, new_obj);
}
@@ -1082,7 +1054,7 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
static GList *
read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
GHashTable *style_ht, GHashTable *pattern_ht,
- GList *list)
+ GList *list, DiaContext *ctx)
{
xmlChar *str;
real width, height;
@@ -1126,19 +1098,12 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
end.x = start.x + width;
end.y = start.y + height;
- if (matrix) {
- /* TODO: for rotated rects we would need to create a polygon */
- transform_point (&start, matrix);
- transform_point (&end, matrix);
- g_free (matrix);
- width = end.x - start.x;
- height = end.y - start.y;
- }
/* 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);
props = prop_list_from_descs(svg_rect_prop_descs, pdtpp_true);
g_assert(props->len == 3);
@@ -1160,6 +1125,13 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
prop_list_free(props);
+ if (matrix) {
+ g_return_val_if_fail (new_obj->ops->transform != NULL, list);
+ if (!new_obj->ops->transform (new_obj, matrix))
+ dia_context_add_message (ctx, _("Failed to apply transformation for '%s'"),
+ new_obj->type->name);
+ g_free (matrix);
+ }
return list;
}
@@ -1171,7 +1143,7 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
static GList *
read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
GHashTable *style_ht, GHashTable *pattern_ht,
- GList *list, const gchar *filename_svg)
+ GList *list, const gchar *filename_svg, DiaContext *ctx)
{
xmlChar *str;
real x, y, width, height;
@@ -1191,21 +1163,6 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
/* 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 = xmlGetNsProp (node, (const xmlChar *)"href", (const xmlChar *)"http://www.w3.org/1999/xlink");
if (str) {
if (strncmp ((char *)str, "data:image/", 11) == 0) {
@@ -1265,6 +1222,13 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
xmlFree(str);
}
+ if (matrix) {
+ g_return_val_if_fail (new_obj->ops->transform, list);
+ if (!new_obj->ops->transform (new_obj, matrix))
+ dia_context_add_message (ctx, _("Failed to apply transformation for '%s'"),
+ new_obj->type->name);
+ g_free (matrix);
+ }
if (new_obj)
return g_list_append (list, new_obj);
@@ -1629,15 +1593,15 @@ read_items (xmlNodePtr startnode,
else if (moreitems)
obj = g_list_last(moreitems)->data;
} else if (!xmlStrcmp(node->name, (const xmlChar *)"rect")) {
- items = read_rect_svg(node, parent_gs, style_ht, pattern_ht, items);
+ items = read_rect_svg(node, parent_gs, style_ht, pattern_ht, items, ctx);
if (items)
obj = g_list_last(items)->data;
} else if (!xmlStrcmp(node->name, (const xmlChar *)"line")) {
- items = read_line_svg(node, parent_gs, style_ht, pattern_ht, items);
+ items = read_line_svg(node, parent_gs, style_ht, pattern_ht, items, ctx);
if (items)
obj = g_list_last(items)->data;
} else if (!xmlStrcmp(node->name, (const xmlChar *)"ellipse") || !xmlStrcmp(node->name, (const xmlChar
*)"circle")) {
- items = read_ellipse_svg(node, parent_gs, style_ht, pattern_ht, items);
+ items = read_ellipse_svg(node, parent_gs, style_ht, pattern_ht, items, ctx);
if (items)
obj = g_list_last(items)->data;
} else if (!xmlStrcmp(node->name, (const xmlChar *)"polyline")) {
@@ -1659,7 +1623,7 @@ read_items (xmlNodePtr startnode,
if (items && g_list_nth(items, first))
obj = g_list_nth(items, first)->data;
} else if(!xmlStrcmp(node->name, (const xmlChar *)"image")) {
- items = read_image_svg(node, parent_gs, style_ht, pattern_ht, items, filename_svg);
+ items = read_image_svg(node, parent_gs, style_ht, pattern_ht, items, filename_svg, ctx);
if (items)
obj = g_list_last(items)->data;
} else if(!xmlStrcmp(node->name, (const xmlChar *)"linearGradient") ||
@@ -1680,7 +1644,7 @@ read_items (xmlNodePtr startnode,
* be target for meta info, comment or something. */
obj = otemp->ops->copy (otemp);
- use_position (obj, node);
+ use_position (obj, node, ctx);
/* this should only be styled from the containing group,
* if it has no style on it's own. Sorry Dia can't create
* objects w/o style so we have two options beside complete
diff --git a/samples/transform-variations.svg b/samples/transform-variations.svg
new file mode 100644
index 0000000..68e822e
--- /dev/null
+++ b/samples/transform-variations.svg
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0" y="0" width="28cm" height="28cm" viewBox="0, -5, 280, 275"
+ stroke-width="2"
+ text-anchor="middle" font-size="6" font-family="sans-serif">
+ <text x="210" y="30" text-anchor="start">Standard - Box</text>
+ <text x="210" y="40" text-anchor="start">Standard - Line</text>
+ <text x="210" y="80" text-anchor="start">Standard - Ellipse</text>
+ <text x="210" y="90" text-anchor="start">Standard - Text</text>
+ <text x="210" y="130" text-anchor="start">Standard - Polygon</text>
+ <text x="210" y="140" text-anchor="start">Standard - Polyline</text>
+ <text x="210" y="180" text-anchor="start">Standard - Beziergon</text>
+ <text x="210" y="190" text-anchor="start">Standard - Bezierline</text>
+ <text x="210" y="230" text-anchor="start">Standard - Image</text>
+
+ <text x="30" y="0" >Reference</text>
+ <!-- to be used below and directly -->
+ <rect id="box" x="18" y="10" width="24" height="40" fill="yellow" stroke="red"/>
+ <line id="line" x1="10" y1="30" x2="50" y2="30" stroke="red"/>
+ <ellipse id="ell" cx="30" cy="80" rx="20" ry="15" fill="lime" stroke="blue"/>
+ <text id="txt" x="30" y="80" text-anchor="middle" fill="blue">Rotate!</text>
+ <polygon id="pg1" points="30,110,50,145,10,145" fill="lightblue"/>
+ <polyline id="pl1" points="30,110,50,145,10,145" stroke="green" fill="none"/>
+ <path id="pc1" d="M30,160C40,170,50,200,30,200C10,200,20,170,30,160z" fill="cyan"/>
+ <path id="po1" d="M30,160C40,170,50,200,30,200C10,200,20,170,30,160" fill="none" stroke="gold"/>
+ <image id="img" x="10" y="210" width="40" height="40"
+
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIkAAACbCAYAAABWOrhZAAAABHNCSVQICAgIfAhkiAAABDBJREFU eJzt3V2SEkEQReFsw0d34C5diLt0B763L4PBMMBt6Kyqm1XnezNCsYc+ZP9QAxGAsCU8xp7wGM9k bCNO+DZ6A+CPSCARCaTv6Y949gyFMxA7TBJIRAKJSCARCSQigUQkkIgEEpFAIhJIRAKJSCARCSQi gUQkkIgEUv56EtaDTIdJAolIIBEJpJ5nELerXzl7KYJJAolIIBEJJCKBRCSQiAQSkUAiEkhEAolI IN3eGm/90VZ4zvKtCiKpYWg8RFJP92CIpLYuwbBUYJzMF2TT55JIPGQF0+Q55RLYwxbGH7xMJF6y QkmNhUj82E0VIvFlM1WIxFvWieipUIjE3/DDD5Hc+Pvrp+sNxWGhEMmVSyCE8hmR1NM9FCL5cDs9 jKdJlsM/H5HU1PUtDSKJx1PDfJp0O+wQSW1dQlk+EjUtzKdJRIdQlo/kiAKhNLV0JBPt/KbTZOlI XjFRUC9bNpIJd3qzabJsJO+YMKxDloxk4p3dZJosF8nZQCYO7KHlIllA+jRZKpIjU+DH7z/ySV5t miwVCd6zTCSvTJEJpknqIWeZSMw4B/bFEpG8cy7SYZqk/xJVK0tE0lLCYcc+lukjOXNFc2SaJMqO JW3bp4/krAEnsU6TZY+YPJKs+yKD2MQybSSZr+7Bl8TDY5k2kiNcpsi+77HvsoNhsUwZSYvDTI9p 4hrLyI/DwodHYWzbod3z7C9lPOfblJNkFi6ThUgg5X/DONIkHG5SjIwk/YfrdV/k6Anqk//r6b93 ieNimsNNzxtnrS6dt207EkjWJx8dNk0kvWVeErvGcTHFOUnx2+/K8O1mkpzQ+Ab
bsMlxq/wkmXCK 2G1r6UnisM40cZrYTI4rW8QEk0QpMEVabR8fG+50mHlzmjhOjrvKRlJciTguSn4pksO5yLs6Hv7O Pkf/t5NJMqe1v++m8hSJqLn95SKZQeNQUhYaXf+hVCQVX4UzKBXJTIyD/3JiXSYS4yfVybrf5jlr IIY/193L85L3SXBX+gnrRYlJAqlZIBFEggOIpL6mUySCSKprHkgEkeAAIqmryxSJIJKqugUSQSQV dQ0kgkiq6R5IBJFUMiSQCCKpYlggEURSwdBAIhb4vZvCst4hPv1GKpF4Gj49rhGJF5vpcY1IPFjG cUEkY1nH8ejB3ZbT4bkuq/uYJDV1XfpJJHUMWxNMJL5sFoqzWh4St+UhEQkkIoFEJJCIBBKRQCIS SEQCiUggEQmkrFvjrZYYcOveQOZOyA6FQExwuIGU/WotsRwPr2m+nkR9Q/bBrzfFQNmHm4w9TjVm mp+TPJsUTJEaWkRyZs9TjaEuVzf3JgZTpI5WkbxTANWY6naf5HpyMEVqaRnJKyVQjbHWO+fozTUi MdZj56hQCMQc791AGv0dtUyRApgkkPhdYEhMEtjZg09TKodJAgAAHPwDyEsX4l8AdBUAAAAASUVO RK5CYII="/>
+
+ <text x="80" y="0">Element rotate</text>
+ <!-- transform object directly - must not have copied id="...", otherwise Dia would
+ translate the wrong object (not the first of id, but the last) -->
+ <rect x="18" y="10" width="24" height="40" fill="yellow" stroke="red"
+ transform="translate(80,30) rotate(30) translate(-30,-30)"/>
+ <line x1="10" y1="30" x2="50" y2="30" stroke="red"
+ transform="translate(80,30) rotate(30) translate(-30,-30)"/>
+ <ellipse cx="30" cy="80" rx="20" ry="15" fill="lime" stroke="blue"
+ transform="translate(80,80) rotate(30) translate(-30,-80)"/>
+ <text x="30" y="80" text-anchor="middle" fill="blue"
+ transform="translate(80,80) rotate(30) translate(-30,-80)">Rotate!</text>
+ <polygon points="30,110,50,145,10,145" fill="lightblue"
+ transform="translate(80,130)rotate(30)translate(-30,-130)"/>
+ <polyline points="30,110,50,145,10,145" fill="none" stroke="green"
+ transform="translate(80,130) rotate(30) translate(-30,-130)"/>
+ <path d="M30,160C40,170,50,200,30,200C10,200,20,170,30,160z" fill="cyan"
+ transform="translate(80,180) rotate(30) translate(-30,-180)"/>
+ <path d="M30,160C40,170,50,200,30,200C10,200,20,170,30,160" fill="none" stroke="gold"
+ transform="translate(80,180) rotate(30) translate(-30,-180)"/>
+ <image x="10" y="210" width="40" height="40"
+ transform="translate(80,230) rotate(30) translate(-30,-230)"
+
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIkAAACbCAYAAABWOrhZAAAABHNCSVQICAgIfAhkiAAABDBJREFU eJzt3V2SEkEQReFsw0d34C5diLt0B763L4PBMMBt6Kyqm1XnezNCsYc+ZP9QAxGAsCU8xp7wGM9k bCNO+DZ6A+CPSCARCaTv6Y949gyFMxA7TBJIRAKJSCARCSQigUQkkIgEEpFAIhJIRAKJSCARCSQi gUQkkIgEUv56EtaDTIdJAolIIBEJpJ5nELerXzl7KYJJAolIIBEJJCKBRCSQiAQSkUAiEkhEAolI IN3eGm/90VZ4zvKtCiKpYWg8RFJP92CIpLYuwbBUYJzMF2TT55JIPGQF0+Q55RLYwxbGH7xMJF6y QkmNhUj82E0VIvFlM1WIxFvWieipUIjE3/DDD5Hc+Pvrp+sNxWGhEMmVSyCE8hmR1NM9FCL5cDs9 jKdJlsM/H5HU1PUtDSKJx1PDfJp0O+wQSW1dQlk+EjUtzKdJRIdQlo/kiAKhNLV0JBPt/KbTZOlI XjFRUC9bNpIJd3qzabJsJO+YMKxDloxk4p3dZJosF8nZQCYO7KHlIllA+jRZKpIjU+DH7z/ySV5t miwVCd6zTCSvTJEJpknqIWeZSMw4B/bFEpG8cy7SYZqk/xJVK0tE0lLCYcc+lukjOXNFc2SaJMqO JW3bp4/krAEnsU6TZY+YPJKs+yKD2MQybSSZr+7Bl8TDY5k2kiNcpsi+77HvsoNhsUwZSYvDTI9p 4hrLyI/DwodHYWzbod3z7C9lPOfblJNkFi6ThUgg5X/DONIkHG5SjIwk/YfrdV/k6Anqk//r6b93 ieNimsNNzxtnrS6dt207EkjWJx8dNk0kvWVeErvGcTHFOUnx2+/K8O1mkpzQ+Ab
bsMlxq/wkmXCK 2G1r6UnisM40cZrYTI4rW8QEk0QpMEVabR8fG+50mHlzmjhOjrvKRlJciTguSn4pksO5yLs6Hv7O Pkf/t5NJMqe1v++m8hSJqLn95SKZQeNQUhYaXf+hVCQVX4UzKBXJTIyD/3JiXSYS4yfVybrf5jlr IIY/193L85L3SXBX+gnrRYlJAqlZIBFEggOIpL6mUySCSKprHkgEkeAAIqmryxSJIJKqugUSQSQV dQ0kgkiq6R5IBJFUMiSQCCKpYlggEURSwdBAIhb4vZvCst4hPv1GKpF4Gj49rhGJF5vpcY1IPFjG cUEkY1nH8ejB3ZbT4bkuq/uYJDV1XfpJJHUMWxNMJL5sFoqzWh4St+UhEQkkIoFEJJCIBBKRQCIS SEQCiUggEQmkrFvjrZYYcOveQOZOyA6FQExwuIGU/WotsRwPr2m+nkR9Q/bBrzfFQNmHm4w9TjVm mp+TPJsUTJEaWkRyZs9TjaEuVzf3JgZTpI5WkbxTANWY6naf5HpyMEVqaRnJKyVQjbHWO+fozTUi MdZj56hQCMQc791AGv0dtUyRApgkkPhdYEhMEtjZg09TKodJAgAAHPwDyEsX4l8AdBUAAAAASUVO RK5CYII="/>
+
+ <text x="130" y="0">Group rotate</text>
+ <!-- just shift with use, transform by group -->
+ <g transform="translate(130,30)rotate(45)translate(-130,-30)">
+ <use x="100" y="0" xlink:href="#box"/>
+ <use x="100" y="0" xlink:href="#line"/>
+ </g>
+ <g transform="translate(130,80)rotate(45)translate(-130,-80)">
+ <use x="100" y="0" xlink:href="#ell"/>
+ <use x="100" y="0" xlink:href="#txt"/>
+ </g>
+ <g transform="translate(130,130)rotate(45)translate(-130,-130)">
+ <use x="100" y="0" xlink:href="#pg1"/>
+ <use x="100" y="0" xlink:href="#pl1"/>
+ </g>
+ <g transform="translate(130,180)rotate(45)translate(-130,-180)">
+ <use x="100" y="0" xlink:href="#pc1"/>
+ <use x="100" y="0" xlink:href="#po1"/>
+ </g>
+ <g transform="translate(130,230)rotate(45)translate(-130,-230)">
+ <use x="100" y="0" xlink:href="#img"/>
+ </g>
+
+ <text x="180" y="0">Use rotate</text>
+ <!-- transformed use, shifted by group -->
+ <g transform="translate(180,30)">
+ <use x="-30" y="-30" xlink:href="#box" transform="rotate(60)"/>
+ <use x="-30" y="-30" xlink:href="#line" transform="rotate(60)"/>
+ </g>
+ <g transform="translate(180,80)">
+ <use x="-30" y="-80" xlink:href="#ell" transform="rotate(60)"/>
+ <use x="-30" y="-80" xlink:href="#txt" transform="rotate(60)"/>
+ </g>
+ <g transform="translate(180,130)">
+ <use x="-30" y="-130" xlink:href="#pg1" transform="rotate(60)"/>
+ <use x="-30" y="-130" xlink:href="#pl1" transform="rotate(60)"/>
+ </g>
+ <g transform="translate(180,180)">
+ <use x="-30" y="-180" xlink:href="#pc1" transform="rotate(60)"/>
+ <use x="-30" y="-180" xlink:href="#po1" transform="rotate(60)"/>
+ </g>
+ <g transform="translate(180,230)">
+ <use x="-30" y="-230" xlink:href="#img" transform="rotate(60)"/>
+ </g>
+</svg>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]