1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.multileveldiagram;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Iterator;
17 import java.util.List;
19 import org.simantics.g2d.diagram.IDiagram;
20 import org.simantics.g2d.diagram.impl.Diagram;
21 import org.simantics.utils.datastructures.hints.IHintContext.Key;
22 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
25 * This class describes a composition of a multi-layer diagram.
27 * @author Toni Kalajainen
29 public class LayerComposition {
31 /** Diagram hint, MorphHandlers read this key from the diagram */
32 public static final Key KEY_PHASE = new KeyOf(MorphPhase.class);
34 /** Transition function */
35 TransitionFunction function = TransitionFunction.SIGMOID;
37 /** Diagramming info */
38 ArrayList<Node> nodes = new ArrayList<Node>();
40 ArrayList<IDiagram> diagrams = new ArrayList<IDiagram>();
42 MorphLevel[] levels = null;
45 * Add a new diagram to the composition.
46 * The top most diagram has startZoom open-ended, and the bottom diagram
47 * has endZoom open-ended.
50 * @param startZoom startZoom in percents or null if open-ended
51 * @param endZoom endZoom in percents or null if open-ended
53 public void addLayer(IDiagram diagram, Double startZoom, Double endZoom)
55 assert(diagram!=null);
56 if (startZoom!=null && endZoom!=null)
57 assert(startZoom<endZoom);
58 assert(startZoom!=null || endZoom!=null);
59 if (startZoom!=null) {
60 nodes.add(new Node(diagram, startZoom));
63 nodes.add(new Node(diagram, endZoom));
68 public void removeLayer(IDiagram diagram)
70 Iterator<Node> i = nodes.iterator();
73 if (n.diagram == diagram)
82 private void _buildZoomLevels()
85 Collections.sort(nodes);
87 ArrayList<MorphLevel> levels = new ArrayList<MorphLevel>(c+1);
88 MorphLevel prevZL = null;
89 for (int i = 0; i<=c; i++ )
91 MorphLevel zl = new MorphLevel();
93 zl.ud = nodes.get(0).diagram;
94 zl.ld = nodes.get(0).diagram;
95 zl.ul = -Double.MAX_VALUE;
96 zl.ll = nodes.get(0).level;
98 zl.ud = nodes.get(c-1).diagram;
99 zl.ld = nodes.get(c-1).diagram;
100 zl.ul = nodes.get(c-1).level;
101 zl.ll = Double.MAX_VALUE;
103 zl.ud = nodes.get(i-1).diagram;
104 zl.ld = nodes.get(i ).diagram;
105 zl.ul = nodes.get(i-1).level;
106 zl.ll = nodes.get(i ).level;
109 if (prevZL!=null && prevZL.ld == zl.ld && prevZL.ud == zl.ud)
111 prevZL.ll = Math.max(prevZL.ll, zl.ll);
112 prevZL.ul = Math.min(prevZL.ul, zl.ul);
119 nodes.get(i-1).upper = prevZL;
120 nodes.get(i-1).lower = zl;
123 if (zl.ud!=null && !diagrams.contains(zl.ud))
125 if (zl.ld!=null && !diagrams.contains(zl.ld))
128 this.levels = levels.toArray(new MorphLevel[levels.size()]);
132 * Get ordered list of zoom levels starting from the top most level
134 * @return ordered list of zoom levels
136 public MorphLevel[] getMorphLevels()
138 if (levels==null) _buildZoomLevels();
142 public MorphPhase getTransitionInfo(double zoomLevel)
144 if (levels==null) _buildZoomLevels();
145 MorphLevel zl = null;
146 for (int i=0; i<levels.length; i++)
149 if (zl.isInLevel(zoomLevel)) break;
152 MorphPhase zp = new MorphPhase();
154 if (zl.ld==null || zl.ud==null || zl.ld==zl.ud)
158 zp.phase = (zoomLevel - zl.ul) / (zl.ll - zl.ul);
159 zp.phase = function.f(zp.phase);
160 if (zp.phase<0) zp.phase = 0;
161 if (zp.phase>1) zp.phase = 1;
165 public void setTransitionFunction(TransitionFunction function)
167 this.function = function;
170 public TransitionFunction getFunction() {
175 * Diagrams from (first occurance) top to down order
178 public List<IDiagram> getDiagrams() {
179 if (levels==null) _buildZoomLevels();
180 return Collections.unmodifiableList(diagrams);
184 public String toString() {
185 return getDiagrams().toString();
188 /** Information about a single layer */
189 public static class LayerInfo {
190 public double ul, ll;
191 public IDiagram diagram;
194 public List<LayerInfo> buildMorphLayers()
196 List<LayerInfo> result = new ArrayList<LayerInfo>();
198 for (MorphLevel ml : getMorphLevels())
200 // Upper and lower layers are the same
201 if (ml.ud != null && ml.ud==ml.ld)
203 LayerInfo li = new LayerInfo();
210 // Build morphing layer
211 IDiagram ud = ml.ud == null ? Diagram.EMPTY_DIAGRAM : ml.ud;
212 IDiagram ld = ml.ld == null ? Diagram.EMPTY_DIAGRAM : ml.ld;
213 LayerInfo li = new LayerInfo();
216 li.diagram = TransitionDiagram.createTransitionDiagram(ud, ld, TransitionDiagram.MORPH_ELEMENT_CLASS);
223 private static class Node implements Comparable<Node> {
226 MorphLevel upper, lower;
228 public int compareTo(Node n) {
229 double diff = level - n.level;
230 if (diff<0) return -1;
231 if (diff>0) return 1;
234 public Node(IDiagram diagram, double level) {
236 this.diagram = diagram;
239 public static class MorphPhase {
240 public MorphLevel level;
241 /** Phase, 0==upper .. 1==lower */
244 public String toString() {
245 return phase + "\t"+level;
249 public static class MorphLevel {
251 * Upper and lower diagrams (one may be null)
253 public IDiagram ud, ld;
254 public double ul, ll;
255 public IDiagram diagram;
258 * Is zoom level locked to a diagram
261 public boolean isLocked()
266 public boolean isInTransition()
271 public boolean isInLevel(double zoomLevel)
273 return zoomLevel >=ul && zoomLevel<=ll;
277 public String toString() {
279 if (ud!=null) un = ud.toString();
281 if (ld!=null) ln = ld.toString();