Code

OCAL. Fix for Bug #638844 (Errors printed to console if openclipart search fails).
[inkscape.git] / src / sp-ellipse.cpp
index f8fb5ca78b7acfcc2b8f4c54e769995223ed2183..ef58e4d6e316b6866ff46efaa3a9dc139270c5fb 100644 (file)
@@ -1,5 +1,3 @@
-#define __SP_ELLIPSE_C__
-
 /*
  * SVG <ellipse> and related implementations
  *
@@ -7,6 +5,7 @@
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   Mitsuru Oka
  *   bulia byak <buliabyak@users.sf.net>
+ *   Abhishek Sharma
  *
  * Copyright (C) 1999-2002 Lauris Kaplinski
  * Copyright (C) 2000-2001 Ximian, Inc.
 #endif
 
 
-#include "libnr/n-art-bpath.h"
-#include "libnr/nr-path.h"
 #include "libnr/nr-matrix-fns.h"
 #include "svg/svg.h"
-#include "svg/stringstream.h"
+#include "svg/path-string.h"
 #include "xml/repr.h"
 #include "attributes.h"
 #include "style.h"
 #include "display/curve.h"
 #include <glibmm/i18n.h>
-
+#include <2geom/transforms.h>
+#include <2geom/pathvector.h>
+#include "document.h"
 #include "sp-ellipse.h"
-
-#include "prefs-utils.h"
+#include "preferences.h"
+#include "snap-candidate.h"
 
 /* Common parent class */
 
@@ -72,13 +71,15 @@ static void sp_genericellipse_init(SPGenericEllipse *ellipse);
 
 static void sp_genericellipse_update(SPObject *object, SPCtx *ctx, guint flags);
 
-static void sp_genericellipse_snappoints(SPItem const *item, SnapPointsIter p);
+static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
 
 static void sp_genericellipse_set_shape(SPShape *shape);
-static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Node *repr,
+static void sp_genericellipse_update_patheffect (SPLPEItem *lpeitem, bool write);
+
+static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
                                                     guint flags);
 
-static bool sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr);
+static gboolean sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr);
 
 static SPShapeClass *ge_parent_class;
 
@@ -108,6 +109,7 @@ static void sp_genericellipse_class_init(SPGenericEllipseClass *klass)
 {
     SPObjectClass *sp_object_class = (SPObjectClass *) klass;
     SPItemClass *item_class = (SPItemClass *) klass;
+    SPLPEItemClass *lpe_item_class = (SPLPEItemClass *) klass;
     SPShapeClass *shape_class = (SPShapeClass *) klass;
 
     ge_parent_class = (SPShapeClass*) g_type_class_ref(SP_TYPE_SHAPE);
@@ -118,6 +120,7 @@ static void sp_genericellipse_class_init(SPGenericEllipseClass *klass)
     item_class->snappoints = sp_genericellipse_snappoints;
 
     shape_class->set_shape = sp_genericellipse_set_shape;
+    lpe_item_class->update_patheffect = sp_genericellipse_update_patheffect;
 }
 
 static void
@@ -139,31 +142,66 @@ sp_genericellipse_update(SPObject *object, SPCtx *ctx, guint flags)
     if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
         SPGenericEllipse *ellipse = (SPGenericEllipse *) object;
         SPStyle const *style = object->style;
-        double const d = 1.0 / NR::expansion(((SPItemCtx const *) ctx)->i2vp);
-        double const em = style->font_size.computed;
-        double const ex = em * 0.5; // fixme: get from pango or libnrtype
-        ellipse->cx.update(em, ex, d);
-        ellipse->cy.update(em, ex, d);
-        ellipse->rx.update(em, ex, d);
-        ellipse->ry.update(em, ex, d);
-        sp_shape_set_shape((SPShape *) object);
+        Geom::OptRect viewbox = ((SPItemCtx const *) ctx)->vp;
+        if (viewbox) {
+            double const dx = viewbox->width();
+            double const dy = viewbox->height();
+            double const dr = sqrt(dx*dx + dy*dy)/sqrt(2);
+            double const em = style->font_size.computed;
+            double const ex = em * 0.5; // fixme: get from pango or libnrtype
+            ellipse->cx.update(em, ex, dx);
+            ellipse->cy.update(em, ex, dy);
+            ellipse->rx.update(em, ex, dr);
+            ellipse->ry.update(em, ex, dr);
+            static_cast<SPShape *>(object)->setShape();
+        }
     }
 
     if (((SPObjectClass *) ge_parent_class)->update)
         ((SPObjectClass *) ge_parent_class)->update(object, ctx, flags);
 }
 
