]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
89ef64d32af583b753e8cb116f5336d0b6a993c6
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.sysdyn.ui.elements2.profiles;\r
13 \r
14 import java.awt.geom.AffineTransform;\r
15 import java.awt.geom.Rectangle2D;\r
16 import java.util.ArrayList;\r
17 \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
51 \r
52 /**\r
53  * Profile style definition for simulation playback mode. Works only with SimulationPlaybackExperiment\r
54  * \r
55  * @author Teemu Lempinen\r
56  *\r
57  */\r
58 public class SimulationPlaybackStyle extends StyleBase<Triple<AffineTransform, Double, ColorGradient>> {\r
59 \r
60     Resource gradientResource;\r
61     ColorGradient cg;\r
62     byte[] gradient;\r
63 \r
64     /**\r
65      * Determine if style needs to be redrawn and return objects that are needed to redraw the style.\r
66      * \r
67      * @return All necessary components that are needed to draw this style\r
68      */\r
69     @Override\r
70     public Triple<AffineTransform, Double, ColorGradient> calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {\r
71 \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
77             return null;\r
78 \r
79         ModelingResources mr = ModelingResources.getInstance(graph);\r
80         DiagramResource dr = DiagramResource.getInstance(graph);\r
81 \r
82         ColorGradient cg = null;\r
83 \r
84         Resource component = graph.getPossibleObject(element, mr.ElementToComponent);\r
85         if (component == null)\r
86             return null;\r
87 \r
88         try {\r
89 \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
94                 return null;\r
95             Variable diagramVariable = rootVariable.browsePossible(graph, dv.substring(6));\r
96             if(diagramVariable == null) \r
97                 return null;\r
98 \r
99             Variable var = diagramVariable.browsePossible(graph, component);\r
100             if(var == null)\r
101                 return null;\r
102 \r
103             // Get simulation result values for this component\r
104             // Get values\r
105             Object object =  var.getPossiblePropertyValue(graph, SysdynVariableProperties.ACTIVE_DATASETS , Bindings.VARIANT);\r
106             if(object == null || !(object instanceof ArrayList<?>))\r
107                 return null;\r
108 \r
109             ArrayList<SysdynDataSet> datasets = new ArrayList<SysdynDataSet>();\r
110 \r
111             for(Object o : (ArrayList<?>)object) {\r
112                 if(o instanceof SysdynDataSet)\r
113                     datasets.add((SysdynDataSet)o);\r
114             }\r
115 \r
116             if(datasets.size() == 0)\r
117                 return null;\r
118 \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
126                     filter[i] = "Sum";\r
127 \r
128                 ArrayList<SysdynDataSet> result2 = VariableRVIUtils.getDataset(datasets, filter);\r
129                 if(result2 != null) {\r
130                     datasets = result2;\r
131                 }\r
132 \r
133             }\r
134 \r
135             // The datasets list should always be size == 1\r
136             SysdynDataSet dataset = datasets.get(0);\r
137             \r
138             // Get values (or sum of values)\r
139             double[] va = dataset.values;\r
140             if(va.length < 2)\r
141                 return null;\r
142 \r
143             // Get simulation timesteps for this component\r
144             double[] ta = dataset.times;\r
145             if(ta == null || ta.length < 2)\r
146                 return null;\r
147 \r
148             if(va.length == 0 || va.length == 2)\r
149                 return null;\r
150 \r
151             // Get playback time from the experiment\r
152             Double time = var.getPossiblePropertyValue(graph, SysdynVariableProperties.TIME , Bindings.DOUBLE);\r
153             if(time == null)\r
154                 return null;\r
155 \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
159                 if(d < min) \r
160                     min = d;\r
161                 if(d > max)\r
162                     max = d;\r
163             }\r
164 \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
167             int index = 0;\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
171                     index--;\r
172             } else {\r
173                 while(ta[index] < time && index < ta.length - 1)\r
174                     index++;\r
175             }\r
176 \r
177             double value = va[index];\r
178 \r
179             // Calculate where the value is located between min and max values [0..1].   \r
180             double multiplier = (value - min) / (max - min);\r
181 \r
182 \r
183             // Get the transform of this element\r
184             AffineTransform at = (AffineTransform) DiagramGraphUtil.getAffineTransform(graph, element,  G2DResource.getInstance(graph).HasTransform, true).clone();\r
185 \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
196                     }\r
197                 }\r
198                 cg = new ColorGradient(colorValues, ColorGradient.HSV);\r
199             } else {\r
200                 cg = this.cg;\r
201             }\r
202 \r
203             return new Triple<AffineTransform, Double, ColorGradient>(at, multiplier, cg);\r
204 \r
205         } catch(Exception ignore) {\r
206             ignore.printStackTrace();\r
207         }\r
208         return null;\r
209     }\r
210 \r
211     @Override\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
215         else\r
216             values.remove(element);\r
217         observer.update();\r
218     }\r
219 \r
220     /**\r
221      * Apply style\r
222      */\r
223     @Override\r
224     public void applyStyleForNode(EvaluationContext observer, INode _node, Triple<AffineTransform, Double, ColorGradient> result) {\r
225         Double multiplier;\r
226         if (result != null && (multiplier = result.second) != null && !multiplier.isNaN()) {\r
227 \r
228             // Create a node that will show the style effect\r
229             A node = ProfileVariables.claimChild(_node, "", "playbackColour", A.class, observer);\r
230             if (node == null)\r
231                 return;\r
232 \r
233             AffineTransform at = result.first;\r
234 \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
238             }\r
239 \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
247 \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
252             node.setColor(c);\r
253             node.setStroke(null);\r
254             node.setValue("shape", expandedElementBounds);\r
255             node.setTransform(at);\r
256 \r
257             // Find z-index for the TextNode associated with the element and place the style node just below that text node \r
258             int zIndex = -1;\r
259             if(n != null) {\r
260                 at = ((TextNode)n).getTransform();\r
261                 zIndex = ((TextNode)n).getZIndex() - 1;\r
262             } else {\r
263                 n = _node;\r
264             }\r
265             node.setZIndex(zIndex);\r
266 \r
267 \r
268         } else {\r
269             cleanupStyleForNode(_node);\r
270         }\r
271     }\r
272 \r
273     @Override\r
274     protected void cleanupStyleForNode(INode node) {\r
275         ProfileVariables.denyChild(node, "", "playbackColour");\r
276     }\r
277 \r
278 \r
279     /**\r
280      * Dummy class for displaying the style\r
281      * \r
282      * @author Teemu Lempinen\r
283      *\r
284      */\r
285     public static class A extends ShapeNode {\r
286 \r
287         private static final long serialVersionUID = -5273246617906214956L;\r
288 \r
289         @Override\r
290         public Rectangle2D getBoundsInLocal() {\r
291             return null;\r
292         }\r
293 \r
294         @Override\r
295         public Rectangle2D getBoundsInLocal(boolean b) {\r
296             return null;\r
297         }\r
298 \r
299         @Override\r
300         public Rectangle2D getBounds() {\r
301             return null;\r
302         }\r
303 \r
304     }\r
305 }\r
306