[dia] [path] new DiaPathRenderer



commit 7f576000f12dfa1b749ec48b03cead88f90d43e3
Author: Hans Breuer <hans breuer org>
Date:   Sun Oct 14 15:16:06 2012 +0200

    [path] new DiaPathRenderer
    
    - might bring "Convert to Path" to a whole new level
    - will allow unit testing of DiaObject::draw()

 lib/Makefile.am       |    2 +
 lib/create.h          |    7 +-
 lib/diapathrenderer.c |  692 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/diapathrenderer.h |   42 +++
 lib/libdia.def        |    3 +
 lib/makefile.msc      |    1 +
 6 files changed, 745 insertions(+), 2 deletions(-)
---
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f0c8d0b..c2cc383 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -156,6 +156,8 @@ libdia_la_SOURCES =  \
 		diainteractiverenderer.c \
 		diagdkrenderer.h \
 		diagdkrenderer.c \
+		diapathrenderer.h \
+		diapathrenderer.c \
 		diasvgrenderer.h \
 		diasvgrenderer.c \
 		dia_svg.h \
diff --git a/lib/create.h b/lib/create.h
index 7278e0f..ad8b01a 100644
--- a/lib/create.h
+++ b/lib/create.h
@@ -16,9 +16,10 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/*! \file create.h contains user_data structures for creating the non-trivial 
- *   standard objects (polylines & polygons).
+/*!
  * \defgroup ObjectCreate Creation of standard objects
+ * \brief Helpers for creation of the non-trivial standard objects
+ *
  * \ingroup StandardObjects
  *
  * Typical import plugins translate some vector representation of the import format
@@ -139,6 +140,8 @@ DiaObject *create_standard_image(real xpos, real ypos, real width, real height,
  */
 DiaObject *create_standard_group(GList *items);
 
+DiaObject *create_standard_path_from_object (DiaObject *obj);
+
 G_END_DECLS
 
 #endif
