Commit 2bf959dc authored by Nico Mack's avatar Nico Mack

Fixed a number of issues with value selection

ValueRange is now generic
Added multiTurn capability to ValueWidget
parent e541381a
......@@ -154,12 +154,8 @@ public class NumericalVariable extends Variable<Double> {
if (this.valueRange != 0) {
double val = this.roundToPrecision(newValue);
if (val < this.minValue)
val = this.minValue;
else if (val > this.maxValue)
val = this.maxValue;
val = Math.max(val, this.minValue);
val = Math.min(val, this.maxValue);
normalized = (val - this.minValue) / this.valueRange;
}
return normalized;
......@@ -275,9 +271,10 @@ public class NumericalVariable extends Variable<Double> {
double val = (newValue != null) ? roundToPrecision(newValue) + 0.0d : 0d; // Avoid -0.0 values
this.normalizedValue = this.normalizeValue(val);
this.modified = ((newValue != null) && (!isEqual(newValue, this.value, this.epsilon)));
this.value = newValue;
// this.modified = ((newValue != null) && (!isEqual(newValue, this.value, this.epsilon)));
// this.value = newValue;
this.modified = ((newValue != null) && (!isEqual(val, this.value, this.epsilon)));
this.value = val;
if (this.modified) {
this.notifyInputChangeListeners(new InputEvent(this));
}
......
......@@ -23,9 +23,9 @@ package lu.list.itis.dkd.tui.utility;
// * Class Definition and Members *
// ***************************************************************************
public class ValueRange {
private Object lowerValue;
private Object upperValue;
public class ValueRange<T> {
private T lowerValue;
private T upperValue;
// ---------------------------------------------------------------------------
// ***************************************************************************
......@@ -33,7 +33,7 @@ public class ValueRange {
// ***************************************************************************
// ---------------------------------------------------------------------------
public ValueRange(Object lower, Object upper) {
public ValueRange(T lower, T upper) {
this.lowerValue = lower;
this.upperValue = upper;
}
......@@ -50,7 +50,7 @@ public class ValueRange {
*/
// ---------------------------------------------------------------------------
public Object getLowerValue() {
public T getLowerValue() {
return lowerValue;
}
......@@ -63,7 +63,7 @@ public class ValueRange {
*/
// ---------------------------------------------------------------------------
public void setLowerValue(Object lowerValue) {
public void setLowerValue(T lowerValue) {
this.lowerValue = lowerValue;
}
......@@ -75,7 +75,7 @@ public class ValueRange {
*/
// ---------------------------------------------------------------------------
public Object getUpperValue() {
public T getUpperValue() {
return upperValue;
}
......@@ -88,7 +88,7 @@ public class ValueRange {
*/
// ---------------------------------------------------------------------------
public void setUpperValue(Object upperValue) {
public void setUpperValue(T upperValue) {
this.upperValue = upperValue;
}
......
......@@ -4,6 +4,7 @@ import lu.list.itis.dkd.tui.adapter.TangibleObject;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.utility.AngleUtils;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.ValueRange;
import lu.list.itis.dkd.tui.widget.builder.SelectorWidgetBuilder;
import lu.list.itis.dkd.tui.widget.corona.SelectableCorona;
import lu.list.itis.dkd.tui.widget.state.StateManager;
......@@ -32,6 +33,8 @@ public class SelectorWidget extends ValueWidget {
protected float presetAngleOffset = 0;
protected boolean isPersistent = false;
private double segmentSpan;
// ***************************************************************************
// * Constants *
// ***************************************************************************
......@@ -40,7 +43,6 @@ public class SelectorWidget extends ValueWidget {
private static final Logger LOGGER = LoggerFactory.getLogger(SelectorWidget.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
......@@ -59,9 +61,8 @@ public class SelectorWidget extends ValueWidget {
this.numberOfPositions = this.getNumberOfPositions();
this.presetPosition = builder.preselect;
if (presetPosition != NONE) {
this.selectPosition(presetPosition);
}
this.buildFromProperties();
}
// ---------------------------------------------------------------------------
......@@ -79,9 +80,7 @@ public class SelectorWidget extends ValueWidget {
this.numberOfPositions = original.numberOfPositions;
this.presetPosition = original.presetPosition;
if (presetPosition != NONE) {
this.selectPosition(presetPosition);
}
this.buildFromProperties();
}
// ---------------------------------------------------------------------------
......@@ -90,6 +89,19 @@ public class SelectorWidget extends ValueWidget {
// ***************************************************************************
// ---------------------------------------------------------------------------
private void buildFromProperties() {
double overallSpan = (withStopAngles) ? Math.toRadians(upperStopAngle - lowerStopAngle) : AngleUtils.TWO_PI;
segmentSpan = overallSpan / numberOfPositions;
if (presetPosition != NONE) {
this.selectPosition(presetPosition);
}
}
// ---------------------------------------------------------------------------
protected int getNumberOfPositions() {
List<SelectableCorona> selectableCoronas = getCoronas(SelectableCorona.class);
Multimap<Integer, SelectableCorona> alreadySeen = TreeMultimap.create();
......@@ -122,20 +134,33 @@ public class SelectorWidget extends ValueWidget {
// ---------------------------------------------------------------------------
protected ValueRange<Double> getSegmentSpan(int position) {
double lower = 0;
double upper = 0;
if (withStopAngles) {
lower = (lowerStopAngle + (segmentSpan * position));
upper = (lowerStopAngle + (segmentSpan * (position + 1)));
} else {
lower = (position - 0.5) * segmentSpan;
upper = (position + 0.5) * segmentSpan;
}
return new ValueRange<>(lower, upper);
}
// ---------------------------------------------------------------------------
protected int getCurrentPosition(float newAngle) {
double range = (constrainted) ? Math.toRadians(upperStopAngle - lowerStopAngle) : AngleUtils.TWO_PI;
double segment = range / numberOfPositions;
int current = 0;
float angle = (float) AngleUtils.moduloTwoPi(newAngle);
// detect in which segment the current rotation is
for (int position = 0; position < numberOfPositions; position++) {
double minrot = (position - 0.5) * segment;
double maxrot = (position + 0.5) * segment;
if ((angle >= minrot) && (angle < maxrot)) {
ValueRange<Double> span = this.getSegmentSpan(position);
if ((angle >= span.getLowerValue()) && (angle < span.getUpperValue())) {
current = position;
break;
}
......@@ -147,14 +172,12 @@ public class SelectorWidget extends ValueWidget {
// ---------------------------------------------------------------------------
protected float getCurrentAngle(int position) {
double segment = TWO_PI / numberOfPositions;
float angle = 0;
if ((position >= 0) && (position < numberOfPositions)) {
double minrot = (position - 0.5) * segment;
double maxrot = (position + 0.5) * segment;
ValueRange<Double> span = this.getSegmentSpan(position);
angle = (float) (minrot + maxrot) / 2f;
angle = (float) (span.getLowerValue() + span.getUpperValue()) / 2f;
}
return angle;
}
......
......@@ -77,7 +77,7 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
/** Whether the handle allows multiple revolutions of its handle. */
protected boolean multiTurn = false;
/** Internal flag specifying whether this widgets rotation is constrainted or not! */
protected boolean constrainted;
protected boolean withStopAngles;
/**
* Field holding the current angular position of the constrainted (lowerStopAngle | upperStopAngle)
......@@ -86,7 +86,6 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
protected double dialAngle;
private double stepAngle;
private double lastAngle;
private double steps;
private List<ValueCorona> dispatcher;
......@@ -160,7 +159,6 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
this.variable = new NumericalVariable(variableName, EquationSystemBundle.EMPTY_STRING, 0d);
}
lastAngle = Double.NaN;
if (!modifyValueOnRotation) {
......@@ -170,16 +168,24 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
this.initialValue = getVariable().getValue();
}
constrainted = !(Double.isNaN(lowerStopAngle) || Double.isNaN(upperStopAngle));
if (!multiTurn && constrainted) {
dialAngle = lowerStopAngle;
steps = (upperBound - lowerBound + 1) / stepSize;
stepAngle = (upperStopAngle - lowerStopAngle) / steps;
withStopAngles = !(Double.isNaN(lowerStopAngle) || Double.isNaN(upperStopAngle));
if (!multiTurn) {
this.updateFromBounds(lowerBound, upperBound);
}
this.setupDispatcher();
}
// ---------------------------------------------------------------------------
private void updateFromBounds(double lower, double upper) {
if (withStopAngles) {
dialAngle = lowerStopAngle;
double steps = (upper - lower + 1) / stepSize;
stepAngle = (upperStopAngle - lowerStopAngle) / steps;
}
}
// ---------------------------------------------------------------------------
/**
* iterates over all value coronas assigned to this widget and populates the dispatcher table, using
......@@ -211,7 +217,7 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
private void updateDisplays() {
for (ValueCorona display : dispatcher) {
display.setInformation(this.variable.getValue());
display.setInformation(this.variable.getConstrainedValue());
}
}
......@@ -235,13 +241,11 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
return;
}
if (constrainted) {
value = lowerBound + (stepSize * Math.floor(((angle - lowerStopAngle) / stepAngle)));
value = Math.max(value, this.lowerBound);
value = Math.min(value, this.upperBound);
if (withStopAngles) {
value = lowerBound + (stepSize * Math.floor((angle - lowerStopAngle) / stepAngle));
} else if (multiTurn) {
value = variable.getConstrainedValue();
if (!Double.isNaN(lastAngle)) {
value = variable.getValue();
double wrapped = AngleUtils.wrapTwoPi(angle - lastAngle);
double degrees = Math.toDegrees(wrapped);
double delta = Math.abs(degrees * stepSize);
......@@ -260,6 +264,9 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
value = lowerBound + (AngleUtils.moduloTwoPi(angle) * (upperBound - lowerBound));
}
value = Math.max(value, this.lowerBound);
value = Math.min(value, this.upperBound);
variable.setValue(value);
this.updateTethers(value);
this.updateDisplays();
......@@ -307,7 +314,7 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
StateManager manager = objectStates.get(tangibleObject.getObjectId());
if (constrainted) {
if (withStopAngles) {
double angle = AngleUtils.moduloTwoPi(lowerStopAngle + Math.PI + tangibleObject.getAngle());
dialAngle = Math.max(angle, lowerStopAngle);
......@@ -394,6 +401,9 @@ public class ValueWidget extends TetherableWidget implements InformationProvider
NumericalVariable numeric = Variable.castTo(systemVariables.get(this.variable.getName()), NumericalVariable.class);
if (numeric != null) {
this.variable = numeric;
this.lowerBound = (Double.isNaN(lowerBound)) ? numeric.getMinValue() : lowerBound;
this.upperBound = (Double.isNaN(upperBound)) ? numeric.getMaxValue() : upperBound;
this.updateFromBounds(this.lowerBound, this.upperBound);
connected.add(this.variable);
}
}
......
......@@ -146,8 +146,8 @@ public abstract class BaseValueWidgetBuilder<B extends BaseValueWidgetBuilder<B>
multiTurn = BootstrappingUtils.getContentAsBoolean(rootElement, CpsNamespace.MULTITURN_NODE, BootstrappingUtils.OPTIONAL, false, context);
if (modifyValueOnRotation) {
lowerBound = BootstrappingUtils.getContentAsDouble(rootElement, Externalization.LOWER_BOUND_NODE, BootstrappingUtils.MANDATORY, null, context);
upperBound = BootstrappingUtils.getContentAsDouble(rootElement, Externalization.UPPER_BOUND_NODE, BootstrappingUtils.MANDATORY, null, context);
lowerBound = BootstrappingUtils.getContentAsDouble(rootElement, Externalization.LOWER_BOUND_NODE, BootstrappingUtils.OPTIONAL, Double.NaN, context);
upperBound = BootstrappingUtils.getContentAsDouble(rootElement, Externalization.UPPER_BOUND_NODE, BootstrappingUtils.OPTIONAL, Double.NaN, context);
lowerStopAngle = BootstrappingUtils.getContentAsDouble(rootElement, CpsNamespace.LOWER_STOP_ANGLE_NODE, BootstrappingUtils.OPTIONAL, Double.NaN, context);
upperStopAngle = BootstrappingUtils.getContentAsDouble(rootElement, CpsNamespace.UPPER_STOP_ANGLE_NODE, BootstrappingUtils.OPTIONAL, Double.NaN, context);
stepSize = BootstrappingUtils.getContentAsDouble(rootElement, CpsNamespace.STEP_SIZE_NODE, BootstrappingUtils.OPTIONAL, 1.0, context);
......
......@@ -254,6 +254,14 @@ public class ArcGraph extends ValueCorona {
// ---------------------------------------------------------------------------
public boolean reachedEndOfScale() {
double epsilon = this.variable.getEpsilon();
return (NumericalVariable.isEqual(normalizedValue, 1d, epsilon)
|| (relative && NumericalVariable.isEqual(normalizedValue, 0d, epsilon)));
}
// ---------------------------------------------------------------------------
public void setNormalizedValue(double value) {
normalizedValue = value;
......@@ -271,13 +279,10 @@ public class ArcGraph extends ValueCorona {
extend = arcSpan * normalizedValue;
}
if (blinkOnOutOfRange) {
double epsilon = this.variable.getEpsilon();
if (NumericalVariable.isEqual(normalizedValue, 1d, epsilon)
|| (relative && NumericalVariable.isEqual(normalizedValue, 0d, epsilon)))
this.startBlinking();
else
this.stopBlinking();
if (blinkOnOutOfRange && reachedEndOfScale()) {
this.startBlinking();
} else {
this.stopBlinking();
}
double diameter = 2 * outerRadius;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment