Commit b3aa8423 authored by Nico Mack's avatar Nico Mack
Browse files

Integrated support for SpatialVariables in PythonExecutor

parent 37e3695e
......@@ -5,6 +5,11 @@
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
......@@ -19,5 +24,6 @@
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/${PROJECT_DIR_NAME}/python</path>
</pydev_pathproperty>
</pydev_project>
'''
Created on Aug 16, 2017
@author: mack
'''
def AddPoints (A, B):
C = {}
C['x'] = A['x'] + B['x']
C['y'] = A['y'] + B['y']
C['a'] = A['a'] + B['a']
return C
\ No newline at end of file
......@@ -52,7 +52,7 @@ public class DisplayWidgetBootstrapper implements BootstrapCallback {
// * Constants *
// ***************************************************************************
private static Logger LOGGER = LoggerFactory.getLogger(DisplayWidgetBootstrapper.class.getName());
private static final Logger LOGGER = LoggerFactory.getLogger(DisplayWidgetBootstrapper.class.getName());
// ---------------------------------------------------------------------------
// ***************************************************************************
......
......@@ -54,7 +54,7 @@ public class Equation {
private String script;
private boolean isolated;
private static Logger LOGGER = LoggerFactory.getLogger(Equation.class.getSimpleName());
private static final Logger LOGGER = LoggerFactory.getLogger(Equation.class.getSimpleName());
/**
* Constructor
......
......@@ -165,11 +165,11 @@ public class NumericalVariable extends Variable<Double> {
this.setValue(this.valueFromObject(object));
}
/** {@inheritDoc} */
@Override
public Double getValue() {
return this.value;
}
// /** {@inheritDoc} */
// @Override
// public Double getValue() {
// return super.getValue();
// }
/**
*
......
......@@ -135,42 +135,42 @@ public class SpatialVariable extends Variable<Point> {
}
@ExecutorScope(identifier = "x")
public double getX() {
return (this.value != null) ? this.value.getX() : 0;
public Double getX() {
return (this.value != null) ? Double.valueOf(this.value.x) : 0;
}
@ExecutorScope(identifier = "x")
public void setX(double value) {
public void setX(Double value) {
if (this.value == null) {
this.value = new Point();
}
this.value.x = (float) value;
this.value.x = (value != null) ? value.floatValue() : 0f;
}
@ExecutorScope(identifier = "y")
public double getY() {
return (this.value != null) ? this.value.getY() : 0;
public Double getY() {
return (this.value != null) ? Double.valueOf(this.value.y) : 0;
}
@ExecutorScope(identifier = "y")
public void setY(double value) {
public void setY(Double value) {
if (this.value == null) {
this.value = new Point();
}
this.value.y = (float) value;
this.value.y = (value != null) ? value.floatValue() : 0f;
}
@ExecutorScope(identifier = "a")
public double getA() {
return (this.value != null) ? this.value.getAngle() : 0;
public Double getAngle() {
return (this.value != null) ? Double.valueOf(this.value.getAngle()) : 0;
}
@ExecutorScope(identifier = "a")
public void setAngle(double value) {
public void setAngle(Double value) {
if (this.value == null) {
this.value = new Point();
}
this.value.setAngle((float) value);
this.value.setAngle((value != null) ? value.floatValue() : 0f);
}
}
......@@ -24,11 +24,19 @@ import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
import lu.list.itis.dkd.tui.cps.InputEvent;
import lu.list.itis.dkd.tui.cps.utility.ExecutorScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
/**
......@@ -56,6 +64,8 @@ public abstract class Variable<V> implements Cloneable {
protected V value;
protected boolean modified = true;
protected int suspendNotificationSemaphore = 0;
public static final String NO_UNIT = ""; //$NON-NLS-1$
......@@ -136,14 +146,27 @@ public abstract class Variable<V> implements Cloneable {
/**
* Simple getter method for the value held by the {@link Variable} instance.
* Simple getter method for the value held by the {@link Variable} instance. Reading the value
* will reset the modified flag.
*
* @return The value held by the {@link Variable} instance.
*/
public V getValue() {
this.modified = false;
return value;
}
/**
* checks whether this variable was modified since it was read for the last time. *
*
* @return <code>true</code> if variable was modified since last read, <code>false</code>
* otherwise.
*/
public boolean wasModified() {
return this.modified;
}
/**
* Method used to set the value held by the variable.
*
......@@ -151,6 +174,8 @@ public abstract class Variable<V> implements Cloneable {
* The new value the variable should have.
*/
public void setValue(V newValue) {
this.modified = ((newValue != null) && (!newValue.equals(this.value)));
this.value = newValue;
this.notifyInputChangeListeners(new InputEvent(this));
}
......@@ -216,6 +241,76 @@ public abstract class Variable<V> implements Cloneable {
return false;
}
/**
*
* @param clazz
* @return
*/
public static Map<String, Method> getValueGetters(Class<?> clazz) {
Map<String, Method> getters = new HashMap<>();
try {
BeanInfo classDetails = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] properties = classDetails.getPropertyDescriptors();
for (Method method : clazz.getDeclaredMethods()) {
ExecutorScope scope = method.getAnnotation(ExecutorScope.class);
if (scope != null) {
String identifier = scope.identifier();
for (PropertyDescriptor descriptor : properties) {
if (method.equals(descriptor.getReadMethod())) {
getters.put(identifier, method);
}
}
}
}
} catch (IntrospectionException e) {
LOGGER.error("Failed to lookup value Getters for variable class {}!", clazz.getSimpleName()); //$NON-NLS-1$
}
return getters;
}
/**
*
* @param clazz
* @return
*/
public static Map<String, Method> getValueSetters(Class<?> clazz) {
Map<String, Method> setters = new HashMap<>();
try {
BeanInfo classDetails = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] properties = classDetails.getPropertyDescriptors();
for (Method method : clazz.getDeclaredMethods()) {
ExecutorScope scope = method.getAnnotation(ExecutorScope.class);
if (scope != null) {
String identifier = scope.identifier();
for (PropertyDescriptor descriptor : properties) {
if (method.equals(descriptor.getWriteMethod())) {
setters.put(identifier, method);
}
}
}
}
} catch (IntrospectionException e) {
LOGGER.error("Failed to lookup value Setters for variable class {}!", clazz.getSimpleName()); //$NON-NLS-1$
}
return setters;
}
public static Object invokeVariableMethod(Method method, Variable<?> variable, Object[] parameters) {
Object result = null;
try {
result = method.invoke(variable, parameters);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("Failed to invoke method {} on variable {}!", method.getName(), variable.getName(), e); //$NON-NLS-1$
}
return result;
}
/**
* Method invoked to add a {@link InputChangeListener} to the {@link Vector} of listeners to
* notify on tick.
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.utility;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class VariableManager {
private HashMap<String, Variable<?>> variables;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
public VariableManager() {
variables = new HashMap<>();
}
// ---------------------------------------------------------------------------
public VariableManager(Collection<Variable<?>> variables) {
this.variables = new HashMap<>();
for (Variable<?> variable : variables) {
this.variables.put(variable.getName(), variable);
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private boolean connect(Variable<?> local, Map<String, Variable<?>> globals) {
boolean connected = false;
if ((globals != null) && globals.containsKey(local.getName())) {
Variable<?> global = globals.get(local.getName());
if (globals.getClass().isAssignableFrom(global.getClass())) {
this.variables.put(local.getName(), global);
connected = true;
}
}
return connected;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
public void connectWithGlobals(Map<String, Variable<?>> globals) {
for (Variable<?> local : variables.values()) {
connect(local, globals);
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, TULIP is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, version 3 of the License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.widget;
import lu.list.itis.dkd.tui.cps.InputChangeListener;
......@@ -8,6 +28,9 @@ import lu.list.itis.dkd.tui.widget.builder.BaseDisplayWidgetBuilder;
import lu.list.itis.dkd.tui.widget.builder.DisplayWidgetBuilder;
import lu.list.itis.dkd.tui.widget.corona.ValueCorona;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import org.python.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -16,29 +39,28 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @author nmack
* Widget bundling multiple display coronas, allowing displaying multiple values. All variable
* changes will be handled by this widget and dispatched to the corresponding display corona.
*
* @date 20 Jan 2016
*
* <br>
* $Log: DisplayWidget.java,v $
* @author Nico Mack [nico.mack@list.lu]
* @since 2.3
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class DisplayWidget extends BaseWidget implements InputChangeListener {
HashMap<String, NumericalVariable> variables;
HashMap<String, ValueCorona> dispatcher;
Multimap<String, ValueCorona> dispatcher;
// ***************************************************************************
// * Constants *
// ***************************************************************************
private static Logger LOGGER = LoggerFactory.getLogger(DisplayWidget.class.getSimpleName());
private static final Logger LOGGER = LoggerFactory.getLogger(DisplayWidget.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
......@@ -49,11 +71,37 @@ public class DisplayWidget extends BaseWidget implements InputChangeListener {
public DisplayWidget(BaseDisplayWidgetBuilder<DisplayWidgetBuilder> builder) {
super(builder);
this.setupDispatcher();
this.variables = new HashMap<>();
if (builder.variables != null) {
this.setVariables(builder.variables);
}
}
this.dispatcher = new HashMap<String, ValueCorona>();
// ---------------------------------------------------------------------------
public DisplayWidget(DisplayWidget original) {
super(original);
// TODO figure out to handle multiple instances of the same variables.
this.setupDispatcher();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* iterates over all value coronas assigned to this widget and populates the dispatcher table,
* using variable names as keys and associating depending coronas as values
*/
// ---------------------------------------------------------------------------
private void setupDispatcher() {
this.dispatcher = TreeMultimap.create();
List<ValueCorona> displays = this.getCoronas(ValueCorona.class);
for (ValueCorona display : displays) {
......@@ -65,11 +113,34 @@ public class DisplayWidget extends BaseWidget implements InputChangeListener {
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
/**
* Updates the display for the corona(s) associated with the specified variable.
*
* @param variableName
* specifies the name of the variable to update the corresponding displays of.
*/
// ---------------------------------------------------------------------------
private void updateDisplayFor(String variableName) {
Variable<?> variable = this.variables.get(variableName);
if (variable != null) {
if (variable.wasModified()) {
Object information = variable.getValue();
Collection<ValueCorona> displays = dispatcher.get(variableName);
if (displays != null) {
for (ValueCorona display : displays) {
display.setInformation(information);
}
} else {
LOGGER.warn("No matching display found for variable {}!", variableName); //$NON-NLS-1$
}
}
} else {
LOGGER.warn("Required variable {} unkown to display widget!", variableName); //$NON-NLS-1$
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
......@@ -77,62 +148,86 @@ public class DisplayWidget extends BaseWidget implements InputChangeListener {
// ---------------------------------------------------------------------------
public void connectWithOutputs(Map<String, Variable<?>> outputs) {
for (String variableName : variables.keySet()) {
NumericalVariable variable = variables.get(variableName);
Preconditions.checkArgument(outputs != null, "Set of variables can't be null!"); //$NON-NLS-1$
for (Entry<String, NumericalVariable> entry : variables.entrySet()) {
String variableName = entry.getKey();
Variable<?> variable = entry.getValue();
if ((outputs != null) && outputs.containsKey(variableName)) {
Variable<?> output = outputs.get(variableName);
if (variable.getClass().isAssignableFrom(output.getClass())) {
NumericalVariable numeric = (NumericalVariable) output;
variables.put(variableName, numeric);
variables.put(variableName, (NumericalVariable) output);
} else {
LOGGER.warn("Variable {} can not be assigned from variable of type {}!", variableName, output.getType()); //$NON-NLS-1$
}
}
}
}
// ---------------------------------------------------------------------------
public void setVariables(Collection<Variable<?>> newVariables) {
Preconditions.checkArgument(newVariables != null, "Set of variables can't be null!"); //$NON-NLS-1$
Preconditions.checkArgument(newVariables != null, "Set of variables can't be null!"); // $NON-NLS-1$
assert newVariables != null;
this.variables = new HashMap<String, NumericalVariable>();
this.variables = new HashMap<>();
for (Variable<?> variable : newVariables) {
this.variables.put(variable.getName(), (NumericalVariable) variable);
NumericalVariable numeric = (NumericalVariable) variable;
this.variables.put(numeric.getName(), numeric);
variable.addListener(this);
}
List<ValueCorona> displays = this.getCoronas(ValueCorona.class);
for (ValueCorona display : displays) {
Variable<?> variable = display.getVariable();
if (variable != null) {
String variableName = variable.getName();
if (this.variables.containsKey(variableName)) {
display.setVariable(this.variables.get(variableName));
} else {
LOGGER.warn("Corona requires variable {} unkown to display widget!", variableName); //$NON-NLS-1$
if (dispatcher.containsKey(numeric.getName())) {
Collection<ValueCorona> displays = dispatcher.get(numeric.getName());
for (ValueCorona display : displays) {
display.setVariable(numeric);
}
} else {
LOGGER.warn("Variable {} appears not to be used by any Value Corona!", numeric.getName()); // $NON-NLS-1$
}
}
}
// public void setVariables(Collection<Variable<?>> newVariables) {
// Preconditions.checkArgument(newVariables != null, "Set of variables can't be null!");
// //$NON-NLS-1$
//
// this.variables = new HashMap<String, NumericalVariable>();
// for (Variable<?> variable : newVariables) {
// this.variables.put(variable.getName(), (NumericalVariable) variable);
// variable.addListener(this);
// }
//
// List<ValueCorona> displays = this.getCoronas(ValueCorona.class);
// for (ValueCorona display : displays) {
// Variable<?> variable = display.getVariable();
// if (variable != null) {