diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index c4ac8c874..4667476c8 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -2,6 +2,7 @@ package net.sf.openrocket.aerodynamics; import static net.sf.openrocket.util.MathUtil.pow2; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -22,7 +23,6 @@ import net.sf.openrocket.rocketcomponent.InstanceMap; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.SymmetricComponent; -import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; @@ -96,6 +96,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // Calculate non-axial force data AerodynamicForces total = calculateNonAxialForces(configuration, conditions, map, warnings); + // Calculate friction data total.setFrictionCD(calculateFrictionDrag(configuration, conditions, map, warnings)); total.setPressureCD(calculatePressureDrag(configuration, conditions, map, warnings)); @@ -173,6 +174,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { if (calcMap == null) buildCalcMap(configuration); + if( ! isContinuous( configuration.getRocket() ) ){ warnings.add( Warning.DIAMETER_DISCONTINUITY); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java index 0e80fbf9b..a5607615e 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java +++ b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java @@ -55,6 +55,24 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC separations.reset(fcid); } + /** + * {@inheritDoc} + * not strictly accurate, but this should provide an acceptable estimate for total vehicle size + */ + @Override + public Collection getComponentBounds() { + Collection bounds = new ArrayList(8); + Coordinate[] instanceLocations = this.getInstanceLocations(); + double x_min = instanceLocations[0].x; + double x_max = x_min + this.length; + double r_max = 0; + + addBound(bounds, x_min, r_max); + addBound(bounds, x_max, r_max); + + return bounds; + } + /** * Check whether the given type can be added to this component. A Stage allows * only BodyComponents to be added. diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index b2a9f134b..be4d06a9a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -10,7 +10,6 @@ import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.motor.MotorConfigurationSet; import net.sf.openrocket.preset.ComponentPreset; 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; @@ -297,7 +296,52 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial private static double getFilledVolume(double r, double l) { return Math.PI * r * r * l; } + + + /** + * Adds bounding coordinates to the given set. The body tube will fit within the + * convex hull of the points. + * + * Currently the points are simply a rectangular box around the body tube. + */ + @Override + public Collection getComponentBounds() { + Collection bounds = new ArrayList(8); + double x_min_shape = 0; + double x_max_shape = this.length; + double r_max_shape = getOuterRadius(); + Coordinate[] locs = this.getLocations(); + // not strictly accurate, but this should provide an acceptable estimate for total vehicle size + double x_min_inst = Double.MAX_VALUE; + double x_max_inst = Double.MIN_VALUE; + double r_max_inst = 0.0; + + // refactor: get component inherent bounds + for (Coordinate cur : locs) { + double x_cur = cur.x; + double r_cur = MathUtil.hypot(cur.y, cur.z); + if (x_min_inst > x_cur) { + x_min_inst = x_cur; + } + if (x_max_inst < x_cur) { + x_max_inst = x_cur; + } + if (r_cur > r_max_inst) { + r_max_inst = r_cur; + } + } + + // combine the position bounds with the inherent shape bounds + double x_min = x_min_shape + x_min_inst; + double x_max = x_max_shape + x_max_inst; + double r_max = r_max_shape + r_max_inst; + + addBoundingBox(bounds, x_min, x_max, r_max); + return bounds; + } + + /** * Check whether the given type can be added to this component. BodyTubes allow any * InternalComponents or ExternalComponents, excluding BodyComponents, to be added. diff --git a/core/src/net/sf/openrocket/rocketcomponent/ComponentAssembly.java b/core/src/net/sf/openrocket/rocketcomponent/ComponentAssembly.java index 3aec4aea7..24468aeb3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/ComponentAssembly.java +++ b/core/src/net/sf/openrocket/rocketcomponent/ComponentAssembly.java @@ -9,7 +9,6 @@ import org.slf4j.LoggerFactory; import net.sf.openrocket.rocketcomponent.position.AxialMethod; import net.sf.openrocket.rocketcomponent.position.AxialPositionable; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Coordinate; @@ -47,6 +46,14 @@ public abstract class ComponentAssembly extends RocketComponent implements Axia public double getAxialOffset() { return getAxialOffset( this.axialMethod ); } + + /** + * Null method (ComponentAssembly has no bounds of itself). + */ + @Override + public Collection getComponentBounds() { + return Collections.emptyList(); + } /** * Null method (ComponentAssembly has no mass of itself). @@ -100,17 +107,6 @@ public abstract class ComponentAssembly extends RocketComponent implements Axia } return outerRadius; } - - /** - * We'll find the bounding box of a component by iterating an - * InstanceMap, not by performing a treewalk of the component. - * So, anything subclassed from a ComponentAssembly will just - * return an empty bounding box - */ - @Override - public BoundingBox getBoundingBox() { - return new BoundingBox(); - } /** * Components have no aerodynamic effect, so return false. diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index e63bf15d5..52ba40843 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -709,16 +709,53 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab BoundingBox singleFinBounds= new BoundingBox().update(getFinPoints()); final double finLength = singleFinBounds.max.x; final double finHeight = singleFinBounds.max.y; - - /* + BoundingBox compBox = new BoundingBox().update(getComponentLocations()); BoundingBox finSetBox = new BoundingBox( compBox.min.sub( 0, finHeight, finHeight ), compBox.max.add( finLength, finHeight, finHeight )); return finSetBox; - */ - - return new BoundingBox(0.0, finLength, finHeight); + } + + /** + * Adds bounding coordinates to the given set. The body tube will fit within the + * convex hull of the points. + * + * Currently the points are simply a rectangular box around the body tube. + */ + @Override + public Collection getComponentBounds() { + Collection bounds = new ArrayList(8); + + // should simply return this component's bounds in this component's body frame. + + double x_min = Double.MAX_VALUE; + double x_max = Double.MIN_VALUE; + double r_max = 0.0; + + for (Coordinate point : getFinPoints()) { + double hypot = MathUtil.hypot(point.y, point.z); + double x_cur = point.x; + if (x_min > x_cur) { + x_min = x_cur; + } + if (x_max < x_cur) { + x_max = x_cur; + } + if (r_max < hypot) { + r_max = hypot; + } + } + + Coordinate location = this.getLocations()[0]; + x_max += location.x; + + if( parent instanceof SymmetricComponent){ + r_max += ((SymmetricComponent)parent).getRadius(0); + } + + addBoundingBox(bounds, x_min, x_max, r_max); + return bounds; } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index f3b3e3e74..4bb7fdc8d 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -63,7 +63,7 @@ public class FlightConfiguration implements FlightConfigurableParameter motors = new HashMap(); private int boundsModID = -1; - private BoundingBox cachedBoundingBox = new BoundingBox(); + private BoundingBox cachedBounds = new BoundingBox(); private double cachedLength = -1; private int refLengthModID = -1; @@ -501,6 +501,18 @@ public class FlightConfiguration implements FlightConfigurableParameterCollection containing coordinates bounding the rocket. + * + * @deprecated Migrate to .getBoundingBox(), when practical. + */ + @Deprecated + public Collection getBounds() { + return getBoundingBox().toCollection(); + } + /** * Return the bounding box of the current configuration. * @@ -508,34 +520,22 @@ public class FlightConfiguration implements FlightConfigurableParameter> entry: imap.entrySet() ) { - final RocketComponent comp = entry.getKey(); - if (this.isComponentActive(comp)) { - - // iterate across all componenent instances - final ArrayList contextList = entry.getValue(); - - for(InstanceContext context: contextList ) { - BoundingBox instanceBox = new BoundingBox(context.transform.transform(comp.getBoundingBox().min), - context.transform.transform(comp.getBoundingBox().max)); - bounds.update(instanceBox); - } - } + + for (RocketComponent component : this.getActiveComponents()) { + BoundingBox componentBounds = new BoundingBox().update(component.getComponentBounds()); + bounds.update( componentBounds ); } boundsModID = rocket.getModID(); cachedLength = bounds.span().x; - cachedBoundingBox.update( bounds ); + cachedBounds.update( bounds ); } /** @@ -546,7 +546,7 @@ public class FlightConfiguration implements FlightConfigurableParametertrue diff --git a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java index 854b67477..0824a3aef 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java +++ b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java @@ -8,7 +8,6 @@ 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; @@ -187,10 +186,13 @@ public class LaunchLug extends ExternalComponent implements AnglePositionable, C public double getComponentVolume() { return length * Math.PI * (MathUtil.pow2(radius) - MathUtil.pow2(radius - thickness)); } - + @Override - public BoundingBox getBoundingBox() { - return new BoundingBox(0, length, radius); + public Collection getComponentBounds() { + ArrayList set = new ArrayList(); + addBound(set, 0, radius); + addBound(set, length, radius); + return set; } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/MassObject.java b/core/src/net/sf/openrocket/rocketcomponent/MassObject.java index 9af0c8ae3..b018919d2 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/MassObject.java +++ b/core/src/net/sf/openrocket/rocketcomponent/MassObject.java @@ -133,4 +133,13 @@ public abstract class MassObject extends InternalComponent { public final double getRotationalUnitInertia() { return pow2(radius) / 2; } + + @Override + public final Collection getComponentBounds() { + Collection c = new ArrayList(); + addBound(c, 0, radius); + addBound(c, length, radius); + return c; + } + } diff --git a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java index 0cfd8b071..daf79abda 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java +++ b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java @@ -44,6 +44,33 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo return trans.get("BoosterSet.BoosterSet"); } + // not strictly accurate, but this should provide an acceptable estimate for total vehicle size + @Override + public Collection getComponentBounds() { + Collection bounds = new ArrayList(8); + double x_min = Double.MAX_VALUE; + double x_max = Double.MIN_VALUE; + double r_max = 0; + + Coordinate[] instanceLocations = this.getComponentLocations(); + + for (Coordinate currentInstanceLocation : instanceLocations) { + if (x_min > (currentInstanceLocation.x)) { + x_min = currentInstanceLocation.x; + } + if (x_max < (currentInstanceLocation.x + this.length)) { + x_max = currentInstanceLocation.x + this.length; + } + if (r_max < (this.getRadiusOffset())) { + r_max = this.getRadiusOffset(); + } + } + addBound(bounds, x_min, r_max); + addBound(bounds, x_max, r_max); + + return bounds; + } + /** * Check whether the given type can be added to this component. A Stage allows * only BodyComponents to be added. diff --git a/core/src/net/sf/openrocket/rocketcomponent/PodSet.java b/core/src/net/sf/openrocket/rocketcomponent/PodSet.java index 2e3a72275..e22fc51aa 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/PodSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/PodSet.java @@ -45,6 +45,33 @@ public class PodSet extends ComponentAssembly implements RingInstanceable { } + // not strictly accurate, but this should provide an acceptable estimate for total vehicle size + @Override + public Collection getComponentBounds() { + Collection bounds = new ArrayList(8); + double x_min = Double.MAX_VALUE; + double x_max = Double.MIN_VALUE; + double r_max = 0; + + Coordinate[] instanceLocations = this.getComponentLocations(); + + for (Coordinate currentInstanceLocation : instanceLocations) { + if (x_min > (currentInstanceLocation.x)) { + x_min = currentInstanceLocation.x; + } + if (x_max < (currentInstanceLocation.x + this.length)) { + x_max = currentInstanceLocation.x + this.length; + } + if (r_max < (this.getRadiusOffset())) { + r_max = this.getRadiusOffset(); + } + } + addBound(bounds, x_min, r_max); + addBound(bounds, x_max, r_max); + + return bounds; + } + /** * Check whether the given type can be added to this component. A Stage allows * only BodyComponents to be added. diff --git a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java index ab39d492b..df6ea275a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java @@ -11,7 +11,6 @@ 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; @@ -233,13 +232,6 @@ public class RailButton extends ExternalComponent implements AnglePositionable, public Type getPresetType() { return ComponentPreset.Type.RAIL_BUTTON; } - - @Override - public BoundingBox getBoundingBox() { - final double r = outerDiameter_m / 2.0; - return new BoundingBox(new Coordinate(-r, -r, 0), - new Coordinate(r, r, totalHeight_m)); - } @Override public void componentChanged(ComponentChangeEvent e) { @@ -295,6 +287,21 @@ public class RailButton extends ExternalComponent implements AnglePositionable, public String getPatternName(){ return (this.getInstanceCount() + "-Line"); } + + @Override + public Collection getComponentBounds() { + final double r = outerDiameter_m / 2.0; + ArrayList set = new ArrayList(); + set.add(new Coordinate(r, totalHeight_m, r)); + set.add(new Coordinate(r, totalHeight_m, -r)); + set.add(new Coordinate(r, 0, r)); + set.add(new Coordinate(r, 0, -r)); + set.add(new Coordinate(-r, 0, r)); + set.add(new Coordinate(-r, 0, -r)); + set.add(new Coordinate(-r, totalHeight_m, r)); + set.add(new Coordinate(-r, totalHeight_m, -r)); + return set; + } @Override public Coordinate getComponentCG() { diff --git a/core/src/net/sf/openrocket/rocketcomponent/RingComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RingComponent.java index 0365a76a3..5dbf4d5ba 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RingComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RingComponent.java @@ -162,6 +162,14 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } + @Override + public Collection getComponentBounds() { + List bounds = new ArrayList(); + addBound(bounds, 0, getOuterRadius()); + addBound(bounds, length, getOuterRadius()); + return bounds; + } + @Override public Coordinate getComponentCG() { Coordinate cg = Coordinate.ZERO; @@ -187,6 +195,7 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi getMaterial().getDensity()) * getInstanceCount(); } + @Override public double getLongitudinalUnitInertia() { return ringLongitudinalUnitInertia(getOuterRadius(), getInnerRadius(), getLength()); diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 1d5794736..fc20dc813 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -19,7 +19,6 @@ import net.sf.openrocket.preset.ComponentPreset; 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.BoundingBox; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.Color; @@ -223,13 +222,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab /** - * Return bounding box of component. + * Return a collection of bounding coordinates. The coordinates must be such that + * the component is fully enclosed in their convex hull. * * Note: this function gets the bounds only for this component. Subchildren must be called individually. * * @return a collection of coordinates that bound the component. */ - public abstract BoundingBox getBoundingBox(); + public abstract Collection getComponentBounds(); /** * Return true if the component may have an aerodynamic effect on the rocket. @@ -1902,9 +1902,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab /** - * Helper method to add two points on opposite corners of a box - * around the component centerline. This box will be (x_max - - * x_min) long, and 2*r wide/high. + * Helper method to add two points on opposite corners of a box around the rocket centerline. This box will be (x_max - x_min) long, and 2*r wide/high. */ protected static final void addBoundingBox(Collection bounds, double x_min, double x_max, double r) { bounds.add(new Coordinate(x_min, -r, -r)); diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketUtils.java b/core/src/net/sf/openrocket/rocketcomponent/RocketUtils.java index 6776e83c1..f875c2b76 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RocketUtils.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RocketUtils.java @@ -1,4 +1,3 @@ -// this class is only used by the Android application package net.sf.openrocket.rocketcomponent; import java.util.Collection; @@ -8,6 +7,20 @@ import net.sf.openrocket.util.Coordinate; public abstract class RocketUtils { public static double getLength(Rocket rocket) { - return rocket.getSelectedConfiguration().getLength(); + double length = 0; + Collection bounds = rocket.getSelectedConfiguration().getBounds(); + if (!bounds.isEmpty()) { + double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY; + for (Coordinate c : bounds) { + if (c.x < minX) + minX = c.x; + if (c.x > maxX) + maxX = c.x; + } + length = maxX - minX; + } + return length; } + + } diff --git a/core/src/net/sf/openrocket/rocketcomponent/Sleeve.java b/core/src/net/sf/openrocket/rocketcomponent/Sleeve.java index 86a5d9191..aafff5422 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Sleeve.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Sleeve.java @@ -2,7 +2,6 @@ package net.sf.openrocket.rocketcomponent; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@ -83,6 +82,9 @@ public class Sleeve extends RingComponent { thickness = t; fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } + + + @Override public void setInnerRadiusAutomatic(boolean auto) { diff --git a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java index e4f0fe36f..a530bfe94 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java @@ -8,7 +8,6 @@ import java.util.List; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.rocketcomponent.position.AxialMethod; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@ -134,17 +133,24 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); clearPreset(); } - + + /** - * Are there any components whose max diameter isn't at either the - * fore or aft end? I don't know of any. + * Adds component bounds at a number of points between 0...length. */ @Override - public BoundingBox getBoundingBox() { - return new BoundingBox(0, getLength(), - Math.max(getForeRadius(), getAftRadius())); + public Collection getComponentBounds() { + List list = new ArrayList(20); + for (int n = 0; n <= 5; n++) { + double x = n * length / 5; + double r = getRadius(x); + addBound(list, x, r); + } + return list; } + + @Override protected void loadFromPreset(ComponentPreset preset) { if ( preset.has(ComponentPreset.THICKNESS) ) { diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index ada0e9fb1..d89f6de69 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -10,7 +10,6 @@ import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset.Type; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@ -434,22 +433,16 @@ public class Transition extends SymmetricComponent { return Math.max(getRadius(x) - thickness, 0); } - /** - * bounding box of transition - * - * It's tempting to ignore the shoulders (if any) on the grounds - * that they will be covered by the fore and aft body tubes, but - * including them won't cause any errors - * - * we will assume the maximum radius will occur at either the fore - * or aft end -- this is true for the transitions that are - * currently allowed, but could conceivably change in the future - */ + + @Override - public BoundingBox getBoundingBox() { - return new BoundingBox(-getForeShoulderLength(), - getLength() + getAftShoulderLength(), - Math.max(getForeRadius(), getAftRadius())); + public Collection getComponentBounds() { + Collection bounds = super.getComponentBounds(); + if (foreShoulderLength > 0.001) + addBound(bounds, -foreShoulderLength, foreShoulderRadius); + if (aftShoulderLength > 0.001) + addBound(bounds, getLength() + aftShoulderLength, aftShoulderRadius); + return bounds; } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java index 4f6b23aa0..aa9ad73ab 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -10,7 +10,6 @@ import net.sf.openrocket.preset.ComponentPreset.Type; 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.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.Transformation; @@ -305,10 +304,16 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { // TODO Auto-generated method stub return false; } - + @Override - public BoundingBox getBoundingBox() { - return new BoundingBox(0, length, outerRadius); + public Collection getComponentBounds() { + List bounds = new ArrayList(); + double r = getBodyRadius(); + + addBound(bounds, 0, 2 * (r + outerRadius)); + addBound(bounds, length, 2 * (r + outerRadius)); + + return bounds; } /** diff --git a/core/src/net/sf/openrocket/simulation/SimulationStatus.java b/core/src/net/sf/openrocket/simulation/SimulationStatus.java index 7831ed4b3..a3aeaf510 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationStatus.java +++ b/core/src/net/sf/openrocket/simulation/SimulationStatus.java @@ -130,7 +130,11 @@ public class SimulationStatus implements Monitorable { } } if (!Double.isNaN(lugPosition)) { - double maxX = this.configuration.getBoundingBox().max.x; + double maxX = 0; + for (Coordinate c : this.configuration.getBounds()) { + if (c.x > maxX) + maxX = c.x; + } if (maxX >= lugPosition) { length = Math.max(0, length - (maxX - lugPosition)); } diff --git a/core/src/net/sf/openrocket/util/BoundingBox.java b/core/src/net/sf/openrocket/util/BoundingBox.java index 2b456cac6..6d5f46eb8 100644 --- a/core/src/net/sf/openrocket/util/BoundingBox.java +++ b/core/src/net/sf/openrocket/util/BoundingBox.java @@ -17,11 +17,6 @@ public class BoundingBox { this.min = _min.clone(); this.max = _max.clone(); } - - public BoundingBox(double xmin, double xmax, double rad) { - min = new Coordinate(xmin, -rad, -rad); - max = new Coordinate(xmax, rad, rad); - } public void clear() { min = Coordinate.MAX.setWeight( 0.0); @@ -118,14 +113,8 @@ public class BoundingBox { update_z_max(other.max.z); return this; } - - public Coordinate span() { - Coordinate tmp = max.sub( min ); - return new Coordinate(Math.max(tmp.x, 0.0), - Math.max(tmp.y, 0.0), - Math.max(tmp.z, 0.0), - Math.max(tmp.weight, 0.0)); - } + + public Coordinate span() { return max.sub( min ); } public Coordinate[] toArray() { return new Coordinate[] { this.min, this.max }; diff --git a/openrocket.log b/openrocket.log new file mode 100644 index 000000000..d5c1f8088 --- /dev/null +++ b/openrocket.log @@ -0,0 +1 @@ +Error: Unable to access jarfile OpenRocket.jar diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java index 6d74f4a37..8b01b734e 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java @@ -49,7 +49,6 @@ import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Preferences; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@ -469,21 +468,64 @@ public class RocketFigure3d extends JPanel implements GLEventListener { redrawExtras = true; } + @SuppressWarnings("unused") + private static class Bounds { + double xMin, xMax, xSize; + double yMin, yMax, ySize; + double zMin, zMax, zSize; + double rMax; + } + + private Bounds cachedBounds = null; + + /** + * Calculates the bounds for the current configuration + * + * @return + */ + private Bounds calculateBounds() { + if (cachedBounds != null) { + return cachedBounds; + } else { + final Bounds b = new Bounds(); + final FlightConfiguration configuration = rkt.getSelectedConfiguration(); + final Collection bounds = configuration.getBounds(); + for (Coordinate c : bounds) { + b.xMax = Math.max(b.xMax, c.x); + b.xMin = Math.min(b.xMin, c.x); + + b.yMax = Math.max(b.yMax, c.y); + b.yMin = Math.min(b.yMin, c.y); + + b.zMax = Math.max(b.zMax, c.z); + b.zMin = Math.min(b.zMin, c.z); + + double r = MathUtil.hypot(c.y, c.z); + b.rMax = Math.max(b.rMax, r); + } + b.xSize = b.xMax - b.xMin; + b.ySize = b.yMax - b.yMin; + b.zSize = b.zMax - b.zMin; + cachedBounds = b; + return b; + } + } + private void setupView(final GL2 gl, final GLU glu) { gl.glLoadIdentity(); gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION, lightPosition, 0); - // Get the bounding box - final BoundingBox b = rkt.getSelectedConfiguration().getBoundingBox(); + // Get the bounds + final Bounds b = calculateBounds(); // Calculate the distance needed to fit the bounds in both the X and Y // direction // Add 10% for space around it. - final double dX = (b.max.x * 1.2 / 2.0) + final double dX = (b.xSize * 1.2 / 2.0) / Math.tan(Math.toRadians(fovX / 2.0)); - final double dY = (b.max.y * 2.0 * 1.2 / 2.0) + final double dY = (b.rMax * 2.0 * 1.2 / 2.0) / Math.tan(Math.toRadians(fovY / 2.0)); // Move back the greater of the 2 distances @@ -493,8 +535,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { gl.glRotated(roll * (180.0 / Math.PI), 1, 0, 0); // Center the rocket in the view. - // gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0); - gl.glTranslated((b.min.x - b.max.x) / 2.0, 0, 0); + gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0); //Change to LEFT Handed coordinates gl.glScaled(1, 1, -1); @@ -513,6 +554,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { */ public void updateFigure() { log.debug("3D Figure Updated"); + cachedBounds = null; if (canvas != null) { ((GLAutoDrawable) canvas).invoke(true, new GLRunnable() { @Override diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java index 42f657060..d4f6f54ea 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java @@ -2,6 +2,7 @@ package net.sf.openrocket.gui.figure3d; import java.awt.Point; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Set; @@ -27,7 +28,6 @@ import net.sf.openrocket.rocketcomponent.InstanceContext; import net.sf.openrocket.rocketcomponent.InstanceMap; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Transformation; diff --git a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java index cd8229381..a0f44b54d 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java @@ -25,7 +25,6 @@ import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.rocketcomponent.Transition.Shape; import net.sf.openrocket.rocketcomponent.TubeFinSet; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Transformation; @@ -122,57 +121,12 @@ public class ComponentRenderer { } else if ( c instanceof ParallelStage ) { } else if ( c instanceof PodSet ) { } else { - renderBoundingBox(gl, c); + renderOther(gl, c); } } - /** - * If I don't have a method to render an object, I'll render its bounding box - */ - private void renderBoundingBox(GL2 gl, RocketComponent c) { - BoundingBox box = c.getBoundingBox(); - - // rectangle at forward end - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.min.x, box.min.y, box.min.z); - gl.glVertex3d(box.min.x, box.max.y, box.min.z); - gl.glVertex3d(box.min.x, box.max.y, box.max.z); - gl.glVertex3d(box.min.x, box.max.x, box.min.z); - gl.glEnd(); - - // rectangle at aft end - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.max.x, box.min.y, box.min.z); - gl.glVertex3d(box.max.x, box.max.y, box.min.z); - gl.glVertex3d(box.max.x, box.max.y, box.max.z); - gl.glVertex3d(box.max.x, box.max.x, box.min.z); - gl.glEnd(); - - // connect forward and aft rectangles - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.min.x, box.min.y, box.min.z); - gl.glVertex3d(box.max.x, box.min.y, box.min.z); - gl.glEnd(); - - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.min.x, box.max.y, box.min.z); - gl.glVertex3d(box.max.x, box.max.y, box.min.z); - gl.glEnd(); - - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.min.x, box.min.y, box.max.z); - gl.glVertex3d(box.max.x, box.min.y, box.max.z); - gl.glEnd(); - - gl.glBegin(GL.GL_LINES); - gl.glVertex3d(box.min.x, box.max.y, box.max.z); - gl.glVertex3d(box.max.x, box.max.y, box.max.z); - gl.glEnd(); - } - - /* private void renderOther(GL2 gl, RocketComponent c) { gl.glBegin(GL.GL_LINES); for (Coordinate cc : c.getComponentBounds()) { @@ -183,7 +137,7 @@ public class ComponentRenderer { } gl.glEnd(); } - */ + private void renderTransition(GL2 gl, Transition t, Surface which) { if (which == Surface.OUTSIDE || which == Surface.INSIDE) { diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoPanel.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoPanel.java index d6212c616..7e92db8b4 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoPanel.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoPanel.java @@ -52,7 +52,6 @@ import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Preferences; -import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@ -93,6 +92,7 @@ public class PhotoPanel extends JPanel implements GLEventListener { @Override public boolean run(final GLAutoDrawable drawable) { PhotoPanel.this.configuration = doc.getSelectedConfiguration(); + cachedBounds = null; rr = new RealisticRenderer(doc); rr.init(drawable); @@ -246,11 +246,11 @@ public class PhotoPanel extends JPanel implements GLEventListener { draw(drawable, 0); if (p.isMotionBlurred()) { - BoundingBox b = configuration.getBoundingBox(); + Bounds b = calculateBounds(); float m = .6f; int c = 10; - float d = (float) (b.max.x - b.min.x) / 25.0f; + float d = (float) b.xSize / 25.0f; gl.glAccum(GL2.GL_LOAD, m); @@ -391,11 +391,11 @@ public class PhotoPanel extends JPanel implements GLEventListener { gl.glLightfv(GLLightingFunc.GL_LIGHT2, GLLightingFunc.GL_SPECULAR, new float[] { color[0], color[1], color[2], 1 }, 0); - BoundingBox b = configuration.getBoundingBox(); + Bounds b = calculateBounds(); gl.glLightf(GLLightingFunc.GL_LIGHT2, GLLightingFunc.GL_QUADRATIC_ATTENUATION, 20f); gl.glLightfv(GLLightingFunc.GL_LIGHT2, GLLightingFunc.GL_POSITION, - new float[] { (float) (b.max.x + .1f), 0, 0, 1 }, 0); + new float[] { (float) (b.xMax + .1f), 0, 0, 1 }, 0); gl.glEnable(GLLightingFunc.GL_LIGHT2); } else { gl.glDisable(GLLightingFunc.GL_LIGHT2); @@ -478,14 +478,56 @@ public class PhotoPanel extends JPanel implements GLEventListener { ratio = (double) w / (double) h; } + @SuppressWarnings("unused") + private static class Bounds { + double xMin, xMax, xSize; + double yMin, yMax, ySize; + double zMin, zMax, zSize; + double rMax; + } + + private Bounds cachedBounds = null; + + /** + * Calculates the bounds for the current configuration + * + * @return + */ + private Bounds calculateBounds() { + if (cachedBounds != null) { + return cachedBounds; + } else { + final Bounds b = new Bounds(); + final Collection bounds = configuration.getBounds(); + for (Coordinate c : bounds) { + b.xMax = Math.max(b.xMax, c.x); + b.xMin = Math.min(b.xMin, c.x); + + b.yMax = Math.max(b.yMax, c.y); + b.yMin = Math.min(b.yMin, c.y); + + b.zMax = Math.max(b.zMax, c.z); + b.zMin = Math.min(b.zMin, c.z); + + double r = MathUtil.hypot(c.y, c.z); + b.rMax = Math.max(b.rMax, r); + } + b.xSize = b.xMax - b.xMin; + b.ySize = b.yMax - b.yMin; + b.zSize = b.zMax - b.zMin; + cachedBounds = b; + return b; + } + } + private void setupModel(final GL2 gl) { + // Get the bounds + final Bounds b = calculateBounds(); gl.glRotated(-p.getPitch() * (180.0 / Math.PI), 0, 0, 1); gl.glRotated(p.getYaw() * (180.0 / Math.PI), 0, 1, 0); gl.glRotated(p.getRoll() * (180.0 / Math.PI), 1, 0, 0); - // Center the rocket in the view. - final BoundingBox b = configuration.getBoundingBox(); - gl.glTranslated((b.min.x - b.max.x) / 2.0, 0, 0); + gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0); } } diff --git a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java index 70d098089..212d50ef5 100644 --- a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java +++ b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java @@ -61,6 +61,10 @@ public class RocketInfo implements FigureElement { private float line = 0; private float x1, x2, y1, y2; + + + + public RocketInfo(FlightConfiguration configuration) { this.configuration = configuration; this.stabilityUnits = UnitGroup.stabilityUnits(configuration); diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index 700426068..5775390a1 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -14,6 +14,7 @@ import java.awt.geom.Ellipse2D; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.Map.Entry; @@ -33,7 +34,6 @@ import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Coordinate; diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index eb534701c..33a014531 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -67,12 +67,12 @@ import net.sf.openrocket.simulation.listeners.SimulationListener; import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener; import net.sf.openrocket.simulation.listeners.system.InterruptListener; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.Chars; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.StateChangeListener; -import net.sf.openrocket.unit.UnitGroup; /** @@ -607,7 +607,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change figure3d.setCP(cp); // Length bound is assumed to be tight - double length = curConfig.getLength(); + double length = 0; + Collection bounds = curConfig.getBounds(); + if (!bounds.isEmpty()) { + double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY; + for (Coordinate c : bounds) { + if (c.x < minX) + minX = c.x; + if (c.x > maxX) + maxX = c.x; + } + length = maxX - minX; + } double diameter = Double.NaN; for (RocketComponent c : curConfig.getCoreComponents()) {