1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.ui.elements2.profiles;
\r
14 import java.awt.geom.AffineTransform;
\r
15 import java.awt.geom.Rectangle2D;
\r
16 import java.util.ArrayList;
\r
18 import org.simantics.databoard.Bindings;
\r
19 import org.simantics.db.ReadGraph;
\r
20 import org.simantics.db.Resource;
\r
21 import org.simantics.db.common.request.ObjectsWithType;
\r
22 import org.simantics.db.exception.DatabaseException;
\r
23 import org.simantics.db.layer0.variable.Variable;
\r
24 import org.simantics.diagram.G2DUtils;
\r
25 import org.simantics.diagram.elements.TextNode;
\r
26 import org.simantics.diagram.profile.StyleBase;
\r
27 import org.simantics.diagram.stubs.DiagramResource;
\r
28 import org.simantics.diagram.stubs.G2DResource;
\r
29 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
\r
30 import org.simantics.modeling.ModelingResources;
\r
31 import org.simantics.project.IProject;
\r
32 import org.simantics.scenegraph.INode;
\r
33 import org.simantics.scenegraph.g2d.nodes.ShapeNode;
\r
34 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
\r
35 import org.simantics.scenegraph.profile.EvaluationContext;
\r
36 import org.simantics.scenegraph.profile.Observer;
\r
37 import org.simantics.scenegraph.profile.common.ProfileVariables;
\r
38 import org.simantics.scenegraph.utils.GeometryUtils;
\r
39 import org.simantics.scenegraph.utils.NodeUtil;
\r
40 import org.simantics.simulation.experiment.IExperiment;
\r
41 import org.simantics.simulation.project.IExperimentManager;
\r
42 import org.simantics.sysdyn.adapter.SysdynVariableProperties;
\r
43 import org.simantics.sysdyn.adapter.VariableRVIUtils;
\r
44 import org.simantics.sysdyn.manager.SysdynDataSet;
\r
45 import org.simantics.sysdyn.manager.SysdynPlaybackExperiment;
\r
46 import org.simantics.ui.SimanticsUI;
\r
47 import org.simantics.utils.datastructures.Triple;
\r
48 import org.simantics.utils.ui.color.Color;
\r
49 import org.simantics.utils.ui.color.ColorGradient;
\r
50 import org.simantics.utils.ui.color.ColorValue;
\r
53 * Profile style definition for simulation playback mode. Works only with SimulationPlaybackExperiment
\r
55 * @author Teemu Lempinen
\r
58 public class SimulationPlaybackStyle extends StyleBase<Triple<AffineTransform, Double, ColorGradient>> {
\r
60 Resource gradientResource;
\r
65 * Determine if style needs to be redrawn and return objects that are needed to redraw the style.
\r
67 * @return All necessary components that are needed to draw this style
\r
70 public Triple<AffineTransform, Double, ColorGradient> calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {
\r
72 // Find SimulationPlaybackExperiment
\r
73 IProject project = SimanticsUI.getProject();
\r
74 IExperimentManager em = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
\r
75 IExperiment experiment = em.getActiveExperiment();
\r
76 if(!(experiment instanceof SysdynPlaybackExperiment))
\r
79 ModelingResources mr = ModelingResources.getInstance(graph);
\r
80 DiagramResource dr = DiagramResource.getInstance(graph);
\r
82 ColorGradient cg = null;
\r
84 Resource component = graph.getPossibleObject(element, mr.ElementToComponent);
\r
85 if (component == null)
\r
90 // Find Variable for this component
\r
91 String dv = graph.getPossibleRelatedValue(runtimeDiagram, dr.RuntimeDiagram_HasVariable);
\r
92 Variable rootVariable = graph.getPossibleAdapter(graph.getRootLibrary(), Variable.class);
\r
93 if (rootVariable == null)
\r
95 Variable diagramVariable = rootVariable.browsePossible(graph, dv.substring(6));
\r
96 if(diagramVariable == null)
\r
99 Variable var = diagramVariable.browsePossible(graph, component);
\r
103 // Get simulation result values for this component
\r
105 Object object = var.getPossiblePropertyValue(graph, SysdynVariableProperties.ACTIVE_DATASETS , Bindings.VARIANT);
\r
106 if(object == null || !(object instanceof ArrayList<?>))
\r
109 ArrayList<SysdynDataSet> datasets = new ArrayList<SysdynDataSet>();
\r
111 for(Object o : (ArrayList<?>)object) {
\r
112 if(o instanceof SysdynDataSet)
\r
113 datasets.add((SysdynDataSet)o);
\r
116 if(datasets.size() == 0)
\r
119 if(datasets.size() > 1) {
\r
120 String range = datasets.get(0).name.substring(
\r
121 datasets.get(0).name.indexOf('[') + 1,
\r
122 datasets.get(0).name.indexOf(']'));
\r
123 int size = range.split(",").length;
\r
124 String[] filter = new String[size];
\r
125 for(int i = 0; i < size; i++)
\r
128 ArrayList<SysdynDataSet> result2 = VariableRVIUtils.getDataset(datasets, filter);
\r
129 if(result2 != null) {
\r
130 datasets = result2;
\r
135 // The datasets list should always be size == 1
\r
136 SysdynDataSet dataset = datasets.get(0);
\r
138 // Get values (or sum of values)
\r
139 double[] va = dataset.values;
\r
143 // Get simulation timesteps for this component
\r
144 double[] ta = dataset.times;
\r
145 if(ta == null || ta.length < 2)
\r
148 if(va.length == 0 || va.length == 2)
\r
151 // Get playback time from the experiment
\r
152 Double time = var.getPossiblePropertyValue(graph, SysdynVariableProperties.TIME , Bindings.DOUBLE);
\r
156 // Find minimum and maximum values for this variable
\r
157 double min = va[0], max = va[0];
\r
158 for(double d : va) {
\r
165 // Find the index in time and value arrays for this time
\r
166 // (time steps may vary, we need to loop to find the correct time)
\r
168 if(ta[ta.length - 1] - time > ta[ta.length / 2] ) {
\r
169 index = ta.length - 1;
\r
170 while(ta[index] > time && index > 0)
\r
173 while(ta[index] < time && index < ta.length - 1)
\r
177 double value = va[index];
\r
179 // Calculate where the value is located between min and max values [0..1].
\r
180 double multiplier = (value - min) / (max - min);
\r
183 // Get the transform of this element
\r
184 AffineTransform at = (AffineTransform) DiagramGraphUtil.getAffineTransform(graph, element, G2DResource.getInstance(graph).HasTransform, true).clone();
\r
186 // Find the gradient used to draw this style
\r
187 G2DResource g2d = G2DResource.getInstance(graph);
\r
188 Resource gradient = graph.getPossibleObject(experiment.getResource(), g2d.HasColorGradient);
\r
189 if(this.gradientResource == null || !this.gradientResource.equals(gradient)) {
\r
190 ArrayList<ColorValue> colorValues = new ArrayList<ColorValue>();
\r
191 for(Resource placement : graph.syncRequest(new ObjectsWithType(gradient, g2d.HasColorPlacement, g2d.ColorPlacement))) {
\r
192 Double position = graph.getPossibleRelatedValue(placement, g2d.HasGradientPosition, Bindings.DOUBLE);
\r
193 Resource rColor = graph.getPossibleObject(placement, g2d.HasColor);
\r
194 if (rColor != null) {
\r
195 colorValues.add(new ColorValue(new Color((java.awt.Color) G2DUtils.getObject(graph, rColor)), position));
\r
198 cg = new ColorGradient(colorValues, ColorGradient.HSV);
\r
203 return new Triple<AffineTransform, Double, ColorGradient>(at, multiplier, cg);
\r
205 } catch(Exception ignore) {
\r
206 ignore.printStackTrace();
\r
212 public void styleResultChanged(Observer observer, Resource element, Triple<AffineTransform, Double, ColorGradient> result) {
\r
213 if (result != null)
\r
214 values.put(element, result);
\r
216 values.remove(element);
\r
224 public void applyStyleForNode(EvaluationContext observer, INode _node, Triple<AffineTransform, Double, ColorGradient> result) {
\r
226 if (result != null && (multiplier = result.second) != null && !multiplier.isNaN()) {
\r
228 // Create a node that will show the style effect
\r
229 A node = ProfileVariables.claimChild(_node, "", "playbackColour", A.class, observer);
\r
233 AffineTransform at = result.first;
\r
235 if(this.cg == null || !this.cg.equals(result.third)) {
\r
236 this.cg = result.third;
\r
237 this.gradient = cg.getGradientArray(101);
\r
240 // Get integer values for red, green and blue
\r
241 int i = (int)(multiplier * 100);
\r
242 int r = (int)(gradient[i * 3 + 0] & 0xff);
\r
243 int g = (int)(gradient[i * 3 + 1] & 0xff);
\r
244 int b = (int)(gradient[i * 3 + 2] & 0xff);
\r
245 // Get color with r, g and b
\r
246 java.awt.Color c = new java.awt.Color(r, g, b, 200);
\r
248 // Create a node for the style
\r
249 INode n = NodeUtil.getNearestChildByClass((SingleElementNode)_node, TextNode.class);
\r
250 Rectangle2D expandedElementBounds = GeometryUtils.expandRectangle( NodeUtil.getLocalElementBounds(n), 0.0);
\r
251 node.setFill(true);
\r
253 node.setStroke(null);
\r
254 node.setValue("shape", expandedElementBounds);
\r
255 node.setTransform(at);
\r
257 // Find z-index for the TextNode associated with the element and place the style node just below that text node
\r
260 at = ((TextNode)n).getTransform();
\r
261 zIndex = ((TextNode)n).getZIndex() - 1;
\r
265 node.setZIndex(zIndex);
\r
269 cleanupStyleForNode(_node);
\r
274 protected void cleanupStyleForNode(INode node) {
\r
275 ProfileVariables.denyChild(node, "", "playbackColour");
\r
280 * Dummy class for displaying the style
\r
282 * @author Teemu Lempinen
\r
285 public static class A extends ShapeNode {
\r
287 private static final long serialVersionUID = -5273246617906214956L;
\r
290 public Rectangle2D getBoundsInLocal() {
\r
295 public Rectangle2D getBoundsInLocal(boolean b) {
\r
300 public Rectangle2D getBounds() {
\r