X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=inline;f=src%2Fsp-rect.cpp;h=c2fe527b664ab40aa7e95458d3ba077dee02c771;hb=dc04c2a317d9e7ea799d78d5b4e9bf28997ca46f;hp=edcea21a24cd757af5bfb77e28a2474ae9d61e37;hpb=6b15695578f07a3f72c4c9475c1a261a3021472a;p=inkscape.git diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index edcea21a2..c2fe527b6 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -1,5 +1,3 @@ -#define __SP_RECT_C__ - /* * SVG implementation * @@ -19,14 +17,18 @@ #include -#include +#include #include +#include "inkscape.h" +#include "document.h" #include "attributes.h" #include "style.h" #include "sp-rect.h" #include #include "xml/repr.h" +#include "sp-guide.h" +#include "preferences.h" #define noRECT_VERBOSE @@ -36,12 +38,14 @@ static void sp_rect_init(SPRect *rect); static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_rect_set(SPObject *object, unsigned key, gchar const *value); static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags); -static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); +static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static gchar *sp_rect_description(SPItem *item); -static NR::Matrix sp_rect_set_transform(SPItem *item, NR::Matrix const &xform); +static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform); +static void sp_rect_convert_to_guides(SPItem *item); static void sp_rect_set_shape(SPShape *shape); +static void sp_rect_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::SnapPreferences const *snapprefs); static SPShapeClass *parent_class; @@ -84,12 +88,14 @@ sp_rect_class_init(SPRectClass *klass) item_class->description = sp_rect_description; item_class->set_transform = sp_rect_set_transform; + item_class->convert_to_guides = sp_rect_convert_to_guides; + item_class->snappoints = sp_rect_snappoints; //override the default sp_shape_snappoints; see sp_rect_snappoints for details shape_class->set_shape = sp_rect_set_shape; } static void -sp_rect_init(SPRect *rect) +sp_rect_init(SPRect */*rect*/) { /* Initializing to zero is automatic */ /* sp_svg_length_unset(&rect->x, SP_SVG_UNIT_NONE, 0.0, 0.0); */ @@ -103,8 +109,6 @@ sp_rect_init(SPRect *rect) static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { - SPRect *rect = SP_RECT(object); - if (((SPObjectClass *) parent_class)->build) ((SPObjectClass *) parent_class)->build(object, document, repr); @@ -114,21 +118,6 @@ sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) sp_object_read_attr(object, "height"); sp_object_read_attr(object, "rx"); sp_object_read_attr(object, "ry"); - - Inkscape::Version const version = sp_object_get_sodipodi_version(object); - - if ( version.major == 0 && version.minor == 29 ) { - if (rect->rx._set && rect->ry._set) { - /* 0.29 treated 0.0 radius as missing value */ - if ((rect->rx.value != 0.0) && (rect->ry.value == 0.0)) { - repr->setAttribute("ry", NULL); - sp_object_read_attr(object, "ry"); - } else if ((rect->ry.value != 0.0) && (rect->rx.value == 0.0)) { - repr->setAttribute("rx", NULL); - sp_object_read_attr(object, "rx"); - } - } - } } static void @@ -185,7 +174,7 @@ sp_rect_update(SPObject *object, SPCtx *ctx, guint flags) SPRect *rect = (SPRect *) object; SPStyle *style = object->style; SPItemCtx const *ictx = (SPItemCtx const *) ctx; - double const d = NR::expansion(ictx->i2vp); + double const d = ictx->i2vp.descrim(); double const w = (ictx->vp.x1 - ictx->vp.x0) / d; double const h = (ictx->vp.y1 - ictx->vp.y0) / d; double const em = style->font_size.computed; @@ -205,12 +194,12 @@ sp_rect_update(SPObject *object, SPCtx *ctx, guint flags) } static Inkscape::XML::Node * -sp_rect_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) +sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { SPRect *rect = SP_RECT(object); if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = sp_repr_new("svg:rect"); + repr = xml_doc->createElement("svg:rect"); } sp_repr_set_svg_double(repr, "width", rect->width.computed); @@ -221,7 +210,7 @@ sp_rect_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) sp_repr_set_svg_double(repr, "y", rect->y.computed); if (((SPObjectClass *) parent_class)->write) - ((SPObjectClass *) parent_class)->write(object, repr, flags); + ((SPObjectClass *) parent_class)->write(object, xml_doc, repr, flags); return repr; } @@ -241,9 +230,12 @@ sp_rect_set_shape(SPShape *shape) { SPRect *rect = (SPRect *) shape; - if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) return; + if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) { + sp_shape_set_curve_insync(SP_SHAPE(rect), NULL, TRUE); + return; + } - SPCurve *c = sp_curve_new(); + SPCurve *c = new SPCurve(); double const x = rect->x.computed; double const y = rect->y.computed; @@ -272,26 +264,26 @@ sp_rect_set_shape(SPShape *shape) * arc fairly well. */ if ((rx > 1e-18) && (ry > 1e-18)) { - sp_curve_moveto(c, x + rx, y); - if (rx < w2) sp_curve_lineto(c, x + w - rx, y); - sp_curve_curveto(c, x + w - rx * (1 - C1), y, x + w, y + ry * (1 - C1), x + w, y + ry); - if (ry < h2) sp_curve_lineto(c, x + w, y + h - ry); - sp_curve_curveto(c, x + w, y + h - ry * (1 - C1), x + w - rx * (1 - C1), y + h, x + w - rx, y + h); - if (rx < w2) sp_curve_lineto(c, x + rx, y + h); - sp_curve_curveto(c, x + rx * (1 - C1), y + h, x, y + h - ry * (1 - C1), x, y + h - ry); - if (ry < h2) sp_curve_lineto(c, x, y + ry); - sp_curve_curveto(c, x, y + ry * (1 - C1), x + rx * (1 - C1), y, x + rx, y); + c->moveto(x + rx, y); + if (rx < w2) c->lineto(x + w - rx, y); + c->curveto(x + w - rx * (1 - C1), y, x + w, y + ry * (1 - C1), x + w, y + ry); + if (ry < h2) c->lineto(x + w, y + h - ry); + c->curveto(x + w, y + h - ry * (1 - C1), x + w - rx * (1 - C1), y + h, x + w - rx, y + h); + if (rx < w2) c->lineto(x + rx, y + h); + c->curveto(x + rx * (1 - C1), y + h, x, y + h - ry * (1 - C1), x, y + h - ry); + if (ry < h2) c->lineto(x, y + ry); + c->curveto(x, y + ry * (1 - C1), x + rx * (1 - C1), y, x + rx, y); } else { - sp_curve_moveto(c, x + 0.0, y + 0.0); - sp_curve_lineto(c, x + w, y + 0.0); - sp_curve_lineto(c, x + w, y + h); - sp_curve_lineto(c, x + 0.0, y + h); - sp_curve_lineto(c, x + 0.0, y + 0.0); + c->moveto(x + 0.0, y + 0.0); + c->lineto(x + w, y + 0.0); + c->lineto(x + w, y + h); + c->lineto(x + 0.0, y + h); + c->lineto(x + 0.0, y + 0.0); } - sp_curve_closepath_current(c); + c->closepath_current(); sp_shape_set_curve_insync(SP_SHAPE(rect), c, TRUE); - sp_curve_unref(c); + c->unref(); } /* fixme: Think (Lauris) */ @@ -342,17 +334,17 @@ sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value) /* fixme: Use preferred units somehow (Lauris) */ /* fixme: Alternately preserve whatever units there are (lauris) */ -static NR::Matrix -sp_rect_set_transform(SPItem *item, NR::Matrix const &xform) +static Geom::Matrix +sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform) { SPRect *rect = SP_RECT(item); /* Calculate rect start in parent coords. */ - NR::Point pos( NR::Point(rect->x.computed, rect->y.computed) * xform ); + Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform ); /* This function takes care of translation and scaling, we return whatever parts we can't handle. */ - NR::Matrix ret(NR::transform(xform)); + Geom::Matrix ret(Geom::Matrix(xform).without_translation()); gdouble const sw = hypot(ret[0], ret[1]); gdouble const sh = hypot(ret[2], ret[3]); if (sw > 1e-9) { @@ -382,8 +374,8 @@ sp_rect_set_transform(SPItem *item, NR::Matrix const &xform) /* Find start in item coords */ pos = pos * ret.inverse(); - rect->x = pos[NR::X]; - rect->y = pos[NR::Y]; + rect->x = pos[Geom::X]; + rect->y = pos[Geom::Y]; sp_rect_set_shape(rect); @@ -391,10 +383,10 @@ sp_rect_set_transform(SPItem *item, NR::Matrix const &xform) sp_item_adjust_stroke(item, sqrt(fabs(sw * sh))); // Adjust pattern fill - sp_item_adjust_pattern(item, xform / ret); + sp_item_adjust_pattern(item, xform * ret.inverse()); // Adjust gradient fill - sp_item_adjust_gradient(item, xform / ret); + sp_item_adjust_gradient(item, xform * ret.inverse()); item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); @@ -406,11 +398,11 @@ sp_rect_set_transform(SPItem *item, NR::Matrix const &xform) Returns the ratio in which the vector from p0 to p1 is stretched by transform */ static gdouble -vector_stretch(NR::Point p0, NR::Point p1, NR::Matrix xform) +vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform) { if (p0 == p1) return 0; - return (NR::distance(p0 * xform, p1 * xform) / NR::distance(p0, p1)); + return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1)); } void @@ -421,8 +413,8 @@ sp_rect_set_visible_rx(SPRect *rect, gdouble rx) rect->rx._set = false; } else { rect->rx.computed = rx / vector_stretch( - NR::Point(rect->x.computed + 1, rect->y.computed), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed + 1, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); rect->rx._set = true; } @@ -437,8 +429,8 @@ sp_rect_set_visible_ry(SPRect *rect, gdouble ry) rect->ry._set = false; } else { rect->ry.computed = ry / vector_stretch( - NR::Point(rect->x.computed, rect->y.computed + 1), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed + 1), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); rect->ry._set = true; } @@ -451,8 +443,8 @@ sp_rect_get_visible_rx(SPRect *rect) if (!rect->rx._set) return 0; return rect->rx.computed * vector_stretch( - NR::Point(rect->x.computed + 1, rect->y.computed), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed + 1, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); } @@ -462,21 +454,21 @@ sp_rect_get_visible_ry(SPRect *rect) if (!rect->ry._set) return 0; return rect->ry.computed * vector_stretch( - NR::Point(rect->x.computed, rect->y.computed + 1), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed + 1), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); } void -sp_rect_compensate_rxry(SPRect *rect, NR::Matrix xform) +sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform) { if (rect->rx.computed == 0 && rect->ry.computed == 0) return; // nothing to compensate // test unit vectors to find out compensation: - NR::Point c(rect->x.computed, rect->y.computed); - NR::Point cx = c + NR::Point(1, 0); - NR::Point cy = c + NR::Point(0, 1); + Geom::Point c(rect->x.computed, rect->y.computed); + Geom::Point cx = c + Geom::Point(1, 0); + Geom::Point cy = c + Geom::Point(0, 1); // apply previous transform if any c *= SP_ITEM(rect)->transform; @@ -509,8 +501,8 @@ void sp_rect_set_visible_width(SPRect *rect, gdouble width) { rect->width.computed = width / vector_stretch( - NR::Point(rect->x.computed + 1, rect->y.computed), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed + 1, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); rect->width._set = true; SP_OBJECT(rect)->updateRepr(); @@ -520,8 +512,8 @@ void sp_rect_set_visible_height(SPRect *rect, gdouble height) { rect->height.computed = height / vector_stretch( - NR::Point(rect->x.computed, rect->y.computed + 1), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed + 1), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); rect->height._set = true; SP_OBJECT(rect)->updateRepr(); @@ -533,8 +525,8 @@ sp_rect_get_visible_width(SPRect *rect) if (!rect->width._set) return 0; return rect->width.computed * vector_stretch( - NR::Point(rect->x.computed + 1, rect->y.computed), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed + 1, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); } @@ -544,11 +536,87 @@ sp_rect_get_visible_height(SPRect *rect) if (!rect->height._set) return 0; return rect->height.computed * vector_stretch( - NR::Point(rect->x.computed, rect->y.computed + 1), - NR::Point(rect->x.computed, rect->y.computed), + Geom::Point(rect->x.computed, rect->y.computed + 1), + Geom::Point(rect->x.computed, rect->y.computed), SP_ITEM(rect)->transform); } +/** + * Sets the snappoint p to the unrounded corners of the rectangle + */ +static void sp_rect_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::SnapPreferences const *snapprefs) +{ + /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method + returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping + the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead + we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners, + but it should be noted that this might be confusing in some cases with relatively large radii. With + small radii though the user will easily understand which point is snapping. */ + + g_assert(item != NULL); + g_assert(SP_IS_RECT(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; + } + + SPRect *rect = SP_RECT(item); + + Geom::Matrix const i2d (sp_item_i2d_affine (item)); + + Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d; + Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d; + Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d; + Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d; + + if (snapprefs->getSnapToItemNode()) { + *p = p0; + *p = p1; + *p = p2; + *p = p3; + } + + if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping) + *p = (p0 + p1)/2; + *p = (p1 + p2)/2; + *p = (p2 + p3)/2; + *p = (p3 + p0)/2; + } + + if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping) + *p = (p0 + p2)/2; + } + +} + +void +sp_rect_convert_to_guides(SPItem *item) { + SPRect *rect = SP_RECT(item); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) { + sp_item_convert_to_guides(SP_ITEM(rect)); + return; + } + + std::list > pts; + + Geom::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(rect))); + + Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d); + Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d); + Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d); + Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d); + + pts.push_back(std::make_pair(A1, A2)); + pts.push_back(std::make_pair(A2, A3)); + pts.push_back(std::make_pair(A3, A4)); + pts.push_back(std::make_pair(A4, A1)); + + sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts); +} + /* Local Variables: mode:c++