[dia] [transform] initial rotation support for "Standard - Image"
- From: Hans Breuer <hans src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] [transform] initial rotation support for "Standard - Image"
- Date: Sun, 2 Nov 2014 14:11:03 +0000 (UTC)
commit 127663095853a7fa06e245d3a686fd71db859645
Author: Hans Breuer <hans breuer org>
Date: Sun Nov 2 14:33:03 2014 +0100
[transform] initial rotation support for "Standard - Image"
Introduce DiaRenderer::draw_rotated_image() and move some code to helper
functions for reuse. Implement DiaCairoRenderer::draw_rotated_image() for
testing the new functionality (mainly with transform-variations.svg).
Give "Standard - Image" an angle property: copy, load, save it.
Set Image::angle in image_transform().
Unrelated: use element_update_connections_rectangle() to ensure proper
directions initialization with less code.
Open issues:
- for now only the cairo renderer implements draw_image_rotated()
- either the angle should be limited like for "Standard - Box" or the
connection point directions for angles outside [-45...45deg] must be fixed
lib/diarenderer.c | 21 ++++++++
lib/diarenderer.h | 6 ++
lib/element.c | 25 ++++++++++
lib/element.h | 4 ++
lib/geometry.c | 11 ++++
lib/geometry.h | 1 +
lib/libdia.def | 2 +
objects/standard/image.c | 89 +++++++++++++++++++++++------------
plug-ins/cairo/diacairo-renderer.c | 27 +++++++++--
9 files changed, 151 insertions(+), 35 deletions(-)
---
diff --git a/lib/diarenderer.c b/lib/diarenderer.c
index ea1ebf4..7ed882a 100644
--- a/lib/diarenderer.c
+++ b/lib/diarenderer.c
@@ -108,6 +108,11 @@ static void draw_text_line (DiaRenderer *renderer,
TextLine *text_line, Point *pos, Alignment alignment, Color *color);
static void draw_rotated_text (DiaRenderer *renderer, Text *text,
Point *center, real angle);
+static void draw_rotated_image (DiaRenderer *renderer,
+ Point *point,
+ real width, real height,
+ real angle,
+ DiaImage *image);
static void draw_polyline (DiaRenderer *renderer,
Point *points, int num_points,
@@ -339,6 +344,7 @@ dia_renderer_class_init (DiaRendererClass *klass)
renderer_class->draw_text = draw_text;
renderer_class->draw_text_line = draw_text_line;
renderer_class->draw_rotated_text = draw_rotated_text;
+ renderer_class->draw_rotated_image = draw_rotated_image;
/* highest level functions */
renderer_class->draw_rounded_rect = draw_rounded_rect;
@@ -707,6 +713,21 @@ draw_rotated_text (DiaRenderer *renderer, Text *text,
}
}
+static void
+draw_rotated_image (DiaRenderer *renderer,
+ Point *point,
+ real width, real height,
+ real angle,
+ DiaImage *image)
+{
+ if (angle == 0.0) {
+ DIA_RENDERER_GET_CLASS (renderer)->draw_image (renderer, point, width, height, image);
+ } else {
+ /* XXX: implement fallback */
+ DIA_RENDERER_GET_CLASS (renderer)->draw_image (renderer, point, width, height, image);
+ }
+}
+
/*!
* \brief Default implementation of draw_text_line
*
diff --git a/lib/diarenderer.h b/lib/diarenderer.h
index 4ee93a2..368beca 100644
--- a/lib/diarenderer.h
+++ b/lib/diarenderer.h
@@ -255,6 +255,12 @@ struct _DiaRendererClass
/*! draw text rotated around center with given angle in degrees */
void (*draw_rotated_text) (DiaRenderer *renderer, Text *text,
Point *center, real angle);
+ /*! draw image rotated around center with given angle in degrees */
+ void (*draw_rotated_image) (DiaRenderer *renderer,
+ Point *point,
+ real width, real height,
+ real angle,
+ DiaImage *image);
};
/*
diff --git a/lib/element.c b/lib/element.c
index 23b6ddf..8099e55 100644
--- a/lib/element.c
+++ b/lib/element.c
@@ -512,3 +512,28 @@ element_change_new (const Point *corner,
return &ec->object_change;
}
+
+void
+element_get_poly (const Element *elem, real angle, Point corners[4])
+{
+ 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 (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*angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ for (i = 0; i < 4; ++i)
+ transform_point (&corners[i], &m);
+ }
+}
diff --git a/lib/element.h b/lib/element.h
index ac72ebe..0a50799 100644
--- a/lib/element.h
+++ b/lib/element.h
@@ -70,6 +70,10 @@ void element_load(Element *elem, ObjectNode obj_node, DiaContext *ctx);
ObjectChange *element_change_new (const Point *corner,
real width, real height,
Element *elem);
+
+void element_get_poly (const Element *elem, real angle, Point corners[4]);
+
+
/* base property stuff ... */
#ifdef G_OS_WIN32
/* see lib/properties.h for the reason */
diff --git a/lib/geometry.c b/lib/geometry.c
index ebbe07a..8f4810c 100644
--- a/lib/geometry.c
+++ b/lib/geometry.c
@@ -840,6 +840,17 @@ dia_matrix_is_invertible (const DiaMatrix *matrix)
return finite(det) && det != 0.0;
}
+void
+dia_matrix_set_rotate_around (DiaMatrix *result,
+ real angle,
+ const Point *around)
+{
+ DiaMatrix m = { 1.0, 0.0, 0.0, 1.0, around->x, around->y };
+ DiaMatrix t = { 1.0, 0.0, 0.0, 1.0, -around->x, -around->y };
+
+ dia_matrix_set_angle_and_scales (&m, angle, 1.0, 1.0);
+ dia_matrix_multiply (result, &t, &m);
+}
/*!
* \brief asin wrapped to limit to valid result range
*
diff --git a/lib/geometry.h b/lib/geometry.h
index d016dc0..699f22d 100644
--- a/lib/geometry.h
+++ b/lib/geometry.h
@@ -141,6 +141,7 @@ void dia_matrix_set_angle_and_scales (DiaMatrix *m,
real sy);
void dia_matrix_multiply (DiaMatrix *result, const DiaMatrix *a, const DiaMatrix *b);
gboolean dia_matrix_is_invertible (const DiaMatrix *matrix);
+void dia_matrix_set_rotate_around (DiaMatrix *result, real angle, const Point *around);
#define ROUND(x) ((int) floor((x)+0.5))
diff --git a/lib/libdia.def b/lib/libdia.def
index fe27357..81d19c6 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -443,6 +443,7 @@ EXPORTS
element_update_handles
element_update_connections_rectangle
element_update_connections_directions
+ element_get_poly
ellipse_bbox
element_change_new
@@ -803,6 +804,7 @@ EXPORTS
dia_matrix_is_identity
dia_matrix_get_angle_and_scales
dia_matrix_set_angle_and_scales
+ dia_matrix_set_rotate_around
dia_matrix_multiply
dia_option_menu_add_item
diff --git a/objects/standard/image.c b/objects/standard/image.c
index 712190c..8d7c9a8 100644
--- a/objects/standard/image.c
+++ b/objects/standard/image.c
@@ -72,6 +72,8 @@ struct _Image {
gboolean draw_border;
gboolean keep_aspect;
+ real angle;
+
time_t mtime;
};
@@ -113,6 +115,8 @@ static ObjectTypeOps image_type_ops =
(ApplyDefaultsFunc) NULL
};
+static PropNumData _image_angle_range = { -180.0, 180.0, 5.0 };
+
static PropDescription image_props[] = {
ELEMENT_COMMON_PROPERTIES,
{ "image_file", PROP_TYPE_FILE, PROP_FLAG_VISIBLE,
@@ -125,6 +129,8 @@ static PropDescription image_props[] = {
N_("Draw border"), NULL, NULL},
{ "keep_aspect", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE,
N_("Keep aspect ratio"), NULL, NULL},
+ { "angle", PROP_TYPE_REAL, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
+ N_("Angle"), NULL, &_image_angle_range },
PROP_STD_LINE_WIDTH,
PROP_STD_LINE_COLOUR,
PROP_STD_LINE_STYLE,
@@ -171,6 +177,7 @@ static PropOffset image_offsets[] = {
{ "pixbuf", PROP_TYPE_PIXBUF, offsetof(Image, pixbuf) },
{ "show_border", PROP_TYPE_BOOL, offsetof(Image, draw_border) },
{ "keep_aspect", PROP_TYPE_BOOL, offsetof(Image, keep_aspect) },
+ { "angle", PROP_TYPE_REAL, offsetof(Image,angle)},
{ PROP_STDNAME_LINE_WIDTH, PROP_STDTYPE_LINE_WIDTH, offsetof(Image, border_width) },
{ "line_colour", PROP_TYPE_COLOUR, offsetof(Image, border_color) },
{ "line_style", PROP_TYPE_LINESTYLE,
@@ -302,6 +309,11 @@ image_distance_from(Image *image, Point *point)
Rectangle rect;
real bw = image->draw_border ? image->border_width : 0;
+ if (image->angle != 0.0) {
+ Point corners[4];
+ element_get_poly (elem, image->angle, corners);
+ return distance_polygon_point (corners, 4, bw, point);
+ }
rect.left = elem->corner.x - bw;
rect.right = elem->corner.x + elem->width + bw;
rect.top = elem->corner.y - bw;
@@ -446,20 +458,30 @@ image_draw(Image *image, DiaRenderer *renderer)
renderer_ops->set_linewidth(renderer, image->border_width);
renderer_ops->set_linestyle(renderer, image->line_style, image->dashlength);
renderer_ops->set_linejoin(renderer, LINEJOIN_MITER);
-
- renderer_ops->draw_rect(renderer,
- &ul_corner,
- &lr_corner,
- NULL,
- &image->border_color);
+
+ if (image->angle != 0.0) {
+ Point poly[4];
+ element_get_poly (elem, image->angle, poly);
+ /* need to grow the poly, XXX: done here by growing the border width */
+ renderer_ops->set_linewidth(renderer, image->border_width * 2);
+ renderer_ops->draw_polygon (renderer, poly, 4, NULL, &image->border_color);
+ } else {
+ renderer_ops->draw_rect (renderer,
+ &ul_corner, &lr_corner,
+ NULL, &image->border_color);
+ }
}
/* Draw the image */
if (image->image) {
- renderer_ops->draw_image(renderer, &elem->corner, elem->width,
- elem->height, image->image);
+ if (image->angle == 0.0)
+ renderer_ops->draw_image (renderer, &elem->corner, elem->width,
+ elem->height, image->image);
+ else
+ renderer_ops->draw_rotated_image (renderer, &elem->corner, elem->width,
+ elem->height, image->angle, image->image);
} else {
DiaImage *broken = dia_image_get_broken();
- renderer_ops->draw_image(renderer, &elem->corner, elem->width,
+ renderer_ops->draw_image (renderer, &elem->corner, elem->width,
elem->height, broken);
dia_image_unref(broken);
}
@@ -484,9 +506,9 @@ image_transform(Image *image, const DiaMatrix *m)
/* rotation is invariant to the center */
transform_point (&c, m);
- /* XXX: implement image rotate! */
elem->width = width;
elem->height = height;
+ image->angle = angle;
elem->corner.x = c.x - width / 2.0;
elem->corner.y = c.y - height / 2.0;
}
@@ -512,30 +534,26 @@ image_update_data(Image *image)
}
/* Update connections: */
- image->connections[0].pos = elem->corner;
- image->connections[1].pos.x = elem->corner.x + elem->width / 2.0;
- image->connections[1].pos.y = elem->corner.y;
- image->connections[2].pos.x = elem->corner.x + elem->width;
- image->connections[2].pos.y = elem->corner.y;
- image->connections[3].pos.x = elem->corner.x;
- image->connections[3].pos.y = elem->corner.y + elem->height / 2.0;
- image->connections[4].pos.x = elem->corner.x + elem->width;
- image->connections[4].pos.y = elem->corner.y + elem->height / 2.0;
- image->connections[5].pos.x = elem->corner.x;
- image->connections[5].pos.y = elem->corner.y + elem->height;
- image->connections[6].pos.x = elem->corner.x + elem->width / 2.0;
- image->connections[6].pos.y = elem->corner.y + elem->height;
- image->connections[7].pos.x = elem->corner.x + elem->width;
- image->connections[7].pos.y = elem->corner.y + elem->height;
- image->connections[8].pos.x = elem->corner.x + elem->width / 2.0;
- image->connections[8].pos.y = elem->corner.y + elem->height / 2.0;
-
+ element_update_connections_rectangle (elem, image->connections);
+
+ if (image->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*image->angle/180, 1.0, 1.0);
+ dia_matrix_multiply (&m, &t, &m);
+ for (i = 0; i < 8; ++i)
+ transform_point (&image->connections[i].pos, &m);
+ }
+
/* the image border is drawn vompletely outside of the image, so no /2.0 on border width */
extra->border_trans = (image->draw_border ? image->border_width : 0.0);
element_update_boundingbox(elem);
obj->position = elem->corner;
- image->connections[8].directions = DIR_ALL;
element_update_handles(elem);
}
@@ -633,6 +651,7 @@ image_copy(Image *image)
newimage->border_width = image->border_width;
newimage->border_color = image->border_color;
newimage->line_style = image->line_style;
+ newimage->angle = image->angle;
for (i=0;i<NUM_CONNECTIONS;i++) {
newobj->connections[i] = &newimage->connections[i];
@@ -647,8 +666,8 @@ image_copy(Image *image)
dia_image_add_ref(image->image);
newimage->image = image->image;
- /* not sure if we only want a reference, but it would be safe when
- * someday editing doe not work inplace, but creates new pixbufs
+ /* not sure if we only want a reference, but it would be safe when someday
+ * editing does not work inplace anymore and instead creates new pixbufs
* for every single undoable step */
newimage->inline_data = image->inline_data;
if (image->pixbuf)
@@ -720,6 +739,9 @@ image_save(Image *image, ObjectNode obj_node, DiaContext *ctx)
data_add_boolean(new_attribute(obj_node, "draw_border"), image->draw_border, ctx);
data_add_boolean(new_attribute(obj_node, "keep_aspect"), image->keep_aspect, ctx);
+ if (image->angle != 0.0)
+ data_add_real(new_attribute(obj_node, "angle"), image->angle, ctx);
+
if (image->file != NULL) {
if (g_path_is_absolute(image->file)) { /* Absolute pathname */
diafile_dir = get_directory(dia_context_get_filename (ctx));
@@ -804,6 +826,11 @@ image_load(ObjectNode obj_node, int version, DiaContext *ctx)
if (attr != NULL)
image->keep_aspect = data_boolean(attribute_first_data(attr), ctx);
+ image->angle = 0.0;
+ attr = object_find_attribute(obj_node, "angle");
+ if (attr != NULL)
+ image->angle = data_real(attribute_first_data(attr), ctx);
+
attr = object_find_attribute(obj_node, "file");
if (attr != NULL) {
image->file = data_filename(attribute_first_data(attr), ctx);
diff --git a/plug-ins/cairo/diacairo-renderer.c b/plug-ins/cairo/diacairo-renderer.c
index 2f7b4d4..047adee 100644
--- a/plug-ins/cairo/diacairo-renderer.c
+++ b/plug-ins/cairo/diacairo-renderer.c
@@ -952,10 +952,11 @@ draw_string(DiaRenderer *self,
}
static void
-draw_image(DiaRenderer *self,
- Point *point,
- real width, real height,
- DiaImage *image)
+draw_rotated_image (DiaRenderer *self,
+ Point *point,
+ real width, real height,
+ real angle,
+ DiaImage *image)
{
DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (self);
cairo_surface_t *surface;
@@ -1044,6 +1045,14 @@ draw_image(DiaRenderer *self,
cairo_scale (renderer->cr, width/w, height/h);
cairo_move_to (renderer->cr, 0.0, 0.0);
cairo_set_source_surface (renderer->cr, surface, 0.0, 0.0);
+ if (angle != 0.0)
+ {
+ DiaMatrix rotate;
+ Point center = { w/2, h/2 };
+
+ dia_matrix_set_rotate_around (&rotate, -G_PI * angle / 180.0, ¢er);
+ cairo_pattern_set_matrix (cairo_get_source (renderer->cr), (cairo_matrix_t *)&rotate);
+ }
#if 0
/*
* CAIRO_FILTER_FAST: aka. CAIRO_FILTER_NEAREST
@@ -1061,6 +1070,14 @@ draw_image(DiaRenderer *self,
DIAG_STATE(renderer->cr);
}
+static void
+draw_image (DiaRenderer *self,
+ Point *point,
+ real width, real height,
+ DiaImage *image)
+{
+ draw_rotated_image (self, point, width, height, 0.0, image);
+}
static gpointer parent_class = NULL;
/*!
@@ -1222,6 +1239,8 @@ cairo_renderer_class_init (DiaCairoRendererClass *klass)
/* highest level functions */
renderer_class->draw_rounded_rect = draw_rounded_rect;
renderer_class->draw_rounded_polyline = draw_rounded_polyline;
+ renderer_class->draw_rotated_image = draw_rotated_image;
+
/* other */
renderer_class->is_capable_to = is_capable_to;
renderer_class->set_pattern = set_pattern;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]