001package horstmann.ch08_graphed; 002import java.awt.Graphics2D; 003import java.awt.geom.Point2D; 004import java.awt.geom.Rectangle2D; 005import java.io.Serializable; 006import java.util.ArrayList; 007import java.util.Collections; 008import java.util.List; 009 010/** 011 A graph consisting of selectable nodes and edges. 012 */ 013public abstract class Graph implements Serializable 014{ 015 private static final long serialVersionUID = 2008L; 016 /** 017 Constructs a graph with no nodes or edges. 018 */ 019 public Graph() 020 { 021 nodes = new ArrayList<Node>(); 022 edges = new ArrayList<Edge>(); 023 } 024 025 /** 026 Adds an edge to the graph that joins the nodes containing 027 the given points. If the points aren't both inside nodes, 028 then no edge is added. 029 @param e the edge to add 030 @param p1 a point in the starting node 031 @param p2 a point in the ending node 032 */ 033 public boolean connect(Edge e, Point2D p1, Point2D p2) 034 { 035 Node n1 = findNode(p1); 036 Node n2 = findNode(p2); 037 if (n1 != null && n2 != null) 038 { 039 e.connect(n1, n2); 040 edges.add(e); 041 return true; 042 } 043 return false; 044 } 045 046 /** 047 Adds a node to the graph so that the top left corner of 048 the bounding rectangle is at the given point. 049 @param n the node to add 050 @param p the desired location 051 */ 052 public boolean add(Node n, Point2D p) 053 { 054 Rectangle2D bounds = n.getBounds(); 055 n.translate(p.getX() - bounds.getX(), 056 p.getY() - bounds.getY()); 057 nodes.add(n); 058 return true; 059 } 060 061 /** 062 Finds a node containing the given point. 063 @param p a point 064 @return a node containing p or null if no nodes contain p 065 */ 066 public Node findNode(Point2D p) 067 { 068 for (int i = nodes.size() - 1; i >= 0; i--) 069 { 070 Node n = nodes.get(i); 071 if (n.contains(p)) return n; 072 } 073 return null; 074 } 075 076 /** 077 Finds an edge containing the given point. 078 @param p a point 079 @return an edge containing p or null if no edges contain p 080 */ 081 public Edge findEdge(Point2D p) 082 { 083 for (int i = edges.size() - 1; i >= 0; i--) 084 { 085 Edge e = edges.get(i); 086 if (e.contains(p)) return e; 087 } 088 return null; 089 } 090 091 /** 092 Draws the graph 093 @param g2 the graphics context 094 */ 095 public void draw(Graphics2D g2) 096 { 097 for (Node n : nodes) 098 n.draw(g2); 099 100 for (Edge e : edges) 101 e.draw(g2); 102 103 } 104 105 /** 106 Removes a node and all edges that start or end with that node 107 @param n the node to remove 108 */ 109 public void removeNode(Node n) 110 { 111 for (int i = edges.size() - 1; i >= 0; i--) 112 { 113 Edge e = edges.get(i); 114 if (e.getStart() == n || e.getEnd() == n) 115 edges.remove(e); 116 } 117 nodes.remove(n); 118 } 119 120 /** 121 Removes an edge from the graph. 122 @param e the edge to remove 123 */ 124 public void removeEdge(Edge e) 125 { 126 edges.remove(e); 127 } 128 129 /** 130 Gets the smallest rectangle enclosing the graph 131 @param g2 the graphics context 132 @return the bounding rectangle 133 */ 134 public Rectangle2D getBounds(Graphics2D g2) 135 { 136 Rectangle2D r = null; 137 for (Node n : nodes) 138 { 139 Rectangle2D b = n.getBounds(); 140 if (r == null) r = b; 141 else r.add(b); 142 } 143 for (Edge e : edges) 144 r.add(e.getBounds(g2)); 145 return r == null ? new Rectangle2D.Double() : r; 146 } 147 148 /** 149 Gets the node types of a particular graph type. 150 @return an array of node prototypes 151 */ 152 public abstract Node[] getNodePrototypes(); 153 154 /** 155 Gets the edge types of a particular graph type. 156 @return an array of edge prototypes 157 */ 158 public abstract Edge[] getEdgePrototypes(); 159 160 /** 161 Gets the nodes of this graph. 162 @return an unmodifiable list of the nodes 163 */ 164 public List<Node> getNodes() 165 { 166 return Collections.unmodifiableList(nodes); } 167 168 /** 169 Gets the edges of this graph. 170 @return an unmodifiable list of the edges 171 */ 172 public List<Edge> getEdges() 173 { 174 return Collections.unmodifiableList(edges); 175 } 176 177 private ArrayList<Node> nodes; 178 private ArrayList<Edge> edges; 179} 180 181 182 183 184