Extract common functionality to DataBranch
This commit is contained in:
parent
9554bf3fe2
commit
621ee57cc2
@ -1,14 +1,133 @@
|
||||
package info.openrocket.core.simulation;
|
||||
|
||||
import info.openrocket.core.util.ArrayList;
|
||||
import info.openrocket.core.util.ModID;
|
||||
import info.openrocket.core.util.Monitorable;
|
||||
import info.openrocket.core.util.Mutable;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A branch of data / collection of data points for a specific type of data.
|
||||
* @param <T> the type of data in this branch
|
||||
*/
|
||||
public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
public abstract class DataBranch<T extends DataType> implements Monitorable {
|
||||
protected final String name;
|
||||
protected final Map<T, ArrayList<Double>> values = new LinkedHashMap<>();
|
||||
protected final Map<T, Double> maxValues = new HashMap<>();
|
||||
protected final Map<T, Double> minValues = new HashMap<>();
|
||||
|
||||
protected final Mutable mutable = new Mutable();
|
||||
protected ModID modID = ModID.INVALID;
|
||||
|
||||
/**
|
||||
* Sole constructor. Defines the name of the DataBranch and at least one variable type.
|
||||
*
|
||||
* @param name the name of this DataBranch.
|
||||
* @param types data types to include (must include at least one type).
|
||||
*/
|
||||
@SafeVarargs
|
||||
public DataBranch(String name, T... types) {
|
||||
if (types.length == 0) {
|
||||
throw new IllegalArgumentException("Must specify at least one data type.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
||||
for (T t : types) {
|
||||
addType(t);
|
||||
}
|
||||
}
|
||||
|
||||
public DataBranch(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected void addType(T type) {
|
||||
if (values.containsKey(type)) {
|
||||
throw new IllegalArgumentException("Value type " + type + " already exists.");
|
||||
}
|
||||
|
||||
values.put(type, new ArrayList<>());
|
||||
minValues.put(type, Double.NaN);
|
||||
maxValues.put(type, Double.NaN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new point into the data branch. The value for all types is set to NaN by default.
|
||||
*
|
||||
* @throws IllegalStateException if this object has been made immutable.
|
||||
*/
|
||||
public void addPoint() {
|
||||
mutable.check();
|
||||
|
||||
for (Map.Entry<T, ArrayList<Double>> entry : values.entrySet()) {
|
||||
sanityCheckValues(entry.getKey(), Double.NaN);
|
||||
entry.getValue().add(Double.NaN);
|
||||
}
|
||||
modID = new ModID();
|
||||
}
|
||||
|
||||
private void sanityCheckValues(T type, Double value) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
|
||||
if (list == null) {
|
||||
list = new info.openrocket.core.util.ArrayList<>();
|
||||
int n = getLength();
|
||||
for (int i = 0; i < n; i++) {
|
||||
list.add(Double.NaN);
|
||||
}
|
||||
values.put(type, list);
|
||||
minValues.put(type, value);
|
||||
maxValues.put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a specific data type at the latest point. New variable types can be
|
||||
* added to the FlightDataBranch transparently.
|
||||
*
|
||||
* @param type the variable to set.
|
||||
* @param value the value to set.
|
||||
* @throws IllegalStateException if this object has been made immutable.
|
||||
*/
|
||||
public void setValue(T type, double value) {
|
||||
mutable.check();
|
||||
|
||||
ArrayList<Double> list = values.computeIfAbsent(type, k -> {
|
||||
ArrayList<Double> newList = new ArrayList<>();
|
||||
int n = getLength();
|
||||
for (int i = 0; i < n; i++) {
|
||||
newList.add(Double.NaN);
|
||||
}
|
||||
minValues.put(k, Double.NaN);
|
||||
maxValues.put(k, Double.NaN);
|
||||
return newList;
|
||||
});
|
||||
|
||||
if (list.size() > 0) {
|
||||
list.set(list.size() - 1, value);
|
||||
}
|
||||
|
||||
double min = minValues.get(type);
|
||||
double max = maxValues.get(type);
|
||||
|
||||
if (Double.isNaN(min) || (value < min)) {
|
||||
minValues.put(type, value);
|
||||
}
|
||||
if (Double.isNaN(max) || (value > max)) {
|
||||
maxValues.put(type, value);
|
||||
}
|
||||
modID = new ModID();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an array of values for the specified variable type.
|
||||
*
|
||||
@ -16,7 +135,12 @@ public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
* @return a list of the variable values, or <code>null</code> if
|
||||
* the variable type hasn't been added to this branch.
|
||||
*/
|
||||
List<Double> get(T type);
|
||||
public List<Double> get(T type) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null)
|
||||
return null;
|
||||
return list.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the specified type at the specified index.
|
||||
@ -24,7 +148,16 @@ public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
* @param index the data index of the value
|
||||
* @return the value at the specified index
|
||||
*/
|
||||
Double getByIndex(T type, int index);
|
||||
public Double getByIndex(T type, int index) {
|
||||
if (index < 0 || index >= getLength()) {
|
||||
throw new IllegalArgumentException("Index out of bounds");
|
||||
}
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last value of the specified type in the branch, or NaN if the type is
|
||||
@ -33,7 +166,12 @@ public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
* @param type the parameter type.
|
||||
* @return the last value in this branch, or NaN.
|
||||
*/
|
||||
double getLast(T type);
|
||||
public double getLast(T type) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null || list.isEmpty())
|
||||
return Double.NaN;
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum value of the specified type in the branch, or NaN if the type
|
||||
@ -42,7 +180,12 @@ public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
* @param type the parameter type.
|
||||
* @return the minimum value in this branch, or NaN.
|
||||
*/
|
||||
double getMinimum(T type);
|
||||
public double getMinimum(T type) {
|
||||
Double v = minValues.get(type);
|
||||
if (v == null)
|
||||
return Double.NaN;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum value of the specified type in the branch, or NaN if the type
|
||||
@ -51,21 +194,59 @@ public interface DataBranch<T extends DataType> extends Monitorable {
|
||||
* @param type the parameter type.
|
||||
* @return the maximum value in this branch, or NaN.
|
||||
*/
|
||||
double getMaximum(T type);
|
||||
public double getMaximum(T type) {
|
||||
Double v = maxValues.get(type);
|
||||
if (v == null)
|
||||
return Double.NaN;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of data points in this branch.
|
||||
*/
|
||||
int getLength();
|
||||
public int getLength() {
|
||||
for (ArrayList<Double> doubles : values.values()) {
|
||||
return doubles.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the variable types included in this branch. The types are sorted in their
|
||||
* natural order.
|
||||
*/
|
||||
T[] getTypes();
|
||||
@SuppressWarnings("unchecked")
|
||||
public T[] getTypes() {
|
||||
Set<T> keySet = values.keySet();
|
||||
T[] array = (T[]) Array.newInstance(keySet.iterator().next().getClass(), keySet.size());
|
||||
keySet.toArray(array);
|
||||
Arrays.sort(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the branch name.
|
||||
*/
|
||||
String getName();
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this FlightDataBranch immutable. Any calls to the set methods that would
|
||||
* modify this object will after this call throw an <code>IllegalStateException</code>.
|
||||
*/
|
||||
public void immute() {
|
||||
mutable.immute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this branch is still mutable.
|
||||
*/
|
||||
public boolean isMutable() {
|
||||
return mutable.isMutable();
|
||||
}
|
||||
|
||||
public ModID getModID() {
|
||||
return modID;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
package info.openrocket.core.simulation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -11,8 +8,6 @@ import info.openrocket.core.rocketcomponent.Rocket;
|
||||
import info.openrocket.core.rocketcomponent.RocketComponent;
|
||||
import info.openrocket.core.util.ArrayList;
|
||||
import info.openrocket.core.util.ModID;
|
||||
import info.openrocket.core.util.Monitorable;
|
||||
import info.openrocket.core.util.Mutable;
|
||||
|
||||
/**
|
||||
* A single branch of flight data. The data is ordered based on some variable, typically time.
|
||||
@ -29,31 +24,11 @@ import info.openrocket.core.util.Mutable;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
|
||||
/** The name of this flight data branch. */
|
||||
private final String name;
|
||||
|
||||
private final Map<FlightDataType, ArrayList<Double>> values = new LinkedHashMap<>();
|
||||
|
||||
private final Map<FlightDataType, Double> maxValues = new HashMap<>();
|
||||
private final Map<FlightDataType, Double> minValues = new HashMap<>();
|
||||
|
||||
/**
|
||||
* time for the rocket to reach apogee if the flight had been no recovery deployment
|
||||
*/
|
||||
public class FlightDataBranch extends DataBranch<FlightDataType> {
|
||||
private double timeToOptimumAltitude = Double.NaN;
|
||||
/**
|
||||
* Altitude the rocket would reach if there had been no recovery deployment.
|
||||
*/
|
||||
private double optimumAltitude = Double.NaN;
|
||||
|
||||
private final ArrayList<FlightEvent> events = new ArrayList<>();
|
||||
|
||||
private final Mutable mutable = new Mutable();
|
||||
|
||||
private ModID modID = ModID.INVALID;
|
||||
|
||||
/**
|
||||
* Sole constructor. Defines the name of the FlightDataBranch and at least one variable type.
|
||||
*
|
||||
@ -61,22 +36,7 @@ public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
* @param types data types to include (must include at least one type).
|
||||
*/
|
||||
public FlightDataBranch(String name, FlightDataType... types) {
|
||||
if (types.length == 0) {
|
||||
throw new IllegalArgumentException("Must specify at least one data type.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
||||
for (FlightDataType t : types) {
|
||||
if (values.containsKey(t)) {
|
||||
throw new IllegalArgumentException("Value type " + t + " specified multiple " +
|
||||
"times in constructor.");
|
||||
}
|
||||
|
||||
values.put(t, new ArrayList<>());
|
||||
minValues.put(t, Double.NaN);
|
||||
maxValues.put(t, Double.NaN);
|
||||
}
|
||||
super(name, types);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +49,7 @@ public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
* @param parent the parent branch to copy data from.
|
||||
*/
|
||||
public FlightDataBranch(String name, RocketComponent srcComponent, FlightDataBranch parent) {
|
||||
this.name = name;
|
||||
super(name);
|
||||
|
||||
// Copy all the values from the parent
|
||||
copyValuesFromBranch(parent, srcComponent);
|
||||
@ -99,72 +59,13 @@ public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
* Makes an 'empty' flight data branch which has no data but all built in data types are defined.
|
||||
*/
|
||||
public FlightDataBranch() {
|
||||
name = "Empty branch";
|
||||
super("Empty branch");
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES) {
|
||||
this.setValue(type, Double.NaN);
|
||||
}
|
||||
this.immute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new point into the data branch. The value for all types is set to NaN by default.
|
||||
*
|
||||
* @throws IllegalStateException if this object has been made immutable.
|
||||
*/
|
||||
public void addPoint() {
|
||||
mutable.check();
|
||||
|
||||
for (Map.Entry<FlightDataType, ArrayList<Double>> entry : values.entrySet()) {
|
||||
sanityCheckValues(entry.getKey(), Double.NaN);
|
||||
entry.getValue().add(Double.NaN);
|
||||
}
|
||||
modID = new ModID();
|
||||
}
|
||||
|
||||
private void sanityCheckValues(FlightDataType type, Double value) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
int n = getLength();
|
||||
for (int i = 0; i < n; i++) {
|
||||
list.add(Double.NaN);
|
||||
}
|
||||
values.put(type, list);
|
||||
minValues.put(type, value);
|
||||
maxValues.put(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a specific data type at the latest point. New variable types can be
|
||||
* added to the FlightDataBranch transparently.
|
||||
*
|
||||
* @param type the variable to set.
|
||||
* @param value the value to set.
|
||||
* @throws IllegalStateException if this object has been made immutable.
|
||||
*/
|
||||
public void setValue(FlightDataType type, double value) {
|
||||
mutable.check();
|
||||
|
||||
sanityCheckValues(type, value);
|
||||
ArrayList<Double> list = values.get(type);
|
||||
|
||||
if (list.size() > 0) {
|
||||
list.set(list.size() - 1, value);
|
||||
}
|
||||
|
||||
double min = minValues.get(type);
|
||||
double max = maxValues.get(type);
|
||||
|
||||
if (Double.isNaN(min) || (value < min)) {
|
||||
minValues.put(type, value);
|
||||
}
|
||||
if (Double.isNaN(max) || (value > max)) {
|
||||
maxValues.put(type, value);
|
||||
}
|
||||
modID = new ModID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all the current values in the branch and copies the values from the given branch.
|
||||
@ -228,70 +129,6 @@ public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlightDataType[] getTypes() {
|
||||
FlightDataType[] array = values.keySet().toArray(new FlightDataType[0]);
|
||||
Arrays.sort(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
for (ArrayList<Double> doubles : values.values()) {
|
||||
return doubles.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Double> get(FlightDataType type) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null)
|
||||
return null;
|
||||
return list.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getByIndex(FlightDataType type, int index) {
|
||||
if (index < 0 || index >= getLength()) {
|
||||
throw new IllegalArgumentException("Index out of bounds");
|
||||
}
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLast(FlightDataType type) {
|
||||
ArrayList<Double> list = values.get(type);
|
||||
if (list == null || list.isEmpty())
|
||||
return Double.NaN;
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMinimum(FlightDataType type) {
|
||||
Double v = minValues.get(type);
|
||||
if (v == null)
|
||||
return Double.NaN;
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaximum(FlightDataType type) {
|
||||
Double v = maxValues.get(type);
|
||||
if (v == null)
|
||||
return Double.NaN;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the timeToOptimumAltitude
|
||||
@ -387,28 +224,6 @@ public class FlightDataBranch implements DataBranch<FlightDataType> {
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this FlightDataBranch immutable. Any calls to the set methods that would
|
||||
* modify this object will after this call throw an <code>IllegalStateException</code>.
|
||||
*/
|
||||
public void immute() {
|
||||
mutable.immute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this branch is still mutable.
|
||||
*/
|
||||
public boolean isMutable() {
|
||||
return mutable.isMutable();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ModID getModID() {
|
||||
return modID;
|
||||
}
|
||||
|
||||
public FlightDataBranch clone() {
|
||||
FlightDataType[] types = getTypes();
|
||||
|
Loading…
x
Reference in New Issue
Block a user