-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g2d.multileveldiagram;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.impl.Diagram;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
-\r
-/**\r
- * This class describes a composition of a multi-layer diagram. \r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public class LayerComposition {\r
-\r
- /** Diagram hint, MorphHandlers read this key from the diagram */\r
- public static final Key KEY_PHASE = new KeyOf(MorphPhase.class);\r
- \r
- /** Transition function */\r
- TransitionFunction function = TransitionFunction.SIGMOID; \r
- \r
- /** Diagramming info */\r
- ArrayList<Node> nodes = new ArrayList<Node>();\r
- /** All diagrams */\r
- ArrayList<IDiagram> diagrams = new ArrayList<IDiagram>();\r
- /** Zoom levels */\r
- MorphLevel[] levels = null;\r
- \r
- /**\r
- * Add a new diagram to the composition.\r
- * The top most diagram has startZoom open-ended, and the bottom diagram\r
- * has endZoom open-ended.\r
- * \r
- * @param diagram\r
- * @param startZoom startZoom in percents or null if open-ended\r
- * @param endZoom endZoom in percents or null if open-ended\r
- */\r
- public void addLayer(IDiagram diagram, Double startZoom, Double endZoom)\r
- {\r
- assert(diagram!=null); \r
- if (startZoom!=null && endZoom!=null)\r
- assert(startZoom<endZoom);\r
- assert(startZoom!=null || endZoom!=null);\r
- if (startZoom!=null) {\r
- nodes.add(new Node(diagram, startZoom));\r
- }\r
- if (endZoom!=null) {\r
- nodes.add(new Node(diagram, endZoom));\r
- }\r
- levels = null;\r
- }\r
- \r
- public void removeLayer(IDiagram diagram)\r
- {\r
- Iterator<Node> i = nodes.iterator();\r
- while (i.hasNext()) {\r
- Node n = i.next();\r
- if (n.diagram == diagram)\r
- i.remove();\r
- }\r
- levels = null;\r
- }\r
- \r
- /**\r
- * Builds Zoom Levels.\r
- */\r
- private void _buildZoomLevels()\r
- {\r
- diagrams.clear();\r
- Collections.sort(nodes);\r
- int c = nodes.size();\r
- ArrayList<MorphLevel> levels = new ArrayList<MorphLevel>(c+1);\r
- MorphLevel prevZL = null;\r
- for (int i = 0; i<=c; i++ )\r
- {\r
- MorphLevel zl = new MorphLevel();\r
- if (i==0) {\r
- zl.ud = nodes.get(0).diagram;\r
- zl.ld = nodes.get(0).diagram;\r
- zl.ul = -Double.MAX_VALUE;\r
- zl.ll = nodes.get(0).level;\r
- } else if (i==c) {\r
- zl.ud = nodes.get(c-1).diagram;\r
- zl.ld = nodes.get(c-1).diagram;\r
- zl.ul = nodes.get(c-1).level;\r
- zl.ll = Double.MAX_VALUE;\r
- } else {\r
- zl.ud = nodes.get(i-1).diagram;\r
- zl.ld = nodes.get(i ).diagram;\r
- zl.ul = nodes.get(i-1).level;\r
- zl.ll = nodes.get(i ).level;\r
- }\r
-\r
- if (prevZL!=null && prevZL.ld == zl.ld && prevZL.ud == zl.ud)\r
- {\r
- prevZL.ll = Math.max(prevZL.ll, zl.ll);\r
- prevZL.ul = Math.min(prevZL.ul, zl.ul);\r
- zl = prevZL;\r
- } else {\r
- prevZL = zl;\r
- levels.add(zl);\r
- } \r
- if (i>0) {\r
- nodes.get(i-1).upper = prevZL;\r
- nodes.get(i-1).lower = zl;\r
- }\r
- \r
- if (zl.ud!=null && !diagrams.contains(zl.ud))\r
- diagrams.add(zl.ud);\r
- if (zl.ld!=null && !diagrams.contains(zl.ld))\r
- diagrams.add(zl.ld);\r
- }\r
- this.levels = levels.toArray(new MorphLevel[levels.size()]);\r
- }\r
- \r
- /**\r
- * Get ordered list of zoom levels starting from the top most level \r
- * (which is diagram)\r
- * @return ordered list of zoom levels\r
- */\r
- public MorphLevel[] getMorphLevels()\r
- {\r
- if (levels==null) _buildZoomLevels();\r
- return levels;\r
- }\r
- \r
- public MorphPhase getTransitionInfo(double zoomLevel)\r
- {\r
- if (levels==null) _buildZoomLevels();\r
- MorphLevel zl = null;\r
- for (int i=0; i<levels.length; i++)\r
- {\r
- zl = levels[i];\r
- if (zl.isInLevel(zoomLevel)) break;\r
- }\r
- \r
- MorphPhase zp = new MorphPhase();\r
- zp.level = zl;\r
- if (zl.ld==null || zl.ud==null || zl.ld==zl.ud)\r
- return zp;\r
- \r
- // Interpolate phase\r
- zp.phase = (zoomLevel - zl.ul) / (zl.ll - zl.ul); \r
- zp.phase = function.f(zp.phase);\r
- if (zp.phase<0) zp.phase = 0;\r
- if (zp.phase>1) zp.phase = 1;\r
- return zp;\r
- }\r
- \r
- public void setTransitionFunction(TransitionFunction function)\r
- {\r
- this.function = function;\r
- }\r
-\r
- public TransitionFunction getFunction() {\r
- return function;\r
- }\r
- \r
- /**\r
- * Diagrams from (first occurance) top to down order\r
- * @return\r
- */\r
- public List<IDiagram> getDiagrams() {\r
- if (levels==null) _buildZoomLevels();\r
- return Collections.unmodifiableList(diagrams);\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- return getDiagrams().toString();\r
- }\r
- \r
- /** Information about a single layer */\r
- public static class LayerInfo {\r
- public double ul, ll;\r
- public IDiagram diagram;\r
- }\r
-\r
- public List<LayerInfo> buildMorphLayers()\r
- {\r
- List<LayerInfo> result = new ArrayList<LayerInfo>();\r
- \r
- for (MorphLevel ml : getMorphLevels())\r
- {\r
- // Upper and lower layers are the same\r
- if (ml.ud != null && ml.ud==ml.ld)\r
- { \r
- LayerInfo li = new LayerInfo();\r
- li.diagram = ml.ud;\r
- li.ll = ml.ll;\r
- li.ul = ml.ul;\r
- result.add(li);\r
- continue;\r
- }\r
- // Build morphing layer\r
- IDiagram ud = ml.ud == null ? Diagram.EMPTY_DIAGRAM : ml.ud;\r
- IDiagram ld = ml.ld == null ? Diagram.EMPTY_DIAGRAM : ml.ld;\r
- LayerInfo li = new LayerInfo();\r
- li.ll = ml.ll;\r
- li.ul = ml.ul;\r
- li.diagram = TransitionDiagram.createTransitionDiagram(ud, ld, TransitionDiagram.MORPH_ELEMENT_CLASS);\r
- result.add(li);\r
- }\r
- \r
- return result;\r
- }\r
- \r
- private static class Node implements Comparable<Node> {\r
- double level;\r
- IDiagram diagram;\r
- MorphLevel upper, lower;\r
- @Override\r
- public int compareTo(Node n) {\r
- double diff = level - n.level;\r
- if (diff<0) return -1;\r
- if (diff>0) return 1;\r
- return 0;\r
- }\r
- public Node(IDiagram diagram, double level) {\r
- this.level = level;\r
- this.diagram = diagram;\r
- } \r
- }\r
- public static class MorphPhase {\r
- public MorphLevel level;\r
- /** Phase, 0==upper .. 1==lower */\r
- public double phase;\r
- @Override\r
- public String toString() {\r
- return phase + "\t"+level;\r
- }\r
- }\r
- \r
- public static class MorphLevel {\r
- /**\r
- * Upper and lower diagrams (one may be null)\r
- */\r
- public IDiagram ud, ld;\r
- public double ul, ll;\r
- public IDiagram diagram;\r
- \r
- /**\r
- * Is zoom level locked to a diagram\r
- * @return\r
- */\r
- public boolean isLocked()\r
- {\r
- return ud == ld;\r
- }\r
- \r
- public boolean isInTransition()\r
- {\r
- return ud != ld;\r
- }\r
- \r
- public boolean isInLevel(double zoomLevel)\r
- {\r
- return zoomLevel >=ul && zoomLevel<=ll;\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- String un = "[]";\r
- if (ud!=null) un = ud.toString();\r
- String ln = "[]";\r
- if (ld!=null) ln = ld.toString();\r
- \r
- return un+" .. "+ln;\r
- }\r
- \r
- } \r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.g2d.multileveldiagram;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.impl.Diagram;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
+
+/**
+ * This class describes a composition of a multi-layer diagram.
+ *
+ * @author Toni Kalajainen
+ */
+public class LayerComposition {
+
+ /** Diagram hint, MorphHandlers read this key from the diagram */
+ public static final Key KEY_PHASE = new KeyOf(MorphPhase.class);
+
+ /** Transition function */
+ TransitionFunction function = TransitionFunction.SIGMOID;
+
+ /** Diagramming info */
+ ArrayList<Node> nodes = new ArrayList<Node>();
+ /** All diagrams */
+ ArrayList<IDiagram> diagrams = new ArrayList<IDiagram>();
+ /** Zoom levels */
+ MorphLevel[] levels = null;
+
+ /**
+ * Add a new diagram to the composition.
+ * The top most diagram has startZoom open-ended, and the bottom diagram
+ * has endZoom open-ended.
+ *
+ * @param diagram
+ * @param startZoom startZoom in percents or null if open-ended
+ * @param endZoom endZoom in percents or null if open-ended
+ */
+ public void addLayer(IDiagram diagram, Double startZoom, Double endZoom)
+ {
+ assert(diagram!=null);
+ if (startZoom!=null && endZoom!=null)
+ assert(startZoom<endZoom);
+ assert(startZoom!=null || endZoom!=null);
+ if (startZoom!=null) {
+ nodes.add(new Node(diagram, startZoom));
+ }
+ if (endZoom!=null) {
+ nodes.add(new Node(diagram, endZoom));
+ }
+ levels = null;
+ }
+
+ public void removeLayer(IDiagram diagram)
+ {
+ Iterator<Node> i = nodes.iterator();
+ while (i.hasNext()) {
+ Node n = i.next();
+ if (n.diagram == diagram)
+ i.remove();
+ }
+ levels = null;
+ }
+
+ /**
+ * Builds Zoom Levels.
+ */
+ private void _buildZoomLevels()
+ {
+ diagrams.clear();
+ Collections.sort(nodes);
+ int c = nodes.size();
+ ArrayList<MorphLevel> levels = new ArrayList<MorphLevel>(c+1);
+ MorphLevel prevZL = null;
+ for (int i = 0; i<=c; i++ )
+ {
+ MorphLevel zl = new MorphLevel();
+ if (i==0) {
+ zl.ud = nodes.get(0).diagram;
+ zl.ld = nodes.get(0).diagram;
+ zl.ul = -Double.MAX_VALUE;
+ zl.ll = nodes.get(0).level;
+ } else if (i==c) {
+ zl.ud = nodes.get(c-1).diagram;
+ zl.ld = nodes.get(c-1).diagram;
+ zl.ul = nodes.get(c-1).level;
+ zl.ll = Double.MAX_VALUE;
+ } else {
+ zl.ud = nodes.get(i-1).diagram;
+ zl.ld = nodes.get(i ).diagram;
+ zl.ul = nodes.get(i-1).level;
+ zl.ll = nodes.get(i ).level;
+ }
+
+ if (prevZL!=null && prevZL.ld == zl.ld && prevZL.ud == zl.ud)
+ {
+ prevZL.ll = Math.max(prevZL.ll, zl.ll);
+ prevZL.ul = Math.min(prevZL.ul, zl.ul);
+ zl = prevZL;
+ } else {
+ prevZL = zl;
+ levels.add(zl);
+ }
+ if (i>0) {
+ nodes.get(i-1).upper = prevZL;
+ nodes.get(i-1).lower = zl;
+ }
+
+ if (zl.ud!=null && !diagrams.contains(zl.ud))
+ diagrams.add(zl.ud);
+ if (zl.ld!=null && !diagrams.contains(zl.ld))
+ diagrams.add(zl.ld);
+ }
+ this.levels = levels.toArray(new MorphLevel[levels.size()]);
+ }
+
+ /**
+ * Get ordered list of zoom levels starting from the top most level
+ * (which is diagram)
+ * @return ordered list of zoom levels
+ */
+ public MorphLevel[] getMorphLevels()
+ {
+ if (levels==null) _buildZoomLevels();
+ return levels;
+ }
+
+ public MorphPhase getTransitionInfo(double zoomLevel)
+ {
+ if (levels==null) _buildZoomLevels();
+ MorphLevel zl = null;
+ for (int i=0; i<levels.length; i++)
+ {
+ zl = levels[i];
+ if (zl.isInLevel(zoomLevel)) break;
+ }
+
+ MorphPhase zp = new MorphPhase();
+ zp.level = zl;
+ if (zl.ld==null || zl.ud==null || zl.ld==zl.ud)
+ return zp;
+
+ // Interpolate phase
+ zp.phase = (zoomLevel - zl.ul) / (zl.ll - zl.ul);
+ zp.phase = function.f(zp.phase);
+ if (zp.phase<0) zp.phase = 0;
+ if (zp.phase>1) zp.phase = 1;
+ return zp;
+ }
+
+ public void setTransitionFunction(TransitionFunction function)
+ {
+ this.function = function;
+ }
+
+ public TransitionFunction getFunction() {
+ return function;
+ }
+
+ /**
+ * Diagrams from (first occurance) top to down order
+ * @return
+ */
+ public List<IDiagram> getDiagrams() {
+ if (levels==null) _buildZoomLevels();
+ return Collections.unmodifiableList(diagrams);
+ }
+
+ @Override
+ public String toString() {
+ return getDiagrams().toString();
+ }
+
+ /** Information about a single layer */
+ public static class LayerInfo {
+ public double ul, ll;
+ public IDiagram diagram;
+ }
+
+ public List<LayerInfo> buildMorphLayers()
+ {
+ List<LayerInfo> result = new ArrayList<LayerInfo>();
+
+ for (MorphLevel ml : getMorphLevels())
+ {
+ // Upper and lower layers are the same
+ if (ml.ud != null && ml.ud==ml.ld)
+ {
+ LayerInfo li = new LayerInfo();
+ li.diagram = ml.ud;
+ li.ll = ml.ll;
+ li.ul = ml.ul;
+ result.add(li);
+ continue;
+ }
+ // Build morphing layer
+ IDiagram ud = ml.ud == null ? Diagram.EMPTY_DIAGRAM : ml.ud;
+ IDiagram ld = ml.ld == null ? Diagram.EMPTY_DIAGRAM : ml.ld;
+ LayerInfo li = new LayerInfo();
+ li.ll = ml.ll;
+ li.ul = ml.ul;
+ li.diagram = TransitionDiagram.createTransitionDiagram(ud, ld, TransitionDiagram.MORPH_ELEMENT_CLASS);
+ result.add(li);
+ }
+
+ return result;
+ }
+
+ private static class Node implements Comparable<Node> {
+ double level;
+ IDiagram diagram;
+ MorphLevel upper, lower;
+ @Override
+ public int compareTo(Node n) {
+ double diff = level - n.level;
+ if (diff<0) return -1;
+ if (diff>0) return 1;
+ return 0;
+ }
+ public Node(IDiagram diagram, double level) {
+ this.level = level;
+ this.diagram = diagram;
+ }
+ }
+ public static class MorphPhase {
+ public MorphLevel level;
+ /** Phase, 0==upper .. 1==lower */
+ public double phase;
+ @Override
+ public String toString() {
+ return phase + "\t"+level;
+ }
+ }
+
+ public static class MorphLevel {
+ /**
+ * Upper and lower diagrams (one may be null)
+ */
+ public IDiagram ud, ld;
+ public double ul, ll;
+ public IDiagram diagram;
+
+ /**
+ * Is zoom level locked to a diagram
+ * @return
+ */
+ public boolean isLocked()
+ {
+ return ud == ld;
+ }
+
+ public boolean isInTransition()
+ {
+ return ud != ld;
+ }
+
+ public boolean isInLevel(double zoomLevel)
+ {
+ return zoomLevel >=ul && zoomLevel<=ll;
+ }
+
+ @Override
+ public String toString() {
+ String un = "[]";
+ if (ud!=null) un = ud.toString();
+ String ln = "[]";
+ if (ld!=null) ln = ld.toString();
+
+ return un+" .. "+ln;
+ }
+
+ }
+
+}