[dia] DiaRenderer::draw_arc() and fill_arc() now preserving direction info



commit fa11a8fd57059aa4ffcebe54aa5d1d6db2e2e7c1
Author: Hans Breuer <hans breuer org>
Date:   Sun Jun 1 17:30:11 2014 +0200

    DiaRenderer::draw_arc() and fill_arc() now preserving direction info
    
    The previous definition of Dia's draw/fill-arc was basically following
    the definition coming from GDK as follows:
    
    '''
    width: the width of the bounding rectangle.
    height: the height of the bounding rectangle.
    angle1: the start angle of the arc, relative to the 3 o'clock position,
         counter-clockwise.
    angle2: the end angle of the arc, relative to angle1
    
    Draws an arc or a filled 'pie slice'. The arc is defined by the bounding
    rectangle of the entire ellipse, and the start and end angles of the part
    of the ellipse to be drawn.
    '''
    
    In contrast to GDK where angle2 is always greater than angle1 Dia's now
    only uses the counter-clockwise rule requiring the backend code to do
    it's own calculations.
    
    The previous approach had shortcomings when backends are actually
    interested in the direction of the arc. One such example is cairo,
    which could use cairo_arc() and cairo_arc_negative().
    If a more complex construct like a path for a rounded rectangle is done
    the direction information becomes crucial to have a continuous path for
    proper filling. The same issue can be observed with recently added
    facilities like DiaPathRenderer and it's convert-to-path use.
    
    Renderer core changes
     - gdk: counter-clockwise
     - import: direction preserving with big_arc and clockwise flags
     - path: XXX: still something wrong with rounded poly-line arcs
     - svg: now using directed arcs
     - transform: using path_build_arc() which migh be the XXX from above;)
    Renderer plug-in changes:
     - cairo: now using directed arcs, also resurrecting draw_rounded_rect
     - cgm: counter-clockwise
     - drs: no change (now using directed arc rendering)
     - dxf: counter-clockwise
     - hpgl: counter-clockwise
     - libart: counter-clockwise (by line approximation as before)
     - metapost: already handled preserving arc direction
     - pgf: counter-clockwise
     - ps: counter-clockwise
     - pstricks: counter-clockwise
     - python: pass-through to plug-ins
       - diadisect.py: warn about angle difference being greater than 360°
       - diasvg.py: direction preserving
       - diastddia.py: direction preserving (removing FIXME from 2009)
       - export-renderer.py: no change, just pass-through
     - vdx: preserving direction (by control angle)
     - wmf: counter-clockwise
     - wpg: counter-clockwise
     - xfig: arc direction preserving

 lib/diagdkrenderer.c                |  104 +++----------------------------
 lib/diaimportrenderer.c             |   15 ++++-
 lib/diapathrenderer.c               |   17 +-----
 lib/diarenderer.c                   |  118 +++++++++++++++++++----------------
 lib/diarenderer.h                   |    2 +-
 lib/diasvgrenderer.c                |   10 +--
 lib/geometry.c                      |   16 +----
 objects/standard/arc.c              |   15 ++++-
 plug-ins/cairo/diacairo-renderer.c  |   98 +++++++++++++++++++++++------
 plug-ins/cgm/cgm.c                  |    6 ++
 plug-ins/dxf/dxf-export.c           |   32 ++++++----
 plug-ins/hpgl/hpgl.c                |    6 ++
 plug-ins/libart/dialibartrenderer.c |   18 ++++--
 plug-ins/metapost/render_metapost.c |    3 +-
 plug-ins/pgf/render_pgf.c           |    6 ++
 plug-ins/postscript/diapsrenderer.c |    6 ++
 plug-ins/pstricks/render_pstricks.c |    6 ++
 plug-ins/python/diadissect.py       |    9 +++-
 plug-ins/python/diastddia.py        |    3 +-
 plug-ins/python/diasvg.py           |    6 +-
 plug-ins/vdx/vdx-export.c           |    6 +--
 plug-ins/wmf/wmf.cpp                |   12 ++++
 plug-ins/wpg/wpg-import.c           |    8 ++-
 plug-ins/wpg/wpg.c                  |   28 +++++++-
 plug-ins/xfig/xfig-export.c         |    2 +-
 25 files changed, 305 insertions(+), 247 deletions(-)
---
diff --git a/lib/diagdkrenderer.c b/lib/diagdkrenderer.c
index 021aa9f..5f97ac1 100644
--- a/lib/diagdkrenderer.c
+++ b/lib/diagdkrenderer.c
@@ -99,9 +99,6 @@ static void draw_polyline (DiaRenderer *renderer,
 static void draw_polygon (DiaRenderer *renderer,
                           Point *points, int num_points,
                           Color *fill, Color *stroke);
-static void draw_rounded_rect (DiaRenderer *renderer,
-                               Point *ul_corner, Point *lr_corner,
-                               Color *fill, Color *stroke, real radius);
 
 static real get_text_width (DiaRenderer *renderer,
                             const gchar *text, int length);
@@ -229,9 +226,6 @@ dia_gdk_renderer_class_init(DiaGdkRendererClass *klass)
   renderer_class->draw_rect    = draw_rect;
   renderer_class->draw_polyline  = draw_polyline;
 
-  /* highest level functions */
-  renderer_class->draw_rounded_rect = draw_rounded_rect;
-
   /* Interactive functions */
   renderer_class->get_text_width = get_text_width;
 }