-#define C1 0.552
+static void
+sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write)
+{
+    SPShape *shape = (SPShape *) lpeitem;
+    sp_genericellipse_set_shape(shape);
 
-/* fixme: Think (Lauris) */
+    if (write) {
+        Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape);
+        if ( shape->curve != NULL ) {
+            gchar *str = sp_svg_write_path(shape->curve->get_pathvector());
+            repr->setAttribute("d", str);
+            g_free(str);
+        } else {
+            repr->setAttribute("d", NULL);
+        }
+    }
+
+    ((SPObject *)shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
 
+/* fixme: Think (Lauris) */
+/* Can't we use arcto in this method? */
 static void sp_genericellipse_set_shape(SPShape *shape)
 {
-    double cx, cy, rx, ry, s, e;
+    if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) {
+        g_warning ("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE");
+        if (SP_OBJECT_REPR(shape)->attribute("d")) {
+            // unconditionally read the curve from d, if any, to preserve appearance
+            Geom::PathVector pv = sp_svg_read_pathv(SP_OBJECT_REPR(shape)->attribute("d"));
+            SPCurve *cold = new SPCurve(pv);
+            shape->setCurveInsync( cold, TRUE);
+            cold->unref();
+        }
+        return;
+    }
+
+    double rx, ry, s, e;
     double x0, y0, x1, y1, x2, y2, x3, y3;
     double len;
     gint slice = FALSE;
-    gint i;
//   gint i;
 
     SPGenericEllipse *ellipse = (SPGenericEllipse *) shape;
 
@@ -172,8 +210,6 @@ static void sp_genericellipse_set_shape(SPShape *shape)
 
     sp_genericellipse_normalize(ellipse);
 
-    cx = 0.0;
-    cy = 0.0;
     rx = ellipse->rx.computed;
     ry = ellipse->ry.computed;
 
@@ -187,26 +223,14 @@ static void sp_genericellipse_set_shape(SPShape *shape)
         slice = TRUE;
     }
 
-    NR::Matrix aff = NR::Matrix(NR::scale(rx, ry));
-    aff[4] = ellipse->cx.computed;
-    aff[5] = ellipse->cy.computed;
-
-    NArtBpath bpath[16];
-    i = 0;
-    if (ellipse->closed) {
-        bpath[i].code = NR_MOVETO;
-    } else {
-        bpath[i].code = NR_MOVETO_OPEN;
-    }
-    bpath[i].x3 = cos(ellipse->start);
-    bpath[i].y3 = sin(ellipse->start);
-    i++;
+    SPCurve * curve = new SPCurve();
+    curve->moveto(cos(ellipse->start), sin(ellipse->start));
 
     for (s = ellipse->start; s < ellipse->end; s += M_PI_2) {
         e = s + M_PI_2;
         if (e > ellipse->end)
             e = ellipse->end;
-        len = C1 * (e - s) / M_PI_2;
+        len = 4*tan((e - s)/4)/3;
         x0 = cos(s);
         y0 = sin(s);
         x1 = x0 + len * cos(s + M_PI_2);
@@ -219,48 +243,96 @@ static void sp_genericellipse_set_shape(SPShape *shape)
         g_print("step %d s %f e %f coords %f %f %f %f %f %f\n",
                 i, s, e, x1, y1, x2, y2, x3, y3);
 #endif
-        bpath[i].code = NR_CURVETO;
-        bpath[i].x1 = x1;
-        bpath[i].y1 = y1;
-        bpath[i].x2 = x2;
-        bpath[i].y2 = y2;
-        bpath[i].x3 = x3;
-        bpath[i].y3 = y3;
-        i++;
+        curve->curveto(x1,y1, x2,y2, x3,y3);
     }
 
