1 /* NetHack 3.6 qt_clust.cpp $NHDT-Date: 1524684507 2018/04/25 19:28:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */
2 /* Copyright (c) Warwick Allison, 1999. */
3 /* NetHack may be freely redistributed. See license for details. */
4 #include "qt_clust.h"
5
6 static
include(QRect & r,const QRect & rect)7 void include(QRect& r, const QRect& rect)
8 {
9 if (rect.left()<r.left()) {
10 r.setLeft(rect.left());
11 }
12 if (rect.right()>r.right()) {
13 r.setRight(rect.right());
14 }
15 if (rect.top()<r.top()) {
16 r.setTop(rect.top());
17 }
18 if (rect.bottom()>r.bottom()) {
19 r.setBottom(rect.bottom());
20 }
21 }
22
23 /*
24 A Clusterizer groups rectangles (QRects) into non-overlapping rectangles
25 by a merging heuristic.
26 */
Clusterizer(int maxclusters)27 Clusterizer::Clusterizer(int maxclusters) :
28 cluster(new QRect[maxclusters]),
29 count(0),
30 max(maxclusters)
31 { }
32
~Clusterizer()33 Clusterizer::~Clusterizer()
34 {
35 delete [] cluster;
36 }
37
clear()38 void Clusterizer::clear()
39 {
40 count=0;
41 }
42
add(int x,int y)43 void Clusterizer::add(int x, int y)
44 {
45 add(QRect(x,y,1,1));
46 }
47
add(int x,int y,int w,int h)48 void Clusterizer::add(int x, int y, int w, int h)
49 {
50 add(QRect(x,y,w,h));
51 }
52
add(const QRect & rect)53 void Clusterizer::add(const QRect& rect)
54 {
55 QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2);
56
57 //assert(rect.width()>0 && rect.height()>0);
58
59 int cursor;
60
61 for (cursor=0; cursor<count; cursor++) {
62 if (cluster[cursor].contains(rect)) {
63 // Wholly contained already.
64 return;
65 }
66 }
67
68 int lowestcost=9999999;
69 int cheapest=-1;
70 for (cursor=0; cursor<count; cursor++) {
71 if (cluster[cursor].intersects(biggerrect)) {
72 QRect larger=cluster[cursor];
73 include(larger,rect);
74 int cost=larger.width()*larger.height()
75 - cluster[cursor].width()*cluster[cursor].height();
76
77 if (cost < lowestcost) {
78 bool bad=FALSE;
79 for (int c=0; c<count && !bad; c++) {
80 bad=cluster[c].intersects(larger) && c!=cursor;
81 }
82 if (!bad) {
83 cheapest=cursor;
84 lowestcost=cost;
85 }
86 }
87 }
88 }
89 if (cheapest>=0) {
90 include(cluster[cheapest],rect);
91 return;
92 }
93
94 if (count < max) {
95 cluster[count++]=rect;
96 return;
97 }
98
99 // Do cheapest of:
100 // add to closest cluster
101 // do cheapest cluster merge, add to new cluster
102
103 lowestcost=9999999;
104 cheapest=-1;
105 for (cursor=0; cursor<count; cursor++) {
106 QRect larger=cluster[cursor];
107 include(larger,rect);
108 int cost=larger.width()*larger.height()
109 - cluster[cursor].width()*cluster[cursor].height();
110 if (cost < lowestcost) {
111 bool bad=FALSE;
112 for (int c=0; c<count && !bad; c++) {
113 bad=cluster[c].intersects(larger) && c!=cursor;
114 }
115 if (!bad) {
116 cheapest=cursor;
117 lowestcost=cost;
118 }
119 }
120 }
121
122 // XXX could make an heuristic guess as to whether we
123 // XXX need to bother looking for a cheap merge.
124
125 int cheapestmerge1=-1;
126 int cheapestmerge2=-1;
127
128 for (int merge1=0; merge1<count; merge1++) {
129 for (int merge2=0; merge2<count; merge2++) {
130 if (merge1!=merge2) {
131 QRect larger=cluster[merge1];
132 include(larger,cluster[merge2]);
133 int cost=larger.width()*larger.height()
134 - cluster[merge1].width()*cluster[merge1].height()
135 - cluster[merge2].width()*cluster[merge2].height();
136 if (cost < lowestcost) {
137 bool bad=FALSE;
138 for (int c=0; c<count && !bad; c++) {
139 bad=cluster[c].intersects(larger) && c!=cursor;
140 }
141 if (!bad) {
142 cheapestmerge1=merge1;
143 cheapestmerge2=merge2;
144 lowestcost=cost;
145 }
146 }
147 }
148 }
149 }
150
151 if (cheapestmerge1>=0) {
152 include(cluster[cheapestmerge1],cluster[cheapestmerge2]);
153 cluster[cheapestmerge2]=cluster[count--];
154 } else {
155 // if (!cheapest) debugRectangles(rect);
156 include(cluster[cheapest],rect);
157 }
158
159 // NB: clusters do not intersect (or intersection will
160 // overwrite). This is a result of the above algorithm,
161 // given the assumption that (x,y) are ordered topleft
162 // to bottomright.
163 }
164
operator [](int i)165 const QRect& Clusterizer::operator[](int i)
166 {
167 return cluster[i];
168 }
169