/******************************************************************************* * 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 nodes = new ArrayList(); /** All diagrams */ ArrayList diagrams = new ArrayList(); /** 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 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 levels = new ArrayList(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; i1) 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 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 buildMorphLayers() { List result = new ArrayList(); 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 { 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; } } }