-    if (slice && ellipse->closed) {
-        bpath[i].code = NR_LINETO;
-        bpath[i].x3 = 0.0;
-        bpath[i].y3 = 0.0;
-        i++;
-        bpath[i].code = NR_LINETO;
-        bpath[i].x3 = bpath[0].x3;
-        bpath[i].y3 = bpath[0].y3;
-        i++;
-    } else if (ellipse->closed) {
-        bpath[i-1].x3 = bpath[0].x3;
-        bpath[i-1].y3 = bpath[0].y3;
+    if (slice && ellipse->closed) {  // TODO: is this check for "ellipse->closed" necessary?
+        curve->lineto(0., 0.);
+    }
+    if (ellipse->closed) {
+        curve->closepath();
     }
 
-    bpath[i].code = NR_END;
-    SPCurve *c = sp_curve_new_from_bpath(nr_artpath_affine(bpath, aff));
-    g_assert(c != NULL);
-
-    sp_shape_set_curve_insync((SPShape *) ellipse, c, TRUE);
-    sp_curve_unref(c);
+    Geom::Matrix aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed);
+    curve->transform(aff);
+
+    /* Reset the shape'scurve to the "original_curve"
+     * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
+    shape->setCurveInsync( curve, TRUE);
+    if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) {
+        SPCurve *c_lpe = curve->copy();
+        bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe);
+        if (success) {
+            shape->setCurveInsync( c_lpe, TRUE);
+        }
+        c_lpe->unref();
+    }
+    curve->unref();
 }
 
-static void sp_genericellipse_snappoints(SPItem const *item, SnapPointsIter p)
+static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
 {
-    SPGenericEllipse const *ge = SP_GENERICELLIPSE(item);
+    g_assert(item != NULL);
+    g_assert(SP_IS_GENERICELLIPSE(item));
 
-    NR::Matrix const i2d = sp_item_i2d_affine(item);
+    // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
+    if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
+        return;
+    }
+
+    SPGenericEllipse *ellipse = SP_GENERICELLIPSE(item);
+    sp_genericellipse_normalize(ellipse);
+    Geom::Matrix const i2d = item->i2d_affine();
+
+    // figure out if we have a slice, while guarding against rounding errors
+    bool slice = false;
+    double len = fmod(ellipse->end - ellipse->start, SP_2PI);
+    if (len < 0.0) len += SP_2PI;
+    if (fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8) {
+        slice = false;
+        ellipse->end = ellipse->start + SP_2PI;
+    } else {
+        slice = true;
+    }
+
+    double rx = ellipse->rx.computed;
+    double ry = ellipse->ry.computed;
+    double cx = ellipse->cx.computed;
+    double cy = ellipse->cy.computed;
+
+    Geom::Point pt;
+
+    // Snap to the 4 quadrant points of the ellipse, but only if the arc
+    // spans far enough to include them
+    if (snapprefs->getSnapToItemNode()) { //TODO: Make a separate snap option toggle for this?
+        double angle = 0;
+        for (angle = 0; angle < SP_2PI; angle += M_PI_2) {
+            if (angle >= ellipse->start && angle <= ellipse->end) {
+                pt = Geom::Point(cx + cos(angle)*rx, cy + sin(angle)*ry) * i2d;
+                p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_ELLIPSE_QUADRANT_POINT, Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT));
+            }
+        }
+    }
 
-    /* Add the centre */
-    *p = NR::Point(ge->cx.computed, ge->cy.computed) * i2d;
+    // Add the centre, if we have a closed slice or when explicitly asked for
+    if ((snapprefs->getSnapToItemNode() && slice && ellipse->closed) || snapprefs->getSnapObjectMidpoints()) {
+        pt = Geom::Point(cx, cy) * i2d;
+        p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_CENTER, Inkscape::SNAPTARGET_CENTER));
+    }
 
-    // TODO: add the ends of radii
+    // And if we have a slice, also snap to the endpoints
+    if (snapprefs->getSnapToItemNode() && slice) {
+        // Add the start point, if it's not coincident with a quadrant point
+        if (fmod(ellipse->start, M_PI_2) != 0.0 ) {
+            pt = Geom::Point(cx + cos(ellipse->start)*rx, cy + sin(ellipse->start)*ry) * i2d;
+            p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+        }
+        // Add the end point, if it's not coincident with a quadrant point
+        if (fmod(ellipse->end, M_PI_2) != 0.0 ) {
+            pt = Geom::Point(cx + cos(ellipse->end)*rx, cy + sin(ellipse->end)*ry) * i2d;
+            p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+        }
+    }
 }
 
 void
@@ -278,13 +350,13 @@ sp_genericellipse_normalize(SPGenericEllipse *ellipse)
     /* Now we keep: 0 <= start < end <= 2*PI */
 }
 
-static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
     SPGenericEllipse *ellipse = SP_GENERICELLIPSE(object);
 
     if (flags & SP_OBJECT_WRITE_EXT) {
         if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-            repr = sp_repr_new("svg:path");
+            repr = xml_doc->createElement("svg:path");
         }
 
         sp_repr_set_svg_double(repr, "sodipodi:cx", ellipse->cx.computed);