diff --git a/lib/diapathrenderer.c b/lib/diapathrenderer.c
new file mode 100644
index 0000000..5488b31
--- /dev/null
+++ b/lib/diapathrenderer.c
@@ -0,0 +1,692 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * diapathrenderer.c -- render _everything_ to a path
+ * Copyright (C) 2012 Hans Breuer <hans breuer org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "config.h"
+
+#include "diapathrenderer.h"
+#include "text.h" /* just for text->color */
+#include "standard-path.h" /* for text_to_path() */
+#include "boundingbox.h"
+
+#include "attributes.h" /* attributes_get_foreground() */
+
+/*!
+ * \brief Renderer which turns everything into a path (or a list thereof)
+ *
+ * The path renderer does not produce any external output by itself. It
+ * stroes it's results only internally in one or more pathes. These are
+ * further processed by e.g. create_standard_path_from_object().
+ *
+ * \extends _DiaRenderer
+ */
+struct _DiaPathRenderer
+{
+  DiaRenderer parent_instance; /*!< inheritance in object oriented C */
+
+  GPtrArray *pathes;
+
+  Color stroke;
+  Color fill;
+};
+
+struct _DiaPathRendererClass
+{
+  DiaRendererClass parent_class; /*!< the base class */
+};
+
+
+G_DEFINE_TYPE (DiaPathRenderer, dia_path_renderer, DIA_TYPE_RENDERER)
+
+/*!
+ * \brief Constructor
+ * Initialize everything which needs something else than 0.
+ */
+static void
+dia_path_renderer_init (DiaPathRenderer *self)
+{
+  self->stroke = attributes_get_foreground ();
+  self->fill = attributes_get_background ();
+}
+/*!
+ * \brief Destructor
+ * If there are still pathes left, deallocate them
+ */
+static void
+dia_path_renderer_finalize (GObject *object)
+{
+  DiaPathRenderer *self = DIA_PATH_RENDERER (object);
+
+  if (self->pathes) {
+    guint i;
+   
+    for (i = 0; i < self->pathes->len; ++i) {
+      GArray *path = g_ptr_array_index (self->pathes, self->pathes->len - 1);
+
+      g_array_free (path, TRUE);
+    }
+    g_ptr_array_free (self->pathes, TRUE);
+    self->pathes = NULL;
+  }
+  G_OBJECT_CLASS (dia_path_renderer_parent_class)->finalize (object);
+}
+
+/*!
+ * \brief Deliver the current path
+ * To be advanced if we want to support more than one path, e.g. for multiple
+ * color support.
+ * @param self   explicit this pointer
+ * @param stroke line color or NULL
+ * @param fill   fill color or NULL
+ * \private \memeberof _DiaPathRenderer
+ */
+static GArray *
+_get_current_path (DiaPathRenderer *self,
+		   const Color     *stroke,
+		   const Color     *fill)
+{
+  GArray *path;
+  /* creating a new path for every new color */
+  gboolean new_path = FALSE;
+
+  if (stroke && memcmp (stroke, &self->stroke, sizeof(*stroke)) != 0) {
+    memcpy (&self->stroke, stroke, sizeof(*stroke));
+    new_path = TRUE;
+  }
+  if (fill  && memcmp (fill, &self->fill, sizeof(*fill)) != 0) {
+    memcpy (&self->fill, fill, sizeof(*fill));
+    new_path = TRUE;
+  }
+
+  if (!self->pathes || new_path) {
+    self->pathes = g_ptr_array_new ();
+    g_ptr_array_add (self->pathes, g_array_new (FALSE, FALSE, sizeof(BezPoint)));
+  }
+  path = g_ptr_array_index (self->pathes, self->pathes->len - 1);
+  return path;
+}
+/*!
+ * \brief Starting a new rendering run
+ * Could be used to clean the path leftovers from a previous run.
+ * Typical export tenderers flush here.
+ */
+static void
+begin_render (DiaRenderer *self, const Rectangle *update)
+{
+}
+/*!
+ * \brief End of current rendering run
+ * Should not be used to clean the accumulated pathes 
+ */
+static void
+end_render(DiaRenderer *self)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+}
+static void
+set_linewidth(DiaRenderer *self, real linewidth)
+{  /* 0 == hairline **/
+}
+static void
+set_linecaps(DiaRenderer *self, LineCaps mode)
+{
+}
+static void
+set_linejoin(DiaRenderer *self, LineJoin mode)
+{
+}
+static void
+set_linestyle(DiaRenderer *self, LineStyle mode)
+{
+}
+static void
+set_dashlength(DiaRenderer *self, real length)
+{  /* dot = 20% of len */
+}
+static void
+set_fillstyle(DiaRenderer *self, FillStyle mode)
+{
+}
+
+/*! Find the last point matching or add a new move-to */
+static void
+_path_append (GArray *points, const Point *pt)
+{
+  const BezPoint *prev = (points->len > 0) ? &g_array_index (points, BezPoint, points->len - 1) : NULL;
+  const Point *last = prev ? (prev->type == BEZ_CURVE_TO ? &prev->p3 : &prev->p1) : NULL;
+
+  if (!last || last->x != pt->x || last->y != pt->y) {
+    BezPoint bp;
+    bp.type = BEZ_MOVE_TO;
+    bp.p1 = *pt;
+    g_array_append_val (points, bp);
+  }
+}
+static void
+_path_moveto (GArray *path, const Point *pt)
+{
+  BezPoint bp;
+  bp.type = BEZ_MOVE_TO;
+  bp.p1 = *pt;
+  g_array_append_val (path, bp);
+}
+static void
+_path_lineto (GArray *path, const Point *pt)
+{
+  BezPoint bp;
+  bp.type = BEZ_LINE_TO;
+  bp.p1 = *pt;
+  g_array_append_val (path, bp);
+}
+/*!
+ * \brief Create an arc segment approximation
+ * Code copied and adapted to our needs from _cairo_arc_segment()
+ */
+static void
+_path_arc_segment (GArray      *path,
+		   const Point *center,
+		   real         radius,
+		   real         angle_A,
+		   real         angle_B)
+{
+  BezPoint bp;
+  real r_sin_A, r_cos_A;
+  real r_sin_B, r_cos_B;
+  real h;
+
+  r_sin_A = radius * sin (angle_A);
+  r_cos_A = radius * cos (angle_A);
+  r_sin_B = radius * sin (angle_B);
+  r_cos_B = radius * cos (angle_B);
+
+  h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+  
+  bp.type = BEZ_CURVE_TO;
+  bp.p1.x = center->x + r_cos_A - h * r_sin_A;
+  bp.p1.y = center->y + r_sin_A + h * r_cos_A,
+  bp.p2.x = center->x + r_cos_B + h * r_sin_B,
+  bp.p2.y = center->y + r_sin_B - h * r_cos_B,
+  bp.p3.x = center->x + r_cos_B;
+  bp.p3.y = center->y + r_sin_B;
+
+  g_array_append_val (path, bp);
+}
+
+static void
+draw_line(DiaRenderer *self, 
+	  Point *start, Point *end, 
+	  Color *line_colour)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *points = _get_current_path (renderer, line_colour, NULL);
+
+  _path_append (points, start);
+  _path_lineto (points, end);
+}
+
+static void
+_polyline(DiaRenderer *self, 
+	  Point *points, int num_points, 
+	  const Color *stroke, const Color *fill)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  int i;
+  GArray *path = _get_current_path (renderer, stroke, fill);
+
+  g_return_if_fail (num_points > 1);
+
+  if (stroke)
+    _path_append (path, &points[0]);
+  else
+    _path_moveto (path, &points[0]);
+
+  for (i = 1; i < num_points; ++i)
+    _path_lineto (path, &points[i]);
+}
+static void
+draw_polyline(DiaRenderer *self, 
+	      Point *points, int num_points, 
+	      Color *line_colour)
+{
+  _polyline (self, points, num_points, line_colour, NULL);
+}
+static void
+draw_polygon(DiaRenderer *self, 
+	      Point *points, int num_points, 
+	      Color *line_colour)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, line_colour, NULL);
+
+  /* FIXME: can't be that simple ;) */
+  _polyline (self, points, num_points, line_colour, NULL);
+  _path_lineto (path, &points[0]);
+}
+static void
+fill_polygon(DiaRenderer *self, 
+	     Point *points, int num_points, 
+	     Color *color)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, NULL, color);
+
+  _polyline (self, points, num_points, NULL, color);
+  _path_lineto (path, &points[0]);
+}
+static void
+_rect (DiaRenderer *self, 
+       Point *ul_corner, Point *lr_corner,
+       const Color *stroke, const Color *fill)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, stroke, fill);
+  int i;
+  real width  = lr_corner->x - ul_corner->x;
+  real height = lr_corner->y - ul_corner->y;
+  Point pt = *ul_corner;
+
+  _path_moveto (path, &pt);
+
+  /* 0: top-right, clock-wise */
+  for (i = 0; i < 4; ++i) {
+    BezPoint bp;
+    
+    bp.type = BEZ_LINE_TO;
+    bp.p1.x = pt.x + (i < 2 ? width : 0);
+    bp.p1.y = pt.y + (i > 0 && i < 3 ? height : 0);
+    g_array_append_val (path, bp);
+  }
+}
+static void
+draw_rect (DiaRenderer *self, 
+	   Point *ul_corner, Point *lr_corner,
+	   Color *color)
+{
+  _rect (self, ul_corner, lr_corner, color, NULL);
+}
+static void
+fill_rect (DiaRenderer *self, 
+	   Point *ul_corner, Point *lr_corner,
+	   Color *color)
+{
+  _rect (self, ul_corner, lr_corner, NULL, color);
+}
+/*!
+ * \brief Convert an arc to some bezier curve-to
+ * \bug For arcs going through angle 0 the result is wrong, 
+ * kind of the opposite of the desired.
+ * \protected \memberof _DiaPathRenderer
+ */
+static void
+_arc (DiaRenderer *self, 
+      Point *center,
+      real width, real height,
+      real angle1, real angle2,
+      const Color *stroke, const Color *fill)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, stroke, fill);
+  Point start, end;
+  real radius = sqrt(width * height) / 2.0;
+  real ar1 = (M_PI / 180.0) * angle1;
+  real ar2 = (M_PI / 180.0) * angle2;
+  int i, segs = 3;
+  real ars = - (ar2 - ar1) / segs;
+
+  /* move to start point */
+  start.x = center->x + (width / 2.0)  * cos(ar1);  
+  start.y = center->y - (height / 2.0) * sin(ar1);
+  end.x = center->x + (width / 2.0)  * cos(ar2);  
+  end.y = center->y - (height / 2.0) * sin(ar2);
+  /* Dia and Cairo don't agree on arc definitions, so it needs
+   * to be converted, i.e. mirrored at the x axis
+   */
+  ar1 = - ar1;
+  ar2 = - ar2;
+
+  if (stroke) {
+    _path_append (path, &start);
+    for (i = 0; i < segs; ++i, ar1 += ars)
+      _path_arc_segment (path, center, radius, ar1, ar1 + ars);
+  } else {
+    _path_moveto (path, &start);
+    _path_arc_segment (path, center, radius, ar1, ar2);
+    _path_lineto (path, center);
+    _path_lineto (path, &start);
+  }
+}
+static void
+draw_arc (DiaRenderer *self, 
+	  Point *center,
+	  real width, real height,
+	  real angle1, real angle2,
+	  Color *color)
+{
+  _arc (self, center, width, height, angle1, angle2, color, NULL);
+}
+static void
+fill_arc (DiaRenderer *self, 
+	  Point *center,
+	  real width, real height,
+	  real angle1, real angle2,
+	  Color *color)
+{
+  _arc (self, center, width, height, angle1, angle2, NULL, color);
+}
+static void
+_ellipse (DiaRenderer *self,
+	  Point *center,
+	  real width, real height,
+	  const Color *stroke, const Color *fill)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, stroke, fill);
+  real w2 = width/2;
+  real h2 = height/2;
+  /* FIXME: just a rough estimation to get started */
+  real dx = w2 * 0.55;
+  real dy = h2 * 0.55;
+  Point pt;
+  int i;
+
+  pt = *center;
+  pt.y -= h2;
+  _path_moveto (path, &pt);
+  for (i = 0; i < 4; ++i) {
+    BezPoint bp;
+
+    /* i=0 is the right-most point, than going clock-wise */
+    pt.x = (i % 2 == 1 ? center->x : (i == 0 ? center->x + w2 : center->x -w2));
+    pt.y = (i % 2 == 0 ? center->y : (i == 1 ? center->y + h2 : center->y - h2));
+    bp.type = BEZ_CURVE_TO;
+    bp.p3 = pt;
+    
+    switch (i) {
+    case 0 : /* going right for p1 */
+      bp.p1.x = center->x + dx;
+      bp.p1.y = center->y - h2;
+      bp.p2.x = pt.x;
+      bp.p2.y = pt.y - dy;
+      break;
+    case 1 : /* going down for p1 */
+      bp.p1.x = center->x + w2;
+      bp.p1.y = center->y + dy;
+      bp.p2.x = pt.x + dx;
+      bp.p2.y = pt.y;
+      break;
+    case 2 : /* going left for p1 */
+      bp.p1.x = center->x - dx;
+      bp.p1.y = center->y + h2;
+      bp.p2.x = pt.x;
+      bp.p2.y = pt.y + dy;
+      break;
+    case 3 : /* going up for p1 */
+      bp.p1.x = center->x - w2;
+      bp.p1.y = center->y - dy;
+      bp.p2.x = pt.x - dx;
+      bp.p2.y = pt.y;
+      break;
+    default :
+      g_assert_not_reached ();
+    }
+
+    g_array_append_val (path, bp);
+  }
+}
+static void
+draw_ellipse (DiaRenderer *self, 
+	      Point *center,
+	      real width, real height,
+	      Color *color)
+{
+  _ellipse (self, center, width, height, color, NULL);
+}
+static void
+fill_ellipse (DiaRenderer *self, 
+	      Point *center,
+	      real width, real height,
+	      Color *color)
+{
+  _ellipse (self, center, width, height, NULL, color);
+}
+static void
+_bezier (DiaRenderer *self, 
+	 BezPoint *points, int numpoints,
+	 const Color *stroke, const Color *fill)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, stroke, fill);
+  int i;
+
+  for (i = 0; i < numpoints; ++i)
+    g_array_append_val (path, points[i]);
+  if (fill)
+    _path_lineto (path, &points[0].p1);
+}
+static void
+draw_bezier (DiaRenderer *self, 
+	     BezPoint *points,
+	     int numpoints,
+	     Color *color)
+{
+  _bezier(self, points, numpoints, color, NULL);
+}
+static void
+fill_bezier(DiaRenderer *self, 
+	    BezPoint *points, /* Last point must be same as first point */
+	    int numpoints,
+	    Color *color)
+{
+  _bezier(self, points, numpoints, NULL, color);
+}
+/*!
+ * \brief Convert the text object to a scaled path
+ * \memberof _DiaPathRenderer
+ */
+static void 
+draw_text (DiaRenderer *self,
+	   Text        *text) 
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  GArray *path = _get_current_path (renderer, NULL, &text->color);
+  int n0 = path->len;
+
+  if (!text_is_empty (text)) {
+    Rectangle bz_bb, tx_bb;
+    PolyBBExtras extra = { 0, };
+    real dx, dy, sx, sy;
+    guint i;
+    
+    text_to_path (text, path);
+
+    polybezier_bbox (&g_array_index (path, BezPoint, n0), path->len - n0, &extra, TRUE, &bz_bb);
+    text_calc_boundingbox (text, &tx_bb);
+    sx = (tx_bb.right - tx_bb.left) / (bz_bb.right - bz_bb.left);
+    sy = (tx_bb.bottom - tx_bb.top) / (bz_bb.bottom - bz_bb.top);
+    dx = tx_bb.left - bz_bb.left * sx;
+    dy = tx_bb.top - bz_bb.top * sy;
+
+    for (i = n0; i < path->len; ++i) {
+      BezPoint *bp = &g_array_index (path, BezPoint, i);
+
+      bp->p1.x = bp->p1.x * sx + dx;
+      bp->p1.y = bp->p1.y * sy + dy;
+      if (bp->type != BEZ_CURVE_TO)
+        continue;
+      bp->p2.x = bp->p2.x * sx + dx;
+      bp->p2.y = bp->p2.y * sy + dy;
+      bp->p3.x = bp->p3.x * sx + dx;
+      bp->p3.y = bp->p3.y * sy + dy;
+    }
+  }
+}
+
+/*!
+ * \brief Convert the string back to a _Text object and render that
+ * \memberof _DiaPathRenderer
+ */
+static void
+draw_string(DiaRenderer *self,
+	    const char *text,
+	    Point *pos, Alignment alignment,
+	    Color *color)
+{
+  if (text && strlen(text)) {
+    Text *text_obj;
+    /* it could have been so easy without the context switch */
+    text_obj = new_text (text,
+			 self->font, self->font_height,
+			 pos, color, alignment);
+    draw_text (self, text_obj);
+    text_destroy (text_obj);
+  }
+}
+
+/*! 
+ * \brief Render just a cheap emulation ;)
+ *
+ * It might be desirable to convert the given pixels to some vector representation.
+ * If simple and fast enough that code could even live in Dia's repository. For now
+ * just rendering the images bounding box has to be enough.
+ *
+ * \memberof _DiaPathRenderer
+ */
+static void
+draw_image(DiaRenderer *self,
+	   Point *point,
+	   real width, real height,
+	   DiaImage *image)
+{
+  DiaPathRenderer *renderer = DIA_PATH_RENDERER (self);
+  /* warning colors ;) */
+  Color stroke = { 1.0, 0.0, 0.0, 0.75 };
+  Color fill = { 1.0, 1.0, 0.0, 0.5 };
+  GArray *path = _get_current_path (renderer, &stroke, &fill);
+  Point to = *point;
+
+  _path_moveto (path, &to);
+  to.x += width;
+  _path_lineto (path, &to);
+  to.y += height;
+  _path_lineto (path, &to);
+  to.x -= width;
+  _path_lineto (path, &to);
+  to.y -= height;
+  _path_lineto (path, &to);
+  to.x += width; to.y += height;
+  _path_lineto (path, &to);
+}
+
+/*!
+ * \brief _DiaPathRenderer class initialization
+ * Overwrite methods of the base classes here.
+ */
+static void
+dia_path_renderer_class_init (DiaPathRendererClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
+
+  object_class->finalize = dia_path_renderer_finalize;
+
+  /* renderer members */
+  renderer_class->begin_render = begin_render;
+  renderer_class->end_render   = end_render;
+
+  renderer_class->set_linewidth  = set_linewidth;
+  renderer_class->set_linecaps   = set_linecaps;
+  renderer_class->set_linejoin   = set_linejoin;
+  renderer_class->set_linestyle  = set_linestyle;
+  renderer_class->set_dashlength = set_dashlength;
+  renderer_class->set_fillstyle  = set_fillstyle;
+
+  renderer_class->draw_line    = draw_line;
+  renderer_class->fill_polygon = fill_polygon;
+  renderer_class->draw_rect    = draw_rect;
+  renderer_class->fill_rect    = fill_rect;
+  renderer_class->draw_arc     = draw_arc;
+  renderer_class->fill_arc     = fill_arc;
+  renderer_class->draw_ellipse = draw_ellipse;
+  renderer_class->fill_ellipse = fill_ellipse;
+
+  renderer_class->draw_string  = draw_string;
+  renderer_class->draw_image   = draw_image;
+
+  /* medium level functions */
+  renderer_class->draw_rect = draw_rect;
+  renderer_class->draw_polyline  = draw_polyline;
+  renderer_class->draw_polygon   = draw_polygon;
+
+  renderer_class->draw_bezier   = draw_bezier;
+  renderer_class->fill_bezier   = fill_bezier;
+  renderer_class->draw_text     = draw_text;
+
+}
+
+#include "object.h"
+#include "create.h"
+#include "group.h"
+
+/*!
+ * \brief Convert an object to a _StdPath by rendering it with _DiaPathRenderer
+ *
+ * The result is either a single _SdtPath or a _Group of _Stdpath depending ont
+ * the criteria implemented in _get_current_path() and of course the content of
+ * the given object.
+ */
+DiaObject *
+create_standard_path_from_object (DiaObject *obj)
+{
+  DiaObject *path;
+  DiaRenderer *renderer;
+  DiaPathRenderer *pr;
+
+  g_return_val_if_fail (obj != NULL, NULL);
+
+  renderer = g_object_new (DIA_TYPE_PATH_RENDERER, 0);
+  pr = DIA_PATH_RENDERER (renderer);
+
+  obj->ops->draw (obj, renderer);
+
+  /* messing with internals */
+  if (!pr->pathes) { /* oops? */
+    path = NULL;
+  } else if (pr->pathes->len == 1) {
+    GArray *points = g_ptr_array_index (pr->pathes, 0);
+    path = create_standard_path (points->len, &g_array_index (points, BezPoint, 0));
+  } else {
+    /* create a group of pathes */
+    GList *list = NULL;
+    GArray *points;
+    gsize i;
+
+    for (i = 0; i < pr->pathes->len; ++i) {
+      GArray *points = g_ptr_array_index (pr->pathes, i);
+      DiaObject *obj;
+
+      obj = create_standard_path (points->len, &g_array_index (points, BezPoint, 0));
+      if (obj)
+        list = g_list_append (list, obj);
+    }
+    path = group_create (list);
+  }
+  g_object_unref (renderer);
+
+  return path;
+}
diff --git a/lib/diapathrenderer.h b/lib/diapathrenderer.h
new file mode 100644
index 0000000..16a9c89
--- /dev/null
+++ b/lib/diapathrenderer.h
@@ -0,0 +1,42 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * diapathrenderer.c -- render _everything_ to a path
+ * Copyright (C) 2012, Hans Breuer <Hans Breuer Org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef DIA_PATH_RENDERER_H
+#define DIA_PATH_RENDERER_H
+
+#include "diarenderer.h"
+
+typedef struct _DiaPathRenderer DiaPathRenderer;
+typedef struct _DiaPathRendererClass DiaPathRendererClass;
+
+/*! GObject boiler plate, create runtime information */
+#define DIA_TYPE_PATH_RENDERER           (dia_path_renderer_get_type ())
+/*! GObject boiler plate, a safe type cast */
+#define DIA_PATH_RENDERER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), DIA_TYPE_PATH_RENDERER, DiaPathRenderer))
+/*! GObject boiler plate, in C++ this would be the vtable */
+#define DIA_PATH_RENDERER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), DIA_TYPE_PATH_RENDERER, DiaPathRendererClass))
+/*! GObject boiler plate, type check */
+#define DIA_IS_PATH_RENDERER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DIA_TYPE_PATH_RENDERER))
+/*! GObject boiler plate, get from object to class (vtable) */
+#define DIA_PATH_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DIA_TYPE_PATH_RENDERER, DiaPathRendererClass))
+
+GType dia_path_renderer_get_type (void) G_GNUC_CONST;
+
+#endif
diff --git a/lib/libdia.def b/lib/libdia.def
index 730b89f..44be57c 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -127,6 +127,7 @@ EXPORTS
  create_standard_group
  create_standard_image
  create_standard_path
+ create_standard_path_from_object
  create_standard_path_from_text
  create_standard_polygon
  create_standard_polyline
@@ -296,6 +297,8 @@ EXPORTS
  pixbuf_encode_base64
  pixbuf_decode_base64
 
+ dia_path_renderer_get_type
+
  dia_interactive_renderer_interface_get_type
  
  dialog_make
diff --git a/lib/makefile.msc b/lib/makefile.msc
index 8548604..81cb5e1 100644
--- a/lib/makefile.msc
+++ b/lib/makefile.msc
@@ -73,6 +73,7 @@ OBJECTS = \
 	diagdkrenderer.obj \
 	diainteractiverenderer.obj \
 	diarenderer.obj \
+	diapathrenderer.obj \
 	diasvgrenderer.obj \
 	dynamic_obj.obj \
 	element.obj \



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