@@ -553,6 +547,7 @@ draw_fill_arc (DiaRenderer *object,
   GdkColor gdkcolor;
   gint top, left, bottom, right;
   real dangle;
+  gboolean counter_clockwise = angle2 > angle1;
   
   dia_transform_coords(renderer->transform,
                        center->x - width/2, center->y - height/2,
@@ -567,14 +562,19 @@ draw_fill_arc (DiaRenderer *object,
   renderer_color_convert(renderer, color, &gdkcolor);
   gdk_gc_set_foreground(gc, &gdkcolor);
 
-  dangle = angle2-angle1;
+  /* GDK wants it always counter-clockwise */
+  if (counter_clockwise)
+    dangle = angle2-angle1;
+  else
+    dangle = angle1-angle2;
   if (dangle<0)
     dangle += 360.0;
 
   gdk_draw_arc(renderer->pixmap,
               gc, fill,
               left, top, right-left, bottom-top,
-              (int) (angle1*64.0), (int) (dangle*64.0));
+              (int) (counter_clockwise ? angle1 : angle2) * 64.0,
+              (int) (dangle * 64.0));
 }
 static void 
 draw_arc (DiaRenderer *object, 
@@ -924,94 +924,6 @@ draw_polyline (DiaRenderer *self,
   g_free(gdk_points);
 }
 
-/*!
- * \brief Fill and/or stroke a rectangle with rounded corner
- * Implemented to avoid seams between arcs and lines caused by the base class
- * working in real which than gets rounded independently to int here
- * \memberof _DiaGdkRenderer
- */
-static void
-draw_rounded_rect (DiaRenderer *self, 
-                  Point *ul_corner, Point *lr_corner,
-                  Color *fill, Color *stroke,
-                  real radius)
-{
-  DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self);
-  GdkGC *gc = renderer->gc;
-  GdkColor gdkcolor;
-  gint top, bottom, left, right, d;
-  gint offset = 0; /* to compensate for a radius smaller than line_width */
-  Color *color = fill ? fill : stroke;
-  gint r = dia_transform_length(renderer->transform, radius);
-
-  g_return_if_fail (color != NULL);
-
-  if (r < 1) {
-    draw_rect (self, ul_corner, lr_corner, fill, stroke);
-    return;
-  }
-
-  dia_transform_coords(renderer->transform, 
-                       ul_corner->x, ul_corner->y, &left, &top);
-  dia_transform_coords(renderer->transform, 
-                       lr_corner->x, lr_corner->y, &right, &bottom);
-  r = dia_transform_length(renderer->transform, radius);
-
-  if ((left>right) || (top>bottom))
-    return;
-  /* adjust radius to possible size */
-  if (r>(right-left)/2)
-    r = (right-left)/2;
-  if (r>(bottom-top)/2)
-    r = (bottom-top)/2;
-
-  d = r<<1;
-  /* line_width is already scaled */
-  if (renderer->line_width > d)
-    offset = (renderer->line_width + 1) / 2;
-
-  renderer_color_convert(renderer, color, &gdkcolor);
-  gdk_gc_set_foreground(gc, &gdkcolor);
-
-  if (d > 0) {
-    if (offset > 0) {
-      /* avoid windowing system defined arc artifacts drawing by some adjustments  */
-      gdk_gc_set_line_attributes(renderer->gc, 
-                                 r, renderer->line_style, 
-                                renderer->cap_style, renderer->join_style);
-      gdk_draw_arc(renderer->pixmap, gc, TRUE, left-offset, top-offset, d, d, 90<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, TRUE, right-d+offset, top-offset, d, d, 0<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, TRUE, right-d+offset, bottom-d+offset, d, d, 270<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, TRUE, left-offset, bottom-d+offset, d, d, 180<<6, 90<<6);
-      gdk_gc_set_line_attributes(renderer->gc, 
-                                 renderer->line_width, renderer->line_style, 
-                                renderer->cap_style, renderer->join_style);
-    } else {
-      gdk_draw_arc(renderer->pixmap, gc, !!fill, left, top, d, d, 90<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, !!fill, right-d, top, d, d, 0<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, !!fill, right-d, bottom-d, d, d, 270<<6, 90<<6);
-      gdk_draw_arc(renderer->pixmap, gc, !!fill, left, bottom-d, d, d, 180<<6, 90<<6);
-    }
-  }
-
-  if (fill) {
-    renderer_color_convert(renderer, fill, &gdkcolor);
-    gdk_gc_set_foreground(gc, &gdkcolor);
-    gdk_draw_rectangle (renderer->pixmap, renderer->gc, TRUE, 
-                        left+r-offset, top, right-left-d+offset, bottom-top);
-    gdk_draw_rectangle (renderer->pixmap, renderer->gc, TRUE, 
-                        left, top+r-offset, right-left, bottom-top-d+offset);
-  }
-  if (stroke) {
-    renderer_color_convert(renderer, stroke, &gdkcolor);
-    gdk_gc_set_foreground(gc, &gdkcolor);
-    gdk_draw_line(renderer->pixmap, gc, left+r-offset, top, right-r+offset, top);
-    gdk_draw_line(renderer->pixmap, gc, right, top+r-offset, right, bottom-r+offset);
-    gdk_draw_line(renderer->pixmap, gc, right-r+offset, bottom, left+r-1-offset, bottom);
-    gdk_draw_line(renderer->pixmap, gc, left, bottom-r+offset, left, top+r-1-offset);
-  }
-}
-
 static int
 get_width_pixels (DiaRenderer *object)
 { 
diff --git a/lib/diaimportrenderer.c b/lib/diaimportrenderer.c
index 190473c..e53e947 100644
--- a/lib/diaimportrenderer.c
+++ b/lib/diaimportrenderer.c
@@ -330,6 +330,13 @@ _make_arc (Point *center,
   real rx = width / 2, ry = height / 2;
   real r = sqrt (rx*ry);
   real a, b, d;
+  /* handle direction information
+   *  - the arc being bigger than 180 => d>r!
+   *  - angle2 < angle1 => d must be negative
+   */
+  gboolean big_arc = fabs(angle2-angle1) > 180.0;
+  gboolean clockwise = angle2 < angle1;
+
   st.x = center->x + rx * cos(angle1*G_PI/180);
   st.y = center->y - ry * sin(angle1*G_PI/180);
   en.x = center->x + rx * cos(angle2*G_PI/180);
@@ -339,8 +346,12 @@ _make_arc (Point *center,
     b = sqrt(r*r - a*a); /* Pythagoras */
   else
     b = 0; /* half circle */
-  d = r - b;
-
+  if (big_arc)
+    d = r + b;
+  else
+    d = r - b;
+  if (clockwise)
+    d = -d;
   object = create_standard_arc (st.x, st.y, en.x, en.y, d, NULL, NULL);
   return object;
 }
diff --git a/lib/diapathrenderer.c b/lib/diapathrenderer.c
index a7519a5..6c5a6bd 100644
--- a/lib/diapathrenderer.c
+++ b/lib/diapathrenderer.c
@@ -386,11 +386,8 @@ path_build_arc (GArray *path,
   int i, segs;
   real ars;
 
-  while (angle1 > angle2)
-    angle1 -= 360;
-
-  ar1 = (M_PI / 180.0) * angle2;
-  ar2 = (M_PI / 180.0) * angle1;
+  ar1 = (M_PI / 180.0) * angle1;
+  ar2 = (M_PI / 180.0) * angle2;
   /* one segment for ever 90 degrees */
   segs = (int)(fabs(ar2 - ar1) / (M_PI/2)) + 1;
   ars = - (ar2 - ar1) / segs;
@@ -399,16 +396,6 @@ path_build_arc (GArray *path,
   start.x = center->x + (width / 2.0)  * cos(ar1);
   start.y = center->y - (height / 2.0) * sin(ar1);
 
-  /* 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;
-  while (ar1 < 0 || ar2 < 0) {
-    ar1 += 2 * M_PI;
-    ar2 += 2 * M_PI;
-  }
-
   if (!closed) {
     _path_append (path, &start);
     for (i = 0; i < segs; ++i, ar1 += ars)
diff --git a/lib/diarenderer.c b/lib/diarenderer.c
index 1bd433c..3745ef4 100644
--- a/lib/diarenderer.c
+++ b/lib/diarenderer.c
@@ -815,16 +815,20 @@ draw_rounded_polyline (DiaRenderer *renderer,
     Point c;
     real start_angle, stop_angle;
     real min_radius;
+    gboolean arc_it;
+
     p3.x = p[i+1].x; p3.y = p[i+1].y;
     p4.x = p[i+2].x; p4.y = p[i+2].y;
-    
+
     /* adjust the radius if it would cause odd rendering */
     min_radius = MIN(radius, calculate_min_radius(&p1,&p2,&p4));
-    if (fillet(&p1,&p2,&p3,&p4, min_radius, &c, &start_angle, &stop_angle))
+    arc_it = fillet(&p1,&p2,&p3,&p4, min_radius, &c, &start_angle, &stop_angle);
+    /* start with the line drawing to allow joining in backend */    
+    klass->draw_line(renderer, &p1, &p2, color);
+    if (arc_it)
       klass->draw_arc(renderer, &c, min_radius*2, min_radius*2,
                      start_angle,
                      stop_angle, color);
-    klass->draw_line(renderer, &p1, &p2, color);
     p1.x = p3.x; p1.y = p3.y;
     p2.x = p4.x; p2.y = p4.y;
   }
@@ -901,54 +905,58 @@ draw_rounded_rect (DiaRenderer *renderer,
   DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
   Point start, end, center;
   Color *color = fill ? fill : stroke;
-
-  radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
-  radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
+  /* clip radius per axis to use the full API;) */
+  real rw = MIN(radius, (lr_corner->x-ul_corner->x)/2);
+  real rh = MIN(radius, (lr_corner->y-ul_corner->y)/2);
   
-  if (radius < 0.00001) {
+  if (rw < 0.00001 || rh < 0.00001) {
     renderer_ops->draw_rect(renderer, ul_corner, lr_corner, fill, stroke);
-    return;
-  }
-
-  /* if the renderer has it's own draw_bezier use that */
-  if (DIA_RENDERER_GET_CLASS(renderer)->draw_bezier != &draw_bezier) {
-    _rounded_rect_with_bezier (renderer, ul_corner, lr_corner, fill, stroke, radius);
-    return;
+  } else {
+    real tlx = ul_corner->x; /* top-left x */
+    real tly = ul_corner->y; /* top-left y */
+    real brx = lr_corner->x; /* bottom-right x */
+    real bry = lr_corner->y; /* bottom-right y */
+    /* calculate all start/end points needed in advance, counter-clockwise */
+    Point pts[8];
+    Point cts[4]; /* ... and centers */
+    int i;
+
+    cts[0].x = tlx + rw; cts[0].y = tly + rh; /* ul */
+    pts[0].x = tlx; pts[0].y = tly + rh;
+    pts[1].x = tlx; pts[1].y = bry - rh; /* down */
+
+    cts[1].x = tlx + rw; cts[1].y = bry - rh; /* ll */
+    pts[2].x = tlx + rw; pts[2].y = bry;
+    pts[3].x = brx - rw; pts[3].y = bry; /* right */
+
+    cts[2].x = brx - rw; cts[2].y = bry - rh; /* lr */
+    pts[4].x = brx; pts[4].y = bry - rh;
+    pts[5].x = brx; pts[5].y = tly + rh; /* up */
+
+    cts[3].x = brx - rw; cts[3].y = tly + rh; /* ur */
+    pts[6].x = brx - rw; pts[6].y = tly; /* left */
+    pts[7].x = tlx + rw; pts[7].y = tly;
+
+ 
+    /* If line_width would be available we could approximate small radius with:
+     * renderer_ops->draw_polygon (renderer, pts, 8, fill, stroke);
+     */
+    /* a filled cross w/ overlap : might not be desirable with alpha */
+    if (fill) {
+      if (pts[3].x > pts[7].x)
+        renderer_ops->draw_rect (renderer, &pts[7], &pts[3], fill, NULL);
+      if (pts[4].y > pts[0].y)
+        renderer_ops->draw_rect (renderer, &pts[0], &pts[4], fill, NULL);
+    }
+    for (i = 0; i < 4; ++i) {
+      if (fill)
+       renderer_ops->fill_arc (renderer, &cts[i], 2*rw, 2*rh, (i+1)*90.0, (i+2)*90.0, fill);
+      if (stroke)
+       renderer_ops->draw_arc (renderer, &cts[i], 2*rw, 2*rh, (i+1)*90.0, (i+2)*90.0, stroke);
+      if (stroke)
+        renderer_ops->draw_line (renderer, &pts[i*2], &pts[i*2+1], stroke);
+    }
   }
-  /* final fallback */
-  //FIXME: needs extended draw_arc 
-  start.x = center.x = ul_corner->x+radius;
-  end.x = lr_corner->x-radius;
-  start.y = end.y = ul_corner->y;
-  renderer_ops->draw_line(renderer, &start, &end, color);
-  start.y = end.y = lr_corner->y;
-  renderer_ops->draw_line(renderer, &start, &end, color);
-
-  center.y = ul_corner->y+radius;
-  renderer_ops->draw_arc(renderer, &center, 
-                         2.0*radius, 2.0*radius,
-                         90.0, 180.0, color);
-  center.x = end.x;
-  renderer_ops->draw_arc(renderer, &center, 
-                         2.0*radius, 2.0*radius,
-                         0.0, 90.0, color);
-
-  start.y = ul_corner->y+radius;
-  start.x = end.x = ul_corner->x;
-  end.y = center.y = lr_corner->y-radius;
-  renderer_ops->draw_line(renderer, &start, &end, color);
-  start.x = end.x = lr_corner->x;
-  renderer_ops->draw_line(renderer, &start, &end, color);
-
-  center.y = lr_corner->y-radius;
-  center.x = ul_corner->x+radius;
-  renderer_ops->draw_arc(renderer, &center, 
-                         2.0*radius, 2.0*radius,
-                         180.0, 270.0, color);
-  center.x = lr_corner->x-radius;
-  renderer_ops->draw_arc(renderer, &center, 
-                         2.0*radius, 2.0*radius,
-                         270.0, 360.0, color);
 }
 
 static void
@@ -1385,17 +1393,17 @@ draw_arc_with_arrows (DiaRenderer *renderer,
   while (angle1 < 0.0) angle1 += 360.0;
   angle2 = -atan2(new_endpoint.y - center.y, new_endpoint.x - center.x)*180.0/G_PI;
   while (angle2 < 0.0) angle2 += 360.0;
-  if (righthand) {
-    real tmp = angle1;
-    angle1 = angle2;
-    angle2 = tmp;
-  }
 
   /* Only draw it if the original direction is preserved */
-  if (is_right_hand (&new_startpoint, midpoint, &new_endpoint) == righthand)
+  if (is_right_hand (&new_startpoint, midpoint, &new_endpoint) == righthand) {
+    /* make it direction aware */
+    if (!righthand && angle2 < angle1)
+      angle1 -= 360.0;
+    else if (righthand && angle2 > angle1)
+      angle2 -= 360.0;
     DIA_RENDERER_GET_CLASS(renderer)->draw_arc(renderer, &center, width, width,
                                               angle1, angle2, color);
-
+  }
   if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
     arrow_draw(renderer, start_arrow->type,
               &start_arrow_head, &start_arrow_end,
diff --git a/lib/diarenderer.h b/lib/diarenderer.h
index 0c9f9b8..51c2f1b 100644
--- a/lib/diarenderer.h
+++ b/lib/diarenderer.h
@@ -138,7 +138,7 @@ struct _DiaRendererClass
                         Point *points, int num_points,
                         Color *fill, Color *stroke);
   /*! Draw an arc, given its center, the bounding box (widget, height),
-     the start angle and the end angle */
+     the start angle and the end angle. It's counter-clockwise if angle2>angle1 */
   void (*draw_arc) (DiaRenderer *renderer,
                     Point *center,
                     real width, real height,
diff --git a/lib/diasvgrenderer.c b/lib/diasvgrenderer.c
index bbdcd59..5ce361b 100644
--- a/lib/diasvgrenderer.c
+++ b/lib/diasvgrenderer.c
@@ -529,7 +529,7 @@ draw_arc(DiaRenderer *self,
   real sy=center->y - ry*sin(angle1*G_PI/180);
   real ex=center->x + rx*cos(angle2*G_PI/180);
   real ey=center->y - ry*sin(angle2*G_PI/180);
-  int swp = 0; /* always drawing negative direction (still) */
+  int swp = (angle2 > angle1) ? 0 : 1; /* not always drawing negative direction anymore */
   int large_arc;
   gchar sx_buf[DTOSTR_BUF_SIZE];
   gchar sy_buf[DTOSTR_BUF_SIZE];
@@ -538,9 +538,7 @@ draw_arc(DiaRenderer *self,
   gchar ex_buf[DTOSTR_BUF_SIZE];
   gchar ey_buf[DTOSTR_BUF_SIZE];
 
-  if (angle1 > angle2)
-    angle2 += 360;
-  large_arc = (angle2 - angle1 >= 180);
+  large_arc = (fabs(angle2 - angle1) >= 180);
 
   node = xmlNewChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"path", NULL);
   
@@ -570,8 +568,8 @@ fill_arc(DiaRenderer *self,
   real sy=center->y - ry*sin(angle1*G_PI/180);
   real ex=center->x + rx*cos(angle2*G_PI/180);
   real ey=center->y - ry*sin(angle2*G_PI/180);
-  int swp = 0; /* always drawin negative direction */
-  int large_arc = (angle2 - angle1 >= 180);
+  int swp = (angle2 > angle1) ? 0 : 1; /* preserve direction */
+  int large_arc = (fabs(angle2 - angle1) >= 180);
   gchar sx_buf[DTOSTR_BUF_SIZE];
   gchar sy_buf[DTOSTR_BUF_SIZE];
   gchar rx_buf[DTOSTR_BUF_SIZE];
diff --git a/lib/geometry.c b/lib/geometry.c
index d27f6b0..1e95562 100644
--- a/lib/geometry.c
+++ b/lib/geometry.c
@@ -594,23 +594,13 @@ fillet(Point *p1, Point *p2, Point *p3, Point *p4,
 
   start_angle = atan2(gv1.y,gv1.x);   /* Beginning angle for arc */
   stop_angle = dot2(&gv1,&gv2);
-  if ( point_cross(&gv1,&gv2) < 0.0 ) {
-    stop_angle = -stop_angle; /* Angle subtended by arc */
-    /* also this means we need to swap our angles later on */
-    righthand = TRUE;
-  }
+  righthand = point_cross(&gv1,&gv2) < 0.0;
   /* now calculate the actual angles in a form that the draw_arc function
      of the renderer can use */
   start_angle = start_angle*180.0/G_PI;
+  if (righthand)
+    stop_angle = -stop_angle;
   stop_angle  = start_angle + stop_angle*180.0/G_PI;
-  while (start_angle < 0.0) start_angle += 360.0;
-  while (stop_angle < 0.0)  stop_angle += 360.0;
-  /* swap the start and stop if we had to negate the cross product */
-  if ( righthand ) {
-    real tmp = start_angle;
-    start_angle = stop_angle;
-    stop_angle = tmp;
-  }
   *pa = start_angle;
   *aa = stop_angle;
   return TRUE;
diff --git a/objects/standard/arc.c b/objects/standard/arc.c
index 4afd0bf..c40af2a 100644
--- a/objects/standard/arc.c
+++ b/objects/standard/arc.c
@@ -629,10 +629,17 @@ arc_draw(Arc *arc, DiaRenderer *renderer)
   if (   arc->start_arrow.type ==  ARROW_NONE
       && arc->end_arrow.type ==  ARROW_NONE
       && !start_cp && !end_cp) {
-    /* avoid all the calculation errors and use what whe have */
+    /* avoid all the calculation errors and start with original arcs */
+    real angle1 = arc->curve_distance > 0.0 ? arc->angle1 : arc->angle2;
+    real angle2 = arc->curve_distance > 0.0 ? arc->angle2 : arc->angle1;
+    /* make it direction aware */
+    if (arc->curve_distance > 0.0 && angle2 < angle1)
+      angle1 -= 360.0;
+    else if (arc->curve_distance < 0.0 && angle2 > angle1)
+      angle2 -= 360.0;
     renderer_ops->draw_arc(renderer, &arc->center_handle.pos,
                           arc->radius*2.0, arc->radius*2.0,
-                          arc->angle1, arc->angle2,
+                          angle1, angle2,
                           &arc->arc_color);
   } else {
     renderer_ops->draw_arc_with_arrows(renderer,
@@ -820,7 +827,9 @@ arc_update_data(Arc *arc)
   if (angle2<0)
     angle2+=360.0;
 
-  /* swap: draw_arc is always counter-clockwise */
+  /* swap: draw_arc is not always counter-clockwise, but our member variables
+   * stay counter-clockwise to keep all the internal calculations simple
+   */
   if (radius<0.0) {
     real tmp;
     tmp = angle1;
diff --git a/plug-ins/cairo/diacairo-renderer.c b/plug-ins/cairo/diacairo-renderer.c
index b7f2938..b5d3c38 100644
--- a/plug-ins/cairo/diacairo-renderer.c
+++ b/plug-ins/cairo/diacairo-renderer.c
@@ -292,10 +292,13 @@ _pattern_build_for_cairo (DiaPattern *pattern, const Rectangle *ext)
  * \brief Make use of the pattern if any
  */
 static void
-_dia_cairo_fill (DiaCairoRenderer *renderer)
+_dia_cairo_fill (DiaCairoRenderer *renderer, gboolean preserve)
 {
   if (!renderer->pattern) {
-    cairo_fill (renderer->cr);
+    if (preserve)
+      cairo_fill_preserve (renderer->cr);
+    else
+      cairo_fill (renderer->cr);
   } else {
     /* maybe we should cache the cairo-pattern */
     cairo_pattern_t *pat;
@@ -306,7 +309,10 @@ _dia_cairo_fill (DiaCairoRenderer *renderer)
 
     pat = _pattern_build_for_cairo (renderer->pattern, &fe);
     cairo_set_source (renderer->cr, pat);
-    cairo_fill (renderer->cr);
+    if (preserve)
+      cairo_fill_preserve (renderer->cr);
+    else
+      cairo_fill (renderer->cr);
     cairo_pattern_destroy (pat);
   }
 }
@@ -567,7 +573,8 @@ draw_line(DiaRenderer *self,
             start->x, start->y, end->x, end->y));
 
   cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, color->alpha);
-  cairo_move_to (renderer->cr, start->x, start->y);
+  if (!renderer->stroke_pending) /* use current point from previous drawing command */
+    cairo_move_to (renderer->cr, start->x, start->y);
   cairo_line_to (renderer->cr, end->x, end->y);
   if (!renderer->stroke_pending)
     cairo_stroke (renderer->cr);
@@ -627,7 +634,7 @@ _polygon(DiaRenderer *self,
   cairo_line_to (renderer->cr, points[0].x, points[0].y);
   cairo_close_path (renderer->cr);
   if (fill)
-    _dia_cairo_fill (renderer);
+    _dia_cairo_fill (renderer, FALSE);
   else
     cairo_stroke (renderer->cr);
   DIAG_STATE(renderer->cr)
@@ -663,7 +670,7 @@ _rect(DiaRenderer *self,
                    lr_corner->x - ul_corner->x, lr_corner->y - ul_corner->y);
 
   if (fill)
-    _dia_cairo_fill (renderer);
+    _dia_cairo_fill (renderer, FALSE);
   else
     cairo_stroke (renderer->cr);
   DIAG_STATE(renderer->cr)
@@ -701,21 +708,25 @@ draw_arc(DiaRenderer *self,
 
   if (!renderer->stroke_pending)
     cairo_new_path (renderer->cr);
-  /* Dia and Cairo don't agree on arc definitions, so it needs
-   * to be converted, i.e. mirrored at the x axis
-   */
   start.x = center->x + (width / 2.0)  * cos((M_PI / 180.0) * angle1);
   start.y = center->y - (height / 2.0) * sin((M_PI / 180.0) * angle1);
-  cairo_move_to (renderer->cr, start.x, start.y);
+  if (!renderer->stroke_pending) /* when activated the first current point must be set */
+    cairo_move_to (renderer->cr, start.x, start.y);
   a1 = - (angle1 / 180.0) * G_PI;
   a2 = - (angle2 / 180.0) * G_PI;
   /* FIXME: to handle width != height some cairo_scale/cairo_translate would be needed */
   ensure_minimum_one_device_unit (renderer, &onedu);
   /* FIXME2: with too small arcs cairo goes into an endless loop */
-  if (height/2.0 > onedu && width/2.0 > onedu)
-    cairo_arc_negative (renderer->cr, center->x, center->y, 
-                        width > height ? height / 2.0 : width / 2.0, /* FIXME 2nd radius */
-                        a1, a2);
+  if (height/2.0 > onedu && width/2.0 > onedu) {
+    if (angle2 > angle1)
+      cairo_arc_negative (renderer->cr, center->x, center->y, 
+                         width > height ? height / 2.0 : width / 2.0, /* FIXME 2nd radius */
+                         a1, a2);
+    else
+      cairo_arc (renderer->cr, center->x, center->y, 
+                width > height ? height / 2.0 : width / 2.0, /* FIXME 2nd radius */
+                a1, a2);
+  }
   if (!renderer->stroke_pending)
     cairo_stroke (renderer->cr);
   DIAG_STATE(renderer->cr)
@@ -745,12 +756,17 @@ fill_arc(DiaRenderer *self,
   a1 = - (angle1 / 180.0) * G_PI;
   a2 = - (angle2 / 180.0) * G_PI;
   /* FIXME: to handle width != height some cairo_scale/cairo_translate would be needed */
-  cairo_arc_negative (renderer->cr, center->x, center->y, 
-                      width > height ? height / 2.0 : width / 2.0, /* FIXME 2nd radius */
-                      a1, a2);
+  if (angle2 > angle1)
+    cairo_arc_negative (renderer->cr, center->x, center->y, 
+                       width > height ? height / 2.0 : width / 2.0, /* XXX 2nd radius */
+                       a1, a2);
+  else
+    cairo_arc (renderer->cr, center->x, center->y, 
+              width > height ? height / 2.0 : width / 2.0, /* XXX 2nd radius */
+              a1, a2);
   cairo_line_to (renderer->cr, center->x, center->y);
   cairo_close_path (renderer->cr);
-  _dia_cairo_fill (renderer);
+  _dia_cairo_fill (renderer, FALSE);
   DIAG_STATE(renderer->cr)
 }
 
@@ -785,7 +801,7 @@ _ellipse(DiaRenderer *self,
   cairo_restore (renderer->cr);
 
   if (fill)
-    _dia_cairo_fill (renderer);
+    _dia_cairo_fill (renderer, FALSE);
   else
     cairo_stroke (renderer->cr);
   DIAG_STATE(renderer->cr)
@@ -844,7 +860,7 @@ _bezier(DiaRenderer *self,
   if (closed)
     cairo_close_path(renderer->cr);
   if (fill)
-    _dia_cairo_fill (renderer);
+    _dia_cairo_fill (renderer, FALSE);
   else
     cairo_stroke (renderer->cr);
   DIAG_STATE(renderer->cr)
@@ -1058,6 +1074,45 @@ draw_image(DiaRenderer *self,
 
 static gpointer parent_class = NULL;
 
+/*!
+ * \brief Fill and/or stroke a rectangle with rounded corner
+ * Implemented to avoid seams between arcs and lines caused by the base class
+ * working in real which than gets rounded independently to int here
+ * \memberof _DiaCairoRenderer
+ */
+static void
+draw_rounded_rect (DiaRenderer *self, 
+                  Point *ul_corner, Point *lr_corner,
+                  Color *fill, Color *stroke,
+                  real radius)
+{
+  DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (self);
+  real r2 = (lr_corner->x - ul_corner->x) / 2.0;
+  radius = MIN(r2, radius);
+  r2 = (lr_corner->y - ul_corner->y) / 2.0;
+  radius = MIN(r2, radius);
+  if (radius < 0.0001) {
+    draw_rect (self, ul_corner, lr_corner, fill, stroke);
+    return;
+  }
+  g_return_if_fail (stroke != NULL || fill != NULL);
+  /* use base class implementation to create a path */
+  cairo_new_path (renderer->cr);
+  cairo_move_to (renderer->cr, ul_corner->x + radius, ul_corner->y);
+  renderer->stroke_pending = TRUE;
+  DIA_RENDERER_CLASS(parent_class)->draw_rounded_rect(self, 
+                                                     ul_corner, lr_corner,
+                                                     NULL, fill, radius);
+  renderer->stroke_pending = FALSE;
+  cairo_close_path (renderer->cr);
+  if (fill) /* if a stroke follows preserve the path */
+    _dia_cairo_fill (renderer, stroke ? TRUE : FALSE);
+  if (stroke) {
+    cairo_set_source_rgba (renderer->cr, stroke->red, stroke->green, stroke->blue, stroke->alpha);
+    cairo_stroke (renderer->cr);
+  }
+}
+
 static void
 draw_rounded_polyline (DiaRenderer *self,
                        Point *points, int num_points,
@@ -1069,6 +1124,8 @@ draw_rounded_polyline (DiaRenderer *self,
   cairo_move_to (renderer->cr, points[0].x, points[0].y);
   /* use base class implementation */
   renderer->stroke_pending = TRUE;
+  /* set the starting point to avoid move-to in between */
+  cairo_move_to (renderer->cr, points[0].x, points[0].y);
   DIA_RENDERER_CLASS(parent_class)->draw_rounded_polyline (self, 
                                                            points, num_points,
                                                           color, radius);
@@ -1180,6 +1237,7 @@ cairo_renderer_class_init (DiaCairoRendererClass *klass)
   renderer_class->draw_beziergon = draw_beziergon;
 
   /* highest level functions */
+  renderer_class->draw_rounded_rect = draw_rounded_rect;
   renderer_class->draw_rounded_polyline = draw_rounded_polyline;
   /* other */
   renderer_class->is_capable_to = is_capable_to;
diff --git a/plug-ins/cgm/cgm.c b/plug-ins/cgm/cgm.c
index 84f43a4..aafcfe0 100644
--- a/plug-ins/cgm/cgm.c
+++ b/plug-ins/cgm/cgm.c
@@ -819,6 +819,12 @@ write_ellarc (CgmRenderer   *renderer,
     int  len;
     real ynew;
 
+    /* Although not explicitly stated CGM seems to want counter-clockwise */
+    if (angle2 < angle1) {
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     /*
     ** Angle's are in degrees, need to be converted to 2PI.
     */
diff --git a/plug-ins/dxf/dxf-export.c b/plug-ins/dxf/dxf-export.c
index 4643234..b5bce1d 100644
--- a/plug-ins/dxf/dxf-export.c
+++ b/plug-ins/dxf/dxf-export.c
@@ -438,21 +438,27 @@ draw_arc(DiaRenderer *self,
 {
     DxfRenderer *renderer = DXF_RENDERER(self);
     gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
-
+    /* DXF arcs are preferably counter-clockwise, so we might need to swap angles
+     * According to my reading of the specs header section group code 70 might allow
+     * clockwise arcs with $ANGDIR = 1 but it's not supported on the single arc level
+     */
+    if (angle2 < angle1) {
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     if(width != 0.0){
-        fprintf(renderer->file, "  0\nARC\n");
-        fprintf(renderer->file, "  8\n%s\n", renderer->layername);
-        fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
-        fprintf(renderer->file, " 10\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", center->x));
-        fprintf(renderer->file, " 20\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (-1)*center->y));
-        fprintf(renderer->file, " 40\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", width/2)); /* radius */
-        fprintf(renderer->file, " 39\n%d\n", (int)(MAGIC_THICKNESS_FACTOR*renderer->lcurrent.width)); /* 
Thickness */
-       /* From specification: "output in degrees to DXF files". But radians work for all
-        * importers I tested. Also there seems to be a problem with arcs to be drawn counter-clockwise
-        */
+       fprintf(renderer->file, "  0\nARC\n");
+       fprintf(renderer->file, "  8\n%s\n", renderer->layername);
+       fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
+       fprintf(renderer->file, " 10\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", center->x));
+       fprintf(renderer->file, " 20\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (-1)*center->y));
+       fprintf(renderer->file, " 40\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", width/2)); /* radius */
+       fprintf(renderer->file, " 39\n%d\n", (int)(MAGIC_THICKNESS_FACTOR*renderer->lcurrent.width)); /* 
Thickness */
+       /* From specification: "output in degrees to DXF files". */
        fprintf(renderer->file, " 100\nAcDbArc\n");
-        fprintf(renderer->file, " 50\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (angle1 ))); /* start 
angle */
-        fprintf(renderer->file, " 51\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (angle2 ))); /* end 
angle */             
+       fprintf(renderer->file, " 50\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (angle1 ))); /* start 
angle */
+       fprintf(renderer->file, " 51\n%s\n", g_ascii_formatd (buf, sizeof(buf), "%g", (angle2 ))); /* end 
angle */
     }
     fprintf(renderer->file, " 62\n%d\n", dxf_color (colour));
 }
diff --git a/plug-ins/hpgl/hpgl.c b/plug-ins/hpgl/hpgl.c
index 15322a3..ba2dcab 100644
--- a/plug-ins/hpgl/hpgl.c
+++ b/plug-ins/hpgl/hpgl.c
@@ -396,6 +396,12 @@ draw_arc(DiaRenderer *object,
               width, height, angle1, angle2));
     hpgl_select_pen(renderer, colour, 0.0);
 
+    /* make counter-clockwise swapping start/end */
+    if (angle2 < angle1) {
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     /* move to start point */
     start.x = center->x + (width / 2.0)  * cos((M_PI / 180.0) * angle1);  
     start.y = - center->y + (height / 2.0) * sin((M_PI / 180.0) * angle1);
diff --git a/plug-ins/libart/dialibartrenderer.c b/plug-ins/libart/dialibartrenderer.c
index 7b57142..788dc4c 100644
--- a/plug-ins/libart/dialibartrenderer.c
+++ b/plug-ins/libart/dialibartrenderer.c
@@ -579,10 +579,14 @@ draw_arc(DiaRenderer *self,
 
   if ((width<0.0) || (height<0.0))
     return;
-  
+
+  if (angle2 < angle1) {
+    /* swap to counter-clockwise to keep the original algorithm */
+    real tmp = angle1;
+    angle1 = angle2;
+    angle2 = tmp;
+  }
   dangle = angle2-angle1;
-  if (dangle<0)
-    dangle += 360.0;
 
   /* Over-approximate the circumference */
   if (width>height)
@@ -666,9 +670,13 @@ fill_arc(DiaRenderer *self,
   if ((width<0.0) || (height<0.0))
     return;
 
+  if (angle2 < angle1) {
+    /* swap to counter-clockwise to keep the original algorithm */
+    real tmp = angle1;
+    angle1 = angle2;
+    angle2 = tmp;
+  }
   dangle = angle2-angle1;
-  if (dangle<0)
-    dangle += 360.0;
 
   /* Over-approximate the circumference */
   if (width>height)
diff --git a/plug-ins/metapost/render_metapost.c b/plug-ins/metapost/render_metapost.c
index d7d913d..cfefe1d 100644
--- a/plug-ins/metapost/render_metapost.c
+++ b/plug-ins/metapost/render_metapost.c
@@ -546,8 +546,7 @@ metapost_arc(MetapostRenderer *renderer,
     fprintf(renderer->file, "%% %s = %s", "height", mp_dtostr(d1_buf, height));
     fprintf(renderer->file, "%% %s = %s", "angle1", mp_dtostr(d1_buf, angle1));
     fprintf(renderer->file, "%% %s = %s", "angle2", mp_dtostr(d1_buf, angle2));
-    
-    
+
     angle1 = angle1*M_PI/180;
     angle2 = angle2*M_PI/180;
     angle3 = (double) (angle1+angle2)/2;
diff --git a/plug-ins/pgf/render_pgf.c b/plug-ins/pgf/render_pgf.c
index 99c764e..0f13231 100644
--- a/plug-ins/pgf/render_pgf.c
+++ b/plug-ins/pgf/render_pgf.c
@@ -671,6 +671,12 @@ pgf_arc(PgfRenderer *renderer,
     radius1=(double) width/2.0;
     radius2=(double) height/2.0;
 
+    /* counter-clockwise */
+    if (angle2 < angle1) {
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     pgf_dtostr(stx_buf,center->x+ radius1*cos(angle1*.017453));
     pgf_dtostr(sty_buf,center->y- radius2*sin(angle1*.017453));
     pgf_dtostr(cx_buf,center->x);
diff --git a/plug-ins/postscript/diapsrenderer.c b/plug-ins/postscript/diapsrenderer.c
index b09864d..1a592c6 100644
--- a/plug-ins/postscript/diapsrenderer.c
+++ b/plug-ins/postscript/diapsrenderer.c
@@ -401,6 +401,12 @@ psrenderer_arc(DiaPsRenderer *renderer,
 
   lazy_setcolor(renderer, color);
 
+  if (angle2 < angle1) {
+    /* swap for counter-clockwise */
+    real tmp = angle1;
+    angle1 = angle2;
+    angle2 = tmp;
+  }
   psrenderer_dtostr(cx_buf, (gdouble) center->x);
   psrenderer_dtostr(cy_buf, (gdouble) center->y);
   psrenderer_dtostr(a1_buf, (gdouble) 360.0 - angle1);
diff --git a/plug-ins/pstricks/render_pstricks.c b/plug-ins/pstricks/render_pstricks.c
index 286237d..73222a3 100644
--- a/plug-ins/pstricks/render_pstricks.c
+++ b/plug-ins/pstricks/render_pstricks.c
@@ -505,6 +505,12 @@ pstricks_arc(PstricksRenderer *renderer,
     pstricks_dtostr(r1_buf,radius1);
     pstricks_dtostr(r2_buf,radius2);
     pstricks_dtostr(sqrt_buf,sqrt(radius1*radius1+radius2*radius2));
+    /* counter-clockwise */
+    if (angle2 < angle1) {
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     pstricks_dtostr(angle1_buf,360.0-angle1);
     pstricks_dtostr(angle2_buf,360.0-angle2);
 
diff --git a/plug-ins/python/diadissect.py b/plug-ins/python/diadissect.py
index 59fd5b4..27ba9de 100644
--- a/plug-ins/python/diadissect.py
+++ b/plug-ins/python/diadissect.py
@@ -115,7 +115,14 @@ class DissectRenderer :
                        self.Warning ("%s width too small" % (fun,))
                if height <= 0 :
                        self.Warning ("%s height too small" % (fun,))
-               # XXX: angles?
+               # angles
+               rot = 0.0
+               if angle1 < angle2 :
+                       rot = angle2 - angle1
+               else :
+                       rot = angle1 - angle2
+               if rot <= 0 or rot >= 360 :
+                       self.Warning ("%s bad rotation %g,%g" % (fun, angle1, angle2))
        def draw_arc (self, center, width, height, angle1, angle2, color) :
                self._arc(center, width, height, angle1, angle2, "draw_arc")
        def fill_arc (self, center, width, height, angle1, angle2, color) :
diff --git a/plug-ins/python/diastddia.py b/plug-ins/python/diastddia.py
index ac526f4..130940c 100644
--- a/plug-ins/python/diastddia.py
+++ b/plug-ins/python/diastddia.py
@@ -200,7 +200,8 @@ class StandardDiaRenderer :
                dx = (sx + ex) / 2.0 - cx
                dy = (sy + ey) / 2.0 - cy
                dist = math.sqrt(dx * dx + dy * dy)
-               # FIXME: need direction, too
+               if angle1 > angle2 :
+                       dist = -dist
                self.f.write('''
     <dia:object type="Standard - Arc" version="0" id="O%d">
       <dia:attribute name="conn_endpoints">
diff --git a/plug-ins/python/diasvg.py b/plug-ins/python/diasvg.py
index a3fca9f..2384d6b 100644
--- a/plug-ins/python/diasvg.py
+++ b/plug-ins/python/diasvg.py
@@ -133,8 +133,10 @@ class SvgRenderer :
                sy = center.y - ry * math.sin(mPi180 * angle1)
                ex = center.x + rx * math.cos(mPi180 * angle2)
                ey = center.y - ry * math.sin(mPi180 * angle2)
-               largearc = (angle2 - angle1 >= 180)
-               sweep = 0 # always draw in negative direction
+               largearc = abs(angle2 - angle1) >= 180
+               sweep = 0 # 0: draw in negative direction
+               if angle1 > angle2 :
+                       sweep = 1
                if not fill :
                        self.f.write('<path stroke="%s" fill="none" stroke-width="%.3f" %s' \
                                % (self._rgb(color), self.line_width, self._stroke_style()))
diff --git a/plug-ins/vdx/vdx-export.c b/plug-ins/vdx/vdx-export.c
index b98c365..937bf65 100644
--- a/plug-ins/vdx/vdx-export.c
+++ b/plug-ins/vdx/vdx-export.c
@@ -937,11 +937,7 @@ static void draw_arc(DiaRenderer *self,
     /* Find a control point at the midpoint of the arc */
     control = *center;
     control_angle = (angle1 + angle2)/2.0;
-    if (angle1 > angle2)
-    {
-        /* Arc goes antclockwise - allow for this */
-        control_angle -= 180;
-    }
+    /* no matter which direction the arc is control_angle is always between start and end */
     control.x += (width/2.0)*cos(control_angle*DEG_TO_RAD);
     control.y -= (height/2.0)*sin(control_angle*DEG_TO_RAD);
     g_debug("control(%f,%f @ %f)", control.x, control.y, control_angle);
diff --git a/plug-ins/wmf/wmf.cpp b/plug-ins/wmf/wmf.cpp
index e1310e5..26eaca8 100644
--- a/plug-ins/wmf/wmf.cpp
+++ b/plug-ins/wmf/wmf.cpp
@@ -754,6 +754,12 @@ draw_arc(DiaRenderer *self,
 
     hPen = UsePen(renderer, colour);
 
+    if (angle1 > angle2) {
+       /* make it counter-clockwise by swapping start/end */
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     /* calculate start and end points of arc */
     ptStart.x = SCX(center->x + (width / 2.0)  * cos((M_PI / 180.0) * angle1));
     ptStart.y = SCY(center->y - (height / 2.0) * sin((M_PI / 180.0) * angle1));
@@ -787,6 +793,12 @@ fill_arc(DiaRenderer *self,
     DIAG_NOTE(renderer, "fill_arc %fx%f <%f,<%f @%f,%f\n", 
               width, height, angle1, angle2, center->x, center->y);
 
+    if (angle1 > angle2) {
+       /* make it counter-clockwise by swapping start/end */
+       real tmp = angle1;
+       angle1 = angle2;
+       angle2 = tmp;
+    }
     /* calculate start and end points of arc */
     ptStart.x = SCX(center->x + (width / 2.0)  * cos((M_PI / 180.0) * angle1));
     ptStart.y = SCY(center->y - (height / 2.0) * sin((M_PI / 180.0) * angle1));
diff --git a/plug-ins/wpg/wpg-import.c b/plug-ins/wpg/wpg-import.c
index f3c48bb..51e4693 100644
--- a/plug-ins/wpg/wpg-import.c
+++ b/plug-ins/wpg/wpg-import.c
@@ -116,17 +116,21 @@ _do_ellipse (WpgImportRenderer *ren, WPGEllipse* pEll)
   center.y = (h - pEll->y) / WPU_PER_DCM;
   
   if (fabs(pEll->EndAngle - pEll->StartAngle) < 360) {
+    /* WPG arcs are counter-clockwise so ensure that end is bigger than start */
+    real arcEnd = pEll->EndAngle;
+    if (arcEnd < pEll->StartAngle)
+      arcEnd += 360;
     if (ren->LineAttr.Type != WPG_LA_NONE)
       DIA_RENDERER_GET_CLASS(ren)->draw_arc (DIA_RENDERER(ren), &center,
                                             2 * pEll->rx / WPU_PER_DCM,
                                             2 * pEll->ry / WPU_PER_DCM,
-                                            pEll->StartAngle, pEll->EndAngle,
+                                            pEll->StartAngle, arcEnd,
                                             &ren->stroke);
     if (ren->FillAttr.Type != WPG_FA_HOLLOW)
       DIA_RENDERER_GET_CLASS(ren)->fill_arc (DIA_RENDERER(ren), &center,
                                             2 * pEll->rx / WPU_PER_DCM,
                                             2 * pEll->ry / WPU_PER_DCM,
-                                            pEll->StartAngle, pEll->EndAngle,
+                                            pEll->StartAngle, arcEnd,
                                             &ren->fill);
   } else {
     DIA_RENDERER_GET_CLASS(ren)->draw_ellipse (DIA_RENDERER(ren), &center,
diff --git a/plug-ins/wpg/wpg.c b/plug-ins/wpg/wpg.c
index 333865a..05240b5 100644
--- a/plug-ins/wpg/wpg.c
+++ b/plug-ins/wpg/wpg.c
@@ -606,6 +606,7 @@ draw_arc(DiaRenderer *self,
 {
   WpgRenderer *renderer = WPG_RENDERER (self);
   WPGEllipse ell;
+  gboolean counter_clockwise = angle2 > angle1;
 
   DIAG_NOTE(g_message("draw_arc %fx%f <%f,<%f", 
             width, height, angle1, angle2));
@@ -616,8 +617,17 @@ draw_arc(DiaRenderer *self,
   ell.rx = SC(width / 2.0);
   ell.ry = SC(height / 2.0);
 
-  ell.StartAngle = angle1;
-  ell.EndAngle   = angle2;
+  /* ensure range of 0..360 */
+  while (angle1 < 0.0) angle1 += 360.0;
+  while (angle2 < 0.0) angle2 += 360.0;
+  /* make it counter-clockwise */
+  if (counter_clockwise) {
+    ell.StartAngle = angle1;
+    ell.EndAngle   = angle2;
+  } else {
+    ell.StartAngle = angle2;
+    ell.EndAngle   = angle1;
+  }
   ell.Flags = 0;
 
   WriteLineAttr(renderer, colour);
@@ -636,6 +646,7 @@ fill_arc(DiaRenderer *self,
 {
   WpgRenderer *renderer = WPG_RENDERER (self);
   WPGEllipse ell;
+  gboolean counter_clockwise = angle2 > angle1;
 
   DIAG_NOTE(g_message("fill_arc %fx%f <%f,<%f", 
             width, height, angle1, angle2));
@@ -646,8 +657,17 @@ fill_arc(DiaRenderer *self,
   ell.rx = SC(width / 2.0);
   ell.ry = SC(height / 2.0);
 
-  ell.StartAngle = angle1;
-  ell.EndAngle   = angle2;
+  /* ensure range of 0..360 */
+  while (angle1 < 0.0) angle1 += 360.0;
+  while (angle2 < 0.0) angle2 += 360.0;
+  /* make it counter-clockwise */
+  if (counter_clockwise) {
+    ell.StartAngle = angle1;
+    ell.EndAngle   = angle2;
+  } else {
+    ell.StartAngle = angle2;
+    ell.EndAngle   = angle1;
+  }
   ell.Flags = 0; /* 0: connect to center; 1: connect start and end */
 
   WriteFillAttr(renderer, colour, TRUE);
diff --git a/plug-ins/xfig/xfig-export.c b/plug-ins/xfig/xfig-export.c
index 8c7cf33..b4925a0 100644
--- a/plug-ins/xfig/xfig-export.c
+++ b/plug-ins/xfig/xfig-export.c
@@ -838,7 +838,7 @@ draw_arc(DiaRenderer *self,
          Color *color) 
 {
   Point first, second, last;
-  int direction = 1; /* Dia always gives counterclockwise */
+  int direction = angle2 > angle1 ? 1 : 0; /* Dia not always gives counterclockwise */
   XfigRenderer *renderer = XFIG_RENDERER(self);
   gchar dl_buf[DTOSTR_BUF_SIZE];
   gchar cx_buf[DTOSTR_BUF_SIZE];



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