]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/LayerComposition.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / multileveldiagram / LayerComposition.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g2d.multileveldiagram;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collections;\r
16 import java.util.Iterator;\r
17 import java.util.List;\r
18 \r
19 import org.simantics.g2d.diagram.IDiagram;\r
20 import org.simantics.g2d.diagram.impl.Diagram;\r
21 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
22 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
23 \r
24 /**\r
25  * This class describes a composition of a multi-layer diagram. \r
26  * \r
27  * @author Toni Kalajainen\r
28  */\r
29 public class LayerComposition {\r
30 \r
31         /** Diagram hint, MorphHandlers read this key from the diagram */\r
32         public static final Key KEY_PHASE = new KeyOf(MorphPhase.class);\r
33         \r
34         /** Transition function */\r
35         TransitionFunction function = TransitionFunction.SIGMOID; \r
36         \r
37         /** Diagramming info */\r
38         ArrayList<Node> nodes = new ArrayList<Node>();\r
39         /** All diagrams */\r
40         ArrayList<IDiagram> diagrams = new ArrayList<IDiagram>();\r
41         /** Zoom levels */\r
42         MorphLevel[] levels = null;\r
43         \r
44         /**\r
45          * Add a new diagram to the composition.\r
46          * The top most diagram has startZoom open-ended, and the bottom diagram\r
47          * has endZoom open-ended.\r
48          * \r
49          * @param diagram\r
50          * @param startZoom startZoom in percents or null if open-ended\r
51          * @param endZoom endZoom in percents or null if open-ended\r
52          */\r
53         public void addLayer(IDiagram diagram, Double startZoom, Double endZoom)\r
54         {\r
55                 assert(diagram!=null);          \r
56                 if (startZoom!=null && endZoom!=null)\r
57                         assert(startZoom<endZoom);\r
58                 assert(startZoom!=null || endZoom!=null);\r
59                 if (startZoom!=null) {\r
60                         nodes.add(new Node(diagram, startZoom));\r
61                 }\r
62                 if (endZoom!=null) {\r
63                         nodes.add(new Node(diagram, endZoom));\r
64                 }\r
65                 levels = null;\r
66         }\r
67         \r
68         public void removeLayer(IDiagram diagram)\r
69         {\r
70                 Iterator<Node> i = nodes.iterator();\r
71                 while (i.hasNext()) {\r
72                         Node n = i.next();\r
73                         if (n.diagram == diagram)\r
74                                 i.remove();\r
75                 }\r
76                 levels = null;\r
77         }\r
78         \r
79         /**\r
80          * Builds Zoom Levels.\r
81          */\r
82         private void _buildZoomLevels()\r
83         {\r
84                 diagrams.clear();\r
85                 Collections.sort(nodes);\r
86                 int c = nodes.size();\r
87                 ArrayList<MorphLevel> levels = new ArrayList<MorphLevel>(c+1);\r
88                 MorphLevel prevZL = null;\r
89                 for (int i = 0; i<=c; i++ )\r
90                 {\r
91                         MorphLevel zl = new MorphLevel();\r
92                         if (i==0) {\r
93                                 zl.ud = nodes.get(0).diagram;\r
94                                 zl.ld = nodes.get(0).diagram;\r
95                                 zl.ul = -Double.MAX_VALUE;\r
96                                 zl.ll = nodes.get(0).level;\r
97                         } else if (i==c) {\r
98                                 zl.ud = nodes.get(c-1).diagram;\r
99                                 zl.ld = nodes.get(c-1).diagram;\r
100                                 zl.ul = nodes.get(c-1).level;\r
101                                 zl.ll = Double.MAX_VALUE;\r
102                         } else {\r
103                                 zl.ud = nodes.get(i-1).diagram;\r
104                                 zl.ld = nodes.get(i  ).diagram;\r
105                                 zl.ul = nodes.get(i-1).level;\r
106                                 zl.ll = nodes.get(i  ).level;\r
107                         }\r
108 \r
109                         if (prevZL!=null && prevZL.ld == zl.ld && prevZL.ud == zl.ud)\r
110                         {\r
111                                 prevZL.ll = Math.max(prevZL.ll, zl.ll);\r
112                                 prevZL.ul = Math.min(prevZL.ul, zl.ul);\r
113                                 zl = prevZL;\r
114                         } else {\r
115                                 prevZL = zl;\r
116                                 levels.add(zl);\r
117                         }                       \r
118                         if (i>0) {\r
119                                 nodes.get(i-1).upper = prevZL;\r
120                                 nodes.get(i-1).lower = zl;\r
121                         }\r
122                         \r
123                         if (zl.ud!=null && !diagrams.contains(zl.ud))\r
124                                 diagrams.add(zl.ud);\r
125                         if (zl.ld!=null && !diagrams.contains(zl.ld))\r
126                                 diagrams.add(zl.ld);\r
127                 }\r
128                 this.levels = levels.toArray(new MorphLevel[levels.size()]);\r
129         }\r
130         \r
131         /**\r
132          * Get ordered list of zoom levels starting from the top most level \r
133          * (which is diagram)\r
134          * @return ordered list of zoom levels\r
135          */\r
136         public MorphLevel[] getMorphLevels()\r
137         {\r
138                 if (levels==null) _buildZoomLevels();\r
139                 return levels;\r
140         }\r
141         \r
142         public MorphPhase getTransitionInfo(double zoomLevel)\r
143         {\r
144                 if (levels==null) _buildZoomLevels();\r
145                 MorphLevel zl = null;\r
146                 for (int i=0; i<levels.length; i++)\r
147                 {\r
148                         zl = levels[i];\r
149                         if (zl.isInLevel(zoomLevel)) break;\r
150                 }\r
151                         \r
152                 MorphPhase zp = new MorphPhase();\r
153                 zp.level = zl;\r
154                 if (zl.ld==null || zl.ud==null || zl.ld==zl.ud)\r
155                         return zp;\r
156                 \r
157                 // Interpolate phase\r
158                 zp.phase = (zoomLevel - zl.ul) / (zl.ll - zl.ul);               \r
159                 zp.phase = function.f(zp.phase);\r
160                 if (zp.phase<0) zp.phase = 0;\r
161                 if (zp.phase>1) zp.phase = 1;\r
162                 return zp;\r
163         }\r
164         \r
165         public void setTransitionFunction(TransitionFunction function)\r
166         {\r
167                 this.function = function;\r
168         }\r
169 \r
170         public TransitionFunction getFunction() {\r
171                 return function;\r
172         }\r
173         \r
174         /**\r
175          * Diagrams from (first occurance) top to down order\r
176          * @return\r
177          */\r
178         public List<IDiagram> getDiagrams() {\r
179                 if (levels==null) _buildZoomLevels();\r
180                 return Collections.unmodifiableList(diagrams);\r
181         }\r
182         \r
183         @Override\r
184         public String toString() {\r
185                 return getDiagrams().toString();\r
186         }\r
187         \r
188         /** Information about a single layer */\r
189         public static class LayerInfo {\r
190                 public double ul, ll;\r
191                 public IDiagram diagram;\r
192         }\r
193 \r
194         public List<LayerInfo> buildMorphLayers()\r
195         {\r
196                 List<LayerInfo> result = new ArrayList<LayerInfo>();\r
197                 \r
198                 for (MorphLevel ml : getMorphLevels())\r
199                 {\r
200                         // Upper and lower layers are the same\r
201                         if (ml.ud != null && ml.ud==ml.ld)\r
202                         {                               \r
203                                 LayerInfo li = new LayerInfo();\r
204                                 li.diagram = ml.ud;\r
205                                 li.ll = ml.ll;\r
206                                 li.ul = ml.ul;\r
207                                 result.add(li);\r
208                                 continue;\r
209                         }\r
210                         // Build morphing layer\r
211                         IDiagram ud = ml.ud == null ? Diagram.EMPTY_DIAGRAM : ml.ud;\r
212                         IDiagram ld = ml.ld == null ? Diagram.EMPTY_DIAGRAM : ml.ld;\r
213                         LayerInfo li = new LayerInfo();\r
214                         li.ll = ml.ll;\r
215                         li.ul = ml.ul;\r
216                         li.diagram = TransitionDiagram.createTransitionDiagram(ud, ld, TransitionDiagram.MORPH_ELEMENT_CLASS);\r
217                         result.add(li);\r
218                 }\r
219                 \r
220                 return result;\r
221         }\r
222         \r
223         private static class Node implements Comparable<Node> {\r
224                 double level;\r
225                 IDiagram diagram;\r
226                 MorphLevel upper, lower;\r
227                 @Override\r
228                 public int compareTo(Node n) {\r
229                         double diff = level - n.level;\r
230                         if (diff<0) return -1;\r
231                         if (diff>0) return 1;\r
232                         return 0;\r
233                 }\r
234                 public Node(IDiagram diagram, double level) {\r
235                         this.level = level;\r
236                         this.diagram = diagram;\r
237                 }               \r
238         }\r
239         public static class MorphPhase {\r
240                 public MorphLevel level;\r
241                 /** Phase, 0==upper .. 1==lower */\r
242                 public double phase;\r
243                 @Override\r
244                 public String toString() {\r
245                         return phase + "\t"+level;\r
246                 }\r
247         }\r
248                 \r
249         public static class MorphLevel {\r
250                 /**\r
251                  * Upper and lower diagrams (one may be null)\r
252                  */\r
253                 public IDiagram ud, ld;\r
254                 public double   ul, ll;\r
255                 public IDiagram diagram;\r
256                 \r
257                 /**\r
258                  * Is zoom level locked to a diagram\r
259                  * @return\r
260                  */\r
261                 public boolean isLocked()\r
262                 {\r
263                         return ud == ld;\r
264                 }\r
265                 \r
266                 public boolean isInTransition()\r
267                 {\r
268                         return ud != ld;\r
269                 }\r
270                 \r
271                 public boolean isInLevel(double zoomLevel)\r
272                 {\r
273                         return zoomLevel >=ul && zoomLevel<=ll;\r
274                 }\r
275                 \r
276                 @Override\r
277                 public String toString() {\r
278                         String un = "[]";\r
279                         if (ud!=null) un = ud.toString();\r
280                         String ln = "[]";\r
281                         if (ld!=null) ln = ld.toString();\r
282                         \r
283                         return un+" .. "+ln;\r
284                 }\r
285                 \r
286         }       \r
287         \r
288 }\r