@@ -297,7 +369,7 @@ static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::
     }
 
     if (((SPObjectClass *) ge_parent_class)->write)
-        ((SPObjectClass *) ge_parent_class)->write(object, repr, flags);
+        ((SPObjectClass *) ge_parent_class)->write(object, xml_doc, repr, flags);
 
     return repr;
 }
@@ -308,7 +380,7 @@ static void sp_ellipse_class_init(SPEllipseClass *klass);
 static void sp_ellipse_init(SPEllipse *ellipse);
 
 static void sp_ellipse_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
-static Inkscape::XML::Node *sp_ellipse_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static Inkscape::XML::Node *sp_ellipse_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 static void sp_ellipse_set(SPObject *object, unsigned int key, gchar const *value);
 static gchar *sp_ellipse_description(SPItem *item);
 
@@ -351,7 +423,7 @@ static void sp_ellipse_class_init(SPEllipseClass *klass)
 }
 
 static void
-sp_ellipse_init(SPEllipse *ellipse)
+sp_ellipse_init(SPEllipse */*ellipse*/)
 {
     /* Nothing special */
 }
@@ -362,21 +434,21 @@ sp_ellipse_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *re
     if (((SPObjectClass *) ellipse_parent_class)->build)
         (* ((SPObjectClass *) ellipse_parent_class)->build) (object, document, repr);
 
-    sp_object_read_attr(object, "cx");
-    sp_object_read_attr(object, "cy");
-    sp_object_read_attr(object, "rx");
-    sp_object_read_attr(object, "ry");
+    object->readAttr( "cx" );
+    object->readAttr( "cy" );
+    object->readAttr( "rx" );
+    object->readAttr( "ry" );
 }
 
 static Inkscape::XML::Node *
-sp_ellipse_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+sp_ellipse_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
     SPGenericEllipse *ellipse;
 
     ellipse = SP_GENERICELLIPSE(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:ellipse");
+        repr = xml_doc->createElement("svg:ellipse");
     }
 
     sp_repr_set_svg_double(repr, "cx", ellipse->cx.computed);
@@ -385,7 +457,7 @@ sp_ellipse_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     sp_repr_set_svg_double(repr, "ry", ellipse->ry.computed);
 
     if (((SPObjectClass *) ellipse_parent_class)->write)
-        (* ((SPObjectClass *) ellipse_parent_class)->write) (object, repr, flags);
+        (* ((SPObjectClass *) ellipse_parent_class)->write) (object, xml_doc, repr, flags);
 
     return repr;
 }
@@ -425,7 +497,7 @@ sp_ellipse_set(SPObject *object, unsigned int key, gchar const *value)
     }
 }
 
-static gchar *sp_ellipse_description(SPItem *item)
+static gchar *sp_ellipse_description(SPItem */*item*/)
 {
     return g_strdup(_("<b>Ellipse</b>"));
 }
@@ -455,7 +527,7 @@ static void sp_circle_class_init(SPCircleClass *klass);
 static void sp_circle_init(SPCircle *circle);
 
 static void sp_circle_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
-static Inkscape::XML::Node *sp_circle_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static Inkscape::XML::Node *sp_circle_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 static void sp_circle_set(SPObject *object, unsigned int key, gchar const *value);
 static gchar *sp_circle_description(SPItem *item);
 
@@ -499,7 +571,7 @@ sp_circle_class_init(SPCircleClass *klass)
 }
 
 static void
-sp_circle_init(SPCircle *circle)
+sp_circle_init(SPCircle */*circle*/)
 {
     /* Nothing special */
 }
@@ -510,20 +582,20 @@ sp_circle_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
     if (((SPObjectClass *) circle_parent_class)->build)
         (* ((SPObjectClass *) circle_parent_class)->build)(object, document, repr);
 
-    sp_object_read_attr(object, "cx");
-    sp_object_read_attr(object, "cy");
-    sp_object_read_attr(object, "r");
+    object->readAttr( "cx" );
+    object->readAttr( "cy" );
+    object->readAttr( "r" );
 }
 
 static Inkscape::XML::Node *
-sp_circle_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+sp_circle_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
     SPGenericEllipse *ellipse;
 
     ellipse = SP_GENERICELLIPSE(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:circle");
+        repr = xml_doc->createElement("svg:circle");
     }
 
     sp_repr_set_svg_double(repr, "cx", ellipse->cx.computed);
