package org.phylowidget.ui; import java.awt.geom.Point2D; import org.andrewberman.ui.menu.Menu; import org.andrewberman.ui.menu.MenuItem; import org.phylowidget.PWContext; import org.phylowidget.PWPlatform; import org.phylowidget.PhyloTree; import org.phylowidget.render.BasicTreeRenderer; import org.phylowidget.render.LayoutBase; import org.phylowidget.render.LayoutCircular; import org.phylowidget.render.LayoutCladogram; import org.phylowidget.render.LayoutDiagonal; import org.phylowidget.render.LayoutUnrooted; import org.phylowidget.tree.PhyloNode; import processing.core.PApplet; public class PhyloScaleBar extends Menu { PWContext context; int mode = MODE_SCALE; public static final int MODE_SCALE = 0; public static final int MODE_TIME = 1; float minSize = 0.1f; float maxSize = 10000f; String units; float percentWidth = .5f; float percentPosition = .5f; float barHeight = 10; double[] sizes = new double[] { 0.01, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,2000,5000 }; public PhyloScaleBar(PApplet app) { super(app); this.context = PWPlatform.getInstance().getThisAppContext(); units = ""; setY(app.height-10); } @Override public synchronized void layout() { super.layout(); } @Override protected synchronized void drawMyself() { super.drawMyself(); if (context.trees().camera == null) return; if (context.trees().getTree() == null) return; if (!context.config().useBranchLengths) return; BasicTreeRenderer renderer = (BasicTreeRenderer) context.trees().getRenderer(); if (renderer.getLayout() instanceof LayoutDiagonal) return; if (renderer.getLayout() instanceof LayoutCircular) return; if (mode == MODE_SCALE) { // Find x and y. float canvasW = canvas.width; float myWidth = canvasW * percentWidth; float myCenter = canvasW * percentPosition; // Special case: if we have a small percentPosition but a large myWidth. if (myCenter - myWidth < 0) { myCenter = myWidth / 2; } // ok, so by now we have the center position and a desired width for the scale bar. // Find the distance-per-pixel. PhyloTree tree = (PhyloTree) context.trees().getTree(); if (tree.getNumEnclosedLeaves(tree.getRoot()) == 1) return; double branchLengthPerPixel = 1; LayoutBase curLayout = renderer.getLayout(); if (curLayout instanceof LayoutUnrooted) { // Find the per-pixel length. PhyloNode n = tree.getFurthestLeafFromVertex(tree.getRoot()); while (n != null) { // Make sure we have a node with >0 branch length. if (tree.getBranchLength(n) > 0) break; n = tree.getParentOf(n); } // Now, find the pixel distance between this node and the next. double branchLength = tree.getBranchLength(n); PhyloNode parent = tree.getParentOf(n); Point2D.Double parentPt = new Point2D.Double(parent.getX(), parent.getY()); Point2D.Double childPt = new Point2D.Double(n.getX(), n.getY()); double distance = parentPt.distance(childPt); branchLengthPerPixel = branchLength / distance; } else if (curLayout instanceof LayoutCladogram) { // Find the per-pixel length. PhyloNode n = tree.getFurthestLeafFromVertex(tree.getRoot()); while (n != null) { // Make sure we have a node with >0 branch length. if (tree.getBranchLength(n) > 0) break; n = tree.getParentOf(n); } // Now, find the pixel distance between this node and the next. double branchLength = tree.getBranchLength(n); PhyloNode parent = tree.getParentOf(n); Point2D.Double parentPt = new Point2D.Double(parent.getX(), parent.getY()); Point2D.Double childPt = new Point2D.Double(n.getX(), n.getY()); // double distance = parentPt.distance(childPt); double distance = Math.abs(parentPt.x - childPt.x); branchLengthPerPixel = branchLength / distance; } else { // Nothing to do... } double idealSize = 0; for (int i=sizes.length-1; i >= 0; i--) { double d = sizes[i]; // Find the would-be width of this size scale. double wouldBeWidth = d/branchLengthPerPixel; if (wouldBeWidth < myWidth || i == 0) { idealSize = d; break; } } double scaleWidth = idealSize / branchLengthPerPixel; // Do the drawing. canvas.strokeWeight(2f); canvas.stroke(0); canvas.fill(0); canvas.textSize(10); canvas.line((float)(myCenter - scaleWidth/2), y, (float)(myCenter+scaleWidth/2), y); canvas.textAlign(canvas.CENTER, canvas.BOTTOM); canvas.text(idealSize+"",myCenter,y); } else if (mode == MODE_TIME) { } } @Override public MenuItem create(String label) { return null; } }