[refactor] Refactored FlightConfiguration.calculateBounds to be clearer
This commit is contained in:
parent
056c6b2b39
commit
0a9df5cc64
15
core/src/net/sf/openrocket/rocketcomponent/BoxBounded.java
Normal file
15
core/src/net/sf/openrocket/rocketcomponent/BoxBounded.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package net.sf.openrocket.rocketcomponent;
|
||||||
|
|
||||||
|
import net.sf.openrocket.util.BoundingBox;
|
||||||
|
|
||||||
|
public interface BoxBounded {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a bounding box for a single instance of this component, from its own reference point.
|
||||||
|
* This is expected to be compbined with a InstanceContext for bounds in the global / rocket frame.
|
||||||
|
*
|
||||||
|
* @return BoundingBox from the instance's reference point.
|
||||||
|
*/
|
||||||
|
BoundingBox getInstanceBoundingBox();
|
||||||
|
|
||||||
|
}
|
@ -25,13 +25,9 @@ import net.sf.openrocket.util.Coordinate;
|
|||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
import net.sf.openrocket.util.Transformation;
|
import net.sf.openrocket.util.Transformation;
|
||||||
|
|
||||||
public abstract class FinSet extends ExternalComponent implements RingInstanceable, AxialPositionable {
|
public abstract class FinSet extends ExternalComponent implements AxialPositionable, BoxBounded, RingInstanceable {
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FinSet.class);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum allowed cant of fins.
|
* Maximum allowed cant of fins.
|
||||||
*/
|
*/
|
||||||
@ -735,13 +731,14 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public BoundingBox getBoundingBox() {
|
public BoundingBox getInstanceBoundingBox(){
|
||||||
BoundingBox singleFinBounds= new BoundingBox().update(getFinPoints());
|
BoundingBox singleFinBounds= new BoundingBox().update(getFinPoints());
|
||||||
final double finLength = singleFinBounds.max.x;
|
final double finLength = singleFinBounds.max.x;
|
||||||
final double finHeight = singleFinBounds.max.y;
|
final double finHeight = singleFinBounds.max.y;
|
||||||
|
|
||||||
Coordinate[] locations = getInstanceLocations();
|
Coordinate[] locations = getInstanceLocations();
|
||||||
double[] angles = getInstanceAngles();
|
double[] angles = getInstanceAngles();
|
||||||
|
|
||||||
BoundingBox finSetBox = new BoundingBox();
|
BoundingBox finSetBox = new BoundingBox();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -550,59 +550,77 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
* in the current configuration.
|
* in the current configuration.
|
||||||
*/
|
*/
|
||||||
private void calculateBounds(){
|
private void calculateBounds(){
|
||||||
BoundingBox bounds = new BoundingBox();
|
BoundingBox rocketBounds = new BoundingBox();
|
||||||
|
|
||||||
InstanceMap map = getActiveInstances();
|
InstanceMap map = getActiveInstances();
|
||||||
for (Map.Entry<RocketComponent, java.util.ArrayList<InstanceContext>> entry : map.entrySet()) {
|
for (Map.Entry<RocketComponent, java.util.ArrayList<InstanceContext>> entry : map.entrySet()) {
|
||||||
RocketComponent component = entry.getKey();
|
RocketComponent component = entry.getKey();
|
||||||
|
BoundingBox componentBounds = new BoundingBox();
|
||||||
List<InstanceContext> contexts = entry.getValue();
|
List<InstanceContext> contexts = entry.getValue();
|
||||||
|
|
||||||
Collection<Coordinate> coordinates = new ArrayList<Coordinate>();
|
|
||||||
/* FinSets already provide a bounding box, so let's use that.
|
/* FinSets already provide a bounding box, so let's use that.
|
||||||
*/
|
*/
|
||||||
if (component instanceof FinSet) {
|
if (component instanceof BoxBounded) {
|
||||||
bounds.update(((FinSet) component).getBoundingBox());
|
for (InstanceContext context : contexts) {
|
||||||
continue;
|
/*
|
||||||
} else {
|
* If the instance is not active in the current context, then
|
||||||
coordinates.addAll(component.getComponentBounds());
|
* skip the bound calculations. This is mildly confusing since
|
||||||
}
|
* getActiveInstances() implies that it will only return the
|
||||||
BoundingBox componentBox = new BoundingBox();
|
* instances that are active, but it returns all instances and
|
||||||
List<Coordinate> transformedCoords = new ArrayList<Coordinate>();
|
* the context indicates if it is active or not.
|
||||||
for (InstanceContext ctxt : contexts) {
|
|
||||||
/*
|
|
||||||
* If the instance is not active in the current context, then
|
|
||||||
* skip the bound calculations. This is mildly confusing since
|
|
||||||
* getActiveInstances() implies that it will only return the
|
|
||||||
* instances that are active, but it returns all instances and
|
|
||||||
* the context indicates if it is active or not.
|
|
||||||
*/
|
|
||||||
if (!ctxt.active) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (Coordinate c : coordinates) {
|
|
||||||
Coordinate tc = null;
|
|
||||||
/* These components do not need the transform performed in
|
|
||||||
* order to provide the proper coordinates for length calculation.
|
|
||||||
* The transformation will cause the values to be calculated
|
|
||||||
* incorrectly. This should be fixed in the appropriate places
|
|
||||||
* not handled as one-offs in here.
|
|
||||||
*/
|
*/
|
||||||
if ((component instanceof AxialStage) || (component instanceof BodyTube) ||
|
if (!context.active) {
|
||||||
(component instanceof PodSet)) {
|
continue;
|
||||||
tc = c;
|
}
|
||||||
} else {
|
|
||||||
tc = ctxt.transform.transform(c);
|
BoundingBox instanceBounds = ((BoxBounded) component).getInstanceBoundingBox();
|
||||||
|
if(instanceBounds.isEmpty()) {
|
||||||
|
// this component is probably non-physical (like an assembly) or has invalid bounds. Skip.
|
||||||
|
// i.e. 'break' out of the per-instance-context loop, and let the per-component loop continue
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
componentBounds = instanceBounds.transform(context.transform);
|
||||||
|
}
|
||||||
|
}else if ((component instanceof AxialStage) || (component instanceof BodyTube) || (component instanceof PodSet)) {
|
||||||
|
// Legacy Case #1:
|
||||||
|
// These components do not need the transform performed in
|
||||||
|
// order to provide the proper coordinates for length calculation.
|
||||||
|
// The transformation will cause the values to be calculated
|
||||||
|
// incorrectly. This should be fixed in the appropriate places
|
||||||
|
// not handled as one-offs in here.
|
||||||
|
componentBounds.update(component.getComponentBounds());
|
||||||
|
} else {
|
||||||
|
// Legacy Case #2:
|
||||||
|
// These components do not implement
|
||||||
|
Collection<Coordinate> instanceCoordinates = component.getComponentBounds();
|
||||||
|
|
||||||
|
for (InstanceContext context : contexts) {
|
||||||
|
/*
|
||||||
|
* If the instance is not active in the current context, then
|
||||||
|
* skip the bound calculations. This is mildly confusing since
|
||||||
|
* getActiveInstances() implies that it will only return the
|
||||||
|
* instances that are active, but it returns all instances and
|
||||||
|
* the context indicates if it is active or not.
|
||||||
|
*/
|
||||||
|
if (!context.active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Coordinate> transformedCoords = new ArrayList<>(instanceCoordinates);
|
||||||
|
// mutating. Transforms coordinates in place.
|
||||||
|
context.transform.transform(instanceCoordinates);
|
||||||
|
|
||||||
|
for (Coordinate tc : transformedCoords) {
|
||||||
|
componentBounds.update(tc);
|
||||||
}
|
}
|
||||||
componentBox.update(tc);
|
|
||||||
transformedCoords.add(tc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bounds.update(componentBox);
|
rocketBounds.update(componentBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
boundsModID = rocket.getModID();
|
boundsModID = rocket.getModID();
|
||||||
cachedLength = bounds.span().x;
|
cachedLength = rocketBounds.span().x;
|
||||||
/* Special case for the scenario that all of the stages are removed and are
|
/* Special case for the scenario that all of the stages are removed and are
|
||||||
* inactive. Its possible that this shouldn't be allowed, but it is currently
|
* inactive. Its possible that this shouldn't be allowed, but it is currently
|
||||||
* so we'll just adjust the length here.
|
* so we'll just adjust the length here.
|
||||||
@ -610,7 +628,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
if (getActiveStages().isEmpty()) {
|
if (getActiveStages().isEmpty()) {
|
||||||
cachedLength = 0;
|
cachedLength = 0;
|
||||||
}
|
}
|
||||||
cachedBounds.update( bounds );
|
cachedBounds.update( rocketBounds );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +28,23 @@ public class BoundingBox {
|
|||||||
return new BoundingBox( this.min, this.max );
|
return new BoundingBox( this.min, this.max );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty(){
|
||||||
|
if( (min.x > max.x) ||
|
||||||
|
(min.y > max.y) ||
|
||||||
|
(min.z > max.z)){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a copy of this bounding box, transformed by the given transformation matrix
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public BoundingBox transform(Transformation transform){
|
||||||
|
return new BoundingBox(transform.transform(this.min), transform.transform(this.max));
|
||||||
|
}
|
||||||
|
|
||||||
private void update_x_min( final double xVal) {
|
private void update_x_min( final double xVal) {
|
||||||
if( min.x > xVal)
|
if( min.x > xVal)
|
||||||
@ -104,6 +121,9 @@ public class BoundingBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BoundingBox update( BoundingBox other ) {
|
public BoundingBox update( BoundingBox other ) {
|
||||||
|
if(other.isEmpty()){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
update_x_min(other.min.x);
|
update_x_min(other.min.x);
|
||||||
update_y_min(other.min.y);
|
update_y_min(other.min.y);
|
||||||
update_z_min(other.min.y);
|
update_z_min(other.min.y);
|
||||||
@ -121,7 +141,7 @@ public class BoundingBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Coordinate> toCollection(){
|
public Collection<Coordinate> toCollection(){
|
||||||
Collection<Coordinate> toReturn = new ArrayList<Coordinate>();
|
Collection<Coordinate> toReturn = new ArrayList<>();
|
||||||
toReturn.add( this.max);
|
toReturn.add( this.max);
|
||||||
toReturn.add( this.min);
|
toReturn.add( this.min);
|
||||||
return toReturn;
|
return toReturn;
|
||||||
|
@ -19,7 +19,7 @@ public class FinRenderer {
|
|||||||
|
|
||||||
public void renderFinSet(final GL2 gl, FinSet finSet ) {
|
public void renderFinSet(final GL2 gl, FinSet finSet ) {
|
||||||
|
|
||||||
BoundingBox bounds = finSet.getBoundingBox();
|
BoundingBox bounds = finSet.getInstanceBoundingBox();
|
||||||
gl.glMatrixMode(GL.GL_TEXTURE);
|
gl.glMatrixMode(GL.GL_TEXTURE);
|
||||||
gl.glPushMatrix();
|
gl.glPushMatrix();
|
||||||
gl.glScaled(1 / (bounds.max.x - bounds.min.x), 1 / (bounds.max.y - bounds.min.y), 0);
|
gl.glScaled(1 / (bounds.max.x - bounds.min.x), 1 / (bounds.max.y - bounds.min.y), 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user