Code

Avoid crash by uninitialized perspectives.
[inkscape.git] / src / sp-rect.cpp
1 /*
2  * SVG <rect> implementation
3  *
4  * Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   bulia byak <buliabyak@users.sf.net>
7  *
8  * Copyright (C) 1999-2002 Lauris Kaplinski
9  * Copyright (C) 2000-2001 Ximian, Inc.
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
19 #include <display/curve.h>
20 #include <libnr/nr-matrix-ops.h>
21 #include <libnr/nr-matrix-fns.h>
22 #include <2geom/rect.h>
24 #include "inkscape.h"
25 #include "document.h"
26 #include "attributes.h"
27 #include "style.h"
28 #include "sp-rect.h"
29 #include <glibmm/i18n.h>
30 #include "xml/repr.h"
31 #include "sp-guide.h"
32 #include "preferences.h"
34 #define noRECT_VERBOSE
36 static void sp_rect_class_init(SPRectClass *klass);
37 static void sp_rect_init(SPRect *rect);
39 static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
40 static void sp_rect_set(SPObject *object, unsigned key, gchar const *value);
41 static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags);
42 static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
44 static gchar *sp_rect_description(SPItem *item);
45 static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform);
46 static void sp_rect_convert_to_guides(SPItem *item);
48 static void sp_rect_set_shape(SPShape *shape);
49 static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
51 static SPShapeClass *parent_class;
53 GType
54 sp_rect_get_type(void)
55 {
56     static GType type = 0;
58     if (!type) {
59         GTypeInfo info = {
60             sizeof(SPRectClass),
61             NULL,   /* base_init */
62             NULL,   /* base_finalize */
63             (GClassInitFunc) sp_rect_class_init,
64             NULL,   /* class_finalize */
65             NULL,   /* class_data */
66             sizeof(SPRect),
67             16,     /* n_preallocs */
68             (GInstanceInitFunc) sp_rect_init,
69             NULL,   /* value_table */
70         };
71         type = g_type_register_static(SP_TYPE_SHAPE, "SPRect", &info, (GTypeFlags)0);
72     }
73     return type;
74 }
76 static void
77 sp_rect_class_init(SPRectClass *klass)
78 {
79     SPObjectClass *sp_object_class = (SPObjectClass *) klass;
80     SPItemClass *item_class = (SPItemClass *) klass;
81     SPShapeClass *shape_class = (SPShapeClass *) klass;
83     parent_class = (SPShapeClass *)g_type_class_ref(SP_TYPE_SHAPE);
85     sp_object_class->build = sp_rect_build;
86     sp_object_class->write = sp_rect_write;
87     sp_object_class->set = sp_rect_set;
88     sp_object_class->update = sp_rect_update;
90     item_class->description = sp_rect_description;
91     item_class->set_transform = sp_rect_set_transform;
92     item_class->convert_to_guides = sp_rect_convert_to_guides;
93     item_class->snappoints = sp_rect_snappoints; //override the default sp_shape_snappoints; see sp_rect_snappoints for details
95     shape_class->set_shape = sp_rect_set_shape;
96 }
98 static void
99 sp_rect_init(SPRect */*rect*/)
101     /* Initializing to zero is automatic */
102     /* sp_svg_length_unset(&rect->x, SP_SVG_UNIT_NONE, 0.0, 0.0); */
103     /* sp_svg_length_unset(&rect->y, SP_SVG_UNIT_NONE, 0.0, 0.0); */
104     /* sp_svg_length_unset(&rect->width, SP_SVG_UNIT_NONE, 0.0, 0.0); */
105     /* sp_svg_length_unset(&rect->height, SP_SVG_UNIT_NONE, 0.0, 0.0); */
106     /* sp_svg_length_unset(&rect->rx, SP_SVG_UNIT_NONE, 0.0, 0.0); */
107     /* sp_svg_length_unset(&rect->ry, SP_SVG_UNIT_NONE, 0.0, 0.0); */
110 static void
111 sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
113     if (((SPObjectClass *) parent_class)->build)
114         ((SPObjectClass *) parent_class)->build(object, document, repr);
116     sp_object_read_attr(object, "x");
117     sp_object_read_attr(object, "y");
118     sp_object_read_attr(object, "width");
119     sp_object_read_attr(object, "height");
120     sp_object_read_attr(object, "rx");
121     sp_object_read_attr(object, "ry");
124 static void
125 sp_rect_set(SPObject *object, unsigned key, gchar const *value)
127     SPRect *rect = SP_RECT(object);
129     /* fixme: We need real error processing some time */
131     switch (key) {
132         case SP_ATTR_X:
133             rect->x.readOrUnset(value);
134             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
135             break;
136         case SP_ATTR_Y:
137             rect->y.readOrUnset(value);
138             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
139             break;
140         case SP_ATTR_WIDTH:
141             if (!rect->width.read(value) || rect->width.value < 0.0) {
142                 rect->width.unset();
143             }
144             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
145             break;
146         case SP_ATTR_HEIGHT:
147             if (!rect->height.read(value) || rect->height.value < 0.0) {
148                 rect->height.unset();
149             }
150             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
151             break;
152         case SP_ATTR_RX:
153             if (!rect->rx.read(value) || rect->rx.value < 0.0) {
154                 rect->rx.unset();
155             }
156             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
157             break;
158         case SP_ATTR_RY:
159             if (!rect->ry.read(value) || rect->ry.value < 0.0) {
160                 rect->ry.unset();
161             }
162             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
163             break;
164         default:
165             if (((SPObjectClass *) parent_class)->set)
166                 ((SPObjectClass *) parent_class)->set(object, key, value);
167             break;
168     }
171 static void
172 sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
174     if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
175         SPRect *rect = (SPRect *) object;
176         SPStyle *style = object->style;
177         SPItemCtx const *ictx = (SPItemCtx const *) ctx;
178         double const w = (ictx->vp.x1 - ictx->vp.x0);
179         double const h = (ictx->vp.y1 - ictx->vp.y0);
180         double const em = style->font_size.computed;
181         double const ex = 0.5 * em;  // fixme: get x height from pango or libnrtype.
182         rect->x.update(em, ex, w);
183         rect->y.update(em, ex, h);
184         rect->width.update(em, ex, w);
185         rect->height.update(em, ex, h);
186         rect->rx.update(em, ex, w);
187         rect->ry.update(em, ex, h);
188         sp_shape_set_shape((SPShape *) object);
189         flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
190     }
192     if (((SPObjectClass *) parent_class)->update)
193         ((SPObjectClass *) parent_class)->update(object, ctx, flags);
196 static Inkscape::XML::Node *
197 sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
199     SPRect *rect = SP_RECT(object);
201     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
202         repr = xml_doc->createElement("svg:rect");
203     }
205     sp_repr_set_svg_double(repr, "width", rect->width.computed);
206     sp_repr_set_svg_double(repr, "height", rect->height.computed);
207     if (rect->rx._set) sp_repr_set_svg_double(repr, "rx", rect->rx.computed);
208     if (rect->ry._set) sp_repr_set_svg_double(repr, "ry", rect->ry.computed);
209     sp_repr_set_svg_double(repr, "x", rect->x.computed);
210     sp_repr_set_svg_double(repr, "y", rect->y.computed);
212     if (((SPObjectClass *) parent_class)->write)
213         ((SPObjectClass *) parent_class)->write(object, xml_doc, repr, flags);
215     return repr;
218 static gchar *
219 sp_rect_description(SPItem *item)
221     g_return_val_if_fail(SP_IS_RECT(item), NULL);
223     return g_strdup(_("<b>Rectangle</b>"));
226 #define C1 0.554
228 static void
229 sp_rect_set_shape(SPShape *shape)
231     SPRect *rect = (SPRect *) shape;
233     if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) {
234         sp_shape_set_curve_insync(SP_SHAPE(rect), NULL, TRUE);
235         return;
236     }
238     SPCurve *c = new SPCurve();
240     double const x = rect->x.computed;
241     double const y = rect->y.computed;
242     double const w = rect->width.computed;
243     double const h = rect->height.computed;
244     double const w2 = w / 2;
245     double const h2 = h / 2;
246     double const rx = std::min(( rect->rx._set
247                                  ? rect->rx.computed
248                                  : ( rect->ry._set
249                                      ? rect->ry.computed
250                                      : 0.0 ) ),
251                                .5 * rect->width.computed);
252     double const ry = std::min(( rect->ry._set
253                                  ? rect->ry.computed
254                                  : ( rect->rx._set
255                                      ? rect->rx.computed
256                                      : 0.0 ) ),
257                                .5 * rect->height.computed);
258     /* TODO: Handle negative rx or ry as per
259      * http://www.w3.org/TR/SVG11/shapes.html#RectElementRXAttribute once Inkscape has proper error
260      * handling (see http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing).
261      */
263     /* We don't use proper circular/elliptical arcs, but bezier curves can approximate a 90-degree
264      * arc fairly well.
265      */
266     if ((rx > 1e-18) && (ry > 1e-18)) {
267         c->moveto(x + rx, y);
268         if (rx < w2) c->lineto(x + w - rx, y);
269         c->curveto(x + w - rx * (1 - C1), y,     x + w, y + ry * (1 - C1),       x + w, y + ry);
270         if (ry < h2) c->lineto(x + w, y + h - ry);
271         c->curveto(x + w, y + h - ry * (1 - C1),     x + w - rx * (1 - C1), y + h,       x + w - rx, y + h);
272         if (rx < w2) c->lineto(x + rx, y + h);
273         c->curveto(x + rx * (1 - C1), y + h,     x, y + h - ry * (1 - C1),       x, y + h - ry);
274         if (ry < h2) c->lineto(x, y + ry);
275         c->curveto(x, y + ry * (1 - C1),     x + rx * (1 - C1), y,       x + rx, y);
276     } else {
277         c->moveto(x + 0.0, y + 0.0);
278         c->lineto(x + w, y + 0.0);
279         c->lineto(x + w, y + h);
280         c->lineto(x + 0.0, y + h);
281         c->lineto(x + 0.0, y + 0.0);
282     }
284     c->closepath_current();
285     sp_shape_set_curve_insync(SP_SHAPE(rect), c, TRUE);
286     c->unref();
289 /* fixme: Think (Lauris) */
291 void
292 sp_rect_position_set(SPRect *rect, gdouble x, gdouble y, gdouble width, gdouble height)
294     g_return_if_fail(rect != NULL);
295     g_return_if_fail(SP_IS_RECT(rect));
297     rect->x.computed = x;
298     rect->y.computed = y;
299     rect->width.computed = width;
300     rect->height.computed = height;
302     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
305 void
306 sp_rect_set_rx(SPRect *rect, gboolean set, gdouble value)
308     g_return_if_fail(rect != NULL);
309     g_return_if_fail(SP_IS_RECT(rect));
311     rect->rx._set = set;
312     if (set) rect->rx.computed = value;
314     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
317 void
318 sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value)
320     g_return_if_fail(rect != NULL);
321     g_return_if_fail(SP_IS_RECT(rect));
323     rect->ry._set = set;
324     if (set) rect->ry.computed = value;
326     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
329 /*
330  * Initially we'll do:
331  * Transform x, y, set x, y, clear translation
332  */
334 /* fixme: Use preferred units somehow (Lauris) */
335 /* fixme: Alternately preserve whatever units there are (lauris) */
337 static Geom::Matrix
338 sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform)
340     SPRect *rect = SP_RECT(item);
342     /* Calculate rect start in parent coords. */
343     Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform );
345     /* This function takes care of translation and scaling, we return whatever parts we can't
346        handle. */
347     Geom::Matrix ret(Geom::Matrix(xform).without_translation());
348     gdouble const sw = hypot(ret[0], ret[1]);
349     gdouble const sh = hypot(ret[2], ret[3]);
350     if (sw > 1e-9) {
351         ret[0] /= sw;
352         ret[1] /= sw;
353     } else {
354         ret[0] = 1.0;
355         ret[1] = 0.0;
356     }
357     if (sh > 1e-9) {
358         ret[2] /= sh;
359         ret[3] /= sh;
360     } else {
361         ret[2] = 0.0;
362         ret[3] = 1.0;
363     }
365     /* fixme: Would be nice to preserve units here */
366     rect->width = rect->width.computed * sw;
367     rect->height = rect->height.computed * sh;
368     if (rect->rx._set) {
369         rect->rx = rect->rx.computed * sw;
370     }
371     if (rect->ry._set) {
372         rect->ry = rect->ry.computed * sh;
373     }
375     /* Find start in item coords */
376     pos = pos * ret.inverse();
377     rect->x = pos[Geom::X];
378     rect->y = pos[Geom::Y];
380     sp_rect_set_shape(rect);
382     // Adjust stroke width
383     sp_item_adjust_stroke(item, sqrt(fabs(sw * sh)));
385     // Adjust pattern fill
386     sp_item_adjust_pattern(item, xform * ret.inverse());
388     // Adjust gradient fill
389     sp_item_adjust_gradient(item, xform * ret.inverse());
391     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
393     return ret;
397 /**
398 Returns the ratio in which the vector from p0 to p1 is stretched by transform
399  */
400 static gdouble
401 vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform)
403     if (p0 == p1)
404         return 0;
405     return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1));
408 void
409 sp_rect_set_visible_rx(SPRect *rect, gdouble rx)
411     if (rx == 0) {
412         rect->rx.computed = 0;
413         rect->rx._set = false;
414     } else {
415         rect->rx.computed = rx / vector_stretch(
416             Geom::Point(rect->x.computed + 1, rect->y.computed),
417             Geom::Point(rect->x.computed, rect->y.computed),
418             SP_ITEM(rect)->transform);
419         rect->rx._set = true;
420     }
421     SP_OBJECT(rect)->updateRepr();
424 void
425 sp_rect_set_visible_ry(SPRect *rect, gdouble ry)
427     if (ry == 0) {
428         rect->ry.computed = 0;
429         rect->ry._set = false;
430     } else {
431         rect->ry.computed = ry / vector_stretch(
432             Geom::Point(rect->x.computed, rect->y.computed + 1),
433             Geom::Point(rect->x.computed, rect->y.computed),
434             SP_ITEM(rect)->transform);
435         rect->ry._set = true;
436     }
437     SP_OBJECT(rect)->updateRepr();
440 gdouble
441 sp_rect_get_visible_rx(SPRect *rect)
443     if (!rect->rx._set)
444         return 0;
445     return rect->rx.computed * vector_stretch(
446         Geom::Point(rect->x.computed + 1, rect->y.computed),
447         Geom::Point(rect->x.computed, rect->y.computed),
448         SP_ITEM(rect)->transform);
451 gdouble
452 sp_rect_get_visible_ry(SPRect *rect)
454     if (!rect->ry._set)
455         return 0;
456     return rect->ry.computed * vector_stretch(
457         Geom::Point(rect->x.computed, rect->y.computed + 1),
458         Geom::Point(rect->x.computed, rect->y.computed),
459         SP_ITEM(rect)->transform);
462 Geom::Rect
463 sp_rect_get_rect (SPRect *rect)
465     Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed);
466     Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
467     return Geom::Rect(p0, p2);
470 void
471 sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform)
473     if (rect->rx.computed == 0 && rect->ry.computed == 0)
474         return; // nothing to compensate
476     // test unit vectors to find out compensation:
477     Geom::Point c(rect->x.computed, rect->y.computed);
478     Geom::Point cx = c + Geom::Point(1, 0);
479     Geom::Point cy = c + Geom::Point(0, 1);
481     // apply previous transform if any
482     c *= SP_ITEM(rect)->transform;
483     cx *= SP_ITEM(rect)->transform;
484     cy *= SP_ITEM(rect)->transform;
486     // find out stretches that we need to compensate
487     gdouble eX = vector_stretch(cx, c, xform);
488     gdouble eY = vector_stretch(cy, c, xform);
490     // If only one of the radii is set, set both radii so they have the same visible length
491     // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform
492     if ((rect->rx._set && !rect->ry._set) || (rect->ry._set && !rect->rx._set)) {
493         gdouble r = MAX(rect->rx.computed, rect->ry.computed);
494         rect->rx.computed = r / eX;
495         rect->ry.computed = r / eY;
496     } else {
497         rect->rx.computed = rect->rx.computed / eX;
498         rect->ry.computed = rect->ry.computed / eY;
499     }
501     // Note that a radius may end up larger than half-side if the rect is scaled down;
502     // that's ok because this preserves the intended radii in case the rect is enlarged again,
503     // and set_shape will take care of trimming too large radii when generating d=
505     rect->rx._set = rect->ry._set = true;
508 void
509 sp_rect_set_visible_width(SPRect *rect, gdouble width)
511     rect->width.computed = width / vector_stretch(
512         Geom::Point(rect->x.computed + 1, rect->y.computed),
513         Geom::Point(rect->x.computed, rect->y.computed),
514         SP_ITEM(rect)->transform);
515     rect->width._set = true;
516     SP_OBJECT(rect)->updateRepr();
519 void
520 sp_rect_set_visible_height(SPRect *rect, gdouble height)
522     rect->height.computed = height / vector_stretch(
523         Geom::Point(rect->x.computed, rect->y.computed + 1),
524         Geom::Point(rect->x.computed, rect->y.computed),
525         SP_ITEM(rect)->transform);
526     rect->height._set = true;
527     SP_OBJECT(rect)->updateRepr();
530 gdouble
531 sp_rect_get_visible_width(SPRect *rect)
533     if (!rect->width._set)
534         return 0;
535     return rect->width.computed * vector_stretch(
536         Geom::Point(rect->x.computed + 1, rect->y.computed),
537         Geom::Point(rect->x.computed, rect->y.computed),
538         SP_ITEM(rect)->transform);
541 gdouble
542 sp_rect_get_visible_height(SPRect *rect)
544     if (!rect->height._set)
545         return 0;
546     return rect->height.computed * vector_stretch(
547         Geom::Point(rect->x.computed, rect->y.computed + 1),
548         Geom::Point(rect->x.computed, rect->y.computed),
549         SP_ITEM(rect)->transform);
552 /**
553  * Sets the snappoint p to the unrounded corners of the rectangle
554  */
555 static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
557     /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method
558     returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping
559     the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead
560     we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners,
561     but it should be noted that this might be confusing in some cases with relatively large radii. With
562     small radii though the user will easily understand which point is snapping. */
564     g_assert(item != NULL);
565     g_assert(SP_IS_RECT(item));
567     // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
568     if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
569         return;
570     }
572     SPRect *rect = SP_RECT(item);
574     Geom::Matrix const i2d (sp_item_i2d_affine (item));
576     Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d;
577     Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
578     Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
579     Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
581     if (snapprefs->getSnapToItemNode()) {
582         p.push_back(Inkscape::SnapCandidatePoint(p0, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
583         p.push_back(Inkscape::SnapCandidatePoint(p1, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
584         p.push_back(Inkscape::SnapCandidatePoint(p2, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
585         p.push_back(Inkscape::SnapCandidatePoint(p3, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
586     }
588     if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
589         p.push_back(Inkscape::SnapCandidatePoint((p0 + p1)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
590         p.push_back(Inkscape::SnapCandidatePoint((p1 + p2)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
591         p.push_back(Inkscape::SnapCandidatePoint((p2 + p3)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
592         p.push_back(Inkscape::SnapCandidatePoint((p3 + p0)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
593     }
595     if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
596         p.push_back(Inkscape::SnapCandidatePoint((p0 + p2)/2, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
597     }
601 void
602 sp_rect_convert_to_guides(SPItem *item) {
603     SPRect *rect = SP_RECT(item);
605     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
606     if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) {
607         sp_item_convert_to_guides(SP_ITEM(rect));
608         return;
609     }
611     std::list<std::pair<Geom::Point, Geom::Point> > pts;
613     Geom::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(rect)));
615     Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d);
616     Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
617     Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
618     Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
620     pts.push_back(std::make_pair(A1, A2));
621     pts.push_back(std::make_pair(A2, A3));
622     pts.push_back(std::make_pair(A3, A4));
623     pts.push_back(std::make_pair(A4, A1));
625     sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts);
628 /*
629   Local Variables:
630   mode:c++
631   c-file-style:"stroustrup"
632   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
633   indent-tabs-mode:nil
634   fill-column:99
635   End:
636 */
637 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :