private Element generateBranch(TreeType treeType,RootedTree tree,Node node,String nodeName,double startLatitude,double finishLatitude,double startLongitude,double finishLongitude,double startAltitude,double finishAltitude,double peakPosition,double peakAltitude,double startDate,double finishDate,double ageCutOff,LineStyle startStyle,LineStyle finishStyle,int divisionCount,List<Element> styles){
  Element element;
  Double rate=(Double)node.getAttribute("rate");
  Double support=(Double)node.getAttribute("posterior");
  double height=tree.getHeight(node);
  boolean hasDivisionStyles=startStyle != null && finishStyle != null;
  if (divisionCount > 0) {
    double latDiff=finishLatitude - startLatitude;
    double latDelta=latDiff / divisionCount;
    double longDiff=finishLongitude - startLongitude;
    double longDelta=longDiff / divisionCount;
    double altDiff=finishAltitude - startAltitude;
    double altDelta=altDiff / divisionCount;
    double dateDiff=finishDate - startDate;
    double dateDelta=dateDiff / divisionCount;
    double lastLatitude=startLatitude;
    double latitude=startLatitude + latDelta;
    double lastLongitude=startLongitude;
    double longitude=startLongitude + longDelta;
    double x=-peakPosition;
    double xDelta=1.0 / divisionCount;
    double a=peakAltitude - finishAltitude;
    if (peakPosition == 0.5) {
      a*=4;
    }
    double altitude=peakAltitude - (a * (x * x));
    double lastAltitude=altitude;
    x+=xDelta;
    double date=startDate;
    String styleName=null;
    if (!hasDivisionStyles && startStyle != null) {
      styleName=nodeName + "_style";
      styles.add(generateLineStyle(styleName,startStyle.getWidth(),startStyle.getColor()));
    }
    element=generateContainer("Folder",nodeName,null,(styleName != null ? "#" + styleName : null));
    for (int division=0; division < divisionCount; division++) {
      if (ageCutOff == 0.0 || date > ageCutOff) {
        String partName=nodeName + "_part" + (division + 1);
        styleName=null;
        if (hasDivisionStyles) {
          styleName=partName + "_style";
        }
        Element placeMark=generateContainer("Placemark",partName,null,(styleName != null ? "#" + styleName : null));
        annotateBranch(placeMark,height,startDate,finishDate,rate,support);
        if (hasDivisionStyles) {
          double width=startStyle.getWidth();
          Color color=getBlendedColor(((float)division) / (divisionCount - 1),startStyle.getColor(),finishStyle.getColor());
          styles.add(generateLineStyle(styleName,width,color));
        }
        if (dateDiff > 0.0) {
          Element timeSpan=new Element("TimeSpan");
          timeSpan.addContent(generateElement("begin",getKMLDate(date)));
          placeMark.addContent(timeSpan);
        }
        Element lineString=new Element("LineString");
        Element coordinates=new Element("coordinates");
        if (altDiff > 0.0 || peakAltitude > 0.0) {
          lineString.addContent(generateElement("altitudeMode",altitudeMode));
          altitude=peakAltitude - (a * (x * x));
          coordinates.addContent("" + lastLongitude + ","+ lastLatitude+ ","+ lastAltitude+ "\r");
          coordinates.addContent("" + longitude + ","+ latitude+ ","+ altitude+ "\r");
        }
 else {
          lineString.addContent(generateElement("altitudeMode","clampToGround"));
          lineString.addContent(generateElement("tessellate",true));
          coordinates.addContent("" + lastLongitude + ","+ lastLatitude+ "\r");
          coordinates.addContent("" + longitude + ","+ latitude+ "\r");
        }
        lastLatitude=latitude;
        latitude+=latDelta;
        lastLongitude=longitude;
        longitude+=longDelta;
        lastAltitude=altitude;
        x+=xDelta;
        date+=dateDelta;
        lineString.addContent(coordinates);
        placeMark.addContent(lineString);
        element.addContent(placeMark);
      }
    }
  }
 else {
    String styleName=null;
    if (startStyle != null) {
      styleName=nodeName + "_style";
      double width=startStyle.getWidth();
      styles.add(generateLineStyle(styleName,width,startStyle.getColor()));
    }
    element=generateContainer("Placemark",nodeName,null,(styleName != null ? "#" + styleName : null));
    annotateBranch(element,height,startDate,finishDate,rate,support);
    Element lineString=new Element("LineString");
    lineString.addContent(generateElement("altitudeMode",altitudeMode));
    Element coordinates=new Element("coordinates");
    if (treeType == TreeType.RECTANGLE_TREE) {
      coordinates.addContent("" + finishLongitude + ","+ finishLatitude+ ","+ finishAltitude+ "\r");
      coordinates.addContent("" + finishLongitude + ","+ finishLatitude+ ","+ startAltitude+ "\r");
      coordinates.addContent("" + startLongitude + ","+ startLatitude+ ","+ startAltitude+ "\r");
    }
 else {
      coordinates.addContent("" + finishLongitude + ","+ finishLatitude+ ","+ finishAltitude+ "\r");
      coordinates.addContent("" + startLongitude + ","+ startLatitude+ ","+ startAltitude+ "\r");
    }
    lineString.addContent(coordinates);
    element.addContent(lineString);
  }
  return element;
}

