Merge pull request #767 from teyrana/fix/756/bound-box-error
Fixes #756 -- Launch Lug & Stage Dimensions
This commit is contained in:
commit
86b0b0fcbd
@ -543,9 +543,13 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
* @return the rocket's bounding box (under the selected configuration)
|
||||
*/
|
||||
public BoundingBox getBoundingBox() {
|
||||
if (rocket.getModID() != boundsModID) {
|
||||
calculateBounds();
|
||||
}
|
||||
// if (rocket.getModID() != boundsModID) {
|
||||
calculateBounds();
|
||||
// }
|
||||
|
||||
if(cachedBounds.isEmpty())
|
||||
cachedBounds = new BoundingBox(Coordinate.ZERO,Coordinate.X_UNIT);
|
||||
|
||||
return cachedBounds;
|
||||
}
|
||||
|
||||
@ -558,11 +562,12 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
|
||||
InstanceMap map = getActiveInstances();
|
||||
for (Map.Entry<RocketComponent, java.util.ArrayList<InstanceContext>> entry : map.entrySet()) {
|
||||
RocketComponent component = entry.getKey();
|
||||
BoundingBox componentBounds = new BoundingBox();
|
||||
List<InstanceContext> contexts = entry.getValue();
|
||||
|
||||
final RocketComponent component = entry.getKey();
|
||||
final BoundingBox componentBounds = new BoundingBox();
|
||||
final List<InstanceContext> contexts = entry.getValue();
|
||||
|
||||
if( ! component.isAerodynamic()){
|
||||
// System.err.println(" << non-aerodynamic");
|
||||
// all non-aerodynamic components should be surrounded by aerodynamic ones
|
||||
continue;
|
||||
}
|
||||
@ -571,6 +576,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
if (component instanceof BoxBounded) {
|
||||
final BoundingBox instanceBounds = ((BoxBounded) component).getInstanceBoundingBox();
|
||||
if(instanceBounds.isEmpty()) {
|
||||
// probably redundant
|
||||
// this component is probably non-physical (like an assembly) or has invalid bounds. Skip.
|
||||
continue;
|
||||
}
|
||||
@ -627,7 +633,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
if (rocketBounds.isEmpty()) {
|
||||
cachedLength = 0;
|
||||
}
|
||||
cachedBounds.update( rocketBounds );
|
||||
cachedBounds = rocketBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -25,7 +26,7 @@ import net.sf.openrocket.util.MathUtil;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class InnerTube extends ThicknessRingComponent implements AxialPositionable, Clusterable, RadialParent, MotorMount {
|
||||
public class InnerTube extends ThicknessRingComponent implements AxialPositionable, BoxBounded, Clusterable, RadialParent, MotorMount {
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final Logger log = LoggerFactory.getLogger(InnerTube.class);
|
||||
|
||||
@ -135,6 +136,18 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
|
||||
}
|
||||
}
|
||||
|
||||
public BoundingBox getInstanceBoundingBox(){
|
||||
BoundingBox instanceBounds = new BoundingBox();
|
||||
|
||||
instanceBounds.update(new Coordinate(this.getLength(), 0,0));
|
||||
|
||||
final double r = getOuterRadius();
|
||||
instanceBounds.update(new Coordinate(0,r,r));
|
||||
instanceBounds.update(new Coordinate(0,-r,-r));
|
||||
|
||||
return instanceBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstanceCount() {
|
||||
return cluster.getClusterCount();
|
||||
|
@ -8,12 +8,13 @@ import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.preset.ComponentPreset.Type;
|
||||
import net.sf.openrocket.rocketcomponent.position.*;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
|
||||
|
||||
public class LaunchLug extends ExternalComponent implements AnglePositionable, Coaxial, LineInstanceable {
|
||||
public class LaunchLug extends ExternalComponent implements AnglePositionable, BoxBounded, Coaxial, LineInstanceable {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
@ -252,7 +253,20 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, C
|
||||
public int getInstanceCount(){
|
||||
return this.instanceCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BoundingBox getInstanceBoundingBox() {
|
||||
BoundingBox instanceBounds = new BoundingBox();
|
||||
|
||||
instanceBounds.update(new Coordinate(this.getLength(), 0,0));
|
||||
|
||||
final double r = getOuterRadius();
|
||||
instanceBounds.update(new Coordinate(0,r,r));
|
||||
instanceBounds.update(new Coordinate(0,-r,-r));
|
||||
|
||||
return instanceBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPatternName(){
|
||||
return (this.getInstanceCount() + "-Line");
|
||||
@ -281,5 +295,4 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, C
|
||||
public void setAngleMethod(AngleMethod newMethod) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import net.sf.openrocket.rocketcomponent.position.AnglePositionable;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialPositionable;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
@ -22,7 +23,7 @@ import net.sf.openrocket.util.MathUtil;
|
||||
* @author widget (Daniel Williams)
|
||||
*
|
||||
*/
|
||||
public class RailButton extends ExternalComponent implements AnglePositionable, AxialPositionable, LineInstanceable {
|
||||
public class RailButton extends ExternalComponent implements AnglePositionable, AxialPositionable, BoxBounded, LineInstanceable {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
@ -210,6 +211,18 @@ public class RailButton extends ExternalComponent implements AnglePositionable,
|
||||
fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
|
||||
}
|
||||
|
||||
public BoundingBox getInstanceBoundingBox(){
|
||||
BoundingBox instanceBounds = new BoundingBox();
|
||||
|
||||
instanceBounds.update(new Coordinate(0, this.getTotalHeight(), 0));
|
||||
|
||||
final double r = this.getOuterDiameter();
|
||||
instanceBounds.update(new Coordinate(r,r,0));
|
||||
instanceBounds.update(new Coordinate(-r,-r,0));
|
||||
|
||||
return instanceBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
Coordinate[] toReturn = new Coordinate[this.getInstanceCount()];
|
||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
@ -16,7 +17,7 @@ import net.sf.openrocket.util.MathUtil;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public abstract class RingComponent extends StructuralComponent implements Coaxial {
|
||||
public abstract class RingComponent extends StructuralComponent implements BoxBounded, Coaxial {
|
||||
|
||||
protected boolean outerRadiusAutomatic = false;
|
||||
protected boolean innerRadiusAutomatic = false;
|
||||
@ -111,9 +112,18 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
|
||||
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
|
||||
}
|
||||
|
||||
public BoundingBox getInstanceBoundingBox(){
|
||||
BoundingBox instanceBounds = new BoundingBox();
|
||||
|
||||
instanceBounds.update(new Coordinate(this.getLength(), 0,0));
|
||||
|
||||
final double r = getOuterRadius();
|
||||
instanceBounds.update(new Coordinate(0,r,r));
|
||||
instanceBounds.update(new Coordinate(0,-r,-r));
|
||||
|
||||
return instanceBounds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the radial position of the component. The position is the distance
|
||||
* of the center of the component from the center of the parent component.
|
||||
|
@ -556,12 +556,13 @@ public class TestRockets {
|
||||
//
|
||||
// This function is used for unit, integration tests, DO NOT CHANGE WITHOUT UPDATING TESTS
|
||||
public static final Rocket makeBeta(){
|
||||
Rocket rocket = makeEstesAlphaIII();
|
||||
final Rocket rocket = makeEstesAlphaIII();
|
||||
rocket.setName("Kit-bash Beta");
|
||||
|
||||
AxialStage sustainerStage = (AxialStage)rocket.getChild(0);
|
||||
final AxialStage sustainerStage = (AxialStage)rocket.getChild(0);
|
||||
sustainerStage.setName( "Sustainer Stage");
|
||||
BodyTube sustainerBody = (BodyTube)sustainerStage.getChild(1);
|
||||
final BodyTube sustainerBody = (BodyTube)sustainerStage.getChild(1);
|
||||
sustainerBody.setName("Sustainer Body Tube");
|
||||
final double sustainerRadius = sustainerBody.getAftRadius();
|
||||
final double sustainerThickness = sustainerBody.getThickness();
|
||||
|
||||
@ -586,7 +587,7 @@ public class TestRockets {
|
||||
double finRootChord = .05;
|
||||
double finTipChord = .03;
|
||||
double finSweep = 0.02;
|
||||
double finHeight = 0.03;
|
||||
double finHeight = 0.05;
|
||||
FinSet finset = new TrapezoidFinSet(finCount, finRootChord, finTipChord, finSweep, finHeight);
|
||||
finset.setName("Booster Fins");
|
||||
finset.setThickness( 0.0032);
|
||||
@ -610,6 +611,15 @@ public class TestRockets {
|
||||
boosterMMT.setMotorConfig( motorConfig, TEST_FCID_1);
|
||||
}
|
||||
boosterBody.addChild(boosterMMT);
|
||||
|
||||
LaunchLug lug = new LaunchLug();
|
||||
lug.setName("Launch Lugs");
|
||||
lug.setAxialMethod(AxialMethod.TOP);
|
||||
lug.setAxialOffset(0.0);
|
||||
lug.setLength(0.050);
|
||||
lug.setOuterRadius(0.0022);
|
||||
lug.setInnerRadius(0.0020);
|
||||
boosterBody.addChild(lug);
|
||||
}
|
||||
|
||||
// Tail Cone
|
||||
|
111
core/test/net/sf/openrocket/rocketcomponent/BoundingBoxTest.java
Normal file
111
core/test/net/sf/openrocket/rocketcomponent/BoundingBoxTest.java
Normal file
@ -0,0 +1,111 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.position.AngleMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.TestRockets;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class BoundingBoxTest extends BaseTestCase {
|
||||
final double EPSILON = MathUtil.EPSILON;
|
||||
|
||||
@Test
|
||||
public void testEstesAlphaIIIBoundingBox(){
|
||||
final Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||
|
||||
final FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||
final BoundingBox bounds = config.getBoundingBox();
|
||||
|
||||
assertEquals("bounds max x", 0.000000000, bounds.min.x, EPSILON);
|
||||
assertEquals("bounds max x", 0.270000000, bounds.max.x, EPSILON);
|
||||
assertEquals("bounds min y", -0.032385640, bounds.min.y, EPSILON);
|
||||
assertEquals("bounds max y", 0.062000000, bounds.max.y, EPSILON);
|
||||
assertEquals("bounds min z", -0.054493575, bounds.min.z, EPSILON);
|
||||
assertEquals("bounds max z", 0.052893575, bounds.max.z, EPSILON);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBetaBoundingBox() {
|
||||
Rocket rocket = TestRockets.makeBeta();
|
||||
|
||||
final FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||
|
||||
{ // case A: All Stages
|
||||
config.setAllStages();
|
||||
|
||||
// DEBUG
|
||||
System.err.println("==== Case A: All Stages ====");
|
||||
|
||||
final BoundingBox bounds = config.getBoundingBox();
|
||||
|
||||
assertEquals("bounds min x", 0.000000000, bounds.min.x, EPSILON);
|
||||
assertEquals("bounds max x", 0.335000000, bounds.max.x, EPSILON);
|
||||
assertEquals("bounds min y", -0.032385640, bounds.min.y, EPSILON);
|
||||
assertEquals("bounds max y", 0.062000000, bounds.max.y, EPSILON);
|
||||
assertEquals("bounds min z", -0.054493575, bounds.min.z, EPSILON);
|
||||
assertEquals("bounds max z", 0.052893575, bounds.max.z, EPSILON);
|
||||
}
|
||||
{ // case B: Sustainer Only
|
||||
config.setOnlyStage(0);
|
||||
|
||||
// DEBUG
|
||||
System.err.println("==== Case B: Sustainer Only ====");
|
||||
|
||||
final BoundingBox bounds = config.getBoundingBox();
|
||||
|
||||
assertEquals("bounds min x", 0.000000000, bounds.min.x, EPSILON);
|
||||
assertEquals("bounds max x", 0.270000000, bounds.max.x, EPSILON);
|
||||
assertEquals("bounds min y", -0.032385640, bounds.min.y, EPSILON);
|
||||
assertEquals("bounds max y", 0.062000000, bounds.max.y, EPSILON);
|
||||
assertEquals("bounds min z", -0.054493575, bounds.min.z, EPSILON);
|
||||
assertEquals("bounds max z", 0.052893575, bounds.max.z, EPSILON);
|
||||
}
|
||||
{ // case C: Booster Only
|
||||
config.setOnlyStage(1);
|
||||
|
||||
// DEBUG
|
||||
System.err.println("==== Case C: Booster Only ====");
|
||||
System.err.println(rocket.toDebugTree());
|
||||
|
||||
final BoundingBox bounds = config.getBoundingBox();
|
||||
|
||||
assertEquals("bounds min x", 0.270000000, bounds.min.x, EPSILON);
|
||||
assertEquals("bounds max x", 0.335000000, bounds.max.x, EPSILON);
|
||||
assertEquals("bounds min y", -0.032385640, bounds.min.y, EPSILON);
|
||||
assertEquals("bounds max y", 0.062000000, bounds.max.y, EPSILON);
|
||||
assertEquals("bounds min z", -0.054493575, bounds.min.z, EPSILON);
|
||||
assertEquals("bounds max z", 0.052893575, bounds.max.z, EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFalcon9HBoundingBox() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
|
||||
// DEBUG
|
||||
System.err.println(rocket.toDebugTree());
|
||||
|
||||
final BoundingBox bounds = rocket.getBoundingBox();
|
||||
assertEquals( 0.0, bounds.min.x, EPSILON);
|
||||
assertEquals( 1.364, bounds.max.x, EPSILON);
|
||||
|
||||
assertEquals( -0.215500, bounds.min.y, EPSILON);
|
||||
assertEquals( 0.215500, bounds.max.y, EPSILON);
|
||||
|
||||
assertEquals( -0.12069451, bounds.min.z, EPSILON);
|
||||
assertEquals( 0.12069451, bounds.max.z, EPSILON);
|
||||
}
|
||||
|
||||
}
|
@ -423,10 +423,12 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
@Override
|
||||
protected void updateSubjectDimensions() {
|
||||
// calculate bounds, and store in class variables
|
||||
BoundingBox newBounds = rocket.getSelectedConfiguration().getBoundingBox();
|
||||
if(newBounds.isEmpty())
|
||||
newBounds = new BoundingBox(Coordinate.ZERO,Coordinate.X_UNIT);
|
||||
|
||||
|
||||
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 double maxR = Math.max( Math.hypot(newBounds.min.y, newBounds.min.z),
|
||||
Math.hypot(newBounds.max.y, newBounds.max.z));
|
||||
|
||||
@ -451,19 +453,19 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
@Override
|
||||
protected void updateCanvasOrigin() {
|
||||
final int subjectWidth = (int)(subjectBounds_m.getWidth()*scale);
|
||||
final int subjectHeight = (int)(subjectBounds_m.getHeight()*scale);
|
||||
final int mid_x = (Math.max(getWidth(), subjectWidth) / 2);
|
||||
|
||||
if (currentViewType == RocketPanel.VIEW_TYPE.BackView){
|
||||
final int newOriginX = mid_x;
|
||||
final int newOriginY = borderThickness_px.height + getHeight() / 2;
|
||||
|
||||
originLocation_px = new Point(newOriginX, newOriginY);
|
||||
}else if (currentViewType == RocketPanel.VIEW_TYPE.SideView){
|
||||
final int newOriginX = mid_x - (int) ((subjectBounds_m.getWidth() * scale) / 2);
|
||||
final int newOriginY = Math.max(getHeight(), subjectHeight + 2*borderThickness_px.height )/ 2;
|
||||
originLocation_px = new Point(newOriginX, newOriginY);
|
||||
}
|
||||
final int subjectHeight = (int)(subjectBounds_m.getHeight()*scale);
|
||||
final int mid_x = (Math.max(getWidth(), subjectWidth) / 2);
|
||||
|
||||
if (currentViewType == RocketPanel.VIEW_TYPE.BackView){
|
||||
final int newOriginX = mid_x;
|
||||
final int newOriginY = borderThickness_px.height + getHeight() / 2;
|
||||
|
||||
originLocation_px = new Point(newOriginX, newOriginY);
|
||||
}else if (currentViewType == RocketPanel.VIEW_TYPE.SideView){
|
||||
final int newOriginX = mid_x - (subjectWidth / 2);
|
||||
final int newOriginY = Math.max(getHeight(), subjectHeight + 2*borderThickness_px.height )/ 2;
|
||||
originLocation_px = new Point(newOriginX, newOriginY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user