/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Node.java * Copyright Remco Bouckaert remco@cs.auckland.ac.nz (C) 2011 */ package viz; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import java.util.Vector; import java.util.List; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; /** class for nodes in building tree data structure **/ public class Node { /** length of branch in the tree **/ public float m_fLength = -1; /** height of the node. This is a derived variable from m_fLength **/ //float m_fHeight = -1; /** x & y coordinate of node **/ public float m_fPosX = 0; public float m_fPosY = 0; /** label nr of node, if this is a leaf, otherwise number of clade **/ public int m_iLabel; public int m_iClade; public int getNr() {return m_iLabel;} /** metadata contained in square brackers in Newick **/ private String m_sMetaData; /** meta data parsed as key-value pairs **/ private Map<String, Object> metaDataMap; public static Map<String, Double> g_minValue = new HashMap<String, Double>(); public static Map<String, Double> g_maxValue = new HashMap<String, Double>(); /** meta data parsed as list of numbers **/ private List<Double> metaDataList; public static List<Double> g_minListValue = new ArrayList<Double>(); public static List<Double> g_maxListValue = new ArrayList<Double>(); /** user data generated by other applications (e.g. DensiTreeG)**/ public Object m_data = null; /** list of children of this node **/ public Node m_left; public Node m_right; //Node[] m_children; /** parent node in the tree, null if root **/ Node m_Parent = null; /** return parent node, or null if this is root **/ public Node getParent() { return m_Parent; } public void setParent(Node parent) { m_Parent = parent; } /** check if current node is root node **/ public boolean isRoot() { return m_Parent == null; } /** check if current node is a leaf node **/ public boolean isLeaf() { return m_left == null; } /** count number of nodes in tree, starting with current node **/ int getNodeCount() { if (isLeaf()) { return 1; } return 1 + m_left.getNodeCount() + m_right.getNodeCount(); } /** * print tree in Newick format, without any length or meta data * information **/ public String toShortNewick() { StringBuffer buf = new StringBuffer(); if (m_left != null) { buf.append("("); buf.append(m_left.toShortNewick()); if (m_right != null) { buf.append(','); buf.append(m_right.toShortNewick()); } buf.append(")"); } else { buf.append(m_iLabel); } return buf.toString(); } /** * print tree in long Newick format, with all length and meta data * information **/ public String toNewick() { StringBuffer buf = new StringBuffer(); if (m_left != null) { buf.append("("); buf.append(m_left.toNewick()); if (m_right != null) { buf.append(','); buf.append(m_right.toNewick()); } buf.append(")"); } else { buf.append(m_iLabel); } // if (m_sMetaData != null) { // buf.append('['); // buf.append(m_sMetaData); // buf.append(']'); // } buf.append(":" + m_fLength); return buf.toString(); } /** * print tree in long Newick format, with position meta data * information **/ public String toNewickWithPos(double fMinLat, double fMaxLat, double fMinLong) { StringBuffer buf = new StringBuffer(); if (m_left != null) { buf.append("("); buf.append(m_left.toNewickWithPos(fMinLat, fMaxLat, fMinLong)); buf.append(','); buf.append(m_right.toNewickWithPos(fMinLat, fMaxLat, fMinLong)); buf.append(")"); } else { buf.append(m_iLabel); } buf.append("[pos="); DecimalFormat df = new DecimalFormat("#.##"); buf.append(df.format(toLongitude(m_fPosX, fMinLat, fMaxLat)) + "x" + df.format(toLatitude(m_fPosY, fMinLong))); buf.append(']'); buf.append(":" + m_fLength); return buf.toString(); } double toLongitude(double fPosX, double fMinLat, double fMaxLat) { return fMaxLat - fPosX + (fMaxLat-fMinLat) / 100.0f; } double toLatitude(double fPosY, double fMinLong) { return fPosY + fMinLong; } /** * print tree in long Newick format, with all length and meta data * information, but with leafs labelled with their names **/ public String toString(Vector<String> sLabels, boolean bShowMetaData) { StringBuffer buf = new StringBuffer(); if (m_left != null) { buf.append("("); buf.append(m_left.toString(sLabels, bShowMetaData)); if (m_right != null) { buf.append(','); buf.append(m_right.toString(sLabels, bShowMetaData)); } buf.append(")"); } else { buf.append(sLabels.elementAt(m_iLabel)); } if (bShowMetaData && getMetaData() != null) { buf.append('['); buf.append(getMetaData()); buf.append(']'); } buf.append(":" + m_fLength); return buf.toString(); } @Override public String toString() { return toNewick(); } /** * 'draw' tree into an array of x & positions. This draws the tree as * block diagram. * * @param nX * @param nY * @param iPos * @return */ public int drawDryWithSingleChild(float[] nX, float[] nY, int iPos, boolean[] bNeedsDrawing, boolean [] bSelection, float fOffset, float fScale) { if (isLeaf()) { bNeedsDrawing[0] = bSelection[m_iLabel]; } else { boolean[] bChildNeedsDrawing = new boolean[2]; iPos = m_left.drawDryWithSingleChild(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale); bChildNeedsDrawing[0] = bNeedsDrawing[0]; float dX; if (m_right != null) { iPos = m_right.drawDryWithSingleChild(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale); bChildNeedsDrawing[1] = bNeedsDrawing[0]; dX = m_fPosX - (m_left.m_fPosX + m_right.m_fPosX)/2; } else { bChildNeedsDrawing[1] = false; dX = m_fPosX - m_left.m_fPosX; } bNeedsDrawing[0] = false; if (bChildNeedsDrawing[0]) { nX[iPos] = m_left.m_fPosX; nY[iPos] = (m_left.m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = nX[iPos - 1] + dX;//nX[iPos - 1]; nY[iPos] = (m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (bChildNeedsDrawing[1]) { nX[iPos] = m_right.m_fPosX + dX; nY[iPos] = nY[iPos - 1]; iPos++; nX[iPos] = m_right.m_fPosX;//nX[iPos - 1]; nY[iPos] = (m_right.m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (isRoot()) { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - m_fLength - fOffset) * fScale; iPos++; } } return iPos; } public int drawDry(float[] nX, float[] nY, int iPos, boolean[] bNeedsDrawing, boolean [] bSelection, float fOffset, float fScale) { if (isLeaf()) { bNeedsDrawing[0] = bSelection[m_iLabel]; } else { boolean[] bChildNeedsDrawing = new boolean[2]; iPos = m_left.drawDry(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale); bChildNeedsDrawing[0] = bNeedsDrawing[0]; iPos = m_right.drawDry(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale); bChildNeedsDrawing[1] = bNeedsDrawing[0]; bNeedsDrawing[0] = false; iPos = (m_iLabel - bSelection.length) * 4; float dX = m_fPosX - (m_left.m_fPosX + m_right.m_fPosX)/2; if (bChildNeedsDrawing[0]) { nX[iPos] = m_left.m_fPosX; nY[iPos] = (m_left.m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = nX[iPos - 1] + dX;//nX[iPos - 1]; nY[iPos] = (m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (bChildNeedsDrawing[1]) { nX[iPos] = m_right.m_fPosX + dX; nY[iPos] = nY[iPos - 1]; iPos++; nX[iPos] = m_right.m_fPosX;//nX[iPos - 1]; nY[iPos] = (m_right.m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (isRoot()) { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - m_fLength - fOffset) * fScale; iPos++; } } return iPos; } public int drawDryCentralised(float[] nX, float[] nY, int iPos, boolean[] bNeedsDrawing, boolean [] bSelection, float fOffset, float fScale, float[] taxonData, float [] fPosX, float [] fNonCentralisedPosX, float [] cladePosition) { if (isLeaf()) { bNeedsDrawing[0] = bSelection[m_iLabel]; m_fPosX = cladePosition[m_iLabel]; taxonData[0] = m_fPosX; fPosX[m_iLabel] = m_fPosX; fNonCentralisedPosX[m_iLabel] = m_fPosX; taxonData[1] = 1; } else { boolean[] bChildNeedsDrawing = new boolean[2]; float [] taxonDataLeft = new float[2]; iPos = m_left.drawDryCentralised(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale, taxonDataLeft, fPosX, fNonCentralisedPosX, cladePosition); bChildNeedsDrawing[0] = bNeedsDrawing[0]; float [] taxonDataRight = new float[2]; iPos = m_right.drawDryCentralised(nX, nY, iPos, bNeedsDrawing, bSelection, fOffset, fScale, taxonDataRight, fPosX, fNonCentralisedPosX, cladePosition); bChildNeedsDrawing[1] = bNeedsDrawing[0]; taxonData[0] = taxonDataLeft[0] + taxonDataRight[0]; taxonData[1] = taxonDataLeft[1] + taxonDataRight[1]; bNeedsDrawing[0] = false; fNonCentralisedPosX[m_iLabel] = (fNonCentralisedPosX[m_left.m_iLabel] + fNonCentralisedPosX[m_right.m_iLabel])/2; float dX = fNonCentralisedPosX[m_iLabel] - m_fPosX; fPosX[m_iLabel] = cladePosition[m_iClade] - dX; //taxonData[0]/taxonData[1] - dX; iPos = (m_iLabel - bSelection.length) * 4; if (bChildNeedsDrawing[0]) { nX[iPos] = fPosX[m_left.m_iLabel]; nY[iPos] = (m_left.m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = fPosX[m_iLabel];//nX[iPos - 1] + dX;//nX[iPos - 1]; nY[iPos] = (m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (bChildNeedsDrawing[1]) { nX[iPos] = fPosX[m_iLabel];//m_right.m_fPosX + dX; nY[iPos] = nY[iPos - 1]; iPos++; nX[iPos] = fPosX[m_right.m_iLabel];//nX[iPos - 1]; nY[iPos] = (m_right.m_fPosY - fOffset) * fScale; bNeedsDrawing[0] = true; } else { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (isRoot()) { nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; nX[iPos] = m_fPosX; nY[iPos] = (m_fPosY - m_fLength - fOffset) * fScale; iPos++; } } return iPos; } public int getStarTreeCladeCenters(float[] cladeCenterX, float[] cladeCenterY, float fOffset, float fScale, float [] cladePosition, float fMaxPosition) { if (isLeaf()) { m_fPosX = cladePosition[m_iLabel]; if (m_fPosX > fMaxPosition - 0.25) { m_fPosX = fMaxPosition - 0.25f; } if (m_fPosX < 0.25) { m_fPosX = 0.25f; } cladeCenterX[m_iLabel] = m_fPosX; cladeCenterY[m_iLabel] = (m_fPosY - fOffset) * fScale; return 1; } else { int nNrOfNodesLeft = m_left.getStarTreeCladeCenters(cladeCenterX, cladeCenterY, fOffset, fScale, cladePosition, fMaxPosition); int nNrOfNodesRight = m_right.getStarTreeCladeCenters(cladeCenterX, cladeCenterY, fOffset, fScale, cladePosition, fMaxPosition); int nNrOfNodes = nNrOfNodesLeft + nNrOfNodesRight; cladeCenterX[m_iLabel] = (nNrOfNodesLeft * cladeCenterX[m_left.m_iLabel] + nNrOfNodesRight * cladeCenterX[m_right.m_iLabel]) / nNrOfNodes; cladeCenterY[m_iLabel] = (nNrOfNodesLeft * cladeCenterY[m_left.m_iLabel] + nNrOfNodesRight * cladeCenterY[m_right.m_iLabel]) / nNrOfNodes; return nNrOfNodes; } } public boolean drawStarTree( float[] nX, float[] nY, float[] cladePosX, float[] cladePosY, float[] cladeCenterX, float[] cladeCenterY, boolean[] bSelection, float fOffset, float fScale) { if (isLeaf()) { cladePosX[m_iLabel] = m_fPosX; cladePosY[m_iLabel] = (m_fPosY - fOffset) * fScale; return bSelection[m_iLabel]; } else { if (isRoot()) { cladePosX[m_iLabel] = cladeCenterX[m_iLabel]; cladePosY[m_iLabel] = (m_fPosY - fOffset) * fScale; } else { float fParentPosX = cladePosX[m_Parent.m_iLabel]; float fParentPosY = cladePosY[m_Parent.m_iLabel]; float fCladeCenterX = cladeCenterX[m_iLabel]; float fCladeCenterY = cladeCenterY[m_iLabel]; cladePosY[m_iLabel] = (m_fPosY - fOffset) * fScale; cladePosX[m_iLabel] = fParentPosX + (fCladeCenterX - fParentPosX) * (cladePosY[m_iLabel] - fParentPosY) / (fCladeCenterY - fParentPosY); } boolean[] bChildNeedsDrawing = new boolean[2]; bChildNeedsDrawing[0] = m_left.drawStarTree(nX, nY, cladePosX, cladePosY, cladeCenterX, cladeCenterY, bSelection, fOffset, fScale); bChildNeedsDrawing[1] = m_right.drawStarTree(nX, nY, cladePosX, cladePosY, cladeCenterX, cladeCenterY, bSelection, fOffset, fScale); int iPos = (m_iLabel - bSelection.length) * 4; // float dX = m_fPosX - (m_left.m_fPosX + m_right.m_fPosX)/2; if (bChildNeedsDrawing[0]) { nX[iPos] = cladePosX[m_left.m_iLabel]; nY[iPos] = cladePosY[m_left.m_iLabel]; iPos++; nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; } else { nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; iPos++; nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; } iPos++; if (bChildNeedsDrawing[1]) { nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; iPos++; nX[iPos] = cladePosX[m_right.m_iLabel]; nY[iPos] = cladePosY[m_right.m_iLabel]; } else { nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; iPos++; nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; } iPos++; if (isRoot()) { nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = cladePosY[m_iLabel]; iPos++; nX[iPos] = cladePosX[m_iLabel]; nY[iPos] = (m_fPosY - m_fLength - fOffset) * fScale; iPos++; } return bChildNeedsDrawing[0] || bChildNeedsDrawing[1]; } } // /** // * 'draw' tree into an array of x & positions. This draws the tree using // * triangles // * // * @param nX // * @param nY // * @param iPos // * @return // */ // public int drawDryTriangle(float[] nX, float[] nY, int iPos, boolean[] bNeedsDrawing, boolean [] bSelection) { // if (isLeaf()) { // bNeedsDrawing[0] = bSelection[m_iLabel]; // } else { // boolean[] bChildNeedsDrawing = new boolean[2]; // iPos = m_left.drawDryTriangle(nX, nY, iPos, bNeedsDrawing, bSelection); // bChildNeedsDrawing[0] = bNeedsDrawing[0]; // iPos = m_right.drawDryTriangle(nX, nY, iPos, bNeedsDrawing, bSelection); // bChildNeedsDrawing[1] = bNeedsDrawing[0]; // bNeedsDrawing[0] = false; // if (bChildNeedsDrawing[0]) { // nX[iPos] = m_left.m_fPosX; // nY[iPos] = m_left.m_fPosY; // bNeedsDrawing[0] = true; // } else { // nX[iPos] = m_fPosX; // nY[iPos] = m_fPosY; // } // iPos++; // nX[iPos] = m_fPosX; // nY[iPos] = m_fPosY; // iPos++; // if (bChildNeedsDrawing[1]) { // nX[iPos] = m_right.m_fPosX; // nY[iPos] = m_right.m_fPosY; // bNeedsDrawing[0] = true; // } else { // nX[iPos] = m_fPosX; // nY[iPos] = m_fPosY; // } // iPos++; // } // if (isRoot()) { // nX[iPos] = m_fPosX; // nY[iPos] = m_fPosY; // iPos++; // nX[iPos] = m_fPosX; // nY[iPos] = m_fPosY - m_fLength; // iPos++; // } // return iPos; // } /** * sorts nodes in children according to lowest numbered label in subtree **/ public int sort() { if (m_left != null) { int iChild1 = m_left.sort(); if (m_right != null) { int iChild2 = m_right.sort(); if (iChild1 > iChild2) { Node tmp = m_left; m_left = m_right; m_right = tmp; return iChild2; } } return iChild1; } // this is a leaf node, just return the label nr return m_iLabel; } // sort /** during parsing, leaf nodes are numbered 0...m_nNrOfLabels-1 * but internal nodes are left to zero. After labeling internal * nodes, m_iLabel uniquely identifies a node in a tree. */ public int labelInternalNodes(int iLabel) { if (isLeaf()) { return iLabel; } else { iLabel = m_left.labelInternalNodes(iLabel); if (m_right != null) { iLabel = m_right.labelInternalNodes(iLabel); } m_iLabel = iLabel++; } return iLabel; } // labelInternalNodes /** create deep copy **/ Node copy() { Node node = new Node(); node.m_fLength = m_fLength; node.m_fPosX = m_fPosX; node.m_fPosY = m_fPosY; node.m_iLabel = m_iLabel; node.m_iClade = m_iClade; node.setMetaData(m_sMetaData); node.m_Parent = null; if (m_left != null) { node.m_left = m_left.copy(); node.m_left.m_Parent = node; if (m_right != null) { node.m_right = m_right.copy(); node.m_right.m_Parent = node; } else { node.m_right = null; } } return node; } // copy float sigmoid(float fLength, float fMaxAngle) { if (fLength < 1.0*fMaxAngle) { return 0; } else { return 1; } //return (float) (1.0/(1.0 + Math.exp(-1-1.0*fLength / fMaxAngle))); //return (float) Math.min(1.0, Math.sqrt(1*fLength / fMaxAngle)); //return (float) Math.min(1.0, (0.5*fLength / fMaxAngle)); } public int doAngleCorrection(float[] nX, float[] nY, int iPos, boolean[] bNeedsDrawing, boolean [] bSelection, float fMaxAngle) { if (isLeaf()) { bNeedsDrawing[0] = bSelection[m_iLabel]; } else { boolean[] bChildNeedsDrawing = new boolean[2]; iPos = m_left.doAngleCorrection(nX, nY, iPos, bNeedsDrawing, bSelection, fMaxAngle); bChildNeedsDrawing[0] = bNeedsDrawing[0]; iPos = m_right.doAngleCorrection(nX, nY, iPos, bNeedsDrawing, bSelection, fMaxAngle); bChildNeedsDrawing[1] = bNeedsDrawing[0]; bNeedsDrawing[0] = false; iPos = (m_iLabel - bSelection.length) * 4; if (bChildNeedsDrawing[0]) { if (!m_left.isLeaf()) { float fWeight = sigmoid(m_left.m_fLength/Math.abs(nX[iPos] - nX[iPos+1]), fMaxAngle);// / ( m_left.m_fLength + m_right.m_fLength); nX[iPos] = nX[iPos] * fWeight + nX[iPos+1] * (1.0f - fWeight); nX[(m_left.m_iLabel - bSelection.length) * 4 + 1] = nX[iPos]; nX[(m_left.m_iLabel - bSelection.length) * 4 + 2] = nX[iPos]; } iPos++; //nX[iPos] = nX[iPos - 1] + dX;//nX[iPos - 1]; bNeedsDrawing[0] = true; } else { // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (bChildNeedsDrawing[1]) { // nX[iPos] = m_right.m_fPosX + dX; iPos++; if (!m_right.isLeaf()) { float fWeight = sigmoid(m_right.m_fLength/Math.abs(nX[iPos-1] - nX[iPos]), fMaxAngle);// / ( m_left.m_fLength + m_right.m_fLength); nX[iPos] = nX[iPos] * fWeight + nX[iPos-1] * (1.0f - fWeight); nX[(m_right.m_iLabel - bSelection.length) * 4 + 1] = nX[iPos]; nX[(m_right.m_iLabel - bSelection.length) * 4 + 2] = nX[iPos]; } bNeedsDrawing[0] = true; } else { // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - fOffset) * fScale; } iPos++; if (isRoot()) { // root remains in the same place // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - fOffset) * fScale; iPos++; // nX[iPos] = m_fPosX; // nY[iPos] = (m_fPosY - m_fLength - fOffset) * fScale; iPos++; } } return iPos; } public String getMetaData() { return m_sMetaData; } public void setMetaData(String sMetaData) { this.m_sMetaData = sMetaData; } public void parseMetaData() { if (metaDataMap == null) { metaDataMap = new HashMap<String, Object>(); metaDataList = new ArrayList<Double>(); } // parse by key=value pairs int i = 0; int start = 1; try { while ((i = m_sMetaData.indexOf('=', i)) >= 0) { String key = m_sMetaData.substring(start, i).trim(); String value = null; int k = 0; if ((k = m_sMetaData.indexOf('=', i+1)) >= 0) { int j = m_sMetaData.lastIndexOf(',', k); value = m_sMetaData.substring(i + 1, j); start = j + 1; } else { value = m_sMetaData.substring(i+1); } if (value.length() > 0 && value.charAt(0)!='{') { try { Double dvalue = Double.parseDouble(value); if (!g_minValue.containsKey(key)) { g_minValue.put(key, dvalue); } else { if (g_minValue.get(key) > dvalue) { g_minValue.put(key, dvalue); } } if (!g_maxValue.containsKey(key)) { g_maxValue.put(key, dvalue); } else { if (g_maxValue.get(key) < dvalue) { g_maxValue.put(key, dvalue); } } metaDataMap.put(key, dvalue); } catch (Exception e) { metaDataMap.put(key, value); } } else { metaDataMap.put(key, value); } i++; } } catch (Exception e) { // TODO: handle exception } // parse as list of numbers i = 0; start = 1; int iNumber = 0; //Pattern pattern = Pattern.compile("^([+-0-9\\.]+)([eE]-??[0-9]+)??.*"); Pattern pattern = Pattern.compile("((-?[0-9]+(\\.[0-9]+)?)([eE]-?[0-9]+)?)"); try { while (i < m_sMetaData.length()) { char c = m_sMetaData.charAt(i); if ((c >= '0' && c <= '9') || c=='+' || c=='-') { String str = m_sMetaData.substring(i); Matcher m = pattern.matcher(str); m.find(); String mantissa = m.group(1); i += mantissa.length(); double value = 0; try { value = Double.parseDouble(mantissa); } catch (Exception e) { System.err.println(e.getMessage()); } metaDataList.add(value); if (g_maxListValue.size() < metaDataList.size()) { g_maxListValue.add(Double.NEGATIVE_INFINITY); g_minListValue.add(Double.POSITIVE_INFINITY); } g_maxListValue.set(iNumber, Math.max(g_maxListValue.get(iNumber), value)); g_minListValue.set(iNumber, Math.min(g_minListValue.get(iNumber), value)); iNumber++; } else { i++; } } } catch (Exception e) { // TODO: handle exception } } public Map<String,Object> getMetaDataSet() { return metaDataMap; } public List<Double> getMetaDataList() { return metaDataList; } } // class Node