PlaceNode2.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 18k
Category:

Windows Develop

Development Platform:

Java

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