Properly fire changes after wind model change

This commit is contained in:
SiboVG 2024-09-21 06:33:06 +01:00
parent b9d2ebd16b
commit 4a3b9efe76
4 changed files with 89 additions and 30 deletions

View File

@ -1,15 +1,22 @@
package info.openrocket.core.models.wind;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import java.util.Collections;
import java.util.Comparator;
import info.openrocket.core.util.ChangeSource;
import info.openrocket.core.util.Coordinate;
import info.openrocket.core.util.ModID;
import info.openrocket.core.util.StateChangeListener;
public class MultiLevelPinkNoiseWindModel implements WindModel {
private List<LevelWindModel> levels;
private final List<StateChangeListener> listeners = new ArrayList<>();
public MultiLevelPinkNoiseWindModel() {
this.levels = new ArrayList<>();
}
@ -21,23 +28,28 @@ public class MultiLevelPinkNoiseWindModel implements WindModel {
pinkNoiseModel.setDirection(direction);
LevelWindModel newLevel = new LevelWindModel(altitude, pinkNoiseModel);
newLevel.addChangeListener(e -> fireChangeEvent());
int index = Collections.binarySearch(levels, newLevel, Comparator.comparingDouble(l -> l.altitude));
if (index >= 0) {
throw new IllegalArgumentException("Wind level already exists for altitude: " + altitude);
}
levels.add(-index - 1, newLevel);
fireChangeEvent();
}
public void removeWindLevel(double altitude) {
levels.removeIf(level -> level.altitude == altitude);
fireChangeEvent();
}
public void removeWindLevelIdx(int index) {
levels.remove(index);
fireChangeEvent();
}
public void clearLevels() {
levels.clear();
fireChangeEvent();
}
public List<LevelWindModel> getLevels() {
@ -127,10 +139,12 @@ public class MultiLevelPinkNoiseWindModel implements WindModel {
return levels.hashCode();
}
public static class LevelWindModel implements Cloneable {
public static class LevelWindModel implements Cloneable, ChangeSource {
protected double altitude;
protected PinkNoiseWindModel model;
private final List<StateChangeListener> listeners = new ArrayList<>();
LevelWindModel(double altitude, PinkNoiseWindModel model) {
this.altitude = altitude;
this.model = model;
@ -142,6 +156,7 @@ public class MultiLevelPinkNoiseWindModel implements WindModel {
public void setAltitude(double altitude) {
this.altitude = altitude;
fireChangeEvent();
}
public double getSpeed() {
@ -194,5 +209,49 @@ public class MultiLevelPinkNoiseWindModel implements WindModel {
LevelWindModel that = (LevelWindModel) obj;
return Double.compare(that.altitude, altitude) == 0 && model.equals(that.model);
}
@Override
public void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
model.addChangeListener(listener);
}
@Override
public void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
model.removeChangeListener(listener);
}
public void fireChangeEvent() {
EventObject event = new EventObject(this);
// Copy the list before iterating to prevent concurrent modification exceptions.
EventListener[] list = listeners.toArray(new EventListener[0]);
for (EventListener l : list) {
if (l instanceof StateChangeListener) {
((StateChangeListener) l).stateChanged(event);
}
}
}
}
@Override
public void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
}
public void fireChangeEvent() {
EventObject event = new EventObject(this);
// Copy the list before iterating to prevent concurrent modification exceptions.
EventListener[] list = listeners.toArray(new EventListener[0]);
for (EventListener l : list) {
if (l instanceof StateChangeListener) {
((StateChangeListener) l).stateChanged(event);
}
}
}
}

View File

@ -1,11 +1,16 @@
package info.openrocket.core.models.wind;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import java.util.Random;
import info.openrocket.core.util.Coordinate;
import info.openrocket.core.util.MathUtil;
import info.openrocket.core.util.ModID;
import info.openrocket.core.util.PinkNoise;
import info.openrocket.core.util.StateChangeListener;
/**
* A wind simulator that generates wind speed as pink noise from a specified
@ -46,6 +51,8 @@ public class PinkNoiseWindModel implements WindModel {
private double time1;
private double value1, value2;
private final List<StateChangeListener> listeners = new ArrayList<>();
/**
* Construct a new wind simulation with a specific seed value.
*
@ -222,4 +229,24 @@ public class PinkNoiseWindModel implements WindModel {
return result;
}
@Override
public void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
}
public void fireChangeEvent() {
EventObject event = new EventObject(this);
// Copy the list before iterating to prevent concurrent modification exceptions.
EventListener[] list = listeners.toArray(new EventListener[0]);
for (EventListener l : list) {
if (l instanceof StateChangeListener) {
((StateChangeListener) l).stateChanged(event);
}
}
}
}

View File

@ -3,38 +3,9 @@ package info.openrocket.core.models.wind;
import info.openrocket.core.util.ChangeSource;
import info.openrocket.core.util.Coordinate;
import info.openrocket.core.util.Monitorable;
import info.openrocket.core.util.StateChangeListener;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
public interface WindModel extends Monitorable, Cloneable, ChangeSource {
List<StateChangeListener> listeners = new ArrayList<>();
Coordinate getWindVelocity(double time, double altitude);
WindModel clone();
@Override
default void addChangeListener(StateChangeListener listener) {
listeners.add(listener);
}
@Override
default void removeChangeListener(StateChangeListener listener) {
listeners.remove(listener);
}
default void fireChangeEvent() {
EventObject event = new EventObject(this);
// Copy the list before iterating to prevent concurrent modification exceptions.
EventListener[] list = listeners.toArray(new EventListener[0]);
for (EventListener l : list) {
if (l instanceof StateChangeListener) {
((StateChangeListener) l).stateChanged(event);
}
}
}
}

View File

@ -86,7 +86,9 @@ public class SimulationOptions implements ChangeSource, Cloneable, SimulationOpt
public SimulationOptions() {
averageWindModel = new PinkNoiseWindModel(randomSeed);
averageWindModel.addChangeListener(e -> fireChangeEvent());
multiLevelPinkNoiseWindModel = new MultiLevelPinkNoiseWindModel();
multiLevelPinkNoiseWindModel.addChangeListener(e -> fireChangeEvent());
}
public double getLaunchRodLength() {