00001
00002
00003
00004
00005
00006 extern "C" {
00007 #include <assert.h>
00008 }
00009
00010 #include <cmath>
00011
00012 #include "split.h"
00013
00014 #include "frame.h"
00015 #include "logger.h"
00016 #include "rectangle.h"
00017 #include "tree.h"
00018 #include "util.h"
00019
00020 Tree *Split::topMostRoot(Tree *first, Tree *last) {
00021
00022 assert(first);
00023 assert(last);
00024
00025 Tree *tmp = first;
00026 while (tmp->parent()) {
00027 tmp = tmp->parent();
00028 tmp->setVisit(tmp->visits() + 1);
00029 }
00030
00031 tmp = last;
00032 while (tmp->parent()) {
00033 tmp = tmp->parent();
00034 tmp->setVisit(tmp->visits() + 1);
00035 }
00036
00037
00038
00039
00040
00041 Tree *result = first;
00042 while (result->visits() < 2) {
00043 result = result->parent();
00044 }
00045
00046
00047 tmp = first;
00048 while (tmp->parent()) {
00049 tmp = tmp->parent();
00050 tmp->setVisit(0);
00051 }
00052
00053 tmp = last;
00054 while (tmp->parent()) {
00055 tmp = tmp->parent();
00056 tmp->setVisit(0);
00057 }
00058
00059 return result;
00060 }
00061
00062
00063 void Split::resize(Tree *root, Tree *origin,
00064 Direction dir, int stepW, int stepH)
00065 {
00066 int newW, newH;
00067
00068 if (!origin->frame()) {
00069 return;
00070 }
00071
00072 Tree *neighbor = Split::neighbor(root, origin, dir);
00073 if (!neighbor|| !neighbor->parent()) {
00074 return;
00075 }
00076
00077
00078
00079
00080 if(0 > stepH || 0 > stepW) {
00081 stepH *= -1;
00082 stepW *= -1;
00083
00084 switch(dir) {
00085 case LEFT: dir = RIGHT; break;
00086 case RIGHT: dir = LEFT; break;
00087 case UP: dir = DOWN; break;
00088 case DOWN: dir = UP; break;
00089 default: break;
00090 }
00091 }
00092
00093
00094
00095
00096 Tree *parent = topMostRoot(origin, neighbor);
00097
00098
00099
00100 Tree *growTree, *shrinkTree;
00101 if ((dir == LEFT) || (dir == UP)) {
00102
00103 growTree = parent->last();
00104 shrinkTree = parent->first();
00105 }
00106 else {
00107
00108 growTree = parent->first();
00109 shrinkTree = parent->last();
00110 }
00111
00112 switch (dir) {
00113 case LEFT:
00114 newW = shrinkTree->width() - stepW;
00115 if (0 >= newW) {
00116 return;
00117 }
00118 growTree->setX(growTree->x() - stepW);
00119 growTree->setWidth(growTree->width() + stepW);
00120 shrinkTree->setWidth(newW);
00121 break;
00122 case RIGHT:
00123 newW = shrinkTree->width() - stepW;
00124 if (0 >= newW) {
00125 return;
00126 }
00127 growTree->setWidth(growTree->width() + stepW);
00128 shrinkTree->setX(shrinkTree->x() + stepW);
00129 shrinkTree->setWidth(newW);
00130 break;
00131 case UP:
00132 newH = shrinkTree->height() - stepH;
00133 if (0 >= newH) {
00134 return;
00135 }
00136 growTree->setY(growTree->y() - stepH);
00137 growTree->setHeight(growTree->height() + stepH);
00138 shrinkTree->setHeight(newH);
00139 break;
00140 case DOWN:
00141 newH = shrinkTree->height() - stepH;
00142 if(0 >= newH) {
00143 return;
00144 }
00145 growTree->setHeight(growTree->height() + stepH);
00146 shrinkTree->setY(shrinkTree->y() + stepH);
00147 shrinkTree->setHeight(newH);
00148 break;
00149 default:
00150 break;
00151 }
00152 adjustSize(growTree, ((dir == LEFT) || (dir == RIGHT)));
00153 adjustSize(shrinkTree, ((dir == LEFT) || (dir == RIGHT)));
00154 }
00155
00156 int Split::distance(Tree *origin, Tree *target) {
00157
00158 int ox = origin->x() + origin->width() / 2;
00159 int oy = origin->y() + origin->height() / 2;
00160 int tx = target->x() + target->width() / 2;
00161 int ty = target->y() + target->height() / 2;
00162
00163 return (int)sqrt((double)(((ox - tx) * (ox - tx)) +
00164 ((oy - ty) * (oy - ty))));
00165 }
00166
00167 bool Split::isNeighbor(Tree *origin, Tree *target, Direction dir) {
00168
00169 switch (dir) {
00170 case LEFT:
00171 return origin->x() >= (int)(target->x() + target->width());
00172 break;
00173 case RIGHT:
00174 return (int)(origin->x() + origin->width()) <= target->x();
00175 break;
00176 case UP:
00177 return origin->y() >= (int)(target->y() + target->height());
00178 break;
00179 case DOWN:
00180 return (int)(origin->y() + origin->height()) <= target->y();
00181 break;
00182 default:
00183 return false;
00184 break;
00185 }
00186 }
00187
00188 Tree *Split::neighbor(Tree *root, Tree *origin, Direction dir) {
00189
00190 if (root == 0) {
00191 return 0;
00192 }
00193
00194 Tree *result1 = neighbor(root->first(), origin, dir);
00195 if (!result1 && root->first()) {
00196 result1 = root->first();
00197 }
00198
00199 Tree *result2 = neighbor(root->last(), origin, dir);
00200 if (!result2 && root->last()) {
00201 result2 = root->last();
00202 }
00203
00204 bool res1 = result1 && (result1 != origin)
00205 && isNeighbor(origin, result1, dir);
00206 bool res2 = result2 && (result2 != origin)
00207 && isNeighbor(origin, result2, dir);
00208
00209 if (res1 && res2) {
00210
00211 if (distance(origin, result1)
00212 < distance(origin, result2))
00213 {
00214 return result1;
00215 }
00216 else {
00217 return result2;
00218 }
00219 }
00220 else if (res1) {
00221 return result1;
00222 }
00223 else if (res2) {
00224 return result2;
00225 }
00226
00227 return 0;
00228 }
00229
00230 void Split::adjustSize(Tree *tree, bool ignoreVert) {
00231
00232 Tree *first = tree->first();
00233 Tree *last = tree->last();
00234 if (first) {
00235 assert(last);
00236 if (tree->isHoriz()) {
00237
00238 if (ignoreVert) {
00239 first->copy(tree);
00240 first->setWidth(tree->width() / 2);
00241 last->copy(first);
00242 last->setX(first->x() + first->width());
00243 }
00244 else {
00245
00246 first->setY(tree->y());
00247 first->setHeight(tree->height());
00248 last->setY(tree->y());
00249 last->setHeight(tree->height());
00250 }
00251 }
00252 else {
00253
00254 if (!ignoreVert) {
00255 first->copy(tree);
00256 first->setHeight(tree->height() / 2);
00257 last->copy(first);
00258 last->setY(first->y() + first->height());
00259 }
00260 else {
00261
00262 first->setX(tree->x());
00263 first->setWidth(tree->width());
00264 last->setX(tree->x());
00265 last->setWidth(tree->width());
00266 }
00267 }
00268 adjustSize(first, ignoreVert);
00269 adjustSize(last, ignoreVert);
00270 }
00271 else {
00272 Frame *frame = tree->frame();
00273 if (frame) {
00274 frame->copy(tree);
00275 frame->resize();
00276 }
00277 }
00278 }
00279
00280 void Split::detach(Tree *root, Tree *origin) {
00281
00282 Tree *parent = origin->parent();
00283
00284 if (parent) {
00285 Tree *child = (parent->first() != origin)
00286 ? parent->first() : parent->last();
00287 delete origin;
00288 assert(child);
00289 if (child->first()) {
00290 assert(child->last());
00291 assert(!child->frame());
00292 parent->setChilds(child->first(), child->last());
00293 parent->setHoriz(child->isHoriz());
00294 adjustSize(parent, parent->isHoriz());
00295 delete child;
00296 }
00297 else {
00298 Frame *frame = child->frame();
00299 assert(frame);
00300 parent->setFrame(frame);
00301 parent->setChilds(0, 0);
00302 frame->resize();
00303 delete child;
00304 }
00305 }
00306 else {
00307 assert(origin == root);
00308 root->setFrame(0);
00309 }
00310 }
00311
00312 Frame *Split::firstLeaf(Tree *tree) {
00313
00314 if (tree->frame()) {
00315 return tree->frame();
00316 }
00317 if (tree->first() && tree->first()->frame()) {
00318 return tree->first()->frame();
00319 }
00320 if (tree->last() && tree->last()->frame()) {
00321 return tree->last()->frame();
00322 }
00323 if (tree->first()) {
00324 return firstLeaf(tree->first());
00325 }
00326 else if (tree->last()) {
00327 return firstLeaf(tree->last());
00328 }
00329 return 0;
00330 }
00331
00332 void Split::attach(Tree *root, Frame *frame, Direction dir) {
00333
00334 Rectangle rect;
00335 assert(root->first() == 0);
00336
00337 Frame *oldFrame = root->frame();
00338 if (!oldFrame) {
00339 root->setFrame(frame);
00340 }
00341 else {
00342 root->setFrame(0);
00343 rect.copy(root);
00344
00345 if ((dir == LEFT) || (dir == RIGHT)) {
00346 root->setHoriz(true);
00347 rect.setWidth(rect.width() / 2);
00348 }
00349 else {
00350 root->setHoriz(false);
00351 rect.setHeight(rect.height() / 2);
00352 }
00353
00354 Tree *first = new Tree(root, &rect);
00355 Tree *last;
00356 if ((dir == LEFT) || (dir == UP)) {
00357 first->setFrame(frame);
00358 if (dir == LEFT) {
00359 rect.setX(rect.x() + rect.width());
00360 }
00361 else {
00362 rect.setY(rect.y() + rect.height());
00363 }
00364 last = new Tree(root, &rect);
00365 last->setFrame(oldFrame);
00366 }
00367 else {
00368 first->setFrame(oldFrame);
00369 if (dir == RIGHT) {
00370 rect.setX(rect.x() + rect.width());
00371 }
00372 else {
00373 rect.setY(rect.y() + rect.height());
00374 }
00375 last = new Tree(root, &rect);
00376 last->setFrame(frame);
00377 }
00378 root->setChilds(first, last);
00379 oldFrame->resize();
00380 }
00381 frame->resize();
00382 }