diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index b01aeb23e..ec1546236 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -136,6 +136,21 @@ public class FlightConfiguration implements FlightConfigurableParameter(this.preloadStageActiveness); clone.cachedBoundsAerodynamic = this.cachedBoundsAerodynamic.clone(); @@ -851,7 +867,7 @@ public class FlightConfiguration implements FlightConfigurableParameter(this.preloadStageActiveness); copy.cachedBoundsAerodynamic = this.cachedBoundsAerodynamic.clone(); copy.cachedBounds = this.cachedBounds.clone(); diff --git a/core/src/net/sf/openrocket/util/BoundingBox.java b/core/src/net/sf/openrocket/util/BoundingBox.java index c262b04b9..b3d997273 100644 --- a/core/src/net/sf/openrocket/util/BoundingBox.java +++ b/core/src/net/sf/openrocket/util/BoundingBox.java @@ -165,4 +165,11 @@ public class BoundingBox { min.x, min.y, min.z, max.x, max.y, max.z ); } + + @Override + public boolean equals(Object other) { + return other instanceof BoundingBox && + ((BoundingBox) other).min.equals(this.min) && + ((BoundingBox) other).max.equals(this.max); + } } diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index 51db91e7d..b671af3b3 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -3,12 +3,19 @@ package net.sf.openrocket.rocketcomponent; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import net.sf.openrocket.util.BoundingBox; import org.junit.Test; import net.sf.openrocket.util.Coordinate; @@ -572,6 +579,134 @@ public class FlightConfigurationTest extends BaseTestCase { assertThat(components.get(1).getName(), equalTo("Core Stage Body")); } + + @Test + public void testCopy() throws NoSuchFieldException, IllegalAccessException { + Rocket rocket = TestRockets.makeFalcon9Heavy(); + FlightConfiguration original = rocket.getSelectedConfiguration(); + original.setOnlyStage(0); + + // vvvv Test Target vvvv + FlightConfiguration copy = original.copy(null); + // ^^^^ Test Target ^^^^ + + assertNotEquals(original, copy); + assertNotSame(original, copy); + assertEquals(original.getName(), copy.getName()); + assertNotEquals(original.getFlightConfigurationID(), copy.getFlightConfigurationID()); + + // Test preloadStageActiveness copy + Field preloadStageActivenessField = FlightConfiguration.class.getDeclaredField("preloadStageActiveness"); + preloadStageActivenessField.setAccessible(true); + Map preloadStageActivenessOriginal = (Map) preloadStageActivenessField.get(original); + Map preloadStageActivenessCopy = (Map) preloadStageActivenessField.get(copy); + assertEquals(preloadStageActivenessOriginal, preloadStageActivenessCopy); + if (preloadStageActivenessOriginal == null) { + assertNull(preloadStageActivenessCopy); + } else { + assertNotSame(preloadStageActivenessOriginal, preloadStageActivenessCopy); + } + + // Test cachedBoundsAerodynamic copy + Field cachedBoundsAerodynamicField = FlightConfiguration.class.getDeclaredField("cachedBoundsAerodynamic"); + cachedBoundsAerodynamicField.setAccessible(true); + BoundingBox cachedBoundsAerodynamicOriginal = (BoundingBox) cachedBoundsAerodynamicField.get(original); + BoundingBox cachedBoundsAerodynamicCopy = (BoundingBox) cachedBoundsAerodynamicField.get(copy); + assertEquals(cachedBoundsAerodynamicOriginal, cachedBoundsAerodynamicCopy); + assertNotSame(cachedBoundsAerodynamicOriginal, cachedBoundsAerodynamicCopy); + + // Test cachedBounds copy + Field cachedBoundsField = FlightConfiguration.class.getDeclaredField("cachedBounds"); + cachedBoundsField.setAccessible(true); + BoundingBox cachedBoundsOriginal = (BoundingBox) cachedBoundsField.get(original); + BoundingBox cachedBoundsCopy = (BoundingBox) cachedBoundsField.get(copy); + assertEquals(cachedBoundsOriginal, cachedBoundsCopy); + assertNotSame(cachedBoundsOriginal, cachedBoundsCopy); + + // Test modID copy + assertEquals(original.getModID(), copy.getModID()); + + // Test boundModID + Field boundsModIDField = FlightConfiguration.class.getDeclaredField("boundsModID"); + boundsModIDField.setAccessible(true); + int boundsModIDCopy = (int) boundsModIDField.get(copy); + assertEquals(-1, boundsModIDCopy); + + // Test refLengthModID + Field refLengthModIDField = FlightConfiguration.class.getDeclaredField("refLengthModID"); + refLengthModIDField.setAccessible(true); + int refLengthModIDCopy = (int) refLengthModIDField.get(copy); + assertEquals(-1, refLengthModIDCopy); + + // Test stageActiveness copy + for (int i = 0; i < original.getStageCount(); i++) { + assertEquals(original.isStageActive(i), copy.isStageActive(i)); + } + } + + @Test + public void testClone() throws NoSuchFieldException, IllegalAccessException { + Rocket rocket = TestRockets.makeFalcon9Heavy(); + FlightConfiguration original = rocket.getSelectedConfiguration(); + original.setOnlyStage(0); + + // vvvv Test Target vvvv + FlightConfiguration clone = original.clone(); + // ^^^^ Test Target ^^^^ + + assertEquals(original, clone); + assertNotSame(original, clone); + assertEquals(original.getName(), clone.getName()); + assertEquals(original.getFlightConfigurationID(), clone.getFlightConfigurationID()); + + // Test preloadStageActiveness clone + Field preloadStageActivenessField = FlightConfiguration.class.getDeclaredField("preloadStageActiveness"); + preloadStageActivenessField.setAccessible(true); + Map preloadStageActivenessOriginal = (Map) preloadStageActivenessField.get(original); + Map preloadStageActivenessClone = (Map) preloadStageActivenessField.get(clone); + assertEquals(preloadStageActivenessOriginal, preloadStageActivenessClone); + if (preloadStageActivenessOriginal == null) { + assertNull(preloadStageActivenessClone); + } else { + assertNotSame(preloadStageActivenessOriginal, preloadStageActivenessClone); + } + + // Test cachedBoundsAerodynamic clone + Field cachedBoundsAerodynamicField = FlightConfiguration.class.getDeclaredField("cachedBoundsAerodynamic"); + cachedBoundsAerodynamicField.setAccessible(true); + BoundingBox cachedBoundsAerodynamicOriginal = (BoundingBox) cachedBoundsAerodynamicField.get(original); + BoundingBox cachedBoundsAerodynamicClone = (BoundingBox) cachedBoundsAerodynamicField.get(clone); + assertEquals(cachedBoundsAerodynamicOriginal, cachedBoundsAerodynamicClone); + assertNotSame(cachedBoundsAerodynamicOriginal, cachedBoundsAerodynamicClone); + + // Test cachedBounds clone + Field cachedBoundsField = FlightConfiguration.class.getDeclaredField("cachedBounds"); + cachedBoundsField.setAccessible(true); + BoundingBox cachedBoundsOriginal = (BoundingBox) cachedBoundsField.get(original); + BoundingBox cachedBoundsClone = (BoundingBox) cachedBoundsField.get(clone); + assertEquals(cachedBoundsOriginal, cachedBoundsClone); + assertNotSame(cachedBoundsOriginal, cachedBoundsClone); + + // Test modID clone + assertEquals(original.getModID(), clone.getModID()); + + // Test boundModID + Field boundsModIDField = FlightConfiguration.class.getDeclaredField("boundsModID"); + boundsModIDField.setAccessible(true); + int boundsModIDClone = (int) boundsModIDField.get(clone); + assertEquals(-1, boundsModIDClone); + + // Test refLengthModID + Field refLengthModIDField = FlightConfiguration.class.getDeclaredField("refLengthModID"); + refLengthModIDField.setAccessible(true); + int refLengthModIDClone = (int) refLengthModIDField.get(clone); + assertEquals(-1, refLengthModIDClone); + + // Test stageActiveness copy + for (int i = 0; i < original.getStageCount(); i++) { + assertEquals(original.isStageActive(i), clone.isStageActive(i)); + } + } } diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index 0fe7cf400..1c0925ed6 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -496,17 +496,14 @@ public class RocketFigure extends AbstractScaleFigure { protected void updateSubjectDimensions() { // calculate bounds, and store in class variables - final FlightConfiguration config = rocket.getSelectedConfiguration().clone(); - // Explicitly zoom & draw at a scale to fit the entire rocket, but only show the selected stages. - config.setAllStages(); - final BoundingBox newBounds = config.getBoundingBox(); + final BoundingBox bounds = rocket.getSelectedConfiguration().getBoundingBox(); - final double maxR = Math.max( Math.hypot(newBounds.min.y, newBounds.min.z), - Math.hypot(newBounds.max.y, newBounds.max.z)); + final double maxR = Math.max( Math.hypot(bounds.min.y, bounds.min.z), + Math.hypot(bounds.max.y, bounds.max.z)); switch (currentViewType) { case SideView: - subjectBounds_m = new Rectangle2D.Double(newBounds.min.x, -maxR, newBounds.span().x, 2 * maxR); + subjectBounds_m = new Rectangle2D.Double(bounds.min.x, -maxR, bounds.span().x, 2 * maxR); break; case BackView: subjectBounds_m = new Rectangle2D.Double(-maxR, -maxR, 2 * maxR, 2 * maxR);