Code

New crosshairs cursor for geometry context
[inkscape.git] / src / sp-ellipse.cpp
index 7a1b0f33e0ef41cc118a6a9d862ed873263a2340..889e8b8ffc5d23885feaefbc7730f8305f32e508 100644 (file)
@@ -19,8 +19,6 @@
 #endif
 
 
-#include "libnr/n-art-bpath.h"
-#include "libnr/nr-path.h"
 #include "libnr/nr-matrix-fns.h"
 #include "svg/svg.h"
 #include "svg/path-string.h"
@@ -29,6 +27,7 @@
 #include "style.h"
 #include "display/curve.h"
 #include <glibmm/i18n.h>
+#include <2geom/transforms.h>
 
 #include "document.h"
 #include "sp-ellipse.h"
@@ -76,9 +75,9 @@ 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_set_shape(SPShape *shape);
-static void sp_genericellipse_update_patheffect (SPShape *shape, bool write);
+static void sp_genericellipse_update_patheffect (SPLPEItem *lpeitem, bool write);
 
-static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Node *repr,
+static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
                                                     guint flags);
 
 static gboolean sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr);
@@ -111,6 +110,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);
@@ -121,7 +121,7 @@ static void sp_genericellipse_class_init(SPGenericEllipseClass *klass)
     item_class->snappoints = sp_genericellipse_snappoints;
 
     shape_class->set_shape = sp_genericellipse_set_shape;
-    shape_class->update_patheffect = sp_genericellipse_update_patheffect;
+    lpe_item_class->update_patheffect = sp_genericellipse_update_patheffect;
 }
 
 static void
@@ -158,21 +158,17 @@ sp_genericellipse_update(SPObject *object, SPCtx *ctx, guint flags)
 }
 
 static void
-sp_genericellipse_update_patheffect(SPShape *shape, bool write)
+sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write)
 {
+    SPShape *shape = (SPShape *) lpeitem;
     sp_genericellipse_set_shape(shape);
 
     if (write) {
         Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape);
         if ( shape->curve != NULL ) {
-            NArtBpath *abp = sp_curve_first_bpath(shape->curve);
-            if (abp) {
-                gchar *str = sp_svg_write_path(abp);
-                repr->setAttribute("d", str);
-                g_free(str);
-            } else {
-                repr->setAttribute("d", "");
-            }
+            gchar *str = sp_svg_write_path(shape->curve->get_pathvector());
+            repr->setAttribute("d", str);
+            g_free(str);
         } else {
             repr->setAttribute("d", NULL);
         }
@@ -185,14 +181,14 @@ sp_genericellipse_update_patheffect(SPShape *shape, bool write)
 #define C1 0.552
 
 /* 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;
+    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;
 
@@ -201,8 +197,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;
 
@@ -216,20 +210,8 @@ 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;
@@ -248,49 +230,73 @@ 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);
+    Geom::Matrix aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed);
+    curve->transform(aff);
 
-    sp_shape_perform_path_effect(c, SP_SHAPE (ellipse));
-    sp_shape_set_curve_insync((SPShape *) ellipse, c, TRUE);
-    sp_curve_unref(c);
+    sp_lpe_item_perform_path_effect(SP_LPE_ITEM (ellipse), curve);
+    sp_shape_set_curve_insync((SPShape *) ellipse, curve, TRUE);
+    curve->unref();
 }
 
 static void sp_genericellipse_snappoints(SPItem const *item, SnapPointsIter p)
 {
-    SPGenericEllipse const *ge = SP_GENERICELLIPSE(item);
-
+    g_assert(item != NULL);
+    g_assert(SP_IS_GENERICELLIPSE(item));
+    
+    SPGenericEllipse *ellipse = SP_GENERICELLIPSE(item);
+    sp_genericellipse_normalize(ellipse);
     NR::Matrix const i2d = sp_item_i2d_affine(item);
 
-    /* Add the centre */
-    *p = NR::Point(ge->cx.computed, ge->cy.computed) * i2d;
+    // figure out if we have a slice, whilst 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;
+    }
 
-    // TODO: add the ends of radii
+    double rx = ellipse->rx.computed;
+    double ry = ellipse->ry.computed;    
+    double cx = ellipse->cx.computed;
+    double cy = ellipse->cy.computed;
+    
+    // Snap to the 4 quadrant points of the ellipse, but only if the arc
+    // spans far enough to include them
+    double angle = 0;
+    for (angle = 0; angle < SP_2PI; angle += M_PI_2) {
+        if (angle >= ellipse->start && angle <= ellipse->end) {
+            *p = NR::Point(cx + cos(angle)*rx, cy + sin(angle)*ry) * i2d;
+        }
+    }
+    
+    // And if we have a slice, also snap to the endpoints and the centre point 
+    if (slice) {
+        // Add the centre, if we have a closed slice
+        if (ellipse->closed) {
+            *p = NR::Point(cx, cy) * i2d;
+        }
+        // Add the start point, if it's not coincident with a quadrant point
+        if (fmod(ellipse->start, M_PI_2) != 0.0 ) {    
+            *p = NR::Point(cx + cos(ellipse->start)*rx, cy + sin(ellipse->start)*ry) * i2d;
+        } 
+        // Add the end point, if it's not coincident with a quadrant point
+        if (fmod(ellipse->end, M_PI_2) != 0.0 ) {    
+            *p = NR::Point(cx + cos(ellipse->end)*rx, cy + sin(ellipse->end)*ry) * i2d;
+        }
+    }
 }
 
 void
@@ -308,13 +314,12 @@ 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) {
-            Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
             repr = xml_doc->createElement("svg:path");
         }
 
@@ -328,7 +333,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;
 }
@@ -339,7 +344,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);
 
@@ -400,14 +405,13 @@ sp_ellipse_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *re
 }
 
 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) {
-        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
         repr = xml_doc->createElement("svg:ellipse");
     }
 
@@ -417,7 +421,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;
 }
@@ -487,7 +491,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);
 
@@ -548,14 +552,13 @@ sp_circle_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
 }
 
 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) {
-        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
         repr = xml_doc->createElement("svg:circle");
     }
 
@@ -564,7 +567,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;
 }
@@ -610,7 +613,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);
 
@@ -723,13 +726,12 @@ sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr)
 }
 
 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) {
-        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
         repr = xml_doc->createElement("svg:path");
     }
 
@@ -758,7 +760,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;
 }