diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp
index 819aed99766dc6f070387eb1bc7c50adcf91f228..ff2e3904437961c62e8f6481a4cb7e12ad9c323e 100644 (file)
--- a/src/sp-ellipse.cpp
+++ b/src/sp-ellipse.cpp
#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 "document.h"
#include "sp-ellipse.h"
-#include "prefs-utils.h"
+#include "preferences.h"
/* Common parent class */
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, bool const target, SnapPointsWithType &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 gboolean sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr);
{
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);
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
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);
+ Geom::OptRect viewbox = ((SPItemCtx const *) ctx)->vp;
+ 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, d);
- ellipse->cy.update(em, ex, d);
- ellipse->rx.update(em, ex, d);
- ellipse->ry.update(em, ex, d);
+ ellipse->cx.update(em, ex, dx);
+ ellipse->cy.update(em, ex, dy);
+ ellipse->rx.update(em, ex, dr);
+ ellipse->ry.update(em, ex, dr);
sp_shape_set_shape((SPShape *) object);
}
((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;
+ 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;
sp_genericellipse_normalize(ellipse);
- cx = 0.0;
- cy = 0.0;
rx = ellipse->rx.computed;
ry = ellipse->ry.computed;
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);
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)*/
+ sp_shape_set_curve_insync (shape, 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) {
+ sp_shape_set_curve_insync (shape, 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, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs)
{
- SPGenericEllipse const *ge = SP_GENERICELLIPSE(item);
+ g_assert(item != NULL);
+ g_assert(SP_IS_GENERICELLIPSE(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 = sp_item_i2d_affine(item);
- NR::Matrix const i2d = sp_item_i2d_affine(item);
+ // 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;
+ }
- /* Add the centre */
- *p = NR::Point(ge->cx.computed, ge->cy.computed) * i2d;
+ 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(std::make_pair(pt, target ? int(Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT) : int(Inkscape::SNAPSOURCE_ELLIPSE_QUADRANT_POINT)));
+ }
+ }
+ }
+
+ // 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(std::make_pair(pt, target ? int(Inkscape::SNAPTARGET_CENTER) : int(Inkscape::SNAPSOURCE_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(std::make_pair(pt, target ? int(Inkscape::SNAPTARGET_NODE_CUSP) : int(Inkscape::SNAPSOURCE_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(std::make_pair(pt, target ? int(Inkscape::SNAPTARGET_NODE_CUSP) : int(Inkscape::SNAPSOURCE_NODE_CUSP)));
+ }
+ }
}
void
/* 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");
}
@@ -299,7 +356,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;
}
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);
}
static void
-sp_ellipse_init(SPEllipse *ellipse)
+sp_ellipse_init(SPEllipse */*ellipse*/)
{
/* Nothing special */
}
@@ -371,14 +428,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");
}
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;
}
}
}
-static gchar *sp_ellipse_description(SPItem *item)
+static gchar *sp_ellipse_description(SPItem */*item*/)
{
return g_strdup(_("<b>Ellipse</b>"));
}
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);
}
static void
-sp_circle_init(SPCircle *circle)
+sp_circle_init(SPCircle */*circle*/)
{
/* Nothing special */
}
@@ -519,14 +575,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");
}
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;
}
}
}
-static gchar *sp_circle_description(SPItem *item)
+static gchar *sp_circle_description(SPItem */*item*/)
{
return g_strdup(_("<b>Circle</b>"));
}
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);
}
static void
-sp_arc_init(SPArc *arc)
+sp_arc_init(SPArc */*arc*/)
{
/* Nothing special */
}
if (((SPObjectClass *) arc_parent_class)->build)
(* ((SPObjectClass *) arc_parent_class)->build) (object, document, repr);
- Inkscape::Version version = sp_object_get_sodipodi_version(object);
-
sp_object_read_attr(object, "sodipodi:cx");
sp_object_read_attr(object, "sodipodi:cy");
sp_object_read_attr(object, "sodipodi:rx");
@@ -662,53 +715,44 @@ sp_arc_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
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;
+
+ str.moveTo(p1);
- dt = fmod(ge->end - ge->start, SP_2PI);
+ 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) {
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
repr = xml_doc->createElement("svg:path");
}
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;
}
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) {
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
sp_shape_set_shape((SPShape *) object);
}
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();
+ if (prefs->getDouble("/tools/shapes/arc/start", 0.0) != 0)
+ ge->start = prefs->getDouble("/tools/shapes/arc/start", 0.0);
+ if (prefs->getDouble("/tools/shapes/arc/end", 0.0) != 0)
+ ge->end = prefs->getDouble("/tools/shapes/arc/end", 0.0);
+ if (!prefs->getBool("/tools/shapes/arc/open"))
ge->closed = 1;
else
ge->closed = 0;
((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);
}