[29] | 1 | /* |
---|
| 2 | * This program is free software; you can redistribute it and/or modify |
---|
| 3 | * it under the terms of the GNU General Public License as published by |
---|
| 4 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 5 | * (at your option) any later version. |
---|
| 6 | * |
---|
| 7 | * This program is distributed in the hope that it will be useful, |
---|
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 10 | * GNU General Public License for more details. |
---|
| 11 | * |
---|
| 12 | * You should have received a copy of the GNU General Public License |
---|
| 13 | * along with this program; if not, write to the Free Software |
---|
| 14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | /* |
---|
| 18 | * PlaceNode2.java |
---|
| 19 | * Copyright (C) 1999 University of Waikato, Hamilton, New Zealand |
---|
| 20 | * |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | package weka.gui.treevisualizer; |
---|
| 24 | |
---|
| 25 | import java.util.*; |
---|
| 26 | |
---|
| 27 | /** |
---|
| 28 | * This class will place the Nodes of a tree. <p> |
---|
| 29 | * |
---|
| 30 | * It will place these nodes so that they fall at evenly below their parent. |
---|
| 31 | * It will then go through and look for places where nodes fall on the wrong |
---|
| 32 | * side of other nodes |
---|
| 33 | * when it finds one it will trace back up the tree to find the first common |
---|
| 34 | * sibling group these two nodes have |
---|
| 35 | * And it will adjust the spacing between these two siblings so that the two |
---|
| 36 | * nodes no longer overlap. |
---|
| 37 | * This is nasty to calculate with , and takes a while with the current |
---|
| 38 | * algorithm I am using to do this.<p> |
---|
| 39 | * |
---|
| 40 | * |
---|
| 41 | * @author Malcolm Ware (mfw4@cs.waikato.ac.nz) |
---|
| 42 | * @version $Revision: 1.4 $ |
---|
| 43 | */ |
---|
| 44 | public class PlaceNode2 implements NodePlace { |
---|
| 45 | /** The space each row will take up. */ |
---|
| 46 | private double m_yRatio; |
---|
| 47 | |
---|
| 48 | /** An array that lists the groups and information about them. */ |
---|
| 49 | private Group[] m_groups; |
---|
| 50 | |
---|
| 51 | /** An array that lists the levels and information about them. */ |
---|
| 52 | private Level[] m_levels; |
---|
| 53 | |
---|
| 54 | /** The Number of groups the tree has */ |
---|
| 55 | private int m_groupNum; |
---|
| 56 | |
---|
| 57 | /** The number of levels the group tree has */ |
---|
| 58 | private int m_levelNum; |
---|
| 59 | |
---|
| 60 | /** |
---|
| 61 | * The Funtion to call to have the nodes arranged. |
---|
| 62 | * |
---|
| 63 | * @param r The top node of the tree to arrange. |
---|
| 64 | */ |
---|
| 65 | public void place(Node r) { |
---|
| 66 | //note i might write count groups into the node class as well as |
---|
| 67 | //it may be useful too; |
---|
| 68 | |
---|
| 69 | m_groupNum = Node.getGCount(r,0); //i could swap over to the node class |
---|
| 70 | //group count,but this works os i'm not gonna |
---|
| 71 | m_groups = new Group[m_groupNum]; |
---|
| 72 | |
---|
| 73 | for (int noa = 0;noa < m_groupNum;noa++) { |
---|
| 74 | m_groups[noa] = new Group(); |
---|
| 75 | m_groups[noa].m_gap = 3; |
---|
| 76 | m_groups[noa].m_start = -1; |
---|
| 77 | } |
---|
| 78 | |
---|
| 79 | groupBuild(r); |
---|
| 80 | m_levelNum = Node.getHeight(r,0); |
---|
| 81 | m_yRatio = 1 / (double)(m_levelNum + 1); |
---|
| 82 | |
---|
| 83 | m_levels = new Level[m_levelNum]; |
---|
| 84 | |
---|
| 85 | for (int noa = 0;noa < m_levelNum;noa++) { |
---|
| 86 | m_levels[noa] = new Level(); |
---|
| 87 | } |
---|
| 88 | r.setTop(m_yRatio); |
---|
| 89 | yPlacer(); |
---|
| 90 | r.setCenter(0); |
---|
| 91 | xPlacer(0); |
---|
| 92 | |
---|
| 93 | |
---|
| 94 | //ok now i just have to untangle then scale down |
---|
| 95 | //note instead of starting with coords between 1 and 0 i will |
---|
| 96 | //use ints then scale them down |
---|
| 97 | //i will scale them down either by all relative to the largest |
---|
| 98 | //line or by each line individually |
---|
| 99 | |
---|
| 100 | untangle2(); |
---|
| 101 | |
---|
| 102 | scaleByMax(); |
---|
| 103 | //scaleByInd(); |
---|
| 104 | } |
---|
| 105 | |
---|
| 106 | |
---|
| 107 | /* |
---|
| 108 | private void thinner() |
---|
| 109 | { |
---|
| 110 | //what this function does is it retains the symmetry of the |
---|
| 111 | // parent node about the children but the children are no longer evenly |
---|
| 112 | //spaced this stops children from being pushed too far to the sides |
---|
| 113 | //,note this algorithm may need the method altered as it may |
---|
| 114 | // require heavy optimisation to go at any decent speed |
---|
| 115 | |
---|
| 116 | Node r,s; |
---|
| 117 | Edge e; |
---|
| 118 | double parent_x; |
---|
| 119 | for (int noa = group_num - 1;noa >= 0;noa--) |
---|
| 120 | { |
---|
| 121 | Vector shifts = new Vector(20,10); |
---|
| 122 | shifts.addElement(0); |
---|
| 123 | int g_num = 0;//this is the offset from groups.m_start to get the right 1 |
---|
| 124 | r = groups[noa].m_p; |
---|
| 125 | parent_x = r.getCenter(); |
---|
| 126 | for (int nob = 1;(e = r.getChild(nob)) != null;nob++) |
---|
| 127 | { |
---|
| 128 | double margin; |
---|
| 129 | s = e.getTarget(); |
---|
| 130 | margin = s_getCenter - r.getChild(nob - 1).getTarget().getCenter-1 |
---|
| 131 | - shift.elementAt(nob-1); |
---|
| 132 | if (margin > 0) |
---|
| 133 | { |
---|
| 134 | margin = check_down(s,g_num,margin); |
---|
| 135 | if (margin > 0) |
---|
| 136 | { |
---|
| 137 | shift.addElement(-margin); |
---|
| 138 | } |
---|
| 139 | else |
---|
| 140 | { |
---|
| 141 | shift.addElement(0); |
---|
| 142 | } |
---|
| 143 | } |
---|
| 144 | else |
---|
| 145 | { |
---|
| 146 | shift.addElement(0); |
---|
| 147 | } |
---|
| 148 | if (s.getChild(0) != null) |
---|
| 149 | { |
---|
| 150 | g_num++; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | } |
---|
| 154 | } |
---|
| 155 | |
---|
| 156 | |
---|
| 157 | private double check_down(Node r,int gn,double m) |
---|
| 158 | { |
---|
| 159 | //note i need to know where the children of the |
---|
| 160 | //other changers are to properly overlap check |
---|
| 161 | //to do this i think the best way is to go up the other group |
---|
| 162 | //parents line and see if it goes through the current group |
---|
| 163 | //this means to save time i need to know the level that is being |
---|
| 164 | //worked with along with the group |
---|
| 165 | |
---|
| 166 | Edge e; |
---|
| 167 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) |
---|
| 168 | { |
---|
| 169 | |
---|
| 170 | } |
---|
| 171 | } |
---|
| 172 | */ |
---|
| 173 | |
---|
| 174 | |
---|
| 175 | /** |
---|
| 176 | * This will set initial places for the x coord of the nodes. |
---|
| 177 | * @param start The `number for the first group to start on (I think). |
---|
| 178 | */ |
---|
| 179 | private void xPlacer(int start) { |
---|
| 180 | //this can be one of a few x_placers (the first) |
---|
| 181 | //it will work by placing 1 space inbetween each node |
---|
| 182 | //ie the first at 0 the second at 1 and so on |
---|
| 183 | //then it will add to this value the place of the parent |
---|
| 184 | //node - half of the size |
---|
| 185 | //i will break this up into several functions |
---|
| 186 | //first the gap setter; |
---|
| 187 | //then the shifter |
---|
| 188 | //it will require a vector shift function added to the node class |
---|
| 189 | //i will write an additional shifter for the untangler |
---|
| 190 | //for its particular situation |
---|
| 191 | |
---|
| 192 | Node r; |
---|
| 193 | Edge e; |
---|
| 194 | if (m_groupNum > 0) { |
---|
| 195 | m_groups[0].m_p.setCenter(0); |
---|
| 196 | for (int noa = start;noa < m_groupNum;noa++) { |
---|
| 197 | int nob,alter =0; |
---|
| 198 | double c = m_groups[noa].m_gap; |
---|
| 199 | r = m_groups[noa].m_p; |
---|
| 200 | for (nob = 0;(e = r.getChild(nob)) != null;nob++) { |
---|
| 201 | if (e.getTarget().getParent(0) == e) { |
---|
| 202 | e.getTarget().setCenter(nob * c); |
---|
| 203 | } |
---|
| 204 | else { |
---|
| 205 | alter++; |
---|
| 206 | } |
---|
| 207 | } |
---|
| 208 | m_groups[noa].m_size = (nob - 1 - alter) * c; |
---|
| 209 | xShift(noa); |
---|
| 210 | } |
---|
| 211 | } |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | /** |
---|
| 215 | * This will shift a group of nodes to be aligned under their parent. |
---|
| 216 | * @param n The group number to shift |
---|
| 217 | */ |
---|
| 218 | private void xShift(int n) { |
---|
| 219 | Edge e; |
---|
| 220 | Node r = m_groups[n].m_p; |
---|
| 221 | double h = m_groups[n].m_size / 2; |
---|
| 222 | double c = m_groups[n].m_p.getCenter(); |
---|
| 223 | double m = c - h; |
---|
| 224 | m_groups[n].m_left = m; |
---|
| 225 | m_groups[n].m_right = c + h; |
---|
| 226 | |
---|
| 227 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 228 | if (e.getTarget().getParent(0) == e) { |
---|
| 229 | e.getTarget().adjustCenter(m); |
---|
| 230 | } |
---|
| 231 | } |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | /** |
---|
| 235 | * This scales all the x values to be between 0 and 1. |
---|
| 236 | */ |
---|
| 237 | private void scaleByMax() { |
---|
| 238 | //ammendment to what i may have commented before |
---|
| 239 | //this takes the lowest x and highest x and uses that as the scaling |
---|
| 240 | //factor |
---|
| 241 | double l_x = 5000,h_x = -5000; |
---|
| 242 | for (int noa = 0;noa < m_groupNum;noa++) { |
---|
| 243 | if (l_x > m_groups[noa].m_left) { |
---|
| 244 | l_x = m_groups[noa].m_left; |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | if (h_x < m_groups[noa].m_right) { |
---|
| 248 | h_x = m_groups[noa].m_right; |
---|
| 249 | } |
---|
| 250 | } |
---|
| 251 | |
---|
| 252 | Edge e; |
---|
| 253 | Node r,s; |
---|
| 254 | double m_scale = h_x - l_x + 1; |
---|
| 255 | if (m_groupNum > 0) { |
---|
| 256 | r = m_groups[0].m_p; |
---|
| 257 | r.setCenter((r.getCenter() - l_x) / m_scale); |
---|
| 258 | //System.out.println("from scaler " + l_x + " " + m_scale); |
---|
| 259 | for (int noa = 0; noa < m_groupNum;noa++) { |
---|
| 260 | r = m_groups[noa].m_p; |
---|
| 261 | for (int nob = 0;(e = r.getChild(nob)) != null;nob++) { |
---|
| 262 | s = e.getTarget(); |
---|
| 263 | if (s.getParent(0) == e) { |
---|
| 264 | s.setCenter((s.getCenter() - l_x) / m_scale); |
---|
| 265 | } |
---|
| 266 | } |
---|
| 267 | } |
---|
| 268 | } |
---|
| 269 | } |
---|
| 270 | |
---|
| 271 | /** |
---|
| 272 | * This scales the x values to between 0 and 1 for each individual line |
---|
| 273 | * rather than doing them all at once. |
---|
| 274 | */ |
---|
| 275 | private void scaleByInd() { |
---|
| 276 | //ammendment to what i may have commented before |
---|
| 277 | //this takes the lowest x and highest x on each line and uses that for |
---|
| 278 | //the line in question |
---|
| 279 | double l_x,h_x; |
---|
| 280 | |
---|
| 281 | Edge e; |
---|
| 282 | Node r,s; |
---|
| 283 | r = m_groups[0].m_p; |
---|
| 284 | r.setCenter(.5); |
---|
| 285 | double m_scale; |
---|
| 286 | for (int noa = 0;noa < m_levelNum;noa++) { |
---|
| 287 | l_x = m_groups[m_levels[noa].m_start].m_left; |
---|
| 288 | h_x = m_groups[m_levels[noa].m_end].m_right; |
---|
| 289 | m_scale = h_x - l_x + 1; |
---|
| 290 | for (int nob = m_levels[noa].m_start; nob <= m_levels[noa].m_end;nob++) { |
---|
| 291 | r = m_groups[nob].m_p; |
---|
| 292 | for (int noc = 0;(e = r.getChild(noc)) != null;noc++) { |
---|
| 293 | s = e.getTarget(); |
---|
| 294 | if (s.getParent(0) == e) { |
---|
| 295 | s.setCenter((s.getCenter() - l_x) / m_scale); |
---|
| 296 | } |
---|
| 297 | } |
---|
| 298 | } |
---|
| 299 | } |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | /** |
---|
| 303 | * This untangles the nodes so that they will will fall on the correct |
---|
| 304 | * side of the other nodes along their row. |
---|
| 305 | */ |
---|
| 306 | private void untangle2() { |
---|
| 307 | Ease a; |
---|
| 308 | Edge e; |
---|
| 309 | Node r,nf = null,ns = null,mark; |
---|
| 310 | int l = 0,times = 0; |
---|
| 311 | int f,s,tf = 0,ts = 0,pf,ps; |
---|
| 312 | while ((a = overlap(l)) != null) { |
---|
| 313 | times++; |
---|
| 314 | //System.out.println("from untang 2 " + group_num); |
---|
| 315 | f = a.m_place; |
---|
| 316 | s = a.m_place + 1; |
---|
| 317 | while (f != s) { |
---|
| 318 | a.m_lev--; |
---|
| 319 | tf = f; |
---|
| 320 | ts = s; |
---|
| 321 | f = m_groups[f].m_pg; |
---|
| 322 | s = m_groups[s].m_pg; |
---|
| 323 | } |
---|
| 324 | l = a.m_lev; |
---|
| 325 | pf = 0; |
---|
| 326 | ps = 0; |
---|
| 327 | r = m_groups[f].m_p; |
---|
| 328 | mark = m_groups[tf].m_p; |
---|
| 329 | nf = null; |
---|
| 330 | ns = null; |
---|
| 331 | for (int noa = 0; nf != mark;noa++) { |
---|
| 332 | pf++; |
---|
| 333 | nf = r.getChild(noa).getTarget(); |
---|
| 334 | } |
---|
| 335 | mark = m_groups[ts].m_p; |
---|
| 336 | for (int noa = pf; ns != mark;noa++) { |
---|
| 337 | ps++; //the number of gaps between the two nodes |
---|
| 338 | ns = r.getChild(noa).getTarget(); |
---|
| 339 | } |
---|
| 340 | //m_groups[f].gap = |
---|
| 341 | // Math.ceil((a.amount / (double)ps) + m_groups[f].gap); |
---|
| 342 | //note for this method i do not need the group gap ,but i will leave |
---|
| 343 | //it for the other methods; |
---|
| 344 | Vector o_pos = new Vector(20,10); |
---|
| 345 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 346 | if (e.getTarget().getParent(0) == e) { |
---|
| 347 | Double tem = new Double(e.getTarget().getCenter()); |
---|
| 348 | o_pos.addElement(tem); |
---|
| 349 | } |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | pf--; |
---|
| 353 | double inc = a.m_amount / (double)ps; |
---|
| 354 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 355 | ns = e.getTarget(); |
---|
| 356 | if (ns.getParent(0) == e) { |
---|
| 357 | if (noa > pf + ps) { |
---|
| 358 | ns.adjustCenter(a.m_amount); |
---|
| 359 | } |
---|
| 360 | else if (noa > pf) { |
---|
| 361 | ns.adjustCenter(inc * (double)(noa - pf)); |
---|
| 362 | } |
---|
| 363 | } |
---|
| 364 | } |
---|
| 365 | |
---|
| 366 | nf = r.getChild(0).getTarget(); |
---|
| 367 | inc = ns.getCenter() - nf.getCenter(); |
---|
| 368 | m_groups[f].m_size = inc; |
---|
| 369 | m_groups[f].m_left = r.getCenter() - inc / 2; |
---|
| 370 | m_groups[f].m_right = m_groups[f].m_left + inc; |
---|
| 371 | inc = m_groups[f].m_left - nf.getCenter(); |
---|
| 372 | |
---|
| 373 | double shift; |
---|
| 374 | int g_num = 0; |
---|
| 375 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 376 | ns = e.getTarget(); |
---|
| 377 | if (ns.getParent(0) == e) { |
---|
| 378 | ns.adjustCenter(inc); |
---|
| 379 | shift = ns.getCenter() - |
---|
| 380 | ((Double)o_pos.elementAt(noa)).doubleValue(); |
---|
| 381 | if (ns.getChild(0) != null) { |
---|
| 382 | moveSubtree(m_groups[f].m_start + g_num,shift); |
---|
| 383 | g_num++; |
---|
| 384 | } |
---|
| 385 | } |
---|
| 386 | //ns.adjustCenter(-shift); |
---|
| 387 | } |
---|
| 388 | //zero_offset(r); |
---|
| 389 | |
---|
| 390 | //x_placer(f); |
---|
| 391 | } |
---|
| 392 | } |
---|
| 393 | |
---|
| 394 | |
---|
| 395 | /** |
---|
| 396 | * This will recursively shift a sub there to be centered about |
---|
| 397 | * a particular value. |
---|
| 398 | * @param n The first group in the sub tree. |
---|
| 399 | * @param o The point to start shifting the subtree. |
---|
| 400 | */ |
---|
| 401 | private void moveSubtree(int n,double o) { |
---|
| 402 | Edge e; |
---|
| 403 | Node r = m_groups[n].m_p; |
---|
| 404 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 405 | if (e.getTarget().getParent(0) == e) { |
---|
| 406 | e.getTarget().adjustCenter(o); |
---|
| 407 | } |
---|
| 408 | } |
---|
| 409 | m_groups[n].m_left += o; |
---|
| 410 | m_groups[n].m_right += o; |
---|
| 411 | if (m_groups[n].m_start != -1) { |
---|
| 412 | for (int noa = m_groups[n].m_start;noa <= m_groups[n].m_end;noa++) { |
---|
| 413 | moveSubtree(noa,o); |
---|
| 414 | } |
---|
| 415 | } |
---|
| 416 | } |
---|
| 417 | |
---|
| 418 | |
---|
| 419 | /** |
---|
| 420 | * This will untangle the nodes in the tree so that they fall on the |
---|
| 421 | * correct side of each other. |
---|
| 422 | */ |
---|
| 423 | private void untangle() { |
---|
| 424 | Ease a; |
---|
| 425 | Edge e; |
---|
| 426 | Node r,nf = null,ns = null,mark; |
---|
| 427 | int l = 0,times = 0; |
---|
| 428 | int f,s,tf = 0,ts = 0,pf,ps; |
---|
| 429 | while ((a = overlap(l)) != null) { |
---|
| 430 | times++; |
---|
| 431 | //System.out.println(group_num); |
---|
| 432 | f = a.m_place; |
---|
| 433 | s = a.m_place + 1; |
---|
| 434 | while (f != s) { |
---|
| 435 | a.m_lev--; |
---|
| 436 | tf = f; |
---|
| 437 | ts = s; |
---|
| 438 | f = m_groups[f].m_pg; |
---|
| 439 | s = m_groups[s].m_pg; |
---|
| 440 | } |
---|
| 441 | l = a.m_lev; |
---|
| 442 | pf = 0; |
---|
| 443 | ps = 0; |
---|
| 444 | r = m_groups[f].m_p; |
---|
| 445 | mark = m_groups[tf].m_p; |
---|
| 446 | nf = null; |
---|
| 447 | ns = null; |
---|
| 448 | for (int noa = 0; nf != mark;noa++) { |
---|
| 449 | pf++; |
---|
| 450 | nf = r.getChild(noa).getTarget(); |
---|
| 451 | } |
---|
| 452 | mark = m_groups[ts].m_p; |
---|
| 453 | for (int noa = pf; ns != mark;noa++) { |
---|
| 454 | ps++; //the number of gaps between the two nodes |
---|
| 455 | ns = r.getChild(noa).getTarget(); |
---|
| 456 | } |
---|
| 457 | m_groups[f].m_gap = |
---|
| 458 | Math.ceil((a.m_amount / (double)ps) + m_groups[f].m_gap); |
---|
| 459 | |
---|
| 460 | xPlacer(f); |
---|
| 461 | } |
---|
| 462 | } |
---|
| 463 | |
---|
| 464 | /** |
---|
| 465 | * This will find an overlap and then return information about that overlap |
---|
| 466 | * @param l The level to start on. |
---|
| 467 | * @return null if there was no overlap , otherwise an object containing |
---|
| 468 | * the group number that overlaps (only need one) how much they overlap by, |
---|
| 469 | * and the level they overlap on. |
---|
| 470 | */ |
---|
| 471 | private Ease overlap(int l) { |
---|
| 472 | Ease a = new Ease(); |
---|
| 473 | for (int noa = l;noa < m_levelNum;noa++) { |
---|
| 474 | for (int nob = m_levels[noa].m_start;nob < m_levels[noa].m_end;nob++) { |
---|
| 475 | a.m_amount = m_groups[nob].m_right - m_groups[nob+1].m_left + 2; |
---|
| 476 | //System.out.println(m_groups[nob].m_right + " + " + |
---|
| 477 | // m_groups[nob+1].m_left + " = " + a.amount); |
---|
| 478 | if (a.m_amount >= 0) { |
---|
| 479 | a.m_amount++; |
---|
| 480 | a.m_lev = noa; |
---|
| 481 | a.m_place = nob; |
---|
| 482 | return a; |
---|
| 483 | } |
---|
| 484 | } |
---|
| 485 | } |
---|
| 486 | return null; |
---|
| 487 | } |
---|
| 488 | |
---|
| 489 | /* private int count_m_groups(Node r,int l) |
---|
| 490 | { |
---|
| 491 | Edge e; |
---|
| 492 | if (r.getChild(0) != null) |
---|
| 493 | { |
---|
| 494 | l++; |
---|
| 495 | } |
---|
| 496 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) |
---|
| 497 | { |
---|
| 498 | l = count_groups(e.getTarget(),l); |
---|
| 499 | } |
---|
| 500 | |
---|
| 501 | return l; |
---|
| 502 | } |
---|
| 503 | */ |
---|
| 504 | |
---|
| 505 | /** |
---|
| 506 | * This function sets up the height of each node, and also fills the |
---|
| 507 | * levels array with information about what the start and end groups on that |
---|
| 508 | * level are. |
---|
| 509 | */ |
---|
| 510 | private void yPlacer() { |
---|
| 511 | //note this places the y height and sets up the levels array |
---|
| 512 | double changer = m_yRatio; |
---|
| 513 | int lev_place = 0; |
---|
| 514 | if (m_groupNum > 0) { |
---|
| 515 | m_groups[0].m_p.setTop(m_yRatio); |
---|
| 516 | m_levels[0].m_start = 0; |
---|
| 517 | |
---|
| 518 | for (int noa = 0;noa < m_groupNum;noa++) { |
---|
| 519 | if (m_groups[noa].m_p.getTop() != changer) { |
---|
| 520 | m_levels[lev_place].m_end = noa - 1; |
---|
| 521 | lev_place++; |
---|
| 522 | m_levels[lev_place].m_start = noa; |
---|
| 523 | changer = m_groups[noa].m_p.getTop(); |
---|
| 524 | } |
---|
| 525 | nodeY(m_groups[noa].m_p); |
---|
| 526 | } |
---|
| 527 | m_levels[lev_place].m_end = m_groupNum - 1; |
---|
| 528 | } |
---|
| 529 | } |
---|
| 530 | |
---|
| 531 | /** |
---|
| 532 | * This will set all of the children node of a particular node to their |
---|
| 533 | * height. |
---|
| 534 | * @param r The parent node of the children to set their height. |
---|
| 535 | */ |
---|
| 536 | private void nodeY(Node r) { |
---|
| 537 | Edge e; |
---|
| 538 | double h = r.getTop() + m_yRatio; |
---|
| 539 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 540 | if (e.getTarget().getParent(0) == e) { |
---|
| 541 | e.getTarget().setTop(h); |
---|
| 542 | if (!e.getTarget().getVisible()) { |
---|
| 543 | //System.out.println("oh bugger"); |
---|
| 544 | } |
---|
| 545 | } |
---|
| 546 | } |
---|
| 547 | } |
---|
| 548 | |
---|
| 549 | /** |
---|
| 550 | * This starts to create the information about the sibling groups. |
---|
| 551 | * As more groups are created the for loop in this will check those groups |
---|
| 552 | * for lower groups. |
---|
| 553 | * @param r The top node. |
---|
| 554 | */ |
---|
| 555 | private void groupBuild(Node r) { |
---|
| 556 | if (m_groupNum > 0) { |
---|
| 557 | m_groupNum = 0; |
---|
| 558 | m_groups[0].m_p = r; |
---|
| 559 | m_groupNum++; |
---|
| 560 | //note i need to count up the num of groups first |
---|
| 561 | //woe is me |
---|
| 562 | for (int noa = 0;noa < m_groupNum ;noa++) { |
---|
| 563 | groupFind(m_groups[noa].m_p,noa); |
---|
| 564 | } |
---|
| 565 | } |
---|
| 566 | } |
---|
| 567 | |
---|
| 568 | /** |
---|
| 569 | * This is called to build the rest of the grouping information. |
---|
| 570 | * @param r The parent of the group. |
---|
| 571 | * @param pg The number for the parents group. |
---|
| 572 | */ |
---|
| 573 | private void groupFind(Node r,int pg) { |
---|
| 574 | Edge e; |
---|
| 575 | boolean first = true; |
---|
| 576 | for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { |
---|
| 577 | if (e.getTarget().getParent(0) == e) { |
---|
| 578 | if (e.getTarget().getChild(0) != null && e.getTarget().getCVisible()) { |
---|
| 579 | if (first) { |
---|
| 580 | m_groups[pg].m_start = m_groupNum; |
---|
| 581 | first = false; |
---|
| 582 | } |
---|
| 583 | m_groups[pg].m_end = m_groupNum; |
---|
| 584 | m_groups[m_groupNum].m_p = e.getTarget(); |
---|
| 585 | m_groups[m_groupNum].m_pg = pg; |
---|
| 586 | m_groups[m_groupNum].m_id = m_groupNum; //just in case I ever need |
---|
| 587 | //this info |
---|
| 588 | m_groupNum++; |
---|
| 589 | } |
---|
| 590 | } |
---|
| 591 | } |
---|
| 592 | } |
---|
| 593 | |
---|
| 594 | |
---|
| 595 | //note these three classes are only to help organise the data and are |
---|
| 596 | //inter related between each other and this placer class |
---|
| 597 | //so don't mess with them or try to use them somewhere else |
---|
| 598 | //(because that would be a mistake and I would pity you) |
---|
| 599 | |
---|
| 600 | |
---|
| 601 | /** |
---|
| 602 | * Inner class for containing the level data. |
---|
| 603 | */ |
---|
| 604 | private class Level { |
---|
| 605 | /** The number for the group on the left of this level. */ |
---|
| 606 | public int m_start; |
---|
| 607 | /** The number for the group on the right of this level. */ |
---|
| 608 | public int m_end; |
---|
| 609 | |
---|
| 610 | /** These two params would appear to not be used. */ |
---|
| 611 | public int m_left; |
---|
| 612 | public int m_right; |
---|
| 613 | } |
---|
| 614 | |
---|
| 615 | /** |
---|
| 616 | * Inner class for containing the grouping data. |
---|
| 617 | */ |
---|
| 618 | private class Group { |
---|
| 619 | /** The parent node of this group. */ |
---|
| 620 | public Node m_p; |
---|
| 621 | |
---|
| 622 | /** The group number for the parent of this group. */ |
---|
| 623 | public int m_pg; |
---|
| 624 | |
---|
| 625 | /** The gap size for the distance between the nodes in this group. */ |
---|
| 626 | public double m_gap; |
---|
| 627 | |
---|
| 628 | /** The leftmost position of this group. */ |
---|
| 629 | public double m_left; |
---|
| 630 | |
---|
| 631 | /** The rightmost position of this group. */ |
---|
| 632 | public double m_right; |
---|
| 633 | |
---|
| 634 | /** The size of this group. */ |
---|
| 635 | public double m_size; |
---|
| 636 | |
---|
| 637 | /** The start node of this group. */ |
---|
| 638 | public int m_start; |
---|
| 639 | |
---|
| 640 | /** The end node of this group. */ |
---|
| 641 | public int m_end; |
---|
| 642 | |
---|
| 643 | /** The group number for this group. (may not be used!?). */ |
---|
| 644 | public int m_id; |
---|
| 645 | } |
---|
| 646 | |
---|
| 647 | /** |
---|
| 648 | * An inner class used to report information about any tangles found. |
---|
| 649 | */ |
---|
| 650 | private class Ease { |
---|
| 651 | /** The number of the group on the left of the tangle. */ |
---|
| 652 | public int m_place; |
---|
| 653 | /** The distance they were tangled. */ |
---|
| 654 | public double m_amount; |
---|
| 655 | /** The level on which they were tangled. */ |
---|
| 656 | public int m_lev; |
---|
| 657 | } |
---|
| 658 | } |
---|
| 659 | |
---|
| 660 | |
---|
| 661 | |
---|
| 662 | |
---|
| 663 | |
---|
| 664 | |
---|
| 665 | |
---|
| 666 | |
---|
| 667 | |
---|
| 668 | |
---|
| 669 | |
---|
| 670 | |
---|
| 671 | |
---|
| 672 | |
---|