package edu.byu.cs.roots.opg.chart.presetvertical; import java.util.ArrayList; /** * This is a class that is used to space a AncessTree. This if done by setting * the parent vertical offsets for each AncesBox in the tree. * */ public class AncesSpacer { private AncesTree tree; private final double DEFAULT_VOFFSET = 3; public AncesSpacer() { return; } /** * Space an AncesTree * @param tree AncesTree to space * @param maxGen max generation to space */ public void space(AncesTree tree, int maxGen) { this.tree = tree; calcCoords((AncesBox)tree.root,maxGen,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 AncesBox (usually starts as 0) * @param duplicateMap */ void calcCoords(AncesBox 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; //Tight fit (jigsaw puzzle like) intersection //calculate the distances between each of the parents by intersecting their subtrees if(curGen < maxGen) { //recursively expand parents if (b.father != null) calcCoords((AncesBox)b.father,maxGen, curGen+1); if (b.mother != null) calcCoords((AncesBox)b.mother,maxGen, curGen+1); double[] dist = findOffsets(b); b.setParentOffsets(dist[0], dist[1]); populateBounds(b); } } /** * Calcuates the upper and lower subtree bounds for a given AncesBox. */ private void populateBounds(AncesBox b) { //upper int i=0; if(b.father != null) for (; i < b.father.upperBounds.size(); ++i) { b.addUpperBound(b.fatherVOffset + b.father.upperBounds.get(i)); } if(b.mother != null) for ( ; i < b.mother.upperBounds.size(); ++i) { b.addUpperBound(b.motherVOffset + b.mother.upperBounds.get(i)); } //lower int k=0; if(b.mother != null) for (; k < b.mother.lowerBounds.size(); ++k) { b.addLowerBound(b.motherVOffset + b.mother.lowerBounds.get(k)); } if(b.father != null) for ( ; k < b.father.lowerBounds.size(); ++k){ b.addLowerBound(b.fatherVOffset + b.father.lowerBounds.get(k)); } } /** * 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 distances) * * @param child box to find offsets for */ // private double[] findOffsets(AncesBox child) // { // AncesBox father = child.father; // AncesBox mother = child.mother; // boolean intrude = child.gen.getWidth() < child.getWidth(); // // //if child doesn't have both parents // if(father == null || mother == null) { // double parentHeight = 0; // if(father != null) { // parentHeight = father.getHeight(); // child.upperBounds.set(0, parentHeight + child.getVerticalSpace()); // } // else if(mother != null) { // parentHeight = mother.getHeight(); // child.lowerBounds.set(0, -parentHeight - child.getVerticalSpace()); // } // // if(intrude) { // double dist = child.getHeight() + parentHeight + child.getVerticalSpace()*2; // return new double[] {dist/2.0,dist/2.0}; // } // else // return new double[] {DEFAULT_VOFFSET,DEFAULT_VOFFSET}; // } // // //if child has both parents // double maxDist = 0; //represents mother offset + father offset // int maxGen = Math.min(father.lowerBounds.size(),mother.upperBounds.size()); //determines how far to compare // // //find the max distance between them (the closest they can be while "intersecting" only at one point) // for (int i = 0; i < maxGen; ++i) { // // double curDist = mother.upperBounds.get(i) - father.lowerBounds.get(i) + father.getVerticalSpace(); // maxDist = Math.max(curDist, maxDist); // } // // int genBase = child.gen.getGenNum(); //used to index into generation array // if(genBase < 0) genBase = 0; //make sure its not negative // double intrudeLen = child.getWidth()-child.gen.getWidth(); //used to find generation that is being intruded upon // double adjustMother = 0.0; //adjustment for offsets // double adjustFather = 0.0; //adjustment for offsets // // for(int i=1; i < maxGen+1; i++) { // intrudeLen -= tree.getGeneration(genBase+i).getWidth(); // // //adjust offsets if intruding into another box // if(intrude && intrudeLen <= 0.0) { // double mOffset = mother.upperBounds.get(i-1) + child.getVerticalSpace()/2; // double fOffset = -father.lowerBounds.get(i-1)+ child.getVerticalSpace()/2; //// double betweenDiff = Math.abs(mother.upperBounds.get(i-1)+father.lowerBounds.get(i-1)); //// if(betweenDiff < child.getHeight()) //// maxDist += child.getHeight() - betweenDiff; // double mDiff = mOffset + child.getHeight()/2 - maxDist/2.0; // double fDiff = fOffset + child.getHeight()/2 - maxDist/2.0; //// adjustFather = fDiff; //// adjustMother = mDiff; // if(fDiff > 0) { // adjustFather += fDiff; //// adjustMother += -mother.upperSubTreeOffset-mDiff; // } // if(mDiff > 0) { // adjustMother += mDiff; //// adjustFather += father.lowerSubTreeOffset+fDiff; // } // double join = mother.upperSubTreeOffset - (maxDist/2.0 + adjustMother); // fDiff = -father.lowerSubTreeOffset + child.getHeight()/2 - maxDist/2.0; // // // break; // } // } // // return new double[] {maxDist/2.0 +adjustFather, -(maxDist/2.0 + adjustMother)}; // } private double[] findOffsets(AncesBox child) { AncesBox father = child.father; AncesBox mother = child.mother; boolean intrude = child.gen.getWidth() < child.getWidth(); //if child doesn't have both parents if(father == null || mother == null) { double parentHeight = 0; if(father != null) { parentHeight = father.getHeight(); child.upperBounds.set(0, parentHeight + child.getVerticalSpace()); } else if(mother != null) { parentHeight = mother.getHeight(); child.lowerBounds.set(0, -parentHeight - child.getVerticalSpace()); } if(intrude) { double dist = child.getHeight() + parentHeight + child.getVerticalSpace()*2; return new double[] {dist/2.0,dist/2.0}; } else return new double[] {DEFAULT_VOFFSET,DEFAULT_VOFFSET}; } //if child has both parents double maxDist = 0; //represents distance from the childs mother and father boxes int maxGen = Math.min(father.lowerBounds.size(),mother.upperBounds.size()); //determines how far to compare //find the max distance between them (the closest they can be while "intersecting" only at one point) for (int i = 0; i < maxGen; ++i) { double curDist = mother.upperBounds.get(i) - father.lowerBounds.get(i) + father.getVerticalSpace(); maxDist = Math.max(curDist, maxDist); } //child is centered between the parents double mOffset = -maxDist/2; double fOffset = maxDist/2; int genBase = child.gen.getGenNum(); //used to index into generation array if(genBase < 0) genBase = 0; //make sure its not negative double intrudeLen = child.getWidth()-child.gen.getWidth(); //used to find generation that is being intruded upon for(int i=1; i < maxGen+1; i++) { intrudeLen -= tree.getGeneration(genBase+i).getWidth(); //if intruding, adjust offsets to center the child between parents in the generation that is being intruded if(intrude && intrudeLen <= 0.0) { double temp = mother.upperBounds.get(i-1) + father.lowerBounds.get(i-1); double diff = maxDist - Math.abs( mother.upperBounds.get(i-1) - father.lowerBounds.get(i-1)); //center the child between the parents fOffset -= temp/2; mOffset -= temp/2; //expand the offsets if gap between parents is too small if(diff < child.getHeight()+child.getVerticalSpace()*2) { double expand = child.getHeight()+child.getVerticalSpace()*3 - diff; fOffset += expand/2; mOffset -= expand/2; } break; } } return new double[] {fOffset, mOffset}; } public void expandOffsets(AncesTree tree, double paperHeight) { double ratio = paperHeight /tree.getHeight(); if(ratio > 1.0){ multiplyOffsets(tree.root,ratio); } } private void multiplyOffsets(AncesBox b, double multiplier) { if(b == null) return; b.fatherVOffset *= multiplier; b.motherVOffset *= multiplier; multiplyOffsets(b.father,multiplier); multiplyOffsets(b.mother,multiplier); } }