diff --git a/core/src/main/java/info/openrocket/core/models/wind/MultiLevelPinkNoiseWindModel.java b/core/src/main/java/info/openrocket/core/models/wind/MultiLevelPinkNoiseWindModel.java index 58954ad36..62365ef64 100644 --- a/core/src/main/java/info/openrocket/core/models/wind/MultiLevelPinkNoiseWindModel.java +++ b/core/src/main/java/info/openrocket/core/models/wind/MultiLevelPinkNoiseWindModel.java @@ -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 levels; + private final List 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 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 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); + } + } } } \ No newline at end of file diff --git a/core/src/main/java/info/openrocket/core/models/wind/PinkNoiseWindModel.java b/core/src/main/java/info/openrocket/core/models/wind/PinkNoiseWindModel.java index a2415cb07..4ebfcd721 100644 --- a/core/src/main/java/info/openrocket/core/models/wind/PinkNoiseWindModel.java +++ b/core/src/main/java/info/openrocket/core/models/wind/PinkNoiseWindModel.java @@ -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 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); + } + } + } } diff --git a/core/src/main/java/info/openrocket/core/models/wind/WindModel.java b/core/src/main/java/info/openrocket/core/models/wind/WindModel.java index 2e4150ef8..379219d19 100644 --- a/core/src/main/java/info/openrocket/core/models/wind/WindModel.java +++ b/core/src/main/java/info/openrocket/core/models/wind/WindModel.java @@ -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 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); - } - } - } } diff --git a/core/src/main/java/info/openrocket/core/simulation/SimulationOptions.java b/core/src/main/java/info/openrocket/core/simulation/SimulationOptions.java index 997a5adf9..ad828f8ee 100644 --- a/core/src/main/java/info/openrocket/core/simulation/SimulationOptions.java +++ b/core/src/main/java/info/openrocket/core/simulation/SimulationOptions.java @@ -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() {