1
28 package demo.view.isometry;
29
30 import y.algo.NodeOrders;
31 import y.base.Edge;
32 import y.base.EdgeCursor;
33 import y.base.Graph;
34 import y.base.ListCell;
35 import y.base.Node;
36 import y.base.NodeCursor;
37 import y.base.NodeList;
38 import y.base.NodeMap;
39 import y.base.YList;
40 import y.view.Bend;
41 import y.view.EdgeLabel;
42 import y.view.EdgeRealizer;
43 import y.view.GenericNodeRealizer;
44 import y.view.Graph2D;
45 import y.view.Graph2DTraversal;
46 import y.view.NodeLabel;
47 import y.view.NodePort;
48 import y.view.NodeRealizer;
49 import y.view.Port;
50 import y.view.hierarchy.HierarchyManager;
51
52 import java.awt.geom.Point2D;
53 import java.awt.geom.Rectangle2D;
54 import java.util.ArrayList;
55 import java.util.Collections;
56 import java.util.Iterator;
57 import java.util.List;
58
59
76 public class IsometryGraphTraversal implements Graph2DTraversal {
77 public Iterator firstToLast(Graph2D graph, int elementTypes) {
78 final List allElements = collectAllGraphElements(graph);
79 final List filteredElements = filterGraphElements(allElements, elementTypes);
80 return filteredElements.iterator();
81 }
82
83 public Iterator lastToFirst(Graph2D graph, int elementTypes) {
84 final List allElements = collectAllGraphElements(graph);
85 final List filteredElements = filterGraphElements(allElements, elementTypes);
86 Collections.reverse(filteredElements);
87 return filteredElements.iterator();
88 }
89
90
93 private static List collectAllGraphElements(final Graph2D graph) {
94 final ArrayList graphElements = new ArrayList();
95 final ArrayList normalNodesAndEdgeLabels = new ArrayList();
96
97 final HierarchyManager hierarchyManager = graph.getHierarchyManager();
100 if (hierarchyManager != null) {
101 for (Iterator it = hierarchyManager.preTraversal(); it.hasNext(); ) {
102 final Node node = (Node) it.next();
103 if (hierarchyManager.isNormalNode(node)) {
104 normalNodesAndEdgeLabels.add(node);
105 } else {
106 graphElements.add(node);
107 final NodeRealizer realizer = graph.getRealizer(node);
108 for (int i = 0; i < realizer.portCount(); i++) {
109 graphElements.add(realizer.getPort(i));
110 }
111 for (int i = 0; i < realizer.labelCount(); i++) {
112 graphElements.add(realizer.getLabel(i));
113 }
114 }
115 }
116 }
117
118 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
120 final Edge edge = ec.edge();
121 graphElements.add(edge);
122 final EdgeRealizer realizer = graph.getRealizer(edge);
123 for (int i = 0; i < realizer.bendCount(); i++) {
124 graphElements.add(realizer.getBend(i));
125 }
126 graphElements.add(realizer.getSourcePort());
127 graphElements.add(realizer.getTargetPort());
128 for (int i = 0; i < realizer.labelCount(); i++) {
129 normalNodesAndEdgeLabels.add(realizer.getLabel(i));
130 }
131 }
132
133 sort(normalNodesAndEdgeLabels);
135
136 for (Iterator it = normalNodesAndEdgeLabels.iterator(); it.hasNext(); ) {
138 final Object element = it.next();
139 graphElements.add(element);
140 if (element instanceof Node) {
141 final NodeRealizer realizer = graph.getRealizer((Node) element);
142 for (int i = 0; i < realizer.portCount(); i++) {
143 graphElements.add(realizer.getPort(i));
144 }
145 for (int i = 0; i < realizer.labelCount(); i++) {
146 graphElements.add(realizer.getLabel(i));
147 }
148 }
149 }
150
151 return graphElements;
152 }
153
154
157 private static List filterGraphElements(final List graphElements, final int elementTypes) {
158 if (elementTypes == ALL) {
159 return new ArrayList(graphElements);
161 }
162
163 final ArrayList filteredElements = new ArrayList();
164 for (Iterator it = graphElements.iterator(); it.hasNext(); ) {
165 final Object element = it.next();
166
167 if ((element instanceof Node && (elementTypes & NODES) != 0)
169 || (element instanceof Edge && (elementTypes & EDGES) != 0)
170 || (element instanceof NodeLabel && (elementTypes & NODE_LABELS) != 0)
171 || (element instanceof EdgeLabel && (elementTypes & EDGE_LABELS) != 0)
172 || (element instanceof Bend && (elementTypes & BENDS) != 0)
173 || (element instanceof Port && (elementTypes & PORTS) != 0)
174 || (element instanceof NodePort && (elementTypes & NODE_PORTS) != 0)) {
175 filteredElements.add(element);
176 }
177 }
178 return filteredElements;
179 }
180
181
189 private static void sort(List elements) {
190 final Graph constraintsGraph = new Graph();
191 final NodeMap constraints2graph = constraintsGraph.createNodeMap();
192 final NodeMap node2rectangle = constraintsGraph.createNodeMap();
193 final ArrayList events = new ArrayList();
194
195 for (Iterator it = elements.iterator(); it.hasNext(); ) {
197 final Object element = it.next();
198 final Rectangle2D bounds = getBounds(element);
199 final Node constraintsNode = constraintsGraph.createNode();
200 constraints2graph.set(constraintsNode, element);
201 node2rectangle.set(constraintsNode, bounds);
202 final double boundsX = bounds.getX();
203 final double boundsY = bounds.getY();
204 events.add(new SweeplineEvent(boundsX, boundsY, constraintsNode, true));
205 events.add(new SweeplineEvent(boundsX + bounds.getWidth(), boundsY + bounds.getHeight(), constraintsNode, false));
206 }
207
208 Collections.sort(events);
210
211 final YList currentElements = new YList();
213 for (Iterator it = events.iterator(); it.hasNext(); ) {
214 final SweeplineEvent event = (SweeplineEvent) it.next();
215 if (event.open) {
216 final ListCell successor = findSuccessor(currentElements, event.coordX, event.coordY, node2rectangle);
219 ListCell cell;
220 if (successor != null) {
221 cell = currentElements.insertBefore(event.node, successor);
222 constraintsGraph.createEdge((Node) successor.getInfo(), event.node);
223 } else {
224 cell = currentElements.addLast(event.node);
225 }
226 if (cell.pred() != null) {
227 constraintsGraph.createEdge(event.node, (Node) cell.pred().getInfo());
228 }
229 } else {
230 final ListCell cell = currentElements.findCell(event.node);
233 if (cell.pred() != null && cell.succ() != null) {
234 constraintsGraph.createEdge((Node) cell.succ().getInfo(), (Node) cell.pred().getInfo());
235 }
236 currentElements.removeCell(cell);
237 }
238 }
239
240 elements.clear();
242 final NodeList topological = NodeOrders.topological(constraintsGraph);
243 for (NodeCursor nc = topological.nodes(); nc.ok(); nc.next()) {
244 final Node constraintNode = nc.node();
245 if (constraints2graph.get(constraintNode) != null) {
246 elements.add(constraints2graph.get(constraintNode));
247 }
248 }
249
250 constraintsGraph.disposeNodeMap(constraints2graph);
252 constraintsGraph.disposeNodeMap(node2rectangle);
253 }
254
255
258 private static ListCell findSuccessor(YList list, double coordX, double coordY, NodeMap node2rectangle) {
259 if (!list.isEmpty()) {
260 for (ListCell cell = list.firstCell(); cell != null; cell = cell.succ()) {
261 final Node node = (Node) cell.getInfo();
262 final Rectangle2D rect = (Rectangle2D) node2rectangle.get(node);
263
264 final double intersectionY = coordX + coordY - (rect.getX() + rect.getWidth());
267
268 double refY;
269 if (intersectionY < rect.getY()) {
270 refY = rect.getY();
273 } else {
274 refY = intersectionY;
277 }
278
279 if (refY < coordY) {
280 return cell;
282 }
283 }
284 }
285 return null;
286 }
287
288
291 private static Rectangle2D getBounds(Object element) {
292 if (element instanceof Node) {
293 final Node node = (Node) element;
294 final Graph2D graph = (Graph2D) node.getGraph();
295 final NodeRealizer realizer = graph.getRealizer(node);
296 if (realizer instanceof GenericNodeRealizer) {
297 final IsometryData isometryData = (IsometryData) ((GenericNodeRealizer) realizer).getUserData();
298
299 final double[] corners = new double[16];
300 isometryData.calculateCorners(corners);
301 IsometryData.moveTo(realizer.getX(), realizer.getY(), corners);
302 final double x = IsometryData.toLayoutX(corners[IsometryData.C0_X], corners[IsometryData.C0_Y]);
303 final double y = IsometryData.toLayoutY(corners[IsometryData.C0_X], corners[IsometryData.C0_Y]);
304 final double w = isometryData.getWidth();
305 final double h = isometryData.getDepth();
306 return new Rectangle2D.Double(x, y, w, h);
307 }
308 } else if (element instanceof EdgeLabel) {
309 final EdgeLabel label = (EdgeLabel) element;
310 final Graph2D graph = (Graph2D) label.getEdge().getGraph();
311 final Point2D sourceIntersection = graph.getRealizer(label.getEdge()).getSourceIntersection();
312 final IsometryData isometryData = (IsometryData) label.getUserData();
313 final double[] corners = new double[16];
314 isometryData.calculateCorners(corners);
315 IsometryData.moveTo(label.getOffsetX() + sourceIntersection.getX(),
316 label.getOffsetY() + sourceIntersection.getY(), corners);
317
318 double x, y, w, h;
319 if (isometryData.isHorizontal()) {
320 x = IsometryData.toLayoutX(corners[IsometryData.C0_X], corners[IsometryData.C0_Y]);
321 y = IsometryData.toLayoutY(corners[IsometryData.C0_X], corners[IsometryData.C0_Y]);
322 w = isometryData.getWidth();
323 h = 0;
324 } else {
325 x = IsometryData.toLayoutX(corners[IsometryData.C1_X], corners[IsometryData.C1_Y]);
326 y = IsometryData.toLayoutY(corners[IsometryData.C1_X], corners[IsometryData.C1_Y]);
327 w = 0;
328 h = isometryData.getDepth();
329 }
330 return new Rectangle2D.Double(x, y, w, h);
331 }
332
333 return null;
334 }
335
336
339 private static class SweeplineEvent implements Comparable {
340 double coordX;
341 double coordY;
342 Node node;
343 boolean open;
344
345 private SweeplineEvent(double coordX, double coordY, Node node, boolean open) {
346 this.coordX = coordX;
347 this.coordY = coordY;
348 this.node = node;
349 this.open = open;
350 }
351
352 public int compareTo(Object o) {
353 final SweeplineEvent other = (SweeplineEvent) o;
354
355 final double thisCoord = coordX + coordY;
356 final double otherCoord = other.coordX + other.coordY;
357
358 if (thisCoord < otherCoord) {
359 return -1;
360 } else if (thisCoord > otherCoord) {
361 return 1;
362 } else {
363 return 0;
364 }
365 }
366 }
367 }
368