]> gerrit.simantics Code Review - simantics/district.git/commitdiff
First prototype of HSV color space based dynamic DN element coloring 41/2341/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sat, 20 Oct 2018 22:59:48 +0000 (01:59 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sat, 20 Oct 2018 22:59:48 +0000 (01:59 +0300)
Both VertexNode and EdgeNode support a new property 'dynamicColor' that
can be set to either a Color or null.

DN.Diagram has three new properties:
* Element Color Hue
* Element Color Saturation
* Element Color Brightness Function

where the first two are constants and the last one is a (Resource ->
<ReadGraph> Double) function that is expected to return a value in [0,1]
which is then used to get the final element color from the HSV gradient.
The Resource argument is the DN diagram element.

The function allows users to define any complex functions in SCLMain to
perform the evaluation for the DN element.

gitlab #2

Change-Id: Ia8dbe0df9400242670949da91e373d68cf7ff758

15 files changed:
org.simantics.district.network.ontology/graph/DistrictNetwork.pgraph
org.simantics.district.network.ontology/graph/DistrictNetworkDiagramSettings.pgraph
org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph
org.simantics.district.network.ontology/scl/Simantics/District/SCLMain.scl
org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/function/Functions.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java
org.simantics.district.network/adapters.xml
org.simantics.district.network/scl/Simantics/District.scl
org.simantics.district.network/src/org/simantics/district/network/profile/ColorGradient.java [new file with mode: 0644]
org.simantics.district.network/src/org/simantics/district/network/profile/Colors.java [new file with mode: 0644]
org.simantics.district.network/src/org/simantics/district/network/profile/DNElementColorStyle.java [new file with mode: 0644]
org.simantics.district.network/src/org/simantics/district/network/profile/DiagramSettings.java
org.simantics.district.network/src/org/simantics/district/network/profile/DiagramSettingsRequest.java

index 392173bf50c25b1998dcd2076240f9edae3a80d9..d258b9261acc8509d4f4fe5001addd69aea9f16b 100644 (file)
@@ -18,8 +18,8 @@ DN = <http://www.simantics.org/DistrictNetwork-1.0> : L0.Ontology
 DN.SCLMain : L0.SCLModule
     L0.SCLModule.definition
         """
-        include "Simantics/District/SCLMain"
-        """
+include "Simantics/District/SCLMain"
+"""
 
 // ----------------------------------------------------------------------------
 
index 10744ea144927aa7120f9d87fd947ba9fa5231c2..0ca711a12d282d61356a76bc0e9c7cbdf3c6d02e 100644 (file)
@@ -1,4 +1,5 @@
 L0 = <http://www.simantics.org/Layer0-1.1>
+L0X = <http://www.simantics.org/Layer0X-1.1>
 DIA = <http://www.simantics.org/Diagram-2.2>
 STR = <http://www.simantics.org/Structural-1.2>
 MOD = <http://www.simantics.org/Modeling-1.2>
@@ -46,6 +47,25 @@ DN.Vertex.ScaleProperty <T L0.Value
     @L0.assert DN.Vertex.ScaleProperty.bias 0.0
 
 DN.Diagram
+    >-- DN.Diagram.elementColoringGradientHue ==> "Float" <R L0.HasProperty : SEL.GenericParameterType
+        L0.HasLabel "Element Color Hue"
+        L0.HasDescription "HSV/HSB color space hue value used for element coloring in degrees (0-360)"
+        L0X.HasUnit "deg"
+        L0X.RequiresDataType $(Float(unit="deg",range=[0..360]))
+        SEL.HasDisplayValue _ : SEL.DisplayValue
+            L0.Literal.HasInputValidator DN.Functions.hueValidator : L0.Function
+    >-- DN.Diagram.elementColoringGradientSaturation ==> "Float" <R L0.HasProperty : SEL.GenericParameterType
+        L0.HasLabel "Element Color Saturation"
+        L0.HasDescription "HSV/HSB color space saturation value used for element coloring in % (0-100)"
+        L0X.HasUnit "%"
+        L0X.RequiresDataType $(Float(unit="%",range=[0..100]))
+        SEL.HasDisplayValue _ : SEL.DisplayValue
+            L0.Literal.HasInputValidator DN.Functions.saturationValidator : L0.Function
+    >-- DN.Diagram.elementColoringFunction --> L0.String ==> "Resource -> <ReadGraph> Double" <R L0.HasProperty : SEL.GenericParameterType
+        L0.HasLabel "Element Color Brightness Function"
+        L0.HasDescription "Defines HSV/HSB color space brightness function whose value is cut off to fit [0,1]. Together with hue and saturation this defines the element color."
+        SEL.HasDisplayValue _ : SEL.DisplayValue
+            L0.Literal.HasInputValidator DN.Functions.brightnessValidator : L0.Function
     >-- DN.Diagram.edgeThicknessGain ==> "Double" <R L0.HasProperty : SEL.GenericParameterType
         L0.HasLabel "Edge Thickness Gain"
     >-- DN.Diagram.edgeThicknessBias ==> "Double" <R L0.HasProperty : SEL.GenericParameterType
@@ -58,6 +78,13 @@ DN.Diagram
         L0.HasLabel "Node Scale Bias"
     >-- DN.Diagram.nodeScaleProperty --> DN.Vertex.ScaleProperty <R L0.HasProperty : DN.VertexScalePropertyParameterType
         L0.HasLabel "Node Scale Property"
+    @L0.assert DN.Diagram.elementColoringGradientHue
+        0.0 : L0.Float
+            L0.HasDataType $(Float(unit="deg",range=[0..360]))
+    @L0.assert DN.Diagram.elementColoringGradientSaturation
+        100.0 : L0.Float
+            L0.HasDataType $(Float(unit="%",range=[0..100]))
+    @MOD.sclAssertion DN.Diagram.elementColoringFunction "\r -> 1.0" "Resource -> <ReadGraph> Double"
     @L0.assert DN.Diagram.edgeThicknessGain 1.0
     @L0.assert DN.Diagram.edgeThicknessBias 0.0
     @L0.assert DN.Diagram.edgeThicknessProperty DN.Edge.ThicknessProperty.Diameter
@@ -68,11 +95,13 @@ DN.Diagram
 // ----------------------------------------------------------------------------
 // Built-in enumerated ScaleProperty & ThicknessProperty instances
 
+DN.Functions.constantOne : L0.Function
+    L0.HasValueType "Resource -> <ReadGraph> Maybe Double"
+
 DN.Edge.ThicknessProperty.OnlyGainAndBias: DN.Edge.ThicknessProperty
     L0.HasLabel "Only Gain and Bias"
     DN.Edge.ThicknessProperty.value
-        DN.Functions.constantOne : L0.Function
-            L0.HasValueType "Resource -> <ReadGraph> Maybe Double"
+        DN.Functions.constantOne
 
 DN.Edge.ThicknessProperty.Diameter : DN.Edge.ThicknessProperty
     L0.HasLabel "Diameter"
@@ -85,8 +114,7 @@ DN.Edge.ThicknessProperty.Diameter : DN.Edge.ThicknessProperty
 DN.Vertex.ScaleProperty.OnlyGainAndBias: DN.Vertex.ScaleProperty
     L0.HasLabel "Only Gain and Bias"
     DN.Vertex.ScaleProperty.value
-        DN.Functions.constantOne : L0.Function
-            L0.HasValueType "Resource -> <ReadGraph> Maybe Double"
+        DN.Functions.constantOne
 
 DN.Vertex.ScaleProperty.NominalSupplyPressure : DN.Vertex.ScaleProperty
     L0.HasLabel "Nominal Supply Pressure"
index 773ddd300212727fd3a8d869bd9aeebf042ea467..ac1cf19fd3ec67b24a986b071656ed89ea0319f7 100644 (file)
@@ -19,6 +19,7 @@ DN.Groups.VertexGroup : DIA.TypeGroup
 DN.Groups.EdgeGroup : DIA.TypeGroup
     DIA.TypeGroup.HasType DN.Edge
 
+DN.ElementColoringStyle : DIA.Style
 DN.VertexSizeStyle : DIA.Style
 DN.EdgeThicknessStyle : DIA.Style
 DN.HideStyle : DIA.Style
index 2d46af9295ef2281e8256eb1a3b7e262214b55f8..e3c62558c80f939e6fe6eb563f2644d93dee5b5e 100644 (file)
@@ -1,13 +1,5 @@
-import "Simantics/DB"
-import "Simantics/Variables"
-
-districtNetworkProfileStyle :: String -> Resource -> <ReadGraph> (String, String, String)
-districtNetworkProfileStyle relation element = do
-    rel = possibleResource relation
-    result = match rel with
-        Just rel -> do
-            match possibleRelatedValue element rel with
-                Just res -> res
-                Nothing -> ""
-        Nothing -> ""
-    ("", result, "")
\ No newline at end of file
+include "Simantics/DB"
+include "Simantics/Variables"
+include "Simantics/Ontologies"
+include "Simantics/District"
+include "http://www.simantics.org/DistrictNetwork-1.0" as DN
index 2f00824db1f2737e91f5aeab673b6bd3707cdee2..f5f5ba0998728366af33420982f00e6083297818 100644 (file)
@@ -27,6 +27,12 @@ public class DistrictNetworkResource {
     public final Resource Diagram_edgeThicknessGain_Inverse;
     public final Resource Diagram_edgeThicknessProperty;
     public final Resource Diagram_edgeThicknessProperty_Inverse;
+    public final Resource Diagram_elementColoringFunction;
+    public final Resource Diagram_elementColoringFunction_Inverse;
+    public final Resource Diagram_elementColoringGradientHue;
+    public final Resource Diagram_elementColoringGradientHue_Inverse;
+    public final Resource Diagram_elementColoringGradientSaturation;
+    public final Resource Diagram_elementColoringGradientSaturation_Inverse;
     public final Resource Diagram_nodeScaleBias;
     public final Resource Diagram_nodeScaleBias_Inverse;
     public final Resource Diagram_nodeScaleGain;
@@ -71,7 +77,9 @@ public class DistrictNetworkResource {
     public final Resource Edge_ThicknessProperty_value;
     public final Resource Edge_ThicknessProperty_value_Inverse;
     public final Resource Element;
+    public final Resource ElementColoringStyle;
     public final Resource Functions;
+    public final Resource Functions_brightnessValidator;
     public final Resource Functions_compositeInstantiator;
     public final Resource Functions_constantOne;
     public final Resource Functions_convertToValue;
@@ -83,9 +91,11 @@ public class DistrictNetworkResource {
     public final Resource Functions_hasDiameterValue;
     public final Resource Functions_hasElevation;
     public final Resource Functions_hasNominalSupplyPressure;
+    public final Resource Functions_hueValidator;
     public final Resource Functions_mappingModifier;
     public final Resource Functions_nodeScalePropertyEnumerationValues;
     public final Resource Functions_nodeScalePropertyModifier;
+    public final Resource Functions_saturationValidator;
     public final Resource Groups;
     public final Resource Groups_EdgeGroup;
     public final Resource Groups_VertexGroup;
@@ -274,6 +284,12 @@ public class DistrictNetworkResource {
         public static final String Diagram_edgeThicknessGain_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/edgeThicknessGain/Inverse";
         public static final String Diagram_edgeThicknessProperty = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/edgeThicknessProperty";
         public static final String Diagram_edgeThicknessProperty_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/edgeThicknessProperty/Inverse";
+        public static final String Diagram_elementColoringFunction = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringFunction";
+        public static final String Diagram_elementColoringFunction_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringFunction/Inverse";
+        public static final String Diagram_elementColoringGradientHue = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringGradientHue";
+        public static final String Diagram_elementColoringGradientHue_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringGradientHue/Inverse";
+        public static final String Diagram_elementColoringGradientSaturation = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringGradientSaturation";
+        public static final String Diagram_elementColoringGradientSaturation_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/elementColoringGradientSaturation/Inverse";
         public static final String Diagram_nodeScaleBias = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/nodeScaleBias";
         public static final String Diagram_nodeScaleBias_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/nodeScaleBias/Inverse";
         public static final String Diagram_nodeScaleGain = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/nodeScaleGain";
@@ -318,7 +334,9 @@ public class DistrictNetworkResource {
         public static final String Edge_ThicknessProperty_value = "http://www.simantics.org/DistrictNetwork-1.0/Edge/ThicknessProperty/value";
         public static final String Edge_ThicknessProperty_value_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Edge/ThicknessProperty/value/Inverse";
         public static final String Element = "http://www.simantics.org/DistrictNetwork-1.0/Element";
+        public static final String ElementColoringStyle = "http://www.simantics.org/DistrictNetwork-1.0/ElementColoringStyle";
         public static final String Functions = "http://www.simantics.org/DistrictNetwork-1.0/Functions";
+        public static final String Functions_brightnessValidator = "http://www.simantics.org/DistrictNetwork-1.0/Functions/brightnessValidator";
         public static final String Functions_compositeInstantiator = "http://www.simantics.org/DistrictNetwork-1.0/Functions/compositeInstantiator";
         public static final String Functions_constantOne = "http://www.simantics.org/DistrictNetwork-1.0/Functions/constantOne";
         public static final String Functions_convertToValue = "http://www.simantics.org/DistrictNetwork-1.0/Functions/convertToValue";
@@ -330,9 +348,11 @@ public class DistrictNetworkResource {
         public static final String Functions_hasDiameterValue = "http://www.simantics.org/DistrictNetwork-1.0/Functions/hasDiameterValue";
         public static final String Functions_hasElevation = "http://www.simantics.org/DistrictNetwork-1.0/Functions/hasElevation";
         public static final String Functions_hasNominalSupplyPressure = "http://www.simantics.org/DistrictNetwork-1.0/Functions/hasNominalSupplyPressure";
+        public static final String Functions_hueValidator = "http://www.simantics.org/DistrictNetwork-1.0/Functions/hueValidator";
         public static final String Functions_mappingModifier = "http://www.simantics.org/DistrictNetwork-1.0/Functions/mappingModifier";
         public static final String Functions_nodeScalePropertyEnumerationValues = "http://www.simantics.org/DistrictNetwork-1.0/Functions/nodeScalePropertyEnumerationValues";
         public static final String Functions_nodeScalePropertyModifier = "http://www.simantics.org/DistrictNetwork-1.0/Functions/nodeScalePropertyModifier";
+        public static final String Functions_saturationValidator = "http://www.simantics.org/DistrictNetwork-1.0/Functions/saturationValidator";
         public static final String Groups = "http://www.simantics.org/DistrictNetwork-1.0/Groups";
         public static final String Groups_EdgeGroup = "http://www.simantics.org/DistrictNetwork-1.0/Groups/EdgeGroup";
         public static final String Groups_VertexGroup = "http://www.simantics.org/DistrictNetwork-1.0/Groups/VertexGroup";
@@ -531,6 +551,12 @@ public class DistrictNetworkResource {
         Diagram_edgeThicknessGain_Inverse = getResourceOrNull(graph, URIs.Diagram_edgeThicknessGain_Inverse);
         Diagram_edgeThicknessProperty = getResourceOrNull(graph, URIs.Diagram_edgeThicknessProperty);
         Diagram_edgeThicknessProperty_Inverse = getResourceOrNull(graph, URIs.Diagram_edgeThicknessProperty_Inverse);
+        Diagram_elementColoringFunction = getResourceOrNull(graph, URIs.Diagram_elementColoringFunction);
+        Diagram_elementColoringFunction_Inverse = getResourceOrNull(graph, URIs.Diagram_elementColoringFunction_Inverse);
+        Diagram_elementColoringGradientHue = getResourceOrNull(graph, URIs.Diagram_elementColoringGradientHue);
+        Diagram_elementColoringGradientHue_Inverse = getResourceOrNull(graph, URIs.Diagram_elementColoringGradientHue_Inverse);
+        Diagram_elementColoringGradientSaturation = getResourceOrNull(graph, URIs.Diagram_elementColoringGradientSaturation);
+        Diagram_elementColoringGradientSaturation_Inverse = getResourceOrNull(graph, URIs.Diagram_elementColoringGradientSaturation_Inverse);
         Diagram_nodeScaleBias = getResourceOrNull(graph, URIs.Diagram_nodeScaleBias);
         Diagram_nodeScaleBias_Inverse = getResourceOrNull(graph, URIs.Diagram_nodeScaleBias_Inverse);
         Diagram_nodeScaleGain = getResourceOrNull(graph, URIs.Diagram_nodeScaleGain);
@@ -575,7 +601,9 @@ public class DistrictNetworkResource {
         Edge_ThicknessProperty_value = getResourceOrNull(graph, URIs.Edge_ThicknessProperty_value);
         Edge_ThicknessProperty_value_Inverse = getResourceOrNull(graph, URIs.Edge_ThicknessProperty_value_Inverse);
         Element = getResourceOrNull(graph, URIs.Element);
+        ElementColoringStyle = getResourceOrNull(graph, URIs.ElementColoringStyle);
         Functions = getResourceOrNull(graph, URIs.Functions);
+        Functions_brightnessValidator = getResourceOrNull(graph, URIs.Functions_brightnessValidator);
         Functions_compositeInstantiator = getResourceOrNull(graph, URIs.Functions_compositeInstantiator);
         Functions_constantOne = getResourceOrNull(graph, URIs.Functions_constantOne);
         Functions_convertToValue = getResourceOrNull(graph, URIs.Functions_convertToValue);
@@ -587,9 +615,11 @@ public class DistrictNetworkResource {
         Functions_hasDiameterValue = getResourceOrNull(graph, URIs.Functions_hasDiameterValue);
         Functions_hasElevation = getResourceOrNull(graph, URIs.Functions_hasElevation);
         Functions_hasNominalSupplyPressure = getResourceOrNull(graph, URIs.Functions_hasNominalSupplyPressure);
+        Functions_hueValidator = getResourceOrNull(graph, URIs.Functions_hueValidator);
         Functions_mappingModifier = getResourceOrNull(graph, URIs.Functions_mappingModifier);
         Functions_nodeScalePropertyEnumerationValues = getResourceOrNull(graph, URIs.Functions_nodeScalePropertyEnumerationValues);
         Functions_nodeScalePropertyModifier = getResourceOrNull(graph, URIs.Functions_nodeScalePropertyModifier);
+        Functions_saturationValidator = getResourceOrNull(graph, URIs.Functions_saturationValidator);
         Groups = getResourceOrNull(graph, URIs.Groups);
         Groups_EdgeGroup = getResourceOrNull(graph, URIs.Groups_EdgeGroup);
         Groups_VertexGroup = getResourceOrNull(graph, URIs.Groups_VertexGroup);
index 04cd94cf46658f2d3c0bbb8431275d06f8640ad0..3aa6f2752cc04363acf417762d1e1ab680ea3ac7 100644 (file)
@@ -1,5 +1,7 @@
 package org.simantics.district.network.ui.function;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -42,6 +44,7 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.RuntimeDatabaseException;
 import org.simantics.db.exception.ServiceException;
 import org.simantics.db.layer0.QueryIndexUtils;
+import org.simantics.db.layer0.util.Layer0Utils;
 import org.simantics.db.layer0.variable.Variable;
 import org.simantics.db.layer0.variable.Variables;
 import org.simantics.db.layer0.variable.Variables.Role;
@@ -52,10 +55,15 @@ import org.simantics.modeling.ModelingResources;
 import org.simantics.modeling.adapters.NewCompositeActionFactory;
 import org.simantics.modeling.typicals.TypicalUtil;
 import org.simantics.operation.Layer0X;
+import org.simantics.scl.compiler.commands.CommandSession;
+import org.simantics.scl.compiler.commands.CommandSessionImportEntry;
+import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.osgi.SCLOsgi;
 import org.simantics.scl.reflection.annotations.SCLValue;
 import org.simantics.scl.runtime.SCLContext;
 import org.simantics.scl.runtime.function.Function1;
 import org.simantics.scl.runtime.function.FunctionImpl1;
+import org.simantics.scl.runtime.reporting.SCLReportingHandler;
 import org.simantics.ui.workbench.action.DefaultActions;
 import org.simantics.utils.ui.SWTUtils;
 import org.slf4j.Logger;
@@ -523,6 +531,10 @@ public class Functions {
         public Double apply(Resource edge) {
             return ONE;
         }
+        @Override
+        public String toString() {
+            return "1";
+        }
     };
 
     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
@@ -547,4 +559,80 @@ public class Functions {
         };
     }
 
+    private static class RangeValidator implements Function1<String, String> {
+        private double min;
+        private double max;
+        public RangeValidator(double min, double max) {
+            this.min = min;
+            this.max = max;
+        }
+        @Override
+        public String apply(String s) {
+            try {
+                double d = Double.parseDouble(s);
+                if (d < min)
+                    return "Value must be greater than or equal to " + min;
+                if (d > max)
+                    return "Value must be less than or equal to " + max;
+                return null;
+            } catch (NumberFormatException e) {
+                return "Specified value is not a number";
+            }
+        }
+    }
+
+    @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
+    public static Object hueValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
+        return new RangeValidator(0, 360);
+    }
+
+    @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
+    public static Object saturationValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
+        return new RangeValidator(0, 100);
+    }
+
+    @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
+    public static Object brightnessValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
+        String importEntry = null;
+        Resource root = Variables.getPossibleIndexRoot(graph, context);
+        if (root != null) {
+            Resource sclmain = Layer0Utils.getPossibleChild(graph, root, "SCLMain");
+            if (sclmain != null) {
+                importEntry = graph.getPossibleURI(sclmain);
+            }
+        }
+        return new BrightnessExpressionValidator(
+                importEntry != null
+                ? Arrays.asList(importEntry)
+                : Collections.emptyList());
+    }
+
+    private static class BrightnessExpressionValidator implements Function1<String, String> {
+        private CommandSession session;
+
+        public BrightnessExpressionValidator(List<String> importEntries) {
+            this.session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, SCLReportingHandler.DEFAULT);
+            this.session.setImportEntries(imports(importEntries));
+        }
+
+        private ArrayList<CommandSessionImportEntry> imports(List<String> entries) {
+            ArrayList<CommandSessionImportEntry> result = new ArrayList<>();
+            entries.stream().map(CommandSessionImportEntry::new).forEach(result::add);
+            if (entries.isEmpty())
+                result.add(new CommandSessionImportEntry("Simantics/District/SCLMain"));
+            return result;
+        }
+
+        @Override
+        public String apply(String s) {
+            s = s.trim();
+            if (!s.startsWith("="))
+                return "Expression expected, must start with '='";
+            CompilationError[] errors = session.validate(s.substring(1));
+            if(errors.length == 0)
+                return null;
+            return errors[0].description;
+        }
+    }
+
 }
index 1e577e97a4553faebcfebd82659f56c4a8c96894..9f8c9a23ed192245813cdccd1ddbf2a0a61ddc16 100644 (file)
@@ -4,7 +4,6 @@ import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
-import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
@@ -21,19 +20,17 @@ public class DistrictNetworkEdgeNode extends G2DNode implements ISelectionPainte
 
     private static final long serialVersionUID = 8049769475036519806L;
 
-    private static final Stroke     SELECTION_STROKE = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
-    private static final Color      SELECTION_COLOR  = new Color(255, 0, 255, 96);
+    private static final BasicStroke STROKE           = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
+    private static final Color       SELECTION_COLOR  = new Color(255, 0, 255, 96);
 
     private DistrictNetworkEdge edge;
     private Rectangle2D bounds;
-    private Line2D path;
+    private transient Line2D path;
 
-    private static final BasicStroke STROKE = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
     private boolean scaleStroke = true;
-
     private Color color;
-
     private Double stroke;
+    private transient Color dynamicColor = null;
 
     @Override
     public void init() {
@@ -54,7 +51,6 @@ public class DistrictNetworkEdgeNode extends G2DNode implements ISelectionPainte
         Color oldColor = g2d.getColor();
         BasicStroke oldStroke = (BasicStroke) g2d.getStroke();
 
-        g2d.setColor(color);
         BasicStroke bs = null;
         if (scaleStroke) {
             double scale = GeometryUtils.getScale(g2d.getTransform());
@@ -73,6 +69,7 @@ public class DistrictNetworkEdgeNode extends G2DNode implements ISelectionPainte
             g2d.draw(path);
         }
 
+        g2d.setColor(dynamicColor != null ? dynamicColor : color);
         g2d.setStroke(bs);
         g2d.draw(path);
 
@@ -153,4 +150,9 @@ public class DistrictNetworkEdgeNode extends G2DNode implements ISelectionPainte
         this.stroke = stroke;
     }
 
+    @PropertySetter(value = "dynamicColor")
+    public void setDynamicColor(Color color) {
+        this.dynamicColor = color;
+    }
+
 }
index 1dd0afe5c5e52a30b773262f85207d79066a9c9b..58e47f4bcf285dff9f5585aafc7d6a8e5f0eb49e 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.district.network.ui.nodes;
 
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
@@ -9,17 +10,19 @@ import java.awt.geom.Rectangle2D;
 
 import org.simantics.district.network.ModelledCRS;
 import org.simantics.district.network.ui.adapters.DistrictNetworkVertex;
+import org.simantics.scenegraph.ISelectionPainterNode;
 import org.simantics.scenegraph.g2d.G2DNode;
 import org.simantics.scenegraph.utils.GeometryUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.simantics.scenegraph.utils.NodeUtil;
 
-public class DistrictNetworkVertexNode extends G2DNode {
+public class DistrictNetworkVertexNode extends G2DNode implements ISelectionPainterNode {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkVertexNode.class);
+    //private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkVertexNode.class);
 
     private static final long serialVersionUID = -2641639101400236719L;
-    private DistrictNetworkVertex vertex;
+
+    private static final BasicStroke STROKE           = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
+    private static final Color       SELECTION_COLOR  = new Color(255, 0, 255, 96);
 
     private static final double left = -0.25;
     private static final double top = -0.25;
@@ -29,10 +32,13 @@ public class DistrictNetworkVertexNode extends G2DNode {
     private static final Rectangle2D NORMAL = new Rectangle2D.Double(left, top, width, height);
     private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 3, top * 3, width * 3, height * 3);
 
+    private DistrictNetworkVertex vertex;
+
     private boolean scaleStroke = true;
     private boolean hover;
 
     private Color color;
+    private transient Color dynamicColor;
 
     private Rectangle2D bounds;
 
@@ -63,7 +69,6 @@ public class DistrictNetworkVertexNode extends G2DNode {
         }
 
         Color oldColor = g2d.getColor();
-        g2d.setColor(color);
 
         double scaleRecip = 1;
         if (scaleStroke) {
@@ -82,7 +87,16 @@ public class DistrictNetworkVertexNode extends G2DNode {
         } else {
             toDraw = new Rectangle2D.Double(res.getX() - (NORMAL.getWidth() / 2 * scaleRecip), res.getY() - (NORMAL.getHeight() / 2 * scaleRecip), NORMAL.getWidth() * scaleRecip, NORMAL.getHeight() * scaleRecip);
         }
+
+        if (NodeUtil.isSelected(this, 1)) {
+            g2d.setColor(SELECTION_COLOR);
+            BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float) scaleRecip*2);
+            g2d.setStroke(ss);
+            g2d.draw(toDraw);
+        }
+
         // render
+        g2d.setColor(dynamicColor != null ? dynamicColor : color);
         g2d.fill(toDraw);
 
         // Reset settings
@@ -176,4 +190,9 @@ public class DistrictNetworkVertexNode extends G2DNode {
             updateBounds();
     }
 
+    @PropertySetter(value = "dynamicColor")
+    public void setDynamicColor(Color color) {
+        this.dynamicColor = color;
+    }
+
 }
index cd7b433747cda8303ecab3b142dd2d3c51c97766..5151e3e3756a923c875a1a8c18def8fad56049ff 100644 (file)
@@ -9,6 +9,9 @@
                </type>
        </target>
        <target interface="org.simantics.scenegraph.profile.Style">
+               <resource uri="http://www.simantics.org/DistrictNetwork-1.0/ElementColoringStyle"
+                       class="org.simantics.district.network.profile.DNElementColorStyle">
+               </resource>
                <resource uri="http://www.simantics.org/DistrictNetwork-1.0/VertexSizeStyle"
                        class="org.simantics.district.network.profile.VertexSizeStyle">
                </resource>
index 6318d7550b5a7bfcf7a15c0a245bdce85c83aef9..b99442e6b0177c9e5e3c032c0ff42eadb029a1cf 100644 (file)
@@ -1,5 +1,7 @@
 import "Simantics/DB"
 import "Simantics/Ontologies"
+import "Simantics/Variables"
+import "http://www.simantics.org/DistrictNetwork-1.0" as DN
 
 import "Map" as Map
 import "MSet" as MSet
@@ -83,3 +85,36 @@ importJava "org.simantics.district.network.DistrictNetworkUtil" where
     createVertex :: Resource -> Vector Double -> Resource -> <WriteGraph, Proc> Resource
     createEdge :: Resource -> Resource -> <WriteGraph, Proc> Resource
 
+"""
+Tries to look for the Variable representing the configuration component
+mapped to the specified district network diagram element.
+
+The variable returned is by default the active experiment context variable
+but if that is not available then a configuration context variable is returned.
+"""
+possibleMappedComponentVariable :: Resource -> <ReadGraph> Maybe Variable
+possibleMappedComponentVariable r = match possibleObject r DN.MappedComponent with
+    Nothing -> Nothing
+    Just me -> match possibleObject me MOD.ElementToComponent with
+        Nothing -> Nothing
+        Just mc -> do
+            mcv = resourceVariable mc
+            match possibleActiveVariable mcv with
+                Nothing -> Just mcv
+                a       -> a
+
+"""
+"""
+possibleMappedComponentPropertyValue :: String -> Resource -> <ReadGraph> Maybe Double
+possibleMappedComponentPropertyValue propName r = match possibleMappedComponentVariable r with
+    Nothing -> Nothing
+    Just mv -> possiblePropertyValue mv propName
+
+"""
+"""
+mappedComponentPropertyValue :: Double -> String -> Resource -> <ReadGraph> Double
+mappedComponentPropertyValue def propName r = match possibleMappedComponentVariable r with
+    Nothing -> def
+    Just mv -> match possiblePropertyValue mv propName with
+        Nothing -> def
+        Just v  -> v
diff --git a/org.simantics.district.network/src/org/simantics/district/network/profile/ColorGradient.java b/org.simantics.district.network/src/org/simantics/district/network/profile/ColorGradient.java
new file mode 100644 (file)
index 0000000..8ce1088
--- /dev/null
@@ -0,0 +1,19 @@
+package org.simantics.district.network.profile;
+
+import java.awt.Color;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+@FunctionalInterface
+public interface ColorGradient {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @return the function result
+     */
+    Color get(double t);
+
+}
\ No newline at end of file
diff --git a/org.simantics.district.network/src/org/simantics/district/network/profile/Colors.java b/org.simantics.district.network/src/org/simantics/district/network/profile/Colors.java
new file mode 100644 (file)
index 0000000..9ead5c3
--- /dev/null
@@ -0,0 +1,55 @@
+package org.simantics.district.network.profile;
+
+import java.awt.Color;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.35.0
+ */
+public class Colors {
+
+    private static class Cache implements ColorGradient {
+        private final ColorGradient proxy;
+        private final int discretization;
+        private final Color[] cache;
+
+        public Cache(ColorGradient proxy, int discretization) {
+            this.proxy = proxy;
+            this.discretization = discretization;
+            this.cache = new Color[discretization+1];
+        }
+
+        private int discretize(double t) {
+            return (int) (saturate(t) * discretization);
+        }
+
+        @Override
+        public Color get(double t) {
+            int d = discretize(t);
+            Color cached = cache[d];
+            if (cached != null)
+                return cached;
+            cached = cache[d] = proxy.get(t);
+            return cached;
+        }
+    }
+
+    public static final ColorGradient cached(ColorGradient cg) {
+        return new Cache(cg, 512);
+    }
+
+    public static final ColorGradient hsvGradient(float hue, float saturation) {
+        return t -> {
+            return Color.getHSBColor(hue, saturation, saturate((float) t));
+        };
+    }
+
+    private static float saturate(float t) {
+        return Math.max(0f, Math.min(t, 1f));
+    }
+
+    private static double saturate(double t) {
+        return Math.max(0, Math.min(t, 1));
+    }
+
+}
diff --git a/org.simantics.district.network/src/org/simantics/district/network/profile/DNElementColorStyle.java b/org.simantics.district.network/src/org/simantics/district/network/profile/DNElementColorStyle.java
new file mode 100644 (file)
index 0000000..682c91f
--- /dev/null
@@ -0,0 +1,56 @@
+package org.simantics.district.network.profile;
+
+import java.awt.Color;
+
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.diagram.profile.StyleBase;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.common.ProfileVariables;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.35.0
+ */
+public class DNElementColorStyle extends StyleBase<Color> {
+
+       private static final boolean DEBUG = false;
+
+       @Override
+       public Color calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource groupItem) throws DatabaseException {
+               DiagramSettings ds = graph.syncRequest(new DiagramSettingsRequest(runtimeDiagram), TransientCacheAsyncListener.instance());
+               if (ds.elementColoringFunction.isPresent()) {
+                       if (DEBUG)
+                               System.out.print("elementColoringFunction: " + ds.elementColoringFunction + "(" + groupItem + "): ");
+                       Double t = Simantics.applySCLRead(graph, ds.elementColoringFunction.get(), groupItem);
+                       if (DEBUG)
+                               System.out.print(t);
+                       if (t != null) {
+                               Color result = ds.coloringGradient.get(t);
+                               //System.out.println("color(" + t + "): " + result);
+                               return result;
+                       }
+               }
+               return null;
+       }
+
+       @Override
+       public void applyStyleForNode(EvaluationContext observer, INode node, Color color) {
+               SingleElementNode n = (SingleElementNode) node;
+               for (INode nn : n.getNodes())
+                       ProfileVariables.claimNodeProperty(nn, "dynamicColor", color, observer);
+       }
+
+       @Override
+       protected void cleanupStyleForNode(EvaluationContext evaluationContext, INode node) {
+               SingleElementNode n = (SingleElementNode) node;
+               for (INode nn : n.getNodes())
+                       ProfileVariables.claimNodeProperty(nn, "dynamicColor", null, evaluationContext);
+       }
+
+}
index 071489de1b0a8cf2f9b2cad1d16f86b0b791b412..13c38bed02d494c1fed8e2ee359a10422e6c6a5b 100644 (file)
@@ -16,14 +16,32 @@ public class DiagramSettings {
        public final Optional<Function1<Resource, Double>> edgeThicknessProperty;
        public final double edgeThicknessGain;
        public final double edgeThicknessBias;
+       public final Optional<Function1<Resource, Double>> elementColoringFunction;
+       public final float elementColoringGradientHue;
+       public final float elementColoringGradientSaturation;
+       public final transient ColorGradient coloringGradient;
 
-       public DiagramSettings(Function1<Resource, Double> vertexScaleProperty, double vertexScaleGain, double vertexScaleBias, Function1<Resource, Double> edgeThicknessProperty, double edgeThicknessGain, double edgeThicknessBias) {
+       public DiagramSettings(
+                       Function1<Resource, Double> vertexScaleProperty, double vertexScaleGain, double vertexScaleBias,
+                       Function1<Resource, Double> edgeThicknessProperty, double edgeThicknessGain, double edgeThicknessBias,
+                       Function1<Resource, Double> elementColoringFunction,
+                       float elementColoringGradientHue,
+                       float elementColoringGradientSaturation
+                       ) {
                this.vertexScaleProperty = Optional.ofNullable(vertexScaleProperty);
                this.vertexScaleGain = vertexScaleGain;
                this.vertexScaleBias = vertexScaleBias;
                this.edgeThicknessProperty = Optional.ofNullable(edgeThicknessProperty);
                this.edgeThicknessGain = edgeThicknessGain;
                this.edgeThicknessBias = edgeThicknessBias;
+               this.elementColoringFunction = Optional.ofNullable(elementColoringFunction);
+               this.elementColoringGradientHue = elementColoringGradientHue;
+               this.elementColoringGradientSaturation = elementColoringGradientSaturation;
+               this.coloringGradient = Colors.cached(
+                               Colors.hsvGradient(
+                                               elementColoringGradientHue,
+                                               elementColoringGradientSaturation)
+                               );
        }
 
        @Override
@@ -41,6 +59,9 @@ public class DiagramSettings {
                result = prime * result + (int) (temp ^ (temp >>> 32));
                temp = Double.doubleToLongBits(vertexScaleBias);
                result = prime * result + (int) (temp ^ (temp >>> 32));
+               result = prime * result + elementColoringFunction.hashCode();
+               result = prime * result + Float.floatToIntBits(elementColoringGradientHue);
+               result = prime * result + Float.floatToIntBits(elementColoringGradientSaturation);
                return result;
        }
 
@@ -65,13 +86,23 @@ public class DiagramSettings {
                        return false;
                if (Double.doubleToLongBits(vertexScaleBias) != Double.doubleToLongBits(other.vertexScaleBias))
                        return false;
+               if (!elementColoringFunction.equals(other.elementColoringFunction))
+                       return false;
+               if (Float.floatToIntBits(elementColoringGradientHue) != Float.floatToIntBits(other.elementColoringGradientHue))
+                       return false;
+               if (Float.floatToIntBits(elementColoringGradientSaturation) != Float.floatToIntBits(other.elementColoringGradientSaturation))
+                       return false;
                return true;
        }
 
        @Override
        public String toString() {
-               return String.format("DiagramSettings[%s * %f + %f - %s * %f + %f]", vertexScaleProperty.toString(),
-                               vertexScaleGain, vertexScaleBias, edgeThicknessProperty, edgeThicknessGain, edgeThicknessBias);
+               return String.format("DiagramSettings[%s * %f + %f - %s * %f + %f - coloringFunction: %s, hue: %f, saturation: %f]",
+                               vertexScaleProperty.toString(), vertexScaleGain, vertexScaleBias,
+                               edgeThicknessProperty, edgeThicknessGain, edgeThicknessBias,
+                               elementColoringFunction.toString(),
+                               elementColoringGradientHue, elementColoringGradientSaturation
+                               );
        }
 
 }
index 6fdb9721f059b20d32498e75f0f423659ebfa5be..a17464d8aefe655ea4e83b9eea54832a513cc9f6 100644 (file)
@@ -20,11 +20,15 @@ public class DiagramSettingsRequest extends ResourceRead<DiagramSettings> {
                super(runtimeDiagram);
        }
 
-       @Override
+       @SuppressWarnings("unchecked")
+    @Override
        public DiagramSettings perform(ReadGraph graph) throws DatabaseException {
                DiagramResource DIA = DiagramResource.getInstance(graph);
                DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
 
+               Function1<Resource, Double> elementColoringFunction = null;
+               float elementColoringGradientHue = 0;
+               float elementColoringGradientSaturation = 1;
                Function1<Resource, Double> edgeThicknessProperty = null;
                Function1<Resource, Double> nodeScaleProperty = null;
                double edgeThicknessGain = 1;
@@ -34,6 +38,20 @@ public class DiagramSettingsRequest extends ResourceRead<DiagramSettings> {
 
                Resource diagram = graph.getPossibleObject(resource, DIA.RuntimeDiagram_HasConfiguration);
                if (diagram != null) {
+                       Variable dv = Variables.getPossibleVariable(graph, diagram);
+                       if (dv != null) {
+                               Object obj = dv.getPossiblePropertyValue(graph, DN.Diagram_elementColoringFunction);
+                               if (obj instanceof Function1<?,?>) {
+                                       elementColoringFunction = (Function1<Resource, Double>) obj;
+                               }
+                       }
+                       elementColoringGradientHue =
+                                       limit(0, 360, safeFloatProperty(graph, diagram, DN.Diagram_elementColoringGradientHue, 0.0f))
+                                       / 360.0f;
+                       elementColoringGradientSaturation =
+                                       limit(0, 100, safeFloatProperty(graph, diagram, DN.Diagram_elementColoringGradientSaturation, 0.0f))
+                                       / 100.0f;
+
                        Resource etp = graph.getPossibleObject(diagram, DN.Diagram_edgeThicknessProperty);
                        //System.out.println("etp: " + NameUtils.getURIOrSafeNameInternal(graph, etp));
                        if (etp != null) {
@@ -69,14 +87,31 @@ public class DiagramSettingsRequest extends ResourceRead<DiagramSettings> {
 
                DiagramSettings ds = new DiagramSettings(
                                nodeScaleProperty, nodeScaleGain, nodeScaleBias,
-                               edgeThicknessProperty, edgeThicknessGain, edgeThicknessBias);
+                               edgeThicknessProperty, edgeThicknessGain, edgeThicknessBias,
+                               elementColoringFunction,
+                               elementColoringGradientHue,
+                               elementColoringGradientSaturation);
                //System.out.println("new diagram settings: " + ds);
                return ds;
        }
 
+       private static float safeFloatProperty(ReadGraph graph, Resource r, Resource property, float defaultValue) throws DatabaseException {
+               Float d = graph.getPossibleRelatedValue(r, property, Bindings.FLOAT);
+               return d != null ? d : defaultValue;
+       }
+
        private static double safeDoubleProperty(ReadGraph graph, Resource r, Resource property, double defaultValue) throws DatabaseException {
                Double d = graph.getPossibleRelatedValue(r, property, Bindings.DOUBLE);
                return d != null ? d : defaultValue;
        }
 
+       private static float limit(float min, float max, float value) {
+               return Math.max(min, Math.min(value,  max));
+       }
+
+       @SuppressWarnings("unused")
+       private static double limit(double min, double max, double value) {
+               return Math.max(min, Math.min(value,  max));
+       }
+
 }