private Element generateBranch ( TreeType treeType , RootedTree tree , Node node , String nodeName , double startLatitude , double finishLatitude , double startLongitude , double finishLongitude , double startAltitude , double finishAltitude , double peakPosition , double peakAltitude , double startDate , double finishDate , double ageCutOff , LineStyle startStyle , LineStyle finishStyle , int divisionCount , List < Element > styles ) { Element element ; Double rate = ( Double ) node . getAttribute ( "rate" ) ; Double support = ( Double ) node . getAttribute ( "posterior" ) ; double height = tree . getHeight ( node ) ; boolean hasDivisionStyles = startStyle != null && finishStyle != null ; if ( divisionCount > 0 ) { double latDiff = finishLatitude - startLatitude ; double latDelta = latDiff / divisionCount ; double longDiff = finishLongitude - startLongitude ; double longDelta = longDiff / divisionCount ; double altDiff = finishAltitude - startAltitude ; double altDelta = altDiff / divisionCount ; double dateDiff = finishDate - startDate ; double dateDelta = dateDiff / divisionCount ; double lastLatitude = startLatitude ; double latitude = startLatitude + latDelta ; double lastLongitude = startLongitude ; double longitude = startLongitude + longDelta ; double x = - peakPosition ; double xDelta = 1.0 / divisionCount ; double a = peakAltitude - finishAltitude ; if ( peakPosition == 0.5 ) { a *= 4 ; } double altitude = peakAltitude - ( a * ( x * x ) ) ; double lastAltitude = altitude ; x += xDelta ; double date = startDate ; String styleName = null ; if ( ! hasDivisionStyles && startStyle != null ) { styleName = nodeName + "_style" ; styles . add ( generateLineStyle ( styleName , startStyle . getWidth ( ) , startStyle . getColor ( ) ) ) ; } element = generateContainer ( "Folder" , nodeName , null , ( styleName != null ? "#" + styleName : null ) ) ; for ( int division = 0 ; division < divisionCount ; division ++ ) { if ( ageCutOff == 0.0 || date > ageCutOff ) { String partName = nodeName + "_part" + ( division + 1 ) ; styleName = null ; if ( hasDivisionStyles ) { styleName = partName + "_style" ; } Element placeMark = generateContainer ( "Placemark" , partName , null , ( styleName != null ? "#" + styleName : null ) ) ; annotateBranch ( placeMark , height , startDate , finishDate , rate , support ) ; if ( hasDivisionStyles ) { double width = startStyle . getWidth ( ) ; Color color = getBlendedColor ( ( ( float ) division ) / ( divisionCount - 1 ) , startStyle . getColor ( ) , finishStyle . getColor ( ) ) ; styles . add ( generateLineStyle ( styleName , width , color ) ) ; } if ( dateDiff > 0.0 ) { Element timeSpan = new Element ( "TimeSpan" ) ; timeSpan . addContent ( generateElement ( "begin" , getKMLDate ( date ) ) ) ; placeMark . addContent ( timeSpan ) ; } Element lineString = new Element ( "LineString" ) ; Element coordinates = new Element ( "coordinates" ) ; if ( altDiff > 0.0 || peakAltitude > 0.0 ) { lineString . addContent ( generateElement ( "altitudeMode" , altitudeMode ) ) ; altitude = peakAltitude - ( a * ( x * x ) ) ; coordinates . addContent ( "" + lastLongitude + "," + lastLatitude + "," + lastAltitude + "\r" ) ; coordinates . addContent ( "" + longitude + "," + latitude + "," + altitude + "\r" ) ; } else { lineString . addContent ( generateElement ( "altitudeMode" , "clampToGround" ) ) ; lineString . addContent ( generateElement ( "tessellate" , true ) ) ; coordinates . addContent ( "" + lastLongitude + "," + lastLatitude + "\r" ) ; coordinates . addContent ( "" + longitude + "," + latitude + "\r" ) ; } lastLatitude = latitude ; latitude += latDelta ; lastLongitude = longitude ; longitude += longDelta ; lastAltitude = altitude ; x += xDelta ; date += dateDelta ; lineString . addContent ( coordinates ) ; placeMark . addContent ( lineString ) ; element . addContent ( placeMark ) ; } } } else { String styleName = null ; if ( startStyle != null ) { styleName = nodeName + "_style" ; double width = startStyle . getWidth ( ) ; styles . add ( generateLineStyle ( styleName , width , startStyle . getColor ( ) ) ) ; } element = generateContainer ( "Placemark" , nodeName , null , ( styleName != null ? "#" + styleName : null ) ) ; annotateBranch ( element , height , startDate , finishDate , rate , support ) ; Element lineString = new Element ( "LineString" ) ; lineString . addContent ( generateElement ( "altitudeMode" , altitudeMode ) ) ; Element coordinates = new Element ( "coordinates" ) ; if ( treeType == TreeType . RECTANGLE_TREE ) { coordinates . addContent ( "" + finishLongitude + "," + finishLatitude + "," + finishAltitude + "\r" ) ; coordinates . addContent ( "" + finishLongitude + "," + finishLatitude + "," + startAltitude + "\r" ) ; coordinates . addContent ( "" + startLongitude + "," + startLatitude + "," + startAltitude + "\r" ) ; } else { coordinates . addContent ( "" + finishLongitude + "," + finishLatitude + "," + finishAltitude + "\r" ) ; coordinates . addContent ( "" + startLongitude + "," + startLatitude + "," + startAltitude + "\r" ) ; } lineString . addContent ( coordinates ) ; element . addContent ( lineString ) ; } return element ; }
create a branch that goes from [ startlatitude , startlongitude , startaltitude ] to [ finishlatitude , finishlongitude , finishaltitude ] , optionally arching through peakaltitude . if divisioncount > 0 then the branch is subdivided into segments , this is required if the branch is arcing or has a colour gradient .