@@ -531,7 +603,7 @@ sp_circle_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     sp_repr_set_svg_double(repr, "r", ellipse->rx.computed);
 
     if (((SPObjectClass *) circle_parent_class)->write)
-        ((SPObjectClass *) circle_parent_class)->write(object, repr, flags);
+        ((SPObjectClass *) circle_parent_class)->write(object, xml_doc, repr, flags);
 
     return repr;
 }
@@ -566,7 +638,7 @@ sp_circle_set(SPObject *object, unsigned int key, gchar const *value)
     }
 }
 
-static gchar *sp_circle_description(SPItem *item)
+static gchar *sp_circle_description(SPItem */*item*/)
 {
     return g_strdup(_("<b>Circle</b>"));
 }
@@ -577,7 +649,7 @@ static void sp_arc_class_init(SPArcClass *klass);
 static void sp_arc_init(SPArc *arc);
 
 static void sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
-static Inkscape::XML::Node *sp_arc_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static Inkscape::XML::Node *sp_arc_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 static void sp_arc_set(SPObject *object, unsigned int key, gchar const *value);
 static void sp_arc_modified(SPObject *object, guint flags);
 
@@ -624,7 +696,7 @@ sp_arc_class_init(SPArcClass *klass)
 }
 
 static void
-sp_arc_init(SPArc *arc)
+sp_arc_init(SPArc */*arc*/)
 {
     /* Nothing special */
 }
@@ -635,16 +707,14 @@ sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
     if (((SPObjectClass *) arc_parent_class)->build)
         (* ((SPObjectClass *) arc_parent_class)->build) (object, document, repr);
 
-    Inkscape::Version version = sp_object_get_sodipodi_version(object);
+    object->readAttr( "sodipodi:cx" );
+    object->readAttr( "sodipodi:cy" );
+    object->readAttr( "sodipodi:rx" );
+    object->readAttr( "sodipodi:ry" );
 
-    sp_object_read_attr(object, "sodipodi:cx");
-    sp_object_read_attr(object, "sodipodi:cy");
-    sp_object_read_attr(object, "sodipodi:rx");
-    sp_object_read_attr(object, "sodipodi:ry");
-
-    sp_object_read_attr(object, "sodipodi:start");
-    sp_object_read_attr(object, "sodipodi:end");
-    sp_object_read_attr(object, "sodipodi:open");
+    object->readAttr( "sodipodi:start" );
+    object->readAttr( "sodipodi:end" );
+    object->readAttr( "sodipodi:open" );
 }
 
 /*
@@ -655,56 +725,48 @@ sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
  * See SVG 1.0 Specification W3C Recommendation
  * ``F.6 Ellptical arc implementation notes'' for more detail.
  */
-static bool
+static gboolean
 sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr)
 {
-    gint fa, fs;
-    gdouble  dt;
-    Inkscape::SVGOStringStream os;
-
     SPGenericEllipse *ge = SP_GENERICELLIPSE(arc);
 
-    NR::Point p1 = sp_arc_get_xy(arc, ge->start);
-    NR::Point p2 = sp_arc_get_xy(arc, ge->end);
+    Inkscape::SVG::PathString str;
+
+    Geom::Point p1 = sp_arc_get_xy(arc, ge->start);
+    Geom::Point p2 = sp_arc_get_xy(arc, ge->end);
+    double rx = ge->rx.computed;
+    double ry = ge->ry.computed;
 
-    dt = fmod(ge->end - ge->start, SP_2PI);
+    str.moveTo(p1);
+
+    double dt = fmod(ge->end - ge->start, SP_2PI);
     if (fabs(dt) < 1e-6) {
-        NR::Point ph = sp_arc_get_xy(arc, (ge->start + ge->end) / 2.0);
-        os << "M " << p1[NR::X] << " " <<  p1[NR::Y]
-           << " A " << ge->rx.computed << " " << ge->ry.computed
-           << " 0 1 1 " << " " << ph[NR::X] << "," << ph[NR::Y]
-           << " A " << ge->rx.computed << " " << ge->ry.computed
-           << " 0 1 1 " << " " << p2[NR::X] << " " << p2[NR::Y] << " z";
+        Geom::Point ph = sp_arc_get_xy(arc, (ge->start + ge->end) / 2.0);
+        str.arcTo(rx, ry, 0, true, true, ph)
+           .arcTo(rx, ry, 0, true, true, p2)
+           .closePath();
     } else {
-        fa = (fabs(dt) > M_PI) ? 1 : 0;
-        fs = (dt > 0) ? 1 : 0;
-#ifdef ARC_VERBOSE
-        g_print("start:%g end:%g fa=%d fs=%d\n", ge->start, ge->end, fa, fs);
-#endif
+        bool fa = (fabs(dt) > M_PI);
+        bool fs = (dt > 0);
+        str.arcTo(rx, ry, 0, fa, fs, p2);
         if (ge->closed) {
-            os << "M " << p1[NR::X] << "," << p1[NR::Y]
-               << " A " << ge->rx.computed << "," << ge->ry.computed
-               << " 0 " << fa << " " << fs << " " << p2[NR::X] << "," << p2[NR::Y]
-               << " L " << ge->cx.computed << "," << ge->cy.computed << " z";
-        } else {
-            os << "M " << p1[NR::X] << "," << p1[NR::Y]
-               << " A " << ge->rx.computed << "," << ge->ry.computed
-               << " 0 " << fa << " " << fs << " " << p2[NR::X] << "," << p2[NR::Y];
-
+            Geom::Point center = Geom::Point(ge->cx.computed, ge->cy.computed);
+            str.lineTo(center).closePath();
         }
     }
-    repr->setAttribute("d", os.str().c_str());
+
+    repr->setAttribute("d", str.c_str());
     return true;
 }
 
 static Inkscape::XML::Node *
