bugfixing core RocketComponent placement code

This commit is contained in:
Daniel_M_Williams 2015-08-01 08:52:37 -04:00
parent c1d9ff5d41
commit 2ac17cd0d5
5 changed files with 90 additions and 211 deletions

View File

@ -2,7 +2,6 @@ package net.sf.openrocket.rocketcomponent;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.EventListener; import java.util.EventListener;
import java.util.EventObject; import java.util.EventObject;
import java.util.Iterator; import java.util.Iterator;
@ -29,7 +28,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
Iterable<RocketComponent>, Monitorable { Iterable<RocketComponent>, Monitorable {
private Rocket rocket; private Rocket rocket;
private BitSet stages = new BitSet(); private BitSet stagesActive = new BitSet();
private String flightConfigurationId = null; private String flightConfigurationId = null;
@ -68,8 +67,8 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
public void setAllStages() { public void setAllStages() {
stages.clear(); stagesActive.clear();
stages.set(0, rocket.getStageCount()); stagesActive.set(0, Stage.getStageCount());
fireChangeEvent(); fireChangeEvent();
} }
@ -81,15 +80,15 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
* @param stage the stage number. * @param stage the stage number.
*/ */
public void setToStage(int stage) { public void setToStage(int stage) {
stages.clear(); stagesActive.clear();
stages.set(0, stage + 1, true); stagesActive.set(0, stage + 1, true);
// stages.set(stage+1, rocket.getStageCount(), false); // stages.set(stage+1, rocket.getStageCount(), false);
fireChangeEvent(); fireChangeEvent();
} }
public void setOnlyStage(int stage) { public void setOnlyStage(int stage) {
stages.clear(); stagesActive.clear();
stages.set(stage, stage + 1, true); stagesActive.set(stage, stage + 1, true);
fireChangeEvent(); fireChangeEvent();
} }
@ -108,33 +107,33 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
* Check whether the stage specified by the index is active. * Check whether the stage specified by the index is active.
*/ */
public boolean isStageActive(int stage) { public boolean isStageActive(int stage) {
if (stage >= rocket.getStageCount()) if (stage >= Stage.getStageCount())
return false; return false;
return stages.get(stage); return stagesActive.get(stage);
} }
public int getStageCount() { public int getStageCount() {
return rocket.getStageCount(); return Stage.getStageCount();
} }
public int getActiveStageCount() { public int getActiveStageCount() {
int count = 0; int count = 0;
int s = rocket.getStageCount(); int s = Stage.getStageCount();
for (int i = 0; i < s; i++) { for (int i = 0; i < s; i++) {
if (stages.get(i)) if (stagesActive.get(i))
count++; count++;
} }
return count; return count;
} }
public int[] getActiveStages() { public int[] getActiveStages() {
int stageCount = rocket.getStageCount(); int stageCount = Stage.getStageCount();
List<Integer> active = new ArrayList<Integer>(); List<Integer> active = new ArrayList<Integer>();
int[] ret; int[] ret;
for (int i = 0; i < stageCount; i++) { for (int i = 0; i < stageCount; i++) {
if (stages.get(i)) { if (stagesActive.get(i)) {
active.add(i); active.add(i);
} }
} }
@ -262,7 +261,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
/** /**
* Return the bounds of the current configuration. The bounds are cached. * Return the bounds of the current configuration. The bounds are cached.
* *
* @return a <code>Collection</code> containing coordinates bouding the rocket. * @return a <code>Collection</code> containing coordinates bounding the rocket.
*/ */
public Collection<Coordinate> getBounds() { public Collection<Coordinate> getBounds() {
if (rocket.getModID() != boundsModID) { if (rocket.getModID() != boundsModID) {
@ -313,9 +312,30 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
*/ */
@Override @Override
public Iterator<RocketComponent> iterator() { public Iterator<RocketComponent> iterator() {
return new ConfigurationIterator(); List<RocketComponent> accumulator = new ArrayList<RocketComponent>();
accumulator = this.getActiveComponents(accumulator, rocket.getChildren());
return accumulator.iterator();
} }
private List<RocketComponent> getActiveComponents(List<RocketComponent> accumulator, final List<RocketComponent> toScan) {
for (RocketComponent rc : toScan) {
if (rc instanceof Stage) {
if (isStageActive(rc.getStageNumber())) {
// recurse to children
getActiveComponents(accumulator, rc.getChildren());
} else {
continue;
}
} else {
accumulator.add(rc);
}
}
return accumulator;
}
/** /**
* Return an iterator that iterates over all <code>MotorMount</code>s within the * Return an iterator that iterates over all <code>MotorMount</code>s within the
@ -337,7 +357,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
try { try {
Configuration config = (Configuration) super.clone(); Configuration config = (Configuration) super.clone();
config.listenerList = new ArrayList<EventListener>(); config.listenerList = new ArrayList<EventListener>();
config.stages = (BitSet) this.stages.clone(); config.stagesActive = (BitSet) this.stagesActive.clone();
config.cachedBounds = new ArrayList<Coordinate>(); config.cachedBounds = new ArrayList<Coordinate>();
config.boundsModID = -1; config.boundsModID = -1;
config.refLengthModID = -1; config.refLengthModID = -1;
@ -354,68 +374,6 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
return modID + rocket.getModID(); return modID + rocket.getModID();
} }
/**
* A class that iterates over all currently active components.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
private class ConfigurationIterator implements Iterator<RocketComponent> {
Iterator<Iterator<RocketComponent>> iterators;
Iterator<RocketComponent> current = null;
public ConfigurationIterator() {
List<Iterator<RocketComponent>> list = new ArrayList<Iterator<RocketComponent>>();
for (RocketComponent stage : rocket.getChildren()) {
if (isComponentActive(stage)) {
list.add(stage.iterator(false));
}
}
// Get iterators and initialize current
iterators = list.iterator();
if (iterators.hasNext()) {
current = iterators.next();
} else {
List<RocketComponent> l = Collections.emptyList();
current = l.iterator();
}
}
@Override
public boolean hasNext() {
if (!current.hasNext())
getNextIterator();
return current.hasNext();
}
@Override
public RocketComponent next() {
if (!current.hasNext())
getNextIterator();
return current.next();
}
/**
* Get the next iterator that has items. If such an iterator does
* not exist, current is left to an empty iterator.
*/
private void getNextIterator() {
while ((!current.hasNext()) && iterators.hasNext()) {
current = iterators.next();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove unsupported");
}
}
private class MotorIterator implements Iterator<MotorMount> { private class MotorIterator implements Iterator<MotorMount> {
private final Iterator<RocketComponent> iterator; private final Iterator<RocketComponent> iterator;
private MotorMount next = null; private MotorMount next = null;

View File

@ -130,7 +130,7 @@ public class Rocket extends RocketComponent {
*/ */
public int getStageCount() { public int getStageCount() {
checkState(); checkState();
return this.getChildCount(); return Stage.getStageCount();
} }

View File

@ -1068,10 +1068,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
} }
protected void update() { protected void update() {
if (null == this.parent) {
return;
}
this.setAxialOffset(this.relativePosition, this.offset); this.setAxialOffset(this.relativePosition, this.offset);
} }
@ -1092,17 +1088,29 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
/** /**
* Returns coordinate c in absolute/global/rocket coordinates. Equivalent to toComponent(c,null). * Returns coordinate c in absolute/global/rocket coordinates. Equivalent to toComponent(c,null).
* Input coordinate C is interpreted to be position relative to this component's *center*, just as
* this component's center is the root of the component coordinate frame.
* *
* @param c Coordinate in the component's coordinate system. * @param c Coordinate in the component's coordinate system.
* @return an array of coordinates describing <code>c</code> in global coordinates. * @return an array of coordinates describing <code>c</code> in global coordinates.
*/ */
public Coordinate[] toAbsolute(Coordinate c) { public Coordinate[] toAbsolute(Coordinate c) {
// checkState(); checkState();
// return toRelative(c, null);
Coordinate absCoord = this.getAbsolutePositionVector().add(c); Coordinate absCoord = this.getAbsolutePositionVector().add(c);
return new Coordinate[] { absCoord }; return new Coordinate[] { absCoord };
} }
// public Coordinate[] toAbsolute(final Coordinate[] toMove) {
// Coordinate[] toReturn = new Coordinate[toMove.length];
//
// Coordinate translation = this.getAbsolutePositionVector();
// for (int coordIndex = 0; coordIndex < toMove.length; coordIndex++) {
// toReturn[coordIndex] = translation.add(toMove[coordIndex]);
// }
// return toReturn;
// }
/** /**
* Return coordinate <code>c</code> described in the coordinate system of * Return coordinate <code>c</code> described in the coordinate system of
* <code>dest</code>. If <code>dest</code> is <code>null</code> returns * <code>dest</code>. If <code>dest</code> is <code>null</code> returns
@ -1122,126 +1130,39 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*/ */
@Deprecated @Deprecated
public final Coordinate[] toRelative(Coordinate c, RocketComponent dest) { public final Coordinate[] toRelative(Coordinate c, RocketComponent dest) {
checkState();
mutex.lock("toRelative");
if (null == dest) { if (null == dest) {
throw new BugException("calling toRelative(c,null) is being refactored. "); throw new BugException("calling toRelative(c,null) is being refactored. ");
} }
try { checkState();
double absoluteX = Double.NaN; mutex.lock("toRelative");
double relativeX = 0;
double relativeY = 0; final Coordinate sourceLoc = this.getAbsolutePositionVector();
double relativeZ = 0; final Coordinate destLoc = dest.getAbsolutePositionVector();
RocketComponent search = dest; Coordinate newCoord = c.add(sourceLoc).sub(destLoc);
Coordinate[] array = new Coordinate[1]; Coordinate[] toReturn = new Coordinate[] { newCoord };
array[0] = c;
mutex.unlock("toRelative");
RocketComponent component = this; return toReturn;
while ((component != search) && (component.parent != null)) {
array = component.shiftCoordinates(array);
switch (component.relativePosition) {
case TOP:
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(relativeX, relativeY, relativeZ);
}
break;
case MIDDLE:
relativeX = component.position.x;
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(relativeX + (component.parent.length - component.length) / 2,
relativeY, relativeZ);
}
break;
case BOTTOM:
relativeX = component.position.x;
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(relativeX + (component.parent.length - component.length),
relativeY, relativeZ);
}
break;
case AFTER:
relativeX = component.position.x;
// Add length of all previous brother-components with POSITION_RELATIVE_AFTER
int index = component.parent.children.indexOf(component);
assert (index >= 0);
for (index--; index >= 0; index--) {
RocketComponent comp = component.parent.children.get(index);
double componentLength = comp.getTotalLength();
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(componentLength, relativeY, relativeZ);
}
}
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(relativeX + component.parent.length, relativeY, relativeZ);
}
break;
case ABSOLUTE:
search = null; // Requires back-search if dest!=null
if (Double.isNaN(absoluteX)) {
// TODO: requires debugging if thsi component is an External Pods or stage
absoluteX = relativeX;
}
break;
default:
throw new BugException("Unknown relative positioning type of component" +
component + ": " + component.relativePosition);
}
component = component.parent; // parent != null
}
if (!Double.isNaN(absoluteX)) {
for (int i = 0; i < array.length; i++) {
// TODO: requires debugging if thsi component is an External Pods or stage
array[i] = array[i].setX(absoluteX + c.x);
}
}
// Check whether destination has been found or whether to backtrack
// TODO: LOW: Backtracking into clustered components uses only one component
if ((dest != null) && (component != dest)) {
Coordinate origin = dest.getAbsolutePositionVector();
for (int i = 0; i < array.length; i++) {
array[i] = array[i].sub(origin);
}
}
return array;
} finally {
mutex.unlock("toRelative");
}
} }
// public final Coordinate[] toRelative(Coordinate[] coords, RocketComponent dest) { /*
// Coordinate[] toReturn = new Coordinate[coords.length]; * @deprecated ? is this used by anything?
// */
// protected static final Coordinate[] rebase(final Coordinate toMove[], final Coordinate source, final Coordinate dest) {
// // Coordinate[] array = new Coordinate[] { c }; if ((null == toMove) || (null == source) || (null == dest)) {
// // // if( dest.isCluster() ){ throw new NullPointerException("rebase with any null pointer is out-of-spec.");
// // // if( dest.multiplicity > 1){ }
// // array = dest.shiftCoordinates(array);
// // return this.toRelative(array, dest); Coordinate[] toReturn = new Coordinate[toMove.length];
// // // }
// Coordinate translation = source.sub(dest);
// Coordinate destCenter = dest.getAbsolutePositionVector(); for (int coordIndex = 0; coordIndex < toMove.length; coordIndex++) {
// Coordinate thisCenter = this.getAbsolutePositionVector(); toReturn[coordIndex] = toMove[coordIndex].add(translation);
// Coordinate relVector = destCenter.sub(thisCenter); }
//
// for (int coord_index = 0; coord_index < coords.length; coord_index++) { return toReturn;
// toReturn[coord_index] = coords[coord_index].add(relVector); }
// }
// return toReturn;
// }
/** /**
* Iteratively sum the lengths of all subcomponents that have position * Iteratively sum the lengths of all subcomponents that have position
@ -1266,7 +1187,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
} }
/////////// Total mass and CG calculation //////////// /////////// Total mass and CG calculation ////////////
/** /**

View File

@ -36,8 +36,10 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
Stage.stageCount++; Stage.stageCount++;
} }
protected String toPositionString() {
return ">> " + this.getName() + " rel: " + this.getRelativePositionVector().x + " abs: " + this.getAbsolutePositionVector().x; @Override
public boolean allowsChildren() {
return true;
} }
@ -47,13 +49,12 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
return trans.get("Stage.Stage"); return trans.get("Stage.Stage");
} }
public FlightConfiguration<StageSeparationConfiguration> getStageSeparationConfiguration() { public static int getStageCount() {
return separationConfigurations; return Stage.stageCount;
} }
@Override public FlightConfiguration<StageSeparationConfiguration> getStageSeparationConfiguration() {
public boolean allowsChildren() { return separationConfigurations;
return true;
} }
// not strictly accurate, but this should provide an acceptable estimate for total vehicle size // not strictly accurate, but this should provide an acceptable estimate for total vehicle size

View File

@ -59,7 +59,7 @@ public final class Coordinate implements Cloneable, Serializable {
//////// End debug section //////// End debug section
public static final Coordinate ZERO = new Coordinate(0, 0, 0, 0);
public static final Coordinate NUL = new Coordinate(0, 0, 0, 0); public static final Coordinate NUL = new Coordinate(0, 0, 0, 0);
public static final Coordinate NaN = new Coordinate(Double.NaN, Double.NaN, public static final Coordinate NaN = new Coordinate(Double.NaN, Double.NaN,
Double.NaN, Double.NaN); Double.NaN, Double.NaN);
@ -151,7 +151,7 @@ public final class Coordinate implements Cloneable, Serializable {
/** /**
* Subtract a Coordinate from this Coordinate. The weight of the resulting Coordinate * Subtract a Coordinate from this Coordinate. The weight of the resulting Coordinate
* is the same as of this Coordinate, the weight of the argument is ignored. * is the same as of this Coordinate; i.e. the weight of the argument is ignored.
* *
* @param other Coordinate to subtract from this. * @param other Coordinate to subtract from this.
* @return The result * @return The result