1   
28  package demo.layout.router;
29  
30  import y.algo.Trees;
31  import y.base.DataAcceptor;
32  import y.base.DataProvider;
33  import y.base.Edge;
34  import y.base.EdgeCursor;
35  import y.base.EdgeList;
36  import y.base.EdgeMap;
37  import y.base.Graph;
38  import y.base.Node;
39  import y.base.NodeCursor;
40  import y.base.NodeList;
41  import y.base.YList;
42  import y.geom.YPoint;
43  import y.layout.LayoutGraph;
44  import y.layout.router.BusDescriptor;
45  import y.layout.router.BusRepresentations;
46  import y.layout.router.BusRouter;
47  import y.util.DataProviderAdapter;
48  import y.util.DataProviders;
49  import y.util.GraphHider;
50  import y.util.Maps;
51  import y.view.Graph2D;
52  
53  import javax.swing.JOptionPane;
54  import java.awt.Color;
55  import java.awt.Component;
56  import java.util.HashMap;
57  import java.util.Iterator;
58  import java.util.List;
59  import java.util.Map;
60  
61  
67  public class HubRoutingSupport {
68    private final BusRouterDemoModule module;
69  
70    public HubRoutingSupport() {
71          module = new BusRouterDemoModule();
73      module.getLayoutExecutor().setLockingView(true);
74      module.getLayoutExecutor().getNodePortConfigurator().setAutomaticPortConstraintsEnabled(true);
75          module.getLayoutExecutor().setBackupRealizersEnabled(false);
77    }
78  
79    BusRouterDemoModule getModule() {
80      return module;
81    }
82  
83    
88    public void doLayout(final Graph2D graph, final int mode) {
89      graph.firePreEvent();
90      try {
91        doLayoutImpl(graph, mode);
92      } finally {
93        graph.firePostEvent();
94      }
95    }
96  
97    
102   protected void doLayoutImpl(final Graph2D graph, final int mode) {
103     final EdgeMap edgeDescriptors = graph.createEdgeMap();
104     final EdgeMap edgeIdMap = graph.createEdgeMap();
105 
106         try {
108       storeOriginalEdges(graph);
109 
110             EdgeList scopeList;
112       try {
113         scopeList = replaceHubs(graph, edgeDescriptors, mode);
114       } catch (IllegalArgumentException e) {
115         String message = "Warning: " + e.getMessage() + "\n" +
116             "The routing of only the moved or new elements failed since the remainder is\n" +
117             "not a valid bus. All selected buses will be routed completely anew instead.";
118         JOptionPane.showMessageDialog((Component) graph.getCurrentView(), message, "Automatic Routing",
119             JOptionPane.INFORMATION_MESSAGE);
120         doLayoutImpl(graph, BusRouterDemo.MODE_SELECTED);
121         return;
122       }
123 
124             switch (mode) {
126         case BusRouterDemo.MODE_SELECTED:
127         case BusRouterDemo.MODE_PARTIAL:
128           module.setScope(BusRouter.SCOPE_SUBSET);
129           graph.addDataProvider(BusRouter.EDGE_SUBSET_DPKEY, new DataProviderAdapter() {
130             public boolean getBool(Object dataHolder) {
131               return edgeDescriptors.get(dataHolder) != null;
132             }
133           });
134           break;
135         case BusRouterDemo.MODE_ALL:
136         default:
137           module.setScope(BusRouter.SCOPE_ALL);
138           break;
139       }
140       graph.addDataProvider(BusRouter.EDGE_DESCRIPTOR_DPKEY, edgeDescriptors);
141       module.start(graph);
142 
143             BusRepresentations.replaceSubgraphByHubs(graph, scopeList.edges(), edgeDescriptors, edgeIdMap);
145       restoreOriginalEdges(graph);
146     } finally {
147       graph.removeDataProvider(BusRouter.EDGE_DESCRIPTOR_DPKEY);
148       graph.removeDataProvider(BusRouter.EDGE_SUBSET_DPKEY);
149 
150       graph.disposeEdgeMap(edgeDescriptors);
151       graph.disposeEdgeMap(edgeIdMap);
152     }
153   }
154 
155   
162   protected void storeOriginalEdges(Graph graph) {
163     EdgeMap sourcePointIdMap = Maps.createHashedEdgeMap();
164     graph.addDataProvider(BusRepresentations.SOURCE_ID_DPKEY, sourcePointIdMap);
165     EdgeMap targetPointIdMap = Maps.createHashedEdgeMap();
166     graph.addDataProvider(BusRepresentations.TARGET_ID_DPKEY, targetPointIdMap);
167 
168     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
169       final Edge edge = ec.edge();
170       if (!BusRouterDemo.isHub(edge.source())) {
171         sourcePointIdMap.set(edge, edge);
172       }
173       if (!BusRouterDemo.isHub(edge.target())) {
174         targetPointIdMap.set(edge, edge);
175       }
176     }
177   }
178 
179   
184   protected void restoreOriginalEdges(LayoutGraph graph) {
185     final DataProvider sourceDataProvider = graph.getDataProvider(BusRepresentations.SOURCE_ID_DPKEY);
186     final DataProvider targetDataProvider = graph.getDataProvider(BusRepresentations.TARGET_ID_DPKEY);
187 
188     try {
189             for (EdgeCursor ec = new EdgeList(graph.edges()).edges(); ec.ok(); ec.next()) {
191         final Edge edge = ec.edge();
192         final Edge sourceEdge = (Edge) sourceDataProvider.get(edge);
193         final Edge targetEdge = (Edge) targetDataProvider.get(edge);
194         if (sourceEdge != null && sourceEdge.getGraph() == null && !BusRouterDemo.isHub(edge.source())) {
195                     graph.changeEdge(sourceEdge, edge.source(), edge.target());
197           graph.reInsertEdge(sourceEdge);
198           graph.setPath(sourceEdge, graph.getPath(edge));
199           graph.removeEdge(edge);
200         }
201         if (targetEdge != null && targetEdge.getGraph() == null && !BusRouterDemo.isHub(edge.target())) {
202                     graph.changeEdge(targetEdge, edge.source(), edge.target());
204           graph.reInsertEdge(targetEdge);
205           graph.setPath(targetEdge, graph.getPath(edge));
206           graph.removeEdge(edge);
207         }
208       }
209     } finally {
210       graph.removeDataProvider(BusRepresentations.SOURCE_ID_DPKEY);
211       graph.removeDataProvider(BusRepresentations.TARGET_ID_DPKEY);
212     }
213   }
214 
215   
229   protected EdgeList replaceHubs(Graph2D graph, EdgeMap busDescriptors, final int mode) {
230     final DataProvider hubDP = graph.getDataProvider(BusRouterDemo.HUB_MARKER_DPKEY);
231 
232         EdgeMap movableMarker = graph.createEdgeMap();
234 
235             GraphHider hider = new GraphHider(graph);
238     List selectedBuses = new YList();
239 
240         try {
242       final EdgeList[] busEdgesArray = calculateBusComponents(graph);
243       hider.hideAll();
244 
245             for (int i = 0; i < busEdgesArray.length; i++) {
247         final EdgeList busEdges = busEdgesArray[i];
248         final NodeList busNodes = new NodeList();
249         for (EdgeCursor ec = busEdges.edges(); ec.ok(); ec.next()) {
250           busNodes.add(ec.edge().source());
251           busNodes.add(ec.edge().target());
252         }
253         hider.unhideNodes(busNodes, false);
254         hider.unhideEdges(busEdges);
255 
256         if (mode == BusRouterDemo.MODE_SELECTED) {
257           for (EdgeCursor ec = busEdges.edges(); ec.ok(); ec.next()) {
258             final Edge edge = ec.edge();
259             if (graph.isSelected(edge) || graph.isSelected(edge.source()) || graph.isSelected(edge.target())) {
260               selectedBuses.add(busEdges);
261               break;
262             }
263           }
264         } else if (mode == BusRouterDemo.MODE_PARTIAL) {
265           if (markMoveableEdges(graph, movableMarker)) {
266             selectedBuses.add(busEdges);
267           }
268         } else {
269           selectedBuses.add(busEdges);
270         }
271 
272         hider.hideAll();
273       }
274     } catch (RuntimeException e) {
275             e.printStackTrace();
277     } finally {
278       hider.unhideAll();
279     }
280 
281             Map idToColor = new HashMap();
284     for (Iterator listIter = selectedBuses.iterator(); listIter.hasNext(); ) {
285       final EdgeList edgeList = (EdgeList) listIter.next();
286       idToColor.put(new Integer(idToColor.size()), graph.getRealizer(edgeList.firstEdge()).getLineColor());
287     }
288 
289         NodeList singletonHubs = new NodeList();
291     for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
292       final Node node = nc.node();
293       if (hubDP.getBool(node) && node.degree() == 0) {
294         singletonHubs.add(node);
295       }
296     }
297     for (NodeCursor nc = singletonHubs.nodes(); nc.ok(); nc.next()) {
298       graph.removeNode(nc.node());
299     }
300 
301         final EdgeList[] selectedBusesArray = (EdgeList[]) selectedBuses.toArray(new EdgeList[selectedBuses.size()]);
303     final EdgeList subGraphEdges = BusRepresentations.replaceHubsBySubgraph(graph, selectedBusesArray,
304         hubDP,
305         mode == BusRouterDemo.MODE_PARTIAL ?
306             DataProviders.createNegatedDataProvider(movableMarker) :
307             DataProviders.createConstantDataProvider(Boolean.FALSE),
308         busDescriptors);
309 
310             for (EdgeCursor ec = subGraphEdges.edges(); ec.ok(); ec.next()) {
313       final Edge edge = ec.edge();
314       final BusDescriptor descriptor = (BusDescriptor) busDescriptors.get(edge);
315       graph.getRealizer(edge).setLineColor((Color) idToColor.get(descriptor.getID()));
316     }
317 
318     return subGraphEdges;
319   }
320 
321   
333   protected boolean markMoveableEdges(Graph2D graph, DataAcceptor moveableMarker) {
334     final DataProvider hubDP = graph.getDataProvider(BusRouterDemo.HUB_MARKER_DPKEY);
335 
336     boolean containsMoveable = false;
337 
338             GraphHider hider = new GraphHider(graph);
341     for (EdgeCursor ec = new EdgeList(graph.edges()).edges(); ec.ok(); ec.next()) {
342       final Edge edge = ec.edge();
343       if (!graph.contains(edge) || (hubDP.getBool(edge.source()) && hubDP.getBool(edge.target()))
344           || !(graph.isSelected(edge) || (graph.isSelected(edge.source()) && !hubDP.getBool(edge.source()))
345           || (graph.isSelected(edge.target()) && !hubDP.getBool(edge.target())))) {
346                 continue;
348       }
349 
350       containsMoveable = true;
351       moveableMarker.setBool(edge, true);
352       Node node = hubDP.getBool(edge.source()) ? edge.source() : edge.target();
353       hider.hide(edge);
354 
355       while (node != null && node.degree() == 1) {
356         final Edge chainEdge = node.inDegree() > 0 ? node.firstInEdge() : node.firstOutEdge();
357         final Node opposite = chainEdge.opposite(node);
358 
359         if (hubDP.getBool(opposite)) {
360           moveableMarker.setBool(chainEdge, true);
361           hider.hide(chainEdge);
362           node = opposite;
363         } else {
364           node = null;
365         }
366       }
367     }
368 
369     if (!containsMoveable) {
370       hider.unhideAll();
371       return false;
372     }
373 
374             EdgeList nodeLinks = new EdgeList();
377     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
378       final Edge edge = ec.edge();
379       if (!hubDP.getBool(edge.source()) || !hubDP.getBool(edge.target())) {
380         nodeLinks.add(edge);
381       }
382     }
383     hider.hide(nodeLinks);
384     if (!Trees.isForest(graph)) {
385       hider.unhideAll();
386       throw new IllegalArgumentException("Fixed subgraph is not a connected tree.");
387     }
388     hider.unhideEdges(nodeLinks);
389 
390     if (!isOrthogonal(graph)) {
391       hider.unhideAll();
392       throw new IllegalArgumentException("Fixed subgraph is not orthogonal.");
393     }
394 
395     hider.unhideAll();
396     return true;
397   }
398 
399   
402   protected EdgeList[] calculateBusComponents(LayoutGraph graph) {
403     return BusRepresentations.toEdgeLists(graph, graph.getDataProvider(BusRouterDemo.HUB_MARKER_DPKEY));
404   }
405 
406   
412   private static boolean isOrthogonal(final LayoutGraph graph) {
413     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
414       final YPoint[] path = graph.getPath(ec.edge()).toArray();
415       for (int i = 1; i < path.length; i++) {
416         final YPoint p1 = path[i - 1];
417         final YPoint p2 = path[i];
418         if (Math.abs(p1.x - p2.x) > 1.0e-5 && Math.abs(p1.y - p2.y) > 1.0e-5) {
419           return false;
420         }
421       }
422     }
423     return true;
424   }
425 }
426