package edu.stanford.hci.flowmap.cluster; import org.codemap.util.geom.Line2D; import org.codemap.util.geom.Point2D; import org.codemap.util.geom.Rectangle2D; import edu.stanford.hci.flowmap.structure.Node; /** * This software is distributed under the Berkeley Software Distribution License. * Please see http://graphics.stanford.edu/~dphan/code/bsd.license.html */ public class Cluster { /** records the spatial extent of this cluster */ public Rectangle2D bounds = null; /** the center of the cluster */ public Point2D center = new Point2D.Double(); /** backpointer to the enclosing cluster */ public Cluster parentCluster = null; /** first child cluster */ public Cluster oneCluster = null; /** second child cluster */ public Cluster twoCluster = null; /** not-null if this cluster is just composed of a node. code uses test if node == null a lot */ private Node leafNode = null; /** the node that would be drawn for this cluster. Every Cluster object should eventually * have this assigned or created for them in the course of running the MultiRoot_ClusterLayout. * This even includes Clusters where leafNode != null (to be consistent) */ private Node renderedNode = null; private double weight; /** * Constructor for a real node item * @param n - the real node item */ public Cluster(Node n) { center.setLocation(n.getLocation()); leafNode = n; bounds = new Rectangle2D.Double(n.getLocation().getX()-5, n.getLocation().getY()-5, 10, 10); weight = n.getWeight(); //System.out.println("Cluster() " + n.getQueryRow()); renderedNode = new Node(n.getLocation()); //renderedNode.setName(n.getName()); } public Cluster(Cluster one, Cluster two) { oneCluster = one; twoCluster = two; // merging leaf nodes if ((one.leafNode != null) && (two.leafNode != null)) { // make a rectangle that bounds the two nodes Point2D onePt = one.leafNode.getLocation(); bounds = new Rectangle2D.Double(onePt.getX(), onePt.getY(), 0, 0); bounds.add(two.leafNode.getLocation()); } else { // merging non-leaf nodes bounds = new Rectangle2D.Double(); if (one.bounds != null && two.bounds != null) { bounds.setRect(one.bounds); bounds.add(two.bounds); } else if ((one.bounds == null) && (two.bounds == null)) { bounds.setRect(one.center.getX(), one.center.getY(), 0, 0); bounds.add(two.center); } else if (one.bounds != null) { bounds.setRect(one.bounds); bounds.add(two.center); } else { bounds.setRect(two.bounds); bounds.add(one.center); } // update the weight of the cluster } weight = one.getWeight() + two.getWeight(); // create a new center point which is the center of the bounding box // there are other ways to do this, but this is easy and consistent center.setLocation(bounds.getCenterX(), bounds.getCenterY()); } public double getWeight() { return weight; } public Point2D getCenter(){ if(leafNode != null){ return leafNode.getLocation(); }else{ return center; } } public Cluster getOtherChild(Cluster aChild){ if(aChild == oneCluster){ return twoCluster; }else if(aChild == twoCluster){ return oneCluster; }else{ return null; } } public boolean intersectWithLine(Line2D line) { if (bounds == null) { return (line.ptLineDist(center) == 0); } else { return line.intersects(bounds); } } /** * * @param other the other cluster * @return distance to the other cluster */ public double distTo(Cluster other) { return center.distance(other.center); } public boolean equals(Object o) { Cluster c = (Cluster)o; if ((leafNode != null) && (c.leafNode != null)) { return leafNode.equals(c.leafNode); } else if ((oneCluster != null) && (c.oneCluster != null) && (twoCluster != null) && (c.twoCluster != null)) { return (oneCluster.equals(c.oneCluster) && twoCluster.equals(c.twoCluster)); } else return false; } public String toString() { StringBuilder sb = new StringBuilder(); if (leafNode != null) { sb.append(leafNode.getName() + " " + center.getX() + "," + center.getY()); } if ((oneCluster != null) && (twoCluster != null)) { //sb.append(bounds.toString()); sb.append("( "); sb.append(oneCluster.toString()); sb.append(", "); sb.append(twoCluster.toString()); sb.append(" )"); } return sb.toString(); } public void setLeafNode(Node n){ leafNode = n; } public Node getLeafNode(){ return leafNode; } public void setRenderedNode(Node renderN) { renderedNode = renderN; } public Node getRenderedNode() { if (leafNode != null) //return leafnode so it has the right name return leafNode; else return renderedNode; } public boolean isNodeCluster(){ return (leafNode != null); } }