1   
28  package demo.layout.router;
29  
30  import y.base.DataMap;
31  import y.base.DataProvider;
32  import y.base.Edge;
33  import y.base.EdgeCursor;
34  import y.base.EdgeList;
35  import y.base.GraphEvent;
36  import y.base.GraphListener;
37  import y.base.Node;
38  import y.base.NodeCursor;
39  import y.base.NodeList;
40  import y.layout.LayoutGraph;
41  import y.layout.router.BusRepresentations;
42  import y.util.Maps;
43  import y.util.pq.IntObjectPQ;
44  import y.view.Graph2D;
45  import y.view.NodeRealizer;
46  
47  import java.awt.Color;
48  import java.util.Random;
49  
50  
54  public class BusDyer implements GraphListener {
55    private final Graph2D graph;
56    private final DataProvider hubMarker;
57    private final IntObjectPQ availableColorsPQ;
58    private final int predefinedColorsCount;
59    private int eventCount;
60  
61    
66    public BusDyer(Graph2D graph) {
67      this.graph = graph;
68      this.hubMarker = graph.getDataProvider(BusRouterDemo.HUB_MARKER_DPKEY);
69  
70      this.eventCount = 0;
71      this.predefinedColorsCount = 50;
72      DataMap backingStore = Maps.createHashedDataMap();
73      this.availableColorsPQ = new IntObjectPQ(predefinedColorsCount, backingStore, backingStore);
74      resetColors();
75    }
76  
77    
80    public void colorize() {
81      colorize(null);
82    }
83  
84    
91    public void colorize(DataProvider colorProvider) {
92      resetColors();
93  
94          final NodeList isolatedHubList = new NodeList();
96      for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
97        final Node node = nc.node();
98        if (node.degree() == 0 && hubMarker.getBool(node)) {
99          isolatedHubList.add(node);
100       }
101     }
102     final Node[] isolatedHubs = isolatedHubList.toNodeArray();
103 
104         final EdgeList[] edgeLists = calculateBusComponents(graph);
106     final Color[] busColors = new Color[edgeLists.length + isolatedHubs.length];
107     for (int i = 0; i < edgeLists.length; i++) {
108       final EdgeList edgeList = edgeLists[i];
109       Color descriptorColor = null;
110       Color presentColor = null;
111       for (EdgeCursor ec = edgeList.edges(); ec.ok(); ec.next()) {
112         final Edge edge = ec.edge();
113         if (colorProvider != null && colorProvider.get(edge) != null) {
114           descriptorColor = (Color) colorProvider.get(edge);
115           break;
116         }
117         final Color lineColor = graph.getRealizer(edge).getLineColor();
118         if (presentColor == null && !lineColor.equals(Color.BLACK)) {
119           presentColor = lineColor;
120         }
121         Color sourceFill = graph.getRealizer(edge.source()).getFillColor();
122         if (presentColor == null && !sourceFill.equals(Color.BLACK)) {
123           presentColor = sourceFill;
124         }
125         Color targetFill = graph.getRealizer(edge.target()).getFillColor();
126         if (presentColor == null && !targetFill.equals(Color.BLACK)) {
127           presentColor = targetFill;
128         }
129         if (presentColor != null && colorProvider == null) {
130           break;
131         }
132       }
133 
134       if (descriptorColor != null && isAvailable(descriptorColor)) {
135         busColors[i] = descriptorColor;
136         use(descriptorColor);
137       } else if (presentColor != null && isAvailable(presentColor)) {
138         busColors[i] = presentColor;
139         use(presentColor);
140       }
141     }
142 
143         for (int i = 0; i < isolatedHubs.length; i++) {
145       final Node isolatedHub = isolatedHubs[i];
146       final Color fillColor = graph.getRealizer(isolatedHub).getFillColor();
147       if (!fillColor.equals(Color.BLACK) && isAvailable(fillColor)) {
148         busColors[edgeLists.length + i] = fillColor;
149         use(fillColor);
150       }
151     }
152 
153         for (int i = 0; i < busColors.length; i++) {
155       if (busColors[i] == null) {
156         busColors[i] = useNextColor();
157       }
158     }
159 
160         for (int i = 0; i < edgeLists.length; i++) {
162       final EdgeList edgeList = edgeLists[i];
163       final Color color = busColors[i];
164       for (EdgeCursor ec = edgeList.edges(); ec.ok(); ec.next()) {
165         final Edge edge = ec.edge();
166         graph.getRealizer(edge).setLineColor(color);
167         colorizeHub(edge.source(), color);
168         colorizeHub(edge.target(), color);
169       }
170     }
171 
172         for (int i = 0; i < isolatedHubs.length; i++) {
174       colorizeHub(isolatedHubs[i], busColors[edgeLists.length + i]);
175     }
176   }
177 
178   
182   public void onGraphEvent(GraphEvent e) {
183     switch (e.getType()) {
184       case GraphEvent.PRE_EVENT:
185         eventCount++;
186         break;
187       case GraphEvent.POST_EVENT:
188         eventCount--;
189         break;
190       case GraphEvent.NODE_CREATION:
191       case GraphEvent.NODE_REINSERTION:
192       case GraphEvent.PRE_NODE_REMOVAL:
193       case GraphEvent.POST_NODE_REMOVAL:
194         return;       default:
196     }
197 
198     if (eventCount == 0) {
199       colorize();
200     }
201   }
202 
203   
206   protected EdgeList[] calculateBusComponents(LayoutGraph graph) {
207     return BusRepresentations.toEdgeLists(graph, graph.getDataProvider(BusRouterDemo.HUB_MARKER_DPKEY));
208   }
209 
210   
216   private void colorizeHub(Node node, Color newColor) {
217     if (!hubMarker.getBool(node)) {
218       return;
219     }
220     final NodeRealizer realizer = graph.getRealizer(node);
221     realizer.setFillColor(newColor);
222     realizer.setLineColor(newColor);
223   }
224 
225   
228   private void resetColors() {
229     availableColorsPQ.clear();
230 
231     Color[] colors = Colors.getColors(predefinedColorsCount + 1);
232     for (int i = 1; i < colors.length; i++) {       final Color color = colors[i];
234       availableColorsPQ.add(color, i - 1);
235     }
236   }
237 
238   
243   private Color useNextColor() {
244     if (availableColorsPQ.isEmpty()) {
245       return Colors.getRandomColor();
246     } else {
247       return (Color) availableColorsPQ.removeMin();
248     }
249   }
250 
251   
256   private void use(final Color color) {
257     if (isAvailable(color)) {
258       availableColorsPQ.remove(color);
259     }
260   }
261 
262   
268   private boolean isAvailable(final Color color) {
269     return availableColorsPQ.contains(color);
270   }
271 
272   
275   static class Colors {
276 
277         private static final Color[] COLORS = {new Color(0x000000), new Color(0xBF0404), new Color(0x009EFF),
279         new Color(0x1B8C48), new Color(0xB300C2), new Color(0xFF6405), new Color(0x2B4BFA), new Color(0x8C6048),
280         new Color(0xFAAFE8), new Color(0xB1D95B), new Color(0xBBB082), new Color(0xFAEE00), new Color(0xAAAAAA),
281         new Color(0x00FFC9), new Color(0x5B519C), new Color(0x666666)};
282 
283     private static final Random RANDOM = new Random(1234L);
284 
285     
288     private Colors() {
289     }
290 
291     
298     static Color[] getColors(int count) {
299       Color[] r = new Color[count];
300       final int numColors = COLORS.length;
301       System.arraycopy(COLORS, 0, r, 0, Math.min(count, numColors));
302       if (count > numColors) {
303         double div = Math.ceil((double) (count / numColors)) + 1.0;
304         for (int i = numColors; i < count; i++) {
305           int j = i % numColors;
306           int k = (j + 1) % numColors;
307           Color c1 = COLORS[j];
308           Color c2 = COLORS[k];
309           double f = 1.0 / div * Math.ceil((double) (i / numColors));
310           r[i] = blendColors(c1, c2, f);
311         }
312       }
313       return r;
314     }
315 
316     
321     static Color getRandomColor() {
322       return new Color(RANDOM.nextFloat(), RANDOM.nextFloat(), RANDOM.nextFloat());
323     }
324 
325     
330     private static Color blendColors(Color c1, Color c2, double div) {
331       int dr = (int) ((double) (c2.getRed() - c1.getRed()) * div);
332       int dg = (int) ((double) (c2.getGreen() - c1.getGreen()) * div);
333       int db = (int) ((double) (c2.getBlue() - c1.getBlue()) * div);
334       return new Color(c1.getRed() + dr, c1.getGreen() + dg, c1.getBlue() + db);
335     }
336 
337   }
338 
339 }
340