summaryrefslogtreecommitdiffstats
path: root/src/removeoverlap/removeoverlap.cpp
blob: 9d7beb45fa2d36b4754537d3e9f1e429d9aa79cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/** \file
 * Interface between Inkscape code (SPItem) and remove-overlaps function.
 */
/*
* Authors:
*   Tim Dwyer <tgdwyer@gmail.com>
*
* Copyright (C) 2005 Authors
*
* Released under GNU GPL.  Read the file 'COPYING' for more information.
*/
#include "util/glib-list-iterators.h"
#include "sp-item.h"
#include "sp-item-transform.h"
#include "removeoverlap/generate-constraints.h"
#include "removeoverlap/remove_rectangle_overlap.h"

/**
* Takes a list of inkscape items and moves them as little as possible
* such that rectangular bounding boxes are separated by at least xGap
* horizontally and yGap vertically
*/
void removeoverlap(GSList const *const items, double const xGap, double const yGap) {
	if(!items) {
		return;
	}

	using Inkscape::Util::GSListConstIterator;
	std::list<SPItem *> selected;
	selected.insert<GSListConstIterator<SPItem *> >(selected.end(), items, NULL);
	if (selected.empty()) return;
	int n=selected.size();

	//Check 2 or more selected objects
	if (n < 2) return;

	Rectangle **rs = new Rectangle*[n];
	int i=0;

	NR::Point const gap(xGap, yGap);
	for (std::list<SPItem *>::iterator it(selected.begin());
		it != selected.end();
		++it)
	{
		using NR::X; using NR::Y;
		NR::Rect const item_box(sp_item_bbox_desktop(*it));
		
		/* The current algorithm requires widths & heights to be strictly positive. */
		NR::Point min(item_box.min());
		NR::Point max(item_box.max());
		for (unsigned d = 0; d < 2; ++d) {
			double const minsize = 1; // arbitrary positive number
			if (max[d] - min[d] + gap[d] < minsize) {
				double const mid = .5 * (min[d] + max[d]);
				min[d] = mid - .5*minsize;
				max[d] = mid + .5*minsize;
			} else {
				min[d] -= .5*gap[d];
				max[d] += .5*gap[d];
			}
		}
		rs[i++] = new Rectangle(min[X], max[X],
					min[Y], max[Y]);
	}
	removeRectangleOverlap(rs, n, 0.0, 0.0);
	i=0;
	for (std::list<SPItem *>::iterator it(selected.begin());
		it != selected.end();
		++it)
	{
		NR::Rect const item_box(sp_item_bbox_desktop(*it));
		Rectangle *r = rs[i++];
		NR::Point const curr(item_box.midpoint());
		NR::Point const dest(r->getCentreX(),
				     r->getCentreY());
		sp_item_move_rel(*it, NR::translate(dest - curr));
		delete r;
	}
	delete [] rs;
}