package edu.byu.cs.roots.opg.chart.presetvertical; import java.util.ArrayList; import java.util.List; /** * Jigsaw spacer for descendents. * */ public class DescSpacer { //private DescTree tree; private final double DEFAULT_VOFFSET = 0; public DescSpacer() { return; } public void space(DescTree tree, int maxGen) { // this.tree = tree; calcCoords(tree.root,Math.abs(maxGen),Math.abs(tree.root.gen.getGenNum())); } /** * Recursively calculates the minimum coordinates for this individual * (and its subtree(s)) based on the minimum font size * * @param options - chart options that contain the minimum font size * @param curGen - current generation of Individual in this DescBox (usually starts as 0) */ private void calcCoords(DescBox b, int maxGen, int curGen) { if (curGen > maxGen) return; //calculate the dimensions for this box b.upperBounds = new ArrayList<Double>(maxGen - curGen); b.lowerBounds = new ArrayList<Double>(maxGen - curGen); //calculate first element of upper bounds array for tight fit double halfHieght = b.getHeight()/2.0; b.upperBounds.add(halfHieght); b.lowerBounds.add(-halfHieght); b.upperSubTreeOffset = halfHieght; b.lowerSubTreeOffset = -halfHieght; b.vOffsets.clear(); if(curGen < maxGen) { for(DescBox child : b.children) { calcCoords(child,maxGen,curGen+1); } //use default offsets if(b.children.size() < 2) { b.vOffsets.add(DEFAULT_VOFFSET); } //calculate distance between children for offsets else { List<Double> childrenOffsets = new ArrayList<Double>(); for(int i=0; i < b.children.size()-1; i++) childrenOffsets.add(calcIntersectDist( b.children.get(i), b.children.get(i+1))); double total = 0; double half = getListSum(childrenOffsets)/2; b.vOffsets.add(half); for(Double d : childrenOffsets) { total += d; b.vOffsets.add(half-total); } } populateBounds(b); updateSubTreeOffsets(b); } } private void updateSubTreeOffsets(DescBox b) { // double usth = 0; // double lsth = 0; // if(!b.children.isEmpty()) { // usth = b.vOffsets.get(0) + b.children.get(0).upperSubTreeOffset; // lsth = b.vOffsets.get(b.vOffsets.size()-1) + b.children.get(b.children.size()-1).lowerSubTreeOffset; // // b.upperSubTreeOffset = Math.max(usth, b.upperSubTreeOffset); // b.lowerSubTreeOffset = Math.min(lsth, b.lowerSubTreeOffset); // } double temp = 0; for(double bound : b.upperBounds) temp = Math.max(temp, bound); b.upperSubTreeOffset = temp; temp = 0; for(double bound : b.lowerBounds) temp = Math.min(temp, bound); b.lowerSubTreeOffset = temp; } private double getListSum(List<Double> list) { double result = 0; for(Double d : list) { result += d; } return result; } private void populateBounds(DescBox b) { //upper int j=0; for (int i=0; i < b.children.size(); i++) { DescBox db = b.children.get(i); for(; j < db.upperBounds.size(); j++) b.addUpperBound(b.vOffsets.get(i) + db.upperBounds.get(j)); } j=0; for (int i=b.children.size()-1; i >= 0; i--) { DescBox db = b.children.get(i); for(; j < db.lowerBounds.size(); j++) b.addLowerBound(b.vOffsets.get(i) + db.lowerBounds.get(j)); } } /** * this method finds the closest distance two individuals (with their subtrees) can be while only touchng at * one point (assuming the bounds for all generations are at different distance) * * @param child1 - the individual on top * @param child2 - the individual on bottom */ public double calcIntersectDist(Box child1, Box child2) { double maxDist = 0; int maxGen = Math.min(child1.upperBounds.size(),child2.upperBounds.size() ); int startGen = 0; //find the max distance between them (the closest they can be while "intesecting" only at one point) for (int i = startGen; i < maxGen; ++i) { double curDist = child2.upperBounds.get(i) - child1.lowerBounds.get(i) + child1.getVerticalSpace(); maxDist = Math.max(curDist, maxDist); } return maxDist; } }