1 /** \file
2 * Interface between Inkscape code (SPItem) and remove-overlaps function.
3 */
4 /*
5 * Authors:
6 * Tim Dwyer <tgdwyer@gmail.com>
7 *
8 * Copyright (C) 2005 Authors
9 *
10 * Released under GNU GPL. Read the file 'COPYING' for more information.
11 */
12 #include "util/glib-list-iterators.h"
13 #include "sp-item.h"
14 #include "sp-item-transform.h"
15 #include "removeoverlap/generate-constraints.h"
16 #include "removeoverlap/remove_rectangle_overlap.h"
18 /**
19 * Takes a list of inkscape items and moves them as little as possible
20 * such that rectangular bounding boxes are separated by at least xGap
21 * horizontally and yGap vertically
22 */
23 void removeoverlap(GSList const *const items, double const xGap, double const yGap) {
24 if(!items) {
25 return;
26 }
28 using Inkscape::Util::GSListConstIterator;
29 std::list<SPItem *> selected;
30 selected.insert<GSListConstIterator<SPItem *> >(selected.end(), items, NULL);
31 if (selected.empty()) return;
32 int n=selected.size();
34 //Check 2 or more selected objects
35 if (n < 2) return;
37 Rectangle **rs = new Rectangle*[n];
38 int i=0;
40 NR::Point const gap(xGap, yGap);
41 for (std::list<SPItem *>::iterator it(selected.begin());
42 it != selected.end();
43 ++it)
44 {
45 using NR::X; using NR::Y;
46 NR::Rect const item_box(sp_item_bbox_desktop(*it));
48 /* The current algorithm requires widths & heights to be strictly positive. */
49 NR::Point min(item_box.min());
50 NR::Point max(item_box.max());
51 for (unsigned d = 0; d < 2; ++d) {
52 double const minsize = 1; // arbitrary positive number
53 if (max[d] - min[d] + gap[d] < minsize) {
54 double const mid = .5 * (min[d] + max[d]);
55 min[d] = mid - .5*minsize;
56 max[d] = mid + .5*minsize;
57 } else {
58 min[d] -= .5*gap[d];
59 max[d] += .5*gap[d];
60 }
61 }
62 rs[i++] = new Rectangle(min[X], max[X],
63 min[Y], max[Y]);
64 }
65 removeRectangleOverlap(rs, n, 0.0, 0.0);
66 i=0;
67 for (std::list<SPItem *>::iterator it(selected.begin());
68 it != selected.end();
69 ++it)
70 {
71 NR::Rect const item_box(sp_item_bbox_desktop(*it));
72 Rectangle *r = rs[i++];
73 NR::Point const curr(item_box.midpoint());
74 NR::Point const dest(r->getCentreX(),
75 r->getCentreY());
76 sp_item_move_rel(*it, NR::translate(dest - curr));
77 delete r;
78 }
79 delete [] rs;
80 }