-sp_arc_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+sp_arc_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
     SPGenericEllipse *ge = SP_GENERICELLIPSE(object);
     SPArc *arc = SP_ARC(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:path");
+        repr = xml_doc->createElement("svg:path");
     }
 
     if (flags & SP_OBJECT_WRITE_EXT) {
@@ -732,7 +794,7 @@ sp_arc_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     sp_arc_set_elliptical_path_attribute(arc, repr);
 
     if (((SPObjectClass *) arc_parent_class)->write)
-        ((SPObjectClass *) arc_parent_class)->write(object, repr, flags);
+        ((SPObjectClass *) arc_parent_class)->write(object, xml_doc, repr, flags);
 
     return repr;
 }
@@ -793,8 +855,8 @@ sp_arc_set(SPObject *object, unsigned int key, gchar const *value)
 static void
 sp_arc_modified(SPObject *object, guint flags)
 {
-    if (flags & SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG) {
-        sp_shape_set_shape((SPShape *) object);
+    if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+        ((SPShape *) object)->setShape();
     }
 
     if (((SPObjectClass *) arc_parent_class)->modified)
@@ -830,11 +892,13 @@ sp_arc_position_set(SPArc *arc, gdouble x, gdouble y, gdouble rx, gdouble ry)
     ge->cy.computed = y;
     ge->rx.computed = rx;
     ge->ry.computed = ry;
-    if (prefs_get_double_attribute("tools.shapes.arc", "start", 0.0) != 0)
-        ge->start = prefs_get_double_attribute("tools.shapes.arc", "start", 0.0);
-    if (prefs_get_double_attribute("tools.shapes.arc", "end", 0.0) != 0)
-        ge->end = prefs_get_double_attribute("tools.shapes.arc", "end", 0.0);
-    if (!prefs_get_string_attribute("tools.shapes.arc", "open"))
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    // those pref values are in degrees, while we want radians
+    if (prefs->getDouble("/tools/shapes/arc/start", 0.0) != 0)
+        ge->start = prefs->getDouble("/tools/shapes/arc/start", 0.0) * M_PI / 180;
+    if (prefs->getDouble("/tools/shapes/arc/end", 0.0) != 0)
+        ge->end = prefs->getDouble("/tools/shapes/arc/end", 0.0) * M_PI / 180;
+    if (!prefs->getBool("/tools/shapes/arc/open"))
         ge->closed = 1;
     else
         ge->closed = 0;
@@ -842,11 +906,11 @@ sp_arc_position_set(SPArc *arc, gdouble x, gdouble y, gdouble rx, gdouble ry)
     ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
-NR::Point sp_arc_get_xy(SPArc *arc, gdouble arg)
+Geom::Point sp_arc_get_xy(SPArc *arc, gdouble arg)
 {
     SPGenericEllipse *ge = SP_GENERICELLIPSE(arc);
 
-    return NR::Point(ge->rx.computed * cos(arg) + ge->cx.computed,
+    return Geom::Point(ge->rx.computed * cos(arg) + ge->cx.computed,
                      ge->ry.computed * sin(arg) + ge->cy.computed);
 }
 
@@ -860,4 +924,4 @@ NR::Point sp_arc_get_xy(SPArc *arc, gdouble arg)
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :