]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/LayerComposition.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/LayerComposition.java
new file mode 100644 (file)
index 0000000..3f341fd
--- /dev/null
@@ -0,0 +1,288 @@
+/*******************************************************************************\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